diff options
-rw-r--r-- | cmds/dumpsys/tests/dumpsys_test.cpp | 1 | ||||
-rw-r--r-- | cmds/servicemanager/ServiceManager.cpp | 93 | ||||
-rw-r--r-- | cmds/servicemanager/ServiceManager.h | 1 | ||||
-rw-r--r-- | libs/binder/IServiceManager.cpp | 15 | ||||
-rw-r--r-- | libs/binder/aidl/android/os/IServiceManager.aidl | 8 | ||||
-rw-r--r-- | libs/binder/include/binder/IServiceManager.h | 5 | ||||
-rw-r--r-- | libs/fakeservicemanager/ServiceManager.cpp | 12 | ||||
-rw-r--r-- | libs/fakeservicemanager/ServiceManager.h | 2 |
8 files changed, 118 insertions, 19 deletions
diff --git a/cmds/dumpsys/tests/dumpsys_test.cpp b/cmds/dumpsys/tests/dumpsys_test.cpp index 3467898f3e..67a77f6015 100644 --- a/cmds/dumpsys/tests/dumpsys_test.cpp +++ b/cmds/dumpsys/tests/dumpsys_test.cpp @@ -55,6 +55,7 @@ class ServiceManagerMock : public IServiceManager { MOCK_METHOD1(listServices, Vector<String16>(int)); MOCK_METHOD1(waitForService, sp<IBinder>(const String16&)); MOCK_METHOD1(isDeclared, bool(const String16&)); + MOCK_METHOD1(getDeclaredInstances, Vector<String16>(const String16&)); protected: MOCK_METHOD0(onAsBinder, IBinder*()); }; diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp index e80c3210f0..c8355e2b6b 100644 --- a/cmds/servicemanager/ServiceManager.cpp +++ b/cmds/servicemanager/ServiceManager.cpp @@ -37,6 +37,27 @@ using ::android::internal::Stability; namespace android { #ifndef VENDORSERVICEMANAGER +struct ManifestWithDescription { + std::shared_ptr<const vintf::HalManifest> manifest; + const char* description; +}; +// func true -> stop search and forEachManifest will return true +static bool forEachManifest(const std::function<bool(const ManifestWithDescription&)>& func) { + for (const ManifestWithDescription& mwd : { + ManifestWithDescription{ vintf::VintfObject::GetDeviceHalManifest(), "device" }, + ManifestWithDescription{ vintf::VintfObject::GetFrameworkHalManifest(), "framework" }, + }) { + if (mwd.manifest == nullptr) { + LOG(ERROR) << "NULL VINTF MANIFEST!: " << mwd.description; + // note, we explicitly do not retry here, so that we can detect VINTF + // or other bugs (b/151696835) + continue; + } + if (func(mwd)) return true; + } + return false; +} + static bool isVintfDeclared(const std::string& name) { size_t firstSlash = name.find('/'); size_t lastDot = name.rfind('.', firstSlash); @@ -49,31 +70,41 @@ static bool isVintfDeclared(const std::string& name) { const std::string iface = name.substr(lastDot+1, firstSlash-lastDot-1); const std::string instance = name.substr(firstSlash+1); - struct ManifestWithDescription { - std::shared_ptr<const vintf::HalManifest> manifest; - const char* description; - }; - for (const ManifestWithDescription& mwd : { - ManifestWithDescription{ vintf::VintfObject::GetDeviceHalManifest(), "device" }, - ManifestWithDescription{ vintf::VintfObject::GetFrameworkHalManifest(), "framework" }, - }) { - if (mwd.manifest == nullptr) { - LOG(ERROR) << "NULL VINTF MANIFEST!: " << mwd.description; - // note, we explicitly do not retry here, so that we can detect VINTF - // or other bugs (b/151696835) - continue; - } + bool found = forEachManifest([&] (const ManifestWithDescription& mwd) { if (mwd.manifest->hasAidlInstance(package, iface, instance)) { LOG(INFO) << "Found " << name << " in " << mwd.description << " VINTF manifest."; return true; } + return false; // continue + }); + + 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."; } - // 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."; - return false; + return found; +} + +static std::vector<std::string> getVintfInstances(const std::string& interface) { + size_t lastDot = interface.rfind('.'); + if (lastDot == std::string::npos) { + LOG(ERROR) << "VINTF interfaces require names in Java package format (e.g. some.package.foo.IFoo) but got: " << interface; + return {}; + } + const std::string package = interface.substr(0, lastDot); + const std::string iface = interface.substr(lastDot+1); + + std::vector<std::string> ret; + (void)forEachManifest([&](const ManifestWithDescription& mwd) { + auto instances = mwd.manifest->getAidlInstances(package, iface); + ret.insert(ret.end(), instances.begin(), instances.end()); + return false; // continue + }); + + return ret; } static bool meetsDeclarationRequirements(const sp<IBinder>& binder, const std::string& name) { @@ -331,6 +362,30 @@ Status ServiceManager::isDeclared(const std::string& name, bool* outReturn) { return Status::ok(); } +binder::Status ServiceManager::getDeclaredInstances(const std::string& interface, std::vector<std::string>* outReturn) { + auto ctx = mAccess->getCallingContext(); + + std::vector<std::string> allInstances; +#ifndef VENDORSERVICEMANAGER + allInstances = getVintfInstances(interface); +#endif + + outReturn->clear(); + + for (const std::string& instance : allInstances) { + // TODO(b/169275998): allow checking policy only once for the interface + if (mAccess->canFind(ctx, interface + "/" + instance)) { + outReturn->push_back(instance); + } + } + + if (outReturn->size() == 0 && allInstances.size() != 0) { + return Status::fromExceptionCode(Status::EX_SECURITY); + } + + 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 a2fc5a84c5..9f43eb4f58 100644 --- a/cmds/servicemanager/ServiceManager.h +++ b/cmds/servicemanager/ServiceManager.h @@ -44,6 +44,7 @@ public: const sp<IServiceCallback>& callback) override; 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 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 9aa82d908c..6d728dc6b1 100644 --- a/libs/binder/IServiceManager.cpp +++ b/libs/binder/IServiceManager.cpp @@ -74,6 +74,7 @@ public: Vector<String16> listServices(int dumpsysPriority) override; sp<IBinder> waitForService(const String16& name16) override; bool isDeclared(const String16& name) override; + Vector<String16> getDeclaredInstances(const String16& interface) override; // for legacy ABI const String16& getInterfaceDescriptor() const override { @@ -373,4 +374,18 @@ bool ServiceManagerShim::isDeclared(const String16& name) { return declared; } +Vector<String16> ServiceManagerShim::getDeclaredInstances(const String16& interface) { + std::vector<std::string> out; + if (!mTheRealServiceManager->getDeclaredInstances(String8(interface).c_str(), &out).isOk()) { + return {}; + } + + Vector<String16> res; + res.setCapacity(out.size()); + for (const std::string& instance : out) { + res.push(String16(instance.c_str())); + } + return res; +} + } // namespace android diff --git a/libs/binder/aidl/android/os/IServiceManager.aidl b/libs/binder/aidl/android/os/IServiceManager.aidl index ff154603e4..2b1e49283f 100644 --- a/libs/binder/aidl/android/os/IServiceManager.aidl +++ b/libs/binder/aidl/android/os/IServiceManager.aidl @@ -99,6 +99,14 @@ interface IServiceManager { boolean isDeclared(@utf8InCpp String name); /** + * 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. + */ + @utf8InCpp String[] getDeclaredInstances(@utf8InCpp String iface); + + /** * 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 1d520c127b..3c5ccc1922 100644 --- a/libs/binder/include/binder/IServiceManager.h +++ b/libs/binder/include/binder/IServiceManager.h @@ -96,6 +96,11 @@ public: * service. */ virtual bool isDeclared(const String16& name) = 0; + + /** + * Get all instances of a service as declared in the VINTF manifest + */ + virtual Vector<String16> getDeclaredInstances(const String16& interface) = 0; }; sp<IServiceManager> defaultServiceManager(); diff --git a/libs/fakeservicemanager/ServiceManager.cpp b/libs/fakeservicemanager/ServiceManager.cpp index 69643249e3..4ecbe531c2 100644 --- a/libs/fakeservicemanager/ServiceManager.cpp +++ b/libs/fakeservicemanager/ServiceManager.cpp @@ -61,4 +61,16 @@ bool ServiceManager::isDeclared(const String16& name) { return mNameToService.find(name) != mNameToService.end(); } +Vector<String16> ServiceManager::getDeclaredInstances(const String16& name) { + Vector<String16> out; + const String16 prefix = name + String16("/"); + for (const auto& [registeredName, service] : mNameToService) { + (void) service; + if (registeredName.startsWith(prefix)) { + out.add(String16(registeredName.string() + prefix.size())); + } + } + return out; +} + } // namespace android diff --git a/libs/fakeservicemanager/ServiceManager.h b/libs/fakeservicemanager/ServiceManager.h index a6b6b84219..4ef47fb043 100644 --- a/libs/fakeservicemanager/ServiceManager.h +++ b/libs/fakeservicemanager/ServiceManager.h @@ -46,6 +46,8 @@ public: bool isDeclared(const String16& name) override; + Vector<String16> getDeclaredInstances(const String16& iface) override; + private: std::map<String16, sp<IBinder>> mNameToService; }; |