am 24eca800: Merge change I887f355f into eclair-mr2

Merge commit '24eca800d4b34e7d13fbcbc1ab74c9d91ff6a4e1' into eclair-mr2-plus-aosp

* commit '24eca800d4b34e7d13fbcbc1ab74c9d91ff6a4e1':
  Propagate background scheduling class across processes.
This commit is contained in:
Dianne Hackborn
2009-12-09 15:49:02 -08:00
committed by Android Git Automerger
9 changed files with 144 additions and 44 deletions

View File

@@ -76,6 +76,13 @@ public class BinderInternal {
*/
public static final native IBinder getContextObject();
/**
* Special for system process to not allow incoming calls to run at
* background scheduling priority.
* @hide
*/
public static final native void disableBackgroundScheduling(boolean disable);
static native final void handleGc();
public static void forceGc(String reason) {

View File

@@ -670,6 +670,12 @@ static void android_os_BinderInternal_joinThreadPool(JNIEnv* env, jobject clazz)
android::IPCThreadState::self()->joinThreadPool();
}
static void android_os_BinderInternal_disableBackgroundScheduling(JNIEnv* env,
jobject clazz, jboolean disable)
{
IPCThreadState::disableBackgroundScheduling(disable ? true : false);
}
static void android_os_BinderInternal_handleGc(JNIEnv* env, jobject clazz)
{
LOGV("Gc has executed, clearing binder ops");
@@ -682,6 +688,7 @@ static const JNINativeMethod gBinderInternalMethods[] = {
/* name, signature, funcPtr */
{ "getContextObject", "()Landroid/os/IBinder;", (void*)android_os_BinderInternal_getContextObject },
{ "joinThreadPool", "()V", (void*)android_os_BinderInternal_joinThreadPool },
{ "disableBackgroundScheduling", "(Z)V", (void*)android_os_BinderInternal_disableBackgroundScheduling },
{ "handleGc", "()V", (void*)android_os_BinderInternal_handleGc }
};

View File

@@ -120,11 +120,7 @@ jint android_os_Process_myUid(JNIEnv* env, jobject clazz)
jint android_os_Process_myTid(JNIEnv* env, jobject clazz)
{
#ifdef HAVE_GETTID
return gettid();
#else
return getpid();
#endif
return androidGetTid();
}
jint android_os_Process_getUidForName(JNIEnv* env, jobject clazz, jstring name)
@@ -191,15 +187,11 @@ jint android_os_Process_getGidForName(JNIEnv* env, jobject clazz, jstring name)
void android_os_Process_setThreadGroup(JNIEnv* env, jobject clazz, int pid, jint grp)
{
if (grp > ANDROID_TGROUP_MAX || grp < 0) {
signalExceptionForGroupError(env, clazz, EINVAL);
int res = androidSetThreadSchedulingGroup(pid, grp);
if (res != NO_ERROR) {
signalExceptionForGroupError(env, clazz, res == BAD_VALUE ? EINVAL : errno);
return;
}
if (set_sched_policy(pid, (grp == ANDROID_TGROUP_BG_NONINTERACT) ?
SP_BACKGROUND : SP_FOREGROUND)) {
signalExceptionForGroupError(env, clazz, errno);
}
}
void android_os_Process_setProcessGroup(JNIEnv* env, jobject clazz, int pid, jint grp)
@@ -275,22 +267,15 @@ void android_os_Process_setProcessGroup(JNIEnv* env, jobject clazz, int pid, jin
void android_os_Process_setThreadPriority(JNIEnv* env, jobject clazz,
jint pid, jint pri)
{
int rc = 0;
if (pri >= ANDROID_PRIORITY_BACKGROUND) {
rc = set_sched_policy(pid, SP_BACKGROUND);
} else if (getpriority(PRIO_PROCESS, pid) >= ANDROID_PRIORITY_BACKGROUND) {
rc = set_sched_policy(pid, SP_FOREGROUND);
}
if (rc) {
signalExceptionForGroupError(env, clazz, errno);
return;
}
if (setpriority(PRIO_PROCESS, pid, pri) < 0) {
signalExceptionForPriorityError(env, clazz, errno);
int rc = androidSetThreadPriority(pid, pri);
if (rc != 0) {
if (rc == INVALID_OPERATION) {
signalExceptionForPriorityError(env, clazz, errno);
} else {
signalExceptionForGroupError(env, clazz, errno);
}
}
//LOGI("Setting priority of %d: %d, getpriority returns %d\n",
// pid, pri, getpriority(PRIO_PROCESS, pid));
}

View File

@@ -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
};

View File

@@ -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;

View File

@@ -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

View File

@@ -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 "

View File

@@ -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 {
/*

View File

@@ -18,6 +18,7 @@ package com.android.server;
import com.android.server.am.ActivityManagerService;
import com.android.server.status.StatusBarService;
import com.android.internal.os.BinderInternal;
import com.android.internal.os.SamplingProfilerIntegration;
import dalvik.system.VMRuntime;
@@ -80,6 +81,8 @@ class ServerThread extends Thread {
android.os.Process.setThreadPriority(
android.os.Process.THREAD_PRIORITY_FOREGROUND);
BinderInternal.disableBackgroundScheduling(true);
String factoryTestStr = SystemProperties.get("ro.factorytest");
int factoryTest = "".equals(factoryTestStr) ? SystemServer.FACTORY_TEST_OFF
: Integer.parseInt(factoryTestStr);