Loading libs/binder/ndk/ibinder.cpp +23 −2 Original line number Diff line number Diff line Loading @@ -373,6 +373,12 @@ const char* AIBinder_Class_getDescriptor(const AIBinder_Class* clazz) { return clazz->getInterfaceDescriptorUtf8(); } AIBinder_DeathRecipient::TransferDeathRecipient::~TransferDeathRecipient() { if (mOnUnlinked != nullptr) { mOnUnlinked(mCookie); } } void AIBinder_DeathRecipient::TransferDeathRecipient::binderDied(const wp<IBinder>& who) { CHECK(who == mWho) << who.unsafe_get() << "(" << who.get_refs() << ") vs " << mWho.unsafe_get() << " (" << mWho.get_refs() << ")"; Loading @@ -394,7 +400,7 @@ void AIBinder_DeathRecipient::TransferDeathRecipient::binderDied(const wp<IBinde } AIBinder_DeathRecipient::AIBinder_DeathRecipient(AIBinder_DeathRecipient_onBinderDied onDied) : mOnDied(onDied) { : mOnDied(onDied), mOnUnlinked(nullptr) { CHECK(onDied != nullptr); } Loading @@ -412,10 +418,12 @@ binder_status_t AIBinder_DeathRecipient::linkToDeath(const sp<IBinder>& binder, std::lock_guard<std::mutex> l(mDeathRecipientsMutex); sp<TransferDeathRecipient> recipient = new TransferDeathRecipient(binder, cookie, this, mOnDied); new TransferDeathRecipient(binder, cookie, this, mOnDied, mOnUnlinked); status_t status = binder->linkToDeath(recipient, cookie, 0 /*flags*/); if (status != STATUS_OK) { // When we failed to link, the destructor of TransferDeathRecipient runs here, which // ensures that mOnUnlinked is called before we return with an error from this method. return PruneStatusT(status); } Loading Loading @@ -448,6 +456,10 @@ binder_status_t AIBinder_DeathRecipient::unlinkToDeath(const sp<IBinder>& binder return STATUS_NAME_NOT_FOUND; } void AIBinder_DeathRecipient::setOnUnlinked(AIBinder_DeathRecipient_onBinderUnlinked onUnlinked) { mOnUnlinked = onUnlinked; } // start of C-API methods AIBinder* AIBinder_new(const AIBinder_Class* clazz, void* args) { Loading Loading @@ -689,6 +701,15 @@ AIBinder_DeathRecipient* AIBinder_DeathRecipient_new( return ret; } void AIBinder_DeathRecipient_setOnUnlinked(AIBinder_DeathRecipient* recipient, AIBinder_DeathRecipient_onBinderUnlinked onUnlinked) { if (recipient == nullptr) { return; } recipient->setOnUnlinked(onUnlinked); } void AIBinder_DeathRecipient_delete(AIBinder_DeathRecipient* recipient) { if (recipient == nullptr) { return; Loading libs/binder/ndk/ibinder_internal.h +11 −2 Original line number Diff line number Diff line Loading @@ -148,8 +148,14 @@ struct AIBinder_DeathRecipient : ::android::RefBase { struct TransferDeathRecipient : ::android::IBinder::DeathRecipient { TransferDeathRecipient(const ::android::wp<::android::IBinder>& who, void* cookie, const ::android::wp<AIBinder_DeathRecipient>& parentRecipient, const AIBinder_DeathRecipient_onBinderDied onDied) : mWho(who), mCookie(cookie), mParentRecipient(parentRecipient), mOnDied(onDied) {} const AIBinder_DeathRecipient_onBinderDied onDied, const AIBinder_DeathRecipient_onBinderUnlinked onUnlinked) : mWho(who), mCookie(cookie), mParentRecipient(parentRecipient), mOnDied(onDied), mOnUnlinked(onUnlinked) {} ~TransferDeathRecipient(); void binderDied(const ::android::wp<::android::IBinder>& who) override; Loading @@ -165,11 +171,13 @@ struct AIBinder_DeathRecipient : ::android::RefBase { // This is kept separately from AIBinder_DeathRecipient in case the death recipient is // deleted while the death notification is fired const AIBinder_DeathRecipient_onBinderDied mOnDied; const AIBinder_DeathRecipient_onBinderUnlinked mOnUnlinked; }; explicit AIBinder_DeathRecipient(AIBinder_DeathRecipient_onBinderDied onDied); binder_status_t linkToDeath(const ::android::sp<::android::IBinder>&, void* cookie); binder_status_t unlinkToDeath(const ::android::sp<::android::IBinder>& binder, void* cookie); void setOnUnlinked(AIBinder_DeathRecipient_onBinderUnlinked onUnlinked); private: // When the user of this API deletes a Bp object but not the death recipient, the Loading @@ -180,4 +188,5 @@ struct AIBinder_DeathRecipient : ::android::RefBase { std::mutex mDeathRecipientsMutex; std::vector<::android::sp<TransferDeathRecipient>> mDeathRecipients; AIBinder_DeathRecipient_onBinderDied mOnDied; AIBinder_DeathRecipient_onBinderUnlinked mOnUnlinked; }; libs/binder/ndk/include_ndk/android/binder_ibinder.h +60 −2 Original line number Diff line number Diff line Loading @@ -319,9 +319,9 @@ binder_status_t AIBinder_dump(AIBinder* binder, int fd, const char** args, uint3 /** * Registers for notifications that the associated binder is dead. The same death recipient may be * associated with multiple different binders. If the binder is local, then no death recipient will * be given (since if the local process dies, then no recipient will exist to recieve a * be given (since if the local process dies, then no recipient will exist to receive a * transaction). The cookie is passed to recipient in the case that this binder dies and can be * null. The exact cookie must also be used to unlink this transaction (see AIBinder_linkToDeath). * null. The exact cookie must also be used to unlink this transaction (see AIBinder_unlinkToDeath). * This function may return a binder transaction failure. The cookie can be used both for * identification and holding user data. * Loading @@ -348,6 +348,10 @@ binder_status_t AIBinder_linkToDeath(AIBinder* binder, AIBinder_DeathRecipient* * If the binder dies, it will automatically unlink. If the binder is deleted, it will be * automatically unlinked. * * Be aware that it is not safe to immediately deallocate the cookie when this call returns. If you * need to clean up the cookie, you should do so in the onUnlinked callback, which can be set using * AIBinder_DeathRecipient_setOnUnlinked. * * Available since API level 29. * * \param binder the binder object to remove a previously linked death recipient from. Loading Loading @@ -567,6 +571,22 @@ __attribute__((warn_unused_result)) AIBinder* AIBinder_Weak_promote(AIBinder_Wea */ typedef void (*AIBinder_DeathRecipient_onBinderDied)(void* cookie) __INTRODUCED_IN(29); /** * This function is intended for cleaning up the data in the provided cookie, and it is executed * when the DeathRecipient is unlinked. When the DeathRecipient is unlinked due to a death receipt, * this method is called after the call to onBinderDied. * * This method is called once for each binder that is unlinked. Hence, if the same cookie is passed * to multiple binders, then the caller is responsible for reference counting the cookie. * * See also AIBinder_linkToDeath/AIBinder_unlinkToDeath. * * Available since API level 33. * * \param cookie the cookie passed to AIBinder_linkToDeath. */ typedef void (*AIBinder_DeathRecipient_onBinderUnlinked)(void* cookie) __INTRODUCED_IN(33); /** * Creates a new binder death recipient. This can be attached to multiple different binder objects. * Loading @@ -579,10 +599,48 @@ typedef void (*AIBinder_DeathRecipient_onBinderDied)(void* cookie) __INTRODUCED_ __attribute__((warn_unused_result)) AIBinder_DeathRecipient* AIBinder_DeathRecipient_new( AIBinder_DeathRecipient_onBinderDied onBinderDied) __INTRODUCED_IN(29); /** * Set the callback to be called when this DeathRecipient is unlinked from a binder. The callback is * called in the following situations: * * 1. If the binder died, shortly after the call to onBinderDied. * 2. If the binder is explicitly unlinked with AIBinder_unlinkToDeath or * AIBinder_DeathRecipient_delete. * 3. During or shortly after the AIBinder_linkToDeath call if it returns an error. * * It is guaranteed that the callback is called exactly once for each call to linkToDeath unless the * process is aborted before the binder is unlinked. * * Be aware that when the binder is explicitly unlinked, it is not guaranteed that onUnlinked has * been called before the call to AIBinder_unlinkToDeath or AIBinder_DeathRecipient_delete returns. * For example, if the binder dies concurrently with a call to AIBinder_unlinkToDeath, the binder is * not unlinked until after the death notification is delivered, even if AIBinder_unlinkToDeath * returns before that happens. * * This method should be called before linking the DeathRecipient to a binder because the function * pointer is cached. If you change it after linking to a binder, it is unspecified whether the old * binder will call the old or new onUnlinked callback. * * The onUnlinked argument may be null. In this case, no notification is given when the binder is * unlinked. * * Available since API level 33. * * \param recipient the DeathRecipient to set the onUnlinked callback for. * \param onUnlinked the callback to call when a binder is unlinked from recipient. */ void AIBinder_DeathRecipient_setOnUnlinked(AIBinder_DeathRecipient* recipient, AIBinder_DeathRecipient_onBinderUnlinked onUnlinked) __INTRODUCED_IN(33); /** * Deletes a binder death recipient. It is not necessary to call AIBinder_unlinkToDeath before * calling this as these will all be automatically unlinked. * * Be aware that it is not safe to immediately deallocate the cookie when this call returns. If you * need to clean up the cookie, you should do so in the onUnlinked callback, which can be set using * AIBinder_DeathRecipient_setOnUnlinked. * * Available since API level 29. * * \param recipient the binder to delete (previously created with AIBinder_DeathRecipient_new). Loading libs/binder/ndk/libbinder_ndk.map.txt +1 −0 Original line number Diff line number Diff line Loading @@ -144,6 +144,7 @@ LIBBINDER_NDK31 { # introduced=31 LIBBINDER_NDK33 { # introduced=33 global: AIBinder_Class_disableInterfaceTokenHeader; AIBinder_DeathRecipient_setOnUnlinked; AParcel_marshal; AParcel_unmarshal; }; Loading libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp +35 −8 Original line number Diff line number Diff line Loading @@ -375,9 +375,16 @@ TEST(NdkBinder, ActiveServicesCallbackTest) { << "Service failed to shut down."; } struct DeathRecipientCookie { std::function<void(void)>*onDeath, *onUnlink; }; void LambdaOnDeath(void* cookie) { auto onDeath = static_cast<std::function<void(void)>*>(cookie); (*onDeath)(); auto funcs = static_cast<DeathRecipientCookie*>(cookie); (*funcs->onDeath)(); }; void LambdaOnUnlink(void* cookie) { auto funcs = static_cast<DeathRecipientCookie*>(cookie); (*funcs->onUnlink)(); }; TEST(NdkBinder, DeathRecipient) { using namespace std::chrono_literals; Loading @@ -389,26 +396,46 @@ TEST(NdkBinder, DeathRecipient) { std::mutex deathMutex; std::condition_variable deathCv; bool deathRecieved = false; bool deathReceived = false; std::function<void(void)> onDeath = [&] { std::cerr << "Binder died (as requested)." << std::endl; deathRecieved = true; deathReceived = true; deathCv.notify_one(); }; std::mutex unlinkMutex; std::condition_variable unlinkCv; bool unlinkReceived = false; bool wasDeathReceivedFirst = false; std::function<void(void)> onUnlink = [&] { std::cerr << "Binder unlinked (as requested)." << std::endl; wasDeathReceivedFirst = deathReceived; unlinkReceived = true; unlinkCv.notify_one(); }; DeathRecipientCookie cookie = {&onDeath, &onUnlink}; AIBinder_DeathRecipient* recipient = AIBinder_DeathRecipient_new(LambdaOnDeath); AIBinder_DeathRecipient_setOnUnlinked(recipient, LambdaOnUnlink); EXPECT_EQ(STATUS_OK, AIBinder_linkToDeath(binder, recipient, static_cast<void*>(&onDeath))); EXPECT_EQ(STATUS_OK, AIBinder_linkToDeath(binder, recipient, static_cast<void*>(&cookie))); // the binder driver should return this if the service dies during the transaction EXPECT_EQ(STATUS_DEAD_OBJECT, foo->die()); foo = nullptr; std::unique_lock<std::mutex> lock(deathMutex); EXPECT_TRUE(deathCv.wait_for(lock, 1s, [&] { return deathRecieved; })); EXPECT_TRUE(deathRecieved); std::unique_lock<std::mutex> lockDeath(deathMutex); EXPECT_TRUE(deathCv.wait_for(lockDeath, 1s, [&] { return deathReceived; })); EXPECT_TRUE(deathReceived); std::unique_lock<std::mutex> lockUnlink(unlinkMutex); EXPECT_TRUE(deathCv.wait_for(lockUnlink, 1s, [&] { return unlinkReceived; })); EXPECT_TRUE(unlinkReceived); EXPECT_TRUE(wasDeathReceivedFirst); AIBinder_DeathRecipient_delete(recipient); AIBinder_decStrong(binder); Loading Loading
libs/binder/ndk/ibinder.cpp +23 −2 Original line number Diff line number Diff line Loading @@ -373,6 +373,12 @@ const char* AIBinder_Class_getDescriptor(const AIBinder_Class* clazz) { return clazz->getInterfaceDescriptorUtf8(); } AIBinder_DeathRecipient::TransferDeathRecipient::~TransferDeathRecipient() { if (mOnUnlinked != nullptr) { mOnUnlinked(mCookie); } } void AIBinder_DeathRecipient::TransferDeathRecipient::binderDied(const wp<IBinder>& who) { CHECK(who == mWho) << who.unsafe_get() << "(" << who.get_refs() << ") vs " << mWho.unsafe_get() << " (" << mWho.get_refs() << ")"; Loading @@ -394,7 +400,7 @@ void AIBinder_DeathRecipient::TransferDeathRecipient::binderDied(const wp<IBinde } AIBinder_DeathRecipient::AIBinder_DeathRecipient(AIBinder_DeathRecipient_onBinderDied onDied) : mOnDied(onDied) { : mOnDied(onDied), mOnUnlinked(nullptr) { CHECK(onDied != nullptr); } Loading @@ -412,10 +418,12 @@ binder_status_t AIBinder_DeathRecipient::linkToDeath(const sp<IBinder>& binder, std::lock_guard<std::mutex> l(mDeathRecipientsMutex); sp<TransferDeathRecipient> recipient = new TransferDeathRecipient(binder, cookie, this, mOnDied); new TransferDeathRecipient(binder, cookie, this, mOnDied, mOnUnlinked); status_t status = binder->linkToDeath(recipient, cookie, 0 /*flags*/); if (status != STATUS_OK) { // When we failed to link, the destructor of TransferDeathRecipient runs here, which // ensures that mOnUnlinked is called before we return with an error from this method. return PruneStatusT(status); } Loading Loading @@ -448,6 +456,10 @@ binder_status_t AIBinder_DeathRecipient::unlinkToDeath(const sp<IBinder>& binder return STATUS_NAME_NOT_FOUND; } void AIBinder_DeathRecipient::setOnUnlinked(AIBinder_DeathRecipient_onBinderUnlinked onUnlinked) { mOnUnlinked = onUnlinked; } // start of C-API methods AIBinder* AIBinder_new(const AIBinder_Class* clazz, void* args) { Loading Loading @@ -689,6 +701,15 @@ AIBinder_DeathRecipient* AIBinder_DeathRecipient_new( return ret; } void AIBinder_DeathRecipient_setOnUnlinked(AIBinder_DeathRecipient* recipient, AIBinder_DeathRecipient_onBinderUnlinked onUnlinked) { if (recipient == nullptr) { return; } recipient->setOnUnlinked(onUnlinked); } void AIBinder_DeathRecipient_delete(AIBinder_DeathRecipient* recipient) { if (recipient == nullptr) { return; Loading
libs/binder/ndk/ibinder_internal.h +11 −2 Original line number Diff line number Diff line Loading @@ -148,8 +148,14 @@ struct AIBinder_DeathRecipient : ::android::RefBase { struct TransferDeathRecipient : ::android::IBinder::DeathRecipient { TransferDeathRecipient(const ::android::wp<::android::IBinder>& who, void* cookie, const ::android::wp<AIBinder_DeathRecipient>& parentRecipient, const AIBinder_DeathRecipient_onBinderDied onDied) : mWho(who), mCookie(cookie), mParentRecipient(parentRecipient), mOnDied(onDied) {} const AIBinder_DeathRecipient_onBinderDied onDied, const AIBinder_DeathRecipient_onBinderUnlinked onUnlinked) : mWho(who), mCookie(cookie), mParentRecipient(parentRecipient), mOnDied(onDied), mOnUnlinked(onUnlinked) {} ~TransferDeathRecipient(); void binderDied(const ::android::wp<::android::IBinder>& who) override; Loading @@ -165,11 +171,13 @@ struct AIBinder_DeathRecipient : ::android::RefBase { // This is kept separately from AIBinder_DeathRecipient in case the death recipient is // deleted while the death notification is fired const AIBinder_DeathRecipient_onBinderDied mOnDied; const AIBinder_DeathRecipient_onBinderUnlinked mOnUnlinked; }; explicit AIBinder_DeathRecipient(AIBinder_DeathRecipient_onBinderDied onDied); binder_status_t linkToDeath(const ::android::sp<::android::IBinder>&, void* cookie); binder_status_t unlinkToDeath(const ::android::sp<::android::IBinder>& binder, void* cookie); void setOnUnlinked(AIBinder_DeathRecipient_onBinderUnlinked onUnlinked); private: // When the user of this API deletes a Bp object but not the death recipient, the Loading @@ -180,4 +188,5 @@ struct AIBinder_DeathRecipient : ::android::RefBase { std::mutex mDeathRecipientsMutex; std::vector<::android::sp<TransferDeathRecipient>> mDeathRecipients; AIBinder_DeathRecipient_onBinderDied mOnDied; AIBinder_DeathRecipient_onBinderUnlinked mOnUnlinked; };
libs/binder/ndk/include_ndk/android/binder_ibinder.h +60 −2 Original line number Diff line number Diff line Loading @@ -319,9 +319,9 @@ binder_status_t AIBinder_dump(AIBinder* binder, int fd, const char** args, uint3 /** * Registers for notifications that the associated binder is dead. The same death recipient may be * associated with multiple different binders. If the binder is local, then no death recipient will * be given (since if the local process dies, then no recipient will exist to recieve a * be given (since if the local process dies, then no recipient will exist to receive a * transaction). The cookie is passed to recipient in the case that this binder dies and can be * null. The exact cookie must also be used to unlink this transaction (see AIBinder_linkToDeath). * null. The exact cookie must also be used to unlink this transaction (see AIBinder_unlinkToDeath). * This function may return a binder transaction failure. The cookie can be used both for * identification and holding user data. * Loading @@ -348,6 +348,10 @@ binder_status_t AIBinder_linkToDeath(AIBinder* binder, AIBinder_DeathRecipient* * If the binder dies, it will automatically unlink. If the binder is deleted, it will be * automatically unlinked. * * Be aware that it is not safe to immediately deallocate the cookie when this call returns. If you * need to clean up the cookie, you should do so in the onUnlinked callback, which can be set using * AIBinder_DeathRecipient_setOnUnlinked. * * Available since API level 29. * * \param binder the binder object to remove a previously linked death recipient from. Loading Loading @@ -567,6 +571,22 @@ __attribute__((warn_unused_result)) AIBinder* AIBinder_Weak_promote(AIBinder_Wea */ typedef void (*AIBinder_DeathRecipient_onBinderDied)(void* cookie) __INTRODUCED_IN(29); /** * This function is intended for cleaning up the data in the provided cookie, and it is executed * when the DeathRecipient is unlinked. When the DeathRecipient is unlinked due to a death receipt, * this method is called after the call to onBinderDied. * * This method is called once for each binder that is unlinked. Hence, if the same cookie is passed * to multiple binders, then the caller is responsible for reference counting the cookie. * * See also AIBinder_linkToDeath/AIBinder_unlinkToDeath. * * Available since API level 33. * * \param cookie the cookie passed to AIBinder_linkToDeath. */ typedef void (*AIBinder_DeathRecipient_onBinderUnlinked)(void* cookie) __INTRODUCED_IN(33); /** * Creates a new binder death recipient. This can be attached to multiple different binder objects. * Loading @@ -579,10 +599,48 @@ typedef void (*AIBinder_DeathRecipient_onBinderDied)(void* cookie) __INTRODUCED_ __attribute__((warn_unused_result)) AIBinder_DeathRecipient* AIBinder_DeathRecipient_new( AIBinder_DeathRecipient_onBinderDied onBinderDied) __INTRODUCED_IN(29); /** * Set the callback to be called when this DeathRecipient is unlinked from a binder. The callback is * called in the following situations: * * 1. If the binder died, shortly after the call to onBinderDied. * 2. If the binder is explicitly unlinked with AIBinder_unlinkToDeath or * AIBinder_DeathRecipient_delete. * 3. During or shortly after the AIBinder_linkToDeath call if it returns an error. * * It is guaranteed that the callback is called exactly once for each call to linkToDeath unless the * process is aborted before the binder is unlinked. * * Be aware that when the binder is explicitly unlinked, it is not guaranteed that onUnlinked has * been called before the call to AIBinder_unlinkToDeath or AIBinder_DeathRecipient_delete returns. * For example, if the binder dies concurrently with a call to AIBinder_unlinkToDeath, the binder is * not unlinked until after the death notification is delivered, even if AIBinder_unlinkToDeath * returns before that happens. * * This method should be called before linking the DeathRecipient to a binder because the function * pointer is cached. If you change it after linking to a binder, it is unspecified whether the old * binder will call the old or new onUnlinked callback. * * The onUnlinked argument may be null. In this case, no notification is given when the binder is * unlinked. * * Available since API level 33. * * \param recipient the DeathRecipient to set the onUnlinked callback for. * \param onUnlinked the callback to call when a binder is unlinked from recipient. */ void AIBinder_DeathRecipient_setOnUnlinked(AIBinder_DeathRecipient* recipient, AIBinder_DeathRecipient_onBinderUnlinked onUnlinked) __INTRODUCED_IN(33); /** * Deletes a binder death recipient. It is not necessary to call AIBinder_unlinkToDeath before * calling this as these will all be automatically unlinked. * * Be aware that it is not safe to immediately deallocate the cookie when this call returns. If you * need to clean up the cookie, you should do so in the onUnlinked callback, which can be set using * AIBinder_DeathRecipient_setOnUnlinked. * * Available since API level 29. * * \param recipient the binder to delete (previously created with AIBinder_DeathRecipient_new). Loading
libs/binder/ndk/libbinder_ndk.map.txt +1 −0 Original line number Diff line number Diff line Loading @@ -144,6 +144,7 @@ LIBBINDER_NDK31 { # introduced=31 LIBBINDER_NDK33 { # introduced=33 global: AIBinder_Class_disableInterfaceTokenHeader; AIBinder_DeathRecipient_setOnUnlinked; AParcel_marshal; AParcel_unmarshal; }; Loading
libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp +35 −8 Original line number Diff line number Diff line Loading @@ -375,9 +375,16 @@ TEST(NdkBinder, ActiveServicesCallbackTest) { << "Service failed to shut down."; } struct DeathRecipientCookie { std::function<void(void)>*onDeath, *onUnlink; }; void LambdaOnDeath(void* cookie) { auto onDeath = static_cast<std::function<void(void)>*>(cookie); (*onDeath)(); auto funcs = static_cast<DeathRecipientCookie*>(cookie); (*funcs->onDeath)(); }; void LambdaOnUnlink(void* cookie) { auto funcs = static_cast<DeathRecipientCookie*>(cookie); (*funcs->onUnlink)(); }; TEST(NdkBinder, DeathRecipient) { using namespace std::chrono_literals; Loading @@ -389,26 +396,46 @@ TEST(NdkBinder, DeathRecipient) { std::mutex deathMutex; std::condition_variable deathCv; bool deathRecieved = false; bool deathReceived = false; std::function<void(void)> onDeath = [&] { std::cerr << "Binder died (as requested)." << std::endl; deathRecieved = true; deathReceived = true; deathCv.notify_one(); }; std::mutex unlinkMutex; std::condition_variable unlinkCv; bool unlinkReceived = false; bool wasDeathReceivedFirst = false; std::function<void(void)> onUnlink = [&] { std::cerr << "Binder unlinked (as requested)." << std::endl; wasDeathReceivedFirst = deathReceived; unlinkReceived = true; unlinkCv.notify_one(); }; DeathRecipientCookie cookie = {&onDeath, &onUnlink}; AIBinder_DeathRecipient* recipient = AIBinder_DeathRecipient_new(LambdaOnDeath); AIBinder_DeathRecipient_setOnUnlinked(recipient, LambdaOnUnlink); EXPECT_EQ(STATUS_OK, AIBinder_linkToDeath(binder, recipient, static_cast<void*>(&onDeath))); EXPECT_EQ(STATUS_OK, AIBinder_linkToDeath(binder, recipient, static_cast<void*>(&cookie))); // the binder driver should return this if the service dies during the transaction EXPECT_EQ(STATUS_DEAD_OBJECT, foo->die()); foo = nullptr; std::unique_lock<std::mutex> lock(deathMutex); EXPECT_TRUE(deathCv.wait_for(lock, 1s, [&] { return deathRecieved; })); EXPECT_TRUE(deathRecieved); std::unique_lock<std::mutex> lockDeath(deathMutex); EXPECT_TRUE(deathCv.wait_for(lockDeath, 1s, [&] { return deathReceived; })); EXPECT_TRUE(deathReceived); std::unique_lock<std::mutex> lockUnlink(unlinkMutex); EXPECT_TRUE(deathCv.wait_for(lockUnlink, 1s, [&] { return unlinkReceived; })); EXPECT_TRUE(unlinkReceived); EXPECT_TRUE(wasDeathReceivedFirst); AIBinder_DeathRecipient_delete(recipient); AIBinder_decStrong(binder); Loading