diff --git a/services/core/java/com/android/server/ThreadPriorityBooster.java b/services/core/java/com/android/server/ThreadPriorityBooster.java index 31726ad85a305..0dfecc051a2d5 100644 --- a/services/core/java/com/android/server/ThreadPriorityBooster.java +++ b/services/core/java/com/android/server/ThreadPriorityBooster.java @@ -16,14 +16,16 @@ package com.android.server; -import android.os.Process; +import static android.os.Process.getThreadPriority; +import static android.os.Process.myTid; +import static android.os.Process.setThreadPriority; /** * Utility class to boost threads in sections where important locks are held. */ public class ThreadPriorityBooster { - private final int mBoostToPriority; + private volatile int mBoostToPriority; private final int mLockGuardIndex; private final ThreadLocal mThreadState = new ThreadLocal() { @@ -38,12 +40,12 @@ public class ThreadPriorityBooster { } public void boost() { - final int tid = Process.myTid(); - final int prevPriority = Process.getThreadPriority(tid); - PriorityState state = mThreadState.get(); + final int tid = myTid(); + final int prevPriority = getThreadPriority(tid); + final PriorityState state = mThreadState.get(); state.prevPriority = prevPriority; if (state.regionCounter == 0 && prevPriority > mBoostToPriority) { - Process.setThreadPriority(tid, mBoostToPriority); + setThreadPriority(tid, mBoostToPriority); } state.regionCounter++; if (LockGuard.ENABLED) { @@ -52,10 +54,28 @@ public class ThreadPriorityBooster { } public void reset() { - PriorityState state = mThreadState.get(); + final PriorityState state = mThreadState.get(); state.regionCounter--; - if (state.regionCounter == 0 && state.prevPriority > mBoostToPriority) { - Process.setThreadPriority(Process.myTid(), state.prevPriority); + final int currentPriority = getThreadPriority(myTid()); + if (state.regionCounter == 0 && state.prevPriority != currentPriority) { + setThreadPriority(myTid(), state.prevPriority); + } + } + + /** + * Updates the priority we boost the threads to, and updates the current thread's priority if + * necessary. + */ + protected void setBoostToPriority(int priority) { + + // We don't care about the other threads here, as long as they see the update of this + // variable immediately. + mBoostToPriority = priority; + final PriorityState state = mThreadState.get(); + final int tid = myTid(); + final int prevPriority = getThreadPriority(tid); + if (state.regionCounter != 0 && prevPriority != priority) { + setThreadPriority(tid, priority); } } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 6c500d85f1c9b..f80dd6204d138 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -453,6 +453,11 @@ import libcore.util.EmptyArray; public class ActivityManagerService extends IActivityManager.Stub implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback { + /** + * Priority we boost main thread and RT of top app to. + */ + public static final int TOP_APP_PRIORITY_BOOST = -10; + private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityManagerService" : TAG_AM; private static final String TAG_BACKUP = TAG + POSTFIX_BACKUP; private static final String TAG_BROADCAST = TAG + POSTFIX_BROADCAST; @@ -13489,7 +13494,7 @@ public class ActivityManagerService extends IActivityManager.Stub setThreadScheduler(proc.renderThreadTid, SCHED_FIFO | SCHED_RESET_ON_FORK, 1); } else { - setThreadPriority(proc.renderThreadTid, -10); + setThreadPriority(proc.renderThreadTid, TOP_APP_PRIORITY_BOOST); } } } else { @@ -21949,10 +21954,11 @@ public class ActivityManagerService extends IActivityManager.Stub } } else { // Boost priority for top app UI and render threads - setThreadPriority(app.pid, -10); + setThreadPriority(app.pid, TOP_APP_PRIORITY_BOOST); if (app.renderThreadTid != 0) { try { - setThreadPriority(app.renderThreadTid, -10); + setThreadPriority(app.renderThreadTid, + TOP_APP_PRIORITY_BOOST); } catch (IllegalArgumentException e) { // thread died, ignore } diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java index 9d8f1241a7aed..c1c72cad0c6b8 100644 --- a/services/core/java/com/android/server/wm/AppTransition.java +++ b/services/core/java/com/android/server/wm/AppTransition.java @@ -313,6 +313,7 @@ public class AppTransition implements Dump { mNextAppTransition = transit; mNextAppTransitionFlags |= flags; setLastAppTransition(TRANSIT_UNSET, null, null); + updateBooster(); } void setLastAppTransition(int transit, AppWindowToken openingApp, AppWindowToken closingApp) { @@ -327,7 +328,7 @@ public class AppTransition implements Dump { } void setReady() { - mAppTransitionState = APP_STATE_READY; + setAppTransitionState(APP_STATE_READY); fetchAppTransitionSpecsFromFuture(); } @@ -336,7 +337,7 @@ public class AppTransition implements Dump { } void setIdle() { - mAppTransitionState = APP_STATE_IDLE; + setAppTransitionState(APP_STATE_IDLE); } boolean isTimeout() { @@ -344,7 +345,7 @@ public class AppTransition implements Dump { } void setTimeout() { - mAppTransitionState = APP_STATE_TIMEOUT; + setAppTransitionState(APP_STATE_TIMEOUT); } GraphicBuffer getAppTransitionThumbnailHeader(int taskId) { @@ -386,7 +387,7 @@ public class AppTransition implements Dump { private boolean prepare() { if (!isRunning()) { - mAppTransitionState = APP_STATE_IDLE; + setAppTransitionState(APP_STATE_IDLE); notifyAppTransitionPendingLocked(); mLastHadClipReveal = false; mLastClipRevealMaxTranslation = 0; @@ -405,7 +406,7 @@ public class AppTransition implements Dump { ArraySet closingApps) { mNextAppTransition = TRANSIT_UNSET; mNextAppTransitionFlags = 0; - mAppTransitionState = APP_STATE_RUNNING; + setAppTransitionState(APP_STATE_RUNNING); int redoLayout = notifyAppTransitionStartingLocked(transit, topOpeningAppAnimator != null ? topOpeningAppAnimator.mAppToken.token : null, topClosingAppAnimator != null ? topClosingAppAnimator.mAppToken.token : null, @@ -450,6 +451,22 @@ public class AppTransition implements Dump { notifyAppTransitionCancelledLocked(transit); } + private void setAppTransitionState(int state) { + mAppTransitionState = state; + updateBooster(); + } + + /** + * Updates whether we currently boost wm locked sections and the animation thread. We want to + * boost the priorities to a more important value whenever an app transition is going to happen + * soon or an app transition is running. + */ + private void updateBooster() { + WindowManagerService.sThreadPriorityBooster.setAppTransitionRunning( + mNextAppTransition != TRANSIT_UNSET || mAppTransitionState == APP_STATE_READY + || mAppTransitionState == APP_STATE_RUNNING); + } + void registerListenerLocked(AppTransitionListener listener) { mListeners.add(listener); } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 9197fd82238aa..7ef1bd5e05156 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -870,8 +870,8 @@ public class WindowManagerService extends IWindowManager.Stub // since they won't be notified through the app window animator. final List mNoAnimationNotifyOnTransitionFinished = new ArrayList<>(); - private static ThreadPriorityBooster sThreadPriorityBooster = new ThreadPriorityBooster( - THREAD_PRIORITY_DISPLAY, INDEX_WINDOW); + static WindowManagerThreadPriorityBooster sThreadPriorityBooster = + new WindowManagerThreadPriorityBooster(); static void boostPriorityForLockedSection() { sThreadPriorityBooster.boost(); diff --git a/services/core/java/com/android/server/wm/WindowManagerThreadPriorityBooster.java b/services/core/java/com/android/server/wm/WindowManagerThreadPriorityBooster.java new file mode 100644 index 0000000000000..6a244a251537a --- /dev/null +++ b/services/core/java/com/android/server/wm/WindowManagerThreadPriorityBooster.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.server.wm; + +import static android.os.Process.THREAD_PRIORITY_DISPLAY; +import static android.os.Process.myTid; +import static android.os.Process.setThreadPriority; + +import static com.android.server.LockGuard.INDEX_WINDOW; +import static com.android.server.am.ActivityManagerService.TOP_APP_PRIORITY_BOOST; + +import com.android.server.AnimationThread; +import com.android.server.ThreadPriorityBooster; + +/** + * Window manager version of {@link ThreadPriorityBooster} that boosts even more during app + * transitions. + */ +class WindowManagerThreadPriorityBooster extends ThreadPriorityBooster { + + private final AnimationThread mAnimationThread; + private boolean mAppTransitionRunning; + + WindowManagerThreadPriorityBooster() { + super(THREAD_PRIORITY_DISPLAY, INDEX_WINDOW); + mAnimationThread = AnimationThread.get(); + } + + @Override + public void boost() { + + // Do not boost the animation thread. As the animation thread is changing priorities, + // boosting it might mess up the priority because we reset it the the previous priority. + if (myTid() == mAnimationThread.getThreadId()) { + return; + } + super.boost(); + } + + @Override + public void reset() { + + // See comment in boost(). + if (myTid() == mAnimationThread.getThreadId()) { + return; + } + super.reset(); + } + + void setAppTransitionRunning(boolean running) { + if (mAppTransitionRunning == running) { + return; + } + + final int priority = calculatePriority(running); + setBoostToPriority(priority); + setThreadPriority(mAnimationThread.getThreadId(), priority); + mAppTransitionRunning = running; + } + + private int calculatePriority(boolean appTransitionRunning) { + return appTransitionRunning ? TOP_APP_PRIORITY_BOOST : THREAD_PRIORITY_DISPLAY; + } +}