diff --git a/content/architecture/application-design.md b/content/architecture/application-design.md index 6b5d1f1de14dbd559a42ee113954c77a545907e3..8212202fe7ac27905c06055024766a4f0a8c10aa 100644 --- a/content/architecture/application-design.md +++ b/content/architecture/application-design.md @@ -11,6 +11,7 @@ aliases = [ ] date = "2016-12-12" +lastmod = "2022-02-01" status = "Deprecated" statusDescription = "This document covers frameworks that have been removed in v2022dev2." @@ -65,7 +66,7 @@ It is likely that there will be times when access to the internet will be limite An Apertis **application bundle** is a set of resources installed as a single unit. The app bundle can include open source / proprietary libraries, -[agents][Agent] and GUI programs. +services, and GUI programs. See the [Application Bundle Specification]( {{< ref "bundle-spec.md" >}} ) for a more formal specification of the contents of application bundles. @@ -103,10 +104,6 @@ For example, the `net.example.ShoppingList` application bundle might contain a main entry point named `net.example.ShoppingList` and an [agent] named `net.example.ShoppingList.CloudSync`. -<!-- Local link definitions --> - -[Agent]: {{< ref "creating-a-canterbury-agent.md" >}} - <!-- External link definitions --> [Reversed domain name notation]: https://en.wikipedia.org/wiki/Reverse_domain_name_notation diff --git a/content/glossary.md b/content/glossary.md index c194b5493dc3e4d436d44ab9ff553282f31c31d3..583ef968878ac5472726df87f06675481dad2a52 100644 --- a/content/glossary.md +++ b/content/glossary.md @@ -10,13 +10,6 @@ aliases = [ ] +++ -{{< glossary-term agent >}} -A persistent non-GUI process launched automatically at boot time, immediately -after application installation or by D-Bus activation. - -See: [Creating a Canterbury agent]({{< ref "creating-a-canterbury-agent.md" >}}) -{{< /glossary-term >}} - {{< glossary-term "application bundle" "app bundle" "bundle" >}} A group of functionally related components (be they services, data, or programs), installed as a unit. This matches the sense with which "app" is diff --git a/content/guides/creating-a-canterbury-agent.md b/content/guides/creating-a-canterbury-agent.md deleted file mode 100644 index 29903242631e47b9e4d9455d318148a7c3855423..0000000000000000000000000000000000000000 --- a/content/guides/creating-a-canterbury-agent.md +++ /dev/null @@ -1,251 +0,0 @@ -+++ -title = "Creating a Canterbury agent" -weight = 100 -toc = true - -aliases = [ - "/old-developer/latest/appdev-agents.html", - "/old-developer/v2019/appdev-agents.html", - "/old-developer/v2020/appdev-agents.html", - "/old-developer/v2021pre/appdev-agents.html", - "/old-developer/v2022dev0/appdev-agents.html", -] - -date = "2016-12-09" -lastmod = "2017-07-01" -+++ - -{{% notice warning %}} -This guide describes creating an agent using the -[Centerbury legacy application framework]({{< ref "canterbury-legacy-application-framework.md" >}}). -This framework has been removed in `v2022dev2` and therefore not recommended -for new development. -{{% /notice %}} - -An agent is a non graphical program which runs in the background. Agents can be used for playing music or computing expensive operations like indexing large databases, for example. - -Following is a step-by-step guide for creating an agent. This guide is based on the [agent sample application](https://git.apertis.org/git/sample-applications/helloworld-agentapp.git) available in the Apertis repos. It will be handy to have the sample application code open while reading through this guide. - -Our sample application is composed of two classes which will be explained in more detail below: - - `HlwAgent`: A wrapper class that manages the process itself and the D-Bus object - - `HlwTickBoard`: A child class that implements the D-Bus interface - -Let's get started! - -# Agents are GApplications - -The [`GApplication`](https://developer.gnome.org/gio/stable/GApplication.html) is the recommended base class for agents, just as it is for graphical applications. -One of the advantages of being derived from `GApplication` is that most of the work of registering with D-Bus is handled by the class, so you need only override a few virtual functions in order to get a running agent. - -The `HlwAgent` class is the entry point for running the agent. This class is defined as: - -``` -G_DEFINE_TYPE (HlwAgent, hlw_agent, G_TYPE_APPLICATION) -``` - -Create and launch an `HlwAgent`: - -``` - app = G_APPLICATION (g_object_new (HLW_TYPE_AGENT, - "application-id", "org.apertis.HelloWorld.Agent", - "flags", G_APPLICATION_IS_SERVICE, - NULL)); - - g_application_run (app, argc, argv); -``` - -The `application_id` property of the GApplication is used to provide the D-Bus bus name. This id should be unique so it is recommend that you use `@BUDNLE_ID@.Agent`. `GApplicationFlags` should be set to `G_APPLICATION_IS_SERVICE`. See [the description](https://developer.gnome.org/gio/stable/GApplication.html#GApplicationFlags) of flags for more information. - -In the `HlwAgent` class, the `dbus_register` and `dbus_unregister` virtual functions should be overridden to catch whether the requested D-Bus name is available to use, and`activate` should be overridden as well, which is a mandatory virtual function for all applications and agents. - -``` -static void -hlw_agent_class_init (HlwAgentClass *klass) -{ - GApplicationClass *app_class = G_APPLICATION_CLASS (klass); - - ... - - app_class->activate = hlw_agent_activate; - app_class->dbus_register = hlw_agent_dbus_register; - app_class->dbus_unregister = hlw_agent_dbus_unregister; - - ... -} -``` - -To cause `HlwAgent` to run in the background and prevent termination by the ending of the main function, the reference count should be held and released properly. In a graphical application, it's clear that `g_application_hold ()` should be called when the window appears and `g_application_release ()` when the window disappears, but unlike a graphical program, it's a bit less clear when to manage reference count in an agent. Fortunately, in the `dbus_register` function, we can assume that the agent is ready to export extra objects on the bus, making it a good place to take the reference with `g_application_hold ()`, and in `dbus_unregister` we can release the reference count with `g_application_release ()`. - -``` -static gboolean -hlw_agent_dbus_register (GApplication *app, - GDBusConnection *connection, - const gchar *object_path, - GError **error) -{ - ... - - g_application_hold (app); - - ... -} - -static void -hlw_agent_dbus_unregister (GApplication *app, - GDBusConnection *connection, - const gchar *object_path) -{ - ... - - g_application_release (app); - - ... -} -``` - -Once the `activate` virtual function is overridden, we will have a runnable agent skeleton. - -# D-Bus Interface - -Using the `GApplication` class allows our agent to run as stand-alone non-graphical program, but it isn't yet able to interact with the outside world. It is recommended that D-Bus be used to communicate with other processes on the system. D-Bus code and documentation can be easily created by `gdbus-codegen`. For more details of the usages of the generator, refer to [gdbus-codegen](https://developer.gnome.org/gio/stable/gdbus-codegen.html). - -## D-Bus XML Schema - -To make our agent application D-Bus aware, let's introduce a simple XML D-Bus interface. - -Our interface will contain the following: - - method: ToggleTick - - property: CurrentTick - -By calling `ToggleTick`, an auto-incremented tick count function is enabled or disabled. Once the function is enabled, the property, `CurrentTick`, is increased by 1 every second. - -``` -<node name="/org/apertis/helloworld/agent/tickboard"> - <interface name="org.apertis.HelloWorld.Agent.TickBoard"> - <method name="ToggleTick"/> - <property name="CurrentTick" type="i" access="read"/> - </interface> -</node> -``` - -To generate the D-Bus code at make time, we introduce a simple rule to the Automake `Makefile.am`. - -``` -helloworld-agent/%.c: helloworld-agent/%.xml Makefile - $(AM_V_GEN)$(GDBUS_CODEGEN) \ - --c-namespace=HlwDBus \ - --interface-prefix=org.apertis.HelloWorld.Agent \ - --generate-c-code helloworld-agent/$* $< -``` - -Note that `--interface-prefix` should be the same as the `application-id` of the agent. - -## D-Bus function implementation - -The D-Bus skeleton is generated by `gdbus-codegen` according to the XML schema. Now we need to create actual behaviors for when the D-Bus APIs are called. In our example, the `HlwDBusTickBoardSkeleton` object and the `HlwDBusTickBoard` interface are created. Although there are various approaches to implementing this interface, being a child of the D-Bus skeleton object will help show how the generated virtual functions should be filled in. - -``` -G_DEFINE_TYPE_WITH_CODE (HlwTickBoard, hlw_tick_board, - HLW_DBUS_TYPE_TICK_BOARD_SKELETON, - G_IMPLEMENT_INTERFACE (HLW_DBUS_TYPE_TICK_BOARD, - hlw_tick_board_tick_board_iface_init)) -``` - -Next, `handle_toggle_tick` of `HlwDbusTickBoardIface` should be overridden. - -``` -static gboolean -hlw_tick_board_handle_toggle_tick (HlwDBusTickBoard *object, - GDBusMethodInvocation *invocation) -{ - ... - - hlw_dbus_tick_board_complete_toggle_tick (object, invocation); - - return TRUE; -} - -static void -hlw_tick_board_tick_board_iface_init (HlwDBusTickBoardIface *iface) -{ - iface->handle_toggle_tick = hlw_tick_board_handle_toggle_tick; -} -``` - -## Exporting the interface to D-Bus - -Once the implementation of the D-Bus interface is completed, it needs to be exported on the bus. `HlwAgent` is already registered on the bus so the `HlwTickBoard`, which is a child object of the D-Bus skeleton, can be easily exported in the `dbus_register` function. - -``` -static gboolean -hlw_agent_dbus_register (GApplication *app, - GDBusConnection *connection, - const gchar *object_path, - GError **error) -{ - gboolean ret; - - ... - - /* chain up */ - ret = G_APPLICATION_CLASS (hlw_agent_parent_class)->dbus_register ( - app, - connection, - object_path, - error); - - if (ret && - !g_dbus_interface_skeleton_export ( - G_DBUS_INTERFACE_SKELETON (self->tick_board), - connection, - "/org/apertis/HelloWorld/Agent/TickBoard", - error)) - { - g_warning ("Failed to export TickBoard D-Bus interface (reason: %s)", - (*error)->message); - } - - return ret; -} -``` - -Note that it is recommended that an application registers as above before exporting any other interfaces to D-Bus. - - -# Apparmor profile - -An agent must be granted different Apparmor permissions than those granted to standard [application bundles]( {{< ref "bundle-spec.md#apparmor-profile" >}} ). Several additional rules are required to allow an agent to access the bus. - -``` -/Applications/@BUNDLE_ID@/** { - #include <abstractions/chaiwala-base> - #include <abstractions/dbus-session-strict> - - /Applications/@BUNDLE_ID@/{bin,libexec}/* pix, - /Applications/@BUNDLE_ID@/{bin,lib,libexec}/{,**} mr, - /Applications/@BUNDLE_ID@/share/{,**} r, - - owner /var/Applications/@BUNDLE_ID@/users/** rwk, - - dbus send - bus=session - path=/org/freedesktop/DBus - interface=org.freedesktop.DBus - member="RequestName" - peer=(name=org.freedesktop.DBus), - - dbus bind - bus=session - name="@BUNDLE_ID@", - - dbus bind - bus=session - name="@BUNDLE_ID@.Agent", - - dbus (send, receive) - bus=session - peer=(label=/Applications/@BUNDLE_ID@/**), - - signal receive peer=/usr/bin/canterbury, -} -```