warmsound / crystal-face

Garmin Connect IQ watch face

Home Page:https://apps.garmin.com/en-GB/apps/9fd04d09-8c80-4c81-9257-17cfa0f0081b

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Crash on Venu 3.80 firmware

warmsound opened this issue · comments

User Tim Marsh has kindly supplied crash logs. All his crashes have the same callstack:

Error: Unexpected Type Error
Details: 'Failed invoking <symbol>'
Time: 2019-12-22T00:50:52Z
Part-Number: 006-B3226-00
Firmware-Version: '3.80'
Language-Code: eng
ConnectIQ-Version: 3.1.5
Store-Id: 9fd04d09-8c80-4c81-9257-17cfa0f0081b
Store-Version: 61
Filename: 9C825636
Appname: Crystal
Stack: 
  - pc: 0x10003189
  - pc: 0x1000301e

Callstack corresponds to the following code:

	function onExitSleep() {
		// ...

		// If watch does not support per-second updates, AND HideSeconds property is false,
		// show seconds, and make move bar original width.
		if (!PER_SECOND_UPDATES_SUPPORTED && !App.getApp().getProperty("HideSeconds")) {
			setHideSeconds(false);
		}

		// ...
	}

	function setHideSeconds(hideSeconds) {
		if (mIsBurnInProtection) {
			return;
		}

		mTime.setHideSeconds(hideSeconds); // <-- CRASH HERE
		mDrawables[:MoveBar].setFullWidth(hideSeconds);
	}

This suggests that PER_SECOND_UPDATES_SUPPORTED is false for Venu, or else setHideSeconds() would not be called. This implies that Ui.WatchFace no longer has :onPartialUpdate in the latest Venu firmware:

	// N.B. Not all watches that support SDK 2.3.0 support per-second updates e.g. 735xt.
	private const PER_SECOND_UPDATES_SUPPORTED = Ui.WatchFace has :onPartialUpdate;

When Venu exits sleep, it is still in always-on mode, so the mTime drawable reference will be null, until the watch face switches back to the regular layout at the beginning of the next onUpdate() draw cycle. This explains the crash.

AFAIK, Venu has never advertised onPartialUpdate support, so setHideSeconds() is always called from onExitSleep(). So mIsBurnInProtection must be failing to be set, so setHideSeconds() fails to return early, causing the crash. mIsBurnInProtection is set as follows in onEnterSleep():

// If watch requires burn-in protection, set flag to true when entering sleep.
// #157 Add screen width test, as Fenix 5X firmware 15.10 incorrectly sets requiresBurnInProtection to true.
// TODO: Remove this workaround before OLED screens with different width are introduced.
var settings = Sys.getDeviceSettings();
if (settings has :requiresBurnInProtection && settings.requiresBurnInProtection && (/* Venu */ settings.screenWidth == 390)) {
	mIsBurnInProtection = true;
	mBurnInProtectionChangedSinceLastDraw = true;
}

Given that Venu was crashing even before the #157 fix that added the screenWidth test, this could mean that Venu is no longer reporting requiresBurnInProtection on firmware 3.80.

An alternative explanation is that Venu starts off in sleep mode, without calling onEnterSleep(), so mIsBurnInProtection fails to be set while in sleep mode.

But if the crash is caused by a mTime being null, this suggests that the always-on layout is active, which is only possible if mBurnInProtectionChangedSinceLastDraw was successfully set to true, AND mIsBurnInProtection was also successfully set to true. This only occurs in onEnterSleep(), since both variables are initialise to false at startup.

So how is isBurnInProtection false at the start of onExitSleep()? Is onExitSleep() being called twice?

Without understanding the underlying cause, given that it's nearly Christmas, a quick fix for the crash would be to return early from setHideSeconds() if mTime is null.