Loading libs/binder/BackendUnifiedServiceManager.cpp +117 −3 Original line number Diff line number Diff line Loading @@ -24,11 +24,111 @@ namespace android { #ifdef LIBBINDER_CLIENT_CACHE constexpr bool kUseCache = true; #else constexpr bool kUseCache = false; #endif using AidlServiceManager = android::os::IServiceManager; using IAccessor = android::os::IAccessor; static const char* kStaticCachableList[] = { "activity", "android.hardware.thermal.IThermal/default", "android.hardware.power.IPower/default", "android.frameworks.stats.IStats/default", "android.system.suspend.ISystemSuspend/default", "appops", "audio", "batterystats", "carrier_config", "connectivity", "content_capture", "device_policy", "display", "dropbox", "econtroller", "isub", "legacy_permission", "location", "media.extractor", "media.metrics", "media.player", "media.resource_manager", "netd_listener", "netstats", "network_management", "nfc", "package_native", "performance_hint", "permission", "permissionmgr", "permission_checker", "phone", "platform_compat", "power", "role", "sensorservice", "statscompanion", "telephony.registry", "thermalservice", "time_detector", "trust", "uimode", "virtualdevice", "virtualdevice_native", "webviewupdate", }; bool BinderCacheWithInvalidation::isClientSideCachingEnabled(const std::string& serviceName) { if (ProcessState::self()->getThreadPoolMaxTotalThreadCount() <= 0) { ALOGW("Thread Pool max thread count is 0. Cannot cache binder as linkToDeath cannot be " "implemented. serviceName: %s", serviceName.c_str()); return false; } for (const char* name : kStaticCachableList) { if (name == serviceName) { return true; } } return false; } binder::Status BackendUnifiedServiceManager::updateCache(const std::string& serviceName, const os::Service& service) { if (!kUseCache) { return binder::Status::ok(); } if (service.getTag() == os::Service::Tag::binder) { sp<IBinder> binder = service.get<os::Service::Tag::binder>(); if (binder && mCacheForGetService->isClientSideCachingEnabled(serviceName) && binder->isBinderAlive()) { return mCacheForGetService->setItem(serviceName, binder); } } return binder::Status::ok(); } bool BackendUnifiedServiceManager::returnIfCached(const std::string& serviceName, os::Service* _out) { if (!kUseCache) { return false; } sp<IBinder> item = mCacheForGetService->getItem(serviceName); // TODO(b/363177618): Enable caching for binders which are always null. if (item != nullptr && item->isBinderAlive()) { *_out = os::Service::make<os::Service::Tag::binder>(item); return true; } return false; } BackendUnifiedServiceManager::BackendUnifiedServiceManager(const sp<AidlServiceManager>& impl) : mTheRealServiceManager(impl) {} : mTheRealServiceManager(impl) { mCacheForGetService = std::make_shared<BinderCacheWithInvalidation>(); } sp<AidlServiceManager> BackendUnifiedServiceManager::getImpl() { return mTheRealServiceManager; Loading @@ -44,10 +144,17 @@ binder::Status BackendUnifiedServiceManager::getService(const ::std::string& nam binder::Status BackendUnifiedServiceManager::getService2(const ::std::string& name, os::Service* _out) { if (returnIfCached(name, _out)) { return binder::Status::ok(); } os::Service service; binder::Status status = mTheRealServiceManager->getService2(name, &service); if (status.isOk()) { status = toBinderService(name, service, _out); if (status.isOk()) { return toBinderService(name, service, _out); return updateCache(name, service); } } return status; } Loading @@ -55,9 +162,16 @@ binder::Status BackendUnifiedServiceManager::getService2(const ::std::string& na binder::Status BackendUnifiedServiceManager::checkService(const ::std::string& name, os::Service* _out) { os::Service service; if (returnIfCached(name, _out)) { return binder::Status::ok(); } binder::Status status = mTheRealServiceManager->checkService(name, &service); if (status.isOk()) { return toBinderService(name, service, _out); status = toBinderService(name, service, _out); if (status.isOk()) { return updateCache(name, service); } } return status; } Loading libs/binder/BackendUnifiedServiceManager.h +81 −0 Original line number Diff line number Diff line Loading @@ -18,9 +18,87 @@ #include <android/os/BnServiceManager.h> #include <android/os/IServiceManager.h> #include <binder/IPCThreadState.h> #include <map> #include <memory> namespace android { class BinderCacheWithInvalidation : public std::enable_shared_from_this<BinderCacheWithInvalidation> { class BinderInvalidation : public IBinder::DeathRecipient { public: BinderInvalidation(std::weak_ptr<BinderCacheWithInvalidation> cache, const std::string& key) : mCache(cache), mKey(key) {} void binderDied(const wp<IBinder>& who) override { sp<IBinder> binder = who.promote(); if (std::shared_ptr<BinderCacheWithInvalidation> cache = mCache.lock()) { cache->removeItem(mKey, binder); } else { ALOGI("Binder Cache pointer expired: %s", mKey.c_str()); } } private: std::weak_ptr<BinderCacheWithInvalidation> mCache; std::string mKey; }; struct Entry { sp<IBinder> service; sp<BinderInvalidation> deathRecipient; }; public: sp<IBinder> getItem(const std::string& key) const { std::lock_guard<std::mutex> lock(mCacheMutex); if (auto it = mCache.find(key); it != mCache.end()) { return it->second.service; } return nullptr; } bool removeItem(const std::string& key, const sp<IBinder>& who) { std::lock_guard<std::mutex> lock(mCacheMutex); if (auto it = mCache.find(key); it != mCache.end()) { if (it->second.service == who) { status_t result = who->unlinkToDeath(it->second.deathRecipient); if (result != DEAD_OBJECT) { ALOGW("Unlinking to dead binder resulted in: %d", result); } mCache.erase(key); return true; } } return false; } binder::Status setItem(const std::string& key, const sp<IBinder>& item) { sp<BinderInvalidation> deathRecipient = sp<BinderInvalidation>::make(shared_from_this(), key); // linkToDeath if binder is a remote binder. if (item->localBinder() == nullptr) { status_t status = item->linkToDeath(deathRecipient); if (status != android::OK) { ALOGE("Failed to linkToDeath binder for service %s. Error: %d", key.c_str(), status); return binder::Status::fromStatusT(status); } } std::lock_guard<std::mutex> lock(mCacheMutex); Entry entry = {.service = item, .deathRecipient = deathRecipient}; mCache[key] = entry; return binder::Status::ok(); } bool isClientSideCachingEnabled(const std::string& serviceName); private: std::map<std::string, Entry> mCache; mutable std::mutex mCacheMutex; }; class BackendUnifiedServiceManager : public android::os::BnServiceManager { public: explicit BackendUnifiedServiceManager(const sp<os::IServiceManager>& impl); Loading Loading @@ -58,9 +136,12 @@ public: } private: std::shared_ptr<BinderCacheWithInvalidation> mCacheForGetService; sp<os::IServiceManager> mTheRealServiceManager; binder::Status toBinderService(const ::std::string& name, const os::Service& in, os::Service* _out); binder::Status updateCache(const std::string& serviceName, const os::Service& service); bool returnIfCached(const std::string& serviceName, os::Service* _out); }; sp<BackendUnifiedServiceManager> getBackendUnifiedServiceManager(); Loading libs/binder/IServiceManager.cpp +6 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ #define LOG_TAG "ServiceManagerCppClient" #include <binder/IServiceManager.h> #include <binder/IServiceManagerUnitTestHelper.h> #include "BackendUnifiedServiceManager.h" #include <inttypes.h> Loading Loading @@ -311,6 +312,11 @@ void setDefaultServiceManager(const sp<IServiceManager>& sm) { } } sp<IServiceManager> getServiceManagerShimFromAidlServiceManagerForTests( const sp<AidlServiceManager>& sm) { return sp<CppBackendShim>::make(sp<BackendUnifiedServiceManager>::make(sm)); } std::weak_ptr<AccessorProvider> addAccessorProvider(RpcAccessorProvider&& providerCallback) { std::lock_guard<std::mutex> lock(gAccessorProvidersMutex); std::shared_ptr<AccessorProvider> provider = Loading libs/binder/TEST_MAPPING +3 −0 Original line number Diff line number Diff line Loading @@ -133,6 +133,9 @@ { "name": "binder_sdk_test", "host": true }, { "name": "binderCacheUnitTest" } ], "imports": [ Loading libs/binder/include/binder/IServiceManagerUnitTestHelper.h 0 → 100644 +29 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include <android/os/IServiceManager.h> #include "IServiceManager.h" namespace android { /** * Encapsulate an AidlServiceManager in a CppBackendShim. Only used for testing. */ LIBBINDER_EXPORTED sp<IServiceManager> getServiceManagerShimFromAidlServiceManagerForTests( const sp<os::IServiceManager>& sm); } // namespace android No newline at end of file Loading
libs/binder/BackendUnifiedServiceManager.cpp +117 −3 Original line number Diff line number Diff line Loading @@ -24,11 +24,111 @@ namespace android { #ifdef LIBBINDER_CLIENT_CACHE constexpr bool kUseCache = true; #else constexpr bool kUseCache = false; #endif using AidlServiceManager = android::os::IServiceManager; using IAccessor = android::os::IAccessor; static const char* kStaticCachableList[] = { "activity", "android.hardware.thermal.IThermal/default", "android.hardware.power.IPower/default", "android.frameworks.stats.IStats/default", "android.system.suspend.ISystemSuspend/default", "appops", "audio", "batterystats", "carrier_config", "connectivity", "content_capture", "device_policy", "display", "dropbox", "econtroller", "isub", "legacy_permission", "location", "media.extractor", "media.metrics", "media.player", "media.resource_manager", "netd_listener", "netstats", "network_management", "nfc", "package_native", "performance_hint", "permission", "permissionmgr", "permission_checker", "phone", "platform_compat", "power", "role", "sensorservice", "statscompanion", "telephony.registry", "thermalservice", "time_detector", "trust", "uimode", "virtualdevice", "virtualdevice_native", "webviewupdate", }; bool BinderCacheWithInvalidation::isClientSideCachingEnabled(const std::string& serviceName) { if (ProcessState::self()->getThreadPoolMaxTotalThreadCount() <= 0) { ALOGW("Thread Pool max thread count is 0. Cannot cache binder as linkToDeath cannot be " "implemented. serviceName: %s", serviceName.c_str()); return false; } for (const char* name : kStaticCachableList) { if (name == serviceName) { return true; } } return false; } binder::Status BackendUnifiedServiceManager::updateCache(const std::string& serviceName, const os::Service& service) { if (!kUseCache) { return binder::Status::ok(); } if (service.getTag() == os::Service::Tag::binder) { sp<IBinder> binder = service.get<os::Service::Tag::binder>(); if (binder && mCacheForGetService->isClientSideCachingEnabled(serviceName) && binder->isBinderAlive()) { return mCacheForGetService->setItem(serviceName, binder); } } return binder::Status::ok(); } bool BackendUnifiedServiceManager::returnIfCached(const std::string& serviceName, os::Service* _out) { if (!kUseCache) { return false; } sp<IBinder> item = mCacheForGetService->getItem(serviceName); // TODO(b/363177618): Enable caching for binders which are always null. if (item != nullptr && item->isBinderAlive()) { *_out = os::Service::make<os::Service::Tag::binder>(item); return true; } return false; } BackendUnifiedServiceManager::BackendUnifiedServiceManager(const sp<AidlServiceManager>& impl) : mTheRealServiceManager(impl) {} : mTheRealServiceManager(impl) { mCacheForGetService = std::make_shared<BinderCacheWithInvalidation>(); } sp<AidlServiceManager> BackendUnifiedServiceManager::getImpl() { return mTheRealServiceManager; Loading @@ -44,10 +144,17 @@ binder::Status BackendUnifiedServiceManager::getService(const ::std::string& nam binder::Status BackendUnifiedServiceManager::getService2(const ::std::string& name, os::Service* _out) { if (returnIfCached(name, _out)) { return binder::Status::ok(); } os::Service service; binder::Status status = mTheRealServiceManager->getService2(name, &service); if (status.isOk()) { status = toBinderService(name, service, _out); if (status.isOk()) { return toBinderService(name, service, _out); return updateCache(name, service); } } return status; } Loading @@ -55,9 +162,16 @@ binder::Status BackendUnifiedServiceManager::getService2(const ::std::string& na binder::Status BackendUnifiedServiceManager::checkService(const ::std::string& name, os::Service* _out) { os::Service service; if (returnIfCached(name, _out)) { return binder::Status::ok(); } binder::Status status = mTheRealServiceManager->checkService(name, &service); if (status.isOk()) { return toBinderService(name, service, _out); status = toBinderService(name, service, _out); if (status.isOk()) { return updateCache(name, service); } } return status; } Loading
libs/binder/BackendUnifiedServiceManager.h +81 −0 Original line number Diff line number Diff line Loading @@ -18,9 +18,87 @@ #include <android/os/BnServiceManager.h> #include <android/os/IServiceManager.h> #include <binder/IPCThreadState.h> #include <map> #include <memory> namespace android { class BinderCacheWithInvalidation : public std::enable_shared_from_this<BinderCacheWithInvalidation> { class BinderInvalidation : public IBinder::DeathRecipient { public: BinderInvalidation(std::weak_ptr<BinderCacheWithInvalidation> cache, const std::string& key) : mCache(cache), mKey(key) {} void binderDied(const wp<IBinder>& who) override { sp<IBinder> binder = who.promote(); if (std::shared_ptr<BinderCacheWithInvalidation> cache = mCache.lock()) { cache->removeItem(mKey, binder); } else { ALOGI("Binder Cache pointer expired: %s", mKey.c_str()); } } private: std::weak_ptr<BinderCacheWithInvalidation> mCache; std::string mKey; }; struct Entry { sp<IBinder> service; sp<BinderInvalidation> deathRecipient; }; public: sp<IBinder> getItem(const std::string& key) const { std::lock_guard<std::mutex> lock(mCacheMutex); if (auto it = mCache.find(key); it != mCache.end()) { return it->second.service; } return nullptr; } bool removeItem(const std::string& key, const sp<IBinder>& who) { std::lock_guard<std::mutex> lock(mCacheMutex); if (auto it = mCache.find(key); it != mCache.end()) { if (it->second.service == who) { status_t result = who->unlinkToDeath(it->second.deathRecipient); if (result != DEAD_OBJECT) { ALOGW("Unlinking to dead binder resulted in: %d", result); } mCache.erase(key); return true; } } return false; } binder::Status setItem(const std::string& key, const sp<IBinder>& item) { sp<BinderInvalidation> deathRecipient = sp<BinderInvalidation>::make(shared_from_this(), key); // linkToDeath if binder is a remote binder. if (item->localBinder() == nullptr) { status_t status = item->linkToDeath(deathRecipient); if (status != android::OK) { ALOGE("Failed to linkToDeath binder for service %s. Error: %d", key.c_str(), status); return binder::Status::fromStatusT(status); } } std::lock_guard<std::mutex> lock(mCacheMutex); Entry entry = {.service = item, .deathRecipient = deathRecipient}; mCache[key] = entry; return binder::Status::ok(); } bool isClientSideCachingEnabled(const std::string& serviceName); private: std::map<std::string, Entry> mCache; mutable std::mutex mCacheMutex; }; class BackendUnifiedServiceManager : public android::os::BnServiceManager { public: explicit BackendUnifiedServiceManager(const sp<os::IServiceManager>& impl); Loading Loading @@ -58,9 +136,12 @@ public: } private: std::shared_ptr<BinderCacheWithInvalidation> mCacheForGetService; sp<os::IServiceManager> mTheRealServiceManager; binder::Status toBinderService(const ::std::string& name, const os::Service& in, os::Service* _out); binder::Status updateCache(const std::string& serviceName, const os::Service& service); bool returnIfCached(const std::string& serviceName, os::Service* _out); }; sp<BackendUnifiedServiceManager> getBackendUnifiedServiceManager(); Loading
libs/binder/IServiceManager.cpp +6 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ #define LOG_TAG "ServiceManagerCppClient" #include <binder/IServiceManager.h> #include <binder/IServiceManagerUnitTestHelper.h> #include "BackendUnifiedServiceManager.h" #include <inttypes.h> Loading Loading @@ -311,6 +312,11 @@ void setDefaultServiceManager(const sp<IServiceManager>& sm) { } } sp<IServiceManager> getServiceManagerShimFromAidlServiceManagerForTests( const sp<AidlServiceManager>& sm) { return sp<CppBackendShim>::make(sp<BackendUnifiedServiceManager>::make(sm)); } std::weak_ptr<AccessorProvider> addAccessorProvider(RpcAccessorProvider&& providerCallback) { std::lock_guard<std::mutex> lock(gAccessorProvidersMutex); std::shared_ptr<AccessorProvider> provider = Loading
libs/binder/TEST_MAPPING +3 −0 Original line number Diff line number Diff line Loading @@ -133,6 +133,9 @@ { "name": "binder_sdk_test", "host": true }, { "name": "binderCacheUnitTest" } ], "imports": [ Loading
libs/binder/include/binder/IServiceManagerUnitTestHelper.h 0 → 100644 +29 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include <android/os/IServiceManager.h> #include "IServiceManager.h" namespace android { /** * Encapsulate an AidlServiceManager in a CppBackendShim. Only used for testing. */ LIBBINDER_EXPORTED sp<IServiceManager> getServiceManagerShimFromAidlServiceManagerForTests( const sp<os::IServiceManager>& sm); } // namespace android No newline at end of file