Skip to content

Latest commit

 

History

History
242 lines (201 loc) · 12.8 KB

File metadata and controls

242 lines (201 loc) · 12.8 KB
Error in user YAML: (<unknown>): did not find expected comment or line break while scanning a block scalar at line 5 column 28
---
contract-id: hackylens.feature-app-sdk
owner: platform-architecture
version: 0.2.0
stability: experimental
compatibility-app-runtime: >=0.2.0,<0.3.0
compatibility-app-manifest: >=0.1.0,<0.2.0
compatibility-capability-api: >=0.1.0,<0.2.0
---

HackyLens Feature App SDK

This document describes the SDK exposed by sdk/include/. Public interface changes follow the change process.

Public entry surface

The Feature App SDK is the public C entry surface for lifecycle-v2 native apps. All SDK-owned public headers live under sdk/include. An app includes only SDK headers and the public capability types intentionally exposed or re-exported by them.

The SDK MAY depend on public Capability API headers under firmware/include/hackylens/capability/. That is the only permitted SDK to Capability dependency direction. The SDK and apps MUST NOT include capability implementation/provider/private headers, portable-service private headers, storage internals, drivers, board/BSP headers, platform/HAL headers, the K210 SDK, runtime-private headers, or generated-registry private headers.

The SDK does not replace public capability types with parallel wrappers. Lights uses runtime-owned channel sessions, obtained with hk_app_context_lights(ctx, channels, &session) and retired by runtime teardown. The binding is immutable; a channel session must not be copied or moved. Display similarly uses hk_app_context_display(ctx, plane, &session), returning a stable runtime-owned plane session. Draw calls take that pointer without an owner argument. Runtime retires both planes on teardown, including failure. External Link uses hk_app_context_external_link(ctx, mode_features, &session) and runtime-owned connector storage. Operation tokens remain separate and retain their generations across session reopen. A new wrapper type requires a concrete ABI, ownership, or language-boundary reason recorded in the contract; naming convenience is not sufficient.

The canonical umbrella is sdk/include/hackylens/app.h. It publishes the Feature App SDK 0.2.0 version, the accepted App Runtime range [0.2.0, 0.3.0), Capability API range [0.1.0, 0.2.0), and Native App Manifest schema major 1 as numeric compile-time metadata. sdk/include/hackylens/app/runtime.h owns the public lifecycle callback typedefs and immutable hk_app_v2_entry_t definition; the firmware runtime consumes that definition and MUST NOT maintain a private parallel lifecycle ABI.

App-facing contracts

SDK 0.2.x defines or re-exports only:

  • lifecycle callback types start, event, render, and stop, plus stop reasons from App Runtime 0.2.x;
  • the borrowed, generation-checked hk_app_context_t interface;
  • ordered app events, including Timer and Runtime Close;
  • the bounded view/surface interface backed by a runtime-owned Display session;
  • typed Time/Input bindings and scoped Lights/Display/External Link sessions;
  • fixed-capacity private app-state access;
  • hk_app_context_request_close as the portable close-request seam;
  • result, version, deadline, cancellation, buffer, and capability types from Capability API 0.1.x.

The context exposes no mutable descriptor, registry table, provider vtable, raw filesystem block access, unrestricted platform path, raw camera/DVP object, peripheral instance, route, board ID inference, HAL object, or driver pointer. Absence and optional fallback are explicit results, never guessed from hardware identity.

The public definition is sdk/include/hackylens/app/context.h. It carries ABI size/version, app identity, context generation and immutable Time/Input binding pointers. It contains no generic owner, grant table or runtime inventory. Lifecycle callbacks receive const hk_app_context_t *; writable app state is available through hk_app_context_state.

During start through stop, accessors validate the current callback context. Time/Input access returns the board-lifetime binding or HK_ERR_CAPABILITY_ABSENT. Lights, Display and External Link accessors return stable runtime-owned sessions. Their providers enforce actual channel, plane and connector conflicts. New sessions cannot be opened during teardown. Build-time required-service checks exclude incompatible apps before firmware compilation; runtime does not repeat manifest version/feature negotiation.

The event, stop-reason, wakeup-token, and render-surface definitions are in sdk/include/hackylens/app/runtime.h. hk_app_event_t is a bounded size/versioned union for Input, SD/media, Timer, Runtime Close, and Wakeup. Its runtime sequence is strictly increasing within one generation. Input embeds the public Capability API hk_input_event_t; no parallel input or button type is introduced. BACK is delivered as an ordinary Input event. An app that should leave on BACK calls hk_app_context_request_close; the runtime does not intercept BACK as navigation.

hk_app_context_wakeup_token creates a fixed slot/context-generation/epoch token with one app-private value. Holding the token creates no work and grants no authority by itself. A producer may return it only through a runtime-owned bounded completion path; stale tokens are rejected before app dispatch.

hk_app_context_request_render records a full or rectangular invalidation. The fixed limit is eight rectangles. hk_app_surface_t is opaque and borrowed only for the current render callback. Its API permits display information, invalidation, clear, rectangle, text, blit, and lock of the runtime-owned BASE backing store; it deliberately has no present, batch, plane-ownership, framebuffer-ownership, LCD, driver, HAL, or platform operation. hk_app_surface_lock and command-batch drawing are mutually exclusive for one render pass. Retaining a surface pointer after callback return is an SDK contract violation and every use outside that borrow returns a stale-handle error when observable by the runtime.

An invalidation requested from inside render applies to a later render pass; it is not consumed by the pass already in progress. Runtime schedules that pending pass immediately rather than waiting for the next manifest tick.

