diff options
| -rw-r--r-- | libs/binder/ndk/include_platform/android/binder_manager.h | 48 | ||||
| -rw-r--r-- | libs/binder/ndk/libbinder_ndk.map.txt | 4 | ||||
| -rw-r--r-- | libs/binder/ndk/service_manager.cpp | 19 | ||||
| -rw-r--r-- | libs/binder/ndk/tests/IBinderNdkUnitTest.aidl | 3 | ||||
| -rw-r--r-- | libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp | 108 |
5 files changed, 180 insertions, 2 deletions
diff --git a/libs/binder/ndk/include_platform/android/binder_manager.h b/libs/binder/ndk/include_platform/android/binder_manager.h index 2784aa823d..9cc10c28ac 100644 --- a/libs/binder/ndk/include_platform/android/binder_manager.h +++ b/libs/binder/ndk/include_platform/android/binder_manager.h @@ -94,4 +94,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 diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt index 9a93bf3c4b..cef0bf31d2 100644 --- a/libs/binder/ndk/libbinder_ndk.map.txt +++ b/libs/binder/ndk/libbinder_ndk.map.txt @@ -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; diff --git a/libs/binder/ndk/service_manager.cpp b/libs/binder/ndk/service_manager.cpp index c782d47c1c..cb0987e3e1 100644 --- a/libs/binder/ndk/service_manager.cpp +++ b/libs/binder/ndk/service_manager.cpp @@ -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 diff --git a/libs/binder/ndk/tests/IBinderNdkUnitTest.aidl b/libs/binder/ndk/tests/IBinderNdkUnitTest.aidl index dc77467d8c..ecbd6490e9 100644 --- a/libs/binder/ndk/tests/IBinderNdkUnitTest.aidl +++ b/libs/binder/ndk/tests/IBinderNdkUnitTest.aidl @@ -28,4 +28,7 @@ interface IBinderNdkUnitTest { void forceFlushCommands(); boolean getsRequestedSid(); + + void forcePersist(boolean persist); + void setCustomActiveServicesCallback(); } diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp index 0d1989e4d5..de1a48dfd8 100644 --- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp +++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp @@ -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)(); @@ -564,10 +660,18 @@ int main(int argc, char* argv[]) { } 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(); |