control: Let Manager::addObjects() take a service

When calling Manager::addObjects(), pass in the service of the object,
if known, so that addObjects() can use that service to call
getManagedObjects() with and add objects to the cache even if the
D-Bus path passed in doesn't exist.

This fixes a bug where if the path doesn't exist, that function won't
add anything at all, even though getProperties() in init.cpp was
depending on it doing that so that it only needed to call addObjects()
once per group as a performance enhancement.

Signed-off-by: Matt Spinler <spinler@us.ibm.com>
Change-Id: I971a244d665d3aaf493c3d03e7a4fec87e7e512d
diff --git a/control/json/manager.cpp b/control/json/manager.cpp
index 9825a32..c9d679f 100644
--- a/control/json/manager.cpp
+++ b/control/json/manager.cpp
@@ -531,17 +531,33 @@
 }
 
 void Manager::addObjects(const std::string& path, const std::string& intf,
-                         const std::string& prop)
+                         const std::string& prop,
+                         const std::string& serviceName)
 {
-    auto service = getService(path, intf);
+    auto service = serviceName;
     if (service.empty())
     {
-        // Log service not found for object
-        log<level::DEBUG>(
-            fmt::format("Unable to get service name for path {}, interface {}",
-                        path, intf)
-                .c_str());
-        return;
+        service = getService(path, intf);
+        if (service.empty())
+        {
+            // Log service not found for object
+            log<level::DEBUG>(
+                fmt::format(
+                    "Unable to get service name for path {}, interface {}",
+                    path, intf)
+                    .c_str());
+            return;
+        }
+    }
+    else
+    {
+        // The service is known, so the service cache can be
+        // populated even if the path itself isn't present.
+        const auto& s = findService(path, intf);
+        if (s.empty())
+        {
+            addServices(intf, 0);
+        }
     }
 
     auto objMgrPaths = getPaths(service, "org.freedesktop.DBus.ObjectManager");
diff --git a/control/json/manager.hpp b/control/json/manager.hpp
index 0f9ff5f..8c2be03 100644
--- a/control/json/manager.hpp
+++ b/control/json/manager.hpp
@@ -353,7 +353,27 @@
      * when the `getManagedObjects` method call fails
      */
     void addObjects(const std::string& path, const std::string& intf,
-                    const std::string& prop);
+                    const std::string& prop)
+    {
+        addObjects(path, intf, prop, std::string{});
+    }
+
+    /**
+     * @copydoc Manager::addObjects()
+     *
+     * If the service is known, then it can be used to add all objects
+     * in that service with the interface passed in to the cache instead of
+     * having to look it up.  This is done so objects can still be
+     * added even when the D-Bus path passed in doesn't exist so it
+     * can't be used to get a service name.
+     *
+     * @param[in] path - Dbus object's path
+     * @param[in] intf - Dbus object's interface
+     * @param[in] prop - Dbus object's property
+     * @param[in] serviceName - The service of the path/intf/prop if known
+     */
+    void addObjects(const std::string& path, const std::string& intf,
+                    const std::string& prop, const std::string& serviceName);
 
     /**
      * @brief Get an object's property value
diff --git a/control/json/triggers/init.cpp b/control/json/triggers/init.cpp
index 7c4af4e..a998e4d 100644
--- a/control/json/triggers/init.cpp
+++ b/control/json/triggers/init.cpp
@@ -52,7 +52,7 @@
             {
                 // Property not in cache, attempt to add it
                 mgr->addObjects(member, group.getInterface(),
-                                group.getProperty());
+                                group.getProperty(), group.getService());
 
                 // If the service was predefined for the group, then we know
                 // all members are in the same service so the above addObjects