Merge "Reland "Track per-process freezable state in BroadcastQueue."" into udc-dev

This commit is contained in:
Sudheer Shanka
2023-06-20 17:17:55 +00:00
committed by Android (Google) Code Review
9 changed files with 178 additions and 105 deletions

View File

@@ -17311,6 +17311,12 @@ public class ActivityManagerService extends IActivityManager.Stub
} }
} }
void onProcessFreezableChangedLocked(ProcessRecord app) {
if (mEnableModernQueue) {
mBroadcastQueues[0].onProcessFreezableChangedLocked(app);
}
}
@VisibleForTesting @VisibleForTesting
public final class LocalService extends ActivityManagerInternal public final class LocalService extends ActivityManagerInternal
implements ActivityManagerLocal { implements ActivityManagerLocal {
@@ -19022,25 +19028,27 @@ public class ActivityManagerService extends IActivityManager.Stub
// too quickly in parallel below // too quickly in parallel below
pingCount.incrementAndGet(); pingCount.incrementAndGet();
synchronized (mProcLock) { synchronized (ActivityManagerService.this) {
final ArrayMap<String, SparseArray<ProcessRecord>> pmap = synchronized (mProcLock) {
mProcessList.getProcessNamesLOSP().getMap(); final ArrayMap<String, SparseArray<ProcessRecord>> pmap =
final int numProc = pmap.size(); mProcessList.getProcessNamesLOSP().getMap();
for (int iProc = 0; iProc < numProc; iProc++) { final int numProc = pmap.size();
final SparseArray<ProcessRecord> apps = pmap.valueAt(iProc); for (int iProc = 0; iProc < numProc; iProc++) {
for (int iApp = 0, numApps = apps.size(); iApp < numApps; iApp++) { final SparseArray<ProcessRecord> apps = pmap.valueAt(iProc);
final ProcessRecord app = apps.valueAt(iApp); for (int iApp = 0, numApps = apps.size(); iApp < numApps; iApp++) {
final IApplicationThread thread = app.getOnewayThread(); final ProcessRecord app = apps.valueAt(iApp);
if (thread != null) { final IApplicationThread thread = app.getOnewayThread();
mOomAdjuster.mCachedAppOptimizer.unfreezeTemporarily(app, if (thread != null) {
CachedAppOptimizer.UNFREEZE_REASON_PING); mOomAdjuster.mCachedAppOptimizer.unfreezeTemporarily(app,
pingCount.incrementAndGet(); CachedAppOptimizer.UNFREEZE_REASON_PING);
try { pingCount.incrementAndGet();
thread.schedulePing(pongCallback); try {
} catch (RemoteException ignored) { thread.schedulePing(pongCallback);
// When we failed to ping remote process, pretend as } catch (RemoteException ignored) {
// if we received the expected pong // When we failed to ping remote process, pretend as
pongCallback.sendResult(null); // if we received the expected pong
pongCallback.sendResult(null);
}
} }
} }
} }

View File

@@ -208,7 +208,7 @@ class BroadcastProcessQueue {
private boolean mLastDeferredStates; private boolean mLastDeferredStates;
private boolean mUidForeground; private boolean mUidForeground;
private boolean mUidCached; private boolean mProcessFreezable;
private boolean mProcessInstrumented; private boolean mProcessInstrumented;
private boolean mProcessPersistent; private boolean mProcessPersistent;
@@ -440,7 +440,7 @@ class BroadcastProcessQueue {
*/ */
@CheckResult @CheckResult
public boolean setProcessAndUidState(@Nullable ProcessRecord app, boolean uidForeground, public boolean setProcessAndUidState(@Nullable ProcessRecord app, boolean uidForeground,
boolean uidCached) { boolean processFreezable) {
this.app = app; this.app = app;
// Since we may have just changed our PID, invalidate cached strings // Since we may have just changed our PID, invalidate cached strings
@@ -449,13 +449,13 @@ class BroadcastProcessQueue {
boolean didSomething = false; boolean didSomething = false;
if (app != null) { if (app != null) {
didSomething |= setUidCached(uidCached);
didSomething |= setUidForeground(uidForeground); didSomething |= setUidForeground(uidForeground);
didSomething |= setProcessFreezable(processFreezable);
didSomething |= setProcessInstrumented(app.getActiveInstrumentation() != null); didSomething |= setProcessInstrumented(app.getActiveInstrumentation() != null);
didSomething |= setProcessPersistent(app.isPersistent()); didSomething |= setProcessPersistent(app.isPersistent());
} else { } else {
didSomething |= setUidCached(uidCached);
didSomething |= setUidForeground(false); didSomething |= setUidForeground(false);
didSomething |= setProcessFreezable(false);
didSomething |= setProcessInstrumented(false); didSomething |= setProcessInstrumented(false);
didSomething |= setProcessPersistent(false); didSomething |= setProcessPersistent(false);
} }
@@ -479,13 +479,13 @@ class BroadcastProcessQueue {
} }
/** /**
* Update if this process is in the "cached" state, typically signaling that * Update if this process is in the "freezable" state, typically signaling that
* broadcast dispatch should be paused or delayed. * broadcast dispatch should be paused or delayed.
*/ */
@CheckResult @CheckResult
private boolean setUidCached(boolean uidCached) { private boolean setProcessFreezable(boolean freezable) {
if (mUidCached != uidCached) { if (mProcessFreezable != freezable) {
mUidCached = uidCached; mProcessFreezable = freezable;
invalidateRunnableAt(); invalidateRunnableAt();
return true; return true;
} else { } else {
@@ -1150,7 +1150,7 @@ class BroadcastProcessQueue {
} else if (mCountManifest > 0) { } else if (mCountManifest > 0) {
mRunnableAt = runnableAt; mRunnableAt = runnableAt;
mRunnableAtReason = REASON_CONTAINS_MANIFEST; mRunnableAtReason = REASON_CONTAINS_MANIFEST;
} else if (mUidCached) { } else if (mProcessFreezable) {
if (r.deferUntilActive) { if (r.deferUntilActive) {
// All enqueued broadcasts are deferrable, defer // All enqueued broadcasts are deferrable, defer
if (mCountDeferred == mCountEnqueued) { if (mCountDeferred == mCountEnqueued) {
@@ -1220,7 +1220,7 @@ class BroadcastProcessQueue {
// When all we have pending is deferred broadcasts, and we're cached, // When all we have pending is deferred broadcasts, and we're cached,
// then we want everything to be marked deferred // then we want everything to be marked deferred
final boolean wantDeferredStates = (mCountDeferred > 0) final boolean wantDeferredStates = (mCountDeferred > 0)
&& (mCountDeferred == mCountEnqueued) && mUidCached; && (mCountDeferred == mCountEnqueued) && mProcessFreezable;
if (mLastDeferredStates != wantDeferredStates) { if (mLastDeferredStates != wantDeferredStates) {
mLastDeferredStates = wantDeferredStates; mLastDeferredStates = wantDeferredStates;
@@ -1407,9 +1407,9 @@ class BroadcastProcessQueue {
if (mUidForeground) { if (mUidForeground) {
sb.append("FG"); sb.append("FG");
} }
if (mUidCached) { if (mProcessFreezable) {
if (sb.length() > 0) sb.append("|"); if (sb.length() > 0) sb.append("|");
sb.append("CACHED"); sb.append("FRZ");
} }
if (mProcessInstrumented) { if (mProcessInstrumented) {
if (sb.length() > 0) sb.append("|"); if (sb.length() > 0) sb.append("|");

View File

@@ -173,6 +173,13 @@ public abstract class BroadcastQueue {
@GuardedBy("mService") @GuardedBy("mService")
public abstract void onApplicationCleanupLocked(@NonNull ProcessRecord app); public abstract void onApplicationCleanupLocked(@NonNull ProcessRecord app);
/**
* Signal from OS internals that the given process is in a freezable state and will be
* frozen soon after.
*/
@GuardedBy("mService")
public abstract void onProcessFreezableChangedLocked(@NonNull ProcessRecord app);
/** /**
* Signal from OS internals that the given package (or some subset of that * Signal from OS internals that the given package (or some subset of that
* package) has been disabled or uninstalled, and that any pending * package) has been disabled or uninstalled, and that any pending

View File

@@ -466,6 +466,10 @@ public class BroadcastQueueImpl extends BroadcastQueue {
skipCurrentOrPendingReceiverLocked(app); skipCurrentOrPendingReceiverLocked(app);
} }
public void onProcessFreezableChangedLocked(ProcessRecord app) {
// Not supported; ignore
}
public boolean sendPendingBroadcastsLocked(ProcessRecord app) public boolean sendPendingBroadcastsLocked(ProcessRecord app)
throws BroadcastDeliveryFailedException { throws BroadcastDeliveryFailedException {
boolean didSomething = false; boolean didSomething = false;

View File

@@ -232,16 +232,6 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
@GuardedBy("mService") @GuardedBy("mService")
private final SparseBooleanArray mUidForeground = new SparseBooleanArray(); private final SparseBooleanArray mUidForeground = new SparseBooleanArray();
/**
* 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 mConstants;
private final BroadcastConstants mFgConstants; private final BroadcastConstants mFgConstants;
private final BroadcastConstants mBgConstants; private final BroadcastConstants mBgConstants;
@@ -258,6 +248,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
private static final int MSG_BG_ACTIVITY_START_TIMEOUT = 4; private static final int MSG_BG_ACTIVITY_START_TIMEOUT = 4;
private static final int MSG_CHECK_HEALTH = 5; private static final int MSG_CHECK_HEALTH = 5;
private static final int MSG_CHECK_PENDING_COLD_START_VALIDITY = 6; private static final int MSG_CHECK_PENDING_COLD_START_VALIDITY = 6;
private static final int MSG_PROCESS_FREEZABLE_CHANGED = 7;
private void enqueueUpdateRunningList() { private void enqueueUpdateRunningList() {
mLocalHandler.removeMessages(MSG_UPDATE_RUNNING_LIST); mLocalHandler.removeMessages(MSG_UPDATE_RUNNING_LIST);
@@ -298,6 +289,12 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
checkPendingColdStartValidity(); checkPendingColdStartValidity();
return true; return true;
} }
case MSG_PROCESS_FREEZABLE_CHANGED: {
synchronized (mService) {
refreshProcessQueueLocked((ProcessRecord) msg.obj);
}
return true;
}
} }
return false; return false;
}; };
@@ -672,6 +669,12 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
enqueueUpdateRunningList(); enqueueUpdateRunningList();
} }
@Override
public void onProcessFreezableChangedLocked(@NonNull ProcessRecord app) {
mLocalHandler.removeMessages(MSG_PROCESS_FREEZABLE_CHANGED, app);
mLocalHandler.sendMessage(mHandler.obtainMessage(MSG_PROCESS_FREEZABLE_CHANGED, app));
}
@Override @Override
public int getPreferredSchedulingGroupLocked(@NonNull ProcessRecord app) { public int getPreferredSchedulingGroupLocked(@NonNull ProcessRecord app) {
final BroadcastProcessQueue queue = getProcessQueue(app); final BroadcastProcessQueue queue = getProcessQueue(app);
@@ -1465,7 +1468,6 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
}; };
broadcastPredicate = BROADCAST_PREDICATE_ANY; broadcastPredicate = BROADCAST_PREDICATE_ANY;
cleanupUserStateLocked(mUidCached, userId);
cleanupUserStateLocked(mUidForeground, userId); cleanupUserStateLocked(mUidForeground, userId);
} }
return forEachMatchingBroadcast(queuePredicate, broadcastPredicate, return forEachMatchingBroadcast(queuePredicate, broadcastPredicate,
@@ -1611,22 +1613,6 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
}, ActivityManager.UID_OBSERVER_PROCSTATE, }, ActivityManager.UID_OBSERVER_PROCSTATE,
ActivityManager.PROCESS_STATE_TOP, "android"); ActivityManager.PROCESS_STATE_TOP, "android");
mService.registerUidObserver(new UidObserver() {
@Override
public void onUidStateChanged(int uid, int procState, long procStateSeq,
int capability) {
synchronized (mService) {
if (procState > ActivityManager.PROCESS_STATE_LAST_ACTIVITY) {
mUidCached.put(uid, true);
} else {
mUidCached.delete(uid);
}
refreshProcessQueuesLocked(uid);
}
}
}, ActivityManager.UID_OBSERVER_PROCSTATE,
ActivityManager.PROCESS_STATE_LAST_ACTIVITY, "android");
// Kick off periodic health checks // Kick off periodic health checks
mLocalHandler.sendEmptyMessage(MSG_CHECK_HEALTH); mLocalHandler.sendEmptyMessage(MSG_CHECK_HEALTH);
} }
@@ -1814,10 +1800,9 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
// warm via this operation, we're going to immediately promote it to // warm via this operation, we're going to immediately promote it to
// be running, and any side effect of this operation will then apply // be running, and any side effect of this operation will then apply
// after it's finished and is returned to the runnable list. // after it's finished and is returned to the runnable list.
queue.setProcessAndUidState( final ProcessRecord app = mService.getProcessRecordLocked(queue.processName, queue.uid);
mService.getProcessRecordLocked(queue.processName, queue.uid), queue.setProcessAndUidState(app, mUidForeground.get(queue.uid, false),
mUidForeground.get(queue.uid, false), isProcessFreezable(app));
mUidCached.get(queue.uid, false));
} }
} }
@@ -1829,11 +1814,21 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
private void setQueueProcess(@NonNull BroadcastProcessQueue queue, private void setQueueProcess(@NonNull BroadcastProcessQueue queue,
@Nullable ProcessRecord app) { @Nullable ProcessRecord app) {
if (queue.setProcessAndUidState(app, mUidForeground.get(queue.uid, false), if (queue.setProcessAndUidState(app, mUidForeground.get(queue.uid, false),
mUidCached.get(queue.uid, false))) { isProcessFreezable(app))) {
updateRunnableList(queue); updateRunnableList(queue);
} }
} }
@GuardedBy("mService")
private boolean isProcessFreezable(@Nullable ProcessRecord app) {
if (app == null) {
return false;
}
synchronized (mService.mProcLock) {
return app.mOptRecord.isPendingFreeze() || app.mOptRecord.isFrozen();
}
}
/** /**
* Refresh the process queues with the latest process state so that runnableAt * Refresh the process queues with the latest process state so that runnableAt
* can be updated. * can be updated.
@@ -1850,6 +1845,20 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
enqueueUpdateRunningList(); enqueueUpdateRunningList();
} }
/**
* Refresh the process queue corresponding to {@code app} with the latest process state
* so that runnableAt can be updated.
*/
@GuardedBy("mService")
private void refreshProcessQueueLocked(@NonNull ProcessRecord app) {
final BroadcastProcessQueue queue = getProcessQueue(app.processName, app.uid);
if (queue == null || queue.app == null || queue.app.getPid() != app.getPid()) {
return;
}
setQueueProcess(queue, queue.app);
enqueueUpdateRunningList();
}
/** /**
* Inform other parts of OS that the given broadcast queue has started * Inform other parts of OS that the given broadcast queue has started
* running, typically for internal bookkeeping. * running, typically for internal bookkeeping.
@@ -2176,12 +2185,6 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
ipw.decreaseIndent(); ipw.decreaseIndent();
ipw.println(); ipw.println();
ipw.println("Cached UIDs:");
ipw.increaseIndent();
ipw.println(mUidCached);
ipw.decreaseIndent();
ipw.println();
ipw.println("Foreground UIDs:"); ipw.println("Foreground UIDs:");
ipw.increaseIndent(); ipw.increaseIndent();
ipw.println(mUidForeground); ipw.println(mUidForeground);

View File

@@ -1402,6 +1402,7 @@ public final class CachedAppOptimizer {
} }
} }
} }
reportProcessFreezableChangedLocked(app);
app.mOptRecord.setLastUsedTimeout(delayMillis); app.mOptRecord.setLastUsedTimeout(delayMillis);
mFreezeHandler.sendMessageDelayed( mFreezeHandler.sendMessageDelayed(
mFreezeHandler.obtainMessage(SET_FROZEN_PROCESS_MSG, DO_FREEZE, 0, app), mFreezeHandler.obtainMessage(SET_FROZEN_PROCESS_MSG, DO_FREEZE, 0, app),
@@ -1440,6 +1441,7 @@ public final class CachedAppOptimizer {
uidRec.setFrozen(false); uidRec.setFrozen(false);
postUidFrozenMessage(uidRec.getUid(), false); postUidFrozenMessage(uidRec.getUid(), false);
} }
reportProcessFreezableChangedLocked(app);
opt.setFreezerOverride(false); opt.setFreezerOverride(false);
if (pid == 0 || !opt.isFrozen()) { if (pid == 0 || !opt.isFrozen()) {
@@ -2121,6 +2123,11 @@ public final class CachedAppOptimizer {
0, uidObj)); 0, uidObj));
} }
@GuardedBy("mAm")
private void reportProcessFreezableChangedLocked(ProcessRecord app) {
mAm.onProcessFreezableChangedLocked(app);
}
private final class FreezeHandler extends Handler implements private final class FreezeHandler extends Handler implements
ProcLocksReader.ProcLocksReaderCallback { ProcLocksReader.ProcLocksReaderCallback {
private FreezeHandler() { private FreezeHandler() {
@@ -2130,7 +2137,7 @@ public final class CachedAppOptimizer {
@Override @Override
public void handleMessage(Message msg) { public void handleMessage(Message msg) {
switch (msg.what) { switch (msg.what) {
case SET_FROZEN_PROCESS_MSG: case SET_FROZEN_PROCESS_MSG: {
ProcessRecord proc = (ProcessRecord) msg.obj; ProcessRecord proc = (ProcessRecord) msg.obj;
synchronized (mAm) { synchronized (mAm) {
freezeProcess(proc); freezeProcess(proc);
@@ -2140,8 +2147,8 @@ public final class CachedAppOptimizer {
removeMessages(DEADLOCK_WATCHDOG_MSG); removeMessages(DEADLOCK_WATCHDOG_MSG);
sendEmptyMessageDelayed(DEADLOCK_WATCHDOG_MSG, FREEZE_DEADLOCK_TIMEOUT_MS); sendEmptyMessageDelayed(DEADLOCK_WATCHDOG_MSG, FREEZE_DEADLOCK_TIMEOUT_MS);
} }
break; } break;
case REPORT_UNFREEZE_MSG: case REPORT_UNFREEZE_MSG: {
int pid = msg.arg1; int pid = msg.arg1;
int frozenDuration = msg.arg2; int frozenDuration = msg.arg2;
Pair<String, Integer> obj = (Pair<String, Integer>) msg.obj; Pair<String, Integer> obj = (Pair<String, Integer>) msg.obj;
@@ -2149,13 +2156,13 @@ public final class CachedAppOptimizer {
int reason = obj.second; int reason = obj.second;
reportUnfreeze(pid, frozenDuration, processName, reason); reportUnfreeze(pid, frozenDuration, processName, reason);
break; } break;
case UID_FROZEN_STATE_CHANGED_MSG: case UID_FROZEN_STATE_CHANGED_MSG: {
final boolean frozen = (msg.arg1 == 1); final boolean frozen = (msg.arg1 == 1);
final int uid = (int) msg.obj; final int uid = (int) msg.obj;
reportOneUidFrozenStateChanged(uid, frozen); reportOneUidFrozenStateChanged(uid, frozen);
break; } break;
case DEADLOCK_WATCHDOG_MSG: case DEADLOCK_WATCHDOG_MSG: {
try { try {
// post-check to prevent deadlock // post-check to prevent deadlock
if (DEBUG_FREEZER) { if (DEBUG_FREEZER) {
@@ -2165,7 +2172,7 @@ public final class CachedAppOptimizer {
} catch (IOException e) { } catch (IOException e) {
Slog.w(TAG_AM, "Unable to check file locks"); Slog.w(TAG_AM, "Unable to check file locks");
} }
break; } break;
default: default:
return; return;
} }

View File

@@ -1197,6 +1197,9 @@ class ProcessRecord implements WindowProcessListener {
"Killing " + toShortString() + " (adj " + mState.getSetAdj() "Killing " + toShortString() + " (adj " + mState.getSetAdj()
+ "): " + reason, info.uid); + "): " + reason, info.uid);
} }
// Since the process is getting killed, reset the freezable related state.
mOptRecord.setPendingFreeze(false);
mOptRecord.setFrozen(false);
if (mPid > 0) { if (mPid > 0) {
mService.mProcessList.noteAppKill(this, reasonCode, subReason, description); mService.mProcessList.noteAppKill(this, reasonCode, subReason, description);
EventLog.writeEvent(EventLogTags.AM_KILL, EventLog.writeEvent(EventLogTags.AM_KILL,

View File

@@ -410,9 +410,9 @@ public final class BroadcastQueueModernImplTest {
List.of(makeMockRegisteredReceiver()), false); List.of(makeMockRegisteredReceiver()), false);
enqueueOrReplaceBroadcast(queue, airplaneRecord, 0); enqueueOrReplaceBroadcast(queue, airplaneRecord, 0);
queue.setProcessAndUidState(null, false, false); queue.setProcessAndUidState(mProcess, false, false);
final long notCachedRunnableAt = queue.getRunnableAt(); final long notCachedRunnableAt = queue.getRunnableAt();
queue.setProcessAndUidState(null, false, true); queue.setProcessAndUidState(mProcess, false, true);
final long cachedRunnableAt = queue.getRunnableAt(); final long cachedRunnableAt = queue.getRunnableAt();
assertThat(cachedRunnableAt).isGreaterThan(notCachedRunnableAt); assertThat(cachedRunnableAt).isGreaterThan(notCachedRunnableAt);
assertFalse(queue.isRunnable()); assertFalse(queue.isRunnable());
@@ -437,9 +437,9 @@ public final class BroadcastQueueModernImplTest {
List.of(makeMockRegisteredReceiver()), false); List.of(makeMockRegisteredReceiver()), false);
enqueueOrReplaceBroadcast(queue, airplaneRecord, 0); enqueueOrReplaceBroadcast(queue, airplaneRecord, 0);
queue.setProcessAndUidState(null, false, false); queue.setProcessAndUidState(mProcess, false, false);
final long notCachedRunnableAt = queue.getRunnableAt(); final long notCachedRunnableAt = queue.getRunnableAt();
queue.setProcessAndUidState(null, false, true); queue.setProcessAndUidState(mProcess, false, true);
final long cachedRunnableAt = queue.getRunnableAt(); final long cachedRunnableAt = queue.getRunnableAt();
assertThat(cachedRunnableAt).isGreaterThan(notCachedRunnableAt); assertThat(cachedRunnableAt).isGreaterThan(notCachedRunnableAt);
assertTrue(queue.isRunnable()); assertTrue(queue.isRunnable());

View File

@@ -421,6 +421,12 @@ public class BroadcastQueueTest {
UserHandle.USER_SYSTEM); UserHandle.USER_SYSTEM);
} }
private ProcessRecord makeActiveProcessRecord(String packageName, String processName)
throws Exception {
return makeActiveProcessRecord(packageName, processName, ProcessBehavior.NORMAL,
UserHandle.USER_SYSTEM);
}
private ProcessRecord makeActiveProcessRecord(String packageName, private ProcessRecord makeActiveProcessRecord(String packageName,
ProcessBehavior behavior) throws Exception { ProcessBehavior behavior) throws Exception {
return makeActiveProcessRecord(packageName, packageName, behavior, UserHandle.USER_SYSTEM); return makeActiveProcessRecord(packageName, packageName, behavior, UserHandle.USER_SYSTEM);
@@ -623,6 +629,11 @@ public class BroadcastQueueTest {
BackgroundStartPrivileges.NONE, false, null, PROCESS_STATE_UNKNOWN); BackgroundStartPrivileges.NONE, false, null, PROCESS_STATE_UNKNOWN);
} }
private void setProcessFreezable(ProcessRecord app, boolean pendingFreeze, boolean frozen) {
app.mOptRecord.setPendingFreeze(pendingFreeze);
app.mOptRecord.setFrozen(frozen);
}
private void assertHealth() { private void assertHealth() {
if (mImpl == Impl.MODERN) { if (mImpl == Impl.MODERN) {
// If this fails, it'll throw a clear reason message // If this fails, it'll throw a clear reason message
@@ -1769,12 +1780,10 @@ public class BroadcastQueueTest {
final ProcessRecord receiverYellowApp = makeActiveProcessRecord(PACKAGE_YELLOW); final ProcessRecord receiverYellowApp = makeActiveProcessRecord(PACKAGE_YELLOW);
final ProcessRecord receiverOrangeApp = makeActiveProcessRecord(PACKAGE_ORANGE); final ProcessRecord receiverOrangeApp = makeActiveProcessRecord(PACKAGE_ORANGE);
mUidCachedStateObserver.onUidStateChanged(getUidForPackage(PACKAGE_GREEN), setProcessFreezable(receiverGreenApp, true, false);
ActivityManager.PROCESS_STATE_CACHED_ACTIVITY, 0, mQueue.onProcessFreezableChangedLocked(receiverGreenApp);
ActivityManager.PROCESS_CAPABILITY_NONE); setProcessFreezable(receiverBlueApp, false, true);
mUidCachedStateObserver.onUidStateChanged(getUidForPackage(PACKAGE_BLUE), mQueue.onProcessFreezableChangedLocked(receiverBlueApp);
ActivityManager.PROCESS_STATE_CACHED_EMPTY, 0,
ActivityManager.PROCESS_CAPABILITY_NONE);
final Intent timeTick = new Intent(Intent.ACTION_TIME_TICK); final Intent timeTick = new Intent(Intent.ACTION_TIME_TICK);
final BroadcastOptions opts = BroadcastOptions.makeBasic() final BroadcastOptions opts = BroadcastOptions.makeBasic()
@@ -1818,16 +1827,14 @@ public class BroadcastQueueTest {
eq(UserHandle.USER_SYSTEM), anyInt(), anyInt(), any()); eq(UserHandle.USER_SYSTEM), anyInt(), anyInt(), any());
// Shift blue to be active and confirm that deferred broadcast is delivered // Shift blue to be active and confirm that deferred broadcast is delivered
mUidCachedStateObserver.onUidStateChanged(getUidForPackage(PACKAGE_BLUE), setProcessFreezable(receiverBlueApp, false, false);
ActivityManager.PROCESS_STATE_TOP, 0, mQueue.onProcessFreezableChangedLocked(receiverBlueApp);
ActivityManager.PROCESS_CAPABILITY_NONE);
waitForIdle(); waitForIdle();
verifyScheduleRegisteredReceiver(times(1), receiverBlueApp, timeTick); verifyScheduleRegisteredReceiver(times(1), receiverBlueApp, timeTick);
// Shift green to be active and confirm that deferred broadcast is delivered // Shift green to be active and confirm that deferred broadcast is delivered
mUidCachedStateObserver.onUidStateChanged(getUidForPackage(PACKAGE_GREEN), setProcessFreezable(receiverGreenApp, false, false);
ActivityManager.PROCESS_STATE_SERVICE, 0, mQueue.onProcessFreezableChangedLocked(receiverGreenApp);
ActivityManager.PROCESS_CAPABILITY_NONE);
waitForIdle(); waitForIdle();
verifyScheduleRegisteredReceiver(times(1), receiverGreenApp, timeTick); verifyScheduleRegisteredReceiver(times(1), receiverGreenApp, timeTick);
} }
@@ -2252,15 +2259,12 @@ public class BroadcastQueueTest {
final ProcessRecord receiverBlueApp = makeActiveProcessRecord(PACKAGE_BLUE); final ProcessRecord receiverBlueApp = makeActiveProcessRecord(PACKAGE_BLUE);
final ProcessRecord receiverYellowApp = makeActiveProcessRecord(PACKAGE_YELLOW); final ProcessRecord receiverYellowApp = makeActiveProcessRecord(PACKAGE_YELLOW);
mUidCachedStateObserver.onUidStateChanged(getUidForPackage(PACKAGE_GREEN), setProcessFreezable(receiverGreenApp, true, true);
ActivityManager.PROCESS_STATE_CACHED_ACTIVITY, 0, mQueue.onProcessFreezableChangedLocked(receiverGreenApp);
ActivityManager.PROCESS_CAPABILITY_NONE); setProcessFreezable(receiverBlueApp, true, false);
mUidCachedStateObserver.onUidStateChanged(getUidForPackage(PACKAGE_BLUE), mQueue.onProcessFreezableChangedLocked(receiverBlueApp);
ActivityManager.PROCESS_STATE_CACHED_EMPTY, 0, setProcessFreezable(receiverYellowApp, false, false);
ActivityManager.PROCESS_CAPABILITY_NONE); mQueue.onProcessFreezableChangedLocked(receiverYellowApp);
mUidCachedStateObserver.onUidStateChanged(getUidForPackage(PACKAGE_YELLOW),
ActivityManager.PROCESS_STATE_SERVICE, 0,
ActivityManager.PROCESS_CAPABILITY_NONE);
final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
final BroadcastOptions opts = BroadcastOptions.makeBasic() final BroadcastOptions opts = BroadcastOptions.makeBasic()
@@ -2283,13 +2287,50 @@ public class BroadcastQueueTest {
verifyScheduleRegisteredReceiver(times(1), receiverYellowApp, airplane); verifyScheduleRegisteredReceiver(times(1), receiverYellowApp, airplane);
// Shift green to be active and confirm that deferred broadcast is delivered // Shift green to be active and confirm that deferred broadcast is delivered
mUidCachedStateObserver.onUidStateChanged(getUidForPackage(PACKAGE_GREEN), setProcessFreezable(receiverGreenApp, false, false);
ActivityManager.PROCESS_STATE_TOP_SLEEPING, 0, mQueue.onProcessFreezableChangedLocked(receiverGreenApp);
ActivityManager.PROCESS_CAPABILITY_NONE);
waitForIdle(); waitForIdle();
verifyScheduleRegisteredReceiver(times(1), receiverGreenApp, airplane); verifyScheduleRegisteredReceiver(times(1), receiverGreenApp, airplane);
} }
/**
* Verify broadcasts to a runtime receiver in cached process is deferred even when a different
* process in the same package is not cached.
*/
@Test
public void testDeferralPolicy_UntilActive_WithMultiProcessUid() throws Exception {
// Legacy stack doesn't support deferral
Assume.assumeTrue(mImpl == Impl.MODERN);
final ProcessRecord callerApp = makeActiveProcessRecord(PACKAGE_RED);
final ProcessRecord receiverGreenApp1 = makeActiveProcessRecord(PACKAGE_GREEN);
final ProcessRecord receiverGreenApp2 = makeActiveProcessRecord(PACKAGE_GREEN,
PACKAGE_GREEN + "_proc2");
setProcessFreezable(receiverGreenApp1, true, true);
mQueue.onProcessFreezableChangedLocked(receiverGreenApp1);
final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
final BroadcastOptions opts = BroadcastOptions.makeBasic()
.setDeferralPolicy(BroadcastOptions.DEFERRAL_POLICY_UNTIL_ACTIVE);
enqueueBroadcast(makeBroadcastRecord(airplane, callerApp, opts,
List.of(makeRegisteredReceiver(receiverGreenApp1),
makeRegisteredReceiver(receiverGreenApp2))));
waitForIdle();
// 1st process in Green package is ignored since it is in a cached state
// but the 2nd process should still receive the broadcast.
verifyScheduleRegisteredReceiver(never(), receiverGreenApp1, airplane);
verifyScheduleRegisteredReceiver(times(1), receiverGreenApp2, airplane);
// Shift the 1st process in Green package to be active and confirm that deferred broadcast
// is delivered
setProcessFreezable(receiverGreenApp1, false, false);
mQueue.onProcessFreezableChangedLocked(receiverGreenApp1);
waitForIdle();
verifyScheduleRegisteredReceiver(times(1), receiverGreenApp1, airplane);
}
@Test @Test
public void testBroadcastDelivery_uidForeground() throws Exception { public void testBroadcastDelivery_uidForeground() throws Exception {
// Legacy stack doesn't support prioritization to foreground app. // Legacy stack doesn't support prioritization to foreground app.