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

Commit db3e5bb0 authored by Devin Moore's avatar Devin Moore Committed by Gerrit Code Review
Browse files

Merge "libbinder_ndk: Add APIs for lazy services"

parents 02d7e69f 6a9394fb
Loading
Loading
Loading
Loading
+44 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@

#include <android/binder_ibinder.h>
#include <android/binder_status.h>
#include <sys/cdefs.h>

__BEGIN_DECLS

@@ -50,4 +51,47 @@ __attribute__((warn_unused_result)) AIBinder* AServiceManager_checkService(const
 */
__attribute__((warn_unused_result)) AIBinder* AServiceManager_getService(const char* instance);

/**
 * Registers a lazy service with the default service manager under the 'instance' name.
 * Does not take ownership of binder.
 * The service must be configured statically with init so it can be restarted with
 * ctl.interface.* messages from servicemanager.
 * AServiceManager_registerLazyService cannot safely be used with AServiceManager_addService
 * in the same process. If one service is registered with AServiceManager_registerLazyService,
 * the entire process will have its lifetime controlled by servicemanager.
 * Instead, all services in the process should be registered using
 * AServiceManager_registerLazyService.
 *
 * \param binder object to register globally with the service manager.
 * \param instance identifier of the service. This will be used to lookup the service.
 *
 * \return STATUS_OK on success.
 */
binder_status_t AServiceManager_registerLazyService(AIBinder* binder, const char* instance)
        __INTRODUCED_IN(31);

/**
 * Gets a binder object with this specific instance name. Efficiently waits for the service.
 * If the service is not declared, it will wait indefinitely. Requires the threadpool
 * to be started in the service.
 * This also implicitly calls AIBinder_incStrong (so the caller of this function is responsible
 * for calling AIBinder_decStrong).
 *
 * \param instance identifier of the service used to lookup the service.
 *
 * \return service if registered, null if not.
 */
__attribute__((warn_unused_result)) AIBinder* AServiceManager_waitForService(const char* instance)
        __INTRODUCED_IN(31);

/**
 * Check if a service is declared (e.g. VINTF manifest).
 *
 * \param instance identifier of the service.
 *
 * \return true on success, meaning AServiceManager_waitForService should always
 *    be able to return the service.
 */
bool AServiceManager_isDeclared(const char* instance) __INTRODUCED_IN(31);

__END_DECLS
+3 −0
Original line number Diff line number Diff line
@@ -117,6 +117,9 @@ LIBBINDER_NDK31 { # introduced=31
    ABinderProcess_setupPolling; # apex
    AIBinder_getCallingSid; # apex
    AIBinder_setRequestingSid; # apex
    AServiceManager_isDeclared; # apex llndk
    AServiceManager_registerLazyService; # llndk
    AServiceManager_waitForService; # apex llndk
};

LIBBINDER_NDK_PLATFORM {
+31 −0
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@
#include "status_internal.h"

#include <binder/IServiceManager.h>
#include <binder/LazyServiceRegistrar.h>

using ::android::defaultServiceManager;
using ::android::IBinder;
@@ -61,3 +62,33 @@ AIBinder* AServiceManager_getService(const char* instance) {
    AIBinder_incStrong(ret.get());
    return ret.get();
}
binder_status_t AServiceManager_registerLazyService(AIBinder* binder, const char* instance) {
    if (binder == nullptr || instance == nullptr) {
        return STATUS_UNEXPECTED_NULL;
    }

    auto serviceRegistrar = android::binder::LazyServiceRegistrar::getInstance();
    status_t status = serviceRegistrar.registerService(binder->getBinder(), instance);

    return PruneStatusT(status);
}
AIBinder* AServiceManager_waitForService(const char* instance) {
    if (instance == nullptr) {
        return nullptr;
    }

    sp<IServiceManager> sm = defaultServiceManager();
    sp<IBinder> binder = sm->waitForService(String16(instance));

    sp<AIBinder> ret = ABpBinder::lookupOrCreateFromBinder(binder);
    AIBinder_incStrong(ret.get());
    return ret.get();
}
bool AServiceManager_isDeclared(const char* instance) {
    if (instance == nullptr) {
        return false;
    }

    sp<IServiceManager> sm = defaultServiceManager();
    return sm->isDeclared(String16(instance));
}
+53 −0
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@ using namespace android;

constexpr char kExistingNonNdkService[] = "SurfaceFlinger";
constexpr char kBinderNdkUnitTestService[] = "BinderNdkUnitTest";
constexpr char kLazyBinderNdkUnitTestService[] = "LazyBinderNdkUnitTest";

class MyBinderNdkUnitTest : public aidl::BnBinderNdkUnitTest {
    ndk::ScopedAStatus repeatInt(int32_t in, int32_t* out) {
@@ -143,6 +144,27 @@ int manualThreadPoolService(const char* instance) {
    return 1;
}

int lazyService(const char* instance) {
    ABinderProcess_setThreadPoolMaxThreadCount(0);
    // Wait to register this service to make sure the main test process will
    // actually wait for the service to be available. Tested with sleep(60),
    // and reduced for sake of time.
    sleep(1);
    // Strong reference to MyBinderNdkUnitTest kept by service manager.
    // This is just for testing, it has no corresponding init behavior.
    auto service = ndk::SharedRefBase::make<MyBinderNdkUnitTest>();
    auto binder = service->asBinder();

    binder_status_t status = AServiceManager_registerLazyService(binder.get(), instance);
    if (status != STATUS_OK) {
        LOG(FATAL) << "Could not register: " << status << " " << instance;
    }

    ABinderProcess_joinThreadPool();

    return 1;  // should not return
}

// This is too slow
// TEST(NdkBinder, GetServiceThatDoesntExist) {
//     sp<IFoo> foo = IFoo::getService("asdfghkl;");
@@ -171,6 +193,33 @@ TEST(NdkBinder, DoubleNumber) {
    EXPECT_EQ(2, out);
}

TEST(NdkBinder, GetLazyService) {
    // Not declared in the vintf manifest
    ASSERT_FALSE(AServiceManager_isDeclared(kLazyBinderNdkUnitTestService));
    ndk::SpAIBinder binder(AServiceManager_waitForService(kLazyBinderNdkUnitTestService));
    std::shared_ptr<aidl::IBinderNdkUnitTest> service =
            aidl::IBinderNdkUnitTest::fromBinder(binder);
    ASSERT_NE(service, nullptr);

    EXPECT_EQ(STATUS_OK, AIBinder_ping(binder.get()));
}

// This is too slow
TEST(NdkBinder, CheckLazyServiceShutDown) {
    ndk::SpAIBinder binder(AServiceManager_waitForService(kLazyBinderNdkUnitTestService));
    std::shared_ptr<aidl::IBinderNdkUnitTest> service =
            aidl::IBinderNdkUnitTest::fromBinder(binder);
    ASSERT_NE(service, nullptr);

    EXPECT_EQ(STATUS_OK, AIBinder_ping(binder.get()));
    binder = nullptr;
    service = nullptr;
    IPCThreadState::self()->flushCommands();
    // Make sure the service is dead after some time of no use
    sleep(10);
    ASSERT_EQ(nullptr, AServiceManager_checkService(kLazyBinderNdkUnitTestService));
}

void LambdaOnDeath(void* cookie) {
    auto onDeath = static_cast<std::function<void(void)>*>(cookie);
    (*onDeath)();
@@ -475,6 +524,10 @@ int main(int argc, char* argv[]) {
        prctl(PR_SET_PDEATHSIG, SIGHUP);
        return manualPollingService(IFoo::kSomeInstanceName);
    }
    if (fork() == 0) {
        prctl(PR_SET_PDEATHSIG, SIGHUP);
        return lazyService(kLazyBinderNdkUnitTestService);
    }
    if (fork() == 0) {
        prctl(PR_SET_PDEATHSIG, SIGHUP);
        return generatedService();