diff options
author | Treehugger Robot <treehugger-gerrit@google.com> | 2022-02-02 22:03:33 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2022-02-02 22:03:33 +0000 |
commit | e9692d4243bc49af0643d0891debbeb1322826dc (patch) | |
tree | 9f8c2aff265afc228c88fcce6a5e0a4c3d273aed | |
parent | 60aac74fbc7ae26d82accb3aa017ae3045da9ed0 (diff) | |
parent | 30700944f8b6527946e139a0c5710c0a6031a4e5 (diff) | |
download | native-e9692d4243bc49af0643d0891debbeb1322826dc.tar.gz |
Merge "IServiceManager: add registerForNotifications."
-rw-r--r-- | cmds/dumpsys/tests/dumpsys_test.cpp | 4 | ||||
-rw-r--r-- | libs/binder/IServiceManager.cpp | 101 | ||||
-rw-r--r-- | libs/binder/include/binder/IServiceManager.h | 11 | ||||
-rw-r--r-- | libs/binder/tests/binderLibTest.cpp | 13 | ||||
-rw-r--r-- | libs/fakeservicemanager/ServiceManager.cpp | 10 | ||||
-rw-r--r-- | libs/fakeservicemanager/ServiceManager.h | 5 |
6 files changed, 144 insertions, 0 deletions
diff --git a/cmds/dumpsys/tests/dumpsys_test.cpp b/cmds/dumpsys/tests/dumpsys_test.cpp index 677d6c78ea..49c1318945 100644 --- a/cmds/dumpsys/tests/dumpsys_test.cpp +++ b/cmds/dumpsys/tests/dumpsys_test.cpp @@ -61,6 +61,10 @@ class ServiceManagerMock : public IServiceManager { MOCK_METHOD1(getDeclaredInstances, Vector<String16>(const String16&)); MOCK_METHOD1(updatableViaApex, std::optional<String16>(const String16&)); MOCK_METHOD1(getConnectionInfo, std::optional<ConnectionInfo>(const String16&)); + MOCK_METHOD2(registerForNotifications, status_t(const String16&, + const sp<LocalRegistrationCallback>&)); + MOCK_METHOD2(unregisterForNotifications, status_t(const String16&, + const sp<LocalRegistrationCallback>&)); protected: MOCK_METHOD0(onAsBinder, IBinder*()); }; diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp index 81e61daae1..ea2f8d2274 100644 --- a/libs/binder/IServiceManager.cpp +++ b/libs/binder/IServiceManager.cpp @@ -43,6 +43,8 @@ namespace android { +using AidlRegistrationCallback = IServiceManager::LocalRegistrationCallback; + using AidlServiceManager = android::os::IServiceManager; using android::binder::Status; @@ -79,7 +81,24 @@ public: Vector<String16> getDeclaredInstances(const String16& interface) override; std::optional<String16> updatableViaApex(const String16& name) override; std::optional<IServiceManager::ConnectionInfo> getConnectionInfo(const String16& name) override; + class RegistrationWaiter : public android::os::BnServiceCallback { + public: + explicit RegistrationWaiter(const sp<AidlRegistrationCallback>& callback) + : mImpl(callback) {} + Status onRegistration(const std::string& name, const sp<IBinder>& binder) override { + mImpl->onServiceRegistration(String16(name.c_str()), binder); + return Status::ok(); + } + + private: + sp<AidlRegistrationCallback> mImpl; + }; + + status_t registerForNotifications(const String16& service, + const sp<AidlRegistrationCallback>& cb) override; + status_t unregisterForNotifications(const String16& service, + const sp<AidlRegistrationCallback>& cb) override; // for legacy ABI const String16& getInterfaceDescriptor() const override { return mTheRealServiceManager->getInterfaceDescriptor(); @@ -90,6 +109,17 @@ public: protected: sp<AidlServiceManager> mTheRealServiceManager; + // AidlRegistrationCallback -> services that its been registered for + // notifications. + using LocalRegistrationAndWaiter = + std::pair<sp<LocalRegistrationCallback>, sp<RegistrationWaiter>>; + using ServiceCallbackMap = std::map<std::string, std::vector<LocalRegistrationAndWaiter>>; + ServiceCallbackMap mNameToRegistrationCallback; + std::mutex mNameToRegistrationLock; + + void removeRegistrationCallbackLocked(const sp<AidlRegistrationCallback>& cb, + ServiceCallbackMap::iterator* it, + sp<RegistrationWaiter>* waiter); // Directly get the service in a way that, for lazy services, requests the service to be started // if it is not currently started. This way, calls directly to ServiceManagerShim::getService @@ -442,6 +472,77 @@ std::optional<IServiceManager::ConnectionInfo> ServiceManagerShim::getConnection : std::nullopt; } +status_t ServiceManagerShim::registerForNotifications(const String16& name, + const sp<AidlRegistrationCallback>& cb) { + if (cb == nullptr) { + ALOGE("%s: null cb passed", __FUNCTION__); + return BAD_VALUE; + } + std::string nameStr = String8(name).c_str(); + sp<RegistrationWaiter> registrationWaiter = sp<RegistrationWaiter>::make(cb); + std::lock_guard<std::mutex> lock(mNameToRegistrationLock); + if (Status status = + mTheRealServiceManager->registerForNotifications(nameStr, registrationWaiter); + !status.isOk()) { + ALOGW("Failed to registerForNotifications for %s: %s", nameStr.c_str(), + status.toString8().c_str()); + return UNKNOWN_ERROR; + } + mNameToRegistrationCallback[nameStr].push_back(std::make_pair(cb, registrationWaiter)); + return OK; +} + +void ServiceManagerShim::removeRegistrationCallbackLocked(const sp<AidlRegistrationCallback>& cb, + ServiceCallbackMap::iterator* it, + sp<RegistrationWaiter>* waiter) { + std::vector<LocalRegistrationAndWaiter>& localRegistrationAndWaiters = (*it)->second; + for (auto lit = localRegistrationAndWaiters.begin(); + lit != localRegistrationAndWaiters.end();) { + if (lit->first == cb) { + if (waiter) { + *waiter = lit->second; + } + lit = localRegistrationAndWaiters.erase(lit); + } else { + ++lit; + } + } + + if (localRegistrationAndWaiters.empty()) { + mNameToRegistrationCallback.erase(*it); + } +} + +status_t ServiceManagerShim::unregisterForNotifications(const String16& name, + const sp<AidlRegistrationCallback>& cb) { + if (cb == nullptr) { + ALOGE("%s: null cb passed", __FUNCTION__); + return BAD_VALUE; + } + std::string nameStr = String8(name).c_str(); + std::lock_guard<std::mutex> lock(mNameToRegistrationLock); + auto it = mNameToRegistrationCallback.find(nameStr); + sp<RegistrationWaiter> registrationWaiter; + if (it != mNameToRegistrationCallback.end()) { + removeRegistrationCallbackLocked(cb, &it, ®istrationWaiter); + } else { + ALOGE("%s no callback registered for notifications on %s", __FUNCTION__, nameStr.c_str()); + return BAD_VALUE; + } + if (registrationWaiter == nullptr) { + ALOGE("%s Callback passed wasn't used to register for notifications", __FUNCTION__); + return BAD_VALUE; + } + if (Status status = mTheRealServiceManager->unregisterForNotifications(String8(name).c_str(), + registrationWaiter); + !status.isOk()) { + ALOGW("Failed to get service manager to unregisterForNotifications for %s: %s", + String8(name).c_str(), status.toString8().c_str()); + return UNKNOWN_ERROR; + } + return OK; +} + #ifndef __ANDROID__ // ServiceManagerShim for host. Implements the old libbinder android::IServiceManager API. // The internal implementation of the AIDL interface android::os::IServiceManager calls into diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h index 240e3c2b26..ea40db8ffa 100644 --- a/libs/binder/include/binder/IServiceManager.h +++ b/libs/binder/include/binder/IServiceManager.h @@ -115,6 +115,17 @@ public: unsigned int port; }; virtual std::optional<ConnectionInfo> getConnectionInfo(const String16& name) = 0; + + struct LocalRegistrationCallback : public virtual RefBase { + virtual void onServiceRegistration(const String16& instance, const sp<IBinder>& binder) = 0; + virtual ~LocalRegistrationCallback() {} + }; + + virtual status_t registerForNotifications(const String16& name, + const sp<LocalRegistrationCallback>& callback) = 0; + + virtual status_t unregisterForNotifications(const String16& name, + const sp<LocalRegistrationCallback>& callback) = 0; }; sp<IServiceManager> defaultServiceManager(); diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp index 63a4b2cc68..700940a529 100644 --- a/libs/binder/tests/binderLibTest.cpp +++ b/libs/binder/tests/binderLibTest.cpp @@ -1220,6 +1220,19 @@ TEST_F(BinderLibTest, GotSid) { EXPECT_THAT(server->transact(BINDER_LIB_TEST_CAN_GET_SID, data, nullptr), StatusEq(OK)); } +TEST(ServiceNotifications, Unregister) { + auto sm = defaultServiceManager(); + using LocalRegistrationCallback = IServiceManager::LocalRegistrationCallback; + class LocalRegistrationCallbackImpl : public virtual LocalRegistrationCallback { + void onServiceRegistration(const String16 &, const sp<IBinder> &) override {} + virtual ~LocalRegistrationCallbackImpl() {} + }; + sp<LocalRegistrationCallback> cb = sp<LocalRegistrationCallbackImpl>::make(); + + EXPECT_EQ(sm->registerForNotifications(String16("RogerRafa"), cb), OK); + EXPECT_EQ(sm->unregisterForNotifications(String16("RogerRafa"), cb), OK); +} + class BinderLibRpcTestBase : public BinderLibTest { public: void SetUp() override { diff --git a/libs/fakeservicemanager/ServiceManager.cpp b/libs/fakeservicemanager/ServiceManager.cpp index 9f0754b891..61e4a98846 100644 --- a/libs/fakeservicemanager/ServiceManager.cpp +++ b/libs/fakeservicemanager/ServiceManager.cpp @@ -84,4 +84,14 @@ std::optional<IServiceManager::ConnectionInfo> ServiceManager::getConnectionInfo return std::nullopt; } +status_t ServiceManager::registerForNotifications(const String16&, + const sp<LocalRegistrationCallback>&) { + return INVALID_OPERATION; +} + +status_t ServiceManager::unregisterForNotifications(const String16&, + const sp<LocalRegistrationCallback>&) { + return INVALID_OPERATION; +} + } // namespace android diff --git a/libs/fakeservicemanager/ServiceManager.h b/libs/fakeservicemanager/ServiceManager.h index b1496ba50b..6d6e008c4f 100644 --- a/libs/fakeservicemanager/ServiceManager.h +++ b/libs/fakeservicemanager/ServiceManager.h @@ -53,6 +53,11 @@ public: std::optional<IServiceManager::ConnectionInfo> getConnectionInfo(const String16& name) override; + status_t registerForNotifications(const String16& name, + const sp<LocalRegistrationCallback>& callback) override; + + status_t unregisterForNotifications(const String16& name, + const sp<LocalRegistrationCallback>& callback) override; private: std::map<String16, sp<IBinder>> mNameToService; }; |