Application Lifecycle

In order to meet common needs of applications running on CE devices, Cobalt implements a well-defined web application lifecycle, managing resources and notifying the application as appropriate.

Summary of changes in Cobalt 22

The application lifecycle has some changes from Cobalt 22:

States:

  • The Paused state is renamed to Blurred.
  • The Suspended state is replaced by Concealed and Frozen.
  • The Preloading state is removed, and Concealed is used instead. Note: The corresponding attribute value ‘prerender’ for document.visibilityState is also removed.

The new Concealed state is used for applications that are not visible but may use CPU or network resources. This state is used to both replace the Preloading state, and as an intermediate state between Blurred and Frozen.

The Frozen state most closely resembles the previous Suspended state, during which applications do not have network access.

State Changes:

  • The Pause event is renamed to Blur.
  • The Unpause event is renamed to Focus.
  • The Suspend event is replaced by Conceal and Freeze.
  • The Resume event is replaced by Unfreeze and Reveal.

Most platforms should only need to replace ‘Pause’ with ‘Blur’, ‘Unpause’ with ‘Focus’, ‘Suspend’ with ‘Freeze’, and ‘Resume’ with ‘Reveal’.

Since there is no longer a special Preloading state, applications should no longer use the Start event when a preloaded application is brought to the foreground. Instead, the same event(s) used for backgrounded applications (Concealed or Frozen) should be used.

Application ‘Backgrounding’ and ‘Foregrounding’.

To signal that the application is being ‘backgrounded’, the use of Suspend should be replaced with Freeze.

To signal that the application is being ‘foregrounded’, the use of Unpause should be replaced with Focus.

Note: If a platform is using Resume (Reveal) to signal that an application is being ‘foregrounded’, then that may result in unexpected application behavior, unless a subsequent Unpause (Focus) is also used when the application receives input focus.

More details about lifecycle states and state changes can be found in src/starboard/event.h.

Deprecated SbEventType values.

The SbEventType enum is defined in src/starboard/event.h.

  • The kSbEventTypePause value is renamed to kSbEventTypeBlur.
  • The kSbEventTypeUnpause value is renamed to kSbEventTypeFocus.
  • The kSbEventTypeSuspend value is replaced by kSbEventTypeConceal and kSbEventTypeFreeze.
  • The kSbEventTypeResume value is replaced by kSbEventTypeUnfreeze and kSbEventTypeReveal.

The corresponding helper functions in starboard::shared::starboard::Application (implemented in starboard/shared/starboard/application.cc) that inject events with these values have been updated correspondingly:

  • The Pause() method is renamed to Blur().
  • The Unpause() method is renamed to Focus().
  • The Suspend() method is replaced by Conceal() and Freeze().
  • The Resume() method is replaced by Unfreeze() and Reveal().

Platforms that inject events themselves should be updated to use renamed event type values, and platforms that use the helper functions should be updated to call the corresponding renamed helper functions.

Deprecated SbSystemRequest functions.

The SbSystemRequest functions are declared in src/starboard/system.h

  • The SbSystemRequestPause event is renamed to SbSystemRequestBlur
  • The SbSystemRequestUnpause event is renamed to SbSystemRequestFocus
  • The SbSystemRequestSuspend event is replaced by SbSystemRequestConceal and SbSystemRequestFreeze
  • The SbSystemRequestResume event is replaced by SbSystemRequestUnfreeze and SbSystemRequestReveal

Application States

Starboard Application StatePage Visibility StateWindow Focused
Startedvisibletrue
Blurredvisiblefalse
Concealedhiddenfalse
Frozenhiddenfalse

When transitioning between Concealed and Frozen, the document.onfreeze and document.onresume events from the Page LifeCycle Web API will be dispatched.

Started

The application is running, visible, and interactive. The normal foreground application state. May be the start state, or can be entered from Blurred.

May only transition to Blurred. In Linux desktop, this happens anytime the top-level Cobalt X11 window loses focus. Linux transition back to Started when the top-level Cobalt X11 window gains focus again.

Blurred

The application may be fully visible, partially visible, or completely obscured, but it has lost input focus, so will receive no input events. It has been allowed to retain all its resources for a very quick return to Started, and the application is still running. May be entered from or transition to Started or Concealed at any time.

