Add waitForService to AIDL.

Eye towards:
- avoiding while(true) getService loops
- need it to make AIDL dynamic HALs
- need it for feature parity w/ HIDL

Bug: 136027762
Test: use in AIDL unit test
Change-Id: I2981eb4ebecff8c4519e09b7dcca51892dfd528d
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index 74f1f47..715a460 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -18,6 +18,7 @@
 
 #include <binder/IServiceManager.h>
 
+#include <android/os/BnServiceCallback.h>
 #include <android/os/IServiceManager.h>
 #include <utils/Log.h>
 #include <binder/IPCThreadState.h>
@@ -212,6 +213,64 @@
         return res;
     }
 
+    sp<IBinder> waitForService(const String16& name16) override {
+        class Waiter : public android::os::BnServiceCallback {
+            Status onRegistration(const std::string& /*name*/,
+                                  const sp<IBinder>& binder) override {
+                std::unique_lock<std::mutex> lock(mMutex);
+                mBinder = binder;
+                lock.unlock();
+                mCv.notify_one();
+                return Status::ok();
+            }
+        public:
+            sp<IBinder> mBinder;
+            std::mutex mMutex;
+            std::condition_variable mCv;
+        };
+
+        const std::string name = String8(name16).c_str();
+
+        sp<IBinder> out;
+        if(!mTheRealServiceManager->checkService(name, &out).isOk()) {
+            return nullptr;
+        }
+        if(out != nullptr) return out;
+
+        sp<Waiter> waiter = new Waiter;
+        if (!mTheRealServiceManager->registerForNotifications(
+                name, waiter).isOk()) {
+            return nullptr;
+        }
+
+        while(true) {
+            {
+                std::unique_lock<std::mutex> lock(waiter->mMutex);
+                using std::literals::chrono_literals::operator""s;
+                waiter->mCv.wait_for(lock, 1s, [&] {
+                    return waiter->mBinder != nullptr;
+                });
+                if (waiter->mBinder != nullptr) return waiter->mBinder;
+            }
+
+            // Handle race condition for lazy services. Here is what can happen:
+            // - the service dies (not processed by init yet).
+            // - sm processes death notification.
+            // - sm gets checkService and calls init to start service.
+            // - init gets the start signal, but the service already appears
+            //   started, so it does nothing.
+            // - init gets death signal, but doesn't know it needs to restart
+            //   the service
+            // - we need to request service again to get it to start
+            if(!mTheRealServiceManager->checkService(name, &out).isOk()) {
+                return nullptr;
+            }
+            if(out != nullptr) return out;
+
+            ALOGW("Waited one second for %s", name.c_str());
+        }
+    }
+
 private:
     sp<AidlServiceManager> mTheRealServiceManager;
 };
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index 30786fa..8ae860d 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -71,11 +71,24 @@
      */
     // NOLINTNEXTLINE(google-default-arguments)
     virtual Vector<String16> listServices(int dumpsysFlags = DUMP_FLAG_PRIORITY_ALL) = 0;
+
+    /**
+     * Efficiently wait for a service.
+     *
+     * Returns nullptr only for permission problem or fatal error.
+     */
+    virtual sp<IBinder> waitForService(const String16& name) = 0;
 };
 
 sp<IServiceManager> defaultServiceManager();
 
 template<typename INTERFACE>
+sp<INTERFACE> waitForService(const String16& name) {
+    const sp<IServiceManager> sm = defaultServiceManager();
+    return interface_cast<INTERFACE>(sm->waitForService(name));
+}
+
+template<typename INTERFACE>
 status_t getService(const String16& name, sp<INTERFACE>* outService)
 {
     const sp<IServiceManager> sm = defaultServiceManager();