From: Marius Vlad Date: Wed, 22 Feb 2023 16:29:42 +0000 (+0200) Subject: 01_Application_Framework: Add an extended version of app startup X-Git-Tag: 15.91.0~7 X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=commitdiff_plain;h=b37b7187f003f409bd20cfcceb3eb0279911016d;p=AGL%2Fdocumentation.git 01_Application_Framework: Add an extended version of app startup And activation, that describes in more detail how that is handled. Bug-AGL: SPEC-4700 Signed-off-by: Marius Vlad Change-Id: I5f9a2764d66947c06bf8dc346dfaef72d993733f Reviewed-on: https://gerrit.automotivelinux.org/gerrit/c/AGL/documentation/+/28526 Reviewed-by: Jan-Simon Moeller Tested-by: Jan-Simon Moeller --- diff --git a/docs/04_Developer_Guides/01_Application_Framework/02_Application_Startup.md b/docs/04_Developer_Guides/01_Application_Framework/02_Application_Startup.md index 6eeae02..56876a4 100644 --- a/docs/04_Developer_Guides/01_Application_Framework/02_Application_Startup.md +++ b/docs/04_Developer_Guides/01_Application_Framework/02_Application_Startup.md @@ -138,7 +138,111 @@ This can be useful, for example, when switching between graphical applications: - the application switcher doesn't need to track the state of each application; instead, it can simply send a `StartApplication` request to `applaunchd` - every time the user requests to switch to another application + every time the user requests to switch to another application. Obviously, the + client needs to subscribe to get these events and act accordingly. - the shell client then receives the `StatusResponse` with the message `status` string set to "started" indicating it that it should activate the window with - the corresponding `id` string + the corresponding `id` string, or alternatively the string `status` is + set to "terminated" to denote that the application has been terminated, + forcibly or not + +## A deeper look at start-up, activation and application switching + +Application start-up, activation and application switching are sometimes +conflated into a single operation but underneath some of these are distinct +steps, and a bit flaky in some circumstances. +The [AGL compositor](../../06_Component_Documentation/02_agl_compositor/) has +some additional events which one can use when creating an application +start-up & switching scheme in different run-times. + +Start-up of application is handled entirely by `applaunchd` service while +activation -- the window which I want to display, but which has never been +shown, and application switching -- bring forward an application already +shown/displayed in the past, are operations handled entirely by the +AGL compositor. + +The issue stems from the fact that underneath `applaunchd` can't make any +guarantees when the application actually started, as it calls into libsystemd +API to start the specific application systemd unit. + +If `StartApplication` can't start the systemd unit, it returns a false +`status` boolean value and a error message in `StartResponse` message, but if +the application is indeed started we doesn't really know the *moment* when the +application is ready to be displayed. Additionally, the AGL compositor +performed the activation on its own when it detected that a new application +has been started, but that implicit activation can now be handled outside +by the desktop run-time/shell client. + +*Note: Some of the run-times still rely on the compositor to perform activation +as this synchronization part between `applaunchd` has not been implemented. The +plan is to migrate all of remaining run-times to using this approach.* + +### Start-up & activation + +This means that we require some sort of interaction between `StartApplication` +method and the events sent by the AGL compositor in order to correctly handle +start-up & activation of application. + +There are couple of ways of achieving that, either using Wayland native calls, +or using the gRPC proxy interface, which underneath is using the same Wayland +native calls. + +For the first approach, the AGL compositor has an `app_state` Wayland event +which contains the application ID, and an enum `app_state` that will propagate +the following application state events: + +``` + + + + + + +``` + +The `started` event can be used in correlation with the `StartApplication` +method from `applaunchd` such that upon received the `started` even, it can +explicitly activate that particular appid in order for the compositor to +display it. See [AGL compositor](../../06_Component_Documentation/02_agl_compositor/) +about how activation should be handled. + +*Note: These can only be received if by the client shell which binds to the +agl_shell interface*. + +Alternatively, when using the gRPC proxy one can register to receive these +status events similar to the `applaunchd` events, subscribing to +`AppStatusState` method from the grpc-proxy helper application, which has the +following protobuf messages: + +``` +message AppStateRequest { +} +message AppStateResponse { + int32 state = 1; + string app_id = 2; +} +``` + +The integer state maps to the `enum app_state` from the Wayland protocol, so +they are a 1:1 match. + +Here's the state diagram for the Qt homescreen implementation of the +application start-up: + +![Application_start](../images/start_and_activation.png) + +### Application switching + +With the compositor providing application status events, it might seem that the +`applaunchd`'s, `GetStatusEvents` might be redundant, but in fact it is being +used to perform application switching. The run-time/shell client would in fact +subscribe to `GetStatusEvents` and each application wanting to switch to another +application would basically call `StartApplication`. That would eventually reach +the run-time/shell-client and have a handler that would ultimately activate the +application ID. + +![Application_switching](../images/application_switching.png) + +*Note: In practice, the run-time/shell-client would subscribe to both `applaunchd` +and to the AGL compositor, either Wayland native events, or using the gPRC-proxy +helper client, although the diagrams show them partly decoupled*. diff --git a/docs/04_Developer_Guides/images/application_switching.msc b/docs/04_Developer_Guides/images/application_switching.msc new file mode 100755 index 0000000..ceeab7c --- /dev/null +++ b/docs/04_Developer_Guides/images/application_switching.msc @@ -0,0 +1,29 @@ +#!/usr/bin/mscgen -Tpng + +msc { + hscale="1.5"; + + u [label = "touch/pointer event" ], + l [label = "launcher app" ], + s [label = "runtime/shell-client"], + a [label = "applaunchd" ], + g [label = "gRPC-proxy" ], + c [label = "compositor" ], + d [label = "libsystemd"]; + + |||; + + --- [label = "initial phase - subscribe for signal/status events, assume app_id already started" ]; + + s >> a [label = "subscribe for applaunchd GetStatusEvents"]; + + --- [label = "handling of application switching" ]; + + u => l [label = "tapShortCut(appid)" ]; + l => a [label = "StartApplication(appid)"]; + a => d [label = "start application's systemd unit"]; + d => a [label = "return status from starting systemd unit"]; + a => s [label = "StartResponse(status = TRUE)"]; + a => s [label = "StatusResponse(app_id, 'started')"]; + s => c [label = "activate_app(app_id)"]; +} diff --git a/docs/04_Developer_Guides/images/application_switching.png b/docs/04_Developer_Guides/images/application_switching.png new file mode 100644 index 0000000..0b5584a Binary files /dev/null and b/docs/04_Developer_Guides/images/application_switching.png differ diff --git a/docs/04_Developer_Guides/images/start_and_activation.msc b/docs/04_Developer_Guides/images/start_and_activation.msc new file mode 100755 index 0000000..d835f8b --- /dev/null +++ b/docs/04_Developer_Guides/images/start_and_activation.msc @@ -0,0 +1,30 @@ +#!/usr/bin/mscgen -Tpng + +msc { + hscale="1.5"; + + u [label = "touch/pointer event" ], + s [label = "runtime/shell-client"], + a [label = "applaunchd" ], + g [label = "gRPC-proxy" ], + c [label = "compositor" ], + d [label = "libsystemd"]; + + |||; + + --- [label = "initial phase - subscribe for signal/status events" ]; + + s >> g [label = "subscribe for AGL compositor AppStatusState"]; + g >> c [label = "listen for app_state Wayland events"]; + + --- [label = "handling start-up & activation" ]; + + u => s [label = "tapShortCut(appid)" ]; + s => a [label = "StartApplication(appid)"]; + a => d [label = "start application's systemd unit"]; + d => a [label = "return status from starting systemd unit"]; + a => s [label = "StartResponse(status = TRUE)"]; + c => g [label = "app_state(app_state = APP_STARTED)"]; + g => s [label = "AppStatusResponse(app_id, APP_STARTED)"]; + s => c [label = "activate_app(app_id)"]; +} diff --git a/docs/04_Developer_Guides/images/start_and_activation.png b/docs/04_Developer_Guides/images/start_and_activation.png new file mode 100644 index 0000000..593fc0e Binary files /dev/null and b/docs/04_Developer_Guides/images/start_and_activation.png differ