Loading services/core/java/com/android/server/am/ProcessStateController.java +54 −18 Original line number Diff line number Diff line Loading @@ -43,6 +43,7 @@ import com.android.server.wm.WindowProcessController; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.function.BiConsumer; import java.util.function.Consumer; Loading @@ -65,6 +66,11 @@ public class ProcessStateController { private final GlobalState mGlobalState = new GlobalState(); /** * Queue for staging asynchronous events. The queue will be drained before each update. */ private final ConcurrentLinkedQueue<Runnable> mStagingQueue = new ConcurrentLinkedQueue<>(); private ProcessStateController(ActivityManagerService ams, ProcessList processList, ActiveUids activeUids, ServiceThread handlerThread, CachedAppOptimizer cachedAppOptimizer, Object lock, Object procLock, Loading Loading @@ -115,7 +121,7 @@ public class ProcessStateController { */ @GuardedBy("mLock") public boolean runUpdate(@NonNull ProcessRecord proc, @OomAdjReason int oomAdjReason) { mGlobalState.commitStagedState(); commitStagedEvents(); return mOomAdjuster.updateOomAdjLocked(proc, oomAdjReason); } Loading @@ -124,15 +130,16 @@ public class ProcessStateController { */ @GuardedBy("mLock") public void runPendingUpdate(@OomAdjReason int oomAdjReason) { mGlobalState.commitStagedState(); commitStagedEvents(); mOomAdjuster.updateOomAdjPendingTargetsLocked(oomAdjReason); } /** * Trigger an update on all processes. */ @GuardedBy("mLock") public void runFullUpdate(@OomAdjReason int oomAdjReason) { mGlobalState.commitStagedState(); commitStagedEvents(); mOomAdjuster.updateOomAdjLocked(oomAdjReason); } Loading @@ -140,8 +147,9 @@ public class ProcessStateController { * Trigger an update on any processes that have been marked for follow up during a previous * update. */ @GuardedBy("mLock") public void runFollowUpUpdate() { mGlobalState.commitStagedState(); commitStagedEvents(); mOomAdjuster.updateOomAdjFollowUpTargetsLocked(); } Loading @@ -151,7 +159,7 @@ public class ProcessStateController { * @param looper which looper to post the async work to. */ public ActivityStateAsyncUpdater createActivityStateAsyncUpdater(Looper looper) { return new ActivityStateAsyncUpdater(this, looper); return new ActivityStateAsyncUpdater(this, looper, mStagingQueue); } /** Loading Loading @@ -776,6 +784,19 @@ public class ProcessStateController { } } @GuardedBy("mLock") private void commitStagedEvents() { mGlobalState.commitStagedState(); if (Flags.pushActivityStateToOomadjuster()) { // Drain any activity state changes from the staging queue. final ConcurrentLinkedQueue<Runnable> queue = mStagingQueue; while (!queue.isEmpty()) { queue.poll().run(); } } } /** * Helper class for sending Activity related state from Window Manager to * ProcessStateController. Because ProcessStateController is guarded by a lock WindowManager Loading @@ -788,11 +809,14 @@ public class ProcessStateController { public static class ActivityStateAsyncUpdater { private final ProcessStateController mPsc; private final Looper mLooper; private ConcurrentLinkedQueue<Runnable> mStagingQueue; private AsyncBatchSession mBatchSession; private ActivityStateAsyncUpdater(ProcessStateController psc, Looper looper) { private ActivityStateAsyncUpdater(ProcessStateController psc, Looper looper, ConcurrentLinkedQueue<Runnable> stagingQueue) { mPsc = psc; mLooper = looper; mStagingQueue = stagingQueue; } /** Loading Loading @@ -829,7 +853,7 @@ public class ProcessStateController { public void setExpandedNotificationShadeAsync(boolean expandedShade) { if (!Flags.pushActivityStateToOomadjuster()) return; getBatchSession().enqueue(() -> mPsc.setExpandedNotificationShade(expandedShade)); getBatchSession().stage(() -> mPsc.setExpandedNotificationShade(expandedShade)); } /** Loading @@ -840,7 +864,7 @@ public class ProcessStateController { if (!Flags.pushActivityStateToOomadjuster()) return; final ProcessRecord top = wpc != null ? (ProcessRecord) wpc.mOwner : null; getBatchSession().enqueue(() -> { getBatchSession().stage(() -> { mPsc.setTopProcess(top); if (clearPrev) { mPsc.setPreviousProcess(null); Loading @@ -857,7 +881,7 @@ public class ProcessStateController { public void setTopProcessStateAsync(@ActivityManager.ProcessState int procState) { if (!Flags.pushActivityStateToOomadjuster()) return; getBatchSession().enqueue(() -> mPsc.setTopProcessState(procState)); getBatchSession().stage(() -> mPsc.setTopProcessState(procState)); } /** Loading @@ -867,7 +891,7 @@ public class ProcessStateController { if (!Flags.pushActivityStateToOomadjuster()) return; final ProcessRecord prev = wpc != null ? (ProcessRecord) wpc.mOwner : null; getBatchSession().enqueue(() -> mPsc.setPreviousProcess(prev)); getBatchSession().stage(() -> mPsc.setPreviousProcess(prev)); } Loading @@ -878,7 +902,7 @@ public class ProcessStateController { if (!Flags.pushActivityStateToOomadjuster()) return; final ProcessRecord home = wpc != null ? (ProcessRecord) wpc.mOwner : null; getBatchSession().enqueue(() -> mPsc.setHomeProcess(home)); getBatchSession().stage(() -> mPsc.setHomeProcess(home)); } Loading @@ -889,7 +913,7 @@ public class ProcessStateController { if (!Flags.pushActivityStateToOomadjuster()) return; final ProcessRecord heavy = wpc != null ? (ProcessRecord) wpc.mOwner : null; getBatchSession().enqueue(() -> mPsc.setHeavyWeightProcess(heavy)); getBatchSession().stage(() -> mPsc.setHeavyWeightProcess(heavy)); } /** Loading @@ -899,7 +923,7 @@ public class ProcessStateController { if (!Flags.pushActivityStateToOomadjuster()) return; final ProcessRecord dozeUi = wpc != null ? (ProcessRecord) wpc.mOwner : null; getBatchSession().enqueue(() -> mPsc.setVisibleDozeUiProcess(dozeUi)); getBatchSession().stage(() -> mPsc.setVisibleDozeUiProcess(dozeUi)); } /** Loading @@ -909,7 +933,7 @@ public class ProcessStateController { if (!Flags.pushActivityStateToOomadjuster()) return; final ProcessRecordInternal activity = (ProcessRecordInternal) wpc.mOwner; getBatchSession().enqueue(() -> mPsc.setHasActivity(activity, hasActivity)); getBatchSession().stage(() -> mPsc.setHasActivity(activity, hasActivity)); } /** Loading @@ -920,7 +944,7 @@ public class ProcessStateController { if (!Flags.pushActivityStateToOomadjuster()) return; final ProcessRecordInternal activity = (ProcessRecordInternal) wpc.mOwner; getBatchSession().enqueue(() -> { getBatchSession().stage(() -> { mPsc.setActivityStateFlags(activity, flags); mPsc.setPerceptibleTaskStoppedTimeMillis(activity, perceptibleStopTimeMs); }); Loading @@ -934,14 +958,14 @@ public class ProcessStateController { if (!Flags.pushActivityStateToOomadjuster()) return; final ProcessRecordInternal proc = (ProcessRecordInternal) wpc.mOwner; getBatchSession().enqueue(() -> mPsc.setHasRecentTasks(proc, hasRecentTasks)); getBatchSession().stage(() -> mPsc.setHasRecentTasks(proc, hasRecentTasks)); } private AsyncBatchSession getBatchSession() { if (mBatchSession == null) { final Handler h = new Handler(mLooper); final Runnable update = () -> mPsc.runFullUpdate(OOM_ADJ_REASON_ACTIVITY); mBatchSession = new AsyncBatchSession(h, mPsc.mLock, update); mBatchSession = new AsyncBatchSession(h, mPsc.mLock, mStagingQueue, update); } return mBatchSession; } Loading @@ -950,6 +974,7 @@ public class ProcessStateController { public static class AsyncBatchSession implements AutoCloseable { final Handler mHandler; final Object mLock; final ConcurrentLinkedQueue<Runnable> mStagingQueue; private final Runnable mUpdateRunnable; private final Runnable mLockedUpdateRunnable; private boolean mRunUpdate = false; Loading @@ -958,9 +983,11 @@ public class ProcessStateController { private ArrayList<Runnable> mBatchList = new ArrayList<>(); AsyncBatchSession(Handler handler, Object lock, Runnable updateRunnable) { AsyncBatchSession(Handler handler, Object lock, ConcurrentLinkedQueue<Runnable> stagingQueue, Runnable updateRunnable) { mHandler = handler; mLock = lock; mStagingQueue = stagingQueue; mUpdateRunnable = updateRunnable; mLockedUpdateRunnable = () -> { synchronized (lock) { Loading @@ -979,6 +1006,15 @@ public class ProcessStateController { } } /** * Stage the runnable to be run on the next ProcessStateController update. The work may be * opportunistically run if an update triggers before the WindowManager posted update is * handled. */ public void stage(Runnable runnable) { mStagingQueue.add(runnable); } /** * Enqueue the work to be run asynchronously done on a Handler thread. * If batch session is currently active, queue up the work to be run when the session ends. Loading services/tests/mockingservicestests/src/com/android/server/am/ProcessStateControllerTest.java +72 −4 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ import org.junit.Before; import org.junit.Test; import java.util.ArrayList; import java.util.concurrent.ConcurrentLinkedQueue; @Presubmit public class ProcessStateControllerTest { Loading Loading @@ -91,7 +92,7 @@ public class ProcessStateControllerTest { public void asyncBatchSession_enqueue() { ArrayList<String> list = new ArrayList<>(); ProcessStateController.AsyncBatchSession session = new ProcessStateController.AsyncBatchSession(mManagedHandler, new Object(), new ProcessStateController.AsyncBatchSession(mManagedHandler, new Object(), null, () -> list.add("UPDATED")); // Enqueue some work and trigger an update mid way, while batching is active. Loading @@ -118,7 +119,7 @@ public class ProcessStateControllerTest { public void asyncBatchSession_enqueue_batched() { ArrayList<String> list = new ArrayList<>(); ProcessStateController.AsyncBatchSession session = new ProcessStateController.AsyncBatchSession(mManagedHandler, new Object(), new ProcessStateController.AsyncBatchSession(mManagedHandler, new Object(), null, () -> list.add("UPDATED")); // Enqueue some work and trigger an update mid way, while batching is active. Loading @@ -144,7 +145,7 @@ public class ProcessStateControllerTest { public void asyncBatchSession_enqueueNoUpdate_batched() { ArrayList<String> list = new ArrayList<>(); ProcessStateController.AsyncBatchSession session = new ProcessStateController.AsyncBatchSession(mManagedHandler, new Object(), new ProcessStateController.AsyncBatchSession(mManagedHandler, new Object(), null, () -> list.add("UPDATED")); // Enqueue some work and trigger an update mid way, while batching is active. Loading @@ -166,7 +167,7 @@ public class ProcessStateControllerTest { public void asyncBatchSession_enqueueBoostPriority_batched() { ArrayList<String> list = new ArrayList<>(); ProcessStateController.AsyncBatchSession session = new ProcessStateController.AsyncBatchSession(mManagedHandler, new Object(), new ProcessStateController.AsyncBatchSession(mManagedHandler, new Object(), null, () -> list.add("UPDATED")); // Enqueue some work , while batching is active and boost the priority of the session. Loading @@ -185,4 +186,71 @@ public class ProcessStateControllerTest { mTestLooperManager.execute(mTestLooperManager.next()); assertThat(list).containsExactly("A", "B", "X"); } @Test public void asyncBatchSession_interlacedEnqueueAndStage() { ArrayList<String> list = new ArrayList<>(); ConcurrentLinkedQueue<Runnable> stagingQueue = new ConcurrentLinkedQueue<>(); ProcessStateController.AsyncBatchSession session = new ProcessStateController.AsyncBatchSession(mManagedHandler, new Object(), stagingQueue, () -> list.add("UPDATED")); // Enqueue some work and trigger an update mid way, while batching is active. session.stage(() -> list.add("1")); session.enqueue(() -> list.add("A")); session.runUpdate(); session.stage(() -> list.add("2")); // Run the first staged runnable. stagingQueue.poll().run(); assertThat(list).containsExactly("1"); // Step through the looper one mTestLooperManager.execute(mTestLooperManager.next()); assertThat(list).containsExactly("1", "A"); // Run the second staged runnable. stagingQueue.poll().run(); assertThat(list).containsExactly("1", "A", "2"); // Step through the looper once more. mTestLooperManager.execute(mTestLooperManager.next()); assertThat(list).containsExactly("1", "A", "2", "UPDATED"); } @Test public void asyncBatchSession_interlacedEnqueueAndStage_batched() { ArrayList<String> list = new ArrayList<>(); ConcurrentLinkedQueue<Runnable> stagingQueue = new ConcurrentLinkedQueue<>(); ProcessStateController.AsyncBatchSession session = new ProcessStateController.AsyncBatchSession(mManagedHandler, new Object(), stagingQueue, () -> list.add("UPDATED")); // Enqueue some work and trigger an update mid way, while batching is active. session.start(); session.stage(() -> list.add("1")); session.enqueue(() -> list.add("A")); session.stage(() -> list.add("2")); session.runUpdate(); session.enqueue(() -> list.add("B")); session.stage(() -> list.add("3")); session.stage(() -> list.add("4")); session.close(); // Run the first staged runnable. stagingQueue.poll().run(); // Run the second staged runnable. stagingQueue.poll().run(); // Run the third staged runnable. stagingQueue.poll().run(); // Step through the looper once to run all batched enqueued work. mTestLooperManager.execute(mTestLooperManager.next()); // Run the last staged runnable. stagingQueue.poll().run(); assertThat(list.get(0)).isEqualTo("1"); assertThat(list.get(1)).isEqualTo("2"); assertThat(list.get(2)).isEqualTo("3"); assertThat(list.get(3)).isEqualTo("A"); assertThat(list.get(4)).isEqualTo("B"); assertThat(list.get(5)).isEqualTo("UPDATED"); assertThat(list.get(6)).isEqualTo("4"); } } Loading
services/core/java/com/android/server/am/ProcessStateController.java +54 −18 Original line number Diff line number Diff line Loading @@ -43,6 +43,7 @@ import com.android.server.wm.WindowProcessController; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.function.BiConsumer; import java.util.function.Consumer; Loading @@ -65,6 +66,11 @@ public class ProcessStateController { private final GlobalState mGlobalState = new GlobalState(); /** * Queue for staging asynchronous events. The queue will be drained before each update. */ private final ConcurrentLinkedQueue<Runnable> mStagingQueue = new ConcurrentLinkedQueue<>(); private ProcessStateController(ActivityManagerService ams, ProcessList processList, ActiveUids activeUids, ServiceThread handlerThread, CachedAppOptimizer cachedAppOptimizer, Object lock, Object procLock, Loading Loading @@ -115,7 +121,7 @@ public class ProcessStateController { */ @GuardedBy("mLock") public boolean runUpdate(@NonNull ProcessRecord proc, @OomAdjReason int oomAdjReason) { mGlobalState.commitStagedState(); commitStagedEvents(); return mOomAdjuster.updateOomAdjLocked(proc, oomAdjReason); } Loading @@ -124,15 +130,16 @@ public class ProcessStateController { */ @GuardedBy("mLock") public void runPendingUpdate(@OomAdjReason int oomAdjReason) { mGlobalState.commitStagedState(); commitStagedEvents(); mOomAdjuster.updateOomAdjPendingTargetsLocked(oomAdjReason); } /** * Trigger an update on all processes. */ @GuardedBy("mLock") public void runFullUpdate(@OomAdjReason int oomAdjReason) { mGlobalState.commitStagedState(); commitStagedEvents(); mOomAdjuster.updateOomAdjLocked(oomAdjReason); } Loading @@ -140,8 +147,9 @@ public class ProcessStateController { * Trigger an update on any processes that have been marked for follow up during a previous * update. */ @GuardedBy("mLock") public void runFollowUpUpdate() { mGlobalState.commitStagedState(); commitStagedEvents(); mOomAdjuster.updateOomAdjFollowUpTargetsLocked(); } Loading @@ -151,7 +159,7 @@ public class ProcessStateController { * @param looper which looper to post the async work to. */ public ActivityStateAsyncUpdater createActivityStateAsyncUpdater(Looper looper) { return new ActivityStateAsyncUpdater(this, looper); return new ActivityStateAsyncUpdater(this, looper, mStagingQueue); } /** Loading Loading @@ -776,6 +784,19 @@ public class ProcessStateController { } } @GuardedBy("mLock") private void commitStagedEvents() { mGlobalState.commitStagedState(); if (Flags.pushActivityStateToOomadjuster()) { // Drain any activity state changes from the staging queue. final ConcurrentLinkedQueue<Runnable> queue = mStagingQueue; while (!queue.isEmpty()) { queue.poll().run(); } } } /** * Helper class for sending Activity related state from Window Manager to * ProcessStateController. Because ProcessStateController is guarded by a lock WindowManager Loading @@ -788,11 +809,14 @@ public class ProcessStateController { public static class ActivityStateAsyncUpdater { private final ProcessStateController mPsc; private final Looper mLooper; private ConcurrentLinkedQueue<Runnable> mStagingQueue; private AsyncBatchSession mBatchSession; private ActivityStateAsyncUpdater(ProcessStateController psc, Looper looper) { private ActivityStateAsyncUpdater(ProcessStateController psc, Looper looper, ConcurrentLinkedQueue<Runnable> stagingQueue) { mPsc = psc; mLooper = looper; mStagingQueue = stagingQueue; } /** Loading Loading @@ -829,7 +853,7 @@ public class ProcessStateController { public void setExpandedNotificationShadeAsync(boolean expandedShade) { if (!Flags.pushActivityStateToOomadjuster()) return; getBatchSession().enqueue(() -> mPsc.setExpandedNotificationShade(expandedShade)); getBatchSession().stage(() -> mPsc.setExpandedNotificationShade(expandedShade)); } /** Loading @@ -840,7 +864,7 @@ public class ProcessStateController { if (!Flags.pushActivityStateToOomadjuster()) return; final ProcessRecord top = wpc != null ? (ProcessRecord) wpc.mOwner : null; getBatchSession().enqueue(() -> { getBatchSession().stage(() -> { mPsc.setTopProcess(top); if (clearPrev) { mPsc.setPreviousProcess(null); Loading @@ -857,7 +881,7 @@ public class ProcessStateController { public void setTopProcessStateAsync(@ActivityManager.ProcessState int procState) { if (!Flags.pushActivityStateToOomadjuster()) return; getBatchSession().enqueue(() -> mPsc.setTopProcessState(procState)); getBatchSession().stage(() -> mPsc.setTopProcessState(procState)); } /** Loading @@ -867,7 +891,7 @@ public class ProcessStateController { if (!Flags.pushActivityStateToOomadjuster()) return; final ProcessRecord prev = wpc != null ? (ProcessRecord) wpc.mOwner : null; getBatchSession().enqueue(() -> mPsc.setPreviousProcess(prev)); getBatchSession().stage(() -> mPsc.setPreviousProcess(prev)); } Loading @@ -878,7 +902,7 @@ public class ProcessStateController { if (!Flags.pushActivityStateToOomadjuster()) return; final ProcessRecord home = wpc != null ? (ProcessRecord) wpc.mOwner : null; getBatchSession().enqueue(() -> mPsc.setHomeProcess(home)); getBatchSession().stage(() -> mPsc.setHomeProcess(home)); } Loading @@ -889,7 +913,7 @@ public class ProcessStateController { if (!Flags.pushActivityStateToOomadjuster()) return; final ProcessRecord heavy = wpc != null ? (ProcessRecord) wpc.mOwner : null; getBatchSession().enqueue(() -> mPsc.setHeavyWeightProcess(heavy)); getBatchSession().stage(() -> mPsc.setHeavyWeightProcess(heavy)); } /** Loading @@ -899,7 +923,7 @@ public class ProcessStateController { if (!Flags.pushActivityStateToOomadjuster()) return; final ProcessRecord dozeUi = wpc != null ? (ProcessRecord) wpc.mOwner : null; getBatchSession().enqueue(() -> mPsc.setVisibleDozeUiProcess(dozeUi)); getBatchSession().stage(() -> mPsc.setVisibleDozeUiProcess(dozeUi)); } /** Loading @@ -909,7 +933,7 @@ public class ProcessStateController { if (!Flags.pushActivityStateToOomadjuster()) return; final ProcessRecordInternal activity = (ProcessRecordInternal) wpc.mOwner; getBatchSession().enqueue(() -> mPsc.setHasActivity(activity, hasActivity)); getBatchSession().stage(() -> mPsc.setHasActivity(activity, hasActivity)); } /** Loading @@ -920,7 +944,7 @@ public class ProcessStateController { if (!Flags.pushActivityStateToOomadjuster()) return; final ProcessRecordInternal activity = (ProcessRecordInternal) wpc.mOwner; getBatchSession().enqueue(() -> { getBatchSession().stage(() -> { mPsc.setActivityStateFlags(activity, flags); mPsc.setPerceptibleTaskStoppedTimeMillis(activity, perceptibleStopTimeMs); }); Loading @@ -934,14 +958,14 @@ public class ProcessStateController { if (!Flags.pushActivityStateToOomadjuster()) return; final ProcessRecordInternal proc = (ProcessRecordInternal) wpc.mOwner; getBatchSession().enqueue(() -> mPsc.setHasRecentTasks(proc, hasRecentTasks)); getBatchSession().stage(() -> mPsc.setHasRecentTasks(proc, hasRecentTasks)); } private AsyncBatchSession getBatchSession() { if (mBatchSession == null) { final Handler h = new Handler(mLooper); final Runnable update = () -> mPsc.runFullUpdate(OOM_ADJ_REASON_ACTIVITY); mBatchSession = new AsyncBatchSession(h, mPsc.mLock, update); mBatchSession = new AsyncBatchSession(h, mPsc.mLock, mStagingQueue, update); } return mBatchSession; } Loading @@ -950,6 +974,7 @@ public class ProcessStateController { public static class AsyncBatchSession implements AutoCloseable { final Handler mHandler; final Object mLock; final ConcurrentLinkedQueue<Runnable> mStagingQueue; private final Runnable mUpdateRunnable; private final Runnable mLockedUpdateRunnable; private boolean mRunUpdate = false; Loading @@ -958,9 +983,11 @@ public class ProcessStateController { private ArrayList<Runnable> mBatchList = new ArrayList<>(); AsyncBatchSession(Handler handler, Object lock, Runnable updateRunnable) { AsyncBatchSession(Handler handler, Object lock, ConcurrentLinkedQueue<Runnable> stagingQueue, Runnable updateRunnable) { mHandler = handler; mLock = lock; mStagingQueue = stagingQueue; mUpdateRunnable = updateRunnable; mLockedUpdateRunnable = () -> { synchronized (lock) { Loading @@ -979,6 +1006,15 @@ public class ProcessStateController { } } /** * Stage the runnable to be run on the next ProcessStateController update. The work may be * opportunistically run if an update triggers before the WindowManager posted update is * handled. */ public void stage(Runnable runnable) { mStagingQueue.add(runnable); } /** * Enqueue the work to be run asynchronously done on a Handler thread. * If batch session is currently active, queue up the work to be run when the session ends. Loading
services/tests/mockingservicestests/src/com/android/server/am/ProcessStateControllerTest.java +72 −4 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ import org.junit.Before; import org.junit.Test; import java.util.ArrayList; import java.util.concurrent.ConcurrentLinkedQueue; @Presubmit public class ProcessStateControllerTest { Loading Loading @@ -91,7 +92,7 @@ public class ProcessStateControllerTest { public void asyncBatchSession_enqueue() { ArrayList<String> list = new ArrayList<>(); ProcessStateController.AsyncBatchSession session = new ProcessStateController.AsyncBatchSession(mManagedHandler, new Object(), new ProcessStateController.AsyncBatchSession(mManagedHandler, new Object(), null, () -> list.add("UPDATED")); // Enqueue some work and trigger an update mid way, while batching is active. Loading @@ -118,7 +119,7 @@ public class ProcessStateControllerTest { public void asyncBatchSession_enqueue_batched() { ArrayList<String> list = new ArrayList<>(); ProcessStateController.AsyncBatchSession session = new ProcessStateController.AsyncBatchSession(mManagedHandler, new Object(), new ProcessStateController.AsyncBatchSession(mManagedHandler, new Object(), null, () -> list.add("UPDATED")); // Enqueue some work and trigger an update mid way, while batching is active. Loading @@ -144,7 +145,7 @@ public class ProcessStateControllerTest { public void asyncBatchSession_enqueueNoUpdate_batched() { ArrayList<String> list = new ArrayList<>(); ProcessStateController.AsyncBatchSession session = new ProcessStateController.AsyncBatchSession(mManagedHandler, new Object(), new ProcessStateController.AsyncBatchSession(mManagedHandler, new Object(), null, () -> list.add("UPDATED")); // Enqueue some work and trigger an update mid way, while batching is active. Loading @@ -166,7 +167,7 @@ public class ProcessStateControllerTest { public void asyncBatchSession_enqueueBoostPriority_batched() { ArrayList<String> list = new ArrayList<>(); ProcessStateController.AsyncBatchSession session = new ProcessStateController.AsyncBatchSession(mManagedHandler, new Object(), new ProcessStateController.AsyncBatchSession(mManagedHandler, new Object(), null, () -> list.add("UPDATED")); // Enqueue some work , while batching is active and boost the priority of the session. Loading @@ -185,4 +186,71 @@ public class ProcessStateControllerTest { mTestLooperManager.execute(mTestLooperManager.next()); assertThat(list).containsExactly("A", "B", "X"); } @Test public void asyncBatchSession_interlacedEnqueueAndStage() { ArrayList<String> list = new ArrayList<>(); ConcurrentLinkedQueue<Runnable> stagingQueue = new ConcurrentLinkedQueue<>(); ProcessStateController.AsyncBatchSession session = new ProcessStateController.AsyncBatchSession(mManagedHandler, new Object(), stagingQueue, () -> list.add("UPDATED")); // Enqueue some work and trigger an update mid way, while batching is active. session.stage(() -> list.add("1")); session.enqueue(() -> list.add("A")); session.runUpdate(); session.stage(() -> list.add("2")); // Run the first staged runnable. stagingQueue.poll().run(); assertThat(list).containsExactly("1"); // Step through the looper one mTestLooperManager.execute(mTestLooperManager.next()); assertThat(list).containsExactly("1", "A"); // Run the second staged runnable. stagingQueue.poll().run(); assertThat(list).containsExactly("1", "A", "2"); // Step through the looper once more. mTestLooperManager.execute(mTestLooperManager.next()); assertThat(list).containsExactly("1", "A", "2", "UPDATED"); } @Test public void asyncBatchSession_interlacedEnqueueAndStage_batched() { ArrayList<String> list = new ArrayList<>(); ConcurrentLinkedQueue<Runnable> stagingQueue = new ConcurrentLinkedQueue<>(); ProcessStateController.AsyncBatchSession session = new ProcessStateController.AsyncBatchSession(mManagedHandler, new Object(), stagingQueue, () -> list.add("UPDATED")); // Enqueue some work and trigger an update mid way, while batching is active. session.start(); session.stage(() -> list.add("1")); session.enqueue(() -> list.add("A")); session.stage(() -> list.add("2")); session.runUpdate(); session.enqueue(() -> list.add("B")); session.stage(() -> list.add("3")); session.stage(() -> list.add("4")); session.close(); // Run the first staged runnable. stagingQueue.poll().run(); // Run the second staged runnable. stagingQueue.poll().run(); // Run the third staged runnable. stagingQueue.poll().run(); // Step through the looper once to run all batched enqueued work. mTestLooperManager.execute(mTestLooperManager.next()); // Run the last staged runnable. stagingQueue.poll().run(); assertThat(list.get(0)).isEqualTo("1"); assertThat(list.get(1)).isEqualTo("2"); assertThat(list.get(2)).isEqualTo("3"); assertThat(list.get(3)).isEqualTo("A"); assertThat(list.get(4)).isEqualTo("B"); assertThat(list.get(5)).isEqualTo("UPDATED"); assertThat(list.get(6)).isEqualTo("4"); } }