libbinder_ndk: expose declared services list

Fixes: 180607992
Test: libbinder_ndk_unit_test
Change-Id: Id3ae079ff3bfaf13617ce39c6ed2738d6703fbd4
diff --git a/libs/binder/ndk/include_platform/android/binder_manager.h b/libs/binder/ndk/include_platform/android/binder_manager.h
index 4580751..5df0012 100644
--- a/libs/binder/ndk/include_platform/android/binder_manager.h
+++ b/libs/binder/ndk/include_platform/android/binder_manager.h
@@ -96,6 +96,22 @@
 bool AServiceManager_isDeclared(const char* instance) __INTRODUCED_IN(31);
 
 /**
+ * Returns all declared instances for a particular interface.
+ *
+ * For instance, if 'android.foo.IFoo/foo' is declared, and 'android.foo.IFoo' is
+ * passed here, then ["foo"] would be returned.
+ *
+ * See also AServiceManager_isDeclared.
+ *
+ * \param interface interface, e.g. 'android.foo.IFoo'
+ * \param context to pass to callback
+ * \param callback taking instance (e.g. 'foo') and context
+ */
+void AServiceManager_forEachDeclaredInstance(const char* interface, void* context,
+                                             void (*callback)(const char*, void*))
+        __INTRODUCED_IN(31);
+
+/**
  * Prevent lazy services without client from shutting down their process
  *
  * \param persist 'true' if the process should not exit.
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index cef0bf3..8d08275 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -118,6 +118,7 @@
     AIBinder_getCallingSid; # apex
     AIBinder_setRequestingSid; # apex
     AServiceManager_isDeclared; # apex llndk
+    AServiceManager_forEachDeclaredInstance; # apex llndk
     AServiceManager_registerLazyService; # llndk
     AServiceManager_waitForService; # apex llndk
     AServiceManager_forceLazyServicesPersist; # llndk
diff --git a/libs/binder/ndk/service_manager.cpp b/libs/binder/ndk/service_manager.cpp
index cb0987e..1ccd0d2 100644
--- a/libs/binder/ndk/service_manager.cpp
+++ b/libs/binder/ndk/service_manager.cpp
@@ -19,6 +19,7 @@
 #include "ibinder_internal.h"
 #include "status_internal.h"
 
+#include <android-base/logging.h>
 #include <binder/IServiceManager.h>
 #include <binder/LazyServiceRegistrar.h>
 
@@ -28,6 +29,7 @@
 using ::android::sp;
 using ::android::status_t;
 using ::android::String16;
+using ::android::String8;
 
 binder_exception_t AServiceManager_addService(AIBinder* binder, const char* instance) {
     if (binder == nullptr || instance == nullptr) {
@@ -92,6 +94,17 @@
     sp<IServiceManager> sm = defaultServiceManager();
     return sm->isDeclared(String16(instance));
 }
+void AServiceManager_forEachDeclaredInstance(const char* interface, void* context,
+                                             void (*callback)(const char*, void*)) {
+    CHECK(interface != nullptr);
+    // context may be nullptr
+    CHECK(callback != nullptr);
+
+    sp<IServiceManager> sm = defaultServiceManager();
+    for (const String16& instance : sm->getDeclaredInstances(String16(interface))) {
+        callback(String8(instance).c_str(), context);
+    }
+}
 void AServiceManager_forceLazyServicesPersist(bool persist) {
     auto serviceRegistrar = android::binder::LazyServiceRegistrar::getInstance();
     serviceRegistrar.forcePersist(persist);
@@ -110,4 +123,4 @@
 void AServiceManager_reRegister() {
     auto serviceRegistrar = android::binder::LazyServiceRegistrar::getInstance();
     serviceRegistrar.reRegister();
-}
\ No newline at end of file
+}
diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
index de1a48d..6a88401 100644
--- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
+++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
@@ -270,6 +270,25 @@
     EXPECT_EQ(2, out);
 }
 
+void defaultInstanceCounter(const char* instance, void* context) {
+    if (strcmp(instance, "default") == 0) {
+        ++*(size_t*)(context);
+    }
+}
+
+TEST(NdkBinder, GetDeclaredInstances) {
+    bool hasLight = AServiceManager_isDeclared("android.hardware.light.ILights/default");
+
+    size_t count;
+    AServiceManager_forEachDeclaredInstance("android.hardware.light.ILights", &count,
+                                            defaultInstanceCounter);
+
+    // At the time of writing this test, there is no good interface guaranteed
+    // to be on all devices. Cuttlefish has light, so this will generally test
+    // things.
+    EXPECT_EQ(count, hasLight ? 1 : 0);
+}
+
 TEST(NdkBinder, GetLazyService) {
     // Not declared in the vintf manifest
     ASSERT_FALSE(AServiceManager_isDeclared(kLazyBinderNdkUnitTestService));