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
diff --git a/libs/binder/BackendUnifiedServiceManager.cpp b/libs/binder/BackendUnifiedServiceManager.cpp
index 9d0a557..ee3d6af 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::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 @@
                                      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 6a0d06a..2496f62 100644
--- a/libs/binder/BackendUnifiedServiceManager.h
+++ b/libs/binder/BackendUnifiedServiceManager.h
@@ -167,5 +167,9 @@
 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 53435c3..5c72ed3 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -304,6 +304,25 @@
     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 da5a8e3..9f656ec 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -1328,6 +1328,109 @@
     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,