Merge "Add waitForHwService."
am: 3b41bfec5d

Change-Id: I76e4c0da2068687d98d11f6f5530d7fb3f1e8c5b
diff --git a/transport/ServiceManagement.cpp b/transport/ServiceManagement.cpp
index 1734935..9a6a3b5 100644
--- a/transport/ServiceManagement.cpp
+++ b/transport/ServiceManagement.cpp
@@ -22,12 +22,14 @@
 #include <hidl/Status.h>
 
 #include <android-base/logging.h>
+#include <condition_variable>
 #include <dlfcn.h>
 #include <dirent.h>
 #include <hidl-util/FQName.h>
 #include <hidl-util/StringHelper.h>
 #include <hwbinder/IPCThreadState.h>
 #include <hwbinder/Parcel.h>
+#include <mutex>
 #include <unistd.h>
 
 #include <android/hidl/manager/1.0/IServiceManager.h>
@@ -175,5 +177,65 @@
     return manager;
 }
 
+namespace details {
+
+struct Waiter : IServiceNotification {
+    Return<void> onRegistration(const hidl_string& /* fqName */,
+                                const hidl_string& /* name */,
+                                bool /* preexisting */) override {
+        std::unique_lock<std::mutex> lock(mMutex);
+        if (mRegistered) {
+            return Void();
+        }
+        mRegistered = true;
+        lock.unlock();
+
+        mCondition.notify_one();
+        return Void();
+    }
+
+    void wait() {
+        std::unique_lock<std::mutex> lock(mMutex);
+        mCondition.wait(lock, [this]{
+            return mRegistered;
+        });
+    }
+
+private:
+    std::mutex mMutex;
+    std::condition_variable mCondition;
+    bool mRegistered = false;
+};
+
+void waitForHwService(
+        const std::string &interface, const std::string &instanceName) {
+    const sp<IServiceManager> manager = defaultServiceManager();
+
+    if (manager == nullptr) {
+        LOG(ERROR) << "Could not get default service manager.";
+        return;
+    }
+
+    sp<Waiter> waiter = new Waiter();
+    Return<bool> ret = manager->registerForNotifications(interface, instanceName, waiter);
+
+    if (!ret.isOk()) {
+        LOG(ERROR) << "Transport error, " << ret.description()
+            << ", during notification registration for "
+            << interface << "/" << instanceName << ".";
+        return;
+    }
+
+    if (!ret) {
+        LOG(ERROR) << "Could not register for notifications for "
+            << interface << "/" << instanceName << ".";
+        return;
+    }
+
+    waiter->wait();
+}
+
+}; // namespace details
+
 }; // namespace hardware
 }; // namespace android
diff --git a/transport/include/hidl/ServiceManagement.h b/transport/include/hidl/ServiceManagement.h
index d4552a7..2035fb7 100644
--- a/transport/include/hidl/ServiceManagement.h
+++ b/transport/include/hidl/ServiceManagement.h
@@ -17,6 +17,7 @@
 #ifndef ANDROID_HARDWARE_ISERVICE_MANAGER_H
 #define ANDROID_HARDWARE_ISERVICE_MANAGER_H
 
+#include <string>
 #include <utils/StrongPointer.h>
 
 namespace android {
@@ -37,6 +38,10 @@
 sp<::android::hidl::manager::V1_0::IServiceManager> defaultServiceManager();
 sp<::android::hidl::manager::V1_0::IServiceManager> getPassthroughServiceManager();
 
+namespace details {
+void waitForHwService(const std::string &interface, const std::string &instanceName);
+};
+
 }; // namespace hardware
 }; // namespace android