From a3acc667d608aeef037d7a4b9ce09c173bbc7818 Mon Sep 17 00:00:00 2001 From: NiLuJe Date: Sat, 7 Sep 2019 03:19:18 +0200 Subject: [PATCH] [Kobo] Restart KOReader after a crash (#5328) * Restart KOReader after a crash, after showing a fancy crash recap screen (our very own Gray Screen of Death!). Kobo only, because it's possibly the platform where getting booted out of KOReader is the most annoying. Keeps track of crashes, to be able to give up after a while, in order to avoid boot loops in the unlikely event of a crash loop on startup. Adds a dev option to *always* exit KOReader after the crash screen. --- base | 2 +- frontend/apps/filemanager/filemanagermenu.lua | 16 +++ platform/kobo/koreader.sh | 102 ++++++++++++++++-- 3 files changed, 112 insertions(+), 8 deletions(-) diff --git a/base b/base index 0ef40965b..1b3c1dfed 160000 --- a/base +++ b/base @@ -1 +1 @@ -Subproject commit 0ef40965bb83f37b2d94c9e7b85c23a97c3a1504 +Subproject commit 1b3c1dfedd794364819571c6436ac1589ec5f519 diff --git a/frontend/apps/filemanager/filemanagermenu.lua b/frontend/apps/filemanager/filemanagermenu.lua index ab4bac289..647e2964b 100644 --- a/frontend/apps/filemanager/filemanagermenu.lua +++ b/frontend/apps/filemanager/filemanagermenu.lua @@ -304,6 +304,22 @@ function FileManagerMenu:setUpdateItemTable() end, }) end + --- @note Currently, only Kobo has a fancy crash display (#5328) + if Device:isKobo() then + table.insert(self.menu_items.developer_options.sub_item_table, { + text = _("Always abort on crash"), + checked_func = function() + return G_reader_settings:isTrue("dev_abort_on_crash") + end, + callback = function() + G_reader_settings:flipNilOrFalse("dev_abort_on_crash") + local InfoMessage = require("ui/widget/infomessage") + UIManager:show(InfoMessage:new{ + text = _("This will take effect on next restart."), + }) + end, + }) + end if not Device.should_restrict_JIT then table.insert(self.menu_items.developer_options.sub_item_table, { text = _("Disable C blitter"), diff --git a/platform/kobo/koreader.sh b/platform/kobo/koreader.sh index ddbc6b5e3..46fea04e5 100755 --- a/platform/kobo/koreader.sh +++ b/platform/kobo/koreader.sh @@ -43,7 +43,7 @@ ko_update_check() { ./fbink -q -y -6 -pm "Update successful :)" ./fbink -q -y -5 -pm "KOReader will start momentarily . . ." else - # Huh ho... + # Uh oh... ./fbink -q -y -6 -pmh "Update failed :(" ./fbink -q -y -5 -pm "KOReader may fail to function properly!" fi @@ -155,7 +155,7 @@ case "${ORIG_FB_BPP}" in 16) ;; 32) ;; *) - # Hu oh? Don't do anything... + # Uh oh? Don't do anything... unset ORIG_FB_BPP ;; esac @@ -196,15 +196,103 @@ if [ -e crash.log ]; then mv -f crash.log.new crash.log fi +CRASH_COUNT=0 +CRASH_TS=0 +CRASH_PREV_TS=0 +# Because we *want* an initial fbdepth pass ;). RETURN_VALUE=85 -while [ $RETURN_VALUE -eq 85 ]; do - # Do an update check now, so we can actually update KOReader via the "Restart KOReader" menu entry ;). - ko_update_check - # Do the fb depth switch, unless it's been disabled - ko_do_fbdepth +while [ $RETURN_VALUE -ne 0 ]; do + # 85 is what we return when asking for a KOReader restart + if [ $RETURN_VALUE -eq 85 ]; then + # Do an update check now, so we can actually update KOReader via the "Restart KOReader" menu entry ;). + ko_update_check + # Do or double-check the fb depth switch, or restore original bitdepth if requested + ko_do_fbdepth + fi ./reader.lua "${args}" >>crash.log 2>&1 RETURN_VALUE=$? + + # Did we crash? + if [ $RETURN_VALUE -ne 0 ] && [ $RETURN_VALUE -ne 85 ]; then + # Increment the crash counter + CRASH_COUNT=$((CRASH_COUNT + 1)) + CRASH_TS=$(date +'%s') + # Reset it to a first crash if it's been a while since our last crash... + if [ $((CRASH_TS - CRASH_PREV_TS)) -ge 20 ]; then + CRASH_COUNT=1 + fi + + # Check if the user requested to always abort on crash + if grep -q '\["dev_abort_on_crash"\] = true' 'settings.reader.lua' 2>/dev/null; then + ALWAYS_ABORT="true" + # In which case, make sure we pause on *every* crash + CRASH_COUNT=1 + else + ALWAYS_ABORT="false" + fi + + # Show a fancy bomb on screen + viewWidth=600 + viewHeight=800 + FONTH=16 + eval "$(./fbink -e | tr ';' '\n' | grep -e viewWidth -e viewHeight -e FONTH | tr '\n' ';')" + # Compute margins & sizes relative to the screen's resolution, so we end up with a similar layout, no matter the device. + # Height @ ~56.7%, w/ a margin worth 1.5 lines + bombHeight=$((viewHeight/2 + viewHeight/15)) + bombMargin=$((FONTH + FONTH/2)) + # With a little notice at the top of the screen, on a big gray screen of death ;). + ./fbink -q -b -c -B GRAY9 -m -y 1 "Don't Panic! (Crash n°${CRASH_COUNT} -> ${RETURN_VALUE})" + if [ ${CRASH_COUNT} -eq 1 ]; then + # Warn that we're waiting on a tap to continue... + ./fbink -q -b -O -m -y 2 "Tap the screen to continue." + fi + # U+1F4A3, the hard way, because we can't use \u or \U escape sequences... + # shellcheck disable=SC2039 + ./fbink -q -b -O -m -t regular=./fonts/freefont/FreeSerif.ttf,px=${bombHeight},top=${bombMargin} $'\xf0\x9f\x92\xa3' + # And then print the tail end of the log on the bottom of the screen... + crashLog="$(tail -n 25 crash.log | sed -e 's/\t/ /g')" + # The idea for the margins being to leave enough room for an fbink -Z bar, small horizontal margins, and a font size based on what 6pt looked like @ 265dpi + ./fbink -q -b -O -t regular=./fonts/droid/DroidSansMono.ttf,top=$((viewHeight/2 + FONTH * 2 + FONTH/2)),left=$((viewWidth/60)),right=$((viewWidth/60)),px=$((viewHeight/64)) "${crashLog}" + # So far, we hadn't triggered an actual screen refresh, do that now, to make sure everything is bundled in a single flashing refresh. + ./fbink -q -f -s top=0,left=0 + # Cue a lemming's faceplant sound effect! + + echo "!!!!" >>crash.log 2>&1 + echo "Uh oh, something went awry... (Crash n°${CRASH_COUNT}: $(date +'%x @ %X'))" >>crash.log 2>&1 + if [ $CRASH_COUNT -lt 5 ] && [ "${ALWAYS_ABORT}" = "false" ]; then + echo "Attempting to restart KOReader . . ." >>crash.log 2>&1 + echo "!!!!" >>crash.log 2>&1 + fi + + # Pause a bit if it's the first crash in a while, so that it actually has a chance of getting noticed ;). + if [ ${CRASH_COUNT} -eq 1 ]; then + # NOTE: We don't actually care about what read read, we're just using it as a fancy sleep ;). + # i.e., we pause either until the 15s timeout, or until the user touches the screen. + # shellcheck disable=SC2039 + read -r -t 15 >crash.log 2>&1 + echo "!!!! ! !!!!" >>crash.log 2>&1 + break + fi + + # If the user requested to always abort on crash, do so. + if [ "${ALWAYS_ABORT}" = "true" ]; then + echo "Aborting . . ." >>crash.log 2>&1 + echo "!!!! ! !!!!" >>crash.log 2>&1 + break + fi + else + # Reset the crash counter if that was a sane exit/restart + CRASH_COUNT=0 + fi done # Restore original fb bitdepth if need be...