diff options
-rw-r--r-- | core/java/com/android/internal/os/BinderInternal.java | 7 | ||||
-rw-r--r-- | core/jni/android_util_Binder.cpp | 7 | ||||
-rw-r--r-- | core/jni/android_util_Process.cpp | 39 | ||||
-rw-r--r-- | include/binder/IBinder.h | 2 | ||||
-rw-r--r-- | include/binder/IPCThreadState.h | 10 | ||||
-rw-r--r-- | include/utils/threads.h | 18 | ||||
-rw-r--r-- | libs/binder/IPCThreadState.cpp | 53 | ||||
-rw-r--r-- | libs/utils/Threads.cpp | 49 | ||||
-rw-r--r-- | services/java/com/android/server/SystemServer.java | 3 |
9 files changed, 144 insertions, 44 deletions
diff --git a/core/java/com/android/internal/os/BinderInternal.java b/core/java/com/android/internal/os/BinderInternal.java index eacf0ce..ba0bf0d 100644 --- a/core/java/com/android/internal/os/BinderInternal.java +++ b/core/java/com/android/internal/os/BinderInternal.java @@ -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) { diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp index f0885fd..627fcbf 100644 --- a/core/jni/android_util_Binder.cpp +++ b/core/jni/android_util_Binder.cpp @@ -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 } }; diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp index 094b02d..e84f2e5 100644 --- a/core/jni/android_util_Process.cpp +++ b/core/jni/android_util_Process.cpp @@ -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)); } 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 { /* diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 73f930d..214ecc1 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -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); |