Blob Blame History Raw
From 1fc22df08e365820fedccf92b95601859ce63f5b Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Fri, 7 Oct 2016 15:40:14 -0400
Subject: [PATCH 1/2] objectManager: handle proxies coming and going

Ever since commit b8e29ae8c78658917c8a8ddd391667d7d9e36971
(I think), start up is littered with this message:

 Gjs-WARNING **: JS ERROR: could not get remote objects for service
 org.gnome.SettingsDaemon.Smartcard path

since gnome-shell is now started before gnome-settings-daemon.

This commit addresses the problem by making the object manager code
not try to autostart its proxy, and instead wait for it to appear.

https://bugzilla.gnome.org/show_bug.cgi?id=772589
---
 js/misc/objectManager.js   | 34 ++++++++++++++++++++++++++++++++--
 1 files changed, 34 insertions(+), 2 deletions(-)

diff --git a/js/misc/objectManager.js b/js/misc/objectManager.js
index 225204347..5db7588b6 100644
--- a/js/misc/objectManager.js
+++ b/js/misc/objectManager.js
@@ -19,101 +19,104 @@ const ObjectManagerIface = '<node> \
   </signal> \
   <signal name="InterfacesRemoved"> \
     <arg name="objectPath" type="o"/> \
     <arg name="interfaces" type="as" /> \
   </signal> \
 </interface> \
 </node>';
 
 const ObjectManagerInfo = Gio.DBusInterfaceInfo.new_for_xml(ObjectManagerIface);
 
 const ObjectManager = new Lang.Class({
     Name: 'ObjectManager',
     _init: function(params) {
         params = Params.parse(params, { connection: null,
                                         name: null,
                                         objectPath: null,
                                         knownInterfaces: null,
                                         cancellable: null,
                                         onLoaded: null });
 
         this._connection = params.connection;
         this._serviceName = params.name;
         this._managerPath = params.objectPath;
         this._cancellable = params.cancellable;
 
         this._managerProxy = new Gio.DBusProxy({ g_connection: this._connection,
                                                  g_interface_name: ObjectManagerInfo.name,
                                                  g_interface_info: ObjectManagerInfo,
                                                  g_name: this._serviceName,
                                                  g_object_path: this._managerPath,
-                                                 g_flags: Gio.DBusProxyFlags.NONE });
+                                                 g_flags: Gio.DBusProxyFlags.DO_NOT_AUTO_START });
 
         this._interfaceInfos = {};
         this._objects = {};
         this._interfaces = {};
         this._onLoaded = params.onLoaded;
 
         if (params.knownInterfaces)
             this._registerInterfaces(params.knownInterfaces);
 
         // Start out inhibiting load until at least the proxy
         // manager is loaded and the remote objects are fetched
         this._numLoadInhibitors = 1;
         this._managerProxy.init_async(GLib.PRIORITY_DEFAULT,
                                       this._cancellable,
                                       Lang.bind(this, this._onManagerProxyLoaded));
     },
 
     _tryToCompleteLoad: function() {
+        if (this._numLoadInhibitors == 0)
+            return;
+
         this._numLoadInhibitors--;
         if (this._numLoadInhibitors == 0) {
             if (this._onLoaded)
                 this._onLoaded();
         }
     },
 
     _addInterface: function(objectPath, interfaceName, onFinished) {
         let info = this._interfaceInfos[interfaceName];
 
         if (!info) {
            if (onFinished)
                onFinished();
            return;
         }
 
         let proxy = new Gio.DBusProxy({ g_connection: this._connection,
                                        g_name: this._serviceName,
                                        g_object_path: objectPath,
                                        g_interface_name: interfaceName,
                                        g_interface_info: info,
-                                       g_flags: Gio.DBusProxyFlags.NONE });
+                                       g_flags: Gio.DBusProxyFlags.DO_NOT_AUTO_START });
 
         proxy.init_async(GLib.PRIORITY_DEFAULT,
                          this._cancellable,
                          Lang.bind(this, function(initable, result) {
                let error = null;
                try {
                    initable.init_finish(result);
                } catch(e) {
                    logError(e, 'could not initialize proxy for interface ' + interfaceName);
 
                    if (onFinished)
                        onFinished();
                    return;
                }
 
                let isNewObject;
                if (!this._objects[objectPath]) {
                    this._objects[objectPath] = {};
                    isNewObject = true;
                } else {
                    isNewObject = false;
                }
 
                this._objects[objectPath][interfaceName] = proxy;
 
                if (!this._interfaces[interfaceName])
                    this._interfaces[interfaceName] = [];
 
                this._interfaces[interfaceName].push(proxy);
 
@@ -154,92 +157,119 @@ const ObjectManager = new Lang.Class({
     },
 
     _onManagerProxyLoaded: function(initable, result) {
         let error = null;
         try {
             initable.init_finish(result);
         } catch(e) {
             logError(e, 'could not initialize object manager for object ' + params.name);
 
             this._tryToCompleteLoad();
             return;
         }
 
         this._managerProxy.connectSignal('InterfacesAdded',
                                          Lang.bind(this, function(objectManager, sender, [objectPath, interfaces]) {
                                              let interfaceNames = Object.keys(interfaces);
                                              for (let i = 0; i < interfaceNames.length; i++)
                                                  this._addInterface(objectPath, interfaceNames[i]);
                                          }));
         this._managerProxy.connectSignal('InterfacesRemoved',
                                          Lang.bind(this, function(objectManager, sender, [objectPath, interfaceNames]) {
                                              for (let i = 0; i < interfaceNames.length; i++)
                                                  this._removeInterface(objectPath, interfaceNames[i]);
                                          }));
 
         if (Object.keys(this._interfaceInfos).length == 0) {
             this._tryToCompleteLoad();
             return;
         }
 
+        this._managerProxy.connect('notify::g-name-owner', Lang.bind(this, function() {
+            if (this._managerProxy.g_name_owner)
+                this._onNameAppeared();
+            else
+                this._onNameVanished();
+        }));
+
+        if (this._managerProxy.g_name_owner)
+            this._onNameAppeared();
+    },
+
+    _onNameAppeared: function() {
         this._managerProxy.GetManagedObjectsRemote(Lang.bind(this, function(result, error) {
             if (!result) {
                 if (error) {
                    logError(error, 'could not get remote objects for service ' + this._serviceName + ' path ' + this._managerPath);
                 }
 
                 this._tryToCompleteLoad();
                 return;
             }
 
             let [objects] = result;
 
             let objectPaths = Object.keys(objects);
             for (let i = 0; i < objectPaths.length; i++) {
                 let objectPath = objectPaths[i];
                 let object = objects[objectPath];
 
                 let interfaceNames = Object.getOwnPropertyNames(object);
                 for (let j = 0; j < interfaceNames.length; j++) {
                     let interfaceName = interfaceNames[j];
 
                     // Prevent load from completing until the interface is loaded
                     this._numLoadInhibitors++;
                     this._addInterface(objectPath,
                                        interfaceName,
                                        Lang.bind(this, this._tryToCompleteLoad));
                 }
             }
             this._tryToCompleteLoad();
         }));
     },
 
+    _onNameVanished: function() {
+        let objectPaths = Object.keys(this._objects);
+        for (let i = 0; i < objectPaths.length; i++) {
+            let object = this._objects[objectPaths];
+
+            let interfaceNames = Object.keys(object);
+            for (let j = 0; i < interfaceNames.length; i++) {
+                let interfaceName = interfaceNames[i];
+
+                if (object[interfaceName])
+                    this._removeInterface(objectPath, interfaceName);
+            }
+        }
+    },
+
     _registerInterfaces: function(interfaces) {
         for (let i = 0; i < interfaces.length; i++) {
             let info = Gio.DBusInterfaceInfo.new_for_xml(interfaces[i]);
             this._interfaceInfos[info.name] = info;
         }
     },
 
     getProxy: function(objectPath, interfaceName) {
         let object = this._objects[objectPath];
 
         if (!object)
             return null;
 
         return object[interfaceName];
     },
 
     getProxiesForInterface: function(interfaceName) {
         let proxyList = this._interfaces[interfaceName];
 
         if (!proxyList)
             return [];
 
         return proxyList;
     },
 
     getAllProxies: function() {
         let proxies = [];
 
         let objectPaths = Object.keys(this._objects);
         for (let i = 0; i < objectPaths.length; i++) {