aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorScott Murray <scott.murray@konsulko.com>2022-07-27 16:06:14 -0400
committerScott Murray <scott.murray@konsulko.com>2022-07-27 16:13:43 -0400
commitc675bafdf15cc19276bd8276c34f56404a5ecb62 (patch)
tree8199080fb9c676c6d8cbb77b41c7ebb94aa23dd7
parentefbd734aca8b813710d7564d79696b1cf150a88c (diff)
Rework to replace the Glib .desktop file based app enumeration scheme with querying systemd for units matching the pattern agl-app*@*.service and parsing out the application ID from the unit instance name. At the moment this assumes the use of template units, but that could be changed to open up using non-templated units if desired. Application icons are now assumed to be named with the application ID, and the systemd unit file "Description" field is read and used as the application display name. This avoids needing metadata outside of the systemd unit files. Bug-AGL: SPEC-4466 Signed-off-by: Scott Murray <scott.murray@konsulko.com> Change-Id: Ida7dc8f7fdb96722df0886eb9a72ee14b0856083
-rw-r--r--README.md6
-rw-r--r--src/app_info.c32
-rw-r--r--src/app_info.h7
-rw-r--r--src/app_launcher.c149
-rw-r--r--src/meson.build1
-rw-r--r--src/process_manager.c220
-rw-r--r--src/process_manager.h38
-rw-r--r--src/systemd_manager.c120
-rw-r--r--src/systemd_manager.h10
9 files changed, 186 insertions, 397 deletions
diff --git a/README.md b/README.md
index 943679c..83ea36d 100644
--- a/README.md
+++ b/README.md
@@ -13,9 +13,9 @@ This interface can be used to:
For more details about the D-Bus interface, please refer to the file
`data/org.automotivelinux.AppLaunch.xml`.
-Applications can be started either through D-Bus activation (using their D-Bus
-name) or by specifying a command line to be executed, and are monitored until
-they exit. Please note `applaunchd` allows only one instance of a given
+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.
AGL repo for source code:
diff --git a/src/app_info.c b/src/app_info.c
index 0d25d37..97ecf7e 100644
--- a/src/app_info.c
+++ b/src/app_info.c
@@ -24,9 +24,7 @@ struct _AppInfo {
gchar *app_id;
gchar *name;
gchar *icon_path;
- gchar *command;
- gboolean systemd_activated;
- gboolean graphical;
+ gchar *service;
AppStatus status;
@@ -50,7 +48,7 @@ static void app_info_dispose(GObject *object)
g_clear_pointer(&self->app_id, g_free);
g_clear_pointer(&self->name, g_free);
g_clear_pointer(&self->icon_path, g_free);
- g_clear_pointer(&self->app_id, g_free);
+ g_clear_pointer(&self->service, g_free);
g_clear_pointer(&self->runtime_data, g_free);
G_OBJECT_CLASS(app_info_parent_class)->dispose(object);
@@ -78,18 +76,14 @@ static void app_info_init(AppInfo *self)
*/
AppInfo *app_info_new(const gchar *app_id, const gchar *name,
- const gchar *icon_path, const gchar *command,
- gboolean systemd_activated,
- gboolean graphical)
+ const gchar *icon_path, const gchar *service)
{
AppInfo *self = g_object_new(APPLAUNCHD_TYPE_APP_INFO, NULL);
self->app_id = g_strdup(app_id);
self->name = g_strdup(name);
self->icon_path = g_strdup(icon_path);
- self->command = g_strdup(command);
- self->systemd_activated = systemd_activated;
- self->graphical = graphical;
+ self->service = g_strdup(service);
return self;
}
@@ -115,25 +109,11 @@ const gchar *app_info_get_icon_path(AppInfo *self)
return self->icon_path;
}
-const gchar *app_info_get_command(AppInfo *self)
+const gchar *app_info_get_service(AppInfo *self)
{
g_return_val_if_fail(APPLAUNCHD_IS_APP_INFO(self), NULL);
- return self->command;
-}
-
-gboolean app_info_get_systemd_activated(AppInfo *self)
-{
- g_return_val_if_fail(APPLAUNCHD_IS_APP_INFO(self), FALSE);
-
- return self->systemd_activated;
-}
-
-gboolean app_info_get_graphical(AppInfo *self)
-{
- g_return_val_if_fail(APPLAUNCHD_IS_APP_INFO(self), FALSE);
-
- return self->graphical;
+ return self->service;
}
AppStatus app_info_get_status(AppInfo *self)
diff --git a/src/app_info.h b/src/app_info.h
index 5e69dc3..f420965 100644
--- a/src/app_info.h
+++ b/src/app_info.h
@@ -33,16 +33,13 @@ G_DECLARE_FINAL_TYPE(AppInfo, app_info, APPLAUNCHD,
APP_INFO, GObject);
AppInfo *app_info_new(const gchar *app_id, const gchar *name,
- const gchar *icon_path, const gchar *command,
- gboolean systemd_activated, gboolean graphical);
+ const gchar *icon_path, const gchar *service);
/* Accessors for read-only members */
const gchar *app_info_get_app_id(AppInfo *self);
const gchar *app_info_get_name(AppInfo *self);
const gchar *app_info_get_icon_path(AppInfo *self);
-const gchar *app_info_get_command(AppInfo *self);
-gboolean app_info_get_systemd_activated(AppInfo *self);
-gboolean app_info_get_graphical(AppInfo *self);
+const gchar *app_info_get_service(AppInfo *self);
/* Accessors for read-write members */
AppStatus app_info_get_status(AppInfo *self);
diff --git a/src/app_launcher.c b/src/app_launcher.c
index 423bf19..417f59a 100644
--- a/src/app_launcher.c
+++ b/src/app_launcher.c
@@ -14,11 +14,8 @@
* limitations under the License.
*/
-#include <gio/gdesktopappinfo.h>
-
#include "app_info.h"
#include "app_launcher.h"
-#include "process_manager.h"
#include "systemd_manager.h"
#include "utils.h"
@@ -29,7 +26,6 @@ typedef struct _AppLauncher {
sd_event *event;
sd_bus *bus;
- ProcessManager *process_manager;
SystemdManager *systemd_manager;
GList *apps_list;
@@ -57,114 +53,87 @@ static void app_launcher_started_cb(AppLauncher *self,
/*
* This function is executed during the object initialization. It goes through
* all available applications on the system and creates a static list
- * containing all the relevant info (ID, name, command, icon...) for further
+ * containing all the relevant info (ID, name, unit, icon...) for further
* processing.
*/
static void app_launcher_update_applications_list(AppLauncher *self)
{
- g_autoptr(GList) app_list = g_app_info_get_all();
g_auto(GStrv) dirlist = NULL;
- guint len = g_list_length(app_list);
char *xdg_data_dirs = getenv("XDG_DATA_DIRS");
if (xdg_data_dirs)
dirlist = g_strsplit(getenv("XDG_DATA_DIRS"), ":", -1);
- for (guint i = 0; i < len; i++) {
- GAppInfo *appinfo = g_list_nth_data(app_list, i);
- const gchar *desktop_id = g_app_info_get_id(appinfo);
- GIcon *icon = g_app_info_get_icon(appinfo);
- g_autoptr(GDesktopAppInfo) desktop_info = g_desktop_app_info_new(desktop_id);
+ GList *units = NULL;
+ if (!systemd_manager_enumerate_app_units(self->systemd_manager, self, &units)) {
+ return;
+ }
+
+ GList *iterator;
+ for (iterator = units; iterator != NULL; iterator = iterator->next) {
g_autofree const gchar *app_id = NULL;
g_autofree const gchar *icon_path = NULL;
AppInfo *app_info = NULL;
- gboolean systemd_activated, graphical;
- if (!desktop_info) {
- g_warning("Unable to find .desktop file for application '%s'", desktop_id);
+ if (!iterator->data)
continue;
- }
- /* Check the application should be part of the apps list */
- if (!g_app_info_should_show(appinfo)) {
- g_debug("Application '%s' shouldn't be shown, skipping...", desktop_id);
- continue;
- }
+ // Parse service and app id out of unit filename
+ gchar *service = g_strrstr(iterator->data, "/");
+ if (!service)
+ service = iterator->data;
+ else
+ service += 1;
- if (g_desktop_app_info_get_is_hidden(desktop_info)) {
- g_debug("Application '%s' is hidden, skipping...", desktop_id);
- continue;
+ g_autofree char *tmp = g_strdup(service);
+ char *end = tmp + strlen(tmp);
+ while (end > tmp && *end != '.') {
+ --end;
}
- if (g_desktop_app_info_get_nodisplay(desktop_info)) {
- g_debug("Application '%s' has NoDisplay set, skipping...", desktop_id);
+ if (end > tmp) {
+ *end = '\0';
+ } else {
+ g_free(tmp);
continue;
}
-
- /*
- * The application ID is usually the .desktop file name. However, a common practice
- * is that .desktop files are named after the executable name, in which case the
- * "StartupWMClass" property indicates the wayland app-id.
- */
- app_id = g_strdup(g_desktop_app_info_get_startup_wm_class(desktop_info));
- if (!app_id) {
- app_id = g_strdup(desktop_id);
- gchar *extension = g_strrstr(app_id, ".desktop");
- if (extension)
- *extension = 0;
+ while (end > tmp && *end != '@') {
+ --end;
}
-
- /*
- * An application can be D-Bus activated if one of those conditions are met:
- * - its .desktop file contains a "DBusActivatable=true" line
- * - it provides a corresponding D-Bus service file
- * HACK: Use "DBusActivatable=true" in .desktop to mark systemd-based service
- */
-
- /* Default to non-DBus-activatable */
- systemd_activated = FALSE;
- if (g_desktop_app_info_get_boolean(desktop_info,
- G_KEY_FILE_DESKTOP_KEY_DBUS_ACTIVATABLE)) {
- systemd_activated = TRUE;
- } else if (dirlist) {
- const gchar *desktop_filename = g_desktop_app_info_get_filename(desktop_info);
- g_autofree gchar *service_file = g_strconcat(app_id, ".service", NULL);
-
- for (GStrv xdg_data_dir = dirlist; *xdg_data_dir != NULL ; xdg_data_dir++) {
- g_autofree gchar *service_path = NULL;
-
- /* Search only in the XDG_DATA_DIR where the .desktop file is located */
- if (!g_str_has_prefix(desktop_filename, *xdg_data_dir))
- continue;
-
- service_path = g_build_filename(*xdg_data_dir, "dbus-1", "services",
- service_file, NULL);
- if (g_file_test(service_path, G_FILE_TEST_EXISTS)) {
- systemd_activated = TRUE;
- break;
- }
- }
+ if (end > tmp) {
+ app_id = g_strdup(end + 1);
+ }
+ // Potentially handle non-template agl-app-foo.service units here
+
+ // Try getting display name from unit Description property
+ char *name = NULL;
+ if (!systemd_manager_get_app_description(self->systemd_manager,
+ self,
+ service,
+ &name) ||
+ name == NULL) {
+
+ // Fall back to the application ID
+ g_warning("Could not retrieve Description of '%s'", service);
+ name = app_id;
}
-
- /* Applications with "Terminal=True" are not graphical apps */
- graphical = !g_desktop_app_info_get_boolean(desktop_info,
- G_KEY_FILE_DESKTOP_KEY_TERMINAL);
/*
* GAppInfo retrieves the icon data but doesn't provide a way to retrieve
* the corresponding file name, so we have to look it up by ourselves.
*/
- if (icon && dirlist)
- icon_path = applaunchd_utils_get_icon(dirlist, g_icon_to_string(icon));
+ if (app_id && dirlist)
+ icon_path = applaunchd_utils_get_icon(dirlist, app_id);
- app_info = app_info_new(app_id, g_app_info_get_name(appinfo),
+ app_info = app_info_new(app_id,
+ name,
icon_path ? icon_path : "",
- g_app_info_get_commandline(appinfo),
- systemd_activated, graphical);
+ service);
- g_debug("Adding application '%s'", app_id);
+ g_debug("Adding application '%s' with display name '%s'", app_id, name);
self->apps_list = g_list_append(self->apps_list, app_info);
}
+ g_list_free_full(units, g_free);
}
/*
@@ -186,9 +155,6 @@ static GVariant *app_launcher_get_list_variant(AppLauncher *self, gboolean graph
GVariantBuilder app_builder;
AppInfo *app_info = g_list_nth_data(self->apps_list, i);
- if (graphical && !app_info_get_graphical(app_info))
- continue;
-
g_variant_builder_init (&app_builder, G_VARIANT_TYPE("(sss)"));
/* Create application entry */
@@ -229,10 +195,7 @@ static gboolean app_launcher_start_app(AppLauncher *self, AppInfo *app_info)
app_launcher_started_cb(self, app_id, NULL);
return TRUE;
case APP_STATUS_INACTIVE:
- if (app_info_get_systemd_activated(app_info))
- systemd_manager_start_app(self->systemd_manager, app_info);
- else
- process_manager_start_app(self->process_manager, app_info);
+ systemd_manager_start_app(self->systemd_manager, app_info);
return TRUE;
default:
g_critical("Unknown status %d for application '%s'", app_status, app_id);
@@ -257,7 +220,7 @@ static gboolean app_launcher_handle_start(applaunchdAppLaunch *object,
AppLauncher *self = APPLAUNCHD_APP_LAUNCHER(object);
g_return_val_if_fail(APPLAUNCHD_IS_APP_LAUNCHER(self), FALSE);
- /* Seach the apps list for the given app-id */
+ /* Search the apps list for the given app-id */
app = app_launcher_get_app_info(self, app_id);
if (!app) {
g_dbus_method_invocation_return_error(invocation, G_DBUS_ERROR,
@@ -343,7 +306,6 @@ static void app_launcher_dispose(GObject *object)
if (self->apps_list)
g_list_free_full(g_steal_pointer(&self->apps_list), g_object_unref);
- g_clear_object(&self->process_manager);
g_clear_object(&self->systemd_manager);
G_OBJECT_CLASS(app_launcher_parent_class)->dispose(object);
@@ -375,17 +337,6 @@ static void app_launcher_init (AppLauncher *self)
g_source_attach(g_sd_event_create_source(self->event, self->bus), g_main_loop_get_context(main_loop));
/*
- * Create the process manager and connect to its signals
- * so we get notified on app startup/termination
- */
- self->process_manager = g_object_new(APPLAUNCHD_TYPE_PROCESS_MANAGER,
- NULL);
- g_signal_connect_swapped(self->process_manager, "started",
- G_CALLBACK(app_launcher_started_cb), self);
- g_signal_connect_swapped(self->process_manager, "terminated",
- G_CALLBACK(app_launcher_terminated_cb), self);
-
- /*
* Create the systemd manager and connect to its signals
* so we get notified on app startup/termination
*/
diff --git a/src/meson.build b/src/meson.build
index 761ad9b..f44aef3 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -28,7 +28,6 @@ executable (
'main.c',
'app_info.c', 'app_info.h',
'app_launcher.c', 'app_launcher.h',
- 'process_manager.c', 'process_manager.h',
'systemd_manager.c', 'systemd_manager.h',
'utils.c', 'utils.h',
],
diff --git a/src/process_manager.c b/src/process_manager.c
deleted file mode 100644
index ad3ea33..0000000
--- a/src/process_manager.c
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * Copyright (C) 2021 Collabora Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "app_launcher.h"
-#include "process_manager.h"
-
-struct _ProcessManager {
- GObject parent_instance;
-
- GList *process_data;
-};
-
-G_DEFINE_TYPE(ProcessManager, process_manager, G_TYPE_OBJECT);
-
-enum {
- STARTED,
- TERMINATED,
- N_SIGNALS
-};
-static guint signals[N_SIGNALS];
-
-/*
- * Application info structure, used for storing relevant data
- * in the `running_apps` list
- */
-struct process_runtime_data {
- guint watcher;
- GPid pid;
- const gchar *app_id;
-};
-
-/*
- * Initialization & cleanup functions
- */
-
-static void process_manager_dispose(GObject *object)
-{
- ProcessManager *self = APPLAUNCHD_PROCESS_MANAGER(object);
-
- g_return_if_fail(APPLAUNCHD_IS_PROCESS_MANAGER(self));
-
- if (self->process_data)
- g_list_free_full(g_steal_pointer(&self->process_data), g_free);
-
- G_OBJECT_CLASS(process_manager_parent_class)->dispose(object);
-}
-
-static void process_manager_finalize(GObject *object)
-{
- G_OBJECT_CLASS(process_manager_parent_class)->finalize(object);
-}
-
-static void process_manager_class_init(ProcessManagerClass *klass)
-{
- GObjectClass *object_class = (GObjectClass *)klass;
-
- object_class->dispose = process_manager_dispose;
- object_class->finalize = process_manager_finalize;
-
- signals[STARTED] = g_signal_new("started", G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_LAST, 0 ,
- NULL, NULL, NULL, G_TYPE_NONE,
- 1, G_TYPE_STRING);
-
- signals[TERMINATED] = g_signal_new("terminated", G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_LAST, 0 ,
- NULL, NULL, NULL, G_TYPE_NONE,
- 1, G_TYPE_STRING);
-}
-
-static void process_manager_init(ProcessManager *self)
-{
-}
-
-/*
- * Internal functions
- */
-
-static const gchar *get_app_id_for_pid(ProcessManager *self, GPid pid)
-{
- g_return_val_if_fail(APPLAUNCHD_IS_PROCESS_MANAGER(self), NULL);
-
- AppLauncher *app_launcher = app_launcher_get_default();
- guint len = g_list_length(self->process_data);
-
- for (guint i = 0; i < len; i++) {
- struct process_runtime_data *runtime_data =
- g_list_nth_data(self->process_data, i);
-
- if (runtime_data->pid == pid)
- return runtime_data->app_id;
- }
-
- return NULL;
-}
-
-/*
- * Internal callbacks
- */
-
-/*
- * This function is called when a watched process terminated, so we can:
- * - cleanup this application's data (and reap the process so it
- * doesn't become a zombie)
- * - notify listeners that the process terminated
- */
-static void process_manager_app_terminated_cb(GPid pid,
- gint wait_status,
- gpointer data)
-{
- ProcessManager *self = data;
- AppLauncher *app_launcher = app_launcher_get_default();
- struct process_runtime_data *runtime_data;
- const gchar *app_id;
- AppInfo *app_info;
-
- g_return_if_fail(APPLAUNCHD_IS_PROCESS_MANAGER(self));
-
- app_id = get_app_id_for_pid(self, pid);
- if (!app_id) {
- g_warning("Unable to retrieve app id for pid %d", pid);
- return;
- }
-
- app_info = app_launcher_get_app_info(app_launcher, app_id);
- if (!app_info) {
- g_warning("Unable to find running app with pid %d", pid);
- return;
- }
-
- if (g_spawn_check_exit_status(wait_status, NULL))
- g_debug("Application '%s' terminated with exit code %i",
- app_id, WEXITSTATUS(wait_status));
- else
- g_warning("Application '%s' crashed", app_id);
-
- g_spawn_close_pid(pid);
-
- runtime_data = app_info_get_runtime_data(app_info);
- g_source_remove(runtime_data->watcher);
-
- app_info_set_status(app_info, APP_STATUS_INACTIVE);
- app_info_set_runtime_data(app_info, NULL);
-
- self->process_data = g_list_remove(self->process_data, runtime_data);
- g_free(runtime_data);
-
- g_signal_emit(self, signals[TERMINATED], 0, app_id);
-}
-
-/*
- * Public functions
- */
-
-ProcessManager *process_manager_new(void)
-{
- return g_object_new(APPLAUNCHD_TYPE_PROCESS_MANAGER, NULL);
-}
-
-/*
- * Start an application by executing the provided command line.
- */
-gboolean process_manager_start_app(ProcessManager *self,
- AppInfo *app_info)
-{
- g_return_val_if_fail(APPLAUNCHD_IS_PROCESS_MANAGER(self), FALSE);
- g_return_val_if_fail(APPLAUNCHD_IS_APP_INFO(app_info), FALSE);
-
- gboolean success;
- g_autofree GStrv args = NULL;
- const gchar *app_id = app_info_get_app_id(app_info);
- const gchar *command = app_info_get_command(app_info);
- struct process_runtime_data *runtime_data;
-
- runtime_data = g_new0(struct process_runtime_data, 1);
- if (!runtime_data) {
- g_critical("Unable to allocate runtime data structure for '%s'",
- app_id);
- return FALSE;
- }
-
- runtime_data->app_id = app_id;
-
- args = g_strsplit(command, " ", -1);
- success = g_spawn_async(NULL, args, NULL,
- G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH,
- NULL, NULL, &runtime_data->pid, NULL);
- if (!success) {
- g_critical("Unable to start application '%s'", app_id);
- g_free(runtime_data);
- return FALSE;
- }
-
- /*
- * Add a watcher for the child PID in order to get notified when it dies
- */
- runtime_data->watcher = g_child_watch_add(runtime_data->pid,
- process_manager_app_terminated_cb,
- self);
- self->process_data = g_list_append(self->process_data, runtime_data);
- app_info_set_runtime_data(app_info, runtime_data);
- app_info_set_status(app_info, APP_STATUS_RUNNING);
-
- g_signal_emit(self, signals[STARTED], 0, app_id);
-
- return TRUE;
-}
diff --git a/src/process_manager.h b/src/process_manager.h
deleted file mode 100644
index 1979cba..0000000
--- a/src/process_manager.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2021 Collabora Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef PROCESSMANAGER_H
-#define PROCESSMANAGER_H
-
-#include <glib-object.h>
-
-#include "app_info.h"
-
-G_BEGIN_DECLS
-
-#define APPLAUNCHD_TYPE_PROCESS_MANAGER process_manager_get_type()
-
-G_DECLARE_FINAL_TYPE(ProcessManager, process_manager,
- APPLAUNCHD, PROCESS_MANAGER, GObject);
-
-ProcessManager *process_manager_new(void);
-
-gboolean process_manager_start_app(ProcessManager *self,
- AppInfo *app_info);
-
-G_END_DECLS
-
-#endif
diff --git a/src/systemd_manager.c b/src/systemd_manager.c
index 3fae7fc..63e7094 100644
--- a/src/systemd_manager.c
+++ b/src/systemd_manager.c
@@ -147,7 +147,119 @@ SystemdManager *systemd_manager_new(void)
}
/*
- * Start an application by executing the provided command line.
+ * Get app unit list
+ */
+gboolean systemd_manager_enumerate_app_units(SystemdManager *self,
+ AppLauncher *launcher,
+ GList **units)
+{
+ g_return_val_if_fail(APPLAUNCHD_IS_SYSTEMD_MANAGER(self), FALSE);
+ g_return_val_if_fail(APPLAUNCHD_IS_APP_LAUNCHER(launcher), FALSE);
+ g_return_val_if_fail(units != NULL, FALSE);
+
+ sd_bus_error error = SD_BUS_ERROR_NULL;
+ sd_bus_message *m = NULL;
+ const char *path;
+ int r;
+
+ r = sd_bus_call_method(
+ app_launcher_get_bus(launcher), /* bus */
+ "org.freedesktop.systemd1", /* service to contact */
+ "/org/freedesktop/systemd1", /* object path */
+ "org.freedesktop.systemd1.Manager", /* interface name */
+ "ListUnitFilesByPatterns", /* method name */
+ &error, /* object to return error in */
+ &m, /* return message on success */
+ "asas", /* input signature */
+ 0, /* first argument (empty array) */
+ 1, /* second argument (array) */
+ "agl-app*@*.service"
+ );
+ if (r < 0) {
+ g_critical("Failed to issue method call: %s", error.message);
+ goto finish;
+ }
+
+ r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
+ if (r < 0) {
+ g_critical("Failed to parse response message: %s", strerror(-r));
+ goto finish;
+ }
+
+ const char *unit;
+ const char *state;
+ while ((r = sd_bus_message_read(m, "(ss)", &unit, &state)) > 0) {
+ if (!g_str_has_suffix(unit, "@.service"))
+ *units = g_list_prepend(*units, g_strdup(unit));
+ }
+ if (r < 0) {
+ g_critical("Failed to parse unit entry: %s", strerror(-r));
+ goto finish;
+ }
+
+ // Exit array
+ r = sd_bus_message_exit_container(m);
+ if (r < 0) {
+ g_critical("Failed to parse response message 5: %s", strerror(-r));
+ goto finish;
+ }
+
+ return TRUE;
+
+finish:
+ sd_bus_error_free(&error);
+ sd_bus_message_unref(m);
+ g_list_free_full(*units, g_free);
+ *units = NULL;
+ return FALSE;
+}
+
+/*
+ * Get app unit description property
+ */
+gboolean systemd_manager_get_app_description(SystemdManager *self,
+ AppLauncher *launcher,
+ gchar *service,
+ gchar **description)
+{
+ g_return_val_if_fail(APPLAUNCHD_IS_SYSTEMD_MANAGER(self), FALSE);
+ g_return_val_if_fail(APPLAUNCHD_IS_APP_LAUNCHER(launcher), FALSE);
+ g_return_val_if_fail(service != NULL, FALSE);
+ g_return_val_if_fail(description != NULL, FALSE);
+
+ sd_bus_error error = SD_BUS_ERROR_NULL;
+ sd_bus_message *m = NULL;
+ gchar *esc_service = NULL;
+ const char *path;
+ int r;
+
+ /* Get the escaped unit name in the systemd hierarchy */
+ sd_bus_path_encode("/org/freedesktop/systemd1/unit", service, &esc_service);
+
+ r = sd_bus_get_property_string(
+ app_launcher_get_bus(launcher), /* bus */
+ "org.freedesktop.systemd1", /* service to contact */
+ esc_service, /* object path */
+ "org.freedesktop.systemd1.Unit",
+ "Description",
+ &error,
+ description);
+ if (r < 0) {
+ g_critical("Failed to issue method call: %s", error.message);
+ goto finish;
+ }
+ return TRUE;
+
+finish:
+ sd_bus_error_free(&error);
+ sd_bus_message_unref(m);
+ g_free(*description);
+ *description = NULL;
+ return FALSE;
+}
+
+/*
+ * Start an application by executing its service.
*/
gboolean systemd_manager_start_app(SystemdManager *self,
AppInfo *app_info)
@@ -156,10 +268,9 @@ gboolean systemd_manager_start_app(SystemdManager *self,
g_return_val_if_fail(APPLAUNCHD_IS_APP_INFO(app_info), FALSE);
AppLauncher *launcher = app_launcher_get_default();
- g_autofree gchar *service = NULL;
gchar *esc_service = NULL;
const gchar *app_id = app_info_get_app_id(app_info);
- const gchar *command = app_info_get_command(app_info);
+ const gchar *service = app_info_get_service(app_info);
struct systemd_runtime_data *runtime_data;
sd_bus_error error = SD_BUS_ERROR_NULL;
@@ -173,10 +284,9 @@ gboolean systemd_manager_start_app(SystemdManager *self,
return FALSE;
}
- /* Compose the corresponding service name */
- service = g_strdup_printf("agl-app@%s.service", command);
/* Get the escaped unit name in the systemd hierarchy */
sd_bus_path_encode("/org/freedesktop/systemd1/unit", service, &esc_service);
+ g_debug("Trying to start service '%s', unit path '%s'", service, esc_service);
runtime_data->mgr = self;
runtime_data->esc_service = esc_service;
diff --git a/src/systemd_manager.h b/src/systemd_manager.h
index a8a4ac7..b866948 100644
--- a/src/systemd_manager.h
+++ b/src/systemd_manager.h
@@ -20,6 +20,7 @@
#include <glib-object.h>
#include "app_info.h"
+#include "app_launcher.h"
G_BEGIN_DECLS
@@ -30,6 +31,15 @@ G_DECLARE_FINAL_TYPE(SystemdManager, systemd_manager,
SystemdManager *systemd_manager_new(void);
+gboolean systemd_manager_enumerate_app_units(SystemdManager *self,
+ AppLauncher *launcher,
+ GList **units);
+
+gboolean systemd_manager_get_app_description(SystemdManager *self,
+ AppLauncher *launcher,
+ gchar *service,
+ gchar **description);
+
gboolean systemd_manager_start_app(SystemdManager *self,
AppInfo *app_info);