[gnome-session/benzea/systemd-issue-35] Delay XDG autostart applications on systemd



commit 20948032bafe839d95bbf48c78cf45bc40fde8d9
Author: Benjamin Berg <bberg redhat com>
Date:   Fri Oct 4 17:09:18 2019 +0200

    Delay XDG autostart applications on systemd
    
    When launching on systemd we did not synchronize the phases after
    the shell is loaded. Due to this, applications may start up before g-s-d
    is started, which should not be the case.
    
    Add a further one-way synchronization point so that gnome-session only
    starts launching applications after gnome-session.target has been
    reached.
    
    Fixes: #35

 data/gnome-session-initialized.target              |  4 +-
 data/gnome-session-manager  service in             |  2 +-
 ...e.in => gnome-session-signal-phase  service in} |  2 +-
 data/gnome-session.target                          |  6 +++
 data/meson.build                                   |  2 +-
 gnome-session/gsm-manager.c                        | 58 ++++++++++++++--------
 gnome-session/org.gnome.SessionManager.xml         |  9 +++-
 tools/gnome-session-ctl.c                          | 16 +++---
 8 files changed, 63 insertions(+), 36 deletions(-)
---
diff --git a/data/gnome-session-initialized.target b/data/gnome-session-initialized.target
index 3ef2ecfe..959a83c0 100644
--- a/data/gnome-session-initialized.target
+++ b/data/gnome-session-initialized.target
@@ -15,5 +15,5 @@ Before=gnome-session.target
 
 # Signal gnome-session that we reached the initialized target and
 # that it may start applications.
-Requires=gnome-session-signal-init.service
-Before=gnome-session-signal-init.service
+Requires=gnome-session-signal-phase@4.service
+Before=gnome-session-signal-phase@4.service
diff --git a/data/gnome-session-manager  service in b/data/gnome-session-manager  service in
index b06dbeb3..13bfc73d 100644
--- a/data/gnome-session-manager  service in
+++ b/data/gnome-session-manager  service in
@@ -15,5 +15,5 @@ Before=gnome-session-manager.target
 
 [Service]
 Type=notify
-ExecStart=@libexecdir@/gnome-session-binary --systemd-service --session=%i
+ExecStart=@libexecdir@/gnome-session-binary --systemd-service --debug --session=%i
 ExecStopPost=-@libexecdir@/gnome-session-ctl --shutdown
diff --git a/data/gnome-session-signal-init.service.in b/data/gnome-session-signal-phase  service in
similarity index 67%
rename from data/gnome-session-signal-init.service.in
rename to data/gnome-session-signal-phase  service in
index e3d2c463..84c40b55 100644
--- a/data/gnome-session-signal-init.service.in
+++ b/data/gnome-session-signal-phase  service in
@@ -5,4 +5,4 @@ PartOf=gnome-session.target
 
 [Service]
 Type=oneshot
-ExecStart=@libexecdir@/gnome-session-ctl --signal-init
+ExecStart=@libexecdir@/gnome-session-ctl --signal-phase=%I
diff --git a/data/gnome-session.target b/data/gnome-session.target
index 55cfc751..ba7ba3f4 100644
--- a/data/gnome-session.target
+++ b/data/gnome-session.target
@@ -14,5 +14,11 @@ Before=graphical-session.target
 BindsTo=gnome-session-monitor.service
 After=gnome-session-monitor.service
 
+# Signal gnome-session that the desktop is fully loaded at this point.
+# Note that this signal is one-way only and prevents XDG autostart
+# applications from loading early.
+Requires=gnome-session-signal-phase@7.service
+Before=gnome-session-signal-phase@7.service
+
 # Pull in timer to mark session as stable (and unstable as long as the timer is active)
 Requires=gnome-session-stable.timer
diff --git a/data/meson.build b/data/meson.build
index ef35c494..647483a3 100644
--- a/data/meson.build
+++ b/data/meson.build
@@ -100,7 +100,7 @@ if enable_systemd_session
   systemd_userunitdir = join_paths(session_prefix, 'lib', 'systemd', 'user')
 
   systemd_service = ['gnome-session-manager@.service',
-                     'gnome-session-signal-init.service',
+                     'gnome-session-signal-phase@.service',
                      'gnome-session-restart-dbus.service',
                      'gnome-session-monitor.service',
                      'gnome-session-failed.service']
