Loading libs/binder/ndk/include_platform/android/binder_manager.h +48 −0 Original line number Diff line number Diff line Loading @@ -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 libs/binder/ndk/libbinder_ndk.map.txt +4 −0 Original line number Diff line number Diff line Loading @@ -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; Loading libs/binder/ndk/service_manager.cpp +19 −0 Original line number Diff line number Diff line Loading @@ -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 libs/binder/ndk/tests/IBinderNdkUnitTest.aidl +3 −0 Original line number Diff line number Diff line Loading @@ -28,4 +28,7 @@ interface IBinderNdkUnitTest { void forceFlushCommands(); boolean getsRequestedSid(); void forcePersist(boolean persist); void setCustomActiveServicesCallback(); } libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp +106 −2 Original line number Diff line number Diff line Loading @@ -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) { Loading Loading @@ -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() { Loading Loading @@ -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()); Loading Loading @@ -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)(); Loading Loading @@ -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(); Loading Loading
libs/binder/ndk/include_platform/android/binder_manager.h +48 −0 Original line number Diff line number Diff line Loading @@ -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
libs/binder/ndk/libbinder_ndk.map.txt +4 −0 Original line number Diff line number Diff line Loading @@ -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; Loading
libs/binder/ndk/service_manager.cpp +19 −0 Original line number Diff line number Diff line Loading @@ -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
libs/binder/ndk/tests/IBinderNdkUnitTest.aidl +3 −0 Original line number Diff line number Diff line Loading @@ -28,4 +28,7 @@ interface IBinderNdkUnitTest { void forceFlushCommands(); boolean getsRequestedSid(); void forcePersist(boolean persist); void setCustomActiveServicesCallback(); }
libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp +106 −2 Original line number Diff line number Diff line Loading @@ -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) { Loading Loading @@ -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() { Loading Loading @@ -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()); Loading Loading @@ -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)(); Loading Loading @@ -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(); Loading