[gnome-settings-daemon/benzea/spawn-in-scope] media-keys: Place spawned processes into a systemd scope



commit f8d187eb68eae1554f508aa930c71335d121eb44
Author: Benjamin Berg <bberg redhat com>
Date:   Tue Nov 26 18:20:16 2019 +0100

    media-keys: Place spawned processes into a systemd scope
    
    This means we isolate the processes from the media-keys scope itself.
    The scope units are created with a gnome-launched- prefix, which allows
    us to create a GNOME wide drop-in to set defaults.
    
    If systemd support is disabled, or we are not running on a systemd
    session, then the code will do nothing.

 meson.build                                 |   5 ++
 plugins/media-keys/gsd-media-keys-manager.c | 130 ++++++++++++++++++++++++++++
 plugins/media-keys/meson.build              |   3 +-
 3 files changed, 137 insertions(+), 1 deletion(-)
---
diff --git a/meson.build b/meson.build
index 0c65f381..400b285a 100644
--- a/meson.build
+++ b/meson.build
@@ -104,7 +104,9 @@ x11_dep = dependency('x11')
 
 enable_systemd = get_option('systemd')
 if enable_systemd
+  libsystemd_dep = dependency('libsystemd')
   systemd_dep = dependency('systemd', required: false)
+  assert(libsystemd_dep.found(), 'Systemd support explicitly required, but libsystemd not found')
   assert(systemd_dep.found(), 'Systemd support explicitly required, but systemd not found')
 
   # XXX: Once https://github.com/systemd/systemd/issues/9595 is fixed and we can
@@ -112,7 +114,10 @@ if enable_systemd
   #  systemduserunitdir = systemd_dep.get_pkgconfig_variable('systemduserunitdir')
   # and uncomment systemd_dep below
   systemd_userunitdir = join_paths(gsd_prefix, 'lib', 'systemd', 'user')
+else
+  libsystemd_dep = []
 endif
+config_h.set10('HAVE_SYSTEMD', enable_systemd)
 
 m_dep = cc.find_library('m')
 
diff --git a/plugins/media-keys/gsd-media-keys-manager.c b/plugins/media-keys/gsd-media-keys-manager.c
index 4e167c86..23de816c 100644
--- a/plugins/media-keys/gsd-media-keys-manager.c
+++ b/plugins/media-keys/gsd-media-keys-manager.c
@@ -46,6 +46,10 @@
 #include <gudev/gudev.h>
 #endif
 
+#if HAVE_SYSTEMD
+#include <systemd/sd-login.h>
+#endif
+
 #include "gsd-settings-migrate.h"
 
 #include "mpris-controller.h"
@@ -264,6 +268,23 @@ G_DEFINE_TYPE_WITH_PRIVATE (GsdMediaKeysManager, gsd_media_keys_manager, G_TYPE_
 
 static gpointer manager_object = NULL;
 
+#if HAVE_SYSTEMD
+static void
+dbus_call_log_error (GObject *source_object,
+                     GAsyncResult *res,
+                     gpointer user_data)
+{
+        g_autoptr(GVariant) result;
+        g_autoptr(GError) error = NULL;
+        const gchar *msg = user_data;
+
+        result = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object),
+                                                res,
+                                                &error);
+        if (error)
+                g_warning ("%s: %s", msg, error->message);
+}
+#endif
 
 static void
 media_key_unref (MediaKey *key)
@@ -996,6 +1017,107 @@ init_kbd (GsdMediaKeysManager *manager)
         gnome_settings_profile_end (NULL);
 }
 
