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
diff --git a/include/binder/IPCThreadState.h b/include/binder/IPCThreadState.h
index 60c2242..1853cff 100644
--- a/include/binder/IPCThreadState.h
+++ b/include/binder/IPCThreadState.h
@@ -76,14 +76,18 @@
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 @@
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 @@
const pid_t mMyThreadId;
Vector<BBinder*> mPendingStrongDerefs;
Vector<RefBase::weakref_type*> mPendingWeakDerefs;
-
+
Parcel mIn;
Parcel mOut;
status_t mLastError;
diff --git a/include/binder/ProcessState.h b/include/binder/ProcessState.h
index 3bc978d..f9edc2a 100644
--- a/include/binder/ProcessState.h
+++ b/include/binder/ProcessState.h
@@ -24,6 +24,8 @@
#include <utils/threads.h>
+#include <pthread.h>
+
// ---------------------------------------------------------------------------
namespace android {
@@ -71,25 +73,33 @@
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.
-
+
Vector<handle_entry>mHandleToObject;
bool mManagesContexts;
context_check_func mBinderContextCheckFunc;
void* mBinderContextUserData;
-
+
KeyedVector<String16, sp<IBinder> >
mContexts;
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index 9f68aa8..2baf474 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -399,6 +399,17 @@
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 @@
<< 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 303d6cf..016d3c5 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -42,12 +42,13 @@
#include <sys/stat.h>
#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 @@
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 @@
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 @@
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)