DO NOT MERGE - Merge PPRL.190305.001 into master

Bug: 127812889
Change-Id: Ic7c1bcb7afbd1c076a06400e05fa6352372ef3e7
diff --git a/AccessControl.cpp b/AccessControl.cpp
index f47705d..c8366ca 100644
--- a/AccessControl.cpp
+++ b/AccessControl.cpp
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 #define LOG_TAG "hwservicemanager"
 
 #include <android-base/logging.h>
@@ -22,7 +38,7 @@
 
 AccessControl::AccessControl() {
     mSeHandle = selinux_android_hw_service_context_handle();
-    LOG_ALWAYS_FATAL_IF(mSeHandle == NULL, "Failed to acquire SELinux handle.");
+    LOG_ALWAYS_FATAL_IF(mSeHandle == nullptr, "Failed to acquire SELinux handle.");
 
     if (getcon(&mSeContext) != 0) {
         LOG_ALWAYS_FATAL("Failed to acquire hwservicemanager context.");
@@ -38,9 +54,9 @@
 }
 
 bool AccessControl::canAdd(const std::string& fqName, const CallingContext& callingContext) {
-    FQName fqIface(fqName);
+    FQName fqIface;
 
-    if (!fqIface.isValid()) {
+    if (!FQName::parse(fqName, &fqIface)) {
         return false;
     }
     const std::string checkName = fqIface.package() + "::" + fqIface.name();
@@ -49,9 +65,9 @@
 }
 
 bool AccessControl::canGet(const std::string& fqName, const CallingContext& callingContext) {
-    FQName fqIface(fqName);
+    FQName fqIface;
 
-    if (!fqIface.isValid()) {
+    if (!FQName::parse(fqName, &fqIface)) {
         return false;
     }
     const std::string checkName = fqIface.package() + "::" + fqIface.name();
diff --git a/AccessControl.h b/AccessControl.h
index 877df99..8d99a08 100644
--- a/AccessControl.h
+++ b/AccessControl.h
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 #include <string>
 
 #include <selinux/android.h>
diff --git a/Android.bp b/Android.bp
index f62c51c..831f721 100644
--- a/Android.bp
+++ b/Android.bp
@@ -12,36 +12,99 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-cc_binary {
-    name: "hwservicemanager",
-    init_rc: [
-        "hwservicemanager.rc",
-    ],
-    srcs: [
-        "AccessControl.cpp",
-        "HidlService.cpp",
-        "ServiceManager.cpp",
-        "service.cpp",
-        "TokenManager.cpp",
-        "Vintf.cpp",
-    ],
+cc_defaults {
+    name: "hwservicemanager_defaults",
     cflags: [
         "-Wall",
         "-Wextra",
         "-Werror",
     ],
     shared_libs: [
-        "android.hidl.token@1.0",
-        "libbase",
-        "libcrypto", // for TokenManager
-        "libcutils",
         "libhidlbase",
         "libhidltransport",
+        "liblog",
+    ],
+}
+
+cc_defaults {
+    name: "libhwservicemanager_shared_libs",
+    shared_libs: [
+        "libbase",
         "libhidl-gen-utils",
         "libhwbinder",
-        "liblog",
         "libselinux",
         "libutils",
         "libvintf",
     ],
 }
+
+cc_library_static {
+    name: "libhwservicemanager",
+    defaults: [
+        "hwservicemanager_defaults",
+        "libhwservicemanager_shared_libs",
+    ],
+    srcs: [
+        "AccessControl.cpp",
+        "HidlService.cpp",
+        "ServiceManager.cpp",
+        "Vintf.cpp",
+    ],
+}
+
+cc_defaults {
+    name: "libtokenmanager_shared_libs",
+    shared_libs: [
+        "android.hidl.token@1.0",
+        "libcrypto",
+    ],
+}
+
+cc_library_static {
+    name: "libtokenmanager",
+    defaults: [
+        "hwservicemanager_defaults",
+        "libtokenmanager_shared_libs",
+    ],
+    srcs: [
+        "TokenManager.cpp",
+    ],
+}
+
+cc_binary {
+    name: "hwservicemanager",
+    defaults: [
+        "hwservicemanager_defaults",
+        "libhwservicemanager_shared_libs",
+        "libtokenmanager_shared_libs",
+    ],
+    init_rc: [
+        "hwservicemanager.rc",
+    ],
+    srcs: [
+        "service.cpp",
+    ],
+    shared_libs: [
+        "libcutils",
+    ],
+    static_libs: [
+        "libhwservicemanager",
+        "libtokenmanager",
+    ],
+}
+
+cc_test {
+    name: "hwservicemanager_test",
+    defaults: [
+        "hwservicemanager_defaults",
+        "libhwservicemanager_shared_libs",
+    ],
+    static_libs: [
+        "libgmock",
+        "libhwservicemanager",
+    ],
+    srcs: [
+        "test_lazy.cpp",
+    ],
+    test_suites: ["device-tests"],
+}
diff --git a/HidlService.cpp b/HidlService.cpp
index dad7bac..6d8c4ff 100644
--- a/HidlService.cpp
+++ b/HidlService.cpp
@@ -1,15 +1,36 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 #define LOG_TAG "hwservicemanager"
 #include "HidlService.h"
 
 #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 {
 namespace implementation {
 
+static constexpr int kNoClientRepeatLimit = 2;
+
 HidlService::HidlService(
     const std::string &interfaceName,
     const std::string &instanceName,
@@ -28,6 +49,11 @@
     mService = service;
     mPid = pid;
 
+    mClientCallbacks.clear();
+    mHasClients = false;
+    mGuaranteeClient = false;
+    mNoClientsCounter = 0;
+
     sendRegistrationNotifications();
 }
 
@@ -56,8 +82,6 @@
 }
 
 bool HidlService::removeListener(const wp<IBase>& listener) {
-    using ::android::hardware::interfacesEqual;
-
     bool found = false;
 
     for (auto it = mListeners.begin(); it != mListeners.end();) {
@@ -80,12 +104,105 @@
     return mPassthroughClients;
 }
 
+void HidlService::addClientCallback(const sp<IClientCallback>& callback) {
+    if (mHasClients) {
+        // we have this kernel feature, so make sure we're in an updated state
+        forceHandleClientCallbacks(false /*onInterval*/);
+    }
+
+    if (mHasClients) {
+        // make sure this callback is in the same state as all of the rest
+        sendClientCallbackNotification(callback, true /*hasClients*/);
+    }
+
+    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;
+}
+
+ssize_t HidlService::handleClientCallbacks(bool isCalledOnInterval) {
+    if (!mClientCallbacks.empty()) {
+        return forceHandleClientCallbacks(isCalledOnInterval);
+    }
+
+    return -1;
+}
+
+ssize_t HidlService::forceHandleClientCallbacks(bool isCalledOnInterval) {
+    ssize_t count = getNodeStrongRefCount();
+
+    // binder driver doesn't support this feature
+    if (count == -1) return count;
+
+    bool hasClients = count > 1; // this process holds a strong count
+
+    if (mGuaranteeClient) {
+        // we have no record of this client
+        if (!mHasClients && !hasClients) {
+            sendClientCallbackNotifications(true);
+        }
+
+        // guarantee is temporary
+        mGuaranteeClient = false;
+    }
+
+    if (hasClients && !mHasClients) {
+        // client was retrieved in some other way
+        sendClientCallbackNotifications(true);
+    }
+
+    // there are no more clients, but the callback has not been called yet
+    if (!hasClients && mHasClients && isCalledOnInterval) {
+        mNoClientsCounter++;
+
+        if (mNoClientsCounter >= kNoClientRepeatLimit) {
+            sendClientCallbackNotifications(false);
+        }
+    }
+
+    return count;
+}
+
+void HidlService::guaranteeClient() {
+    mGuaranteeClient = true;
+}
+
 std::string HidlService::string() const {
     std::stringstream ss;
     ss << mInterfaceName << "/" << mInstanceName;
     return ss.str();
 }
 
+ssize_t HidlService::getNodeStrongRefCount() {
+    using ::android::hardware::toBinder;
+    using ::android::hardware::BpHwBinder;
+    using ::android::hardware::IBinder;
+
+    if (mService == nullptr) return -1;
+
+    // this justifies the bp cast below, no in-process HALs need this
+    if (!mService->isRemote()) return -1;
+
+    sp<IBinder> binder = toBinder(mService);
+    if (binder == nullptr) return -1;
+
+    sp<BpHwBinder> bpBinder = static_cast<BpHwBinder*>(binder.get());
+    return bpBinder->getNodeStrongRefCount();
+}
+
 void HidlService::sendRegistrationNotifications() {
     if (mListeners.size() == 0 || mService == nullptr) {
         return;
@@ -106,6 +223,28 @@
     }
 }
 
+void HidlService::sendClientCallbackNotifications(bool hasClients) {
+    CHECK(hasClients != mHasClients) << "Record shows: " << mHasClients
+        << " so we can't tell clients again that we have client: " << hasClients;
+
+    LOG(INFO) << "Notifying " << string() << " they have clients: " << hasClients;
+
+    for (const auto& cb : mClientCallbacks) {
+        sendClientCallbackNotification(cb, hasClients);
+    }
+
+    mNoClientsCounter = 0;
+    mHasClients = hasClients;
+}
+
+void HidlService::sendClientCallbackNotification(const sp<IClientCallback>& callback, bool hasClients) {
+    Return<void> ret = callback->onClients(getService(), hasClients);
+    if (!ret.isOk()) {
+        LOG(WARNING) << "onClients callback failed for " << string() << ": " << ret.description();
+    }
+}
+
+
 }  // namespace implementation
 }  // namespace manager
 }  // namespace hidl
diff --git a/HidlService.h b/HidlService.h
index 64fdabb..e2a6232 100644
--- a/HidlService.h
+++ b/HidlService.h
@@ -1,9 +1,25 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 #ifndef ANDROID_HARDWARE_MANAGER_HIDLSERVICE_H
 #define ANDROID_HARDWARE_MANAGER_HIDLSERVICE_H
 
 #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 +35,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 {
@@ -34,6 +51,7 @@
         nullptr,
         static_cast<pid_t>(IServiceManager::PidConstant::NO_PID))
     {}
+    virtual ~HidlService() {}
 
     /**
      * Note, getService() can be nullptr. This is because you can have a HidlService
@@ -49,12 +67,37 @@
     bool removeListener(const wp<IBase> &listener);
     void registerPassthroughClient(pid_t pid);
 
+    // also sends onClients(true) if we have clients
+    void addClientCallback(const sp<IClientCallback>& callback);
+    bool removeClientCallback(const sp<IClientCallback>& callback);
+
+    // return is number of clients (-1 means this is not implemented or we didn't check)
+    // count includes one held by hwservicemanager
+    ssize_t handleClientCallbacks(bool isCalledOnInterval);
+
+    // Updates client callbacks (even if mClientCallbacks is emtpy)
+    // see handleClientCallbacks
+    ssize_t forceHandleClientCallbacks(bool isCalledOnInterval);
+
+    // when giving out a handle to a client, but the kernel might not know this yet
+    void guaranteeClient();
+
     std::string string() const; // e.x. "android.hidl.manager@1.0::IServiceManager/manager"
     const std::set<pid_t> &getPassthroughClients() const;
 
+protected:
+    // mockable number of clients including hwservicemanager. -1 if not implemented or unavailable.
+    virtual ssize_t getNodeStrongRefCount();
+
 private:
     void sendRegistrationNotifications();
 
+    // Also updates mHasClients (of what the last callback was)
+    void sendClientCallbackNotifications(bool hasClients);
+
+    // Only sends notification
+    void sendClientCallbackNotification(const sp<IClientCallback>& callback, bool hasClients);
+
     const std::string                     mInterfaceName; // e.x. "android.hidl.manager@1.0::IServiceManager"
     const std::string                     mInstanceName;  // e.x. "manager"
     sp<IBase>                             mService;
@@ -62,6 +105,11 @@
     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.
+    bool                                  mGuaranteeClient = false; // whenever a client is handed out
+    size_t                                mNoClientsCounter = 0;
 };
 
 }  // namespace implementation
diff --git a/ServiceManager.cpp b/ServiceManager.cpp
index 01ccd88..f76afcd 100644
--- a/ServiceManager.cpp
+++ b/ServiceManager.cpp
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 #define LOG_TAG "hwservicemanager"
 
 #include "ServiceManager.h"
@@ -13,6 +29,7 @@
 #include <thread>
 
 using android::hardware::IPCThreadState;
+using ::android::hardware::interfacesEqual;
 
 namespace android {
 namespace hidl {
@@ -39,45 +56,95 @@
 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;
+            }
+        }
+    }
+}
+
+HidlService* ServiceManager::lookup(const std::string& fqName, const std::string& name) {
+    auto ifaceIt = mServiceMap.find(fqName);
+    if (ifaceIt == mServiceMap.end()) {
+        return nullptr;
+    }
+
+    PackageInterfaceMap &ifaceMap = ifaceIt->second;
+
+    HidlService *hidlService = ifaceMap.lookup(name);
+
+    return hidlService;
+}
+
 void ServiceManager::serviceDied(uint64_t cookie, const wp<IBase>& who) {
+    bool serviceRemoved = false;
     switch (cookie) {
         case kServiceDiedCookie:
-            removeService(who, nullptr /* restrictToInstanceName */);
+            serviceRemoved = removeService(who, nullptr /* restrictToInstanceName */);
             break;
         case kPackageListenerDiedCookie:
-            removePackageListener(who);
+            serviceRemoved = removePackageListener(who);
             break;
         case kServiceListenerDiedCookie:
-            removeServiceListener(who);
+            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 interface instance not removed. Cookie: "
+                   << cookie << " Service pointer: " << who.promote().get();
     }
 }
 
