ServiceManager: add isDeclared
Most of the time, AIDL services exist in client/service pairs. In this
context, `while(true) getService` or `waitForService` makes sense.
However, for VINTF services, this client/server coupling isn't
guaranteed. A device may or may not have specific hardware. So, now
IServiceManager can tell a client when a server will exist so it will
know if it needs to wait for this service during boot-up. The function
waitForDeclaredService is provided for this.
These functions are generic (not referring to VINTF specifically)
because they may be expanded to include information about APEX services
in the future OR the infrastructure may be made generic to work, if
desired, on system services.
Bug: 141828236
Test: binderStabilityTest, using waitForDeclaredService function
Change-Id: Ia230625e44e1685cc3fa9230ece8f0a25c88585e
diff --git a/cmds/dumpsys/tests/dumpsys_test.cpp b/cmds/dumpsys/tests/dumpsys_test.cpp
index cf4e0b5..b9395ba 100644
--- a/cmds/dumpsys/tests/dumpsys_test.cpp
+++ b/cmds/dumpsys/tests/dumpsys_test.cpp
@@ -54,6 +54,7 @@
MOCK_METHOD4(addService, status_t(const String16&, const sp<IBinder>&, bool, int));
MOCK_METHOD1(listServices, Vector<String16>(int));
MOCK_METHOD1(waitForService, sp<IBinder>(const String16&));
+ MOCK_METHOD1(isDeclared, bool(const String16&));
protected:
MOCK_METHOD0(onAsBinder, IBinder*());
};
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index 934646d..91e89ae 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -34,11 +34,7 @@
namespace android {
#ifndef VENDORSERVICEMANAGER
-static bool meetsDeclarationRequirements(const sp<IBinder>& binder, const std::string& name) {
- if (!Stability::requiresVintfDeclaration(binder)) {
- return true;
- }
-
+static bool isVintfDeclared(const std::string& name) {
size_t firstSlash = name.find('/');
size_t lastDot = name.rfind('.', firstSlash);
if (firstSlash == std::string::npos || lastDot == std::string::npos) {
@@ -62,6 +58,14 @@
<< " in the VINTF manifest.";
return false;
}
+
+static bool meetsDeclarationRequirements(const sp<IBinder>& binder, const std::string& name) {
+ if (!Stability::requiresVintfDeclaration(binder)) {
+ return true;
+ }
+
+ return isVintfDeclared(name);
+}
#endif // !VENDORSERVICEMANAGER
ServiceManager::ServiceManager(std::unique_ptr<Access>&& access) : mAccess(std::move(access)) {}
@@ -270,6 +274,21 @@
return Status::ok();
}
+Status ServiceManager::isDeclared(const std::string& name, bool* outReturn) {
+ auto ctx = mAccess->getCallingContext();
+
+ if (!mAccess->canFind(ctx, name)) {
+ return Status::fromExceptionCode(Status::EX_SECURITY);
+ }
+
+ *outReturn = false;
+
+#ifndef VENDORSERVICEMANAGER
+ *outReturn = isVintfDeclared(name);
+#endif
+ return Status::ok();
+}
+
void ServiceManager::removeCallback(const wp<IBinder>& who,
CallbackMap::iterator* it,
bool* found) {
diff --git a/cmds/servicemanager/ServiceManager.h b/cmds/servicemanager/ServiceManager.h
index 006e519..7dcdaa4 100644
--- a/cmds/servicemanager/ServiceManager.h
+++ b/cmds/servicemanager/ServiceManager.h
@@ -40,6 +40,7 @@
const sp<IServiceCallback>& callback) override;
binder::Status unregisterForNotifications(const std::string& name,
const sp<IServiceCallback>& callback) override;
+ binder::Status isDeclared(const std::string& name, bool* outReturn) override;
void binderDied(const wp<IBinder>& who) override;
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index a30df14..4f47db1 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -72,6 +72,7 @@
bool allowIsolated, int dumpsysPriority) override;
Vector<String16> listServices(int dumpsysPriority) override;
sp<IBinder> waitForService(const String16& name16) override;
+ bool isDeclared(const String16& name) override;
// for legacy ABI
const String16& getInterfaceDescriptor() const override {
@@ -321,4 +322,12 @@
}
}
+bool ServiceManagerShim::isDeclared(const String16& name) {
+ bool declared;
+ if (!mTheRealServiceManager->isDeclared(String8(name).c_str(), &declared).isOk()) {
+ return false;
+ }
+ return declared;
+}
+
} // namespace android
diff --git a/libs/binder/aidl/android/os/IServiceManager.aidl b/libs/binder/aidl/android/os/IServiceManager.aidl
index 471b63f..8c7ebba 100644
--- a/libs/binder/aidl/android/os/IServiceManager.aidl
+++ b/libs/binder/aidl/android/os/IServiceManager.aidl
@@ -89,4 +89,11 @@
* Unregisters all requests for notifications for a specific callback.
*/
void unregisterForNotifications(@utf8InCpp String name, IServiceCallback callback);
+
+ /**
+ * Returns whether a given interface is declared on the device, even if it
+ * is not started yet. For instance, this could be a service declared in the VINTF
+ * manifest.
+ */
+ boolean isDeclared(@utf8InCpp String name);
}
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index a675513..4a44c5a 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -88,6 +88,14 @@
* Returns nullptr only for permission problem or fatal error.
*/
virtual sp<IBinder> waitForService(const String16& name) = 0;
+
+ /**
+ * Check if a service is declared (e.g. VINTF manifest).
+ *
+ * If this returns true, waitForService should always be able to return the
+ * service.
+ */
+ virtual bool isDeclared(const String16& name) = 0;
};
sp<IServiceManager> defaultServiceManager();
@@ -99,6 +107,13 @@
}
template<typename INTERFACE>
+sp<INTERFACE> waitForDeclaredService(const String16& name) {
+ const sp<IServiceManager> sm = defaultServiceManager();
+ if (!sm->isDeclared(name)) return nullptr;
+ return interface_cast<INTERFACE>(sm->waitForService(name));
+}
+
+template<typename INTERFACE>
status_t getService(const String16& name, sp<INTERFACE>* outService)
{
const sp<IServiceManager> sm = defaultServiceManager();
diff --git a/libs/binder/tests/binderStabilityTest.cpp b/libs/binder/tests/binderStabilityTest.cpp
index 0bee56c..1f2779a 100644
--- a/libs/binder/tests/binderStabilityTest.cpp
+++ b/libs/binder/tests/binderStabilityTest.cpp
@@ -134,18 +134,15 @@
TEST(BinderStability, VintfStabilityServerMustBeDeclaredInManifest) {
sp<IBinder> vintfServer = BadStableBinder::vintf();
- EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
- android::defaultServiceManager()->addService(String16("."), vintfServer));
- EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
- android::defaultServiceManager()->addService(String16("/"), vintfServer));
- EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
- android::defaultServiceManager()->addService(String16("/."), vintfServer));
- EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
- android::defaultServiceManager()->addService(String16("a.d.IFoo"), vintfServer));
- EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
- android::defaultServiceManager()->addService(String16("foo"), vintfServer));
- EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
- android::defaultServiceManager()->addService(String16("a.d.IFoo/foo"), vintfServer));
+ for (const char* instance8 : {
+ ".", "/", "/.", "a.d.IFoo", "foo", "a.d.IFoo/foo"
+ }) {
+ String16 instance (instance8);
+
+ EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
+ android::defaultServiceManager()->addService(String16("."), vintfServer)) << instance8;
+ EXPECT_FALSE(android::defaultServiceManager()->isDeclared(instance)) << instance8;
+ }
}
TEST(BinderStability, CantCallVendorBinderInSystemContext) {