Merge "Add a callback to listen to uid foreground-ness change." into udc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
b0302b10b2
@@ -200,6 +200,7 @@ class BroadcastProcessQueue {
|
|||||||
*/
|
*/
|
||||||
private boolean mLastDeferredStates;
|
private boolean mLastDeferredStates;
|
||||||
|
|
||||||
|
private boolean mUidForeground;
|
||||||
private boolean mUidCached;
|
private boolean mUidCached;
|
||||||
private boolean mProcessInstrumented;
|
private boolean mProcessInstrumented;
|
||||||
private boolean mProcessPersistent;
|
private boolean mProcessPersistent;
|
||||||
@@ -409,7 +410,8 @@ class BroadcastProcessQueue {
|
|||||||
* {@link BroadcastQueueModernImpl#updateRunnableList}
|
* {@link BroadcastQueueModernImpl#updateRunnableList}
|
||||||
*/
|
*/
|
||||||
@CheckResult
|
@CheckResult
|
||||||
public boolean setProcessAndUidCached(@Nullable ProcessRecord app, boolean uidCached) {
|
public boolean setProcessAndUidState(@Nullable ProcessRecord app, boolean uidForeground,
|
||||||
|
boolean uidCached) {
|
||||||
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
|
||||||
@@ -419,16 +421,34 @@ class BroadcastProcessQueue {
|
|||||||
boolean didSomething = false;
|
boolean didSomething = false;
|
||||||
if (app != null) {
|
if (app != null) {
|
||||||
didSomething |= setUidCached(uidCached);
|
didSomething |= setUidCached(uidCached);
|
||||||
|
didSomething |= setUidForeground(uidForeground);
|
||||||
didSomething |= setProcessInstrumented(app.getActiveInstrumentation() != null);
|
didSomething |= setProcessInstrumented(app.getActiveInstrumentation() != null);
|
||||||
didSomething |= setProcessPersistent(app.isPersistent());
|
didSomething |= setProcessPersistent(app.isPersistent());
|
||||||
} else {
|
} else {
|
||||||
didSomething |= setUidCached(uidCached);
|
didSomething |= setUidCached(uidCached);
|
||||||
|
didSomething |= setUidForeground(false);
|
||||||
didSomething |= setProcessInstrumented(false);
|
didSomething |= setProcessInstrumented(false);
|
||||||
didSomething |= setProcessPersistent(false);
|
didSomething |= setProcessPersistent(false);
|
||||||
}
|
}
|
||||||
return didSomething;
|
return didSomething;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update if the UID this process is belongs to is in "foreground" state, which signals
|
||||||
|
* broadcast dispatch should prioritize delivering broadcasts to this process to minimize any
|
||||||
|
* delays in UI updates.
|
||||||
|
*/
|
||||||
|
@CheckResult
|
||||||
|
private boolean setUidForeground(boolean uidForeground) {
|
||||||
|
if (mUidForeground != uidForeground) {
|
||||||
|
mUidForeground = uidForeground;
|
||||||
|
invalidateRunnableAt();
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update if this process is in the "cached" state, typically signaling that
|
* Update if this process is in the "cached" state, typically signaling that
|
||||||
* broadcast dispatch should be paused or delayed.
|
* broadcast dispatch should be paused or delayed.
|
||||||
@@ -994,7 +1014,7 @@ class BroadcastProcessQueue {
|
|||||||
static final int REASON_CONTAINS_RESULT_TO = 15;
|
static final int REASON_CONTAINS_RESULT_TO = 15;
|
||||||
static final int REASON_CONTAINS_INSTRUMENTED = 16;
|
static final int REASON_CONTAINS_INSTRUMENTED = 16;
|
||||||
static final int REASON_CONTAINS_MANIFEST = 17;
|
static final int REASON_CONTAINS_MANIFEST = 17;
|
||||||
static final int REASON_FOREGROUND_ACTIVITIES = 18;
|
static final int REASON_FOREGROUND = 18;
|
||||||
|
|
||||||
@IntDef(flag = false, prefix = { "REASON_" }, value = {
|
@IntDef(flag = false, prefix = { "REASON_" }, value = {
|
||||||
REASON_EMPTY,
|
REASON_EMPTY,
|
||||||
@@ -1014,7 +1034,7 @@ class BroadcastProcessQueue {
|
|||||||
REASON_CONTAINS_RESULT_TO,
|
REASON_CONTAINS_RESULT_TO,
|
||||||
REASON_CONTAINS_INSTRUMENTED,
|
REASON_CONTAINS_INSTRUMENTED,
|
||||||
REASON_CONTAINS_MANIFEST,
|
REASON_CONTAINS_MANIFEST,
|
||||||
REASON_FOREGROUND_ACTIVITIES,
|
REASON_FOREGROUND,
|
||||||
})
|
})
|
||||||
@Retention(RetentionPolicy.SOURCE)
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
public @interface Reason {}
|
public @interface Reason {}
|
||||||
@@ -1038,7 +1058,7 @@ class BroadcastProcessQueue {
|
|||||||
case REASON_CONTAINS_RESULT_TO: return "CONTAINS_RESULT_TO";
|
case REASON_CONTAINS_RESULT_TO: return "CONTAINS_RESULT_TO";
|
||||||
case REASON_CONTAINS_INSTRUMENTED: return "CONTAINS_INSTRUMENTED";
|
case REASON_CONTAINS_INSTRUMENTED: return "CONTAINS_INSTRUMENTED";
|
||||||
case REASON_CONTAINS_MANIFEST: return "CONTAINS_MANIFEST";
|
case REASON_CONTAINS_MANIFEST: return "CONTAINS_MANIFEST";
|
||||||
case REASON_FOREGROUND_ACTIVITIES: return "FOREGROUND_ACTIVITIES";
|
case REASON_FOREGROUND: return "FOREGROUND";
|
||||||
default: return Integer.toString(reason);
|
default: return Integer.toString(reason);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1077,11 +1097,9 @@ class BroadcastProcessQueue {
|
|||||||
} else if (mProcessInstrumented) {
|
} else if (mProcessInstrumented) {
|
||||||
mRunnableAt = runnableAt + constants.DELAY_URGENT_MILLIS;
|
mRunnableAt = runnableAt + constants.DELAY_URGENT_MILLIS;
|
||||||
mRunnableAtReason = REASON_INSTRUMENTED;
|
mRunnableAtReason = REASON_INSTRUMENTED;
|
||||||
} else if (app != null && app.hasForegroundActivities()) {
|
} else if (mUidForeground) {
|
||||||
// TODO: Listen for uid state changes to check when an uid goes in and out of
|
|
||||||
// the TOP state.
|
|
||||||
mRunnableAt = runnableAt + constants.DELAY_URGENT_MILLIS;
|
mRunnableAt = runnableAt + constants.DELAY_URGENT_MILLIS;
|
||||||
mRunnableAtReason = REASON_FOREGROUND_ACTIVITIES;
|
mRunnableAtReason = REASON_FOREGROUND;
|
||||||
} else if (mCountOrdered > 0) {
|
} else if (mCountOrdered > 0) {
|
||||||
mRunnableAt = runnableAt;
|
mRunnableAt = runnableAt;
|
||||||
mRunnableAtReason = REASON_CONTAINS_ORDERED;
|
mRunnableAtReason = REASON_CONTAINS_ORDERED;
|
||||||
@@ -1351,7 +1369,11 @@ class BroadcastProcessQueue {
|
|||||||
@NeverCompile
|
@NeverCompile
|
||||||
private void dumpProcessState(@NonNull IndentingPrintWriter pw) {
|
private void dumpProcessState(@NonNull IndentingPrintWriter pw) {
|
||||||
final StringBuilder sb = new StringBuilder();
|
final StringBuilder sb = new StringBuilder();
|
||||||
|
if (mUidForeground) {
|
||||||
|
sb.append("FG");
|
||||||
|
}
|
||||||
if (mUidCached) {
|
if (mUidCached) {
|
||||||
|
if (sb.length() > 0) sb.append("|");
|
||||||
sb.append("CACHED");
|
sb.append("CACHED");
|
||||||
}
|
}
|
||||||
if (mProcessInstrumented) {
|
if (mProcessInstrumented) {
|
||||||
|
|||||||
@@ -211,6 +211,17 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
|
|||||||
private final AtomicReference<ArraySet<BroadcastRecord>> mReplacedBroadcastsCache =
|
private final AtomicReference<ArraySet<BroadcastRecord>> mReplacedBroadcastsCache =
|
||||||
new AtomicReference<>();
|
new AtomicReference<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map from UID to its last known "foreground" state. A UID is considered to be in
|
||||||
|
* "foreground" state when it's procState is {@link ActivityManager#PROCESS_STATE_TOP}.
|
||||||
|
* <p>
|
||||||
|
* We manually maintain this data structure since the lifecycle of
|
||||||
|
* {@link ProcessRecord} and {@link BroadcastProcessQueue} can be
|
||||||
|
* mismatched.
|
||||||
|
*/
|
||||||
|
@GuardedBy("mService")
|
||||||
|
private final SparseBooleanArray mUidForeground = new SparseBooleanArray();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map from UID to its last known "cached" state.
|
* Map from UID to its last known "cached" state.
|
||||||
* <p>
|
* <p>
|
||||||
@@ -1284,11 +1295,24 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
|
|||||||
return UserHandle.getUserId(q.uid) == userId;
|
return UserHandle.getUserId(q.uid) == userId;
|
||||||
};
|
};
|
||||||
broadcastPredicate = BROADCAST_PREDICATE_ANY;
|
broadcastPredicate = BROADCAST_PREDICATE_ANY;
|
||||||
|
|
||||||
|
cleanupUserStateLocked(mUidCached, userId);
|
||||||
|
cleanupUserStateLocked(mUidForeground, userId);
|
||||||
}
|
}
|
||||||
return forEachMatchingBroadcast(queuePredicate, broadcastPredicate,
|
return forEachMatchingBroadcast(queuePredicate, broadcastPredicate,
|
||||||
mBroadcastConsumerSkip, true);
|
mBroadcastConsumerSkip, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GuardedBy("mService")
|
||||||
|
private void cleanupUserStateLocked(@NonNull SparseBooleanArray uidState, int userId) {
|
||||||
|
for (int i = uidState.size() - 1; i >= 0; --i) {
|
||||||
|
final int uid = uidState.keyAt(i);
|
||||||
|
if (UserHandle.getUserId(uid) == userId) {
|
||||||
|
uidState.removeAt(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static final Predicate<BroadcastProcessQueue> QUEUE_PREDICATE_ANY =
|
private static final Predicate<BroadcastProcessQueue> QUEUE_PREDICATE_ANY =
|
||||||
(q) -> true;
|
(q) -> true;
|
||||||
private static final BroadcastPredicate BROADCAST_PREDICATE_ANY =
|
private static final BroadcastPredicate BROADCAST_PREDICATE_ANY =
|
||||||
@@ -1403,6 +1427,19 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
|
|||||||
mBgConstants.startObserving(mHandler, resolver);
|
mBgConstants.startObserving(mHandler, resolver);
|
||||||
|
|
||||||
mService.registerUidObserver(new UidObserver() {
|
mService.registerUidObserver(new UidObserver() {
|
||||||
|
@Override
|
||||||
|
public void onUidStateChanged(int uid, int procState, long procStateSeq,
|
||||||
|
int capability) {
|
||||||
|
synchronized (mService) {
|
||||||
|
if (procState == ActivityManager.PROCESS_STATE_TOP) {
|
||||||
|
mUidForeground.put(uid, true);
|
||||||
|
} else {
|
||||||
|
mUidForeground.delete(uid);
|
||||||
|
}
|
||||||
|
refreshProcessQueuesLocked(uid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onUidCachedChanged(int uid, boolean cached) {
|
public void onUidCachedChanged(int uid, boolean cached) {
|
||||||
synchronized (mService) {
|
synchronized (mService) {
|
||||||
@@ -1411,18 +1448,11 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
|
|||||||
} else {
|
} else {
|
||||||
mUidCached.delete(uid);
|
mUidCached.delete(uid);
|
||||||
}
|
}
|
||||||
|
refreshProcessQueuesLocked(uid);
|
||||||
BroadcastProcessQueue leaf = mProcessQueues.get(uid);
|
|
||||||
while (leaf != null) {
|
|
||||||
// Update internal state by refreshing values previously
|
|
||||||
// read from any known running process
|
|
||||||
setQueueProcess(leaf, leaf.app);
|
|
||||||
leaf = leaf.processNameNext;
|
|
||||||
}
|
|
||||||
enqueueUpdateRunningList();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, ActivityManager.UID_OBSERVER_CACHED, 0, "android");
|
}, ActivityManager.UID_OBSERVER_PROCSTATE | ActivityManager.UID_OBSERVER_CACHED,
|
||||||
|
ActivityManager.PROCESS_STATE_TOP, "android");
|
||||||
|
|
||||||
// Kick off periodic health checks
|
// Kick off periodic health checks
|
||||||
mLocalHandler.sendEmptyMessage(MSG_CHECK_HEALTH);
|
mLocalHandler.sendEmptyMessage(MSG_CHECK_HEALTH);
|
||||||
@@ -1611,8 +1641,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.setProcessAndUidCached(
|
queue.setProcessAndUidState(
|
||||||
mService.getProcessRecordLocked(queue.processName, queue.uid),
|
mService.getProcessRecordLocked(queue.processName, queue.uid),
|
||||||
|
mUidForeground.get(queue.uid, false),
|
||||||
mUidCached.get(queue.uid, false));
|
mUidCached.get(queue.uid, false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1624,11 +1655,28 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
|
|||||||
*/
|
*/
|
||||||
private void setQueueProcess(@NonNull BroadcastProcessQueue queue,
|
private void setQueueProcess(@NonNull BroadcastProcessQueue queue,
|
||||||
@Nullable ProcessRecord app) {
|
@Nullable ProcessRecord app) {
|
||||||
if (queue.setProcessAndUidCached(app, mUidCached.get(queue.uid, false))) {
|
if (queue.setProcessAndUidState(app, mUidForeground.get(queue.uid, false),
|
||||||
|
mUidCached.get(queue.uid, false))) {
|
||||||
updateRunnableList(queue);
|
updateRunnableList(queue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refresh the process queues with the latest process state so that runnableAt
|
||||||
|
* can be updated.
|
||||||
|
*/
|
||||||
|
@GuardedBy("mService")
|
||||||
|
private void refreshProcessQueuesLocked(int uid) {
|
||||||
|
BroadcastProcessQueue leaf = mProcessQueues.get(uid);
|
||||||
|
while (leaf != null) {
|
||||||
|
// Update internal state by refreshing values previously
|
||||||
|
// read from any known running process
|
||||||
|
setQueueProcess(leaf, leaf.app);
|
||||||
|
leaf = leaf.processNameNext;
|
||||||
|
}
|
||||||
|
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.
|
||||||
@@ -1950,7 +1998,13 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
|
|||||||
|
|
||||||
ipw.println("Cached UIDs:");
|
ipw.println("Cached UIDs:");
|
||||||
ipw.increaseIndent();
|
ipw.increaseIndent();
|
||||||
ipw.println(mUidCached.toString());
|
ipw.println(mUidCached);
|
||||||
|
ipw.decreaseIndent();
|
||||||
|
ipw.println();
|
||||||
|
|
||||||
|
ipw.println("Foreground UIDs:");
|
||||||
|
ipw.increaseIndent();
|
||||||
|
ipw.println(mUidForeground);
|
||||||
ipw.decreaseIndent();
|
ipw.decreaseIndent();
|
||||||
ipw.println();
|
ipw.println();
|
||||||
|
|
||||||
|
|||||||
@@ -1072,11 +1072,6 @@ class ProcessRecord implements WindowProcessListener {
|
|||||||
return mState.isCached();
|
return mState.isCached();
|
||||||
}
|
}
|
||||||
|
|
||||||
@GuardedBy(anyOf = {"mService", "mProcLock"})
|
|
||||||
public boolean hasForegroundActivities() {
|
|
||||||
return mState.hasForegroundActivities();
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean hasActivities() {
|
boolean hasActivities() {
|
||||||
return mWindowProcessController.hasActivities();
|
return mWindowProcessController.hasActivities();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -393,9 +393,9 @@ public final class BroadcastQueueModernImplTest {
|
|||||||
List.of(makeMockRegisteredReceiver()), false);
|
List.of(makeMockRegisteredReceiver()), false);
|
||||||
enqueueOrReplaceBroadcast(queue, airplaneRecord, 0);
|
enqueueOrReplaceBroadcast(queue, airplaneRecord, 0);
|
||||||
|
|
||||||
queue.setProcessAndUidCached(null, false);
|
queue.setProcessAndUidState(null, false, false);
|
||||||
final long notCachedRunnableAt = queue.getRunnableAt();
|
final long notCachedRunnableAt = queue.getRunnableAt();
|
||||||
queue.setProcessAndUidCached(null, true);
|
queue.setProcessAndUidState(null, 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());
|
||||||
@@ -420,9 +420,9 @@ public final class BroadcastQueueModernImplTest {
|
|||||||
List.of(makeMockRegisteredReceiver()), false);
|
List.of(makeMockRegisteredReceiver()), false);
|
||||||
enqueueOrReplaceBroadcast(queue, airplaneRecord, 0);
|
enqueueOrReplaceBroadcast(queue, airplaneRecord, 0);
|
||||||
|
|
||||||
queue.setProcessAndUidCached(null, false);
|
queue.setProcessAndUidState(null, false, false);
|
||||||
final long notCachedRunnableAt = queue.getRunnableAt();
|
final long notCachedRunnableAt = queue.getRunnableAt();
|
||||||
queue.setProcessAndUidCached(null, true);
|
queue.setProcessAndUidState(null, 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());
|
||||||
@@ -452,13 +452,13 @@ public final class BroadcastQueueModernImplTest {
|
|||||||
// verify that:
|
// verify that:
|
||||||
// (a) the queue is immediately runnable by existence of a fg-priority broadcast
|
// (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
|
// (b) the next one up is the fg-priority broadcast despite its later enqueue time
|
||||||
queue.setProcessAndUidCached(null, false);
|
queue.setProcessAndUidState(null, false, false);
|
||||||
assertTrue(queue.isRunnable());
|
assertTrue(queue.isRunnable());
|
||||||
assertThat(queue.getRunnableAt()).isAtMost(airplaneRecord.enqueueClockTime);
|
assertThat(queue.getRunnableAt()).isAtMost(airplaneRecord.enqueueClockTime);
|
||||||
assertEquals(ProcessList.SCHED_GROUP_UNDEFINED, queue.getPreferredSchedulingGroupLocked());
|
assertEquals(ProcessList.SCHED_GROUP_UNDEFINED, queue.getPreferredSchedulingGroupLocked());
|
||||||
assertEquals(queue.peekNextBroadcastRecord(), airplaneRecord);
|
assertEquals(queue.peekNextBroadcastRecord(), airplaneRecord);
|
||||||
|
|
||||||
queue.setProcessAndUidCached(null, true);
|
queue.setProcessAndUidState(null, false, true);
|
||||||
assertTrue(queue.isRunnable());
|
assertTrue(queue.isRunnable());
|
||||||
assertThat(queue.getRunnableAt()).isAtMost(airplaneRecord.enqueueClockTime);
|
assertThat(queue.getRunnableAt()).isAtMost(airplaneRecord.enqueueClockTime);
|
||||||
assertEquals(ProcessList.SCHED_GROUP_UNDEFINED, queue.getPreferredSchedulingGroupLocked());
|
assertEquals(ProcessList.SCHED_GROUP_UNDEFINED, queue.getPreferredSchedulingGroupLocked());
|
||||||
@@ -515,6 +515,28 @@ public final class BroadcastQueueModernImplTest {
|
|||||||
assertEquals(BroadcastProcessQueue.REASON_MAX_PENDING, queue.getRunnableAtReason());
|
assertEquals(BroadcastProcessQueue.REASON_MAX_PENDING, queue.getRunnableAtReason());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRunnableAt_uidForeground() {
|
||||||
|
final BroadcastProcessQueue queue = new BroadcastProcessQueue(mConstants, PACKAGE_GREEN,
|
||||||
|
getUidForPackage(PACKAGE_GREEN));
|
||||||
|
|
||||||
|
final Intent timeTick = new Intent(Intent.ACTION_TIME_TICK);
|
||||||
|
final BroadcastRecord timeTickRecord = makeBroadcastRecord(timeTick,
|
||||||
|
List.of(makeMockRegisteredReceiver()));
|
||||||
|
enqueueOrReplaceBroadcast(queue, timeTickRecord, 0);
|
||||||
|
|
||||||
|
assertThat(queue.getRunnableAt()).isGreaterThan(timeTickRecord.enqueueTime);
|
||||||
|
assertEquals(BroadcastProcessQueue.REASON_NORMAL, queue.getRunnableAtReason());
|
||||||
|
|
||||||
|
queue.setProcessAndUidState(mProcess, true, false);
|
||||||
|
assertThat(queue.getRunnableAt()).isLessThan(timeTickRecord.enqueueTime);
|
||||||
|
assertEquals(BroadcastProcessQueue.REASON_FOREGROUND, queue.getRunnableAtReason());
|
||||||
|
|
||||||
|
queue.setProcessAndUidState(mProcess, false, false);
|
||||||
|
assertThat(queue.getRunnableAt()).isGreaterThan(timeTickRecord.enqueueTime);
|
||||||
|
assertEquals(BroadcastProcessQueue.REASON_NORMAL, queue.getRunnableAtReason());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify that a cached process that would normally be delayed becomes
|
* Verify that a cached process that would normally be delayed becomes
|
||||||
* immediately runnable when the given broadcast is enqueued.
|
* immediately runnable when the given broadcast is enqueued.
|
||||||
@@ -522,7 +544,7 @@ public final class BroadcastQueueModernImplTest {
|
|||||||
private void doRunnableAt_Cached(BroadcastRecord testRecord, int testRunnableAtReason) {
|
private void doRunnableAt_Cached(BroadcastRecord testRecord, int testRunnableAtReason) {
|
||||||
final BroadcastProcessQueue queue = new BroadcastProcessQueue(mConstants,
|
final BroadcastProcessQueue queue = new BroadcastProcessQueue(mConstants,
|
||||||
PACKAGE_GREEN, getUidForPackage(PACKAGE_GREEN));
|
PACKAGE_GREEN, getUidForPackage(PACKAGE_GREEN));
|
||||||
queue.setProcessAndUidCached(null, true);
|
queue.setProcessAndUidState(null, false, true);
|
||||||
|
|
||||||
final BroadcastRecord lazyRecord = makeBroadcastRecord(
|
final BroadcastRecord lazyRecord = makeBroadcastRecord(
|
||||||
new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED),
|
new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED),
|
||||||
|
|||||||
@@ -25,12 +25,15 @@ import static com.android.server.am.BroadcastProcessQueue.reasonToString;
|
|||||||
import static com.android.server.am.BroadcastRecord.deliveryStateToString;
|
import static com.android.server.am.BroadcastRecord.deliveryStateToString;
|
||||||
import static com.android.server.am.BroadcastRecord.isReceiverEquals;
|
import static com.android.server.am.BroadcastRecord.isReceiverEquals;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertNotEquals;
|
import static org.junit.Assert.assertNotEquals;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
import static org.junit.Assert.assertNull;
|
import static org.junit.Assert.assertNull;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||||
import static org.mockito.ArgumentMatchers.anyInt;
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
@@ -2132,4 +2135,75 @@ public class BroadcastQueueTest {
|
|||||||
waitForIdle();
|
waitForIdle();
|
||||||
verifyScheduleRegisteredReceiver(times(1), receiverGreenApp, airplane);
|
verifyScheduleRegisteredReceiver(times(1), receiverGreenApp, airplane);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBroadcastDelivery_uidForeground() throws Exception {
|
||||||
|
// Legacy stack doesn't support prioritization to foreground app.
|
||||||
|
Assume.assumeTrue(mImpl == Impl.MODERN);
|
||||||
|
|
||||||
|
final ProcessRecord callerApp = makeActiveProcessRecord(PACKAGE_RED);
|
||||||
|
final ProcessRecord receiverBlueApp = makeActiveProcessRecord(PACKAGE_BLUE);
|
||||||
|
final ProcessRecord receiverGreenApp = makeActiveProcessRecord(PACKAGE_GREEN);
|
||||||
|
|
||||||
|
mUidObserver.onUidStateChanged(receiverGreenApp.info.uid,
|
||||||
|
ActivityManager.PROCESS_STATE_TOP, 0, ActivityManager.PROCESS_CAPABILITY_NONE);
|
||||||
|
|
||||||
|
final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
|
||||||
|
final Intent timeTick = new Intent(Intent.ACTION_TIME_TICK);
|
||||||
|
|
||||||
|
final BroadcastFilter receiverBlue = makeRegisteredReceiver(receiverBlueApp);
|
||||||
|
final BroadcastFilter receiverGreen = makeRegisteredReceiver(receiverGreenApp);
|
||||||
|
final BroadcastRecord airplaneRecord = makeBroadcastRecord(airplane, callerApp,
|
||||||
|
List.of(receiverBlue));
|
||||||
|
final BroadcastRecord timeTickRecord = makeBroadcastRecord(timeTick, callerApp,
|
||||||
|
List.of(receiverBlue, receiverGreen));
|
||||||
|
|
||||||
|
enqueueBroadcast(airplaneRecord);
|
||||||
|
enqueueBroadcast(timeTickRecord);
|
||||||
|
|
||||||
|
waitForIdle();
|
||||||
|
// Verify that broadcasts to receiverGreenApp gets scheduled first.
|
||||||
|
assertThat(getReceiverScheduledTime(timeTickRecord, receiverGreen))
|
||||||
|
.isLessThan(getReceiverScheduledTime(airplaneRecord, receiverBlue));
|
||||||
|
assertThat(getReceiverScheduledTime(timeTickRecord, receiverGreen))
|
||||||
|
.isLessThan(getReceiverScheduledTime(timeTickRecord, receiverBlue));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPrioritizedBroadcastDelivery_uidForeground() throws Exception {
|
||||||
|
// Legacy stack doesn't support prioritization to foreground app.
|
||||||
|
Assume.assumeTrue(mImpl == Impl.MODERN);
|
||||||
|
|
||||||
|
final ProcessRecord callerApp = makeActiveProcessRecord(PACKAGE_RED);
|
||||||
|
final ProcessRecord receiverBlueApp = makeActiveProcessRecord(PACKAGE_BLUE);
|
||||||
|
final ProcessRecord receiverGreenApp = makeActiveProcessRecord(PACKAGE_GREEN);
|
||||||
|
|
||||||
|
mUidObserver.onUidStateChanged(receiverGreenApp.info.uid,
|
||||||
|
ActivityManager.PROCESS_STATE_TOP, 0, ActivityManager.PROCESS_CAPABILITY_NONE);
|
||||||
|
|
||||||
|
final Intent timeTick = new Intent(Intent.ACTION_TIME_TICK);
|
||||||
|
|
||||||
|
final BroadcastFilter receiverBlue = makeRegisteredReceiver(receiverBlueApp, 10);
|
||||||
|
final BroadcastFilter receiverGreen = makeRegisteredReceiver(receiverGreenApp, 5);
|
||||||
|
final BroadcastRecord prioritizedRecord = makeBroadcastRecord(timeTick, callerApp,
|
||||||
|
List.of(receiverBlue, receiverGreen));
|
||||||
|
|
||||||
|
enqueueBroadcast(prioritizedRecord);
|
||||||
|
|
||||||
|
waitForIdle();
|
||||||
|
// Verify that uid foreground-ness does not impact that delivery of prioritized broadcast.
|
||||||
|
// That is, broadcast to receiverBlueApp gets scheduled before the one to receiverGreenApp.
|
||||||
|
assertThat(getReceiverScheduledTime(prioritizedRecord, receiverGreen))
|
||||||
|
.isGreaterThan(getReceiverScheduledTime(prioritizedRecord, receiverBlue));
|
||||||
|
}
|
||||||
|
|
||||||
|
private long getReceiverScheduledTime(@NonNull BroadcastRecord r, @NonNull Object receiver) {
|
||||||
|
for (int i = 0; i < r.receivers.size(); ++i) {
|
||||||
|
if (isReceiverEquals(receiver, r.receivers.get(i))) {
|
||||||
|
return r.scheduledTime[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fail(receiver + "not found in " + r);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user