Tick and render intervals/budgets come only from the immutable generated descriptor. Apps cannot refresh them or create a catch-up loop. Timer events run synchronously on the existing firmware loop; there is no public tick callback. Render runs only for a pending invalidation and runtime owns Display begin/present/abort.

Lifecycle teardown deadline access

The SDK declares:

hk_result_t hk_app_context_teardown_deadline(
    const hk_app_context_t *ctx,
    hk_deadline_t *deadline);

During stop, this accessor returns the one finite absolute monotonic deadline stored by App Runtime when teardown began. It returns HK_ERR_INVALID_STATE outside teardown. Repeated calls return the same hk_deadline_t; the accessor MUST NOT refresh, extend, partition, or derive a per-stage or per-provider deadline.

Stop code passes this value unchanged to deadline-aware capability and service release operations. It does not call a raw clock, choose a hardware timer, or acquire a second Time implementation. App Runtime creates the value exactly once through public hk_time_deadline_after_us, the immutable Time service binding, and a runtime-controlled finite policy budget; the manifest and app cannot configure or extend it. An already-expired value remains the required value for later scoped service cleanup.

Ownership and memory

Contexts, handles, surfaces, events, and state views are borrowed for the lifetimes specified by App Runtime and the corresponding capability. Apps MUST NOT retain a callback-scoped context or surface after the callback returns. Scoped service sessions remain valid during stop; runtime then attempts retirement of every session before invalidating the context and reusing state. Sessions must not be copied or moved: provider claims use their stable address. Copying a context does not extend its lifetime or authorize a later generation. Immutable Time/Input bindings have board lifetime; context and asynchronous operation generations remain where they protect real lifetimes.

Session storage and cleanup authority remain private to runtime. Cleanup never trusts fields read back from a callback's public context snapshot.

SDK functions are bounded and allocation-free. They do not create tasks, queues, cores, general background work, or hidden heap storage. Large buffers remain explicit borrows. App state is descriptor-sized fixed storage and is reused only after the normative runtime teardown and generation invalidation. The app entry supplies state storage and its size; the descriptor uses the fixed HK_APP_STATE_ALIGNMENT ABI policy; alignment is not a runtime request or an app-manifest tuning field.

Host tests and portability

The SDK contract is platform-independent. Host tests compile the production app runtime core with typed Time, Input, and Display doubles rather than a second lifecycle engine. Test support may create descriptors, provide clock and capability/service operations, call the production runtime API, and record traces or inject faults at those seams. It MUST NOT implement its own lifecycle states, transitions, unwind, teardown ordering, or generation model.

Public lifecycle callbacks are start, event, render, and stop(ctx). hk_app_context_request_render and hk_app_context_request_close remain legal only in RUNNING, never while start is executing. Lifecycle HK_PENDING is normalized to HK_ERR_INVALID_STATE by production Runtime. Teardown creates one finite absolute monotonic deadline at teardown start and uses that same deadline for stop and scoped service provider cleanup.

Typed service operations preserve their bounded behavior. Every Input event reader has an independent caller-owned sequence cursor and reports HK_ERR_OVERFLOW with the latest stable state and exact dropped count before resynchronizing without replay. Time rejects durations above HK_TIME_MAX_SLEEP_US and addition overflow with HK_ERR_LIMIT. Ordinary close rejects UINT64_MAX as an invalid absolute deadline; forced retirement still invalidates the session and quarantines an unsafe resource on failure. Display treats zero-area rectangles as successful no-ops, accepts set_clip(NULL) as the full display, requires the normative batch/surface state for commands, present, and abort, and preserves staged state after validation failure.

Standalone CMake consumers use add_subdirectory(<hackylens>/sdk) and link HackyLens::AppSDK. Make consumers include sdk/hackylens-app-sdk.mk and use its public include flags. App sources compile from SDK headers plus their own private headers; they do not include firmware runtime, generated registry, board, platform, HAL, driver, or provider headers. Host tests may compile production runtime sources privately as test support. That is not a public host runtime framework and MUST NOT be installed or exported as an SDK target.

The SDK conformance gate recursively checks public header closure, compiles C11 and C++17 consumers, and builds/runs one minimal lifecycle-v2 app through both CMake and Make against the production runtime test support. The architecture guard rejects SDK dependencies on repository-private layers. Bundled apps are checked for architecture layering, cross-feature dependencies and raw platform access. Their existing portable firmware services are not exported by the SDK. Standalone fixtures still reject private and undeclared third-party headers; C++ syntax does not waive resource ownership rules.

A native app is portable only when it builds against this entry surface and its declared public capabilities. Successful compilation against SEN0305 private headers is not SDK conformance.

Compatibility

SDK 0.2.x accepts App Runtime 0.2.x, Native App Manifest 0.1.x schema major 1, and Capability API 0.1.x. Runtime and SDK consumers request [0.2.0, 0.3.0); Capability API remains [0.1.0, 0.2.0). An experimental breaking change increments MINOR. Publishing this SDK does not change Firmware 0.4.0, HMPY 1.1.0, Board Port 0.1.0, or MicroPython API 1.0.0.

All twelve bundled apps use the same runtime entry. No legacy adapter or manifest lifecycle selector remains. Menu, BACK, autostart, debug forced exit, safe-mode fallback, and rapid switching use one close/unwind decision.

Bundled apps may call the existing portable firmware services under architecture layer and feature-boundary guards. That does not make those services part of the standalone SDK. Standalone SDK fixtures and external apps still require strict public-header closure; migrating a lifecycle alone does not prove standalone portability. Diagnostic handlers run only for an explicitly matched command. Resource cleanup polls pending KPU/core1 completion, not inactive apps.

References