diff options
| -rw-r--r-- | services/core/java/com/android/server/ThreadPriorityBooster.java | 26 | ||||
| -rw-r--r-- | services/tests/servicestests/src/com/android/server/ThreadPriorityBoosterTest.java | 97 |
2 files changed, 109 insertions, 14 deletions
diff --git a/services/core/java/com/android/server/ThreadPriorityBooster.java b/services/core/java/com/android/server/ThreadPriorityBooster.java index f74a438509c2..dab6bc4bbfb0 100644 --- a/services/core/java/com/android/server/ThreadPriorityBooster.java +++ b/services/core/java/com/android/server/ThreadPriorityBooster.java @@ -26,6 +26,7 @@ import static android.os.Process.setThreadPriority; public class ThreadPriorityBooster { private static final boolean ENABLE_LOCK_GUARD = false; + private static final int PRIORITY_NOT_ADJUSTED = Integer.MAX_VALUE; private volatile int mBoostToPriority; private final int mLockGuardIndex; @@ -42,13 +43,12 @@ public class ThreadPriorityBooster { } public void boost() { - final int tid = myTid(); final PriorityState state = mThreadState.get(); if (state.regionCounter == 0) { - final int prevPriority = getThreadPriority(tid); - state.prevPriority = prevPriority; + final int prevPriority = getThreadPriority(state.tid); if (prevPriority > mBoostToPriority) { - setThreadPriority(tid, mBoostToPriority); + setThreadPriority(state.tid, mBoostToPriority); + state.prevPriority = prevPriority; } } state.regionCounter++; @@ -60,11 +60,9 @@ public class ThreadPriorityBooster { public void reset() { final PriorityState state = mThreadState.get(); state.regionCounter--; - if (state.regionCounter == 0) { - final int currentPriority = getThreadPriority(myTid()); - if (state.prevPriority != currentPriority) { - setThreadPriority(myTid(), state.prevPriority); - } + if (state.regionCounter == 0 && state.prevPriority != PRIORITY_NOT_ADJUSTED) { + setThreadPriority(state.tid, state.prevPriority); + state.prevPriority = PRIORITY_NOT_ADJUSTED; } } @@ -78,16 +76,16 @@ public class ThreadPriorityBooster { // variable immediately. mBoostToPriority = priority; final PriorityState state = mThreadState.get(); - final int tid = myTid(); if (state.regionCounter != 0) { - final int prevPriority = getThreadPriority(tid); + final int prevPriority = getThreadPriority(state.tid); if (prevPriority != priority) { - setThreadPriority(tid, priority); + setThreadPriority(state.tid, priority); } } } private static class PriorityState { + final int tid = myTid(); /** * Acts as counter for number of synchronized region that needs to acquire 'this' as a lock @@ -99,6 +97,6 @@ public class ThreadPriorityBooster { /** * The thread's previous priority before boosting. */ - int prevPriority; + int prevPriority = PRIORITY_NOT_ADJUSTED; } -}
\ No newline at end of file +} diff --git a/services/tests/servicestests/src/com/android/server/ThreadPriorityBoosterTest.java b/services/tests/servicestests/src/com/android/server/ThreadPriorityBoosterTest.java new file mode 100644 index 000000000000..b4e9ff77744c --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/ThreadPriorityBoosterTest.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2019 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; + +import static android.os.Process.getThreadPriority; +import static android.os.Process.myTid; +import static android.os.Process.setThreadPriority; + +import static org.junit.Assert.assertEquals; + +import android.os.Process; +import android.platform.test.annotations.Presubmit; + +import androidx.test.filters.SmallTest; + +import org.junit.Test; + +/** + * Tests for {@link ThreadPriorityBooster}. + * Build/Install/Run: + * atest FrameworksServicesTests:ThreadPriorityBoosterTest + */ +@SmallTest +@Presubmit +public class ThreadPriorityBoosterTest { + private static final int PRIORITY_BOOST = Process.THREAD_PRIORITY_FOREGROUND; + private static final int PRIORITY_BOOST_MORE = Process.THREAD_PRIORITY_DISPLAY; + + private final ThreadPriorityBooster mBooster = new ThreadPriorityBooster(PRIORITY_BOOST, + 0 /* lockGuardIndex */); + + @Test + public void testThreadPriorityBooster() { + joinNewThread(() -> { + final int origPriority = Process.THREAD_PRIORITY_DEFAULT; + setThreadPriority(origPriority); + + boost(() -> { + assertThreadPriority(PRIORITY_BOOST); + boost(() -> { + // Inside the boost region, the priority should also apply to current thread. + mBooster.setBoostToPriority(PRIORITY_BOOST_MORE); + assertThreadPriority(PRIORITY_BOOST_MORE); + }); + // It is still in the boost region so the set priority should be kept. + assertThreadPriority(PRIORITY_BOOST_MORE); + + joinNewThread(() -> boost(() -> assertThreadPriority(PRIORITY_BOOST_MORE))); + }); + // The priority should be restored after leaving the boost region. + assertThreadPriority(origPriority); + + // It doesn't apply to current thread because outside of the boost region, but the boost + // in other threads will use the set priority. + mBooster.setBoostToPriority(PRIORITY_BOOST); + joinNewThread(() -> boost(() -> assertThreadPriority(PRIORITY_BOOST))); + + assertThreadPriority(origPriority); + }); + } + + private static void assertThreadPriority(int expectedPriority) { + assertEquals(expectedPriority, getThreadPriority(myTid())); + } + + private static void joinNewThread(Runnable action) { + final Thread thread = new Thread(action); + thread.start(); + try { + thread.join(); + } catch (InterruptedException ignored) { + } + } + + private void boost(Runnable action) { + try { + mBooster.boost(); + action.run(); + } finally { + mBooster.reset(); + } + } +} |