checkpoint: split libutils into libutils + libbinder
This commit is contained in:
parent
a393a7dd94
commit
b8db306e1a
|
@ -103,19 +103,6 @@ include $(CLEAR_VARS)
|
|||
# we have the common sources, plus some device-specific stuff
|
||||
LOCAL_SRC_FILES:= \
|
||||
$(commonSources) \
|
||||
Binder.cpp \
|
||||
BpBinder.cpp \
|
||||
IInterface.cpp \
|
||||
IMemory.cpp \
|
||||
IPCThreadState.cpp \
|
||||
MemoryDealer.cpp \
|
||||
MemoryBase.cpp \
|
||||
MemoryHeapBase.cpp \
|
||||
MemoryHeapPmem.cpp \
|
||||
Parcel.cpp \
|
||||
ProcessState.cpp \
|
||||
IPermissionController.cpp \
|
||||
IServiceManager.cpp \
|
||||
Unicode.cpp \
|
||||
backup_data.cpp \
|
||||
backup_helper_file.cpp
|
||||
|
|
|
@ -1,242 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <utils/Binder.h>
|
||||
|
||||
#include <utils/Atomic.h>
|
||||
#include <utils/BpBinder.h>
|
||||
#include <utils/IInterface.h>
|
||||
#include <utils/Parcel.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
sp<IInterface> IBinder::queryLocalInterface(const String16& descriptor)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BBinder* IBinder::localBinder()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BpBinder* IBinder::remoteBinder()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool IBinder::checkSubclass(const void* /*subclassID*/) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
class BBinder::Extras
|
||||
{
|
||||
public:
|
||||
Mutex mLock;
|
||||
BpBinder::ObjectManager mObjects;
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
BBinder::BBinder()
|
||||
: mExtras(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
bool BBinder::isBinderAlive() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
status_t BBinder::pingBinder()
|
||||
{
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
String16 BBinder::getInterfaceDescriptor() const
|
||||
{
|
||||
LOGW("reached BBinder::getInterfaceDescriptor (this=%p)", this);
|
||||
return String16();
|
||||
}
|
||||
|
||||
status_t BBinder::transact(
|
||||
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
|
||||
{
|
||||
data.setDataPosition(0);
|
||||
|
||||
status_t err = NO_ERROR;
|
||||
switch (code) {
|
||||
case PING_TRANSACTION:
|
||||
reply->writeInt32(pingBinder());
|
||||
break;
|
||||
default:
|
||||
err = onTransact(code, data, reply, flags);
|
||||
break;
|
||||
}
|
||||
|
||||
if (reply != NULL) {
|
||||
reply->setDataPosition(0);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
status_t BBinder::linkToDeath(
|
||||
const sp<DeathRecipient>& recipient, void* cookie, uint32_t flags)
|
||||
{
|
||||
return INVALID_OPERATION;
|
||||
}
|
||||
|
||||
status_t BBinder::unlinkToDeath(
|
||||
const wp<DeathRecipient>& recipient, void* cookie, uint32_t flags,
|
||||
wp<DeathRecipient>* outRecipient)
|
||||
{
|
||||
return INVALID_OPERATION;
|
||||
}
|
||||
|
||||
status_t BBinder::dump(int fd, const Vector<String16>& args)
|
||||
{
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
void BBinder::attachObject(
|
||||
const void* objectID, void* object, void* cleanupCookie,
|
||||
object_cleanup_func func)
|
||||
{
|
||||
Extras* e = mExtras;
|
||||
|
||||
if (!e) {
|
||||
e = new Extras;
|
||||
if (android_atomic_cmpxchg(0, reinterpret_cast<int32_t>(e),
|
||||
reinterpret_cast<volatile int32_t*>(&mExtras)) != 0) {
|
||||
delete e;
|
||||
e = mExtras;
|
||||
}
|
||||
if (e == 0) return; // out of memory
|
||||
}
|
||||
|
||||
AutoMutex _l(e->mLock);
|
||||
e->mObjects.attach(objectID, object, cleanupCookie, func);
|
||||
}
|
||||
|
||||
void* BBinder::findObject(const void* objectID) const
|
||||
{
|
||||
Extras* e = mExtras;
|
||||
if (!e) return NULL;
|
||||
|
||||
AutoMutex _l(e->mLock);
|
||||
return e->mObjects.find(objectID);
|
||||
}
|
||||
|
||||
void BBinder::detachObject(const void* objectID)
|
||||
{
|
||||
Extras* e = mExtras;
|
||||
if (!e) return;
|
||||
|
||||
AutoMutex _l(e->mLock);
|
||||
e->mObjects.detach(objectID);
|
||||
}
|
||||
|
||||
BBinder* BBinder::localBinder()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
BBinder::~BBinder()
|
||||
{
|
||||
if (mExtras) delete mExtras;
|
||||
}
|
||||
|
||||
|
||||
status_t BBinder::onTransact(
|
||||
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
|
||||
{
|
||||
switch (code) {
|
||||
case INTERFACE_TRANSACTION:
|
||||
reply->writeString16(getInterfaceDescriptor());
|
||||
return NO_ERROR;
|
||||
|
||||
case DUMP_TRANSACTION: {
|
||||
int fd = data.readFileDescriptor();
|
||||
int argc = data.readInt32();
|
||||
Vector<String16> args;
|
||||
for (int i = 0; i < argc && data.dataAvail() > 0; i++) {
|
||||
args.add(data.readString16());
|
||||
}
|
||||
return dump(fd, args);
|
||||
}
|
||||
default:
|
||||
return UNKNOWN_TRANSACTION;
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
enum {
|
||||
// This is used to transfer ownership of the remote binder from
|
||||
// the BpRefBase object holding it (when it is constructed), to the
|
||||
// owner of the BpRefBase object when it first acquires that BpRefBase.
|
||||
kRemoteAcquired = 0x00000001
|
||||
};
|
||||
|
||||
BpRefBase::BpRefBase(const sp<IBinder>& o)
|
||||
: mRemote(o.get()), mRefs(NULL), mState(0)
|
||||
{
|
||||
extendObjectLifetime(OBJECT_LIFETIME_WEAK);
|
||||
|
||||
if (mRemote) {
|
||||
mRemote->incStrong(this); // Removed on first IncStrong().
|
||||
mRefs = mRemote->createWeak(this); // Held for our entire lifetime.
|
||||
}
|
||||
}
|
||||
|
||||
BpRefBase::~BpRefBase()
|
||||
{
|
||||
if (mRemote) {
|
||||
if (!(mState&kRemoteAcquired)) {
|
||||
mRemote->decStrong(this);
|
||||
}
|
||||
mRefs->decWeak(this);
|
||||
}
|
||||
}
|
||||
|
||||
void BpRefBase::onFirstRef()
|
||||
{
|
||||
android_atomic_or(kRemoteAcquired, &mState);
|
||||
}
|
||||
|
||||
void BpRefBase::onLastStrongRef(const void* id)
|
||||
{
|
||||
if (mRemote) {
|
||||
mRemote->decStrong(this);
|
||||
}
|
||||
}
|
||||
|
||||
bool BpRefBase::onIncStrongAttempted(uint32_t flags, const void* id)
|
||||
{
|
||||
return mRemote ? mRefs->attemptIncStrong(this) : false;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
}; // namespace android
|
|
@ -1,348 +0,0 @@
|
|||
/*
|
||||
* 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 <utils/BpBinder.h>
|
||||
|
||||
#include <utils/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
|
|
@ -1,89 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2006 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.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <utils/Parcel.h>
|
||||
|
||||
#include <utils/IDataConnection.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
enum
|
||||
{
|
||||
CONNECT_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
|
||||
DISCONNECT_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 1
|
||||
};
|
||||
|
||||
class BpDataConnection : public BpInterface<IDataConnection>
|
||||
{
|
||||
public:
|
||||
BpDataConnection::BpDataConnection(const sp<IBinder>& impl)
|
||||
: BpInterface<IDataConnection>(impl)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void connect()
|
||||
{
|
||||
Parcel data, reply;
|
||||
data.writeInterfaceToken(IDataConnection::descriptor());
|
||||
remote()->transact(CONNECT_TRANSACTION, data, &reply);
|
||||
}
|
||||
|
||||
virtual void disconnect()
|
||||
{
|
||||
Parcel data, reply;
|
||||
remote()->transact(DISCONNECT_TRANSACTION, data, &reply);
|
||||
}
|
||||
};
|
||||
|
||||
IMPLEMENT_META_INTERFACE(DataConnection, "android.utils.IDataConnection");
|
||||
|
||||
#define CHECK_INTERFACE(interface, data, reply) \
|
||||
do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
|
||||
LOGW("Call incorrectly routed to " #interface); \
|
||||
return PERMISSION_DENIED; \
|
||||
} } while (0)
|
||||
|
||||
status_t BnDataConnection::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
|
||||
{
|
||||
switch(code)
|
||||
{
|
||||
case CONNECT_TRANSACTION:
|
||||
{
|
||||
CHECK_INTERFACE(IDataConnection, data, reply);
|
||||
connect();
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
case DISCONNECT_TRANSACTION:
|
||||
{
|
||||
CHECK_INTERFACE(IDataConnection, data, reply);
|
||||
disconnect();
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
default:
|
||||
return BBinder::onTransact(code, data, reply, flags);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
}; // namespace android
|
|
@ -1,35 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <utils/IInterface.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
sp<IBinder> IInterface::asBinder()
|
||||
{
|
||||
return this ? onAsBinder() : NULL;
|
||||
}
|
||||
|
||||
sp<const IBinder> IInterface::asBinder() const
|
||||
{
|
||||
return this ? const_cast<IInterface*>(this)->onAsBinder() : NULL;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
}; // namespace android
|
|
@ -1,486 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2008 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 "IMemory"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include <utils/IMemory.h>
|
||||
#include <utils/KeyedVector.h>
|
||||
#include <utils/threads.h>
|
||||
#include <utils/Atomic.h>
|
||||
#include <utils/Parcel.h>
|
||||
#include <utils/CallStack.h>
|
||||
|
||||
#define VERBOSE 0
|
||||
|
||||
namespace android {
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
class HeapCache : public IBinder::DeathRecipient
|
||||
{
|
||||
public:
|
||||
HeapCache();
|
||||
virtual ~HeapCache();
|
||||
|
||||
virtual void binderDied(const wp<IBinder>& who);
|
||||
|
||||
sp<IMemoryHeap> find_heap(const sp<IBinder>& binder);
|
||||
void pin_heap(const sp<IBinder>& binder);
|
||||
void free_heap(const sp<IBinder>& binder);
|
||||
sp<IMemoryHeap> get_heap(const sp<IBinder>& binder);
|
||||
void dump_heaps();
|
||||
|
||||
private:
|
||||
// For IMemory.cpp
|
||||
struct heap_info_t {
|
||||
sp<IMemoryHeap> heap;
|
||||
int32_t count;
|
||||
};
|
||||
|
||||
void free_heap(const wp<IBinder>& binder);
|
||||
|
||||
Mutex mHeapCacheLock;
|
||||
KeyedVector< wp<IBinder>, heap_info_t > mHeapCache;
|
||||
};
|
||||
|
||||
static sp<HeapCache> gHeapCache = new HeapCache();
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
enum {
|
||||
HEAP_ID = IBinder::FIRST_CALL_TRANSACTION
|
||||
};
|
||||
|
||||
class BpMemoryHeap : public BpInterface<IMemoryHeap>
|
||||
{
|
||||
public:
|
||||
BpMemoryHeap(const sp<IBinder>& impl);
|
||||
virtual ~BpMemoryHeap();
|
||||
|
||||
virtual int getHeapID() const;
|
||||
virtual void* getBase() const;
|
||||
virtual size_t getSize() const;
|
||||
virtual uint32_t getFlags() const;
|
||||
|
||||
private:
|
||||
friend class IMemory;
|
||||
friend class HeapCache;
|
||||
|
||||
// for debugging in this module
|
||||
static inline sp<IMemoryHeap> find_heap(const sp<IBinder>& binder) {
|
||||
return gHeapCache->find_heap(binder);
|
||||
}
|
||||
static inline void free_heap(const sp<IBinder>& binder) {
|
||||
gHeapCache->free_heap(binder);
|
||||
}
|
||||
static inline sp<IMemoryHeap> get_heap(const sp<IBinder>& binder) {
|
||||
return gHeapCache->get_heap(binder);
|
||||
}
|
||||
static inline void dump_heaps() {
|
||||
gHeapCache->dump_heaps();
|
||||
}
|
||||
void inline pin_heap() const {
|
||||
gHeapCache->pin_heap(const_cast<BpMemoryHeap*>(this)->asBinder());
|
||||
}
|
||||
|
||||
void assertMapped() const;
|
||||
void assertReallyMapped() const;
|
||||
void pinHeap() const;
|
||||
|
||||
mutable volatile int32_t mHeapId;
|
||||
mutable void* mBase;
|
||||
mutable size_t mSize;
|
||||
mutable uint32_t mFlags;
|
||||
mutable bool mRealHeap;
|
||||
mutable Mutex mLock;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
enum {
|
||||
GET_MEMORY = IBinder::FIRST_CALL_TRANSACTION
|
||||
};
|
||||
|
||||
class BpMemory : public BpInterface<IMemory>
|
||||
{
|
||||
public:
|
||||
BpMemory(const sp<IBinder>& impl);
|
||||
virtual ~BpMemory();
|
||||
virtual sp<IMemoryHeap> getMemory(ssize_t* offset=0, size_t* size=0) const;
|
||||
|
||||
private:
|
||||
mutable sp<IMemoryHeap> mHeap;
|
||||
mutable ssize_t mOffset;
|
||||
mutable size_t mSize;
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void* IMemory::fastPointer(const sp<IBinder>& binder, ssize_t offset) const
|
||||
{
|
||||
sp<IMemoryHeap> realHeap = BpMemoryHeap::get_heap(binder);
|
||||
void* const base = realHeap->base();
|
||||
if (base == MAP_FAILED)
|
||||
return 0;
|
||||
return static_cast<char*>(base) + offset;
|
||||
}
|
||||
|
||||
void* IMemory::pointer() const {
|
||||
ssize_t offset;
|
||||
sp<IMemoryHeap> heap = getMemory(&offset);
|
||||
void* const base = heap!=0 ? heap->base() : MAP_FAILED;
|
||||
if (base == MAP_FAILED)
|
||||
return 0;
|
||||
return static_cast<char*>(base) + offset;
|
||||
}
|
||||
|
||||
size_t IMemory::size() const {
|
||||
size_t size;
|
||||
getMemory(NULL, &size);
|
||||
return size;
|
||||
}
|
||||
|
||||
ssize_t IMemory::offset() const {
|
||||
ssize_t offset;
|
||||
getMemory(&offset);
|
||||
return offset;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
BpMemory::BpMemory(const sp<IBinder>& impl)
|
||||
: BpInterface<IMemory>(impl), mOffset(0), mSize(0)
|
||||
{
|
||||
}
|
||||
|
||||
BpMemory::~BpMemory()
|
||||
{
|
||||
}
|
||||
|
||||
sp<IMemoryHeap> BpMemory::getMemory(ssize_t* offset, size_t* size) const
|
||||
{
|
||||
if (mHeap == 0) {
|
||||
Parcel data, reply;
|
||||
data.writeInterfaceToken(IMemory::getInterfaceDescriptor());
|
||||
if (remote()->transact(GET_MEMORY, data, &reply) == NO_ERROR) {
|
||||
sp<IBinder> heap = reply.readStrongBinder();
|
||||
ssize_t o = reply.readInt32();
|
||||
size_t s = reply.readInt32();
|
||||
if (heap != 0) {
|
||||
mHeap = interface_cast<IMemoryHeap>(heap);
|
||||
if (mHeap != 0) {
|
||||
mOffset = o;
|
||||
mSize = s;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (offset) *offset = mOffset;
|
||||
if (size) *size = mSize;
|
||||
return mHeap;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
IMPLEMENT_META_INTERFACE(Memory, "android.utils.IMemory");
|
||||
|
||||
#define CHECK_INTERFACE(interface, data, reply) \
|
||||
do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
|
||||
LOGW("Call incorrectly routed to " #interface); \
|
||||
return PERMISSION_DENIED; \
|
||||
} } while (0)
|
||||
|
||||
status_t BnMemory::onTransact(
|
||||
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
|
||||
{
|
||||
switch(code) {
|
||||
case GET_MEMORY: {
|
||||
CHECK_INTERFACE(IMemory, data, reply);
|
||||
ssize_t offset;
|
||||
size_t size;
|
||||
reply->writeStrongBinder( getMemory(&offset, &size)->asBinder() );
|
||||
reply->writeInt32(offset);
|
||||
reply->writeInt32(size);
|
||||
return NO_ERROR;
|
||||
} break;
|
||||
default:
|
||||
return BBinder::onTransact(code, data, reply, flags);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
BpMemoryHeap::BpMemoryHeap(const sp<IBinder>& impl)
|
||||
: BpInterface<IMemoryHeap>(impl),
|
||||
mHeapId(-1), mBase(MAP_FAILED), mSize(0), mFlags(0), mRealHeap(false)
|
||||
{
|
||||
}
|
||||
|
||||
BpMemoryHeap::~BpMemoryHeap() {
|
||||
if (mHeapId != -1) {
|
||||
close(mHeapId);
|
||||
if (mRealHeap) {
|
||||
// by construction we're the last one
|
||||
if (mBase != MAP_FAILED) {
|
||||
sp<IBinder> binder = const_cast<BpMemoryHeap*>(this)->asBinder();
|
||||
|
||||
if (VERBOSE) {
|
||||
LOGD("UNMAPPING binder=%p, heap=%p, size=%d, fd=%d",
|
||||
binder.get(), this, mSize, mHeapId);
|
||||
CallStack stack;
|
||||
stack.update();
|
||||
stack.dump("callstack");
|
||||
}
|
||||
|
||||
munmap(mBase, mSize);
|
||||
}
|
||||
} else {
|
||||
// remove from list only if it was mapped before
|
||||
sp<IBinder> binder = const_cast<BpMemoryHeap*>(this)->asBinder();
|
||||
free_heap(binder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BpMemoryHeap::assertMapped() const
|
||||
{
|
||||
if (mHeapId == -1) {
|
||||
sp<IBinder> binder(const_cast<BpMemoryHeap*>(this)->asBinder());
|
||||
sp<BpMemoryHeap> heap(static_cast<BpMemoryHeap*>(find_heap(binder).get()));
|
||||
heap->assertReallyMapped();
|
||||
if (heap->mBase != MAP_FAILED) {
|
||||
Mutex::Autolock _l(mLock);
|
||||
if (mHeapId == -1) {
|
||||
mBase = heap->mBase;
|
||||
mSize = heap->mSize;
|
||||
android_atomic_write( dup( heap->mHeapId ), &mHeapId );
|
||||
}
|
||||
} else {
|
||||
// something went wrong
|
||||
free_heap(binder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BpMemoryHeap::assertReallyMapped() const
|
||||
{
|
||||
if (mHeapId == -1) {
|
||||
|
||||
// remote call without mLock held, worse case scenario, we end up
|
||||
// calling transact() from multiple threads, but that's not a problem,
|
||||
// only mmap below must be in the critical section.
|
||||
|
||||
Parcel data, reply;
|
||||
data.writeInterfaceToken(IMemoryHeap::getInterfaceDescriptor());
|
||||
status_t err = remote()->transact(HEAP_ID, data, &reply);
|
||||
int parcel_fd = reply.readFileDescriptor();
|
||||
ssize_t size = reply.readInt32();
|
||||
uint32_t flags = reply.readInt32();
|
||||
|
||||
LOGE_IF(err, "binder=%p transaction failed fd=%d, size=%d, err=%d (%s)",
|
||||
asBinder().get(), parcel_fd, size, err, strerror(-err));
|
||||
|
||||
int fd = dup( parcel_fd );
|
||||
LOGE_IF(fd==-1, "cannot dup fd=%d, size=%d, err=%d (%s)",
|
||||
parcel_fd, size, err, strerror(errno));
|
||||
|
||||
int access = PROT_READ;
|
||||
if (!(flags & READ_ONLY)) {
|
||||
access |= PROT_WRITE;
|
||||
}
|
||||
|
||||
Mutex::Autolock _l(mLock);
|
||||
if (mHeapId == -1) {
|
||||
mRealHeap = true;
|
||||
mBase = mmap(0, size, access, MAP_SHARED, fd, 0);
|
||||
if (mBase == MAP_FAILED) {
|
||||
LOGE("cannot map BpMemoryHeap (binder=%p), size=%d, fd=%d (%s)",
|
||||
asBinder().get(), size, fd, strerror(errno));
|
||||
close(fd);
|
||||
} else {
|
||||
if (flags & MAP_ONCE) {
|
||||
//LOGD("pinning heap (binder=%p, size=%d, fd=%d",
|
||||
// asBinder().get(), size, fd);
|
||||
pin_heap();
|
||||
}
|
||||
mSize = size;
|
||||
mFlags = flags;
|
||||
android_atomic_write(fd, &mHeapId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int BpMemoryHeap::getHeapID() const {
|
||||
assertMapped();
|
||||
return mHeapId;
|
||||
}
|
||||
|
||||
void* BpMemoryHeap::getBase() const {
|
||||
assertMapped();
|
||||
return mBase;
|
||||
}
|
||||
|
||||
size_t BpMemoryHeap::getSize() const {
|
||||
assertMapped();
|
||||
return mSize;
|
||||
}
|
||||
|
||||
uint32_t BpMemoryHeap::getFlags() const {
|
||||
assertMapped();
|
||||
return mFlags;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
IMPLEMENT_META_INTERFACE(MemoryHeap, "android.utils.IMemoryHeap");
|
||||
|
||||
status_t BnMemoryHeap::onTransact(
|
||||
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
|
||||
{
|
||||
switch(code) {
|
||||
case HEAP_ID: {
|
||||
CHECK_INTERFACE(IMemoryHeap, data, reply);
|
||||
reply->writeFileDescriptor(getHeapID());
|
||||
reply->writeInt32(getSize());
|
||||
reply->writeInt32(getFlags());
|
||||
return NO_ERROR;
|
||||
} break;
|
||||
default:
|
||||
return BBinder::onTransact(code, data, reply, flags);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
HeapCache::HeapCache()
|
||||
: DeathRecipient()
|
||||
{
|
||||
}
|
||||
|
||||
HeapCache::~HeapCache()
|
||||
{
|
||||
}
|
||||
|
||||
void HeapCache::binderDied(const wp<IBinder>& binder)
|
||||
{
|
||||
//LOGD("binderDied binder=%p", binder.unsafe_get());
|
||||
free_heap(binder);
|
||||
}
|
||||
|
||||
sp<IMemoryHeap> HeapCache::find_heap(const sp<IBinder>& binder)
|
||||
{
|
||||
Mutex::Autolock _l(mHeapCacheLock);
|
||||
ssize_t i = mHeapCache.indexOfKey(binder);
|
||||
if (i>=0) {
|
||||
heap_info_t& info = mHeapCache.editValueAt(i);
|
||||
LOGD_IF(VERBOSE,
|
||||
"found binder=%p, heap=%p, size=%d, fd=%d, count=%d",
|
||||
binder.get(), info.heap.get(),
|
||||
static_cast<BpMemoryHeap*>(info.heap.get())->mSize,
|
||||
static_cast<BpMemoryHeap*>(info.heap.get())->mHeapId,
|
||||
info.count);
|
||||
android_atomic_inc(&info.count);
|
||||
return info.heap;
|
||||
} else {
|
||||
heap_info_t info;
|
||||
info.heap = interface_cast<IMemoryHeap>(binder);
|
||||
info.count = 1;
|
||||
//LOGD("adding binder=%p, heap=%p, count=%d",
|
||||
// binder.get(), info.heap.get(), info.count);
|
||||
mHeapCache.add(binder, info);
|
||||
return info.heap;
|
||||
}
|
||||
}
|
||||
|
||||
void HeapCache::pin_heap(const sp<IBinder>& binder)
|
||||
{
|
||||
Mutex::Autolock _l(mHeapCacheLock);
|
||||
ssize_t i = mHeapCache.indexOfKey(binder);
|
||||
if (i>=0) {
|
||||
heap_info_t& info(mHeapCache.editValueAt(i));
|
||||
android_atomic_inc(&info.count);
|
||||
binder->linkToDeath(this);
|
||||
} else {
|
||||
LOGE("pin_heap binder=%p not found!!!", binder.get());
|
||||
}
|
||||
}
|
||||
|
||||
void HeapCache::free_heap(const sp<IBinder>& binder) {
|
||||
free_heap( wp<IBinder>(binder) );
|
||||
}
|
||||
|
||||
void HeapCache::free_heap(const wp<IBinder>& binder)
|
||||
{
|
||||
sp<IMemoryHeap> rel;
|
||||
{
|
||||
Mutex::Autolock _l(mHeapCacheLock);
|
||||
ssize_t i = mHeapCache.indexOfKey(binder);
|
||||
if (i>=0) {
|
||||
heap_info_t& info(mHeapCache.editValueAt(i));
|
||||
int32_t c = android_atomic_dec(&info.count);
|
||||
if (c == 1) {
|
||||
LOGD_IF(VERBOSE,
|
||||
"removing binder=%p, heap=%p, size=%d, fd=%d, count=%d",
|
||||
binder.unsafe_get(), info.heap.get(),
|
||||
static_cast<BpMemoryHeap*>(info.heap.get())->mSize,
|
||||
static_cast<BpMemoryHeap*>(info.heap.get())->mHeapId,
|
||||
info.count);
|
||||
rel = mHeapCache.valueAt(i).heap;
|
||||
mHeapCache.removeItemsAt(i);
|
||||
}
|
||||
} else {
|
||||
LOGE("free_heap binder=%p not found!!!", binder.unsafe_get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sp<IMemoryHeap> HeapCache::get_heap(const sp<IBinder>& binder)
|
||||
{
|
||||
sp<IMemoryHeap> realHeap;
|
||||
Mutex::Autolock _l(mHeapCacheLock);
|
||||
ssize_t i = mHeapCache.indexOfKey(binder);
|
||||
if (i>=0) realHeap = mHeapCache.valueAt(i).heap;
|
||||
else realHeap = interface_cast<IMemoryHeap>(binder);
|
||||
return realHeap;
|
||||
}
|
||||
|
||||
void HeapCache::dump_heaps()
|
||||
{
|
||||
Mutex::Autolock _l(mHeapCacheLock);
|
||||
int c = mHeapCache.size();
|
||||
for (int i=0 ; i<c ; i++) {
|
||||
const heap_info_t& info = mHeapCache.valueAt(i);
|
||||
BpMemoryHeap const* h(static_cast<BpMemoryHeap const *>(info.heap.get()));
|
||||
LOGD("hey=%p, heap=%p, count=%d, (fd=%d, base=%p, size=%d)",
|
||||
mHeapCache.keyAt(i).unsafe_get(),
|
||||
info.heap.get(), info.count,
|
||||
h->mHeapId, h->mBase, h->mSize);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
}; // namespace android
|
File diff suppressed because it is too large
Load Diff
|
@ -1,86 +0,0 @@
|
|||
/*
|
||||
* 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 "PermissionController"
|
||||
|
||||
#include <utils/IPermissionController.h>
|
||||
|
||||
#include <utils/Debug.h>
|
||||
#include <utils/Log.h>
|
||||
#include <utils/Parcel.h>
|
||||
#include <utils/String8.h>
|
||||
|
||||
#include <private/utils/Static.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
class BpPermissionController : public BpInterface<IPermissionController>
|
||||
{
|
||||
public:
|
||||
BpPermissionController(const sp<IBinder>& impl)
|
||||
: BpInterface<IPermissionController>(impl)
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool checkPermission(const String16& permission, int32_t pid, int32_t uid)
|
||||
{
|
||||
Parcel data, reply;
|
||||
data.writeInterfaceToken(IPermissionController::getInterfaceDescriptor());
|
||||
data.writeString16(permission);
|
||||
data.writeInt32(pid);
|
||||
data.writeInt32(uid);
|
||||
remote()->transact(CHECK_PERMISSION_TRANSACTION, data, &reply);
|
||||
// fail on exception
|
||||
if (reply.readInt32() != 0) return 0;
|
||||
return reply.readInt32() != 0;
|
||||
}
|
||||
};
|
||||
|
||||
IMPLEMENT_META_INTERFACE(PermissionController, "android.os.IPermissionController");
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
#define CHECK_INTERFACE(interface, data, reply) \
|
||||
do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
|
||||
LOGW("Call incorrectly routed to " #interface); \
|
||||
return PERMISSION_DENIED; \
|
||||
} } while (0)
|
||||
|
||||
status_t BnPermissionController::onTransact(
|
||||
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
|
||||
{
|
||||
//printf("PermissionController received: "); data.print();
|
||||
switch(code) {
|
||||
case CHECK_PERMISSION_TRANSACTION: {
|
||||
CHECK_INTERFACE(IPermissionController, data, reply);
|
||||
String16 permission = data.readString16();
|
||||
int32_t pid = data.readInt32();
|
||||
int32_t uid = data.readInt32();
|
||||
bool res = checkPermission(permission, pid, uid);
|
||||
// write exception
|
||||
reply->writeInt32(0);
|
||||
reply->writeInt32(res ? 1 : 0);
|
||||
return NO_ERROR;
|
||||
} break;
|
||||
default:
|
||||
return BBinder::onTransact(code, data, reply, flags);
|
||||
}
|
||||
}
|
||||
|
||||
}; // namespace android
|
||||
|
|
@ -1,230 +0,0 @@
|
|||
/*
|
||||
* 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 "ServiceManager"
|
||||
|
||||
#include <utils/IServiceManager.h>
|
||||
|
||||
#include <utils/Debug.h>
|
||||
#include <utils/IPCThreadState.h>
|
||||
#include <utils/Log.h>
|
||||
#include <utils/Parcel.h>
|
||||
#include <utils/String8.h>
|
||||
#include <utils/SystemClock.h>
|
||||
|
||||
#include <private/utils/Static.h>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
sp<IServiceManager> defaultServiceManager()
|
||||
{
|
||||
if (gDefaultServiceManager != NULL) return gDefaultServiceManager;
|
||||
|
||||
{
|
||||
AutoMutex _l(gDefaultServiceManagerLock);
|
||||
if (gDefaultServiceManager == NULL) {
|
||||
gDefaultServiceManager = interface_cast<IServiceManager>(
|
||||
ProcessState::self()->getContextObject(NULL));
|
||||
}
|
||||
}
|
||||
|
||||
return gDefaultServiceManager;
|
||||
}
|
||||
|
||||
bool checkCallingPermission(const String16& permission)
|
||||
{
|
||||
return checkCallingPermission(permission, NULL, NULL);
|
||||
}
|
||||
|
||||
static String16 _permission("permission");
|
||||
|
||||
bool checkCallingPermission(const String16& permission, int32_t* outPid, int32_t* outUid)
|
||||
{
|
||||
IPCThreadState* ipcState = IPCThreadState::self();
|
||||
int32_t pid = ipcState->getCallingPid();
|
||||
int32_t uid = ipcState->getCallingUid();
|
||||
if (outPid) *outPid = pid;
|
||||
if (outUid) *outUid= uid;
|
||||
|
||||
sp<IPermissionController> pc;
|
||||
gDefaultServiceManagerLock.lock();
|
||||
pc = gPermissionController;
|
||||
gDefaultServiceManagerLock.unlock();
|
||||
|
||||
int64_t startTime = 0;
|
||||
|
||||
while (true) {
|
||||
if (pc != NULL) {
|
||||
bool res = pc->checkPermission(permission, pid, uid);
|
||||
if (res) {
|
||||
if (startTime != 0) {
|
||||
LOGI("Check passed after %d seconds for %s from uid=%d pid=%d",
|
||||
(int)((uptimeMillis()-startTime)/1000),
|
||||
String8(permission).string(), uid, pid);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// Is this a permission failure, or did the controller go away?
|
||||
if (pc->asBinder()->isBinderAlive()) {
|
||||
LOGW("Permission failure: %s from uid=%d pid=%d",
|
||||
String8(permission).string(), uid, pid);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Object is dead!
|
||||
gDefaultServiceManagerLock.lock();
|
||||
if (gPermissionController == pc) {
|
||||
gPermissionController = NULL;
|
||||
}
|
||||
gDefaultServiceManagerLock.unlock();
|
||||
}
|
||||
|
||||
// Need to retrieve the permission controller.
|
||||
sp<IBinder> binder = defaultServiceManager()->checkService(_permission);
|
||||
if (binder == NULL) {
|
||||
// Wait for the permission controller to come back...
|
||||
if (startTime == 0) {
|
||||
startTime = uptimeMillis();
|
||||
LOGI("Waiting to check permission %s from uid=%d pid=%d",
|
||||
String8(permission).string(), uid, pid);
|
||||
}
|
||||
sleep(1);
|
||||
} else {
|
||||
pc = interface_cast<IPermissionController>(binder);
|
||||
// Install the new permission controller, and try again.
|
||||
gDefaultServiceManagerLock.lock();
|
||||
gPermissionController = pc;
|
||||
gDefaultServiceManagerLock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
class BpServiceManager : public BpInterface<IServiceManager>
|
||||
{
|
||||
public:
|
||||
BpServiceManager(const sp<IBinder>& impl)
|
||||
: BpInterface<IServiceManager>(impl)
|
||||
{
|
||||
}
|
||||
|
||||
virtual sp<IBinder> getService(const String16& name) const
|
||||
{
|
||||
unsigned n;
|
||||
for (n = 0; n < 5; n++){
|
||||
sp<IBinder> svc = checkService(name);
|
||||
if (svc != NULL) return svc;
|
||||
LOGI("Waiting for sevice %s...\n", String8(name).string());
|
||||
sleep(1);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
virtual sp<IBinder> checkService( const String16& name) const
|
||||
{
|
||||
Parcel data, reply;
|
||||
data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
|
||||
data.writeString16(name);
|
||||
remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply);
|
||||
return reply.readStrongBinder();
|
||||
}
|
||||
|
||||
virtual status_t addService(const String16& name, const sp<IBinder>& service)
|
||||
{
|
||||
Parcel data, reply;
|
||||
data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
|
||||
data.writeString16(name);
|
||||
data.writeStrongBinder(service);
|
||||
status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
|
||||
return err == NO_ERROR ? reply.readInt32() : err;
|
||||
}
|
||||
|
||||
virtual Vector<String16> listServices()
|
||||
{
|
||||
Vector<String16> res;
|
||||
int n = 0;
|
||||
|
||||
for (;;) {
|
||||
Parcel data, reply;
|
||||
data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
|
||||
data.writeInt32(n++);
|
||||
status_t err = remote()->transact(LIST_SERVICES_TRANSACTION, data, &reply);
|
||||
if (err != NO_ERROR)
|
||||
break;
|
||||
res.add(reply.readString16());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager");
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
#define CHECK_INTERFACE(interface, data, reply) \
|
||||
do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
|
||||
LOGW("Call incorrectly routed to " #interface); \
|
||||
return PERMISSION_DENIED; \
|
||||
} } while (0)
|
||||
|
||||
status_t BnServiceManager::onTransact(
|
||||
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
|
||||
{
|
||||
//printf("ServiceManager received: "); data.print();
|
||||
switch(code) {
|
||||
case GET_SERVICE_TRANSACTION: {
|
||||
CHECK_INTERFACE(IServiceManager, data, reply);
|
||||
String16 which = data.readString16();
|
||||
sp<IBinder> b = const_cast<BnServiceManager*>(this)->getService(which);
|
||||
reply->writeStrongBinder(b);
|
||||
return NO_ERROR;
|
||||
} break;
|
||||
case CHECK_SERVICE_TRANSACTION: {
|
||||
CHECK_INTERFACE(IServiceManager, data, reply);
|
||||
String16 which = data.readString16();
|
||||
sp<IBinder> b = const_cast<BnServiceManager*>(this)->checkService(which);
|
||||
reply->writeStrongBinder(b);
|
||||
return NO_ERROR;
|
||||
} break;
|
||||
case ADD_SERVICE_TRANSACTION: {
|
||||
CHECK_INTERFACE(IServiceManager, data, reply);
|
||||
String16 which = data.readString16();
|
||||
sp<IBinder> b = data.readStrongBinder();
|
||||
status_t err = addService(which, b);
|
||||
reply->writeInt32(err);
|
||||
return NO_ERROR;
|
||||
} break;
|
||||
case LIST_SERVICES_TRANSACTION: {
|
||||
CHECK_INTERFACE(IServiceManager, data, reply);
|
||||
Vector<String16> list = listServices();
|
||||
const size_t N = list.size();
|
||||
reply->writeInt32(N);
|
||||
for (size_t i=0; i<N; i++) {
|
||||
reply->writeString16(list[i]);
|
||||
}
|
||||
return NO_ERROR;
|
||||
} break;
|
||||
default:
|
||||
return BBinder::onTransact(code, data, reply, flags);
|
||||
}
|
||||
}
|
||||
|
||||
}; // namespace android
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2008 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.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <utils/MemoryBase.h>
|
||||
|
||||
|
||||
namespace android {
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
MemoryBase::MemoryBase(const sp<IMemoryHeap>& heap,
|
||||
ssize_t offset, size_t size)
|
||||
: mSize(size), mOffset(offset), mHeap(heap)
|
||||
{
|
||||
}
|
||||
|
||||
sp<IMemoryHeap> MemoryBase::getMemory(ssize_t* offset, size_t* size) const
|
||||
{
|
||||
if (offset) *offset = mOffset;
|
||||
if (size) *size = mSize;
|
||||
return mHeap;
|
||||
}
|
||||
|
||||
MemoryBase::~MemoryBase()
|
||||
{
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
}; // namespace android
|
|
@ -1,409 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2007 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 "MemoryDealer"
|
||||
|
||||
#include <utils/MemoryDealer.h>
|
||||
|
||||
#include <utils/Log.h>
|
||||
#include <utils/IPCThreadState.h>
|
||||
#include <utils/SortedVector.h>
|
||||
#include <utils/String8.h>
|
||||
#include <utils/MemoryBase.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/file.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class SimpleMemory : public MemoryBase {
|
||||
public:
|
||||
SimpleMemory(const sp<IMemoryHeap>& heap, ssize_t offset, size_t size);
|
||||
virtual ~SimpleMemory();
|
||||
};
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
MemoryDealer::Allocation::Allocation(
|
||||
const sp<MemoryDealer>& dealer, ssize_t offset, size_t size,
|
||||
const sp<IMemory>& memory)
|
||||
: mDealer(dealer), mOffset(offset), mSize(size), mMemory(memory)
|
||||
{
|
||||
}
|
||||
|
||||
MemoryDealer::Allocation::~Allocation()
|
||||
{
|
||||
if (mSize) {
|
||||
/* NOTE: it's VERY important to not free allocations of size 0 because
|
||||
* they're special as they don't have any record in the allocator
|
||||
* and could alias some real allocation (their offset is zero). */
|
||||
mDealer->deallocate(mOffset);
|
||||
}
|
||||
}
|
||||
|
||||
sp<IMemoryHeap> MemoryDealer::Allocation::getMemory(
|
||||
ssize_t* offset, size_t* size) const
|
||||
{
|
||||
return mMemory->getMemory(offset, size);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
MemoryDealer::MemoryDealer(size_t size, uint32_t flags, const char* name)
|
||||
: mHeap(new SharedHeap(size, flags, name)),
|
||||
mAllocator(new SimpleBestFitAllocator(size))
|
||||
{
|
||||
}
|
||||
|
||||
MemoryDealer::MemoryDealer(const sp<HeapInterface>& heap)
|
||||
: mHeap(heap),
|
||||
mAllocator(new SimpleBestFitAllocator(heap->virtualSize()))
|
||||
{
|
||||
}
|
||||
|
||||
MemoryDealer::MemoryDealer( const sp<HeapInterface>& heap,
|
||||
const sp<AllocatorInterface>& allocator)
|
||||
: mHeap(heap), mAllocator(allocator)
|
||||
{
|
||||
}
|
||||
|
||||
MemoryDealer::~MemoryDealer()
|
||||
{
|
||||
}
|
||||
|
||||
sp<IMemory> MemoryDealer::allocate(size_t size, uint32_t flags)
|
||||
{
|
||||
sp<IMemory> memory;
|
||||
const ssize_t offset = allocator()->allocate(size, flags);
|
||||
if (offset >= 0) {
|
||||
sp<IMemory> new_memory = heap()->mapMemory(offset, size);
|
||||
if (new_memory != 0) {
|
||||
memory = new Allocation(this, offset, size, new_memory);
|
||||
} else {
|
||||
LOGE("couldn't map [%8x, %d]", offset, size);
|
||||
if (size) {
|
||||
/* NOTE: it's VERY important to not free allocations of size 0
|
||||
* because they're special as they don't have any record in the
|
||||
* allocator and could alias some real allocation
|
||||
* (their offset is zero). */
|
||||
allocator()->deallocate(offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
return memory;
|
||||
}
|
||||
|
||||
void MemoryDealer::deallocate(size_t offset)
|
||||
{
|
||||
allocator()->deallocate(offset);
|
||||
}
|
||||
|
||||
void MemoryDealer::dump(const char* what, uint32_t flags) const
|
||||
{
|
||||
allocator()->dump(what, flags);
|
||||
}
|
||||
|
||||
const sp<HeapInterface>& MemoryDealer::heap() const {
|
||||
return mHeap;
|
||||
}
|
||||
|
||||
const sp<AllocatorInterface>& MemoryDealer::allocator() const {
|
||||
return mAllocator;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// align all the memory blocks on a cache-line boundary
|
||||
const int SimpleBestFitAllocator::kMemoryAlign = 32;
|
||||
|
||||
SimpleBestFitAllocator::SimpleBestFitAllocator(size_t size)
|
||||
{
|
||||
size_t pagesize = getpagesize();
|
||||
mHeapSize = ((size + pagesize-1) & ~(pagesize-1));
|
||||
|
||||
chunk_t* node = new chunk_t(0, mHeapSize / kMemoryAlign);
|
||||
mList.insertHead(node);
|
||||
}
|
||||
|
||||
SimpleBestFitAllocator::~SimpleBestFitAllocator()
|
||||
{
|
||||
while(!mList.isEmpty()) {
|
||||
delete mList.remove(mList.head());
|
||||
}
|
||||
}
|
||||
|
||||
size_t SimpleBestFitAllocator::size() const
|
||||
{
|
||||
return mHeapSize;
|
||||
}
|
||||
|
||||
size_t SimpleBestFitAllocator::allocate(size_t size, uint32_t flags)
|
||||
{
|
||||
Mutex::Autolock _l(mLock);
|
||||
ssize_t offset = alloc(size, flags);
|
||||
return offset;
|
||||
}
|
||||
|
||||
status_t SimpleBestFitAllocator::deallocate(size_t offset)
|
||||
{
|
||||
Mutex::Autolock _l(mLock);
|
||||
chunk_t const * const freed = dealloc(offset);
|
||||
if (freed) {
|
||||
return NO_ERROR;
|
||||
}
|
||||
return NAME_NOT_FOUND;
|
||||
}
|
||||
|
||||
ssize_t SimpleBestFitAllocator::alloc(size_t size, uint32_t flags)
|
||||
{
|
||||
if (size == 0) {
|
||||
return 0;
|
||||
}
|
||||
size = (size + kMemoryAlign-1) / kMemoryAlign;
|
||||
chunk_t* free_chunk = 0;
|
||||
chunk_t* cur = mList.head();
|
||||
|
||||
size_t pagesize = getpagesize();
|
||||
while (cur) {
|
||||
int extra = 0;
|
||||
if (flags & PAGE_ALIGNED)
|
||||
extra = ( -cur->start & ((pagesize/kMemoryAlign)-1) ) ;
|
||||
|
||||
// best fit
|
||||
if (cur->free && (cur->size >= (size+extra))) {
|
||||
if ((!free_chunk) || (cur->size < free_chunk->size)) {
|
||||
free_chunk = cur;
|
||||
}
|
||||
if (cur->size == size) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
cur = cur->next;
|
||||
}
|
||||
|
||||
if (free_chunk) {
|
||||
const size_t free_size = free_chunk->size;
|
||||
free_chunk->free = 0;
|
||||
free_chunk->size = size;
|
||||
if (free_size > size) {
|
||||
int extra = 0;
|
||||
if (flags & PAGE_ALIGNED)
|
||||
extra = ( -free_chunk->start & ((pagesize/kMemoryAlign)-1) ) ;
|
||||
if (extra) {
|
||||
chunk_t* split = new chunk_t(free_chunk->start, extra);
|
||||
free_chunk->start += extra;
|
||||
mList.insertBefore(free_chunk, split);
|
||||
}
|
||||
|
||||
LOGE_IF((flags&PAGE_ALIGNED) &&
|
||||
((free_chunk->start*kMemoryAlign)&(pagesize-1)),
|
||||
"PAGE_ALIGNED requested, but page is not aligned!!!");
|
||||
|
||||
const ssize_t tail_free = free_size - (size+extra);
|
||||
if (tail_free > 0) {
|
||||
chunk_t* split = new chunk_t(
|
||||
free_chunk->start + free_chunk->size, tail_free);
|
||||
mList.insertAfter(free_chunk, split);
|
||||
}
|
||||
}
|
||||
return (free_chunk->start)*kMemoryAlign;
|
||||
}
|
||||
return NO_MEMORY;
|
||||
}
|
||||
|
||||
SimpleBestFitAllocator::chunk_t* SimpleBestFitAllocator::dealloc(size_t start)
|
||||
{
|
||||
start = start / kMemoryAlign;
|
||||
chunk_t* cur = mList.head();
|
||||
while (cur) {
|
||||
if (cur->start == start) {
|
||||
LOG_FATAL_IF(cur->free,
|
||||
"block at offset 0x%08lX of size 0x%08lX already freed",
|
||||
cur->start*kMemoryAlign, cur->size*kMemoryAlign);
|
||||
|
||||
// merge freed blocks together
|
||||
chunk_t* freed = cur;
|
||||
cur->free = 1;
|
||||
do {
|
||||
chunk_t* const p = cur->prev;
|
||||
chunk_t* const n = cur->next;
|
||||
if (p && (p->free || !cur->size)) {
|
||||
freed = p;
|
||||
p->size += cur->size;
|
||||
mList.remove(cur);
|
||||
delete cur;
|
||||
}
|
||||
cur = n;
|
||||
} while (cur && cur->free);
|
||||
|
||||
#ifndef NDEBUG
|
||||
if (!freed->free) {
|
||||
dump_l("dealloc (!freed->free)");
|
||||
}
|
||||
#endif
|
||||
LOG_FATAL_IF(!freed->free,
|
||||
"freed block at offset 0x%08lX of size 0x%08lX is not free!",
|
||||
freed->start * kMemoryAlign, freed->size * kMemoryAlign);
|
||||
|
||||
return freed;
|
||||
}
|
||||
cur = cur->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SimpleBestFitAllocator::dump(const char* what, uint32_t flags) const
|
||||
{
|
||||
Mutex::Autolock _l(mLock);
|
||||
dump_l(what, flags);
|
||||
}
|
||||
|
||||
void SimpleBestFitAllocator::dump_l(const char* what, uint32_t flags) const
|
||||
{
|
||||
String8 result;
|
||||
dump_l(result, what, flags);
|
||||
LOGD("%s", result.string());
|
||||
}
|
||||
|
||||
void SimpleBestFitAllocator::dump(String8& result,
|
||||
const char* what, uint32_t flags) const
|
||||
{
|
||||
Mutex::Autolock _l(mLock);
|
||||
dump_l(result, what, flags);
|
||||
}
|
||||
|
||||
void SimpleBestFitAllocator::dump_l(String8& result,
|
||||
const char* what, uint32_t flags) const
|
||||
{
|
||||
size_t size = 0;
|
||||
int32_t i = 0;
|
||||
chunk_t const* cur = mList.head();
|
||||
|
||||
const size_t SIZE = 256;
|
||||
char buffer[SIZE];
|
||||
snprintf(buffer, SIZE, " %s (%p, size=%u)\n",
|
||||
what, this, (unsigned int)mHeapSize);
|
||||
|
||||
result.append(buffer);
|
||||
|
||||
while (cur) {
|
||||
const char* errs[] = {"", "| link bogus NP",
|
||||
"| link bogus PN", "| link bogus NP+PN" };
|
||||
int np = ((cur->next) && cur->next->prev != cur) ? 1 : 0;
|
||||
int pn = ((cur->prev) && cur->prev->next != cur) ? 2 : 0;
|
||||
|
||||
snprintf(buffer, SIZE, " %3u: %08x | 0x%08X | 0x%08X | %s %s\n",
|
||||
i, int(cur), int(cur->start*kMemoryAlign),
|
||||
int(cur->size*kMemoryAlign),
|
||||
int(cur->free) ? "F" : "A",
|
||||
errs[np|pn]);
|
||||
|
||||
result.append(buffer);
|
||||
|
||||
if (!cur->free)
|
||||
size += cur->size*kMemoryAlign;
|
||||
|
||||
i++;
|
||||
cur = cur->next;
|
||||
}
|
||||
snprintf(buffer, SIZE, " size allocated: %u (%u KB)\n", int(size), int(size/1024));
|
||||
result.append(buffer);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
SharedHeap::SharedHeap(size_t size, uint32_t flags, char const * name)
|
||||
: MemoryHeapBase(size, flags, name)
|
||||
{
|
||||
}
|
||||
|
||||
SharedHeap::~SharedHeap()
|
||||
{
|
||||
}
|
||||
|
||||
sp<IMemory> SharedHeap::mapMemory(size_t offset, size_t size)
|
||||
{
|
||||
return new SimpleMemory(this, offset, size);
|
||||
}
|
||||
|
||||
|
||||
SimpleMemory::SimpleMemory(const sp<IMemoryHeap>& heap,
|
||||
ssize_t offset, size_t size)
|
||||
: MemoryBase(heap, offset, size)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
void* const start_ptr = (void*)(intptr_t(heap->base()) + offset);
|
||||
memset(start_ptr, 0xda, size);
|
||||
#endif
|
||||
}
|
||||
|
||||
SimpleMemory::~SimpleMemory()
|
||||
{
|
||||
size_t freedOffset = getOffset();
|
||||
size_t freedSize = getSize();
|
||||
|
||||
// keep the size to unmap in excess
|
||||
size_t pagesize = getpagesize();
|
||||
size_t start = freedOffset;
|
||||
size_t end = start + freedSize;
|
||||
start &= ~(pagesize-1);
|
||||
end = (end + pagesize-1) & ~(pagesize-1);
|
||||
|
||||
// give back to the kernel the pages we don't need
|
||||
size_t free_start = freedOffset;
|
||||
size_t free_end = free_start + freedSize;
|
||||
if (start < free_start)
|
||||
start = free_start;
|
||||
if (end > free_end)
|
||||
end = free_end;
|
||||
start = (start + pagesize-1) & ~(pagesize-1);
|
||||
end &= ~(pagesize-1);
|
||||
|
||||
if (start < end) {
|
||||
void* const start_ptr = (void*)(intptr_t(getHeap()->base()) + start);
|
||||
size_t size = end-start;
|
||||
|
||||
#ifndef NDEBUG
|
||||
memset(start_ptr, 0xdf, size);
|
||||
#endif
|
||||
|
||||
// MADV_REMOVE is not defined on Dapper based Goobuntu
|
||||
#ifdef MADV_REMOVE
|
||||
if (size) {
|
||||
int err = madvise(start_ptr, size, MADV_REMOVE);
|
||||
LOGW_IF(err, "madvise(%p, %u, MADV_REMOVE) returned %s",
|
||||
start_ptr, size, err<0 ? strerror(errno) : "Ok");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
}; // namespace android
|
|
@ -1,183 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2008 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 "MemoryHeapBase"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <cutils/log.h>
|
||||
#include <cutils/ashmem.h>
|
||||
#include <cutils/atomic.h>
|
||||
|
||||
#include <utils/MemoryHeapBase.h>
|
||||
|
||||
#if HAVE_ANDROID_OS
|
||||
#include <linux/android_pmem.h>
|
||||
#endif
|
||||
|
||||
|
||||
namespace android {
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
MemoryHeapBase::MemoryHeapBase()
|
||||
: mFD(-1), mSize(0), mBase(MAP_FAILED),
|
||||
mDevice(NULL), mNeedUnmap(false)
|
||||
{
|
||||
}
|
||||
|
||||
MemoryHeapBase::MemoryHeapBase(size_t size, uint32_t flags, char const * name)
|
||||
: mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
|
||||
mDevice(0), mNeedUnmap(false)
|
||||
{
|
||||
const size_t pagesize = getpagesize();
|
||||
size = ((size + pagesize-1) & ~(pagesize-1));
|
||||
int fd = ashmem_create_region(name == NULL ? "MemoryHeapBase" : name, size);
|
||||
LOGE_IF(fd<0, "error creating ashmem region: %s", strerror(errno));
|
||||
if (fd >= 0) {
|
||||
if (mapfd(fd, size) == NO_ERROR) {
|
||||
if (flags & READ_ONLY) {
|
||||
ashmem_set_prot_region(fd, PROT_READ);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MemoryHeapBase::MemoryHeapBase(const char* device, size_t size, uint32_t flags)
|
||||
: mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
|
||||
mDevice(0), mNeedUnmap(false)
|
||||
{
|
||||
int fd = open(device, O_RDWR);
|
||||
LOGE_IF(fd<0, "error opening %s: %s", device, strerror(errno));
|
||||
if (fd >= 0) {
|
||||
const size_t pagesize = getpagesize();
|
||||
size = ((size + pagesize-1) & ~(pagesize-1));
|
||||
if (mapfd(fd, size) == NO_ERROR) {
|
||||
mDevice = device;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MemoryHeapBase::MemoryHeapBase(int fd, size_t size, uint32_t flags)
|
||||
: mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
|
||||
mDevice(0), mNeedUnmap(false)
|
||||
{
|
||||
const size_t pagesize = getpagesize();
|
||||
size = ((size + pagesize-1) & ~(pagesize-1));
|
||||
mapfd(dup(fd), size);
|
||||
}
|
||||
|
||||
status_t MemoryHeapBase::init(int fd, void *base, int size, int flags, const char* device)
|
||||
{
|
||||
if (mFD != -1) {
|
||||
return INVALID_OPERATION;
|
||||
}
|
||||
mFD = fd;
|
||||
mBase = base;
|
||||
mSize = size;
|
||||
mFlags = flags;
|
||||
mDevice = device;
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
status_t MemoryHeapBase::mapfd(int fd, size_t size)
|
||||
{
|
||||
if (size == 0) {
|
||||
// try to figure out the size automatically
|
||||
#if HAVE_ANDROID_OS
|
||||
// first try the PMEM ioctl
|
||||
pmem_region reg;
|
||||
int err = ioctl(fd, PMEM_GET_TOTAL_SIZE, ®);
|
||||
if (err == 0)
|
||||
size = reg.len;
|
||||
#endif
|
||||
if (size == 0) { // try fstat
|
||||
struct stat sb;
|
||||
if (fstat(fd, &sb) == 0)
|
||||
size = sb.st_size;
|
||||
}
|
||||
// if it didn't work, let mmap() fail.
|
||||
}
|
||||
|
||||
if ((mFlags & DONT_MAP_LOCALLY) == 0) {
|
||||
void* base = (uint8_t*)mmap(0, size,
|
||||
PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
if (base == MAP_FAILED) {
|
||||
LOGE("mmap(fd=%d, size=%u) failed (%s)",
|
||||
fd, uint32_t(size), strerror(errno));
|
||||
close(fd);
|
||||
return -errno;
|
||||
}
|
||||
//LOGD("mmap(fd=%d, base=%p, size=%lu)", fd, base, size);
|
||||
mBase = base;
|
||||
mNeedUnmap = true;
|
||||
} else {
|
||||
mBase = 0; // not MAP_FAILED
|
||||
mNeedUnmap = false;
|
||||
}
|
||||
mFD = fd;
|
||||
mSize = size;
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
MemoryHeapBase::~MemoryHeapBase()
|
||||
{
|
||||
dispose();
|
||||
}
|
||||
|
||||
void MemoryHeapBase::dispose()
|
||||
{
|
||||
int fd = android_atomic_or(-1, &mFD);
|
||||
if (fd >= 0) {
|
||||
if (mNeedUnmap) {
|
||||
//LOGD("munmap(fd=%d, base=%p, size=%lu)", fd, mBase, mSize);
|
||||
munmap(mBase, mSize);
|
||||
}
|
||||
mBase = 0;
|
||||
mSize = 0;
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
int MemoryHeapBase::getHeapID() const {
|
||||
return mFD;
|
||||
}
|
||||
|
||||
void* MemoryHeapBase::getBase() const {
|
||||
return mBase;
|
||||
}
|
||||
|
||||
size_t MemoryHeapBase::getSize() const {
|
||||
return mSize;
|
||||
}
|
||||
|
||||
uint32_t MemoryHeapBase::getFlags() const {
|
||||
return mFlags;
|
||||
}
|
||||
|
||||
const char* MemoryHeapBase::getDevice() const {
|
||||
return mDevice;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
}; // namespace android
|
|
@ -1,248 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2008 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 "MemoryHeapPmem"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <cutils/log.h>
|
||||
|
||||
#include <utils/MemoryHeapPmem.h>
|
||||
#include <utils/MemoryHeapBase.h>
|
||||
|
||||
#if HAVE_ANDROID_OS
|
||||
#include <linux/android_pmem.h>
|
||||
#endif
|
||||
|
||||
namespace android {
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
MemoryHeapPmem::MemoryPmem::MemoryPmem(const sp<MemoryHeapPmem>& heap)
|
||||
: BnMemory(), mClientHeap(heap)
|
||||
{
|
||||
}
|
||||
|
||||
MemoryHeapPmem::MemoryPmem::~MemoryPmem() {
|
||||
if (mClientHeap != NULL) {
|
||||
mClientHeap->remove(this);
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
class SubRegionMemory : public MemoryHeapPmem::MemoryPmem {
|
||||
public:
|
||||
SubRegionMemory(const sp<MemoryHeapPmem>& heap, ssize_t offset, size_t size);
|
||||
virtual ~SubRegionMemory();
|
||||
virtual sp<IMemoryHeap> getMemory(ssize_t* offset, size_t* size) const;
|
||||
private:
|
||||
friend class MemoryHeapPmem;
|
||||
void revoke();
|
||||
size_t mSize;
|
||||
ssize_t mOffset;
|
||||
};
|
||||
|
||||
SubRegionMemory::SubRegionMemory(const sp<MemoryHeapPmem>& heap,
|
||||
ssize_t offset, size_t size)
|
||||
: MemoryHeapPmem::MemoryPmem(heap), mSize(size), mOffset(offset)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
void* const start_ptr = (void*)(intptr_t(getHeap()->base()) + offset);
|
||||
memset(start_ptr, 0xda, size);
|
||||
#endif
|
||||
|
||||
#if HAVE_ANDROID_OS
|
||||
if (size > 0) {
|
||||
const size_t pagesize = getpagesize();
|
||||
size = (size + pagesize-1) & ~(pagesize-1);
|
||||
int our_fd = heap->heapID();
|
||||
struct pmem_region sub = { offset, size };
|
||||
int err = ioctl(our_fd, PMEM_MAP, &sub);
|
||||
LOGE_IF(err<0, "PMEM_MAP failed (%s), "
|
||||
"mFD=%d, sub.offset=%lu, sub.size=%lu",
|
||||
strerror(errno), our_fd, sub.offset, sub.len);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
sp<IMemoryHeap> SubRegionMemory::getMemory(ssize_t* offset, size_t* size) const
|
||||
{
|
||||
if (offset) *offset = mOffset;
|
||||
if (size) *size = mSize;
|
||||
return getHeap();
|
||||
}
|
||||
|
||||
SubRegionMemory::~SubRegionMemory()
|
||||
{
|
||||
revoke();
|
||||
}
|
||||
|
||||
|
||||
void SubRegionMemory::revoke()
|
||||
{
|
||||
// NOTE: revoke() doesn't need to be protected by a lock because it
|
||||
// can only be called from MemoryHeapPmem::revoke(), which means
|
||||
// that we can't be in ~SubRegionMemory(), or in ~SubRegionMemory(),
|
||||
// which means MemoryHeapPmem::revoke() wouldn't have been able to
|
||||
// promote() it.
|
||||
|
||||
#if HAVE_ANDROID_OS
|
||||
if (mSize != NULL) {
|
||||
const sp<MemoryHeapPmem>& heap(getHeap());
|
||||
int our_fd = heap->heapID();
|
||||
struct pmem_region sub;
|
||||
sub.offset = mOffset;
|
||||
sub.len = mSize;
|
||||
int err = ioctl(our_fd, PMEM_UNMAP, &sub);
|
||||
LOGE_IF(err<0, "PMEM_UNMAP failed (%s), "
|
||||
"mFD=%d, sub.offset=%lu, sub.size=%lu",
|
||||
strerror(errno), our_fd, sub.offset, sub.len);
|
||||
mSize = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
MemoryHeapPmem::MemoryHeapPmem(const sp<MemoryHeapBase>& pmemHeap,
|
||||
uint32_t flags)
|
||||
: HeapInterface(), MemoryHeapBase()
|
||||
{
|
||||
char const * const device = pmemHeap->getDevice();
|
||||
#if HAVE_ANDROID_OS
|
||||
if (device) {
|
||||
int fd = open(device, O_RDWR);
|
||||
LOGE_IF(fd<0, "couldn't open %s (%s)", device, strerror(errno));
|
||||
if (fd >= 0) {
|
||||
int err = ioctl(fd, PMEM_CONNECT, pmemHeap->heapID());
|
||||
if (err < 0) {
|
||||
LOGE("PMEM_CONNECT failed (%s), mFD=%d, sub-fd=%d",
|
||||
strerror(errno), fd, pmemHeap->heapID());
|
||||
close(fd);
|
||||
} else {
|
||||
// everything went well...
|
||||
mParentHeap = pmemHeap;
|
||||
MemoryHeapBase::init(fd,
|
||||
pmemHeap->getBase(),
|
||||
pmemHeap->getSize(),
|
||||
pmemHeap->getFlags() | flags,
|
||||
device);
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
mParentHeap = pmemHeap;
|
||||
MemoryHeapBase::init(
|
||||
dup(pmemHeap->heapID()),
|
||||
pmemHeap->getBase(),
|
||||
pmemHeap->getSize(),
|
||||
pmemHeap->getFlags() | flags,
|
||||
device);
|
||||
#endif
|
||||
}
|
||||
|
||||
MemoryHeapPmem::~MemoryHeapPmem()
|
||||
{
|
||||
}
|
||||
|
||||
sp<IMemory> MemoryHeapPmem::mapMemory(size_t offset, size_t size)
|
||||
{
|
||||
sp<MemoryPmem> memory = createMemory(offset, size);
|
||||
if (memory != 0) {
|
||||
Mutex::Autolock _l(mLock);
|
||||
mAllocations.add(memory);
|
||||
}
|
||||
return memory;
|
||||
}
|
||||
|
||||
sp<MemoryHeapPmem::MemoryPmem> MemoryHeapPmem::createMemory(
|
||||
size_t offset, size_t size)
|
||||
{
|
||||
sp<SubRegionMemory> memory;
|
||||
if (heapID() > 0)
|
||||
memory = new SubRegionMemory(this, offset, size);
|
||||
return memory;
|
||||
}
|
||||
|
||||
status_t MemoryHeapPmem::slap()
|
||||
{
|
||||
#if HAVE_ANDROID_OS
|
||||
size_t size = getSize();
|
||||
const size_t pagesize = getpagesize();
|
||||
size = (size + pagesize-1) & ~(pagesize-1);
|
||||
int our_fd = getHeapID();
|
||||
struct pmem_region sub = { 0, size };
|
||||
int err = ioctl(our_fd, PMEM_MAP, &sub);
|
||||
LOGE_IF(err<0, "PMEM_MAP failed (%s), "
|
||||
"mFD=%d, sub.offset=%lu, sub.size=%lu",
|
||||
strerror(errno), our_fd, sub.offset, sub.len);
|
||||
return -errno;
|
||||
#else
|
||||
return NO_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
status_t MemoryHeapPmem::unslap()
|
||||
{
|
||||
#if HAVE_ANDROID_OS
|
||||
size_t size = getSize();
|
||||
const size_t pagesize = getpagesize();
|
||||
size = (size + pagesize-1) & ~(pagesize-1);
|
||||
int our_fd = getHeapID();
|
||||
struct pmem_region sub = { 0, size };
|
||||
int err = ioctl(our_fd, PMEM_UNMAP, &sub);
|
||||
LOGE_IF(err<0, "PMEM_UNMAP failed (%s), "
|
||||
"mFD=%d, sub.offset=%lu, sub.size=%lu",
|
||||
strerror(errno), our_fd, sub.offset, sub.len);
|
||||
return -errno;
|
||||
#else
|
||||
return NO_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
void MemoryHeapPmem::revoke()
|
||||
{
|
||||
SortedVector< wp<MemoryPmem> > allocations;
|
||||
|
||||
{ // scope for lock
|
||||
Mutex::Autolock _l(mLock);
|
||||
allocations = mAllocations;
|
||||
}
|
||||
|
||||
ssize_t count = allocations.size();
|
||||
for (ssize_t i=0 ; i<count ; i++) {
|
||||
sp<MemoryPmem> memory(allocations[i].promote());
|
||||
if (memory != 0)
|
||||
memory->revoke();
|
||||
}
|
||||
}
|
||||
|
||||
void MemoryHeapPmem::remove(const wp<MemoryPmem>& memory)
|
||||
{
|
||||
Mutex::Autolock _l(mLock);
|
||||
mAllocations.remove(memory);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
}; // namespace android
|
File diff suppressed because it is too large
Load Diff
|
@ -1,398 +0,0 @@
|
|||
/*
|
||||
* 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 "ProcessState"
|
||||
|
||||
#include <cutils/process_name.h>
|
||||
|
||||
#include <utils/ProcessState.h>
|
||||
|
||||
#include <utils/Atomic.h>
|
||||
#include <utils/BpBinder.h>
|
||||
#include <utils/IPCThreadState.h>
|
||||
#include <utils/Log.h>
|
||||
#include <utils/String8.h>
|
||||
#include <utils/IServiceManager.h>
|
||||
#include <utils/String8.h>
|
||||
#include <utils/threads.h>
|
||||
|
||||
#include <private/utils/binder_module.h>
|
||||
#include <private/utils/Static.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#define BINDER_VM_SIZE (1*1024*1024)
|
||||
|
||||
static bool gSingleProcess = false;
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
namespace android {
|
||||
|
||||
// Global variables
|
||||
int mArgC;
|
||||
const char* const* mArgV;
|
||||
int mArgLen;
|
||||
|
||||
class PoolThread : public Thread
|
||||
{
|
||||
public:
|
||||
PoolThread(bool isMain)
|
||||
: mIsMain(isMain)
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual bool threadLoop()
|
||||
{
|
||||
IPCThreadState::self()->joinThreadPool(mIsMain);
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool mIsMain;
|
||||
};
|
||||
|
||||
sp<ProcessState> ProcessState::self()
|
||||
{
|
||||
if (gProcess != NULL) return gProcess;
|
||||
|
||||
AutoMutex _l(gProcessMutex);
|
||||
if (gProcess == NULL) gProcess = new ProcessState;
|
||||
return gProcess;
|
||||
}
|
||||
|
||||
void ProcessState::setSingleProcess(bool singleProcess)
|
||||
{
|
||||
gSingleProcess = singleProcess;
|
||||
}
|
||||
|
||||
|
||||
void ProcessState::setContextObject(const sp<IBinder>& object)
|
||||
{
|
||||
setContextObject(object, String16("default"));
|
||||
}
|
||||
|
||||
sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& caller)
|
||||
{
|
||||
if (supportsProcesses()) {
|
||||
return getStrongProxyForHandle(0);
|
||||
} else {
|
||||
return getContextObject(String16("default"), caller);
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessState::setContextObject(const sp<IBinder>& object, const String16& name)
|
||||
{
|
||||
AutoMutex _l(mLock);
|
||||
mContexts.add(name, object);
|
||||
}
|
||||
|
||||
sp<IBinder> ProcessState::getContextObject(const String16& name, const sp<IBinder>& caller)
|
||||
{
|
||||
mLock.lock();
|
||||
sp<IBinder> object(
|
||||
mContexts.indexOfKey(name) >= 0 ? mContexts.valueFor(name) : NULL);
|
||||
mLock.unlock();
|
||||
|
||||
//printf("Getting context object %s for %p\n", String8(name).string(), caller.get());
|
||||
|
||||
if (object != NULL) return object;
|
||||
|
||||
// Don't attempt to retrieve contexts if we manage them
|
||||
if (mManagesContexts) {
|
||||
LOGE("getContextObject(%s) failed, but we manage the contexts!\n",
|
||||
String8(name).string());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
IPCThreadState* ipc = IPCThreadState::self();
|
||||
{
|
||||
Parcel data, reply;
|
||||
// no interface token on this magic transaction
|
||||
data.writeString16(name);
|
||||
data.writeStrongBinder(caller);
|
||||
status_t result = ipc->transact(0 /*magic*/, 0, data, &reply, 0);
|
||||
if (result == NO_ERROR) {
|
||||
object = reply.readStrongBinder();
|
||||
}
|
||||
}
|
||||
|
||||
ipc->flushCommands();
|
||||
|
||||
if (object != NULL) setContextObject(object, name);
|
||||
return object;
|
||||
}
|
||||
|
||||
bool ProcessState::supportsProcesses() const
|
||||
{
|
||||
return mDriverFD >= 0;
|
||||
}
|
||||
|
||||
void ProcessState::startThreadPool()
|
||||
{
|
||||
AutoMutex _l(mLock);
|
||||
if (!mThreadPoolStarted) {
|
||||
mThreadPoolStarted = true;
|
||||
spawnPooledThread(true);
|
||||
}
|
||||
}
|
||||
|
||||
bool ProcessState::isContextManager(void) const
|
||||
{
|
||||
return mManagesContexts;
|
||||
}
|
||||
|
||||
bool ProcessState::becomeContextManager(context_check_func checkFunc, void* userData)
|
||||
{
|
||||
if (!mManagesContexts) {
|
||||
AutoMutex _l(mLock);
|
||||
mBinderContextCheckFunc = checkFunc;
|
||||
mBinderContextUserData = userData;
|
||||
if (mDriverFD >= 0) {
|
||||
int dummy = 0;
|
||||
#if defined(HAVE_ANDROID_OS)
|
||||
status_t result = ioctl(mDriverFD, BINDER_SET_CONTEXT_MGR, &dummy);
|
||||
#else
|
||||
status_t result = INVALID_OPERATION;
|
||||
#endif
|
||||
if (result == 0) {
|
||||
mManagesContexts = true;
|
||||
} else if (result == -1) {
|
||||
mBinderContextCheckFunc = NULL;
|
||||
mBinderContextUserData = NULL;
|
||||
LOGE("Binder ioctl to become context manager failed: %s\n", strerror(errno));
|
||||
}
|
||||
} else {
|
||||
// If there is no driver, our only world is the local
|
||||
// process so we can always become the context manager there.
|
||||
mManagesContexts = true;
|
||||
}
|
||||
}
|
||||
return mManagesContexts;
|
||||
}
|
||||
|
||||
ProcessState::handle_entry* ProcessState::lookupHandleLocked(int32_t handle)
|
||||
{
|
||||
const size_t N=mHandleToObject.size();
|
||||
if (N <= (size_t)handle) {
|
||||
handle_entry e;
|
||||
e.binder = NULL;
|
||||
e.refs = NULL;
|
||||
status_t err = mHandleToObject.insertAt(e, N, handle+1-N);
|
||||
if (err < NO_ERROR) return NULL;
|
||||
}
|
||||
return &mHandleToObject.editItemAt(handle);
|
||||
}
|
||||
|
||||
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
|
||||
{
|
||||
sp<IBinder> result;
|
||||
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
handle_entry* e = lookupHandleLocked(handle);
|
||||
|
||||
if (e != NULL) {
|
||||
// We need to create a new BpBinder if there isn't currently one, OR we
|
||||
// are unable to acquire a weak reference on this current one. See comment
|
||||
// in getWeakProxyForHandle() for more info about this.
|
||||
IBinder* b = e->binder;
|
||||
if (b == NULL || !e->refs->attemptIncWeak(this)) {
|
||||
b = new BpBinder(handle);
|
||||
e->binder = b;
|
||||
if (b) e->refs = b->getWeakRefs();
|
||||
result = b;
|
||||
} else {
|
||||
// This little bit of nastyness is to allow us to add a primary
|
||||
// reference to the remote proxy when this team doesn't have one
|
||||
// but another team is sending the handle to us.
|
||||
result.force_set(b);
|
||||
e->refs->decWeak(this);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
wp<IBinder> ProcessState::getWeakProxyForHandle(int32_t handle)
|
||||
{
|
||||
wp<IBinder> result;
|
||||
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
handle_entry* e = lookupHandleLocked(handle);
|
||||
|
||||
if (e != NULL) {
|
||||
// We need to create a new BpBinder if there isn't currently one, OR we
|
||||
// are unable to acquire a weak reference on this current one. The
|
||||
// attemptIncWeak() is safe because we know the BpBinder destructor will always
|
||||
// call expungeHandle(), which acquires the same lock we are holding now.
|
||||
// We need to do this because there is a race condition between someone
|
||||
// releasing a reference on this BpBinder, and a new reference on its handle
|
||||
// arriving from the driver.
|
||||
IBinder* b = e->binder;
|
||||
if (b == NULL || !e->refs->attemptIncWeak(this)) {
|
||||
b = new BpBinder(handle);
|
||||
result = b;
|
||||
e->binder = b;
|
||||
if (b) e->refs = b->getWeakRefs();
|
||||
} else {
|
||||
result = b;
|
||||
e->refs->decWeak(this);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void ProcessState::expungeHandle(int32_t handle, IBinder* binder)
|
||||
{
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
handle_entry* e = lookupHandleLocked(handle);
|
||||
|
||||
// This handle may have already been replaced with a new BpBinder
|
||||
// (if someone failed the AttemptIncWeak() above); we don't want
|
||||
// to overwrite it.
|
||||
if (e && e->binder == binder) e->binder = NULL;
|
||||
}
|
||||
|
||||
void ProcessState::setArgs(int argc, const char* const argv[])
|
||||
{
|
||||
mArgC = argc;
|
||||
mArgV = (const char **)argv;
|
||||
|
||||
mArgLen = 0;
|
||||
for (int i=0; i<argc; i++) {
|
||||
mArgLen += strlen(argv[i]) + 1;
|
||||
}
|
||||
mArgLen--;
|
||||
}
|
||||
|
||||
int ProcessState::getArgC() const
|
||||
{
|
||||
return mArgC;
|
||||
}
|
||||
|
||||
const char* const* ProcessState::getArgV() const
|
||||
{
|
||||
return mArgV;
|
||||
}
|
||||
|
||||
void ProcessState::setArgV0(const char* txt)
|
||||
{
|
||||
if (mArgV != NULL) {
|
||||
strncpy((char*)mArgV[0], txt, mArgLen);
|
||||
set_process_name(txt);
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessState::spawnPooledThread(bool isMain)
|
||||
{
|
||||
if (mThreadPoolStarted) {
|
||||
int32_t s = android_atomic_add(1, &mThreadPoolSeq);
|
||||
char buf[32];
|
||||
sprintf(buf, "Binder Thread #%d", s);
|
||||
LOGV("Spawning new pooled thread, name=%s\n", buf);
|
||||
sp<Thread> t = new PoolThread(isMain);
|
||||
t->run(buf);
|
||||
}
|
||||
}
|
||||
|
||||
static int open_driver()
|
||||
{
|
||||
if (gSingleProcess) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int fd = open("/dev/binder", O_RDWR);
|
||||
if (fd >= 0) {
|
||||
fcntl(fd, F_SETFD, FD_CLOEXEC);
|
||||
int vers;
|
||||
#if defined(HAVE_ANDROID_OS)
|
||||
status_t result = ioctl(fd, BINDER_VERSION, &vers);
|
||||
#else
|
||||
status_t result = -1;
|
||||
errno = EPERM;
|
||||
#endif
|
||||
if (result == -1) {
|
||||
LOGE("Binder ioctl to obtain version failed: %s", strerror(errno));
|
||||
close(fd);
|
||||
fd = -1;
|
||||
}
|
||||
if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) {
|
||||
LOGE("Binder driver protocol does not match user space protocol!");
|
||||
close(fd);
|
||||
fd = -1;
|
||||
}
|
||||
#if defined(HAVE_ANDROID_OS)
|
||||
size_t maxThreads = 15;
|
||||
result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
|
||||
if (result == -1) {
|
||||
LOGE("Binder ioctl to set max threads failed: %s", strerror(errno));
|
||||
}
|
||||
#endif
|
||||
|
||||
} else {
|
||||
LOGW("Opening '/dev/binder' failed: %s\n", strerror(errno));
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
ProcessState::ProcessState()
|
||||
: mDriverFD(open_driver())
|
||||
, mVMStart(MAP_FAILED)
|
||||
, mManagesContexts(false)
|
||||
, mBinderContextCheckFunc(NULL)
|
||||
, mBinderContextUserData(NULL)
|
||||
, mThreadPoolStarted(false)
|
||||
, mThreadPoolSeq(1)
|
||||
{
|
||||
if (mDriverFD >= 0) {
|
||||
// XXX Ideally, there should be a specific define for whether we
|
||||
// have mmap (or whether we could possibly have the kernel module
|
||||
// availabla).
|
||||
#if !defined(HAVE_WIN32_IPC)
|
||||
// mmap the binder, providing a chunk of virtual address space to receive transactions.
|
||||
mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
|
||||
if (mVMStart == MAP_FAILED) {
|
||||
// *sigh*
|
||||
LOGE("Using /dev/binder failed: unable to mmap transaction memory.\n");
|
||||
close(mDriverFD);
|
||||
mDriverFD = -1;
|
||||
}
|
||||
#else
|
||||
mDriverFD = -1;
|
||||
#endif
|
||||
}
|
||||
if (mDriverFD < 0) {
|
||||
// Need to run without the driver, starting our own thread pool.
|
||||
}
|
||||
}
|
||||
|
||||
ProcessState::~ProcessState()
|
||||
{
|
||||
}
|
||||
|
||||
}; // namespace android
|
|
@ -20,7 +20,6 @@
|
|||
#include <private/utils/Static.h>
|
||||
|
||||
#include <utils/BufferedTextOutput.h>
|
||||
#include <utils/IPCThreadState.h>
|
||||
#include <utils/Log.h>
|
||||
|
||||
namespace android {
|
||||
|
@ -87,34 +86,4 @@ TextOutput& alog(gLogTextOutput);
|
|||
TextOutput& aout(gStdoutTextOutput);
|
||||
TextOutput& aerr(gStderrTextOutput);
|
||||
|
||||
#ifndef LIBUTILS_NATIVE
|
||||
|
||||
// ------------ ProcessState.cpp
|
||||
|
||||
Mutex gProcessMutex;
|
||||
sp<ProcessState> gProcess;
|
||||
|
||||
class LibUtilsIPCtStatics
|
||||
{
|
||||
public:
|
||||
LibUtilsIPCtStatics()
|
||||
{
|
||||
}
|
||||
|
||||
~LibUtilsIPCtStatics()
|
||||
{
|
||||
IPCThreadState::shutdown();
|
||||
}
|
||||
};
|
||||
|
||||
static LibUtilsIPCtStatics gIPCStatics;
|
||||
|
||||
// ------------ ServiceManager.cpp
|
||||
|
||||
Mutex gDefaultServiceManagerLock;
|
||||
sp<IServiceManager> gDefaultServiceManager;
|
||||
sp<IPermissionController> gPermissionController;
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace android
|
||||
|
|
Loading…
Reference in New Issue