diff options
author | 2024-10-23 19:29:49 +0000 | |
---|---|---|
committer | 2025-01-03 21:37:10 +0000 | |
commit | a3867c739a80d0c8a58dcb00bcae8f98afdc78ef (patch) | |
tree | 5bf41f147391b2bc923398563857c6a4d814c892 | |
parent | 3c93111ce80d2d7ea3375c39d75bf7dd54f3e15b (diff) |
Add listServices/isDeclared/getDeclaredInstances for Accessors
We associate specific accessors with instance names, so we can get
more information about what is available through the existing service
manager APIs.
Test: atest binderRpcTest
Bug: 358427181
Change-Id: I337430a222b537643351bfc70178ccd1dc06d73b
-rw-r--r-- | libs/binder/BackendUnifiedServiceManager.cpp | 47 | ||||
-rw-r--r-- | libs/binder/BackendUnifiedServiceManager.h | 4 | ||||
-rw-r--r-- | libs/binder/IServiceManager.cpp | 19 | ||||
-rw-r--r-- | libs/binder/tests/binderRpcTest.cpp | 103 |
4 files changed, 164 insertions, 9 deletions
diff --git a/libs/binder/BackendUnifiedServiceManager.cpp b/libs/binder/BackendUnifiedServiceManager.cpp index 9d0a557f4e..ee3d6af742 100644 --- a/libs/binder/BackendUnifiedServiceManager.cpp +++ b/libs/binder/BackendUnifiedServiceManager.cpp @@ -15,6 +15,7 @@ */ #include "BackendUnifiedServiceManager.h" +#include <android-base/strings.h> #include <android/os/IAccessor.h> #include <android/os/IServiceManager.h> #include <binder/RpcSession.h> @@ -339,11 +340,15 @@ Status BackendUnifiedServiceManager::addService(const ::std::string& name, } Status BackendUnifiedServiceManager::listServices(int32_t dumpPriority, ::std::vector<::std::string>* _aidl_return) { + Status status = Status::ok(); if (mTheRealServiceManager) { - return mTheRealServiceManager->listServices(dumpPriority, _aidl_return); + status = mTheRealServiceManager->listServices(dumpPriority, _aidl_return); } - return Status::fromExceptionCode(Status::EX_UNSUPPORTED_OPERATION, - kUnsupportedOpNoServiceManager); + if (!status.isOk()) return status; + + appendInjectedAccessorServices(_aidl_return); + + return status; } Status BackendUnifiedServiceManager::registerForNotifications( const ::std::string& name, const sp<os::IServiceCallback>& callback) { @@ -362,19 +367,43 @@ Status BackendUnifiedServiceManager::unregisterForNotifications( kUnsupportedOpNoServiceManager); } Status BackendUnifiedServiceManager::isDeclared(const ::std::string& name, bool* _aidl_return) { + Status status = Status::ok(); if (mTheRealServiceManager) { - return mTheRealServiceManager->isDeclared(name, _aidl_return); + status = mTheRealServiceManager->isDeclared(name, _aidl_return); } - return Status::fromExceptionCode(Status::EX_UNSUPPORTED_OPERATION, - kUnsupportedOpNoServiceManager); + if (!status.isOk()) return status; + + if (!*_aidl_return) { + forEachInjectedAccessorService([&](const std::string& instance) { + if (name == instance) { + *_aidl_return = true; + } + }); + } + + return status; } Status BackendUnifiedServiceManager::getDeclaredInstances( const ::std::string& iface, ::std::vector<::std::string>* _aidl_return) { + Status status = Status::ok(); if (mTheRealServiceManager) { - return mTheRealServiceManager->getDeclaredInstances(iface, _aidl_return); + status = mTheRealServiceManager->getDeclaredInstances(iface, _aidl_return); } - return Status::fromExceptionCode(Status::EX_UNSUPPORTED_OPERATION, - kUnsupportedOpNoServiceManager); + if (!status.isOk()) return status; + + forEachInjectedAccessorService([&](const std::string& instance) { + // Declared instances have the format + // <interface>/instance like foo.bar.ISomething/instance + // If it does not have that format, consider the instance to be "" + std::string_view name(instance); + if (base::ConsumePrefix(&name, iface + "/")) { + _aidl_return->emplace_back(name); + } else if (iface == instance) { + _aidl_return->push_back(""); + } + }); + + return status; } Status BackendUnifiedServiceManager::updatableViaApex( const ::std::string& name, ::std::optional<::std::string>* _aidl_return) { diff --git a/libs/binder/BackendUnifiedServiceManager.h b/libs/binder/BackendUnifiedServiceManager.h index 6a0d06a079..2496f62503 100644 --- a/libs/binder/BackendUnifiedServiceManager.h +++ b/libs/binder/BackendUnifiedServiceManager.h @@ -167,5 +167,9 @@ private: sp<BackendUnifiedServiceManager> getBackendUnifiedServiceManager(); android::binder::Status getInjectedAccessor(const std::string& name, android::os::Service* service); +void appendInjectedAccessorServices(std::vector<std::string>* list); +// Do not call any other service manager APIs that might take the accessor +// mutex because this will be holding it! +void forEachInjectedAccessorService(const std::function<void(const std::string&)>& f); } // namespace android diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp index 53435c357b..5c72ed3197 100644 --- a/libs/binder/IServiceManager.cpp +++ b/libs/binder/IServiceManager.cpp @@ -304,6 +304,25 @@ android::binder::Status getInjectedAccessor(const std::string& name, return android::binder::Status::ok(); } +void appendInjectedAccessorServices(std::vector<std::string>* list) { + LOG_ALWAYS_FATAL_IF(list == nullptr, + "Attempted to get list of services from Accessors with nullptr"); + std::lock_guard<std::mutex> lock(gAccessorProvidersMutex); + for (const auto& entry : gAccessorProviders) { + list->insert(list->end(), entry.mProvider->instances().begin(), + entry.mProvider->instances().end()); + } +} + +void forEachInjectedAccessorService(const std::function<void(const std::string&)>& f) { + std::lock_guard<std::mutex> lock(gAccessorProvidersMutex); + for (const auto& entry : gAccessorProviders) { + for (const auto& instance : entry.mProvider->instances()) { + f(instance); + } + } +} + sp<IServiceManager> defaultServiceManager() { std::call_once(gSmOnce, []() { diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp index da5a8e3881..9f656ec96c 100644 --- a/libs/binder/tests/binderRpcTest.cpp +++ b/libs/binder/tests/binderRpcTest.cpp @@ -1328,6 +1328,109 @@ TEST_P(BinderRpcAccessor, InjectNoSockaddrProvided) { EXPECT_EQ(status, OK); } +class BinderRpcAccessorNoConnection : public ::testing::Test {}; + +TEST_F(BinderRpcAccessorNoConnection, listServices) { + const String16 kInstanceName("super.cool.service/better_than_default"); + const String16 kInstanceName2("super.cool.service/better_than_default2"); + + auto receipt = + addAccessorProvider({String8(kInstanceName).c_str(), String8(kInstanceName2).c_str()}, + [&](const String16&) -> sp<IBinder> { return nullptr; }); + EXPECT_FALSE(receipt.expired()); + Vector<String16> list = + defaultServiceManager()->listServices(IServiceManager::DUMP_FLAG_PRIORITY_ALL); + bool name1 = false; + bool name2 = false; + for (auto name : list) { + if (name == kInstanceName) name1 = true; + if (name == kInstanceName2) name2 = true; + } + EXPECT_TRUE(name1); + EXPECT_TRUE(name2); + status_t status = removeAccessorProvider(receipt); + EXPECT_EQ(status, OK); +} + +TEST_F(BinderRpcAccessorNoConnection, isDeclared) { + const String16 kInstanceName("super.cool.service/default"); + const String16 kInstanceName2("still_counts_as_declared"); + + auto receipt = + addAccessorProvider({String8(kInstanceName).c_str(), String8(kInstanceName2).c_str()}, + [&](const String16&) -> sp<IBinder> { return nullptr; }); + EXPECT_FALSE(receipt.expired()); + EXPECT_TRUE(defaultServiceManager()->isDeclared(kInstanceName)); + EXPECT_TRUE(defaultServiceManager()->isDeclared(kInstanceName2)); + EXPECT_FALSE(defaultServiceManager()->isDeclared(String16("doesnt_exist"))); + status_t status = removeAccessorProvider(receipt); + EXPECT_EQ(status, OK); +} + +TEST_F(BinderRpcAccessorNoConnection, getDeclaredInstances) { + const String16 kInstanceName("super.cool.service.IFoo/default"); + const String16 kInstanceName2("super.cool.service.IFoo/extra/default"); + const String16 kInstanceName3("super.cool.service.IFoo"); + + auto receipt = + addAccessorProvider({String8(kInstanceName).c_str(), String8(kInstanceName2).c_str(), + String8(kInstanceName3).c_str()}, + [&](const String16&) -> sp<IBinder> { return nullptr; }); + EXPECT_FALSE(receipt.expired()); + Vector<String16> list = + defaultServiceManager()->getDeclaredInstances(String16("super.cool.service.IFoo")); + // We would prefer ASSERT_EQ here, but we must call removeAccessorProvider + EXPECT_EQ(list.size(), 3u); + if (list.size() == 3) { + bool name1 = false; + bool name2 = false; + bool name3 = false; + for (auto name : list) { + if (name == String16("default")) name1 = true; + if (name == String16("extra/default")) name2 = true; + if (name == String16()) name3 = true; + } + EXPECT_TRUE(name1) << String8(list[0]); + EXPECT_TRUE(name2) << String8(list[1]); + EXPECT_TRUE(name3) << String8(list[2]); + } + + status_t status = removeAccessorProvider(receipt); + EXPECT_EQ(status, OK); +} + +TEST_F(BinderRpcAccessorNoConnection, getDeclaredWrongInstances) { + const String16 kInstanceName("super.cool.service.IFoo"); + + auto receipt = addAccessorProvider({String8(kInstanceName).c_str()}, + [&](const String16&) -> sp<IBinder> { return nullptr; }); + EXPECT_FALSE(receipt.expired()); + Vector<String16> list = defaultServiceManager()->getDeclaredInstances(String16("unknown")); + EXPECT_TRUE(list.empty()); + + status_t status = removeAccessorProvider(receipt); + EXPECT_EQ(status, OK); +} + +TEST_F(BinderRpcAccessorNoConnection, getDeclaredInstancesSlash) { + // This is treated as if there were no '/' and the declared instance is "" + const String16 kInstanceName("super.cool.service.IFoo/"); + + auto receipt = addAccessorProvider({String8(kInstanceName).c_str()}, + [&](const String16&) -> sp<IBinder> { return nullptr; }); + EXPECT_FALSE(receipt.expired()); + Vector<String16> list = + defaultServiceManager()->getDeclaredInstances(String16("super.cool.service.IFoo")); + bool name1 = false; + for (auto name : list) { + if (name == String16("")) name1 = true; + } + EXPECT_TRUE(name1); + + status_t status = removeAccessorProvider(receipt); + EXPECT_EQ(status, OK); +} + constexpr const char* kARpcInstance = "some.instance.name.IFoo/default"; const char* kARpcSupportedServices[] = { kARpcInstance, |