Implement addWithChain.
am: 707f22c374

Change-Id: Ic454bfc085ff5f57251edcd86d5239a2cdf33389
diff --git a/ServiceManager.cpp b/ServiceManager.cpp
index cbae635..fcf07be 100644
--- a/ServiceManager.cpp
+++ b/ServiceManager.cpp
@@ -244,81 +244,88 @@
 }
 
 Return<bool> ServiceManager::add(const hidl_string& name, const sp<IBase>& service) {
-    bool isValidService = false;
+    bool addSuccess = false;
 
     if (service == nullptr) {
         return false;
     }
 
-    // TODO(b/34235311): use HIDL way to determine this
-    // also, this assumes that the PID that is registering is the pid that is the service
     pid_t pid = IPCThreadState::self()->getCallingPid();
     auto context = mAcl.getContext(pid);
 
     auto ret = service->interfaceChain([&](const auto &interfaceChain) {
-        if (interfaceChain.size() == 0) {
-            return;
-        }
-
-        // First, verify you're allowed to add() the whole interface hierarchy
-        for(size_t i = 0; i < interfaceChain.size(); i++) {
-            const std::string fqName = interfaceChain[i];
-
-            if (!mAcl.canAdd(fqName, context, pid)) {
-                return;
-            }
-        }
-
-        {
-            // For IBar extends IFoo if IFoo/default is being registered, remove
-            // IBar/default. This makes sure the following two things are equivalent
-            // 1). IBar::castFrom(IFoo::getService(X))
-            // 2). IBar::getService(X)
-            // assuming that IBar is declared in the device manifest and there
-            // is also not an IBaz extends IFoo.
-            const std::string childFqName = interfaceChain[0];
-            const PackageInterfaceMap &ifaceMap = mServiceMap[childFqName];
-            const HidlService *hidlService = ifaceMap.lookup(name);
-            if (hidlService != nullptr) {
-                const sp<IBase> remove = hidlService->getService();
-
-                if (remove != nullptr) {
-                    const std::string instanceName = name;
-                    removeService(remove, &instanceName /* restrictToInstanceName */);
-                }
-            }
-        }
-
-        for(size_t i = 0; i < interfaceChain.size(); i++) {
-            const std::string fqName = interfaceChain[i];
-
-            PackageInterfaceMap &ifaceMap = mServiceMap[fqName];
-            HidlService *hidlService = ifaceMap.lookup(name);
-
-            if (hidlService == nullptr) {
-                ifaceMap.insertService(
-                    std::make_unique<HidlService>(fqName, name, service, pid));
-            } else {
-                hidlService->setService(service, pid);
-            }
-
-            ifaceMap.sendPackageRegistrationNotification(fqName, name);
-        }
-
-        bool linkRet = service->linkToDeath(this, kServiceDiedCookie).withDefault(false);
-        if (!linkRet) {
-            LOG(ERROR) << "Could not link to death for " << interfaceChain[0] << "/" << name;
-        }
-
-        isValidService = true;
+        addSuccess = addImpl(name, service, interfaceChain, context, pid);
     });
 
     if (!ret.isOk()) {
-        LOG(ERROR) << "Failed to retrieve interface chain.";
+        LOG(ERROR) << "Failed to retrieve interface chain: " << ret.description();
         return false;
     }
 
-    return isValidService;
+    return addSuccess;
+}
+
+bool ServiceManager::addImpl(const hidl_string& name,
+                             const sp<IBase>& service,
+                             const hidl_vec<hidl_string>& interfaceChain,
+                             const AccessControl::Context &context,
+                             pid_t pid) {
+    if (interfaceChain.size() == 0) {
+        LOG(WARNING) << "Empty interface chain for " << name;
+        return false;
+    }
+
+    // First, verify you're allowed to add() the whole interface hierarchy
+    for(size_t i = 0; i < interfaceChain.size(); i++) {
+        const std::string fqName = interfaceChain[i];
+
+        if (!mAcl.canAdd(fqName, context, pid)) {
+            return false;
+        }
+    }
+
+    {
+        // For IBar extends IFoo if IFoo/default is being registered, remove
+        // IBar/default. This makes sure the following two things are equivalent
+        // 1). IBar::castFrom(IFoo::getService(X))
+        // 2). IBar::getService(X)
+        // assuming that IBar is declared in the device manifest and there
+        // is also not an IBaz extends IFoo.
+        const std::string childFqName = interfaceChain[0];
+        const PackageInterfaceMap &ifaceMap = mServiceMap[childFqName];
+        const HidlService *hidlService = ifaceMap.lookup(name);
+        if (hidlService != nullptr) {
+            const sp<IBase> remove = hidlService->getService();
+
+            if (remove != nullptr) {
+                const std::string instanceName = name;
+                removeService(remove, &instanceName /* restrictToInstanceName */);
+            }
+        }
+    }
+
+    for(size_t i = 0; i < interfaceChain.size(); i++) {
+        const std::string fqName = interfaceChain[i];
+
+        PackageInterfaceMap &ifaceMap = mServiceMap[fqName];
+        HidlService *hidlService = ifaceMap.lookup(name);
+
+        if (hidlService == nullptr) {
+            ifaceMap.insertService(
+                std::make_unique<HidlService>(fqName, name, service, pid));
+        } else {
+            hidlService->setService(service, pid);
+        }
+
+        ifaceMap.sendPackageRegistrationNotification(fqName, name);
+    }
+
+    bool linkRet = service->linkToDeath(this, kServiceDiedCookie).withDefault(false);
+    if (!linkRet) {
+        LOG(ERROR) << "Could not link to death for " << interfaceChain[0] << "/" << name;
+    }
+
+    return true;
 }
 
 Return<ServiceManager::Transport> ServiceManager::getTransport(const hidl_string& fqName,
@@ -541,6 +548,19 @@
     });
 }
 
+Return<bool> ServiceManager::addWithChain(const hidl_string& name,
+                                          const sp<IBase>& service,
+                                          const hidl_vec<hidl_string>& chain) {
+    if (service == nullptr) {
+        return false;
+    }
+
+    pid_t pid = IPCThreadState::self()->getCallingPid();
+    auto context = mAcl.getContext(pid);
+
+    return addImpl(name, service, chain, context, pid);
+}
+
 Return<void> ServiceManager::debugDump(debugDump_cb _cb) {
     pid_t pid = IPCThreadState::self()->getCallingPid();
     if (!mAcl.canList(pid)) {
diff --git a/ServiceManager.h b/ServiceManager.h
index 361cfd4..44936d5 100644
--- a/ServiceManager.h
+++ b/ServiceManager.h
@@ -57,11 +57,20 @@
                                         const sp<IClientCallback>& cb) override;
     Return<bool> unregisterClientCallback(const sp<IBase>& server,
                                           const sp<IClientCallback>& cb) override;
+    Return<bool> addWithChain(const hidl_string& name,
+                              const sp<IBase>& service,
+                              const hidl_vec<hidl_string>& chain) override;
 
     void handleClientCallbacks();
 
     virtual void serviceDied(uint64_t cookie, const wp<IBase>& who);
 private:
+    bool addImpl(const hidl_string& name,
+                 const sp<IBase>& service,
+                 const hidl_vec<hidl_string>& interfaceChain,
+                 const AccessControl::Context &context,
+                 pid_t pid);
+
     // if restrictToInstanceName is nullptr, remove all, otherwise only those services
     // which match this instance name. Returns whether all instances were removed.
     bool removeService(const wp<IBase>& who, const std::string* restrictToInstanceName);