Update LazyServiceRegistrar for tryUnregister.

This now successfully dissassociates. After b/111320612 it might make
sense to unregister all things at once (rather than unregister and
re-register).

Bug: 123318663
Test: drm tests w/ lazy drm
Change-Id: I853fd197d4da8cc9811e997282cedb8f9cb82365
diff --git a/transport/HidlLazyUtils.cpp b/transport/HidlLazyUtils.cpp
index 429ab8b..ed40416 100644
--- a/transport/HidlLazyUtils.cpp
+++ b/transport/HidlLazyUtils.cpp
@@ -26,26 +26,42 @@
 namespace hardware {
 namespace details {
 
+using ::android::hidl::base::V1_0::IBase;
+
 class ClientCounterCallback : public ::android::hidl::manager::V1_2::IClientCallback {
    public:
-    ClientCounterCallback() : mNumConnectedServices(0), mNumRegisteredServices(0) {}
+    ClientCounterCallback() : mNumConnectedServices(0) {}
 
-    void incServiceCounter();
+    bool addRegisteredService(const sp<IBase>& service, const std::string& name);
 
    protected:
-    Return<void> onClients(const sp<::android::hidl::base::V1_0::IBase>& service,
-                           bool clients) override;
+    Return<void> onClients(const sp<IBase>& service, bool clients) override;
 
    private:
     /**
+     * Registers or re-registers services. Returns whether successful.
+     */
+    bool registerService(const sp<IBase>& service, const std::string& name);
+
+    /**
+     * Unregisters all services that we can. If we can't unregister all, re-register other
+     * services.
+     */
+    void tryShutdown();
+
+    /**
      * Counter of the number of services that currently have at least one client.
      */
     size_t mNumConnectedServices;
 
+    struct Service {
+        sp<IBase> service;
+        std::string name;
+    };
     /**
      * Number of services that have been registered.
      */
-    size_t mNumRegisteredServices;
+    std::vector<Service> mRegisteredServices;
 };
 
 class LazyServiceRegistrarImpl {
@@ -59,8 +75,37 @@
     sp<ClientCounterCallback> mClientCallback;
 };
 
-void ClientCounterCallback::incServiceCounter() {
-    mNumRegisteredServices++;
+bool ClientCounterCallback::addRegisteredService(const sp<IBase>& service,
+                                                 const std::string& name) {
+    bool success = registerService(service, name);
+
+    if (success) {
+        mRegisteredServices.push_back({service, name});
+    }
+
+    return success;
+}
+
+bool ClientCounterCallback::registerService(const sp<IBase>& service, const std::string& name) {
+    auto manager = hardware::defaultServiceManager1_2();
+
+    const std::string descriptor = getDescriptor(service.get());
+
+    LOG(INFO) << "Registering HAL: " << descriptor << " with name: " << name;
+
+    status_t res = android::hardware::details::registerAsServiceInternal(service, name);
+    if (res != android::OK) {
+        LOG(ERROR) << "Failed to register as service.";
+        return false;
+    }
+
+    bool ret = manager->registerClientCallback(getDescriptor(service.get()), name, service, this);
+    if (!ret) {
+        LOG(ERROR) << "Failed to add client callback.";
+        return false;
+    }
+
+    return true;
 }
 
 /**
@@ -70,39 +115,65 @@
 Return<void> ClientCounterCallback::onClients(const sp<::android::hidl::base::V1_0::IBase>& service,
                                               bool clients) {
     if (clients) {
-        LOG(INFO) << "HAL " << getDescriptor(service.get()) << " connected.";
         mNumConnectedServices++;
     } else {
-        LOG(INFO) << "HAL " << getDescriptor(service.get()) << " disconnected.";
         mNumConnectedServices--;
     }
-    LOG(INFO) << "HAL has " << mNumConnectedServices << " (of " << mNumRegisteredServices
-              << " available) clients in use.";
+
+    LOG(INFO) << "Process has " << mNumConnectedServices << " (of " << mRegisteredServices.size()
+              << " available) clients in use after notification " << getDescriptor(service.get())
+              << " has clients: " << clients;
 
     if (mNumConnectedServices == 0) {
-        LOG(INFO) << "Exiting HAL. No clients in use for any service in process.";
+        tryShutdown();
+    }
+
+    return Status::ok();
+}
+
+void ClientCounterCallback::tryShutdown() {
+    LOG(INFO) << "Trying to exit HAL. No clients in use for any service in process.";
+
+    auto manager = hardware::defaultServiceManager1_2();
+
+    auto unRegisterIt = mRegisteredServices.begin();
+    for (; unRegisterIt != mRegisteredServices.end(); ++unRegisterIt) {
+        auto& entry = (*unRegisterIt);
+
+        const std::string descriptor = getDescriptor(entry.service.get());
+        bool success = manager->tryUnregister(descriptor, entry.name, entry.service);
+
+        if (!success) {
+            LOG(INFO) << "Failed to unregister HAL " << descriptor << "/" << entry.name
+                      << ". Going to re-register remaining instances.";
+            break;
+        }
+    }
+
+    if (unRegisterIt == mRegisteredServices.end()) {
+        LOG(INFO) << "Unregistered all clients and exiting";
         exit(EXIT_SUCCESS);
     }
-    return Status::ok();
+
+    for (auto reRegisterIt = mRegisteredServices.begin(); reRegisterIt != unRegisterIt;
+         reRegisterIt++) {
+        auto& entry = (*reRegisterIt);
+
+        // re-register entry
+        if (!registerService(entry.service, entry.name)) {
+            // Must restart. Otherwise, clients will never be able to get ahold of this service.
+            LOG(FATAL) << "Bad state: could not re-register " << getDescriptor(entry.service.get());
+        }
+    }
 }
 
 status_t LazyServiceRegistrarImpl::registerService(
     const sp<::android::hidl::base::V1_0::IBase>& service, const std::string& name) {
-    static auto manager = hardware::defaultServiceManager1_2();
-    LOG(INFO) << "Registering HAL: " << getDescriptor(service.get()) << " with name: " << name;
-    status_t res = android::hardware::details::registerAsServiceInternal(service, name);
-    if (res == android::OK) {
-        mClientCallback->incServiceCounter();
-        bool ret = manager->registerClientCallback(getDescriptor(service.get()), name, service,
-                                                   mClientCallback);
-        if (!ret) {
-            res = android::INVALID_OPERATION;
-            LOG(ERROR) << "Failed to add client callback";
-        }
-    } else {
-        LOG(ERROR) << "Failed to register as service";
+    if (!mClientCallback->addRegisteredService(service, name)) {
+        return ::android::UNKNOWN_ERROR;
     }
-    return res;
+
+    return ::android::OK;
 }
 
 }  // namespace details