Update for IClientCallback
am: d8536200ab

Change-Id: I4ebf2a5566b2f8af4d7eca41dbe7917f33cb7c18
diff --git a/HidlService.cpp b/HidlService.cpp
index a0f2cab..d3698a6 100644
--- a/HidlService.cpp
+++ b/HidlService.cpp
@@ -3,8 +3,11 @@
 
 #include <android-base/logging.h>
 #include <hidl/HidlTransportSupport.h>
+#include <hwbinder/BpHwBinder.h>
 #include <sstream>
 
+using ::android::hardware::interfacesEqual;
+
 namespace android {
 namespace hidl {
 namespace manager {
@@ -28,6 +31,8 @@
     mService = service;
     mPid = pid;
 
+    mClientCallbacks.clear();
+
     sendRegistrationNotifications();
 }
 
@@ -56,8 +61,6 @@
 }
 
 bool HidlService::removeListener(const wp<IBase>& listener) {
-    using ::android::hardware::interfacesEqual;
-
     bool found = false;
 
     for (auto it = mListeners.begin(); it != mListeners.end();) {
@@ -80,6 +83,61 @@
     return mPassthroughClients;
 }
 
+void HidlService::addClientCallback(const sp<IClientCallback>& callback) {
+    mClientCallbacks.push_back(callback);
+}
+
+bool HidlService::removeClientCallback(const sp<IClientCallback>& callback) {
+    bool found = false;
+
+    for (auto it = mClientCallbacks.begin(); it != mClientCallbacks.end();) {
+        if (interfacesEqual(*it, callback)) {
+            it = mClientCallbacks.erase(it);
+            found = true;
+        } else {
+            ++it;
+        }
+    }
+
+    return found;
+}
+
+void HidlService::handleClientCallbacks() {
+    using ::android::hardware::toBinder;
+    using ::android::hardware::BpHwBinder;
+    using ::android::hardware::IBinder;
+
+    if (mClientCallbacks.empty()) return;
+    if (mService == nullptr) return;
+
+    // this justifies the bp cast below, no in-process HALs need this
+    if (!mService->isRemote()) return;
+
+    sp<IBinder> binder = toBinder(mService);
+    if (binder == nullptr) return;
+
+    sp<BpHwBinder> bpBinder = static_cast<BpHwBinder*>(binder.get());
+    ssize_t count = bpBinder->getNodeStrongRefCount();
+
+    // binder driver doesn't support this feature
+    if (count == -1) return;
+
+    bool hasClients = count > 1; // this process holds a strong count
+
+    // going from having clients to not having clients
+    if (!hasClients && mHasClients) {
+        LOG(INFO) << "Notifying " << string() << " they have no clients.";
+
+        for (const auto& cb : mClientCallbacks) {
+            if (!cb->onNoClients(getService()).isOk()) {
+                LOG(WARNING) << "No-clients callback failed for " << string();
+            }
+        }
+    }
+
+    mHasClients = hasClients;
+}
+
 std::string HidlService::string() const {
     std::stringstream ss;
     ss << mInterfaceName << "/" << mInstanceName;
diff --git a/HidlService.h b/HidlService.h
index 2fcb0d6..96a8aa9 100644
--- a/HidlService.h
+++ b/HidlService.h
@@ -3,7 +3,7 @@
 
 #include <set>
 
-#include <android/hidl/manager/1.1/IServiceManager.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
 #include <hidl/Status.h>
 #include <hidl/MQDescriptor.h>
 
@@ -19,6 +19,7 @@
 using ::android::hidl::base::V1_0::IBase;
 using ::android::hidl::manager::V1_0::IServiceNotification;
 using ::android::hidl::manager::V1_1::IServiceManager;
+using ::android::hidl::manager::V1_2::IClientCallback;
 using ::android::sp;
 
 struct HidlService {
@@ -49,6 +50,10 @@
     bool removeListener(const wp<IBase> &listener);
     void registerPassthroughClient(pid_t pid);
 
+    void addClientCallback(const sp<IClientCallback>& callback);
+    bool removeClientCallback(const sp<IClientCallback>& callback);
+    void handleClientCallbacks();
+
     std::string string() const; // e.x. "android.hidl.manager@1.0::IServiceManager/manager"
     const std::set<pid_t> &getPassthroughClients() const;
 
@@ -62,6 +67,9 @@
     std::vector<sp<IServiceNotification>> mListeners{};
     std::set<pid_t>                       mPassthroughClients{};
     pid_t                                 mPid = static_cast<pid_t>(IServiceManager::PidConstant::NO_PID);
+
+    std::vector<sp<IClientCallback>>      mClientCallbacks{};
+    bool                                  mHasClients = false; // notifications sent on true -> false.
 };
 
 }  // namespace implementation
diff --git a/ServiceManager.cpp b/ServiceManager.cpp
index a858f7f..cbae635 100644
--- a/ServiceManager.cpp
+++ b/ServiceManager.cpp
@@ -13,6 +13,7 @@
 #include <thread>
 
 using android::hardware::IPCThreadState;
+using ::android::hardware::interfacesEqual;
 
 namespace android {
 namespace hidl {
@@ -22,30 +23,55 @@
 static constexpr uint64_t kServiceDiedCookie = 0;
 static constexpr uint64_t kPackageListenerDiedCookie = 1;
 static constexpr uint64_t kServiceListenerDiedCookie = 2;
+static constexpr uint64_t kClientCallbackDiedCookie = 3;
 
 size_t ServiceManager::countExistingService() const {
     size_t total = 0;
     forEachExistingService([&] (const HidlService *) {
         ++total;
+        return true;  // continue
     });
     return total;
 }
 
-void ServiceManager::forEachExistingService(std::function<void(const HidlService *)> f) const {
-    forEachServiceEntry([f] (const HidlService *service) {
+void ServiceManager::forEachExistingService(std::function<bool(const HidlService *)> f) const {
+    forEachServiceEntry([&] (const HidlService *service) {
         if (service->getService() == nullptr) {
-            return;
+            return true;  // continue
         }
-        f(service);
+        return f(service);
     });
 }
 
-void ServiceManager::forEachServiceEntry(std::function<void(const HidlService *)> f) const {
-    for (const auto &interfaceMapping : mServiceMap) {
-        const auto &instanceMap = interfaceMapping.second.getInstanceMap();
+void ServiceManager::forEachExistingService(std::function<bool(HidlService *)> f) {
+    forEachServiceEntry([&] (HidlService *service) {
+        if (service->getService() == nullptr) {
+            return true;  // continue
+        }
+        return f(service);
+    });
+}
 
-        for (const auto &instanceMapping : instanceMap) {
-            f(instanceMapping.second.get());
+void ServiceManager::forEachServiceEntry(std::function<bool(const HidlService *)> f) const {
+    for (const auto& interfaceMapping : mServiceMap) {
+        const auto& instanceMap = interfaceMapping.second.getInstanceMap();
+
+        for (const auto& instanceMapping : instanceMap) {
+            if (!f(instanceMapping.second.get())) {
+                return;
+            }
+        }
+    }
+}
+
+void ServiceManager::forEachServiceEntry(std::function<bool(HidlService *)> f) {
+    for (auto& interfaceMapping : mServiceMap) {
+        auto& instanceMap = interfaceMapping.second.getInstanceMap();
+
+        for (auto& instanceMapping : instanceMap) {
+            if (!f(instanceMapping.second.get())) {
+                return;
+            }
         }
     }
 }
@@ -62,11 +88,17 @@
         case kServiceListenerDiedCookie:
             serviceRemoved = removeServiceListener(who);
             break;
+        case kClientCallbackDiedCookie: {
+            sp<IBase> base = who.promote();
+            IClientCallback* callback = static_cast<IClientCallback*>(base.get());
+            serviceRemoved = unregisterClientCallback(nullptr /*service*/,
+                                                      sp<IClientCallback>(callback));
+        } break;
     }
 
     if (!serviceRemoved) {
-        LOG(ERROR) << "Received death notification but serivce not removed. Cookie: " << cookie
-                   << " Service pointer: " << who.promote().get();
+        LOG(ERROR) << "Received death notification but interface instance not removed. Cookie: "
+                   << cookie << " Service pointer: " << who.promote().get();
     }
 }
 
@@ -140,8 +172,6 @@
 }
 
 bool ServiceManager::PackageInterfaceMap::removePackageListener(const wp<IBase>& who) {
-    using ::android::hardware::interfacesEqual;
-
     bool found = false;
 
     for (auto it = mPackageListeners.begin(); it != mPackageListeners.end();) {
@@ -157,8 +187,6 @@
 }
 
 bool ServiceManager::PackageInterfaceMap::removeServiceListener(const wp<IBase>& who) {
-    using ::android::hardware::interfacesEqual;
-
     bool found = false;
 
     for (auto &servicePair : getInstanceMap()) {
@@ -327,6 +355,7 @@
     size_t idx = 0;
     forEachExistingService([&] (const HidlService *service) {
         list[idx++] = service->string();
+        return true;  // continue
     });
 
     _hidl_cb(list);
@@ -451,6 +480,67 @@
     return service->removeListener(callback);
 }
 
+Return<bool> ServiceManager::registerClientCallback(const sp<IBase>& server,
+                                                    const sp<IClientCallback>& cb) {
+    if (server == nullptr || cb == nullptr) return false;
+
+    // only the server of the interface can register a client callback
+    pid_t pid = IPCThreadState::self()->getCallingPid();
+
+    HidlService* registered = nullptr;
+
+    forEachExistingService([&] (HidlService *service) {
+        if (service->getPid() != pid) {
+            return true;  // continue
+        }
+
+        if (interfacesEqual(service->getService(), server)) {
+            service->addClientCallback(cb);
+            registered = service;
+            return false;  // break
+        }
+        return true;  // continue
+    });
+
+    if (registered != nullptr) {
+        bool linkRet = cb->linkToDeath(this, kClientCallbackDiedCookie).withDefault(false);
+        if (!linkRet) {
+            LOG(ERROR) << "Could not link to death for registerClientCallback";
+            unregisterClientCallback(server, cb);
+            registered = nullptr;
+        }
+    }
+
+    if (registered != nullptr) {
+        registered->handleClientCallbacks();
+    }
+
+    return registered != nullptr;
+}
+
+Return<bool> ServiceManager::unregisterClientCallback(const sp<IBase>& server,
+                                                      const sp<IClientCallback>& cb) {
+    if (cb == nullptr) return false;
+
+    bool removed = false;
+
+    forEachExistingService([&] (HidlService *service) {
+        if (server == nullptr || interfacesEqual(service->getService(), server)) {
+            removed |= service->removeClientCallback(cb);
+        }
+        return true;  // continue
+    });
+
+    return removed;
+}
+
+void ServiceManager::handleClientCallbacks() {
+    forEachServiceEntry([&] (HidlService *service) {
+        service->handleClientCallbacks();
+        return true;  // continue
+    });
+}
+
 Return<void> ServiceManager::debugDump(debugDump_cb _cb) {
     pid_t pid = IPCThreadState::self()->getCallingPid();
     if (!mAcl.canList(pid)) {
@@ -475,6 +565,8 @@
             .clientPids = clientPids,
             .arch = ::android::hidl::base::V1_0::DebugInfo::Architecture::UNKNOWN
         });
+
+        return true;  // continue
     });
 
     _cb(list);
@@ -514,8 +606,6 @@
 }
 
 bool ServiceManager::removeService(const wp<IBase>& who, const std::string* restrictToInstanceName) {
-    using ::android::hardware::interfacesEqual;
-
     bool keepInstance = false;
     bool removed = false;
     for (auto &interfaceMapping : mServiceMap) {
diff --git a/ServiceManager.h b/ServiceManager.h
index 0007de9..361cfd4 100644
--- a/ServiceManager.h
+++ b/ServiceManager.h
@@ -21,6 +21,7 @@
 using ::android::hardware::Void;
 using ::android::hidl::base::V1_0::IBase;
 using ::android::hidl::manager::V1_0::IServiceNotification;
+using ::android::hidl::manager::V1_2::IClientCallback;
 using ::android::sp;
 using ::android::wp;
 
@@ -51,6 +52,14 @@
                                             const hidl_string& name,
                                             const sp<IServiceNotification>& callback) override;
 
+    // Methods from ::android::hidl::manager::V1_2::IServiceManager follow.
+    Return<bool> registerClientCallback(const sp<IBase>& server,
+                                        const sp<IClientCallback>& cb) override;
+    Return<bool> unregisterClientCallback(const sp<IBase>& server,
+                                          const sp<IClientCallback>& cb) override;
+
+    void handleClientCallbacks();
+
     virtual void serviceDied(uint64_t cookie, const wp<IBase>& who);
 private:
     // if restrictToInstanceName is nullptr, remove all, otherwise only those services
@@ -59,8 +68,12 @@
     bool removePackageListener(const wp<IBase>& who);
     bool removeServiceListener(const wp<IBase>& who);
     size_t countExistingService() const;
-    void forEachExistingService(std::function<void(const HidlService *)> f) const;
-    void forEachServiceEntry(std::function<void(const HidlService *)> f) const;
+
+    // true = continue, false = break
+    void forEachExistingService(std::function<bool(const HidlService *)> f) const;
+    void forEachExistingService(std::function<bool(HidlService *)> f);
+    void forEachServiceEntry(std::function<bool(const HidlService *)> f) const;
+    void forEachServiceEntry(std::function<bool(HidlService *)> f);
 
     using InstanceMap = std::map<
             std::string, // instance name e.x. "manager"
diff --git a/service.cpp b/service.cpp
index 263f368..bfbcb69 100644
--- a/service.cpp
+++ b/service.cpp
@@ -4,6 +4,7 @@
 
 #include <inttypes.h>
 #include <unistd.h>
+#include <sys/timerfd.h>
 
 #include <android/hidl/manager/1.1/BnHwServiceManager.h>
 #include <android/hidl/token/1.0/ITokenManager.h>
@@ -33,7 +34,6 @@
 
 // hidl types
 using android::hidl::manager::V1_1::BnHwServiceManager;
-using android::hidl::token::V1_0::ITokenManager;
 
 // implementations
 using android::hidl::manager::implementation::ServiceManager;
@@ -69,15 +69,61 @@
     }
 };
 
-int main() {
-    ServiceManager *manager = new ServiceManager();
+// LooperCallback for IClientCallback
+class ClientCallbackCallback : public LooperCallback {
+public:
+    static sp<ClientCallbackCallback> setupTo(const sp<Looper>& looper, const sp<ServiceManager>& manager) {
+        sp<ClientCallbackCallback> cb = new ClientCallbackCallback(manager);
 
+        int fdTimer = timerfd_create(CLOCK_MONOTONIC, 0 /*flags*/);
+        LOG_ALWAYS_FATAL_IF(fdTimer < 0, "Failed to timerfd_create: fd: %d err: %d", fdTimer, errno);
+
+        itimerspec timespec {
+            .it_interval = {
+                .tv_sec = 5,
+                .tv_nsec = 0,
+            },
+            .it_value = {
+                .tv_sec = 5,
+                .tv_nsec = 0,
+            },
+        };
+
+        int timeRes = timerfd_settime(fdTimer, 0 /*flags*/, &timespec, nullptr);
+        LOG_ALWAYS_FATAL_IF(timeRes < 0, "Failed to timerfd_settime: res: %d err: %d", timeRes, errno);
+
+        int addRes = looper->addFd(fdTimer,
+                                   Looper::POLL_CALLBACK,
+                                   Looper::EVENT_INPUT,
+                                   cb,
+                                   nullptr);
+        LOG_ALWAYS_FATAL_IF(addRes != 1, "Failed to add client callback FD to Looper");
+
+        return cb;
+    }
+
+    int handleEvent(int fd, int /*events*/, void* /*data*/) override {
+        uint64_t expirations;
+        int ret = read(fd, &expirations, sizeof(expirations));
+        if (ret != sizeof(expirations)) {
+            ALOGE("Read failed to callback FD: ret: %d err: %d", ret, errno);
+        }
+
+        mManager->handleClientCallbacks();
+        return 1;  // Continue receiving callbacks.
+    }
+private:
+    ClientCallbackCallback(const sp<ServiceManager>& manager) : mManager(manager) {}
+    sp<ServiceManager> mManager;
+};
+
+int main() {
+    sp<ServiceManager> manager = new ServiceManager();
     if (!manager->add(serviceName, manager)) {
         ALOGE("Failed to register hwservicemanager with itself.");
     }
 
-    TokenManager *tokenManager = new TokenManager();
-
+    sp<TokenManager> tokenManager = new TokenManager();
     if (!manager->add(serviceName, tokenManager)) {
         ALOGE("Failed to register ITokenManager with hwservicemanager.");
     }
@@ -97,6 +143,7 @@
     sp<Looper> looper = Looper::prepare(0 /* opts */);
 
     (void)HwBinderCallback::setupTo(looper);
+    (void)ClientCallbackCallback::setupTo(looper, manager);
 
     ALOGI("hwservicemanager is ready now.");