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

Commit 66050ee7 authored by Jon Spivack's avatar Jon Spivack Committed by Gerrit Code Review
Browse files

Merge "ServiceManager signals init to start lazy services"

parents eb5512eb 0d84430b
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;