diff options
-rw-r--r-- | core/java/android/os/Process.java | 35 | ||||
-rw-r--r-- | core/jni/android_util_Process.cpp | 79 | ||||
-rw-r--r-- | include/utils/threads.h | 7 |
3 files changed, 121 insertions, 0 deletions
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java index e4412a3..30acef9 100644 --- a/core/java/android/os/Process.java +++ b/core/java/android/os/Process.java @@ -176,6 +176,26 @@ public class Process { */ public static final int THREAD_PRIORITY_LESS_FAVORABLE = +1; + /** + * Default thread group - gets a 'normal' share of the CPU + * @hide + */ + public static final int THREAD_GROUP_DEFAULT = 0; + + /** + * Background non-interactive thread group - All threads in + * this group are scheduled with a reduced share of the CPU. + * @hide + */ + public static final int THREAD_GROUP_BG_NONINTERACTIVE = 1; + + /** + * Foreground 'boost' thread group - All threads in + * this group are scheduled with an increased share of the CPU + * @hide + **/ + public static final int THREAD_GROUP_FG_BOOST = 2; + public static final int SIGNAL_QUIT = 3; public static final int SIGNAL_KILL = 9; public static final int SIGNAL_USR1 = 10; @@ -569,6 +589,21 @@ public class Process { */ public static final native void setThreadPriority(int tid, int priority) throws IllegalArgumentException, SecurityException; + + /** + * Sets the scheduling group for a thread. + * @hide + * @param tid The indentifier of the thread/process to change. + * @param group The target group for this thread/process. + * + * @throws IllegalArgumentException Throws IllegalArgumentException if + * <var>tid</var> does not exist. + * @throws SecurityException Throws SecurityException if your process does + * not have permission to modify the given thread, or to use the given + * priority. + */ + public static final native void setThreadGroup(int tid, int group) + throws IllegalArgumentException, SecurityException; /** * Set the priority of the calling thread, based on Linux priorities. See diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp index bd56605..d760feb 100644 --- a/core/jni/android_util_Process.cpp +++ b/core/jni/android_util_Process.cpp @@ -50,6 +50,16 @@ pid_t gettid() { return syscall(__NR_gettid);} #undef __KERNEL__ #endif +#define ENABLE_CGROUP_ERR_LOGGING 0 + +/* + * List of cgroup names which map to ANDROID_TGROUP_ values in Thread.h + * and Process.java + * These names are used to construct the path to the cgroup control dir + */ + +static const char *cgroup_names[] = { NULL, "bg_non_interactive", "fg_boost" }; + using namespace android; static void signalExceptionForPriorityError(JNIEnv* env, jobject obj, int err) @@ -73,6 +83,28 @@ static void signalExceptionForPriorityError(JNIEnv* env, jobject obj, int err) } } +static void signalExceptionForGroupError(JNIEnv* env, jobject obj, int err) +{ + switch (err) { + case EINVAL: + jniThrowException(env, "java/lang/IllegalArgumentException", NULL); + break; + case ESRCH: + jniThrowException(env, "java/lang/IllegalArgumentException", "Given thread does not exist"); + break; + case EPERM: + jniThrowException(env, "java/lang/SecurityException", "No permission to modify given thread"); + break; + case EACCES: + jniThrowException(env, "java/lang/SecurityException", "No permission to set to given group"); + break; + default: + jniThrowException(env, "java/lang/RuntimeException", "Unknown error"); + break; + } +} + + static void fakeProcessEntry(void* arg) { String8* cls = (String8*)arg; @@ -164,9 +196,55 @@ jint android_os_Process_getGidForName(JNIEnv* env, jobject clazz, jstring name) return -1; } +static int add_pid_to_cgroup(int pid, int grp) +{ + FILE *fp; + char path[255]; + int rc; + + sprintf(path, "/dev/cpuctl/%s/tasks", (cgroup_names[grp] ? cgroup_names[grp] : "")); + + if (!(fp = fopen(path, "w"))) { +#if ENABLE_CGROUP_ERR_LOGGING + LOGW("Unable to open %s (%s)\n", path, strerror(errno)); +#endif + return -errno; + } + + rc = fprintf(fp, "%d", pid); + fclose(fp); + + if (rc < 0) { +#if ENABLE_CGROUP_ERR_LOGGING + LOGW("Unable to move pid %d to cgroup %s (%s)\n", pid, + (cgroup_names[grp] ? cgroup_names[grp] : "<default>"), + strerror(errno)); +#endif + } + + return (rc < 0) ? errno : 0; +} + +void android_os_Process_setThreadGroup(JNIEnv* env, jobject clazz, int pid, jint grp) +{ + if (grp > ANDROID_TGROUP_MAX || grp < 0) { + signalExceptionForGroupError(env, clazz, EINVAL); + return; + } + + if (add_pid_to_cgroup(pid, grp)) + signalExceptionForGroupError(env, clazz, errno); +} + void android_os_Process_setThreadPriority(JNIEnv* env, jobject clazz, jint pid, jint pri) { + if (pri == ANDROID_PRIORITY_BACKGROUND) { + add_pid_to_cgroup(pid, ANDROID_TGROUP_BG_NONINTERACT); + } else if (getpriority(PRIO_PROCESS, pid) == ANDROID_PRIORITY_BACKGROUND) { + add_pid_to_cgroup(pid, ANDROID_TGROUP_DEFAULT); + } + if (setpriority(PRIO_PROCESS, pid, pri) < 0) { signalExceptionForPriorityError(env, clazz, errno); } @@ -741,6 +819,7 @@ static const JNINativeMethod methods[] = { {"setThreadPriority", "(II)V", (void*)android_os_Process_setThreadPriority}, {"setThreadPriority", "(I)V", (void*)android_os_Process_setCallingThreadPriority}, {"getThreadPriority", "(I)I", (void*)android_os_Process_getThreadPriority}, + {"setThreadGroup", "(II)V", (void*)android_os_Process_setThreadGroup}, {"setOomAdj", "(II)Z", (void*)android_os_Process_setOomAdj}, {"setArgV0", "(Ljava/lang/String;)V", (void*)android_os_Process_setArgV0}, {"setUid", "(I)I", (void*)android_os_Process_setUid}, diff --git a/include/utils/threads.h b/include/utils/threads.h index 8d8d46a..b320915 100644 --- a/include/utils/threads.h +++ b/include/utils/threads.h @@ -79,6 +79,13 @@ enum { ANDROID_PRIORITY_LESS_FAVORABLE = +1, }; +enum { + ANDROID_TGROUP_DEFAULT = 0, + ANDROID_TGROUP_BG_NONINTERACT = 1, + ANDROID_TGROUP_FG_BOOST = 2, + ANDROID_TGROUP_MAX = ANDROID_TGROUP_FG_BOOST, +}; + // Create and run a new thread. extern int androidCreateThread(android_thread_func_t, void *); |