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;
 };