Loading libs/binder/ndk/include_platform/android/binder_manager.h +61 −0 Original line number Diff line number Diff line Loading @@ -108,6 +108,67 @@ binder_status_t AServiceManager_registerLazyService(AIBinder* binder, const char __attribute__((warn_unused_result)) AIBinder* AServiceManager_waitForService(const char* instance) __INTRODUCED_IN(31); /** * Function to call when a service is registered. The instance is passed as well as * ownership of the binder named 'registered'. * * WARNING: a lock is held when this method is called in order to prevent races with * AServiceManager_NotificationRegistration_delete. Do not make synchronous binder calls when * implementing this method to avoid deadlocks. * * \param instance instance name of service registered * \param registered ownership-passed instance of service registered * \param cookie data passed during registration for notifications */ typedef void (*AServiceManager_onRegister)(const char* instance, AIBinder* registered, void* cookie); /** * Represents a registration to servicemanager which can be cleared anytime. */ struct AServiceManager_NotificationRegistration; /** * Get notifications when a service is registered. If the service is already registered, * you will immediately get a notification. * * WARNING: it is strongly recommended to use AServiceManager_waitForService API instead. * That API will wait synchronously, which is what you usually want in cases, including * using some feature or during boot up. There is a history of bugs where waiting for * notifications like this races with service startup. Also, when this API is used, a service * bug will result in silent failure (rather than a debuggable deadlock). Furthermore, there * is a history of this API being used to know when a service is up as a proxy for whethre * that service should be started. This should only be used if you are intending to get * ahold of the service as a client. For lazy services, whether a service is registered * should not be used as a proxy for when it should be registered, which is only known * by the real client. * * WARNING: if you use this API, you must also ensure that you check missing services are * started and crash otherwise. If service failures are ignored, the system rots. * * \param instance name of service to wait for notifications about * \param onRegister callback for when service is registered * \param cookie data associated with this callback * * \return the token for this registration. Deleting this token will unregister. */ __attribute__((warn_unused_result)) AServiceManager_NotificationRegistration* AServiceManager_registerForServiceNotifications(const char* instance, AServiceManager_onRegister onRegister, void* cookie) __INTRODUCED_IN(34); /** * Unregister for notifications and delete the object. * * After this method is called, the callback is guaranteed to no longer be invoked. This will block * until any in-progress onRegister callbacks have completed. It is therefore safe to immediately * destroy the void* cookie that was registered when this method returns. * * \param notification object to dismiss */ void AServiceManager_NotificationRegistration_delete( AServiceManager_NotificationRegistration* notification) __INTRODUCED_IN(34); /** * Check if a service is declared (e.g. VINTF manifest). * Loading libs/binder/ndk/libbinder_ndk.map.txt +2 −0 Original line number Diff line number Diff line Loading @@ -155,6 +155,8 @@ LIBBINDER_NDK33 { # introduced=33 LIBBINDER_NDK34 { # introduced=UpsideDownCake global: AServiceManager_getUpdatableApexName; # systemapi AServiceManager_registerForServiceNotifications; # systemapi llndk AServiceManager_NotificationRegistration_delete; # systemapi llndk }; LIBBINDER_NDK_PLATFORM { Loading libs/binder/ndk/service_manager.cpp +62 −0 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ using ::android::IBinder; using ::android::IServiceManager; using ::android::sp; using ::android::status_t; using ::android::statusToString; using ::android::String16; using ::android::String8; Loading Loading @@ -86,6 +87,67 @@ AIBinder* AServiceManager_waitForService(const char* instance) { AIBinder_incStrong(ret.get()); return ret.get(); } typedef void (*AServiceManager_onRegister)(const char* instance, AIBinder* registered, void* cookie); struct AServiceManager_NotificationRegistration : public IServiceManager::LocalRegistrationCallback { std::mutex m; const char* instance = nullptr; void* cookie = nullptr; AServiceManager_onRegister onRegister = nullptr; virtual void onServiceRegistration(const String16& smInstance, const sp<IBinder>& binder) { std::lock_guard<std::mutex> l(m); if (onRegister == nullptr) return; CHECK_EQ(String8(smInstance), instance); sp<AIBinder> ret = ABpBinder::lookupOrCreateFromBinder(binder); AIBinder_incStrong(ret.get()); onRegister(instance, ret.get(), cookie); } void clear() { std::lock_guard<std::mutex> l(m); instance = nullptr; cookie = nullptr; onRegister = nullptr; } }; __attribute__((warn_unused_result)) AServiceManager_NotificationRegistration* AServiceManager_registerForServiceNotifications(const char* instance, AServiceManager_onRegister onRegister, void* cookie) { CHECK_NE(instance, nullptr); CHECK_NE(onRegister, nullptr) << instance; // cookie can be nullptr auto cb = sp<AServiceManager_NotificationRegistration>::make(); cb->instance = instance; cb->onRegister = onRegister; cb->cookie = cookie; sp<IServiceManager> sm = defaultServiceManager(); if (status_t res = sm->registerForNotifications(String16(instance), cb); res != STATUS_OK) { LOG(ERROR) << "Failed to register for service notifications for " << instance << ": " << statusToString(res); return nullptr; } cb->incStrong(nullptr); return cb.get(); } void AServiceManager_NotificationRegistration_delete( AServiceManager_NotificationRegistration* notification) { CHECK_NE(notification, nullptr); notification->clear(); notification->decStrong(nullptr); } bool AServiceManager_isDeclared(const char* instance) { if (instance == nullptr) { return false; Loading libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp +41 −0 Original line number Diff line number Diff line Loading @@ -254,6 +254,47 @@ TEST(NdkBinder, CheckServiceThatDoesExist) { AIBinder_decStrong(binder); } struct ServiceData { std::string instance; ndk::SpAIBinder binder; static void fillOnRegister(const char* instance, AIBinder* binder, void* cookie) { ServiceData* d = reinterpret_cast<ServiceData*>(cookie); d->instance = instance; d->binder = ndk::SpAIBinder(binder); } }; TEST(NdkBinder, RegisterForServiceNotificationsNonExisting) { ServiceData data; auto* notif = AServiceManager_registerForServiceNotifications( "DOES_NOT_EXIST", ServiceData::fillOnRegister, (void*)&data); ASSERT_NE(notif, nullptr); sleep(1); // give us a chance to fail AServiceManager_NotificationRegistration_delete(notif); // checking after deleting to avoid needing a mutex over the data - otherwise // in an environment w/ multiple threads, you would need to guard access EXPECT_EQ(data.instance, ""); EXPECT_EQ(data.binder, nullptr); } TEST(NdkBinder, RegisterForServiceNotificationsExisting) { ServiceData data; auto* notif = AServiceManager_registerForServiceNotifications( kExistingNonNdkService, ServiceData::fillOnRegister, (void*)&data); ASSERT_NE(notif, nullptr); sleep(1); // give us a chance to fail AServiceManager_NotificationRegistration_delete(notif); // checking after deleting to avoid needing a mutex over the data - otherwise // in an environment w/ multiple threads, you would need to guard access EXPECT_EQ(data.instance, kExistingNonNdkService); EXPECT_EQ(data.binder, ndk::SpAIBinder(AServiceManager_checkService(kExistingNonNdkService))); } TEST(NdkBinder, UnimplementedDump) { sp<IFoo> foo = IFoo::getService(IFoo::kSomeInstanceName); ASSERT_NE(foo, nullptr); Loading Loading
libs/binder/ndk/include_platform/android/binder_manager.h +61 −0 Original line number Diff line number Diff line Loading @@ -108,6 +108,67 @@ binder_status_t AServiceManager_registerLazyService(AIBinder* binder, const char __attribute__((warn_unused_result)) AIBinder* AServiceManager_waitForService(const char* instance) __INTRODUCED_IN(31); /** * Function to call when a service is registered. The instance is passed as well as * ownership of the binder named 'registered'. * * WARNING: a lock is held when this method is called in order to prevent races with * AServiceManager_NotificationRegistration_delete. Do not make synchronous binder calls when * implementing this method to avoid deadlocks. * * \param instance instance name of service registered * \param registered ownership-passed instance of service registered * \param cookie data passed during registration for notifications */ typedef void (*AServiceManager_onRegister)(const char* instance, AIBinder* registered, void* cookie); /** * Represents a registration to servicemanager which can be cleared anytime. */ struct AServiceManager_NotificationRegistration; /** * Get notifications when a service is registered. If the service is already registered, * you will immediately get a notification. * * WARNING: it is strongly recommended to use AServiceManager_waitForService API instead. * That API will wait synchronously, which is what you usually want in cases, including * using some feature or during boot up. There is a history of bugs where waiting for * notifications like this races with service startup. Also, when this API is used, a service * bug will result in silent failure (rather than a debuggable deadlock). Furthermore, there * is a history of this API being used to know when a service is up as a proxy for whethre * that service should be started. This should only be used if you are intending to get * ahold of the service as a client. For lazy services, whether a service is registered * should not be used as a proxy for when it should be registered, which is only known * by the real client. * * WARNING: if you use this API, you must also ensure that you check missing services are * started and crash otherwise. If service failures are ignored, the system rots. * * \param instance name of service to wait for notifications about * \param onRegister callback for when service is registered * \param cookie data associated with this callback * * \return the token for this registration. Deleting this token will unregister. */ __attribute__((warn_unused_result)) AServiceManager_NotificationRegistration* AServiceManager_registerForServiceNotifications(const char* instance, AServiceManager_onRegister onRegister, void* cookie) __INTRODUCED_IN(34); /** * Unregister for notifications and delete the object. * * After this method is called, the callback is guaranteed to no longer be invoked. This will block * until any in-progress onRegister callbacks have completed. It is therefore safe to immediately * destroy the void* cookie that was registered when this method returns. * * \param notification object to dismiss */ void AServiceManager_NotificationRegistration_delete( AServiceManager_NotificationRegistration* notification) __INTRODUCED_IN(34); /** * Check if a service is declared (e.g. VINTF manifest). * Loading
libs/binder/ndk/libbinder_ndk.map.txt +2 −0 Original line number Diff line number Diff line Loading @@ -155,6 +155,8 @@ LIBBINDER_NDK33 { # introduced=33 LIBBINDER_NDK34 { # introduced=UpsideDownCake global: AServiceManager_getUpdatableApexName; # systemapi AServiceManager_registerForServiceNotifications; # systemapi llndk AServiceManager_NotificationRegistration_delete; # systemapi llndk }; LIBBINDER_NDK_PLATFORM { Loading
libs/binder/ndk/service_manager.cpp +62 −0 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ using ::android::IBinder; using ::android::IServiceManager; using ::android::sp; using ::android::status_t; using ::android::statusToString; using ::android::String16; using ::android::String8; Loading Loading @@ -86,6 +87,67 @@ AIBinder* AServiceManager_waitForService(const char* instance) { AIBinder_incStrong(ret.get()); return ret.get(); } typedef void (*AServiceManager_onRegister)(const char* instance, AIBinder* registered, void* cookie); struct AServiceManager_NotificationRegistration : public IServiceManager::LocalRegistrationCallback { std::mutex m; const char* instance = nullptr; void* cookie = nullptr; AServiceManager_onRegister onRegister = nullptr; virtual void onServiceRegistration(const String16& smInstance, const sp<IBinder>& binder) { std::lock_guard<std::mutex> l(m); if (onRegister == nullptr) return; CHECK_EQ(String8(smInstance), instance); sp<AIBinder> ret = ABpBinder::lookupOrCreateFromBinder(binder); AIBinder_incStrong(ret.get()); onRegister(instance, ret.get(), cookie); } void clear() { std::lock_guard<std::mutex> l(m); instance = nullptr; cookie = nullptr; onRegister = nullptr; } }; __attribute__((warn_unused_result)) AServiceManager_NotificationRegistration* AServiceManager_registerForServiceNotifications(const char* instance, AServiceManager_onRegister onRegister, void* cookie) { CHECK_NE(instance, nullptr); CHECK_NE(onRegister, nullptr) << instance; // cookie can be nullptr auto cb = sp<AServiceManager_NotificationRegistration>::make(); cb->instance = instance; cb->onRegister = onRegister; cb->cookie = cookie; sp<IServiceManager> sm = defaultServiceManager(); if (status_t res = sm->registerForNotifications(String16(instance), cb); res != STATUS_OK) { LOG(ERROR) << "Failed to register for service notifications for " << instance << ": " << statusToString(res); return nullptr; } cb->incStrong(nullptr); return cb.get(); } void AServiceManager_NotificationRegistration_delete( AServiceManager_NotificationRegistration* notification) { CHECK_NE(notification, nullptr); notification->clear(); notification->decStrong(nullptr); } bool AServiceManager_isDeclared(const char* instance) { if (instance == nullptr) { return false; Loading
libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp +41 −0 Original line number Diff line number Diff line Loading @@ -254,6 +254,47 @@ TEST(NdkBinder, CheckServiceThatDoesExist) { AIBinder_decStrong(binder); } struct ServiceData { std::string instance; ndk::SpAIBinder binder; static void fillOnRegister(const char* instance, AIBinder* binder, void* cookie) { ServiceData* d = reinterpret_cast<ServiceData*>(cookie); d->instance = instance; d->binder = ndk::SpAIBinder(binder); } }; TEST(NdkBinder, RegisterForServiceNotificationsNonExisting) { ServiceData data; auto* notif = AServiceManager_registerForServiceNotifications( "DOES_NOT_EXIST", ServiceData::fillOnRegister, (void*)&data); ASSERT_NE(notif, nullptr); sleep(1); // give us a chance to fail AServiceManager_NotificationRegistration_delete(notif); // checking after deleting to avoid needing a mutex over the data - otherwise // in an environment w/ multiple threads, you would need to guard access EXPECT_EQ(data.instance, ""); EXPECT_EQ(data.binder, nullptr); } TEST(NdkBinder, RegisterForServiceNotificationsExisting) { ServiceData data; auto* notif = AServiceManager_registerForServiceNotifications( kExistingNonNdkService, ServiceData::fillOnRegister, (void*)&data); ASSERT_NE(notif, nullptr); sleep(1); // give us a chance to fail AServiceManager_NotificationRegistration_delete(notif); // checking after deleting to avoid needing a mutex over the data - otherwise // in an environment w/ multiple threads, you would need to guard access EXPECT_EQ(data.instance, kExistingNonNdkService); EXPECT_EQ(data.binder, ndk::SpAIBinder(AServiceManager_checkService(kExistingNonNdkService))); } TEST(NdkBinder, UnimplementedDump) { sp<IFoo> foo = IFoo::getService(IFoo::kSomeInstanceName); ASSERT_NE(foo, nullptr); Loading