summaryrefslogtreecommitdiff
path: root/BpHwBinder.cpp
diff options
context:
space:
mode:
authorYifan Hong <elsk@google.com>2017-01-12 14:42:28 -0800
committerYifan Hong <elsk@google.com>2017-01-12 14:43:15 -0800
commit1e118d2b86540f7a7d840ec1510337da49f1446c (patch)
tree039545b0c3820d3690c4a2ed0aad953741257785 /BpHwBinder.cpp
parentdde40f31347a51aa7249cb192f97276c30d984f5 (diff)
downloadlibhwbinder-1e118d2b86540f7a7d840ec1510337da49f1446c.tar.gz
BpBinder -> BpHwBinder.
Test: mma Test: croot && make Bug: 33554989 Change-Id: I484c9e2e30f12ac3352aabecdf5b30fcf090a191
Diffstat (limited to 'BpHwBinder.cpp')
-rw-r--r--BpHwBinder.cpp366
1 files changed, 366 insertions, 0 deletions
diff --git a/BpHwBinder.cpp b/BpHwBinder.cpp
new file mode 100644
index 0000000..c6d6fcf
--- /dev/null
+++ b/BpHwBinder.cpp
@@ -0,0 +1,366 @@
+/*
+ * Copyright (C) 2005 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "BpHwBinder"
+//#define LOG_NDEBUG 0
+
+#include <hwbinder/BpHwBinder.h>
+
+#include <hwbinder/IPCThreadState.h>
+#include <utils/Log.h>
+
+#include <stdio.h>
+
+//#undef ALOGV
+//#define ALOGV(...) fprintf(stderr, __VA_ARGS__)
+
+namespace android {
+namespace hardware {
+
+// ---------------------------------------------------------------------------
+
+BpHwBinder::ObjectManager::ObjectManager()
+{
+}
+
+BpHwBinder::ObjectManager::~ObjectManager()
+{
+ kill();
+}
+
+void BpHwBinder::ObjectManager::attach(
+ const void* objectID, void* object, void* cleanupCookie,
+ IBinder::object_cleanup_func func)
+{
+ entry_t e;
+ e.object = object;
+ e.cleanupCookie = cleanupCookie;
+ e.func = func;
+
+ if (mObjects.indexOfKey(objectID) >= 0) {
+ ALOGE("Trying to attach object ID %p to binder ObjectManager %p with object %p, but object ID already in use",
+ objectID, this, object);
+ return;
+ }
+
+ mObjects.add(objectID, e);
+}
+
+void* BpHwBinder::ObjectManager::find(const void* objectID) const
+{
+ const ssize_t i = mObjects.indexOfKey(objectID);
+ if (i < 0) return NULL;
+ return mObjects.valueAt(i).object;
+}
+
+void BpHwBinder::ObjectManager::detach(const void* objectID)
+{
+ mObjects.removeItem(objectID);
+}
+
+void BpHwBinder::ObjectManager::kill()
+{
+ const size_t N = mObjects.size();
+ ALOGV("Killing %zu objects in manager %p", N, this);
+ for (size_t i=0; i<N; i++) {
+ const entry_t& e = mObjects.valueAt(i);
+ if (e.func != NULL) {
+ e.func(mObjects.keyAt(i), e.object, e.cleanupCookie);
+ }
+ }
+
+ mObjects.clear();
+}
+
+// ---------------------------------------------------------------------------
+
+BpHwBinder::BpHwBinder(int32_t handle)
+ : mHandle(handle)
+ , mAlive(1)
+ , mObitsSent(0)
+ , mObituaries(NULL)
+{
+ ALOGV("Creating BpHwBinder %p handle %d\n", this, mHandle);
+
+ extendObjectLifetime(OBJECT_LIFETIME_WEAK);
+ IPCThreadState::self()->incWeakHandle(handle);
+}
+
+bool BpHwBinder::isDescriptorCached() const {
+ Mutex::Autolock _l(mLock);
+ return mDescriptorCache.size() ? true : false;
+}
+
+const String16& BpHwBinder::getInterfaceDescriptor() const
+{
+ if (isDescriptorCached() == false) {
+ Parcel send, reply;
+ // do the IPC without a lock held.
+ status_t err = const_cast<BpHwBinder*>(this)->transact(
+ INTERFACE_TRANSACTION, send, &reply);
+ if (err == NO_ERROR) {
+ String16 res(reply.readString16());
+ Mutex::Autolock _l(mLock);
+ // mDescriptorCache could have been assigned while the lock was
+ // released.
+ if (mDescriptorCache.size() == 0)
+ mDescriptorCache = res;
+ }
+ }
+
+ // we're returning a reference to a non-static object here. Usually this
+ // is not something smart to do, however, with binder objects it is
+ // (usually) safe because they are reference-counted.
+
+ return mDescriptorCache;
+}
+
+bool BpHwBinder::isBinderAlive() const
+{
+ return mAlive != 0;
+}
+
+status_t BpHwBinder::pingBinder()
+{
+ Parcel send;
+ Parcel reply;
+ status_t err = transact(PING_TRANSACTION, send, &reply);
+ if (err != NO_ERROR) return err;
+ if (reply.dataSize() < sizeof(status_t)) return NOT_ENOUGH_DATA;
+ return (status_t)reply.readInt32();
+}
+
+status_t BpHwBinder::dump(int fd, const Vector<String16>& args)
+{
+ Parcel send;
+ Parcel reply;
+ send.writeFileDescriptor(fd);
+ const size_t numArgs = args.size();
+ send.writeInt32(numArgs);
+ for (size_t i = 0; i < numArgs; i++) {
+ send.writeString16(args[i]);
+ }
+ status_t err = transact(DUMP_TRANSACTION, send, &reply);
+ return err;
+}
+
+status_t BpHwBinder::transact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags, TransactCallback /*callback*/)
+{
+ // Once a binder has died, it will never come back to life.
+ if (mAlive) {
+ status_t status = IPCThreadState::self()->transact(
+ mHandle, code, data, reply, flags);
+ if (status == DEAD_OBJECT) mAlive = 0;
+ return status;
+ }
+
+ return DEAD_OBJECT;
+}
+
+status_t BpHwBinder::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);
+ self->flushCommands();
+ }
+ ssize_t res = mObituaries->add(ob);
+ return res >= (ssize_t)NO_ERROR ? (status_t)NO_ERROR : res;
+ }
+ }
+
+ return DEAD_OBJECT;
+}
+
+status_t BpHwBinder::unlinkToDeath(
+ const wp<DeathRecipient>& recipient, void* cookie, uint32_t flags,
+ wp<DeathRecipient>* outRecipient)
+{
+ AutoMutex _l(mLock);
+
+ if (mObitsSent) {
+ return DEAD_OBJECT;
+ }
+
+ const size_t N = mObituaries ? mObituaries->size() : 0;
+ for (size_t i=0; i<N; i++) {
+ const Obituary& obit = mObituaries->itemAt(i);
+ if ((obit.recipient == recipient
+ || (recipient == NULL && obit.cookie == cookie))
+ && obit.flags == flags) {
+ if (outRecipient != NULL) {
+ *outRecipient = mObituaries->itemAt(i).recipient;
+ }
+ mObituaries->removeAt(i);
+ if (mObituaries->size() == 0) {
+ ALOGV("Clearing death notification: %p handle %d\n", this, mHandle);
+ IPCThreadState* self = IPCThreadState::self();
+ self->clearDeathNotification(mHandle, this);
+ self->flushCommands();
+ delete mObituaries;
+ mObituaries = NULL;
+ }
+ return NO_ERROR;
+ }
+ }
+
+ return NAME_NOT_FOUND;
+}
+
+void BpHwBinder::sendObituary()
+{
+ ALOGV("Sending obituary for proxy %p handle %d, mObitsSent=%s\n",
+ this, mHandle, mObitsSent ? "true" : "false");
+
+ mAlive = 0;
+ if (mObitsSent) return;
+
+ mLock.lock();
+ Vector<Obituary>* obits = mObituaries;
+ if(obits != NULL) {
+ ALOGV("Clearing sent death notification: %p handle %d\n", this, mHandle);
+ IPCThreadState* self = IPCThreadState::self();
+ self->clearDeathNotification(mHandle, this);
+ self->flushCommands();
+ mObituaries = NULL;
+ }
+ mObitsSent = 1;
+ mLock.unlock();
+
+ ALOGV("Reporting death of proxy %p for %zu recipients\n",
+ this, obits ? obits->size() : 0U);
+
+ if (obits != NULL) {
+ const size_t N = obits->size();
+ for (size_t i=0; i<N; i++) {
+ reportOneDeath(obits->itemAt(i));
+ }
+
+ delete obits;
+ }
+}
+
+void BpHwBinder::reportOneDeath(const Obituary& obit)
+{
+ sp<DeathRecipient> recipient = obit.recipient.promote();
+ ALOGV("Reporting death to recipient: %p\n", recipient.get());
+ if (recipient == NULL) return;
+
+ recipient->binderDied(this);
+}
+
+
+void BpHwBinder::attachObject(
+ const void* objectID, void* object, void* cleanupCookie,
+ object_cleanup_func func)
+{
+ AutoMutex _l(mLock);
+ ALOGV("Attaching object %p to binder %p (manager=%p)", object, this, &mObjects);
+ mObjects.attach(objectID, object, cleanupCookie, func);
+}
+
+void* BpHwBinder::findObject(const void* objectID) const
+{
+ AutoMutex _l(mLock);
+ return mObjects.find(objectID);
+}
+
+void BpHwBinder::detachObject(const void* objectID)
+{
+ AutoMutex _l(mLock);
+ mObjects.detach(objectID);
+}
+
+BpHwBinder* BpHwBinder::remoteBinder()
+{
+ return this;
+}
+
+BpHwBinder::~BpHwBinder()
+{
+ ALOGV("Destroying BpHwBinder %p handle %d\n", this, mHandle);
+
+ IPCThreadState* ipc = IPCThreadState::self();
+
+ mLock.lock();
+ Vector<Obituary>* obits = mObituaries;
+ if(obits != NULL) {
+ if (ipc) ipc->clearDeathNotification(mHandle, this);
+ mObituaries = NULL;
+ }
+ mLock.unlock();
+
+ if (obits != NULL) {
+ // XXX Should we tell any remaining DeathRecipient
+ // objects that the last strong ref has gone away, so they
+ // are no longer linked?
+ delete obits;
+ }
+
+ if (ipc) {
+ ipc->expungeHandle(mHandle, this);
+ ipc->decWeakHandle(mHandle);
+ }
+}
+
+void BpHwBinder::onFirstRef()
+{
+ ALOGV("onFirstRef BpHwBinder %p handle %d\n", this, mHandle);
+ IPCThreadState* ipc = IPCThreadState::self();
+ if (ipc) ipc->incStrongHandle(mHandle);
+}
+
+void BpHwBinder::onLastStrongRef(const void* /*id*/)
+{
+ ALOGV("onLastStrongRef BpHwBinder %p handle %d\n", this, mHandle);
+ IF_ALOGV() {
+ printRefs();
+ }
+ IPCThreadState* ipc = IPCThreadState::self();
+ if (ipc) ipc->decStrongHandle(mHandle);
+}
+
+bool BpHwBinder::onIncStrongAttempted(uint32_t /*flags*/, const void* /*id*/)
+{
+ ALOGV("onIncStrongAttempted BpHwBinder %p handle %d\n", this, mHandle);
+ IPCThreadState* ipc = IPCThreadState::self();
+ return ipc ? ipc->attemptIncStrongHandle(mHandle) == NO_ERROR : false;
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace hardware
+}; // namespace android