diff options
author | Pierre Langlois <pierre.langlois@arm.com> | 2015-02-12 18:23:11 +0000 |
---|---|---|
committer | Pierre Langlois <pierre.langlois@arm.com> | 2016-03-04 18:01:17 +0000 |
commit | faa15a27bff96bebe6e522c8c6662fef10f6a55d (patch) | |
tree | bf25b273083bf6fea2bd1d2adf374e034604c983 | |
parent | a4444561cb4e52ae8890a9670357e44d6ba4d0bc (diff) | |
download | kdbinder-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.h | 9 | ||||
-rw-r--r-- | include/kdbinder/binder/IPCThreadState.h | 2 | ||||
-rw-r--r-- | include/kdbinder/binder/ProcessState.h | 2 | ||||
-rw-r--r-- | libs/kdbinder/binder/BpBinder.cpp | 49 | ||||
-rw-r--r-- | libs/kdbinder/binder/IPCThreadState.cpp | 66 |
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 |