diff options
| -rw-r--r-- | cmds/servicemanager/ServiceManager.cpp | 56 | ||||
| -rw-r--r-- | cmds/servicemanager/ServiceManager.h | 5 | ||||
| -rw-r--r-- | cmds/servicemanager/test_sm.cpp | 20 | ||||
| -rw-r--r-- | libs/binder/IServiceManager.cpp | 6 |
4 files changed, 57 insertions, 30 deletions
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp index b3aa342a19..463d67f945 100644 --- a/cmds/servicemanager/ServiceManager.cpp +++ b/cmds/servicemanager/ServiceManager.cpp @@ -17,8 +17,10 @@ #include "ServiceManager.h" #include <android-base/logging.h> +#include <android-base/properties.h> #include <cutils/android_filesystem_config.h> #include <cutils/multiuser.h> +#include <thread> using ::android::binder::Status; @@ -41,39 +43,44 @@ ServiceManager::~ServiceManager() { } Status ServiceManager::getService(const std::string& name, sp<IBinder>* outBinder) { - // Servicemanager is single-threaded and cannot block. This method exists for legacy reasons. - return checkService(name, outBinder); + *outBinder = tryGetService(name, true); + // returns ok regardless of result for legacy reasons + return Status::ok(); } Status ServiceManager::checkService(const std::string& name, sp<IBinder>* outBinder) { - auto ctx = mAccess->getCallingContext(); + *outBinder = tryGetService(name, false); + // returns ok regardless of result for legacy reasons + return Status::ok(); +} - auto it = mNameToService.find(name); - if (it == mNameToService.end()) { - *outBinder = nullptr; - return Status::ok(); - } +sp<IBinder> ServiceManager::tryGetService(const std::string& name, bool startIfNotFound) { + auto ctx = mAccess->getCallingContext(); - const Service& service = it->second; + sp<IBinder> out; + if (auto it = mNameToService.find(name); it != mNameToService.end()) { + const Service& service = it->second; - if (!service.allowIsolated) { - uid_t appid = multiuser_get_app_id(ctx.uid); - bool isIsolated = appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END; + if (!service.allowIsolated) { + uid_t appid = multiuser_get_app_id(ctx.uid); + bool isIsolated = appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END; - if (isIsolated) { - *outBinder = nullptr; - return Status::ok(); + if (isIsolated) { + return nullptr; + } } + out = service.binder; } if (!mAccess->canFind(ctx, name)) { - // returns ok and null for legacy reasons - *outBinder = nullptr; - return Status::ok(); + return nullptr; } - *outBinder = service.binder; - return Status::ok(); + if (!out && startIfNotFound) { + tryStartService(name); + } + + return out; } bool isValidServiceName(const std::string& name) { @@ -253,4 +260,13 @@ void ServiceManager::binderDied(const wp<IBinder>& who) { } } +void ServiceManager::tryStartService(const std::string& name) { + ALOGI("Since '%s' could not be found, trying to start it as a lazy AIDL service", + name.c_str()); + + std::thread([=] { + (void)base::SetProperty("ctl.interface_start", "aidl/" + name); + }).detach(); +} + } // namespace android diff --git a/cmds/servicemanager/ServiceManager.h b/cmds/servicemanager/ServiceManager.h index fcc5124fa2..006e51947b 100644 --- a/cmds/servicemanager/ServiceManager.h +++ b/cmds/servicemanager/ServiceManager.h @@ -30,6 +30,7 @@ public: ServiceManager(std::unique_ptr<Access>&& access); ~ServiceManager(); + // getService will try to start any services it cannot find binder::Status getService(const std::string& name, sp<IBinder>* outBinder) override; binder::Status checkService(const std::string& name, sp<IBinder>* outBinder) override; binder::Status addService(const std::string& name, const sp<IBinder>& binder, @@ -42,6 +43,9 @@ public: void binderDied(const wp<IBinder>& who) override; +protected: + virtual void tryStartService(const std::string& name); + private: struct Service { sp<IBinder> binder; // not null @@ -57,6 +61,7 @@ private: void removeCallback(const wp<IBinder>& who, CallbackMap::iterator* it, bool* found); + sp<IBinder> tryGetService(const std::string& name, bool startIfNotFound); CallbackMap mNameToCallback; ServiceMap mNameToService; diff --git a/cmds/servicemanager/test_sm.cpp b/cmds/servicemanager/test_sm.cpp index 3c211d285f..25245beaf7 100644 --- a/cmds/servicemanager/test_sm.cpp +++ b/cmds/servicemanager/test_sm.cpp @@ -57,6 +57,12 @@ public: MOCK_METHOD1(canList, bool(const CallingContext&)); }; +class MockServiceManager : public ServiceManager { + public: + MockServiceManager(std::unique_ptr<Access>&& access) : ServiceManager(std::move(access)) {} + MOCK_METHOD1(tryStartService, void(const std::string& name)); +}; + static sp<ServiceManager> getPermissiveServiceManager() { std::unique_ptr<MockAccess> access = std::make_unique<NiceMock<MockAccess>>(); @@ -65,7 +71,7 @@ static sp<ServiceManager> getPermissiveServiceManager() { ON_CALL(*access, canFind(_, _)).WillByDefault(Return(true)); ON_CALL(*access, canList(_)).WillByDefault(Return(true)); - sp<ServiceManager> sm = new ServiceManager(std::move(access)); + sp<ServiceManager> sm = new NiceMock<MockServiceManager>(std::move(access)); return sm; } @@ -113,7 +119,7 @@ TEST(AddService, AddDisallowedFromApp) { .uid = uid, })); EXPECT_CALL(*access, canAdd(_, _)).Times(0); - sp<ServiceManager> sm = new ServiceManager(std::move(access)); + sp<ServiceManager> sm = new NiceMock<MockServiceManager>(std::move(access)); EXPECT_FALSE(sm->addService("foo", getBinder(), false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); @@ -135,7 +141,7 @@ TEST(AddService, NoPermissions) { EXPECT_CALL(*access, getCallingContext()).WillOnce(Return(Access::CallingContext{})); EXPECT_CALL(*access, canAdd(_, _)).WillOnce(Return(false)); - sp<ServiceManager> sm = new ServiceManager(std::move(access)); + sp<ServiceManager> sm = new NiceMock<MockServiceManager>(std::move(access)); EXPECT_FALSE(sm->addService("foo", getBinder(), false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); @@ -168,7 +174,7 @@ TEST(GetService, NoPermissionsForGettingService) { EXPECT_CALL(*access, canAdd(_, _)).WillOnce(Return(true)); EXPECT_CALL(*access, canFind(_, _)).WillOnce(Return(false)); - sp<ServiceManager> sm = new ServiceManager(std::move(access)); + sp<ServiceManager> sm = new NiceMock<MockServiceManager>(std::move(access)); EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); @@ -192,7 +198,7 @@ TEST(GetService, AllowedFromIsolated) { EXPECT_CALL(*access, canAdd(_, _)).WillOnce(Return(true)); EXPECT_CALL(*access, canFind(_, _)).WillOnce(Return(true)); - sp<ServiceManager> sm = new ServiceManager(std::move(access)); + sp<ServiceManager> sm = new NiceMock<MockServiceManager>(std::move(access)); sp<IBinder> service = getBinder(); EXPECT_TRUE(sm->addService("foo", service, true /*allowIsolated*/, @@ -218,7 +224,7 @@ TEST(GetService, NotAllowedFromIsolated) { // TODO(b/136023468): when security check is first, this should be called first // EXPECT_CALL(*access, canFind(_, _)).WillOnce(Return(true)); - sp<ServiceManager> sm = new ServiceManager(std::move(access)); + sp<ServiceManager> sm = new NiceMock<MockServiceManager>(std::move(access)); EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); @@ -235,7 +241,7 @@ TEST(ListServices, NoPermissions) { EXPECT_CALL(*access, getCallingContext()).WillOnce(Return(Access::CallingContext{})); EXPECT_CALL(*access, canList(_)).WillOnce(Return(false)); - sp<ServiceManager> sm = new ServiceManager(std::move(access)); + sp<ServiceManager> sm = new NiceMock<MockServiceManager>(std::move(access)); std::vector<std::string> out; EXPECT_FALSE(sm->listServices(IServiceManager::DUMP_FLAG_PRIORITY_ALL, &out).isOk()); diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp index 715a4609d6..eefc5b1c4f 100644 --- a/libs/binder/IServiceManager.cpp +++ b/libs/binder/IServiceManager.cpp @@ -232,7 +232,7 @@ public: const std::string name = String8(name16).c_str(); sp<IBinder> out; - if(!mTheRealServiceManager->checkService(name, &out).isOk()) { + if (!mTheRealServiceManager->getService(name, &out).isOk()) { return nullptr; } if(out != nullptr) return out; @@ -256,13 +256,13 @@ public: // Handle race condition for lazy services. Here is what can happen: // - the service dies (not processed by init yet). // - sm processes death notification. - // - sm gets checkService and calls init to start service. + // - sm gets getService and calls init to start service. // - init gets the start signal, but the service already appears // started, so it does nothing. // - init gets death signal, but doesn't know it needs to restart // the service // - we need to request service again to get it to start - if(!mTheRealServiceManager->checkService(name, &out).isOk()) { + if (!mTheRealServiceManager->getService(name, &out).isOk()) { return nullptr; } if(out != nullptr) return out; |