Skip to content

Commit 69333d6

Browse files
Treehugger RobotGerrit Code Review
authored andcommitted
Merge "Add a cache to getService with invalidation" into main
2 parents d955e73 + b6ed0eb commit 69333d6

7 files changed

Lines changed: 474 additions & 3 deletions

File tree

libs/binder/BackendUnifiedServiceManager.cpp

Lines changed: 117 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,111 @@
2424

2525
namespace android {
2626

27+
#ifdef LIBBINDER_CLIENT_CACHE
28+
constexpr bool kUseCache = true;
29+
#else
30+
constexpr bool kUseCache = false;
31+
#endif
32+
2733
using AidlServiceManager = android::os::IServiceManager;
2834
using IAccessor = android::os::IAccessor;
2935

36+
static const char* kStaticCachableList[] = {
37+
"activity",
38+
"android.hardware.thermal.IThermal/default",
39+
"android.hardware.power.IPower/default",
40+
"android.frameworks.stats.IStats/default",
41+
"android.system.suspend.ISystemSuspend/default",
42+
"appops",
43+
"audio",
44+
"batterystats",
45+
"carrier_config",
46+
"connectivity",
47+
"content_capture",
48+
"device_policy",
49+
"display",
50+
"dropbox",
51+
"econtroller",
52+
"isub",
53+
"legacy_permission",
54+
"location",
55+
"media.extractor",
56+
"media.metrics",
57+
"media.player",
58+
"media.resource_manager",
59+
"netd_listener",
60+
"netstats",
61+
"network_management",
62+
"nfc",
63+
"package_native",
64+
"performance_hint",
65+
"permission",
66+
"permissionmgr",
67+
"permission_checker",
68+
"phone",
69+
"platform_compat",
70+
"power",
71+
"role",
72+
"sensorservice",
73+
"statscompanion",
74+
"telephony.registry",
75+
"thermalservice",
76+
"time_detector",
77+
"trust",
78+
"uimode",
79+
"virtualdevice",
80+
"virtualdevice_native",
81+
"webviewupdate",
82+
};
83+
84+
bool BinderCacheWithInvalidation::isClientSideCachingEnabled(const std::string& serviceName) {
85+
if (ProcessState::self()->getThreadPoolMaxTotalThreadCount() <= 0) {
86+
ALOGW("Thread Pool max thread count is 0. Cannot cache binder as linkToDeath cannot be "
87+
"implemented. serviceName: %s",
88+
serviceName.c_str());
89+
return false;
90+
}
91+
for (const char* name : kStaticCachableList) {
92+
if (name == serviceName) {
93+
return true;
94+
}
95+
}
96+
return false;
97+
}
98+
99+
binder::Status BackendUnifiedServiceManager::updateCache(const std::string& serviceName,
100+
const os::Service& service) {
101+
if (!kUseCache) {
102+
return binder::Status::ok();
103+
}
104+
if (service.getTag() == os::Service::Tag::binder) {
105+
sp<IBinder> binder = service.get<os::Service::Tag::binder>();
106+
if (binder && mCacheForGetService->isClientSideCachingEnabled(serviceName) &&
107+
binder->isBinderAlive()) {
108+
return mCacheForGetService->setItem(serviceName, binder);
109+
}
110+
}
111+
return binder::Status::ok();
112+
}
113+
114+
bool BackendUnifiedServiceManager::returnIfCached(const std::string& serviceName,
115+
os::Service* _out) {
116+
if (!kUseCache) {
117+
return false;
118+
}
119+
sp<IBinder> item = mCacheForGetService->getItem(serviceName);
120+
// TODO(b/363177618): Enable caching for binders which are always null.
121+
if (item != nullptr && item->isBinderAlive()) {
122+
*_out = os::Service::make<os::Service::Tag::binder>(item);
123+
return true;
124+
}
125+
return false;
126+
}
127+
30128
BackendUnifiedServiceManager::BackendUnifiedServiceManager(const sp<AidlServiceManager>& impl)
31-
: mTheRealServiceManager(impl) {}
129+
: mTheRealServiceManager(impl) {
130+
mCacheForGetService = std::make_shared<BinderCacheWithInvalidation>();
131+
}
32132

33133
sp<AidlServiceManager> BackendUnifiedServiceManager::getImpl() {
34134
return mTheRealServiceManager;
@@ -44,20 +144,34 @@ binder::Status BackendUnifiedServiceManager::getService(const ::std::string& nam
44144

45145
binder::Status BackendUnifiedServiceManager::getService2(const ::std::string& name,
46146
os::Service* _out) {
147+
if (returnIfCached(name, _out)) {
148+
return binder::Status::ok();
149+
}
47150
os::Service service;
48151
binder::Status status = mTheRealServiceManager->getService2(name, &service);
152+
49153
if (status.isOk()) {
50-
return toBinderService(name, service, _out);
154+
status = toBinderService(name, service, _out);
155+
if (status.isOk()) {
156+
return updateCache(name, service);
157+
}
51158
}
52159
return status;
53160
}
54161

55162
binder::Status BackendUnifiedServiceManager::checkService(const ::std::string& name,
56163
os::Service* _out) {
57164
os::Service service;
165+
if (returnIfCached(name, _out)) {
166+
return binder::Status::ok();
167+
}
168+
58169
binder::Status status = mTheRealServiceManager->checkService(name, &service);
59170
if (status.isOk()) {
60-
return toBinderService(name, service, _out);
171+
status = toBinderService(name, service, _out);
172+
if (status.isOk()) {
173+
return updateCache(name, service);
174+
}
61175
}
62176
return status;
63177
}

libs/binder/BackendUnifiedServiceManager.h

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,87 @@
1818
#include <android/os/BnServiceManager.h>
1919
#include <android/os/IServiceManager.h>
2020
#include <binder/IPCThreadState.h>
21+
#include <map>
22+
#include <memory>
2123

2224
namespace android {
2325

26+
class BinderCacheWithInvalidation
27+
: public std::enable_shared_from_this<BinderCacheWithInvalidation> {
28+
class BinderInvalidation : public IBinder::DeathRecipient {
29+
public:
30+
BinderInvalidation(std::weak_ptr<BinderCacheWithInvalidation> cache, const std::string& key)
31+
: mCache(cache), mKey(key) {}
32+
33+
void binderDied(const wp<IBinder>& who) override {
34+
sp<IBinder> binder = who.promote();
35+
if (std::shared_ptr<BinderCacheWithInvalidation> cache = mCache.lock()) {
36+
cache->removeItem(mKey, binder);
37+
} else {
38+
ALOGI("Binder Cache pointer expired: %s", mKey.c_str());
39+
}
40+
}
41+
42+
private:
43+
std::weak_ptr<BinderCacheWithInvalidation> mCache;
44+
std::string mKey;
45+
};
46+
struct Entry {
47+
sp<IBinder> service;
48+
sp<BinderInvalidation> deathRecipient;
49+
};
50+
51+
public:
52+
sp<IBinder> getItem(const std::string& key) const {
53+
std::lock_guard<std::mutex> lock(mCacheMutex);
54+
55+
if (auto it = mCache.find(key); it != mCache.end()) {
56+
return it->second.service;
57+
}
58+
return nullptr;
59+
}
60+
61+
bool removeItem(const std::string& key, const sp<IBinder>& who) {
62+
std::lock_guard<std::mutex> lock(mCacheMutex);
63+
if (auto it = mCache.find(key); it != mCache.end()) {
64+
if (it->second.service == who) {
65+
status_t result = who->unlinkToDeath(it->second.deathRecipient);
66+
if (result != DEAD_OBJECT) {
67+
ALOGW("Unlinking to dead binder resulted in: %d", result);
68+
}
69+
mCache.erase(key);
70+
return true;
71+
}
72+
}
73+
return false;
74+
}
75+
76+
binder::Status setItem(const std::string& key, const sp<IBinder>& item) {
77+
sp<BinderInvalidation> deathRecipient =
78+
sp<BinderInvalidation>::make(shared_from_this(), key);
79+
80+
// linkToDeath if binder is a remote binder.
81+
if (item->localBinder() == nullptr) {
82+
status_t status = item->linkToDeath(deathRecipient);
83+
if (status != android::OK) {
84+
ALOGE("Failed to linkToDeath binder for service %s. Error: %d", key.c_str(),
85+
status);
86+
return binder::Status::fromStatusT(status);
87+
}
88+
}
89+
std::lock_guard<std::mutex> lock(mCacheMutex);
90+
Entry entry = {.service = item, .deathRecipient = deathRecipient};
91+
mCache[key] = entry;
92+
return binder::Status::ok();
93+
}
94+
95+
bool isClientSideCachingEnabled(const std::string& serviceName);
96+
97+
private:
98+
std::map<std::string, Entry> mCache;
99+
mutable std::mutex mCacheMutex;
100+
};
101+
24102
class BackendUnifiedServiceManager : public android::os::BnServiceManager {
25103
public:
26104
explicit BackendUnifiedServiceManager(const sp<os::IServiceManager>& impl);
@@ -58,9 +136,12 @@ class BackendUnifiedServiceManager : public android::os::BnServiceManager {
58136
}
59137

60138
private:
139+
std::shared_ptr<BinderCacheWithInvalidation> mCacheForGetService;
61140
sp<os::IServiceManager> mTheRealServiceManager;
62141
binder::Status toBinderService(const ::std::string& name, const os::Service& in,
63142
os::Service* _out);
143+
binder::Status updateCache(const std::string& serviceName, const os::Service& service);
144+
bool returnIfCached(const std::string& serviceName, os::Service* _out);
64145
};
65146

66147
sp<BackendUnifiedServiceManager> getBackendUnifiedServiceManager();

libs/binder/IServiceManager.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#define LOG_TAG "ServiceManagerCppClient"
1919

2020
#include <binder/IServiceManager.h>
21+
#include <binder/IServiceManagerUnitTestHelper.h>
2122
#include "BackendUnifiedServiceManager.h"
2223

2324
#include <inttypes.h>
@@ -311,6 +312,11 @@ void setDefaultServiceManager(const sp<IServiceManager>& sm) {
311312
}
312313
}
313314

315+
sp<IServiceManager> getServiceManagerShimFromAidlServiceManagerForTests(
316+
const sp<AidlServiceManager>& sm) {
317+
return sp<CppBackendShim>::make(sp<BackendUnifiedServiceManager>::make(sm));
318+
}
319+
314320
std::weak_ptr<AccessorProvider> addAccessorProvider(RpcAccessorProvider&& providerCallback) {
315321
std::lock_guard<std::mutex> lock(gAccessorProvidersMutex);
316322
std::shared_ptr<AccessorProvider> provider =

libs/binder/TEST_MAPPING

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,9 @@
133133
{
134134
"name": "binder_sdk_test",
135135
"host": true
136+
},
137+
{
138+
"name": "binderCacheUnitTest"
136139
}
137140
],
138141
"imports": [
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
* Copyright (C) 2024 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#pragma once
18+
19+
#include <android/os/IServiceManager.h>
20+
#include "IServiceManager.h"
21+
namespace android {
22+
23+
/**
24+
* Encapsulate an AidlServiceManager in a CppBackendShim. Only used for testing.
25+
*/
26+
LIBBINDER_EXPORTED sp<IServiceManager> getServiceManagerShimFromAidlServiceManagerForTests(
27+
const sp<os::IServiceManager>& sm);
28+
29+
} // namespace android

libs/binder/tests/Android.bp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,30 @@ cc_test {
5151
],
5252
}
5353

54+
cc_test {
55+
name: "binderCacheUnitTest",
56+
target: {
57+
darwin: {
58+
enabled: false,
59+
},
60+
},
61+
srcs: [
62+
"binderCacheUnitTest.cpp",
63+
],
64+
shared_libs: [
65+
"liblog",
66+
"libbinder",
67+
"libcutils",
68+
"libutils",
69+
],
70+
static_libs: [
71+
"libfakeservicemanager",
72+
],
73+
defaults: ["libbinder_client_cache_flag"],
74+
test_suites: ["general-tests"],
75+
require_root: true,
76+
}
77+
5478
// unit test only, which can run on host and doesn't use /dev/binder
5579
cc_test {
5680
name: "binderUnitTest",

0 commit comments

Comments
 (0)