@@ -151,8 +218,6 @@
 }
 
 bool ServiceManager::PackageInterfaceMap::removePackageListener(const wp<IBase>& who) {
-    using ::android::hardware::interfacesEqual;
-
     bool found = false;
 
     for (auto it = mPackageListeners.begin(); it != mPackageListeners.end();) {
@@ -168,8 +233,6 @@
 }
 
 bool ServiceManager::PackageInterfaceMap::removeServiceListener(const wp<IBase>& who) {
-    using ::android::hardware::interfacesEqual;
-
     bool found = false;
 
     for (auto &servicePair : getInstanceMap()) {
@@ -202,102 +265,115 @@
         return nullptr;
     }
 
-    auto ifaceIt = mServiceMap.find(fqName);
-    if (ifaceIt == mServiceMap.end()) {
-        tryStartService(fqName, hidlName);
-        return nullptr;
-    }
-
-    const PackageInterfaceMap &ifaceMap = ifaceIt->second;
-    const HidlService *hidlService = ifaceMap.lookup(name);
-
+    HidlService* hidlService = lookup(fqName, name);
     if (hidlService == nullptr) {
-        tryStartService(fqName, hidlName);
+        tryStartService(fqName, name);
         return nullptr;
     }
 
     sp<IBase> service = hidlService->getService();
     if (service == nullptr) {
-        tryStartService(fqName, hidlName);
+        tryStartService(fqName, name);
         return nullptr;
     }
 
+    // Let HidlService know that we handed out a client. If the client drops the service before the
+    // next time handleClientCallbacks is called, it will still know that the service had been handed out.
+    hidlService->guaranteeClient();
+
+    // This is executed immediately after the binder driver confirms the transaction. The driver
+    // will update the appropriate data structures to reflect the fact that the client now has the
+    // service this function is returning. Nothing else can update the HidlService at the same
+    // time. This will run before anything else can modify the HidlService which is owned by this
+    // object, so it will be in the same state that it was when this function returns.
+    hardware::addPostCommandTask([hidlService] {
+        hidlService->handleClientCallbacks(false /* isCalledOnInterval */);
+    });
+
     return service;
 }
 
 Return<bool> ServiceManager::add(const hidl_string& name, const sp<IBase>& service) {
-    bool isValidService = false;
+    bool addSuccess = false;
 
     if (service == nullptr) {
         return false;
     }
 
-    auto callingContext = getBinderCallingContext();
+    auto pidcon = getBinderCallingContext();
 
     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, callingContext)) {
-                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, callingContext.pid));
-            } else {
-                hidlService->setService(service, callingContext.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, pidcon);
     });
 
     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::CallingContext& callingContext) {
+    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, callingContext)) {
+            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, callingContext.pid));
+        } else {
+            hidlService->setService(service, callingContext.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,
@@ -332,6 +408,7 @@
     size_t idx = 0;
     forEachExistingService([&] (const HidlService *service) {
         list[idx++] = service->string();
+        return true;  // continue
     });
 
     _hidl_cb(list);
@@ -390,8 +467,8 @@
     PackageInterfaceMap &ifaceMap = mServiceMap[fqName];
 
     if (name.empty()) {
-        auto ret = callback->linkToDeath(this, kPackageListenerDiedCookie);
-        if (!ret.isOk()) {
+        bool ret = callback->linkToDeath(this, kPackageListenerDiedCookie).withDefault(false);
+        if (!ret) {
             LOG(ERROR) << "Failed to register death recipient for " << fqName << "/" << name;
             return false;
         }
@@ -401,8 +478,8 @@
 
     HidlService *service = ifaceMap.lookup(name);
 
-    auto ret = callback->linkToDeath(this, kServiceListenerDiedCookie);
-    if (!ret.isOk()) {
+    bool ret = callback->linkToDeath(this, kServiceListenerDiedCookie).withDefault(false);
+    if (!ret) {
         LOG(ERROR) << "Failed to register death recipient for " << fqName << "/" << name;
         return false;
     }
@@ -454,6 +531,159 @@
     return service->removeListener(callback);
 }
 
+Return<bool> ServiceManager::registerClientCallback(const hidl_string& hidlFqName,
+                                                    const hidl_string& hidlName,
+                                                    const sp<IBase>& server,
+                                                    const sp<IClientCallback>& cb) {
+    if (server == nullptr || cb == nullptr) return false;
+
+    const std::string fqName = hidlFqName;
+    const std::string name = hidlName;
+
+    // only the server of the interface can register a client callback
+    pid_t pid = IPCThreadState::self()->getCallingPid();
+    if (!mAcl.canAdd(fqName, getBinderCallingContext())) {
+        return false;
+    }
+
+    HidlService* registered = lookup(fqName, name);
+
+    if (registered == nullptr) {
+        return false;
+    }
+
+    // sanity
+    if (registered->getDebugPid() != pid) {
+        LOG(WARNING) << "Only a server can register for client callbacks (for " << fqName
+            << "/" << name << ")";
+        return false;
+    }
+
+    sp<IBase> service = registered->getService();
+
+    if (!interfacesEqual(service, server)) {
+        LOG(WARNING) << "Tried to register client callback for " << fqName << "/" << name
+            << " but a different service is registered under this name.";
+        return false;
+    }
+
+    bool linkRet = cb->linkToDeath(this, kClientCallbackDiedCookie).withDefault(false);
+    if (!linkRet) {
+        LOG(ERROR) << "Could not link to death for registerClientCallback";
+        return false;
+    }
+
+    registered->addClientCallback(cb);
+
+    return true;
+}
+
+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(true /* isCalledOnInterval */);
+        return true;  // continue
+    });
+}
+
+Return<bool> ServiceManager::addWithChain(const hidl_string& name,
+                                          const sp<IBase>& service,
+                                          const hidl_vec<hidl_string>& chain) {
+    if (service == nullptr) {
+        return false;
+    }
+
+    auto callingContext = getBinderCallingContext();
+
+    return addImpl(name, service, chain, callingContext);
+}
+
+Return<void> ServiceManager::listManifestByInterface(const hidl_string& fqName,
+                                                     listManifestByInterface_cb _hidl_cb) {
+    if (!mAcl.canGet(fqName, getBinderCallingContext())) {
+        _hidl_cb({});
+        return Void();
+    }
+
+    std::set<std::string> instances = getInstances(fqName);
+    hidl_vec<hidl_string> ret(instances.begin(), instances.end());
+
+    _hidl_cb(ret);
+    return Void();
+}
+
+Return<bool> ServiceManager::tryUnregister(const hidl_string& hidlFqName,
+                                           const hidl_string& hidlName,
+                                           const sp<IBase>& service) {
+    const std::string fqName = hidlFqName;
+    const std::string name = hidlName;
+
+    if (service == nullptr) {
+        return false;
+    }
+
+    if (!mAcl.canAdd(fqName, getBinderCallingContext())) {
+        return false;
+    }
+
+    HidlService* registered = lookup(fqName, name);
+
+    // sanity
+    pid_t pid = IPCThreadState::self()->getCallingPid();
+    if (registered->getDebugPid() != pid) {
+        LOG(WARNING) << "Only a server can unregister itself (for " << fqName
+            << "/" << name << ")";
+        return false;
+    }
+
+    sp<IBase> server = registered->getService();
+
+    if (!interfacesEqual(service, server)) {
+        LOG(WARNING) << "Tried to unregister for " << fqName << "/" << name
+            << " but a different service is registered under this name.";
+        return false;
+    }
+
+    int clients = registered->forceHandleClientCallbacks(false /* isCalledOnInterval */);
+
+    // clients < 0: feature not implemented or other error. Assume clients.
+    // Otherwise:
+    // - kernel driver will hold onto one refcount (during this transaction)
+    // - hwservicemanager has a refcount (guaranteed by this transaction)
+    // So, if clients > 2, then at least one other service on the system must hold a refcount.
+    if (clients < 0 || clients > 2) {
+        // client callbacks are either disabled or there are other clients
+        LOG(INFO) << "Tried to unregister for " << fqName << "/" << name
+            << " but there are clients: " << clients;
+        return false;
+    }
+
+    // will remove entire parent hierarchy
+    bool success = removeService(service, &name /*restrictToInstanceName*/);
+
+    if (registered->getService() != nullptr) {
+        LOG(ERROR) << "Bad state. Unregistration failed for " << fqName << "/" << name << ".";
+        return false;
+    }
+
+    return success;
+}
+
 Return<void> ServiceManager::debugDump(debugDump_cb _cb) {
     if (!mAcl.canList(getBinderCallingContext())) {
         _cb({});
@@ -477,6 +707,8 @@
             .clientPids = clientPids,
             .arch = ::android::hidl::base::V1_0::DebugInfo::Architecture::UNKNOWN
         });
+
+        return true;  // continue
     });
 
     _cb(list);
