diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index a838aadc404e3..abbb01406c4b8 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -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 mProcessObservers = new RemoteCallbackList<>(); ProcessChangeItem[] mActiveProcessChanges = new ProcessChangeItem[5]; @@ -1469,12 +1390,6 @@ public class ActivityManagerService extends IActivityManager.Stub final ArrayList mPendingProcessChanges = new ArrayList<>(); final ArrayList mAvailProcessChanges = new ArrayList<>(); - final RemoteCallbackList mUidObservers = new RemoteCallbackList<>(); - UidRecord.ChangeItem[] mActiveUidChanges = new UidRecord.ChangeItem[5]; - - final ArrayList mPendingUidChanges = new ArrayList<>(); - final ArrayList 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 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 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(); diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java index bf15f1737cfcc..bad042cd3a682 100644 --- a/services/core/java/com/android/server/am/OomAdjuster.java +++ b/services/core/java/com/android/server/am/OomAdjuster.java @@ -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) { diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index 5721fb7f51285..2e8660e1317ad 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -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, diff --git a/services/core/java/com/android/server/am/UidObserverController.java b/services/core/java/com/android/server/am/UidObserverController.java new file mode 100644 index 0000000000000..4c4dd8b8defa7 --- /dev/null +++ b/services/core/java/com/android/server/am/UidObserverController.java @@ -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 mUidObservers = new RemoteCallbackList<>(); + + UidRecord.ChangeItem[] mActiveUidChanges = new UidRecord.ChangeItem[5]; + final ArrayList mPendingUidChanges = new ArrayList<>(); + final ArrayList 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 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= 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