You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
397 lines
12 KiB
397 lines
12 KiB
/* |
|
* Copyright (C) 2005 The Android Open Source Project |
|
* |
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
* you may not use this file except in compliance with the License. |
|
* You may obtain a copy of the License at |
|
* |
|
* http://www.apache.org/licenses/LICENSE-2.0 |
|
* |
|
* Unless required by applicable law or agreed to in writing, software |
|
* distributed under the License is distributed on an "AS IS" BASIS, |
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
* See the License for the specific language governing permissions and |
|
* limitations under the License. |
|
*/ |
|
|
|
#define LOG_TAG "hw-ProcessState" |
|
|
|
#include <hwbinder/ProcessState.h> |
|
|
|
#include <hwbinder/BpHwBinder.h> |
|
#include <hwbinder/IPCThreadState.h> |
|
#include <hwbinder/binder_kernel.h> |
|
#include <utils/Atomic.h> |
|
#include <utils/Log.h> |
|
#include <utils/String8.h> |
|
#include <utils/threads.h> |
|
|
|
#include <private/binder/binder_module.h> |
|
#include <hwbinder/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> |
|
#include <sys/types.h> |
|
|
|
#define BINDER_VM_SIZE ((1 * 1024 * 1024) - sysconf(_SC_PAGE_SIZE) * 2) |
|
#define DEFAULT_MAX_BINDER_THREADS 0 |
|
|
|
// ------------------------------------------------------------------------- |
|
|
|
namespace android { |
|
namespace hardware { |
|
|
|
class PoolThread : public Thread |
|
{ |
|
public: |
|
explicit 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; |
|
} |
|
|
|
sp<ProcessState> ProcessState::selfOrNull() { |
|
Mutex::Autolock _l(gProcessMutex); |
|
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; |
|
if (mSpawnThreadOnStart) { |
|
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; |
|
} |
|
|
|
// Get references to userspace objects held by the kernel binder driver |
|
// Writes up to count elements into buf, and returns the total number |
|
// of references the kernel has, which may be larger than count. |
|
// buf may be NULL if count is 0. The pointers returned by this method |
|
// should only be used for debugging and not dereferenced, they may |
|
// already be invalid. |
|
ssize_t ProcessState::getKernelReferences(size_t buf_count, uintptr_t* buf) { |
|
binder_node_debug_info info = {}; |
|
|
|
uintptr_t* end = buf ? buf + buf_count : NULL; |
|
size_t count = 0; |
|
|
|
do { |
|
status_t result = ioctl(mDriverFD, BINDER_GET_NODE_DEBUG_INFO, &info); |
|
if (result < 0) { |
|
return -1; |
|
} |
|
if (info.ptr != 0) { |
|
if (buf && buf < end) *buf++ = info.ptr; |
|
count++; |
|
if (buf && buf < end) *buf++ = info.cookie; |
|
count++; |
|
} |
|
} while (info.ptr != 0); |
|
|
|
return count; |
|
} |
|
|
|
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 BpHwBinder 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 BpHwBinder(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 BpHwBinder 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 BpHwBinder 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 BpHwBinder, and a new reference on its handle |
|
// arriving from the driver. |
|
IBinder* b = e->binder; |
|
if (b == NULL || !e->refs->attemptIncWeak(this)) { |
|
b = new BpHwBinder(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 BpHwBinder |
|
// (if someone failed the AttemptIncWeak() above); we don't want |
|
// to overwrite it. |
|
if (e && e->binder == binder) e->binder = NULL; |
|
} |
|
|
|
String8 ProcessState::makeBinderThreadName() { |
|
int32_t s = android_atomic_add(1, &mThreadPoolSeq); |
|
pid_t pid = getpid(); |
|
String8 name; |
|
name.appendFormat("HwBinder:%d_%X", pid, s); |
|
return name; |
|
} |
|
|
|
void ProcessState::spawnPooledThread(bool isMain) |
|
{ |
|
if (mThreadPoolStarted) { |
|
String8 name = makeBinderThreadName(); |
|
ALOGV("Spawning new pooled thread, name=%s\n", name.string()); |
|
sp<Thread> t = new PoolThread(isMain); |
|
t->run(name.string()); |
|
} |
|
} |
|
|
|
status_t ProcessState::setThreadPoolConfiguration(size_t maxThreads, bool callerJoinsPool) { |
|
LOG_ALWAYS_FATAL_IF(maxThreads < 1, "Binder threadpool must have a minimum of one thread."); |
|
status_t result = NO_ERROR; |
|
// the BINDER_SET_MAX_THREADS ioctl really tells the kernel how many threads |
|
// it's allowed to spawn, *in addition* to any threads we may have already |
|
// spawned locally. If 'callerJoinsPool' is true, it means that the caller |
|
// will join the threadpool, and so the kernel needs to create one less thread. |
|
// If 'callerJoinsPool' is false, we will still spawn a thread locally, and we should |
|
// also tell the kernel to create one less thread than what was requested here. |
|
size_t kernelMaxThreads = maxThreads - 1; |
|
if (ioctl(mDriverFD, BINDER_SET_MAX_THREADS, &kernelMaxThreads) != -1) { |
|
AutoMutex _l(mLock); |
|
mMaxThreads = maxThreads; |
|
mSpawnThreadOnStart = !callerJoinsPool; |
|
} else { |
|
result = -errno; |
|
ALOGE("Binder ioctl to set max threads failed: %s", strerror(-result)); |
|
} |
|
return result; |
|
} |
|
|
|
void ProcessState::giveThreadPoolName() { |
|
androidSetThreadName( makeBinderThreadName().string() ); |
|
} |
|
|
|
static int open_driver() |
|
{ |
|
int fd = open("/dev/hwbinder", O_RDWR | O_CLOEXEC); |
|
if (fd >= 0) { |
|
int vers = 0; |
|
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(%d) does not match user space protocol(%d)!", vers, BINDER_CURRENT_PROTOCOL_VERSION); |
|
close(fd); |
|
fd = -1; |
|
} |
|
size_t maxThreads = DEFAULT_MAX_BINDER_THREADS; |
|
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/hwbinder' failed: %s\n", strerror(errno)); |
|
} |
|
return fd; |
|
} |
|
|
|
ProcessState::ProcessState() |
|
: mDriverFD(open_driver()) |
|
, mVMStart(MAP_FAILED) |
|
, mThreadCountLock(PTHREAD_MUTEX_INITIALIZER) |
|
, mThreadCountDecrement(PTHREAD_COND_INITIALIZER) |
|
, mExecutingThreadsCount(0) |
|
, mMaxThreads(DEFAULT_MAX_BINDER_THREADS) |
|
, mStarvationStartTimeMs(0) |
|
, mManagesContexts(false) |
|
, mBinderContextCheckFunc(NULL) |
|
, mBinderContextUserData(NULL) |
|
, mThreadPoolStarted(false) |
|
, mSpawnThreadOnStart(true) |
|
, mThreadPoolSeq(1) |
|
{ |
|
if (mDriverFD >= 0) { |
|
// 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/hwbinder failed: unable to mmap transaction memory.\n"); |
|
close(mDriverFD); |
|
mDriverFD = -1; |
|
} |
|
} |
|
else { |
|
ALOGE("Binder driver could not be opened. Terminating."); |
|
} |
|
} |
|
|
|
ProcessState::~ProcessState() |
|
{ |
|
if (mDriverFD >= 0) { |
|
if (mVMStart != MAP_FAILED) { |
|
munmap(mVMStart, BINDER_VM_SIZE); |
|
} |
|
close(mDriverFD); |
|
} |
|
mDriverFD = -1; |
|
} |
|
|
|
}; // namespace hardware |
|
}; // namespace android
|
|
|