diff options
4 files changed, 61 insertions, 33 deletions
diff --git a/services/core/java/com/android/server/am/BroadcastProcessQueue.java b/services/core/java/com/android/server/am/BroadcastProcessQueue.java index 48ab96cee562..d5b8bb44e853 100644 --- a/services/core/java/com/android/server/am/BroadcastProcessQueue.java +++ b/services/core/java/com/android/server/am/BroadcastProcessQueue.java @@ -188,7 +188,7 @@ class BroadcastProcessQueue { private @Reason int mRunnableAtReason = REASON_EMPTY; private boolean mRunnableAtInvalidated; - private boolean mProcessCached; + private boolean mUidCached; private boolean mProcessInstrumented; private boolean mProcessPersistent; @@ -382,14 +382,14 @@ class BroadcastProcessQueue { /** * Update the actively running "warm" process for this process. */ - public void setProcess(@Nullable ProcessRecord app) { + public void setProcessAndUidCached(@Nullable ProcessRecord app, boolean uidCached) { this.app = app; if (app != null) { - setProcessCached(app.isCached()); + setUidCached(uidCached); setProcessInstrumented(app.getActiveInstrumentation() != null); setProcessPersistent(app.isPersistent()); } else { - setProcessCached(false); + setUidCached(uidCached); setProcessInstrumented(false); setProcessPersistent(false); } @@ -403,10 +403,9 @@ class BroadcastProcessQueue { * Update if this process is in the "cached" state, typically signaling that * broadcast dispatch should be paused or delayed. */ - @VisibleForTesting - void setProcessCached(boolean cached) { - if (mProcessCached != cached) { - mProcessCached = cached; + private void setUidCached(boolean uidCached) { + if (mUidCached != uidCached) { + mUidCached = uidCached; invalidateRunnableAt(); } } @@ -416,7 +415,7 @@ class BroadcastProcessQueue { * signaling that broadcast dispatch should bypass all pauses or delays, to * avoid holding up test suites. */ - public void setProcessInstrumented(boolean instrumented) { + private void setProcessInstrumented(boolean instrumented) { if (mProcessInstrumented != instrumented) { mProcessInstrumented = instrumented; invalidateRunnableAt(); @@ -427,7 +426,7 @@ class BroadcastProcessQueue { * Update if this process is in the "persistent" state, which signals broadcast dispatch should * bypass all pauses or delays to prevent the system from becoming out of sync with itself. */ - public void setProcessPersistent(boolean persistent) { + private void setProcessPersistent(boolean persistent) { if (mProcessPersistent != persistent) { mProcessPersistent = persistent; invalidateRunnableAt(); @@ -986,7 +985,7 @@ class BroadcastProcessQueue { } else if (mProcessPersistent) { mRunnableAt = runnableAt; mRunnableAtReason = REASON_PERSISTENT; - } else if (mProcessCached) { + } else if (mUidCached) { if (r.deferUntilActive) { // All enqueued broadcasts are deferrable, defer if (mCountDeferred == mCountEnqueued) { @@ -1195,7 +1194,7 @@ class BroadcastProcessQueue { @NeverCompile private void dumpProcessState(@NonNull IndentingPrintWriter pw) { final StringBuilder sb = new StringBuilder(); - if (mProcessCached) { + if (mUidCached) { sb.append("CACHED"); } if (mProcessInstrumented) { diff --git a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java index 40ae6e211235..b18997a8d21f 100644 --- a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java +++ b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java @@ -72,6 +72,7 @@ import android.util.MathUtils; import android.util.Pair; import android.util.Slog; import android.util.SparseArray; +import android.util.SparseBooleanArray; import android.util.TimeUtils; import android.util.proto.ProtoOutputStream; @@ -209,6 +210,16 @@ class BroadcastQueueModernImpl extends BroadcastQueue { private final AtomicReference<ArraySet<BroadcastRecord>> mReplacedBroadcastsCache = new AtomicReference<>(); + /** + * Map from UID to its last known "cached" state. + * <p> + * We manually maintain this data structure since the lifecycle of + * {@link ProcessRecord} and {@link BroadcastProcessQueue} can be + * mismatched. + */ + @GuardedBy("mService") + private final SparseBooleanArray mUidCached = new SparseBooleanArray(); + private final BroadcastConstants mConstants; private final BroadcastConstants mFgConstants; private final BroadcastConstants mBgConstants; @@ -485,7 +496,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue { // relevant per-process queue final BroadcastProcessQueue queue = getProcessQueue(app); if (queue != null) { - queue.setProcess(app); + setQueueProcess(queue, app); } boolean didSomething = false; @@ -526,7 +537,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue { // relevant per-process queue final BroadcastProcessQueue queue = getProcessQueue(app); if (queue != null) { - queue.setProcess(null); + setQueueProcess(queue, null); } if ((mRunningColdStart != null) && (mRunningColdStart == queue)) { @@ -1332,11 +1343,17 @@ class BroadcastQueueModernImpl extends BroadcastQueue { @Override public void onUidCachedChanged(int uid, boolean cached) { synchronized (mService) { + if (cached) { + mUidCached.put(uid, true); + } else { + mUidCached.delete(uid); + } + BroadcastProcessQueue leaf = mProcessQueues.get(uid); while (leaf != null) { // Update internal state by refreshing values previously // read from any known running process - leaf.setProcess(leaf.app); + setQueueProcess(leaf, leaf.app); updateQueueDeferred(leaf); updateRunnableList(leaf); leaf = leaf.processNameNext; @@ -1498,11 +1515,20 @@ class BroadcastQueueModernImpl extends BroadcastQueue { private void updateWarmProcess(@NonNull BroadcastProcessQueue queue) { if (!queue.isProcessWarm()) { - queue.setProcess(mService.getProcessRecordLocked(queue.processName, queue.uid)); + setQueueProcess(queue, mService.getProcessRecordLocked(queue.processName, queue.uid)); } } /** + * Update the {@link ProcessRecord} associated with the given + * {@link BroadcastProcessQueue}. + */ + private void setQueueProcess(@NonNull BroadcastProcessQueue queue, + @Nullable ProcessRecord app) { + queue.setProcessAndUidCached(app, mUidCached.get(queue.uid, false)); + } + + /** * Inform other parts of OS that the given broadcast queue has started * running, typically for internal bookkeeping. */ @@ -1692,7 +1718,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue { } BroadcastProcessQueue created = new BroadcastProcessQueue(mConstants, processName, uid); - created.setProcess(mService.getProcessRecordLocked(processName, uid)); + setQueueProcess(created, mService.getProcessRecordLocked(processName, uid)); if (leaf == null) { mProcessQueues.put(uid, created); @@ -1815,12 +1841,18 @@ class BroadcastQueueModernImpl extends BroadcastQueue { ipw.decreaseIndent(); ipw.println(); - ipw.println(" Broadcasts with ignored delivery group policies:"); + ipw.println("Broadcasts with ignored delivery group policies:"); ipw.increaseIndent(); mService.dumpDeliveryGroupPolicyIgnoredActions(ipw); ipw.decreaseIndent(); ipw.println(); + ipw.println("Cached UIDs:"); + ipw.increaseIndent(); + ipw.println(mUidCached.toString()); + ipw.decreaseIndent(); + ipw.println(); + if (dumpConstants) { mConstants.dump(ipw); } diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java index 41a5ddb60a7f..0c512d2a0bd3 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java @@ -372,9 +372,9 @@ public final class BroadcastQueueModernImplTest { List.of(makeMockRegisteredReceiver()), false); queue.enqueueOrReplaceBroadcast(airplaneRecord, 0, false); - queue.setProcessCached(false); + queue.setProcessAndUidCached(null, false); final long notCachedRunnableAt = queue.getRunnableAt(); - queue.setProcessCached(true); + queue.setProcessAndUidCached(null, true); final long cachedRunnableAt = queue.getRunnableAt(); assertThat(cachedRunnableAt).isGreaterThan(notCachedRunnableAt); assertFalse(queue.isRunnable()); @@ -399,9 +399,9 @@ public final class BroadcastQueueModernImplTest { List.of(makeMockRegisteredReceiver()), false); queue.enqueueOrReplaceBroadcast(airplaneRecord, 0, false); - queue.setProcessCached(false); + queue.setProcessAndUidCached(null, false); final long notCachedRunnableAt = queue.getRunnableAt(); - queue.setProcessCached(true); + queue.setProcessAndUidCached(null, true); final long cachedRunnableAt = queue.getRunnableAt(); assertThat(cachedRunnableAt).isGreaterThan(notCachedRunnableAt); assertTrue(queue.isRunnable()); @@ -431,13 +431,13 @@ public final class BroadcastQueueModernImplTest { // verify that: // (a) the queue is immediately runnable by existence of a fg-priority broadcast // (b) the next one up is the fg-priority broadcast despite its later enqueue time - queue.setProcessCached(false); + queue.setProcessAndUidCached(null, false); assertTrue(queue.isRunnable()); assertThat(queue.getRunnableAt()).isAtMost(airplaneRecord.enqueueClockTime); assertEquals(ProcessList.SCHED_GROUP_DEFAULT, queue.getPreferredSchedulingGroupLocked()); assertEquals(queue.peekNextBroadcastRecord(), airplaneRecord); - queue.setProcessCached(true); + queue.setProcessAndUidCached(null, true); assertTrue(queue.isRunnable()); assertThat(queue.getRunnableAt()).isAtMost(airplaneRecord.enqueueClockTime); assertEquals(ProcessList.SCHED_GROUP_DEFAULT, queue.getPreferredSchedulingGroupLocked()); @@ -500,7 +500,7 @@ public final class BroadcastQueueModernImplTest { private void doRunnableAt_Cached(BroadcastRecord testRecord, int testRunnableAtReason) { final BroadcastProcessQueue queue = new BroadcastProcessQueue(mConstants, PACKAGE_GREEN, getUidForPackage(PACKAGE_GREEN)); - queue.setProcessCached(true); + queue.setProcessAndUidCached(null, true); final BroadcastRecord lazyRecord = makeBroadcastRecord( new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED), diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java index 3b964bcb78ac..cbc259797c12 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java @@ -1659,8 +1659,8 @@ public class BroadcastQueueTest { final ProcessRecord receiverYellowApp = makeActiveProcessRecord(PACKAGE_YELLOW); final ProcessRecord receiverOrangeApp = makeActiveProcessRecord(PACKAGE_ORANGE); - receiverGreenApp.setCached(true); - receiverBlueApp.setCached(true); + mUidObserver.onUidCachedChanged(getUidForPackage(PACKAGE_GREEN), true); + mUidObserver.onUidCachedChanged(getUidForPackage(PACKAGE_BLUE), true); final Intent timeTick = new Intent(Intent.ACTION_TIME_TICK); final BroadcastOptions opts = BroadcastOptions.makeBasic() @@ -1704,13 +1704,11 @@ public class BroadcastQueueTest { eq(UserHandle.USER_SYSTEM), anyInt(), anyInt(), any()); // Shift blue to be active and confirm that deferred broadcast is delivered - receiverBlueApp.setCached(false); mUidObserver.onUidCachedChanged(getUidForPackage(PACKAGE_BLUE), false); waitForIdle(); verifyScheduleRegisteredReceiver(times(1), receiverBlueApp, timeTick); // Shift green to be active and confirm that deferred broadcast is delivered - receiverGreenApp.setCached(false); mUidObserver.onUidCachedChanged(getUidForPackage(PACKAGE_GREEN), false); waitForIdle(); verifyScheduleRegisteredReceiver(times(1), receiverGreenApp, timeTick); @@ -2044,9 +2042,9 @@ public class BroadcastQueueTest { final ProcessRecord receiverBlueApp = makeActiveProcessRecord(PACKAGE_BLUE); final ProcessRecord receiverYellowApp = makeActiveProcessRecord(PACKAGE_YELLOW); - receiverGreenApp.setCached(true); - receiverBlueApp.setCached(true); - receiverYellowApp.setCached(false); + mUidObserver.onUidCachedChanged(getUidForPackage(PACKAGE_GREEN), true); + mUidObserver.onUidCachedChanged(getUidForPackage(PACKAGE_BLUE), true); + mUidObserver.onUidCachedChanged(getUidForPackage(PACKAGE_YELLOW), false); final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); final BroadcastOptions opts = BroadcastOptions.makeBasic() @@ -2069,7 +2067,6 @@ public class BroadcastQueueTest { verifyScheduleRegisteredReceiver(times(1), receiverYellowApp, airplane); // Shift green to be active and confirm that deferred broadcast is delivered - receiverGreenApp.setCached(false); mUidObserver.onUidCachedChanged(getUidForPackage(PACKAGE_GREEN), false); waitForIdle(); verifyScheduleRegisteredReceiver(times(1), receiverGreenApp, airplane); |