@@ -517,8 +749,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 54ecb37..8f0c83a 100644
--- a/ServiceManager.h
+++ b/ServiceManager.h
@@ -1,7 +1,23 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 #ifndef ANDROID_HARDWARE_MANAGER_SERVICEMANAGER_H
 #define ANDROID_HARDWARE_MANAGER_SERVICEMANAGER_H
 
-#include <android/hidl/manager/1.1/IServiceManager.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
 #include <hidl/Status.h>
 #include <hidl/MQDescriptor.h>
 #include <map>
@@ -20,12 +36,12 @@
 using ::android::hardware::Return;
 using ::android::hardware::Void;
 using ::android::hidl::base::V1_0::IBase;
-using ::android::hidl::manager::V1_1::IServiceManager;
 using ::android::hidl::manager::V1_0::IServiceNotification;
+using ::android::hidl::manager::V1_2::IClientCallback;
 using ::android::sp;
 using ::android::wp;
 
-struct ServiceManager : public IServiceManager, hidl_death_recipient {
+struct ServiceManager : public V1_2::IServiceManager, hidl_death_recipient {
     // Methods from ::android::hidl::manager::V1_0::IServiceManager follow.
     Return<sp<IBase>> get(const hidl_string& fqName,
                           const hidl_string& name) override;
@@ -52,16 +68,45 @@
                                             const hidl_string& name,
                                             const sp<IServiceNotification>& callback) override;
 
+    // Methods from ::android::hidl::manager::V1_2::IServiceManager follow.
+    Return<bool> registerClientCallback(const hidl_string& fqName,
+                                        const hidl_string& name,
+                                        const sp<IBase>& server,
+                                        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;
+    Return<void> listManifestByInterface(const hidl_string& fqInstanceName,
+                                         listManifestByInterface_cb _hidl_cb) override;
+    Return<bool> tryUnregister(const hidl_string& fqName,
+                               const hidl_string& name,
+                               const sp<IBase>& service) 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::CallingContext& callingContext);
+
     // 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);
     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);
