diff options
Diffstat (limited to 'libs')
| -rw-r--r-- | libs/binder/ndk/include_platform/android/binder_manager.h | 44 | ||||
| -rw-r--r-- | libs/binder/ndk/libbinder_ndk.map.txt | 3 | ||||
| -rw-r--r-- | libs/binder/ndk/service_manager.cpp | 31 | ||||
| -rw-r--r-- | libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp | 53 |
4 files changed, 131 insertions, 0 deletions
diff --git a/libs/binder/ndk/include_platform/android/binder_manager.h b/libs/binder/ndk/include_platform/android/binder_manager.h index 055c79bca1..52bcd20d9e 100644 --- a/libs/binder/ndk/include_platform/android/binder_manager.h +++ b/libs/binder/ndk/include_platform/android/binder_manager.h @@ -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 diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt index d4353823a0..1701fb5705 100644 --- a/libs/binder/ndk/libbinder_ndk.map.txt +++ b/libs/binder/ndk/libbinder_ndk.map.txt @@ -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 { diff --git a/libs/binder/ndk/service_manager.cpp b/libs/binder/ndk/service_manager.cpp index d0b166d318..6b2184ebaa 100644 --- a/libs/binder/ndk/service_manager.cpp +++ b/libs/binder/ndk/service_manager.cpp @@ -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)); +} diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp index 9b2fcf009a..332b4ca5b8 100644 --- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp +++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp @@ -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)(); @@ -477,6 +526,10 @@ int main(int argc, char* argv[]) { } if (fork() == 0) { prctl(PR_SET_PDEATHSIG, SIGHUP); + return lazyService(kLazyBinderNdkUnitTestService); + } + if (fork() == 0) { + prctl(PR_SET_PDEATHSIG, SIGHUP); return generatedService(); } |