Loading core/java/android/app/Instrumentation.java +3 −0 Original line number Diff line number Diff line Loading @@ -2613,6 +2613,9 @@ public class Instrumentation { } public void run() { try { // We have historically always done this in a way that does not propagate to // Java-created child threads. It is unclear whether this is really necessary // or useful, but it is less risky than a change. Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY); } catch (RuntimeException e) { Log.w(TAG, "Exception setting priority of instrumentation thread " Loading core/java/android/os/Process.java +57 −15 Original line number Diff line number Diff line Loading @@ -1083,20 +1083,41 @@ public class Process { } /** * Set the priority of a thread, based on Linux priorities. * Set the OS priority of a thread, using Linux niceness priorities. Does not affect the value * cached for use by {@code java.lang.Thread.getPriority()}. If this is used with a * non-negative priority (Linux niceness), the priority may, on rare occasion, be reset * by the runtime to its cached value, especially when setting the priority of another thread. * * The new priority is not inherited by Java-created child threads. It may or may not * be inherited by threads created from native code. Use {@code * java/lang/Thread.setPriority()} to allow child threads to inherit the new priority. * * @param tid The identifier of the thread/process to change. * @param priority A Linux priority level, from -20 for highest scheduling * @param priority A Linux priority a.k.a. "niceness" level, from -20 for highest scheduling * priority to 19 for lowest scheduling priority. * * @throws IllegalArgumentException Throws IllegalArgumentException if * <var>tid</var> does not exist. * <var>tid</var> does not exist, or <var>priority</var> is out of range. * @throws SecurityException Throws SecurityException if your process does * not have permission to modify the given thread, or to use the given * priority. */ @RavenwoodRedirect public static final native void setThreadPriority(int tid, public static final void setThreadPriority(int tid, @IntRange(from = -20, to = THREAD_PRIORITY_LOWEST) int priority) throws IllegalArgumentException, SecurityException { if (com.android.libcore.Flags.nicenessApis() && Process.myTid() == tid) { // Prefer the same thread version that informs ART of the priority change. setThreadPriority(priority); } else { if (priority < -20 || priority > THREAD_PRIORITY_LOWEST) { throw new IllegalArgumentException("Priority/niceness " + priority + " is invalid"); } setThreadPriorityNative(tid, priority); } } private static native void setThreadPriorityNative(int tid, @IntRange(from = -20, to = THREAD_PRIORITY_LOWEST) int priority) throws IllegalArgumentException, SecurityException; Loading @@ -1104,12 +1125,17 @@ public class Process { * Call with 'false' to cause future calls to {@link #setThreadPriority(int)} to * throw an exception if passed a background-level thread priority. This is only * effective if the JNI layer is built with GUARD_THREAD_PRIORITY defined to 1. * This does not prevent a thread from backgrounding itself via other means, such * as a call to Thread.setPriority() or a native setpriority() call. * * @hide */ @RavenwoodRedirect public static final native void setCanSelfBackground(boolean backgroundOk); @RavenwoodRedirect private static native boolean getCanSelfBackground(); /** * Sets the scheduling group for a thread. * @hide Loading Loading @@ -1249,31 +1275,47 @@ public class Process { public static final native long[] getSchedAffinity(int tid); /** * Set the priority of the calling thread, based on Linux priorities. See * {@link #setThreadPriority(int, int)} for more information. * Set the priority of the calling thread, based on Linux niceness priorities. See * {@link #setThreadPriority(int, int)} for more information. This is preferred over * the two argument version when possible. The new priority is not inherited by Java * child threads. * * @param priority A Linux priority level, from -20 for highest scheduling * priority to 19 for lowest scheduling priority. * * @throws IllegalArgumentException Throws IllegalArgumentException if * <var>tid</var> does not exist. * <var>priority</var> is out of range. * @throws SecurityException Throws SecurityException if your process does * not have permission to modify the given thread, or to use the given * priority. * * @see #setThreadPriority(int, int) */ @RavenwoodReplace public static final native void setThreadPriority( @RavenwoodRedirect public static final void setThreadPriority( @IntRange(from = -20, to = THREAD_PRIORITY_LOWEST) int priority) throws IllegalArgumentException, SecurityException; private static void setThreadPriority$ravenwood(int priority) { throws IllegalArgumentException, SecurityException { if (!com.android.libcore.Flags.nicenessApis()) { // Fall back to not updating the cached priority if we don't have libcore support. setThreadPriority(myTid(), priority); return; } if (priority >= THREAD_PRIORITY_BACKGROUND && !getCanSelfBackground()) { throw new IllegalArgumentException( "Priority " + priority + " blocked by setCanSelfBackground()"); } boolean succ = VMRuntime.getRuntime().setThreadNiceness(Thread.currentThread(), priority); // VMRuntime.setThreadNiceness() just returns false for out-of-range priority. if (!succ) { if (priority < -20 || priority > THREAD_PRIORITY_LOWEST) { throw new IllegalArgumentException("Priority/niceness " + priority + " is invalid"); } throw new SecurityException("Cannot set priority to " + priority); } } /** * Return the current priority of a thread, based on Linux priorities. * Ignores the {@code java.lang.Thread.getPriority()} cached priority, which is used * to set the priority of newly created child Java threads. * * @param tid The identifier of the thread/process. If tid equals zero, the priority of the * calling process/thread will be returned. Loading core/java/android/os/Process_ravenwood.java +24 −6 Original line number Diff line number Diff line Loading @@ -36,16 +36,27 @@ public class Process_ravenwood { */ public static void setThreadPriority(int tid, int priority) { if (Process.myTid() == tid) { boolean backgroundOk = sThreadPriority.get().second; setThreadPriority(priority); } else { throw new UnsupportedOperationException( "Cross-thread priority management not yet available in Ravenwood"); } } /** * Called by {@link Process#setThreadPriority(int)} * The real implementation uses an Android-specific API. */ public static void setThreadPriority(int priority) { boolean backgroundOk = getCanSelfBackground(); if (priority >= Process.THREAD_PRIORITY_BACKGROUND && !backgroundOk) { throw new IllegalArgumentException( "Priority " + priority + " blocked by setCanSelfBackground()"); } sThreadPriority.set(Pair.create(priority, backgroundOk)); } else { throw new UnsupportedOperationException( "Cross-thread priority management not yet available in Ravenwood"); if (priority < -20 || priority > 19) { throw new IllegalArgumentException("Priority/niceness " + priority + " is invalid"); } sThreadPriority.set(Pair.create(priority, backgroundOk)); } /** Loading @@ -56,6 +67,13 @@ public class Process_ravenwood { sThreadPriority.set(Pair.create(priority, backgroundOk)); } /** * Called by {@link Process#getCanSelfBackground(int)} */ public static boolean getCanSelfBackground() { return sThreadPriority.get().second; } /** * Called by {@link Process#getThreadPriority(int)} */ Loading core/jni/android_util_Process.cpp +14 −12 Original line number Diff line number Diff line Loading @@ -540,7 +540,7 @@ static void android_os_Process_setCanSelfBackground(JNIEnv* env, jobject clazz, #if GUARD_THREAD_PRIORITY ALOGV("Process.setCanSelfBackground(%d) : tid=%d", bgOk, gettid()); { Mutex::Autolock _l(gKeyCreateMutex); Mutex::Autolock _l(gKeyCreateMutex); // Acquired nowhere else. if (gBgKey == -1) { pthread_key_create(&gBgKey, NULL); } Loading @@ -551,6 +551,16 @@ static void android_os_Process_setCanSelfBackground(JNIEnv* env, jobject clazz, #endif } static jboolean android_os_Process_getCanSelfBackground(JNIEnv* env, jclass clazz) { #if GUARD_THREAD_PRIORITY void* bgOk = pthread_getspecific(gBgKey); if (bgOk == ((void*)0xbaad)) { return false; } #endif return true; } jint android_os_Process_getThreadScheduler(JNIEnv* env, jclass clazz, jint tid) { Loading Loading @@ -584,9 +594,7 @@ void android_os_Process_setThreadScheduler(JNIEnv* env, jclass clazz, #endif } void android_os_Process_setThreadPriority(JNIEnv* env, jobject clazz, jint pid, jint pri) { void android_os_Process_setThreadPriorityNative(JNIEnv* env, jobject clazz, jint pid, jint pri) { #if GUARD_THREAD_PRIORITY // if we're putting the current thread into the background, check the TLS // to make sure this thread isn't guarded. If it is, raise an exception. Loading Loading @@ -615,12 +623,6 @@ void android_os_Process_setThreadPriority(JNIEnv* env, jobject clazz, // pid, pri, getpriority(PRIO_PROCESS, pid)); } void android_os_Process_setCallingThreadPriority(JNIEnv* env, jobject clazz, jint pri) { android_os_Process_setThreadPriority(env, clazz, gettid(), pri); } jint android_os_Process_getThreadPriority(JNIEnv* env, jobject clazz, jint pid) { Loading Loading @@ -1406,10 +1408,10 @@ void android_os_Process_freezeCgroupUID(JNIEnv* env, jobject clazz, jint uid, jb static const JNINativeMethod methods[] = { {"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}, {"setThreadPriorityNative", "(II)V", (void*)android_os_Process_setThreadPriorityNative}, {"setThreadScheduler", "(III)V", (void*)android_os_Process_setThreadScheduler}, {"setCanSelfBackground", "(Z)V", (void*)android_os_Process_setCanSelfBackground}, {"setThreadPriority", "(I)V", (void*)android_os_Process_setCallingThreadPriority}, {"getCanSelfBackground", "()Z", (void*)android_os_Process_getCanSelfBackground}, {"getThreadPriority", "(I)I", (void*)android_os_Process_getThreadPriority}, {"getThreadScheduler", "(I)I", (void*)android_os_Process_getThreadScheduler}, {"setThreadGroup", "(II)V", (void*)android_os_Process_setThreadGroup}, Loading core/tests/coretests/src/android/os/BinderThreadPriorityTest.java +2 −0 Original line number Diff line number Diff line Loading @@ -106,6 +106,8 @@ public class BinderThreadPriorityTest { public void tearDown() throws Exception { // HACK -- see bug 2665914 -- setThreadPriority() doesn't always set the // scheduler group reliably unless we start out with background priority. // As of July, 2025 this looks obsolete and incorrect, probably making the // hack unnecessary, but not seriously harmful. Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); Process.setThreadPriority(mSavedPriority); assertEquals(mSavedPriority, Process.getThreadPriority(Process.myTid())); Loading Loading
core/java/android/app/Instrumentation.java +3 −0 Original line number Diff line number Diff line Loading @@ -2613,6 +2613,9 @@ public class Instrumentation { } public void run() { try { // We have historically always done this in a way that does not propagate to // Java-created child threads. It is unclear whether this is really necessary // or useful, but it is less risky than a change. Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY); } catch (RuntimeException e) { Log.w(TAG, "Exception setting priority of instrumentation thread " Loading
core/java/android/os/Process.java +57 −15 Original line number Diff line number Diff line Loading @@ -1083,20 +1083,41 @@ public class Process { } /** * Set the priority of a thread, based on Linux priorities. * Set the OS priority of a thread, using Linux niceness priorities. Does not affect the value * cached for use by {@code java.lang.Thread.getPriority()}. If this is used with a * non-negative priority (Linux niceness), the priority may, on rare occasion, be reset * by the runtime to its cached value, especially when setting the priority of another thread. * * The new priority is not inherited by Java-created child threads. It may or may not * be inherited by threads created from native code. Use {@code * java/lang/Thread.setPriority()} to allow child threads to inherit the new priority. * * @param tid The identifier of the thread/process to change. * @param priority A Linux priority level, from -20 for highest scheduling * @param priority A Linux priority a.k.a. "niceness" level, from -20 for highest scheduling * priority to 19 for lowest scheduling priority. * * @throws IllegalArgumentException Throws IllegalArgumentException if * <var>tid</var> does not exist. * <var>tid</var> does not exist, or <var>priority</var> is out of range. * @throws SecurityException Throws SecurityException if your process does * not have permission to modify the given thread, or to use the given * priority. */ @RavenwoodRedirect public static final native void setThreadPriority(int tid, public static final void setThreadPriority(int tid, @IntRange(from = -20, to = THREAD_PRIORITY_LOWEST) int priority) throws IllegalArgumentException, SecurityException { if (com.android.libcore.Flags.nicenessApis() && Process.myTid() == tid) { // Prefer the same thread version that informs ART of the priority change. setThreadPriority(priority); } else { if (priority < -20 || priority > THREAD_PRIORITY_LOWEST) { throw new IllegalArgumentException("Priority/niceness " + priority + " is invalid"); } setThreadPriorityNative(tid, priority); } } private static native void setThreadPriorityNative(int tid, @IntRange(from = -20, to = THREAD_PRIORITY_LOWEST) int priority) throws IllegalArgumentException, SecurityException; Loading @@ -1104,12 +1125,17 @@ public class Process { * Call with 'false' to cause future calls to {@link #setThreadPriority(int)} to * throw an exception if passed a background-level thread priority. This is only * effective if the JNI layer is built with GUARD_THREAD_PRIORITY defined to 1. * This does not prevent a thread from backgrounding itself via other means, such * as a call to Thread.setPriority() or a native setpriority() call. * * @hide */ @RavenwoodRedirect public static final native void setCanSelfBackground(boolean backgroundOk); @RavenwoodRedirect private static native boolean getCanSelfBackground(); /** * Sets the scheduling group for a thread. * @hide Loading Loading @@ -1249,31 +1275,47 @@ public class Process { public static final native long[] getSchedAffinity(int tid); /** * Set the priority of the calling thread, based on Linux priorities. See * {@link #setThreadPriority(int, int)} for more information. * Set the priority of the calling thread, based on Linux niceness priorities. See * {@link #setThreadPriority(int, int)} for more information. This is preferred over * the two argument version when possible. The new priority is not inherited by Java * child threads. * * @param priority A Linux priority level, from -20 for highest scheduling * priority to 19 for lowest scheduling priority. * * @throws IllegalArgumentException Throws IllegalArgumentException if * <var>tid</var> does not exist. * <var>priority</var> is out of range. * @throws SecurityException Throws SecurityException if your process does * not have permission to modify the given thread, or to use the given * priority. * * @see #setThreadPriority(int, int) */ @RavenwoodReplace public static final native void setThreadPriority( @RavenwoodRedirect public static final void setThreadPriority( @IntRange(from = -20, to = THREAD_PRIORITY_LOWEST) int priority) throws IllegalArgumentException, SecurityException; private static void setThreadPriority$ravenwood(int priority) { throws IllegalArgumentException, SecurityException { if (!com.android.libcore.Flags.nicenessApis()) { // Fall back to not updating the cached priority if we don't have libcore support. setThreadPriority(myTid(), priority); return; } if (priority >= THREAD_PRIORITY_BACKGROUND && !getCanSelfBackground()) { throw new IllegalArgumentException( "Priority " + priority + " blocked by setCanSelfBackground()"); } boolean succ = VMRuntime.getRuntime().setThreadNiceness(Thread.currentThread(), priority); // VMRuntime.setThreadNiceness() just returns false for out-of-range priority. if (!succ) { if (priority < -20 || priority > THREAD_PRIORITY_LOWEST) { throw new IllegalArgumentException("Priority/niceness " + priority + " is invalid"); } throw new SecurityException("Cannot set priority to " + priority); } } /** * Return the current priority of a thread, based on Linux priorities. * Ignores the {@code java.lang.Thread.getPriority()} cached priority, which is used * to set the priority of newly created child Java threads. * * @param tid The identifier of the thread/process. If tid equals zero, the priority of the * calling process/thread will be returned. Loading
core/java/android/os/Process_ravenwood.java +24 −6 Original line number Diff line number Diff line Loading @@ -36,16 +36,27 @@ public class Process_ravenwood { */ public static void setThreadPriority(int tid, int priority) { if (Process.myTid() == tid) { boolean backgroundOk = sThreadPriority.get().second; setThreadPriority(priority); } else { throw new UnsupportedOperationException( "Cross-thread priority management not yet available in Ravenwood"); } } /** * Called by {@link Process#setThreadPriority(int)} * The real implementation uses an Android-specific API. */ public static void setThreadPriority(int priority) { boolean backgroundOk = getCanSelfBackground(); if (priority >= Process.THREAD_PRIORITY_BACKGROUND && !backgroundOk) { throw new IllegalArgumentException( "Priority " + priority + " blocked by setCanSelfBackground()"); } sThreadPriority.set(Pair.create(priority, backgroundOk)); } else { throw new UnsupportedOperationException( "Cross-thread priority management not yet available in Ravenwood"); if (priority < -20 || priority > 19) { throw new IllegalArgumentException("Priority/niceness " + priority + " is invalid"); } sThreadPriority.set(Pair.create(priority, backgroundOk)); } /** Loading @@ -56,6 +67,13 @@ public class Process_ravenwood { sThreadPriority.set(Pair.create(priority, backgroundOk)); } /** * Called by {@link Process#getCanSelfBackground(int)} */ public static boolean getCanSelfBackground() { return sThreadPriority.get().second; } /** * Called by {@link Process#getThreadPriority(int)} */ Loading
core/jni/android_util_Process.cpp +14 −12 Original line number Diff line number Diff line Loading @@ -540,7 +540,7 @@ static void android_os_Process_setCanSelfBackground(JNIEnv* env, jobject clazz, #if GUARD_THREAD_PRIORITY ALOGV("Process.setCanSelfBackground(%d) : tid=%d", bgOk, gettid()); { Mutex::Autolock _l(gKeyCreateMutex); Mutex::Autolock _l(gKeyCreateMutex); // Acquired nowhere else. if (gBgKey == -1) { pthread_key_create(&gBgKey, NULL); } Loading @@ -551,6 +551,16 @@ static void android_os_Process_setCanSelfBackground(JNIEnv* env, jobject clazz, #endif } static jboolean android_os_Process_getCanSelfBackground(JNIEnv* env, jclass clazz) { #if GUARD_THREAD_PRIORITY void* bgOk = pthread_getspecific(gBgKey); if (bgOk == ((void*)0xbaad)) { return false; } #endif return true; } jint android_os_Process_getThreadScheduler(JNIEnv* env, jclass clazz, jint tid) { Loading Loading @@ -584,9 +594,7 @@ void android_os_Process_setThreadScheduler(JNIEnv* env, jclass clazz, #endif } void android_os_Process_setThreadPriority(JNIEnv* env, jobject clazz, jint pid, jint pri) { void android_os_Process_setThreadPriorityNative(JNIEnv* env, jobject clazz, jint pid, jint pri) { #if GUARD_THREAD_PRIORITY // if we're putting the current thread into the background, check the TLS // to make sure this thread isn't guarded. If it is, raise an exception. Loading Loading @@ -615,12 +623,6 @@ void android_os_Process_setThreadPriority(JNIEnv* env, jobject clazz, // pid, pri, getpriority(PRIO_PROCESS, pid)); } void android_os_Process_setCallingThreadPriority(JNIEnv* env, jobject clazz, jint pri) { android_os_Process_setThreadPriority(env, clazz, gettid(), pri); } jint android_os_Process_getThreadPriority(JNIEnv* env, jobject clazz, jint pid) { Loading Loading @@ -1406,10 +1408,10 @@ void android_os_Process_freezeCgroupUID(JNIEnv* env, jobject clazz, jint uid, jb static const JNINativeMethod methods[] = { {"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}, {"setThreadPriorityNative", "(II)V", (void*)android_os_Process_setThreadPriorityNative}, {"setThreadScheduler", "(III)V", (void*)android_os_Process_setThreadScheduler}, {"setCanSelfBackground", "(Z)V", (void*)android_os_Process_setCanSelfBackground}, {"setThreadPriority", "(I)V", (void*)android_os_Process_setCallingThreadPriority}, {"getCanSelfBackground", "()Z", (void*)android_os_Process_getCanSelfBackground}, {"getThreadPriority", "(I)I", (void*)android_os_Process_getThreadPriority}, {"getThreadScheduler", "(I)I", (void*)android_os_Process_getThreadScheduler}, {"setThreadGroup", "(II)V", (void*)android_os_Process_setThreadGroup}, Loading
core/tests/coretests/src/android/os/BinderThreadPriorityTest.java +2 −0 Original line number Diff line number Diff line Loading @@ -106,6 +106,8 @@ public class BinderThreadPriorityTest { public void tearDown() throws Exception { // HACK -- see bug 2665914 -- setThreadPriority() doesn't always set the // scheduler group reliably unless we start out with background priority. // As of July, 2025 this looks obsolete and incorrect, probably making the // hack unnecessary, but not seriously harmful. Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); Process.setThreadPriority(mSavedPriority); assertEquals(mSavedPriority, Process.getThreadPriority(Process.myTid())); Loading