+
+    HidlService* lookup(const std::string& fqName, const std::string& name);
 
     using InstanceMap = std::map<
             std::string, // instance name e.x. "manager"
diff --git a/TEST_MAPPING b/TEST_MAPPING
new file mode 100644
index 0000000..54334db
--- /dev/null
+++ b/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+    {
+      "name": "hwservicemanager_test"
+    }
+  ]
+}
diff --git a/TokenManager.cpp b/TokenManager.cpp
index 92ed844..378ee16 100644
--- a/TokenManager.cpp
+++ b/TokenManager.cpp
@@ -1,8 +1,23 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 #define LOG_TAG "hwservicemanager"
 
 #include "TokenManager.h"
 
-#include <android-base/logging.h>
 #include <functional>
 #include <log/log.h>
 #include <openssl/hmac.h>
@@ -47,6 +62,12 @@
 
     uint64_t id = getTokenId(interface.token);
 
+    if (id != interface.id) {
+        ALOGE("Token creation failed.");
+        hidl_cb({});
+        return Void();
+    }
+
     if (id == TOKEN_ID_NONE) {
         hidl_cb({});
         return Void();
@@ -112,19 +133,19 @@
 
     uint8_t *hmacOut = HMAC(EVP_sha256(),
                             mKey.data(), mKey.size(),
-                            (uint8_t*) &id, ID_SIZE,
+                            (uint8_t*) &id, sizeof(id),
                             hmac.data(), &hmacSize);
 
     if (hmacOut == nullptr ||
             hmacOut != hmac.data()) {
         ALOGE("Generating token failed, got %p.", hmacOut);
-        return { nullptr, {} };
+        return { nullptr, TOKEN_ID_NONE, {} };
     }
 
     // only care about the first HMAC_SIZE bytes of the HMAC
-    const hidl_vec<uint8_t> &token = TokenManager::getToken(id, hmac.data(), hmacSize);
+    const hidl_vec<uint8_t> &token = makeToken(id, hmac.data(), hmacSize);
 
-    return { interface, token };
+    return { interface, id, token };
 }
 
 __attribute__((optnone))
