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

Commit 32c015f3 authored by Amos Bianchi's avatar Amos Bianchi Committed by Automerger Merge Worker
Browse files

Merge "Expose custom lazy service shutdown APIs to stable AIDL." am:...

Merge "Expose custom lazy service shutdown APIs to stable AIDL." am: d31cbfd7 am: 74558663 am: 7f6c4b87

Original change: https://android-review.googlesource.com/c/platform/frameworks/native/+/1559436

MUST ONLY BE SUBMITTED BY AUTOMERGER

Change-Id: I0af6236f7cdd948e73af51d90d1dd1b4e7914156
parents 95a8eac5 7f6c4b87
Loading
Loading
Loading
Loading
+48 −0
Original line number Diff line number Diff line
@@ -95,4 +95,52 @@ __attribute__((warn_unused_result)) AIBinder* AServiceManager_waitForService(con
 */
bool AServiceManager_isDeclared(const char* instance) __INTRODUCED_IN(31);

/**
 * Prevent lazy services without client from shutting down their process
 *
 * \param persist 'true' if the process should not exit.
 */
void AServiceManager_forceLazyServicesPersist(bool persist) __INTRODUCED_IN(31);

/**
 * Set a callback that is invoked when the active service count (i.e. services with clients)
 * registered with this process drops to zero (or becomes nonzero).
 * The callback takes a boolean argument, which is 'true' if there is
 * at least one service with clients.
 *
 * \param callback function to call when the number of services
 *    with clients changes.
 * \param context opaque pointer passed back as second parameter to the
 * callback.
 *
 * The callback takes two arguments. The first is a boolean that represents if there are
 * services with clients (true) or not (false).
 * The second is the 'context' pointer passed during the registration.
 *
 * Callback return value:
 * - false: Default behavior for lazy services (shut down the process if there
 *          are no clients).
 * - true:  Don't shut down the process even if there are no clients.
 *
 * This callback gives a chance to:
 * 1 - Perform some additional operations before exiting;
 * 2 - Prevent the process from exiting by returning "true" from the callback.
 */
void AServiceManager_setActiveServicesCallback(bool (*callback)(bool, void*), void* context)
        __INTRODUCED_IN(31);

/**
 * Try to unregister all services previously registered with 'registerService'.
 *
 * \return true on success.
 */
bool AServiceManager_tryUnregister() __INTRODUCED_IN(31);

/**
 * Re-register services that were unregistered by 'tryUnregister'.
 * This method should be called in the case 'tryUnregister' fails
 * (and should be called on the same thread).
 */
void AServiceManager_reRegister() __INTRODUCED_IN(31);

__END_DECLS
+4 −0
Original line number Diff line number Diff line
@@ -120,6 +120,10 @@ LIBBINDER_NDK31 { # introduced=31
    AServiceManager_isDeclared; # apex llndk
    AServiceManager_registerLazyService; # llndk
    AServiceManager_waitForService; # apex llndk
    AServiceManager_forceLazyServicesPersist; # llndk
    AServiceManager_setActiveServicesCallback; # llndk
    AServiceManager_tryUnregister; # llndk
    AServiceManager_reRegister; # llndk

    AIBinder_Class_getDescriptor;
    AIBinder_Weak_clone;
+19 −0
Original line number Diff line number Diff line
@@ -92,3 +92,22 @@ bool AServiceManager_isDeclared(const char* instance) {
    sp<IServiceManager> sm = defaultServiceManager();
    return sm->isDeclared(String16(instance));
}
void AServiceManager_forceLazyServicesPersist(bool persist) {
    auto serviceRegistrar = android::binder::LazyServiceRegistrar::getInstance();
    serviceRegistrar.forcePersist(persist);
}
void AServiceManager_setActiveServicesCallback(bool (*callback)(bool, void*), void* context) {
    auto serviceRegistrar = android::binder::LazyServiceRegistrar::getInstance();
    std::function<bool(bool)> fn = [=](bool hasClients) -> bool {
        return callback(hasClients, context);
    };
    serviceRegistrar.setActiveServicesCallback(fn);
}
bool AServiceManager_tryUnregister() {
    auto serviceRegistrar = android::binder::LazyServiceRegistrar::getInstance();
    return serviceRegistrar.tryUnregister();
}
void AServiceManager_reRegister() {
    auto serviceRegistrar = android::binder::LazyServiceRegistrar::getInstance();
    serviceRegistrar.reRegister();
}
 No newline at end of file
+3 −0
Original line number Diff line number Diff line
@@ -28,4 +28,7 @@ interface IBinderNdkUnitTest {
    void forceFlushCommands();

    boolean getsRequestedSid();

    void forcePersist(boolean persist);
    void setCustomActiveServicesCallback();
}
+106 −2
Original line number Diff line number Diff line
@@ -46,6 +46,11 @@ using namespace android;
constexpr char kExistingNonNdkService[] = "SurfaceFlinger";
constexpr char kBinderNdkUnitTestService[] = "BinderNdkUnitTest";
constexpr char kLazyBinderNdkUnitTestService[] = "LazyBinderNdkUnitTest";
constexpr char kForcePersistNdkUnitTestService[] = "ForcePersistNdkUnitTestService";
constexpr char kActiveServicesNdkUnitTestService[] = "ActiveServicesNdkUnitTestService";

constexpr unsigned int kShutdownWaitTime = 10;
constexpr uint64_t kContextTestValue = 0xb4e42fb4d9a1d715;

class MyBinderNdkUnitTest : public aidl::BnBinderNdkUnitTest {
    ndk::ScopedAStatus repeatInt(int32_t in, int32_t* out) {
@@ -76,6 +81,46 @@ class MyBinderNdkUnitTest : public aidl::BnBinderNdkUnitTest {
        fsync(out);
        return STATUS_OK;
    }
    ndk::ScopedAStatus forcePersist(bool persist) {
        AServiceManager_forceLazyServicesPersist(persist);
        return ndk::ScopedAStatus::ok();
    }
    ndk::ScopedAStatus setCustomActiveServicesCallback() {
        AServiceManager_setActiveServicesCallback(activeServicesCallback, this);
        return ndk::ScopedAStatus::ok();
    }
    static bool activeServicesCallback(bool hasClients, void* context) {
        if (hasClients) {
            return false;
        }

        // Unregister all services
        if (!AServiceManager_tryUnregister()) {
            // Prevent shutdown (test will fail)
            return false;
        }

        // Re-register all services
        AServiceManager_reRegister();

        // Unregister again before shutdown
        if (!AServiceManager_tryUnregister()) {
            // Prevent shutdown (test will fail)
            return false;
        }

        // Check if the context was passed correctly
        MyBinderNdkUnitTest* service = static_cast<MyBinderNdkUnitTest*>(context);
        if (service->contextTestValue != kContextTestValue) {
            // Prevent shutdown (test will fail)
            return false;
        }

        exit(EXIT_SUCCESS);
        // Unreachable
    }

    uint64_t contextTestValue = kContextTestValue;
};

int generatedService() {
@@ -168,6 +213,16 @@ int lazyService(const char* instance) {
    return 1;  // should not return
}

bool isServiceRunning(const char* serviceName) {
    AIBinder* binder = AServiceManager_checkService(serviceName);
    if (binder == nullptr) {
        return false;
    }
    AIBinder_decStrong(binder);

    return true;
}

TEST(NdkBinder, GetServiceThatDoesntExist) {
    sp<IFoo> foo = IFoo::getService("asdfghkl;");
    EXPECT_EQ(nullptr, foo.get());
@@ -238,10 +293,51 @@ TEST(NdkBinder, CheckLazyServiceShutDown) {
    service = nullptr;
    IPCThreadState::self()->flushCommands();
    // Make sure the service is dead after some time of no use
    sleep(10);
    sleep(kShutdownWaitTime);
    ASSERT_EQ(nullptr, AServiceManager_checkService(kLazyBinderNdkUnitTestService));
}

TEST(NdkBinder, ForcedPersistenceTest) {
    for (int i = 0; i < 2; i++) {
        ndk::SpAIBinder binder(AServiceManager_waitForService(kForcePersistNdkUnitTestService));
        std::shared_ptr<aidl::IBinderNdkUnitTest> service =
                aidl::IBinderNdkUnitTest::fromBinder(binder);
        ASSERT_NE(service, nullptr);
        ASSERT_TRUE(service->forcePersist(i == 0).isOk());

        binder = nullptr;
        service = nullptr;
        IPCThreadState::self()->flushCommands();

        sleep(kShutdownWaitTime);

        bool isRunning = isServiceRunning(kForcePersistNdkUnitTestService);

        if (i == 0) {
            ASSERT_TRUE(isRunning) << "Service shut down when it shouldn't have.";
        } else {
            ASSERT_FALSE(isRunning) << "Service failed to shut down.";
        }
    }
}

TEST(NdkBinder, ActiveServicesCallbackTest) {
    ndk::SpAIBinder binder(AServiceManager_waitForService(kActiveServicesNdkUnitTestService));
    std::shared_ptr<aidl::IBinderNdkUnitTest> service =
            aidl::IBinderNdkUnitTest::fromBinder(binder);
    ASSERT_NE(service, nullptr);
    ASSERT_TRUE(service->setCustomActiveServicesCallback().isOk());

    binder = nullptr;
    service = nullptr;
    IPCThreadState::self()->flushCommands();

    sleep(kShutdownWaitTime);

    ASSERT_FALSE(isServiceRunning(kActiveServicesNdkUnitTestService))
            << "Service failed to shut down.";
}

void LambdaOnDeath(void* cookie) {
    auto onDeath = static_cast<std::function<void(void)>*>(cookie);
    (*onDeath)();
@@ -562,12 +658,20 @@ int main(int argc, char* argv[]) {
        prctl(PR_SET_PDEATHSIG, SIGHUP);
        return lazyService(kLazyBinderNdkUnitTestService);
    }
    if (fork() == 0) {
        prctl(PR_SET_PDEATHSIG, SIGHUP);
        return lazyService(kForcePersistNdkUnitTestService);
    }
    if (fork() == 0) {
        prctl(PR_SET_PDEATHSIG, SIGHUP);
        return lazyService(kActiveServicesNdkUnitTestService);
    }
    if (fork() == 0) {
        prctl(PR_SET_PDEATHSIG, SIGHUP);
        return generatedService();
    }

    ABinderProcess_setThreadPoolMaxThreadCount(1);  // to recieve death notifications/callbacks
    ABinderProcess_setThreadPoolMaxThreadCount(1);  // to receive death notifications/callbacks
    ABinderProcess_startThreadPool();

    return RUN_ALL_TESTS();