Propagate background scheduling class across processes.
This is a very simply implementation: upon receiving an IPC, if the handling thread is at a background priority (the driver will have taken care of propagating this from the calling thread), then stick it in to the background scheduling group. Plus an API to turn this off for the process, which is used by the system process. This also pulls some of the code for managing scheduling classes out of the Process JNI wrappers and in to some convenience methods in thread.h.
This commit is contained in:
parent
d56352bddd
commit
8c6cedc9bc
@ -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
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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 "
|
||||
|
@ -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 {
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user