@@ -142,29 +163,23 @@
 }
 
 uint64_t TokenManager::getTokenId(const hidl_vec<uint8_t> &token) {
-    if (token.size() < ID_SIZE) {
+    uint64_t id = 0;
+
+    if (token.size() < sizeof(id)) {
         return TOKEN_ID_NONE;
     }
 
-    uint64_t id = 0;
-    for (size_t i = 0; i < ID_SIZE; i++) {
-        id |= token[i] << i;
-    }
+    memcpy(&id, token.data(), sizeof(id));
 
     return id;
 }
 
-hidl_vec<uint8_t> TokenManager::getToken(const uint64_t id, const uint8_t *hmac, uint64_t hmacSize) {
+hidl_vec<uint8_t> TokenManager::makeToken(const uint64_t id, const uint8_t *hmac, uint64_t hmacSize) {
     hidl_vec<uint8_t> token;
-    token.resize(ID_SIZE + hmacSize);
+    token.resize(sizeof(id) + hmacSize);
 
-    for (size_t i = 0; i < ID_SIZE; i++) {
-        token[i] = (id >> i) & 0xFF;
-    }
-
-    for (size_t i = 0; i < hmacSize; i++) {
-        token[i + ID_SIZE] = hmac[i];
-    }
+    memcpy(token.data(), &id, sizeof(id));
+    memcpy(token.data() + sizeof(id), hmac, hmacSize);
 
     return token;
 }
diff --git a/TokenManager.h b/TokenManager.h
index 319191a..d82f841 100644
--- a/TokenManager.h
+++ b/TokenManager.h
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 #ifndef ANDROID_HIDL_TOKEN_V1_0_TOKENMANAGER_H
 #define ANDROID_HIDL_TOKEN_V1_0_TOKENMANAGER_H
 
@@ -32,20 +48,20 @@
     Return<sp<IBase>> get(const hidl_vec<uint8_t> &token) override;
 
 private:
-    static constexpr uint64_t ID_SIZE = sizeof(uint64_t) / sizeof(uint8_t);
     static constexpr uint64_t KEY_SIZE = 16;
 
     static constexpr uint64_t TOKEN_ID_NONE = 0;
 
     static bool constantTimeCompare(const hidl_vec<uint8_t> &t1, const hidl_vec<uint8_t> &t2);
 
-    static hidl_vec<uint8_t> getToken(const uint64_t id, const uint8_t *hmac, uint64_t hmacSize);
+    static hidl_vec<uint8_t> makeToken(const uint64_t id, const uint8_t *hmac, uint64_t hmacSize);
     static uint64_t getTokenId(const hidl_vec<uint8_t> &token);
 
     std::array<uint8_t, KEY_SIZE> mKey;
 
     struct TokenInterface {
         sp<IBase> interface;
+        uint64_t id;
         hidl_vec<uint8_t> token; // First eight bytes are tokenId. Remaining bytes are hmac.
     };
 
diff --git a/Vintf.cpp b/Vintf.cpp
index d2d2f00..ae4ba45 100644
--- a/Vintf.cpp
+++ b/Vintf.cpp
@@ -1,10 +1,25 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 #define LOG_TAG "hwservicemanager"
 //#define LOG_NDEBUG 0
 
 #include "Vintf.h"
 
 #include <android-base/logging.h>
-#include <hidl-util/FQName.h>
 #include <vintf/parse_string.h>
 #include <vintf/VintfObject.h>
 
@@ -17,16 +32,15 @@
     if (vm == nullptr) {
         return vintf::Transport::EMPTY;
     }
-    return vm->getTransport(fqName.package(),
-            vintf::Version{fqName.getPackageMajorVersion(), fqName.getPackageMinorVersion()},
-            fqName.name(), instanceName);
+    return vm->getTransport(fqName.package(), fqName.getVersion(), fqName.name(), instanceName);
 }
 
 vintf::Transport getTransport(const std::string &interfaceName, const std::string &instanceName) {
-    FQName fqName(interfaceName);
-    if (!fqName.isValid()) {
+    FQName fqName;
+
+    if (!FQName::parse(interfaceName, &fqName)) {
         LOG(ERROR) << __FUNCTION__ << ": " << interfaceName
-                   << " is not a valid fully-qualified name ";
+                   << " is not a valid fully-qualified name.";
         return vintf::Transport::EMPTY;
     }
     if (!fqName.hasVersion()) {
@@ -51,11 +65,36 @@
         return tr;
     }
 
-    LOG(WARNING) << __FUNCTION__ << ": Cannot find entry "
-                 << fqName.string() << "/" << instanceName
-                 << " in either framework or device manifest.";
+    LOG(INFO) << __FUNCTION__ << ": Cannot find entry " << fqName.string() << "/" << instanceName
+              << " in either framework or device manifest.";
     return vintf::Transport::EMPTY;
 }
 
+std::set<std::string> getInstances(const std::string& interfaceName) {
+    FQName fqName;
+    if (!FQName::parse(interfaceName, &fqName) || !fqName.isFullyQualified() ||
+            fqName.isValidValueName() || !fqName.isInterfaceName()) {
+        LOG(ERROR) << __FUNCTION__ << ": " << interfaceName
+                   << " is not a valid fully-qualified name.";
+        return {};
+    }
+
+    std::set<std::string> ret;
+
+    auto deviceManifest = vintf::VintfObject::GetDeviceHalManifest();
+    auto frameworkManifest = vintf::VintfObject::GetFrameworkHalManifest();
+
+    std::set<std::string> deviceSet =
+        deviceManifest->getInstances(fqName.package(), fqName.getVersion(), fqName.name());
+    std::set<std::string> frameworkSet =
+        frameworkManifest->getInstances(fqName.package(), fqName.getVersion(), fqName.name());
+
+    ret.insert(deviceSet.begin(), deviceSet.end());
+    ret.insert(frameworkSet.begin(), frameworkSet.end());
+
+    return ret;
+}
+
+
 }  // hardware
 }  // android
