Skip to content

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.

Load once, with multiple rounds of start-up and stopgm_plugin_entry and on_load establish the load lifecycle. on_start begins a visible run; on_loop/on_event perform work; on_suspend/on_resume suspend and resume; on_stop ends the run; and on_unload finally releases load-lifetime resources.MEMOMIND / NATIVE LIFECYCLELoad once, with multiple rounds of start-up and stopLoad the imagegm_plugin_entry → on_loadon_startCreate this run's UI /subscriptionsRunningon_loop / on_eventBrief updates and eventhandlingsuspend /resumeEntry:on_suspendReturn:on_resumeon_stopRelease this run's UI andactive serviceson_unloadRelease loadresourcesStop current cycleMay call on_start againSame loaded imageNormal path. In matching firmware and Studio, failed on_load does not trigger on_unload,and failed on_start does not trigger on_stop. Failing callbacks clean up their own partialinitialization.
Load once, with multiple rounds of start-up and stopgm_plugin_entry and on_load establish the load lifecycle. on_start begins a visible run; on_loop/on_event perform work; on_suspend/on_resume suspend and resume; on_stop ends the run; and on_unload finally releases load-lifetime resources.MEMOMIND / NATIVE LIFECYCLELoad once, with multiplerounds of start-up andstopLoad the imagegm_plugin_entry →on_loadon_startCreate this run's UI /subscriptionsRunningon_loop / on_eventBrief updates and eventhandlingOptional: suspend /resumeEntry: on_suspendReturn: on_resumeon_stopEnd this round andrelease UI resourceson_unloadRelease load resourcesbefore unloadDashed line: the same loaded imagecan call on_start again afterstopping. Suspension is optional;stopping does not require suspensionfirst.Normal path. In matching firmware andStudio, failed on_load does nottrigger on_unload, and failedon_start does not trigger on_stop.Failing callbacks clean up their ownpartial initialization.
Normal states can transition back and forth. See below for callback details and failure cleanup.

What each callback does#

CallbackAppropriate workCommon Errors
gm_plugin_entryValidate the Host and fill in the descriptorAllocating memory at entry, leaving no cleanup opportunity after validation fails.
on_loadNon-UI resources held during loadingCreating UI before the LVGL root exists, or relying on later callbacks to clean up partially initialized resources after a load failure.
on_startCreate UI for the current visible cycle, enable inputWaiting for on_stop to clean up after failure. A failing on_start must release its own acquired resources.
on_loopBrief game updates, IMU reads, and incremental tasksBlocking waits, infinite loops, and sleep calls that stall the display task.
on_eventRead button, connection, or BT messages and update stateRetaining borrowed event/data pointers for later use.
on_suspend / on_resumePause and resume active tasksRecreating existing resources on resume.
on_stopRelease this run's UI/subscriptions and stop active servicesDelete the LVGL root object owned by the Host.
on_unloadRelease resources held for the load lifecycleAssuming 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#

  1. Run, stop, and re-run three times in Studio to observe whether there is a repeat object or an old event.
  2. On the physical device, stop the application, switch to another plugin, then return to the original.
  3. After calling host->app_exit(), stop further work in the current callback immediately and do not access UI again.
  4. 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/ContentMemory behavior
Code and ordinary read-only constantsExecuted 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 TableAllocated separately at load time, with initialized data copied and BSS zeroed. Total runtime use also includes dynamic heap, task stacks, and Host overhead.
Installation buffersTransfers 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 executionRelease 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 unloadStopping 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