Merge "Track per-process freezable state in BroadcastQueue." into udc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
a8dbdd9477
@@ -17236,6 +17236,12 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
}
|
||||
}
|
||||
|
||||
void onProcessFreezableChangedLocked(ProcessRecord app) {
|
||||
if (mEnableModernQueue) {
|
||||
mBroadcastQueues[0].onProcessFreezableChangedLocked(app);
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public final class LocalService extends ActivityManagerInternal
|
||||
implements ActivityManagerLocal {
|
||||
|
||||
@@ -201,7 +201,7 @@ class BroadcastProcessQueue {
|
||||
private boolean mLastDeferredStates;
|
||||
|
||||
private boolean mUidForeground;
|
||||
private boolean mUidCached;
|
||||
private boolean mProcessFreezable;
|
||||
private boolean mProcessInstrumented;
|
||||
private boolean mProcessPersistent;
|
||||
|
||||
@@ -411,7 +411,7 @@ class BroadcastProcessQueue {
|
||||
*/
|
||||
@CheckResult
|
||||
public boolean setProcessAndUidState(@Nullable ProcessRecord app, boolean uidForeground,
|
||||
boolean uidCached) {
|
||||
boolean processFreezable) {
|
||||
this.app = app;
|
||||
|
||||
// Since we may have just changed our PID, invalidate cached strings
|
||||
@@ -420,13 +420,13 @@ class BroadcastProcessQueue {
|
||||
|
||||
boolean didSomething = false;
|
||||
if (app != null) {
|
||||
didSomething |= setUidCached(uidCached);
|
||||
didSomething |= setUidForeground(uidForeground);
|
||||
didSomething |= setProcessFreezable(processFreezable);
|
||||
didSomething |= setProcessInstrumented(app.getActiveInstrumentation() != null);
|
||||
didSomething |= setProcessPersistent(app.isPersistent());
|
||||
} else {
|
||||
didSomething |= setUidCached(uidCached);
|
||||
didSomething |= setUidForeground(false);
|
||||
didSomething |= setProcessFreezable(false);
|
||||
didSomething |= setProcessInstrumented(false);
|
||||
didSomething |= setProcessPersistent(false);
|
||||
}
|
||||
@@ -450,13 +450,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.
|
||||
*/
|
||||
@CheckResult
|
||||
private boolean setUidCached(boolean uidCached) {
|
||||
if (mUidCached != uidCached) {
|
||||
mUidCached = uidCached;
|
||||
private boolean setProcessFreezable(boolean freezable) {
|
||||
if (mProcessFreezable != freezable) {
|
||||
mProcessFreezable = freezable;
|
||||
invalidateRunnableAt();
|
||||
return true;
|
||||
} else {
|
||||
@@ -1115,7 +1115,7 @@ class BroadcastProcessQueue {
|
||||
} else if (mCountManifest > 0) {
|
||||
mRunnableAt = runnableAt;
|
||||
mRunnableAtReason = REASON_CONTAINS_MANIFEST;
|
||||
} else if (mUidCached) {
|
||||
} else if (mProcessFreezable) {
|
||||
if (r.deferUntilActive) {
|
||||
// All enqueued broadcasts are deferrable, defer
|
||||
if (mCountDeferred == mCountEnqueued) {
|
||||
@@ -1185,7 +1185,7 @@ class BroadcastProcessQueue {
|
||||
// When all we have pending is deferred broadcasts, and we're cached,
|
||||
// then we want everything to be marked deferred
|
||||
final boolean wantDeferredStates = (mCountDeferred > 0)
|
||||
&& (mCountDeferred == mCountEnqueued) && mUidCached;
|
||||
&& (mCountDeferred == mCountEnqueued) && mProcessFreezable;
|
||||
|
||||
if (mLastDeferredStates != wantDeferredStates) {
|
||||
mLastDeferredStates = wantDeferredStates;
|
||||
@@ -1372,9 +1372,9 @@ class BroadcastProcessQueue {
|
||||
if (mUidForeground) {
|
||||
sb.append("FG");
|
||||
}
|
||||
if (mUidCached) {
|
||||
if (mProcessFreezable) {
|
||||
if (sb.length() > 0) sb.append("|");
|
||||
sb.append("CACHED");
|
||||
sb.append("FRZN");
|
||||
}
|
||||
if (mProcessInstrumented) {
|
||||
if (sb.length() > 0) sb.append("|");
|
||||
|
||||
@@ -172,6 +172,13 @@ public abstract class BroadcastQueue {
|
||||
@GuardedBy("mService")
|
||||
public abstract void onApplicationCleanupLocked(@NonNull ProcessRecord app);
|
||||
|
||||
/**
|
||||
* Signal from OS internals that the given process is in a freezable state and will be
|
||||
* freezed soon after.
|
||||
*/
|
||||
@GuardedBy("mService")
|
||||
public abstract void onProcessFreezableChangedLocked(@NonNull ProcessRecord app);
|
||||
|
||||
/**
|
||||
* Signal from OS internals that the given package (or some subset of that
|
||||
* package) has been disabled or uninstalled, and that any pending
|
||||
|
||||
@@ -449,6 +449,10 @@ public class BroadcastQueueImpl extends BroadcastQueue {
|
||||
skipCurrentOrPendingReceiverLocked(app);
|
||||
}
|
||||
|
||||
public void onProcessFreezableChangedLocked(ProcessRecord app) {
|
||||
// Not supported; ignore
|
||||
}
|
||||
|
||||
public boolean sendPendingBroadcastsLocked(ProcessRecord app) {
|
||||
boolean didSomething = false;
|
||||
final BroadcastRecord br = mPendingBroadcast;
|
||||
|
||||
@@ -223,16 +223,6 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
|
||||
@GuardedBy("mService")
|
||||
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 mFgConstants;
|
||||
private final BroadcastConstants mBgConstants;
|
||||
@@ -574,6 +564,13 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProcessFreezableChangedLocked(@NonNull ProcessRecord app) {
|
||||
synchronized (mService) {
|
||||
refreshProcessQueueLocked(app);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPreferredSchedulingGroupLocked(@NonNull ProcessRecord app) {
|
||||
final BroadcastProcessQueue queue = getProcessQueue(app);
|
||||
@@ -1305,7 +1302,6 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
|
||||
};
|
||||
broadcastPredicate = BROADCAST_PREDICATE_ANY;
|
||||
|
||||
cleanupUserStateLocked(mUidCached, userId);
|
||||
cleanupUserStateLocked(mUidForeground, userId);
|
||||
}
|
||||
return forEachMatchingBroadcast(queuePredicate, broadcastPredicate,
|
||||
@@ -1448,20 +1444,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
|
||||
refreshProcessQueuesLocked(uid);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUidCachedChanged(int uid, boolean cached) {
|
||||
synchronized (mService) {
|
||||
if (cached) {
|
||||
mUidCached.put(uid, true);
|
||||
} else {
|
||||
mUidCached.delete(uid);
|
||||
}
|
||||
refreshProcessQueuesLocked(uid);
|
||||
}
|
||||
}
|
||||
}, ActivityManager.UID_OBSERVER_PROCSTATE | ActivityManager.UID_OBSERVER_CACHED,
|
||||
ActivityManager.PROCESS_STATE_TOP, "android");
|
||||
}, ActivityManager.UID_OBSERVER_PROCSTATE, ActivityManager.PROCESS_STATE_TOP, "android");
|
||||
|
||||
// Kick off periodic health checks
|
||||
mLocalHandler.sendEmptyMessage(MSG_CHECK_HEALTH);
|
||||
@@ -1650,10 +1633,9 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
|
||||
// warm via this operation, we're going to immediately promote it to
|
||||
// be running, and any side effect of this operation will then apply
|
||||
// after it's finished and is returned to the runnable list.
|
||||
queue.setProcessAndUidState(
|
||||
mService.getProcessRecordLocked(queue.processName, queue.uid),
|
||||
mUidForeground.get(queue.uid, false),
|
||||
mUidCached.get(queue.uid, false));
|
||||
final ProcessRecord app = mService.getProcessRecordLocked(queue.processName, queue.uid);
|
||||
queue.setProcessAndUidState(app, mUidForeground.get(queue.uid, false),
|
||||
isProcessFreezable(app));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1665,11 +1647,21 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
|
||||
private void setQueueProcess(@NonNull BroadcastProcessQueue queue,
|
||||
@Nullable ProcessRecord app) {
|
||||
if (queue.setProcessAndUidState(app, mUidForeground.get(queue.uid, false),
|
||||
mUidCached.get(queue.uid, false))) {
|
||||
isProcessFreezable(app))) {
|
||||
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
|
||||
* can be updated.
|
||||
@@ -1686,6 +1678,20 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
|
||||
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
|
||||
* running, typically for internal bookkeeping.
|
||||
@@ -2005,12 +2011,6 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
|
||||
ipw.decreaseIndent();
|
||||
ipw.println();
|
||||
|
||||
ipw.println("Cached UIDs:");
|
||||
ipw.increaseIndent();
|
||||
ipw.println(mUidCached);
|
||||
ipw.decreaseIndent();
|
||||
ipw.println();
|
||||
|
||||
ipw.println("Foreground UIDs:");
|
||||
ipw.increaseIndent();
|
||||
ipw.println(mUidForeground);
|
||||
|
||||
@@ -300,6 +300,7 @@ public final class CachedAppOptimizer {
|
||||
static final int COMPACT_NATIVE_MSG = 5;
|
||||
static final int UID_FROZEN_STATE_CHANGED_MSG = 6;
|
||||
static final int DEADLOCK_WATCHDOG_MSG = 7;
|
||||
static final int REPORT_PROCESS_FREEZABLE_CHANGED = 8;
|
||||
|
||||
// When free swap falls below this percentage threshold any full (file + anon)
|
||||
// compactions will be downgraded to file only compactions to reduce pressure
|
||||
@@ -1352,6 +1353,7 @@ public final class CachedAppOptimizer {
|
||||
}
|
||||
}
|
||||
}
|
||||
postProcessFreezableChangedMessage(app);
|
||||
mFreezeHandler.sendMessageDelayed(
|
||||
mFreezeHandler.obtainMessage(SET_FROZEN_PROCESS_MSG, DO_FREEZE, 0, app),
|
||||
delayMillis);
|
||||
@@ -1389,6 +1391,7 @@ public final class CachedAppOptimizer {
|
||||
uidRec.setFrozen(false);
|
||||
postUidFrozenMessage(uidRec.getUid(), false);
|
||||
}
|
||||
postProcessFreezableChangedMessage(app);
|
||||
|
||||
opt.setFreezerOverride(false);
|
||||
if (pid == 0 || !opt.isFrozen()) {
|
||||
@@ -2066,6 +2069,21 @@ public final class CachedAppOptimizer {
|
||||
0, uidObj));
|
||||
}
|
||||
|
||||
private void reportProcessFreezableChanged(ProcessRecord app) {
|
||||
synchronized (mAm) {
|
||||
mAm.onProcessFreezableChangedLocked(app);
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("mAm")
|
||||
private void postProcessFreezableChangedMessage(ProcessRecord app) {
|
||||
if (app.getPid() == 0) {
|
||||
return;
|
||||
}
|
||||
mFreezeHandler.obtainMessage(REPORT_PROCESS_FREEZABLE_CHANGED, 0, 0, app)
|
||||
.sendToTarget();
|
||||
}
|
||||
|
||||
private final class FreezeHandler extends Handler implements
|
||||
ProcLocksReader.ProcLocksReaderCallback {
|
||||
private FreezeHandler() {
|
||||
@@ -2075,7 +2093,7 @@ public final class CachedAppOptimizer {
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
case SET_FROZEN_PROCESS_MSG:
|
||||
case SET_FROZEN_PROCESS_MSG: {
|
||||
ProcessRecord proc = (ProcessRecord) msg.obj;
|
||||
synchronized (mAm) {
|
||||
freezeProcess(proc);
|
||||
@@ -2085,8 +2103,8 @@ public final class CachedAppOptimizer {
|
||||
removeMessages(DEADLOCK_WATCHDOG_MSG);
|
||||
sendEmptyMessageDelayed(DEADLOCK_WATCHDOG_MSG, FREEZE_DEADLOCK_TIMEOUT_MS);
|
||||
}
|
||||
break;
|
||||
case REPORT_UNFREEZE_MSG:
|
||||
} break;
|
||||
case REPORT_UNFREEZE_MSG: {
|
||||
int pid = msg.arg1;
|
||||
int frozenDuration = msg.arg2;
|
||||
Pair<String, Integer> obj = (Pair<String, Integer>) msg.obj;
|
||||
@@ -2094,13 +2112,13 @@ public final class CachedAppOptimizer {
|
||||
int reason = obj.second;
|
||||
|
||||
reportUnfreeze(pid, frozenDuration, processName, reason);
|
||||
break;
|
||||
case UID_FROZEN_STATE_CHANGED_MSG:
|
||||
} break;
|
||||
case UID_FROZEN_STATE_CHANGED_MSG: {
|
||||
final boolean frozen = (msg.arg1 == 1);
|
||||
final int uid = (int) msg.obj;
|
||||
reportOneUidFrozenStateChanged(uid, frozen);
|
||||
break;
|
||||
case DEADLOCK_WATCHDOG_MSG:
|
||||
} break;
|
||||
case DEADLOCK_WATCHDOG_MSG: {
|
||||
try {
|
||||
// post-check to prevent deadlock
|
||||
if (DEBUG_FREEZER) {
|
||||
@@ -2110,7 +2128,11 @@ public final class CachedAppOptimizer {
|
||||
} catch (IOException e) {
|
||||
Slog.w(TAG_AM, "Unable to check file locks");
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
case REPORT_PROCESS_FREEZABLE_CHANGED: {
|
||||
final ProcessRecord app = (ProcessRecord) msg.obj;
|
||||
reportProcessFreezableChanged(app);
|
||||
} break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1192,6 +1192,9 @@ class ProcessRecord implements WindowProcessListener {
|
||||
"Killing " + toShortString() + " (adj " + mState.getSetAdj()
|
||||
+ "): " + reason, info.uid);
|
||||
}
|
||||
// Since the process is getting killed, reset the freezable related state.
|
||||
mOptRecord.setPendingFreeze(false);
|
||||
mOptRecord.setFrozen(false);
|
||||
if (mPid > 0) {
|
||||
mService.mProcessList.noteAppKill(this, reasonCode, subReason, description);
|
||||
EventLog.writeEvent(EventLogTags.AM_KILL,
|
||||
|
||||
@@ -393,9 +393,9 @@ public final class BroadcastQueueModernImplTest {
|
||||
List.of(makeMockRegisteredReceiver()), false);
|
||||
enqueueOrReplaceBroadcast(queue, airplaneRecord, 0);
|
||||
|
||||
queue.setProcessAndUidState(null, false, false);
|
||||
queue.setProcessAndUidState(mProcess, false, false);
|
||||
final long notCachedRunnableAt = queue.getRunnableAt();
|
||||
queue.setProcessAndUidState(null, false, true);
|
||||
queue.setProcessAndUidState(mProcess, false, true);
|
||||
final long cachedRunnableAt = queue.getRunnableAt();
|
||||
assertThat(cachedRunnableAt).isGreaterThan(notCachedRunnableAt);
|
||||
assertFalse(queue.isRunnable());
|
||||
@@ -420,9 +420,9 @@ public final class BroadcastQueueModernImplTest {
|
||||
List.of(makeMockRegisteredReceiver()), false);
|
||||
enqueueOrReplaceBroadcast(queue, airplaneRecord, 0);
|
||||
|
||||
queue.setProcessAndUidState(null, false, false);
|
||||
queue.setProcessAndUidState(mProcess, false, false);
|
||||
final long notCachedRunnableAt = queue.getRunnableAt();
|
||||
queue.setProcessAndUidState(null, false, true);
|
||||
queue.setProcessAndUidState(mProcess, false, true);
|
||||
final long cachedRunnableAt = queue.getRunnableAt();
|
||||
assertThat(cachedRunnableAt).isGreaterThan(notCachedRunnableAt);
|
||||
assertTrue(queue.isRunnable());
|
||||
|
||||
@@ -399,6 +399,12 @@ public class BroadcastQueueTest {
|
||||
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,
|
||||
ProcessBehavior behavior) throws Exception {
|
||||
return makeActiveProcessRecord(packageName, packageName, behavior, UserHandle.USER_SYSTEM);
|
||||
@@ -596,6 +602,11 @@ public class BroadcastQueueTest {
|
||||
BackgroundStartPrivileges.NONE, false, null);
|
||||
}
|
||||
|
||||
private void setProcessFreezable(ProcessRecord app, boolean pendingFreeze, boolean frozen) {
|
||||
app.mOptRecord.setPendingFreeze(pendingFreeze);
|
||||
app.mOptRecord.setFrozen(frozen);
|
||||
}
|
||||
|
||||
private void assertHealth() {
|
||||
if (mImpl == Impl.MODERN) {
|
||||
// If this fails, it'll throw a clear reason message
|
||||
@@ -1659,8 +1670,10 @@ public class BroadcastQueueTest {
|
||||
final ProcessRecord receiverYellowApp = makeActiveProcessRecord(PACKAGE_YELLOW);
|
||||
final ProcessRecord receiverOrangeApp = makeActiveProcessRecord(PACKAGE_ORANGE);
|
||||
|
||||
mUidObserver.onUidCachedChanged(getUidForPackage(PACKAGE_GREEN), true);
|
||||
mUidObserver.onUidCachedChanged(getUidForPackage(PACKAGE_BLUE), true);
|
||||
setProcessFreezable(receiverGreenApp, true, false);
|
||||
mQueue.onProcessFreezableChangedLocked(receiverGreenApp);
|
||||
setProcessFreezable(receiverBlueApp, false, true);
|
||||
mQueue.onProcessFreezableChangedLocked(receiverBlueApp);
|
||||
|
||||
final Intent timeTick = new Intent(Intent.ACTION_TIME_TICK);
|
||||
final BroadcastOptions opts = BroadcastOptions.makeBasic()
|
||||
@@ -1704,12 +1717,14 @@ public class BroadcastQueueTest {
|
||||
eq(UserHandle.USER_SYSTEM), anyInt(), anyInt(), any());
|
||||
|
||||
// Shift blue to be active and confirm that deferred broadcast is delivered
|
||||
mUidObserver.onUidCachedChanged(getUidForPackage(PACKAGE_BLUE), false);
|
||||
setProcessFreezable(receiverBlueApp, false, false);
|
||||
mQueue.onProcessFreezableChangedLocked(receiverBlueApp);
|
||||
waitForIdle();
|
||||
verifyScheduleRegisteredReceiver(times(1), receiverBlueApp, timeTick);
|
||||
|
||||
// Shift green to be active and confirm that deferred broadcast is delivered
|
||||
mUidObserver.onUidCachedChanged(getUidForPackage(PACKAGE_GREEN), false);
|
||||
setProcessFreezable(receiverGreenApp, false, false);
|
||||
mQueue.onProcessFreezableChangedLocked(receiverGreenApp);
|
||||
waitForIdle();
|
||||
verifyScheduleRegisteredReceiver(times(1), receiverGreenApp, timeTick);
|
||||
}
|
||||
@@ -2106,9 +2121,12 @@ public class BroadcastQueueTest {
|
||||
final ProcessRecord receiverBlueApp = makeActiveProcessRecord(PACKAGE_BLUE);
|
||||
final ProcessRecord receiverYellowApp = makeActiveProcessRecord(PACKAGE_YELLOW);
|
||||
|
||||
mUidObserver.onUidCachedChanged(getUidForPackage(PACKAGE_GREEN), true);
|
||||
mUidObserver.onUidCachedChanged(getUidForPackage(PACKAGE_BLUE), true);
|
||||
mUidObserver.onUidCachedChanged(getUidForPackage(PACKAGE_YELLOW), false);
|
||||
setProcessFreezable(receiverGreenApp, true, true);
|
||||
mQueue.onProcessFreezableChangedLocked(receiverGreenApp);
|
||||
setProcessFreezable(receiverBlueApp, true, false);
|
||||
mQueue.onProcessFreezableChangedLocked(receiverBlueApp);
|
||||
setProcessFreezable(receiverYellowApp, false, false);
|
||||
mQueue.onProcessFreezableChangedLocked(receiverYellowApp);
|
||||
|
||||
final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
|
||||
final BroadcastOptions opts = BroadcastOptions.makeBasic()
|
||||
@@ -2131,11 +2149,50 @@ public class BroadcastQueueTest {
|
||||
verifyScheduleRegisteredReceiver(times(1), receiverYellowApp, airplane);
|
||||
|
||||
// Shift green to be active and confirm that deferred broadcast is delivered
|
||||
mUidObserver.onUidCachedChanged(getUidForPackage(PACKAGE_GREEN), false);
|
||||
setProcessFreezable(receiverGreenApp, false, false);
|
||||
mQueue.onProcessFreezableChangedLocked(receiverGreenApp);
|
||||
waitForIdle();
|
||||
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
|
||||
public void testBroadcastDelivery_uidForeground() throws Exception {
|
||||
// Legacy stack doesn't support prioritization to foreground app.
|
||||
|
||||
Reference in New Issue
Block a user