diff --git a/Vintf.h b/Vintf.h
index ceee286..e298dc3 100644
--- a/Vintf.h
+++ b/Vintf.h
@@ -1,8 +1,26 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 #pragma once
 
-#include <string>
 #include <vintf/Transport.h>
 
+#include <set>
+#include <string>
+
 namespace android {
 namespace hardware {
 
@@ -13,5 +31,8 @@
 vintf::Transport getTransport(const std::string &interfaceName,
                               const std::string &instanceName);
 
+// All HALs on the device in manifests.
+std::set<std::string> getInstances(const std::string& interfaceName);
+
 }  // hardware
 }  // android
diff --git a/hwservicemanager.rc b/hwservicemanager.rc
index 96fd5b0..b09ac11 100644
--- a/hwservicemanager.rc
+++ b/hwservicemanager.rc
@@ -4,6 +4,7 @@
     group system readproc
     critical
     onrestart setprop hwservicemanager.ready false
+    onrestart class_restart main
     onrestart class_restart hal
     onrestart class_restart early_hal
     writepid /dev/cpuset/system-background/tasks
diff --git a/service.cpp b/service.cpp
index a3d8c2c..51527ad 100644
--- a/service.cpp
+++ b/service.cpp
@@ -1,13 +1,31 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 #define LOG_TAG "hwservicemanager"
 
 #include <utils/Log.h>
 
 #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>
 #include <cutils/properties.h>
+#include <hidl/HidlBinderSupport.h>
+#include <hidl/HidlTransportSupport.h>
 #include <hidl/Status.h>
 #include <hwbinder/IPCThreadState.h>
 #include <hwbinder/ProcessState.h>
@@ -20,47 +38,123 @@
 
 // libutils:
 using android::sp;
-using android::status_t;
+using android::Looper;
+using android::LooperCallback;
 
 // libhwbinder:
+using android::hardware::BHwBinder;
+using android::hardware::IBinder;
 using android::hardware::IPCThreadState;
 using android::hardware::ProcessState;
 
 // libhidl
