Ignore older UID state change callbacks in NPMS.
Since the onUidStateChanged() callbacks will be happening from more than one thread, we need to make sure we only handle the latest uid state change callbacks and ignore any older callbacks that could override the latest uid states in NPMS. In order to this, every uid state change will be associated with a unique seq number. Also, remove the UidRecord.lastDispatchedProcStateSeq. This was added as a safety measure to make sure we don't unnecessarily end up waiting but it isn't necessary and if we need to keep it, we need to add a way to access it without holding global AMS lock, which isn't worth the complexity. Bug: 226299593 Test: atest tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java Change-Id: I631f5e01f6627916a96c930c22849a1d11eab636
This commit is contained in:
@@ -817,11 +817,13 @@ public class NetworkPolicyManager {
|
||||
public static final class UidState {
|
||||
public int uid;
|
||||
public int procState;
|
||||
public long procStateSeq;
|
||||
public int capability;
|
||||
|
||||
public UidState(int uid, int procState, int capability) {
|
||||
public UidState(int uid, int procState, long procStateSeq, int capability) {
|
||||
this.uid = uid;
|
||||
this.procState = procState;
|
||||
this.procStateSeq = procStateSeq;
|
||||
this.capability = capability;
|
||||
}
|
||||
|
||||
@@ -830,6 +832,8 @@ public class NetworkPolicyManager {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append("{procState=");
|
||||
sb.append(procStateToString(procState));
|
||||
sb.append(",seq=");
|
||||
sb.append(procStateSeq);
|
||||
sb.append(",cap=");
|
||||
ActivityManager.printCapabilitiesSummary(sb, capability);
|
||||
sb.append("}");
|
||||
|
||||
@@ -15257,7 +15257,6 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
uid, change, procState, procStateSeq, capability, ephemeral);
|
||||
if (uidRec != null) {
|
||||
uidRec.setLastReportedChange(enqueuedChange);
|
||||
uidRec.updateLastDispatchedProcStateSeq(enqueuedChange);
|
||||
}
|
||||
|
||||
// Directly update the power manager, since we sit on top of it and it is critical
|
||||
@@ -16523,18 +16522,13 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
return;
|
||||
}
|
||||
record.lastNetworkUpdatedProcStateSeq = procStateSeq;
|
||||
if (record.curProcStateSeq > procStateSeq) {
|
||||
if (DEBUG_NETWORK) {
|
||||
Slog.d(TAG_NETWORK, "No need to handle older seq no., Uid: " + uid
|
||||
+ ", curProcstateSeq: " + record.curProcStateSeq
|
||||
+ ", procStateSeq: " + procStateSeq);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (record.waitingForNetwork) {
|
||||
if (record.procStateSeqWaitingForNetwork != 0
|
||||
&& procStateSeq >= record.procStateSeqWaitingForNetwork) {
|
||||
if (DEBUG_NETWORK) {
|
||||
Slog.d(TAG_NETWORK, "Notifying all blocking threads for uid: " + uid
|
||||
+ ", procStateSeq: " + procStateSeq);
|
||||
+ ", procStateSeq: " + procStateSeq
|
||||
+ ", procStateSeqWaitingForNetwork: "
|
||||
+ record.procStateSeqWaitingForNetwork);
|
||||
}
|
||||
record.networkStateLock.notifyAll();
|
||||
}
|
||||
@@ -17279,7 +17273,7 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
if (mNetworkPolicyUidObserver != null) {
|
||||
try {
|
||||
mNetworkPolicyUidObserver.onUidStateChanged(uid, PROCESS_STATE_TOP,
|
||||
mProcessList.getProcStateSeqCounter(), PROCESS_CAPABILITY_ALL);
|
||||
mProcessList.getNextProcStateSeq(), PROCESS_CAPABILITY_ALL);
|
||||
} catch (RemoteException e) {
|
||||
// Should not happen; call is within the same process
|
||||
}
|
||||
@@ -17568,23 +17562,6 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
}
|
||||
}
|
||||
synchronized (record.networkStateLock) {
|
||||
if (record.lastDispatchedProcStateSeq < procStateSeq) {
|
||||
if (DEBUG_NETWORK) {
|
||||
Slog.d(TAG_NETWORK, "Uid state change for seq no. " + procStateSeq + " is not "
|
||||
+ "dispatched to NPMS yet, so don't wait. Uid: " + callingUid
|
||||
+ " lastProcStateSeqDispatchedToObservers: "
|
||||
+ record.lastDispatchedProcStateSeq);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (record.curProcStateSeq > procStateSeq) {
|
||||
if (DEBUG_NETWORK) {
|
||||
Slog.d(TAG_NETWORK, "Ignore the wait requests for older seq numbers. Uid: "
|
||||
+ callingUid + ", curProcStateSeq: " + record.curProcStateSeq
|
||||
+ ", procStateSeq: " + procStateSeq);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (record.lastNetworkUpdatedProcStateSeq >= procStateSeq) {
|
||||
if (DEBUG_NETWORK) {
|
||||
Slog.d(TAG_NETWORK, "Network rules have been already updated for seq no. "
|
||||
@@ -17600,9 +17577,9 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
+ " Uid: " + callingUid + " procStateSeq: " + procStateSeq);
|
||||
}
|
||||
final long startTime = SystemClock.uptimeMillis();
|
||||
record.waitingForNetwork = true;
|
||||
record.procStateSeqWaitingForNetwork = procStateSeq;
|
||||
record.networkStateLock.wait(mWaitForNetworkTimeoutMs);
|
||||
record.waitingForNetwork = false;
|
||||
record.procStateSeqWaitingForNetwork = 0;
|
||||
final long totalTime = SystemClock.uptimeMillis() - startTime;
|
||||
if (totalTime >= mWaitForNetworkTimeoutMs || DEBUG_NETWORK) {
|
||||
Slog.w(TAG_NETWORK, "Total time waited for network rules to get updated: "
|
||||
|
||||
@@ -4781,13 +4781,17 @@ public final class ProcessList {
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if any uid is coming from background to foreground or vice versa and if so, increments
|
||||
* the {@link UidRecord#curProcStateSeq} corresponding to that uid using global seq counter
|
||||
* {@link ProcessList#mProcStateSeqCounter} and notifies the app if it needs to block.
|
||||
* Increments the {@link UidRecord#curProcStateSeq} for all uids using global seq counter
|
||||
* {@link ProcessList#mProcStateSeqCounter} and checks if any uid is coming
|
||||
* from background to foreground or vice versa and if so, notifies the app if it needs to block.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
@GuardedBy(anyOf = {"mService", "mProcLock"})
|
||||
void incrementProcStateSeqAndNotifyAppsLOSP(ActiveUids activeUids) {
|
||||
for (int i = activeUids.size() - 1; i >= 0; --i) {
|
||||
final UidRecord uidRec = activeUids.valueAt(i);
|
||||
uidRec.curProcStateSeq = getNextProcStateSeq();
|
||||
}
|
||||
if (mService.mWaitForNetworkTimeoutMs <= 0) {
|
||||
return;
|
||||
}
|
||||
@@ -4814,7 +4818,6 @@ public final class ProcessList {
|
||||
continue;
|
||||
}
|
||||
synchronized (uidRec.networkStateLock) {
|
||||
uidRec.curProcStateSeq = ++mProcStateSeqCounter; // TODO: use method
|
||||
if (blockState == NETWORK_STATE_BLOCK) {
|
||||
if (blockingUids == null) {
|
||||
blockingUids = new ArrayList<>();
|
||||
@@ -4825,7 +4828,7 @@ public final class ProcessList {
|
||||
Slog.d(TAG_NETWORK, "uid going to background, notifying all blocking"
|
||||
+ " threads for uid: " + uidRec);
|
||||
}
|
||||
if (uidRec.waitingForNetwork) {
|
||||
if (uidRec.procStateSeqWaitingForNetwork != 0) {
|
||||
uidRec.networkStateLock.notifyAll();
|
||||
}
|
||||
}
|
||||
@@ -4859,8 +4862,8 @@ public final class ProcessList {
|
||||
}
|
||||
}
|
||||
|
||||
long getProcStateSeqCounter() {
|
||||
return mProcStateSeqCounter;
|
||||
long getNextProcStateSeq() {
|
||||
return ++mProcStateSeqCounter;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -229,7 +229,6 @@ public class UidObserverController {
|
||||
validateUid.setCurProcState(item.procState);
|
||||
validateUid.setSetCapability(item.capability);
|
||||
validateUid.setCurCapability(item.capability);
|
||||
validateUid.lastDispatchedProcStateSeq = item.procStateSeq;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,16 +99,9 @@ public final class UidRecord {
|
||||
long lastNetworkUpdatedProcStateSeq;
|
||||
|
||||
/**
|
||||
* Last seq number for which AcitivityManagerService dispatched uid state change to
|
||||
* NetworkPolicyManagerService.
|
||||
* Indicates if any thread is waiting for network rules to get updated for {@link #mUid}.
|
||||
*/
|
||||
@GuardedBy("networkStateUpdate")
|
||||
long lastDispatchedProcStateSeq;
|
||||
|
||||
/**
|
||||
* Indicates if any thread is waiting for network rules to get updated for {@link #uid}.
|
||||
*/
|
||||
volatile boolean waitingForNetwork;
|
||||
volatile long procStateSeqWaitingForNetwork;
|
||||
|
||||
/**
|
||||
* Indicates whether this uid has internet permission or not.
|
||||
@@ -345,18 +338,6 @@ public final class UidRecord {
|
||||
mUid) == PackageManager.PERMISSION_GRANTED;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the change being dispatched is not CHANGE_GONE (not interested in
|
||||
* these changes), then update the {@link #lastDispatchedProcStateSeq} with
|
||||
* {@link #curProcStateSeq}.
|
||||
*/
|
||||
public void updateLastDispatchedProcStateSeq(int changeToDispatch) {
|
||||
if ((changeToDispatch & CHANGE_GONE) == 0) {
|
||||
lastDispatchedProcStateSeq = curProcStateSeq;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void dumpDebug(ProtoOutputStream proto, long fieldId) {
|
||||
long token = proto.start(fieldId);
|
||||
proto.write(UidRecordProto.UID, mUid);
|
||||
@@ -377,7 +358,6 @@ public final class UidRecord {
|
||||
proto.write(UidRecordProto.ProcStateSequence.CURURENT, curProcStateSeq);
|
||||
proto.write(UidRecordProto.ProcStateSequence.LAST_NETWORK_UPDATED,
|
||||
lastNetworkUpdatedProcStateSeq);
|
||||
proto.write(UidRecordProto.ProcStateSequence.LAST_DISPATCHED, lastDispatchedProcStateSeq);
|
||||
proto.end(seqToken);
|
||||
|
||||
proto.end(token);
|
||||
@@ -460,8 +440,6 @@ public final class UidRecord {
|
||||
sb.append(curProcStateSeq);
|
||||
sb.append(",");
|
||||
sb.append(lastNetworkUpdatedProcStateSeq);
|
||||
sb.append(",");
|
||||
sb.append(lastDispatchedProcStateSeq);
|
||||
sb.append(")}");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import static android.Manifest.permission.READ_PHONE_STATE;
|
||||
import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE;
|
||||
import static android.app.ActivityManager.PROCESS_STATE_UNKNOWN;
|
||||
import static android.app.ActivityManager.isProcStateConsideredInteraction;
|
||||
import static android.app.ActivityManager.procStateToString;
|
||||
import static android.app.PendingIntent.FLAG_IMMUTABLE;
|
||||
import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
|
||||
import static android.content.Intent.ACTION_PACKAGE_ADDED;
|
||||
@@ -1119,7 +1120,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
callbackInfo = new UidStateCallbackInfo();
|
||||
mUidStateCallbackInfos.put(uid, callbackInfo);
|
||||
}
|
||||
callbackInfo.update(uid, procState, procStateSeq, capability);
|
||||
if (callbackInfo.procStateSeq == -1 || procStateSeq > callbackInfo.procStateSeq) {
|
||||
callbackInfo.update(uid, procState, procStateSeq, capability);
|
||||
}
|
||||
if (!callbackInfo.isPending) {
|
||||
mUidEventHandler.obtainMessage(UID_MSG_STATE_CHANGED, callbackInfo)
|
||||
.sendToTarget();
|
||||
@@ -1146,8 +1149,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
|
||||
private static final class UidStateCallbackInfo {
|
||||
public int uid;
|
||||
public int procState;
|
||||
public long procStateSeq;
|
||||
public int procState = ActivityManager.PROCESS_STATE_NONEXISTENT;
|
||||
public long procStateSeq = -1;
|
||||
@ProcessCapability
|
||||
public int capability;
|
||||
public boolean isPending;
|
||||
@@ -4044,13 +4047,22 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
* {@link #updateRulesForPowerRestrictionsUL(int)}. Returns true if the state was updated.
|
||||
*/
|
||||
@GuardedBy("mUidRulesFirstLock")
|
||||
private boolean updateUidStateUL(int uid, int procState, @ProcessCapability int capability) {
|
||||
private boolean updateUidStateUL(int uid, int procState, long procStateSeq,
|
||||
@ProcessCapability int capability) {
|
||||
Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateUidStateUL");
|
||||
try {
|
||||
final UidState oldUidState = mUidState.get(uid);
|
||||
if (oldUidState != null && procStateSeq < oldUidState.procStateSeq) {
|
||||
if (LOGV) {
|
||||
Slog.v(TAG, "Ignoring older uid state updates; uid=" + uid
|
||||
+ ",procState=" + procStateToString(procState) + ",seq=" + procStateSeq
|
||||
+ ",cap=" + capability + ",oldUidState=" + oldUidState);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (oldUidState == null || oldUidState.procState != procState
|
||||
|| oldUidState.capability != capability) {
|
||||
final UidState newUidState = new UidState(uid, procState, capability);
|
||||
final UidState newUidState = new UidState(uid, procState, procStateSeq, capability);
|
||||
// state changed, push updated rules
|
||||
mUidState.put(uid, newUidState);
|
||||
updateRestrictBackgroundRulesOnUidStatusChangedUL(uid, oldUidState, newUidState);
|
||||
@@ -4797,6 +4809,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
synchronized (mUidBlockedState) {
|
||||
mUidBlockedState.delete(uid);
|
||||
}
|
||||
mUidState.delete(uid);
|
||||
mUidPolicy.delete(uid);
|
||||
mUidFirewallStandbyRules.delete(uid);
|
||||
mUidFirewallDozableRules.delete(uid);
|
||||
@@ -5438,21 +5451,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
public boolean handleMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
case UID_MSG_STATE_CHANGED: {
|
||||
final UidStateCallbackInfo uidStateCallbackInfo =
|
||||
(UidStateCallbackInfo) msg.obj;
|
||||
final int uid;
|
||||
final int procState;
|
||||
final long procStateSeq;
|
||||
final int capability;
|
||||
synchronized (mUidStateCallbackInfos) {
|
||||
uid = uidStateCallbackInfo.uid;
|
||||
procState = uidStateCallbackInfo.procState;
|
||||
procStateSeq = uidStateCallbackInfo.procStateSeq;
|
||||
capability = uidStateCallbackInfo.capability;
|
||||
uidStateCallbackInfo.isPending = false;
|
||||
}
|
||||
|
||||
handleUidChanged(uid, procState, procStateSeq, capability);
|
||||
handleUidChanged((UidStateCallbackInfo) msg.obj);
|
||||
return true;
|
||||
}
|
||||
case UID_MSG_GONE: {
|
||||
@@ -5467,17 +5466,28 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
}
|
||||
};
|
||||
|
||||
void handleUidChanged(int uid, int procState, long procStateSeq,
|
||||
@ProcessCapability int capability) {
|
||||
void handleUidChanged(@NonNull UidStateCallbackInfo uidStateCallbackInfo) {
|
||||
Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "onUidStateChanged");
|
||||
try {
|
||||
boolean updated;
|
||||
final int uid;
|
||||
final int procState;
|
||||
final long procStateSeq;
|
||||
final int capability;
|
||||
synchronized (mUidRulesFirstLock) {
|
||||
synchronized (mUidStateCallbackInfos) {
|
||||
uid = uidStateCallbackInfo.uid;
|
||||
procState = uidStateCallbackInfo.procState;
|
||||
procStateSeq = uidStateCallbackInfo.procStateSeq;
|
||||
capability = uidStateCallbackInfo.capability;
|
||||
uidStateCallbackInfo.isPending = false;
|
||||
}
|
||||
|
||||
// We received a uid state change callback, add it to the history so that it
|
||||
// will be useful for debugging.
|
||||
mLogger.uidStateChanged(uid, procState, procStateSeq, capability);
|
||||
// Now update the network policy rules as per the updated uid state.
|
||||
updated = updateUidStateUL(uid, procState, capability);
|
||||
updated = updateUidStateUL(uid, procState, procStateSeq, capability);
|
||||
// Updating the network rules is done, so notify AMS about this.
|
||||
mActivityManagerInternal.notifyNetworkPolicyRulesUpdated(uid, procStateSeq);
|
||||
}
|
||||
|
||||
@@ -129,7 +129,7 @@ public class ActivityManagerInternalTest {
|
||||
thread2.assertWaiting("Unexpected state for " + record2);
|
||||
thread2.interrupt();
|
||||
|
||||
mAms.mProcessList.mActiveUids.clear();
|
||||
clearActiveUids();
|
||||
}
|
||||
|
||||
private UidRecord addActiveUidRecord(int uid, long curProcStateSeq,
|
||||
@@ -137,11 +137,21 @@ public class ActivityManagerInternalTest {
|
||||
final UidRecord record = new UidRecord(uid, mAms);
|
||||
record.lastNetworkUpdatedProcStateSeq = lastNetworkUpdatedProcStateSeq;
|
||||
record.curProcStateSeq = curProcStateSeq;
|
||||
record.waitingForNetwork = true;
|
||||
mAms.mProcessList.mActiveUids.put(uid, record);
|
||||
record.procStateSeqWaitingForNetwork = 1;
|
||||
addActiveUidRecord(uid, record);
|
||||
return record;
|
||||
}
|
||||
|
||||
@SuppressWarnings("GuardedBy")
|
||||
private void addActiveUidRecord(int uid, UidRecord record) {
|
||||
mAms.mProcessList.mActiveUids.put(uid, record);
|
||||
}
|
||||
|
||||
@SuppressWarnings("GuardedBy")
|
||||
private void clearActiveUids() {
|
||||
mAms.mProcessList.mActiveUids.clear();
|
||||
}
|
||||
|
||||
static class CustomThread extends Thread {
|
||||
private static final long WAIT_TIMEOUT_MS = 1000;
|
||||
private static final long WAIT_INTERVAL_MS = 100;
|
||||
|
||||
@@ -196,8 +196,6 @@ public class ActivityManagerServiceTest {
|
||||
verifySeqCounterAndInteractions(uidRec,
|
||||
PROCESS_STATE_TOP, // prevState
|
||||
PROCESS_STATE_TOP, // curState
|
||||
0, // expectedGlobalCounter
|
||||
0, // exptectedCurProcStateSeq
|
||||
NETWORK_STATE_NO_CHANGE, // expectedBlockState
|
||||
false); // expectNotify
|
||||
|
||||
@@ -205,8 +203,6 @@ public class ActivityManagerServiceTest {
|
||||
verifySeqCounterAndInteractions(uidRec,
|
||||
PROCESS_STATE_FOREGROUND_SERVICE, // prevState
|
||||
PROCESS_STATE_SERVICE, // curState
|
||||
1, // expectedGlobalCounter
|
||||
1, // exptectedCurProcStateSeq
|
||||
NETWORK_STATE_UNBLOCK, // expectedBlockState
|
||||
true); // expectNotify
|
||||
|
||||
@@ -218,8 +214,6 @@ public class ActivityManagerServiceTest {
|
||||
verifySeqCounterAndInteractions(uidRec,
|
||||
PROCESS_STATE_TRANSIENT_BACKGROUND, // prevState
|
||||
PROCESS_STATE_IMPORTANT_BACKGROUND, // curState
|
||||
42, // expectedGlobalCounter
|
||||
1, // exptectedCurProcStateSeq
|
||||
NETWORK_STATE_NO_CHANGE, // expectedBlockState
|
||||
false); // expectNotify
|
||||
|
||||
@@ -227,73 +221,22 @@ public class ActivityManagerServiceTest {
|
||||
verifySeqCounterAndInteractions(uidRec,
|
||||
PROCESS_STATE_LAST_ACTIVITY, // prevState
|
||||
PROCESS_STATE_TOP, // curState
|
||||
43, // expectedGlobalCounter
|
||||
43, // exptectedCurProcStateSeq
|
||||
NETWORK_STATE_BLOCK, // expectedBlockState
|
||||
false); // expectNotify
|
||||
|
||||
// verify waiting threads are not notified.
|
||||
uidRec.waitingForNetwork = false;
|
||||
uidRec.procStateSeqWaitingForNetwork = 0;
|
||||
// Uid state is moving from foreground to background.
|
||||
verifySeqCounterAndInteractions(uidRec,
|
||||
PROCESS_STATE_FOREGROUND_SERVICE, // prevState
|
||||
PROCESS_STATE_SERVICE, // curState
|
||||
44, // expectedGlobalCounter
|
||||
44, // exptectedCurProcStateSeq
|
||||
NETWORK_STATE_UNBLOCK, // expectedBlockState
|
||||
false); // expectNotify
|
||||
|
||||
// Verify when uid is not restricted, procStateSeq is not incremented.
|
||||
uidRec.waitingForNetwork = true;
|
||||
mInjector.setNetworkRestrictedForUid(false);
|
||||
verifySeqCounterAndInteractions(uidRec,
|
||||
PROCESS_STATE_IMPORTANT_BACKGROUND, // prevState
|
||||
PROCESS_STATE_TOP, // curState
|
||||
44, // expectedGlobalCounter
|
||||
44, // exptectedCurProcStateSeq
|
||||
-1, // expectedBlockState, -1 to verify there are no interactions with main thread.
|
||||
false); // expectNotify
|
||||
|
||||
// Verify when waitForNetworkTimeout is 0, then procStateSeq is not incremented.
|
||||
mAms.mWaitForNetworkTimeoutMs = 0;
|
||||
mInjector.setNetworkRestrictedForUid(true);
|
||||
verifySeqCounterAndInteractions(uidRec,
|
||||
PROCESS_STATE_TOP, // prevState
|
||||
PROCESS_STATE_IMPORTANT_BACKGROUND, // curState
|
||||
44, // expectedGlobalCounter
|
||||
44, // exptectedCurProcStateSeq
|
||||
-1, // expectedBlockState, -1 to verify there are no interactions with main thread.
|
||||
false); // expectNotify
|
||||
|
||||
// Verify when the uid doesn't have internet permission, then procStateSeq is not
|
||||
// incremented.
|
||||
uidRec.hasInternetPermission = false;
|
||||
mAms.mWaitForNetworkTimeoutMs = 111;
|
||||
mInjector.setNetworkRestrictedForUid(true);
|
||||
verifySeqCounterAndInteractions(uidRec,
|
||||
PROCESS_STATE_CACHED_ACTIVITY, // prevState
|
||||
PROCESS_STATE_FOREGROUND_SERVICE, // curState
|
||||
44, // expectedGlobalCounter
|
||||
44, // exptectedCurProcStateSeq
|
||||
-1, // expectedBlockState, -1 to verify there are no interactions with main thread.
|
||||
false); // expectNotify
|
||||
|
||||
// Verify procStateSeq is not incremented when the uid is not an application, regardless
|
||||
// of the process state.
|
||||
final int notAppUid = 111;
|
||||
final UidRecord uidRec2 = addUidRecord(notAppUid);
|
||||
verifySeqCounterAndInteractions(uidRec2,
|
||||
PROCESS_STATE_CACHED_EMPTY, // prevState
|
||||
PROCESS_STATE_TOP, // curState
|
||||
44, // expectedGlobalCounter
|
||||
0, // exptectedCurProcStateSeq
|
||||
-1, // expectedBlockState, -1 to verify there are no interactions with main thread.
|
||||
false); // expectNotify
|
||||
}
|
||||
|
||||
private UidRecord addUidRecord(int uid) {
|
||||
final UidRecord uidRec = new UidRecord(uid, mAms);
|
||||
uidRec.waitingForNetwork = true;
|
||||
uidRec.procStateSeqWaitingForNetwork = 1;
|
||||
uidRec.hasInternetPermission = true;
|
||||
mAms.mProcessList.mActiveUids.put(uid, uidRec);
|
||||
|
||||
@@ -310,18 +253,26 @@ public class ActivityManagerServiceTest {
|
||||
|
||||
@SuppressWarnings("GuardedBy")
|
||||
private void verifySeqCounterAndInteractions(UidRecord uidRec, int prevState, int curState,
|
||||
int expectedGlobalCounter, int expectedCurProcStateSeq, int expectedBlockState,
|
||||
boolean expectNotify) throws Exception {
|
||||
int expectedBlockState, boolean expectNotify) throws Exception {
|
||||
CustomThread thread = new CustomThread(uidRec.networkStateLock);
|
||||
thread.startAndWait("Unexpected state for " + uidRec);
|
||||
|
||||
uidRec.setSetProcState(prevState);
|
||||
uidRec.setCurProcState(curState);
|
||||
final long beforeProcStateSeq = mAms.mProcessList.mProcStateSeqCounter;
|
||||
|
||||
mAms.mProcessList.incrementProcStateSeqAndNotifyAppsLOSP(mAms.mProcessList.mActiveUids);
|
||||
|
||||
// @SuppressWarnings("GuardedBy")
|
||||
assertEquals(expectedGlobalCounter, mAms.mProcessList.mProcStateSeqCounter);
|
||||
assertEquals(expectedCurProcStateSeq, uidRec.curProcStateSeq);
|
||||
final long afterProcStateSeq = beforeProcStateSeq
|
||||
+ mAms.mProcessList.mActiveUids.size();
|
||||
assertEquals("beforeProcStateSeq=" + beforeProcStateSeq
|
||||
+ ",activeUids.size=" + mAms.mProcessList.mActiveUids.size(),
|
||||
afterProcStateSeq, mAms.mProcessList.mProcStateSeqCounter);
|
||||
assertTrue("beforeProcStateSeq=" + beforeProcStateSeq
|
||||
+ ",afterProcStateSeq=" + afterProcStateSeq
|
||||
+ ",uidCurProcStateSeq=" + uidRec.curProcStateSeq,
|
||||
uidRec.curProcStateSeq > beforeProcStateSeq
|
||||
&& uidRec.curProcStateSeq <= afterProcStateSeq);
|
||||
|
||||
for (int i = mAms.mProcessList.getLruSizeLOSP() - 1; i >= 0; --i) {
|
||||
final ProcessRecord app = mAms.mProcessList.getLruProcessesLOSP().get(i);
|
||||
@@ -819,49 +770,12 @@ public class ActivityManagerServiceTest {
|
||||
0, mAms.mUidObserverController.getValidateUidsForTest().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEnqueueUidChangeLocked_procStateSeqUpdated() {
|
||||
final UidRecord uidRecord = new UidRecord(TEST_UID, mAms);
|
||||
uidRecord.curProcStateSeq = TEST_PROC_STATE_SEQ1;
|
||||
|
||||
// Verify with no pending changes for TEST_UID.
|
||||
verifyLastProcStateSeqUpdated(uidRecord, -1, TEST_PROC_STATE_SEQ1);
|
||||
|
||||
// Add a pending change for TEST_UID and verify enqueueUidChangeLocked still works as
|
||||
// expected.
|
||||
uidRecord.curProcStateSeq = TEST_PROC_STATE_SEQ2;
|
||||
verifyLastProcStateSeqUpdated(uidRecord, -1, TEST_PROC_STATE_SEQ2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEnqueueUidChangeLocked_nullUidRecord() {
|
||||
// Use "null" uidRecord to make sure there is no crash.
|
||||
mAms.enqueueUidChangeLocked(null, TEST_UID, UidRecord.CHANGE_ACTIVE);
|
||||
}
|
||||
|
||||
private void verifyLastProcStateSeqUpdated(UidRecord uidRecord, int uid, long curProcstateSeq) {
|
||||
// Test enqueueUidChangeLocked with every UidRecord.CHANGE_*
|
||||
for (int i = 0; i < UID_RECORD_CHANGES.length; ++i) {
|
||||
final int changeToDispatch = UID_RECORD_CHANGES[i];
|
||||
// Reset lastProcStateSeqDispatchToObservers after every test.
|
||||
uidRecord.lastDispatchedProcStateSeq = 0;
|
||||
mAms.enqueueUidChangeLocked(uidRecord, uid, changeToDispatch);
|
||||
// Verify there is no effect on curProcStateSeq.
|
||||
assertEquals(curProcstateSeq, uidRecord.curProcStateSeq);
|
||||
if ((changeToDispatch & UidRecord.CHANGE_GONE) != 0) {
|
||||
// Since the change is CHANGE_GONE or CHANGE_GONE_IDLE, verify that
|
||||
// lastProcStateSeqDispatchedToObservers is not updated.
|
||||
assertNotEquals(uidRecord.curProcStateSeq,
|
||||
uidRecord.lastDispatchedProcStateSeq);
|
||||
} else {
|
||||
// Since the change is neither CHANGE_GONE nor CHANGE_GONE_IDLE, verify that
|
||||
// lastProcStateSeqDispatchedToObservers has been updated to curProcStateSeq.
|
||||
assertEquals(uidRecord.curProcStateSeq,
|
||||
uidRecord.lastDispatchedProcStateSeq);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@MediumTest
|
||||
@Test
|
||||
public void testEnqueueUidChangeLocked_dispatchUidsChanged() {
|
||||
@@ -898,29 +812,10 @@ public class ActivityManagerServiceTest {
|
||||
// Check there is no crash when there is no UidRecord for myUid
|
||||
mAms.waitForNetworkStateUpdate(TEST_PROC_STATE_SEQ1);
|
||||
|
||||
// Verify there is no waiting when UidRecord.curProcStateSeq is greater than
|
||||
// the procStateSeq in the request to wait.
|
||||
verifyWaitingForNetworkStateUpdate(
|
||||
TEST_PROC_STATE_SEQ1, // curProcStateSeq
|
||||
TEST_PROC_STATE_SEQ1, // lastDsipatchedProcStateSeq
|
||||
TEST_PROC_STATE_SEQ1 - 4, // lastNetworkUpdatedProcStateSeq
|
||||
TEST_PROC_STATE_SEQ1 - 2, // procStateSeqToWait
|
||||
false); // expectWait
|
||||
|
||||
// Verify there is no waiting when the procStateSeq in the request to wait is
|
||||
// not dispatched to NPMS.
|
||||
verifyWaitingForNetworkStateUpdate(
|
||||
TEST_PROC_STATE_SEQ1, // curProcStateSeq
|
||||
TEST_PROC_STATE_SEQ1 - 1, // lastDsipatchedProcStateSeq
|
||||
TEST_PROC_STATE_SEQ1 - 1, // lastNetworkUpdatedProcStateSeq
|
||||
TEST_PROC_STATE_SEQ1, // procStateSeqToWait
|
||||
false); // expectWait
|
||||
|
||||
// Verify there is not waiting when the procStateSeq in the request already has
|
||||
// an updated network state.
|
||||
verifyWaitingForNetworkStateUpdate(
|
||||
TEST_PROC_STATE_SEQ1, // curProcStateSeq
|
||||
TEST_PROC_STATE_SEQ1, // lastDsipatchedProcStateSeq
|
||||
TEST_PROC_STATE_SEQ1, // lastNetworkUpdatedProcStateSeq
|
||||
TEST_PROC_STATE_SEQ1, // procStateSeqToWait
|
||||
false); // expectWait
|
||||
@@ -928,18 +823,16 @@ public class ActivityManagerServiceTest {
|
||||
// Verify waiting for network works
|
||||
verifyWaitingForNetworkStateUpdate(
|
||||
TEST_PROC_STATE_SEQ1, // curProcStateSeq
|
||||
TEST_PROC_STATE_SEQ1, // lastDsipatchedProcStateSeq
|
||||
TEST_PROC_STATE_SEQ1 - 1, // lastNetworkUpdatedProcStateSeq
|
||||
TEST_PROC_STATE_SEQ1, // procStateSeqToWait
|
||||
true); // expectWait
|
||||
}
|
||||
|
||||
private void verifyWaitingForNetworkStateUpdate(long curProcStateSeq,
|
||||
long lastDispatchedProcStateSeq, long lastNetworkUpdatedProcStateSeq,
|
||||
long lastNetworkUpdatedProcStateSeq,
|
||||
final long procStateSeqToWait, boolean expectWait) throws Exception {
|
||||
final UidRecord record = new UidRecord(Process.myUid(), mAms);
|
||||
record.curProcStateSeq = curProcStateSeq;
|
||||
record.lastDispatchedProcStateSeq = lastDispatchedProcStateSeq;
|
||||
record.lastNetworkUpdatedProcStateSeq = lastNetworkUpdatedProcStateSeq;
|
||||
mAms.mProcessList.mActiveUids.put(Process.myUid(), record);
|
||||
|
||||
@@ -958,7 +851,7 @@ public class ActivityManagerServiceTest {
|
||||
}
|
||||
thread.assertTerminated(errMsg);
|
||||
assertTrue(thread.mNotified);
|
||||
assertFalse(record.waitingForNetwork);
|
||||
assertEquals(0, record.procStateSeqWaitingForNetwork);
|
||||
} else {
|
||||
thread.start();
|
||||
thread.assertTerminated(errMsg);
|
||||
|
||||
@@ -991,19 +991,20 @@ public class NetworkPolicyManagerServiceTest {
|
||||
@Test
|
||||
public void testUidForeground() throws Exception {
|
||||
// push all uids into background
|
||||
callOnUidStateChanged(UID_A, ActivityManager.PROCESS_STATE_SERVICE, 0);
|
||||
callOnUidStateChanged(UID_B, ActivityManager.PROCESS_STATE_SERVICE, 0);
|
||||
long procStateSeq = 0;
|
||||
callOnUidStateChanged(UID_A, ActivityManager.PROCESS_STATE_SERVICE, procStateSeq++);
|
||||
callOnUidStateChanged(UID_B, ActivityManager.PROCESS_STATE_SERVICE, procStateSeq++);
|
||||
assertFalse(mService.isUidForeground(UID_A));
|
||||
assertFalse(mService.isUidForeground(UID_B));
|
||||
|
||||
// push one of the uids into foreground
|
||||
callOnUidStateChanged(UID_A, ActivityManager.PROCESS_STATE_TOP, 0);
|
||||
callOnUidStateChanged(UID_A, ActivityManager.PROCESS_STATE_TOP, procStateSeq++);
|
||||
assertTrue(mService.isUidForeground(UID_A));
|
||||
assertFalse(mService.isUidForeground(UID_B));
|
||||
|
||||
// and swap another uid into foreground
|
||||
callOnUidStateChanged(UID_A, ActivityManager.PROCESS_STATE_SERVICE, 0);
|
||||
callOnUidStateChanged(UID_B, ActivityManager.PROCESS_STATE_TOP, 0);
|
||||
callOnUidStateChanged(UID_A, ActivityManager.PROCESS_STATE_SERVICE, procStateSeq++);
|
||||
callOnUidStateChanged(UID_B, ActivityManager.PROCESS_STATE_TOP, procStateSeq++);
|
||||
assertFalse(mService.isUidForeground(UID_A));
|
||||
assertTrue(mService.isUidForeground(UID_B));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user