aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPierre Langlois <pierre.langlois@arm.com>2015-02-12 18:23:11 +0000
committerPierre Langlois <pierre.langlois@arm.com>2016-03-04 18:01:17 +0000
commitfaa15a27bff96bebe6e522c8c6662fef10f6a55d (patch)
treebf25b273083bf6fea2bd1d2adf374e034604c983
parenta4444561cb4e52ae8890a9670357e44d6ba4d0bc (diff)
downloadkdbinder-faa15a27bff96bebe6e522c8c6662fef10f6a55d.tar.gz
libkdbinder: implement linkToDeath
This commit implements `IPCThreadState::requestDeathNotification` and `IPCThreadState::clearDeathNotification`. The implementation is very similar to that of handling transaction: * Add a mDeathRecipientTable table of Connections associated to Binder objects. * `requestDeathNotification` will create a dedicated Connection for monitoring the given Binder and add them to the table. We request for a death notification by using `kdbus::Connection::notify_when_dead`. * `clearDeathNotification` will remove the entry from the table. * In the same way that `handleService` handles a transaction, `handleDeathRecipient` dequeues a death notification and calls the recipient. We then call `handleDeathRecipient` periodically just like `handleService`. TODO: This implementation is not very efficient. Change-Id: I977cfb244ca5de8564a293c619978c8bd3f5d79b
-rw-r--r--include/kdbinder/binder/BpBinder.h9
-rw-r--r--include/kdbinder/binder/IPCThreadState.h2
-rw-r--r--include/kdbinder/binder/ProcessState.h2
-rw-r--r--libs/kdbinder/binder/BpBinder.cpp49
-rw-r--r--libs/kdbinder/binder/IPCThreadState.cpp66
5 files changed, 114 insertions, 14 deletions
diff --git a/include/kdbinder/binder/BpBinder.h b/include/kdbinder/binder/BpBinder.h
index 058903a..f1a38b7 100644
--- a/include/kdbinder/binder/BpBinder.h
+++ b/include/kdbinder/binder/BpBinder.h
@@ -22,6 +22,7 @@
#include <utils/Errors.h>
#include <utils/String16.h>
#include <utils/Mutex.h>
+#include <utils/Vector.h>
namespace android {
@@ -62,8 +63,16 @@ class BpBinder : public IBinder {
private:
bool isDescriptorCached() const;
+ struct Obituary {
+ wp<DeathRecipient> recipient;
+ void* cookie;
+ uint32_t flags;
+ };
+
mutable Mutex mLock;
mutable String16 mDescriptorCache;
+ volatile int32_t mObitsSent;
+ Vector<Obituary> *mObituaries;
const int32_t mHandle;
volatile int32_t mAlive;
};
diff --git a/include/kdbinder/binder/IPCThreadState.h b/include/kdbinder/binder/IPCThreadState.h
index 144b1a1..e034fe7 100644
--- a/include/kdbinder/binder/IPCThreadState.h
+++ b/include/kdbinder/binder/IPCThreadState.h
@@ -72,6 +72,8 @@ class IPCThreadState : public virtual RefBase {
// entry.binder->transact. Overwise return after kQuantumMs
// milliseconds.
status_t handleService(const struct ProcessState::binder_entry& entry);
+ status_t handleDeathRecipient(
+ const struct ProcessState::binder_entry& entry);
const pid_t mMyThreadId;
sp<ProcessState> mProcess;
diff --git a/include/kdbinder/binder/ProcessState.h b/include/kdbinder/binder/ProcessState.h
index 97c831b..df8f41a 100644
--- a/include/kdbinder/binder/ProcessState.h
+++ b/include/kdbinder/binder/ProcessState.h
@@ -95,6 +95,8 @@ class ProcessState : public virtual RefBase {
mutable Mutex mServiceLock;
std::vector<struct binder_entry> mServiceTable;
+ mutable Mutex mDeathRecipientLock;
+ std::vector<struct binder_entry> mDeathRecipientTable;
};
} // namespace android
diff --git a/libs/kdbinder/binder/BpBinder.cpp b/libs/kdbinder/binder/BpBinder.cpp
index a1532f2..abef5d1 100644
--- a/libs/kdbinder/binder/BpBinder.cpp
+++ b/libs/kdbinder/binder/BpBinder.cpp
@@ -21,7 +21,9 @@
namespace android {
BpBinder::BpBinder(int32_t handle)
- : mHandle(handle),
+ : mObitsSent(0),
+ mObituaries(NULL),
+ mHandle(handle),
mAlive(1) {}
BpBinder::~BpBinder() {}
@@ -85,11 +87,37 @@ const String16& BpBinder::getInterfaceDescriptor() const {
return mDescriptorCache;
}
-status_t BpBinder::linkToDeath(const sp<DeathRecipient>& /*recipient*/,
- void * /*cookie*/,
- uint32_t /*flags*/) {
- // TODO: unimplemented.
- return FAILED_TRANSACTION;
+status_t BpBinder::linkToDeath(const sp<DeathRecipient>& recipient,
+ void * cookie,
+ uint32_t flags) {
+ Obituary ob;
+ ob.recipient = recipient;
+ ob.cookie = cookie;
+ ob.flags = flags;
+
+ LOG_ALWAYS_FATAL_IF(recipient == NULL,
+ "linkToDeath(): recipient must be non-NULL");
+
+ {
+ AutoMutex _l(mLock);
+
+ if (!mObitsSent) {
+ if (!mObituaries) {
+ mObituaries = new Vector<Obituary>;
+ if (!mObituaries) {
+ return NO_MEMORY;
+ }
+ ALOGV("Requesting death notification: %p handle %d\n", this, mHandle);
+ getWeakRefs()->incWeak(this);
+ IPCThreadState* self = IPCThreadState::self();
+ self->requestDeathNotification(mHandle, this);
+ }
+ ssize_t res = mObituaries->add(ob);
+ return res >= (ssize_t)NO_ERROR ? (status_t)NO_ERROR : res;
+ }
+ }
+
+ return DEAD_OBJECT;
}
status_t BpBinder::unlinkToDeath(const wp<DeathRecipient>& /*recipient*/,
@@ -101,7 +129,14 @@ status_t BpBinder::unlinkToDeath(const wp<DeathRecipient>& /*recipient*/,
}
void BpBinder::sendObituary() {
- // TODO: unimplemented.
+ mAlive = 0;
+ if (mObituaries != NULL) {
+ const size_t N = mObituaries->size();
+ for (size_t i = 0; i < N; i++) {
+ sp<DeathRecipient> recipient = mObituaries->itemAt(i).recipient.promote();
+ recipient->binderDied(this);
+ }
+ }
}
bool BpBinder::isDescriptorCached() const {
diff --git a/libs/kdbinder/binder/IPCThreadState.cpp b/libs/kdbinder/binder/IPCThreadState.cpp
index 5a73c05..743a828 100644
--- a/libs/kdbinder/binder/IPCThreadState.cpp
+++ b/libs/kdbinder/binder/IPCThreadState.cpp
@@ -112,6 +112,16 @@ void IPCThreadState::joinThreadPool(bool /*isMain*/) {
if (handleService(service) == FAILED_TRANSACTION) break;
}
+
+ for (std::vector<struct ProcessState::binder_entry>::size_type i = 0;
+ i < mProcess->mDeathRecipientTable.size();
+ i++) {
+ mProcess->mDeathRecipientLock.lock();
+ auto recipient = mProcess->mDeathRecipientTable[i];
+ mProcess->mDeathRecipientLock.unlock();
+
+ if (handleDeathRecipient(recipient) == FAILED_TRANSACTION) break;
+ }
}
LOG_THREADPOOL("**** THREAD %p (PID %d) IS LEAVING THE THREAD POOL\n",
@@ -180,16 +190,39 @@ status_t IPCThreadState::transact(int32_t handle,
return NO_ERROR;
}
-status_t IPCThreadState::requestDeathNotification(int32_t /*handle*/,
- BpBinder * /*proxy*/) {
- // TODO: unimplemented.
- return UNKNOWN_TRANSACTION;
+status_t IPCThreadState::requestDeathNotification(int32_t handle,
+ BpBinder* proxy) {
+ auto connection = kdbus::Connection::hello("0-services", "death-recipient");
+
+ connection->notify_when_dead(handle);
+
+ {
+ // add service to table.
+ AutoMutex _l(mProcess->mDeathRecipientLock);
+ mProcess->mDeathRecipientTable.emplace_back(std::move(connection), proxy);
+ }
+
+ return NO_ERROR;
}
status_t IPCThreadState::clearDeathNotification(int32_t /*handle*/,
- BpBinder * /*proxy*/) {
- // TODO: unimplemented.
- return UNKNOWN_TRANSACTION;
+ BpBinder *proxy) {
+ auto entry = std::find_if(
+ mProcess->mDeathRecipientTable.cbegin(),
+ mProcess->mDeathRecipientTable.cend(),
+ [&proxy](const struct ProcessState::binder_entry& entry) {
+ return entry.binder == proxy;
+ });
+
+ if (entry == mProcess->mDeathRecipientTable.end()) {
+ return BAD_VALUE;
+ } else {
+ {
+ AutoMutex _l(mProcess->mDeathRecipientLock);
+ mProcess->mDeathRecipientTable.erase(entry);
+ }
+ return NO_ERROR;
+ }
}
status_t IPCThreadState::handleService(
@@ -264,4 +297,23 @@ status_t IPCThreadState::handleService(
return NO_ERROR;
}
+status_t IPCThreadState::handleDeathRecipient(
+ const struct ProcessState::binder_entry& entry) {
+ sp<BpBinder> recipient = entry.binder->remoteBinder();
+ std::shared_ptr<kdbus::Connection> connection = entry.connection;
+
+ auto who_died = connection->dequeue_death_notification_blocking(
+ IPCThreadState::kQuantumMs);
+
+ if (who_died.error_code == -ETIMEDOUT) {
+ return NO_ERROR;
+ } else if (who_died.error_code != 0) {
+ return FAILED_TRANSACTION;
+ } else {
+ recipient->sendObituary();
+
+ return NO_ERROR;
+ }
+}
+
} // namespace android