-using android::hardware::configureRpcThreadpool;
-using android::hardware::hidl_string;
-using android::hardware::hidl_vec;
-using android::hardware::joinRpcThreadpool;
-using android::hardware::setRequestingSid;
-
-// hidl types
-using android::hidl::manager::V1_1::BnHwServiceManager;
-using android::hidl::token::V1_0::ITokenManager;
+using android::hardware::handleTransportPoll;
+using android::hardware::HidlReturnRestriction;
+using android::hardware::setProcessHidlReturnRestriction;
+using android::hardware::setupTransportPolling;
+using android::hardware::toBinder;
 
 // implementations
 using android::hidl::manager::implementation::ServiceManager;
+using android::hidl::manager::V1_0::IServiceManager;
 using android::hidl::token::V1_0::implementation::TokenManager;
 
 static std::string serviceName = "default";
 
+class HwBinderCallback : public LooperCallback {
+public:
+    static sp<HwBinderCallback> setupTo(const sp<Looper>& looper) {
+        sp<HwBinderCallback> cb = new HwBinderCallback;
+
+        int fdHwBinder = setupTransportPolling();
+        LOG_ALWAYS_FATAL_IF(fdHwBinder < 0, "Failed to setupTransportPolling: %d", fdHwBinder);
+
+        // Flush after setupPolling(), to make sure the binder driver
+        // knows about this thread handling commands.
+        IPCThreadState::self()->flushCommands();
+
+        int ret = looper->addFd(fdHwBinder,
+                                Looper::POLL_CALLBACK,
+                                Looper::EVENT_INPUT,
+                                cb,
+                                nullptr /*data*/);
+        LOG_ALWAYS_FATAL_IF(ret != 1, "Failed to add binder FD to Looper");
+
+        return cb;
+    }
+
+    int handleEvent(int fd, int /*events*/, void* /*data*/) override {
+        handleTransportPoll(fd);
+        return 1;  // Continue receiving callbacks.
+    }
+};
+
+// 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() {
-    configureRpcThreadpool(1, true /* callerWillJoin */);
+    // If hwservicemanager crashes, the system may be unstable and hard to debug. This is both why
+    // we log this and why we care about this at all.
+    setProcessHidlReturnRestriction(HidlReturnRestriction::ERROR_IF_UNCHECKED);
 
     sp<ServiceManager> manager = new ServiceManager();
-    setRequestingSid(manager, true);
-
-    if (!manager->add(serviceName, manager)) {
+    if (!manager->add(serviceName, manager).withDefault(false)) {
         ALOGE("Failed to register hwservicemanager with itself.");
     }
 
-    TokenManager *tokenManager = new TokenManager();
-
-    if (!manager->add(serviceName, tokenManager)) {
+    sp<TokenManager> tokenManager = new TokenManager();
+    if (!manager->add(serviceName, tokenManager).withDefault(false)) {
         ALOGE("Failed to register ITokenManager with hwservicemanager.");
     }
 
     // Tell IPCThreadState we're the service manager
-    sp<BnHwServiceManager> service = new BnHwServiceManager(manager);
+    sp<IBinder> binder = toBinder<IServiceManager>(manager);
+    sp<BHwBinder> service = static_cast<BHwBinder*>(binder.get()); // local binder object
     IPCThreadState::self()->setTheContextObject(service);
     // Then tell the kernel
     ProcessState::self()->becomeContextManager(nullptr, nullptr);
@@ -71,8 +165,16 @@
               "HAL services will not start!\n", rc);
     }
 
+    sp<Looper> looper = Looper::prepare(0 /* opts */);
+
+    (void)HwBinderCallback::setupTo(looper);
+    (void)ClientCallbackCallback::setupTo(looper, manager);
+
     ALOGI("hwservicemanager is ready now.");
-    joinRpcThreadpool();
+
+    while (true) {
+        looper->pollAll(-1 /* timeoutMillis */);
+    }
 
     return 0;
 }
