Move logic for handling uid observers outside AMS.
Bug: 163963556 Test: atest src/android/app/cts/ActivityManagerProcessStateTest.java Test: atest services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java Test: atest src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java Test: check activity dump contains uid observers info Change-Id: I1292decd1f24b6cbae094a909662aa795dd054a4
This commit is contained in:
@@ -98,7 +98,6 @@ import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESSES;
|
||||
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESS_OBSERVERS;
|
||||
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PSS;
|
||||
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SERVICE;
|
||||
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_UID_OBSERVERS;
|
||||
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_WHITELISTS;
|
||||
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_BACKUP;
|
||||
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_BROADCAST;
|
||||
@@ -146,7 +145,6 @@ import android.app.ActivityManager;
|
||||
import android.app.ActivityManager.RunningTaskInfo;
|
||||
import android.app.ActivityManager.StackInfo;
|
||||
import android.app.ActivityManagerInternal;
|
||||
import android.app.ActivityManagerProto;
|
||||
import android.app.ActivityThread;
|
||||
import android.app.AppGlobals;
|
||||
import android.app.AppOpsManager;
|
||||
@@ -176,7 +174,6 @@ import android.app.PendingIntent;
|
||||
import android.app.ProcessMemoryState;
|
||||
import android.app.ProfilerInfo;
|
||||
import android.app.WaitResult;
|
||||
import android.app.backup.BackupManager;
|
||||
import android.app.backup.BackupManager.OperationType;
|
||||
import android.app.backup.IBackupManager;
|
||||
import android.app.usage.UsageEvents;
|
||||
@@ -349,7 +346,6 @@ import com.android.server.SystemServiceManager;
|
||||
import com.android.server.ThreadPriorityBooster;
|
||||
import com.android.server.UserspaceRebootLogger;
|
||||
import com.android.server.Watchdog;
|
||||
import com.android.server.am.ActivityManagerServiceDumpProcessesProto.UidObserverRegistrationProto;
|
||||
import com.android.server.appop.AppOpsService;
|
||||
import com.android.server.compat.PlatformCompat;
|
||||
import com.android.server.contentcapture.ContentCaptureManagerInternal;
|
||||
@@ -490,9 +486,6 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
// as one line, but close enough for now.
|
||||
static final int RESERVED_BYTES_PER_LOGCAT_LINE = 100;
|
||||
|
||||
/** If a UID observer takes more than this long, send a WTF. */
|
||||
private static final int SLOW_UID_OBSERVER_THRESHOLD_MS = 20;
|
||||
|
||||
// Necessary ApplicationInfo flags to mark an app as persistent
|
||||
static final int PERSISTENT_MASK =
|
||||
ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT;
|
||||
@@ -644,9 +637,6 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
@VisibleForTesting
|
||||
long mWaitForNetworkTimeoutMs;
|
||||
|
||||
/** Total # of UID change events dispatched, shown in dumpsys. */
|
||||
int mUidChangeDispatchCount;
|
||||
|
||||
/**
|
||||
* Uids of apps with current active camera sessions. Access synchronized on
|
||||
* the IntArray instance itself, and no other locks must be acquired while that
|
||||
@@ -1013,12 +1003,6 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* This is for verifying the UID report flow.
|
||||
*/
|
||||
static final boolean VALIDATE_UID_STATES = true;
|
||||
final ActiveUids mValidateUids = new ActiveUids(this, false /* postChangesToAtm */);
|
||||
|
||||
/**
|
||||
* Fingerprints (hashCode()) of stack traces that we've
|
||||
* already logged DropBox entries for. Guarded by itself. If
|
||||
@@ -1399,69 +1383,6 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
int foregroundServiceTypes;
|
||||
}
|
||||
|
||||
static final class UidObserverRegistration {
|
||||
final int uid;
|
||||
final String pkg;
|
||||
final int which;
|
||||
final int cutpoint;
|
||||
|
||||
/**
|
||||
* Total # of callback calls that took more than {@link #SLOW_UID_OBSERVER_THRESHOLD_MS}.
|
||||
* We show it in dumpsys.
|
||||
*/
|
||||
int mSlowDispatchCount;
|
||||
|
||||
/** Max time it took for each dispatch. */
|
||||
int mMaxDispatchTime;
|
||||
|
||||
final SparseIntArray lastProcStates;
|
||||
|
||||
// Please keep the enum lists in sync
|
||||
private static int[] ORIG_ENUMS = new int[]{
|
||||
ActivityManager.UID_OBSERVER_IDLE,
|
||||
ActivityManager.UID_OBSERVER_ACTIVE,
|
||||
ActivityManager.UID_OBSERVER_GONE,
|
||||
ActivityManager.UID_OBSERVER_PROCSTATE,
|
||||
};
|
||||
private static int[] PROTO_ENUMS = new int[]{
|
||||
ActivityManagerProto.UID_OBSERVER_FLAG_IDLE,
|
||||
ActivityManagerProto.UID_OBSERVER_FLAG_ACTIVE,
|
||||
ActivityManagerProto.UID_OBSERVER_FLAG_GONE,
|
||||
ActivityManagerProto.UID_OBSERVER_FLAG_PROCSTATE,
|
||||
};
|
||||
|
||||
UidObserverRegistration(int _uid, String _pkg, int _which, int _cutpoint) {
|
||||
uid = _uid;
|
||||
pkg = _pkg;
|
||||
which = _which;
|
||||
cutpoint = _cutpoint;
|
||||
if (cutpoint >= ActivityManager.MIN_PROCESS_STATE) {
|
||||
lastProcStates = new SparseIntArray();
|
||||
} else {
|
||||
lastProcStates = null;
|
||||
}
|
||||
}
|
||||
|
||||
void dumpDebug(ProtoOutputStream proto, long fieldId) {
|
||||
final long token = proto.start(fieldId);
|
||||
proto.write(UidObserverRegistrationProto.UID, uid);
|
||||
proto.write(UidObserverRegistrationProto.PACKAGE, pkg);
|
||||
ProtoUtils.writeBitWiseFlagsToProtoEnum(proto, UidObserverRegistrationProto.FLAGS,
|
||||
which, ORIG_ENUMS, PROTO_ENUMS);
|
||||
proto.write(UidObserverRegistrationProto.CUT_POINT, cutpoint);
|
||||
if (lastProcStates != null) {
|
||||
final int NI = lastProcStates.size();
|
||||
for (int i=0; i<NI; i++) {
|
||||
final long pToken = proto.start(UidObserverRegistrationProto.LAST_PROC_STATES);
|
||||
proto.write(UidObserverRegistrationProto.ProcState.UID, lastProcStates.keyAt(i));
|
||||
proto.write(UidObserverRegistrationProto.ProcState.STATE, lastProcStates.valueAt(i));
|
||||
proto.end(pToken);
|
||||
}
|
||||
}
|
||||
proto.end(token);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Move below 4 members and code to ProcessList
|
||||
final RemoteCallbackList<IProcessObserver> mProcessObservers = new RemoteCallbackList<>();
|
||||
ProcessChangeItem[] mActiveProcessChanges = new ProcessChangeItem[5];
|
||||
@@ -1469,12 +1390,6 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
final ArrayList<ProcessChangeItem> mPendingProcessChanges = new ArrayList<>();
|
||||
final ArrayList<ProcessChangeItem> mAvailProcessChanges = new ArrayList<>();
|
||||
|
||||
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<>();
|
||||
|
||||
OomAdjObserver mCurOomAdjObserver;
|
||||
int mCurOomAdjUid;
|
||||
|
||||
@@ -1525,6 +1440,8 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
public final ActivityManagerInternal mInternal;
|
||||
final ActivityThread mSystemThread;
|
||||
|
||||
final UidObserverController mUidObserverController;
|
||||
|
||||
private final class AppDeathRecipient implements IBinder.DeathRecipient {
|
||||
final ProcessRecord mApp;
|
||||
final int mPid;
|
||||
@@ -1570,7 +1487,6 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
static final int NOTIFY_CLEARTEXT_NETWORK_MSG = 49;
|
||||
static final int POST_DUMP_HEAP_NOTIFICATION_MSG = 50;
|
||||
static final int ABORT_DUMPHEAP_MSG = 51;
|
||||
static final int DISPATCH_UIDS_CHANGED_UI_MSG = 53;
|
||||
static final int SHUTDOWN_UI_AUTOMATION_CONNECTION_MSG = 56;
|
||||
static final int CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG = 57;
|
||||
static final int IDLE_UIDS_MSG = 58;
|
||||
@@ -1698,17 +1614,14 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
break;
|
||||
}
|
||||
case DISPATCH_PROCESS_DIED_UI_MSG: {
|
||||
if (false) { // DO NOT SUBMIT WITH TRUE
|
||||
maybeTriggerWatchdog();
|
||||
}
|
||||
final int pid = msg.arg1;
|
||||
final int uid = msg.arg2;
|
||||
dispatchProcessDied(pid, uid);
|
||||
break;
|
||||
}
|
||||
case DISPATCH_UIDS_CHANGED_UI_MSG: {
|
||||
if (false) { // DO NOT SUBMIT WITH TRUE
|
||||
maybeTriggerWatchdog();
|
||||
}
|
||||
dispatchUidsChanged();
|
||||
} break;
|
||||
case DISPATCH_OOM_ADJ_OBSERVER_MSG: {
|
||||
dispatchOomAdjObserver((String) msg.obj);
|
||||
} break;
|
||||
@@ -2505,6 +2418,7 @@ 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);
|
||||
@@ -2600,6 +2514,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);
|
||||
|
||||
final File systemDir = SystemServiceManager.ensureSystemDir();
|
||||
|
||||
@@ -3416,153 +3331,6 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
mProcessObservers.finishBroadcast();
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void dispatchUidsChanged() {
|
||||
int N;
|
||||
synchronized (this) {
|
||||
N = mPendingUidChanges.size();
|
||||
if (mActiveUidChanges.length < N) {
|
||||
mActiveUidChanges = new UidRecord.ChangeItem[N];
|
||||
}
|
||||
for (int i=0; i<N; i++) {
|
||||
final UidRecord.ChangeItem change = mPendingUidChanges.get(i);
|
||||
mActiveUidChanges[i] = change;
|
||||
if (change.uidRecord != null) {
|
||||
change.uidRecord.pendingChange = null;
|
||||
change.uidRecord = null;
|
||||
}
|
||||
}
|
||||
mPendingUidChanges.clear();
|
||||
if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
|
||||
"*** Delivering " + N + " uid changes");
|
||||
}
|
||||
|
||||
mUidChangeDispatchCount += N;
|
||||
int i = mUidObservers.beginBroadcast();
|
||||
while (i > 0) {
|
||||
i--;
|
||||
dispatchUidsChangedForObserver(mUidObservers.getBroadcastItem(i),
|
||||
(UidObserverRegistration) mUidObservers.getBroadcastCookie(i), N);
|
||||
}
|
||||
mUidObservers.finishBroadcast();
|
||||
|
||||
if (VALIDATE_UID_STATES && mUidObservers.getRegisteredCallbackCount() > 0) {
|
||||
for (int j = 0; j < N; ++j) {
|
||||
final UidRecord.ChangeItem item = mActiveUidChanges[j];
|
||||
if ((item.change & UidRecord.CHANGE_GONE) != 0) {
|
||||
mValidateUids.remove(item.uid);
|
||||
} else {
|
||||
UidRecord validateUid = mValidateUids.get(item.uid);
|
||||
if (validateUid == null) {
|
||||
validateUid = new UidRecord(item.uid);
|
||||
mValidateUids.put(item.uid, validateUid);
|
||||
}
|
||||
if ((item.change & UidRecord.CHANGE_IDLE) != 0) {
|
||||
validateUid.idle = true;
|
||||
} else if ((item.change & UidRecord.CHANGE_ACTIVE) != 0) {
|
||||
validateUid.idle = false;
|
||||
}
|
||||
validateUid.setCurProcState(validateUid.setProcState = item.processState);
|
||||
validateUid.curCapability = validateUid.setCapability = item.capability;
|
||||
validateUid.lastDispatchedProcStateSeq = item.procStateSeq;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
synchronized (this) {
|
||||
for (int j = 0; j < N; j++) {
|
||||
mAvailUidChanges.add(mActiveUidChanges[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void dispatchUidsChangedForObserver(IUidObserver observer,
|
||||
UidObserverRegistration reg, int changesSize) {
|
||||
if (observer == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
for (int j = 0; j < changesSize; j++) {
|
||||
UidRecord.ChangeItem item = mActiveUidChanges[j];
|
||||
final int change = item.change;
|
||||
if (change == UidRecord.CHANGE_PROCSTATE &&
|
||||
(reg.which & ActivityManager.UID_OBSERVER_PROCSTATE) == 0) {
|
||||
// No-op common case: no significant change, the observer is not
|
||||
// interested in all proc state changes.
|
||||
continue;
|
||||
}
|
||||
final long start = SystemClock.uptimeMillis();
|
||||
if ((change & UidRecord.CHANGE_IDLE) != 0) {
|
||||
if ((reg.which & ActivityManager.UID_OBSERVER_IDLE) != 0) {
|
||||
if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
|
||||
"UID idle uid=" + item.uid);
|
||||
observer.onUidIdle(item.uid, item.ephemeral);
|
||||
}
|
||||
} else if ((change & UidRecord.CHANGE_ACTIVE) != 0) {
|
||||
if ((reg.which & ActivityManager.UID_OBSERVER_ACTIVE) != 0) {
|
||||
if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
|
||||
"UID active uid=" + item.uid);
|
||||
observer.onUidActive(item.uid);
|
||||
}
|
||||
}
|
||||
if ((reg.which & ActivityManager.UID_OBSERVER_CACHED) != 0) {
|
||||
if ((change & UidRecord.CHANGE_CACHED) != 0) {
|
||||
if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
|
||||
"UID cached uid=" + item.uid);
|
||||
observer.onUidCachedChanged(item.uid, true);
|
||||
} else if ((change & UidRecord.CHANGE_UNCACHED) != 0) {
|
||||
if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
|
||||
"UID active uid=" + item.uid);
|
||||
observer.onUidCachedChanged(item.uid, false);
|
||||
}
|
||||
}
|
||||
if ((change & UidRecord.CHANGE_GONE) != 0) {
|
||||
if ((reg.which & ActivityManager.UID_OBSERVER_GONE) != 0) {
|
||||
if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
|
||||
"UID gone uid=" + item.uid);
|
||||
observer.onUidGone(item.uid, item.ephemeral);
|
||||
}
|
||||
if (reg.lastProcStates != null) {
|
||||
reg.lastProcStates.delete(item.uid);
|
||||
}
|
||||
} else {
|
||||
if ((reg.which & ActivityManager.UID_OBSERVER_PROCSTATE) != 0) {
|
||||
if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
|
||||
"UID CHANGED uid=" + item.uid
|
||||
+ ": " + item.processState + ": " + item.capability);
|
||||
boolean doReport = true;
|
||||
if (reg.cutpoint >= ActivityManager.MIN_PROCESS_STATE) {
|
||||
final int lastState = reg.lastProcStates.get(item.uid,
|
||||
ActivityManager.PROCESS_STATE_UNKNOWN);
|
||||
if (lastState != ActivityManager.PROCESS_STATE_UNKNOWN) {
|
||||
final boolean lastAboveCut = lastState <= reg.cutpoint;
|
||||
final boolean newAboveCut = item.processState <= reg.cutpoint;
|
||||
doReport = lastAboveCut != newAboveCut;
|
||||
} else {
|
||||
doReport = item.processState != PROCESS_STATE_NONEXISTENT;
|
||||
}
|
||||
}
|
||||
if (doReport) {
|
||||
if (reg.lastProcStates != null) {
|
||||
reg.lastProcStates.put(item.uid, item.processState);
|
||||
}
|
||||
observer.onUidStateChanged(item.uid, item.processState,
|
||||
item.procStateSeq, item.capability);
|
||||
}
|
||||
}
|
||||
}
|
||||
final int duration = (int) (SystemClock.uptimeMillis() - start);
|
||||
if (reg.mMaxDispatchTime < duration) {
|
||||
reg.mMaxDispatchTime = duration;
|
||||
}
|
||||
if (duration >= SLOW_UID_OBSERVER_THRESHOLD_MS) {
|
||||
reg.mSlowDispatchCount++;
|
||||
}
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
|
||||
void dispatchOomAdjObserver(String msg) {
|
||||
OomAdjObserver observer;
|
||||
synchronized (this) {
|
||||
@@ -7494,15 +7262,15 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
"registerUidObserver");
|
||||
}
|
||||
synchronized (this) {
|
||||
mUidObservers.register(observer, new UidObserverRegistration(Binder.getCallingUid(),
|
||||
callingPackage, which, cutpoint));
|
||||
mUidObserverController.register(observer, which, cutpoint, callingPackage,
|
||||
Binder.getCallingUid());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterUidObserver(IUidObserver observer) {
|
||||
synchronized (this) {
|
||||
mUidObservers.unregister(observer);
|
||||
mUidObserverController.unregister(observer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10121,9 +9889,9 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
}
|
||||
|
||||
if (dumpAll) {
|
||||
if (mValidateUids.size() > 0) {
|
||||
if (dumpUids(pw, dumpPackage, dumpAppId, mValidateUids, "UID validation:",
|
||||
needSep)) {
|
||||
if (mUidObserverController.mValidateUids.size() > 0) {
|
||||
if (dumpUids(pw, dumpPackage, dumpAppId, mUidObserverController.mValidateUids,
|
||||
"UID validation:", needSep)) {
|
||||
needSep = true;
|
||||
}
|
||||
}
|
||||
@@ -10255,45 +10023,8 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
}
|
||||
}
|
||||
if (dumpAll) {
|
||||
final int NI = mUidObservers.getRegisteredCallbackCount();
|
||||
boolean printed = false;
|
||||
for (int i=0; i<NI; i++) {
|
||||
final UidObserverRegistration reg = (UidObserverRegistration)
|
||||
mUidObservers.getRegisteredCallbackCookie(i);
|
||||
if (dumpPackage == null || dumpPackage.equals(reg.pkg)) {
|
||||
if (!printed) {
|
||||
pw.println(" mUidObservers:");
|
||||
printed = true;
|
||||
}
|
||||
pw.print(" "); UserHandle.formatUid(pw, reg.uid);
|
||||
pw.print(" "); pw.print(reg.pkg);
|
||||
final IUidObserver observer = mUidObservers.getRegisteredCallbackItem(i);
|
||||
pw.print(" "); pw.print(observer.getClass().getTypeName()); pw.print(":");
|
||||
if ((reg.which&ActivityManager.UID_OBSERVER_IDLE) != 0) {
|
||||
pw.print(" IDLE");
|
||||
}
|
||||
if ((reg.which&ActivityManager.UID_OBSERVER_ACTIVE) != 0) {
|
||||
pw.print(" ACT" );
|
||||
}
|
||||
if ((reg.which&ActivityManager.UID_OBSERVER_GONE) != 0) {
|
||||
pw.print(" GONE");
|
||||
}
|
||||
if ((reg.which&ActivityManager.UID_OBSERVER_PROCSTATE) != 0) {
|
||||
pw.print(" STATE");
|
||||
pw.print(" (cut="); pw.print(reg.cutpoint);
|
||||
pw.print(")");
|
||||
}
|
||||
pw.println();
|
||||
if (reg.lastProcStates != null) {
|
||||
final int NJ = reg.lastProcStates.size();
|
||||
for (int j=0; j<NJ; j++) {
|
||||
pw.print(" Last ");
|
||||
UserHandle.formatUid(pw, reg.lastProcStates.keyAt(j));
|
||||
pw.print(": "); pw.println(reg.lastProcStates.valueAt(j));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
mUidObserverController.dump(pw, dumpPackage);
|
||||
|
||||
pw.println(" mDeviceIdleWhitelist=" + Arrays.toString(mDeviceIdleWhitelist));
|
||||
pw.println(" mDeviceIdleExceptIdleWhitelist="
|
||||
+ Arrays.toString(mDeviceIdleExceptIdleWhitelist));
|
||||
@@ -10421,25 +10152,6 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
pw.print(" mLowRamSinceLastIdle=");
|
||||
TimeUtils.formatDuration(getLowRamTimeSinceIdle(now), pw);
|
||||
pw.println();
|
||||
pw.println();
|
||||
pw.print(" mUidChangeDispatchCount=");
|
||||
pw.print(mUidChangeDispatchCount);
|
||||
pw.println();
|
||||
|
||||
pw.println(" Slow UID dispatches:");
|
||||
final int N = mUidObservers.beginBroadcast();
|
||||
for (int i = 0; i < N; 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");
|
||||
}
|
||||
mUidObservers.finishBroadcast();
|
||||
|
||||
pw.println();
|
||||
pw.println(" ServiceManager statistics:");
|
||||
@@ -10507,8 +10219,8 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
uidRec.dumpDebug(proto, ActivityManagerServiceDumpProcessesProto.ACTIVE_UIDS);
|
||||
}
|
||||
|
||||
for (int i = 0; i < mValidateUids.size(); i++) {
|
||||
UidRecord uidRec = mValidateUids.valueAt(i);
|
||||
for (int i = 0; i < mUidObserverController.mValidateUids.size(); i++) {
|
||||
UidRecord uidRec = mUidObserverController.mValidateUids.valueAt(i);
|
||||
if (dumpPackage != null && UserHandle.getAppId(uidRec.uid) != whichAppId) {
|
||||
continue;
|
||||
}
|
||||
@@ -10593,14 +10305,7 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
ActivityManagerServiceDumpProcessesProto.USER_CONTROLLER);
|
||||
}
|
||||
|
||||
final int NI = mUidObservers.getRegisteredCallbackCount();
|
||||
for (int i=0; i<NI; i++) {
|
||||
final UidObserverRegistration reg = (UidObserverRegistration)
|
||||
mUidObservers.getRegisteredCallbackCookie(i);
|
||||
if (dumpPackage == null || dumpPackage.equals(reg.pkg)) {
|
||||
reg.dumpDebug(proto, ActivityManagerServiceDumpProcessesProto.UID_OBSERVERS);
|
||||
}
|
||||
}
|
||||
mUidObserverController.dumpDebug(proto, dumpPackage);
|
||||
|
||||
for (int v : mDeviceIdleWhitelist) {
|
||||
proto.write(ActivityManagerServiceDumpProcessesProto.DEVICE_IDLE_WHITELIST, v);
|
||||
@@ -16299,101 +16004,6 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isEphemeralLocked(int uid) {
|
||||
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]);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
final void enqueueUidChangeLocked(UidRecord uidRec, int uid, int change) {
|
||||
final UidRecord.ChangeItem pendingChange;
|
||||
if (uidRec == null || uidRec.pendingChange == null) {
|
||||
if (mPendingUidChanges.size() == 0) {
|
||||
if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
|
||||
"*** Enqueueing dispatch uid changed!");
|
||||
mUiHandler.obtainMessage(DISPATCH_UIDS_CHANGED_UI_MSG).sendToTarget();
|
||||
}
|
||||
final int NA = mAvailUidChanges.size();
|
||||
if (NA > 0) {
|
||||
pendingChange = mAvailUidChanges.remove(NA-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 (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) {
|
||||
mLocalPowerManager.uidActive(pendingChange.uid);
|
||||
}
|
||||
if ((change & UidRecord.CHANGE_IDLE) != 0) {
|
||||
mLocalPowerManager.uidIdle(pendingChange.uid);
|
||||
}
|
||||
if ((change & UidRecord.CHANGE_GONE) != 0) {
|
||||
mLocalPowerManager.uidGone(pendingChange.uid);
|
||||
} else {
|
||||
mLocalPowerManager.updateUidProcState(pendingChange.uid,
|
||||
pendingChange.processState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final void setProcessTrackerStateLocked(ProcessRecord proc, int memFactor, long now) {
|
||||
if (proc.thread != null && proc.baseProcessTracker != null) {
|
||||
final int procState = proc.getReportedProcState();
|
||||
@@ -16812,7 +16422,7 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
@GuardedBy("this")
|
||||
final void doStopUidLocked(int uid, final UidRecord uidRec) {
|
||||
mServices.stopInBackgroundLocked(uid);
|
||||
enqueueUidChangeLocked(uidRec, uid, UidRecord.CHANGE_IDLE);
|
||||
mUidObserverController.enqueueUidChangeLocked(uidRec, uid, UidRecord.CHANGE_IDLE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -18473,7 +18083,8 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
Slog.w(TAG_NETWORK, "Total time waited for network rules to get updated: "
|
||||
+ totalTime + ". Uid: " + callingUid + " procStateSeq: "
|
||||
+ procStateSeq + " UidRec: " + record
|
||||
+ " validateUidRec: " + mValidateUids.get(callingUid));
|
||||
+ " validateUidRec: "
|
||||
+ mUidObserverController.mValidateUids.get(callingUid));
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
|
||||
@@ -987,7 +987,7 @@ public final class OomAdjuster {
|
||||
uidRec.setWhitelist = uidRec.curWhitelist;
|
||||
uidRec.setIdle = uidRec.idle;
|
||||
mService.mAtmInternal.onUidProcStateChanged(uidRec.uid, uidRec.setProcState);
|
||||
mService.enqueueUidChangeLocked(uidRec, -1, uidChange);
|
||||
mService.mUidObserverController.enqueueUidChangeLocked(uidRec, -1, uidChange);
|
||||
mService.noteUidProcessState(uidRec.uid, uidRec.getCurProcState(),
|
||||
uidRec.curCapability);
|
||||
if (uidRec.foregroundServices) {
|
||||
|
||||
@@ -2960,7 +2960,8 @@ 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.enqueueUidChangeLocked(uidRecord, -1, UidRecord.CHANGE_GONE);
|
||||
mService.mUidObserverController.enqueueUidChangeLocked(uidRecord, -1,
|
||||
UidRecord.CHANGE_GONE);
|
||||
EventLogTags.writeAmUidStopped(uid);
|
||||
mActiveUids.remove(uid);
|
||||
mService.noteUidProcessState(uid, ActivityManager.PROCESS_STATE_NONEXISTENT,
|
||||
|
||||
@@ -0,0 +1,460 @@
|
||||
/*
|
||||
* 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_STATE_NONEXISTENT;
|
||||
|
||||
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_UID_OBSERVERS;
|
||||
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.RemoteCallbackList;
|
||||
import android.os.RemoteException;
|
||||
import android.os.SystemClock;
|
||||
import android.os.UserHandle;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseIntArray;
|
||||
import android.util.proto.ProtoOutputStream;
|
||||
import android.util.proto.ProtoUtils;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.server.am.ActivityManagerServiceDumpProcessesProto.UidObserverRegistrationProto;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* This is for verifying the UID report flow.
|
||||
*/
|
||||
static final boolean VALIDATE_UID_STATES = true;
|
||||
final ActiveUids mValidateUids;
|
||||
|
||||
UidObserverController(ActivityManagerService service) {
|
||||
mService = service;
|
||||
mValidateUids = new ActiveUids(mService, 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));
|
||||
}
|
||||
|
||||
@GuardedBy("mService")
|
||||
void unregister(IUidObserver observer) {
|
||||
mUidObservers.unregister(observer);
|
||||
}
|
||||
|
||||
@GuardedBy("mService")
|
||||
final void enqueueUidChangeLocked(UidRecord uidRec, int uid, int change) {
|
||||
final UidRecord.ChangeItem pendingChange;
|
||||
if (uidRec == null || uidRec.pendingChange == null) {
|
||||
if (mPendingUidChanges.size() == 0) {
|
||||
if (DEBUG_UID_OBSERVERS) {
|
||||
Slog.i(TAG_UID_OBSERVERS, "*** Enqueueing dispatch uid changed!");
|
||||
}
|
||||
mService.mUiHandler.post(this::dispatchUidsChanged);
|
||||
}
|
||||
final int NA = mAvailUidChanges.size();
|
||||
if (NA > 0) {
|
||||
pendingChange = mAvailUidChanges.remove(NA-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);
|
||||
} else {
|
||||
mService.mLocalPowerManager.updateUidProcState(pendingChange.uid,
|
||||
pendingChange.processState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void dispatchUidsChanged() {
|
||||
int N;
|
||||
synchronized (mService) {
|
||||
N = mPendingUidChanges.size();
|
||||
if (mActiveUidChanges.length < N) {
|
||||
mActiveUidChanges = new UidRecord.ChangeItem[N];
|
||||
}
|
||||
for (int i=0; i<N; i++) {
|
||||
final UidRecord.ChangeItem change = mPendingUidChanges.get(i);
|
||||
mActiveUidChanges[i] = change;
|
||||
if (change.uidRecord != null) {
|
||||
change.uidRecord.pendingChange = null;
|
||||
change.uidRecord = null;
|
||||
}
|
||||
}
|
||||
mPendingUidChanges.clear();
|
||||
if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
|
||||
"*** Delivering " + N + " uid changes");
|
||||
}
|
||||
|
||||
mUidChangeDispatchCount += N;
|
||||
int i = mUidObservers.beginBroadcast();
|
||||
while (i > 0) {
|
||||
i--;
|
||||
dispatchUidsChangedForObserver(mUidObservers.getBroadcastItem(i),
|
||||
(UidObserverRegistration) mUidObservers.getBroadcastCookie(i), N);
|
||||
}
|
||||
mUidObservers.finishBroadcast();
|
||||
|
||||
if (VALIDATE_UID_STATES && mUidObservers.getRegisteredCallbackCount() > 0) {
|
||||
for (int j = 0; j < N; ++j) {
|
||||
final UidRecord.ChangeItem item = mActiveUidChanges[j];
|
||||
if ((item.change & UidRecord.CHANGE_GONE) != 0) {
|
||||
mValidateUids.remove(item.uid);
|
||||
} else {
|
||||
UidRecord validateUid = mValidateUids.get(item.uid);
|
||||
if (validateUid == null) {
|
||||
validateUid = new UidRecord(item.uid);
|
||||
mValidateUids.put(item.uid, validateUid);
|
||||
}
|
||||
if ((item.change & UidRecord.CHANGE_IDLE) != 0) {
|
||||
validateUid.idle = true;
|
||||
} else if ((item.change & UidRecord.CHANGE_ACTIVE) != 0) {
|
||||
validateUid.idle = false;
|
||||
}
|
||||
validateUid.setCurProcState(validateUid.setProcState = item.processState);
|
||||
validateUid.curCapability = validateUid.setCapability = item.capability;
|
||||
validateUid.lastDispatchedProcStateSeq = item.procStateSeq;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
synchronized (mService) {
|
||||
for (int j = 0; j < N; j++) {
|
||||
mAvailUidChanges.add(mActiveUidChanges[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void dispatchUidsChangedForObserver(IUidObserver observer,
|
||||
UidObserverRegistration reg, int changesSize) {
|
||||
if (observer == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
for (int j = 0; j < changesSize; j++) {
|
||||
UidRecord.ChangeItem item = mActiveUidChanges[j];
|
||||
final int change = item.change;
|
||||
if (change == UidRecord.CHANGE_PROCSTATE &&
|
||||
(reg.which & ActivityManager.UID_OBSERVER_PROCSTATE) == 0) {
|
||||
// No-op common case: no significant change, the observer is not
|
||||
// interested in all proc state changes.
|
||||
continue;
|
||||
}
|
||||
final long start = SystemClock.uptimeMillis();
|
||||
if ((change & UidRecord.CHANGE_IDLE) != 0) {
|
||||
if ((reg.which & ActivityManager.UID_OBSERVER_IDLE) != 0) {
|
||||
if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
|
||||
"UID idle uid=" + item.uid);
|
||||
observer.onUidIdle(item.uid, item.ephemeral);
|
||||
}
|
||||
} else if ((change & UidRecord.CHANGE_ACTIVE) != 0) {
|
||||
if ((reg.which & ActivityManager.UID_OBSERVER_ACTIVE) != 0) {
|
||||
if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
|
||||
"UID active uid=" + item.uid);
|
||||
observer.onUidActive(item.uid);
|
||||
}
|
||||
}
|
||||
if ((reg.which & ActivityManager.UID_OBSERVER_CACHED) != 0) {
|
||||
if ((change & UidRecord.CHANGE_CACHED) != 0) {
|
||||
if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
|
||||
"UID cached uid=" + item.uid);
|
||||
observer.onUidCachedChanged(item.uid, true);
|
||||
} else if ((change & UidRecord.CHANGE_UNCACHED) != 0) {
|
||||
if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
|
||||
"UID active uid=" + item.uid);
|
||||
observer.onUidCachedChanged(item.uid, false);
|
||||
}
|
||||
}
|
||||
if ((change & UidRecord.CHANGE_GONE) != 0) {
|
||||
if ((reg.which & ActivityManager.UID_OBSERVER_GONE) != 0) {
|
||||
if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
|
||||
"UID gone uid=" + item.uid);
|
||||
observer.onUidGone(item.uid, item.ephemeral);
|
||||
}
|
||||
if (reg.lastProcStates != null) {
|
||||
reg.lastProcStates.delete(item.uid);
|
||||
}
|
||||
} else {
|
||||
if ((reg.which & ActivityManager.UID_OBSERVER_PROCSTATE) != 0) {
|
||||
if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
|
||||
"UID CHANGED uid=" + item.uid
|
||||
+ ": " + item.processState + ": " + item.capability);
|
||||
boolean doReport = true;
|
||||
if (reg.cutpoint >= ActivityManager.MIN_PROCESS_STATE) {
|
||||
final int lastState = reg.lastProcStates.get(item.uid,
|
||||
ActivityManager.PROCESS_STATE_UNKNOWN);
|
||||
if (lastState != ActivityManager.PROCESS_STATE_UNKNOWN) {
|
||||
final boolean lastAboveCut = lastState <= reg.cutpoint;
|
||||
final boolean newAboveCut = item.processState <= reg.cutpoint;
|
||||
doReport = lastAboveCut != newAboveCut;
|
||||
} else {
|
||||
doReport = item.processState != PROCESS_STATE_NONEXISTENT;
|
||||
}
|
||||
}
|
||||
if (doReport) {
|
||||
if (reg.lastProcStates != null) {
|
||||
reg.lastProcStates.put(item.uid, item.processState);
|
||||
}
|
||||
observer.onUidStateChanged(item.uid, item.processState,
|
||||
item.procStateSeq, item.capability);
|
||||
}
|
||||
}
|
||||
}
|
||||
final int duration = (int) (SystemClock.uptimeMillis() - start);
|
||||
if (reg.mMaxDispatchTime < duration) {
|
||||
reg.mMaxDispatchTime = duration;
|
||||
}
|
||||
if (duration >= SLOW_UID_OBSERVER_THRESHOLD_MS) {
|
||||
reg.mSlowDispatchCount++;
|
||||
}
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isEphemeralLocked(int uid) {
|
||||
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]);
|
||||
}
|
||||
|
||||
@GuardedBy("mService")
|
||||
void dump(PrintWriter pw, String dumpPackage) {
|
||||
final int NI = mUidObservers.getRegisteredCallbackCount();
|
||||
boolean printed = false;
|
||||
for (int i=0; i<NI; i++) {
|
||||
final UidObserverRegistration reg = (UidObserverRegistration)
|
||||
mUidObservers.getRegisteredCallbackCookie(i);
|
||||
if (dumpPackage == null || dumpPackage.equals(reg.pkg)) {
|
||||
if (!printed) {
|
||||
pw.println(" mUidObservers:");
|
||||
printed = true;
|
||||
}
|
||||
pw.print(" "); UserHandle.formatUid(pw, reg.uid);
|
||||
pw.print(" "); pw.print(reg.pkg);
|
||||
final IUidObserver observer = mUidObservers.getRegisteredCallbackItem(i);
|
||||
pw.print(" "); pw.print(observer.getClass().getTypeName()); pw.print(":");
|
||||
if ((reg.which&ActivityManager.UID_OBSERVER_IDLE) != 0) {
|
||||
pw.print(" IDLE");
|
||||
}
|
||||
if ((reg.which&ActivityManager.UID_OBSERVER_ACTIVE) != 0) {
|
||||
pw.print(" ACT" );
|
||||
}
|
||||
if ((reg.which&ActivityManager.UID_OBSERVER_GONE) != 0) {
|
||||
pw.print(" GONE");
|
||||
}
|
||||
if ((reg.which&ActivityManager.UID_OBSERVER_PROCSTATE) != 0) {
|
||||
pw.print(" STATE");
|
||||
pw.print(" (cut="); pw.print(reg.cutpoint);
|
||||
pw.print(")");
|
||||
}
|
||||
pw.println();
|
||||
if (reg.lastProcStates != null) {
|
||||
final int NJ = reg.lastProcStates.size();
|
||||
for (int j=0; j<NJ; j++) {
|
||||
pw.print(" Last ");
|
||||
UserHandle.formatUid(pw, reg.lastProcStates.keyAt(j));
|
||||
pw.print(": "); pw.println(reg.lastProcStates.valueAt(j));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pw.println();
|
||||
pw.print(" mUidChangeDispatchCount=");
|
||||
pw.print(mUidChangeDispatchCount);
|
||||
pw.println();
|
||||
pw.println(" Slow UID dispatches:");
|
||||
final int N = mUidObservers.beginBroadcast();
|
||||
for (int i = 0; i < N; 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");
|
||||
}
|
||||
mUidObservers.finishBroadcast();
|
||||
}
|
||||
|
||||
@GuardedBy("mService")
|
||||
void dumpDebug(ProtoOutputStream proto, String dumpPackage) {
|
||||
final int NI = mUidObservers.getRegisteredCallbackCount();
|
||||
for (int i=0; i<NI; i++) {
|
||||
final UidObserverRegistration reg = (UidObserverRegistration)
|
||||
mUidObservers.getRegisteredCallbackCookie(i);
|
||||
if (dumpPackage == null || dumpPackage.equals(reg.pkg)) {
|
||||
reg.dumpDebug(proto, ActivityManagerServiceDumpProcessesProto.UID_OBSERVERS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static final class UidObserverRegistration {
|
||||
final int uid;
|
||||
final String pkg;
|
||||
final int which;
|
||||
final int cutpoint;
|
||||
|
||||
/**
|
||||
* Total # of callback calls that took more than {@link #SLOW_UID_OBSERVER_THRESHOLD_MS}.
|
||||
* We show it in dumpsys.
|
||||
*/
|
||||
int mSlowDispatchCount;
|
||||
|
||||
/** Max time it took for each dispatch. */
|
||||
int mMaxDispatchTime;
|
||||
|
||||
final SparseIntArray lastProcStates;
|
||||
|
||||
// Please keep the enum lists in sync
|
||||
private static int[] ORIG_ENUMS = new int[]{
|
||||
ActivityManager.UID_OBSERVER_IDLE,
|
||||
ActivityManager.UID_OBSERVER_ACTIVE,
|
||||
ActivityManager.UID_OBSERVER_GONE,
|
||||
ActivityManager.UID_OBSERVER_PROCSTATE,
|
||||
};
|
||||
private static int[] PROTO_ENUMS = new int[]{
|
||||
ActivityManagerProto.UID_OBSERVER_FLAG_IDLE,
|
||||
ActivityManagerProto.UID_OBSERVER_FLAG_ACTIVE,
|
||||
ActivityManagerProto.UID_OBSERVER_FLAG_GONE,
|
||||
ActivityManagerProto.UID_OBSERVER_FLAG_PROCSTATE,
|
||||
};
|
||||
|
||||
UidObserverRegistration(int _uid, String _pkg, int _which, int _cutpoint) {
|
||||
uid = _uid;
|
||||
pkg = _pkg;
|
||||
which = _which;
|
||||
cutpoint = _cutpoint;
|
||||
if (cutpoint >= ActivityManager.MIN_PROCESS_STATE) {
|
||||
lastProcStates = new SparseIntArray();
|
||||
} else {
|
||||
lastProcStates = null;
|
||||
}
|
||||
}
|
||||
|
||||
void dumpDebug(ProtoOutputStream proto, long fieldId) {
|
||||
final long token = proto.start(fieldId);
|
||||
proto.write(UidObserverRegistrationProto.UID, uid);
|
||||
proto.write(UidObserverRegistrationProto.PACKAGE, pkg);
|
||||
ProtoUtils.writeBitWiseFlagsToProtoEnum(proto, UidObserverRegistrationProto.FLAGS,
|
||||
which, ORIG_ENUMS, PROTO_ENUMS);
|
||||
proto.write(UidObserverRegistrationProto.CUT_POINT, cutpoint);
|
||||
if (lastProcStates != null) {
|
||||
final int NI = lastProcStates.size();
|
||||
for (int i=0; i<NI; i++) {
|
||||
final long pToken = proto.start(UidObserverRegistrationProto.LAST_PROC_STATES);
|
||||
proto.write(UidObserverRegistrationProto.ProcState.UID,
|
||||
lastProcStates.keyAt(i));
|
||||
proto.write(UidObserverRegistrationProto.ProcState.STATE,
|
||||
lastProcStates.valueAt(i));
|
||||
proto.end(pToken);
|
||||
}
|
||||
}
|
||||
proto.end(token);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -32,7 +32,6 @@ import static android.util.DebugUtils.valueToString;
|
||||
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
|
||||
|
||||
import static com.android.server.am.ActivityManagerInternalTest.CustomThread;
|
||||
import static com.android.server.am.ActivityManagerService.DISPATCH_UIDS_CHANGED_UI_MSG;
|
||||
import static com.android.server.am.ActivityManagerService.Injector;
|
||||
import static com.android.server.am.ProcessList.NETWORK_STATE_BLOCK;
|
||||
import static com.android.server.am.ProcessList.NETWORK_STATE_NO_CHANGE;
|
||||
@@ -548,10 +547,10 @@ public class ActivityManagerServiceTest {
|
||||
pendingChange.processState = procStatesForPendingUidRecords[i];
|
||||
pendingChange.procStateSeq = i;
|
||||
changeItems.put(changesForPendingUidRecords[i], pendingChange);
|
||||
mAms.mPendingUidChanges.add(pendingChange);
|
||||
mAms.mUidObserverController.mPendingUidChanges.add(pendingChange);
|
||||
}
|
||||
|
||||
mAms.dispatchUidsChanged();
|
||||
mAms.mUidObserverController.dispatchUidsChanged();
|
||||
// Verify the required changes have been dispatched to observers.
|
||||
for (int i = 0; i < observers.length; ++i) {
|
||||
final int changeToObserve = changesToObserve[i];
|
||||
@@ -647,8 +646,8 @@ public class ActivityManagerServiceTest {
|
||||
changeItem.change = UidRecord.CHANGE_PROCSTATE;
|
||||
changeItem.processState = ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
|
||||
changeItem.procStateSeq = 111;
|
||||
mAms.mPendingUidChanges.add(changeItem);
|
||||
mAms.dispatchUidsChanged();
|
||||
mAms.mUidObserverController.mPendingUidChanges.add(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,
|
||||
@@ -657,15 +656,15 @@ public class ActivityManagerServiceTest {
|
||||
verifyNoMoreInteractions(observer);
|
||||
|
||||
changeItem.processState = ActivityManager.PROCESS_STATE_RECEIVER;
|
||||
mAms.mPendingUidChanges.add(changeItem);
|
||||
mAms.dispatchUidsChanged();
|
||||
mAms.mUidObserverController.mPendingUidChanges.add(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.mPendingUidChanges.add(changeItem);
|
||||
mAms.dispatchUidsChanged();
|
||||
mAms.mUidObserverController.mPendingUidChanges.add(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.
|
||||
@@ -675,15 +674,15 @@ public class ActivityManagerServiceTest {
|
||||
verifyNoMoreInteractions(observer);
|
||||
|
||||
changeItem.processState = ActivityManager.PROCESS_STATE_TOP;
|
||||
mAms.mPendingUidChanges.add(changeItem);
|
||||
mAms.dispatchUidsChanged();
|
||||
mAms.mUidObserverController.mPendingUidChanges.add(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.mPendingUidChanges.add(changeItem);
|
||||
mAms.dispatchUidsChanged();
|
||||
mAms.mUidObserverController.mPendingUidChanges.add(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.
|
||||
@@ -720,20 +719,21 @@ public class ActivityManagerServiceTest {
|
||||
|
||||
// Verify that when there no observers listening to uid state changes, then there will
|
||||
// be no changes to validateUids.
|
||||
mAms.mPendingUidChanges.addAll(pendingItemsForUids);
|
||||
mAms.dispatchUidsChanged();
|
||||
mAms.mUidObserverController.mPendingUidChanges.addAll(pendingItemsForUids);
|
||||
mAms.mUidObserverController.dispatchUidsChanged();
|
||||
assertEquals("No observers registered, so validateUids should be empty",
|
||||
0, mAms.mValidateUids.size());
|
||||
0, mAms.mUidObserverController.mValidateUids.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.mPendingUidChanges.addAll(pendingItemsForUids);
|
||||
mAms.dispatchUidsChanged();
|
||||
mAms.mUidObserverController.mPendingUidChanges.addAll(pendingItemsForUids);
|
||||
mAms.mUidObserverController.dispatchUidsChanged();
|
||||
for (int i = 0; i < pendingItemsForUids.size(); ++i) {
|
||||
final UidRecord.ChangeItem item = pendingItemsForUids.get(i);
|
||||
final UidRecord validateUidRecord = mAms.mValidateUids.get(item.uid);
|
||||
final UidRecord validateUidRecord =
|
||||
mAms.mUidObserverController.mValidateUids.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);
|
||||
@@ -759,7 +759,7 @@ 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.mValidateUids.size());
|
||||
mAms.mUidObserverController.mValidateUids.size());
|
||||
for (int i = 0; i < pendingItemsForUids.size(); ++i) {
|
||||
final UidRecord.ChangeItem item = pendingItemsForUids.get(i);
|
||||
// Assign CHANGE_GONE_IDLE to some items and CHANGE_GONE to the others, using even/odd
|
||||
@@ -767,10 +767,11 @@ public class ActivityManagerServiceTest {
|
||||
item.change = (i % 2) == 0 ? (UidRecord.CHANGE_GONE | UidRecord.CHANGE_IDLE)
|
||||
: UidRecord.CHANGE_GONE;
|
||||
}
|
||||
mAms.mPendingUidChanges.addAll(pendingItemsForUids);
|
||||
mAms.dispatchUidsChanged();
|
||||
assertEquals("validateUids should be empty, size=" + mAms.mValidateUids.size(),
|
||||
0, mAms.mValidateUids.size());
|
||||
mAms.mUidObserverController.mPendingUidChanges.addAll(pendingItemsForUids);
|
||||
mAms.mUidObserverController.dispatchUidsChanged();
|
||||
assertEquals("validateUids should be empty, size="
|
||||
+ mAms.mUidObserverController.mValidateUids.size(),
|
||||
0, mAms.mUidObserverController.mValidateUids.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -792,7 +793,7 @@ public class ActivityManagerServiceTest {
|
||||
@Test
|
||||
public void testEnqueueUidChangeLocked_nullUidRecord() {
|
||||
// Use "null" uidRecord to make sure there is no crash.
|
||||
mAms.enqueueUidChangeLocked(null, TEST_UID, UidRecord.CHANGE_ACTIVE);
|
||||
mAms.mUidObserverController.enqueueUidChangeLocked(null, TEST_UID, UidRecord.CHANGE_ACTIVE);
|
||||
}
|
||||
|
||||
private void verifyLastProcStateSeqUpdated(UidRecord uidRecord, int uid, long curProcstateSeq) {
|
||||
@@ -801,7 +802,7 @@ public class ActivityManagerServiceTest {
|
||||
final int changeToDispatch = UID_RECORD_CHANGES[i];
|
||||
// Reset lastProcStateSeqDispatchToObservers after every test.
|
||||
uidRecord.lastDispatchedProcStateSeq = 0;
|
||||
mAms.enqueueUidChangeLocked(uidRecord, uid, changeToDispatch);
|
||||
mAms.mUidObserverController.enqueueUidChangeLocked(uidRecord, uid, changeToDispatch);
|
||||
// Verify there is no effect on curProcStateSeq.
|
||||
assertEquals(curProcstateSeq, uidRecord.curProcStateSeq);
|
||||
if ((changeToDispatch & UidRecord.CHANGE_GONE) != 0) {
|
||||
@@ -833,9 +834,9 @@ public class ActivityManagerServiceTest {
|
||||
// Reset the current state
|
||||
mHandler.reset();
|
||||
uidRecord.pendingChange = null;
|
||||
mAms.mPendingUidChanges.clear();
|
||||
mAms.mUidObserverController.mPendingUidChanges.clear();
|
||||
|
||||
mAms.enqueueUidChangeLocked(uidRecord, -1, changeToDispatch);
|
||||
mAms.mUidObserverController.enqueueUidChangeLocked(uidRecord, -1, changeToDispatch);
|
||||
|
||||
// Verify that UidRecord.pendingChange is updated correctly.
|
||||
assertNotNull(uidRecord.pendingChange);
|
||||
@@ -843,8 +844,7 @@ public class ActivityManagerServiceTest {
|
||||
assertEquals(expectedProcState, uidRecord.pendingChange.processState);
|
||||
assertEquals(TEST_PROC_STATE_SEQ1, uidRecord.pendingChange.procStateSeq);
|
||||
|
||||
// Verify that DISPATCH_UIDS_CHANGED_UI_MSG is posted to handler.
|
||||
mHandler.waitForMessage(DISPATCH_UIDS_CHANGED_UI_MSG);
|
||||
// TODO: Verify that DISPATCH_UIDS_CHANGED_UI_MSG is posted to handler.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user