diff --git a/requirements/specifications/lifecycle/index.md b/requirements/specifications/lifecycle/index.md index 5c099a095..f1ba59f21 100644 --- a/requirements/specifications/lifecycle/index.md +++ b/requirements/specifications/lifecycle/index.md @@ -6,7 +6,7 @@ See [Firebolt Requirements Governance](../../governance.md) for more info. | Contributor | Organization | | -------------- | -------------- | -| Andrew Bennet | Sky | +| Andrew Bennett | Sky | | Cody Bonney | Charter | | Bart Catrysse | Liberty | | Tim Dibben | Sky | @@ -23,40 +23,39 @@ See [Firebolt Requirements Governance](../../governance.md) for more info. This document describes the requirements that Firebolt platforms and Firebolt applications must fulfill when managing App Lifecycles. *App Lifecycle* refers to the lifecycle of an individual app from the time -it is launched/loaded to the time it is unloaded and all runtime +it is launched/loaded to the time it is destroyed and all runtime resources are discarded. -*Loading* an app refers to fetching the initial resources, e.g. the +*Initializing* an app refers to fetching the initial resources, e.g. the app-manifest and index.html, and loading them into a container capable of running the app, e.g. a web browser. *Activating* an app refers to the process of getting an app into a state where it is presented as part of the user-perceptible experience (e.g. -visible, audible, or responding to input). This may include *loading* +visible, audible, or responding to input). This may include *initializing* the app first, if needed. For details on presentation, see [App Presentation](./presentation.md). *Closing* an app refers to the process of getting an app out of a state where it is the primary user experience (e.g not visible, not audible, -and not responding to input). This **does not** involve *unloading* the +and not responding to input). This **does not** involve *destroying* the app. -*Suspending* an app refers to reducing the app's memory usage and CPU -cycles, and deallocating its graphics compositors so that other apps -will have more resources available. +*Suspending* an app refers to reducing the app's memory and CPU usage, +and deallocating its graphics surface so that other apps will have +more resources available. -*Resuming* an app refers to reallocating its graphics compositors and +*Resuming* an app refers to reallocating its graphics surface and resuming normal CPU and memory allocations. -*Destroying* / unloading an app refers to the process of notifying an app to do any +*Destroying* an app refers to the process of notifying an app to do any needed clean up, and then *terminating* it. *Terminating* an app refers to shutting down the app's container and reclaiming any memory, CPU, etc. that it was consuming. -*Sleeping* an app refers to turning off all CPU cycles for that app -and possibly copying the app's memory stack out of RAM so it may be -revived later. +*Sleeping* an app refers to putting the app into a state where it does +not use CPU cycles, which allows the platform to optimise memory consumption. *Waking* an app refers to copying a Sleeping app back into the memory space of a compatible process so that it resumes where it left @@ -71,7 +70,6 @@ off. - [2.5. Sleeping](#25-sleeping) - [3. Getting the current state](#3-getting-the-current-state) - [4. Lifecycle State Transitions](#4-lifecycle-state-transitions) - - [4.1. Loading an app](#41-loading-an-app) - [4.2. Initializing an app](#42-initializing-an-app) - [4.3. Activating an app](#43-activating-an-app) - [4.4. Deactivating an app](#44-deactivating-an-app) @@ -79,9 +77,8 @@ off. - [4.6. Resuming an app](#46-resuming-an-app) - [4.7. Putting an app to sleep](#47-putting-an-app-to-sleep) - [4.8. Waking an app from sleep](#48-waking-an-app-from-sleep) - - [4.9. Unloading an app](#49-unloading-an-app) + - [4.9. Destroying an app](#49-destroying-an-app) - [4.10. Terminating an app](#410-terminating-an-app) -- [5. Getting the current status](#5-getting-the-current-status) - [6. Activity Navigation](#6-activity-navigation) - [7. Launch Parameters](#7-launch-parameters) - [8. Core SDK APIs](#8-core-sdk-apis) @@ -103,7 +100,7 @@ to state. A Firebolt app, once running, **MUST** be in one of several states and **MUST NOT** be in more than one state at a time. -As an app changes states the platform will invoke specific app-provided transition methods, see [Transitions](#3-lifecycle-state-transitions), for more on this. +As an app changes states the platform will invoke specific app-provided transition methods, see [Transitions](#4-lifecycle-state-transitions), for more on this. ![Lifecycle States](../../images/specifications/lifecycle/lifecycle-states.png) @@ -122,7 +119,7 @@ As an app changes states the platform will invoke specific app-provided transiti | F/S | File System | | Net | Network | | GFX | Graphics rendering | -| SFC | Graphics compositor surface | +| SFC | Graphics surface | | A/V | Audio Video Decoder | | ↓ | Limited | | ✔ | Normal access | @@ -132,10 +129,10 @@ As an app changes states the platform will invoke specific app-provided transiti This is the initial state an app exists from the moment it starts receiving CPU cycles. -When an app starts running is **MUST** initialize the Firebolt SDK as quickly as possible -and then wait for the `Application.create()` inteface to be called before doing further setup. +When an app starts running it **MUST** initialize the Firebolt SDK as quickly as possible +and then wait for the `Application.create()` interface to be called before doing further setup. -Apps in this state **MUST NOT** have access to the graphics compositor. +Apps in this state **MUST NOT** have a graphics surface allocated yet. Apps in this state **MUST NOT** be visible. @@ -145,6 +142,8 @@ Apps in this state **MUST NOT** have access to the audio-video decoder. Apps in this state **MUST NOT** use the media pipeline. +See [Initializing an app](#42-initializing-an-app) for more information. + ### 2.2. Running This state allows an app to be running and ready to go, but not actively part @@ -153,7 +152,10 @@ of the user-perceptible experience. Running apps can execute code, but are not [Presented](./presentation.md) to the user, do not receive any input from RCUs, and cannot use the video decoder. -Apps in this state **MUST** have access to the graphics compositor. +Apps in this state **MUST** have access to the graphics surface. + +Apps in this state **MAY** have created, allocated a graphics surface +but it will not be made visible by platform compositor. Apps in this state **MUST NOT** be visible. @@ -190,19 +192,12 @@ they have permission to the `xrn:firebolt:capability:decoder:video` capability and the platform has an available software or hardware decoder. -Apps in this state **MUST** have access to the graphics compositor. - -Apps in this state **SHOULD NOT** have performance negatively impacted -by other processes on the device. +Apps in this state **MUST** have access to the graphics surface. -Apps in this state **SHOULD** use less than XXX megabytes of RAM. - -**TODO**: do we want tiers of apps? per-app config? +Apps in this state **SHOULD** reduce memory usage, if possible. When an app transitions to this state, the platform **MUST** dispatch -the `Lifecycle.onActive` notification with the current state and -previous states. - +the `Lifecycle.onStateChanged` notification with the current state. ### 2.4. Suspended @@ -211,7 +206,8 @@ This state allows an app to remain in memory and consume fewer resources. Suspended apps can execute code, but are not [Presented](./presentation.md) to the user, do not receive any input from RCUs, and cannot use the video decoder. -Apps in this state **MUST NOT** have access to the graphics compositor. +Apps in this state **MUST NOT** have a graphics surface allocated any +longer. It **MUST** have been deallocated in the `suspend()` transition. Apps in this state **MUST NOT** be visible. @@ -219,16 +215,9 @@ Apps in this state **MUST NOT** receive RCU key presses. Apps in this state **MUST NOT** have access to the audio-video decoder. -Apps in this state **SHOULD NOT** have performance negatively impacted -by other processes on the device. - -Apps in this state **SHOULD** use less than XXX megabytes of RAM. +Apps in this state **SHOULD** further reduce memory usage (more so than in the `active` state), if possible. -**TODO**: do we want tiers of apps? per-app config? - -When an app transitions to this state, the platform **MUST** dispatch -the `Lifecycle.onSuspended` notification with the current state and -previous states. +**TODO**:: add all the transition pre-requisites, e.g. Apps **MUST** only enter this state from the `SUSPENDED` state, via the `sleep()` interface. ### 2.5. Sleeping @@ -236,34 +225,25 @@ This state allows an app to be copied from memory to local storage and then terminated to save resources. Subsequently, the app may be copied back into memory, and resume in the same state. -Apps **MUST** be able to subscribe to the Lifecycle.onSleeping -notification without errors regardless of whether the platform supports -suspending apps. For platforms that do not support it the notification -will just never fire. - *If* a platform does not support the -`xrn:firebolt:capability:lifecycle:sleep`, then the following +`xrn:firebolt:capability:lifecycle:sleepable` capability, then the following requirements **MUST NOT** be fulfilled, even partially. A platform **MUST NOT** use the APIs documented here to implement an alternate, non-compliant version of the app sleeping feature. -*If* a platform supports the `xrn:firebolt:capability:lifecycle:sleep` +*If* a platform supports the `xrn:firebolt:capability:lifecycle:sleepable` capability, then the following requirements **MUST** be fulfilled. -Apps **MUST** only enter this state from the `RUNNING` state, via -the `suspend()` interface. +Apps **MUST** only enter this state from the `SUSPENDED` state, via +the `sleep()` interface. -*Immediately before* an app transitions to this state, the platform -**MUST** dispatch the Lifecycle.onSleeping notification with the -current state and previous states. +If a platform supports copying sleeping apps memory out of RAM then: -The platform **MUST** save the app's memory space at this point, so -that it may be unsuspended later. If storing the app\'s memory space -fails for any reason, then the app **MUST** be treated as though it -were unloaded. - -Finally, the app and its container **MUST** be removed from memory -and have other resources released as well. +> The platform **MAY** save the app's memory space at this point, so +> that it may be woken later. +> +> Finally, the app and its container **MAY** be removed from memory +> and have other resources released as well. ## 3. Getting the current state The Lifecycle module **MUST** provide a `state` property API that @@ -283,9 +263,10 @@ The `state` API must have one of the following values: - `Running` - `Suspended` - `Active` +- `Sleeping` -Note that an app could never call `state` while the app is in the -`Sleeping` state, so it is not a valid value. +Note that the `onStateChanged` notification **MUST** never be dispatched +for the `Sleeping` state since it would not be received anyway. ## 4. Lifecycle State Transitions There are several state transitions where the app and the platform need @@ -304,8 +285,8 @@ methods from the `Application` interface: | | CPU | RAM | Net | GFX | A/V | Description | |----------------|-----|-----|-----|-----|-----|-------------------------------------------------------------------------------| | `create()` | ✔ | ✔ | ✔ | ✔ | | Creation of the app, from a Firebolt Lifecycle perspective. | -| `suspend()` | ✔ | ✔ | ✔ | ✔ | | Reduce memory usage and CPU cycles, deallocate graphics compositors. | -| `resume()` | ✔ | ✔ | ✔ | ✔ | | Graphics compositors reallocated, full memory usage and normal CPU cycles. | +| `suspend()` | ✔ | ✔ | ✔ | ✔ | | Reduce memory and CPU usage, deallocate graphics surface. | +| `resume()` | ✔ | ✔ | ✔ | ✔ | | graphics surface reallocated, full memory usage and normal CPU cycles. | | `destroy()` | ✔/↓ | ✔/↓ | ✔ | | | Preprare for the app to be deallocated and removed from execution. CPU & RAM based on previous state. | If an app implements the `Activity` interface, then the following transitions may be invoked: @@ -323,7 +304,7 @@ Finally, if an app implements the `Sleepable` interface, then the following tran | `sleep()` | ↓ | ↓ | ✔ | | | Prepare for an extended period with no CPU cycles given to app. | | `wake()` | ↓ | ↓ | ✔ | | | Cleanup after an extended period with no CPU, e.g. reset timers / network connections. | -These transition APIs are asynchronous, and each one has a platform-configurable timeout that specifies how long the app has to fulfill the method. +All of these transition APIs are blocking, and each one has a platform-configurable timeout that specifies how long the app has to fulfill the method. The platform **MUST** never invoke a transions on an app when that app is already running a transition. @@ -338,9 +319,9 @@ This includes: By providing an implementation of the `xrn:firebolt:capability:lifecycle:application` interface, an app can -influence how resources are managed during these state transitions. See [Application Interface](#71-application-interface) for more info. +influence how resources are managed during these state transitions. See [Application Interface](#81-application-interface) for more info. -User-facing apps **MUST** implement the `Activity` interface, `xrn:firebolt:capability:lifecycle:activity`. +User-facing apps **MUST** implement the `Activity` interface, `xrn:firebolt:capability:lifecycle:activatible`. This includes: @@ -349,41 +330,13 @@ This includes: - `Application.navigate()` By providing an implementation of the -`xrn:firebolt:capability:lifecycle:activity` interface, an app can -influence how resources are managed during these state transitions. See [Activity Interface](#72-activity-interface) for more info. - -### 4.1. Loading an app - -**TODO**: Should this be it's own spec, and out of scope? - -Loading an app fetches the initial resources, e.g. the app-manifest and -index.html, and loads them into a container capable of running the app, -e.g. a web browser. This happens before any Lifecycle transition occur, -because part of the loading process is connecting to the Firebolt SDK. - -The platform may load apps for any number of reasons that are out of -scope for this document. - -Loading an app requires the platform to know the URL to the app's -Firebolt manifest. - -To load an app, platforms **MUST** use the following process. - -First, fetch the app manifest and validate its signature (See 'App -Manifests' for more info). - -The app **MUST** be terminated if the signature is not valid and the -manifest's releaseStatus is not developer. - -Next, if the app is an HTML/JavaScript app, then load the app's initial -URL (from the app manifest) into the browser. - -**TODO**: add more details here, e.g. containers, graphics, media pipeline, ram +`xrn:firebolt:capability:lifecycle:activatible` interface, an app can +influence how resources are managed during these state transitions. See [Activity Interface](#82-activity-interface) for more info. ### 4.2. Initializing an app Once an app is loaded it **MUST** be initialized immediately. -Initialzing consists of three parts: +Initializing consists of three parts: - Registration of the Firebolt Application provider - Any other code that automatically runs within the app executable @@ -406,7 +359,7 @@ Otherwise, the platform **MUST** call the app's implementation of > and is ready to be activated and presented to the user. > > If the app times out or makes a `createError` call, then the app -> **MUST** be terminated. +> **MUST** be immediately terminated by the platform. Apps **SHOULD** set up any Firebolt event listeners either before calling `Lifecycle.provide` or during `create()`, since the platform will wait until @@ -421,7 +374,7 @@ global style sheet or a logo used throughout the experience, during initialization. During the `create()` transition, apps **MUST** inspect the `params` -parameter for [LaunchParameters](#7-launch-parameters) and prepare to fulfill the +parameter for [Parameters](#7-launch-parameters) and prepare to fulfill the provided launch configuration. Example Launch Parameters: @@ -429,6 +382,7 @@ Example Launch Parameters: ```json { "preload": true, + "launchMode"?: "running" | "suspend", "privacy": { "limitAdTracking": true } @@ -437,10 +391,8 @@ Example Launch Parameters: **TODO**: discuss this ^^ -Once the `create` method returns the app **MUST** be transitioned to -the `RUNNING` state within 100 milliseconds. - -**TODO** Discuss ^^ +Once the `create` method returns the app **MUST** be immediately transitioned to +the `RUNNING` state. ### 4.3. Activating an app @@ -457,18 +409,18 @@ To activate an app, platforms **MUST** use the following process. If the app is already in the `ACTIVE` state, then it is already activated and there is no need to do anything else. The platform **MUST NOT** dispatch any *additional* lifecycle notifications when attempting -to activate an app that is already in the foreground state and the +to activate an app that is already in the active state and the remainder of this section does not apply. -If the app is not loaded, then the platform **MUST** [load](#31-loading-an-app) it first. +If the app is not loaded, then the platform **MUST** [load](undefined) it first. -If the app is not initialized, the platform **MUST** [initialize](#32-initializing-an-app) it first. +If the app is not initialized, the platform **MUST** [initialize](#42-initializing-an-app) it first. -If the app is suspended, then it **MUST** be [resumed](#37-resuming-an-app) first. +If the app is suspended, then it **MUST** be [resumed](#46-resuming-an-app) first. At this point, the app **MUST** be in the `RUNNING` state. -If an app provides the `xrn:firebolt:capability:lifecycle:activity` +If an app provides the `xrn:firebolt:capability:lifecycle:activatible` capability, then the platform **MUST** call the app's implementation of `Activity.activate()`: @@ -526,6 +478,8 @@ dispatch any *additional* lifecycle notifications when attempting to close an app that is already in the `RUNNING` state and the remainder of this section does not apply. +**TODO**: list out all possible transition "interuptions" and make sure they are described in this doc. + If an app is in the `initializing` state, then it is not If an app is already performing a `deactivate()` transition, the platform @@ -534,19 +488,19 @@ closure to complete, and the remainder of this section does not apply. If an app is already performing an `activate()` transition, the platform **MUST** wait for the activate call to succeed or fail and then skip the -remaining [activation steps](#33-activating-an-app). +remaining [activation steps](#43-activating-an-app). -If an app is currently [initializing](#32-initializing-an-app), the +If an app is currently [initializing](#42-initializing-an-app), the platform **MUST** wait for initialization to succeed or fail and then skip any activation that may have been pending. -If an app is currently [unloading](#38-unloading-an-app) then the app -cannot be closed and the platform **MUST NOT** close it, and the +If an app is currently in a [destroy](#49-destroying-an-app) transition then +the app cannot be closed and the platform **MUST NOT** close it, and the remainder of this section does not apply. At this point, the app **MUST** be in the `ACTIVE` state. -If an app provides the `xrn:firebolt:capability:lifecycle:application` +If an app provides the `xrn:firebolt:capability:lifecycle:activatible` capability, then the platform **MUST** call the app's implementation of `Activity.deactivate()`: @@ -564,7 +518,7 @@ capability, then the platform **MUST** call the app's implementation of During the `deactivate()` transition, the app **MUST** deallocate any A/V decoders. -The platform **MAY** begin to transition your app out of view as soon as +The platform **MAY** begin to transition the app out of view as soon as `deactivate()` is called. ### 4.5. Suspending an app @@ -600,8 +554,8 @@ happen. At this point, the app **MUST** be in the `RUNNING` state. -If an app provides the `xrn:firebolt:capability:lifecycle:application` -capability, then the platform **MUST** call the app's implementation of +Since every app **MUST** provide the `xrn:firebolt:capability:lifecycle:application` +capability, the platform **MUST** call the app's implementation of `Application.suspend()`: > The platform **MUST** dispatch the `Lifecycle.onRequestSuspend` @@ -613,30 +567,28 @@ capability, then the platform **MUST** call the app's implementation of > may be moved to the `SUSPENDED` state. > > If the app times out or makes a `suspendError` call, then the app -> **MUST** be [unloaded](#38-unloading-an-app). +> **MUST** be [destroyed](#49-destroying-an-app). During the `suspend()` transition, the app: -> **MUST** deallocate any graphics compositors. +> **MUST** deallocate any graphics surface. > -> **SHOULD** reduce memory usage to under XXX megabytes - -**TODO**: discuss ^^ +> **SHOULD** reduce memory usage, if possible. ### 4.6. Resuming an app Resuming an app allows it to reallocate graphics composition and reload any resources it might have deallocated during `suspend()`. -The platform may unsuspend apps so they can access more resources or +The platform may resume apps so they can access more resources or in preperation to activate them. -To unsuspend an app, platforms **MUST** use the following process. +To resume an app, platforms **MUST** use the following process. -If an app is not in the `SUSPENDED` state, then it cannot be unsuspended +If an app is not in the `SUSPENDED` state, then it cannot be resumed and there is no need to do anything else. The platform **MUST NOT** dispatch any *additional* lifecycle notifications when attempting to -unsuspend an app that is not in the `SUSPENDED` state and the remainder of +resume an app that is not in the `SUSPENDED` state and the remainder of this section does not apply. At this point, the app **MUST** be in the `SUSPENDED` state. @@ -665,34 +617,36 @@ composition and other necessary resources. ### 4.7. Putting an app to sleep TBD -Firebolt apps that have permission to use the `xrn:firebolt:capability:lifecycle:sleep` capability **MUST** implement `Sleepable.sleep()`. +Firebolt apps that have permission to use the `xrn:firebolt:capability:lifecycle:sleepable` capability **MUST** implement `Sleepable.sleep()`. + +TODO: if you don't call provide, we won't do this. ### 4.8. Waking an app from sleep TBD -Firebolt apps that have permission to use the `xrn:firebolt:capability:lifecycle:sleep` capability **MUST** implement `Sleepable.wake()`. +Firebolt apps that have permission to use the `xrn:firebolt:capability:lifecycle:sleepable` capability **MUST** implement `Sleepable.wake()`. -### 4.9. Unloading an app +### 4.9. Destroying an app -Unloading an app transitions it out of memory, so that it is no longer +Destroying an app transitions it out of memory, so that it is no longer using resources on the device. -The platform may unload apps for any number of reasons that are out of +The platform may destroy apps for any number of reasons that are out of scope for this document. -To unload an app, platforms **MUST** use the following process. +To destroy an app, platforms **MUST** use the following process. -If an app is not in the `RUNNING` state, then it cannot be unloaded and +If an app is not in the `RUNNING` state, then it cannot be destroyed and there is no need to do anything else. The platform **MUST NOT** dispatch -any *additional* lifecycle notifications when attempting to unload an +any *additional* lifecycle notifications when attempting to destroy an app that is not in the `RUNNING` state and the remainder of this section does not need to happen. At this point, the app **MUST** be in the `RUNNING` state. -If an app provides the `xrn:firebolt:capability:lifecycle:application` -capability, then the platform **MUST** call the app's implementation of -`Application.unload()`: +Since every app **MUST** provide the `xrn:firebolt:capability:lifecycle:application` +capability, the platform **MUST** call the app's implementation of +`Application.destroy()`: > The platform **MUST** dispatch the `Lifecycle.onRequestDestroy` > notification to the app, and wait for `appDestroyTimeout` milliseconds @@ -700,7 +654,7 @@ capability, then the platform **MUST** call the app's implementation of > call in response. > > Once the platform receives the `destroyResult` call, then the platform -> may proceed with app unloading. +> may proceed with app destroying. > > If the app times out or makes an `destroyError` call, then the app > **MUST** be terminated. @@ -717,35 +671,7 @@ Terminating an app results in removing it from memory and all resources held by the app and it's container being freed up. Platforms **MAY** terminate an app when needed but **SHOULD NOT** do -this in place of graceful [unloading](#38-unloading-an-app). - -## 5. Getting the current status -The Lifecycle module **MUST** provide a `status` property API that -returns the current lifecycle transition of the app if one is in -progress, otherwise, it returns the current state. - -If an app is in a transtition from one state to another, then it -**MUST** be considered in the transition until -such time as the app's implementation of the [transition](#4-lifecycle-state-transitions) has returned -and the platfrom has finshed the transition. - -The `status` API **MUST** have a corresponding `onStatusChanged` -notification. - -The `status` API must have one of the following values: - -- `Initializing` -- `Creating` -- `Running` -- `Suspending` -- `Suspended` -- `Resuming` -- `Activating` -- `Active` -- `Deactivating` -- `Sleeping` -- `Waking` -- `Destroying` +this in place of graceful [destroying](#49-destroying-an-app). ## 6. Activity Navigation Typically navigation is handled either when the app is activated, via @@ -772,14 +698,21 @@ the app, which may include: The `LaunchParameters` type is an object with the following properties: ```typescript -type LaunchParameters = { +type Parameters = { preload: boolean, + reason: "boot" | "restart" // load-reason, preload-reason privacy: { - limitAdTrackign: boolean + limitAdTracking: boolean } } ``` +// Parameters.initialization() + +- suspended after app restart +- suspended after power on +- foreground after app start + ^^^ need to dicuss what we need in here, and also what to do w/ US-centric stuff like 'limitAdTracking' ## 8. Core SDK APIs @@ -797,7 +730,7 @@ All apps **MUST** implement the Application interface. ```typescript interface Application { - function create(params: LaunchParameters): Promise; + function create(params: Parameters): Promise; function suspend(): Promise; function resume(): Promise; function destroy(): Promsie; @@ -808,8 +741,8 @@ interface Application { | Method | Description | | -------- | ----------- | | `create()` | Called when the platform is ready to create the lifecycle session for the app. Only called only once, during the `INITIALIZING` state. | -| `suspend()` | Called when the platform requires the app to deallocate its graphics compositor and reduce memory as much as possible. This may be called anytime the app is in the `RUNNING` state. | -| `resume()` | Called when the platform wants the app to reallocate its graphics compositor and prepare to be potentially used. | +| `suspend()` | Called when the platform requires the app to deallocate its graphics surface and reduce memory as much as possible. This may be called anytime the app is in the `RUNNING` state. | +| `resume()` | Called when the platform wants the app to reallocate its graphics surface and prepare to be potentially used. | | `destroy()` | Called when the platform is ready to end the lifecycle session for the app. Only called once. | ### 8.2. Activity Interface @@ -899,7 +832,7 @@ class ExampleApplication implements Lifecycle.Application, Lifecycle.Activity { Lifecycle.provide([ "xrn:firebolt:capability:lifecycle:application", - "xrn:firebolt:capability:lifecycle:activity" + "xrn:firebolt:capability:lifecycle:activatible" ], new ExampleApplication()) ``` @@ -927,19 +860,19 @@ the app is requesting to be closed: |------------------------------------|------------------------------------| | CloseReason.REMOTE_BUTTON | The user pressed the back or last button on the RCU and the App has determined it is at the top of it's navigation stack and should go back to the platform home screen. | | CloseReason.USER_EXIT | The user selected an exit control exposed by the app's UI. | -| CloseReason.ERROR | The app is experiencing unrecoverable issues and needs to be closed and unloaded. | +| CloseReason.ERROR | The app is experiencing unrecoverable issues and needs to be closed and destroyed. | Platforms generally **SHOULD** respect this call and move the app to the -started state, but there may be edge cases where this is not possible, +running state, but there may be edge cases where this is not possible, e.g. the app is considered to be the default experience for the device, and closing it would leave no other UX present. When the request to close is not respected, the Lifecycle.close() method **MUST** return an error. -Platforms **MAY** prioritize apps to be unloaded based on the reason +Platforms **MAY** prioritize apps to be destroyed based on the reason provided. For example, apps closed due to the RCU are less likely to be -unloaded since it may be an accidental RCU press, whereas an explicit +destroyed since it may be an accidental RCU press, whereas an explicit user exit is more likely to be intentional. ### 8.7. State @@ -950,8 +883,6 @@ notifications. This method **MUST NOT** be asynchronous. ## 9. Lifecycle Configuration -**TODO**: do we want these to be per spec, per distributor, or per app? - In order to enable Firebolt Certification of a device's Lifecycle Management features, the device **MUST** support the following configuration options, so that the Firebolt Certification Test Suite @@ -960,13 +891,14 @@ for state transitions. The LifecyclePolicy fields are: -| Field | Type | Required | Description | -|-------------------|-------|----------|-------------------------------------| -| appCreateTimeout | bigint | Yes | Number of milliseconds the platform should wait before terminating a loaded app that did not finish `create()`. | -| appDestroyTimeout | bigint | Yes | Number of milliseconds the platform should wait after dispatching the onUnloading notification before terminating an app that did not finsih `destroy()`. | -| appActivateTimeout | bigint | Yes | Number of milliseconds the platform should wait after dispatching the onRequestActivate notification before terminating an app that did finish `activate()` | -| appDeactivateTimeout | bigint | Yes | Number of milliseconds the platform should wait after dispatching the onRequestDeactivate notification before terminating an app that did finish `deactivate()` | -| appSuspendTimeout | bigint | Yes | Number of milliseconds the platform should wait after dispatching the onRequestSuspend notification before terminating an app that did finish `suspend()` | -| appResumeTimeout | bigint | Yes | Number of milliseconds the platform should wait after dispatching the onRequestResume notification before terminating an app that did finish `resume()` | -| appSleepTimeout | bigint | Yes | Number of milliseconds the platform should wait after dispatching the onRequestSleep notification before terminating an app that did finish `sleep()` | -| appWakeTimeout | bigint | Yes | Number of milliseconds the platform should wait after dispatching the onRequestWake notification before terminating an app that did finish `wake()` | +| Field | Type | Required | Description | +|----------------------|--------|----------|--------------------------------------------------------------------------------------------------------------------------| +| appInitializeTimeout | bigint | Yes | Number of milliseconds the platform should wait before terminating a loaded app that did not call `Lifecycle.provide()`. | +| appCreateTimeout | bigint | Yes | Number of milliseconds the platform should wait before terminating a loaded app that did not finish `create()`. | +| appDestroyTimeout | bigint | Yes | Number of milliseconds the platform should wait before terminating an app that did not finsih `destroy()`. | +| appActivateTimeout | bigint | Yes | Number of milliseconds the platform should wait before terminating an app that did finish `activate()`. | +| appDeactivateTimeout | bigint | Yes | Number of milliseconds the platform should wait before terminating an app that did finish `deactivate()`. | +| appSuspendTimeout | bigint | Yes | Number of milliseconds the platform should wait before terminating an app that did finish `suspend()`. | +| appResumeTimeout | bigint | Yes | Number of milliseconds the platform should wait before terminating an app that did finish `resume()`. | +| appSleepTimeout | bigint | Yes | Number of milliseconds the platform should wait before terminating an app that did finish `sleep()`. | +| appWakeTimeout | bigint | Yes | Number of milliseconds the platform should wait before terminating an app that did finish `wake()`. | diff --git a/src/js/github.io/markdown.mjs b/src/js/github.io/markdown.mjs new file mode 100644 index 000000000..9068792e0 --- /dev/null +++ b/src/js/github.io/markdown.mjs @@ -0,0 +1,62 @@ +import nopt from 'nopt' +import path from 'path' +import { readJson, readDir, readFiles, readText, writeFiles, writeText, writeJson } from '../../../node_modules/@firebolt-js/openrpc/src/shared/filesystem.mjs' + +const knownOpts = { + 'file': [String] +} + +const defaultOpts = { +} + +const shortHands = { + 'f': '--file' +} + +// Last 2 arguments are the defaults. +const parsedArgs = Object.assign(defaultOpts, nopt(knownOpts, shortHands, process.argv, 2)) + +const signOff = () => console.log('\nThis has been a presentation of \x1b[38;5;202mFirebolt\x1b[0m \u{1F525} \u{1F529}\n') + +//const packageJson = await readJson(process.env.npm_package_json) +//const version = channel(packageJson.version) +const requirements = await readFiles(await readDir(path.join('.', 'requirements'), { recursive: true }), path.join('.')) + +const processFiles = (docs) => { + Object.keys(docs).forEach(ref => { + + if (ref.endsWith('.md')) { + let data = docs[ref] + +// console.log(data) + // find all headers + const headers = data.match(/#+[ \t]+(([0-9]+\.)+)[ /t]+(.*?)\n/g) + + // turn to slugs + const slugs = headers.map(h => h.replace(/#/g, '')) + .map(h => h.replace(/\t/g, '')) + .map(h => h.replace(/\./g, '')) + .map(h => h.replace(/^ /g, '')) + .map(h => h.replace(/\n$/g, '')) + .map(h => h.replace(/ /g, '-')) + .map(h => h.toLowerCase()) + .map(h => '#' + h) + + const links = data.match(/\]\(.*?\#.*?\)/g) + + links.map(l => l.slice(2, -1)).forEach(link => { + if (!slugs.find(s => s === link)) { + const best = slugs.find(s => s.match(new RegExp(link.replace(/^\#[0-9]+/, '#[0-9]+')))) || slugs.find(s => s.startsWith(link.split('-')[0] + '-')) + console.log('Fixing broken link: (' + link + ') -> (' + best + ')') + data = data.replace('](' + link + ')', '](' + best + ')') + } + }) + docs[ref] = data + } + }) +} + +processFiles(requirements) +writeFiles(requirements) + +signOff()