Concealed

The application is not visible and will receive no input, but is running. Can be entered as the start state. May be entered from or transition to Blurred or Frozen at any time. The application may be terminated in this state without notification.

Upon entering, all graphics resources will be revoked until revealed, so the application should expect all images to be lost, and all caches to be cleared.

Expectations for the web application

The application should shut down playback, releasing resources. On resume, all resources need to be reloaded, and playback should be reinitialized where it left off, or at the nearest key frame.

Frozen

The application is not visible and will receive no input, and, once Frozen, will not run any code. May be entered from or transition to Concealed at any time. The application may be terminated in this state without notification.

Upon entering, all graphics and media resources will be revoked until resumed, so the application should expect all images to be lost, all caches to be cleared, and all network requests to be aborted.

Expectations for the porter

Currently, Cobalt does not manually stop JavaScript execution when it goes into the Frozen state. In Linux desktop, it expects that a SIGSTOP will be raised, causing all the threads not to get any more CPU time until resumed. This will be fixed in a future version of Cobalt.

Application Startup Expectations for the porter

The starboard application lifecycle, with descriptions of the states and the state changes can be found in src/starboard/event.h.

For applications that can be preloaded, the platform should send kSbEventTypePreload as the first Starboard event instead of kSbEventTypeStart. Subclasses of src/starboard/shared/starboard/application.cc can opt-in to use the already implemented support for the --preload command-line switch.

If started with kSbEventTypePreload, the platform can at any time send kSbEventTypeFocus when the application brought to the foreground. In Linux desktop (linux-x64x11), this can be done by sending a SIGCONT to the process that is in the Preloading state (see starboard/shared/signal/suspend_signals.cc)

If the platform wants to only give applications a certain amount of time to preload, they can send SbSystemRequestFreeze to halt preloading and move to the Frozen state. In Linux desktop, this can be done by sending SIGUSR1 to the process that is in the Preloading state.

Implementing the Application Lifecycle (for the porter)

The platform Starboard implementation must always send events in the prescribed order - meaning, for example, that it should never send a kSbEventTypeConceal event unless in the Blurred state.

Most porters will want to subclass either starboard::shared::Application (in src/starboard/shared/starboard/application.cc) or starboard::shared::QueueApplication (in src/starboard/shared/starboard/queue_application.cc), as these are reference classes that rigorously implement the Starboard application lifecycle. They are optional, and platforms can directly dispatch events to SbEventHandle(), but it is then up to them to ensure that events are always sent in the correct state as specified in the Starboard documentation.

starboard::shared::Application (in starboard/shared/starboard/application.cc) guarantees the correct ordering by implementing a small state machine that ignores invalid application state transitions, and inserts any necessary transitions to make them valid. For example, you can call starboard::shared::Application::Conceal(), and if you are in Blurred, it will just dispatch a kSbEventTypeConceal event. But if you call Conceal() in the Started state, it will first dispatch kSbEventTypeBlur, followed by a kSbEventTypeConceal event. If you call Conceal() in the Concealed state, it just does nothing.

This behavior can be ensured by only dispatching events to SbEventHandle() using Application::DispatchAndDelete() either directly, or indirectly such as by using Application::RunLoop() with the default implementation of Application::DispatchNextEvent().

To control starting up in the Concealed state for preloading, Application subclasses must override two functions:

class MyApplication : public shared::starboard::QueueApplication {
  // [ ... ]
  bool IsStartImmediate() override;
  bool IsPreloadImmediate() override;
  // [ ... ]
}

To start up in the Concealed state, IsStartImmediate() should return false and IsPreloadImmediate() should return true.

To start up in the Starting state (which is the default), IsStartImmediate() should return true and IsPreloadImmediate() will not be called.

To delay starting up until some later event, IsStartImmediate() and IsPreloadImmediate() should both return false. No initial event will be automatically sent to the application, and it is then up to the porter to dispatch a kSbEventTypeStart or kSbEventTypePreload event as the first event. This is useful if you need to wait for an asynchronous system activity to complete before starting Cobalt.

To support the --preload command-line argument:

  bool IsStartImmediate() override { return !HasPreloadSwitch(); }
  bool IsPreloadImmediate() override { return HasPreloadSwitch(); }