/*
* 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 "hw-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);
}
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);
ipc->flushCommands();
}
}
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