Different Toybox.Communications behaviour in Service Delegate Fenix 6 vs other devices

Hi fellow devs,

I have been developing a watchface (apps.garmin.com/.../10b12ea2-fa1c-4f46-9938-d7479d25280d) for a couple of years and recently come across some behaviour that I cannot explain/figure out....

Over time I have developed the watchface to support a variety of different devices starting with the Fenix 6 family (including derivatives such as Enduro and Marq) and other older devices such as the Venu 2 and Vivoactive 4 through to the latest generation of Fenix 8 etc.  Following a recent update users of Fenix 6 devices (and their derivatives) now get an error -403 when making a Communications.HTTP_REQUEST_METHOD_GET call in a ServiceDelegate - but not for any other devices, most notably the Vivoactive 4 and Venu 2 still work OK.  

I'm aware that there is a memory limit for background tasks but I thought this would be the same across all devices and can't see any way to identify what (if any) limit I might be breaching.  When I look at memory usage there is no issue (peak memory only about 50% of total memory available, hardly any objects used etc) and so I can't see any obvious issues.

The error started happening after making a change to add an additional property to the watchface (literally just display 12 or 24 hour time format) that does not have any implications for the API call or any logic in the ServiceDelegate.

Hs anyone had any similar experiences or ideas on what I could do next to diagnose/fix this (other than stop making it available to older devices!).

Many thanks for your input/advice!

Phil

  • The error started happening after making a change to add an additional property to the watchface (literally just display 12 or 24 hour time format

    Properties are constantly stored in app memory (in a Monkey C dictionary). Both the amount of the data and length of the property key strings have an impact on memory usage.

    Unfortunately the memory used by properties has a significant impact on apps with low amounts of available memory (e.g. data fields on old devices) or background processes (which also have low amounts of available memory). Since properties stay in memory pretty much all the time, they constantly reduce the total amount of memory available to the app.

    What you can do to mitigate this problem is to either:

    - remove unnecessary properties (may not be possible in your case)

    - reduce the length of your property key names (this might be an issue for backwards compatibility tho)

    Additionally, if you load even one resource, then the entire resource table (just indexes, not contents) is loaded into memory. Again this is a dictionary, and every entry in the dictionary has a relatively big overhead (e.g. maybe 10-20 bytes).

    For CIQ devices since 3.1.0 (including Fenix 6), by default, resources will only be loaded in the foreground, and any background resources must be explicitly scoped as such.

    So you shouldn't have a problem with too many resources, unless your background task does load resources and unless too many resources are scoped to the background.

    When I look at memory usage there is no issue (peak memory only about 50% of total memory available, hardly any objects used etc) and so I can't see any obvious issues.

    The memory viewer doesn't tell you anything about your background process tho.

    You might want to use System.getStats() to log the available and free memory before you call makeWebRequest in your background process. You won't be able to see the peak memory, but will be able to see how close to the limit you are.

    If you are testing in the simulator, you can also play with the appTypes.memoryLimit limit for type=background, in compiler.json [*] for your device (make a backup first). That way you can:

    - lower the memory limit until it crashes at the web request. (Or if it's already crashing, raise the limit until it doesn't crash)

    - note the used memory before the web request

    - raise the limit incrementally until it doesn't crash

    - the difference between the new limit and the used memory before the crash should be equal to the additional memory required for the request to succeed (including overhead plus the size of the returned data itself)

    - this difference should also be the worst case amount of extra memory you need to free up. (Ofc in the best case, you might just need to free a little bit of memory

    As far as saving memory in your background process goes, you might just have to optimize the code by hand, or perhaps try splitting requests into smaller pieces if possible.

    [*]

    - Device configs are located in .../ConnectIIQ/Devices/DEVICE_ID, where DEVICE_ID is the ID used in manifest.xml when selecting supported devices. e.g. fenix6, fenix6s

    - What I refer to as ".../ConnectIIQ" is the parent folder of the SDKs and device configs.

    e.g. the current SDK is located at .../ConnectIQ/SDKs/CURRENT_SDK

    You can navigate to .../ConnectIQ as follows:

    - In VS Code, open command palette (CTRL/CMD-SHIFT-P, and select "Monkey C: Open Samples folder"

    This opens a folder like .../ConnectIQ/SDKs/CURRENT_SDK/Samples

    - Navigate to the parent folder 3 times until you reach ConnectIQ

    Or, navigate directly to the folder:

    Windows: %APPDATA%\Garmin\ConnectIQ\

    Mac: $HOME/Library/Application Support/Garmin/ConnectIQ/

    Linux: $HOME/.Garmin/ConnectIQ/

  • Hi flowstate,


    Many thanks for the information.  I've run some tests and you are spot on about the properties, the only way I've managed to stop the error is by rationalising down the number of properties.  It looks like the way forward will be to create a separate watchface for the F6 family of devices with limited options (properties).

    I appreciate you taking the time to share your knowledge.

    Regards

    Phil