Add a cache to getService with invalidation

Test: atest binderCacheUnitTest
Bug: 333854840
Flag: LIBBINDER_CLIENT_CACHE
Change-Id: I1b4e8482817c422850aed7359beaf7174b55445e
diff --git a/libs/binder/BackendUnifiedServiceManager.cpp b/libs/binder/BackendUnifiedServiceManager.cpp
index fee36da..5680798 100644
--- a/libs/binder/BackendUnifiedServiceManager.cpp
+++ b/libs/binder/BackendUnifiedServiceManager.cpp
@@ -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;
@@ -44,10 +144,17 @@
 
 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()) {
-        return toBinderService(name, service, _out);
+        status = toBinderService(name, service, _out);
+        if (status.isOk()) {
+            return updateCache(name, service);
+        }
     }
     return status;
 }
@@ -55,9 +162,16 @@
 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;
 }