+#if HAVE_SYSTEMD
+static void
+app_launched_cb (GAppLaunchContext *context,
+                 GAppInfo          *info,
+                 GVariant          *platform_data,
+                 gpointer           user_data)
+{
+        GsdMediaKeysManager *manager = GSD_MEDIA_KEYS_MANAGER (user_data);
+        GsdMediaKeysManagerPrivate *priv = GSD_MEDIA_KEYS_MANAGER_GET_PRIVATE (manager);
+        const char *valid_chars =
+                "-._1234567890"
+                "abcdefghijklmnopqrstuvwxyz"
+                "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+        gint32 pid;
+        GVariantBuilder builder;
+        const gchar *app_id;
+        g_autofree gchar *mangled_app_id = NULL;
+        g_autofree gchar *unit_name = NULL;
+        g_autofree gchar *own_unit = NULL;
+        g_autoptr(GVariantDict) dict = NULL;
+        gint res;
+
+        g_return_if_fail (platform_data != NULL);
+
+        dict = g_variant_dict_new (platform_data);
+
+        g_return_if_fail (g_variant_dict_contains (dict, "pid"));
+
+        if (!g_variant_dict_lookup (dict, "pid", "i", &pid)) {
+                g_critical ("Could not unpack pid from platform data.");
+                return;
+        }
+
+        /* We cannot do anything if this process is not managed by the
+         * systemd user instance. */
+        res = sd_pid_get_user_unit (getpid (), &own_unit);
+        if (res == -ENODATA) {
+                g_debug ("Not systemd managed, will not move PID %d into transient scope\n", pid);
+                return;
+        }
+        if (res < 0) {
+                g_warning ("Error retrieving user unit for own PID: %i", -res);
+                return;
+        }
+
+        g_debug ("Trying to create transient scope for PID %d\n", pid);
+
+        g_assert (priv->connection);
+
+        /* Create a nice and (mangled) name to embed into the unit */
+        app_id = g_app_info_get_id (info);
+        if (app_id == NULL)
+                app_id = g_app_info_get_executable (info);
+        if (app_id == NULL)
+                app_id = "anonymous";
+
+        if (app_id[0] == '/')
+                app_id++;
+
+        mangled_app_id = g_str_to_ascii (app_id, "C");
+        g_strdelimit (mangled_app_id, "/", '-');
+        g_strcanon (mangled_app_id, valid_chars, '_');
+
+        /* This needs to be unique, hopefully the pid will be enough. */
+        unit_name = g_strdup_printf ("gnome-launched-%s-%d.scope", mangled_app_id, pid);
+
+        /* Build arguments */
+        g_variant_builder_init (&builder, G_VARIANT_TYPE ("(ssa(sv)a(sa(sv)))"));
+        g_variant_builder_add (&builder, "s", unit_name);
+        g_variant_builder_add (&builder, "s", "fail");
+
+        g_variant_builder_open (&builder, G_VARIANT_TYPE ("a(sv)"));
+        g_variant_builder_add (&builder,
+                               "(sv)",
+                               "Description",
+                               g_variant_new_string ("Application launched by gsd-media-keys"));
+        g_variant_builder_add (&builder,
+                               "(sv)",
+                               "PIDs",
+                               g_variant_new_fixed_array (G_VARIANT_TYPE_UINT32, &pid, 1, 4));
+
+        g_variant_builder_close (&builder);
+
+        g_variant_builder_open (&builder, G_VARIANT_TYPE ("a(sa(sv))"));
+        g_variant_builder_close (&builder);
+
+        g_dbus_connection_call (priv->connection,
+                                "org.freedesktop.systemd1",
+                                "/org/freedesktop/systemd1",
+                                "org.freedesktop.systemd1.Manager",
+                                "StartTransientUnit",
+                                g_variant_builder_end (&builder),
+                                G_VARIANT_TYPE ("(o)"),
+                                G_DBUS_CALL_FLAGS_NO_AUTO_START,
+                                1000,
+                                NULL,
+                                dbus_call_log_error,
+                                "Failed to create transient unit");
+}
+#endif
+
 static void
 launch_app (GsdMediaKeysManager *manager,
            GAppInfo            *app_info,
@@ -1009,6 +1131,14 @@ launch_app (GsdMediaKeysManager *manager,
         gdk_app_launch_context_set_timestamp (launch_context, timestamp);
         set_launch_context_env (manager, G_APP_LAUNCH_CONTEXT (launch_context));
 
+#if HAVE_SYSTEMD
+        g_signal_connect_object (launch_context,
+                                 "launched",
+                                 G_CALLBACK (app_launched_cb),
+                                 manager,
+                                 0);
+#endif
+
        if (!g_app_info_launch (app_info, NULL, G_APP_LAUNCH_CONTEXT (launch_context), &error)) {
                g_warning ("Could not launch '%s': %s",
                           g_app_info_get_commandline (app_info),
diff --git a/plugins/media-keys/meson.build b/plugins/media-keys/meson.build
index e6c1d2ac..d233b5e8 100644
--- a/plugins/media-keys/meson.build
+++ b/plugins/media-keys/meson.build
@@ -30,7 +30,8 @@ deps = plugins_deps + [
   libgvc_dep,
   libpulse_mainloop_glib_dep,
   m_dep,
-  upower_glib_dep
+  upower_glib_dep,
+  libsystemd_dep
 ]
 
 if enable_gudev


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]