Add android.os.Process.setThreadScheduler

And add the associated SCHED_* constants
and remove redundant parameter to signalExceptionForPriorityError
and signalExceptionForGroupError.

Change-Id: I5a4e9652155aef2e5d544185e0d73a0120f89d97
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index dbefb1f..a6cbd895 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -213,6 +213,36 @@
     public static final int THREAD_PRIORITY_LESS_FAVORABLE = +1;
 
     /**
+     * Default scheduling policy
+     * @hide
+     */
+    public static final int SCHED_OTHER = 0;
+
+    /**
+     * First-In First-Out scheduling policy
+     * @hide
+     */
+    public static final int SCHED_FIFO = 1;
+
+    /**
+     * Round-Robin scheduling policy
+     * @hide
+     */
+    public static final int SCHED_RR = 2;
+
+    /**
+     * Batch scheduling policy
+     * @hide
+     */
+    public static final int SCHED_BATCH = 3;
+
+    /**
+     * Idle scheduling policy
+     * @hide
+     */
+    public static final int SCHED_IDLE = 5;
+
+    /**
      * Default thread group - gets a 'normal' share of the CPU
      * @hide
      */
@@ -736,6 +766,24 @@
             throws IllegalArgumentException;
     
     /**
+     * Set the scheduling policy and priority of a thread, based on Linux.
+     *
+     * @param tid The identifier of the thread/process to change.
+     * @param policy A Linux scheduling policy such as SCHED_OTHER etc.
+     * @param priority A Linux priority level in a range appropriate for the given policy.
+     *
+     * @throws IllegalArgumentException Throws IllegalArgumentException if
+     * <var>tid</var> does not exist, or if <var>priority</var> is out of range for the policy.
+     * @throws SecurityException Throws SecurityException if your process does
+     * not have permission to modify the given thread, or to use the given
+     * scheduling policy or priority.
+     *
+     * {@hide}
+     */
+    public static final native void setThreadScheduler(int tid, int policy, int priority)
+            throws IllegalArgumentException;
+
+    /**
      * Determine whether the current environment supports multiple processes.
      * 
      * @return Returns true if the system can run in multiple processes, else
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index 0960b25..d3c9132 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -50,7 +50,7 @@
 static pthread_key_t gBgKey = -1;
 #endif
 
-static void signalExceptionForPriorityError(JNIEnv* env, jobject obj, int err)
+static void signalExceptionForPriorityError(JNIEnv* env, int err)
 {
     switch (err) {
         case EINVAL:
@@ -71,7 +71,7 @@
     }
 }
 
-static void signalExceptionForGroupError(JNIEnv* env, jobject obj, int err)
+static void signalExceptionForGroupError(JNIEnv* env, int err)
 {
     switch (err) {
         case EINVAL:
@@ -173,7 +173,7 @@
 {
     int res = androidSetThreadSchedulingGroup(pid, grp);
     if (res != NO_ERROR) {
-        signalExceptionForGroupError(env, clazz, res == BAD_VALUE ? EINVAL : errno);
+        signalExceptionForGroupError(env, res == BAD_VALUE ? EINVAL : errno);
         return;
     }
 }
@@ -186,7 +186,7 @@
     struct dirent *de;
 
     if (grp > ANDROID_TGROUP_MAX || grp < 0) {
-        signalExceptionForGroupError(env, clazz, EINVAL);
+        signalExceptionForGroupError(env, EINVAL);
         return;
     }
 
@@ -214,7 +214,7 @@
     if (!(d = opendir(proc_path))) {
         // If the process exited on us, don't generate an exception
         if (errno != ENOENT)
-            signalExceptionForGroupError(env, clazz, errno);
+            signalExceptionForGroupError(env, errno);
         return;
     }
 
@@ -240,7 +240,7 @@
         }
 
         if (androidSetThreadSchedulingGroup(t_pid, grp) != NO_ERROR) {
-            signalExceptionForGroupError(env, clazz, errno);
+            signalExceptionForGroupError(env, errno);
             break;
         }
     }
@@ -264,6 +264,17 @@
 #endif
 }
 
+void android_os_Process_setThreadScheduler(JNIEnv* env, jclass clazz,
+                                              jint tid, jint policy, jint pri)
+{
+    struct sched_param param;
+    param.sched_priority = pri;
+    int rc = sched_setscheduler(tid, policy, &param);
+    if (rc) {
+        signalExceptionForPriorityError(env, errno);
+    }
+}
+
 void android_os_Process_setThreadPriority(JNIEnv* env, jobject clazz,
                                               jint pid, jint pri)
 {
@@ -285,9 +296,9 @@
     int rc = androidSetThreadPriority(pid, pri);
     if (rc != 0) {
         if (rc == INVALID_OPERATION) {
-            signalExceptionForPriorityError(env, clazz, errno);
+            signalExceptionForPriorityError(env, errno);
         } else {
-            signalExceptionForGroupError(env, clazz, errno);
+            signalExceptionForGroupError(env, errno);
         }
     }
 
@@ -308,7 +319,7 @@
     errno = 0;
     jint pri = getpriority(PRIO_PROCESS, pid);
     if (errno != 0) {
-        signalExceptionForPriorityError(env, clazz, errno);
+        signalExceptionForPriorityError(env, errno);
     }
     //LOGI("Returning priority of %d: %d\n", pid, pri);
     return pri;
@@ -867,6 +878,7 @@
     {"getUidForName",       "(Ljava/lang/String;)I", (void*)android_os_Process_getUidForName},
     {"getGidForName",       "(Ljava/lang/String;)I", (void*)android_os_Process_getGidForName},
     {"setThreadPriority",   "(II)V", (void*)android_os_Process_setThreadPriority},
+    {"setThreadScheduler",  "(III)V", (void*)android_os_Process_setThreadScheduler},
     {"setCanSelfBackground", "(Z)V", (void*)android_os_Process_setCanSelfBackground},
     {"setThreadPriority",   "(I)V", (void*)android_os_Process_setCallingThreadPriority},
     {"getThreadPriority",   "(I)I", (void*)android_os_Process_getThreadPriority},