X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;f=docs%2F04_Developer_Guides%2F01_Application_Framework%2F02_Application_Startup.md;h=56876a469fee714ac853760051d6340b60c1f75f;hb=3b03a1073c29653e8401da4d540aeac3880728b3;hp=232f41e1a3feb73a9d5ff91ce6bd61985184c279;hpb=120a2677992ea299eea5fb5cb0ed1081f76bb92c;p=AGL%2Fdocumentation.git 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 232f41e..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 @@ -4,181 +4,245 @@ title: Application Startup # Introduction -At system runtime, it may be necessary for applications to start other applications -on demand. Such actions can be executed in reaction to a user request, or they may -be needed to perform a specific task. +At system runtime, it may be necessary for applications to start other +applications on demand. Such actions can be executed in reaction to a user +request, or they may be needed to perform a specific task. In order to do so, running applications and services need an established way of -discovering installed applications and executing those. The -[Desktop Entry specification](https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html) -defines how applications can be discovered by using `.desktop` files, but there's no -simple reference implementation for this function. +discovering installed applications and executing those. -In order to provide a language-independent interface for applications and service to -use, AGL includes `applaunchd`, a user service part of the default session. - -*Note: as mentioned [previously](../01_Introduction/), services are managed using `systemd` -and are therefore not in the scope of this document.* +In order to provide a language-independent interface for applications and +service to use, AGL includes `applaunchd`, a system service. # Application launcher service -The purpose of `applaunchd` is to enumerate applications available on the system and -provide a way for other applications to query this list and start those on demand. -It is also able to notify clients of the startup and termination of applications it -manages. +The purpose of `applaunchd` is to enumerate applications available on the +system and provide a way for other applications to query this list and start +those on demand. It is also able to notify clients of the startup and +termination of applications it manages. -To that effect, `applaunchd` provides a D-Bus interface other applications can use -in order to execute those actions. +To that effect, `applaunchd` provides a gRPC interface which other applications +can use in order to execute those actions. -*Note: `applaunchd` will only send notifications for applications it started; it isn't -aware of applications started by other means (`systemd`, direct executable call...), -and therefore can't send notifications for those.* +*Note: `applaunchd` will only send notifications for applications it started; +it isn't aware of applications started by other means (`systemd`, direct +executable call...), and therefore can't send notifications for those.* ## Application discovery -On startup, `applaunchd` inspects all `.desktop` files present under the `applications/` -subfolder of any element of the `XDG_DATA_DIRS` environment variable, ignoring all entries -containing either the `NoDisplay=true` or `Hidden=true` lines. - -It then looks for the following keys: -- `Terminal` -- `DBusActivatable` - -If the desktop entry file contains the `Terminal` key set to `true`, then the application -is marked as a non-graphical one. As such, it won't be included in the applications list -if the client requests only graphical applications. - -If `DBusActivatable` is set to `true`, then the application is marked as D-Bus activated. -Additionally, `applaunchd` will search for a corresponding D-Bus service file in case this -line is missing. This is a workaround allowing D-Bus activated applications providing -an incomplete desktop entry file (i.e missing the `DBusActivatable` key) to be -identified as such. - -### Requirements for D-Bus activation - -`applaunchd` will always start D-Bus activatable applications using D-Bus activation -instead of executing the command line stated in the desktop entry file. - -This is handled by calling the `Activate` method of the -[org.freedesktop.Application](https://specifications.freedesktop.org/desktop-entry-spec/1.1/ar01s07.html) -interface with an empty argument. - -As a consequence, all D-Bus activatable applications **must** implement this D-Bus -interface. +Applications are enumerated from systemd's list of available units based on the +pattern `agl-app*@*.service`, and are started and controled using their systemd +unit. Please note `applaunchd` allows only one instance of a given +application. ## Application identifiers -Each application is identified by a unique Application ID. Although this ID can be -any valid string, it is highly recommended to use the "reverse DNS" convention in order -to avoid potential name collisions and ease D-Bus integration. +Each application is identified by a unique Application ID. Although this ID can +be any valid string, it is highly recommended to use the "reverse DNS" +convention in order to avoid potential name collisions. -The application ID is set in the desktop entry file itself for -[graphical applications](../3_Creating_a_New_Application/#graphical-applications): -it is the value of the `StartupWMClass` field, which must be identical to the `app-id` -advertised through the Wayland XDG toplevel protocol. In case this field is missing -(as is usually the case for non-graphical application), the application ID will be the -desktop entry file name, stripped from its `.desktop` extension. +## gRPC interface -## D-Bus interface +The interface provides methods for the following actions: -The `applaunchd` D-Bus interface is named `org.automotivelinux.AppLaunch`. The object -path for `applaunchd` is `/org/automotivelinux/AppLaunch`. The interface provides methods -for the following actions: -- retrieve the list of available applications; the client can choose to retrieve all - available applications, or only those suitable for a graphical environment +- retrieve the list of available applications - request an application to be started +- subscribe to status events + +Moreover, with the gRPC the client subscribes to a status signal to be notified +when an application has successfully started or its execution terminated. -Moreover, signals are available for clients to be notified when an application has -successfully started or its execution terminated. +The gRPC protobuf file provides a Request and Response arguments to RPC methods +even though in some cases these might be empty in order to allow forward +compatibility in case additional fields are required. +It is a good standard practice to follow up with these recommendation when +developing a new protobuf specification. ### Applications list -The `listApplications` method allows clients to retrieve the list of available applications. -It takes one boolean argument named `graphical`: -- if set to `true`, only applications suitable for graphical environments are returned -- otherwise, the list contains all applications +The `ListApplications` method allows clients to retrieve the list of available +applications. -This method returns an array of variants (type `av`), each element being a structure made up -of 3 strings (type `(sss)`): -- the application ID -- the application's displayed name -- the full path to the application icon file (or an empty string if no icon was specified in - the application's desktop entry file) +The `ListRequest` is an empty message, while `ListResponse` contains the following: + +``` +message AppInfo { + string id = 1; + string name = 2; + string icon_path = 3; +} + +message ListResponse { + repeated AppInfo apps = 1; +} +``` ### Application startup request -Applications can be started by using the `start` method, passing the corresponding application -ID as the only argument. This method doesn't return any data. +Applications can be started by using the `StartApplication` method, passing the +`StartRequest` message, defined as: -If the application is already running, `applaunchd` won't start another instance, but instead -emit a `started` signal to notify clients the application is ready. +``` +message StartRequest { + string id = 1; +} +``` -### Status notifications +In reply, the following `StartResponse` will be returned: -The `org.automotivelinux.AppLaunch` interface provides 2 signals clients can connect to: -- `started` indicates an application has started - - for D-Bus activated applications, it is emitted upon successful completion of the - call to the `Activate` method of the `org.freedesktop.Application` interface - - for other applications, this signal is emitted as soon as the child process has been - successfully created -- `terminated` is emitted when an application quits +``` +message StartResponse { + bool status = 1; + string message = 2; +} +``` -Both signals have an additional argument named `appid`, containing the ID of the application -affected by the event. +The "message" string of `StartResponse` message will contain an error message +in case we couldn't start the application for whatever reason, or if the "id" +isn't a known application ID. The "status" string would be boolean set to +boolean `TRUE` otherwise. -As mentioned above, the `started` signal is also emitted if `applaunchd` receives a request to -start an already running application. 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 `start` request to `applaunchd` every time the user requests to switch to another - application -- the desktop environment then receives the `started` signal, indicating it should activate the - window with the corresponding `app-id` +If the application is already running, `applaunchd` won't start another +instance, but instead reply with a `AppStatus` message setting the `status` +string to "started". -## Testing +### Status notifications -`applaunchd` can be manually tested using the `gdbus` command-line tool: +The gRPC interface provides clients with a subscription model to receive +status events. Client should subscribe to `GetStatusEvents` method to receive +them. -1. Query the application list (graphical applications only): +The `StatusRequest` is empty, while the `StatusResponse` is defined as +following: ``` -$ gdbus call --session --dest "org.automotivelinux.AppLaunch" \ - --object-path "/org/automotivelinux/AppLaunch" \ - --method "org.automotivelinux.AppLaunch.listApplications" \ - true +message AppStatus { + string id = 1; + string status = 2; +} + +message LauncherStatus { +} + +message StatusResponse { + oneof status { + AppStatus app = 1; + LauncherStatus launcher = 2; + } +} ``` -This command will output something similar to what follows: +As mentioned above, the `status` string is set to "started" and is also emitted +if `applaunchd` receives a request to start an already running application. +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. 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, 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: ``` -([<('navigation', 'Navigation', '/usr/share/icons/hicolor/scalable/navigation.svg')>, - <('settings', 'Settings', '/usr/share/icons/hicolor/scalable/settings.svg')>, - <('dashboard', 'Dashboard', '/usr/share/icons/hicolor/scalable/dashboard.svg')>, - <('hvac', 'HVAC', '/usr/share/icons/hicolor/scalable/hvac.svg')>, - <('org.freedesktop.weston.wayland-terminal', 'Weston Terminal', '/usr/share/icons/Adwaita/scalable/apps/utilities-terminal-symbolic.svg')>],) + + + + + + ``` -2. Request startup of the `org.freedesktop.weston.wayland-terminal` application: +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. -``` -$ gdbus call --session --dest "org.automotivelinux.AppLaunch" \ - --object-path "/org/automotivelinux/AppLaunch" \ - --method "org.automotivelinux.AppLaunch.start" \ - "org.freedesktop.weston.wayland-terminal" -``` +*Note: These can only be received if by the client shell which binds to the +agl_shell interface*. -3. Monitor signals emitted by `applaunchd`: +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: ``` -$ gdbus monitor --session --dest "org.automotivelinux.AppLaunch" +message AppStateRequest { +} +message AppStateResponse { + int32 state = 1; + string app_id = 2; +} ``` -This results in the following output when starting, then exiting, the -`org.freedesktop.weston.wayland-terminal` application: +The integer state maps to the `enum app_state` from the Wayland protocol, so +they are a 1:1 match. -``` -Monitoring signals from all objects owned by org.automotivelinux.AppLaunch -The name org.automotivelinux.AppLaunch is owned by :1.4 -/org/automotivelinux/AppLaunch: org.automotivelinux.AppLaunch.started ('org.freedesktop.weston.wayland-terminal',) -/org/automotivelinux/AppLaunch: org.automotivelinux.AppLaunch.terminated ('org.freedesktop.weston.wayland-terminal',) -``` +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*.