servicemanager: expose updatable-via-apex
Service manager is already reading VINTF, so processes that need this
information can access this information w/o needing more permissions.
Bug: 185832616
Test: two added tests + manually specifying updatable-via-apex on a
service and checking the result
Change-Id: Id86a72d49466048a3e2173e40526981abb6f3123
diff --git a/cmds/dumpsys/tests/dumpsys_test.cpp b/cmds/dumpsys/tests/dumpsys_test.cpp
index 67a77f6..0ad2564 100644
--- a/cmds/dumpsys/tests/dumpsys_test.cpp
+++ b/cmds/dumpsys/tests/dumpsys_test.cpp
@@ -56,6 +56,7 @@
MOCK_METHOD1(waitForService, sp<IBinder>(const String16&));
MOCK_METHOD1(isDeclared, bool(const String16&));
MOCK_METHOD1(getDeclaredInstances, Vector<String16>(const String16&));
+ MOCK_METHOD1(updatableViaApex, std::optional<String16>(const String16&));
protected:
MOCK_METHOD0(onAsBinder, IBinder*());
};
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index 2f55249..b429fb3 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -58,22 +58,34 @@
return false;
}
-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) {
- LOG(ERROR) << "VINTF HALs require names in the format type/instance (e.g. "
- << "some.package.foo.IFoo/default) but got: " << name;
- return false;
- }
- const std::string package = name.substr(0, lastDot);
- const std::string iface = name.substr(lastDot+1, firstSlash-lastDot-1);
- const std::string instance = name.substr(firstSlash+1);
+struct AidlName {
+ std::string package;
+ std::string iface;
+ std::string instance;
- bool found = forEachManifest([&] (const ManifestWithDescription& mwd) {
- if (mwd.manifest->hasAidlInstance(package, iface, instance)) {
+ static bool fill(const std::string& name, AidlName* aname) {
+ size_t firstSlash = name.find('/');
+ size_t lastDot = name.rfind('.', firstSlash);
+ if (firstSlash == std::string::npos || lastDot == std::string::npos) {
+ LOG(ERROR) << "VINTF HALs require names in the format type/instance (e.g. "
+ << "some.package.foo.IFoo/default) but got: " << name;
+ return false;
+ }
+ aname->package = name.substr(0, lastDot);
+ aname->iface = name.substr(lastDot + 1, firstSlash - lastDot - 1);
+ aname->instance = name.substr(firstSlash + 1);
+ return true;
+ }
+};
+
+static bool isVintfDeclared(const std::string& name) {
+ AidlName aname;
+ if (!AidlName::fill(name, &aname)) return false;
+
+ bool found = forEachManifest([&](const ManifestWithDescription& mwd) {
+ if (mwd.manifest->hasAidlInstance(aname.package, aname.iface, aname.instance)) {
LOG(INFO) << "Found " << name << " in " << mwd.description << " VINTF manifest.";
- return true;
+ return true; // break
}
return false; // continue
});
@@ -81,13 +93,34 @@
if (!found) {
// Although it is tested, explicitly rebuilding qualified name, in case it
// becomes something unexpected.
- LOG(ERROR) << "Could not find " << package << "." << iface << "/" << instance
- << " in the VINTF manifest.";
+ LOG(ERROR) << "Could not find " << aname.package << "." << aname.iface << "/"
+ << aname.instance << " in the VINTF manifest.";
}
return found;
}
+static std::optional<std::string> getVintfUpdatableApex(const std::string& name) {
+ AidlName aname;
+ if (!AidlName::fill(name, &aname)) return std::nullopt;
+
+ std::optional<std::string> updatableViaApex;
+
+ forEachManifest([&](const ManifestWithDescription& mwd) {
+ mwd.manifest->forEachInstance([&](const auto& manifestInstance) {
+ if (manifestInstance.format() != vintf::HalFormat::AIDL) return true;
+ if (manifestInstance.package() != aname.package) return true;
+ if (manifestInstance.interface() != aname.iface) return true;
+ if (manifestInstance.instance() != aname.instance) return true;
+ updatableViaApex = manifestInstance.updatableViaApex();
+ return false; // break (libvintf uses opposite convention)
+ });
+ return false; // continue
+ });
+
+ return updatableViaApex;
+}
+
static std::vector<std::string> getVintfInstances(const std::string& interface) {
size_t lastDot = interface.rfind('.');
if (lastDot == std::string::npos) {
@@ -388,6 +421,22 @@
return Status::ok();
}
+Status ServiceManager::updatableViaApex(const std::string& name,
+ std::optional<std::string>* outReturn) {
+ auto ctx = mAccess->getCallingContext();
+
+ if (!mAccess->canFind(ctx, name)) {
+ return Status::fromExceptionCode(Status::EX_SECURITY);
+ }
+
+ *outReturn = std::nullopt;
+
+#ifndef VENDORSERVICEMANAGER
+ *outReturn = getVintfUpdatableApex(name);
+#endif
+ return Status::ok();
+}
+
void ServiceManager::removeRegistrationCallback(const wp<IBinder>& who,
ServiceCallbackMap::iterator* it,
bool* found) {
diff --git a/cmds/servicemanager/ServiceManager.h b/cmds/servicemanager/ServiceManager.h
index c089115..4f23c21 100644
--- a/cmds/servicemanager/ServiceManager.h
+++ b/cmds/servicemanager/ServiceManager.h
@@ -46,6 +46,8 @@
binder::Status isDeclared(const std::string& name, bool* outReturn) override;
binder::Status getDeclaredInstances(const std::string& interface, std::vector<std::string>* outReturn) override;
+ binder::Status updatableViaApex(const std::string& name,
+ std::optional<std::string>* outReturn) override;
binder::Status registerClientCallback(const std::string& name, const sp<IBinder>& service,
const sp<IClientCallback>& cb) override;
binder::Status tryUnregisterService(const std::string& name, const sp<IBinder>& binder) override;
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index 61f4581..f684cf6 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -75,6 +75,7 @@
sp<IBinder> waitForService(const String16& name16) override;
bool isDeclared(const String16& name) override;
Vector<String16> getDeclaredInstances(const String16& interface) override;
+ std::optional<String16> updatableViaApex(const String16& name) override;
// for legacy ABI
const String16& getInterfaceDescriptor() const override {
@@ -388,4 +389,12 @@
return res;
}
+std::optional<String16> ServiceManagerShim::updatableViaApex(const String16& name) {
+ std::optional<std::string> declared;
+ if (!mTheRealServiceManager->updatableViaApex(String8(name).c_str(), &declared).isOk()) {
+ return std::nullopt;
+ }
+ return declared ? std::optional<String16>(String16(declared.value().c_str())) : std::nullopt;
+}
+
} // namespace android
diff --git a/libs/binder/aidl/android/os/IServiceManager.aidl b/libs/binder/aidl/android/os/IServiceManager.aidl
index 2fabf94..75c4092 100644
--- a/libs/binder/aidl/android/os/IServiceManager.aidl
+++ b/libs/binder/aidl/android/os/IServiceManager.aidl
@@ -108,6 +108,11 @@
@utf8InCpp String[] getDeclaredInstances(@utf8InCpp String iface);
/**
+ * If updatable-via-apex, returns the APEX via which this is updated.
+ */
+ @nullable @utf8InCpp String updatableViaApex(@utf8InCpp String name);
+
+ /**
* Request a callback when the number of clients of the service changes.
* Used by LazyServiceRegistrar to dynamically stop services that have no clients.
*/
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index 5f0d056..3dbe2c4 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -20,6 +20,8 @@
#include <utils/Vector.h>
#include <utils/String16.h>
+#include <optional>
+
namespace android {
// ----------------------------------------------------------------------
@@ -99,6 +101,12 @@
* Get all instances of a service as declared in the VINTF manifest
*/
virtual Vector<String16> getDeclaredInstances(const String16& interface) = 0;
+
+ /**
+ * If this instance is updatable via an APEX, returns the APEX with which
+ * this can be updated.
+ */
+ virtual std::optional<String16> updatableViaApex(const String16& name) = 0;
};
sp<IServiceManager> defaultServiceManager();
diff --git a/libs/binder/ndk/include_platform/android/binder_manager.h b/libs/binder/ndk/include_platform/android/binder_manager.h
index 5516914..a90b4aa 100644
--- a/libs/binder/ndk/include_platform/android/binder_manager.h
+++ b/libs/binder/ndk/include_platform/android/binder_manager.h
@@ -124,6 +124,15 @@
__INTRODUCED_IN(31);
/**
+ * Check if a service is updatable via an APEX module.
+ *
+ * \param instance identifier of the service
+ *
+ * \return whether the interface is updatable via APEX
+ */
+bool AServiceManager_isUpdatableViaApex(const char* instance) __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 67c85b6..7d4b82e 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -118,14 +118,15 @@
AIBinder_getCallingSid; # apex
AIBinder_setRequestingSid; # apex
AParcel_markSensitive; # llndk
- AServiceManager_isDeclared; # apex llndk
AServiceManager_forEachDeclaredInstance; # apex llndk
- AServiceManager_registerLazyService; # llndk
- AServiceManager_waitForService; # apex llndk
AServiceManager_forceLazyServicesPersist; # llndk
+ AServiceManager_isDeclared; # apex llndk
+ AServiceManager_isUpdatableViaApex; # apex
+ AServiceManager_reRegister; # llndk
+ AServiceManager_registerLazyService; # llndk
AServiceManager_setActiveServicesCallback; # llndk
AServiceManager_tryUnregister; # llndk
- AServiceManager_reRegister; # llndk
+ AServiceManager_waitForService; # apex llndk
AIBinder_forceDowngradeToSystemStability; # apex
AIBinder_forceDowngradeToVendorStability; # llndk
diff --git a/libs/binder/ndk/service_manager.cpp b/libs/binder/ndk/service_manager.cpp
index 1ccd0d2..7649a26 100644
--- a/libs/binder/ndk/service_manager.cpp
+++ b/libs/binder/ndk/service_manager.cpp
@@ -105,6 +105,14 @@
callback(String8(instance).c_str(), context);
}
}
+bool AServiceManager_isUpdatableViaApex(const char* instance) {
+ if (instance == nullptr) {
+ return false;
+ }
+
+ sp<IServiceManager> sm = defaultServiceManager();
+ return sm->updatableViaApex(String16(instance)) != std::nullopt;
+}
void AServiceManager_forceLazyServicesPersist(bool persist) {
auto serviceRegistrar = android::binder::LazyServiceRegistrar::getInstance();
serviceRegistrar.forcePersist(persist);
diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
index 496a915..1c43948 100644
--- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
+++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
@@ -280,6 +280,11 @@
EXPECT_EQ(STATUS_OK, AIBinder_ping(binder.get()));
}
+TEST(NdkBinder, IsUpdatable) {
+ bool isUpdatable = AServiceManager_isUpdatableViaApex("android.hardware.light.ILights/default");
+ EXPECT_EQ(isUpdatable, false);
+}
+
// This is too slow
TEST(NdkBinder, CheckLazyServiceShutDown) {
ndk::SpAIBinder binder(AServiceManager_waitForService(kLazyBinderNdkUnitTestService));
diff --git a/libs/binder/tests/binderStabilityTest.cpp b/libs/binder/tests/binderStabilityTest.cpp
index cb309bd..2ce13df 100644
--- a/libs/binder/tests/binderStabilityTest.cpp
+++ b/libs/binder/tests/binderStabilityTest.cpp
@@ -192,6 +192,8 @@
EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
android::defaultServiceManager()->addService(String16("."), vintfServer)) << instance8;
EXPECT_FALSE(android::defaultServiceManager()->isDeclared(instance)) << instance8;
+ EXPECT_EQ(std::nullopt, android::defaultServiceManager()->updatableViaApex(instance))
+ << instance8;
}
}
diff --git a/libs/fakeservicemanager/ServiceManager.cpp b/libs/fakeservicemanager/ServiceManager.cpp
index 4ecbe53..761e45c 100644
--- a/libs/fakeservicemanager/ServiceManager.cpp
+++ b/libs/fakeservicemanager/ServiceManager.cpp
@@ -73,4 +73,9 @@
return out;
}
+std::optional<String16> ServiceManager::updatableViaApex(const String16& name) {
+ (void)name;
+ return std::nullopt;
+}
+
} // namespace android
diff --git a/libs/fakeservicemanager/ServiceManager.h b/libs/fakeservicemanager/ServiceManager.h
index 4ef47fb..e26c21b 100644
--- a/libs/fakeservicemanager/ServiceManager.h
+++ b/libs/fakeservicemanager/ServiceManager.h
@@ -19,6 +19,7 @@
#include <binder/IServiceManager.h>
#include <map>
+#include <optional>
namespace android {
@@ -48,6 +49,8 @@
Vector<String16> getDeclaredInstances(const String16& iface) override;
+ std::optional<String16> updatableViaApex(const String16& name) override;
+
private:
std::map<String16, sp<IBinder>> mNameToService;
};