diff --git a/gnome-session/gsm-manager.c b/gnome-session/gsm-manager.c
index d41bdcac..1e1a1ed3 100644
--- a/gnome-session/gsm-manager.c
+++ b/gnome-session/gsm-manager.c
@@ -126,8 +126,8 @@ struct GsmManagerPrivate
 {
         gboolean                failsafe;
         gboolean                systemd_managed;
-        gboolean                systemd_initialized;
-        gboolean                manager_initialized;
+        gint                    systemd_phase;
+        gboolean                manager_waiting_systemd;
         GsmStore               *clients;
         GsmStore               *inhibitors;
         GsmInhibitorFlag        inhibited_actions;
@@ -540,16 +540,24 @@ end_phase (GsmManager *manager)
         case GSM_MANAGER_PHASE_DISPLAY_SERVER:
                 break;
         case GSM_MANAGER_PHASE_INITIALIZATION:
-                manager->priv->manager_initialized = TRUE;
-                /* Wait for systemd if it isn't initialized yet*/
-                if (manager->priv->systemd_managed && !manager->priv->systemd_initialized) {
+                /* Wait for systemd to reach the same state */
+                if (manager->priv->systemd_managed && manager->priv->systemd_phase < 
GSM_MANAGER_PHASE_INITIALIZATION) {
                         sd_notify (0, "STATUS=GNOME Session Manager waiting for 
gnome-session-initialized.target (via signal)");
+                        manager->priv->manager_waiting_systemd = TRUE;
                         start_next_phase = FALSE;
                 }
                 break;
         case GSM_MANAGER_PHASE_WINDOW_MANAGER:
         case GSM_MANAGER_PHASE_PANEL:
+                break;
         case GSM_MANAGER_PHASE_DESKTOP:
+                /* Wait for systemd to reach the same state */
+                if (manager->priv->systemd_managed && manager->priv->systemd_phase < 
GSM_MANAGER_PHASE_APPLICATION) {
+                        sd_notify (0, "STATUS=GNOME Session Manager waiting for gnome-session.target (via 
signal)");
+                        manager->priv->manager_waiting_systemd = TRUE;
+                        start_next_phase = FALSE;
+                }
+                break;
         case GSM_MANAGER_PHASE_APPLICATION:
                 break;
         case GSM_MANAGER_PHASE_RUNNING:
@@ -2676,36 +2684,44 @@ gsm_manager_setenv (GsmExportedManager    *skeleton,
 }
 
 static gboolean
-gsm_manager_initialized (GsmExportedManager    *skeleton,
-                         GDBusMethodInvocation *invocation,
-                         GsmManager            *manager)
+gsm_manager_systemd_phase (GsmExportedManager    *skeleton,
+                           GDBusMethodInvocation *invocation,
+                           gint                   phase_done,
+                           GsmManager            *manager)
 {
-        /* Signaled by helper when gnome-session-initialized.target is reached. */
+        /* Signaled by helper when gnome-session-initialized.target
+         * or gnome-session.target are reached. */
         if (!manager->priv->systemd_managed) {
                 g_dbus_method_invocation_return_error (invocation,
                                                        GSM_MANAGER_ERROR,
                                                        GSM_MANAGER_ERROR_GENERAL,
                                                        "Initialized interface is only available when 
gnome-session is managed by systemd");
-        } else if (manager->priv->systemd_initialized) {
+        } else if (manager->priv->systemd_phase >= phase_done) {
                 g_dbus_method_invocation_return_error (invocation,
                                                        GSM_MANAGER_ERROR,
                                                        GSM_MANAGER_ERROR_NOT_IN_INITIALIZATION,
-                                                       "Systemd initialization was already signaled");
-        } else if (manager->priv->phase > GSM_MANAGER_PHASE_INITIALIZATION) {
+                                                       "Systemd already signalled equal or higher phase");
+        } else if (manager->priv->phase > GSM_MANAGER_PHASE_DESKTOP) {
                 g_dbus_method_invocation_return_error (invocation,
                                                        GSM_MANAGER_ERROR,
                                                        GSM_MANAGER_ERROR_NOT_IN_INITIALIZATION,
                                                        "Initialized interface is only available during 
startup");
         } else {
-                manager->priv->systemd_initialized = TRUE;
-
-                if (manager->priv->manager_initialized) {
-                        g_assert (manager->priv->phase == GSM_MANAGER_PHASE_INITIALIZATION);
-                        manager->priv->phase++;
-                        start_phase (manager);
+                manager->priv->systemd_phase = phase_done;
+                g_debug ("Systemd startup signalled phase %i as reached, waiting: %i, internal phase: %i",
+                         phase_done,
+                         manager->priv->manager_waiting_systemd,
+                         manager->priv->systemd_phase);
+
+                if (manager->priv->manager_waiting_systemd) {
+                        if (manager->priv->phase <= manager->priv->systemd_phase) {
+                                manager->priv->manager_waiting_systemd = FALSE;
+                                manager->priv->phase++;
+                                start_phase (manager);
+                        }
                 }
 
-                gsm_exported_manager_complete_initialized (skeleton, invocation);
+                gsm_exported_manager_complete_phase_done (skeleton, invocation);
         }
 
         return TRUE;
@@ -3308,8 +3324,8 @@ register_manager (GsmManager *manager)
                           G_CALLBACK (gsm_manager_set_reboot_to_firmware_setup), manager);
         g_signal_connect (skeleton, "handle-setenv",
                           G_CALLBACK (gsm_manager_setenv), manager);
-        g_signal_connect (skeleton, "handle-initialized",
-                          G_CALLBACK (gsm_manager_initialized), manager);
+        g_signal_connect (skeleton, "handle-phase-done",
+                          G_CALLBACK (gsm_manager_systemd_phase), manager);
         g_signal_connect (skeleton, "handle-shutdown",
                           G_CALLBACK (gsm_manager_shutdown), manager);
         g_signal_connect (skeleton, "handle-uninhibit",
diff --git a/gnome-session/org.gnome.SessionManager.xml b/gnome-session/org.gnome.SessionManager.xml
index ce4b8c07..be792306 100644
--- a/gnome-session/org.gnome.SessionManager.xml
+++ b/gnome-session/org.gnome.SessionManager.xml
@@ -59,10 +59,15 @@
       </doc:doc>
     </method>
 
-    <method name="Initialized">
+    <method name="PhaseDone">
+      <arg type="i" name="phase" direction="in">
+        <doc:doc>
+          <doc:summary>The reached phase, must be 4 or 7 for the Initialization or Desktop 
phases</doc:summary>
+        </doc:doc>
+      </arg>
       <doc:doc>
         <doc:description>
-          <doc:para>Run from systemd to signal that gnome-session-initialized.target has been 
reached.</doc:para>
+          <doc:para>Run from systemd to signal that gnome-session-initialized.target or gnome-session.target 
have been reached.</doc:para>
         </doc:description>
       </doc:doc>
     </method>
diff --git a/tools/gnome-session-ctl.c b/tools/gnome-session-ctl.c
index 9276a0ad..7f46955c 100644
--- a/tools/gnome-session-ctl.c
+++ b/tools/gnome-session-ctl.c
@@ -59,7 +59,7 @@ get_session_bus (void)
 }
 
 static void
-do_signal_init (void)
+do_signal_phase (gint opt_signal_phase)
 {
         g_autoptr(GDBusConnection) connection = NULL;
         g_autoptr(GVariant) reply = NULL;
@@ -73,8 +73,8 @@ do_signal_init (void)
                                              GSM_SERVICE_DBUS,
                                              GSM_PATH_DBUS,
                                              GSM_INTERFACE_DBUS,
-                                             "Initialized",
-                                             NULL,
+                                             "PhaseDone",
+                                             g_variant_new ("(i)", opt_signal_phase),
                                              NULL,
                                              G_DBUS_CALL_FLAGS_NO_AUTO_START,
                                              -1, NULL, &error);
@@ -236,14 +236,14 @@ main (int argc, char *argv[])
         g_autoptr(GError) error = NULL;
         static gboolean   opt_shutdown;
         static gboolean   opt_monitor;
-        static gboolean   opt_signal_init;
+        static gint       opt_signal_phase;
         static gboolean   opt_restart_dbus;
         int     conflicting_options;
         GOptionContext *ctx;
         static const GOptionEntry options[] = {
                 { "shutdown", '\0', 0, G_OPTION_ARG_NONE, &opt_shutdown, N_("Start 
gnome-session-shutdown.target"), NULL },
                 { "monitor", '\0', 0, G_OPTION_ARG_NONE, &opt_monitor, N_("Start 
gnome-session-shutdown.target when receiving EOF or a single byte on stdin"), NULL },
-                { "signal-init", '\0', 0, G_OPTION_ARG_NONE, &opt_signal_init, N_("Signal initialization 
done to gnome-session"), NULL },
+                { "signal-phase", '\0', 0, G_OPTION_ARG_INT, &opt_signal_phase, N_("Signal finished phase to 
gnome-session"), NULL },
                 { "restart-dbus", '\0', 0, G_OPTION_ARG_NONE, &opt_restart_dbus, N_("Restart dbus.service if 
it is running"), NULL },
                 { NULL },
         };
@@ -267,7 +267,7 @@ main (int argc, char *argv[])
                 conflicting_options++;
         if (opt_monitor)
                 conflicting_options++;
-        if (opt_signal_init)
+        if (opt_signal_phase)
                 conflicting_options++;
         if (opt_restart_dbus)
                 conflicting_options++;
@@ -278,8 +278,8 @@ main (int argc, char *argv[])
 
         sd_notify (0, "READY=1");
 
-        if (opt_signal_init) {
-                do_signal_init ();
+        if (opt_signal_phase) {
+                do_signal_phase (opt_signal_phase);
         } else if (opt_restart_dbus) {
                 do_restart_dbus ();
         } else if (opt_shutdown) {


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