Store "cached" state separate from ProcessRecord.
It ends up that ProcessRecord.isCached() isn't maintained with the same lifecycle as onUidCachedChanged(), so we pivot to maintaining our own collection of last-reported cached states. Bug: 276243219, 275142200, 275594411 Test: atest FrameworksMockingServicesTests:BroadcastQueueTest Test: atest FrameworksMockingServicesTests:BroadcastQueueModernImplTest Test: atest FrameworksMockingServicesTests:BroadcastRecordTest Change-Id: I83531444df5c467a54da9c7fa53eea206677b6e1
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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,10 +1515,19 @@ 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);
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user