| /* |
| * 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. |
| */ |
| #include "BackendUnifiedServiceManager.h" |
| |
| #include <android/os/IAccessor.h> |
| #include <android/os/IServiceManager.h> |
| #include <binder/RpcSession.h> |
| |
| #if defined(__BIONIC__) && !defined(__ANDROID_VNDK__) |
| #include <android-base/properties.h> |
| #endif |
| |
| namespace android { |
| |
| #ifdef LIBBINDER_CLIENT_CACHE |
| constexpr bool kUseCache = true; |
| #else |
| constexpr bool kUseCache = false; |
| #endif |
| |
| #ifdef LIBBINDER_ADDSERVICE_CACHE |
| constexpr bool kUseCacheInAddService = true; |
| #else |
| constexpr bool kUseCacheInAddService = false; |
| #endif |
| |
| #ifdef LIBBINDER_REMOVE_CACHE_STATIC_LIST |
| constexpr bool kRemoveStaticList = true; |
| #else |
| constexpr bool kRemoveStaticList = false; |
| #endif |
| |
| using AidlServiceManager = android::os::IServiceManager; |
| using android::os::IAccessor; |
| using binder::Status; |
| |
| static const char* kStaticCachableList[] = { |
| // go/keep-sorted start |
| "accessibility", |
| "account", |
| "activity", |
| "alarm", |
| "android.frameworks.stats.IStats/default", |
| "android.system.keystore2.IKeystoreService/default", |
| "appops", |
| "audio", |
| "autofill", |
| "batteryproperties", |
| "batterystats", |
| "biometic", |
| "carrier_config", |
| "connectivity", |
| "content", |
| "content_capture", |
| "device_policy", |
| "display", |
| "dropbox", |
| "econtroller", |
| "graphicsstats", |
| "input", |
| "input_method", |
| "isub", |
| "jobscheduler", |
| "legacy_permission", |
| "location", |
| "lock_settings", |
| "media.extractor", |
| "media.metrics", |
| "media.player", |
| "media.resource_manager", |
| "media_resource_monitor", |
| "mount", |
| "netd_listener", |
| "netstats", |
| "network_management", |
| "nfc", |
| "notification", |
| "package", |
| "package_native", |
| "performance_hint", |
| "permission", |
| "permission_checker", |
| "permissionmgr", |
| "phone", |
| "platform_compat", |
| "power", |
| "processinfo", |
| "role", |
| "sensitive_content_protection_service", |
| "sensorservice", |
| "statscompanion", |
| "telephony.registry", |
| "thermalservice", |
| "time_detector", |
| "tracing.proxy", |
| "trust", |
| "uimode", |
| "user", |
| "vibrator", |
| "virtualdevice", |
| "virtualdevice_native", |
| "webviewupdate", |
| "window", |
| // go/keep-sorted end |
| }; |
| |
| os::ServiceWithMetadata createServiceWithMetadata(const sp<IBinder>& service, bool isLazyService) { |
| os::ServiceWithMetadata out = os::ServiceWithMetadata(); |
| out.service = service; |
| out.isLazyService = isLazyService; |
| return out; |
| } |
| |
| bool BinderCacheWithInvalidation::isClientSideCachingEnabled(const std::string& serviceName) { |
| sp<ProcessState> self = ProcessState::selfOrNull(); |
| if (!self || 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; |
| } |
| if (kRemoveStaticList) return true; |
| for (const char* name : kStaticCachableList) { |
| if (name == serviceName) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| Status BackendUnifiedServiceManager::updateCache(const std::string& serviceName, |
| const os::Service& service) { |
| if (!kUseCache) { |
| return Status::ok(); |
| } |
| |
| if (service.getTag() == os::Service::Tag::serviceWithMetadata) { |
| auto serviceWithMetadata = service.get<os::Service::Tag::serviceWithMetadata>(); |
| return updateCache(serviceName, serviceWithMetadata.service, |
| serviceWithMetadata.isLazyService); |
| } |
| return Status::ok(); |
| } |
| |
| Status BackendUnifiedServiceManager::updateCache(const std::string& serviceName, |
| const sp<IBinder>& binder, bool isServiceLazy) { |
| std::string traceStr; |
| // Don't cache if service is lazy |
| if (kRemoveStaticList && isServiceLazy) { |
| return Status::ok(); |
| } |
| if (atrace_is_tag_enabled(ATRACE_TAG_AIDL)) { |
| traceStr = "BinderCacheWithInvalidation::updateCache : " + serviceName; |
| } |
| binder::ScopedTrace aidlTrace(ATRACE_TAG_AIDL, traceStr.c_str()); |
| if (!binder) { |
| binder::ScopedTrace |
| aidlTrace(ATRACE_TAG_AIDL, |
| "BinderCacheWithInvalidation::updateCache failed: binder_null"); |
| } else if (!binder->isBinderAlive()) { |
| binder::ScopedTrace aidlTrace(ATRACE_TAG_AIDL, |
| "BinderCacheWithInvalidation::updateCache failed: " |
| "isBinderAlive_false"); |
| } |
| // If we reach here with kRemoveStaticList=true then we know service isn't lazy |
| else if (mCacheForGetService->isClientSideCachingEnabled(serviceName)) { |
| binder::ScopedTrace aidlTrace(ATRACE_TAG_AIDL, |
| "BinderCacheWithInvalidation::updateCache successful"); |
| return mCacheForGetService->setItem(serviceName, binder); |
| } else { |
| binder::ScopedTrace aidlTrace(ATRACE_TAG_AIDL, |
| "BinderCacheWithInvalidation::updateCache failed: " |
| "caching_not_enabled"); |
| } |
| return 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 = createServiceWithMetadata(item, false); |
| return true; |
| } |
| return false; |
| } |
| |
| BackendUnifiedServiceManager::BackendUnifiedServiceManager(const sp<AidlServiceManager>& impl) |
| : mTheRealServiceManager(impl) { |
| mCacheForGetService = std::make_shared<BinderCacheWithInvalidation>(); |
| } |
| |
| Status BackendUnifiedServiceManager::getService(const ::std::string& name, |
| sp<IBinder>* _aidl_return) { |
| os::Service service; |
| Status status = getService2(name, &service); |
| *_aidl_return = service.get<os::Service::Tag::serviceWithMetadata>().service; |
| return status; |
| } |
| |
| Status BackendUnifiedServiceManager::getService2(const ::std::string& name, os::Service* _out) { |
| if (returnIfCached(name, _out)) { |
| return Status::ok(); |
| } |
| os::Service service; |
| Status status = mTheRealServiceManager->getService2(name, &service); |
| |
| if (status.isOk()) { |
| status = toBinderService(name, service, _out); |
| if (status.isOk()) { |
| return updateCache(name, service); |
| } |
| } |
| return status; |
| } |
| |
| Status BackendUnifiedServiceManager::checkService(const ::std::string& name, os::Service* _out) { |
| os::Service service; |
| if (returnIfCached(name, _out)) { |
| return Status::ok(); |
| } |
| |
| Status status = mTheRealServiceManager->checkService(name, &service); |
| if (status.isOk()) { |
| status = toBinderService(name, service, _out); |
| if (status.isOk()) { |
| return updateCache(name, service); |
| } |
| } |
| return status; |
| } |
| |
| Status BackendUnifiedServiceManager::toBinderService(const ::std::string& name, |
| const os::Service& in, os::Service* _out) { |
| switch (in.getTag()) { |
| case os::Service::Tag::serviceWithMetadata: { |
| auto serviceWithMetadata = in.get<os::Service::Tag::serviceWithMetadata>(); |
| if (serviceWithMetadata.service == nullptr) { |
| // failed to find a service. Check to see if we have any local |
| // injected Accessors for this service. |
| os::Service accessor; |
| Status status = getInjectedAccessor(name, &accessor); |
| if (!status.isOk()) { |
| *_out = os::Service::make<os::Service::Tag::serviceWithMetadata>( |
| createServiceWithMetadata(nullptr, false)); |
| return status; |
| } |
| if (accessor.getTag() == os::Service::Tag::accessor && |
| accessor.get<os::Service::Tag::accessor>() != nullptr) { |
| ALOGI("Found local injected service for %s, will attempt to create connection", |
| name.c_str()); |
| // Call this again using the accessor Service to get the real |
| // service's binder into _out |
| return toBinderService(name, accessor, _out); |
| } |
| } |
| |
| *_out = in; |
| return Status::ok(); |
| } |
| case os::Service::Tag::accessor: { |
| sp<IBinder> accessorBinder = in.get<os::Service::Tag::accessor>(); |
| sp<IAccessor> accessor = interface_cast<IAccessor>(accessorBinder); |
| if (accessor == nullptr) { |
| ALOGE("Service#accessor doesn't have accessor. VM is maybe starting..."); |
| *_out = os::Service::make<os::Service::Tag::serviceWithMetadata>( |
| createServiceWithMetadata(nullptr, false)); |
| return Status::ok(); |
| } |
| auto request = [=] { |
| os::ParcelFileDescriptor fd; |
| Status ret = accessor->addConnection(&fd); |
| if (ret.isOk()) { |
| return base::unique_fd(fd.release()); |
| } else { |
| ALOGE("Failed to connect to RpcSession: %s", ret.toString8().c_str()); |
| return base::unique_fd(-1); |
| } |
| }; |
| auto session = RpcSession::make(); |
| status_t status = session->setupPreconnectedClient(base::unique_fd{}, request); |
| if (status != OK) { |
| ALOGE("Failed to set up preconnected binder RPC client: %s", |
| statusToString(status).c_str()); |
| return Status::fromStatusT(status); |
| } |
| session->setSessionSpecificRoot(accessorBinder); |
| *_out = os::Service::make<os::Service::Tag::serviceWithMetadata>( |
| createServiceWithMetadata(session->getRootObject(), false)); |
| return Status::ok(); |
| } |
| default: { |
| LOG_ALWAYS_FATAL("Unknown service type: %d", in.getTag()); |
| } |
| } |
| } |
| |
| Status BackendUnifiedServiceManager::addService(const ::std::string& name, |
| const sp<IBinder>& service, bool allowIsolated, |
| int32_t dumpPriority) { |
| Status status = mTheRealServiceManager->addService(name, service, allowIsolated, dumpPriority); |
| // mEnableAddServiceCache is true by default. |
| if (kUseCacheInAddService && mEnableAddServiceCache && status.isOk()) { |
| return updateCache(name, service, |
| dumpPriority & android::os::IServiceManager::FLAG_IS_LAZY_SERVICE); |
| } |
| return status; |
| } |
| Status BackendUnifiedServiceManager::listServices(int32_t dumpPriority, |
| ::std::vector<::std::string>* _aidl_return) { |
| return mTheRealServiceManager->listServices(dumpPriority, _aidl_return); |
| } |
| Status BackendUnifiedServiceManager::registerForNotifications( |
| const ::std::string& name, const sp<os::IServiceCallback>& callback) { |
| return mTheRealServiceManager->registerForNotifications(name, callback); |
| } |
| Status BackendUnifiedServiceManager::unregisterForNotifications( |
| const ::std::string& name, const sp<os::IServiceCallback>& callback) { |
| return mTheRealServiceManager->unregisterForNotifications(name, callback); |
| } |
| Status BackendUnifiedServiceManager::isDeclared(const ::std::string& name, bool* _aidl_return) { |
| return mTheRealServiceManager->isDeclared(name, _aidl_return); |
| } |
| Status BackendUnifiedServiceManager::getDeclaredInstances( |
| const ::std::string& iface, ::std::vector<::std::string>* _aidl_return) { |
| return mTheRealServiceManager->getDeclaredInstances(iface, _aidl_return); |
| } |
| Status BackendUnifiedServiceManager::updatableViaApex( |
| const ::std::string& name, ::std::optional<::std::string>* _aidl_return) { |
| return mTheRealServiceManager->updatableViaApex(name, _aidl_return); |
| } |
| Status BackendUnifiedServiceManager::getUpdatableNames(const ::std::string& apexName, |
| ::std::vector<::std::string>* _aidl_return) { |
| return mTheRealServiceManager->getUpdatableNames(apexName, _aidl_return); |
| } |
| Status BackendUnifiedServiceManager::getConnectionInfo( |
| const ::std::string& name, ::std::optional<os::ConnectionInfo>* _aidl_return) { |
| return mTheRealServiceManager->getConnectionInfo(name, _aidl_return); |
| } |
| Status BackendUnifiedServiceManager::registerClientCallback( |
| const ::std::string& name, const sp<IBinder>& service, |
| const sp<os::IClientCallback>& callback) { |
| return mTheRealServiceManager->registerClientCallback(name, service, callback); |
| } |
| Status BackendUnifiedServiceManager::tryUnregisterService(const ::std::string& name, |
| const sp<IBinder>& service) { |
| return mTheRealServiceManager->tryUnregisterService(name, service); |
| } |
| Status BackendUnifiedServiceManager::getServiceDebugInfo( |
| ::std::vector<os::ServiceDebugInfo>* _aidl_return) { |
| return mTheRealServiceManager->getServiceDebugInfo(_aidl_return); |
| } |
| |
| [[clang::no_destroy]] static std::once_flag gUSmOnce; |
| [[clang::no_destroy]] static sp<BackendUnifiedServiceManager> gUnifiedServiceManager; |
| |
| sp<BackendUnifiedServiceManager> getBackendUnifiedServiceManager() { |
| std::call_once(gUSmOnce, []() { |
| #if defined(__BIONIC__) && !defined(__ANDROID_VNDK__) |
| /* wait for service manager */ { |
| using std::literals::chrono_literals::operator""s; |
| using android::base::WaitForProperty; |
| while (!WaitForProperty("servicemanager.ready", "true", 1s)) { |
| ALOGE("Waited for servicemanager.ready for a second, waiting another..."); |
| } |
| } |
| #endif |
| |
| sp<AidlServiceManager> sm = nullptr; |
| while (sm == nullptr) { |
| sm = interface_cast<AidlServiceManager>( |
| ProcessState::self()->getContextObject(nullptr)); |
| if (sm == nullptr) { |
| ALOGE("Waiting 1s on context object on %s.", |
| ProcessState::self()->getDriverName().c_str()); |
| sleep(1); |
| } |
| } |
| |
| gUnifiedServiceManager = sp<BackendUnifiedServiceManager>::make(sm); |
| }); |
| |
| return gUnifiedServiceManager; |
| } |
| |
| } // namespace android |