Added IPCThreadState::blockUntilThreadAvailable() method.

Will be used by the system_server watchdog to monitor the
availability of binder threads in the process to handle
incoming IPC requests.

Bug: 19297165
Change-Id: I39175f3869ad14da5620fddb47f454e6e4ee2b25
This commit is contained in:
Wale Ogunwale 2015-04-13 16:16:10 -07:00
parent e88e366963
commit 376b822728
4 changed files with 54 additions and 13 deletions

View File

@ -76,14 +76,18 @@ public:
BpBinder* proxy); BpBinder* proxy);
static void shutdown(); static void shutdown();
// Call this to disable switching threads to background scheduling when // Call this to disable switching threads to background scheduling when
// receiving incoming IPC calls. This is specifically here for the // receiving incoming IPC calls. This is specifically here for the
// Android system process, since it expects to have background apps calling // 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 // in to it but doesn't want to acquire locks in its services while in
// the background. // the background.
static void disableBackgroundScheduling(bool disable); 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: private:
IPCThreadState(); IPCThreadState();
~IPCThreadState(); ~IPCThreadState();
@ -101,9 +105,9 @@ private:
status_t getAndExecuteCommand(); status_t getAndExecuteCommand();
status_t executeCommand(int32_t command); status_t executeCommand(int32_t command);
void processPendingDerefs(); void processPendingDerefs();
void clearCaller(); void clearCaller();
static void threadDestructor(void *st); static void threadDestructor(void *st);
static void freeBuffer(Parcel* parcel, static void freeBuffer(Parcel* parcel,
const uint8_t* data, size_t dataSize, const uint8_t* data, size_t dataSize,
@ -114,7 +118,7 @@ private:
const pid_t mMyThreadId; const pid_t mMyThreadId;
Vector<BBinder*> mPendingStrongDerefs; Vector<BBinder*> mPendingStrongDerefs;
Vector<RefBase::weakref_type*> mPendingWeakDerefs; Vector<RefBase::weakref_type*> mPendingWeakDerefs;
Parcel mIn; Parcel mIn;
Parcel mOut; Parcel mOut;
status_t mLastError; status_t mLastError;

View File

@ -24,6 +24,8 @@
#include <utils/threads.h> #include <utils/threads.h>
#include <pthread.h>
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
namespace android { namespace android {
@ -71,25 +73,33 @@ private:
ProcessState(const ProcessState& o); ProcessState(const ProcessState& o);
ProcessState& operator=(const ProcessState& o); ProcessState& operator=(const ProcessState& o);
String8 makeBinderThreadName(); String8 makeBinderThreadName();
struct handle_entry { struct handle_entry {
IBinder* binder; IBinder* binder;
RefBase::weakref_type* refs; RefBase::weakref_type* refs;
}; };
handle_entry* lookupHandleLocked(int32_t handle); handle_entry* lookupHandleLocked(int32_t handle);
int mDriverFD; int mDriverFD;
void* mVMStart; 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. mutable Mutex mLock; // protects everything below.
Vector<handle_entry>mHandleToObject; Vector<handle_entry>mHandleToObject;
bool mManagesContexts; bool mManagesContexts;
context_check_func mBinderContextCheckFunc; context_check_func mBinderContextCheckFunc;
void* mBinderContextUserData; void* mBinderContextUserData;
KeyedVector<String16, sp<IBinder> > KeyedVector<String16, sp<IBinder> >
mContexts; mContexts;

View File

@ -399,6 +399,17 @@ void IPCThreadState::flushCommands()
talkWithDriver(false); 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 IPCThreadState::getAndExecuteCommand()
{ {
status_t result; status_t result;
@ -414,8 +425,17 @@ status_t IPCThreadState::getAndExecuteCommand()
<< getReturnString(cmd) << endl; << getReturnString(cmd) << endl;
} }
pthread_mutex_lock(&mProcess->mThreadCountLock);
mProcess->mExecutingThreadsCount++;
pthread_mutex_unlock(&mProcess->mThreadCountLock);
result = executeCommand(cmd); 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 // After executing the command, ensure that the thread is returned to the
// foreground cgroup before rejoining the pool. The driver takes care of // foreground cgroup before rejoining the pool. The driver takes care of
// restoring the priority, but doesn't do anything with cgroups so we // restoring the priority, but doesn't do anything with cgroups so we

View File

@ -42,12 +42,13 @@
#include <sys/stat.h> #include <sys/stat.h>
#define BINDER_VM_SIZE ((1*1024*1024) - (4096 *2)) #define BINDER_VM_SIZE ((1*1024*1024) - (4096 *2))
#define DEFAULT_MAX_BINDER_THREADS 15
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
namespace android { namespace android {
class PoolThread : public Thread class PoolThread : public Thread
{ {
public: public:
@ -294,7 +295,9 @@ void ProcessState::spawnPooledThread(bool isMain)
status_t ProcessState::setThreadPoolMaxThreadCount(size_t maxThreads) { status_t ProcessState::setThreadPoolMaxThreadCount(size_t maxThreads) {
status_t result = NO_ERROR; 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; result = -errno;
ALOGE("Binder ioctl to set max threads failed: %s", strerror(-result)); ALOGE("Binder ioctl to set max threads failed: %s", strerror(-result));
} }
@ -322,7 +325,7 @@ static int open_driver()
close(fd); close(fd);
fd = -1; fd = -1;
} }
size_t maxThreads = 15; size_t maxThreads = DEFAULT_MAX_BINDER_THREADS;
result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads); result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
if (result == -1) { if (result == -1) {
ALOGE("Binder ioctl to set max threads failed: %s", strerror(errno)); ALOGE("Binder ioctl to set max threads failed: %s", strerror(errno));
@ -336,6 +339,10 @@ static int open_driver()
ProcessState::ProcessState() ProcessState::ProcessState()
: mDriverFD(open_driver()) : mDriverFD(open_driver())
, mVMStart(MAP_FAILED) , mVMStart(MAP_FAILED)
, mThreadCountLock(PTHREAD_MUTEX_INITIALIZER)
, mThreadCountDecrement(PTHREAD_COND_INITIALIZER)
, mExecutingThreadsCount(0)
, mMaxThreads(DEFAULT_MAX_BINDER_THREADS)
, mManagesContexts(false) , mManagesContexts(false)
, mBinderContextCheckFunc(NULL) , mBinderContextCheckFunc(NULL)
, mBinderContextUserData(NULL) , mBinderContextUserData(NULL)