summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/binder/IBinder.h2
-rw-r--r--include/binder/IPCThreadState.h10
-rw-r--r--include/utils/threads.h18
-rw-r--r--libs/binder/IPCThreadState.cpp53
-rw-r--r--libs/utils/Threads.cpp49
5 files changed, 115 insertions, 17 deletions
diff --git a/include/binder/IBinder.h b/include/binder/IBinder.h
index 884b5c1..749a977 100644
--- a/include/binder/IBinder.h
+++ b/include/binder/IBinder.h
@@ -52,7 +52,7 @@ public:
DUMP_TRANSACTION = B_PACK_CHARS('_','D','M','P'),
INTERFACE_TRANSACTION = B_PACK_CHARS('_', 'N', 'T', 'F'),
- // Corresponds to tfOneWay -- an asynchronous call.
+ // Corresponds to TF_ONE_WAY -- an asynchronous call.
FLAG_ONEWAY = 0x00000001
};
diff --git a/include/binder/IPCThreadState.h b/include/binder/IPCThreadState.h
index 78306b2..3ab985d 100644
--- a/include/binder/IPCThreadState.h
+++ b/include/binder/IPCThreadState.h
@@ -68,6 +68,13 @@ public:
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);
+
private:
IPCThreadState();
~IPCThreadState();
@@ -93,9 +100,10 @@ private:
void* cookie);
const sp<ProcessState> mProcess;
+ const pid_t mMyThreadId;
Vector<BBinder*> mPendingStrongDerefs;
Vector<RefBase::weakref_type*> mPendingWeakDerefs;
-
+
Parcel mIn;
Parcel mOut;
status_t mLastError;
diff --git a/include/utils/threads.h b/include/utils/threads.h
index 0fc533f..130d83c 100644
--- a/include/utils/threads.h
+++ b/include/utils/threads.h
@@ -124,6 +124,24 @@ typedef int (*android_create_thread_fn)(android_thread_func_t entryFunction,
extern void androidSetCreateThreadFunc(android_create_thread_fn func);
+// ------------------------------------------------------------------
+// Extra functions working with raw pids.
+
+// Get pid for the current thread.
+extern pid_t androidGetTid();
+
+// Change the scheduling group of a particular thread. The group
+// should be one of the ANDROID_TGROUP constants. Returns BAD_VALUE if
+// grp is out of range, else another non-zero value with errno set if
+// the operation failed.
+extern int androidSetThreadSchedulingGroup(pid_t tid, int grp);
+
+// Change the priority AND scheduling group of a particular thread. The priority
+// should be one of the ANDROID_PRIORITY constants. Returns INVALID_OPERATION
+// if the priority set failed, else another value if just the group set failed;
+// in either case errno is set.
+extern int androidSetThreadPriority(pid_t tid, int prio);
+
#ifdef __cplusplus
}
#endif
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index b2a7db8..473f580 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -292,6 +292,7 @@ static pthread_mutex_t gTLSMutex = PTHREAD_MUTEX_INITIALIZER;
static bool gHaveTLS = false;
static pthread_key_t gTLS = 0;
static bool gShutdown = false;
+static bool gDisableBackgroundScheduling = false;
IPCThreadState* IPCThreadState::self()
{
@@ -332,6 +333,11 @@ void IPCThreadState::shutdown()
}
}
+void IPCThreadState::disableBackgroundScheduling(bool disable)
+{
+ gDisableBackgroundScheduling = disable;
+}
+
sp<ProcessState> IPCThreadState::process()
{
return mProcess;
@@ -386,6 +392,11 @@ void IPCThreadState::joinThreadPool(bool isMain)
mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
+ // This thread may have been spawned by a thread that was in the background
+ // scheduling group, so first we will make sure it is in the default/foreground
+ // one to avoid performing an initial transaction in the background.
+ androidSetThreadSchedulingGroup(mMyThreadId, ANDROID_TGROUP_DEFAULT);
+
status_t result;
do {
int32_t cmd;
@@ -427,19 +438,13 @@ void IPCThreadState::joinThreadPool(bool isMain)
}
// After executing the command, ensure that the thread is returned to the
- // default cgroup and priority before rejoining the pool. This is a failsafe
- // in case the command implementation failed to properly restore the thread's
- // scheduling parameters upon completion.
- int my_id;
-#ifdef HAVE_GETTID
- my_id = gettid();
-#else
- my_id = getpid();
-#endif
- if (!set_sched_policy(my_id, SP_FOREGROUND)) {
- // success; reset the priority as well
- setpriority(PRIO_PROCESS, my_id, ANDROID_PRIORITY_NORMAL);
- }
+ // default cgroup before rejoining the pool. The driver takes care of
+ // restoring the priority, but doesn't do anything with cgroups so we
+ // need to take care of that here in userspace. Note that we do make
+ // sure to go in the foreground after executing a transaction, but
+ // there are other callbacks into user code that could have changed
+ // our group so we want to make absolutely sure it is put back.
+ androidSetThreadSchedulingGroup(mMyThreadId, ANDROID_TGROUP_DEFAULT);
// Let this thread exit the thread pool if it is no longer
// needed and it is not the main process thread.
@@ -583,10 +588,10 @@ status_t IPCThreadState::clearDeathNotification(int32_t handle, BpBinder* proxy)
}
IPCThreadState::IPCThreadState()
- : mProcess(ProcessState::self())
+ : mProcess(ProcessState::self()), mMyThreadId(androidGetTid())
{
pthread_setspecific(gTLS, this);
- clearCaller();
+ clearCaller();
mIn.setDataCapacity(256);
mOut.setDataCapacity(256);
}
@@ -930,6 +935,17 @@ status_t IPCThreadState::executeCommand(int32_t cmd)
mCallingPid = tr.sender_pid;
mCallingUid = tr.sender_euid;
+ bool doBackground = !gDisableBackgroundScheduling &&
+ getpriority(PRIO_PROCESS, mMyThreadId)
+ >= ANDROID_PRIORITY_BACKGROUND;
+ if (doBackground) {
+ // We have inherited a background priority from the caller.
+ // Ensure this thread is in the background scheduling class,
+ // since the driver won't modify scheduling classes for us.
+ androidSetThreadSchedulingGroup(mMyThreadId,
+ ANDROID_TGROUP_BG_NONINTERACT);
+ }
+
//LOGI(">>>> TRANSACT from pid %d uid %d\n", mCallingPid, mCallingUid);
Parcel reply;
@@ -967,6 +983,13 @@ status_t IPCThreadState::executeCommand(int32_t cmd)
mCallingPid = origPid;
mCallingUid = origUid;
+ if (doBackground) {
+ // We moved to the background scheduling group to execute
+ // this transaction, so now that we are done go back in the
+ // foreground.
+ androidSetThreadSchedulingGroup(mMyThreadId, ANDROID_TGROUP_DEFAULT);
+ }
+
IF_LOG_TRANSACTIONS() {
TextOutput::Bundle _b(alog);
alog << "BC_REPLY thr " << (void*)pthread_self() << " / obj "
diff --git a/libs/utils/Threads.cpp b/libs/utils/Threads.cpp
index ec3db09..6ca2603 100644
--- a/libs/utils/Threads.cpp
+++ b/libs/utils/Threads.cpp
@@ -20,6 +20,8 @@
#include <utils/threads.h>
#include <utils/Log.h>
+#include <cutils/sched_policy.h>
+
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
@@ -269,6 +271,53 @@ void androidSetCreateThreadFunc(android_create_thread_fn func)
gCreateThreadFn = func;
}
+pid_t androidGetTid()
+{
+#ifdef HAVE_GETTID
+ return gettid();
+#else
+ return getpid();
+#endif
+}
+
+int androidSetThreadSchedulingGroup(pid_t tid, int grp)
+{
+ if (grp > ANDROID_TGROUP_MAX || grp < 0) {
+ return BAD_VALUE;
+ }
+
+ if (set_sched_policy(tid, (grp == ANDROID_TGROUP_BG_NONINTERACT) ?
+ SP_BACKGROUND : SP_FOREGROUND)) {
+ return PERMISSION_DENIED;
+ }
+
+ return NO_ERROR;
+}
+
+int androidSetThreadPriority(pid_t tid, int pri)
+{
+ int rc = 0;
+ int lasterr = 0;
+
+ if (pri >= ANDROID_PRIORITY_BACKGROUND) {
+ rc = set_sched_policy(tid, SP_BACKGROUND);
+ } else if (getpriority(PRIO_PROCESS, tid) >= ANDROID_PRIORITY_BACKGROUND) {
+ rc = set_sched_policy(tid, SP_FOREGROUND);
+ }
+
+ if (rc) {
+ lasterr = errno;
+ }
+
+ if (setpriority(PRIO_PROCESS, tid, pri) < 0) {
+ rc = INVALID_OPERATION;
+ } else {
+ errno = lasterr;
+ }
+
+ return rc;
+}
+
namespace android {
/*