diff options
| author | 2019-08-30 12:08:53 -0700 | |
|---|---|---|
| committer | 2019-08-30 12:08:53 -0700 | |
| commit | 217dd40021b4b6f346a588bbdb3bf9afd9790568 (patch) | |
| tree | 519f3edee2141a79d8ff3cbd9da64870b00ca86d | |
| parent | 1aed07f3295a34e2e1c41a841d0b92b6176b84c6 (diff) | |
| parent | c122d611fd09e9ead0d3b90c20cd507251238332 (diff) | |
Merge changes from topic "wait-for-aidl" into stage-aosp-master am: c53bc39904 am: 2941ff2cf0 am: c41f708e75
am: c122d611fd
Change-Id: I98b6243cf9815c5af79ed40761e06b6e39e62a92
| -rw-r--r-- | cmds/dumpsys/tests/dumpsys_test.cpp | 2 | ||||
| -rw-r--r-- | libs/binder/IServiceManager.cpp | 59 | ||||
| -rw-r--r-- | libs/binder/include/binder/IServiceManager.h | 13 |
3 files changed, 73 insertions, 1 deletions
diff --git a/cmds/dumpsys/tests/dumpsys_test.cpp b/cmds/dumpsys/tests/dumpsys_test.cpp index 3ada15398c..cbac839e6f 100644 --- a/cmds/dumpsys/tests/dumpsys_test.cpp +++ b/cmds/dumpsys/tests/dumpsys_test.cpp @@ -53,7 +53,7 @@ class ServiceManagerMock : public IServiceManager { MOCK_CONST_METHOD1(checkService, sp<IBinder>(const String16&)); MOCK_METHOD4(addService, status_t(const String16&, const sp<IBinder>&, bool, int)); MOCK_METHOD1(listServices, Vector<String16>(int)); - + MOCK_METHOD1(waitForService, sp<IBinder>(const String16&)); protected: MOCK_METHOD0(onAsBinder, IBinder*()); }; diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp index 74f1f47c7a..715a4609d6 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 @@ public: 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 30786fa0cb..8ae860df38 100644 --- a/libs/binder/include/binder/IServiceManager.h +++ b/libs/binder/include/binder/IServiceManager.h @@ -71,11 +71,24 @@ public: */ // 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(); |