diff --git a/test_lazy.cpp b/test_lazy.cpp
new file mode 100644
index 0000000..21108ba
--- /dev/null
+++ b/test_lazy.cpp
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <HidlService.h>
+
+#include <android/hidl/manager/1.2/IClientCallback.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hidl::base::V1_0::IBase;
+using ::android::hidl::manager::implementation::HidlService;
+using ::android::hidl::manager::V1_2::IClientCallback;
+using ::android::sp;
+using ::testing::ElementsAre;
+using ::testing::Invoke;
+using ::testing::NiceMock;
+
+class RecordingClientCallback : public IClientCallback {
+public:
+    Return<void> onClients(const sp<IBase>& /*base*/, bool clients) override {
+        stream.push_back(clients);
+        return Void();
+    }
+
+    std::vector<bool> stream;
+};
+
+class MockHidlService : public HidlService {
+public:
+    MockHidlService() : HidlService("fqname", "instance") {}
+    MOCK_METHOD0(getNodeStrongRefCount, ssize_t());
+};
+
+class HidlServiceLazyTest : public ::testing::Test {
+public:
+    // Note that this should include one count for hwservicemanager. A count of
+    // 1 indicates that hwservicemanager is the only process holding the service.
+    void setReportedClientCount(ssize_t count) {
+        mState.mInjectedReportCount = count;
+    }
+
+    // Essentially, the number of times the kernel API would be called
+    size_t getNumTimesReported() {
+        return mState.mInjectedTimes;
+    }
+
+    std::unique_ptr<HidlService> makeService() {
+        auto service = std::make_unique<NiceMock<MockHidlService>>();
+        ON_CALL(*service, getNodeStrongRefCount()).WillByDefault(Invoke([&]() {
+            mState.mInjectedTimes++;
+            return mState.mInjectedReportCount;
+        }));
+        return service;
+    }
+
+protected:
+    void SetUp() override {
+        mState = TestState();
+    }
+
+    struct TestState {
+        ssize_t mInjectedReportCount = -1;
+        size_t mInjectedTimes = 0;
+    } mState;
+};
+
+TEST_F(HidlServiceLazyTest, NoChange) {
+    sp<RecordingClientCallback> cb = new RecordingClientCallback;
+
+    std::unique_ptr<HidlService> service = makeService();
+    service->addClientCallback(cb);
+
+    setReportedClientCount(1);
+
+    for (size_t i = 0; i < 100; i++) {
+        service->handleClientCallbacks(true /*onInterval*/);
+    }
+
+    ASSERT_THAT(cb->stream, ElementsAre());
+}
+
+TEST_F(HidlServiceLazyTest, GetAndDrop) {
+    sp<RecordingClientCallback> cb = new RecordingClientCallback;
+
+    std::unique_ptr<HidlService> service = makeService();
+    service->addClientCallback(cb);
+
+    // some other process has the service
+    setReportedClientCount(2);
+    service->handleClientCallbacks(true /*onInterval*/);
+
+    ASSERT_THAT(cb->stream, ElementsAre(true));
+
+    // just hwservicemanager has the service
+    setReportedClientCount(1);
+    service->handleClientCallbacks(true /*onInterval*/);
+
+    ASSERT_THAT(cb->stream, ElementsAre(true));
+    service->handleClientCallbacks(true /*onInterval*/);
+
+    ASSERT_THAT(cb->stream, ElementsAre(true, false)); // reported only after two intervals
+}
+
+TEST_F(HidlServiceLazyTest, GetGuarantee) {
+    sp<RecordingClientCallback> cb = new RecordingClientCallback;
+
+    std::unique_ptr<HidlService> service = makeService();
+    service->addClientCallback(cb);
+
+    service->guaranteeClient();
+
+    setReportedClientCount(1);
+    service->handleClientCallbacks(false /*onInterval*/);
+    ASSERT_THAT(cb->stream, ElementsAre(true));
+
+    service->handleClientCallbacks(true /*onInterval*/);
+    ASSERT_THAT(cb->stream, ElementsAre(true));
+
+    service->handleClientCallbacks(true /*onInterval*/);
+    ASSERT_THAT(cb->stream, ElementsAre(true, false)); // reported only after two intervals
+}
+
+TEST_F(HidlServiceLazyTest, ManyUpdatesOffInterval) {
+    sp<RecordingClientCallback> cb = new RecordingClientCallback;
+
+    std::unique_ptr<HidlService> service = makeService();
+    service->addClientCallback(cb);
+
+    // Clients can appear and dissappear as many times as necessary, but they are only considered
+    // dropped when the fixed interval stops.
+    for (size_t i = 0; i < 100; i++) {
+        setReportedClientCount(2);
+        service->handleClientCallbacks(false /*onInterval*/);
+        setReportedClientCount(1);
+        service->handleClientCallbacks(false /*onInterval*/);
+    }
+
+    ASSERT_THAT(cb->stream, ElementsAre(true));
+
+    service->handleClientCallbacks(true /*onInterval*/);
+    ASSERT_THAT(cb->stream, ElementsAre(true));
+
+    service->handleClientCallbacks(true /*onInterval*/);
+    ASSERT_THAT(cb->stream, ElementsAre(true, false)); // reported only after two intervals
+}
+
+TEST_F(HidlServiceLazyTest, AcquisitionAfterGuarantee) {
+    sp<RecordingClientCallback> cb = new RecordingClientCallback;
+
+    std::unique_ptr<HidlService> service = makeService();
+    service->addClientCallback(cb);
+
+    setReportedClientCount(2);
+    service->handleClientCallbacks(false /*onInterval*/);
+    ASSERT_THAT(cb->stream, ElementsAre(true));
+
+    setReportedClientCount(1);
+    service->guaranteeClient();
+
+    service->handleClientCallbacks(false /*onInterval*/);
+    ASSERT_THAT(cb->stream, ElementsAre(true));
+
+    service->handleClientCallbacks(true /*onInterval*/);
+    ASSERT_THAT(cb->stream, ElementsAre(true));
+
+    service->handleClientCallbacks(true /*onInterval*/);
+    ASSERT_THAT(cb->stream, ElementsAre(true, false)); // reported only after two intervals
+}
+
+TEST_F(HidlServiceLazyTest, NotificationSentForNewClientCallback) {
+    sp<RecordingClientCallback> cb = new RecordingClientCallback;
+
+    std::unique_ptr<HidlService> service = makeService();
+    service->addClientCallback(cb);
+
+    setReportedClientCount(2);
+    service->handleClientCallbacks(false /*onInterval*/);
+    ASSERT_THAT(cb->stream, ElementsAre(true));
+
+    sp<RecordingClientCallback> laterCb = new RecordingClientCallback;
+    service->addClientCallback(laterCb);
+
+    ASSERT_THAT(cb->stream, ElementsAre(true));
+    ASSERT_THAT(laterCb->stream, ElementsAre(true));
+
+    setReportedClientCount(1);
+
+    service->handleClientCallbacks(true /*onInterval*/);
+    ASSERT_THAT(cb->stream, ElementsAre(true));
+    ASSERT_THAT(laterCb->stream, ElementsAre(true));
+
+    service->handleClientCallbacks(true /*onInterval*/);
+    ASSERT_THAT(cb->stream, ElementsAre(true, false)); // reported only after two intervals
+    ASSERT_THAT(laterCb->stream, ElementsAre(true, false)); // reported only after two intervals
+}
+
+TEST_F(HidlServiceLazyTest, ClientWithoutLazy) {
+    std::unique_ptr<HidlService> service = makeService();
+
+    setReportedClientCount(2);
+    service->handleClientCallbacks(false /*onInterval*/);
+
+    // kernel API should not be called
+    EXPECT_EQ(0u, getNumTimesReported());
+}