1b80f793d2
Change-Id: I70f02908d8362a465eb8a2a24356f6989847f7ba
370 lines
10 KiB
C++
370 lines
10 KiB
C++
/*
|
|
* Copyright (C) 2005 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#define LOG_TAG "ProcessState"
|
|
|
|
#include <cutils/process_name.h>
|
|
|
|
#include <binder/ProcessState.h>
|
|
|
|
#include <utils/Atomic.h>
|
|
#include <binder/BpBinder.h>
|
|
#include <binder/IPCThreadState.h>
|
|
#include <utils/Log.h>
|
|
#include <utils/String8.h>
|
|
#include <binder/IServiceManager.h>
|
|
#include <utils/String8.h>
|
|
#include <utils/threads.h>
|
|
|
|
#include <private/binder/binder_module.h>
|
|
#include <private/binder/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) - (4096 *2))
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
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()
|
|
{
|
|
Mutex::Autolock _l(gProcessMutex);
|
|
if (gProcess != NULL) {
|
|
return gProcess;
|
|
}
|
|
gProcess = new ProcessState;
|
|
return gProcess;
|
|
}
|
|
|
|
void ProcessState::setContextObject(const sp<IBinder>& object)
|
|
{
|
|
setContextObject(object, String16("default"));
|
|
}
|
|
|
|
sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& caller)
|
|
{
|
|
return getStrongProxyForHandle(0);
|
|
}
|
|
|
|
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) {
|
|
ALOGE("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;
|
|
}
|
|
|
|
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;
|
|
|
|
int dummy = 0;
|
|
status_t result = ioctl(mDriverFD, BINDER_SET_CONTEXT_MGR, &dummy);
|
|
if (result == 0) {
|
|
mManagesContexts = true;
|
|
} else if (result == -1) {
|
|
mBinderContextCheckFunc = NULL;
|
|
mBinderContextUserData = NULL;
|
|
ALOGE("Binder ioctl to become context manager failed: %s\n", strerror(errno));
|
|
}
|
|
}
|
|
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[16];
|
|
snprintf(buf, sizeof(buf), "Binder_%X", s);
|
|
ALOGV("Spawning new pooled thread, name=%s\n", buf);
|
|
sp<Thread> t = new PoolThread(isMain);
|
|
t->run(buf);
|
|
}
|
|
}
|
|
|
|
status_t ProcessState::setThreadPoolMaxThreadCount(size_t maxThreads) {
|
|
status_t result = NO_ERROR;
|
|
if (ioctl(mDriverFD, BINDER_SET_MAX_THREADS, &maxThreads) == -1) {
|
|
result = -errno;
|
|
ALOGE("Binder ioctl to set max threads failed: %s", strerror(-result));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
static int open_driver()
|
|
{
|
|
int fd = open("/dev/binder", O_RDWR);
|
|
if (fd >= 0) {
|
|
fcntl(fd, F_SETFD, FD_CLOEXEC);
|
|
int vers;
|
|
status_t result = ioctl(fd, BINDER_VERSION, &vers);
|
|
if (result == -1) {
|
|
ALOGE("Binder ioctl to obtain version failed: %s", strerror(errno));
|
|
close(fd);
|
|
fd = -1;
|
|
}
|
|
if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) {
|
|
ALOGE("Binder driver protocol does not match user space protocol!");
|
|
close(fd);
|
|
fd = -1;
|
|
}
|
|
size_t maxThreads = 15;
|
|
result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
|
|
if (result == -1) {
|
|
ALOGE("Binder ioctl to set max threads failed: %s", strerror(errno));
|
|
}
|
|
} else {
|
|
ALOGW("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*
|
|
ALOGE("Using /dev/binder failed: unable to mmap transaction memory.\n");
|
|
close(mDriverFD);
|
|
mDriverFD = -1;
|
|
}
|
|
#else
|
|
mDriverFD = -1;
|
|
#endif
|
|
}
|
|
|
|
LOG_ALWAYS_FATAL_IF(mDriverFD < 0, "Binder driver could not be opened. Terminating.");
|
|
}
|
|
|
|
ProcessState::~ProcessState()
|
|
{
|
|
}
|
|
|
|
}; // namespace android
|