diff options
Diffstat (limited to 'libs/binder/IServiceManager.cpp')
-rw-r--r-- | libs/binder/IServiceManager.cpp | 117 |
1 files changed, 87 insertions, 30 deletions
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp index 9d816e8ad6..715a4609d6 100644 --- a/libs/binder/IServiceManager.cpp +++ b/libs/binder/IServiceManager.cpp @@ -18,6 +18,8 @@ #include <binder/IServiceManager.h> +#include <android/os/BnServiceCallback.h> +#include <android/os/IServiceManager.h> #include <utils/Log.h> #include <binder/IPCThreadState.h> #ifndef __ANDROID_VNDK__ @@ -34,6 +36,9 @@ namespace android { +using AidlServiceManager = android::os::IServiceManager; +using android::binder::Status; + sp<IServiceManager> defaultServiceManager() { static Mutex gDefaultServiceManagerLock; @@ -142,11 +147,12 @@ class BpServiceManager : public BpInterface<IServiceManager> { public: explicit BpServiceManager(const sp<IBinder>& impl) - : BpInterface<IServiceManager>(impl) + : BpInterface<IServiceManager>(impl), + mTheRealServiceManager(interface_cast<AidlServiceManager>(impl)) { } - virtual sp<IBinder> getService(const String16& name) const + sp<IBinder> getService(const String16& name) const override { static bool gSystemBootCompleted = false; @@ -179,43 +185,94 @@ public: return nullptr; } - virtual sp<IBinder> checkService( const String16& name) const - { - Parcel data, reply; - data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor()); - data.writeString16(name); - remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply); - return reply.readStrongBinder(); + sp<IBinder> checkService(const String16& name) const override { + sp<IBinder> ret; + if (!mTheRealServiceManager->checkService(String8(name).c_str(), &ret).isOk()) { + return nullptr; + } + return ret; } - virtual status_t addService(const String16& name, const sp<IBinder>& service, - bool allowIsolated, int dumpsysPriority) { - Parcel data, reply; - data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor()); - data.writeString16(name); - data.writeStrongBinder(service); - data.writeInt32(allowIsolated ? 1 : 0); - data.writeInt32(dumpsysPriority); - status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply); - return err == NO_ERROR ? reply.readExceptionCode() : err; + status_t addService(const String16& name, const sp<IBinder>& service, + bool allowIsolated, int dumpsysPriority) override { + Status status = mTheRealServiceManager->addService(String8(name).c_str(), service, allowIsolated, dumpsysPriority); + return status.exceptionCode(); } virtual Vector<String16> listServices(int dumpsysPriority) { - Vector<String16> res; - int n = 0; + std::vector<std::string> ret; + if (!mTheRealServiceManager->listServices(dumpsysPriority, &ret).isOk()) { + return {}; + } - for (;;) { - Parcel data, reply; - data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor()); - data.writeInt32(n++); - data.writeInt32(dumpsysPriority); - status_t err = remote()->transact(LIST_SERVICES_TRANSACTION, data, &reply); - if (err != NO_ERROR) - break; - res.add(reply.readString16()); + Vector<String16> res; + res.setCapacity(ret.size()); + for (const std::string& name : ret) { + res.push(String16(name.c_str())); } 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; }; IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager"); |