diff --git a/include/binder/IPCThreadState.h b/include/binder/IPCThreadState.h index 60c224249..1853cff23 100644 --- a/include/binder/IPCThreadState.h +++ b/include/binder/IPCThreadState.h @@ -76,14 +76,18 @@ public: BpBinder* proxy); static void shutdown(); - + // Call this to disable switching threads to background scheduling when // receiving incoming IPC calls. This is specifically here for the // Android system process, since it expects to have background apps calling // in to it but doesn't want to acquire locks in its services while in // the background. static void disableBackgroundScheduling(bool disable); - + + // Call blocks until the number of executing binder threads is less than + // the maximum number of binder threads threads allowed for this process. + void blockUntilThreadAvailable(); + private: IPCThreadState(); ~IPCThreadState(); @@ -101,9 +105,9 @@ private: status_t getAndExecuteCommand(); status_t executeCommand(int32_t command); void processPendingDerefs(); - + void clearCaller(); - + static void threadDestructor(void *st); static void freeBuffer(Parcel* parcel, const uint8_t* data, size_t dataSize, @@ -114,7 +118,7 @@ private: const pid_t mMyThreadId; Vector mPendingStrongDerefs; Vector mPendingWeakDerefs; - + Parcel mIn; Parcel mOut; status_t mLastError; diff --git a/include/binder/ProcessState.h b/include/binder/ProcessState.h index 3bc978d9e..f9edc2a69 100644 --- a/include/binder/ProcessState.h +++ b/include/binder/ProcessState.h @@ -24,6 +24,8 @@ #include +#include + // --------------------------------------------------------------------------- namespace android { @@ -71,25 +73,33 @@ private: ProcessState(const ProcessState& o); ProcessState& operator=(const ProcessState& o); String8 makeBinderThreadName(); - + struct handle_entry { IBinder* binder; RefBase::weakref_type* refs; }; - + handle_entry* lookupHandleLocked(int32_t handle); int mDriverFD; void* mVMStart; - + + // Protects thread count variable below. + pthread_mutex_t mThreadCountLock; + pthread_cond_t mThreadCountDecrement; + // Number of binder threads current executing a command. + size_t mExecutingThreadsCount; + // Maximum number for binder threads allowed for this process. + size_t mMaxThreads; + mutable Mutex mLock; // protects everything below. - + VectormHandleToObject; bool mManagesContexts; context_check_func mBinderContextCheckFunc; void* mBinderContextUserData; - + KeyedVector > mContexts; diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp index 9f68aa8a0..2baf474f3 100644 --- a/libs/binder/IPCThreadState.cpp +++ b/libs/binder/IPCThreadState.cpp @@ -399,6 +399,17 @@ void IPCThreadState::flushCommands() talkWithDriver(false); } +void IPCThreadState::blockUntilThreadAvailable() +{ + pthread_mutex_lock(&mProcess->mThreadCountLock); + while (mProcess->mExecutingThreadsCount >= mProcess->mMaxThreads) { + ALOGW("Waiting for thread to be free. mExecutingThreadsCount=%i mMaxThreads=%i\n", + mProcess->mExecutingThreadsCount, mProcess->mMaxThreads); + pthread_cond_wait(&mProcess->mThreadCountDecrement, &mProcess->mThreadCountLock); + } + pthread_mutex_unlock(&mProcess->mThreadCountLock); +} + status_t IPCThreadState::getAndExecuteCommand() { status_t result; @@ -414,8 +425,17 @@ status_t IPCThreadState::getAndExecuteCommand() << getReturnString(cmd) << endl; } + pthread_mutex_lock(&mProcess->mThreadCountLock); + mProcess->mExecutingThreadsCount++; + pthread_mutex_unlock(&mProcess->mThreadCountLock); + result = executeCommand(cmd); + pthread_mutex_lock(&mProcess->mThreadCountLock); + mProcess->mExecutingThreadsCount--; + pthread_cond_broadcast(&mProcess->mThreadCountDecrement); + pthread_mutex_unlock(&mProcess->mThreadCountLock); + // After executing the command, ensure that the thread is returned to the // foreground cgroup before rejoining the pool. The driver takes care of // restoring the priority, but doesn't do anything with cgroups so we diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp index 303d6cf3a..016d3c54b 100644 --- a/libs/binder/ProcessState.cpp +++ b/libs/binder/ProcessState.cpp @@ -42,12 +42,13 @@ #include #define BINDER_VM_SIZE ((1*1024*1024) - (4096 *2)) +#define DEFAULT_MAX_BINDER_THREADS 15 // --------------------------------------------------------------------------- namespace android { - + class PoolThread : public Thread { public: @@ -294,7 +295,9 @@ void ProcessState::spawnPooledThread(bool isMain) status_t ProcessState::setThreadPoolMaxThreadCount(size_t maxThreads) { status_t result = NO_ERROR; - if (ioctl(mDriverFD, BINDER_SET_MAX_THREADS, &maxThreads) == -1) { + if (ioctl(mDriverFD, BINDER_SET_MAX_THREADS, &maxThreads) != -1) { + mMaxThreads = maxThreads; + } else { result = -errno; ALOGE("Binder ioctl to set max threads failed: %s", strerror(-result)); } @@ -322,7 +325,7 @@ static int open_driver() close(fd); fd = -1; } - size_t maxThreads = 15; + 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)); @@ -336,6 +339,10 @@ static int open_driver() ProcessState::ProcessState() : mDriverFD(open_driver()) , mVMStart(MAP_FAILED) + , mThreadCountLock(PTHREAD_MUTEX_INITIALIZER) + , mThreadCountDecrement(PTHREAD_COND_INITIALIZER) + , mExecutingThreadsCount(0) + , mMaxThreads(DEFAULT_MAX_BINDER_THREADS) , mManagesContexts(false) , mBinderContextCheckFunc(NULL) , mBinderContextUserData(NULL)