349 lines
9.1 KiB
C++
349 lines
9.1 KiB
C++
/*
|
|
* 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
|