Merge "Move logic for handling uid observers outside AMS - part2"
This commit is contained in:
committed by
Android (Google) Code Review
commit
6deb38617b
@@ -16,7 +16,12 @@
|
||||
|
||||
package com.android.server.am;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.os.UserHandle;
|
||||
import android.util.SparseArray;
|
||||
import android.util.proto.ProtoOutputStream;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
|
||||
/** Class for tracking active uids for running processes. */
|
||||
final class ActiveUids {
|
||||
@@ -71,4 +76,43 @@ final class ActiveUids {
|
||||
int indexOfKey(int uid) {
|
||||
return mActiveUids.indexOfKey(uid);
|
||||
}
|
||||
|
||||
boolean dump(PrintWriter pw, String dumpPackage, int dumpAppId,
|
||||
String header, boolean needSep) {
|
||||
boolean printed = false;
|
||||
for (int i = 0; i < mActiveUids.size(); i++) {
|
||||
final UidRecord uidRec = mActiveUids.valueAt(i);
|
||||
if (dumpPackage != null && UserHandle.getAppId(uidRec.uid) != dumpAppId) {
|
||||
continue;
|
||||
}
|
||||
if (!printed) {
|
||||
printed = true;
|
||||
if (needSep) {
|
||||
pw.println();
|
||||
}
|
||||
pw.print(" "); pw.println(header);
|
||||
}
|
||||
pw.print(" UID "); UserHandle.formatUid(pw, uidRec.uid);
|
||||
pw.print(": "); pw.println(uidRec);
|
||||
pw.print(" curProcState="); pw.print(uidRec.mCurProcState);
|
||||
pw.print(" curCapability=");
|
||||
ActivityManager.printCapabilitiesFull(pw, uidRec.curCapability);
|
||||
pw.println();
|
||||
for (int j = uidRec.procRecords.size() - 1; j >= 0; j--) {
|
||||
pw.print(" proc=");
|
||||
pw.println(uidRec.procRecords.valueAt(j));
|
||||
}
|
||||
}
|
||||
return printed;
|
||||
}
|
||||
|
||||
void dumpProto(ProtoOutputStream proto, String dumpPackage, int dumpAppId, long fieldId) {
|
||||
for (int i = 0; i < mActiveUids.size(); i++) {
|
||||
UidRecord uidRec = mActiveUids.valueAt(i);
|
||||
if (dumpPackage != null && UserHandle.getAppId(uidRec.uid) != dumpAppId) {
|
||||
continue;
|
||||
}
|
||||
uidRec.dumpDebug(proto, fieldId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1979,7 +1979,6 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
mConstants = hasHandlerThread
|
||||
? new ActivityManagerConstants(mContext, this, mHandler) : null;
|
||||
final ActiveUids activeUids = new ActiveUids(this, false /* postChangesToAtm */);
|
||||
mUidObserverController = new UidObserverController(this);
|
||||
mPlatformCompat = null;
|
||||
mProcessList = injector.getProcessList(this);
|
||||
mProcessList.init(this, activeUids, mPlatformCompat);
|
||||
@@ -1997,6 +1996,7 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
mServices = hasHandlerThread ? new ActiveServices(this) : null;
|
||||
mSystemThread = null;
|
||||
mUiHandler = injector.getUiHandler(null /* service */);
|
||||
mUidObserverController = new UidObserverController(mUiHandler);
|
||||
mUserController = hasHandlerThread ? new UserController(this) : null;
|
||||
mPendingIntentController = hasHandlerThread
|
||||
? new PendingIntentController(handlerThread.getLooper(), mUserController,
|
||||
@@ -2077,7 +2077,7 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
mCpHelper = new ContentProviderHelper(this, true);
|
||||
mPackageWatchdog = PackageWatchdog.getInstance(mUiContext);
|
||||
mAppErrors = new AppErrors(mUiContext, this, mPackageWatchdog);
|
||||
mUidObserverController = new UidObserverController(this);
|
||||
mUidObserverController = new UidObserverController(mUiHandler);
|
||||
|
||||
final File systemDir = SystemServiceManager.ensureSystemDir();
|
||||
|
||||
@@ -8816,37 +8816,6 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
return -1;
|
||||
}
|
||||
|
||||
boolean dumpUids(PrintWriter pw, String dumpPackage, int dumpAppId, ActiveUids uids,
|
||||
String header, boolean needSep) {
|
||||
boolean printed = false;
|
||||
for (int i=0; i<uids.size(); i++) {
|
||||
UidRecord uidRec = uids.valueAt(i);
|
||||
if (dumpPackage != null && UserHandle.getAppId(uidRec.uid) != dumpAppId) {
|
||||
continue;
|
||||
}
|
||||
if (!printed) {
|
||||
printed = true;
|
||||
if (needSep) {
|
||||
pw.println();
|
||||
}
|
||||
pw.print(" ");
|
||||
pw.println(header);
|
||||
needSep = true;
|
||||
}
|
||||
pw.print(" UID "); UserHandle.formatUid(pw, uidRec.uid);
|
||||
pw.print(": "); pw.println(uidRec);
|
||||
pw.print(" curProcState="); pw.print(uidRec.mCurProcState);
|
||||
pw.print(" curCapability=");
|
||||
ActivityManager.printCapabilitiesFull(pw, uidRec.curCapability);
|
||||
pw.println();
|
||||
for (int j = uidRec.procRecords.size() - 1; j >= 0; j--) {
|
||||
pw.print(" proc=");
|
||||
pw.println(uidRec.procRecords.valueAt(j));
|
||||
}
|
||||
}
|
||||
return printed;
|
||||
}
|
||||
|
||||
void dumpBinderProxyInterfaceCounts(PrintWriter pw, String header) {
|
||||
final BinderProxy.InterfaceCount[] proxyCounts = BinderProxy.getSortedInterfaceCounts(50);
|
||||
|
||||
@@ -9096,19 +9065,13 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
needSep = dumpProcessesToGc(pw, needSep, dumpPackage);
|
||||
|
||||
if (mProcessList.mActiveUids.size() > 0) {
|
||||
if (dumpUids(pw, dumpPackage, dumpAppId, mProcessList.mActiveUids,
|
||||
"UID states:", needSep)) {
|
||||
needSep = true;
|
||||
}
|
||||
needSep |= mProcessList.mActiveUids.dump(pw, dumpPackage, dumpAppId,
|
||||
"UID states:", needSep);
|
||||
}
|
||||
|
||||
if (dumpAll) {
|
||||
if (mUidObserverController.mValidateUids.size() > 0) {
|
||||
if (dumpUids(pw, dumpPackage, dumpAppId, mUidObserverController.mValidateUids,
|
||||
"UID validation:", needSep)) {
|
||||
needSep = true;
|
||||
}
|
||||
}
|
||||
needSep |= mUidObserverController.dumpValidateUids(pw,
|
||||
dumpPackage, dumpAppId, "UID validation:", needSep);
|
||||
}
|
||||
|
||||
if (needSep) {
|
||||
@@ -9377,22 +9340,12 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
ActivityManagerServiceDumpProcessesProto.ACTIVE_INSTRUMENTATIONS);
|
||||
}
|
||||
|
||||
int whichAppId = getAppId(dumpPackage);
|
||||
for (int i = 0; i < mProcessList.mActiveUids.size(); i++) {
|
||||
UidRecord uidRec = mProcessList.mActiveUids.valueAt(i);
|
||||
if (dumpPackage != null && UserHandle.getAppId(uidRec.uid) != whichAppId) {
|
||||
continue;
|
||||
}
|
||||
uidRec.dumpDebug(proto, ActivityManagerServiceDumpProcessesProto.ACTIVE_UIDS);
|
||||
}
|
||||
final int dumpAppId = getAppId(dumpPackage);
|
||||
mProcessList.mActiveUids.dumpProto(proto, dumpPackage, dumpAppId,
|
||||
ActivityManagerServiceDumpProcessesProto.ACTIVE_UIDS);
|
||||
|
||||
for (int i = 0; i < mUidObserverController.mValidateUids.size(); i++) {
|
||||
UidRecord uidRec = mUidObserverController.mValidateUids.valueAt(i);
|
||||
if (dumpPackage != null && UserHandle.getAppId(uidRec.uid) != whichAppId) {
|
||||
continue;
|
||||
}
|
||||
uidRec.dumpDebug(proto, ActivityManagerServiceDumpProcessesProto.VALIDATE_UIDS);
|
||||
}
|
||||
mUidObserverController.dumpValidateUidsProto(proto, dumpPackage, dumpAppId,
|
||||
ActivityManagerServiceDumpProcessesProto.VALIDATE_UIDS);
|
||||
|
||||
if (mProcessList.getLruSizeLocked() > 0) {
|
||||
long lruToken = proto.start(ActivityManagerServiceDumpProcessesProto.LRU_PROCS);
|
||||
@@ -14892,6 +14845,58 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isEphemeralLocked(int uid) {
|
||||
final String[] packages = mContext.getPackageManager().getPackagesForUid(uid);
|
||||
if (packages == null || packages.length != 1) { // Ephemeral apps cannot share uid
|
||||
return false;
|
||||
}
|
||||
return getPackageManagerInternalLocked().isPackageEphemeral(
|
||||
UserHandle.getUserId(uid), packages[0]);
|
||||
}
|
||||
|
||||
void enqueueUidChangeLocked(UidRecord uidRec, int uid, int change) {
|
||||
uid = uidRec != null ? uidRec.uid : uid;
|
||||
if (uid < 0) {
|
||||
throw new IllegalArgumentException("No UidRecord or uid");
|
||||
}
|
||||
|
||||
final int procState = uidRec != null
|
||||
? uidRec.setProcState : PROCESS_STATE_NONEXISTENT;
|
||||
final long procStateSeq = uidRec != null ? uidRec.curProcStateSeq : 0;
|
||||
final int capability = uidRec != null ? uidRec.setCapability : 0;
|
||||
final boolean ephemeral = uidRec != null ? uidRec.ephemeral : isEphemeralLocked(uid);
|
||||
|
||||
if (uidRec != null && !uidRec.idle && (change & UidRecord.CHANGE_GONE) != 0) {
|
||||
// If this uid is going away, and we haven't yet reported it is gone,
|
||||
// then do so now.
|
||||
change |= UidRecord.CHANGE_IDLE;
|
||||
}
|
||||
final int enqueuedChange = mUidObserverController.enqueueUidChange(
|
||||
uid, change, procState, procStateSeq, capability, ephemeral);
|
||||
if (uidRec != null) {
|
||||
uidRec.lastReportedChange = enqueuedChange;
|
||||
uidRec.updateLastDispatchedProcStateSeq(enqueuedChange);
|
||||
}
|
||||
|
||||
// Directly update the power manager, since we sit on top of it and it is critical
|
||||
// it be kept in sync (so wake locks will be held as soon as appropriate).
|
||||
if (mLocalPowerManager != null) {
|
||||
// TODO: dispatch cached/uncached changes here, so we don't need to report
|
||||
// all proc state changes.
|
||||
if ((enqueuedChange & UidRecord.CHANGE_ACTIVE) != 0) {
|
||||
mLocalPowerManager.uidActive(uid);
|
||||
}
|
||||
if ((enqueuedChange & UidRecord.CHANGE_IDLE) != 0) {
|
||||
mLocalPowerManager.uidIdle(uid);
|
||||
}
|
||||
if ((enqueuedChange & UidRecord.CHANGE_GONE) != 0) {
|
||||
mLocalPowerManager.uidGone(uid);
|
||||
} else {
|
||||
mLocalPowerManager.updateUidProcState(uid, procState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final void setProcessTrackerStateLocked(ProcessRecord proc, int memFactor, long now) {
|
||||
synchronized (mProcessStats.mLock) {
|
||||
if (proc.thread != null && proc.baseProcessTracker != null) {
|
||||
@@ -15157,7 +15162,7 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
@GuardedBy("this")
|
||||
final void doStopUidLocked(int uid, final UidRecord uidRec) {
|
||||
mServices.stopInBackgroundLocked(uid);
|
||||
mUidObserverController.enqueueUidChangeLocked(uidRec, uid, UidRecord.CHANGE_IDLE);
|
||||
enqueueUidChangeLocked(uidRec, uid, UidRecord.CHANGE_IDLE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -16707,7 +16712,7 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
+ totalTime + ". Uid: " + callingUid + " procStateSeq: "
|
||||
+ procStateSeq + " UidRec: " + record
|
||||
+ " validateUidRec: "
|
||||
+ mUidObserverController.mValidateUids.get(callingUid));
|
||||
+ mUidObserverController.getValidateUidRecord(callingUid));
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
|
||||
@@ -1147,7 +1147,7 @@ public final class OomAdjuster {
|
||||
uidRec.setWhitelist = uidRec.curWhitelist;
|
||||
uidRec.setIdle = uidRec.idle;
|
||||
mService.mAtmInternal.onUidProcStateChanged(uidRec.uid, uidRec.setProcState);
|
||||
mService.mUidObserverController.enqueueUidChangeLocked(uidRec, -1, uidChange);
|
||||
mService.enqueueUidChangeLocked(uidRec, -1, uidChange);
|
||||
mService.noteUidProcessState(uidRec.uid, uidRec.getCurProcState(),
|
||||
uidRec.curCapability);
|
||||
if (uidRec.foregroundServices) {
|
||||
|
||||
@@ -2948,7 +2948,7 @@ public final class ProcessList {
|
||||
// No more processes using this uid, tell clients it is gone.
|
||||
if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
|
||||
"No more processes in " + uidRecord);
|
||||
mService.mUidObserverController.enqueueUidChangeLocked(uidRecord, -1,
|
||||
mService.enqueueUidChangeLocked(uidRecord, -1,
|
||||
UidRecord.CHANGE_GONE);
|
||||
EventLogTags.writeAmUidStopped(uid);
|
||||
mActiveUids.remove(uid);
|
||||
|
||||
@@ -23,11 +23,13 @@ import static com.android.server.am.ActivityManagerService.TAG_UID_OBSERVERS;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.ActivityManagerProto;
|
||||
import android.app.IUidObserver;
|
||||
import android.os.Handler;
|
||||
import android.os.RemoteCallbackList;
|
||||
import android.os.RemoteException;
|
||||
import android.os.SystemClock;
|
||||
import android.os.UserHandle;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
import android.util.SparseIntArray;
|
||||
import android.util.proto.ProtoOutputStream;
|
||||
import android.util.proto.ProtoUtils;
|
||||
@@ -40,158 +42,150 @@ import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class UidObserverController {
|
||||
private final ActivityManagerService mService;
|
||||
final RemoteCallbackList<IUidObserver> mUidObservers = new RemoteCallbackList<>();
|
||||
|
||||
UidRecord.ChangeItem[] mActiveUidChanges = new UidRecord.ChangeItem[5];
|
||||
final ArrayList<UidRecord.ChangeItem> mPendingUidChanges = new ArrayList<>();
|
||||
final ArrayList<UidRecord.ChangeItem> mAvailUidChanges = new ArrayList<>();
|
||||
|
||||
/** Total # of UID change events dispatched, shown in dumpsys. */
|
||||
int mUidChangeDispatchCount;
|
||||
|
||||
/** If a UID observer takes more than this long, send a WTF. */
|
||||
private static final int SLOW_UID_OBSERVER_THRESHOLD_MS = 20;
|
||||
|
||||
private final Handler mHandler;
|
||||
|
||||
private final Object mLock = new Object();
|
||||
|
||||
@GuardedBy("mLock")
|
||||
final RemoteCallbackList<IUidObserver> mUidObservers = new RemoteCallbackList<>();
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private final SparseArray<ChangeRecord> mPendingUidChanges = new SparseArray<>();
|
||||
@GuardedBy("mLock")
|
||||
private final ArrayList<ChangeRecord> mAvailUidChanges = new ArrayList<>();
|
||||
|
||||
private ChangeRecord[] mActiveUidChanges = new ChangeRecord[5];
|
||||
|
||||
/** Total # of UID change events dispatched, shown in dumpsys. */
|
||||
@GuardedBy("mLock")
|
||||
private int mUidChangeDispatchCount;
|
||||
|
||||
private final Runnable mDispatchRunnable = this::dispatchUidsChanged;
|
||||
|
||||
/**
|
||||
* This is for verifying the UID report flow.
|
||||
*/
|
||||
static final boolean VALIDATE_UID_STATES = true;
|
||||
final ActiveUids mValidateUids;
|
||||
private static final boolean VALIDATE_UID_STATES = true;
|
||||
private final ActiveUids mValidateUids;
|
||||
|
||||
UidObserverController(ActivityManagerService service) {
|
||||
mService = service;
|
||||
mValidateUids = new ActiveUids(mService, false /* postChangesToAtm */);
|
||||
UidObserverController(Handler handler) {
|
||||
mHandler = handler;
|
||||
mValidateUids = new ActiveUids(null /* service */, false /* postChangesToAtm */);
|
||||
}
|
||||
|
||||
@GuardedBy("mService")
|
||||
void register(IUidObserver observer, int which, int cutpoint, String callingPackage,
|
||||
int callingUid) {
|
||||
mUidObservers.register(observer, new UidObserverRegistration(callingUid,
|
||||
callingPackage, which, cutpoint));
|
||||
synchronized (mLock) {
|
||||
mUidObservers.register(observer, new UidObserverRegistration(callingUid,
|
||||
callingPackage, which, cutpoint));
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("mService")
|
||||
void unregister(IUidObserver observer) {
|
||||
mUidObservers.unregister(observer);
|
||||
synchronized (mLock) {
|
||||
mUidObservers.unregister(observer);
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("mService")
|
||||
final void enqueueUidChangeLocked(UidRecord uidRec, int uid, int change) {
|
||||
final UidRecord.ChangeItem pendingChange;
|
||||
if (uidRec == null || uidRec.pendingChange == null) {
|
||||
int enqueueUidChange(int uid, int change, int procState, long procStateSeq,
|
||||
int capability, boolean ephemeral) {
|
||||
synchronized (mLock) {
|
||||
if (mPendingUidChanges.size() == 0) {
|
||||
if (DEBUG_UID_OBSERVERS) {
|
||||
Slog.i(TAG_UID_OBSERVERS, "*** Enqueueing dispatch uid changed!");
|
||||
}
|
||||
mService.mUiHandler.post(this::dispatchUidsChanged);
|
||||
mHandler.post(mDispatchRunnable);
|
||||
}
|
||||
final int size = mAvailUidChanges.size();
|
||||
if (size > 0) {
|
||||
pendingChange = mAvailUidChanges.remove(size - 1);
|
||||
if (DEBUG_UID_OBSERVERS) {
|
||||
Slog.i(TAG_UID_OBSERVERS, "Retrieving available item: " + pendingChange);
|
||||
}
|
||||
} else {
|
||||
pendingChange = new UidRecord.ChangeItem();
|
||||
if (DEBUG_UID_OBSERVERS) {
|
||||
Slog.i(TAG_UID_OBSERVERS, "Allocating new item: " + pendingChange);
|
||||
}
|
||||
}
|
||||
if (uidRec != null) {
|
||||
uidRec.pendingChange = pendingChange;
|
||||
if ((change & UidRecord.CHANGE_GONE) != 0 && !uidRec.idle) {
|
||||
// If this uid is going away, and we haven't yet reported it is gone,
|
||||
// then do so now.
|
||||
change |= UidRecord.CHANGE_IDLE;
|
||||
}
|
||||
} else if (uid < 0) {
|
||||
throw new IllegalArgumentException("No UidRecord or uid");
|
||||
}
|
||||
pendingChange.uidRecord = uidRec;
|
||||
pendingChange.uid = uidRec != null ? uidRec.uid : uid;
|
||||
mPendingUidChanges.add(pendingChange);
|
||||
} else {
|
||||
pendingChange = uidRec.pendingChange;
|
||||
// If there is no change in idle or active state, then keep whatever was pending.
|
||||
if ((change & (UidRecord.CHANGE_IDLE | UidRecord.CHANGE_ACTIVE)) == 0) {
|
||||
change |= (pendingChange.change & (UidRecord.CHANGE_IDLE
|
||||
| UidRecord.CHANGE_ACTIVE));
|
||||
}
|
||||
// If there is no change in cached or uncached state, then keep whatever was pending.
|
||||
if ((change & (UidRecord.CHANGE_CACHED | UidRecord.CHANGE_UNCACHED)) == 0) {
|
||||
change |= (pendingChange.change & (UidRecord.CHANGE_CACHED
|
||||
| UidRecord.CHANGE_UNCACHED));
|
||||
}
|
||||
// If this is a report of the UID being gone, then we shouldn't keep any previous
|
||||
// report of it being active or cached. (That is, a gone uid is never active,
|
||||
// and never cached.)
|
||||
if ((change & UidRecord.CHANGE_GONE) != 0) {
|
||||
change &= ~(UidRecord.CHANGE_ACTIVE | UidRecord.CHANGE_CACHED);
|
||||
if (!uidRec.idle) {
|
||||
// If this uid is going away, and we haven't yet reported it is gone,
|
||||
// then do so now.
|
||||
change |= UidRecord.CHANGE_IDLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
pendingChange.change = change;
|
||||
pendingChange.processState = uidRec != null
|
||||
? uidRec.setProcState : PROCESS_STATE_NONEXISTENT;
|
||||
pendingChange.capability = uidRec != null ? uidRec.setCapability : 0;
|
||||
pendingChange.ephemeral = uidRec != null ? uidRec.ephemeral : isEphemeralLocked(uid);
|
||||
pendingChange.procStateSeq = uidRec != null ? uidRec.curProcStateSeq : 0;
|
||||
if (uidRec != null) {
|
||||
uidRec.lastReportedChange = change;
|
||||
uidRec.updateLastDispatchedProcStateSeq(change);
|
||||
}
|
||||
|
||||
// Directly update the power manager, since we sit on top of it and it is critical
|
||||
// it be kept in sync (so wake locks will be held as soon as appropriate).
|
||||
if (mService.mLocalPowerManager != null) {
|
||||
// TO DO: dispatch cached/uncached changes here, so we don't need to report
|
||||
// all proc state changes.
|
||||
if ((change & UidRecord.CHANGE_ACTIVE) != 0) {
|
||||
mService.mLocalPowerManager.uidActive(pendingChange.uid);
|
||||
}
|
||||
if ((change & UidRecord.CHANGE_IDLE) != 0) {
|
||||
mService.mLocalPowerManager.uidIdle(pendingChange.uid);
|
||||
}
|
||||
if ((change & UidRecord.CHANGE_GONE) != 0) {
|
||||
mService.mLocalPowerManager.uidGone(pendingChange.uid);
|
||||
ChangeRecord changeRecord = mPendingUidChanges.get(uid);
|
||||
if (changeRecord == null) {
|
||||
changeRecord = getOrCreateChangeRecordLocked();
|
||||
mPendingUidChanges.put(uid, changeRecord);
|
||||
} else {
|
||||
mService.mLocalPowerManager.updateUidProcState(pendingChange.uid,
|
||||
pendingChange.processState);
|
||||
change = mergeWithPendingChange(change, changeRecord.change);
|
||||
}
|
||||
|
||||
changeRecord.uid = uid;
|
||||
changeRecord.change = change;
|
||||
changeRecord.procState = procState;
|
||||
changeRecord.procStateSeq = procStateSeq;
|
||||
changeRecord.capability = capability;
|
||||
changeRecord.ephemeral = ephemeral;
|
||||
|
||||
return changeRecord.change;
|
||||
}
|
||||
}
|
||||
|
||||
SparseArray<ChangeRecord> getPendingUidChangesForTest() {
|
||||
return mPendingUidChanges;
|
||||
}
|
||||
|
||||
ActiveUids getValidateUidsForTest() {
|
||||
return mValidateUids;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static int mergeWithPendingChange(int currentChange, int pendingChange) {
|
||||
// If there is no change in idle or active state, then keep whatever was pending.
|
||||
if ((currentChange & (UidRecord.CHANGE_IDLE | UidRecord.CHANGE_ACTIVE)) == 0) {
|
||||
currentChange |= (pendingChange & (UidRecord.CHANGE_IDLE
|
||||
| UidRecord.CHANGE_ACTIVE));
|
||||
}
|
||||
// If there is no change in cached or uncached state, then keep whatever was pending.
|
||||
if ((currentChange & (UidRecord.CHANGE_CACHED | UidRecord.CHANGE_UNCACHED)) == 0) {
|
||||
currentChange |= (pendingChange & (UidRecord.CHANGE_CACHED
|
||||
| UidRecord.CHANGE_UNCACHED));
|
||||
}
|
||||
// If this is a report of the UID being gone, then we shouldn't keep any previous
|
||||
// report of it being active or cached. (That is, a gone uid is never active,
|
||||
// and never cached.)
|
||||
if ((currentChange & UidRecord.CHANGE_GONE) != 0) {
|
||||
currentChange &= ~(UidRecord.CHANGE_ACTIVE | UidRecord.CHANGE_CACHED);
|
||||
}
|
||||
return currentChange;
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private ChangeRecord getOrCreateChangeRecordLocked() {
|
||||
final ChangeRecord changeRecord;
|
||||
final int size = mAvailUidChanges.size();
|
||||
if (size > 0) {
|
||||
changeRecord = mAvailUidChanges.remove(size - 1);
|
||||
if (DEBUG_UID_OBSERVERS) {
|
||||
Slog.i(TAG_UID_OBSERVERS, "Retrieving available item: " + changeRecord);
|
||||
}
|
||||
} else {
|
||||
changeRecord = new ChangeRecord();
|
||||
if (DEBUG_UID_OBSERVERS) {
|
||||
Slog.i(TAG_UID_OBSERVERS, "Allocating new item: " + changeRecord);
|
||||
}
|
||||
}
|
||||
return changeRecord;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void dispatchUidsChanged() {
|
||||
int numUidChanges;
|
||||
synchronized (mService) {
|
||||
final int numUidChanges;
|
||||
synchronized (mLock) {
|
||||
numUidChanges = mPendingUidChanges.size();
|
||||
if (mActiveUidChanges.length < numUidChanges) {
|
||||
mActiveUidChanges = new UidRecord.ChangeItem[numUidChanges];
|
||||
mActiveUidChanges = new ChangeRecord[numUidChanges];
|
||||
}
|
||||
for (int i = 0; i < numUidChanges; i++) {
|
||||
final UidRecord.ChangeItem change = mPendingUidChanges.get(i);
|
||||
mActiveUidChanges[i] = change;
|
||||
if (change.uidRecord != null) {
|
||||
change.uidRecord.pendingChange = null;
|
||||
change.uidRecord = null;
|
||||
}
|
||||
mActiveUidChanges[i] = mPendingUidChanges.valueAt(i);
|
||||
}
|
||||
mPendingUidChanges.clear();
|
||||
if (DEBUG_UID_OBSERVERS) {
|
||||
Slog.i(TAG_UID_OBSERVERS, "*** Delivering " + numUidChanges + " uid changes");
|
||||
}
|
||||
mUidChangeDispatchCount += numUidChanges;
|
||||
}
|
||||
|
||||
mUidChangeDispatchCount += numUidChanges;
|
||||
int i = mUidObservers.beginBroadcast();
|
||||
while (i > 0) {
|
||||
i--;
|
||||
while (i-- > 0) {
|
||||
dispatchUidsChangedForObserver(mUidObservers.getBroadcastItem(i),
|
||||
(UidObserverRegistration) mUidObservers.getBroadcastCookie(i), numUidChanges);
|
||||
}
|
||||
@@ -199,7 +193,7 @@ public class UidObserverController {
|
||||
|
||||
if (VALIDATE_UID_STATES && mUidObservers.getRegisteredCallbackCount() > 0) {
|
||||
for (int j = 0; j < numUidChanges; ++j) {
|
||||
final UidRecord.ChangeItem item = mActiveUidChanges[j];
|
||||
final ChangeRecord item = mActiveUidChanges[j];
|
||||
if ((item.change & UidRecord.CHANGE_GONE) != 0) {
|
||||
mValidateUids.remove(item.uid);
|
||||
} else {
|
||||
@@ -213,14 +207,14 @@ public class UidObserverController {
|
||||
} else if ((item.change & UidRecord.CHANGE_ACTIVE) != 0) {
|
||||
validateUid.idle = false;
|
||||
}
|
||||
validateUid.setCurProcState(validateUid.setProcState = item.processState);
|
||||
validateUid.setCurProcState(validateUid.setProcState = item.procState);
|
||||
validateUid.curCapability = validateUid.setCapability = item.capability;
|
||||
validateUid.lastDispatchedProcStateSeq = item.procStateSeq;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
synchronized (mService) {
|
||||
synchronized (mLock) {
|
||||
for (int j = 0; j < numUidChanges; j++) {
|
||||
mAvailUidChanges.add(mActiveUidChanges[j]);
|
||||
}
|
||||
@@ -234,7 +228,7 @@ public class UidObserverController {
|
||||
}
|
||||
try {
|
||||
for (int j = 0; j < changesSize; j++) {
|
||||
UidRecord.ChangeItem item = mActiveUidChanges[j];
|
||||
final ChangeRecord item = mActiveUidChanges[j];
|
||||
final int change = item.change;
|
||||
if (change == UidRecord.CHANGE_PROCSTATE
|
||||
&& (reg.mWhich & ActivityManager.UID_OBSERVER_PROCSTATE) == 0) {
|
||||
@@ -285,7 +279,7 @@ public class UidObserverController {
|
||||
if ((reg.mWhich & ActivityManager.UID_OBSERVER_PROCSTATE) != 0) {
|
||||
if (DEBUG_UID_OBSERVERS) {
|
||||
Slog.i(TAG_UID_OBSERVERS, "UID CHANGED uid=" + item.uid
|
||||
+ ": " + item.processState + ": " + item.capability);
|
||||
+ ": " + item.procState + ": " + item.capability);
|
||||
}
|
||||
boolean doReport = true;
|
||||
if (reg.mCutpoint >= ActivityManager.MIN_PROCESS_STATE) {
|
||||
@@ -293,17 +287,17 @@ public class UidObserverController {
|
||||
ActivityManager.PROCESS_STATE_UNKNOWN);
|
||||
if (lastState != ActivityManager.PROCESS_STATE_UNKNOWN) {
|
||||
final boolean lastAboveCut = lastState <= reg.mCutpoint;
|
||||
final boolean newAboveCut = item.processState <= reg.mCutpoint;
|
||||
final boolean newAboveCut = item.procState <= reg.mCutpoint;
|
||||
doReport = lastAboveCut != newAboveCut;
|
||||
} else {
|
||||
doReport = item.processState != PROCESS_STATE_NONEXISTENT;
|
||||
doReport = item.procState != PROCESS_STATE_NONEXISTENT;
|
||||
}
|
||||
}
|
||||
if (doReport) {
|
||||
if (reg.mLastProcStates != null) {
|
||||
reg.mLastProcStates.put(item.uid, item.processState);
|
||||
reg.mLastProcStates.put(item.uid, item.procState);
|
||||
}
|
||||
observer.onUidStateChanged(item.uid, item.processState,
|
||||
observer.onUidStateChanged(item.uid, item.procState,
|
||||
item.procStateSeq, item.capability);
|
||||
}
|
||||
}
|
||||
@@ -320,94 +314,82 @@ public class UidObserverController {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isEphemeralLocked(int uid) {
|
||||
final String[] packages = mService.mContext.getPackageManager().getPackagesForUid(uid);
|
||||
if (packages == null || packages.length != 1) { // Ephemeral apps cannot share uid
|
||||
return false;
|
||||
}
|
||||
return mService.getPackageManagerInternalLocked().isPackageEphemeral(
|
||||
UserHandle.getUserId(uid), packages[0]);
|
||||
UidRecord getValidateUidRecord(int uid) {
|
||||
return mValidateUids.get(uid);
|
||||
}
|
||||
|
||||
@GuardedBy("mService")
|
||||
void dump(PrintWriter pw, String dumpPackage) {
|
||||
final int count = mUidObservers.getRegisteredCallbackCount();
|
||||
boolean printed = false;
|
||||
for (int i = 0; i < count; i++) {
|
||||
final UidObserverRegistration reg = (UidObserverRegistration)
|
||||
mUidObservers.getRegisteredCallbackCookie(i);
|
||||
if (dumpPackage == null || dumpPackage.equals(reg.mPkg)) {
|
||||
if (!printed) {
|
||||
pw.println(" mUidObservers:");
|
||||
printed = true;
|
||||
}
|
||||
pw.print(" "); UserHandle.formatUid(pw, reg.mUid);
|
||||
pw.print(" "); pw.print(reg.mPkg);
|
||||
final IUidObserver observer = mUidObservers.getRegisteredCallbackItem(i);
|
||||
pw.print(" "); pw.print(observer.getClass().getTypeName()); pw.print(":");
|
||||
if ((reg.mWhich & ActivityManager.UID_OBSERVER_IDLE) != 0) {
|
||||
pw.print(" IDLE");
|
||||
}
|
||||
if ((reg.mWhich & ActivityManager.UID_OBSERVER_ACTIVE) != 0) {
|
||||
pw.print(" ACT");
|
||||
}
|
||||
if ((reg.mWhich & ActivityManager.UID_OBSERVER_GONE) != 0) {
|
||||
pw.print(" GONE");
|
||||
}
|
||||
if ((reg.mWhich & ActivityManager.UID_OBSERVER_PROCSTATE) != 0) {
|
||||
pw.print(" STATE");
|
||||
pw.print(" (cut="); pw.print(reg.mCutpoint);
|
||||
pw.print(")");
|
||||
}
|
||||
pw.println();
|
||||
if (reg.mLastProcStates != null) {
|
||||
final int size = reg.mLastProcStates.size();
|
||||
for (int j = 0; j < size; j++) {
|
||||
pw.print(" Last ");
|
||||
UserHandle.formatUid(pw, reg.mLastProcStates.keyAt(j));
|
||||
pw.print(": "); pw.println(reg.mLastProcStates.valueAt(j));
|
||||
synchronized (mLock) {
|
||||
final int count = mUidObservers.getRegisteredCallbackCount();
|
||||
boolean printed = false;
|
||||
for (int i = 0; i < count; i++) {
|
||||
final UidObserverRegistration reg = (UidObserverRegistration)
|
||||
mUidObservers.getRegisteredCallbackCookie(i);
|
||||
if (dumpPackage == null || dumpPackage.equals(reg.mPkg)) {
|
||||
if (!printed) {
|
||||
pw.println(" mUidObservers:");
|
||||
printed = true;
|
||||
}
|
||||
reg.dump(pw, mUidObservers.getRegisteredCallbackItem(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pw.println();
|
||||
pw.print(" mUidChangeDispatchCount=");
|
||||
pw.print(mUidChangeDispatchCount);
|
||||
pw.println();
|
||||
pw.println(" Slow UID dispatches:");
|
||||
final int size = mUidObservers.beginBroadcast();
|
||||
for (int i = 0; i < size; i++) {
|
||||
UidObserverRegistration r =
|
||||
(UidObserverRegistration) mUidObservers.getBroadcastCookie(i);
|
||||
pw.print(" ");
|
||||
pw.print(mUidObservers.getBroadcastItem(i).getClass().getTypeName());
|
||||
pw.print(": ");
|
||||
pw.print(r.mSlowDispatchCount);
|
||||
pw.print(" / Max ");
|
||||
pw.print(r.mMaxDispatchTime);
|
||||
pw.println("ms");
|
||||
pw.println();
|
||||
pw.print(" mUidChangeDispatchCount=");
|
||||
pw.print(mUidChangeDispatchCount);
|
||||
pw.println();
|
||||
pw.println(" Slow UID dispatches:");
|
||||
for (int i = 0; i < count; i++) {
|
||||
final UidObserverRegistration reg = (UidObserverRegistration)
|
||||
mUidObservers.getRegisteredCallbackCookie(i);
|
||||
pw.print(" ");
|
||||
pw.print(mUidObservers.getRegisteredCallbackItem(i).getClass().getTypeName());
|
||||
pw.print(": ");
|
||||
pw.print(reg.mSlowDispatchCount);
|
||||
pw.print(" / Max ");
|
||||
pw.print(reg.mMaxDispatchTime);
|
||||
pw.println("ms");
|
||||
}
|
||||
}
|
||||
mUidObservers.finishBroadcast();
|
||||
}
|
||||
|
||||
@GuardedBy("mService")
|
||||
void dumpDebug(ProtoOutputStream proto, String dumpPackage) {
|
||||
final int count = mUidObservers.getRegisteredCallbackCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
final UidObserverRegistration reg = (UidObserverRegistration)
|
||||
mUidObservers.getRegisteredCallbackCookie(i);
|
||||
if (dumpPackage == null || dumpPackage.equals(reg.mPkg)) {
|
||||
reg.dumpDebug(proto, ActivityManagerServiceDumpProcessesProto.UID_OBSERVERS);
|
||||
synchronized (mLock) {
|
||||
final int count = mUidObservers.getRegisteredCallbackCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
final UidObserverRegistration reg = (UidObserverRegistration)
|
||||
mUidObservers.getRegisteredCallbackCookie(i);
|
||||
if (dumpPackage == null || dumpPackage.equals(reg.mPkg)) {
|
||||
reg.dumpDebug(proto, ActivityManagerServiceDumpProcessesProto.UID_OBSERVERS);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean dumpValidateUids(PrintWriter pw, String dumpPackage, int dumpAppId,
|
||||
String header, boolean needSep) {
|
||||
return mValidateUids.dump(pw, dumpPackage, dumpAppId, header, needSep);
|
||||
}
|
||||
|
||||
void dumpValidateUidsProto(ProtoOutputStream proto, String dumpPackage,
|
||||
int dumpAppId, long fieldId) {
|
||||
mValidateUids.dumpProto(proto, dumpPackage, dumpAppId, fieldId);
|
||||
}
|
||||
|
||||
static final class ChangeRecord {
|
||||
public int uid;
|
||||
public int change;
|
||||
public int procState;
|
||||
public int capability;
|
||||
public boolean ephemeral;
|
||||
public long procStateSeq;
|
||||
}
|
||||
|
||||
private static final class UidObserverRegistration {
|
||||
final int mUid;
|
||||
final String mPkg;
|
||||
final int mWhich;
|
||||
final int mCutpoint;
|
||||
private final int mUid;
|
||||
private final String mPkg;
|
||||
private final int mWhich;
|
||||
private final int mCutpoint;
|
||||
|
||||
/**
|
||||
* Total # of callback calls that took more than {@link #SLOW_UID_OBSERVER_THRESHOLD_MS}.
|
||||
@@ -439,10 +421,42 @@ public class UidObserverController {
|
||||
this.mPkg = pkg;
|
||||
this.mWhich = which;
|
||||
this.mCutpoint = cutpoint;
|
||||
if (cutpoint >= ActivityManager.MIN_PROCESS_STATE) {
|
||||
mLastProcStates = new SparseIntArray();
|
||||
} else {
|
||||
mLastProcStates = null;
|
||||
mLastProcStates = cutpoint >= ActivityManager.MIN_PROCESS_STATE
|
||||
? new SparseIntArray() : null;
|
||||
}
|
||||
|
||||
void dump(PrintWriter pw, IUidObserver observer) {
|
||||
pw.print(" ");
|
||||
UserHandle.formatUid(pw, mUid);
|
||||
pw.print(" ");
|
||||
pw.print(mPkg);
|
||||
pw.print(" ");
|
||||
pw.print(observer.getClass().getTypeName());
|
||||
pw.print(":");
|
||||
if ((mWhich & ActivityManager.UID_OBSERVER_IDLE) != 0) {
|
||||
pw.print(" IDLE");
|
||||
}
|
||||
if ((mWhich & ActivityManager.UID_OBSERVER_ACTIVE) != 0) {
|
||||
pw.print(" ACT");
|
||||
}
|
||||
if ((mWhich & ActivityManager.UID_OBSERVER_GONE) != 0) {
|
||||
pw.print(" GONE");
|
||||
}
|
||||
if ((mWhich & ActivityManager.UID_OBSERVER_PROCSTATE) != 0) {
|
||||
pw.print(" STATE");
|
||||
pw.print(" (cut=");
|
||||
pw.print(mCutpoint);
|
||||
pw.print(")");
|
||||
}
|
||||
pw.println();
|
||||
if (mLastProcStates != null) {
|
||||
final int size = mLastProcStates.size();
|
||||
for (int j = 0; j < size; j++) {
|
||||
pw.print(" Last ");
|
||||
UserHandle.formatUid(pw, mLastProcStates.keyAt(j));
|
||||
pw.print(": ");
|
||||
pw.println(mLastProcStates.valueAt(j));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -107,17 +107,6 @@ public final class UidRecord {
|
||||
UidRecordProto.CHANGE_UNCACHED,
|
||||
};
|
||||
|
||||
static final class ChangeItem {
|
||||
UidRecord uidRecord;
|
||||
int uid;
|
||||
int change;
|
||||
int processState;
|
||||
int capability;
|
||||
boolean ephemeral;
|
||||
long procStateSeq;
|
||||
}
|
||||
|
||||
ChangeItem pendingChange;
|
||||
int lastReportedChange;
|
||||
|
||||
public UidRecord(int _uid) {
|
||||
|
||||
@@ -68,6 +68,7 @@ import android.os.Message;
|
||||
import android.os.Process;
|
||||
import android.os.RemoteException;
|
||||
import android.os.SystemClock;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import androidx.test.filters.FlakyTest;
|
||||
import androidx.test.filters.MediumTest;
|
||||
@@ -76,6 +77,7 @@ import androidx.test.filters.SmallTest;
|
||||
import com.android.server.LocalServices;
|
||||
import com.android.server.am.ProcessList.IsolatedUidRange;
|
||||
import com.android.server.am.ProcessList.IsolatedUidRangeAllocator;
|
||||
import com.android.server.am.UidObserverController.ChangeRecord;
|
||||
import com.android.server.appop.AppOpsService;
|
||||
import com.android.server.wm.ActivityTaskManagerService;
|
||||
|
||||
@@ -539,15 +541,15 @@ public class ActivityManagerServiceTest {
|
||||
ActivityManager.PROCESS_STATE_CACHED_ACTIVITY,
|
||||
ActivityManager.PROCESS_STATE_TOP
|
||||
};
|
||||
final Map<Integer, UidRecord.ChangeItem> changeItems = new HashMap<>();
|
||||
final Map<Integer, ChangeRecord> changeItems = new HashMap<>();
|
||||
for (int i = 0; i < changesForPendingUidRecords.length; ++i) {
|
||||
final UidRecord.ChangeItem pendingChange = new UidRecord.ChangeItem();
|
||||
final ChangeRecord pendingChange = new ChangeRecord();
|
||||
pendingChange.change = changesForPendingUidRecords[i];
|
||||
pendingChange.uid = i;
|
||||
pendingChange.processState = procStatesForPendingUidRecords[i];
|
||||
pendingChange.procState = procStatesForPendingUidRecords[i];
|
||||
pendingChange.procStateSeq = i;
|
||||
changeItems.put(changesForPendingUidRecords[i], pendingChange);
|
||||
mAms.mUidObserverController.mPendingUidChanges.add(pendingChange);
|
||||
addPendingUidChange(pendingChange);
|
||||
}
|
||||
|
||||
mAms.mUidObserverController.dispatchUidsChanged();
|
||||
@@ -602,7 +604,7 @@ public class ActivityManagerServiceTest {
|
||||
verifyObserverReceivedChanges(observerToTest, changesToVerify, changeItems,
|
||||
(observer, changeItem) -> {
|
||||
verify(observer).onUidStateChanged(changeItem.uid,
|
||||
changeItem.processState, changeItem.procStateSeq,
|
||||
changeItem.procState, changeItem.procStateSeq,
|
||||
ActivityManager.PROCESS_CAPABILITY_NONE);
|
||||
});
|
||||
}
|
||||
@@ -612,14 +614,14 @@ public class ActivityManagerServiceTest {
|
||||
}
|
||||
|
||||
private interface ObserverChangesVerifier {
|
||||
void verify(IUidObserver observer, UidRecord.ChangeItem changeItem) throws RemoteException;
|
||||
void verify(IUidObserver observer, ChangeRecord changeItem) throws RemoteException;
|
||||
}
|
||||
|
||||
private void verifyObserverReceivedChanges(IUidObserver observer, int[] changesToVerify,
|
||||
Map<Integer, UidRecord.ChangeItem> changeItems, ObserverChangesVerifier verifier)
|
||||
Map<Integer, ChangeRecord> changeItems, ObserverChangesVerifier verifier)
|
||||
throws RemoteException {
|
||||
for (int change : changesToVerify) {
|
||||
final UidRecord.ChangeItem changeItem = changeItems.get(change);
|
||||
final ChangeRecord changeItem = changeItems.get(change);
|
||||
verifier.verify(observer, changeItem);
|
||||
}
|
||||
}
|
||||
@@ -641,59 +643,59 @@ public class ActivityManagerServiceTest {
|
||||
// So, resetting the mock here.
|
||||
Mockito.reset(observer);
|
||||
|
||||
final UidRecord.ChangeItem changeItem = new UidRecord.ChangeItem();
|
||||
final ChangeRecord changeItem = new ChangeRecord();
|
||||
changeItem.uid = TEST_UID;
|
||||
changeItem.change = UidRecord.CHANGE_PROCSTATE;
|
||||
changeItem.processState = ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
|
||||
changeItem.procState = ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
|
||||
changeItem.procStateSeq = 111;
|
||||
mAms.mUidObserverController.mPendingUidChanges.add(changeItem);
|
||||
addPendingUidChange(changeItem);
|
||||
mAms.mUidObserverController.dispatchUidsChanged();
|
||||
// First process state message is always delivered regardless of whether the process state
|
||||
// change is above or below the cutpoint (PROCESS_STATE_SERVICE).
|
||||
verify(observer).onUidStateChanged(TEST_UID,
|
||||
changeItem.processState, changeItem.procStateSeq,
|
||||
changeItem.procState, changeItem.procStateSeq,
|
||||
ActivityManager.PROCESS_CAPABILITY_NONE);
|
||||
verifyNoMoreInteractions(observer);
|
||||
|
||||
changeItem.processState = ActivityManager.PROCESS_STATE_RECEIVER;
|
||||
mAms.mUidObserverController.mPendingUidChanges.add(changeItem);
|
||||
changeItem.procState = ActivityManager.PROCESS_STATE_RECEIVER;
|
||||
addPendingUidChange(changeItem);
|
||||
mAms.mUidObserverController.dispatchUidsChanged();
|
||||
// Previous process state change is below cutpoint (PROCESS_STATE_SERVICE) and
|
||||
// the current process state change is also below cutpoint, so no callback will be invoked.
|
||||
verifyNoMoreInteractions(observer);
|
||||
|
||||
changeItem.processState = ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
|
||||
mAms.mUidObserverController.mPendingUidChanges.add(changeItem);
|
||||
changeItem.procState = ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
|
||||
addPendingUidChange(changeItem);
|
||||
mAms.mUidObserverController.dispatchUidsChanged();
|
||||
// Previous process state change is below cutpoint (PROCESS_STATE_SERVICE) and
|
||||
// the current process state change is above cutpoint, so callback will be invoked with the
|
||||
// current process state change.
|
||||
verify(observer).onUidStateChanged(TEST_UID,
|
||||
changeItem.processState, changeItem.procStateSeq,
|
||||
changeItem.procState, changeItem.procStateSeq,
|
||||
ActivityManager.PROCESS_CAPABILITY_NONE);
|
||||
verifyNoMoreInteractions(observer);
|
||||
|
||||
changeItem.processState = ActivityManager.PROCESS_STATE_TOP;
|
||||
mAms.mUidObserverController.mPendingUidChanges.add(changeItem);
|
||||
changeItem.procState = ActivityManager.PROCESS_STATE_TOP;
|
||||
addPendingUidChange(changeItem);
|
||||
mAms.mUidObserverController.dispatchUidsChanged();
|
||||
// Previous process state change is above cutpoint (PROCESS_STATE_SERVICE) and
|
||||
// the current process state change is also above cutpoint, so no callback will be invoked.
|
||||
verifyNoMoreInteractions(observer);
|
||||
|
||||
changeItem.processState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
|
||||
mAms.mUidObserverController.mPendingUidChanges.add(changeItem);
|
||||
changeItem.procState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
|
||||
addPendingUidChange(changeItem);
|
||||
mAms.mUidObserverController.dispatchUidsChanged();
|
||||
// Previous process state change is above cutpoint (PROCESS_STATE_SERVICE) and
|
||||
// the current process state change is below cutpoint, so callback will be invoked with the
|
||||
// current process state change.
|
||||
verify(observer).onUidStateChanged(TEST_UID,
|
||||
changeItem.processState, changeItem.procStateSeq,
|
||||
changeItem.procState, changeItem.procStateSeq,
|
||||
ActivityManager.PROCESS_CAPABILITY_NONE);
|
||||
verifyNoMoreInteractions(observer);
|
||||
}
|
||||
|
||||
/**
|
||||
* This test verifies that {@link ActivityManagerService#mValidateUids} which is a
|
||||
* This test verifies that {@link UidObserverController#getValidateUidsForTest()} which is a
|
||||
* part of dumpsys is correctly updated.
|
||||
*/
|
||||
@Test
|
||||
@@ -707,45 +709,45 @@ public class ActivityManagerServiceTest {
|
||||
ActivityManager.PROCESS_STATE_SERVICE,
|
||||
ActivityManager.PROCESS_STATE_RECEIVER
|
||||
};
|
||||
final ArrayList<UidRecord.ChangeItem> pendingItemsForUids =
|
||||
final ArrayList<ChangeRecord> pendingItemsForUids =
|
||||
new ArrayList<>(changesForPendingItems.length);
|
||||
for (int i = 0; i < changesForPendingItems.length; ++i) {
|
||||
final UidRecord.ChangeItem item = new UidRecord.ChangeItem();
|
||||
final ChangeRecord item = new ChangeRecord();
|
||||
item.uid = i;
|
||||
item.change = changesForPendingItems[i];
|
||||
item.processState = procStatesForPendingItems[i];
|
||||
item.procState = procStatesForPendingItems[i];
|
||||
pendingItemsForUids.add(i, item);
|
||||
}
|
||||
|
||||
// Verify that when there no observers listening to uid state changes, then there will
|
||||
// be no changes to validateUids.
|
||||
mAms.mUidObserverController.mPendingUidChanges.addAll(pendingItemsForUids);
|
||||
addPendingUidChanges(pendingItemsForUids);
|
||||
mAms.mUidObserverController.dispatchUidsChanged();
|
||||
assertEquals("No observers registered, so validateUids should be empty",
|
||||
0, mAms.mUidObserverController.mValidateUids.size());
|
||||
0, mAms.mUidObserverController.getValidateUidsForTest().size());
|
||||
|
||||
final IUidObserver observer = mock(IUidObserver.Stub.class);
|
||||
when(observer.asBinder()).thenReturn((IBinder) observer);
|
||||
mAms.registerUidObserver(observer, 0, 0, null);
|
||||
// Verify that when observers are registered, then validateUids is correctly updated.
|
||||
mAms.mUidObserverController.mPendingUidChanges.addAll(pendingItemsForUids);
|
||||
addPendingUidChanges(pendingItemsForUids);
|
||||
mAms.mUidObserverController.dispatchUidsChanged();
|
||||
for (int i = 0; i < pendingItemsForUids.size(); ++i) {
|
||||
final UidRecord.ChangeItem item = pendingItemsForUids.get(i);
|
||||
final ChangeRecord item = pendingItemsForUids.get(i);
|
||||
final UidRecord validateUidRecord =
|
||||
mAms.mUidObserverController.mValidateUids.get(item.uid);
|
||||
mAms.mUidObserverController.getValidateUidsForTest().get(item.uid);
|
||||
if ((item.change & UidRecord.CHANGE_GONE) != 0) {
|
||||
assertNull("validateUidRecord should be null since the change is either "
|
||||
+ "CHANGE_GONE or CHANGE_GONE_IDLE", validateUidRecord);
|
||||
} else {
|
||||
assertNotNull("validateUidRecord should not be null since the change is neither "
|
||||
+ "CHANGE_GONE nor CHANGE_GONE_IDLE", validateUidRecord);
|
||||
assertEquals("processState: " + item.processState + " curProcState: "
|
||||
assertEquals("processState: " + item.procState + " curProcState: "
|
||||
+ validateUidRecord.getCurProcState() + " should have been equal",
|
||||
item.processState, validateUidRecord.getCurProcState());
|
||||
assertEquals("processState: " + item.processState + " setProcState: "
|
||||
item.procState, validateUidRecord.getCurProcState());
|
||||
assertEquals("processState: " + item.procState + " setProcState: "
|
||||
+ validateUidRecord.getCurProcState() + " should have been equal",
|
||||
item.processState, validateUidRecord.setProcState);
|
||||
item.procState, validateUidRecord.setProcState);
|
||||
if (item.change == UidRecord.CHANGE_IDLE) {
|
||||
assertTrue("UidRecord.idle should be updated to true for CHANGE_IDLE",
|
||||
validateUidRecord.idle);
|
||||
@@ -759,19 +761,19 @@ public class ActivityManagerServiceTest {
|
||||
// Verify that when uid state changes to CHANGE_GONE or CHANGE_GONE_IDLE, then it
|
||||
// will be removed from validateUids.
|
||||
assertNotEquals("validateUids should not be empty", 0,
|
||||
mAms.mUidObserverController.mValidateUids.size());
|
||||
mAms.mUidObserverController.getValidateUidsForTest().size());
|
||||
for (int i = 0; i < pendingItemsForUids.size(); ++i) {
|
||||
final UidRecord.ChangeItem item = pendingItemsForUids.get(i);
|
||||
final ChangeRecord item = pendingItemsForUids.get(i);
|
||||
// Assign CHANGE_GONE_IDLE to some items and CHANGE_GONE to the others, using even/odd
|
||||
// distribution for this assignment.
|
||||
item.change = (i % 2) == 0 ? (UidRecord.CHANGE_GONE | UidRecord.CHANGE_IDLE)
|
||||
: UidRecord.CHANGE_GONE;
|
||||
}
|
||||
mAms.mUidObserverController.mPendingUidChanges.addAll(pendingItemsForUids);
|
||||
addPendingUidChanges(pendingItemsForUids);
|
||||
mAms.mUidObserverController.dispatchUidsChanged();
|
||||
assertEquals("validateUids should be empty, size="
|
||||
+ mAms.mUidObserverController.mValidateUids.size(),
|
||||
0, mAms.mUidObserverController.mValidateUids.size());
|
||||
+ mAms.mUidObserverController.getValidateUidsForTest().size(),
|
||||
0, mAms.mUidObserverController.getValidateUidsForTest().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -784,8 +786,6 @@ public class ActivityManagerServiceTest {
|
||||
|
||||
// Add a pending change for TEST_UID and verify enqueueUidChangeLocked still works as
|
||||
// expected.
|
||||
final UidRecord.ChangeItem changeItem = new UidRecord.ChangeItem();
|
||||
uidRecord.pendingChange = changeItem;
|
||||
uidRecord.curProcStateSeq = TEST_PROC_STATE_SEQ2;
|
||||
verifyLastProcStateSeqUpdated(uidRecord, -1, TEST_PROC_STATE_SEQ2);
|
||||
}
|
||||
@@ -793,7 +793,7 @@ public class ActivityManagerServiceTest {
|
||||
@Test
|
||||
public void testEnqueueUidChangeLocked_nullUidRecord() {
|
||||
// Use "null" uidRecord to make sure there is no crash.
|
||||
mAms.mUidObserverController.enqueueUidChangeLocked(null, TEST_UID, UidRecord.CHANGE_ACTIVE);
|
||||
mAms.enqueueUidChangeLocked(null, TEST_UID, UidRecord.CHANGE_ACTIVE);
|
||||
}
|
||||
|
||||
private void verifyLastProcStateSeqUpdated(UidRecord uidRecord, int uid, long curProcstateSeq) {
|
||||
@@ -802,7 +802,7 @@ public class ActivityManagerServiceTest {
|
||||
final int changeToDispatch = UID_RECORD_CHANGES[i];
|
||||
// Reset lastProcStateSeqDispatchToObservers after every test.
|
||||
uidRecord.lastDispatchedProcStateSeq = 0;
|
||||
mAms.mUidObserverController.enqueueUidChangeLocked(uidRecord, uid, changeToDispatch);
|
||||
mAms.enqueueUidChangeLocked(uidRecord, uid, changeToDispatch);
|
||||
// Verify there is no effect on curProcStateSeq.
|
||||
assertEquals(curProcstateSeq, uidRecord.curProcStateSeq);
|
||||
if ((changeToDispatch & UidRecord.CHANGE_GONE) != 0) {
|
||||
@@ -833,16 +833,16 @@ public class ActivityManagerServiceTest {
|
||||
|
||||
// Reset the current state
|
||||
mHandler.reset();
|
||||
uidRecord.pendingChange = null;
|
||||
mAms.mUidObserverController.mPendingUidChanges.clear();
|
||||
clearPendingUidChanges();
|
||||
|
||||
mAms.mUidObserverController.enqueueUidChangeLocked(uidRecord, -1, changeToDispatch);
|
||||
mAms.enqueueUidChangeLocked(uidRecord, -1, changeToDispatch);
|
||||
|
||||
// Verify that UidRecord.pendingChange is updated correctly.
|
||||
assertNotNull(uidRecord.pendingChange);
|
||||
assertEquals(TEST_UID, uidRecord.pendingChange.uid);
|
||||
assertEquals(expectedProcState, uidRecord.pendingChange.processState);
|
||||
assertEquals(TEST_PROC_STATE_SEQ1, uidRecord.pendingChange.procStateSeq);
|
||||
// Verify that pendingChange is updated correctly.
|
||||
final ChangeRecord pendingChange = getPendingChange(uidRecord.uid);
|
||||
assertNotNull(pendingChange);
|
||||
assertEquals(TEST_UID, pendingChange.uid);
|
||||
assertEquals(expectedProcState, pendingChange.procState);
|
||||
assertEquals(TEST_PROC_STATE_SEQ1, pendingChange.procStateSeq);
|
||||
|
||||
// TODO: Verify that DISPATCH_UIDS_CHANGED_UI_MSG is posted to handler.
|
||||
}
|
||||
@@ -923,6 +923,29 @@ public class ActivityManagerServiceTest {
|
||||
mAms.mProcessList.mActiveUids.clear();
|
||||
}
|
||||
|
||||
private ChangeRecord getPendingChange(int uid) {
|
||||
final SparseArray<ChangeRecord> pendingChanges =
|
||||
mAms.mUidObserverController.getPendingUidChangesForTest();
|
||||
return pendingChanges.get(uid);
|
||||
}
|
||||
|
||||
private void addPendingUidChange(ChangeRecord record) {
|
||||
mAms.mUidObserverController.getPendingUidChangesForTest().put(record.uid, record);
|
||||
}
|
||||
|
||||
private void addPendingUidChanges(ArrayList<ChangeRecord> changes) {
|
||||
final SparseArray<ChangeRecord> pendingChanges =
|
||||
mAms.mUidObserverController.getPendingUidChangesForTest();
|
||||
for (int i = 0; i < changes.size(); ++i) {
|
||||
final ChangeRecord record = changes.get(i);
|
||||
pendingChanges.put(record.uid, record);
|
||||
}
|
||||
}
|
||||
|
||||
private void clearPendingUidChanges() {
|
||||
mAms.mUidObserverController.getPendingUidChangesForTest().clear();
|
||||
}
|
||||
|
||||
private static class TestHandler extends Handler {
|
||||
private static final long WAIT_FOR_MSG_TIMEOUT_MS = 4000; // 4 sec
|
||||
private static final long WAIT_FOR_MSG_INTERVAL_MS = 400; // 0.4 sec
|
||||
|
||||
@@ -0,0 +1,233 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.am;
|
||||
|
||||
import static android.app.ActivityManager.PROCESS_CAPABILITY_ALL;
|
||||
import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION;
|
||||
import static android.app.ActivityManager.PROCESS_CAPABILITY_NONE;
|
||||
import static android.app.ActivityManager.PROCESS_STATE_CACHED_RECENT;
|
||||
import static android.app.ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
|
||||
import static android.app.ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND;
|
||||
import static android.app.ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
|
||||
import static android.app.ActivityManager.PROCESS_STATE_RECEIVER;
|
||||
import static android.app.ActivityManager.PROCESS_STATE_SERVICE;
|
||||
import static android.app.ActivityManager.PROCESS_STATE_TOP;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static junit.framework.Assert.assertNotNull;
|
||||
import static junit.framework.Assert.assertNull;
|
||||
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.app.IUidObserver;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.util.DebugUtils;
|
||||
import android.util.Pair;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.server.am.UidObserverController.ChangeRecord;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
@SmallTest
|
||||
public class UidObserverControllerTest {
|
||||
private static final int TEST_UID1 = 1111;
|
||||
private static final int TEST_UID2 = 2222;
|
||||
private static final int TEST_UID3 = 3333;
|
||||
|
||||
private static final String TEST_PKG1 = "com.example1";
|
||||
private static final String TEST_PKG2 = "com.example2";
|
||||
private static final String TEST_PKG3 = "com.example3";
|
||||
|
||||
private UidObserverController mUidObserverController;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mUidObserverController = new UidObserverController(Mockito.mock(Handler.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEnqueueUidChange() {
|
||||
int change = mUidObserverController.enqueueUidChange(TEST_UID1, UidRecord.CHANGE_ACTIVE,
|
||||
PROCESS_STATE_FOREGROUND_SERVICE, PROCESS_CAPABILITY_ALL, 0, false);
|
||||
assertEquals("expected=ACTIVE,actual=" + changeToStr(change),
|
||||
UidRecord.CHANGE_ACTIVE, change);
|
||||
assertPendingChange(TEST_UID1, UidRecord.CHANGE_ACTIVE, PROCESS_STATE_FOREGROUND_SERVICE,
|
||||
PROCESS_CAPABILITY_ALL, 0, false);
|
||||
assertNull(getPendingChange(TEST_UID2));
|
||||
|
||||
change = mUidObserverController.enqueueUidChange(TEST_UID2, UidRecord.CHANGE_CACHED,
|
||||
PROCESS_STATE_CACHED_RECENT, PROCESS_CAPABILITY_NONE, 99, true);
|
||||
assertEquals("expected=ACTIVE,actual=" + changeToStr(change),
|
||||
UidRecord.CHANGE_CACHED, change);
|
||||
assertPendingChange(TEST_UID1, UidRecord.CHANGE_ACTIVE, PROCESS_STATE_FOREGROUND_SERVICE,
|
||||
PROCESS_CAPABILITY_ALL, 0, false);
|
||||
assertPendingChange(TEST_UID2, UidRecord.CHANGE_CACHED, PROCESS_STATE_CACHED_RECENT,
|
||||
PROCESS_CAPABILITY_NONE, 99, true);
|
||||
|
||||
change = mUidObserverController.enqueueUidChange(TEST_UID1, UidRecord.CHANGE_UNCACHED,
|
||||
PROCESS_STATE_TOP, PROCESS_CAPABILITY_ALL, 0, false);
|
||||
assertEquals("expected=ACTIVE|UNCACHED,actual=" + changeToStr(change),
|
||||
UidRecord.CHANGE_ACTIVE | UidRecord.CHANGE_UNCACHED, change);
|
||||
assertPendingChange(TEST_UID1, UidRecord.CHANGE_ACTIVE | UidRecord.CHANGE_UNCACHED,
|
||||
PROCESS_STATE_TOP, PROCESS_CAPABILITY_ALL, 0, false);
|
||||
assertPendingChange(TEST_UID2, UidRecord.CHANGE_CACHED, PROCESS_STATE_CACHED_RECENT,
|
||||
PROCESS_CAPABILITY_NONE, 99, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMergeWithPendingChange() {
|
||||
final SparseArray<Pair<Integer, Integer>> changesToVerify = new SparseArray<>();
|
||||
|
||||
changesToVerify.put(UidRecord.CHANGE_ACTIVE,
|
||||
Pair.create(UidRecord.CHANGE_ACTIVE, UidRecord.CHANGE_IDLE));
|
||||
changesToVerify.put(UidRecord.CHANGE_IDLE,
|
||||
Pair.create(UidRecord.CHANGE_IDLE, UidRecord.CHANGE_ACTIVE));
|
||||
changesToVerify.put(UidRecord.CHANGE_CACHED,
|
||||
Pair.create(UidRecord.CHANGE_CACHED, UidRecord.CHANGE_UNCACHED));
|
||||
changesToVerify.put(UidRecord.CHANGE_UNCACHED,
|
||||
Pair.create(UidRecord.CHANGE_UNCACHED, UidRecord.CHANGE_CACHED));
|
||||
changesToVerify.put(UidRecord.CHANGE_ACTIVE | UidRecord.CHANGE_UNCACHED,
|
||||
Pair.create(UidRecord.CHANGE_ACTIVE, UidRecord.CHANGE_UNCACHED));
|
||||
changesToVerify.put(UidRecord.CHANGE_IDLE | UidRecord.CHANGE_CACHED,
|
||||
Pair.create(UidRecord.CHANGE_IDLE, UidRecord.CHANGE_CACHED));
|
||||
changesToVerify.put(UidRecord.CHANGE_GONE,
|
||||
Pair.create(UidRecord.CHANGE_GONE, UidRecord.CHANGE_ACTIVE));
|
||||
changesToVerify.put(UidRecord.CHANGE_GONE,
|
||||
Pair.create(UidRecord.CHANGE_GONE, UidRecord.CHANGE_CACHED));
|
||||
|
||||
for (int i = 0; i < changesToVerify.size(); ++i) {
|
||||
final int expectedChange = changesToVerify.keyAt(i);
|
||||
final int currentChange = changesToVerify.valueAt(i).first;
|
||||
final int pendingChange = changesToVerify.valueAt(i).second;
|
||||
assertEquals("current=" + changeToStr(currentChange) + ", pending="
|
||||
+ changeToStr(pendingChange) + "exp=" + changeToStr(expectedChange),
|
||||
expectedChange, UidObserverController.mergeWithPendingChange(
|
||||
currentChange, pendingChange));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDispatchUidsChanged() throws RemoteException {
|
||||
addPendingChange(TEST_UID1, UidRecord.CHANGE_ACTIVE | UidRecord.CHANGE_PROCSTATE,
|
||||
PROCESS_STATE_TOP, 0, PROCESS_CAPABILITY_ALL, false);
|
||||
|
||||
final IUidObserver observer1 = Mockito.mock(IUidObserver.Stub.class);
|
||||
registerObserver(observer1,
|
||||
ActivityManager.UID_OBSERVER_PROCSTATE | ActivityManager.UID_OBSERVER_ACTIVE,
|
||||
PROCESS_STATE_IMPORTANT_FOREGROUND, TEST_PKG2, TEST_UID2);
|
||||
final IUidObserver observer2 = Mockito.mock(IUidObserver.Stub.class);
|
||||
registerObserver(observer2, ActivityManager.UID_OBSERVER_PROCSTATE,
|
||||
PROCESS_STATE_SERVICE, TEST_PKG3, TEST_UID3);
|
||||
|
||||
mUidObserverController.dispatchUidsChanged();
|
||||
verify(observer1).onUidStateChanged(TEST_UID1, PROCESS_STATE_TOP,
|
||||
0, PROCESS_CAPABILITY_ALL);
|
||||
verify(observer1).onUidActive(TEST_UID1);
|
||||
verifyNoMoreInteractions(observer1);
|
||||
verify(observer2).onUidStateChanged(TEST_UID1, PROCESS_STATE_TOP,
|
||||
0, PROCESS_CAPABILITY_ALL);
|
||||
verifyNoMoreInteractions(observer2);
|
||||
|
||||
addPendingChange(TEST_UID1, UidRecord.CHANGE_PROCSTATE, PROCESS_STATE_IMPORTANT_BACKGROUND,
|
||||
99, PROCESS_CAPABILITY_FOREGROUND_LOCATION, false);
|
||||
mUidObserverController.dispatchUidsChanged();
|
||||
verify(observer1).onUidStateChanged(TEST_UID1, PROCESS_STATE_IMPORTANT_BACKGROUND,
|
||||
99, PROCESS_CAPABILITY_FOREGROUND_LOCATION);
|
||||
verifyNoMoreInteractions(observer1);
|
||||
verifyNoMoreInteractions(observer2);
|
||||
|
||||
addPendingChange(TEST_UID1, UidRecord.CHANGE_PROCSTATE, PROCESS_STATE_RECEIVER,
|
||||
111, PROCESS_CAPABILITY_NONE, false);
|
||||
mUidObserverController.dispatchUidsChanged();
|
||||
verify(observer2).onUidStateChanged(TEST_UID1, PROCESS_STATE_RECEIVER,
|
||||
111, PROCESS_CAPABILITY_NONE);
|
||||
verifyNoMoreInteractions(observer1);
|
||||
verifyNoMoreInteractions(observer2);
|
||||
|
||||
unregisterObserver(observer1);
|
||||
|
||||
addPendingChange(TEST_UID1, UidRecord.CHANGE_PROCSTATE, PROCESS_STATE_TOP,
|
||||
112, PROCESS_CAPABILITY_ALL, false);
|
||||
mUidObserverController.dispatchUidsChanged();
|
||||
verify(observer2).onUidStateChanged(TEST_UID1, PROCESS_STATE_TOP,
|
||||
112, PROCESS_CAPABILITY_ALL);
|
||||
verifyNoMoreInteractions(observer1);
|
||||
verifyNoMoreInteractions(observer2);
|
||||
|
||||
unregisterObserver(observer2);
|
||||
|
||||
addPendingChange(TEST_UID1, UidRecord.CHANGE_PROCSTATE, PROCESS_STATE_CACHED_RECENT,
|
||||
112, PROCESS_CAPABILITY_NONE, false);
|
||||
mUidObserverController.dispatchUidsChanged();
|
||||
verifyNoMoreInteractions(observer1);
|
||||
verifyNoMoreInteractions(observer2);
|
||||
}
|
||||
|
||||
private void registerObserver(IUidObserver observer, int which, int cutpoint,
|
||||
String callingPackage, int callingUid) {
|
||||
when(observer.asBinder()).thenReturn((IBinder) observer);
|
||||
mUidObserverController.register(observer, which, cutpoint, callingPackage, callingUid);
|
||||
Mockito.reset(observer);
|
||||
}
|
||||
|
||||
private void unregisterObserver(IUidObserver observer) {
|
||||
when(observer.asBinder()).thenReturn((IBinder) observer);
|
||||
mUidObserverController.unregister(observer);
|
||||
Mockito.reset(observer);
|
||||
}
|
||||
|
||||
private void addPendingChange(int uid, int change, int procState, long procStateSeq,
|
||||
int capability, boolean ephemeral) {
|
||||
final ChangeRecord record = new ChangeRecord();
|
||||
record.uid = uid;
|
||||
record.change = change;
|
||||
record.procState = procState;
|
||||
record.procStateSeq = procStateSeq;
|
||||
record.capability = capability;
|
||||
record.ephemeral = ephemeral;
|
||||
mUidObserverController.getPendingUidChangesForTest().put(uid, record);
|
||||
}
|
||||
|
||||
private void assertPendingChange(int uid, int change, int procState, long procStateSeq,
|
||||
int capability, boolean ephemeral) {
|
||||
final ChangeRecord record = getPendingChange(uid);
|
||||
assertNotNull(record);
|
||||
assertEquals(change, record.change);
|
||||
assertEquals(procState, record.procState);
|
||||
assertEquals(procStateSeq, record.procStateSeq);
|
||||
assertEquals(capability, record.capability);
|
||||
assertEquals(ephemeral, record.ephemeral);
|
||||
}
|
||||
|
||||
private ChangeRecord getPendingChange(int uid) {
|
||||
return mUidObserverController.getPendingUidChangesForTest().get(uid);
|
||||
}
|
||||
|
||||
private static String changeToStr(int change) {
|
||||
return DebugUtils.flagsToString(UidRecord.class, "CHANGE_", change);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user