Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8c8b131b authored by Jon Spivack's avatar Jon Spivack Committed by android-build-merger
Browse files

Merge "ServiceManager signals init to start lazy services" am: 66050ee7

am: 94ddc169

Change-Id: I9be47cfe686479e5998fadeb636646d6e7c2241d
parents 291ac48c 94ddc169
Loading
Loading
Loading
Loading
+36 −20
Original line number Diff line number Diff line
@@ -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,19 +43,22 @@ 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();

    auto it = mNameToService.find(name);
    if (it == mNameToService.end()) {
        *outBinder = nullptr;
    *outBinder = tryGetService(name, false);
    // returns ok regardless of result for legacy reasons
    return Status::ok();
}

sp<IBinder> ServiceManager::tryGetService(const std::string& name, bool startIfNotFound) {
    auto ctx = mAccess->getCallingContext();

    sp<IBinder> out;
    if (auto it = mNameToService.find(name); it != mNameToService.end()) {
        const Service& service = it->second;

        if (!service.allowIsolated) {
@@ -61,19 +66,21 @@ Status ServiceManager::checkService(const std::string& name, sp<IBinder>* outBin
            bool isIsolated = appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END;

            if (isIsolated) {
            *outBinder = nullptr;
            return Status::ok();
                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
+5 −0
Original line number Diff line number Diff line
@@ -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;
+13 −7
Original line number Diff line number Diff line
@@ -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());
+3 −3
Original line number Diff line number Diff line
@@ -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;