libbinder_ndk: linkToDeath/unlinkToDeath
This adds AIBinder_DeathRecipient and methods to use it in order
to receive death notifications.
Bug: 111445392
Test: ./ndk/runtests.sh
Test: manually killing a service and finding its death recipient
Change-Id: I556435cae88b01e6e2cfdc0a286bdb660859872c
diff --git a/libs/binder/ndk/AIBinder.cpp b/libs/binder/ndk/AIBinder.cpp
index 2219f8e..ee1d48a 100644
--- a/libs/binder/ndk/AIBinder.cpp
+++ b/libs/binder/ndk/AIBinder.cpp
@@ -22,6 +22,8 @@
#include <android-base/logging.h>
+using DeathRecipient = ::android::IBinder::DeathRecipient;
+
using ::android::IBinder;
using ::android::Parcel;
using ::android::sp;
@@ -179,6 +181,63 @@
return new AIBinder_Class(interfaceDescriptor, onCreate, onDestroy, onTransact);
}
+void AIBinder_DeathRecipient::TransferDeathRecipient::binderDied(const wp<IBinder>& who) {
+ CHECK(who == mWho);
+
+ mOnDied(mCookie);
+ mWho = nullptr;
+}
+
+AIBinder_DeathRecipient::AIBinder_DeathRecipient(AIBinder_DeathRecipient_onBinderDied onDied)
+ : mOnDied(onDied) {
+ CHECK(onDied != nullptr);
+}
+
+binder_status_t AIBinder_DeathRecipient::linkToDeath(AIBinder* binder, void* cookie) {
+ CHECK(binder != nullptr);
+
+ std::lock_guard<std::mutex> l(mDeathRecipientsMutex);
+
+ sp<TransferDeathRecipient> recipient =
+ new TransferDeathRecipient(binder->getBinder(), cookie, mOnDied);
+
+ binder_status_t status = binder->getBinder()->linkToDeath(recipient, cookie, 0 /*flags*/);
+ if (status != EX_NONE) {
+ return status;
+ }
+
+ mDeathRecipients.push_back(recipient);
+ return EX_NONE;
+}
+
+binder_status_t AIBinder_DeathRecipient::unlinkToDeath(AIBinder* binder, void* cookie) {
+ CHECK(binder != nullptr);
+
+ std::lock_guard<std::mutex> l(mDeathRecipientsMutex);
+
+ for (auto it = mDeathRecipients.rbegin(); it != mDeathRecipients.rend(); ++it) {
+ sp<TransferDeathRecipient> recipient = *it;
+
+ if (recipient->getCookie() == cookie &&
+
+ recipient->getWho() == binder->getBinder()) {
+ mDeathRecipients.erase(it.base() - 1);
+
+ binder_status_t status =
+ binder->getBinder()->unlinkToDeath(recipient, cookie, 0 /*flags*/);
+ if (status != EX_NONE) {
+ LOG(ERROR) << __func__
+ << ": removed reference to death recipient but unlink failed.";
+ }
+ return status;
+ }
+ }
+
+ return -ENOENT;
+}
+
+// start of C-API methods
+
AIBinder* AIBinder_new(const AIBinder_Class* clazz, void* args) {
if (clazz == nullptr) {
LOG(ERROR) << __func__ << ": Must provide class to construct local binder.";
@@ -218,6 +277,26 @@
return binder->getBinder()->pingBinder();
}
+binder_status_t AIBinder_linkToDeath(AIBinder* binder, AIBinder_DeathRecipient* recipient,
+ void* cookie) {
+ if (binder == nullptr || recipient == nullptr) {
+ LOG(ERROR) << __func__ << ": Must provide binder and recipient.";
+ return EX_NULL_POINTER;
+ }
+
+ return recipient->linkToDeath(binder, cookie);
+}
+
+binder_status_t AIBinder_unlinkToDeath(AIBinder* binder, AIBinder_DeathRecipient* recipient,
+ void* cookie) {
+ if (binder == nullptr || recipient == nullptr) {
+ LOG(ERROR) << __func__ << ": Must provide binder and recipient.";
+ return EX_NULL_POINTER;
+ }
+
+ return recipient->unlinkToDeath(binder, cookie);
+}
+
void AIBinder_incStrong(AIBinder* binder) {
if (binder == nullptr) {
LOG(ERROR) << __func__ << ": on null binder";
@@ -347,3 +426,21 @@
return parcelStatus;
}
+
+AIBinder_DeathRecipient* AIBinder_DeathRecipient_new(
+ AIBinder_DeathRecipient_onBinderDied onBinderDied) {
+ if (onBinderDied == nullptr) {
+ LOG(ERROR) << __func__ << ": requires non-null onBinderDied parameter.";
+ return nullptr;
+ }
+ return new AIBinder_DeathRecipient(onBinderDied);
+}
+
+void AIBinder_DeathRecipient_delete(AIBinder_DeathRecipient** recipient) {
+ if (recipient == nullptr) {
+ return;
+ }
+
+ delete *recipient;
+ *recipient = nullptr;
+}