Glasses plugin lifecycle
Create, run, and release resources in the appropriate callbacks to avoid errors on repeated starts and exit.
Callback order#
Distinguish the load lifecycle from visible runs. Once an image is loaded, it can start and stop repeatedly, and may suspend and resume. The diagram shows normal transitions; the callback table defines cleanup responsibilities on failure.
What each callback does#
| Callback | Appropriate work | Common Errors |
|---|---|---|
| gm_plugin_entry | Validate the Host and fill in the descriptor | Allocating memory at entry, leaving no cleanup opportunity after validation fails. |
| on_load | Non-UI resources held during loading | Creating UI before the LVGL root exists, or relying on later callbacks to clean up partially initialized resources after a load failure. |
| on_start | Create UI for the current visible cycle, enable input | Waiting for on_stop to clean up after failure. A failing on_start must release its own acquired resources. |
| on_loop | Brief game updates, IMU reads, and incremental tasks | Blocking waits, infinite loops, and sleep calls that stall the display task. |
| on_event | Read button, connection, or BT messages and update state | Retaining borrowed event/data pointers for later use. |
| on_suspend / on_resume | Pause and resume active tasks | Recreating existing resources on resume. |
| on_stop | Release this run's UI/subscriptions and stop active services | Delete the LVGL root object owned by the Host. |
| on_unload | Release resources held for the load lifecycle | Assuming full initialization during cleanup, or releasing resources already freed by the on_load failure path. |
Clean up within the failing load callback#
The current matching glasses firmware and Studio behave the same way: a failed on_load does not trigger on_unload, and a failed on_start does not trigger on_stop. A failing callback must release the business resources it acquired instead of waiting for an end callback that will never arrive.
Centralize cleanup in repeatable functions that check ownership state. Clear pointers and ownership flags after release. Host-managed memory reclamation is a fallback, not a substitute for correct plugin cleanup of UI, subscriptions, and external resources.
Verify exit and restart behavior#
- Run, stop, and re-run three times in Studio to observe whether there is a repeat object or an old event.
- On the physical device, stop the application, switch to another plugin, then return to the original.
- After calling host->app_exit(), stop further work in the current callback immediately and do not access UI again.
- Save persistent data through a supported storage mechanism. GMP images are cached in Flash, but writable data and static variables remain in RAM. Stop is not unload; after unload or reboot, do not rely on previous values. The Flash cache is not business-data storage.
Flash cache, updates and eviction#
The current reference glasses use a 3 MiB raw CUS8 Flash partition without a filesystem. Firmware stores the directory, image addresses, lengths, identities, and states. Plugins neither need nor have permission to manage Flash addresses themselves.
Directory metadata uses 64 KiB. The remaining image area is further reduced by quarantined bad sectors and allocation alignment. The directory currently supports at most 28 records, including update candidates, so it does not guarantee room for 28 complete plugins.
- A same-name update reserves space for that plugin's old complete image and new candidate; it does not divide the entire partition into equal halves. The new candidate replaces the old version only after full validation and successful commit. A partially written package cannot run.
- When space or directory records run out, discardable candidates are reclaimed first. External plugins are then evicted by least recent successful use, not download order or usage count. Protected entries are excluded from ordinary eviction.
- Stop the current plugin before starting another; only one runs at a time. Defragmentation may move inactive images, but a running image cannot be moved or erased.
- After disconnection or reboot, the official App and glasses determine resumable progress. A small final segment not yet persisted may be retransmitted. Resume requires the complete identity and firmware binding to still match; otherwise, transmission starts again.
- The official App checks installation capacity. Insufficient Flash space is reported separately from insufficient RAM. A capacity query does not reserve space; the actual installation result is authoritative.
- Factory protection is reserved for trusted internal firmware entry points. Lab installation uses an external path; a plugin manifest or self-assigned GM_STORE_PROTECTED cannot grant internal privileges. Protected plugins can be updated internally. No automatic factory-plugin restoration list has currently been delivered.
- Firmware upgrades may invalidate runtime-address bindings; retransmission from the phone can repair this at first start. Do not promise that OTA always preserves or clears plugin caches, or make plugin-cache anomalies a condition that blocks native OTA.
Execution from Flash: what still uses RAM#
| Phase/Content | Memory behavior |
|---|---|
| Code and ordinary read-only constants | Executed or read through Flash mapping without copying the entire GMP into RAM. Constant pointer tables requiring relocation may still occupy RAM; the presence of const in source alone is insufficient. |
| data/BSS, GOT and Pointer Table | Allocated separately at load time, with initialized data copied and BSS zeroed. Total runtime use also includes dynamic heap, task stacks, and Host overhead. |
| Installation buffers | Transfers default to blocks of 64 KiB before compression. The decompression arena is 65,824 B. Receive frames use about 8 KiB, with additional directory, task, and protocol overhead. This is not a fixed whole-device peak of 72 KiB. |
| Transition from transfer to execution | Release pipeline buffers first, then commit and release the directory session, then allocate runtime RAM. A 500 KiB ROM image does not require a 500 KiB receive buffer. |
| Stop and unload | Stopping ends a run and may retain loaded data for another start. Unloading reclaims loaded data and managed allocations, while a complete Flash cache entry may remain. |
First transfer, cache hits and bounded compressed transfers#
The official MemoMind App manages plugin installation, start, stop, and cancellation. Use a complete Studio-generated installation package and import it in the App by scanning or entering the installation address. You do not need to implement phone-to-glasses transfer.
On first installation or a cache miss, the App transfers the component and the glasses run it after complete validation. A complete cache match reuses the image without retransmission. The App handles retry or recovery after interruption.
Transfers use bounded buffers and compression as needed, overlapping reception with Flash writes where possible. Focus on installation results and memory budgets; you do not need to compress GMP manually or control low-level chunks.
Reference files in the toolkit#
- GlassSDK/include/gm_plugin.h
- GlassSDK/docs/ABI.md
- GlassSDK/docs/INSTALLATION.md