diff options
Diffstat (limited to 'libs/binder/BpBinder.cpp')
-rw-r--r-- | libs/binder/BpBinder.cpp | 348 |
1 files changed, 348 insertions, 0 deletions
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp new file mode 100644 index 0000000..56bf413 --- /dev/null +++ b/libs/binder/BpBinder.cpp @@ -0,0 +1,348 @@ +/* + * 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 "BpBinder" +//#define LOG_NDEBUG 0 + +#include <binder/BpBinder.h> + +#include <binder/IPCThreadState.h> +#include <utils/Log.h> + +#include <stdio.h> + +//#undef LOGV +//#define LOGV(...) fprintf(stderr, __VA_ARGS__) + +namespace android { + +// --------------------------------------------------------------------------- + +BpBinder::ObjectManager::ObjectManager() +{ +} + +BpBinder::ObjectManager::~ObjectManager() +{ + kill(); +} + +void BpBinder::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) { + LOGE("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* BpBinder::ObjectManager::find(const void* objectID) const +{ + const ssize_t i = mObjects.indexOfKey(objectID); + if (i < 0) return NULL; + return mObjects.valueAt(i).object; +} + +void BpBinder::ObjectManager::detach(const void* objectID) +{ + mObjects.removeItem(objectID); +} + +void BpBinder::ObjectManager::kill() +{ + const size_t N = mObjects.size(); + LOGV("Killing %d 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(); +} + +// --------------------------------------------------------------------------- + +BpBinder::BpBinder(int32_t handle) + : mHandle(handle) + , mAlive(1) + , mObitsSent(0) + , mObituaries(NULL) +{ + LOGV("Creating BpBinder %p handle %d\n", this, mHandle); + + extendObjectLifetime(OBJECT_LIFETIME_WEAK); + IPCThreadState::self()->incWeakHandle(handle); +} + +String16 BpBinder::getInterfaceDescriptor() const +{ + String16 res; + Parcel send, reply; + status_t err = const_cast<BpBinder*>(this)->transact( + INTERFACE_TRANSACTION, send, &reply); + if (err == NO_ERROR) { + res = reply.readString16(); + } + return res; +} + +bool BpBinder::isBinderAlive() const +{ + return mAlive != 0; +} + +status_t BpBinder::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 BpBinder::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 BpBinder::transact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) +{ + // 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 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; + } + LOGV("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 BpBinder::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) { + const uint32_t allFlags = obit.flags|flags; + if (outRecipient != NULL) { + *outRecipient = mObituaries->itemAt(i).recipient; + } + mObituaries->removeAt(i); + if (mObituaries->size() == 0) { + LOGV("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 BpBinder::sendObituary() +{ + LOGV("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) { + LOGV("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(); + + LOGV("Reporting death of proxy %p for %d recipients\n", + this, obits ? obits->size() : 0); + + if (obits != NULL) { + const size_t N = obits->size(); + for (size_t i=0; i<N; i++) { + reportOneDeath(obits->itemAt(i)); + } + + delete obits; + } +} + +void BpBinder::reportOneDeath(const Obituary& obit) +{ + sp<DeathRecipient> recipient = obit.recipient.promote(); + LOGV("Reporting death to recipient: %p\n", recipient.get()); + if (recipient == NULL) return; + + recipient->binderDied(this); +} + + +void BpBinder::attachObject( + const void* objectID, void* object, void* cleanupCookie, + object_cleanup_func func) +{ + AutoMutex _l(mLock); + LOGV("Attaching object %p to binder %p (manager=%p)", object, this, &mObjects); + mObjects.attach(objectID, object, cleanupCookie, func); +} + +void* BpBinder::findObject(const void* objectID) const +{ + AutoMutex _l(mLock); + return mObjects.find(objectID); +} + +void BpBinder::detachObject(const void* objectID) +{ + AutoMutex _l(mLock); + mObjects.detach(objectID); +} + +BpBinder* BpBinder::remoteBinder() +{ + return this; +} + +BpBinder::~BpBinder() +{ + LOGV("Destroying BpBinder %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 BpBinder::onFirstRef() +{ + LOGV("onFirstRef BpBinder %p handle %d\n", this, mHandle); + IPCThreadState* ipc = IPCThreadState::self(); + if (ipc) ipc->incStrongHandle(mHandle); +} + +void BpBinder::onLastStrongRef(const void* id) +{ + LOGV("onLastStrongRef BpBinder %p handle %d\n", this, mHandle); + IF_LOGV() { + printRefs(); + } + IPCThreadState* ipc = IPCThreadState::self(); + if (ipc) ipc->decStrongHandle(mHandle); +} + +bool BpBinder::onIncStrongAttempted(uint32_t flags, const void* id) +{ + LOGV("onIncStrongAttempted BpBinder %p handle %d\n", this, mHandle); + IPCThreadState* ipc = IPCThreadState::self(); + return ipc ? ipc->attemptIncStrongHandle(mHandle) == NO_ERROR : false; +} + +// --------------------------------------------------------------------------- + +}; // namespace android |