diff --git a/core/java/com/android/internal/annotations/CompositeRWLock.java b/core/java/com/android/internal/annotations/CompositeRWLock.java new file mode 100644 index 0000000000000..b6ddfc4d2cc4e --- /dev/null +++ b/core/java/com/android/internal/annotations/CompositeRWLock.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2021 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.internal.annotations; + +import static java.lang.annotation.ElementType.FIELD; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Specifies a list of locks which are required for read/write operations on a data field. + * + *

+ * To annotate methods accessing the data field with the annotation {@link CompositeRWLock}, + * use {@link GuardedBy#value} to annotate method w/ write and/or read access to the data field, + * use {@link GuardedBy#anyOf} to annotate method w/ read only access to the data field. + *

+ * + *

+ * When its {@link #value()} consists of multiple locks: + *

+ *

+ */ +@Target({FIELD}) +@Retention(RetentionPolicy.CLASS) +public @interface CompositeRWLock { + String[] value() default {}; +} diff --git a/core/java/com/android/internal/annotations/GuardedBy.java b/core/java/com/android/internal/annotations/GuardedBy.java index 0e63214b4f1a6..c05c4abd10e46 100644 --- a/core/java/com/android/internal/annotations/GuardedBy.java +++ b/core/java/com/android/internal/annotations/GuardedBy.java @@ -16,7 +16,9 @@ package com.android.internal.annotations; -import java.lang.annotation.ElementType; +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; + import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @@ -25,8 +27,32 @@ import java.lang.annotation.Target; * Annotation type used to mark a method or field that can only be accessed when * holding the referenced locks. */ -@Target({ ElementType.FIELD, ElementType.METHOD }) +@Target({FIELD, METHOD}) @Retention(RetentionPolicy.CLASS) public @interface GuardedBy { - String[] value(); + /** + * Specifies a list of locks to be held in order to access the field/method + * annotated with this; when used in conjunction with the {@link CompositeRWLock}, locks + * should be acquired in the order of the appearance in the {@link #value} here. + * + *

+ * If specified, {@link #anyOf()} must be null. + *

+ * + * @see CompositeRWLock + */ + String[] value() default {}; + + /** + * Specifies a list of locks where at least one of them must be held in order to access + * the field/method annotated with this; it should be only used in the conjunction + * with the {@link CompositeRWLock}. + * + *

+ * If specified, {@link #allOf()} must be null. + *

+ * + * @see CompositeRWLock + */ + String[] anyOf() default {}; } diff --git a/services/core/Android.bp b/services/core/Android.bp index 6de227e7ee7ae..e01c4df42ff5d 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -158,9 +158,9 @@ java_genrule { srcs: [":services.core.unboosted"], tools: ["lockedregioncodeinjection"], cmd: "$(location lockedregioncodeinjection) " + - " --targets \"Lcom/android/server/am/ActivityManagerService;,Lcom/android/server/wm/WindowManagerGlobalLock;\" " + - " --pre \"com/android/server/am/ActivityManagerService.boostPriorityForLockedSection,com/android/server/wm/WindowManagerService.boostPriorityForLockedSection\" " + - " --post \"com/android/server/am/ActivityManagerService.resetPriorityAfterLockedSection,com/android/server/wm/WindowManagerService.resetPriorityAfterLockedSection\" " + + " --targets \"Lcom/android/server/am/ActivityManagerService;,Lcom/android/server/am/ActivityManagerGlobalLock;,Lcom/android/server/wm/WindowManagerGlobalLock;\" " + + " --pre \"com/android/server/am/ActivityManagerService.boostPriorityForLockedSection,com/android/server/am/ActivityManagerService.boostPriorityForProcLockedSection,com/android/server/wm/WindowManagerService.boostPriorityForLockedSection\" " + + " --post \"com/android/server/am/ActivityManagerService.resetPriorityAfterLockedSection,com/android/server/am/ActivityManagerService.resetPriorityAfterProcLockedSection,com/android/server/wm/WindowManagerService.resetPriorityAfterLockedSection\" " + " -o $(out) " + " -i $(in)", out: ["services.core.priorityboosted.jar"], diff --git a/services/core/java/com/android/server/LockGuard.java b/services/core/java/com/android/server/LockGuard.java index 5ce16c49a9457..b894f34ffd9f2 100644 --- a/services/core/java/com/android/server/LockGuard.java +++ b/services/core/java/com/android/server/LockGuard.java @@ -22,8 +22,6 @@ import android.util.ArrayMap; import android.util.ArraySet; import android.util.Slog; -import com.android.internal.os.BackgroundThread; - import java.io.FileDescriptor; import java.io.PrintWriter; @@ -74,8 +72,9 @@ public class LockGuard { public static final int INDEX_PACKAGES = 3; public static final int INDEX_STORAGE = 4; public static final int INDEX_WINDOW = 5; - public static final int INDEX_ACTIVITY = 6; - public static final int INDEX_DPMS = 7; + public static final int INDEX_PROC = 6; + public static final int INDEX_ACTIVITY = 7; + public static final int INDEX_DPMS = 8; private static Object[] sKnownFixed = new Object[INDEX_DPMS + 1]; @@ -229,6 +228,7 @@ public class LockGuard { case INDEX_PACKAGES: return "PACKAGES"; case INDEX_STORAGE: return "STORAGE"; case INDEX_WINDOW: return "WINDOW"; + case INDEX_PROC: return "PROCESS"; case INDEX_ACTIVITY: return "ACTIVITY"; case INDEX_DPMS: return "DPMS"; default: return Integer.toString(index); diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 15afb9815a146..a4ff230b06788 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -19,6 +19,9 @@ package com.android.server.am; import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND; import static android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND; import static android.Manifest.permission.SYSTEM_ALERT_WINDOW; +import static android.app.ActivityManager.PROCESS_STATE_HEAVY_WEIGHT; +import static android.app.ActivityManager.PROCESS_STATE_RECEIVER; +import static android.app.ActivityManager.PROCESS_STATE_TOP; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MANIFEST; import static android.os.Process.NFC_UID; @@ -48,7 +51,6 @@ import android.app.ActivityManagerInternal; import android.app.ActivityThread; import android.app.AppGlobals; import android.app.AppOpsManager; -import android.app.ApplicationExitInfo; import android.app.BroadcastOptions; import android.app.IApplicationThread; import android.app.IServiceConnection; @@ -621,14 +623,14 @@ public final class ActiveServices { final boolean callerFg; if (caller != null) { - final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller); + final ProcessRecord callerApp = mAm.getRecordForAppLOSP(caller); if (callerApp == null) { throw new SecurityException( "Unable to find app for caller " + caller + " (pid=" + callingPid + ") when starting service " + service); } - callerFg = callerApp.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND; + callerFg = callerApp.mState.getSetSchedGroup() != ProcessList.SCHED_GROUP_BACKGROUND; } else { callerFg = true; } @@ -656,7 +658,7 @@ public final class ActiveServices { // If we're starting indirectly (e.g. from PendingIntent), figure out whether // we're launching into an app in a background state. This keys off of the same // idleness state tracking as e.g. O+ background service start policy. - final boolean bgLaunch = !mAm.isUidActiveLocked(r.appInfo.uid); + final boolean bgLaunch = !mAm.isUidActiveLOSP(r.appInfo.uid); // If the app has strict background restrictions, we treat any bg service // start analogously to the legacy-app forced-restrictions case, regardless @@ -727,7 +729,7 @@ public final class ActiveServices { if (forcedStandby || (!r.startRequested && !fgRequired)) { // Before going further -- if this app is not allowed to start services in the // background, then at this point we aren't going to let it period. - final int allowed = mAm.getAppStartModeLocked(r.appInfo.uid, r.packageName, + final int allowed = mAm.getAppStartModeLOSP(r.appInfo.uid, r.packageName, r.appInfo.targetSdkVersion, callingPid, false, false, forcedStandby); if (allowed != ActivityManager.APP_START_MODE_NORMAL) { Slog.w(TAG, "Background start not allowed: service " @@ -752,7 +754,7 @@ public final class ActiveServices { } // This app knows it is in the new model where this operation is not // allowed, so tell it what has happened. - UidRecord uidRec = mAm.mProcessList.getUidRecordLocked(r.appInfo.uid); + UidRecord uidRec = mAm.mProcessList.getUidRecordLOSP(r.appInfo.uid); return new ComponentName("?", "app is in background uid " + uidRec); } } @@ -825,7 +827,7 @@ public final class ActiveServices { if (!callerFg && !fgRequired && r.app == null && mAm.mUserController.hasStartedUserState(r.userId)) { ProcessRecord proc = mAm.getProcessRecordLocked(r.processName, r.appInfo.uid, false); - if (proc == null || proc.getCurProcState() > ActivityManager.PROCESS_STATE_RECEIVER) { + if (proc == null || proc.mState.getCurProcState() > PROCESS_STATE_RECEIVER) { // If this is not coming from a foreground caller, then we may want // to delay the start if there are already other background services // that are starting. This is to avoid process start spam when lots @@ -853,7 +855,7 @@ public final class ActiveServices { } if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "Not delaying: " + r); addToStarting = true; - } else if (proc.getCurProcState() >= ActivityManager.PROCESS_STATE_SERVICE) { + } else if (proc.mState.getCurProcState() >= ActivityManager.PROCESS_STATE_SERVICE) { // We slightly loosen when we will enqueue this new service as a background // starting service we are waiting for, to also include processes that are // currently running other services or receivers. @@ -862,9 +864,9 @@ public final class ActiveServices { "Not delaying, but counting as bg: " + r); } else if (DEBUG_DELAYED_STARTS) { StringBuilder sb = new StringBuilder(128); - sb.append("Not potential delay (state=").append(proc.getCurProcState()) - .append(' ').append(proc.adjType); - String reason = proc.makeAdjReason(); + sb.append("Not potential delay (state=").append(proc.mState.getCurProcState()) + .append(' ').append(proc.mState.getAdjType()); + String reason = proc.mState.makeAdjReason(); if (reason != null) { sb.append(' '); sb.append(reason); @@ -1159,7 +1161,7 @@ public final class ActiveServices { if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "stopService: " + service + " type=" + resolvedType); - final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller); + final ProcessRecord callerApp = mAm.getRecordForAppLOSP(caller); if (caller != null && callerApp == null) { throw new SecurityException( "Unable to find app for caller " + caller @@ -1195,7 +1197,7 @@ public final class ActiveServices { for (int i = services.mServicesByInstanceName.size() - 1; i >= 0; i--) { ServiceRecord service = services.mServicesByInstanceName.valueAt(i); if (service.appInfo.uid == uid && service.startRequested) { - if (mAm.getAppStartModeLocked(service.appInfo.uid, service.packageName, + if (mAm.getAppStartModeLOSP(service.appInfo.uid, service.packageName, service.appInfo.targetSdkVersion, -1, false, false, false) != ActivityManager.APP_START_MODE_NORMAL) { if (stopping == null) { @@ -1625,13 +1627,13 @@ public final class ActiveServices { } void foregroundServiceProcStateChangedLocked(UidRecord uidRec) { - ServiceMap smap = mServiceMap.get(UserHandle.getUserId(uidRec.uid)); + ServiceMap smap = mServiceMap.get(UserHandle.getUserId(uidRec.getUid())); if (smap != null) { boolean changed = false; for (int j = smap.mActiveForegroundApps.size()-1; j >= 0; j--) { ActiveForegroundApp active = smap.mActiveForegroundApps.valueAt(j); - if (active.mUid == uidRec.uid) { - if (uidRec.getCurProcState() <= ActivityManager.PROCESS_STATE_TOP) { + if (active.mUid == uidRec.getUid()) { + if (uidRec.getCurProcState() <= PROCESS_STATE_TOP) { if (!active.mAppOnTop) { active.mAppOnTop = true; changed = true; @@ -1650,7 +1652,7 @@ public final class ActiveServices { } private boolean appIsTopLocked(int uid) { - return mAm.getUidState(uid) <= ActivityManager.PROCESS_STATE_TOP; + return mAm.getUidStateLocked(uid) <= PROCESS_STATE_TOP; } /** @@ -1682,13 +1684,13 @@ public final class ActiveServices { default: mAm.enforcePermission( android.Manifest.permission.INSTANT_APP_FOREGROUND_SERVICE, - r.app.pid, r.appInfo.uid, "startForeground"); + r.app.getPid(), r.appInfo.uid, "startForeground"); } } else { if (r.appInfo.targetSdkVersion >= Build.VERSION_CODES.P) { mAm.enforcePermission( android.Manifest.permission.FOREGROUND_SERVICE, - r.app.pid, r.appInfo.uid, "startForeground"); + r.app.getPid(), r.appInfo.uid, "startForeground"); } int manifestType = r.serviceInfo.getForegroundServiceType(); @@ -1729,6 +1731,7 @@ public final class ActiveServices { ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_MSG, r); } + final ProcessServiceRecord psr = r.app.mServices; try { boolean ignoreForeground = false; final int mode = mAm.getAppOpsManager().checkOpNoThrow( @@ -1758,7 +1761,7 @@ public final class ActiveServices { + r.shortInstanceName); // Back off of any foreground expectations around this service, since we've // just turned down its fg request. - updateServiceForegroundLocked(r.app, false); + updateServiceForegroundLocked(psr, false); ignoreForeground = true; } @@ -1771,7 +1774,7 @@ public final class ActiveServices { + r.shortInstanceName; Slog.w(TAG, msg); showFgsBgRestrictedNotificationLocked(r); - updateServiceForegroundLocked(r.app, true); + updateServiceForegroundLocked(psr, true); ignoreForeground = true; if (CompatChanges.isChangeEnabled(FGS_START_EXCEPTION_CHANGE_ID, r.appInfo.uid)) { @@ -1802,10 +1805,12 @@ public final class ActiveServices { active.mPackageName = r.packageName; active.mUid = r.appInfo.uid; active.mShownWhileScreenOn = mScreenOn; - if (r.app != null && r.app.uidRecord != null) { - active.mAppOnTop = active.mShownWhileTop = - r.app.uidRecord.getCurProcState() - <= ActivityManager.PROCESS_STATE_TOP; + if (r.app != null) { + final UidRecord uidRec = r.app.getUidRecord(); + if (uidRec != null) { + active.mAppOnTop = active.mShownWhileTop = + uidRec.getCurProcState() <= PROCESS_STATE_TOP; + } } active.mStartTime = active.mStartVisibleTime = SystemClock.elapsedRealtime(); @@ -1837,7 +1842,7 @@ public final class ActiveServices { } postFgsNotificationLocked(r); if (r.app != null) { - updateServiceForegroundLocked(r.app, true); + updateServiceForegroundLocked(psr, true); } getServiceMapLocked(r.userId).ensureNotStartingBackgroundLocked(r); mAm.notifyPackageUse(r.serviceInfo.packageName, @@ -1889,7 +1894,7 @@ public final class ActiveServices { mAm.updateForegroundServiceUsageStats(r.name, r.userId, false); if (r.app != null) { mAm.updateLruProcessLocked(r.app, false, null); - updateServiceForegroundLocked(r.app, true); + updateServiceForegroundLocked(r.app.mServices, true); } } // Leave the time-to-display as already set: re-entering foreground mode will @@ -2127,7 +2132,7 @@ public final class ActiveServices { } private boolean isNotTop() { - return mProcessRecord.getCurProcState() != ActivityManager.PROCESS_STATE_TOP; + return mProcessRecord.mState.getCurProcState() != PROCESS_STATE_TOP; } private void incrementOpCount(int op, boolean allowed) { @@ -2225,36 +2230,45 @@ public final class ActiveServices { } } - private void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) { + private void updateServiceForegroundLocked(ProcessServiceRecord psr, boolean oomAdj) { boolean anyForeground = false; int fgServiceTypes = 0; - for (int i = proc.numberOfRunningServices() - 1; i >= 0; i--) { - ServiceRecord sr = proc.getRunningServiceAt(i); + for (int i = psr.numberOfRunningServices() - 1; i >= 0; i--) { + ServiceRecord sr = psr.getRunningServiceAt(i); if (sr.isForeground || sr.fgRequired) { anyForeground = true; fgServiceTypes |= sr.foregroundServiceType; } } - mAm.updateProcessForegroundLocked(proc, anyForeground, fgServiceTypes, oomAdj); + mAm.updateProcessForegroundLocked(psr.mApp, anyForeground, fgServiceTypes, oomAdj); } - private void updateAllowlistManagerLocked(ProcessRecord proc) { - proc.mAllowlistManager = false; - for (int i = proc.numberOfRunningServices() - 1; i >= 0; i--) { - ServiceRecord sr = proc.getRunningServiceAt(i); + private void updateAllowlistManagerLocked(ProcessServiceRecord psr) { + psr.mAllowlistManager = false; + for (int i = psr.numberOfRunningServices() - 1; i >= 0; i--) { + ServiceRecord sr = psr.getRunningServiceAt(i); if (sr.whitelistManager) { - proc.mAllowlistManager = true; + psr.mAllowlistManager = true; break; } } } - public void updateServiceConnectionActivitiesLocked(ProcessRecord clientProc) { + private void stopServiceAndUpdateAllowlistManagerLocked(ServiceRecord service) { + final ProcessServiceRecord psr = service.app.mServices; + psr.stopService(service); + psr.updateBoundClientUids(); + if (service.whitelistManager) { + updateAllowlistManagerLocked(psr); + } + } + + void updateServiceConnectionActivitiesLocked(ProcessServiceRecord clientPsr) { ArraySet updatedProcesses = null; - for (int i = 0; i < clientProc.connections.size(); i++) { - final ConnectionRecord conn = clientProc.connections.valueAt(i); + for (int i = 0; i < clientPsr.numberOfConnections(); i++) { + final ConnectionRecord conn = clientPsr.getConnectionAt(i); final ProcessRecord proc = conn.binding.service.app; - if (proc == null || proc == clientProc) { + if (proc == null || proc == clientPsr.mApp) { continue; } else if (updatedProcesses == null) { updatedProcesses = new ArraySet<>(); @@ -2262,11 +2276,11 @@ public final class ActiveServices { continue; } updatedProcesses.add(proc); - updateServiceClientActivitiesLocked(proc, null, false); + updateServiceClientActivitiesLocked(proc.mServices, null, false); } } - private boolean updateServiceClientActivitiesLocked(ProcessRecord proc, + private boolean updateServiceClientActivitiesLocked(ProcessServiceRecord psr, ConnectionRecord modCr, boolean updateLru) { if (modCr != null && modCr.binding.client != null) { if (!modCr.binding.client.hasActivities()) { @@ -2277,14 +2291,14 @@ public final class ActiveServices { } boolean anyClientActivities = false; - for (int i = proc.numberOfRunningServices() - 1; i >= 0 && !anyClientActivities; i--) { - ServiceRecord sr = proc.getRunningServiceAt(i); + for (int i = psr.numberOfRunningServices() - 1; i >= 0 && !anyClientActivities; i--) { + ServiceRecord sr = psr.getRunningServiceAt(i); ArrayMap> connections = sr.getConnections(); for (int conni = connections.size() - 1; conni >= 0 && !anyClientActivities; conni--) { ArrayList clist = connections.valueAt(conni); for (int cri=clist.size()-1; cri>=0; cri--) { ConnectionRecord cr = clist.get(cri); - if (cr.binding.client == null || cr.binding.client == proc) { + if (cr.binding.client == null || cr.binding.client == psr.mApp) { // Binding to ourself is not interesting. continue; } @@ -2295,10 +2309,10 @@ public final class ActiveServices { } } } - if (anyClientActivities != proc.hasClientActivities()) { - proc.setHasClientActivities(anyClientActivities); + if (anyClientActivities != psr.hasClientActivities()) { + psr.setHasClientActivities(anyClientActivities); if (updateLru) { - mAm.updateLruProcessLocked(proc, anyClientActivities, null); + mAm.updateLruProcessLocked(psr.mApp, anyClientActivities, null); } return true; } @@ -2314,7 +2328,7 @@ public final class ActiveServices { + " flags=0x" + Integer.toHexString(flags)); final int callingPid = Binder.getCallingPid(); final int callingUid = Binder.getCallingUid(); - final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller); + final ProcessRecord callerApp = mAm.getRecordForAppLOSP(caller); if (callerApp == null) { throw new SecurityException( "Unable to find app for caller " + caller @@ -2386,7 +2400,8 @@ public final class ActiveServices { "BIND_ALLOW_FOREGROUND_SERVICE_STARTS_FROM_BACKGROUND"); } - final boolean callerFg = callerApp.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND; + final boolean callerFg = callerApp.mState.getSetSchedGroup() + != ProcessList.SCHED_GROUP_BACKGROUND; final boolean isBindExternal = (flags & Context.BIND_EXTERNAL_SERVICE) != 0; final boolean allowInstant = (flags & Context.BIND_ALLOW_INSTANT) != 0; @@ -2440,7 +2455,7 @@ public final class ActiveServices { } mAm.startAssociationLocked(callerApp.uid, callerApp.processName, - callerApp.getCurProcState(), s.appInfo.uid, s.appInfo.longVersionCode, + callerApp.mState.getCurProcState(), s.appInfo.uid, s.appInfo.longVersionCode, s.instanceName, s.processName); // Once the apps have become associated, if one of them is caller is ephemeral // the target app should now be able to see the calling app @@ -2458,10 +2473,11 @@ public final class ActiveServices { if (activity != null) { activity.addConnection(c); } - b.client.connections.add(c); + final ProcessServiceRecord clientPsr = b.client.mServices; + clientPsr.addConnection(c); c.startAssociationIfNeeded(); if ((c.flags&Context.BIND_ABOVE_CLIENT) != 0) { - b.client.hasAboveClient = true; + clientPsr.setHasAboveClient(true); } if ((c.flags&Context.BIND_ALLOW_WHITELIST_MANAGEMENT) != 0) { s.whitelistManager = true; @@ -2475,7 +2491,7 @@ public final class ActiveServices { } if (s.app != null) { - updateServiceClientActivitiesLocked(s.app, c, true); + updateServiceClientActivitiesLocked(s.app.mServices, c, true); } ArrayList clist = mServiceConnections.get(binder); if (clist == null) { @@ -2497,17 +2513,18 @@ public final class ActiveServices { setFgsRestrictionLocked(callingPackage, callingPid, callingUid, service, s, false); if (s.app != null) { + ProcessServiceRecord servicePsr = s.app.mServices; if ((flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) { - s.app.treatLikeActivity = true; + servicePsr.setTreatLikeActivity(true); } if (s.whitelistManager) { - s.app.mAllowlistManager = true; + servicePsr.mAllowlistManager = true; } // This could have made the service more important. - mAm.updateLruProcessLocked(s.app, - (callerApp.hasActivitiesOrRecentTasks() && s.app.hasClientActivities()) - || (callerApp.getCurProcState() <= ActivityManager.PROCESS_STATE_TOP - && (flags & Context.BIND_TREAT_LIKE_ACTIVITY) != 0), + mAm.updateLruProcessLocked(s.app, (callerApp.hasActivitiesOrRecentTasks() + && servicePsr.hasClientActivities()) + || (callerApp.mState.getCurProcState() <= PROCESS_STATE_TOP + && (flags & Context.BIND_TREAT_LIKE_ACTIVITY) != 0), b.client); needOomAdj = true; mAm.enqueueOomAdjTargetLocked(s.app); @@ -2627,14 +2644,15 @@ public final class ActiveServices { final ServiceRecord srec = crec.binding.service; if (srec != null && (srec.serviceInfo.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) != 0) { if (srec.app != null) { + final ProcessServiceRecord psr = srec.app.mServices; if (group > 0) { - srec.app.connectionService = srec; - srec.app.connectionGroup = group; - srec.app.connectionImportance = importance; + psr.setConnectionService(srec); + psr.setConnectionGroup(group); + psr.setConnectionImportance(importance); } else { - srec.app.connectionService = null; - srec.app.connectionGroup = 0; - srec.app.connectionImportance = 0; + psr.setConnectionService(null); + psr.setConnectionGroup(0); + psr.setConnectionImportance(0); } } else { if (group > 0) { @@ -2672,15 +2690,14 @@ public final class ActiveServices { final ProcessRecord app = r.binding.service.app; if (app != null) { - if (app.mAllowlistManager) { - updateAllowlistManagerLocked(app); + final ProcessServiceRecord psr = app.mServices; + if (psr.mAllowlistManager) { + updateAllowlistManagerLocked(psr); } // This could have made the service less important. if ((r.flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) { - app.treatLikeActivity = true; - mAm.updateLruProcessLocked(app, - app.hasClientActivities() - || app.treatLikeActivity, null); + psr.setTreatLikeActivity(true); + mAm.updateLruProcessLocked(app, true, null); } mAm.enqueueOomAdjTargetLocked(app); } @@ -2714,7 +2731,7 @@ public final class ActiveServices { boolean inFg = false; for (int i=b.apps.size()-1; i>=0; i--) { ProcessRecord client = b.apps.valueAt(i).client; - if (client != null && client.setSchedGroup + if (client != null && client.mState.getSetSchedGroup() != ProcessList.SCHED_GROUP_BACKGROUND) { inFg = true; break; @@ -3028,7 +3045,7 @@ public final class ActiveServices { // happen.) boolean timeoutNeeded = true; if ((mAm.mBootPhase < SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) - && (r.app != null) && (r.app.pid == android.os.Process.myPid())) { + && (r.app != null) && (r.app.getPid() == ActivityManagerService.MY_PID)) { Slog.w(TAG, "Too early to start/bind service in system_server: Phase=" + mAm.mBootPhase + " " + r.getComponentName()); @@ -3036,6 +3053,7 @@ public final class ActiveServices { } long now = SystemClock.uptimeMillis(); + ProcessServiceRecord psr; if (r.executeNesting == 0) { r.executeFg = fg; ServiceState stracker = r.getTracker(); @@ -3043,16 +3061,20 @@ public final class ActiveServices { stracker.setExecuting(true, mAm.mProcessStats.getMemFactorLocked(), now); } if (r.app != null) { - r.app.executingServices.add(r); - r.app.execServicesFg |= fg; - if (timeoutNeeded && r.app.executingServices.size() == 1) { + psr = r.app.mServices; + psr.startExecutingService(r); + psr.setExecServicesFg(psr.shouldExecServicesFg() || fg); + if (timeoutNeeded && psr.numberOfExecutingServices() == 1) { scheduleServiceTimeoutLocked(r.app); } } - } else if (r.app != null && fg && !r.app.execServicesFg) { - r.app.execServicesFg = true; - if (timeoutNeeded) { - scheduleServiceTimeoutLocked(r.app); + } else if (r.app != null && fg) { + psr = r.app.mServices; + if (!psr.shouldExecServicesFg()) { + psr.setExecServicesFg(true); + if (timeoutNeeded) { + scheduleServiceTimeoutLocked(r.app); + } } } r.executeFg |= fg; @@ -3062,7 +3084,7 @@ public final class ActiveServices { private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i, boolean execInFg, boolean rebind) throws TransactionTooLargeException { - if (r.app == null || r.app.thread == null) { + if (r.app == null || r.app.getThread() == null) { // If service is not currently running, can't yet bind. return false; } @@ -3071,9 +3093,9 @@ public final class ActiveServices { if ((!i.requested || rebind) && i.apps.size() > 0) { try { bumpServiceExecutingLocked(r, execInFg, "bind"); - r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE); - r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind, - r.app.getReportedProcState()); + r.app.mState.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE); + r.app.getThread().scheduleBindService(r, i.intent.getIntent(), rebind, + r.app.mState.getReportedProcState()); if (!rebind) { i.requested = true; } @@ -3296,7 +3318,7 @@ public final class ActiveServices { boolean whileRestarting, boolean permissionsReviewRequired, boolean packageFrozen, boolean enqueueOomAdj) throws TransactionTooLargeException { - if (r.app != null && r.app.thread != null) { + if (r.app != null && r.app.getThread() != null) { sendServiceArgsLocked(r, execInFg, false); return null; } @@ -3354,19 +3376,26 @@ public final class ActiveServices { app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false); if (DEBUG_MU) Slog.v(TAG_MU, "bringUpServiceLocked: appInfo.uid=" + r.appInfo.uid + " app=" + app); - if (app != null && app.thread != null) { - try { - app.addPackage(r.appInfo.packageName, r.appInfo.longVersionCode, mAm.mProcessStats); - realStartServiceLocked(r, app, execInFg, enqueueOomAdj); - return null; - } catch (TransactionTooLargeException e) { - throw e; - } catch (RemoteException e) { - Slog.w(TAG, "Exception when starting service " + r.shortInstanceName, e); - } + if (app != null) { + final IApplicationThread thread = app.getThread(); + final int pid = app.getPid(); + final UidRecord uidRecord = app.getUidRecord(); + if (thread != null) { + try { + app.addPackage(r.appInfo.packageName, r.appInfo.longVersionCode, + mAm.mProcessStats); + realStartServiceLocked(r, app, thread, pid, uidRecord, execInFg, + enqueueOomAdj); + return null; + } catch (TransactionTooLargeException e) { + throw e; + } catch (RemoteException e) { + Slog.w(TAG, "Exception when starting service " + r.shortInstanceName, e); + } - // If a dead object exception was thrown -- fall through to - // restart the application. + // If a dead object exception was thrown -- fall through to + // restart the application. + } } } else { // If this service runs in an isolated process, then each time @@ -3391,8 +3420,8 @@ public final class ActiveServices { if (app == null && !permissionsReviewRequired && !packageFrozen) { // TODO (chriswailes): Change the Zygote policy flags based on if the launch-for-service // was initiated from a notification tap or not. - if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags, - hostingRecord, ZYGOTE_POLICY_FLAG_EMPTY, false, isolated, false)) == null) { + if ((app = mAm.startProcessLocked(procName, r.appInfo, true, intentFlags, + hostingRecord, ZYGOTE_POLICY_FLAG_EMPTY, false, isolated, false)) == null) { String msg = "Unable to launch app " + r.appInfo.packageName + "/" + r.appInfo.uid + " for service " @@ -3448,21 +3477,23 @@ public final class ActiveServices { * The "start" here means bring up the instance in the client, and this method is called * from bindService() as well. */ - private final void realStartServiceLocked(ServiceRecord r, - ProcessRecord app, boolean execInFg, boolean enqueueOomAdj) throws RemoteException { - if (app.thread == null) { + private void realStartServiceLocked(ServiceRecord r, ProcessRecord app, + IApplicationThread thread, int pid, UidRecord uidRecord, boolean execInFg, + boolean enqueueOomAdj) throws RemoteException { + if (thread == null) { throw new RemoteException(); } if (DEBUG_MU) Slog.v(TAG_MU, "realStartServiceLocked, ServiceRecord.uid = " + r.appInfo.uid + ", ProcessRecord.uid = " + app.uid); - r.setProcess(app); + r.setProcess(app, thread, pid, uidRecord); r.restartTime = r.lastActivity = SystemClock.uptimeMillis(); - final boolean newService = app.startService(r); + final ProcessServiceRecord psr = app.mServices; + final boolean newService = psr.startService(r); bumpServiceExecutingLocked(r, execInFg, "create"); mAm.updateLruProcessLocked(app, false, null); - updateServiceForegroundLocked(r.app, /* oomAdj= */ false); + updateServiceForegroundLocked(psr, /* oomAdj= */ false); if (enqueueOomAdj) { mAm.enqueueOomAdjTargetLocked(app); } else { @@ -3477,7 +3508,7 @@ public final class ActiveServices { nameTerm = lastPeriod >= 0 ? r.shortInstanceName.substring(lastPeriod) : r.shortInstanceName; EventLogTags.writeAmCreateService( - r.userId, System.identityHashCode(r), nameTerm, r.app.uid, r.app.pid); + r.userId, System.identityHashCode(r), nameTerm, r.app.uid, pid); } final int uid = r.appInfo.uid; @@ -3488,10 +3519,10 @@ public final class ActiveServices { mAm.mBatteryStatsService.noteServiceStartLaunch(uid, packageName, serviceName); mAm.notifyPackageUse(r.serviceInfo.packageName, PackageManager.NOTIFY_PACKAGE_USE_SERVICE); - app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE); - app.thread.scheduleCreateService(r, r.serviceInfo, + app.mState.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE); + thread.scheduleCreateService(r, r.serviceInfo, mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo), - app.getReportedProcState()); + app.mState.getReportedProcState()); r.postNotification(); created = true; } catch (DeadObjectException e) { @@ -3506,8 +3537,8 @@ public final class ActiveServices { // Cleanup. if (newService) { - app.stopService(r); - r.setProcess(null); + psr.stopService(r); + r.setProcess(null, null, 0, null); } // Retry. @@ -3518,15 +3549,15 @@ public final class ActiveServices { } if (r.whitelistManager) { - app.mAllowlistManager = true; + psr.mAllowlistManager = true; } requestServiceBindingsLocked(r, execInFg); - updateServiceClientActivitiesLocked(app, null, true); + updateServiceClientActivitiesLocked(psr, null, true); if (newService && created) { - app.addBoundClientUidsOfNewService(r); + psr.addBoundClientUidsOfNewService(r); } // If the service is in the started state, and there are no @@ -3620,7 +3651,7 @@ public final class ActiveServices { slice.setInlineCountLimit(4); Exception caughtException = null; try { - r.app.thread.scheduleServiceArgs(r, slice); + r.app.getThread().scheduleServiceArgs(r, slice); } catch (TransactionTooLargeException e) { if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Transaction too large for " + args.size() + " args, first: " + args.get(0).args); @@ -3712,7 +3743,7 @@ public final class ActiveServices { boolean needOomAdj = false; // Tell the service that it has been unbound. - if (r.app != null && r.app.thread != null) { + if (r.app != null && r.app.getThread() != null) { for (int i = r.bindings.size() - 1; i >= 0; i--) { IntentBindRecord ibr = r.bindings.valueAt(i); if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Bringing down binding " + ibr @@ -3723,7 +3754,7 @@ public final class ActiveServices { needOomAdj = true; ibr.hasBound = false; ibr.requested = false; - r.app.thread.scheduleUnbindService(r, + r.app.getThread().scheduleUnbindService(r, ibr.intent.getIntent()); } catch (Exception e) { Slog.w(TAG, "Exception when unbinding service " @@ -3770,7 +3801,7 @@ public final class ActiveServices { r.destroyTime = SystemClock.uptimeMillis(); if (LOG_SERVICE_START_STOP) { EventLogTags.writeAmDestroyService( - r.userId, System.identityHashCode(r), (r.app != null) ? r.app.pid : -1); + r.userId, System.identityHashCode(r), (r.app != null) ? r.app.getPid() : -1); } final ServiceMap smap = getServiceMapLocked(r.userId); @@ -3832,20 +3863,15 @@ public final class ActiveServices { if (r.app != null) { mAm.mBatteryStatsService.noteServiceStopLaunch(r.appInfo.uid, r.name.getPackageName(), r.name.getClassName()); - r.app.stopService(r); - r.app.updateBoundClientUids(); - if (r.whitelistManager) { - updateAllowlistManagerLocked(r.app); - } - if (r.app.thread != null) { - updateServiceForegroundLocked(r.app, false); + stopServiceAndUpdateAllowlistManagerLocked(r); + if (r.app.getThread() != null) { + updateServiceForegroundLocked(r.app.mServices, false); try { bumpServiceExecutingLocked(r, false, "destroy"); mDestroyingServices.add(r); r.destroying = true; - mAm.updateOomAdjLocked(r.app, true, - OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE); - r.app.thread.scheduleStopService(r); + needOomAdj = true; + r.app.getThread().scheduleStopService(r); } catch (Exception e) { Slog.w(TAG, "Exception when destroying service " + r.shortInstanceName, e); @@ -3907,16 +3933,17 @@ public final class ActiveServices { c.activity.removeConnection(c); } if (b.client != skipApp) { - b.client.connections.remove(c); + final ProcessServiceRecord psr = b.client.mServices; + psr.removeConnection(c); if ((c.flags&Context.BIND_ABOVE_CLIENT) != 0) { - b.client.updateHasAboveClientLocked(); + psr.updateHasAboveClientLocked(); } // If this connection requested whitelist management, see if we should // now clear that state. if ((c.flags&Context.BIND_ALLOW_WHITELIST_MANAGEMENT) != 0) { s.updateWhitelistManager(); if (!s.whitelistManager && s.app != null) { - updateAllowlistManagerLocked(s.app); + updateAllowlistManagerLocked(s.app.mServices); } } // And do the same for bg activity starts ability. @@ -3927,7 +3954,7 @@ public final class ActiveServices { s.updateIsAllowedBgFgsStartsByBinding(); } if (s.app != null) { - updateServiceClientActivitiesLocked(s.app, c, true); + updateServiceClientActivitiesLocked(s.app.mServices, c, true); } } clist = mServiceConnections.get(binder); @@ -3948,12 +3975,12 @@ public final class ActiveServices { if (!c.serviceDead) { if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Disconnecting binding " + b.intent + ": shouldUnbind=" + b.intent.hasBound); - if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0 + if (s.app != null && s.app.getThread() != null && b.intent.apps.size() == 0 && b.intent.hasBound) { try { bumpServiceExecutingLocked(s, false, "unbind"); if (b.client != s.app && (c.flags&Context.BIND_WAIVE_PRIORITY) == 0 - && s.app.setProcState <= ActivityManager.PROCESS_STATE_HEAVY_WEIGHT) { + && s.app.mState.getSetProcState() <= PROCESS_STATE_HEAVY_WEIGHT) { // If this service's process is not already in the cached list, // then update it in the LRU list here because this may be causing // it to go down there and we want it to start out near the top. @@ -3969,7 +3996,7 @@ public final class ActiveServices { // Assume the client doesn't want to know about a rebind; // we will deal with that later if it asks for one. b.intent.doRebind = false; - s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent()); + s.app.getThread().scheduleUnbindService(s, b.intent.intent.getIntent()); } catch (Exception e) { Slog.w(TAG, "Exception when unbinding service " + s.shortInstanceName, e); serviceProcessGoneLocked(s, enqueueOomAdj); @@ -4100,19 +4127,20 @@ public final class ActiveServices { r.executeNesting--; if (r.executeNesting <= 0) { if (r.app != null) { + final ProcessServiceRecord psr = r.app.mServices; if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Nesting at 0 of " + r.shortInstanceName); - r.app.execServicesFg = false; - r.app.executingServices.remove(r); - if (r.app.executingServices.size() == 0) { + psr.setExecServicesFg(false); + psr.stopExecutingService(r); + if (psr.numberOfExecutingServices() == 0) { if (DEBUG_SERVICE || DEBUG_SERVICE_EXECUTING) Slog.v(TAG_SERVICE_EXECUTING, "No more executingServices of " + r.shortInstanceName); mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app); } else if (r.executeFg) { // Need to re-evaluate whether the app still needs to be in the foreground. - for (int i=r.app.executingServices.size()-1; i>=0; i--) { - if (r.app.executingServices.valueAt(i).executeFg) { - r.app.execServicesFg = true; + for (int i = psr.numberOfExecutingServices() - 1; i >= 0; i--) { + if (psr.getExecutingServiceAt(i).executeFg) { + psr.setExecServicesFg(true); break; } } @@ -4142,13 +4170,9 @@ public final class ActiveServices { } if (finishing) { if (r.app != null && !r.app.isPersistent()) { - r.app.stopService(r); - r.app.updateBoundClientUids(); - if (r.whitelistManager) { - updateAllowlistManagerLocked(r.app); - } + stopServiceAndUpdateAllowlistManagerLocked(r); } - r.setProcess(null); + r.setProcess(null, null, 0, null); } } } @@ -4167,11 +4191,15 @@ public final class ActiveServices { continue; } + final IApplicationThread thread = proc.getThread(); + final int pid = proc.getPid(); + final UidRecord uidRecord = proc.getUidRecord(); mPendingServices.remove(i); i--; proc.addPackage(sr.appInfo.packageName, sr.appInfo.longVersionCode, mAm.mProcessStats); - realStartServiceLocked(sr, proc, sr.createdFromFg, true); + realStartServiceLocked(sr, proc, thread, pid, uidRecord, sr.createdFromFg, + true); didSomething = true; if (!isServiceNeededLocked(sr, false, false)) { // We were waiting for this service to start, but it is actually no @@ -4246,13 +4274,9 @@ public final class ActiveServices { didSomething = true; Slog.i(TAG, " Force stopping service " + service); if (service.app != null && !service.app.isPersistent()) { - service.app.stopService(service); - service.app.updateBoundClientUids(); - if (service.whitelistManager) { - updateAllowlistManagerLocked(service.app); - } + stopServiceAndUpdateAllowlistManagerLocked(service); } - service.setProcess(null); + service.setProcess(null, null, 0, null); service.isolatedProc = null; if (mTmpCollectionResults == null) { mTmpCollectionResults = new ArrayList<>(); @@ -4352,7 +4376,7 @@ public final class ActiveServices { } else { sr.pendingStarts.add(new ServiceRecord.StartItem(sr, true, sr.getLastStartId(), baseIntent, null, 0)); - if (sr.app != null && sr.app.thread != null) { + if (sr.app != null && sr.app.getThread() != null) { // We always run in the foreground, since this is called as // part of the "remove task" UI operation. try { @@ -4370,13 +4394,14 @@ public final class ActiveServices { } final void killServicesLocked(ProcessRecord app, boolean allowRestart) { + final ProcessServiceRecord psr = app.mServices; // Report disconnected services. if (false) { // XXX we are letting the client link to the service for // death notifications. - int numberOfRunningServices = app.numberOfRunningServices(); + int numberOfRunningServices = psr.numberOfRunningServices(); for (int sIndex = 0; sIndex < numberOfRunningServices; sIndex++) { - ServiceRecord r = app.getRunningServiceAt(sIndex); + ServiceRecord r = psr.getRunningServiceAt(sIndex); ArrayMap> connections = r.getConnections(); for (int conni = connections.size() - 1; conni >= 0; conni--) { ArrayList cl = connections.valueAt(conni); @@ -4398,25 +4423,25 @@ public final class ActiveServices { } // Clean up any connections this application has to other services. - for (int i = app.connections.size() - 1; i >= 0; i--) { - ConnectionRecord r = app.connections.valueAt(i); + for (int i = psr.numberOfConnections() - 1; i >= 0; i--) { + ConnectionRecord r = psr.getConnectionAt(i); removeConnectionLocked(r, app, null, true); } - updateServiceConnectionActivitiesLocked(app); - app.connections.clear(); + updateServiceConnectionActivitiesLocked(psr); + psr.removeAllConnections(); - app.mAllowlistManager = false; + psr.mAllowlistManager = false; // Clear app state from services. - for (int i = app.numberOfRunningServices() - 1; i >= 0; i--) { - ServiceRecord sr = app.getRunningServiceAt(i); + for (int i = psr.numberOfRunningServices() - 1; i >= 0; i--) { + ServiceRecord sr = psr.getRunningServiceAt(i); mAm.mBatteryStatsService.noteServiceStopLaunch(sr.appInfo.uid, sr.name.getPackageName(), sr.name.getClassName()); if (sr.app != app && sr.app != null && !sr.app.isPersistent()) { - sr.app.stopService(sr); - sr.app.updateBoundClientUids(); + sr.app.mServices.stopService(sr); + sr.app.mServices.updateBoundClientUids(); } - sr.setProcess(null); + sr.setProcess(null, null, 0, null); sr.isolatedProc = null; sr.executeNesting = 0; sr.forceClearTracker(); @@ -4438,7 +4463,7 @@ public final class ActiveServices { for (int appi=b.apps.size()-1; appi>=0; appi--) { final ProcessRecord proc = b.apps.keyAt(appi); // If the process is already gone, skip it. - if (proc.killedByAm || proc.thread == null) { + if (proc.isKilledByAm() || proc.getThread() == null) { continue; } // Only do this for processes that have an auto-create binding; @@ -4446,7 +4471,7 @@ public final class ActiveServices { // service to restart. final AppBindRecord abind = b.apps.valueAt(appi); boolean hasCreate = false; - for (int conni=abind.connections.size()-1; conni>=0; conni--) { + for (int conni = abind.connections.size() - 1; conni >= 0; conni--) { ConnectionRecord conn = abind.connections.valueAt(conni); if ((conn.flags&(Context.BIND_AUTO_CREATE|Context.BIND_ALLOW_OOM_MANAGEMENT |Context.BIND_WAIVE_PRIORITY)) == Context.BIND_AUTO_CREATE) { @@ -4458,13 +4483,15 @@ public final class ActiveServices { continue; } // XXX turned off for now until we have more time to get a better policy. - if (false && proc != null && !proc.isPersistent() && proc.thread != null - && proc.pid != 0 && proc.pid != ActivityManagerService.MY_PID - && proc.setProcState >= ActivityManager.PROCESS_STATE_LAST_ACTIVITY) { - proc.kill("bound to service " + sr.shortInstanceName + /* + if (false && proc != null && !proc.isPersistent() && proc.getThread() != null + && proc.getPid() != 0 && proc.getPid() != ActivityManagerService.MY_PID + && proc.mState.getSetProcState() >= PROCESS_STATE_LAST_ACTIVITY) { + proc.killLocked("bound to service " + sr.shortInstanceName + " in dying proc " + (app != null ? app.processName : "??"), ApplicationExitInfo.REASON_OTHER, true); } + */ } } } @@ -4472,14 +4499,14 @@ public final class ActiveServices { ServiceMap smap = getServiceMapLocked(app.userId); // Now do remaining service cleanup. - for (int i = app.numberOfRunningServices() - 1; i >= 0; i--) { - ServiceRecord sr = app.getRunningServiceAt(i); + for (int i = psr.numberOfRunningServices() - 1; i >= 0; i--) { + ServiceRecord sr = psr.getRunningServiceAt(i); // Unless the process is persistent, this process record is going away, // so make sure the service is cleaned out of it. if (!app.isPersistent()) { - app.stopService(sr); - app.updateBoundClientUids(); + psr.stopService(sr); + psr.updateBoundClientUids(); } // Sanity check: if the service listed for the app is not one @@ -4501,7 +4528,7 @@ public final class ActiveServices { Slog.w(TAG, "Service crashed " + sr.crashCount + " times, stopping: " + sr); EventLog.writeEvent(EventLogTags.AM_SERVICE_CRASHED_TOO_MUCH, - sr.userId, sr.crashCount, sr.shortInstanceName, app.pid); + sr.userId, sr.crashCount, sr.shortInstanceName, sr.app.getPid()); bringDownServiceLocked(sr, true); } else if (!allowRestart || !mAm.mUserController.isUserRunning(sr.userId, 0)) { @@ -4530,8 +4557,8 @@ public final class ActiveServices { mAm.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE); if (!allowRestart) { - app.stopAllServices(); - app.clearBoundClientUids(); + psr.stopAllServices(); + psr.clearBoundClientUids(); // Make sure there are no more restarting services for this process. for (int i=mRestartingServices.size()-1; i>=0; i--) { @@ -4570,7 +4597,7 @@ public final class ActiveServices { } } - app.executingServices.clear(); + psr.stopAllExecutingServices(); } ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) { @@ -4578,7 +4605,7 @@ public final class ActiveServices { new ActivityManager.RunningServiceInfo(); info.service = r.name; if (r.app != null) { - info.pid = r.app.pid; + info.pid = r.app.getPid(); } info.uid = r.appInfo.uid; info.process = r.processName; @@ -4594,7 +4621,7 @@ public final class ActiveServices { if (r.startRequested) { info.flags |= ActivityManager.RunningServiceInfo.FLAG_STARTED; } - if (r.app != null && r.app.pid == ActivityManagerService.MY_PID) { + if (r.app != null && r.app.getPid() == ActivityManagerService.MY_PID) { info.flags |= ActivityManager.RunningServiceInfo.FLAG_SYSTEM_PROCESS; } if (r.app != null && r.app.isPersistent()) { @@ -4693,16 +4720,17 @@ public final class ActiveServices { // The app's being debugged, ignore timeout. return; } - if (proc.executingServices.size() == 0 || proc.thread == null) { + final ProcessServiceRecord psr = proc.mServices; + if (psr.numberOfExecutingServices() == 0 || proc.getThread() == null) { return; } final long now = SystemClock.uptimeMillis(); final long maxTime = now - - (proc.execServicesFg ? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT); + (psr.shouldExecServicesFg() ? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT); ServiceRecord timeout = null; long nextTime = 0; - for (int i=proc.executingServices.size()-1; i>=0; i--) { - ServiceRecord sr = proc.executingServices.valueAt(i); + for (int i = psr.numberOfExecutingServices() - 1; i >= 0; i--) { + ServiceRecord sr = psr.getExecutingServiceAt(i); if (sr.executingStart < maxTime) { timeout = sr; break; @@ -4711,7 +4739,7 @@ public final class ActiveServices { nextTime = sr.executingStart; } } - if (timeout != null && mAm.mProcessList.mLruProcesses.contains(proc)) { + if (timeout != null && mAm.mProcessList.isInLruListLOSP(proc)) { Slog.w(TAG, "Timeout executing service: " + timeout); StringWriter sw = new StringWriter(); PrintWriter pw = new FastPrintWriter(sw, false, 1024); @@ -4726,7 +4754,7 @@ public final class ActiveServices { Message msg = mAm.mHandler.obtainMessage( ActivityManagerService.SERVICE_TIMEOUT_MSG); msg.obj = proc; - mAm.mHandler.sendMessageAtTime(msg, proc.execServicesFg + mAm.mHandler.sendMessageAtTime(msg, psr.shouldExecServicesFg() ? (nextTime+SERVICE_TIMEOUT) : (nextTime + SERVICE_BACKGROUND_TIMEOUT)); } } @@ -4780,24 +4808,24 @@ public final class ActiveServices { } void serviceForegroundCrash(ProcessRecord app, CharSequence serviceRecord) { - mAm.crashApplication(app.uid, app.pid, app.info.packageName, app.userId, + mAm.crashApplication(app.uid, app.getPid(), app.info.packageName, app.userId, "Context.startForegroundService() did not then call Service.startForeground(): " + serviceRecord, false /*force*/); } void scheduleServiceTimeoutLocked(ProcessRecord proc) { - if (proc.executingServices.size() == 0 || proc.thread == null) { + if (proc.mServices.numberOfExecutingServices() == 0 || proc.getThread() == null) { return; } Message msg = mAm.mHandler.obtainMessage( ActivityManagerService.SERVICE_TIMEOUT_MSG); msg.obj = proc; - mAm.mHandler.sendMessageDelayed(msg, - proc.execServicesFg ? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT); + mAm.mHandler.sendMessageDelayed(msg, proc.mServices.shouldExecServicesFg() + ? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT); } void scheduleServiceForegroundTransitionTimeoutLocked(ServiceRecord r) { - if (r.app.executingServices.size() == 0 || r.app.thread == null) { + if (r.app.mServices.numberOfExecutingServices() == 0 || r.app.getThread() == null) { return; } Message msg = mAm.mHandler.obtainMessage( @@ -4994,7 +5022,7 @@ public final class ActiveServices { if (proc == null) { return; } - final IApplicationThread thread = proc.thread; + final IApplicationThread thread = proc.getThread(); if (thread == null) { return; } @@ -5320,20 +5348,21 @@ public final class ActiveServices { pw.print(Integer.toHexString(System.identityHashCode(r))); pw.print(" pid="); if (r.app != null) { - pw.print(r.app.pid); + pw.print(r.app.getPid()); pw.print(" user="); pw.println(r.userId); } else pw.println("(not running)"); if (dumpAll) { r.dump(pw, innerPrefix); } } - if (r.app != null && r.app.thread != null) { + IApplicationThread thread; + if (r.app != null && (thread = r.app.getThread()) != null) { pw.print(prefix); pw.println(" Client:"); pw.flush(); try { TransferPipe tp = new TransferPipe(); try { - r.app.thread.dumpService(tp.getWriteFd(), r, args); + thread.dumpService(tp.getWriteFd(), r, args); tp.setBufferPrefix(prefix + " "); tp.go(fd); } finally { @@ -5395,10 +5424,10 @@ public final class ActiveServices { boolean allowBackgroundActivityStarts) { int ret = FGS_FEATURE_DENIED; - final int uidState = mAm.getUidState(callingUid); + final int uidState = mAm.getUidStateLocked(callingUid); if (ret == FGS_FEATURE_DENIED) { // Is the calling UID at PROCESS_STATE_TOP or above? - if (uidState <= ActivityManager.PROCESS_STATE_TOP) { + if (uidState <= PROCESS_STATE_TOP) { ret = FGS_FEATURE_ALLOWED_BY_UID_STATE; } } @@ -5439,14 +5468,16 @@ public final class ActiveServices { } if (ret == FGS_FEATURE_DENIED) { - for (int i = mAm.mProcessList.mLruProcesses.size() - 1; i >= 0; i--) { - final ProcessRecord pr = mAm.mProcessList.mLruProcesses.get(i); + final Integer allowedType = mAm.mProcessList.searchEachLruProcessesLOSP(false, pr -> { if (pr.uid == callingUid) { if (pr.getWindowProcessController().areBackgroundFgsStartsAllowed()) { - ret = FGS_FEATURE_ALLOWED_BY_ACTIVITY_STARTER; - break; + return FGS_FEATURE_ALLOWED_BY_ACTIVITY_STARTER; } } + return null; + }); + if (allowedType != null) { + ret = allowedType; } } @@ -5501,46 +5532,37 @@ public final class ActiveServices { int ret = allowWhileInUse; final StringBuilder sb = new StringBuilder(64); - final int uidState = mAm.getUidState(callingUid); + final int uidState = mAm.getUidStateLocked(callingUid); if (ret == FGS_FEATURE_DENIED) { // Is the calling UID at PROCESS_STATE_TOP or above? - if (uidState <= ActivityManager.PROCESS_STATE_TOP) { + if (uidState <= PROCESS_STATE_TOP) { sb.append("uidState=").append(uidState); ret = FGS_FEATURE_ALLOWED_BY_UID_STATE; } } if (ret == FGS_FEATURE_DENIED) { - for (int i = mAm.mProcessList.mLruProcesses.size() - 1; i >= 0; i--) { - final ProcessRecord pr = mAm.mProcessList.mLruProcesses.get(i); - if (pr.uid == callingUid) { - if (pr.mAllowStartFgs != FGS_FEATURE_DENIED) { - ret = pr.mAllowStartFgs; - break; - } else if (pr.isAllowedStartFgsState()) { - ret = FGS_FEATURE_ALLOWED_BY_PROC_STATE; - break; - } - } - } - } - - if (ret == FGS_FEATURE_DENIED) { - for (int i = mAm.mProcessList.mLruProcesses.size() - 1; i >= 0; i--) { - final ProcessRecord pr = mAm.mProcessList.mLruProcesses.get(i); - if (pr.uid == callingUid) { - if (pr.areBackgroundFgsStartsAllowedByToken()) { - ret = FGS_FEATURE_ALLOWED_BY_FGS_BINDING; - break; + final Integer allowedType = mAm.mProcessList.searchEachLruProcessesLOSP(false, app -> { + if (app.uid == callingUid) { + final ProcessStateRecord state = app.mState; + if (state.getAllowedStartFgs() != FGS_FEATURE_DENIED) { + return state.getAllowedStartFgs(); + } else if (state.isAllowedStartFgsState()) { + return FGS_FEATURE_ALLOWED_BY_PROC_STATE; + } else if (state.areBackgroundFgsStartsAllowedByToken()) { + return FGS_FEATURE_ALLOWED_BY_FGS_BINDING; } else { - final ActiveInstrumentation instr = pr.getActiveInstrumentation(); + final ActiveInstrumentation instr = app.getActiveInstrumentation(); if (instr != null && instr.mHasBackgroundForegroundServiceStartsPermission) { - ret = FGS_FEATURE_ALLOWED_BY_INSTR_BACKGROUND_FGS_PERMISSION; - break; + return FGS_FEATURE_ALLOWED_BY_INSTR_BACKGROUND_FGS_PERMISSION; } } } + return null; + }); + if (allowedType != null) { + ret = allowedType; } } @@ -5559,7 +5581,7 @@ public final class ActiveServices { } if (ret == FGS_FEATURE_DENIED) { - if (mAm.isAllowlistedForFgsStartLocked(callingUid)) { + if (mAm.isAllowlistedForFgsStartLOSP(callingUid)) { // uid is on DeviceIdleController's user/system allowlist // or AMS's FgsStartTempAllowList. ret = FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST; diff --git a/services/core/java/com/android/server/am/ActiveUids.java b/services/core/java/com/android/server/am/ActiveUids.java index 27be53a5faf48..31db95b7d48ca 100644 --- a/services/core/java/com/android/server/am/ActiveUids.java +++ b/services/core/java/com/android/server/am/ActiveUids.java @@ -21,21 +21,29 @@ import android.os.UserHandle; import android.util.SparseArray; import android.util.proto.ProtoOutputStream; +import com.android.internal.annotations.CompositeRWLock; +import com.android.internal.annotations.GuardedBy; + import java.io.PrintWriter; /** Class for tracking active uids for running processes. */ final class ActiveUids { - private ActivityManagerService mService; + private final ActivityManagerService mService; + private final ActivityManagerGlobalLock mProcLock; - private boolean mPostChangesToAtm; + private final boolean mPostChangesToAtm; + + @CompositeRWLock({"mService", "mProcLock"}) private final SparseArray mActiveUids = new SparseArray<>(); ActiveUids(ActivityManagerService service, boolean postChangesToAtm) { mService = service; + mProcLock = service != null ? service.mProcLock : null; mPostChangesToAtm = postChangesToAtm; } + @GuardedBy({"mService", "mProcLock"}) void put(int uid, UidRecord value) { mActiveUids.put(uid, value); if (mPostChangesToAtm) { @@ -43,6 +51,7 @@ final class ActiveUids { } } + @GuardedBy({"mService", "mProcLock"}) void remove(int uid) { mActiveUids.remove(uid); if (mPostChangesToAtm) { @@ -50,38 +59,45 @@ final class ActiveUids { } } + @GuardedBy({"mService", "mProcLock"}) void clear() { mActiveUids.clear(); // It is only called for a temporal container with mPostChangesToAtm == false or test case. // So there is no need to notify activity task manager. } + @GuardedBy(anyOf = {"mService", "mProcLock"}) UidRecord get(int uid) { return mActiveUids.get(uid); } + @GuardedBy(anyOf = {"mService", "mProcLock"}) int size() { return mActiveUids.size(); } + @GuardedBy(anyOf = {"mService", "mProcLock"}) UidRecord valueAt(int index) { return mActiveUids.valueAt(index); } + @GuardedBy(anyOf = {"mService", "mProcLock"}) int keyAt(int index) { return mActiveUids.keyAt(index); } + @GuardedBy(anyOf = {"mService", "mProcLock"}) int indexOfKey(int uid) { return mActiveUids.indexOfKey(uid); } - boolean dump(PrintWriter pw, String dumpPackage, int dumpAppId, + @GuardedBy(anyOf = {"mService", "mProcLock"}) + boolean dump(final 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) { + if (dumpPackage != null && UserHandle.getAppId(uidRec.getUid()) != dumpAppId) { continue; } if (!printed) { @@ -91,16 +107,16 @@ final class ActiveUids { } pw.print(" "); pw.println(header); } - pw.print(" UID "); UserHandle.formatUid(pw, uidRec.uid); + pw.print(" UID "); UserHandle.formatUid(pw, uidRec.getUid()); pw.print(": "); pw.println(uidRec); - pw.print(" curProcState="); pw.print(uidRec.mCurProcState); + pw.print(" curProcState="); pw.print(uidRec.getCurProcState()); pw.print(" curCapability="); - ActivityManager.printCapabilitiesFull(pw, uidRec.curCapability); + ActivityManager.printCapabilitiesFull(pw, uidRec.getCurCapability()); pw.println(); - for (int j = uidRec.procRecords.size() - 1; j >= 0; j--) { + uidRec.forEachProcess(app -> { pw.print(" proc="); - pw.println(uidRec.procRecords.valueAt(j)); - } + pw.println(app); + }); } return printed; } @@ -108,7 +124,7 @@ final class ActiveUids { 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) { + if (dumpPackage != null && UserHandle.getAppId(uidRec.getUid()) != dumpAppId) { continue; } uidRec.dumpDebug(proto, fieldId); diff --git a/services/core/java/com/android/server/am/ActivityManagerGlobalLock.java b/services/core/java/com/android/server/am/ActivityManagerGlobalLock.java new file mode 100644 index 0000000000000..7823038fa37e5 --- /dev/null +++ b/services/core/java/com/android/server/am/ActivityManagerGlobalLock.java @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2021 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; + +/** + * Interface to mark whichever class with the implementation is considered as a global lock + * to be used in the package of ActivityManagerService. + */ +interface ActivityManagerGlobalLock { +} diff --git a/services/core/java/com/android/server/am/ActivityManagerProcLock.java b/services/core/java/com/android/server/am/ActivityManagerProcLock.java new file mode 100644 index 0000000000000..3ef19ad8290ee --- /dev/null +++ b/services/core/java/com/android/server/am/ActivityManagerProcLock.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2021 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; + +/** + * Class that is used to generate an instance of the {@link ActivityManagerService#mProcLock}, + * so the CPU booster can identify the critical section. + * + *

+ * Use "-Lpr" as the suffix of functions locked with this lock. + *

+ */ +final class ActivityManagerProcLock implements ActivityManagerGlobalLock { +} diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 8a8d487bdaee1..75d8cd2fc5d31 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -27,6 +27,7 @@ import static android.app.ActivityManager.INSTR_FLAG_DISABLE_HIDDEN_API_CHECKS; import static android.app.ActivityManager.INSTR_FLAG_DISABLE_ISOLATED_STORAGE; import static android.app.ActivityManager.INSTR_FLAG_DISABLE_TEST_API_CHECKS; import static android.app.ActivityManager.INSTR_FLAG_NO_RESTART; +import static android.app.ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND; import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT; import static android.app.ActivityManager.PROCESS_STATE_TOP; import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY; @@ -110,7 +111,6 @@ import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_NETWORK; import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_OOM_ADJ; import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_POWER; import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PROCESSES; -import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PROCESS_OBSERVERS; import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SERVICE; import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_UID_OBSERVERS; import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; @@ -295,6 +295,7 @@ import android.view.View; import android.view.WindowManager; import android.view.autofill.AutofillManagerInternal; +import com.android.internal.annotations.CompositeRWLock; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IAppOpsActiveCallback; @@ -397,7 +398,7 @@ import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicInteger; public class ActivityManagerService extends IActivityManager.Stub - implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback { + implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback, ActivityManagerGlobalLock { /** * Priority we boost main thread and RT of top app to. @@ -417,7 +418,6 @@ public class ActivityManagerService extends IActivityManager.Stub static final String TAG_NETWORK = TAG + POSTFIX_NETWORK; static final String TAG_OOM_ADJ = TAG + POSTFIX_OOM_ADJ; private static final String TAG_POWER = TAG + POSTFIX_POWER; - static final String TAG_PROCESS_OBSERVERS = TAG + POSTFIX_PROCESS_OBSERVERS; static final String TAG_PROCESSES = TAG + POSTFIX_PROCESSES; private static final String TAG_SERVICE = TAG + POSTFIX_SERVICE; private static final String TAG_SWITCH = TAG + POSTFIX_SWITCH; @@ -528,12 +528,55 @@ public class ActivityManagerService extends IActivityManager.Stub final InstrumentationReporter mInstrumentationReporter = new InstrumentationReporter(); + @CompositeRWLock({"this", "mProcLock"}) final ArrayList mActiveInstrumentation = new ArrayList<>(); public final IntentFirewall mIntentFirewall; public OomAdjProfiler mOomAdjProfiler = new OomAdjProfiler(); + /** + * The global lock for AMS, it's de-facto the ActivityManagerService object as of now. + */ + final ActivityManagerGlobalLock mGlobalLock = ActivityManagerService.this; + + /** + * Whether or not to enable the {@link #mProcLock}. If {@code false}, the {@link #mProcLock} + * will be equivalent to the {@link #mGlobalLock}. + */ + private static final boolean ENABLE_PROC_LOCK = true; + + /** + * The lock for process management. + * + *

+ * This lock is widely used in conjunction with the {@link #mGlobalLock} at present, + * where it'll require any of the locks to read from a data class, and both of the locks + * to write into that data class. + * + * For the naming convention of function suffixes: + *

    + *
  • -LOSP: Locked with any Of global am Service or Process lock
  • + *
  • -LSP: Locked with both of global am Service and Process lock
  • + *
  • -Locked: Locked with global am service lock alone
  • + *
  • -LPr: Locked with Process lock alone
  • + *
+ * For the simplicity, the getters/setters of the fields in data classes usually don't end with + * the above suffixes even if they're guarded by the locks here. + *

+ * + *

+ * In terms of locking order, it should be right below to the {@link #mGlobalLock}, + * and above everything else which used to be underneath the {@link #mGlobalLock}. + * As of today, the core components(services/providers/broadcasts) are still guarded by + * the {@link #mGlobalLock} alone, so be cautious, avoid from acquiring the {@link #mGlobalLock} + * while holding this lock. + *

+ * + */ + final ActivityManagerGlobalLock mProcLock = ENABLE_PROC_LOCK + ? new ActivityManagerProcLock() : mGlobalLock; + // Whether we should use SCHED_FIFO for UI and RenderThreads. final boolean mUseFifoUiScheduling; @@ -549,7 +592,10 @@ public class ActivityManagerService extends IActivityManager.Stub // so that dispatch of foreground broadcasts gets precedence. final BroadcastQueue[] mBroadcastQueues = new BroadcastQueue[3]; + @GuardedBy("this") BroadcastStats mLastBroadcastStats; + + @GuardedBy("this") BroadcastStats mCurBroadcastStats; BroadcastQueue broadcastQueueForIntent(Intent intent) { @@ -570,10 +616,11 @@ public class ActivityManagerService extends IActivityManager.Stub /** * The package name of the DeviceOwner. This package is not permitted to have its data cleared. + *

Not actually used

*/ - String mDeviceOwnerName; + private volatile String mDeviceOwnerName; - private int mDeviceOwnerUid = Process.INVALID_UID; + private volatile int mDeviceOwnerUid = Process.INVALID_UID; /** * Map userId to its companion app uids. @@ -644,6 +691,25 @@ public class ActivityManagerService extends IActivityManager.Stub sThreadPriorityBooster.reset(); } + private static ThreadPriorityBooster sProcThreadPriorityBooster = new ThreadPriorityBooster( + THREAD_PRIORITY_FOREGROUND, LockGuard.INDEX_PROC); + + static void boostPriorityForProcLockedSection() { + if (ENABLE_PROC_LOCK) { + sProcThreadPriorityBooster.boost(); + } else { + sThreadPriorityBooster.boost(); + } + } + + static void resetPriorityAfterProcLockedSection() { + if (ENABLE_PROC_LOCK) { + sProcThreadPriorityBooster.reset(); + } else { + sThreadPriorityBooster.reset(); + } + } + /** * Process management. */ @@ -664,20 +730,23 @@ public class ActivityManagerService extends IActivityManager.Stub /** * Non-persistent appId allowlist for background restrictions */ - int[] mBackgroundAppIdAllowlist = new int[] { + @CompositeRWLock({"this", "mProcLock"}) + private int[] mBackgroundAppIdAllowlist = new int[] { BLUETOOTH_UID }; /** * Broadcast actions that will always be deliverable to unlaunched/background apps */ - ArraySet mBackgroundLaunchBroadcasts; + @GuardedBy("this") + private ArraySet mBackgroundLaunchBroadcasts; /** * When an app has restrictions on the other apps that can have associations with it, * it appears here with a set of the allowed apps and also track debuggability of the app. */ - ArrayMap mAllowedAssociations; + @GuardedBy("this") + private ArrayMap mAllowedAssociations; /** * Tracks association information for a particular package along with debuggability. @@ -755,24 +824,24 @@ public class ActivityManagerService extends IActivityManager.Stub return mPidMap.indexOfKey(key); } - void doAddInternal(ProcessRecord app) { - mPidMap.put(app.pid, app); + void doAddInternal(int pid, ProcessRecord app) { + mPidMap.put(pid, app); } - boolean doRemoveInternal(ProcessRecord app) { - final ProcessRecord existingApp = mPidMap.get(app.pid); - if (existingApp != null && existingApp.startSeq == app.startSeq) { - mPidMap.remove(app.pid); + boolean doRemoveInternal(int pid, ProcessRecord app) { + final ProcessRecord existingApp = mPidMap.get(pid); + if (existingApp != null && existingApp.getStartSeq() == app.getStartSeq()) { + mPidMap.remove(pid); return true; } return false; } - boolean doRemoveIfNoThreadInternal(ProcessRecord app) { - if (app == null || app.thread != null) { + boolean doRemoveIfNoThreadInternal(int pid, ProcessRecord app) { + if (app == null || app.getThread() != null) { return false; } - return doRemoveInternal(app); + return doRemoveInternal(pid, app); } } @@ -783,18 +852,20 @@ public class ActivityManagerService extends IActivityManager.Stub *

NOTE: Callers should avoid acquiring the mPidsSelfLocked lock before calling this * method. */ + @GuardedBy("this") void addPidLocked(ProcessRecord app) { + final int pid = app.getPid(); synchronized (mPidsSelfLocked) { - mPidsSelfLocked.doAddInternal(app); + mPidsSelfLocked.doAddInternal(pid, app); } synchronized (sActiveProcessInfoSelfLocked) { if (app.processInfo != null) { - sActiveProcessInfoSelfLocked.put(app.pid, app.processInfo); + sActiveProcessInfoSelfLocked.put(pid, app.processInfo); } else { - sActiveProcessInfoSelfLocked.remove(app.pid); + sActiveProcessInfoSelfLocked.remove(pid); } } - mAtmInternal.onProcessMapped(app.pid, app.getWindowProcessController()); + mAtmInternal.onProcessMapped(pid, app.getWindowProcessController()); } /** @@ -802,16 +873,17 @@ public class ActivityManagerService extends IActivityManager.Stub *

NOTE: Callers should avoid acquiring the mPidsSelfLocked lock before calling this * method. */ - void removePidLocked(ProcessRecord app) { + @GuardedBy("this") + void removePidLocked(int pid, ProcessRecord app) { final boolean removed; synchronized (mPidsSelfLocked) { - removed = mPidsSelfLocked.doRemoveInternal(app); + removed = mPidsSelfLocked.doRemoveInternal(pid, app); } if (removed) { synchronized (sActiveProcessInfoSelfLocked) { - sActiveProcessInfoSelfLocked.remove(app.pid); + sActiveProcessInfoSelfLocked.remove(pid); } - mAtmInternal.onProcessUnMapped(app.pid); + mAtmInternal.onProcessUnMapped(pid); } } @@ -820,16 +892,18 @@ public class ActivityManagerService extends IActivityManager.Stub *

NOTE: Callers should avoid acquiring the mPidsSelfLocked lock before calling this * method. */ - boolean removePidIfNoThread(ProcessRecord app) { + @GuardedBy("this") + private boolean removePidIfNoThreadLocked(ProcessRecord app) { final boolean removed; + final int pid = app.getPid(); synchronized (mPidsSelfLocked) { - removed = mPidsSelfLocked.doRemoveIfNoThreadInternal(app); + removed = mPidsSelfLocked.doRemoveIfNoThreadInternal(pid, app); } if (removed) { synchronized (sActiveProcessInfoSelfLocked) { - sActiveProcessInfoSelfLocked.remove(app.pid); + sActiveProcessInfoSelfLocked.remove(pid); } - mAtmInternal.onProcessUnMapped(app.pid); + mAtmInternal.onProcessUnMapped(pid); } return removed; } @@ -866,6 +940,7 @@ public class ActivityManagerService extends IActivityManager.Stub proto.end(pToken); } } + @GuardedBy("this") final SparseArray mImportantProcesses = new SparseArray(); /** @@ -873,12 +948,14 @@ public class ActivityManagerService extends IActivityManager.Stub * system was ready. We don't start them at that point, but ensure they * are started by the time booting is complete. */ + @GuardedBy("this") final ArrayList mProcessesOnHold = new ArrayList(); /** * List of persistent applications that are in the process * of being started. */ + @GuardedBy("this") final ArrayList mPersistentStartingProcesses = new ArrayList(); private final ActivityMetricsLaunchObserver mActivityLaunchObserver = @@ -926,6 +1003,7 @@ public class ActivityManagerService extends IActivityManager.Stub * Keeps track of all IIntentReceivers that have been registered for broadcasts. * Hash keys are the receiver IBinder, hash value is a ReceiverList. */ + @GuardedBy("this") final HashMap mRegisteredReceivers = new HashMap<>(); /** @@ -978,6 +1056,7 @@ public class ActivityManagerService extends IActivityManager.Stub * by the user ID the sticky is for, and can include UserHandle.USER_ALL * for stickies that are sent to all users. */ + @GuardedBy("this") final SparseArray>> mStickyBroadcasts = new SparseArray>>(); @@ -1017,6 +1096,7 @@ public class ActivityManagerService extends IActivityManager.Stub * have seen. Mapping is target uid -> target component -> source uid -> source process name * -> association data. */ + @GuardedBy("this") final SparseArray>>> mAssociations = new SparseArray<>(); boolean mTrackingAssociations; @@ -1068,16 +1148,19 @@ public class ActivityManagerService extends IActivityManager.Stub /** * Power-save whitelisted app-ids (not including except-idle-whitelisted ones). */ + @CompositeRWLock({"this", "mProcLock"}) int[] mDeviceIdleAllowlist = new int[0]; /** * Power-save whitelisted app-ids (including except-idle-whitelisted ones). */ + @CompositeRWLock({"this", "mProcLock"}) int[] mDeviceIdleExceptIdleAllowlist = new int[0]; /** * Set of app ids that are temporarily allowed to escape bg check due to high-pri message */ + @CompositeRWLock({"this", "mProcLock"}) int[] mDeviceIdleTempAllowlist = new int[0]; static final class PendingTempAllowlist { @@ -1103,11 +1186,13 @@ public class ActivityManagerService extends IActivityManager.Stub } } + @CompositeRWLock({"this", "mProcLock"}) final PendingTempAllowlists mPendingTempAllowlist = new PendingTempAllowlists(this); /** * The temp-allowlist that is allowed to start FGS from background. */ + @CompositeRWLock({"this", "mProcLock"}) final FgsStartTempAllowList mFgsStartTempAllowList = new FgsStartTempAllowList(); /** @@ -1123,11 +1208,6 @@ public class ActivityManagerService extends IActivityManager.Stub ArrayMap mAppBindArgs; ArrayMap mIsolatedAppBindArgs; - /** - * Temporary to avoid allocations. Protected by main lock. - */ - final StringBuilder mStringBuilder = new StringBuilder(256); - volatile boolean mProcessesReady = false; volatile boolean mSystemReady = false; volatile boolean mOnBattery = false; @@ -1148,6 +1228,7 @@ public class ActivityManagerService extends IActivityManager.Stub /** * Last time (in uptime) at which we checked for power usage. */ + @GuardedBy("mProcLock") long mLastPowerCheckUptime; /** @@ -1163,10 +1244,14 @@ public class ActivityManagerService extends IActivityManager.Stub /** * The uptime of the last time we performed idle maintenance. */ + @GuardedBy("mProcLock") long mLastIdleTime = SystemClock.uptimeMillis(); /** * For reporting to battery stats the current top application. + * + *

It has its own lock to avoid from the need of double locking if using the global + * ActivityManagerService lock and proc lock to guard it.

*/ @GuardedBy("mCurResumedAppLock") private String mCurResumedPackage = null; @@ -1184,22 +1269,38 @@ public class ActivityManagerService extends IActivityManager.Stub * service. The ProcessMap is package/uid tuples; each of these contain * an array of the currently foreground processes. */ + @GuardedBy("this") final ProcessMap> mForegroundPackages = new ProcessMap>(); /** * Set if the systemServer made a call to enterSafeMode. */ + @GuardedBy("this") boolean mSafeMode; - String mDebugApp = null; - boolean mWaitForDebugger = false; - boolean mDebugTransient = false; - String mOrigDebugApp = null; - boolean mOrigWaitForDebugger = false; + @GuardedBy("this") + private String mDebugApp = null; + + @GuardedBy("this") + private boolean mWaitForDebugger = false; + + @GuardedBy("this") + private boolean mDebugTransient = false; + + @GuardedBy("this") + private String mOrigDebugApp = null; + + @GuardedBy("this") + private boolean mOrigWaitForDebugger = false; + + @GuardedBy("this") boolean mAlwaysFinishActivities = false; - String mTrackAllocationApp = null; + @GuardedBy("mProcLock") + private String mTrackAllocationApp = null; + + @GuardedBy("this") String mNativeDebuggingApp = null; final Injector mInjector; @@ -1344,10 +1445,12 @@ public class ActivityManagerService extends IActivityManager.Stub /** * Whether to force background check on all apps (for battery saver) or not. */ - boolean mForceBackgroundCheck; + @CompositeRWLock({"this", "mProcLock"}) + private boolean mForceBackgroundCheck; private static String sTheRealBuildSerial = Build.UNKNOWN; + @GuardedBy("mProcLock") private ParcelFileDescriptor[] mLifeMonitorFds; static final HostingRecord sNullHostingRecord = new HostingRecord(null); @@ -1369,6 +1472,7 @@ public class ActivityManagerService extends IActivityManager.Stub /** * The last time when the binder heavy hitter auto sampler started. */ + @GuardedBy("mProcLock") private long mLastBinderHeavyHitterAutoSamplerStart = 0L; final AppProfiler mAppProfiler; @@ -1406,19 +1510,19 @@ public class ActivityManagerService extends IActivityManager.Stub } break; case SHOW_STRICT_MODE_VIOLATION_UI_MSG: { HashMap data = (HashMap) msg.obj; - synchronized (ActivityManagerService.this) { + synchronized (mProcLock) { ProcessRecord proc = (ProcessRecord) data.get("app"); if (proc == null) { Slog.e(TAG, "App not found when showing strict mode dialog."); break; } - if (proc.getDialogController().hasViolationDialogs()) { + if (proc.mErrorState.getDialogController().hasViolationDialogs()) { Slog.e(TAG, "App already has strict mode dialog: " + proc); return; } AppErrorResult res = (AppErrorResult) data.get("result"); if (mAtmInternal.showStrictModeViolationDialog()) { - proc.getDialogController().showViolationDialogs(res); + proc.mErrorState.getDialogController().showViolationDialogs(res); } else { // The device is asleep, so just pretend that the user // saw a crash dialog and hit "force quit". @@ -1428,15 +1532,15 @@ public class ActivityManagerService extends IActivityManager.Stub ensureBootCompleted(); } break; case WAIT_FOR_DEBUGGER_UI_MSG: { - synchronized (ActivityManagerService.this) { + synchronized (mProcLock) { ProcessRecord app = (ProcessRecord) msg.obj; if (msg.arg1 != 0) { - if (!app.waitedForDebugger) { - app.getDialogController().showDebugWaitingDialogs(); - app.waitedForDebugger = true; + if (!app.hasWaitedForDebugger()) { + app.mErrorState.getDialogController().showDebugWaitingDialogs(); + app.setWaitedForDebugger(true); } } else { - app.getDialogController().clearWaitingDialog(); + app.mErrorState.getDialogController().clearWaitingDialog(); } } } break; @@ -1487,23 +1591,23 @@ public class ActivityManagerService extends IActivityManager.Stub msg.getData().getCharSequence(SERVICE_RECORD_KEY)); } break; case UPDATE_TIME_ZONE: { - synchronized (ActivityManagerService.this) { - for (int i = mProcessList.mLruProcesses.size() - 1; i >= 0; i--) { - ProcessRecord r = mProcessList.mLruProcesses.get(i); - if (r.thread != null) { + synchronized (mProcLock) { + mProcessList.forEachLruProcessesLOSP(false, app -> { + final IApplicationThread thread = app.getThread(); + if (thread != null) { try { - r.thread.updateTimeZone(); + thread.updateTimeZone(); } catch (RemoteException ex) { Slog.w(TAG, "Failed to update time zone for: " - + r.info.processName); + + app.info.processName); } - } + } + }); } - } } break; case CLEAR_DNS_CACHE_MSG: { - synchronized (ActivityManagerService.this) { - mProcessList.clearAllDnsCacheLocked(); + synchronized (mProcLock) { + mProcessList.clearAllDnsCacheLOSP(); } } break; case UPDATE_HTTP_PROXY_MSG: { @@ -1558,8 +1662,8 @@ public class ActivityManagerService extends IActivityManager.Stub case UPDATE_TIME_PREFERENCE_MSG: { // The user's time format preference might have changed. // For convenience we re-use the Intent extra values. - synchronized (ActivityManagerService.this) { - mProcessList.updateAllTimePrefsLocked(msg.arg1); + synchronized (mProcLock) { + mProcessList.updateAllTimePrefsLOSP(msg.arg1); } break; } @@ -1567,19 +1671,21 @@ public class ActivityManagerService extends IActivityManager.Stub final int uid = msg.arg1; final byte[] firstPacket = (byte[]) msg.obj; - synchronized (mPidsSelfLocked) { - for (int i = 0; i < mPidsSelfLocked.size(); i++) { - final ProcessRecord p = mPidsSelfLocked.valueAt(i); - if (p.uid == uid && p.thread != null) { - try { - p.thread.notifyCleartextNetwork(firstPacket); - } catch (RemoteException ignored) { + synchronized (mProcLock) { + synchronized (mPidsSelfLocked) { + for (int i = 0; i < mPidsSelfLocked.size(); i++) { + final ProcessRecord p = mPidsSelfLocked.valueAt(i); + final IApplicationThread thread = p.getThread(); + if (p.uid == uid && thread != null) { + try { + thread.notifyCleartextNetwork(firstPacket); + } catch (RemoteException ignored) { + } } } } } - break; - } + } break; case POST_DUMP_HEAP_NOTIFICATION_MSG: { mAppProfiler.handlePostDumpHeapNotification(); } break; @@ -1601,8 +1707,8 @@ public class ActivityManagerService extends IActivityManager.Stub idleUids(); } break; case HANDLE_TRUST_STORAGE_UPDATE_MSG: { - synchronized (ActivityManagerService.this) { - mProcessList.handleAllTrustStorageUpdateLocked(); + synchronized (mProcLock) { + mProcessList.handleAllTrustStorageUpdateLOSP(); } } break; case BINDER_HEAVYHITTER_AUTOSAMPLER_TIMEOUT_MSG: { @@ -1642,12 +1748,12 @@ public class ActivityManagerService extends IActivityManager.Stub 0, new HostingRecord("system")); app.setPersistent(true); - app.pid = MY_PID; + app.mPid = MY_PID; app.getWindowProcessController().setPid(MY_PID); - app.maxAdj = ProcessList.SYSTEM_ADJ; + app.mState.setMaxAdj(ProcessList.SYSTEM_ADJ); app.makeActive(mSystemThread.getApplicationThread(), mProcessStats); addPidLocked(app); - mProcessList.updateLruProcessLocked(app, false, null); + updateLruProcessLocked(app, false, null); updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE); } } catch (PackageManager.NameNotFoundException e) { @@ -2297,16 +2403,18 @@ public class ActivityManagerService extends IActivityManager.Stub if (code == SYSPROPS_TRANSACTION) { // We need to tell all apps about the system property change. ArrayList procs = new ArrayList(); - synchronized (this) { - final int NP = mProcessList.mProcessNames.getMap().size(); - for (int ip = 0; ip < NP; ip++) { - SparseArray apps = - mProcessList.mProcessNames.getMap().valueAt(ip); - final int NA = apps.size(); - for (int ia = 0; ia < NA; ia++) { + synchronized (mProcLock) { + final ArrayMap> pmap = + mProcessList.getProcessNamesLOSP().getMap(); + final int numOfNames = pmap.size(); + for (int ip = 0; ip < numOfNames; ip++) { + SparseArray apps = pmap.valueAt(ip); + final int numOfApps = apps.size(); + for (int ia = 0; ia < numOfApps; ia++) { ProcessRecord app = apps.valueAt(ia); - if (app.thread != null) { - procs.add(app.thread.asBinder()); + final IApplicationThread thread = app.getThread(); + if (thread != null) { + procs.add(thread.asBinder()); } } } @@ -2358,10 +2466,8 @@ public class ActivityManagerService extends IActivityManager.Stub // When plugging in, update the CPU stats first before changing // the plug state. updateCpuStatsNow(); - synchronized (this) { - synchronized(mPidsSelfLocked) { - mOnBattery = DEBUG_POWER ? true : onBattery; - } + synchronized (mProcLock) { + mOnBattery = DEBUG_POWER ? true : onBattery; mOomAdjProfiler.batteryPowerChanged(onBattery); } } @@ -2456,21 +2562,25 @@ public class ActivityManagerService extends IActivityManager.Stub mActivityTaskManager.unregisterTaskStackListener(listener); } + @GuardedBy("this") final void updateLruProcessLocked(ProcessRecord app, boolean activityChange, ProcessRecord client) { mProcessList.updateLruProcessLocked(app, activityChange, client); } + @GuardedBy("this") final void removeLruProcessLocked(ProcessRecord app) { mProcessList.removeLruProcessLocked(app); } + @GuardedBy("this") final ProcessRecord getProcessRecordLocked(String processName, int uid, boolean keepIfLarge) { return mProcessList.getProcessRecordLocked(processName, uid, keepIfLarge); } - final ProcessMap getProcessNames() { - return mProcessList.mProcessNames; + @GuardedBy(anyOf = {"this", "mProcLock"}) + final ProcessMap getProcessNamesLOSP() { + return mProcessList.getProcessNamesLOSP(); } void notifyPackageUse(String packageName, int reason) { @@ -2553,7 +2663,7 @@ public class ActivityManagerService extends IActivityManager.Stub if (mUsageStatsService != null) { mUsageStatsService.reportEvent(activity, userId, event, appToken.hashCode(), taskRoot); } - final ContentCaptureManagerInternal contentCaptureService = mContentCaptureService; + ContentCaptureManagerInternal contentCaptureService = mContentCaptureService; if (contentCaptureService != null && (event == Event.ACTIVITY_PAUSED || event == Event.ACTIVITY_RESUMED || event == Event.ACTIVITY_STOPPED || event == Event.ACTIVITY_DESTROYED)) { @@ -2627,19 +2737,18 @@ public class ActivityManagerService extends IActivityManager.Stub "getPackageProcessState"); } - int procState = PROCESS_STATE_NONEXISTENT; - synchronized (this) { - for (int i=mProcessList.mLruProcesses.size()-1; i>=0; i--) { - final ProcessRecord proc = mProcessList.mLruProcesses.get(i); - if (procState > proc.setProcState) { - if (proc.getPkgList().containsKey(packageName) - || (proc.pkgDeps != null && proc.pkgDeps.contains(packageName))) { - procState = proc.setProcState; + final int[] procState = {PROCESS_STATE_NONEXISTENT}; + synchronized (mProcLock) { + mProcessList.forEachLruProcessesLOSP(false, proc -> { + if (procState[0] > proc.mState.getSetProcState()) { + if (proc.getPkgList().containsKey(packageName) || (proc.getPkgDeps() != null + && proc.getPkgDeps().contains(packageName))) { + procState[0] = proc.mState.getSetProcState(); } } - } + }); } - return procState; + return procState[0]; } @Override @@ -2649,11 +2758,12 @@ public class ActivityManagerService extends IActivityManager.Stub throw new SecurityException("Only shell can call it"); } synchronized (this) { - final ProcessRecord app = findProcessLocked(process, userId, "setProcessMemoryTrimLevel"); + final ProcessRecord app = findProcessLOSP(process, userId, "setProcessMemoryTrimLevel"); if (app == null) { throw new IllegalArgumentException("Unknown process: " + process); } - if (app.thread == null) { + final IApplicationThread thread = app.getThread(); + if (thread == null) { throw new IllegalArgumentException("Process has no app thread"); } if (app.mProfile.getTrimMemoryLevel() >= level) { @@ -2661,12 +2771,14 @@ public class ActivityManagerService extends IActivityManager.Stub "Unable to set a higher trim level than current level"); } if (!(level < ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN || - app.getCurProcState() > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND)) { + app.mState.getCurProcState() > PROCESS_STATE_IMPORTANT_FOREGROUND)) { throw new IllegalArgumentException("Unable to set a background trim level " + "on a foreground process"); } - app.thread.scheduleTrimMemory(level); - app.mProfile.setTrimMemoryLevel(level); + thread.scheduleTrimMemory(level); + synchronized (mProcLock) { + app.mProfile.setTrimMemoryLevel(level); + } return true; } } @@ -2823,10 +2935,9 @@ public class ActivityManagerService extends IActivityManager.Stub * to the process. */ @GuardedBy("this") - final void handleAppDiedLocked(ProcessRecord app, + final void handleAppDiedLocked(ProcessRecord app, int pid, boolean restarting, boolean allowRestart) { - int pid = app.pid; - boolean kept = cleanUpApplicationRecordLocked(app, restarting, allowRestart, -1, + boolean kept = cleanUpApplicationRecordLocked(app, pid, restarting, allowRestart, -1, false /*replacingPid*/); if (!kept && !restarting) { removeLruProcessLocked(app); @@ -2846,24 +2957,26 @@ public class ActivityManagerService extends IActivityManager.Stub }); } - ProcessRecord getRecordForAppLocked(IApplicationThread thread) { + @GuardedBy(anyOf = {"this", "mProcLock"}) + ProcessRecord getRecordForAppLOSP(IApplicationThread thread) { if (thread == null) { return null; } - ProcessRecord record = mProcessList.getLRURecordForAppLocked(thread); + ProcessRecord record = mProcessList.getLRURecordForAppLOSP(thread); if (record != null) return record; // Validation: if it isn't in the LRU list, it shouldn't exist, but let's // double-check that. final IBinder threadBinder = thread.asBinder(); final ArrayMap> pmap = - mProcessList.mProcessNames.getMap(); + mProcessList.getProcessNamesLOSP().getMap(); for (int i = pmap.size()-1; i >= 0; i--) { final SparseArray procs = pmap.valueAt(i); for (int j = procs.size()-1; j >= 0; j--) { final ProcessRecord proc = procs.valueAt(j); - if (proc.thread != null && proc.thread.asBinder() == threadBinder) { + final IApplicationThread procThread = proc.getThread(); + if (procThread != null && procThread.asBinder() == threadBinder) { Slog.wtf(TAG, "getRecordForApp: exists in name list but not in LRU list: " + proc); return proc; @@ -2876,7 +2989,7 @@ public class ActivityManagerService extends IActivityManager.Stub @GuardedBy("this") final void appDiedLocked(ProcessRecord app, String reason) { - appDiedLocked(app, app.pid, app.thread, false, reason); + appDiedLocked(app, app.getPid(), app.getThread(), false, reason); } @GuardedBy("this") @@ -2893,26 +3006,31 @@ public class ActivityManagerService extends IActivityManager.Stub mBatteryStatsService.noteProcessDied(app.info.uid, pid); - if (!app.killed) { + if (!app.isKilled()) { if (!fromBinderDied) { killProcessQuiet(pid); mProcessList.noteAppKill(app, ApplicationExitInfo.REASON_OTHER, ApplicationExitInfo.SUBREASON_UNKNOWN, reason); } ProcessList.killProcessGroup(app.uid, pid); - app.killed = true; + synchronized (mProcLock) { + app.setKilled(true); + } } // Clean up already done if the process has been re-started. - if (app.pid == pid && app.thread != null && - app.thread.asBinder() == thread.asBinder()) { + IApplicationThread appThread; + final int setAdj = app.mState.getSetAdj(); + final int setProcState = app.mState.getSetProcState(); + if (app.getPid() == pid && (appThread = app.getThread()) != null + && appThread.asBinder() == thread.asBinder()) { boolean doLowMem = app.getActiveInstrumentation() == null; boolean doOomAdj = doLowMem; - if (!app.killedByAm) { + if (!app.isKilledByAm()) { reportUidInfoMessageLocked(TAG, "Process " + app.processName + " (pid " + pid + ") has died: " - + ProcessList.makeOomAdjString(app.setAdj, true) + " " - + ProcessList.makeProcStateString(app.setProcState), app.info.uid); + + ProcessList.makeOomAdjString(setAdj, true) + " " + + ProcessList.makeProcStateString(setProcState), app.info.uid); mAppProfiler.setAllowLowerMemLevelLocked(true); } else { // Note that we always want to do oom adj to update our state with the @@ -2920,11 +3038,10 @@ public class ActivityManagerService extends IActivityManager.Stub mAppProfiler.setAllowLowerMemLevelLocked(false); doLowMem = false; } - EventLogTags.writeAmProcDied(app.userId, app.pid, app.processName, app.setAdj, - app.setProcState); + EventLogTags.writeAmProcDied(app.userId, pid, app.processName, setAdj, setProcState); if (DEBUG_CLEANUP) Slog.v(TAG_CLEANUP, "Dying app: " + app + ", pid: " + pid + ", thread: " + thread.asBinder()); - handleAppDiedLocked(app, false, true); + handleAppDiedLocked(app, pid, false, true); if (doOomAdj) { updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_PROCESS_END); @@ -2932,14 +3049,14 @@ public class ActivityManagerService extends IActivityManager.Stub if (doLowMem) { mAppProfiler.doLowMemReportIfNeededLocked(app); } - } else if (app.pid != pid) { + } else if (app.getPid() != pid) { // A new process has already been started. reportUidInfoMessageLocked(TAG, "Process " + app.processName + " (pid " + pid - + ") has died and restarted (pid " + app.pid + ").", app.info.uid); + + ") has died and restarted (pid " + app.getPid() + ").", app.info.uid); - EventLogTags.writeAmProcDied(app.userId, app.pid, app.processName, app.setAdj, - app.setProcState); + EventLogTags.writeAmProcDied(app.userId, app.getPid(), app.processName, + setAdj, setProcState); } else if (DEBUG_PROCESSES) { Slog.d(TAG_PROCESSES, "Received spurious death notification for thread " + thread.asBinder()); @@ -3387,9 +3504,11 @@ public class ActivityManagerService extends IActivityManager.Stub return; } synchronized (this) { - mProcessList.killPackageProcessesLocked(packageName, appId, targetUserId, - ProcessList.SERVICE_ADJ, ApplicationExitInfo.REASON_USER_REQUESTED, - ApplicationExitInfo.SUBREASON_UNKNOWN, "kill background"); + synchronized (mProcLock) { + mProcessList.killPackageProcessesLSP(packageName, appId, targetUserId, + ProcessList.SERVICE_ADJ, ApplicationExitInfo.REASON_USER_REQUESTED, + ApplicationExitInfo.SUBREASON_UNKNOWN, "kill background"); + } } } } finally { @@ -3414,11 +3533,13 @@ public class ActivityManagerService extends IActivityManager.Stub // Allow memory level to go down (the flag needs to be set before updating oom adj) // because this method is also used to simulate low memory. mAppProfiler.setAllowLowerMemLevelLocked(true); - mProcessList.killPackageProcessesLocked(null /* packageName */, -1 /* appId */, - UserHandle.USER_ALL, ProcessList.CACHED_APP_MIN_ADJ, - ApplicationExitInfo.REASON_USER_REQUESTED, - ApplicationExitInfo.SUBREASON_UNKNOWN, - "kill all background"); + synchronized (mProcLock) { + mProcessList.killPackageProcessesLSP(null /* packageName */, -1 /* appId */, + UserHandle.USER_ALL, ProcessList.CACHED_APP_MIN_ADJ, + ApplicationExitInfo.REASON_USER_REQUESTED, + ApplicationExitInfo.SUBREASON_UNKNOWN, + "kill all background"); + } mAppProfiler.doLowMemReportIfNeededLocked(null); } @@ -3449,7 +3570,9 @@ public class ActivityManagerService extends IActivityManager.Stub final long callingId = Binder.clearCallingIdentity(); try { synchronized (this) { - mProcessList.killAllBackgroundProcessesExceptLocked(minTargetSdk, maxProcState); + synchronized (mProcLock) { + mProcessList.killAllBackgroundProcessesExceptLSP(minTargetSdk, maxProcState); + } } } finally { Binder.restoreCallingIdentity(callingId); @@ -3524,11 +3647,14 @@ public class ActivityManagerService extends IActivityManager.Stub proc = mPidsSelfLocked.get(Binder.getCallingPid()); } if (proc != null) { + ArraySet pkgDeps = proc.getPkgDeps(); synchronized (this) { - if (proc.pkgDeps == null) { - proc.pkgDeps = new ArraySet(1); + synchronized (mProcLock) { + if (pkgDeps == null) { + proc.setPkgDeps(pkgDeps = new ArraySet(1)); + } + pkgDeps.add(packageName); } - proc.pkgDeps.add(packageName); } } } @@ -3588,12 +3714,14 @@ public class ActivityManagerService extends IActivityManager.Stub // Check if the caller is actually instrumented and from shell, if it's true, we may lift // the throttle of PSS info sampling. boolean isCallerInstrumentedFromShell = false; - synchronized (mPidsSelfLocked) { - ProcessRecord caller = mPidsSelfLocked.get(callingPid); - if (caller != null) { - final ActiveInstrumentation instr = caller.getActiveInstrumentation(); - isCallerInstrumentedFromShell = instr != null - && (instr.mSourceUid == SHELL_UID || instr.mSourceUid == ROOT_UID); + synchronized (mProcLock) { + synchronized (mPidsSelfLocked) { + ProcessRecord caller = mPidsSelfLocked.get(callingPid); + if (caller != null) { + final ActiveInstrumentation instr = caller.getActiveInstrumentation(); + isCallerInstrumentedFromShell = instr != null + && (instr.mSourceUid == SHELL_UID || instr.mSourceUid == ROOT_UID); + } } } @@ -3688,10 +3816,10 @@ public class ActivityManagerService extends IActivityManager.Stub for (int i=pids.length-1; i>=0; i--) { ProcessRecord proc; int oomAdj; - synchronized (this) { + synchronized (mProcLock) { synchronized (mPidsSelfLocked) { proc = mPidsSelfLocked.get(pids[i]); - oomAdj = proc != null ? proc.setAdj : 0; + oomAdj = proc != null ? proc.mState.getSetAdj() : 0; } } if (!allUids || (!allUsers && UserHandle.getUserId(proc.uid) != userId)) { @@ -3740,9 +3868,10 @@ public class ActivityManagerService extends IActivityManager.Stub if (callerUid == SYSTEM_UID) { synchronized (this) { ProcessRecord app = getProcessRecordLocked(processName, uid, true); - if (app != null && app.thread != null) { + IApplicationThread thread; + if (app != null && (thread = app.getThread()) != null) { try { - app.thread.scheduleSuicide(); + thread.scheduleSuicide(); } catch (RemoteException e) { // If the other end already died, then our work here is done. } @@ -3904,6 +4033,7 @@ public class ActivityManagerService extends IActivityManager.Stub } } + boolean didSomething; if (doit) { if (packageName != null) { Slog.i(TAG, "Force stopping " + packageName + " appid=" + appId @@ -3915,20 +4045,22 @@ public class ActivityManagerService extends IActivityManager.Stub mAppErrors.resetProcessCrashTime(packageName == null, appId, userId); } - // Notify first that the package is stopped, so its process won't be restarted unexpectedly - // if there is an activity of the package without attached process becomes visible when - // killing its other processes with visible activities. - boolean didSomething = - mAtmInternal.onForceStopPackage(packageName, doit, evenPersistent, userId); + synchronized (mProcLock) { + // Notify first that the package is stopped, so its process won't be restarted + // unexpectedly if there is an activity of the package without attached process + // becomes visible when killing its other processes with visible activities. + didSomething = mAtmInternal.onForceStopPackage( + packageName, doit, evenPersistent, userId); - didSomething |= mProcessList.killPackageProcessesLocked(packageName, appId, userId, - ProcessList.INVALID_ADJ, callerWillRestart, false /* allowRestart */, doit, - evenPersistent, true /* setRemoved */, - packageName == null ? ApplicationExitInfo.REASON_USER_STOPPED - : ApplicationExitInfo.REASON_USER_REQUESTED, - ApplicationExitInfo.SUBREASON_UNKNOWN, - (packageName == null ? ("stop user " + userId) : ("stop " + packageName)) - + " due to " + reason); + didSomething |= mProcessList.killPackageProcessesLSP(packageName, appId, userId, + ProcessList.INVALID_ADJ, callerWillRestart, false /* allowRestart */, doit, + evenPersistent, true /* setRemoved */, + packageName == null ? ApplicationExitInfo.REASON_USER_STOPPED + : ApplicationExitInfo.REASON_USER_REQUESTED, + ApplicationExitInfo.SUBREASON_UNKNOWN, + (packageName == null ? ("stop user " + userId) : ("stop " + packageName)) + + " due to " + reason); + } if (mServices.bringDownDisabledPackageServicesLocked( packageName, null /* filterByClasses */, userId, evenPersistent, doit)) { @@ -3987,26 +4119,29 @@ public class ActivityManagerService extends IActivityManager.Stub @GuardedBy("this") private final void processStartTimedOutLocked(ProcessRecord app) { - final int pid = app.pid; - boolean gone = removePidIfNoThread(app); + final int pid = app.getPid(); + boolean gone = removePidIfNoThreadLocked(app); if (gone) { Slog.w(TAG, "Process " + app + " failed to attach"); EventLogTags.writeAmProcessStartTimeout(app.userId, pid, app.uid, app.processName); - mProcessList.removeProcessNameLocked(app.processName, app.uid); - mAtmInternal.clearHeavyWeightProcessIfEquals(app.getWindowProcessController()); - mBatteryStatsService.noteProcessFinish(app.processName, app.info.uid); - // Take care of any launching providers waiting for this process. - mCpHelper.cleanupAppInLaunchingProvidersLocked(app, true); - // Take care of any services that are waiting for the process. - mServices.processStartTimedOutLocked(app); - app.kill("start timeout", ApplicationExitInfo.REASON_INITIALIZATION_FAILURE, true); - if (app.isolated) { - mBatteryStatsService.removeIsolatedUid(app.uid, app.info.uid); + synchronized (mProcLock) { + mProcessList.removeProcessNameLocked(app.processName, app.uid); + mAtmInternal.clearHeavyWeightProcessIfEquals(app.getWindowProcessController()); + mBatteryStatsService.noteProcessFinish(app.processName, app.info.uid); + // Take care of any launching providers waiting for this process. + mCpHelper.cleanupAppInLaunchingProvidersLocked(app, true); + // Take care of any services that are waiting for the process. + mServices.processStartTimedOutLocked(app); + app.killLocked("start timeout", ApplicationExitInfo.REASON_INITIALIZATION_FAILURE, + true); + if (app.isolated) { + mBatteryStatsService.removeIsolatedUid(app.uid, app.info.uid); + } + removeLruProcessLocked(app); } - removeLruProcessLocked(app); final BackupRecord backupTarget = mBackupTargets.get(app.userId); - if (backupTarget != null && backupTarget.app.pid == pid) { + if (backupTarget != null && backupTarget.app.getPid() == pid) { Slog.w(TAG, "Unattached app died before backup, skipping"); mHandler.post(new Runnable() { @Override @@ -4044,7 +4179,7 @@ public class ActivityManagerService extends IActivityManager.Stub synchronized (mPidsSelfLocked) { app = mPidsSelfLocked.get(pid); } - if (app != null && (app.startUid != callingUid || app.startSeq != startSeq)) { + if (app != null && (app.getStartUid() != callingUid || app.getStartSeq() != startSeq)) { String processName = null; final ProcessRecord pending = mProcessList.mPendingStarts.get(startSeq); if (pending != null) { @@ -4054,14 +4189,14 @@ public class ActivityManagerService extends IActivityManager.Stub + " startSeq:" + startSeq + " pid:" + pid + " belongs to another existing app:" + app.processName - + " startSeq:" + app.startSeq; + + " startSeq:" + app.getStartSeq(); Slog.wtf(TAG, msg); // SafetyNet logging for b/131105245. - EventLog.writeEvent(0x534e4554, "131105245", app.startUid, msg); + EventLog.writeEvent(0x534e4554, "131105245", app.getStartUid(), msg); // If there is already an app occupying that pid that hasn't been cleaned up - cleanUpApplicationRecordLocked(app, false, false, -1, - true /*replacingPid*/); - removePidLocked(app); + cleanUpApplicationRecordLocked(app, pid, false, false, -1, + true /*replacingPid*/); + removePidLocked(pid, app); app = null; } } else { @@ -4072,10 +4207,10 @@ public class ActivityManagerService extends IActivityManager.Stub // update the internal state. if (app == null && startSeq > 0) { final ProcessRecord pending = mProcessList.mPendingStarts.get(startSeq); - if (pending != null && pending.startUid == callingUid && pending.startSeq == startSeq - && mProcessList.handleProcessStartedLocked(pending, pid, pending - .isUsingWrapper(), - startSeq, true)) { + if (pending != null && pending.getStartUid() == callingUid + && pending.getStartSeq() == startSeq + && mProcessList.handleProcessStartedLocked(pending, pid, + pending.isUsingWrapper(), startSeq, true)) { app = pending; } } @@ -4101,8 +4236,8 @@ public class ActivityManagerService extends IActivityManager.Stub // If this application record is still attached to a previous // process, clean it up now. - if (app.thread != null) { - handleAppDiedLocked(app, true, true); + if (app.getThread() != null) { + handleAppDiedLocked(app, pid, true, true); } // Tell the process all about itself. @@ -4115,7 +4250,7 @@ public class ActivityManagerService extends IActivityManager.Stub AppDeathRecipient adr = new AppDeathRecipient( app, pid, thread); thread.asBinder().linkToDeath(adr, 0); - app.deathRecipient = adr; + app.setDeathRecipient(adr); } catch (RemoteException e) { app.resetPackageList(mProcessStats); mProcessList.startProcessLocked(app, @@ -4124,23 +4259,25 @@ public class ActivityManagerService extends IActivityManager.Stub return false; } - EventLogTags.writeAmProcBound(app.userId, app.pid, app.processName); + EventLogTags.writeAmProcBound(app.userId, pid, app.processName); - app.curAdj = app.setAdj = app.verifiedAdj = ProcessList.INVALID_ADJ; - mOomAdjuster.setAttachingSchedGroupLocked(app); - app.forcingToImportant = null; - updateProcessForegroundLocked(app, false, 0, false); - app.hasShownUi = false; - app.setDebugging(false); - app.setCached(false); - app.killedByAm = false; - app.killed = false; - - - // We carefully use the same state that PackageManager uses for - // filtering, since we use this flag to decide if we need to install - // providers when user is unlocked later - app.unlocked = StorageManager.isUserKeyUnlocked(app.userId); + synchronized (mProcLock) { + app.mState.setCurAdj(ProcessList.INVALID_ADJ); + app.mState.setSetAdj(ProcessList.INVALID_ADJ); + app.mState.setVerifiedAdj(ProcessList.INVALID_ADJ); + mOomAdjuster.setAttachingSchedGroupLSP(app); + app.mState.setForcingToImportant(null); + updateProcessForegroundLocked(app, false, 0, false); + app.mState.setHasShownUi(false); + app.mState.setCached(false); + app.setDebugging(false); + app.setKilledByAm(false); + app.setKilled(false); + // We carefully use the same state that PackageManager uses for + // filtering, since we use this flag to decide if we need to install + // providers when user is unlocked later + app.setUnlocked(StorageManager.isUserKeyUnlocked(app.userId)); + } mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app); @@ -4180,9 +4317,11 @@ public class ActivityManagerService extends IActivityManager.Stub } boolean enableTrackAllocation = false; - if (mTrackAllocationApp != null && mTrackAllocationApp.equals(processName)) { - enableTrackAllocation = true; - mTrackAllocationApp = null; + synchronized (mProcLock) { + if (mTrackAllocationApp != null && mTrackAllocationApp.equals(processName)) { + enableTrackAllocation = true; + mTrackAllocationApp = null; + } } // If the app is being launched for restore or full backup, set it up specially @@ -4203,7 +4342,7 @@ public class ActivityManagerService extends IActivityManager.Stub ProtoLog.v(WM_DEBUG_CONFIGURATION, "Binding proc %s with config %s", processName, app.getWindowProcessController().getConfiguration()); ApplicationInfo appInfo = instr != null ? instr.mTargetInfo : app.info; - app.compat = compatibilityInfoForPackage(appInfo); + app.setCompat(compatibilityInfoForPackage(appInfo)); ProfilerInfo profilerInfo = mAppProfiler.setupProfilerInfoLocked(thread, app, instr); @@ -4247,10 +4386,11 @@ public class ActivityManagerService extends IActivityManager.Stub mPlatformCompat.resetReporting(app.info); } final ProviderInfoList providerList = ProviderInfoList.fromList(providers); - if (app.isolatedEntryPoint != null) { + if (app.getIsolatedEntryPoint() != null) { // This is an isolated process which should just call an entry point instead of // being bound to an application. - thread.runIsolatedEntryPoint(app.isolatedEntryPoint, app.isolatedEntryPointArgs); + thread.runIsolatedEntryPoint( + app.getIsolatedEntryPoint(), app.getIsolatedEntryPointArgs()); } else if (instr2 != null) { thread.bindApplication(processName, appInfo, providerList, instr2.mClass, @@ -4260,20 +4400,20 @@ public class ActivityManagerService extends IActivityManager.Stub mBinderTransactionTrackingEnabled, enableTrackAllocation, isRestrictedBackupMode || !normalMode, app.isPersistent(), new Configuration(app.getWindowProcessController().getConfiguration()), - app.compat, getCommonServicesLocked(app.isolated), + app.getCompat(), getCommonServicesLocked(app.isolated), mCoreSettingsObserver.getCoreSettingsLocked(), buildSerial, autofillOptions, contentCaptureOptions, - app.mDisabledCompatChanges, serializedSystemFontMap); + app.getDisabledCompatChanges(), serializedSystemFontMap); } else { thread.bindApplication(processName, appInfo, providerList, null, profilerInfo, null, null, null, testMode, mBinderTransactionTrackingEnabled, enableTrackAllocation, isRestrictedBackupMode || !normalMode, app.isPersistent(), new Configuration(app.getWindowProcessController().getConfiguration()), - app.compat, getCommonServicesLocked(app.isolated), + app.getCompat(), getCommonServicesLocked(app.isolated), mCoreSettingsObserver.getCoreSettingsLocked(), buildSerial, autofillOptions, contentCaptureOptions, - app.mDisabledCompatChanges, serializedSystemFontMap); + app.getDisabledCompatChanges(), serializedSystemFontMap); } if (profilerInfo != null) { profilerInfo.closeFd(); @@ -4282,9 +4422,11 @@ public class ActivityManagerService extends IActivityManager.Stub // Make app active after binding application or client may be running requests (e.g // starting activities) before it is ready. - app.makeActive(thread, mProcessStats); - checkTime(startTime, "attachApplicationLocked: immediately after bindApplication"); - mProcessList.updateLruProcessLocked(app, false, null); + synchronized (mProcLock) { + app.makeActive(thread, mProcessStats); + checkTime(startTime, "attachApplicationLocked: immediately after bindApplication"); + } + updateLruProcessLocked(app, false, null); checkTime(startTime, "attachApplicationLocked: after updateLruProcessLocked"); final long now = SystemClock.uptimeMillis(); synchronized (mAppProfiler.mProfilerLock) { @@ -4296,8 +4438,9 @@ public class ActivityManagerService extends IActivityManager.Stub Slog.wtf(TAG, "Exception thrown during bind of " + app, e); app.resetPackageList(mProcessStats); app.unlinkDeathRecipient(); - app.kill("error during bind", ApplicationExitInfo.REASON_INITIALIZATION_FAILURE, true); - handleAppDiedLocked(app, false, true); + app.killLocked("error during bind", ApplicationExitInfo.REASON_INITIALIZATION_FAILURE, + true); + handleAppDiedLocked(app, pid, false, true); return false; } @@ -4360,8 +4503,9 @@ public class ActivityManagerService extends IActivityManager.Stub } if (badApp) { - app.kill("error during init", ApplicationExitInfo.REASON_INITIALIZATION_FAILURE, true); - handleAppDiedLocked(app, false, true); + app.killLocked("error during init", ApplicationExitInfo.REASON_INITIALIZATION_FAILURE, + true); + handleAppDiedLocked(app, pid, false, true); return false; } @@ -4373,14 +4517,14 @@ public class ActivityManagerService extends IActivityManager.Stub FrameworkStatsLog.write( FrameworkStatsLog.PROCESS_START_TIME, app.info.uid, - app.pid, + pid, app.info.packageName, FrameworkStatsLog.PROCESS_START_TIME__TYPE__COLD, - app.startTime, - (int) (bindApplicationTimeMillis - app.startTime), - (int) (SystemClock.elapsedRealtime() - app.startTime), - app.hostingRecord.getType(), - (app.hostingRecord.getName() != null ? app.hostingRecord.getName() : "")); + app.getStartTime(), + (int) (bindApplicationTimeMillis - app.getStartTime()), + (int) (SystemClock.elapsedRealtime() - app.getStartTime()), + app.getHostingRecord().getType(), + (app.getHostingRecord().getName() != null ? app.getHostingRecord().getName() : "")); return true; } @@ -4473,11 +4617,11 @@ public class ActivityManagerService extends IActivityManager.Stub // up. final int NP = mProcessesOnHold.size(); if (NP > 0) { - ArrayList procs = - new ArrayList(mProcessesOnHold); - for (int ip=0; ip procs = new ArrayList(mProcessesOnHold); + for (int ip = 0; ip < NP; ip++) { + if (DEBUG_PROCESSES) { + Slog.v(TAG_PROCESSES, "Starting process on hold: " + procs.get(ip)); + } mProcessList.startProcessLocked(procs.get(ip), new HostingRecord("on-hold"), ZYGOTE_POLICY_FLAG_BATCH_LAUNCH); @@ -4509,8 +4653,8 @@ public class ActivityManagerService extends IActivityManager.Stub public void performReceive(Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky, int sendingUser) { - synchronized (ActivityManagerService.this) { - mAppProfiler.requestPssAllProcsLocked( + synchronized (mProcLock) { + mAppProfiler.requestPssAllProcsLPr( SystemClock.uptimeMillis(), true, false); } } @@ -4945,7 +5089,7 @@ public class ActivityManagerService extends IActivityManager.Stub if (pr == null) { return; } - pr.forcingToImportant = null; + pr.mState.setForcingToImportant(null); updateProcessForegroundLocked(pr, false, 0, false); } updateOomAdjLocked(pr, OomAdjuster.OOM_ADJ_REASON_UI_VISIBILITY); @@ -4971,7 +5115,7 @@ public class ActivityManagerService extends IActivityManager.Stub oldToken.token.unlinkToDeath(oldToken, 0); mImportantProcesses.remove(pid); if (pr != null) { - pr.forcingToImportant = null; + pr.mState.setForcingToImportant(null); } changed = true; } @@ -4985,7 +5129,7 @@ public class ActivityManagerService extends IActivityManager.Stub try { token.linkToDeath(newToken, 0); mImportantProcesses.put(pid, newToken); - pr.forcingToImportant = newToken; + pr.mState.setForcingToImportant(newToken); changed = true; } catch (RemoteException e) { // If the process died while doing this, we will later @@ -5001,13 +5145,12 @@ public class ActivityManagerService extends IActivityManager.Stub } private boolean isAppForeground(int uid) { - synchronized (this) { + synchronized (mProcLock) { UidRecord uidRec = mProcessList.mActiveUids.get(uid); - if (uidRec == null || uidRec.idle) { + if (uidRec == null || uidRec.isIdle()) { return false; } - return uidRec.getCurProcState() - <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND; + return uidRec.getCurProcState() <= PROCESS_STATE_IMPORTANT_FOREGROUND; } } @@ -5018,11 +5161,16 @@ public class ActivityManagerService extends IActivityManager.Stub // NOTE: this is an internal method used by the OnShellCommand implementation only and should // be guarded by permission checking. int getUidState(int uid) { - synchronized (this) { - return mProcessList.getUidProcStateLocked(uid); + synchronized (mProcLock) { + return mProcessList.getUidProcStateLOSP(uid); } } + @GuardedBy("this") + int getUidStateLocked(int uid) { + return mProcessList.getUidProcStateLOSP(uid); + } + // ========================================================= // PROCESS INFO // ========================================================= @@ -5071,20 +5219,23 @@ public class ActivityManagerService extends IActivityManager.Stub throw new IllegalArgumentException("pids and scores arrays have different lengths!"); } - synchronized (mPidsSelfLocked) { - for (int i = 0; i < pids.length; i++) { - ProcessRecord pr = mPidsSelfLocked.get(pids[i]); - if (pr != null) { - final boolean isPendingTop = + synchronized (mProcLock) { + synchronized (mPidsSelfLocked) { + for (int i = 0; i < pids.length; i++) { + ProcessRecord pr = mPidsSelfLocked.get(pids[i]); + if (pr != null) { + final boolean isPendingTop = mPendingStartActivityUids.isPendingTopPid(pr.uid, pids[i]); - states[i] = isPendingTop ? PROCESS_STATE_TOP : pr.getCurProcState(); - if (scores != null) { - scores[i] = isPendingTop ? (ProcessList.FOREGROUND_APP_ADJ - 1) : pr.curAdj; - } - } else { - states[i] = PROCESS_STATE_NONEXISTENT; - if (scores != null) { - scores[i] = ProcessList.INVALID_ADJ; + states[i] = isPendingTop ? PROCESS_STATE_TOP : pr.mState.getCurProcState(); + if (scores != null) { + scores[i] = isPendingTop + ? (ProcessList.FOREGROUND_APP_ADJ - 1) : pr.mState.getCurAdj(); + } + } else { + states[i] = PROCESS_STATE_NONEXISTENT; + if (scores != null) { + scores[i] = ProcessList.INVALID_ADJ; + } } } } @@ -5262,8 +5413,8 @@ public class ActivityManagerService extends IActivityManager.Stub } public boolean isAppStartModeDisabled(int uid, String packageName) { - synchronized (this) { - return getAppStartModeLocked(uid, packageName, 0, -1, false, true, false) + synchronized (mProcLock) { + return getAppStartModeLOSP(uid, packageName, 0, -1, false, true, false) == ActivityManager.APP_START_MODE_DISABLED; } } @@ -5274,7 +5425,8 @@ public class ActivityManagerService extends IActivityManager.Stub } // Unified app-op and target sdk check - int appRestrictedInBackgroundLocked(int uid, String packageName, int packageTargetSdk) { + @GuardedBy(anyOf = {"this", "mProcLock"}) + int appRestrictedInBackgroundLOSP(int uid, String packageName, int packageTargetSdk) { // Apps that target O+ are always subject to background check if (packageTargetSdk >= Build.VERSION_CODES.O) { if (DEBUG_BACKGROUND_CHECK) { @@ -5303,7 +5455,7 @@ public class ActivityManagerService extends IActivityManager.Stub // If force-background-check is enabled, restrict all apps that aren't whitelisted. if (mForceBackgroundCheck && !UserHandle.isCore(uid) && - !isOnDeviceIdleAllowlistLocked(uid, /*allowExceptIdleToo=*/ true)) { + !isOnDeviceIdleAllowlistLOSP(uid, /*allowExceptIdleToo=*/ true)) { if (DEBUG_BACKGROUND_CHECK) { Slog.i(TAG, "Force background check: " + uid + "/" + packageName + " restricted"); @@ -5321,7 +5473,8 @@ public class ActivityManagerService extends IActivityManager.Stub // Service launch is available to apps with run-in-background exemptions but // some other background operations are not. If we're doing a check // of service-launch policy, allow those callers to proceed unrestricted. - int appServicesRestrictedInBackgroundLocked(int uid, String packageName, int packageTargetSdk) { + @GuardedBy(anyOf = {"this", "mProcLock"}) + int appServicesRestrictedInBackgroundLOSP(int uid, String packageName, int packageTargetSdk) { // Persistent app? if (mPackageManagerInt.isPackagePersistent(packageName)) { if (DEBUG_BACKGROUND_CHECK) { @@ -5332,7 +5485,7 @@ public class ActivityManagerService extends IActivityManager.Stub } // Non-persistent but background whitelisted? - if (uidOnBackgroundAllowlist(uid)) { + if (uidOnBackgroundAllowlistLOSP(uid)) { if (DEBUG_BACKGROUND_CHECK) { Slog.i(TAG, "App " + uid + "/" + packageName + " on background whitelist; not restricted in background"); @@ -5341,7 +5494,7 @@ public class ActivityManagerService extends IActivityManager.Stub } // Is this app on the battery whitelist? - if (isOnDeviceIdleAllowlistLocked(uid, /*allowExceptIdleToo=*/ false)) { + if (isOnDeviceIdleAllowlistLOSP(uid, /*allowExceptIdleToo=*/ false)) { if (DEBUG_BACKGROUND_CHECK) { Slog.i(TAG, "App " + uid + "/" + packageName + " on idle whitelist; not restricted in background"); @@ -5350,25 +5503,26 @@ public class ActivityManagerService extends IActivityManager.Stub } // None of the service-policy criteria apply, so we apply the common criteria - return appRestrictedInBackgroundLocked(uid, packageName, packageTargetSdk); + return appRestrictedInBackgroundLOSP(uid, packageName, packageTargetSdk); } - int getAppStartModeLocked(int uid, String packageName, int packageTargetSdk, + @GuardedBy(anyOf = {"this", "mProcLock"}) + int getAppStartModeLOSP(int uid, String packageName, int packageTargetSdk, int callingPid, boolean alwaysRestrict, boolean disabledOnly, boolean forcedStandby) { if (mInternal.isPendingTopUid(uid)) { return ActivityManager.APP_START_MODE_NORMAL; } - UidRecord uidRec = mProcessList.getUidRecordLocked(uid); + UidRecord uidRec = mProcessList.getUidRecordLOSP(uid); if (DEBUG_BACKGROUND_CHECK) Slog.d(TAG, "checkAllowBackground: uid=" + uid + " pkg=" + packageName + " rec=" + uidRec + " always=" + alwaysRestrict + " idle=" - + (uidRec != null ? uidRec.idle : false)); - if (uidRec == null || alwaysRestrict || forcedStandby || uidRec.idle) { + + (uidRec != null ? uidRec.isIdle() : false)); + if (uidRec == null || alwaysRestrict || forcedStandby || uidRec.isIdle()) { boolean ephemeral; if (uidRec == null) { ephemeral = getPackageManagerInternal().isPackageEphemeral( UserHandle.getUserId(uid), packageName); } else { - ephemeral = uidRec.ephemeral; + ephemeral = uidRec.isEphemeral(); } if (ephemeral) { @@ -5383,14 +5537,14 @@ public class ActivityManagerService extends IActivityManager.Stub return ActivityManager.APP_START_MODE_NORMAL; } final int startMode = (alwaysRestrict) - ? appRestrictedInBackgroundLocked(uid, packageName, packageTargetSdk) - : appServicesRestrictedInBackgroundLocked(uid, packageName, + ? appRestrictedInBackgroundLOSP(uid, packageName, packageTargetSdk) + : appServicesRestrictedInBackgroundLOSP(uid, packageName, packageTargetSdk); if (DEBUG_BACKGROUND_CHECK) { Slog.d(TAG, "checkAllowBackground: uid=" + uid + " pkg=" + packageName + " startMode=" + startMode - + " onallowlist=" + isOnDeviceIdleAllowlistLocked(uid, false) - + " onallowlist(ei)=" + isOnDeviceIdleAllowlistLocked(uid, true)); + + " onallowlist=" + isOnDeviceIdleAllowlistLOSP(uid, false) + + " onallowlist(ei)=" + isOnDeviceIdleAllowlistLOSP(uid, true)); } if (startMode == ActivityManager.APP_START_MODE_DELAYED) { // This is an old app that has been forced into a "compatible as possible" @@ -5401,8 +5555,8 @@ public class ActivityManagerService extends IActivityManager.Stub synchronized (mPidsSelfLocked) { proc = mPidsSelfLocked.get(callingPid); } - if (proc != null && - !ActivityManager.isProcStateBackground(proc.getCurProcState())) { + if (proc != null && !ActivityManager.isProcStateBackground( + proc.mState.getCurProcState())) { // Whoever is instigating this is in the foreground, so we will allow it // to go through. return ActivityManager.APP_START_MODE_NORMAL; @@ -5418,7 +5572,8 @@ public class ActivityManagerService extends IActivityManager.Stub /** * @return whether a UID is in the system, user or temp doze allowlist. */ - boolean isOnDeviceIdleAllowlistLocked(int uid, boolean allowExceptIdleToo) { + @GuardedBy(anyOf = {"this", "mProcLock"}) + boolean isOnDeviceIdleAllowlistLOSP(int uid, boolean allowExceptIdleToo) { final int appId = UserHandle.getAppId(uid); final int[] allowlist = allowExceptIdleToo @@ -5430,7 +5585,8 @@ public class ActivityManagerService extends IActivityManager.Stub || mPendingTempAllowlist.indexOfKey(uid) >= 0; } - boolean isAllowlistedForFgsStartLocked(int uid) { + @GuardedBy(anyOf = {"this", "mProcLock"}) + boolean isAllowlistedForFgsStartLOSP(int uid) { return Arrays.binarySearch(mDeviceIdleExceptIdleAllowlist, UserHandle.getAppId(uid)) >= 0 || mFgsStartTempAllowList.isAllowed(uid); } @@ -5439,7 +5595,8 @@ public class ActivityManagerService extends IActivityManager.Stub * @return allowlist tag for a uid from mPendingTempAllowlist, null if not currently on * the allowlist */ - String getPendingTempAllowlistTagForUidLocked(int uid) { + @GuardedBy(anyOf = {"this", "mProcLock"}) + String getPendingTempAllowlistTagForUidLOSP(int uid) { final PendingTempAllowlist ptw = mPendingTempAllowlist.get(uid); return ptw != null ? ptw.tag : null; } @@ -5484,8 +5641,8 @@ public class ActivityManagerService extends IActivityManager.Stub final int modeFlags, int userId) { enforceNotIsolatedCaller("grantUriPermission"); GrantUri grantUri = new GrantUri(userId, uri, modeFlags); - synchronized(this) { - final ProcessRecord r = getRecordForAppLocked(caller); + synchronized (mProcLock) { + final ProcessRecord r = getRecordForAppLOSP(caller); if (r == null) { throw new SecurityException("Unable to find app for caller " + caller @@ -5518,8 +5675,8 @@ public class ActivityManagerService extends IActivityManager.Stub public void revokeUriPermission(IApplicationThread caller, String targetPackage, Uri uri, final int modeFlags, int userId) { enforceNotIsolatedCaller("revokeUriPermission"); - synchronized(this) { - final ProcessRecord r = getRecordForAppLocked(caller); + synchronized (mProcLock) { + final ProcessRecord r = getRecordForAppLOSP(caller); if (r == null) { throw new SecurityException("Unable to find app for caller " + caller @@ -5550,9 +5707,8 @@ public class ActivityManagerService extends IActivityManager.Stub @Override public void showWaitingForDebugger(IApplicationThread who, boolean waiting) { - synchronized (this) { - ProcessRecord app = - who != null ? getRecordForAppLocked(who) : null; + synchronized (mProcLock) { + final ProcessRecord app = who != null ? getRecordForAppLOSP(who) : null; if (app == null) return; Message msg = Message.obtain(); @@ -5851,7 +6007,8 @@ public class ActivityManagerService extends IActivityManager.Stub // GLOBAL MANAGEMENT // ========================================================= - private boolean uidOnBackgroundAllowlist(final int uid) { + @GuardedBy(anyOf = {"this", "mProcLock"}) + private boolean uidOnBackgroundAllowlistLOSP(final int uid) { final int appId = UserHandle.getAppId(uid); final int[] allowlist = mBackgroundAppIdAllowlist; for (int i = 0, len = allowlist.length; i < len; i++) { @@ -5895,11 +6052,13 @@ public class ActivityManagerService extends IActivityManager.Stub Slog.i(TAG, "Adding uid " + uid + " to bg uid whitelist"); } synchronized (this) { - final int num = mBackgroundAppIdAllowlist.length; - int[] newList = new int[num + 1]; - System.arraycopy(mBackgroundAppIdAllowlist, 0, newList, 0, num); - newList[num] = UserHandle.getAppId(uid); - mBackgroundAppIdAllowlist = newList; + synchronized (mProcLock) { + final int num = mBackgroundAppIdAllowlist.length; + int[] newList = new int[num + 1]; + System.arraycopy(mBackgroundAppIdAllowlist, 0, newList, 0, num); + newList[num] = UserHandle.getAppId(uid); + mBackgroundAppIdAllowlist = newList; + } } } @@ -5925,8 +6084,8 @@ public class ActivityManagerService extends IActivityManager.Stub if (app == null) { app = mProcessList.newProcessRecordLocked(info, customProcess, isolated, 0, new HostingRecord("added application", - customProcess != null ? customProcess : info.processName)); - mProcessList.updateLruProcessLocked(app, false, null); + customProcess != null ? customProcess : info.processName)); + updateLruProcessLocked(app, false, null); updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_PROCESS_BEGIN); } @@ -5942,9 +6101,9 @@ public class ActivityManagerService extends IActivityManager.Stub if ((info.flags & PERSISTENT_MASK) == PERSISTENT_MASK) { app.setPersistent(true); - app.maxAdj = ProcessList.PERSISTENT_PROC_ADJ; + app.mState.setMaxAdj(ProcessList.PERSISTENT_PROC_ADJ); } - if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) { + if (app.getThread() == null && mPersistentStartingProcesses.indexOf(app) < 0) { mPersistentStartingProcesses.add(app); mProcessList.startProcessLocked(app, new HostingRecord("added application", customProcess != null ? customProcess : app.processName), @@ -6015,7 +6174,7 @@ public class ActivityManagerService extends IActivityManager.Stub } void onWakefulnessChanged(int wakefulness) { - synchronized(this) { + synchronized (this) { boolean wasAwake = mWakefulness.getAndSet(wakefulness) == PowerManagerInternal.WAKEFULNESS_AWAKE; boolean isAwake = wakefulness == PowerManagerInternal.WAKEFULNESS_AWAKE; @@ -6142,13 +6301,13 @@ public class ActivityManagerService extends IActivityManager.Stub } void setTrackAllocationApp(ApplicationInfo app, String processName) { - synchronized (this) { - if (!Build.IS_DEBUGGABLE) { - if ((app.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0) { - throw new SecurityException("Process not debuggable: " + app.packageName); - } + if (!Build.IS_DEBUGGABLE) { + if ((app.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0) { + throw new SecurityException("Process not debuggable: " + app.packageName); } + } + synchronized (mProcLock) { mTrackAllocationApp = processName; } } @@ -6205,7 +6364,7 @@ public class ActivityManagerService extends IActivityManager.Stub @Override public void setUserIsMonkey(boolean userIsMonkey) { - synchronized (this) { + synchronized (mProcLock) { synchronized (mPidsSelfLocked) { final int callingPid = Binder.getCallingPid(); ProcessRecord proc = mPidsSelfLocked.get(callingPid); @@ -6224,7 +6383,7 @@ public class ActivityManagerService extends IActivityManager.Stub @Override public boolean isUserAMonkey() { - synchronized (this) { + synchronized (mProcLock) { // If there is a controller also implies the user is a monkey. return mUserIsMonkey || mActivityTaskManager.isControllerAMonkey(); } @@ -6445,8 +6604,8 @@ public class ActivityManagerService extends IActivityManager.Stub "getUidProcessState"); } - synchronized (this) { - return mProcessList.getUidProcStateLocked(uid); + synchronized (mProcLock) { + return mProcessList.getUidProcStateLOSP(uid); } } @@ -6472,17 +6631,18 @@ public class ActivityManagerService extends IActivityManager.Stub enforceCallingPermission(android.Manifest.permission.PACKAGE_USAGE_STATS, "isUidActive"); } - synchronized (this) { - if (isUidActiveLocked(uid)) { + synchronized (mProcLock) { + if (isUidActiveLOSP(uid)) { return true; } } return mInternal.isPendingTopUid(uid); } - boolean isUidActiveLocked(int uid) { - final UidRecord uidRecord = mProcessList.getUidRecordLocked(uid); - return uidRecord != null && !uidRecord.setIdle; + @GuardedBy(anyOf = {"this", "mProcLock"}) + boolean isUidActiveLOSP(int uid) { + final UidRecord uidRecord = mProcessList.getUidRecordLOSP(uid); + return uidRecord != null && !uidRecord.isSetIdle(); } @Override @@ -6540,7 +6700,7 @@ public class ActivityManagerService extends IActivityManager.Stub @Override public void setRenderThread(int tid) { - synchronized (this) { + synchronized (mProcLock) { ProcessRecord proc; int pid = Binder.getCallingPid(); if (pid == Process.myPid()) { @@ -6549,33 +6709,32 @@ public class ActivityManagerService extends IActivityManager.Stub } synchronized (mPidsSelfLocked) { proc = mPidsSelfLocked.get(pid); - if (proc != null && proc.renderThreadTid == 0 && tid > 0) { - // ensure the tid belongs to the process - if (!isThreadInProcess(pid, tid)) { - throw new IllegalArgumentException( + } + if (proc != null && proc.getRenderThreadTid() == 0 && tid > 0) { + // ensure the tid belongs to the process + if (!isThreadInProcess(pid, tid)) { + throw new IllegalArgumentException( "Render thread does not belong to process"); - } - proc.renderThreadTid = tid; - if (DEBUG_OOM_ADJ) { - Slog.d("UI_FIFO", "Set RenderThread tid " + tid + " for pid " + pid); - } - // promote to FIFO now - if (proc.getCurrentSchedulingGroup() == ProcessList.SCHED_GROUP_TOP_APP) { - if (DEBUG_OOM_ADJ) Slog.d("UI_FIFO", "Promoting " + tid + "out of band"); - if (mUseFifoUiScheduling) { - setThreadScheduler(proc.renderThreadTid, + } + proc.setRenderThreadTid(tid); + if (DEBUG_OOM_ADJ) { + Slog.d("UI_FIFO", "Set RenderThread tid " + tid + " for pid " + pid); + } + // promote to FIFO now + if (proc.mState.getCurrentSchedulingGroup() == ProcessList.SCHED_GROUP_TOP_APP) { + if (DEBUG_OOM_ADJ) Slog.d("UI_FIFO", "Promoting " + tid + "out of band"); + if (mUseFifoUiScheduling) { + setThreadScheduler(proc.getRenderThreadTid(), SCHED_FIFO | SCHED_RESET_ON_FORK, 1); - } else { - setThreadPriority(proc.renderThreadTid, TOP_APP_PRIORITY_BOOST); - } - } - } else { - if (DEBUG_OOM_ADJ) { - Slog.d("UI_FIFO", "Didn't set thread from setRenderThread? " + - "PID: " + pid + ", TID: " + tid + " FIFO: " + - mUseFifoUiScheduling); + } else { + setThreadPriority(proc.getRenderThreadTid(), TOP_APP_PRIORITY_BOOST); } } + } else { + if (DEBUG_OOM_ADJ) { + Slog.d("UI_FIFO", "Didn't set thread from setRenderThread? " + + "PID: " + pid + ", TID: " + tid + " FIFO: " + mUseFifoUiScheduling); + } } } } @@ -6631,11 +6790,11 @@ public class ActivityManagerService extends IActivityManager.Stub Slog.w(TAG, "setHasTopUi called on unknown pid: " + pid); return; } - if (pr.hasTopUi() != hasTopUi) { + if (pr.mState.hasTopUi() != hasTopUi) { if (DEBUG_OOM_ADJ) { Slog.d(TAG, "Setting hasTopUi=" + hasTopUi + " for pid=" + pid); } - pr.setHasTopUi(hasTopUi); + pr.mState.setHasTopUi(hasTopUi); changed = true; } } @@ -6815,42 +6974,46 @@ public class ActivityManagerService extends IActivityManager.Stub // manager calls in with its locks held. boolean killed = false; - synchronized (mPidsSelfLocked) { - int worstType = 0; - for (int i=0; i worstType) { - worstType = type; + synchronized (this) { + synchronized (mProcLock) { + synchronized (mPidsSelfLocked) { + int worstType = 0; + for (int i = 0; i < pids.length; i++) { + ProcessRecord proc = mPidsSelfLocked.get(pids[i]); + if (proc != null) { + int type = proc.mState.getSetAdj(); + if (type > worstType) { + worstType = type; + } + } } - } - } - // If the worst oom_adj is somewhere in the cached proc LRU range, - // then constrain it so we will kill all cached procs. - if (worstType < ProcessList.CACHED_APP_MAX_ADJ - && worstType > ProcessList.CACHED_APP_MIN_ADJ) { - worstType = ProcessList.CACHED_APP_MIN_ADJ; - } + // If the worst oom_adj is somewhere in the cached proc LRU range, + // then constrain it so we will kill all cached procs. + if (worstType < ProcessList.CACHED_APP_MAX_ADJ + && worstType > ProcessList.CACHED_APP_MIN_ADJ) { + worstType = ProcessList.CACHED_APP_MIN_ADJ; + } - // If this is not a secure call, don't let it kill processes that - // are important. - if (!secure && worstType < ProcessList.SERVICE_ADJ) { - worstType = ProcessList.SERVICE_ADJ; - } + // If this is not a secure call, don't let it kill processes that + // are important. + if (!secure && worstType < ProcessList.SERVICE_ADJ) { + worstType = ProcessList.SERVICE_ADJ; + } - Slog.w(TAG, "Killing processes " + reason + " at adjustment " + worstType); - for (int i=0; i= worstType && !proc.killedByAm) { - proc.kill(reason, ApplicationExitInfo.REASON_OTHER, - ApplicationExitInfo.SUBREASON_KILL_PID, true); - killed = true; + Slog.w(TAG, "Killing processes " + reason + " at adjustment " + worstType); + for (int i = 0; i < pids.length; i++) { + ProcessRecord proc = mPidsSelfLocked.get(pids[i]); + if (proc == null) { + continue; + } + int adj = proc.mState.getSetAdj(); + if (adj >= worstType && !proc.isKilledByAm()) { + proc.killLocked(reason, ApplicationExitInfo.REASON_OTHER, + ApplicationExitInfo.SUBREASON_KILL_PID, true); + killed = true; + } + } } } } @@ -6863,13 +7026,15 @@ public class ActivityManagerService extends IActivityManager.Stub synchronized (this) { final long identity = Binder.clearCallingIdentity(); try { - mProcessList.killPackageProcessesLocked(null /* packageName */, appId, userId, - ProcessList.PERSISTENT_PROC_ADJ, false /* callerWillRestart */, - true /* callerWillRestart */, true /* doit */, true /* evenPersistent */, - false /* setRemoved */, - ApplicationExitInfo.REASON_OTHER, - ApplicationExitInfo.SUBREASON_KILL_UID, - reason != null ? reason : "kill uid"); + synchronized (mProcLock) { + mProcessList.killPackageProcessesLSP(null /* packageName */, appId, userId, + ProcessList.PERSISTENT_PROC_ADJ, false /* callerWillRestart */, + true /* callerWillRestart */, true /* doit */, + true /* evenPersistent */, false /* setRemoved */, + ApplicationExitInfo.REASON_OTHER, + ApplicationExitInfo.SUBREASON_KILL_UID, + reason != null ? reason : "kill uid"); + } } finally { Binder.restoreCallingIdentity(identity); } @@ -6882,13 +7047,15 @@ public class ActivityManagerService extends IActivityManager.Stub synchronized (this) { final long identity = Binder.clearCallingIdentity(); try { - mProcessList.killPackageProcessesLocked(null /* packageName */, appId, userId, - ProcessList.PERSISTENT_PROC_ADJ, false /* callerWillRestart */, - true /* callerWillRestart */, true /* doit */, true /* evenPersistent */, - false /* setRemoved */, - ApplicationExitInfo.REASON_PERMISSION_CHANGE, - ApplicationExitInfo.SUBREASON_UNKNOWN, - reason != null ? reason : "kill uid"); + synchronized (mProcLock) { + mProcessList.killPackageProcessesLSP(null /* packageName */, appId, userId, + ProcessList.PERSISTENT_PROC_ADJ, false /* callerWillRestart */, + true /* callerWillRestart */, true /* doit */, + true /* evenPersistent */, false /* setRemoved */, + ApplicationExitInfo.REASON_PERMISSION_CHANGE, + ApplicationExitInfo.SUBREASON_UNKNOWN, + reason != null ? reason : "kill uid"); + } } finally { Binder.restoreCallingIdentity(identity); } @@ -6910,17 +7077,22 @@ public class ActivityManagerService extends IActivityManager.Stub } boolean killed = false; - synchronized (mPidsSelfLocked) { - final int size = mPidsSelfLocked.size(); - for (int i = 0; i < size; i++) { - final int pid = mPidsSelfLocked.keyAt(i); - final ProcessRecord proc = mPidsSelfLocked.valueAt(i); - if (proc == null) continue; + synchronized (this) { + synchronized (mProcLock) { + synchronized (mPidsSelfLocked) { + final int size = mPidsSelfLocked.size(); + for (int i = 0; i < size; i++) { + final int pid = mPidsSelfLocked.keyAt(i); + final ProcessRecord proc = mPidsSelfLocked.valueAt(i); + if (proc == null) continue; - final int adj = proc.setAdj; - if (adj > belowAdj && !proc.killedByAm) { - proc.kill(reason, ApplicationExitInfo.REASON_PERMISSION_CHANGE, true); - killed = true; + final int adj = proc.mState.getSetAdj(); + if (adj > belowAdj && !proc.isKilledByAm()) { + proc.killLocked(reason, ApplicationExitInfo.REASON_PERMISSION_CHANGE, + true); + killed = true; + } + } } } } @@ -7026,16 +7198,16 @@ public class ActivityManagerService extends IActivityManager.Stub + android.Manifest.permission.SET_ACTIVITY_WATCHER); } - synchronized (this) { + synchronized (mProcLock) { final long now = SystemClock.uptimeMillis(); final long timeSinceLastIdle = now - mLastIdleTime; // Compact all non-zygote processes to freshen up the page cache. mOomAdjuster.mCachedAppOptimizer.compactAllSystem(); - final long lowRamSinceLastIdle = mAppProfiler.getLowRamTimeSinceIdleLocked(now); + final long lowRamSinceLastIdle = mAppProfiler.getLowRamTimeSinceIdleLPr(now); mLastIdleTime = now; - mAppProfiler.updateLowRamTimestampLocked(now); + mAppProfiler.updateLowRamTimestampLPr(now); StringBuilder sb = new StringBuilder(128); sb.append("Idle maintenance over "); @@ -7052,13 +7224,13 @@ public class ActivityManagerService extends IActivityManager.Stub final long totalMemoryInKb = getTotalMemory() / 1000; final long memoryGrowthThreshold = Math.max(totalMemoryInKb / 100, MINIMUM_MEMORY_GROWTH_THRESHOLD); - - for (int i = mProcessList.mLruProcesses.size() - 1 ; i >= 0 ; i--) { - ProcessRecord proc = mProcessList.mLruProcesses.get(i); + mProcessList.forEachLruProcessesLOSP(false, proc -> { final ProcessProfileRecord pr = proc.mProfile; - if (proc.notCachedSinceIdle) { - if (proc.setProcState >= ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE - && proc.setProcState <= ActivityManager.PROCESS_STATE_SERVICE) { + final ProcessStateRecord state = proc.mState; + final int setProcState = state.getSetProcState(); + if (state.isNotCachedSinceIdle()) { + if (setProcState >= ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE + && setProcState <= ActivityManager.PROCESS_STATE_SERVICE) { final long initialIdlePss, lastPss, lastSwapPss; synchronized (mAppProfiler.mProfilerLock) { initialIdlePss = pr.getInitialIdlePss(); @@ -7066,39 +7238,43 @@ public class ActivityManagerService extends IActivityManager.Stub lastSwapPss = pr.getLastSwapPss(); } if (doKilling && initialIdlePss != 0 - && lastPss > ((initialIdlePss * 3) / 2) + && lastPss > (initialIdlePss * 3 / 2) && lastPss > (initialIdlePss + memoryGrowthThreshold)) { - sb = new StringBuilder(128); - sb.append("Kill"); - sb.append(proc.processName); - sb.append(" in idle maint: pss="); - sb.append(lastPss); - sb.append(", swapPss="); - sb.append(lastSwapPss); - sb.append(", initialPss="); - sb.append(initialIdlePss); - sb.append(", period="); - TimeUtils.formatDuration(timeSinceLastIdle, sb); - sb.append(", lowRamPeriod="); - TimeUtils.formatDuration(lowRamSinceLastIdle, sb); - Slog.wtfQuiet(TAG, sb.toString()); - proc.kill("idle maint (pss " + lastPss - + " from " + initialIdlePss + ")", - ApplicationExitInfo.REASON_OTHER, - ApplicationExitInfo.SUBREASON_MEMORY_PRESSURE, - true); + final StringBuilder sb2 = new StringBuilder(128); + sb2.append("Kill"); + sb2.append(proc.processName); + sb2.append(" in idle maint: pss="); + sb2.append(lastPss); + sb2.append(", swapPss="); + sb2.append(lastSwapPss); + sb2.append(", initialPss="); + sb2.append(initialIdlePss); + sb2.append(", period="); + TimeUtils.formatDuration(timeSinceLastIdle, sb2); + sb2.append(", lowRamPeriod="); + TimeUtils.formatDuration(lowRamSinceLastIdle, sb2); + Slog.wtfQuiet(TAG, sb2.toString()); + mHandler.post(() -> { + synchronized (ActivityManagerService.this) { + proc.killLocked("idle maint (pss " + lastPss + + " from " + initialIdlePss + ")", + ApplicationExitInfo.REASON_OTHER, + ApplicationExitInfo.SUBREASON_MEMORY_PRESSURE, + true); + } + }); } } - } else if (proc.setProcState < ActivityManager.PROCESS_STATE_HOME - && proc.setProcState >= ActivityManager.PROCESS_STATE_PERSISTENT) { - proc.notCachedSinceIdle = true; + } else if (setProcState < ActivityManager.PROCESS_STATE_HOME + && setProcState >= ActivityManager.PROCESS_STATE_PERSISTENT) { + state.setNotCachedSinceIdle(true); synchronized (mAppProfiler.mProfilerLock) { pr.setInitialIdlePss(0); mAppProfiler.updateNextPssTimeLPf( - proc.setProcState, proc.mProfile, now, true); + state.getSetProcState(), proc.mProfile, now, true); } } - } + }); } } @@ -7209,7 +7385,7 @@ public class ActivityManagerService extends IActivityManager.Stub synchronized(this) { if (procsToKill != null) { - for (int i=procsToKill.size()-1; i>=0; i--) { + for (int i = procsToKill.size() - 1; i >= 0; i--) { ProcessRecord proc = procsToKill.get(i); Slog.i(TAG, "Removing system update proc: " + proc); mProcessList.removeProcessLocked(proc, true, false, @@ -7436,16 +7612,18 @@ public class ActivityManagerService extends IActivityManager.Stub private void updateForceBackgroundCheck(boolean enabled) { synchronized (this) { - if (mForceBackgroundCheck != enabled) { - mForceBackgroundCheck = enabled; + synchronized (mProcLock) { + if (mForceBackgroundCheck != enabled) { + mForceBackgroundCheck = enabled; - if (DEBUG_BACKGROUND_CHECK) { - Slog.i(TAG, "Force background check " + (enabled ? "enabled" : "disabled")); - } + if (DEBUG_BACKGROUND_CHECK) { + Slog.i(TAG, "Force background check " + (enabled ? "enabled" : "disabled")); + } - if (mForceBackgroundCheck) { - // Stop background services for idle UIDs. - mProcessList.doStopUidForIdleUidsLocked(); + if (mForceBackgroundCheck) { + // Stop background services for idle UIDs. + mProcessList.doStopUidForIdleUidsLocked(); + } } } } @@ -7510,7 +7688,7 @@ public class ActivityManagerService extends IActivityManager.Stub (r != null) ? r.uid : -1, eventType, processName, - (r != null) ? r.pid : -1, + (r != null) ? r.getPid() : -1, (r != null && r.info != null) ? r.info.packageName : "", (r != null && r.info != null) ? (r.info.isInstantApp() ? FrameworkStatsLog.APP_CRASH_OCCURRED__IS_INSTANT_APP__TRUE @@ -7756,8 +7934,8 @@ public class ActivityManagerService extends IActivityManager.Stub return null; } - synchronized (this) { - return mProcessList.findAppProcessLocked(app, reason); + synchronized (mProcLock) { + return mProcessList.findAppProcessLOSP(app, reason); } } @@ -7766,7 +7944,7 @@ public class ActivityManagerService extends IActivityManager.Stub * to append various headers to the dropbox log text. */ void appendDropBoxProcessHeaders(ProcessRecord process, String processName, - StringBuilder sb) { + final StringBuilder sb) { // Watchdog thread ends up invoking this function (with // a null ProcessRecord) to add the stack file to dropbox. // Do not acquire a lock on this (am) in such cases, as it @@ -7780,17 +7958,18 @@ public class ActivityManagerService extends IActivityManager.Stub // Note: ProcessRecord 'process' is guarded by the service // instance. (notably process.pkgList, which could otherwise change // concurrently during execution of this method) - synchronized (this) { + synchronized (mProcLock) { sb.append("Process: ").append(processName).append("\n"); - sb.append("PID: ").append(process.pid).append("\n"); + sb.append("PID: ").append(process.getPid()).append("\n"); sb.append("UID: ").append(process.uid).append("\n"); int flags = process.info.flags; - IPackageManager pm = AppGlobals.getPackageManager(); + final IPackageManager pm = AppGlobals.getPackageManager(); sb.append("Flags: 0x").append(Integer.toHexString(flags)).append("\n"); + final int callingUserId = UserHandle.getCallingUserId(); process.getPkgList().forEachPackage(pkg -> { sb.append("Package: ").append(pkg); try { - PackageInfo pi = pm.getPackageInfo(pkg, 0, UserHandle.getCallingUserId()); + final PackageInfo pi = pm.getPackageInfo(pkg, 0, callingUserId); if (pi != null) { sb.append(" v").append(pi.getLongVersionCode()); if (pi.versionName != null) { @@ -7809,7 +7988,7 @@ public class ActivityManagerService extends IActivityManager.Stub } private static String processClass(ProcessRecord process) { - if (process == null || process.pid == MY_PID) { + if (process == null || process.getPid() == MY_PID) { return "system_server"; } else if ((process.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { return "system_app"; @@ -7871,8 +8050,8 @@ public class ActivityManagerService extends IActivityManager.Stub sb.append("Foreground: ") .append(process.isInterestingToUserLocked() ? "Yes" : "No") .append("\n"); - if (process.startTime > 0) { - long runtimeMillis = SystemClock.elapsedRealtime() - process.startTime; + if (process.getStartTime() > 0) { + long runtimeMillis = SystemClock.elapsedRealtime() - process.getStartTime(); sb.append("Process-Runtime: ").append(runtimeMillis).append("\n"); } } @@ -7880,7 +8059,7 @@ public class ActivityManagerService extends IActivityManager.Stub sb.append("Activity: ").append(activityShortComponentName).append("\n"); } if (parentShortComponentName != null) { - if (parentProcess != null && parentProcess.pid != process.pid) { + if (parentProcess != null && parentProcess.getPid() != process.getPid()) { sb.append("Parent-Process: ").append(parentProcess.processName).append("\n"); } if (!parentShortComponentName.equals(activityShortComponentName)) { @@ -7976,47 +8155,46 @@ public class ActivityManagerService extends IActivityManager.Stub public List getProcessesInErrorState() { enforceNotIsolatedCaller("getProcessesInErrorState"); // assume our apps are happy - lazy create the list - List errList = null; + final List[] errList = new List[1]; final boolean allUsers = ActivityManager.checkUidPermission(INTERACT_ACROSS_USERS_FULL, Binder.getCallingUid()) == PackageManager.PERMISSION_GRANTED; int userId = UserHandle.getUserId(Binder.getCallingUid()); - synchronized (this) { - + synchronized (mProcLock) { // iterate across all processes - for (int i=mProcessList.mLruProcesses.size()-1; i>=0; i--) { - ProcessRecord app = mProcessList.mLruProcesses.get(i); + mProcessList.forEachLruProcessesLOSP(false, app -> { if (!allUsers && app.userId != userId) { - continue; + return; } - final boolean crashing = app.isCrashing(); - final boolean notResponding = app.isNotResponding(); - if ((app.thread != null) && (crashing || notResponding)) { + final ProcessErrorStateRecord errState = app.mErrorState; + final boolean crashing = errState.isCrashing(); + final boolean notResponding = errState.isNotResponding(); + if ((app.getThread() != null) && (crashing || notResponding)) { // This one's in trouble, so we'll generate a report for it // crashes are higher priority (in case there's a crash *and* an anr) ActivityManager.ProcessErrorStateInfo report = null; if (crashing) { - report = app.crashingReport; + report = errState.getCrashingReport(); } else if (notResponding) { - report = app.notRespondingReport; + report = errState.getNotRespondingReport(); } if (report != null) { - if (errList == null) { - errList = new ArrayList<>(1); + if (errList[0] == null) { + errList[0] = new ArrayList<>(1); } - errList.add(report); + errList[0].add(report); } else { Slog.w(TAG, "Missing app error report, app = " + app.processName + " crashing = " + crashing + " notResponding = " + notResponding); } } - } + }); } - return errList; + return errList[0]; } @Override @@ -8032,9 +8210,9 @@ public class ActivityManagerService extends IActivityManager.Stub final boolean allUids = mAtmInternal.isGetTasksAllowed( "getRunningAppProcesses", Binder.getCallingPid(), callingUid); - synchronized (this) { + synchronized (mProcLock) { // Iterate across all processes - return mProcessList.getRunningAppProcessesLocked(allUsers, userId, allUids, + return mProcessList.getRunningAppProcessesLOSP(allUsers, userId, allUids, callingUid, clientTargetSdk); } } @@ -8145,13 +8323,13 @@ public class ActivityManagerService extends IActivityManager.Stub final int callingUid = Binder.getCallingUid(); final int clientTargetSdk = mPackageManagerInt.getUidTargetSdkVersion(callingUid); - synchronized (this) { + synchronized (mProcLock) { ProcessRecord proc; synchronized (mPidsSelfLocked) { proc = mPidsSelfLocked.get(Binder.getCallingPid()); } if (proc != null) { - mProcessList.fillInProcMemInfoLocked(proc, outState, clientTargetSdk); + mProcessList.fillInProcMemInfoLOSP(proc, outState, clientTargetSdk); } } } @@ -8197,7 +8375,9 @@ public class ActivityManagerService extends IActivityManager.Stub synchronized(this) { mConstants.dump(pw); - mOomAdjuster.dumpCachedAppOptimizerSettings(pw); + synchronized (mProcLock) { + mOomAdjuster.dumpCachedAppOptimizerSettings(pw); + } mOomAdjuster.dumpCacheOomRankerSettings(pw); pw.println(); if (dumpAll) { @@ -8329,7 +8509,9 @@ public class ActivityManagerService extends IActivityManager.Stub if (dumpAll) { pw.println("-------------------------------------------------------------------------------"); } - mProcessList.dumpProcessesLocked(fd, pw, args, opti, dumpAll, dumpPackage, dumpAppId); + synchronized (mProcLock) { + mProcessList.dumpProcessesLSP(fd, pw, args, opti, dumpAll, dumpPackage, dumpAppId); + } pw.println(); if (dumpAll) { pw.println("-------------------------------------------------------------------------------"); @@ -8433,7 +8615,9 @@ public class ActivityManagerService extends IActivityManager.Stub } // output proto is ProcessProto synchronized (this) { - mProcessList.writeProcessesToProtoLocked(proto, dumpPackage); + synchronized (mProcLock) { + mProcessList.writeProcessesToProtoLSP(proto, dumpPackage); + } } } else { // default option, dump everything, output is ActivityManagerServiceProto @@ -8452,7 +8636,9 @@ public class ActivityManagerService extends IActivityManager.Stub proto.end(serviceToken); long processToken = proto.start(ActivityManagerServiceProto.PROCESSES); - mProcessList.writeProcessesToProtoLocked(proto, dumpPackage); + synchronized (mProcLock) { + mProcessList.writeProcessesToProtoLSP(proto, dumpPackage); + } proto.end(processToken); } } @@ -8526,8 +8712,10 @@ public class ActivityManagerService extends IActivityManager.Stub opti++; } synchronized (this) { - mProcessList.dumpProcessesLocked( - fd, pw, args, opti, true, dumpPackage, dumpAppId); + synchronized (mProcLock) { + mProcessList.dumpProcessesLSP( + fd, pw, args, opti, true, dumpPackage, dumpAppId); + } } } else if ("oom".equals(cmd) || "o".equals(cmd)) { synchronized (this) { @@ -8615,6 +8803,8 @@ public class ActivityManagerService extends IActivityManager.Stub } else if ("settings".equals(cmd)) { synchronized (this) { mConstants.dump(pw); + } + synchronized (mProcLock) { mOomAdjuster.dumpCachedAppOptimizerSettings(pw); mOomAdjuster.dumpCacheOomRankerSettings(pw); } @@ -8864,8 +9054,8 @@ public class ActivityManagerService extends IActivityManager.Stub return needSep; } - @GuardedBy("this") - void dumpOtherProcessesInfoLocked(FileDescriptor fd, PrintWriter pw, + @GuardedBy({"this", "mProcLock"}) + void dumpOtherProcessesInfoLSP(FileDescriptor fd, PrintWriter pw, boolean dumpAll, String dumpPackage, int dumpAppId, int numPers, boolean needSep) { if (dumpAll || dumpPackage != null) { final SparseArray pidToProcess = new SparseArray<>(); @@ -8873,7 +9063,7 @@ public class ActivityManagerService extends IActivityManager.Stub boolean printed = false; for (int i = 0, size = mPidsSelfLocked.size(); i < size; i++) { ProcessRecord r = mPidsSelfLocked.valueAt(i); - pidToProcess.put(r.pid, r); + pidToProcess.put(r.getPid(), r); if (dumpPackage != null && !r.getPkgList().containsKey(dumpPackage)) { continue; } @@ -8884,7 +9074,7 @@ public class ActivityManagerService extends IActivityManager.Stub printed = true; } pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i)); - pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i)); + pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i)); } } @@ -8924,8 +9114,7 @@ public class ActivityManagerService extends IActivityManager.Stub synchronized (mPidsSelfLocked) { boolean printed = false; for (int i = 0, size = mImportantProcesses.size(); i < size; i++) { - ProcessRecord r = mPidsSelfLocked.get( - mImportantProcesses.valueAt(i).pid); + ProcessRecord r = mPidsSelfLocked.get(mImportantProcesses.valueAt(i).pid); if (dumpPackage != null && (r == null || !r.getPkgList().containsKey(dumpPackage))) { continue; @@ -8966,7 +9155,7 @@ public class ActivityManagerService extends IActivityManager.Stub "OnHold Norm", "OnHold PERS", dumpPackage); } - needSep = mAppErrors.dumpLocked(fd, pw, needSep, dumpPackage); + needSep = mAppErrors.dumpLPr(fd, pw, needSep, dumpPackage); needSep = mAtmInternal.dumpForProcesses(fd, pw, dumpAll, dumpPackage, dumpAppId, needSep, mAppProfiler.getTestPssMode(), mWakefulness.get()); @@ -9061,7 +9250,7 @@ public class ActivityManagerService extends IActivityManager.Stub TimeUtils.formatDuration(now, mLastIdleTime, pw); pw.print(" mLowRamSinceLastIdle="); TimeUtils.formatDuration( - mAppProfiler.getLowRamTimeSinceIdleLocked(now), pw); + mAppProfiler.getLowRamTimeSinceIdleLPr(now), pw); pw.println(); pw.println(); @@ -9078,8 +9267,8 @@ public class ActivityManagerService extends IActivityManager.Stub mUserController.dump(pw); } - @GuardedBy("this") - void writeOtherProcessesInfoToProtoLocked(ProtoOutputStream proto, String dumpPackage, + @GuardedBy({"this", "mProcLock"}) + void writeOtherProcessesInfoToProtoLSP(ProtoOutputStream proto, String dumpPackage, int dumpAppId, int numPers) { for (int i = 0, size = mActiveInstrumentation.size(); i < size; i++) { ActiveInstrumentation ai = mActiveInstrumentation.get(i); @@ -9096,7 +9285,7 @@ public class ActivityManagerService extends IActivityManager.Stub if (dumpPackage != null) { synchronized (mPidsSelfLocked) { - for (int i=0; i=0; i--) { - ProcessRecord r = (ProcessRecord)list.get(i); + for (int i = list.size() - 1; i >= 0; i--) { + ProcessRecord r = (ProcessRecord) list.get(i); if (dumpPackage != null && !dumpPackage.equals(r.info.packageName)) { continue; } @@ -9595,8 +9783,8 @@ public class ActivityManagerService extends IActivityManager.Stub ArrayList collectProcesses(PrintWriter pw, int start, boolean allPkgs, String[] args) { - synchronized (this) { - return mProcessList.collectProcessesLocked(start, allPkgs, args); + synchronized (mProcLock) { + return mProcessList.collectProcessesLOSP(start, allPkgs, args); } } @@ -9615,13 +9803,15 @@ public class ActivityManagerService extends IActivityManager.Stub for (int i = procs.size() - 1 ; i >= 0 ; i--) { ProcessRecord r = procs.get(i); - if (r.thread != null) { - pw.println("\n** Graphics info for pid " + r.pid + " [" + r.processName + "] **"); + final int pid = r.getPid(); + final IApplicationThread thread = r.getThread(); + if (thread != null) { + pw.println("\n** Graphics info for pid " + pid + " [" + r.processName + "] **"); pw.flush(); try { TransferPipe tp = new TransferPipe(); try { - r.thread.dumpGfxInfo(tp.getWriteFd(), args); + thread.dumpGfxInfo(tp.getWriteFd(), args); tp.go(fd); } finally { tp.kill(); @@ -9648,13 +9838,15 @@ public class ActivityManagerService extends IActivityManager.Stub for (int i = procs.size() - 1; i >= 0; i--) { ProcessRecord r = procs.get(i); - if (r.thread != null) { - pw.println("\n\n** Cache info for pid " + r.pid + " [" + r.processName + "] **"); + final int pid = r.getPid(); + final IApplicationThread thread = r.getThread(); + if (thread != null) { + pw.println("\n\n** Cache info for pid " + pid + " [" + r.processName + "] **"); pw.flush(); try { TransferPipe tp = new TransferPipe(); try { - r.thread.dumpCacheInfo(tp.getWriteFd(), args); + thread.dumpCacheInfo(tp.getWriteFd(), args); tp.go(fd); } finally { tp.kill(); @@ -9681,13 +9873,15 @@ public class ActivityManagerService extends IActivityManager.Stub for (int i = procs.size() - 1 ; i >= 0 ; i--) { ProcessRecord r = procs.get(i); - if (r.thread != null) { - pw.println("\n** Database info for pid " + r.pid + " [" + r.processName + "] **"); + final int pid = r.getPid(); + final IApplicationThread thread = r.getThread(); + if (thread != null) { + pw.println("\n** Database info for pid " + pid + " [" + r.processName + "] **"); pw.flush(); try { TransferPipe tp = new TransferPipe(); try { - r.thread.dumpDbInfo(tp.getWriteFd(), args); + thread.dumpDbInfo(tp.getWriteFd(), args); tp.go(fd); } finally { tp.kill(); @@ -10150,10 +10344,10 @@ public class ActivityManagerService extends IActivityManager.Stub final int pid; final int oomAdj; final boolean hasActivities; - synchronized (this) { - thread = r.thread; - pid = r.pid; - oomAdj = r.getSetAdjWithServices(); + synchronized (mProcLock) { + thread = r.getThread(); + pid = r.getPid(); + oomAdj = r.mState.getSetAdjWithServices(); hasActivities = r.hasActivities(); } if (thread != null) { @@ -10224,8 +10418,8 @@ public class ActivityManagerService extends IActivityManager.Stub final long myTotalRss = mi.getTotalRss(); final long myTotalSwapPss = mi.getTotalSwappedOutPss(); - synchronized (this) { - if (r.thread != null && oomAdj == r.getSetAdjWithServices()) { + synchronized (mProcLock) { + if (r.getThread() != null && oomAdj == r.mState.getSetAdjWithServices()) { // Record this for posterity if the process has been stable. r.mProfile.addPss(myTotalPss, myTotalUss, myTotalRss, true, reportType, endTime - startTime); @@ -10735,10 +10929,10 @@ public class ActivityManagerService extends IActivityManager.Stub final int pid; final int oomAdj; final boolean hasActivities; - synchronized (this) { - thread = r.thread; - pid = r.pid; - oomAdj = r.getSetAdjWithServices(); + synchronized (mProcLock) { + thread = r.getThread(); + pid = r.getPid(); + oomAdj = r.mState.getSetAdjWithServices(); hasActivities = r.hasActivities(); } if (thread == null) { @@ -10804,8 +10998,8 @@ public class ActivityManagerService extends IActivityManager.Stub final long myTotalRss = mi.getTotalRss(); final long myTotalSwapPss = mi.getTotalSwappedOutPss(); - synchronized (this) { - if (r.thread != null && oomAdj == r.getSetAdjWithServices()) { + synchronized (mProcLock) { + if (r.getThread() != null && oomAdj == r.mState.getSetAdjWithServices()) { // Record this for posterity if the process has been stable. r.mProfile.addPss(myTotalPss, myTotalUss, myTotalRss, true, reportType, endTime - startTime); @@ -11144,96 +11338,26 @@ public class ActivityManagerService extends IActivityManager.Stub * app that was passed in must remain on the process lists. */ @GuardedBy("this") - final boolean cleanUpApplicationRecordLocked(ProcessRecord app, + final boolean cleanUpApplicationRecordLocked(ProcessRecord app, int pid, boolean restarting, boolean allowRestart, int index, boolean replacingPid) { - if (index >= 0) { - removeLruProcessLocked(app); - ProcessList.remove(app.pid); - } + boolean restart; + synchronized (mProcLock) { + if (index >= 0) { + removeLruProcessLocked(app); + ProcessList.remove(pid); + } + restart = app.onCleanupApplicationRecordLSP(mProcessStats, allowRestart); + } mAppProfiler.onCleanupApplicationRecordLocked(app); - - // Dismiss any open dialogs. - app.getDialogController().clearAllErrorDialogs(); - - app.setCrashing(false); - app.setNotResponding(false); - - app.resetPackageList(mProcessStats); - app.unlinkDeathRecipient(); - app.makeInactive(mProcessStats); - app.waitingToKill = null; - app.forcingToImportant = null; - updateProcessForegroundLocked(app, false, 0, false); - app.setHasForegroundActivities(false); - app.hasShownUi = false; - app.treatLikeActivity = false; - app.hasAboveClient = false; - app.setHasClientActivities(false); - - mServices.killServicesLocked(app, allowRestart); - mPhantomProcessList.onAppDied(app.pid); - - boolean restart = false; - - // Remove published content providers. - for (int i = app.pubProviders.size() - 1; i >= 0; i--) { - ContentProviderRecord cpr = app.pubProviders.valueAt(i); - if (cpr.proc != app) { - // If the hosting process record isn't really us, bail out - continue; - } - final boolean alwaysRemove = app.bad || !allowRestart; - final boolean inLaunching = mCpHelper.removeDyingProviderLocked(app, cpr, alwaysRemove); - if (!alwaysRemove && inLaunching && cpr.hasConnectionOrHandle()) { - // We left the provider in the launching list, need to - // restart it. - restart = true; - } - - cpr.provider = null; - cpr.setProcess(null); - } - app.pubProviders.clear(); - - // Take care of any launching providers waiting for this process. - if (mCpHelper.cleanupAppInLaunchingProvidersLocked(app, false)) { - mProcessList.noteProcessDiedLocked(app); - restart = true; - } - - // Unregister from connected content providers. - if (!app.conProviders.isEmpty()) { - for (int i = app.conProviders.size() - 1; i >= 0; i--) { - ContentProviderConnection conn = app.conProviders.get(i); - conn.provider.connections.remove(conn); - stopAssociationLocked(app.uid, app.processName, conn.provider.uid, - conn.provider.appInfo.longVersionCode, conn.provider.name, - conn.provider.info.processName); - } - app.conProviders.clear(); - } - - // At this point there may be remaining entries in mLaunchingProviders - // where we were the only one waiting, so they are no longer of use. - // Look for these and clean up if found. - // XXX Commented out for now. Trying to figure out a way to reproduce - // the actual situation to identify what is actually going on. - if (false) { - mCpHelper.cleanupLaunchingProvidersLocked(); - } - skipCurrentReceiverLocked(app); - - // Unregister any receivers. - for (int i = app.receivers.size() - 1; i >= 0; i--) { - removeReceiverLocked(app.receivers.valueAt(i)); - } - app.receivers.clear(); + updateProcessForegroundLocked(app, false, 0, false); + mServices.killServicesLocked(app, allowRestart); + mPhantomProcessList.onAppDied(pid); // If the app is undergoing backup, tell the backup manager about it final BackupRecord backupTarget = mBackupTargets.get(app.userId); - if (backupTarget != null && app.pid == backupTarget.app.pid) { + if (backupTarget != null && pid == backupTarget.app.getPid()) { if (DEBUG_BACKUP || DEBUG_CLEANUP) Slog.d(TAG_CLEANUP, "App " + backupTarget.appInfo + " died during backup"); mHandler.post(new Runnable() { @@ -11250,9 +11374,9 @@ public class ActivityManagerService extends IActivityManager.Stub }); } - mProcessList.scheduleDispatchProcessDiedLocked(app.pid, app.info.uid); + mProcessList.scheduleDispatchProcessDiedLocked(pid, app.info.uid); - // If this is a precede instance of another process instance + // If this is a preceding instance of another process instance allowRestart = true; synchronized (app) { if (app.mSuccessor != null) { @@ -11260,13 +11384,13 @@ public class ActivityManagerService extends IActivityManager.Stub // because we have created a new one already. allowRestart = false; // If it's persistent, add the successor to mPersistentStartingProcesses - if (app.isPersistent() && !app.removed) { + if (app.isPersistent() && !app.isRemoved()) { if (mPersistentStartingProcesses.indexOf(app.mSuccessor) < 0) { mPersistentStartingProcesses.add(app.mSuccessor); } } // clean up the field so the successor's proc starter could proceed. - app.mSuccessor.mPrecedence = null; + app.mSuccessor.mPredecessor = null; app.mSuccessor = null; // Notify if anyone is waiting for it. app.notifyAll(); @@ -11286,7 +11410,7 @@ public class ActivityManagerService extends IActivityManager.Stub mProcessList.removeProcessNameLocked(app.processName, app.uid, app); } mAtmInternal.clearHeavyWeightProcessIfEquals(app.getWindowProcessController()); - } else if (!app.removed) { + } else if (!app.isRemoved()) { // This app is persistent, so we need to keep its record around. // If it is not already on the pending app list, add it there // and start a new process for it. @@ -11306,7 +11430,7 @@ public class ActivityManagerService extends IActivityManager.Stub // We have components that still need to be running in the // process, so re-launch it. if (index < 0) { - ProcessList.remove(app.pid); + ProcessList.remove(pid); } // Remove provider publish timeout because we will start a new timeout when the @@ -11314,14 +11438,13 @@ public class ActivityManagerService extends IActivityManager.Stub mHandler.removeMessages(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG, app); mProcessList.addProcessNameLocked(app); - app.pendingStart = false; - mProcessList.startProcessLocked(app, - new HostingRecord("restart", app.processName), + app.setPendingStart(false); + mProcessList.startProcessLocked(app, new HostingRecord("restart", app.processName), ZYGOTE_POLICY_FLAG_EMPTY); return true; - } else if (app.pid > 0 && app.pid != MY_PID) { + } else if (pid > 0 && pid != MY_PID) { // Goodbye! - removePidLocked(app); + removePidLocked(pid, app); mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app); mBatteryStatsService.noteProcessFinish(app.processName, app.info.uid); if (app.isolated) { @@ -11660,12 +11783,12 @@ public class ActivityManagerService extends IActivityManager.Stub // process after the full backup is done and the ProcessRecord will vaporize anyway. if (UserHandle.isApp(app.uid) && backupMode == ApplicationThreadConstants.BACKUP_MODE_FULL) { - proc.inFullBackup = true; + proc.setInFullBackup(true); } r.app = proc; final BackupRecord backupTarget = mBackupTargets.get(targetUserId); oldBackupUid = backupTarget != null ? backupTarget.appInfo.uid : -1; - newBackupUid = proc.inFullBackup ? r.appInfo.uid : -1; + newBackupUid = proc.isInFullBackup() ? r.appInfo.uid : -1; mBackupTargets.put(targetUserId, r); // Try not to kill the process during backup @@ -11673,10 +11796,11 @@ public class ActivityManagerService extends IActivityManager.Stub // If the process is already attached, schedule the creation of the backup agent now. // If it is not yet live, this will be done when it attaches to the framework. - if (proc.thread != null) { + final IApplicationThread thread = proc.getThread(); + if (thread != null) { if (DEBUG_BACKUP) Slog.v(TAG_BACKUP, "Agent proc already running: " + proc); try { - proc.thread.scheduleCreateBackupAgent(app, + thread.scheduleCreateBackupAgent(app, compatibilityInfoForPackage(app), backupMode, targetUserId, operationType); } catch (RemoteException e) { @@ -11786,14 +11910,15 @@ public class ActivityManagerService extends IActivityManager.Stub // Not backing this app up any more; reset its OOM adjustment final ProcessRecord proc = backupTarget.app; updateOomAdjLocked(proc, true, OomAdjuster.OOM_ADJ_REASON_NONE); - proc.inFullBackup = false; + proc.setInFullBackup(false); oldBackupUid = backupTarget != null ? backupTarget.appInfo.uid : -1; // If the app crashed during backup, 'thread' will be null here - if (proc.thread != null) { + final IApplicationThread thread = proc.getThread(); + if (thread != null) { try { - proc.thread.scheduleDestroyBackupAgent(appInfo, + thread.scheduleDestroyBackupAgent(appInfo, compatibilityInfoForPackage(appInfo), userId); } catch (Exception e) { Slog.e(TAG, "Exception when unbinding backup agent:"); @@ -11888,7 +12013,7 @@ public class ActivityManagerService extends IActivityManager.Stub boolean instantApp; synchronized(this) { if (caller != null) { - callerApp = getRecordForAppLocked(caller); + callerApp = getRecordForAppLOSP(caller); if (callerApp == null) { throw new SecurityException( "Unable to find app for caller " + caller @@ -11902,7 +12027,7 @@ public class ActivityManagerService extends IActivityManager.Stub + " is not running in process " + callerApp); } callingUid = callerApp.info.uid; - callingPid = callerApp.pid; + callingPid = callerApp.getPid(); } else { callerPackage = null; callingUid = Binder.getCallingUid(); @@ -11971,8 +12096,9 @@ public class ActivityManagerService extends IActivityManager.Stub } synchronized (this) { - if (callerApp != null && (callerApp.thread == null - || callerApp.thread.asBinder() != caller.asBinder())) { + IApplicationThread thread; + if (callerApp != null && ((thread = callerApp.getThread()) == null + || thread.asBinder() != caller.asBinder())) { // Original caller already died return null; } @@ -11981,13 +12107,13 @@ public class ActivityManagerService extends IActivityManager.Stub rl = new ReceiverList(this, callerApp, callingPid, callingUid, userId, receiver); if (rl.app != null) { - final int totalReceiversForApp = rl.app.receivers.size(); + final int totalReceiversForApp = rl.app.mReceivers.numberOfReceivers(); if (totalReceiversForApp >= MAX_RECEIVERS_ALLOWED_PER_APP) { throw new IllegalStateException("Too many receivers, total of " + totalReceiversForApp + ", registered for pid: " + rl.pid + ", callerPackage: " + callerPackage); } - rl.app.receivers.add(rl); + rl.app.mReceivers.addReceiver(rl); } else { try { receiver.asBinder().linkToDeath(rl, 0); @@ -12073,7 +12199,7 @@ public class ActivityManagerService extends IActivityManager.Stub } if (rl.app != null) { - rl.app.receivers.remove(rl); + rl.app.mReceivers.removeReceiver(rl); } removeReceiverLocked(rl); if (rl.linkedToDeath) { @@ -12372,7 +12498,7 @@ public class ActivityManagerService extends IActivityManager.Stub } } if (brOptions.isDontSendToRestrictedApps() - && !isUidActiveLocked(callingUid) + && !isUidActiveLOSP(callingUid) && isBackgroundRestrictedNoCheck(callingUid, callerPackage)) { Slog.i(TAG, "Not sending broadcast " + action + " - app " + callerPackage + " has background restrictions"); @@ -12579,12 +12705,14 @@ public class ActivityManagerService extends IActivityManager.Stub if (killProcess) { final int extraUid = intent.getIntExtra(Intent.EXTRA_UID, -1); - mProcessList.killPackageProcessesLocked(ssp, - UserHandle.getAppId(extraUid), - userId, ProcessList.INVALID_ADJ, - ApplicationExitInfo.REASON_USER_REQUESTED, - ApplicationExitInfo.SUBREASON_UNKNOWN, - "change " + ssp); + synchronized (mProcLock) { + mProcessList.killPackageProcessesLSP(ssp, + UserHandle.getAppId(extraUid), + userId, ProcessList.INVALID_ADJ, + ApplicationExitInfo.REASON_USER_REQUESTED, + ApplicationExitInfo.SUBREASON_UNKNOWN, + "change " + ssp); + } } cleanupDisabledPackageComponentsLocked(ssp, userId, intent.getStringArrayExtra( @@ -12728,7 +12856,7 @@ public class ActivityManagerService extends IActivityManager.Stub Intent.ACTION_PACKAGE_REPLACED.equals(action)) { final int uid = getUidFromIntent(intent); if (uid != -1) { - final UidRecord uidRec = mProcessList.getUidRecordLocked(uid); + final UidRecord uidRec = mProcessList.getUidRecordLOSP(uid); if (uidRec != null) { uidRec.updateHasInternetPermission(); } @@ -13113,7 +13241,7 @@ public class ActivityManagerService extends IActivityManager.Stub synchronized(this) { intent = verifyBroadcastLocked(intent); - final ProcessRecord callerApp = getRecordForAppLocked(caller); + final ProcessRecord callerApp = getRecordForAppLOSP(caller); final int callingPid = Binder.getCallingPid(); final int callingUid = Binder.getCallingUid(); @@ -13353,27 +13481,29 @@ public class ActivityManagerService extends IActivityManager.Stub final long origId = Binder.clearCallingIdentity(); ProcessRecord app; - if (noRestart) { - app = getProcessRecordLocked(ai.processName, ai.uid, true); - } else { - // Instrumentation can kill and relaunch even persistent processes - forceStopPackageLocked(ii.targetPackage, -1, true, false, true, true, false, userId, - "start instr"); - // Inform usage stats to make the target package active - if (mUsageStatsService != null) { - mUsageStatsService.reportEvent(ii.targetPackage, userId, - UsageEvents.Event.SYSTEM_INTERACTION); + synchronized (mProcLock) { + if (noRestart) { + app = getProcessRecordLocked(ai.processName, ai.uid, true); + } else { + // Instrumentation can kill and relaunch even persistent processes + forceStopPackageLocked(ii.targetPackage, -1, true, false, true, true, false, + userId, "start instr"); + // Inform usage stats to make the target package active + if (mUsageStatsService != null) { + mUsageStatsService.reportEvent(ii.targetPackage, userId, + UsageEvents.Event.SYSTEM_INTERACTION); + } + app = addAppLocked(ai, defProcess, false, disableHiddenApiChecks, abiOverride, + ZYGOTE_POLICY_FLAG_EMPTY); } - app = addAppLocked(ai, defProcess, false, disableHiddenApiChecks, abiOverride, - ZYGOTE_POLICY_FLAG_EMPTY); - } - app.setActiveInstrumentation(activeInstr); - activeInstr.mFinished = false; - activeInstr.mSourceUid = callingUid; - activeInstr.mRunningProcesses.add(app); - if (!mActiveInstrumentation.contains(activeInstr)) { - mActiveInstrumentation.add(activeInstr); + app.setActiveInstrumentation(activeInstr); + activeInstr.mFinished = false; + activeInstr.mSourceUid = callingUid; + activeInstr.mRunningProcesses.add(app); + if (!mActiveInstrumentation.contains(activeInstr)) { + mActiveInstrumentation.add(activeInstr); + } } if ((flags & INSTR_FLAG_DISABLE_ISOLATED_STORAGE) != 0) { @@ -13400,7 +13530,7 @@ public class ActivityManagerService extends IActivityManager.Stub } try { - pr.thread.instrumentWithoutRestart( + pr.getThread().instrumentWithoutRestart( activeInstr.mClass, activeInstr.mArguments, activeInstr.mWatcher, @@ -13460,7 +13590,7 @@ public class ActivityManagerService extends IActivityManager.Stub } synchronized(this) { - ProcessRecord app = getRecordForAppLocked(target); + ProcessRecord app = getRecordForAppLOSP(target); if (app == null) { Slog.w(TAG, "addInstrumentationResults: no app for " + target); return; @@ -13482,36 +13612,38 @@ public class ActivityManagerService extends IActivityManager.Stub return; } - if (!instr.mFinished) { - if (instr.mWatcher != null) { - Bundle finalResults = instr.mCurResults; - if (finalResults != null) { - if (instr.mCurResults != null && results != null) { - finalResults.putAll(results); + synchronized (mProcLock) { + if (!instr.mFinished) { + if (instr.mWatcher != null) { + Bundle finalResults = instr.mCurResults; + if (finalResults != null) { + if (instr.mCurResults != null && results != null) { + finalResults.putAll(results); + } + } else { + finalResults = results; } - } else { - finalResults = results; + mInstrumentationReporter.reportFinished(instr.mWatcher, + instr.mClass, resultCode, finalResults); } - mInstrumentationReporter.reportFinished(instr.mWatcher, - instr.mClass, resultCode, finalResults); + + // Can't call out of the system process with a lock held, so post a message. + if (instr.mUiAutomationConnection != null) { + // Go back to the default mode of denying OP_NO_ISOLATED_STORAGE app op. + mAppOpsService.setMode(AppOpsManager.OP_NO_ISOLATED_STORAGE, app.uid, + app.info.packageName, AppOpsManager.MODE_ERRORED); + mAppOpsService.setAppOpsServiceDelegate(null); + getPermissionManagerInternal().stopShellPermissionIdentityDelegation(); + mHandler.obtainMessage(SHUTDOWN_UI_AUTOMATION_CONNECTION_MSG, + instr.mUiAutomationConnection).sendToTarget(); + } + instr.mFinished = true; } - // Can't call out of the system process with a lock held, so post a message. - if (instr.mUiAutomationConnection != null) { - // Go back to the default mode of denying OP_NO_ISOLATED_STORAGE app op. - mAppOpsService.setMode(AppOpsManager.OP_NO_ISOLATED_STORAGE, app.uid, - app.info.packageName, AppOpsManager.MODE_ERRORED); - mAppOpsService.setAppOpsServiceDelegate(null); - getPermissionManagerInternal().stopShellPermissionIdentityDelegation(); - mHandler.obtainMessage(SHUTDOWN_UI_AUTOMATION_CONNECTION_MSG, - instr.mUiAutomationConnection).sendToTarget(); - } - instr.mFinished = true; + instr.removeProcess(app); + app.setActiveInstrumentation(null); } - instr.removeProcess(app); - app.setActiveInstrumentation(null); - if (!instr.mNoRestart) { forceStopPackageLocked(app.info.packageName, -1, false, false, true, true, false, app.userId, @@ -13547,7 +13679,7 @@ public class ActivityManagerService extends IActivityManager.Stub } synchronized(this) { - ProcessRecord app = getRecordForAppLocked(target); + ProcessRecord app = getRecordForAppLOSP(target); if (app == null) { Slog.w(TAG, "finishInstrumentation: no app for " + target); return; @@ -13653,10 +13785,11 @@ public class ActivityManagerService extends IActivityManager.Stub // the current [or imminent] receiver on. boolean isReceivingBroadcastLocked(ProcessRecord app, ArraySet receivingQueues) { - final int N = app.curReceivers.size(); - if (N > 0) { - for (int i = 0; i < N; i++) { - receivingQueues.add(app.curReceivers.valueAt(i).queue); + final ProcessReceiverRecord prr = app.mReceivers; + final int numOfReceivers = prr.numberOfCurReceivers(); + if (numOfReceivers > 0) { + for (int i = 0; i < numOfReceivers; i++) { + receivingQueues.add(prr.getCurReceiverAt(i).queue); } return true; } @@ -13775,6 +13908,7 @@ public class ActivityManagerService extends IActivityManager.Stub /** * Returns true if things are idle enough to perform GCs. */ + @GuardedBy("this") final boolean canGcNowLocked() { for (BroadcastQueue q : mBroadcastQueues) { if (!q.mParallelBroadcasts.isEmpty() || !q.mDispatcher.isEmpty()) { @@ -13787,77 +13921,91 @@ public class ActivityManagerService extends IActivityManager.Stub private void checkExcessivePowerUsage() { updateCpuStatsNow(); - synchronized (this) { - boolean doCpuKills = true; - if (mLastPowerCheckUptime == 0) { - doCpuKills = false; - } + synchronized (mProcLock) { + final boolean doCpuKills = mLastPowerCheckUptime != 0; final long curUptime = SystemClock.uptimeMillis(); final long uptimeSince = curUptime - mLastPowerCheckUptime; mLastPowerCheckUptime = curUptime; - int i = mProcessList.mLruProcesses.size(); - while (i > 0) { - i--; - final ProcessRecord app = mProcessList.mLruProcesses.get(i); - if (app.setProcState >= ActivityManager.PROCESS_STATE_HOME) { + mProcessList.forEachLruProcessesLOSP(false, app -> { + if (app.mState.getSetProcState() >= ActivityManager.PROCESS_STATE_HOME) { int cpuLimit; - long checkDur = curUptime - app.getWhenUnimportant(); + long checkDur = curUptime - app.mState.getWhenUnimportant(); if (checkDur <= mConstants.POWER_CHECK_INTERVAL) { cpuLimit = mConstants.POWER_CHECK_MAX_CPU_1; } else if (checkDur <= (mConstants.POWER_CHECK_INTERVAL * 2) - || app.setProcState <= ActivityManager.PROCESS_STATE_HOME) { + || app.mState.getSetProcState() <= ActivityManager.PROCESS_STATE_HOME) { cpuLimit = mConstants.POWER_CHECK_MAX_CPU_2; } else if (checkDur <= (mConstants.POWER_CHECK_INTERVAL * 3)) { cpuLimit = mConstants.POWER_CHECK_MAX_CPU_3; } else { cpuLimit = mConstants.POWER_CHECK_MAX_CPU_4; } - synchronized (mAppProfiler.mProfilerLock) { - final ProcessProfileRecord profile = app.mProfile; - final long curCpuTime = profile.mCurCpuTime.get(); - final long lastCpuTime = profile.mLastCpuTime.get(); - if (lastCpuTime > 0) { - final long cputimeUsed = curCpuTime - lastCpuTime; - if (checkExcessivePowerUsageLocked(uptimeSince, doCpuKills, cputimeUsed, - app.processName, app.toShortString(), cpuLimit, app)) { - app.kill("excessive cpu " + cputimeUsed + " during " + uptimeSince - + " dur=" + checkDur + " limit=" + cpuLimit, - ApplicationExitInfo.REASON_EXCESSIVE_RESOURCE_USAGE, - ApplicationExitInfo.SUBREASON_EXCESSIVE_CPU, - true); - profile.reportExcessiveCpu(); - } - } - profile.mLastCpuTime.set(curCpuTime); - } + updateAppProcessCpuTimeLPr(uptimeSince, doCpuKills, checkDur, cpuLimit, app); // Also check the phantom processes if there is any - final long chkDur = checkDur; - final int cpuLmt = cpuLimit; - final boolean doKill = doCpuKills; - mPhantomProcessList.forEachPhantomProcessOfApp(app, r -> { - if (r.mLastCputime > 0) { - final long cputimeUsed = r.mCurrentCputime - r.mLastCputime; - if (checkExcessivePowerUsageLocked(uptimeSince, doKill, cputimeUsed, - app.processName, r.toString(), cpuLimit, app)) { - mPhantomProcessList.killPhantomProcessGroupLocked(app, r, - ApplicationExitInfo.REASON_EXCESSIVE_RESOURCE_USAGE, - ApplicationExitInfo.SUBREASON_EXCESSIVE_CPU, - "excessive cpu " + cputimeUsed + " during " - + uptimeSince + " dur=" + chkDur + " limit=" + cpuLmt); - return false; - } - } - r.mLastCputime = r.mCurrentCputime; - return true; - }); + updatePhantomProcessCpuTimeLPr( + uptimeSince, doCpuKills, checkDur, cpuLimit, app); } - } + }); } } - private boolean checkExcessivePowerUsageLocked(final long uptimeSince, boolean doCpuKills, + @GuardedBy("mProcLock") + private void updateAppProcessCpuTimeLPr(final long uptimeSince, final boolean doCpuKills, + final long checkDur, final int cpuLimit, final ProcessRecord app) { + synchronized (mAppProfiler.mProfilerLock) { + final ProcessProfileRecord profile = app.mProfile; + final long curCpuTime = profile.mCurCpuTime.get(); + final long lastCpuTime = profile.mLastCpuTime.get(); + if (lastCpuTime > 0) { + final long cpuTimeUsed = curCpuTime - lastCpuTime; + if (checkExcessivePowerUsageLPr(uptimeSince, doCpuKills, cpuTimeUsed, + app.processName, app.toShortString(), cpuLimit, app)) { + mHandler.post(() -> { + synchronized (ActivityManagerService.this) { + app.killLocked("excessive cpu " + cpuTimeUsed + " during " + + uptimeSince + " dur=" + checkDur + " limit=" + cpuLimit, + ApplicationExitInfo.REASON_EXCESSIVE_RESOURCE_USAGE, + ApplicationExitInfo.SUBREASON_EXCESSIVE_CPU, + true); + } + }); + profile.reportExcessiveCpu(); + } + } + + profile.mLastCpuTime.set(curCpuTime); + } + } + + @GuardedBy("mProcLock") + private void updatePhantomProcessCpuTimeLPr(final long uptimeSince, final boolean doCpuKills, + final long checkDur, final int cpuLimit, final ProcessRecord app) { + mPhantomProcessList.forEachPhantomProcessOfApp(app, r -> { + if (r.mLastCputime > 0) { + final long cpuTimeUsed = r.mCurrentCputime - r.mLastCputime; + if (checkExcessivePowerUsageLPr(uptimeSince, doCpuKills, cpuTimeUsed, + app.processName, r.toString(), cpuLimit, app)) { + mHandler.post(() -> { + synchronized (ActivityManagerService.this) { + mPhantomProcessList.killPhantomProcessGroupLocked(app, r, + ApplicationExitInfo.REASON_EXCESSIVE_RESOURCE_USAGE, + ApplicationExitInfo.SUBREASON_EXCESSIVE_CPU, + "excessive cpu " + cpuTimeUsed + " during " + + uptimeSince + " dur=" + checkDur + " limit=" + cpuLimit); + } + }); + return false; + } + } + r.mLastCputime = r.mCurrentCputime; + return true; + }); + } + + @GuardedBy("mProcLock") + private boolean checkExcessivePowerUsageLPr(final long uptimeSince, boolean doCpuKills, final long cputimeUsed, final String processName, final String description, final int cpuLimit, final ProcessRecord app) { if (DEBUG_POWER) { @@ -13902,19 +14050,20 @@ public class ActivityManagerService extends IActivityManager.Stub UserHandle.getUserId(uid), packages[0]); } + @GuardedBy("this") void enqueueUidChangeLocked(UidRecord uidRec, int uid, int change) { - uid = uidRec != null ? uidRec.uid : uid; + uid = uidRec != null ? uidRec.getUid() : uid; if (uid < 0) { throw new IllegalArgumentException("No UidRecord or uid"); } final int procState = uidRec != null - ? uidRec.setProcState : PROCESS_STATE_NONEXISTENT; + ? uidRec.getSetProcState() : 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); + final int capability = uidRec != null ? uidRec.getSetCapability() : 0; + final boolean ephemeral = uidRec != null ? uidRec.isEphemeral() : isEphemeralLocked(uid); - if (uidRec != null && !uidRec.idle && (change & UidRecord.CHANGE_GONE) != 0) { + if (uidRec != null && !uidRec.isIdle() && (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; @@ -13923,7 +14072,7 @@ public class ActivityManagerService extends IActivityManager.Stub uidRec == null ? null : uidRec.pendingChange, uid, change, procState, procStateSeq, capability, ephemeral); if (uidRec != null) { - uidRec.lastReportedChange = enqueuedChange; + uidRec.setLastReportedChange(enqueuedChange); uidRec.updateLastDispatchedProcStateSeq(enqueuedChange); } @@ -13946,21 +14095,21 @@ public class ActivityManagerService extends IActivityManager.Stub } } - final void setProcessTrackerStateLocked(ProcessRecord proc, int memFactor, long now) { - synchronized (mProcessStats.mLock) { - if (proc.thread != null) { - proc.mProfile.setProcessTrackerState( - proc.getReportedProcState(), memFactor, now); - } + @GuardedBy(anyOf = {"this", "mProcLock"}) + final void setProcessTrackerStateLOSP(ProcessRecord proc, int memFactor, long now) { + if (proc.getThread() != null) { + proc.mProfile.setProcessTrackerState( + proc.mState.getReportedProcState(), memFactor, now); } } @GuardedBy("this") final void updateProcessForegroundLocked(ProcessRecord proc, boolean isForeground, int fgServiceTypes, boolean oomAdj) { - if (isForeground != proc.hasForegroundServices() - || proc.getForegroundServiceTypes() != fgServiceTypes) { - proc.setHasForegroundServices(isForeground, fgServiceTypes); + final ProcessServiceRecord psr = proc.mServices; + if (isForeground != psr.hasForegroundServices() + || psr.getForegroundServiceTypes() != fgServiceTypes) { + psr.setHasForegroundServices(isForeground, fgServiceTypes); ArrayList curProcs = mForegroundPackages.get(proc.info.packageName, proc.info.uid); if (isForeground) { @@ -13986,9 +14135,9 @@ public class ActivityManagerService extends IActivityManager.Stub } } - proc.setReportedForegroundServiceTypes(fgServiceTypes); + psr.setReportedForegroundServiceTypes(fgServiceTypes); ProcessChangeItem item = mProcessList.enqueueProcessChangeItemLocked( - proc.pid, proc.info.uid); + proc.getPid(), proc.info.uid); item.changes |= ProcessChangeItem.CHANGE_FOREGROUND_SERVICES; item.foregroundServiceTypes = fgServiceTypes; } @@ -14031,7 +14180,6 @@ public class ActivityManagerService extends IActivityManager.Stub } finally { Binder.restoreCallingIdentity(identity); } - } } return r; @@ -14141,17 +14289,20 @@ public class ActivityManagerService extends IActivityManager.Stub final int appId = UserHandle.getAppId(pkgUid); for (int i = mProcessList.mActiveUids.size() - 1; i >= 0; i--) { final UidRecord uidRec = mProcessList.mActiveUids.valueAt(i); - final long bgTime = uidRec.lastBackgroundTime; - if (bgTime > 0 && !uidRec.idle) { - if (UserHandle.getAppId(uidRec.uid) == appId) { + final long bgTime = uidRec.getLastBackgroundTime(); + if (bgTime > 0 && !uidRec.isIdle()) { + final int uid = uidRec.getUid(); + if (UserHandle.getAppId(uid) == appId) { if (userId == UserHandle.USER_ALL - || userId == UserHandle.getUserId(uidRec.uid)) { - EventLogTags.writeAmUidIdle(uidRec.uid); - uidRec.idle = true; - uidRec.setIdle = true; - Slog.w(TAG, "Idling uid " + UserHandle.formatUid(uidRec.uid) + || userId == UserHandle.getUserId(uid)) { + EventLogTags.writeAmUidIdle(uid); + synchronized (mProcLock) { + uidRec.setIdle(true); + uidRec.setSetIdle(true); + } + Slog.w(TAG, "Idling uid " + UserHandle.formatUid(uid) + " from package " + packageName + " user " + userId); - doStopUidLocked(uidRec.uid, uidRec); + doStopUidLocked(uid, uidRec); } } } @@ -14176,11 +14327,11 @@ public class ActivityManagerService extends IActivityManager.Stub final void runInBackgroundDisabled(int uid) { synchronized (this) { - UidRecord uidRec = mProcessList.getUidRecordLocked(uid); + UidRecord uidRec = mProcessList.getUidRecordLOSP(uid); if (uidRec != null) { // This uid is actually running... should it be considered background now? - if (uidRec.idle) { - doStopUidLocked(uidRec.uid, uidRec); + if (uidRec.isIdle()) { + doStopUidLocked(uidRec.getUid(), uidRec); } } else { // This uid isn't actually running... still send a report about it being "stopped". @@ -14234,7 +14385,7 @@ public class ActivityManagerService extends IActivityManager.Stub + callerPid); return; } - if (!pr.mAllowlistManager) { + if (!pr.mServices.mAllowlistManager) { if (checkPermission(CHANGE_DEVICE_IDLE_TEMP_WHITELIST, callerPid, callerUid) != PackageManager.PERMISSION_GRANTED && checkPermission(START_ACTIVITIES_FROM_BACKGROUND, callerPid, callerUid) @@ -14258,13 +14409,15 @@ public class ActivityManagerService extends IActivityManager.Stub */ @GuardedBy("this") void tempAllowlistUidLocked(int targetUid, long duration, String tag, int type) { - mPendingTempAllowlist.put(targetUid, - new PendingTempAllowlist(targetUid, duration, tag, type)); - setUidTempAllowlistStateLocked(targetUid, true); - mUiHandler.obtainMessage(PUSH_TEMP_ALLOWLIST_UI_MSG).sendToTarget(); + synchronized (mProcLock) { + mPendingTempAllowlist.put(targetUid, + new PendingTempAllowlist(targetUid, duration, tag, type)); + setUidTempAllowlistStateLSP(targetUid, true); + mUiHandler.obtainMessage(PUSH_TEMP_ALLOWLIST_UI_MSG).sendToTarget(); - if (type == TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_ALLOWED) { - mFgsStartTempAllowList.add(targetUid, duration); + if (type == TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_ALLOWED) { + mFgsStartTempAllowList.add(targetUid, duration); + } } } @@ -14274,7 +14427,7 @@ public class ActivityManagerService extends IActivityManager.Stub // First copy out the pending changes... we need to leave them in the map for now, // in case someone needs to check what is coming up while we don't have the lock held. - synchronized(this) { + synchronized (mProcLock) { N = mPendingTempAllowlist.size(); list = new PendingTempAllowlist[N]; for (int i = 0; i < N; i++) { @@ -14294,25 +14447,27 @@ public class ActivityManagerService extends IActivityManager.Stub } // And now we can safely remove them from the map. - synchronized(this) { - for (int i = 0; i < N; i++) { - PendingTempAllowlist ptw = list[i]; - int index = mPendingTempAllowlist.indexOfKey(ptw.targetUid); - if (index >= 0 && mPendingTempAllowlist.valueAt(index) == ptw) { - mPendingTempAllowlist.removeAt(index); + synchronized (this) { + synchronized (mProcLock) { + for (int i = 0; i < N; i++) { + PendingTempAllowlist ptw = list[i]; + int index = mPendingTempAllowlist.indexOfKey(ptw.targetUid); + if (index >= 0 && mPendingTempAllowlist.valueAt(index) == ptw) { + mPendingTempAllowlist.removeAt(index); + } } } } } - @GuardedBy("this") - final void setAppIdTempAllowlistStateLocked(int uid, boolean onAllowlist) { - mOomAdjuster.setAppIdTempAllowlistStateLocked(uid, onAllowlist); + @GuardedBy({"this", "mProcLock"}) + final void setAppIdTempAllowlistStateLSP(int uid, boolean onAllowlist) { + mOomAdjuster.setAppIdTempAllowlistStateLSP(uid, onAllowlist); } - @GuardedBy("this") - final void setUidTempAllowlistStateLocked(int uid, boolean onAllowlist) { - mOomAdjuster.setUidTempAllowlistStateLocked(uid, onAllowlist); + @GuardedBy({"this", "mProcLock"}) + final void setUidTempAllowlistStateLSP(int uid, boolean onAllowlist) { + mOomAdjuster.setUidTempAllowlistStateLSP(uid, onAllowlist); } private void trimApplications(boolean forceFullOomAdj, String oomAdjReason) { @@ -14329,26 +14484,28 @@ public class ActivityManagerService extends IActivityManager.Stub for (int i = mProcessList.mRemovedProcesses.size() - 1; i >= 0; i--) { final ProcessRecord app = mProcessList.mRemovedProcesses.get(i); if (!app.hasActivitiesOrRecentTasks() - && app.curReceivers.isEmpty() && app.numberOfRunningServices() == 0) { - Slog.i( - TAG, "Exiting empty application process " - + app.toShortString() + " (" - + (app.thread != null ? app.thread.asBinder() : null) - + ")\n"); - if (app.pid > 0 && app.pid != MY_PID) { - app.kill("empty", + && app.mReceivers.numberOfCurReceivers() == 0 + && app.mServices.numberOfRunningServices() == 0) { + final IApplicationThread thread = app.getThread(); + Slog.i(TAG, "Exiting empty application process " + + app.toShortString() + " (" + + (thread != null ? thread.asBinder() : null) + + ")\n"); + final int pid = app.getPid(); + if (pid > 0 && pid != MY_PID) { + app.killLocked("empty", ApplicationExitInfo.REASON_OTHER, ApplicationExitInfo.SUBREASON_TRIM_EMPTY, false); - } else if (app.thread != null) { + } else if (thread != null) { try { - app.thread.scheduleExit(); + thread.scheduleExit(); } catch (Exception e) { // Ignore exceptions. } } didSomething = true; - cleanUpApplicationRecordLocked(app, false, true, -1, false /*replacingPid*/); + cleanUpApplicationRecordLocked(app, pid, false, true, -1, false /*replacingPid*/); mProcessList.mRemovedProcesses.remove(i); if (app.isPersistent()) { @@ -14369,7 +14526,7 @@ public class ActivityManagerService extends IActivityManager.Stub } /** This method sends the specified signal to each of the persistent apps */ - public void signalPersistentProcesses(int sig) throws RemoteException { + public void signalPersistentProcesses(final int sig) throws RemoteException { if (sig != SIGNAL_USR1) { throw new SecurityException("Only SIGNAL_USR1 is allowed"); } @@ -14380,13 +14537,12 @@ public class ActivityManagerService extends IActivityManager.Stub + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES); } - synchronized (this) { - for (int i = mProcessList.mLruProcesses.size() - 1 ; i >= 0 ; i--) { - ProcessRecord r = mProcessList.mLruProcesses.get(i); - if (r.thread != null && r.isPersistent()) { - sendSignal(r.pid, sig); + synchronized (mProcLock) { + mProcessList.forEachLruProcessesLOSP(false, app -> { + if (app.getThread() != null && app.isPersistent()) { + sendSignal(app.getPid(), sig); } - } + }); } } @@ -14405,21 +14561,23 @@ public class ActivityManagerService extends IActivityManager.Stub } ProcessRecord proc = null; - synchronized (this) { + synchronized (mProcLock) { if (process != null) { - proc = findProcessLocked(process, userId, "profileControl"); + proc = findProcessLOSP(process, userId, "profileControl"); } - if (start && (proc == null || proc.thread == null)) { + if (start && (proc == null || proc.getThread() == null)) { throw new IllegalArgumentException("Unknown process: " + process); } } + synchronized (mAppProfiler.mProfilerLock) { return mAppProfiler.profileControlLPf(proc, start, profilerInfo, profileType); } } - private ProcessRecord findProcessLocked(String process, int userId, String callName) { + @GuardedBy(anyOf = {"this", "mProcLock"}) + private ProcessRecord findProcessLOSP(String process, int userId, String callName) { userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId, true, ALLOW_FULL_ONLY, callName, null); ProcessRecord proc = null; @@ -14432,8 +14590,8 @@ public class ActivityManagerService extends IActivityManager.Stub } if (proc == null) { - ArrayMap> all - = mProcessList.mProcessNames.getMap(); + ArrayMap> all = + mProcessList.getProcessNamesLOSP().getMap(); SparseArray procs = all.get(process); if (procs != null && procs.size() > 0) { proc = procs.valueAt(0); @@ -14455,7 +14613,6 @@ public class ActivityManagerService extends IActivityManager.Stub @Override public boolean dumpHeap(String process, int userId, boolean managed, boolean mallocInfo, boolean runGc, String path, ParcelFileDescriptor fd, RemoteCallback finishCallback) { - try { // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to // its own permission (same as profileControl). @@ -14469,9 +14626,10 @@ public class ActivityManagerService extends IActivityManager.Stub throw new IllegalArgumentException("null fd"); } - synchronized (this) { - ProcessRecord proc = findProcessLocked(process, userId, "dumpHeap"); - if (proc == null || proc.thread == null) { + synchronized (mProcLock) { + ProcessRecord proc = findProcessLOSP(process, userId, "dumpHeap"); + IApplicationThread thread; + if (proc == null || (thread = proc.getThread()) == null) { throw new IllegalArgumentException("Unknown process: " + process); } @@ -14493,7 +14651,7 @@ public class ActivityManagerService extends IActivityManager.Stub } }, null); - proc.thread.dumpHeap(managed, mallocInfo, runGc, path, fd, intermediateCallback); + thread.dumpHeap(managed, mallocInfo, runGc, path, fd, intermediateCallback); fd = null; return true; } @@ -14548,8 +14706,8 @@ public class ActivityManagerService extends IActivityManager.Stub } void onCoreSettingsChange(Bundle settings) { - synchronized (this) { - mProcessList.updateCoreSettingsLocked(settings); + synchronized (mProcLock) { + mProcessList.updateCoreSettingsLOSP(settings); } } @@ -14701,8 +14859,9 @@ public class ActivityManagerService extends IActivityManager.Stub return info; } - private boolean processSanityChecksLocked(ProcessRecord process) { - if (process == null || process.thread == null) { + @GuardedBy("mProcLock") + private boolean processSanityChecksLPr(ProcessRecord process, IApplicationThread thread) { + if (process == null || thread == null) { return false; } @@ -14724,34 +14883,36 @@ public class ActivityManagerService extends IActivityManager.Stub + android.Manifest.permission.SET_ACTIVITY_WATCHER); } - synchronized (this) { + synchronized (mProcLock) { mBinderTransactionTrackingEnabled = true; - for (int i = 0; i < mProcessList.mLruProcesses.size(); i++) { - ProcessRecord process = mProcessList.mLruProcesses.get(i); - if (!processSanityChecksLocked(process)) { - continue; + mProcessList.forEachLruProcessesLOSP(true, process -> { + final IApplicationThread thread = process.getThread(); + if (!processSanityChecksLPr(process, thread)) { + return; } try { - process.thread.startBinderTracking(); + thread.startBinderTracking(); } catch (RemoteException e) { Log.v(TAG, "Process disappared"); } - } - return true; + }); } + return true; } - public boolean stopBinderTrackingAndDump(ParcelFileDescriptor fd) throws RemoteException { - try { - // TODO: hijacking SET_ACTIVITY_WATCHER, but should be changed to its own - // permission (same as profileControl). - if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER) - != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Requires permission " - + android.Manifest.permission.SET_ACTIVITY_WATCHER); - } + @Override + public boolean stopBinderTrackingAndDump(final ParcelFileDescriptor fd) throws RemoteException { + // TODO: hijacking SET_ACTIVITY_WATCHER, but should be changed to its own + // permission (same as profileControl). + if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Requires permission " + + android.Manifest.permission.SET_ACTIVITY_WATCHER); + } - synchronized (this) { + boolean closeFd = true; + try { + synchronized (mProcLock) { if (fd == null) { throw new IllegalArgumentException("null fd"); } @@ -14759,9 +14920,10 @@ public class ActivityManagerService extends IActivityManager.Stub PrintWriter pw = new FastPrintWriter(new FileOutputStream(fd.getFileDescriptor())); pw.println("Binder transaction traces for all processes.\n"); - for (ProcessRecord process : mProcessList.mLruProcesses) { - if (!processSanityChecksLocked(process)) { - continue; + mProcessList.forEachLruProcessesLOSP(true, process -> { + final IApplicationThread thread = process.getThread(); + if (!processSanityChecksLPr(process, thread)) { + return; } pw.println("Traces for process: " + process.processName); @@ -14769,7 +14931,7 @@ public class ActivityManagerService extends IActivityManager.Stub try { TransferPipe tp = new TransferPipe(); try { - process.thread.stopBinderTrackingAndDump(tp.getWriteFd()); + thread.stopBinderTrackingAndDump(tp.getWriteFd()); tp.go(fd.getFileDescriptor()); } finally { tp.kill(); @@ -14783,12 +14945,12 @@ public class ActivityManagerService extends IActivityManager.Stub process + ". Exception: " + e); pw.flush(); } - } - fd = null; + }); + closeFd = false; return true; } } finally { - if (fd != null) { + if (fd != null && closeFd) { try { fd.close(); } catch (IOException e) { @@ -14833,12 +14995,12 @@ public class ActivityManagerService extends IActivityManager.Stub @Override public void killForegroundAppsForUser(@UserIdInt int userId) { - synchronized (ActivityManagerService.this) { - final ArrayList procs = new ArrayList<>(); - final int NP = mProcessList.mProcessNames.getMap().size(); - for (int ip = 0; ip < NP; ip++) { + final ArrayList procs = new ArrayList<>(); + synchronized (mProcLock) { + final int numOfProcs = mProcessList.getProcessNamesLOSP().getMap().size(); + for (int ip = 0; ip < numOfProcs; ip++) { final SparseArray apps = - mProcessList.mProcessNames.getMap().valueAt(ip); + mProcessList.getProcessNamesLOSP().getMap().valueAt(ip); final int NA = apps.size(); for (int ia = 0; ia < NA; ia++) { final ProcessRecord app = apps.valueAt(ia); @@ -14846,19 +15008,23 @@ public class ActivityManagerService extends IActivityManager.Stub // We don't kill persistent processes. continue; } - if (app.removed - || (app.userId == userId && app.hasForegroundActivities())) { + if (app.isRemoved() + || (app.userId == userId && app.mState.hasForegroundActivities())) { procs.add(app); } } } + } - final int N = procs.size(); - for (int i = 0; i < N; i++) { - mProcessList.removeProcessLocked(procs.get(i), false, true, - ApplicationExitInfo.REASON_OTHER, - ApplicationExitInfo.SUBREASON_KILL_ALL_FG, - "kill all fg"); + final int numOfProcs = procs.size(); + if (numOfProcs > 0) { + synchronized (ActivityManagerService.this) { + for (int i = 0; i < numOfProcs; i++) { + mProcessList.removeProcessLocked(procs.get(i), false, true, + ApplicationExitInfo.REASON_OTHER, + ApplicationExitInfo.SUBREASON_KILL_ALL_FG, + "kill all fg"); + } } } } @@ -14904,8 +15070,10 @@ public class ActivityManagerService extends IActivityManager.Stub @Override public void setDeviceIdleWhitelist(int[] allAppids, int[] exceptIdleAppids) { synchronized (ActivityManagerService.this) { - mDeviceIdleAllowlist = allAppids; - mDeviceIdleExceptIdleAllowlist = exceptIdleAppids; + synchronized (mProcLock) { + mDeviceIdleAllowlist = allAppids; + mDeviceIdleExceptIdleAllowlist = exceptIdleAppids; + } } } @@ -14913,13 +15081,15 @@ public class ActivityManagerService extends IActivityManager.Stub public void updateDeviceIdleTempWhitelist(int[] appids, int changingUid, boolean adding, long durationMs, @TempAllowListType int type) { synchronized (ActivityManagerService.this) { - mDeviceIdleTempAllowlist = appids; - if (adding) { - if (type == TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_ALLOWED) { - mFgsStartTempAllowList.add(changingUid, durationMs); + synchronized (mProcLock) { + mDeviceIdleTempAllowlist = appids; + if (adding) { + if (type == TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_ALLOWED) { + mFgsStartTempAllowList.add(changingUid, durationMs); + } } + setAppIdTempAllowlistStateLSP(changingUid, adding); } - setAppIdTempAllowlistStateLocked(changingUid, adding); } } @@ -14957,10 +15127,10 @@ public class ActivityManagerService extends IActivityManager.Stub return; } } - if (pr.hasOverlayUi() == hasOverlayUi) { + if (pr.mState.hasOverlayUi() == hasOverlayUi) { return; } - pr.setHasOverlayUi(hasOverlayUi); + pr.mState.setHasOverlayUi(hasOverlayUi); //Slog.i(TAG, "Setting hasOverlayUi=" + pr.hasOverlayUi + " for pid=" + pid); updateOomAdjLocked(pr, true, OomAdjuster.OOM_ADJ_REASON_UI_VISIBILITY); } @@ -14978,8 +15148,8 @@ public class ActivityManagerService extends IActivityManager.Stub + uid + " seq: " + procStateSeq); } UidRecord record; - synchronized (ActivityManagerService.this) { - record = mProcessList.getUidRecordLocked(uid); + synchronized (mProcLock) { + record = mProcessList.getUidRecordLOSP(uid); if (record == null) { if (DEBUG_NETWORK) { Slog.d(TAG_NETWORK, "No active uidRecord for uid: " + uid @@ -15042,19 +15212,21 @@ public class ActivityManagerService extends IActivityManager.Stub @Override public boolean isUidActive(int uid) { - synchronized (ActivityManagerService.this) { - return isUidActiveLocked(uid); + synchronized (mProcLock) { + return isUidActiveLOSP(uid); } } @Override public List getMemoryStateForProcesses() { List processMemoryStates = new ArrayList<>(); - synchronized (mPidsSelfLocked) { - for (int i = 0, size = mPidsSelfLocked.size(); i < size; i++) { - final ProcessRecord r = mPidsSelfLocked.valueAt(i); - processMemoryStates.add( - new ProcessMemoryState(r.uid, r.pid, r.processName, r.curAdj)); + synchronized (mProcLock) { + synchronized (mPidsSelfLocked) { + for (int i = 0, size = mPidsSelfLocked.size(); i < size; i++) { + final ProcessRecord r = mPidsSelfLocked.valueAt(i); + processMemoryStates.add(new ProcessMemoryState( + r.uid, r.getPid(), r.processName, r.mState.getCurAdj())); + } } } return processMemoryStates; @@ -15094,14 +15266,14 @@ public class ActivityManagerService extends IActivityManager.Stub final WindowProcessController wpc = (WindowProcessController) procsToKill.get(i); final ProcessRecord pr = (ProcessRecord) wpc.mOwner; - if (pr.setSchedGroup == ProcessList.SCHED_GROUP_BACKGROUND - && pr.curReceivers.isEmpty()) { - pr.kill("remove task", ApplicationExitInfo.REASON_USER_REQUESTED, + if (pr.mState.getSetSchedGroup() == ProcessList.SCHED_GROUP_BACKGROUND + && pr.mReceivers.numberOfCurReceivers() == 0) { + pr.killLocked("remove task", ApplicationExitInfo.REASON_USER_REQUESTED, ApplicationExitInfo.SUBREASON_UNKNOWN, true); } else { // We delay killing processes that are not in the background or running a // receiver. - pr.waitingToKill = "remove task"; + pr.setWaitingToKill("remove task"); } } } @@ -15123,18 +15295,15 @@ public class ActivityManagerService extends IActivityManager.Stub public boolean hasRunningActivity(int uid, @Nullable String packageName) { if (packageName == null) return false; - synchronized (ActivityManagerService.this) { - for (int i = 0; i < mProcessList.mLruProcesses.size(); i++) { - final ProcessRecord pr = mProcessList.mLruProcesses.get(i); - if (pr.uid != uid) { - continue; + synchronized (mProcLock) { + return mProcessList.searchEachLruProcessesLOSP(true, app -> { + if (app.uid == uid + && app.getWindowProcessController().hasRunningActivity(packageName)) { + return Boolean.TRUE; } - if (pr.getWindowProcessController().hasRunningActivity(packageName)) { - return true; - } - } + return null; + }) != null; } - return false; } @Override @@ -15565,7 +15734,7 @@ public class ActivityManagerService extends IActivityManager.Stub } synchronized (mPidsSelfLocked) { final ProcessRecord pr = mPidsSelfLocked.get(pid); - return pr == null ? Zygote.MOUNT_EXTERNAL_NONE : pr.mountMode; + return pr == null ? Zygote.MOUNT_EXTERNAL_NONE : pr.getMountMode(); } } @@ -15596,19 +15765,17 @@ public class ActivityManagerService extends IActivityManager.Stub @Override public boolean hasRunningForegroundService(int uid, int foregroundServicetype) { synchronized (ActivityManagerService.this) { - for (int i = 0; i < mProcessList.mLruProcesses.size(); i++) { - final ProcessRecord pr = mProcessList.mLruProcesses.get(i); - if (pr.uid != uid) { - continue; + return mProcessList.searchEachLruProcessesLOSP(true, app -> { + if (app.uid != uid) { + return null; } - if ((pr.getForegroundServiceTypes() & foregroundServicetype) != 0) { - return true; + if ((app.mServices.getForegroundServiceTypes() & foregroundServicetype) != 0) { + return Boolean.TRUE; } - } + return null; + }) != null; } - - return false; } @Override @@ -15623,7 +15790,7 @@ public class ActivityManagerService extends IActivityManager.Stub @Override public boolean isUidCurrentlyInstrumented(int uid) { - synchronized (ActivityManagerService.this) { + synchronized (mProcLock) { for (int i = mActiveInstrumentation.size() - 1; i >= 0; i--) { ActiveInstrumentation activeInst = mActiveInstrumentation.get(i); if (!activeInst.mFinished && activeInst.mTargetInfo != null @@ -15775,8 +15942,8 @@ public class ActivityManagerService extends IActivityManager.Stub Slog.d(TAG_NETWORK, "Called from " + callingUid + " to wait for seq: " + procStateSeq); } UidRecord record; - synchronized (this) { - record = mProcessList.getUidRecordLocked(callingUid); + synchronized (mProcLock) { + record = mProcessList.getUidRecordLOSP(callingUid); if (record == null) { return; } @@ -15892,11 +16059,13 @@ public class ActivityManagerService extends IActivityManager.Stub } try { synchronized(this) { - mProcessList.killPackageProcessesLocked(packageName, UserHandle.getAppId(pkgUid), - userId, ProcessList.FOREGROUND_APP_ADJ, - ApplicationExitInfo.REASON_DEPENDENCY_DIED, - ApplicationExitInfo.SUBREASON_UNKNOWN, - "dep: " + packageName); + synchronized (mProcLock) { + mProcessList.killPackageProcessesLSP(packageName, UserHandle.getAppId(pkgUid), + userId, ProcessList.FOREGROUND_APP_ADJ, + ApplicationExitInfo.REASON_DEPENDENCY_DIED, + ApplicationExitInfo.SUBREASON_UNKNOWN, + "dep: " + packageName); + } } } finally { Binder.restoreCallingIdentity(callingId); @@ -15913,10 +16082,10 @@ public class ActivityManagerService extends IActivityManager.Stub enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION, "scheduleApplicationInfoChanged()"); - synchronized (this) { + synchronized (mProcLock) { final long origId = Binder.clearCallingIdentity(); try { - updateApplicationInfoLocked(packageNames, userId); + updateApplicationInfoLOSP(packageNames, userId); } finally { Binder.restoreCallingIdentity(origId); } @@ -15935,12 +16104,13 @@ public class ActivityManagerService extends IActivityManager.Stub ActivityThread.currentActivityThread().handleSystemApplicationInfoChanged(ai); } - void updateApplicationInfoLocked(@NonNull List packagesToUpdate, int userId) { + @GuardedBy(anyOf = {"this", "mProcLock"}) + private void updateApplicationInfoLOSP(@NonNull List packagesToUpdate, int userId) { final boolean updateFrameworkRes = packagesToUpdate.contains("android"); if (updateFrameworkRes) { PackageParser.readConfigUseRoundIcon(null); } - mProcessList.updateApplicationInfoLocked(packagesToUpdate, userId, updateFrameworkRes); + mProcessList.updateApplicationInfoLOSP(packagesToUpdate, userId, updateFrameworkRes); if (updateFrameworkRes) { // Update system server components that need to know about changed overlays. Because the @@ -15969,7 +16139,7 @@ public class ActivityManagerService extends IActivityManager.Stub final int batchSize; final float threshold; final BinderCallHeavyHitterListener listener; - synchronized (ActivityManagerService.this) { + synchronized (mProcLock) { if (mConstants.BINDER_HEAVY_HITTER_WATCHER_ENABLED) { // Default watcher takes precedence, ignore the auto sampler. mHandler.removeMessages(BINDER_HEAVYHITTER_AUTOSAMPLER_TIMEOUT_MSG); @@ -16006,7 +16176,7 @@ public class ActivityManagerService extends IActivityManager.Stub final int batchSize; final float threshold; final long now; - synchronized (ActivityManagerService.this) { + synchronized (mProcLock) { if (!mConstants.BINDER_HEAVY_HITTER_AUTO_SAMPLER_ENABLED) { // It's configured OFF return; @@ -16040,7 +16210,7 @@ public class ActivityManagerService extends IActivityManager.Stub * Stop the binder heavy hitter auto sampler after given timeout. */ private void handleBinderHeavyHitterAutoSamplerTimeOut() { - synchronized (ActivityManagerService.this) { + synchronized (mProcLock) { if (mConstants.BINDER_HEAVY_HITTER_WATCHER_ENABLED) { // The default watcher is ON, don't bother to stop it. return; @@ -16086,10 +16256,11 @@ public class ActivityManagerService extends IActivityManager.Stub */ public void attachAgent(String process, String path) { try { - synchronized (this) { - ProcessRecord proc = findProcessLocked(process, UserHandle.USER_SYSTEM, + synchronized (mProcLock) { + ProcessRecord proc = findProcessLOSP(process, UserHandle.USER_SYSTEM, "attachAgent"); - if (proc == null || proc.thread == null) { + IApplicationThread thread; + if (proc == null || (thread = proc.getThread()) == null) { throw new IllegalArgumentException("Unknown process: " + process); } @@ -16099,7 +16270,7 @@ public class ActivityManagerService extends IActivityManager.Stub } } - proc.thread.attachAgent(path); + thread.attachAgent(path); } } catch (RemoteException e) { throw new IllegalStateException("Process disappeared"); @@ -16168,7 +16339,7 @@ public class ActivityManagerService extends IActivityManager.Stub } // We allow delegation only to one instrumentation started from the shell - synchronized (ActivityManagerService.this) { + synchronized (mProcLock) { // If the delegate is already set up for the target UID, nothing to do. if (mAppOpsService.getAppOpsServiceDelegate() != null) { if (!(mAppOpsService.getAppOpsServiceDelegate() instanceof ShellDelegate)) { @@ -16214,7 +16385,7 @@ public class ActivityManagerService extends IActivityManager.Stub && UserHandle.getCallingAppId() != Process.ROOT_UID) { throw new SecurityException("Only the shell can delegate its permissions"); } - synchronized (ActivityManagerService.this) { + synchronized (mProcLock) { mAppOpsService.setAppOpsServiceDelegate(null); getPermissionManagerInternal().stopShellPermissionIdentityDelegation(); } @@ -16336,7 +16507,7 @@ public class ActivityManagerService extends IActivityManager.Stub if (!isCallerShell()) { throw new SecurityException("Only shell can call it"); } - synchronized (this) { + synchronized (mProcLock) { try { if (mLifeMonitorFds == null) { mLifeMonitorFds = ParcelFileDescriptor.createPipe(); diff --git a/services/core/java/com/android/server/am/AnrHelper.java b/services/core/java/com/android/server/am/AnrHelper.java index a7119d18117ab..34d9a60d78aae 100644 --- a/services/core/java/com/android/server/am/AnrHelper.java +++ b/services/core/java/com/android/server/am/AnrHelper.java @@ -160,7 +160,7 @@ class AnrHelper { } void appNotResponding(boolean onlyDumpSelf) { - mApp.appNotResponding(mActivityShortComponentName, mAppInfo, + mApp.mErrorState.appNotResponding(mActivityShortComponentName, mAppInfo, mParentShortComponentName, mParentProcess, mAboveSystem, mAnnotation, onlyDumpSelf); } diff --git a/services/core/java/com/android/server/am/AppErrorDialog.java b/services/core/java/com/android/server/am/AppErrorDialog.java index 779d37858ce2a..48222cb075cd2 100644 --- a/services/core/java/com/android/server/am/AppErrorDialog.java +++ b/services/core/java/com/android/server/am/AppErrorDialog.java @@ -38,6 +38,7 @@ import android.widget.TextView; final class AppErrorDialog extends BaseErrorDialog implements View.OnClickListener { private final ActivityManagerService mService; + private final ActivityManagerGlobalLock mProcLock; private final AppErrorResult mResult; private final ProcessRecord mProc; private final boolean mIsRestartable; @@ -63,6 +64,7 @@ final class AppErrorDialog extends BaseErrorDialog implements View.OnClickListen Resources res = context.getResources(); mService = service; + mProcLock = service.mProcLock; mProc = data.proc; mResult = data.result; mIsRestartable = (data.taskId != INVALID_TASK_ID || data.isRestartableForService) @@ -71,7 +73,7 @@ final class AppErrorDialog extends BaseErrorDialog implements View.OnClickListen BidiFormatter bidi = BidiFormatter.getInstance(); CharSequence name; - if ((mProc.getPkgList().size() == 1) + if (mProc.getPkgList().size() == 1 && (name = context.getPackageManager().getApplicationLabel(mProc.info)) != null) { setTitle(res.getString( data.repeating ? com.android.internal.R.string.aerr_application_repeated @@ -112,7 +114,7 @@ final class AppErrorDialog extends BaseErrorDialog implements View.OnClickListen LayoutInflater.from(context).inflate( com.android.internal.R.layout.app_error_dialog, frame, true); - final boolean hasReceiver = mProc.errorReportReceiver != null; + final boolean hasReceiver = mProc.mErrorState.getErrorReportReceiver() != null; final TextView restart = findViewById(com.android.internal.R.id.aerr_restart); restart.setOnClickListener(this); @@ -166,11 +168,11 @@ final class AppErrorDialog extends BaseErrorDialog implements View.OnClickListen } private void setResult(int result) { - synchronized (mService) { + synchronized (mProcLock) { if (mProc != null) { // Don't dismiss again since it leads to recursive call between dismiss and this // method. - mProc.getDialogController().clearCrashDialogs(false /* needDismiss */); + mProc.mErrorState.getDialogController().clearCrashDialogs(false /* needDismiss */); } } mResult.set(result); diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java index 7be54c29a218f..e5a5cff409b3e 100644 --- a/services/core/java/com/android/server/am/AppErrors.java +++ b/services/core/java/com/android/server/am/AppErrors.java @@ -72,6 +72,7 @@ class AppErrors { private static final String TAG = TAG_WITH_CLASS_NAME ? "AppErrors" : TAG_AM; private final ActivityManagerService mService; + private final ActivityManagerGlobalLock mProcLock; private final Context mContext; private final PackageWatchdog mPackageWatchdog; @@ -137,6 +138,7 @@ class AppErrors { AppErrors(Context context, ActivityManagerService service, PackageWatchdog watchdog) { context.assertRuntimeOverlayThemable(); mService = service; + mProcLock = service.mProcLock; mContext = context; mPackageWatchdog = watchdog; } @@ -154,17 +156,48 @@ class AppErrors { } } - void dumpDebug(ProtoOutputStream proto, long fieldId, String dumpPackage) { - synchronized (mBadProcessLock) { - final ProcessMap badProcesses = mBadProcesses; - if (mProcessCrashTimes.getMap().isEmpty() && badProcesses.getMap().isEmpty()) { - return; + @GuardedBy("mProcLock") + void dumpDebugLPr(ProtoOutputStream proto, long fieldId, String dumpPackage) { + final ProcessMap badProcesses = mBadProcesses; + if (mProcessCrashTimes.getMap().isEmpty() && badProcesses.getMap().isEmpty()) { + return; + } + + final long token = proto.start(fieldId); + final long now = SystemClock.uptimeMillis(); + proto.write(AppErrorsProto.NOW_UPTIME_MS, now); + + if (!badProcesses.getMap().isEmpty()) { + final ArrayMap> pmap = badProcesses.getMap(); + final int processCount = pmap.size(); + for (int ip = 0; ip < processCount; ip++) { + final long btoken = proto.start(AppErrorsProto.BAD_PROCESSES); + final String pname = pmap.keyAt(ip); + final SparseArray uids = pmap.valueAt(ip); + final int uidCount = uids.size(); + + proto.write(AppErrorsProto.BadProcess.PROCESS_NAME, pname); + for (int i = 0; i < uidCount; i++) { + final int puid = uids.keyAt(i); + final ProcessRecord r = mService.getProcessNamesLOSP().get(pname, puid); + if (dumpPackage != null && (r == null + || !r.getPkgList().containsKey(dumpPackage))) { + continue; + } + final BadProcessInfo info = uids.valueAt(i); + final long etoken = proto.start(AppErrorsProto.BadProcess.ENTRIES); + proto.write(AppErrorsProto.BadProcess.Entry.UID, puid); + proto.write(AppErrorsProto.BadProcess.Entry.CRASHED_AT_MS, info.time); + proto.write(AppErrorsProto.BadProcess.Entry.SHORT_MSG, info.shortMsg); + proto.write(AppErrorsProto.BadProcess.Entry.LONG_MSG, info.longMsg); + proto.write(AppErrorsProto.BadProcess.Entry.STACK, info.stack); + proto.end(etoken); + } + proto.end(btoken); } + } - final long token = proto.start(fieldId); - final long now = SystemClock.uptimeMillis(); - proto.write(AppErrorsProto.NOW_UPTIME_MS, now); - + synchronized (mBadProcessLock) { if (!mProcessCrashTimes.getMap().isEmpty()) { final ArrayMap> pmap = mProcessCrashTimes.getMap(); final int procCount = pmap.size(); @@ -177,7 +210,7 @@ class AppErrors { proto.write(AppErrorsProto.ProcessCrashTime.PROCESS_NAME, pname); for (int i = 0; i < uidCount; i++) { final int puid = uids.keyAt(i); - final ProcessRecord r = mService.getProcessNames().get(pname, puid); + final ProcessRecord r = mService.getProcessNamesLOSP().get(pname, puid); if (dumpPackage != null && (r == null || !r.getPkgList().containsKey(dumpPackage))) { continue; @@ -190,44 +223,14 @@ class AppErrors { } proto.end(ctoken); } - } - - if (!badProcesses.getMap().isEmpty()) { - final ArrayMap> pmap = badProcesses.getMap(); - final int processCount = pmap.size(); - for (int ip = 0; ip < processCount; ip++) { - final long btoken = proto.start(AppErrorsProto.BAD_PROCESSES); - final String pname = pmap.keyAt(ip); - final SparseArray uids = pmap.valueAt(ip); - final int uidCount = uids.size(); - - proto.write(AppErrorsProto.BadProcess.PROCESS_NAME, pname); - for (int i = 0; i < uidCount; i++) { - final int puid = uids.keyAt(i); - final ProcessRecord r = mService.getProcessNames().get(pname, puid); - if (dumpPackage != null && (r == null - || !r.getPkgList().containsKey(dumpPackage))) { - continue; - } - final BadProcessInfo info = uids.valueAt(i); - final long etoken = proto.start(AppErrorsProto.BadProcess.ENTRIES); - proto.write(AppErrorsProto.BadProcess.Entry.UID, puid); - proto.write(AppErrorsProto.BadProcess.Entry.CRASHED_AT_MS, info.time); - proto.write(AppErrorsProto.BadProcess.Entry.SHORT_MSG, info.shortMsg); - proto.write(AppErrorsProto.BadProcess.Entry.LONG_MSG, info.longMsg); - proto.write(AppErrorsProto.BadProcess.Entry.STACK, info.stack); - proto.end(etoken); - } - proto.end(btoken); - } - } - - proto.end(token); } + + proto.end(token); } - boolean dumpLocked(FileDescriptor fd, PrintWriter pw, boolean needSep, String dumpPackage) { + @GuardedBy("mProcLock") + boolean dumpLPr(FileDescriptor fd, PrintWriter pw, boolean needSep, String dumpPackage) { final long now = SystemClock.uptimeMillis(); synchronized (mBadProcessLock) { if (!mProcessCrashTimes.getMap().isEmpty()) { @@ -240,9 +243,9 @@ class AppErrors { final int uidCount = uids.size(); for (int i = 0; i < uidCount; i++) { final int puid = uids.keyAt(i); - final ProcessRecord r = mService.getProcessNames().get(pname, puid); - if (dumpPackage != null && (r == null - || !r.getPkgList().containsKey(dumpPackage))) { + final ProcessRecord r = mService.getProcessNamesLOSP().get(pname, puid); + if (dumpPackage != null + && (r == null || !r.getPkgList().containsKey(dumpPackage))) { continue; } if (!printed) { @@ -271,7 +274,7 @@ class AppErrors { final int uidCount = uids.size(); for (int i = 0; i < uidCount; i++) { final int puid = uids.keyAt(i); - final ProcessRecord r = mService.getProcessNames().get(pname, puid); + final ProcessRecord r = mService.getProcessNamesLOSP().get(pname, puid); if (dumpPackage != null && (r == null || !r.getPkgList().containsKey(dumpPackage))) { continue; @@ -303,7 +306,7 @@ class AppErrors { final int uidCount = uids.size(); for (int i = 0; i < uidCount; i++) { final int puid = uids.keyAt(i); - final ProcessRecord r = mService.getProcessNames().get(pname, puid); + final ProcessRecord r = mService.getProcessNamesLOSP().get(pname, puid); if (dumpPackage != null && (r == null || !r.getPkgList().containsKey(dumpPackage))) { continue; @@ -330,14 +333,14 @@ class AppErrors { for (int pos = 0; pos < info.stack.length(); pos++) { if (info.stack.charAt(pos) == '\n') { pw.print(" "); - pw.write(info.stack, lastPos, pos-lastPos); + pw.write(info.stack, lastPos, pos - lastPos); pw.println(); - lastPos = pos+1; + lastPos = pos + 1; } } if (lastPos < info.stack.length()) { pw.print(" "); - pw.write(info.stack, lastPos, info.stack.length()-lastPos); + pw.write(info.stack, lastPos, info.stack.length() - lastPos); pw.println(); } } @@ -437,32 +440,38 @@ class AppErrors { } } + @GuardedBy("mService") void killAppAtUserRequestLocked(ProcessRecord app) { - ProcessRecord.ErrorDialogController controller = - app.getDialogController(); + ErrorDialogController controller = app.mErrorState.getDialogController(); int reasonCode = ApplicationExitInfo.REASON_ANR; int subReason = ApplicationExitInfo.SUBREASON_UNKNOWN; - if (controller.hasDebugWaitingDialog()) { - reasonCode = ApplicationExitInfo.REASON_OTHER; - subReason = ApplicationExitInfo.SUBREASON_WAIT_FOR_DEBUGGER; + synchronized (mProcLock) { + if (controller.hasDebugWaitingDialog()) { + reasonCode = ApplicationExitInfo.REASON_OTHER; + subReason = ApplicationExitInfo.SUBREASON_WAIT_FOR_DEBUGGER; + } + controller.clearAllErrorDialogs(); + killAppImmediateLSP(app, reasonCode, subReason, + "user-terminated", "user request after error"); } - - controller.clearAllErrorDialogs(); - killAppImmediateLocked(app, reasonCode, subReason, - "user-terminated", "user request after error"); } - private void killAppImmediateLocked(ProcessRecord app, int reasonCode, int subReason, + @GuardedBy({"mService", "mProcLock"}) + private void killAppImmediateLSP(ProcessRecord app, int reasonCode, int subReason, String reason, String killReason) { - app.setCrashing(false); - app.crashingReport = null; - app.setNotResponding(false); - app.notRespondingReport = null; - if (app.pid > 0 && app.pid != MY_PID) { - handleAppCrashLocked(app, reason, - null /*shortMsg*/, null /*longMsg*/, null /*stackTrace*/, null /*data*/); - app.kill(killReason, reasonCode, subReason, true); + final ProcessErrorStateRecord errState = app.mErrorState; + errState.setCrashing(false); + errState.setCrashingReport(null); + errState.setNotResponding(false); + errState.setNotRespondingReport(null); + final int pid = errState.mApp.getPid(); + if (pid > 0 && pid != MY_PID) { + synchronized (mBadProcessLock) { + handleAppCrashLSPB(app, reason, + null /*shortMsg*/, null /*longMsg*/, null /*stackTrace*/, null /*data*/); + } + app.killLocked(killReason, reasonCode, subReason, true); } } @@ -489,7 +498,7 @@ class AppErrors { if (uid >= 0 && p.uid != uid) { continue; } - if (p.pid == initialPid) { + if (p.getPid() == initialPid) { proc = p; break; } @@ -508,7 +517,7 @@ class AppErrors { return; } - proc.scheduleCrash(message); + proc.scheduleCrashLocked(message); if (force) { // If the app is responsive, the scheduled crash will happen as expected // and then the delayed summary kill will be a no-op. @@ -516,9 +525,11 @@ class AppErrors { mService.mHandler.postDelayed( () -> { synchronized (mService) { - killAppImmediateLocked(p, ApplicationExitInfo.REASON_OTHER, - ApplicationExitInfo.SUBREASON_INVALID_STATE, - "forced", "killed for invalid state"); + synchronized (mProcLock) { + killAppImmediateLSP(p, ApplicationExitInfo.REASON_OTHER, + ApplicationExitInfo.SUBREASON_INVALID_STATE, + "forced", "killed for invalid state"); + } } }, 5000L); @@ -627,52 +638,54 @@ class AppErrors { if (res == AppErrorDialog.TIMEOUT || res == AppErrorDialog.CANCEL) { res = AppErrorDialog.FORCE_QUIT; } - if (res == AppErrorDialog.MUTE) { - synchronized (mBadProcessLock) { - stopReportingCrashesLBp(r); - } - } - if (res == AppErrorDialog.RESTART) { - synchronized (mService) { - mService.mProcessList.removeProcessLocked(r, false, true, - ApplicationExitInfo.REASON_CRASH, "crash"); - } - if (taskId != INVALID_TASK_ID) { - try { - mService.startActivityFromRecents(taskId, - ActivityOptions.makeBasic().toBundle()); - } catch (IllegalArgumentException e) { - // Hmm...that didn't work. Task should either be in recents or associated - // with a stack. - Slog.e(TAG, "Could not restart taskId=" + taskId, e); + switch (res) { + case AppErrorDialog.MUTE: + synchronized (mBadProcessLock) { + stopReportingCrashesLBp(r); } - } - } - if (res == AppErrorDialog.FORCE_QUIT) { - final long orig = Binder.clearCallingIdentity(); - try { - // Kill it with fire! - mService.mAtmInternal.onHandleAppCrash(r.getWindowProcessController()); - if (!r.isPersistent()) { - synchronized (mService) { - mService.mProcessList.removeProcessLocked(r, false, false, - ApplicationExitInfo.REASON_CRASH, "crash"); + break; + case AppErrorDialog.RESTART: + synchronized (mService) { + mService.mProcessList.removeProcessLocked(r, false, true, + ApplicationExitInfo.REASON_CRASH, "crash"); + } + if (taskId != INVALID_TASK_ID) { + try { + mService.startActivityFromRecents(taskId, + ActivityOptions.makeBasic().toBundle()); + } catch (IllegalArgumentException e) { + // Hmm...that didn't work. Task should either be in recents or associated + // with a stack. + Slog.e(TAG, "Could not restart taskId=" + taskId, e); } - mService.mAtmInternal.resumeTopActivities(false /* scheduleIdle */); } - } finally { - Binder.restoreCallingIdentity(orig); - } - } - if (res == AppErrorDialog.APP_INFO) { - appErrorIntent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); - appErrorIntent.setData(Uri.parse("package:" + r.info.packageName)); - appErrorIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - } - if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) { - synchronized (mService) { - appErrorIntent = createAppErrorIntentLocked(r, timeMillis, crashInfo); - } + break; + case AppErrorDialog.FORCE_QUIT: + final long orig = Binder.clearCallingIdentity(); + try { + // Kill it with fire! + mService.mAtmInternal.onHandleAppCrash(r.getWindowProcessController()); + if (!r.isPersistent()) { + synchronized (mService) { + mService.mProcessList.removeProcessLocked(r, false, false, + ApplicationExitInfo.REASON_CRASH, "crash"); + } + mService.mAtmInternal.resumeTopActivities(false /* scheduleIdle */); + } + } finally { + Binder.restoreCallingIdentity(orig); + } + break; + case AppErrorDialog.APP_INFO: + appErrorIntent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + appErrorIntent.setData(Uri.parse("package:" + r.info.packageName)); + appErrorIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + break; + case AppErrorDialog.FORCE_QUIT_AND_REPORT: + synchronized (mProcLock) { + appErrorIntent = createAppErrorIntentLOSP(r, timeMillis, crashInfo); + } + break; } if (appErrorIntent != null) { @@ -684,13 +697,14 @@ class AppErrors { } } + @GuardedBy("mService") private boolean handleAppCrashInActivityController(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo, String shortMsg, String longMsg, String stackTrace, long timeMillis, int callingPid, int callingUid) { String name = r != null ? r.processName : null; - int pid = r != null ? r.pid : callingPid; + int pid = r != null ? r.getPid() : callingPid; int uid = r != null ? r.info.uid : callingUid; return mService.mAtmInternal.handleAppCrashInActivityController( @@ -703,7 +717,7 @@ class AppErrors { Slog.w(TAG, "Force-killing crashed app " + name + " at watcher's request"); if (r != null) { if (!makeAppCrashingLocked(r, shortMsg, longMsg, stackTrace, null)) { - r.kill("crash", ApplicationExitInfo.REASON_CRASH, true); + r.killLocked("crash", ApplicationExitInfo.REASON_CRASH, true); } } else { // Huh. @@ -718,15 +732,22 @@ class AppErrors { }); } + @GuardedBy("mService") private boolean makeAppCrashingLocked(ProcessRecord app, String shortMsg, String longMsg, String stackTrace, AppErrorDialog.Data data) { - app.setCrashing(true); - app.crashingReport = generateProcessError(app, - ActivityManager.ProcessErrorStateInfo.CRASHED, null, shortMsg, longMsg, stackTrace); - app.startAppProblemLocked(); - app.getWindowProcessController().stopFreezingActivities(); - return handleAppCrashLocked(app, "force-crash" /*reason*/, shortMsg, longMsg, stackTrace, - data); + synchronized (mProcLock) { + final ProcessErrorStateRecord errState = app.mErrorState; + errState.setCrashing(true); + errState.setCrashingReport(generateProcessError(app, + ActivityManager.ProcessErrorStateInfo.CRASHED, + null, shortMsg, longMsg, stackTrace)); + errState.startAppProblemLSP(); + app.getWindowProcessController().stopFreezingActivities(); + synchronized (mBadProcessLock) { + return handleAppCrashLSPB(app, "force-crash" /*reason*/, shortMsg, longMsg, + stackTrace, data); + } + } } /** @@ -748,7 +769,7 @@ class AppErrors { report.condition = condition; report.processName = app.processName; - report.pid = app.pid; + report.pid = app.getPid(); report.uid = app.info.uid; report.tag = activity; report.shortMsg = shortMsg; @@ -758,170 +779,157 @@ class AppErrors { return report; } - Intent createAppErrorIntentLocked(ProcessRecord r, + @GuardedBy(anyOf = {"mService", "mProcLock"}) + Intent createAppErrorIntentLOSP(ProcessRecord r, long timeMillis, ApplicationErrorReport.CrashInfo crashInfo) { - ApplicationErrorReport report = createAppErrorReportLocked(r, timeMillis, crashInfo); + ApplicationErrorReport report = createAppErrorReportLOSP(r, timeMillis, crashInfo); if (report == null) { return null; } Intent result = new Intent(Intent.ACTION_APP_ERROR); - result.setComponent(r.errorReportReceiver); + result.setComponent(r.mErrorState.getErrorReportReceiver()); result.putExtra(Intent.EXTRA_BUG_REPORT, report); result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); return result; } - private ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r, + @GuardedBy(anyOf = {"mService", "mProcLock"}) + private ApplicationErrorReport createAppErrorReportLOSP(ProcessRecord r, long timeMillis, ApplicationErrorReport.CrashInfo crashInfo) { - if (r.errorReportReceiver == null) { + final ProcessErrorStateRecord errState = r.mErrorState; + if (errState.getErrorReportReceiver() == null) { return null; } - if (!r.isCrashing() && !r.isNotResponding() && !r.forceCrashReport) { + if (!errState.isCrashing() && !errState.isNotResponding() + && !errState.isForceCrashReport()) { return null; } ApplicationErrorReport report = new ApplicationErrorReport(); report.packageName = r.info.packageName; - report.installerPackageName = r.errorReportReceiver.getPackageName(); + report.installerPackageName = errState.getErrorReportReceiver().getPackageName(); report.processName = r.processName; report.time = timeMillis; report.systemApp = (r.info.flags & FLAG_SYSTEM) != 0; - if (r.isCrashing() || r.forceCrashReport) { + if (errState.isCrashing() || errState.isForceCrashReport()) { report.type = ApplicationErrorReport.TYPE_CRASH; report.crashInfo = crashInfo; - } else if (r.isNotResponding()) { + } else if (errState.isNotResponding()) { report.type = ApplicationErrorReport.TYPE_ANR; report.anrInfo = new ApplicationErrorReport.AnrInfo(); - report.anrInfo.activity = r.notRespondingReport.tag; - report.anrInfo.cause = r.notRespondingReport.shortMsg; - report.anrInfo.info = r.notRespondingReport.longMsg; + report.anrInfo.activity = errState.getNotRespondingReport().tag; + report.anrInfo.cause = errState.getNotRespondingReport().shortMsg; + report.anrInfo.info = errState.getNotRespondingReport().longMsg; } return report; } - private boolean handleAppCrashLocked(ProcessRecord app, String reason, + @GuardedBy({"mService", "mProcLock", "mBadProcessLock"}) + private boolean handleAppCrashLSPB(ProcessRecord app, String reason, String shortMsg, String longMsg, String stackTrace, AppErrorDialog.Data data) { final long now = SystemClock.uptimeMillis(); final boolean showBackground = Settings.Secure.getIntForUser(mContext.getContentResolver(), Settings.Secure.ANR_SHOW_BACKGROUND, 0, mService.mUserController.getCurrentUserId()) != 0; - final boolean procIsBoundForeground = - (app.getCurProcState() == ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE); - Long crashTime; Long crashTimePersistent; - boolean tryAgain = false; + final String processName = app.processName; + final int uid = app.uid; + final int userId = app.userId; + final boolean isolated = app.isolated; + final boolean persistent = app.isPersistent(); + final WindowProcessController proc = app.getWindowProcessController(); + final ProcessErrorStateRecord errState = app.mErrorState; - synchronized (mBadProcessLock) { - if (!app.isolated) { - crashTime = mProcessCrashTimes.get(app.processName, app.uid); - crashTimePersistent = mProcessCrashTimesPersistent.get(app.processName, app.uid); - } else { - crashTime = crashTimePersistent = null; - } + if (!app.isolated) { + crashTime = mProcessCrashTimes.get(processName, uid); + crashTimePersistent = mProcessCrashTimesPersistent.get(processName, uid); + } else { + crashTime = crashTimePersistent = null; + } - // Bump up the crash count of any services currently running in the proc. - for (int i = app.numberOfRunningServices() - 1; i >= 0; i--) { - // Any services running in the application need to be placed - // back in the pending list. - ServiceRecord sr = app.getRunningServiceAt(i); - // If the service was restarted a while ago, then reset crash count, - // else increment it. - if (now > sr.restartTime + ActivityManagerConstants.MIN_CRASH_INTERVAL) { - sr.crashCount = 1; - } else { - sr.crashCount++; - } - // Allow restarting for started or bound foreground services that are crashing. - // This includes wallpapers. - if (sr.crashCount < mService.mConstants.BOUND_SERVICE_MAX_CRASH_RETRY - && (sr.isForeground || procIsBoundForeground)) { - tryAgain = true; - } - } + // Bump up the crash count of any services currently running in the proc. + boolean tryAgain = app.mServices.incServiceCrashCountLocked(now); - final boolean quickCrash = crashTime != null - && now < crashTime + ActivityManagerConstants.MIN_CRASH_INTERVAL; - if (quickCrash || isProcOverCrashLimitLBp(app, now)) { - // The process either crashed again very quickly or has been crashing periodically - // in the last few hours. If it was a bound foreground service, let's try to - // restart again in a while, otherwise the process loses! - Slog.w(TAG, "Process " + app.processName + " has crashed too many times, killing!" - + " Reason: " - + (quickCrash ? "crashed quickly" : "over process crash limit")); - EventLog.writeEvent(EventLogTags.AM_PROCESS_CRASHED_TOO_MUCH, - app.userId, app.processName, app.uid); - mService.mAtmInternal.onHandleAppCrash(app.getWindowProcessController()); - if (!app.isPersistent()) { - // We don't want to start this process again until the user - // explicitly does so... but for persistent process, we really - // need to keep it running. If a persistent process is actually - // repeatedly crashing, then badness for everyone. - EventLog.writeEvent(EventLogTags.AM_PROC_BAD, app.userId, app.uid, - app.processName); - if (!app.isolated) { - // XXX We don't have a way to mark isolated processes - // as bad, since they don't have a persistent identity. - markBadProcess(app.processName, app.uid, - new BadProcessInfo(now, shortMsg, longMsg, stackTrace)); - mProcessCrashTimes.remove(app.processName, app.uid); - mProcessCrashCounts.remove(app.processName, app.uid); - } - app.bad = true; - app.removed = true; - // Don't let services in this process be restarted and potentially - // annoy the user repeatedly. Unless it is persistent, since those - // processes run critical code. - mService.mProcessList.removeProcessLocked(app, false, tryAgain, - ApplicationExitInfo.REASON_CRASH, "crash"); - mService.mAtmInternal.resumeTopActivities(false /* scheduleIdle */); - if (!showBackground) { - return false; - } + final boolean quickCrash = crashTime != null + && now < crashTime + ActivityManagerConstants.MIN_CRASH_INTERVAL; + if (quickCrash || isProcOverCrashLimitLBp(app, now)) { + // The process either crashed again very quickly or has been crashing periodically in + // the last few hours. If it was a bound foreground service, let's try to restart again + // in a while, otherwise the process loses! + Slog.w(TAG, "Process " + processName + " has crashed too many times, killing!" + + " Reason: " + (quickCrash ? "crashed quickly" : "over process crash limit")); + EventLog.writeEvent(EventLogTags.AM_PROCESS_CRASHED_TOO_MUCH, + userId, processName, uid); + mService.mAtmInternal.onHandleAppCrash(proc); + if (!persistent) { + // We don't want to start this process again until the user + // explicitly does so... but for persistent process, we really + // need to keep it running. If a persistent process is actually + // repeatedly crashing, then badness for everyone. + EventLog.writeEvent(EventLogTags.AM_PROC_BAD, userId, uid, + processName); + if (!isolated) { + // XXX We don't have a way to mark isolated processes + // as bad, since they don't have a persistent identity. + markBadProcess(processName, app.uid, + new BadProcessInfo(now, shortMsg, longMsg, stackTrace)); + mProcessCrashTimes.remove(processName, app.uid); + mProcessCrashCounts.remove(processName, app.uid); } + errState.setBad(true); + app.setRemoved(true); + // Don't let services in this process be restarted and potentially + // annoy the user repeatedly. Unless it is persistent, since those + // processes run critical code. + mService.mProcessList.removeProcessLocked(app, false, tryAgain, + ApplicationExitInfo.REASON_CRASH, "crash"); mService.mAtmInternal.resumeTopActivities(false /* scheduleIdle */); - } else { - final int affectedTaskId = mService.mAtmInternal.finishTopCrashedActivities( - app.getWindowProcessController(), reason); - if (data != null) { - data.taskId = affectedTaskId; - } - if (data != null && crashTimePersistent != null - && now < crashTimePersistent - + ActivityManagerConstants.MIN_CRASH_INTERVAL) { - data.repeating = true; + if (!showBackground) { + return false; } } - - if (data != null && tryAgain) { - data.isRestartableForService = true; + mService.mAtmInternal.resumeTopActivities(false /* scheduleIdle */); + } else { + final int affectedTaskId = mService.mAtmInternal.finishTopCrashedActivities( + proc, reason); + if (data != null) { + data.taskId = affectedTaskId; } - - // If the crashing process is what we consider to be the "home process" and it has been - // replaced by a third-party app, clear the package preferred activities from packages - // with a home activity running in the process to prevent a repeatedly crashing app - // from blocking the user to manually clear the list. - final WindowProcessController proc = app.getWindowProcessController(); - if (proc.isHomeProcess() && proc.hasActivities() - && (app.info.flags & FLAG_SYSTEM) == 0) { - proc.clearPackagePreferredForHomeActivities(); - } - - if (!app.isolated) { - // XXX Can't keep track of crash times for isolated processes, - // because they don't have a persistent identity. - mProcessCrashTimes.put(app.processName, app.uid, now); - mProcessCrashTimesPersistent.put(app.processName, app.uid, now); - updateProcessCrashCountLBp(app.processName, app.uid, now); + if (data != null && crashTimePersistent != null + && now < crashTimePersistent + ActivityManagerConstants.MIN_CRASH_INTERVAL) { + data.repeating = true; } } - if (app.crashHandler != null) mService.mHandler.post(app.crashHandler); + if (data != null && tryAgain) { + data.isRestartableForService = true; + } + + // If the crashing process is what we consider to be the "home process" and it has been + // replaced by a third-party app, clear the package preferred activities from packages + // with a home activity running in the process to prevent a repeatedly crashing app + // from blocking the user to manually clear the list. + if (proc.isHomeProcess() && proc.hasActivities() && (app.info.flags & FLAG_SYSTEM) == 0) { + proc.clearPackagePreferredForHomeActivities(); + } + + if (!isolated) { + // XXX Can't keep track of crash times for isolated processes, + // because they don't have a persistent identity. + mProcessCrashTimes.put(processName, uid, now); + mProcessCrashTimesPersistent.put(processName, uid, now); + updateProcessCrashCountLBp(processName, uid, now); + } + + if (errState.getCrashHandler() != null) { + mService.mHandler.post(errState.getCrashHandler()); + } return true; } @@ -951,15 +959,16 @@ class AppErrors { mService.mUserController.getCurrentUserId()) != 0; final int userId; - synchronized (mService) { + synchronized (mProcLock) { final ProcessRecord proc = data.proc; final AppErrorResult res = data.result; if (proc == null) { Slog.e(TAG, "handleShowAppErrorUi: proc is null"); return; } + final ProcessErrorStateRecord errState = proc.mErrorState; userId = proc.userId; - if (proc.getDialogController().hasCrashDialogs()) { + if (errState.getDialogController().hasCrashDialogs()) { Slog.e(TAG, "App already has crash dialog: " + proc); if (res != null) { res.set(AppErrorDialog.ALREADY_SHOWING); @@ -968,7 +977,7 @@ class AppErrors { } boolean isBackground = (UserHandle.getAppId(proc.uid) >= Process.FIRST_APPLICATION_UID - && proc.pid != MY_PID); + && proc.getPid() != MY_PID); for (int profileId : mService.mUserController.getCurrentProfileIds()) { isBackground &= (userId != profileId); } @@ -1001,7 +1010,7 @@ class AppErrors { if ((mService.mAtmInternal.canShowErrorDialogs() || showBackground) && !crashSilenced && !shouldThottle && (showFirstCrash || showFirstCrashDevOption || data.repeating)) { - proc.getDialogController().showCrashDialogs(data); + errState.getDialogController().showCrashDialogs(data); if (!proc.isolated) { mProcessCrashShowDialogTimes.put(proc.processName, proc.uid, now); } @@ -1026,17 +1035,19 @@ class AppErrors { void handleShowAnrUi(Message msg) { List packageList = null; - synchronized (mService) { - AppNotRespondingDialog.Data data = (AppNotRespondingDialog.Data) msg.obj; - final ProcessRecord proc = data.proc; - if (proc == null) { - Slog.e(TAG, "handleShowAnrUi: proc is null"); - return; - } + boolean doKill = false; + AppNotRespondingDialog.Data data = (AppNotRespondingDialog.Data) msg.obj; + final ProcessRecord proc = data.proc; + if (proc == null) { + Slog.e(TAG, "handleShowAnrUi: proc is null"); + return; + } + synchronized (mProcLock) { + final ProcessErrorStateRecord errState = proc.mErrorState; if (!proc.isPersistent()) { packageList = proc.getPackageListWithVersionCode(); } - if (proc.getDialogController().hasAnrDialogs()) { + if (errState.getDialogController().hasAnrDialogs()) { Slog.e(TAG, "App already has anr dialog: " + proc); MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_APP_ANR, AppNotRespondingDialog.ALREADY_SHOWING); @@ -1047,14 +1058,17 @@ class AppErrors { Settings.Secure.ANR_SHOW_BACKGROUND, 0, mService.mUserController.getCurrentUserId()) != 0; if (mService.mAtmInternal.canShowErrorDialogs() || showBackground) { - proc.getDialogController().showAnrDialogs(data); + errState.getDialogController().showAnrDialogs(data); } else { MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_APP_ANR, AppNotRespondingDialog.CANT_SHOW); // Just kill the app if there is no dialog to be shown. - mService.killAppAtUsersRequest(proc); + doKill = true; } } + if (doKill) { + mService.killAppAtUsersRequest(proc); + } // Notify PackageWatchdog without the lock held if (packageList != null) { mPackageWatchdog.onPackageFailure(packageList, diff --git a/services/core/java/com/android/server/am/AppExitInfoTracker.java b/services/core/java/com/android/server/am/AppExitInfoTracker.java index 48aa8be1e2d57..17be2100414fb 100644 --- a/services/core/java/com/android/server/am/AppExitInfoTracker.java +++ b/services/core/java/com/android/server/am/AppExitInfoTracker.java @@ -920,20 +920,20 @@ public final class AppExitInfoTracker { info = new ApplicationExitInfo(); } - synchronized (mService) { - final int definingUid = app.hostingRecord != null - ? app.hostingRecord.getDefiningUid() : 0; - info.setPid(app.pid); + synchronized (mService.mProcLock) { + final int definingUid = app.getHostingRecord() != null + ? app.getHostingRecord().getDefiningUid() : 0; + info.setPid(app.getPid()); info.setRealUid(app.uid); info.setPackageUid(app.info.uid); info.setDefiningUid(definingUid > 0 ? definingUid : app.info.uid); info.setProcessName(app.processName); - info.setConnectionGroup(app.connectionGroup); + info.setConnectionGroup(app.mServices.getConnectionGroup()); info.setPackageName(app.info.packageName); info.setPackageList(app.getPackageList()); info.setReason(ApplicationExitInfo.REASON_UNKNOWN); info.setStatus(0); - info.setImportance(procStateToImportance(app.setProcState)); + info.setImportance(procStateToImportance(app.mState.getSetProcState())); info.setPss(app.mProfile.getLastPss()); info.setRss(app.mProfile.getLastRss()); info.setTimestamp(System.currentTimeMillis()); diff --git a/services/core/java/com/android/server/am/AppNotRespondingDialog.java b/services/core/java/com/android/server/am/AppNotRespondingDialog.java index 96e6f6ea4476b..77d2898842c62 100644 --- a/services/core/java/com/android/server/am/AppNotRespondingDialog.java +++ b/services/core/java/com/android/server/am/AppNotRespondingDialog.java @@ -63,7 +63,7 @@ final class AppNotRespondingDialog extends BaseErrorDialog implements View.OnCli ? data.aInfo.loadLabel(context.getPackageManager()) : null; CharSequence name2 = null; - if ((mProc.getPkgList().size() == 1) + if (mProc.getPkgList().size() == 1 && (name2 = context.getPackageManager().getApplicationLabel(mProc.info)) != null) { if (name1 != null) { resid = com.android.internal.R.string.anr_activity_application; @@ -108,7 +108,7 @@ final class AppNotRespondingDialog extends BaseErrorDialog implements View.OnCli final TextView report = findViewById(com.android.internal.R.id.aerr_report); report.setOnClickListener(this); - final boolean hasReceiver = mProc.errorReportReceiver != null; + final boolean hasReceiver = mProc.mErrorState.getErrorReportReceiver() != null; report.setVisibility(hasReceiver ? View.VISIBLE : View.GONE); final TextView close = findViewById(com.android.internal.R.id.aerr_close); close.setOnClickListener(this); @@ -152,15 +152,18 @@ final class AppNotRespondingDialog extends BaseErrorDialog implements View.OnCli // Continue waiting for the application. synchronized (mService) { ProcessRecord app = mProc; + final ProcessErrorStateRecord errState = app.mErrorState; if (msg.what == WAIT_AND_REPORT) { - appErrorIntent = mService.mAppErrors.createAppErrorIntentLocked(app, + appErrorIntent = mService.mAppErrors.createAppErrorIntentLOSP(app, System.currentTimeMillis(), null); } - app.setNotResponding(false); - app.notRespondingReport = null; - app.getDialogController().clearAnrDialogs(); + synchronized (mService.mProcLock) { + errState.setNotResponding(false); + errState.setNotRespondingReport(null); + errState.getDialogController().clearAnrDialogs(); + } mService.mServices.scheduleServiceTimeoutLocked(app); } break; diff --git a/services/core/java/com/android/server/am/AppProfiler.java b/services/core/java/com/android/server/am/AppProfiler.java index 3df058c8ed82f..8f11a5ab900b2 100644 --- a/services/core/java/com/android/server/am/AppProfiler.java +++ b/services/core/java/com/android/server/am/AppProfiler.java @@ -207,7 +207,6 @@ public class AppProfiler { */ private volatile boolean mTestPssMode = false; - @GuardedBy("mService") private final LowMemDetector mLowMemDetector; /** @@ -239,13 +238,13 @@ public class AppProfiler { /** * Total time spent with RAM that has been added in the past since the last idle time. */ - @GuardedBy("mService") + @GuardedBy("mProcLock") private long mLowRamTimeSinceLastIdle = 0; /** * If RAM is currently low, when that horrible situation started. */ - @GuardedBy("mService") + @GuardedBy("mProcLock") private long mLowRamStartTime = 0; /** @@ -331,6 +330,8 @@ public class AppProfiler { */ final Object mProfilerLock = new Object(); + final ActivityManagerGlobalLock mProcLock; + /** * Observe DeviceConfig changes to the PSS calculation interval */ @@ -852,8 +853,8 @@ public class AppProfiler { /** * Schedule PSS collection of all processes. */ - @GuardedBy("mService") - void requestPssAllProcsLocked(long now, boolean always, boolean memLowered) { + @GuardedBy("mProcLock") + void requestPssAllProcsLPr(long now, boolean always, boolean memLowered) { synchronized (mProfilerLock) { if (!always) { if (now < (mLastFullPssTime @@ -870,10 +871,9 @@ public class AppProfiler { for (int i = mPendingPssProfiles.size() - 1; i >= 0; i--) { mPendingPssProfiles.get(i).abortNextPssTime(); } - mPendingPssProfiles.ensureCapacity(mService.mProcessList.getLruSizeLocked()); + mPendingPssProfiles.ensureCapacity(mService.mProcessList.getLruSizeLOSP()); mPendingPssProfiles.clear(); - for (int i = mService.mProcessList.getLruSizeLocked() - 1; i >= 0; i--) { - ProcessRecord app = mService.mProcessList.mLruProcesses.get(i); + mService.mProcessList.forEachLruProcessesLOSP(false, app -> { final ProcessProfileRecord profile = app.mProfile; if (profile.getThread() == null || profile.getSetProcState() == PROCESS_STATE_NONEXISTENT) { @@ -889,7 +889,7 @@ public class AppProfiler { updateNextPssTimeLPf(profile.getSetProcState(), profile, now, true); mPendingPssProfiles.add(profile); } - } + }); if (!mBgHandler.hasMessages(BgHandler.COLLECT_PSS_BG_MSG)) { mBgHandler.sendEmptyMessage(BgHandler.COLLECT_PSS_BG_MSG); } @@ -897,12 +897,12 @@ public class AppProfiler { } void setTestPssMode(boolean enabled) { - synchronized (mService) { + synchronized (mProcLock) { mTestPssMode = enabled; if (enabled) { // Whenever we enable the mode, we want to take a snapshot all of current // process mem use. - requestPssAllProcsLocked(SystemClock.uptimeMillis(), true, true); + requestPssAllProcsLPr(SystemClock.uptimeMillis(), true, true); } } } @@ -921,8 +921,8 @@ public class AppProfiler { return mLastMemoryLevel <= ADJ_MEM_FACTOR_NORMAL; } - @GuardedBy("mService") - void updateLowRamTimestampLocked(long now) { + @GuardedBy("mProcLock") + void updateLowRamTimestampLPr(long now) { mLowRamTimeSinceLastIdle = 0; if (mLowRamStartTime != 0) { mLowRamStartTime = now; @@ -939,9 +939,8 @@ public class AppProfiler { mMemFactorOverride = factor; } - @GuardedBy("mService") - boolean updateLowMemStateLocked(int numCached, int numEmpty, int numTrimming) { - final int numOfLru = mService.mProcessList.getLruSizeLocked(); + @GuardedBy({"mService", "mProcLock"}) + boolean updateLowMemStateLSP(int numCached, int numEmpty, int numTrimming) { final long now = SystemClock.uptimeMillis(); int memFactor; if (mLowMemDetector != null && mLowMemDetector.isAvailable()) { @@ -973,7 +972,7 @@ public class AppProfiler { if (DEBUG_OOM_ADJ) { Slog.d(TAG_OOM_ADJ, "oom: memFactor=" + memFactor + " override=" + mMemFactorOverride + " last=" + mLastMemoryLevel + " allowLow=" + mAllowLowerMemLevel - + " numProcs=" + mService.mProcessList.getLruSizeLocked() + + " numProcs=" + mService.mProcessList.getLruSizeLOSP() + " last=" + mLastNumProcesses); } boolean override; @@ -982,7 +981,7 @@ public class AppProfiler { } if (memFactor > mLastMemoryLevel) { if (!override && (!mAllowLowerMemLevel - || mService.mProcessList.getLruSizeLocked() >= mLastNumProcesses)) { + || mService.mProcessList.getLruSizeLOSP() >= mLastNumProcesses)) { memFactor = mLastMemoryLevel; if (DEBUG_OOM_ADJ) Slog.d(TAG_OOM_ADJ, "Keeping last mem factor!"); } @@ -992,7 +991,7 @@ public class AppProfiler { FrameworkStatsLog.write(FrameworkStatsLog.MEMORY_FACTOR_STATE_CHANGED, memFactor); } mLastMemoryLevel = memFactor; - mLastNumProcesses = mService.mProcessList.getLruSizeLocked(); + mLastNumProcesses = mService.mProcessList.getLruSizeLOSP(); boolean allChanged; int trackerMemFactor; synchronized (mService.mProcessStats.mLock) { @@ -1004,7 +1003,6 @@ public class AppProfiler { if (mLowRamStartTime == 0) { mLowRamStartTime = now; } - int step = 0; int fgTrimLevel; switch (memFactor) { case ADJ_MEM_FACTOR_CRITICAL: @@ -1022,126 +1020,129 @@ public class AppProfiler { if (mHasHomeProcess) minFactor++; if (mHasPreviousProcess) minFactor++; if (factor < minFactor) factor = minFactor; - int curLevel = ComponentCallbacks2.TRIM_MEMORY_COMPLETE; - for (int i = 0; i < numOfLru; i++) { - final ProcessRecord app = mService.mProcessList.mLruProcesses.get(i); + final int actualFactor = factor; + final int[] step = {0}; + final int[] curLevel = {ComponentCallbacks2.TRIM_MEMORY_COMPLETE}; + mService.mProcessList.forEachLruProcessesLOSP(true, app -> { final ProcessProfileRecord profile = app.mProfile; final int trimMemoryLevel = profile.getTrimMemoryLevel(); - if (allChanged || app.procStateChanged) { - mService.setProcessTrackerStateLocked(app, trackerMemFactor, now); - app.procStateChanged = false; + final ProcessStateRecord state = app.mState; + final int curProcState = state.getCurProcState(); + IApplicationThread thread; + if (allChanged || state.hasProcStateChanged()) { + mService.setProcessTrackerStateLOSP(app, trackerMemFactor, now); + state.setProcStateChanged(false); } - if (app.getCurProcState() >= ActivityManager.PROCESS_STATE_HOME - && !app.killedByAm) { - if (trimMemoryLevel < curLevel && app.thread != null) { + if (curProcState >= ActivityManager.PROCESS_STATE_HOME && !app.isKilledByAm()) { + if (trimMemoryLevel < curLevel[0] && (thread = app.getThread()) != null) { try { if (DEBUG_SWITCH || DEBUG_OOM_ADJ) { Slog.v(TAG_OOM_ADJ, "Trimming memory of " + app.processName - + " to " + curLevel); + + " to " + curLevel[0]); } - app.thread.scheduleTrimMemory(curLevel); + thread.scheduleTrimMemory(curLevel[0]); } catch (RemoteException e) { } } - profile.setTrimMemoryLevel(curLevel); - step++; - if (step >= factor) { - step = 0; - switch (curLevel) { + profile.setTrimMemoryLevel(curLevel[0]); + step[0]++; + if (step[0] >= actualFactor) { + step[0] = 0; + switch (curLevel[0]) { case ComponentCallbacks2.TRIM_MEMORY_COMPLETE: - curLevel = ComponentCallbacks2.TRIM_MEMORY_MODERATE; + curLevel[0] = ComponentCallbacks2.TRIM_MEMORY_MODERATE; break; case ComponentCallbacks2.TRIM_MEMORY_MODERATE: - curLevel = ComponentCallbacks2.TRIM_MEMORY_BACKGROUND; + curLevel[0] = ComponentCallbacks2.TRIM_MEMORY_BACKGROUND; break; } } - } else if (app.getCurProcState() == ActivityManager.PROCESS_STATE_HEAVY_WEIGHT - && !app.killedByAm) { + } else if (curProcState == ActivityManager.PROCESS_STATE_HEAVY_WEIGHT + && !app.isKilledByAm()) { if (trimMemoryLevel < ComponentCallbacks2.TRIM_MEMORY_BACKGROUND - && app.thread != null) { + && (thread = app.getThread()) != null) { try { if (DEBUG_SWITCH || DEBUG_OOM_ADJ) { Slog.v(TAG_OOM_ADJ, "Trimming memory of heavy-weight " + app.processName + " to " + ComponentCallbacks2.TRIM_MEMORY_BACKGROUND); } - app.thread.scheduleTrimMemory( + thread.scheduleTrimMemory( ComponentCallbacks2.TRIM_MEMORY_BACKGROUND); } catch (RemoteException e) { } } profile.setTrimMemoryLevel(ComponentCallbacks2.TRIM_MEMORY_BACKGROUND); } else { - if ((app.getCurProcState() >= ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND - || app.systemNoUi) && profile.hasPendingUiClean()) { + if ((curProcState >= ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND + || state.isSystemNoUi()) && profile.hasPendingUiClean()) { // If this application is now in the background and it // had done UI, then give it the special trim level to // have it free UI resources. final int level = ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN; - if (trimMemoryLevel < level && app.thread != null) { + if (trimMemoryLevel < level && (thread = app.getThread()) != null) { try { if (DEBUG_SWITCH || DEBUG_OOM_ADJ) { Slog.v(TAG_OOM_ADJ, "Trimming memory of bg-ui " + app.processName + " to " + level); } - app.thread.scheduleTrimMemory(level); + thread.scheduleTrimMemory(level); } catch (RemoteException e) { } } profile.setPendingUiClean(false); } - if (trimMemoryLevel < fgTrimLevel && app.thread != null) { + if (trimMemoryLevel < fgTrimLevel && (thread = app.getThread()) != null) { try { if (DEBUG_SWITCH || DEBUG_OOM_ADJ) { Slog.v(TAG_OOM_ADJ, "Trimming memory of fg " + app.processName + " to " + fgTrimLevel); } - app.thread.scheduleTrimMemory(fgTrimLevel); + thread.scheduleTrimMemory(fgTrimLevel); } catch (RemoteException e) { } } profile.setTrimMemoryLevel(fgTrimLevel); } - } + }); } else { if (mLowRamStartTime != 0) { mLowRamTimeSinceLastIdle += now - mLowRamStartTime; mLowRamStartTime = 0; } - for (int i = 0; i < numOfLru; i++) { - final ProcessRecord app = mService.mProcessList.mLruProcesses.get(i); + mService.mProcessList.forEachLruProcessesLOSP(true, app -> { final ProcessProfileRecord profile = app.mProfile; - if (allChanged || app.procStateChanged) { - mService.setProcessTrackerStateLocked(app, trackerMemFactor, now); - app.procStateChanged = false; + final IApplicationThread thread; + final ProcessStateRecord state = app.mState; + if (allChanged || state.hasProcStateChanged()) { + mService.setProcessTrackerStateLOSP(app, trackerMemFactor, now); + state.setProcStateChanged(false); } - if ((app.getCurProcState() >= ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND - || app.systemNoUi) && profile.hasPendingUiClean()) { + if ((state.getCurProcState() >= ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND + || state.isSystemNoUi()) && profile.hasPendingUiClean()) { if (profile.getTrimMemoryLevel() < ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN - && app.thread != null) { + && (thread = app.getThread()) != null) { try { if (DEBUG_SWITCH || DEBUG_OOM_ADJ) { Slog.v(TAG_OOM_ADJ, "Trimming memory of ui hidden " + app.processName + " to " + ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN); } - app.thread.scheduleTrimMemory( - ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN); + thread.scheduleTrimMemory(ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN); } catch (RemoteException e) { } } profile.setPendingUiClean(false); } profile.setTrimMemoryLevel(0); - } + }); } return allChanged; } - @GuardedBy("mService") - long getLowRamTimeSinceIdleLocked(long now) { + @GuardedBy("mProcLock") + long getLowRamTimeSinceIdleLPr(long now) { return mLowRamTimeSinceLastIdle + (mLowRamStartTime > 0 ? (now - mLowRamStartTime) : 0); } @@ -1262,7 +1263,7 @@ public class AppProfiler { // If there are no longer any background processes running, // and the app that died was not running instrumentation, // then tell everyone we are now low on memory. - if (!mService.mProcessList.haveBackgroundProcessLocked()) { + if (!mService.mProcessList.haveBackgroundProcessLOSP()) { boolean doReport = Build.IS_DEBUGGABLE; final long now = SystemClock.uptimeMillis(); if (doReport) { @@ -1272,19 +1273,19 @@ public class AppProfiler { mLastMemUsageReportTime = now; } } - final int lruSize = mService.mProcessList.getLruSizeLocked(); + final int lruSize = mService.mProcessList.getLruSizeLOSP(); final ArrayList memInfos = doReport ? new ArrayList(lruSize) : null; EventLogTags.writeAmLowMemory(lruSize); - for (int i = lruSize - 1; i >= 0; i--) { - ProcessRecord rec = mService.mProcessList.mLruProcesses.get(i); - if (rec == dyingProc || rec.thread == null) { + mService.mProcessList.forEachLruProcessesLOSP(false, rec -> { + if (rec == dyingProc || rec.getThread() == null) { return; } + final ProcessStateRecord state = rec.mState; if (memInfos != null) { - memInfos.add(new ProcessMemInfo(rec.processName, rec.pid, - rec.setAdj, rec.setProcState, - rec.adjType, rec.makeAdjReason())); + memInfos.add(new ProcessMemInfo(rec.processName, rec.getPid(), + state.getSetAdj(), state.getSetProcState(), + state.getAdjType(), state.makeAdjReason())); } final ProcessProfileRecord profile = rec.mProfile; if ((profile.getLastLowMemory() + mService.mConstants.GC_MIN_INTERVAL) <= now) { @@ -1292,7 +1293,7 @@ public class AppProfiler { // state for a GC request. Make sure to do // heavy/important/visible/foreground processes first. synchronized (mProfilerLock) { - if (rec.setAdj <= ProcessList.HEAVY_WEIGHT_APP_ADJ) { + if (state.getSetAdj() <= ProcessList.HEAVY_WEIGHT_APP_ADJ) { profile.setLastRequestedGc(0); } else { profile.setLastRequestedGc(profile.getLastLowMemory()); @@ -1303,7 +1304,7 @@ public class AppProfiler { addProcessToGcListLPf(rec); } } - } + }); if (doReport) { Message msg = mService.mHandler.obtainMessage(REPORT_MEM_USAGE_MSG, memInfos); mService.mHandler.sendMessage(msg); @@ -1554,7 +1555,9 @@ public class AppProfiler { PrintWriter catPw = new FastPrintWriter(catSw, false, 256); String[] emptyArgs = new String[] { }; catPw.println(); - mService.mProcessList.dumpProcessesLocked(null, catPw, emptyArgs, 0, false, null, -1); + synchronized (mProcLock) { + mService.mProcessList.dumpProcessesLSP(null, catPw, emptyArgs, 0, false, null, -1); + } catPw.println(); mService.mServices.newServiceDumperLocked(null, catPw, emptyArgs, 0, false, null).dumpLocked(); @@ -1575,7 +1578,7 @@ public class AppProfiler { } } - @GuardedBy("mService") + @GuardedBy("mProfilerLock") private void stopProfilerLPf(ProcessRecord proc, int profileType) { if (proc == null || proc == mProfileData.getProfileProc()) { proc = mProfileData.getProfileProc(); @@ -1644,7 +1647,7 @@ public class AppProfiler { } mProfileData.getProfilerInfo().profileFd = null; - if (proc.pid == mService.MY_PID) { + if (proc.getPid() == mService.MY_PID) { // When profiling the system server itself, avoid closing the file // descriptor, as profilerControl will not create a copy. // Note: it is also not correct to just set profileFd to null, as the @@ -1930,6 +1933,7 @@ public class AppProfiler { AppProfiler(ActivityManagerService service, Looper bgLooper, LowMemDetector detector) { mService = service; + mProcLock = service.mProcLock; mBgHandler = new BgHandler(bgLooper); mLowMemDetector = detector; mProcessCpuThread = new ProcessCpuThread("CpuTracker"); @@ -2027,19 +2031,21 @@ public class AppProfiler { i >= 0 && app.getActiveInstrumentation() == null; i--) { ActiveInstrumentation aInstr = mService.mActiveInstrumentation.get(i); if (!aInstr.mFinished && aInstr.mTargetInfo.uid == app.uid) { - if (aInstr.mTargetProcesses.length == 0) { - // This is the wildcard mode, where every process brought up for - // the target instrumentation should be included. - if (aInstr.mTargetInfo.packageName.equals(app.info.packageName)) { - app.setActiveInstrumentation(aInstr); - aInstr.mRunningProcesses.add(app); - } - } else { - for (String proc : aInstr.mTargetProcesses) { - if (proc.equals(app.processName)) { + synchronized (mProcLock) { + if (aInstr.mTargetProcesses.length == 0) { + // This is the wildcard mode, where every process brought up for + // the target instrumentation should be included. + if (aInstr.mTargetInfo.packageName.equals(app.info.packageName)) { app.setActiveInstrumentation(aInstr); aInstr.mRunningProcesses.add(app); - break; + } + } else { + for (String proc : aInstr.mTargetProcesses) { + if (proc.equals(app.processName)) { + app.setActiveInstrumentation(aInstr); + aInstr.mRunningProcesses.add(app); + break; + } } } } diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java index fca3a52aeeaca..7e65434b81897 100644 --- a/services/core/java/com/android/server/am/BroadcastQueue.java +++ b/services/core/java/com/android/server/am/BroadcastQueue.java @@ -26,6 +26,7 @@ import android.app.ActivityManager; import android.app.AppGlobals; import android.app.AppOpsManager; import android.app.BroadcastOptions; +import android.app.IApplicationThread; import android.app.PendingIntent; import android.content.ComponentName; import android.content.ContentResolver; @@ -222,7 +223,7 @@ public final class BroadcastQueue { } public boolean isPendingBroadcastProcessLocked(int pid) { - return mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid; + return mPendingBroadcast != null && mPendingBroadcast.curApp.getPid() == pid; } public void enqueueParallelBroadcastLocked(BroadcastRecord r) { @@ -286,19 +287,21 @@ public final class BroadcastQueue { ProcessRecord app) throws RemoteException { if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Process cur broadcast " + r + " for app " + app); - if (app.thread == null) { + final IApplicationThread thread = app.getThread(); + if (thread == null) { throw new RemoteException(); } - if (app.inFullBackup) { + if (app.isInFullBackup()) { skipReceiverLocked(r); return; } - r.receiver = app.thread.asBinder(); + r.receiver = thread.asBinder(); r.curApp = app; - app.curReceivers.add(r); - app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_RECEIVER); - mService.mProcessList.updateLruProcessLocked(app, false, null); + final ProcessReceiverRecord prr = app.mReceivers; + prr.addCurReceiver(r); + app.mState.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_RECEIVER); + mService.updateLruProcessLocked(app, false, null); // Make sure the oom adj score is updated before delivering the broadcast. // Force an update, even if there are other pending requests, overall it still saves time, // because time(updateOomAdj(N apps)) <= N * time(updateOomAdj(1 app)). @@ -315,10 +318,10 @@ public final class BroadcastQueue { + ": " + r); mService.notifyPackageUse(r.intent.getComponent().getPackageName(), PackageManager.NOTIFY_PACKAGE_USE_BROADCAST_RECEIVER); - app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver, + thread.scheduleReceiver(new Intent(r.intent), r.curReceiver, mService.compatibilityInfoForPackage(r.curReceiver.applicationInfo), r.resultCode, r.resultData, r.resultExtras, r.ordered, r.userId, - app.getReportedProcState()); + app.mState.getReportedProcState()); if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Process cur broadcast " + r + " DELIVERED for app " + app); started = true; @@ -328,7 +331,7 @@ public final class BroadcastQueue { "Process cur broadcast " + r + ": NOT STARTED!"); r.receiver = null; r.curApp = null; - app.curReceivers.remove(r); + prr.removeCurReceiver(r); } } } @@ -336,7 +339,7 @@ public final class BroadcastQueue { public boolean sendPendingBroadcastsLocked(ProcessRecord app) { boolean didSomething = false; final BroadcastRecord br = mPendingBroadcast; - if (br != null && br.curApp.pid > 0 && br.curApp.pid == app.pid) { + if (br != null && br.curApp.getPid() > 0 && br.curApp.getPid() == app.getPid()) { if (br.curApp != app) { Slog.e(TAG, "App mismatch when sending pending broadcast to " + app.processName + ", intended target is " + br.curApp.processName); @@ -363,7 +366,7 @@ public final class BroadcastQueue { public void skipPendingBroadcastLocked(int pid) { final BroadcastRecord br = mPendingBroadcast; - if (br != null && br.curApp.pid == pid) { + if (br != null && br.curApp.getPid() == pid) { br.state = BroadcastRecord.IDLE; br.nextReceiver = mPendingBroadcastRecvIndex; mPendingBroadcast = null; @@ -503,8 +506,8 @@ public final class BroadcastQueue { r.receiver = null; r.intent.setComponent(null); - if (r.curApp != null && r.curApp.curReceivers.contains(r)) { - r.curApp.curReceivers.remove(r); + if (r.curApp != null && r.curApp.mReceivers.hasCurReceiver(r)) { + r.curApp.mReceivers.removeCurReceiver(r); mService.enqueueOomAdjTargetLocked(r.curApp); } if (r.curFilter != null) { @@ -578,12 +581,14 @@ public final class BroadcastQueue { throws RemoteException { // Send the intent to the receiver asynchronously using one-way binder calls. if (app != null) { - if (app.thread != null) { + final IApplicationThread thread = app.getThread(); + if (thread != null) { // If we have an app thread, do the call through that so it is // correctly ordered with other one-way calls. try { - app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode, - data, extras, ordered, sticky, sendingUser, app.getReportedProcState()); + thread.scheduleRegisteredReceiver(receiver, intent, resultCode, + data, extras, ordered, sticky, sendingUser, + app.mState.getReportedProcState()); // TODO: Uncomment this when (b/28322359) is fixed and we aren't getting // DeadObjectException when the process isn't actually dead. //} catch (DeadObjectException ex) { @@ -593,8 +598,8 @@ public final class BroadcastQueue { // Failed to call into the process. It's either dying or wedged. Kill it gently. synchronized (mService) { Slog.w(TAG, "Can't deliver broadcast to " + app.processName - + " (pid " + app.pid + "). Crashing it."); - app.scheduleCrash("can't deliver broadcast"); + + " (pid " + app.getPid() + "). Crashing it."); + app.scheduleCrashLocked("can't deliver broadcast"); } throw ex; } @@ -724,8 +729,8 @@ public final class BroadcastQueue { skip = true; } - if (!skip && (filter.receiverList.app == null || filter.receiverList.app.killed - || filter.receiverList.app.isCrashing())) { + if (!skip && (filter.receiverList.app == null || filter.receiverList.app.isKilled() + || filter.receiverList.app.mErrorState.isCrashing())) { Slog.w(TAG, "Skipping deliver [" + mQueueName + "] " + r + " to " + filter.receiverList + ": process gone or crashing"); skip = true; @@ -794,7 +799,7 @@ public final class BroadcastQueue { // things that directly call the IActivityManager API, which // are already core system stuff so don't matter for this. r.curApp = filter.receiverList.app; - filter.receiverList.app.curReceivers.add(r); + filter.receiverList.app.mReceivers.addCurReceiver(r); mService.enqueueOomAdjTargetLocked(r.curApp); mService.updateOomAdjPendingTargetsLocked( OomAdjuster.OOM_ADJ_REASON_START_RECEIVER); @@ -806,7 +811,7 @@ public final class BroadcastQueue { try { if (DEBUG_BROADCAST_LIGHT) Slog.i(TAG_BROADCAST, "Delivering to " + filter + " : " + r); - if (filter.receiverList.app != null && filter.receiverList.app.inFullBackup) { + if (filter.receiverList.app != null && filter.receiverList.app.isInFullBackup()) { // Skip delivery if full backup in progress // If it's an ordered broadcast, we need to continue to the next receiver. if (ordered) { @@ -833,7 +838,7 @@ public final class BroadcastQueue { if (filter.receiverList.app != null) { filter.receiverList.app.removeAllowBackgroundActivityStartsToken(r); if (ordered) { - filter.receiverList.app.curReceivers.remove(r); + filter.receiverList.app.mReceivers.removeCurReceiver(r); // Something wrong, its oom adj could be downgraded, but not in a hurry. mService.enqueueOomAdjTargetLocked(r.curApp); } @@ -856,8 +861,8 @@ public final class BroadcastQueue { } final boolean callerForeground = receiverRecord.callerApp != null - ? receiverRecord.callerApp.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND - : true; + ? receiverRecord.callerApp.mState.getSetSchedGroup() + != ProcessList.SCHED_GROUP_BACKGROUND : true; // Show a permission review UI only for explicit broadcast from a foreground app if (callerForeground && receiverRecord.intent.getComponent() != null) { @@ -1018,16 +1023,16 @@ public final class BroadcastQueue { + mPendingBroadcast.curApp); boolean isDead; - if (mPendingBroadcast.curApp.pid > 0) { + if (mPendingBroadcast.curApp.getPid() > 0) { synchronized (mService.mPidsSelfLocked) { ProcessRecord proc = mService.mPidsSelfLocked.get( - mPendingBroadcast.curApp.pid); - isDead = proc == null || proc.isCrashing(); + mPendingBroadcast.curApp.getPid()); + isDead = proc == null || proc.mErrorState.isCrashing(); } } else { - final ProcessRecord proc = mService.mProcessList.mProcessNames.get( + final ProcessRecord proc = mService.mProcessList.getProcessNamesLOSP().get( mPendingBroadcast.curApp.processName, mPendingBroadcast.curApp.uid); - isDead = proc == null || !proc.pendingStart; + isDead = proc == null || !proc.isPendingStart(); } if (!isDead) { // It's still alive, so keep waiting @@ -1497,7 +1502,7 @@ public final class BroadcastQueue { + " (uid " + r.callingUid + ")"); skip = true; } - if (r.curApp != null && r.curApp.isCrashing()) { + if (r.curApp != null && r.curApp.mErrorState.isCrashing()) { // If the target process is crashing, just skip it. Slog.w(TAG, "Skipping deliver ordered [" + mQueueName + "] " + r + " to " + r.curApp + ": process crashing"); @@ -1548,14 +1553,14 @@ public final class BroadcastQueue { info.activityInfo.applicationInfo.uid, false); if (!skip) { - final int allowed = mService.getAppStartModeLocked( + final int allowed = mService.getAppStartModeLOSP( info.activityInfo.applicationInfo.uid, info.activityInfo.packageName, info.activityInfo.applicationInfo.targetSdkVersion, -1, true, false, false); if (allowed != ActivityManager.APP_START_MODE_NORMAL) { // We won't allow this receiver to be launched if the app has been // completely disabled from launches, or it was not explicitly sent // to it and the app is in a state that should not receive it - // (depending on how getAppStartModeLocked has determined that). + // (depending on how getAppStartModeLOSP has determined that). if (allowed == ActivityManager.APP_START_MODE_DISABLED) { Slog.w(TAG, "Background execution disabled: receiving " + r.intent + " to " @@ -1630,7 +1635,7 @@ public final class BroadcastQueue { } // Is this receiver's application already running? - if (app != null && app.thread != null && !app.killed) { + if (app != null && app.getThread() != null && !app.isKilled()) { try { app.addPackage(info.activityInfo.packageName, info.activityInfo.applicationInfo.longVersionCode, mService.mProcessStats); @@ -1665,13 +1670,13 @@ public final class BroadcastQueue { if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Need to start app [" + mQueueName + "] " + targetProcess + " for broadcast " + r); - if ((r.curApp=mService.startProcessLocked(targetProcess, + r.curApp = mService.startProcessLocked(targetProcess, info.activityInfo.applicationInfo, true, r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND, - new HostingRecord("broadcast", r.curComponent), - isActivityCapable ? ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE : ZYGOTE_POLICY_FLAG_EMPTY, - (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false, false)) - == null) { + new HostingRecord("broadcast", r.curComponent), isActivityCapable + ? ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE : ZYGOTE_POLICY_FLAG_EMPTY, + (r.intent.getFlags() & Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false, false); + if (r.curApp == null) { // Ah, this recipient is unavailable. Finish it if necessary, // and mark the broadcast record as ready for the next. Slog.w(TAG, "Unable to launch app " diff --git a/services/core/java/com/android/server/am/CacheOomRanker.java b/services/core/java/com/android/server/am/CacheOomRanker.java index 45ce4c5021bb2..50278fd81bb24 100644 --- a/services/core/java/com/android/server/am/CacheOomRanker.java +++ b/services/core/java/com/android/server/am/CacheOomRanker.java @@ -61,6 +61,7 @@ public class CacheOomRanker { private final Object mPhenotypeFlagLock = new Object(); private final ActivityManagerService mService; + private final ActivityManagerGlobalLock mProcLock; private final Object mProfilerLock; @GuardedBy("mPhenotypeFlagLock") @@ -106,6 +107,7 @@ public class CacheOomRanker { CacheOomRanker(final ActivityManagerService service) { mService = service; + mProcLock = service.mProcLock; mProfilerLock = service.mAppProfiler.mProfilerLock; } @@ -179,15 +181,14 @@ public class CacheOomRanker { * Re-rank the cached processes in the lru list with a weighted ordering * of lru, rss size and number of times the process has been put in the cache. */ - public void reRankLruCachedApps(ProcessList processList) { + @GuardedBy({"mService", "mProcLock"}) + void reRankLruCachedAppsLSP(ArrayList lruList, int lruProcessServiceStart) { float lruWeight; float usesWeight; float rssWeight; int[] lruPositions; RankedProcessRecord[] scoredProcessRecords; - ArrayList lruList = processList.mLruProcesses; - synchronized (mPhenotypeFlagLock) { lruWeight = mLruWeight; usesWeight = mUsesWeight; @@ -204,11 +205,11 @@ public class CacheOomRanker { // Collect the least recently used processes to re-rank, only rank cached // processes further down the list than mLruProcessServiceStart. int cachedProcessPos = 0; - for (int i = 0; i < processList.mLruProcessServiceStart + for (int i = 0; i < lruProcessServiceStart && cachedProcessPos < scoredProcessRecords.length; ++i) { ProcessRecord app = lruList.get(i); // Processes that will be assigned a cached oom adj score. - if (!app.killedByAm && app.thread != null && app.curAdj + if (!app.isKilledByAm() && app.getThread() != null && app.mState.getCurAdj() >= ProcessList.UNKNOWN_ADJ) { scoredProcessRecords[cachedProcessPos].proc = app; scoredProcessRecords[cachedProcessPos].score = 0.0f; @@ -247,7 +248,8 @@ public class CacheOomRanker { if (ActivityManagerDebugConfig.DEBUG_OOM_ADJ) { boolean printedHeader = false; for (int i = 0; i < scoredProcessRecords.length; ++i) { - if (scoredProcessRecords[i].proc.pid != lruList.get(lruPositions[i]).pid) { + if (scoredProcessRecords[i].proc.getPid() + != lruList.get(lruPositions[i]).getPid()) { if (!printedHeader) { Slog.i(OomAdjuster.TAG, "reRankLruCachedApps"); printedHeader = true; @@ -291,15 +293,15 @@ public class CacheOomRanker { private static class LastActivityTimeComparator implements Comparator { @Override public int compare(RankedProcessRecord o1, RankedProcessRecord o2) { - return Long.compare(o1.proc.lastActivityTime, o2.proc.lastActivityTime); + return Long.compare(o1.proc.getLastActivityTime(), o2.proc.getLastActivityTime()); } } private static class CacheUseComparator implements Comparator { @Override public int compare(RankedProcessRecord o1, RankedProcessRecord o2) { - return Long.compare(o1.proc.getCacheOomRankerUseCount(), - o2.proc.getCacheOomRankerUseCount()); + return Long.compare(o1.proc.mState.getCacheOomRankerUseCount(), + o2.proc.mState.getCacheOomRankerUseCount()); } } diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java index c558b3d004007..c18031fd6de60 100644 --- a/services/core/java/com/android/server/am/CachedAppOptimizer.java +++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java @@ -42,7 +42,6 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.FrameworkStatsLog; import com.android.server.ServiceThread; -import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.io.PrintWriter; @@ -153,9 +152,14 @@ public final class CachedAppOptimizer { */ final ServiceThread mCachedAppOptimizerThread; + @GuardedBy("mProcLock") private final ArrayList mPendingCompactionProcesses = new ArrayList(); + private final ActivityManagerService mAm; + + private final ActivityManagerGlobalLock mProcLock; + private final OnPropertiesChangedListener mOnFlagsChangedListener = new OnPropertiesChangedListener() { @Override @@ -234,7 +238,7 @@ public final class CachedAppOptimizer { @VisibleForTesting Handler mCompactionHandler; private Handler mFreezeHandler; - @GuardedBy("mAm") + @GuardedBy("mProcLock") private boolean mFreezerOverride = false; // Maps process ID to last compaction statistics for processes that we've fully compacted. Used @@ -242,6 +246,7 @@ public final class CachedAppOptimizer { // data for "some" compactions. Uses LinkedHashMap to ensure insertion order is kept and // facilitate removal of the oldest entry. @VisibleForTesting + @GuardedBy("mProcLock") LinkedHashMap mLastCompactionStats = new LinkedHashMap() { @Override @@ -264,6 +269,7 @@ public final class CachedAppOptimizer { CachedAppOptimizer(ActivityManagerService am, PropertyChangedCallbackForTest callback, ProcessDependencies processDependencies) { mAm = am; + mProcLock = am.mProcLock; mCachedAppOptimizerThread = new ServiceThread("CachedAppOptimizerThread", Process.THREAD_GROUP_SYSTEM, true); mProcStateThrottle = new HashSet<>(); @@ -309,7 +315,7 @@ public final class CachedAppOptimizer { } } - @GuardedBy("mAm") + @GuardedBy("mProcLock") void dump(PrintWriter pw) { pw.println("CachedAppOptimizer settings"); synchronized (mPhenotypeFlagLock) { @@ -350,58 +356,57 @@ public final class CachedAppOptimizer { } } - @GuardedBy("mAm") + @GuardedBy("mProcLock") void compactAppSome(ProcessRecord app) { - app.reqCompactAction = COMPACT_PROCESS_SOME; + app.mOptRecord.setReqCompactAction(COMPACT_PROCESS_SOME); mPendingCompactionProcesses.add(app); mCompactionHandler.sendMessage( mCompactionHandler.obtainMessage( - COMPACT_PROCESS_MSG, app.setAdj, app.setProcState)); + COMPACT_PROCESS_MSG, app.mState.getSetAdj(), app.mState.getSetProcState())); } - @GuardedBy("mAm") + @GuardedBy("mProcLock") void compactAppFull(ProcessRecord app) { - app.reqCompactAction = COMPACT_PROCESS_FULL; + app.mOptRecord.setReqCompactAction(COMPACT_PROCESS_FULL); mPendingCompactionProcesses.add(app); mCompactionHandler.sendMessage( mCompactionHandler.obtainMessage( - COMPACT_PROCESS_MSG, app.setAdj, app.setProcState)); + COMPACT_PROCESS_MSG, app.mState.getSetAdj(), app.mState.getSetProcState())); } - @GuardedBy("mAm") + @GuardedBy("mProcLock") void compactAppPersistent(ProcessRecord app) { - app.reqCompactAction = COMPACT_PROCESS_PERSISTENT; + app.mOptRecord.setReqCompactAction(COMPACT_PROCESS_PERSISTENT); mPendingCompactionProcesses.add(app); mCompactionHandler.sendMessage( mCompactionHandler.obtainMessage( - COMPACT_PROCESS_MSG, app.curAdj, app.setProcState)); + COMPACT_PROCESS_MSG, app.mState.getCurAdj(), app.mState.getSetProcState())); } - @GuardedBy("mAm") + @GuardedBy("mProcLock") boolean shouldCompactPersistent(ProcessRecord app, long now) { - return (app.lastCompactTime == 0 - || (now - app.lastCompactTime) > mCompactThrottlePersistent); + return (app.mOptRecord.getLastCompactTime() == 0 + || (now - app.mOptRecord.getLastCompactTime()) > mCompactThrottlePersistent); } - @GuardedBy("mAm") + @GuardedBy("mProcLock") void compactAppBfgs(ProcessRecord app) { - app.reqCompactAction = COMPACT_PROCESS_BFGS; + app.mOptRecord.setReqCompactAction(COMPACT_PROCESS_BFGS); mPendingCompactionProcesses.add(app); mCompactionHandler.sendMessage( mCompactionHandler.obtainMessage( - COMPACT_PROCESS_MSG, app.curAdj, app.setProcState)); + COMPACT_PROCESS_MSG, app.mState.getCurAdj(), app.mState.getSetProcState())); } - @GuardedBy("mAm") + @GuardedBy("mProcLock") boolean shouldCompactBFGS(ProcessRecord app, long now) { - return (app.lastCompactTime == 0 - || (now - app.lastCompactTime) > mCompactThrottleBFGS); + return (app.mOptRecord.getLastCompactTime() == 0 + || (now - app.mOptRecord.getLastCompactTime()) > mCompactThrottleBFGS); } - @GuardedBy("mAm") void compactAllSystem() { - if (mUseCompaction) { + if (useCompaction()) { mCompactionHandler.sendMessage(mCompactionHandler.obtainMessage( COMPACT_SYSTEM_MSG)); } @@ -468,29 +473,28 @@ public final class CachedAppOptimizer { // Override is applied immediately, restore is delayed synchronized (mAm) { - int processCount = mAm.mProcessList.mLruProcesses.size(); + synchronized (mProcLock) { + mFreezerOverride = !enable; + Slog.d(TAG_AM, "freezer override set to " + mFreezerOverride); - mFreezerOverride = !enable; - Slog.d(TAG_AM, "freezer override set to " + mFreezerOverride); + mAm.mProcessList.forEachLruProcessesLOSP(true, process -> { + if (process == null) { + return; + } - for (int i = 0; i < processCount; i++) { - ProcessRecord process = mAm.mProcessList.mLruProcesses.get(i); + final ProcessCachedOptimizerRecord opt = process.mOptRecord; + if (enable && opt.hasFreezerOverride()) { + freezeAppAsyncLSP(process); + opt.setFreezerOverride(false); + } - if (process == null) { - continue; - } + if (!enable && opt.isFrozen()) { + unfreezeAppLSP(process); - if (enable && process.freezerOverride) { - freezeAppAsync(process); - process.freezerOverride = false; - } - - if (!enable && process.frozen) { - unfreezeAppLocked(process); - - // Set freezerOverride *after* calling unfreezeAppLocked (it resets the flag) - process.freezerOverride = true; - } + // Set freezerOverride *after* calling unfreezeAppLSP (it resets the flag) + opt.setFreezerOverride(true); + } + }); } } @@ -740,19 +744,20 @@ public final class CachedAppOptimizer { } // This will ensure app will be out of the freezer for at least FREEZE_TIMEOUT_MS + @GuardedBy("mAm") void unfreezeTemporarily(ProcessRecord app) { if (mUseFreezer) { - synchronized (mAm) { - if (app.frozen) { - unfreezeAppLocked(app); - freezeAppAsync(app); + synchronized (mProcLock) { + if (app.mOptRecord.isFrozen()) { + unfreezeAppLSP(app); + freezeAppAsyncLSP(app); } } } } - @GuardedBy("mAm") - void freezeAppAsync(ProcessRecord app) { + @GuardedBy({"mAm", "mProcLock"}) + void freezeAppAsyncLSP(ProcessRecord app) { mFreezeHandler.removeMessages(SET_FROZEN_PROCESS_MSG, app); mFreezeHandler.sendMessageDelayed( @@ -761,16 +766,17 @@ public final class CachedAppOptimizer { FREEZE_TIMEOUT_MS); } - @GuardedBy("mAm") - void unfreezeAppLocked(ProcessRecord app) { + @GuardedBy({"mAm", "mProcLock"}) + void unfreezeAppLSP(ProcessRecord app) { mFreezeHandler.removeMessages(SET_FROZEN_PROCESS_MSG, app); - app.freezerOverride = false; - - if (!app.frozen) { + final int pid = app.getPid(); + final ProcessCachedOptimizerRecord opt = app.mOptRecord; + opt.setFreezerOverride(false); + if (!opt.isFrozen()) { if (DEBUG_FREEZER) { Slog.d(TAG_AM, - "Skipping unfreeze for process " + app.pid + " " + "Skipping unfreeze for process " + pid + " " + app.processName + " (not frozen)"); } return; @@ -781,25 +787,25 @@ public final class CachedAppOptimizer { boolean processKilled = false; try { - int freezeInfo = getBinderFreezeInfo(app.pid); + int freezeInfo = getBinderFreezeInfo(pid); if ((freezeInfo & SYNC_RECEIVED_WHILE_FROZEN) != 0) { - Slog.d(TAG_AM, "pid " + app.pid + " " + app.processName + " " + Slog.d(TAG_AM, "pid " + pid + " " + app.processName + " " + " received sync transactions while frozen, killing"); - app.kill("Sync transaction while in frozen state", + app.killLocked("Sync transaction while in frozen state", ApplicationExitInfo.REASON_OTHER, ApplicationExitInfo.SUBREASON_INVALID_STATE, true); processKilled = true; } if ((freezeInfo & ASYNC_RECEIVED_WHILE_FROZEN) != 0) { - Slog.d(TAG_AM, "pid " + app.pid + " " + app.processName + " " + Slog.d(TAG_AM, "pid " + pid + " " + app.processName + " " + " received async transactions while frozen"); } } catch (Exception e) { - Slog.d(TAG_AM, "Unable to query binder frozen info for pid " + app.pid + " " + Slog.d(TAG_AM, "Unable to query binder frozen info for pid " + pid + " " + app.processName + ". Killing it. Exception: " + e); - app.kill("Unable to query binder frozen stats", + app.killLocked("Unable to query binder frozen stats", ApplicationExitInfo.REASON_OTHER, ApplicationExitInfo.SUBREASON_INVALID_STATE, true); processKilled = true; @@ -809,38 +815,38 @@ public final class CachedAppOptimizer { return; } - long freezeTime = app.freezeUnfreezeTime; + long freezeTime = opt.getFreezeUnfreezeTime(); try { - freezeBinder(app.pid, false); + freezeBinder(pid, false); } catch (RuntimeException e) { - Slog.e(TAG_AM, "Unable to unfreeze binder for " + app.pid + " " + app.processName + Slog.e(TAG_AM, "Unable to unfreeze binder for " + pid + " " + app.processName + ". Killing it"); - app.kill("Unable to unfreeze", + app.killLocked("Unable to unfreeze", ApplicationExitInfo.REASON_OTHER, ApplicationExitInfo.SUBREASON_INVALID_STATE, true); return; } try { - Process.setProcessFrozen(app.pid, app.uid, false); + Process.setProcessFrozen(pid, app.uid, false); - app.freezeUnfreezeTime = SystemClock.uptimeMillis(); - app.frozen = false; + opt.setFreezeUnfreezeTime(SystemClock.uptimeMillis()); + opt.setFrozen(false); } catch (Exception e) { - Slog.e(TAG_AM, "Unable to unfreeze " + app.pid + " " + app.processName + Slog.e(TAG_AM, "Unable to unfreeze " + pid + " " + app.processName + ". This might cause inconsistency or UI hangs."); } - if (!app.frozen) { + if (!opt.isFrozen()) { if (DEBUG_FREEZER) { - Slog.d(TAG_AM, "sync unfroze " + app.pid + " " + app.processName); + Slog.d(TAG_AM, "sync unfroze " + pid + " " + app.processName); } mFreezeHandler.sendMessage( mFreezeHandler.obtainMessage(REPORT_UNFREEZE_MSG, - app.pid, - (int) Math.min(app.freezeUnfreezeTime - freezeTime, Integer.MAX_VALUE), + pid, + (int) Math.min(opt.getFreezeUnfreezeTime() - freezeTime, Integer.MAX_VALUE), app.processName)); } } @@ -869,6 +875,7 @@ public final class CachedAppOptimizer { case COMPACT_PROCESS_MSG: { long start = SystemClock.uptimeMillis(); ProcessRecord proc; + final ProcessCachedOptimizerRecord opt; int pid; String action; final String name; @@ -877,18 +884,19 @@ public final class CachedAppOptimizer { LastCompactionStats lastCompactionStats; int lastOomAdj = msg.arg1; int procState = msg.arg2; - synchronized (mAm) { + synchronized (mProcLock) { proc = mPendingCompactionProcesses.remove(0); + opt = proc.mOptRecord; - pendingAction = proc.reqCompactAction; - pid = proc.pid; + pendingAction = opt.getReqCompactAction(); + pid = proc.getPid(); name = proc.processName; // don't compact if the process has returned to perceptible // and this is only a cached/home/prev compaction if ((pendingAction == COMPACT_PROCESS_SOME || pendingAction == COMPACT_PROCESS_FULL) - && (proc.setAdj <= ProcessList.PERCEPTIBLE_APP_ADJ)) { + && (proc.mState.getSetAdj() <= ProcessList.PERCEPTIBLE_APP_ADJ)) { if (DEBUG_COMPACTION) { Slog.d(TAG_AM, "Skipping compaction as process " + name + " is " @@ -897,8 +905,8 @@ public final class CachedAppOptimizer { return; } - lastCompactAction = proc.lastCompactAction; - lastCompactTime = proc.lastCompactTime; + lastCompactAction = opt.getLastCompactAction(); + lastCompactTime = opt.getLastCompactTime(); lastCompactionStats = mLastCompactionStats.get(pid); } @@ -1076,9 +1084,9 @@ public final class CachedAppOptimizer { lastOomAdj, ActivityManager.processStateAmToProto(procState), zramFreeKbBefore, zramFreeKbAfter); } - synchronized (mAm) { - proc.lastCompactTime = end; - proc.lastCompactAction = pendingAction; + synchronized (mProcLock) { + opt.setLastCompactTime(end); + opt.setLastCompactAction(pendingAction); } if (action.equals(COMPACT_ACTION_STRING[COMPACT_ACTION_FULL]) || action.equals(COMPACT_ACTION_STRING[COMPACT_ACTION_ANON])) { @@ -1126,11 +1134,12 @@ public final class CachedAppOptimizer { } } - private void freezeProcess(ProcessRecord proc) { - final int pid = proc.pid; + private void freezeProcess(final ProcessRecord proc) { + int pid = proc.getPid(); // Unlocked intentionally final String name = proc.processName; final long unfrozenDuration; final boolean frozen; + final ProcessCachedOptimizerRecord opt = proc.mOptRecord; try { // pre-check for locks to avoid unnecessary freeze/unfreeze operations @@ -1146,26 +1155,27 @@ public final class CachedAppOptimizer { return; } - synchronized (mAm) { - if (proc.curAdj < ProcessList.CACHED_APP_MIN_ADJ - || proc.shouldNotFreeze) { + synchronized (mProcLock) { + pid = proc.getPid(); + if (proc.mState.getCurAdj() < ProcessList.CACHED_APP_MIN_ADJ + || opt.shouldNotFreeze()) { if (DEBUG_FREEZER) { Slog.d(TAG_AM, "Skipping freeze for process " + pid - + " " + name + " curAdj = " + proc.curAdj - + ", shouldNotFreeze = " + proc.shouldNotFreeze); + + " " + name + " curAdj = " + proc.mState.getCurAdj() + + ", shouldNotFreeze = " + opt.shouldNotFreeze()); } return; } if (mFreezerOverride) { - proc.freezerOverride = true; + opt.setFreezerOverride(true); Slog.d(TAG_AM, "Skipping freeze for process " + pid - + " " + name + " curAdj = " + proc.curAdj + + " " + name + " curAdj = " + proc.mState.getCurAdj() + "(override)"); return; } - if (pid == 0 || proc.frozen) { + if (pid == 0 || opt.isFrozen()) { // Already frozen or not a real process, either one being // launched or one being killed return; @@ -1177,24 +1187,28 @@ public final class CachedAppOptimizer { freezeBinder(pid, true); } catch (RuntimeException e) { Slog.e(TAG_AM, "Unable to freeze binder for " + pid + " " + name); - proc.kill("Unable to freeze binder interface", - ApplicationExitInfo.REASON_OTHER, - ApplicationExitInfo.SUBREASON_INVALID_STATE, true); + mFreezeHandler.post(() -> { + synchronized (mAm) { + proc.killLocked("Unable to freeze binder interface", + ApplicationExitInfo.REASON_OTHER, + ApplicationExitInfo.SUBREASON_INVALID_STATE, true); + } + }); } - long unfreezeTime = proc.freezeUnfreezeTime; + long unfreezeTime = opt.getFreezeUnfreezeTime(); try { Process.setProcessFrozen(pid, proc.uid, true); - proc.freezeUnfreezeTime = SystemClock.uptimeMillis(); - proc.frozen = true; + opt.setFreezeUnfreezeTime(SystemClock.uptimeMillis()); + opt.setFrozen(true); } catch (Exception e) { Slog.w(TAG_AM, "Unable to freeze " + pid + " " + name); } - unfrozenDuration = proc.freezeUnfreezeTime - unfreezeTime; - frozen = proc.frozen; + unfrozenDuration = opt.getFreezeUnfreezeTime() - unfreezeTime; + frozen = opt.isFrozen(); } if (!frozen) { @@ -1225,13 +1239,17 @@ public final class CachedAppOptimizer { } synchronized (mAm) { - unfreezeAppLocked(proc); + synchronized (mProcLock) { + unfreezeAppLSP(proc); + } } } } catch (IOException e) { Slog.e(TAG_AM, "Unable to check file locks for " + name + "(" + pid + "): " + e); synchronized (mAm) { - unfreezeAppLocked(proc); + synchronized (mProcLock) { + unfreezeAppLSP(proc); + } } } } diff --git a/services/core/java/com/android/server/am/ContentProviderHelper.java b/services/core/java/com/android/server/am/ContentProviderHelper.java index 478c512338f00..f43c7f6278c93 100644 --- a/services/core/java/com/android/server/am/ContentProviderHelper.java +++ b/services/core/java/com/android/server/am/ContentProviderHelper.java @@ -57,6 +57,7 @@ import android.os.RemoteException; import android.os.SystemClock; import android.os.UserHandle; import android.provider.Settings; +import android.util.ArrayMap; import android.util.Log; import android.util.Slog; import android.util.SparseArray; @@ -148,7 +149,7 @@ public class ContentProviderHelper { ProcessRecord r = null; if (caller != null) { - r = mService.getRecordForAppLocked(caller); + r = mService.getRecordForAppLOSP(caller); if (r == null) { throw new SecurityException("Unable to find app for caller " + caller + " (pid=" + Binder.getCallingPid() + ") when getting content provider " @@ -183,14 +184,14 @@ public class ContentProviderHelper { ProcessRecord dyingProc = null; if (cpr != null && cpr.proc != null) { - providerRunning = !cpr.proc.killed; + providerRunning = !cpr.proc.isKilled(); // Note if killedByAm is also set, this means the provider process has just been // killed by AM (in ProcessRecord.kill()), but appDiedLocked() hasn't been called // yet. So we need to call appDiedLocked() here and let it clean up. // (See the commit message on I2c4ba1e87c2d47f2013befff10c49b3dc337a9a7 to see // how to test this case.) - if (cpr.proc.killed && cpr.proc.killedByAm) { + if (cpr.proc.isKilled() && cpr.proc.isKilledByAm()) { Slog.wtf(TAG, cpr.proc.toString() + " was killed by AM but isn't really dead"); // Now we are going to wait for the death before starting the new process. dyingProc = cpr.proc; @@ -235,7 +236,7 @@ public class ContentProviderHelper { callingTag, stable, true, startTime, mService.mProcessList); checkTime(startTime, "getContentProviderImpl: before updateOomAdj"); - final int verifiedAdj = cpr.proc.verifiedAdj; + final int verifiedAdj = cpr.proc.mState.getVerifiedAdj(); boolean success = mService.updateOomAdjLocked(cpr.proc, true, OomAdjuster.OOM_ADJ_REASON_GET_PROVIDER); // XXX things have changed so updateOomAdjLocked doesn't actually tell us @@ -243,7 +244,7 @@ public class ContentProviderHelper { // it, we will check whether the process still exists. Note that this doesn't // completely get rid of races with LMK killing the process, but should make // them much smaller. - if (success && verifiedAdj != cpr.proc.setAdj + if (success && verifiedAdj != cpr.proc.mState.getSetAdj() && !isProcessAliveLocked(cpr.proc)) { success = false; } @@ -275,7 +276,7 @@ public class ContentProviderHelper { conn = null; dyingProc = cpr.proc; } else { - cpr.proc.verifiedAdj = cpr.proc.setAdj; + cpr.proc.mState.setVerifiedAdj(cpr.proc.mState.getSetAdj()); } } finally { Binder.restoreCallingIdentity(origId); @@ -428,15 +429,18 @@ public class ContentProviderHelper { checkTime(startTime, "getContentProviderImpl: looking for process record"); ProcessRecord proc = mService.getProcessRecordLocked( cpi.processName, cpr.appInfo.uid, false); - if (proc != null && proc.thread != null && !proc.killed) { + IApplicationThread thread; + if (proc != null && (thread = proc.getThread()) != null + && !proc.isKilled()) { if (ActivityManagerDebugConfig.DEBUG_PROVIDER) { Slog.d(TAG, "Installing in existing process " + proc); } - if (!proc.pubProviders.containsKey(cpi.name)) { + final ProcessProviderRecord pr = proc.mProviders; + if (!pr.hasProvider(cpi.name)) { checkTime(startTime, "getContentProviderImpl: scheduling install"); - proc.pubProviders.put(cpi.name, cpr); + pr.installProvider(cpi.name, cpr); try { - proc.thread.scheduleInstallProvider(cpi); + thread.scheduleInstallProvider(cpi); } catch (RemoteException e) { } } @@ -445,8 +449,8 @@ public class ContentProviderHelper { proc = mService.startProcessLocked( cpi.processName, cpr.appInfo, false, 0, new HostingRecord("content provider", - new ComponentName( - cpi.applicationInfo.packageName, cpi.name)), + new ComponentName( + cpi.applicationInfo.packageName, cpi.name)), Process.ZYGOTE_POLICY_FLAG_EMPTY, false, false, false); checkTime(startTime, "getContentProviderImpl: after start process"); if (proc == null) { @@ -558,9 +562,9 @@ public class ContentProviderHelper { // Note we do it after releasing the lock. String callerName = "unknown"; if (caller != null) { - synchronized (mService) { + synchronized (mService.mProcLock) { final ProcessRecord record = - mService.mProcessList.getLRURecordForAppLocked(caller); + mService.mProcessList.getLRURecordForAppLOSP(caller); if (record != null) { callerName = record.processName; } @@ -600,7 +604,7 @@ public class ContentProviderHelper { mService.enforceNotIsolatedCaller("publishContentProviders"); synchronized (mService) { - final ProcessRecord r = mService.getRecordForAppLocked(caller); + final ProcessRecord r = mService.getRecordForAppLOSP(caller); if (DEBUG_MU) { Slog.v(TAG_MU, "ProcessRecord uid = " + r.uid); } @@ -617,7 +621,7 @@ public class ContentProviderHelper { if (src == null || src.info == null || src.provider == null) { continue; } - ContentProviderRecord dst = r.pubProviders.get(src.info.name); + ContentProviderRecord dst = r.mProviders.getProvider(src.info.name); if (dst == null) { continue; } @@ -808,7 +812,7 @@ public class ContentProviderHelper { } ProcessRecord proc = conn.provider.proc; - if (proc == null || proc.thread == null) { + if (proc == null || proc.getThread() == null) { // Seems like the process is already cleaned up. return; } @@ -816,7 +820,7 @@ public class ContentProviderHelper { // As far as we're concerned, this is just like receiving a // death notification... just a bit prematurely. mService.reportUidInfoMessageLocked(TAG, "Process " + proc.processName - + " (pid " + proc.pid + ") early provider death", proc.info.uid); + + " (pid " + proc.getPid() + ") early provider death", proc.info.uid); final long token = Binder.clearCallingIdentity(); try { mService.appDiedLocked(proc, "unstable content provider"); @@ -1074,7 +1078,8 @@ public class ContentProviderHelper { } int numProviders = providers.size(); - app.pubProviders.ensureCapacity(numProviders + app.pubProviders.size()); + final ProcessProviderRecord pr = app.mProviders; + pr.ensureProviderCapacity(numProviders + pr.numberOfProviders()); for (int i = 0; i < numProviders; i++) { // NOTE: keep logic in sync with installEncryptionUnawareProviders ProviderInfo cpi = providers.get(i); @@ -1111,7 +1116,7 @@ public class ContentProviderHelper { if (DEBUG_MU) { Slog.v(TAG_MU, "generateApplicationProvidersLocked, cpi.uid = " + cpr.uid); } - app.pubProviders.put(cpi.name, cpr); + pr.installProvider(cpi.name, cpr); if (!cpi.multiprocess || !"android".equals(cpi.packageName)) { // Don't add this if it is a platform component that is marked // to run in multiple processes, because this is actually @@ -1162,7 +1167,8 @@ public class ContentProviderHelper { public final void installSystemProviders() { List providers; synchronized (mService) { - ProcessRecord app = mService.mProcessList.mProcessNames.get("system", SYSTEM_UID); + ProcessRecord app = mService.mProcessList + .getProcessNamesLOSP().get("system", SYSTEM_UID); providers = generateApplicationProvidersLocked(app); if (providers != null) { for (int i = providers.size() - 1; i >= 0; i--) { @@ -1205,25 +1211,29 @@ public class ContentProviderHelper { final int matchFlags = PackageManager.GET_PROVIDERS | PackageManager.MATCH_DIRECT_BOOT_UNAWARE; - synchronized (mService) { - final int numProc = mService.mProcessList.mProcessNames.getMap().size(); + synchronized (mService.mProcLock) { + final ArrayMap> pmap = + mService.mProcessList.getProcessNamesLOSP().getMap(); + final int numProc = pmap.size(); for (int iProc = 0; iProc < numProc; iProc++) { - final SparseArray apps = - mService.mProcessList.mProcessNames.getMap().valueAt(iProc); + final SparseArray apps = pmap.valueAt(iProc); for (int iApp = 0, numApps = apps.size(); iApp < numApps; iApp++) { final ProcessRecord app = apps.valueAt(iApp); - if (app.userId != userId || app.thread == null || app.unlocked) continue; + if (app.userId != userId || app.getThread() == null || app.isUnlocked()) { + continue; + } app.getPkgList().forEachPackage(pkgName -> { try { final PackageInfo pkgInfo = AppGlobals.getPackageManager() - .getPackageInfo(pkgName, matchFlags, userId); + .getPackageInfo(pkgName, matchFlags, app.userId); + final IApplicationThread thread = app.getThread(); if (pkgInfo != null && !ArrayUtils.isEmpty(pkgInfo.providers)) { for (ProviderInfo pi : pkgInfo.providers) { // NOTE: keep in sync with generateApplicationProvidersLocked final boolean processMatch = Objects.equals(pi.processName, app.processName) - || pi.multiprocess; + || pi.multiprocess; final boolean userMatch = !mService.isSingleton( pi.processName, pi.applicationInfo, pi.name, pi.flags) || app.userId == UserHandle.USER_SYSTEM; @@ -1234,7 +1244,7 @@ public class ContentProviderHelper { if (processMatch && userMatch && (!isInstantApp || splitInstalled)) { Log.v(TAG, "Installing " + pi); - app.thread.scheduleInstallProvider(pi); + thread.scheduleInstallProvider(pi); } else { Log.v(TAG, "Skipping " + pi); } @@ -1259,8 +1269,9 @@ public class ContentProviderHelper { } - for (int i = 0, size = r.conProviders.size(); i < size; i++) { - ContentProviderConnection conn = r.conProviders.get(i); + final ProcessProviderRecord pr = r.mProviders; + for (int i = 0, size = pr.numberOfProviderConnections(); i < size; i++) { + ContentProviderConnection conn = pr.getProviderConnectionAt(i); if (conn.provider == cpr) { conn.incrementCount(stable); return conn; @@ -1272,10 +1283,11 @@ public class ContentProviderHelper { conn.startAssociationIfNeeded(); conn.initializeCount(stable); cpr.connections.add(conn); - r.conProviders.add(conn); - mService.startAssociationLocked(r.uid, r.processName, r.getCurProcState(), + pr.addProviderConnection(conn); + mService.startAssociationLocked(r.uid, r.processName, r.mState.getCurProcState(), cpr.uid, cpr.appInfo.longVersionCode, cpr.name, cpr.info.processName); - if (updateLru && cpr.proc != null && r.setAdj <= ProcessList.PERCEPTIBLE_LOW_APP_ADJ) { + if (updateLru && cpr.proc != null + && r.mState.getSetAdj() <= ProcessList.PERCEPTIBLE_LOW_APP_ADJ) { // If this is a perceptible app accessing the provider, make // sure to count it as being accessed and thus back up on // the LRU list. This is good because content providers are @@ -1325,13 +1337,14 @@ public class ContentProviderHelper { final ContentProviderRecord cpr = conn.provider; conn.stopAssociation(); cpr.connections.remove(conn); - conn.client.conProviders.remove(conn); - if (conn.client.setProcState < ActivityManager.PROCESS_STATE_LAST_ACTIVITY) { + conn.client.mProviders.removeProviderConnection(conn); + if (conn.client.mState.getSetProcState() + < ActivityManager.PROCESS_STATE_LAST_ACTIVITY) { // The client is more important than last activity -- note the time this // is happening, so we keep the old provider process around a bit as last // activity to avoid thrashing it. if (cpr.proc != null) { - cpr.proc.lastProviderTime = SystemClock.uptimeMillis(); + cpr.proc.mProviders.setLastProviderTime(SystemClock.uptimeMillis()); } } mService.stopAssociationLocked(conn.client.uid, conn.client.processName, cpr.uid, @@ -1429,9 +1442,9 @@ public class ContentProviderHelper { return mService.validateAssociationAllowedLocked(cpi.packageName, cpi.applicationInfo.uid, null, callingUid) ? null : ""; } - final String r = callingApp.getPkgList().forEachPackage(pkgName -> { + final String r = callingApp.getPkgList().searchEachPackage(pkgName -> { if (!mService.validateAssociationAllowedLocked(pkgName, - callingApp.uid, cpi.packageName, cpi.applicationInfo.uid)) { + callingApp.uid, cpi.packageName, cpi.applicationInfo.uid)) { return cpi.packageName; } return null; @@ -1455,8 +1468,8 @@ public class ContentProviderHelper { private void maybeUpdateProviderUsageStatsLocked(ProcessRecord app, String providerPkgName, String authority) { - if (app == null - || app.getCurProcState() > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) { + if (app == null || app.mState.getCurProcState() + > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) { return; } @@ -1483,31 +1496,30 @@ public class ContentProviderHelper { private final long[] mProcessStateStatsLongs = new long[1]; private boolean isProcessAliveLocked(ProcessRecord proc) { - if (proc.pid <= 0) { + final int pid = proc.getPid(); + if (pid <= 0) { if (ActivityManagerDebugConfig.DEBUG_OOM_ADJ) { Slog.d(ActivityManagerService.TAG, "Process hasn't started yet: " + proc); } return false; } - if (proc.procStatFile == null) { - proc.procStatFile = "/proc/" + proc.pid + "/stat"; - } + final String procStatFile = "/proc/" + pid + "/stat"; mProcessStateStatsLongs[0] = 0; - if (!Process.readProcFile(proc.procStatFile, PROCESS_STATE_STATS_FORMAT, null, + if (!Process.readProcFile(procStatFile, PROCESS_STATE_STATS_FORMAT, null, mProcessStateStatsLongs, null)) { if (ActivityManagerDebugConfig.DEBUG_OOM_ADJ) { Slog.d(ActivityManagerService.TAG, - "UNABLE TO RETRIEVE STATE FOR " + proc.procStatFile); + "UNABLE TO RETRIEVE STATE FOR " + procStatFile); } return false; } final long state = mProcessStateStatsLongs[0]; if (ActivityManagerDebugConfig.DEBUG_OOM_ADJ) { Slog.d(ActivityManagerService.TAG, - "RETRIEVED STATE FOR " + proc.procStatFile + ": " + (char) state); + "RETRIEVED STATE FOR " + procStatFile + ": " + (char) state); } if (state != 'Z' && state != 'X' && state != 'x' && state != 'K') { - return Process.getUidForPid(proc.pid) == proc.uid; + return Process.getUidForPid(pid) == proc.uid; } return false; } @@ -1537,7 +1549,7 @@ public class ContentProviderHelper { } final boolean callerForeground = r == null - || r.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND; + || r.mState.getSetSchedGroup() != ProcessList.SCHED_GROUP_BACKGROUND; // Show a permission review UI only for starting from a foreground app if (!callerForeground) { @@ -1611,26 +1623,29 @@ public class ContentProviderHelper { } } ProcessRecord capp = conn.client; + final IApplicationThread thread = capp.getThread(); conn.dead = true; if (conn.stableCount() > 0) { - if (!capp.isPersistent() && capp.thread != null - && capp.pid != 0 && capp.pid != ActivityManagerService.MY_PID) { - capp.kill("depends on provider " + cpr.name.flattenToShortString() - + " in dying proc " + (proc != null ? proc.processName : "??") - + " (adj " + (proc != null ? proc.setAdj : "??") + ")", + final int pid = capp.getPid(); + if (!capp.isPersistent() && thread != null + && pid != 0 && pid != ActivityManagerService.MY_PID) { + capp.killLocked( + "depends on provider " + cpr.name.flattenToShortString() + + " in dying proc " + (proc != null ? proc.processName : "??") + + " (adj " + (proc != null ? proc.mState.getSetAdj() : "??") + ")", ApplicationExitInfo.REASON_DEPENDENCY_DIED, ApplicationExitInfo.SUBREASON_UNKNOWN, true); } - } else if (capp.thread != null && conn.provider.provider != null) { + } else if (thread != null && conn.provider.provider != null) { try { - capp.thread.unstableProviderDied(conn.provider.provider.asBinder()); + thread.unstableProviderDied(conn.provider.provider.asBinder()); } catch (RemoteException e) { } // In the protocol here, we don't expect the client to correctly // clean up this connection, we'll just remove it. cpr.connections.remove(i); - if (conn.client.conProviders.remove(conn)) { + if (conn.client.mProviders.removeProviderConnection(conn)) { mService.stopAssociationLocked(capp.uid, capp.processName, cpr.uid, cpr.appInfo.longVersionCode, cpr.name, cpr.info.processName); } @@ -1671,7 +1686,7 @@ public class ContentProviderHelper { // It's being launched but we've reached maximum attempts, mark it as bad alwaysBad = true; } - if (!alwaysBad && !app.bad && cpr.hasConnectionOrHandle()) { + if (!alwaysBad && !app.mErrorState.isBad() && cpr.hasConnectionOrHandle()) { restart = true; } else { removeDyingProviderLocked(app, cpr, true); diff --git a/services/core/java/com/android/server/am/ContentProviderRecord.java b/services/core/java/com/android/server/am/ContentProviderRecord.java index 59a19398420d2..b217cae61d4cb 100644 --- a/services/core/java/com/android/server/am/ContentProviderRecord.java +++ b/services/core/java/com/android/server/am/ContentProviderRecord.java @@ -19,6 +19,7 @@ package com.android.server.am; import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import android.app.ContentProviderHolder; +import android.app.IApplicationThread; import android.content.ComponentName; import android.content.IContentProvider; import android.content.pm.ApplicationInfo; @@ -211,9 +212,10 @@ final class ContentProviderRecord implements ComponentName.WithComponentName { + " caller=" + client); } } - if (client.thread != null) { + final IApplicationThread thread = client.getThread(); + if (thread != null) { try { - client.thread.notifyContentProviderPublishStatus( + thread.notifyContentProviderPublishStatus( newHolder(status ? conn : null, false), info.authority, userId, status); } catch (RemoteException e) { @@ -343,8 +345,8 @@ final class ContentProviderRecord implements ComponentName.WithComponentName { && mAssociation == null && provider.proc != null && (provider.appInfo.uid != mOwningUid || !provider.info.processName.equals(mOwningProcessName))) { - ProcessStats.ProcessStateHolder holder = provider.proc.getPkgList().get( - provider.name.getPackageName()); + ProcessStats.ProcessStateHolder holder = + provider.proc.getPkgList().get(provider.name.getPackageName()); if (holder == null) { Slog.wtf(TAG_AM, "No package in referenced provider " + provider.name.toShortString() + ": proc=" + provider.proc); @@ -373,7 +375,7 @@ final class ContentProviderRecord implements ComponentName.WithComponentName { if (hasExternalProcessHandles() && externalProcessTokenToHandle.get(mToken) != null) { removeExternalProcessHandleInternalLocked(mToken); - } + } } } } diff --git a/services/core/java/com/android/server/am/ErrorDialogController.java b/services/core/java/com/android/server/am/ErrorDialogController.java new file mode 100644 index 0000000000000..ef135d55e43cd --- /dev/null +++ b/services/core/java/com/android/server/am/ErrorDialogController.java @@ -0,0 +1,251 @@ +/* + * 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 android.app.Dialog; +import android.content.Context; + +import com.android.internal.annotations.GuardedBy; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; + +/** + * A controller to generate error dialogs in {@link ProcessRecord}. + */ +final class ErrorDialogController { + private final ProcessRecord mApp; + private final ActivityManagerService mService; + private final ActivityManagerGlobalLock mProcLock; + + /** + * Dialogs being displayed due to crash. + */ + @GuardedBy("mProcLock") + private List mCrashDialogs; + + /** + * Dialogs being displayed due to app not responding. + */ + @GuardedBy("mProcLock") + private List mAnrDialogs; + + /** + * Dialogs displayed due to strict mode violation. + */ + @GuardedBy("mProcLock") + private List mViolationDialogs; + + /** + * Current wait for debugger dialog. + */ + @GuardedBy("mProcLock") + private AppWaitingForDebuggerDialog mWaitDialog; + + @GuardedBy("mProcLock") + boolean hasCrashDialogs() { + return mCrashDialogs != null; + } + + @GuardedBy("mProcLock") + List getCrashDialogs() { + return mCrashDialogs; + } + + @GuardedBy("mProcLock") + boolean hasAnrDialogs() { + return mAnrDialogs != null; + } + + @GuardedBy("mProcLock") + List getAnrDialogs() { + return mAnrDialogs; + } + + @GuardedBy("mProcLock") + boolean hasViolationDialogs() { + return mViolationDialogs != null; + } + + @GuardedBy("mProcLock") + boolean hasDebugWaitingDialog() { + return mWaitDialog != null; + } + + @GuardedBy("mProcLock") + void clearAllErrorDialogs() { + clearCrashDialogs(); + clearAnrDialogs(); + clearViolationDialogs(); + clearWaitingDialog(); + } + + @GuardedBy("mProcLock") + void clearCrashDialogs() { + clearCrashDialogs(true /* needDismiss */); + } + + @GuardedBy("mProcLock") + void clearCrashDialogs(boolean needDismiss) { + if (mCrashDialogs == null) { + return; + } + if (needDismiss) { + forAllDialogs(mCrashDialogs, Dialog::dismiss); + } + mCrashDialogs = null; + } + + @GuardedBy("mProcLock") + void clearAnrDialogs() { + if (mAnrDialogs == null) { + return; + } + forAllDialogs(mAnrDialogs, Dialog::dismiss); + mAnrDialogs = null; + } + + @GuardedBy("mProcLock") + void clearViolationDialogs() { + if (mViolationDialogs == null) { + return; + } + forAllDialogs(mViolationDialogs, Dialog::dismiss); + mViolationDialogs = null; + } + + @GuardedBy("mProcLock") + void clearWaitingDialog() { + if (mWaitDialog == null) { + return; + } + mWaitDialog.dismiss(); + mWaitDialog = null; + } + + void forAllDialogs(List dialogs, Consumer c) { + for (int i = dialogs.size() - 1; i >= 0; i--) { + c.accept(dialogs.get(i)); + } + } + + @GuardedBy("mProcLock") + void showCrashDialogs(AppErrorDialog.Data data) { + List contexts = getDisplayContexts(false /* lastUsedOnly */); + mCrashDialogs = new ArrayList<>(); + for (int i = contexts.size() - 1; i >= 0; i--) { + final Context c = contexts.get(i); + mCrashDialogs.add(new AppErrorDialog(c, mService, data)); + } + mService.mUiHandler.post(() -> { + List dialogs; + synchronized (mProcLock) { + dialogs = mCrashDialogs; + } + if (dialogs != null) { + forAllDialogs(dialogs, Dialog::show); + } + }); + } + + @GuardedBy("mProcLock") + void showAnrDialogs(AppNotRespondingDialog.Data data) { + List contexts = getDisplayContexts( + mApp.mErrorState.isSilentAnr() /* lastUsedOnly */); + mAnrDialogs = new ArrayList<>(); + for (int i = contexts.size() - 1; i >= 0; i--) { + final Context c = contexts.get(i); + mAnrDialogs.add(new AppNotRespondingDialog(mService, c, data)); + } + mService.mUiHandler.post(() -> { + List dialogs; + synchronized (mProcLock) { + dialogs = mAnrDialogs; + } + if (dialogs != null) { + forAllDialogs(dialogs, Dialog::show); + } + }); + } + + @GuardedBy("mProcLock") + void showViolationDialogs(AppErrorResult res) { + List contexts = getDisplayContexts(false /* lastUsedOnly */); + mViolationDialogs = new ArrayList<>(); + for (int i = contexts.size() - 1; i >= 0; i--) { + final Context c = contexts.get(i); + mViolationDialogs.add( + new StrictModeViolationDialog(c, mService, res, mApp)); + } + mService.mUiHandler.post(() -> { + List dialogs; + synchronized (mProcLock) { + dialogs = mViolationDialogs; + } + if (dialogs != null) { + forAllDialogs(dialogs, Dialog::show); + } + }); + } + + @GuardedBy("mProcLock") + void showDebugWaitingDialogs() { + List contexts = getDisplayContexts(true /* lastUsedOnly */); + final Context c = contexts.get(0); + mWaitDialog = new AppWaitingForDebuggerDialog(mService, c, mApp); + + mService.mUiHandler.post(() -> { + Dialog dialog; + synchronized (mProcLock) { + dialog = mWaitDialog; + } + if (dialog != null) { + dialog.show(); + } + }); + } + + /** + * Helper function to collect contexts from crashed app located displays. + * + * @param lastUsedOnly Sets to {@code true} to indicate to only get last used context. + * Sets to {@code false} to collect contexts from crashed app located + * displays. + * + * @return display context list. + */ + private List getDisplayContexts(boolean lastUsedOnly) { + List displayContexts = new ArrayList<>(); + if (!lastUsedOnly) { + mApp.getWindowProcessController().getDisplayContextsWithErrorDialogs(displayContexts); + } + // If there is no foreground window display, fallback to last used display. + if (displayContexts.isEmpty() || lastUsedOnly) { + displayContexts.add(mService.mWmInternal != null + ? mService.mWmInternal.getTopFocusedDisplayUiContext() + : mService.mUiContext); + } + return displayContexts; + } + + ErrorDialogController(ProcessRecord app) { + mApp = app; + mService = app.mService; + mProcLock = mService.mProcLock; + } +} diff --git a/services/core/java/com/android/server/am/NativeCrashListener.java b/services/core/java/com/android/server/am/NativeCrashListener.java index 6e42aee3ba2aa..94eb07611037b 100644 --- a/services/core/java/com/android/server/am/NativeCrashListener.java +++ b/services/core/java/com/android/server/am/NativeCrashListener.java @@ -16,6 +16,12 @@ package com.android.server.am; +import static android.system.OsConstants.AF_UNIX; +import static android.system.OsConstants.SOCK_STREAM; +import static android.system.OsConstants.SOL_SOCKET; +import static android.system.OsConstants.SO_RCVTIMEO; +import static android.system.OsConstants.SO_SNDTIMEO; + import android.app.ApplicationErrorReport.CrashInfo; import android.system.ErrnoException; import android.system.Os; @@ -23,8 +29,6 @@ import android.system.StructTimeval; import android.system.UnixSocketAddress; import android.util.Slog; -import static android.system.OsConstants.*; - import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileDescriptor; @@ -259,8 +263,10 @@ final class NativeCrashListener extends Thread { // even though the process will vanish as soon as we let // debuggerd proceed. synchronized (mAm) { - pr.setCrashing(true); - pr.forceCrashReport = true; + synchronized (mAm.mProcLock) { + pr.mErrorState.setCrashing(true); + pr.mErrorState.setForceCrashReport(true); + } } // Crash reporting is synchronous but we want to let debuggerd diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java index c075336ecc1ec..d79fb8a265e88 100644 --- a/services/core/java/com/android/server/am/OomAdjuster.java +++ b/services/core/java/com/android/server/am/OomAdjuster.java @@ -100,6 +100,7 @@ import android.util.Pair; import android.util.Slog; import android.util.proto.ProtoOutputStream; +import com.android.internal.annotations.CompositeRWLock; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.compat.IPlatformCompat; @@ -206,11 +207,12 @@ public final class OomAdjuster { int mNumCachedHiddenProcs = 0; /** Track all uids that have actively running processes. */ + @CompositeRWLock({"mService", "mProcLock"}) ActiveUids mActiveUids; /** * The handler to execute {@link #setProcessGroup} (it may be heavy if the process has many - * threads) for reducing the time spent in {@link #applyOomAdjLocked}. + * threads) for reducing the time spent in {@link #applyOomAdjLSP}. */ private final Handler mProcessGroupHandler; @@ -218,6 +220,7 @@ public final class OomAdjuster { private final ActivityManagerService mService; private final ProcessList mProcessList; + private final ActivityManagerGlobalLock mProcLock; private final int mNumSlots; private final ArrayList mTmpProcessList = new ArrayList(); @@ -333,6 +336,7 @@ public final class OomAdjuster { ServiceThread adjusterThread) { mService = service; mProcessList = processList; + mProcLock = service.mProcLock; mActiveUids = activeUids; mLocalPowerManager = LocalServices.getService(PowerManagerInternal.class); @@ -389,24 +393,28 @@ public final class OomAdjuster { @VisibleForTesting @GuardedBy("mService") void handleUserSwitchedLocked() { + mProcessList.forEachLruProcessesLOSP(false, + this::updateKeepWarmIfNecessaryForProcessLocked); + } + + @GuardedBy("mService") + private void updateKeepWarmIfNecessaryForProcessLocked(final ProcessRecord app) { final ArraySet warmServices = mService.mConstants.KEEP_WARMING_SERVICES; - final ArrayList processes = mProcessList.mLruProcesses; - for (int i = processes.size() - 1; i >= 0; i--) { - final ProcessRecord app = processes.get(i); - boolean includeWarmPkg = false; - for (int j = warmServices.size() - 1; j >= 0; j--) { - if (app.getPkgList().containsKey(warmServices.valueAt(j).getPackageName())) { - includeWarmPkg = true; - break; - } - } - if (!includeWarmPkg) { - continue; - } - for (int j = app.numberOfRunningServices() - 1; j >= 0; j--) { - app.getRunningServiceAt(j).updateKeepWarmLocked(); + boolean includeWarmPkg = false; + final PackageList pkgList = app.getPkgList(); + for (int j = warmServices.size() - 1; j >= 0; j--) { + if (pkgList.containsKey(warmServices.valueAt(j).getPackageName())) { + includeWarmPkg = true; + break; } } + if (!includeWarmPkg) { + return; + } + final ProcessServiceRecord psr = app.mServices; + for (int j = psr.numberOfRunningServices() - 1; j >= 0; j--) { + psr.getRunningServiceAt(j).updateKeepWarmLocked(); + } } /** @@ -420,11 +428,20 @@ public final class OomAdjuster { @GuardedBy("mService") boolean updateOomAdjLocked(ProcessRecord app, boolean oomAdjAll, String oomAdjReason) { + synchronized (mProcLock) { + return updateOomAdjLSP(app, oomAdjAll, oomAdjReason); + } + } + + @GuardedBy({"mService", "mProcLock"}) + private boolean updateOomAdjLSP(ProcessRecord app, boolean oomAdjAll, + String oomAdjReason) { if (oomAdjAll && mConstants.OOMADJ_UPDATE_QUICK) { - return updateOomAdjLocked(app, oomAdjReason); + return updateOomAdjLSP(app, oomAdjReason); } final ProcessRecord topApp = mService.getTopApp(); - final boolean wasCached = app.isCached(); + final ProcessStateRecord state = app.mState; + final boolean wasCached = state.isCached(); mAdjSeq++; @@ -432,30 +449,31 @@ public final class OomAdjuster { // If our app is currently cached, we know it, and that is it. Otherwise, // we don't know it yet, and it needs to now be cached we will then // need to do a complete oom adj. - final int cachedAdj = app.getCurRawAdj() >= ProcessList.CACHED_APP_MIN_ADJ - ? app.getCurRawAdj() : ProcessList.UNKNOWN_ADJ; + final int cachedAdj = state.getCurRawAdj() >= ProcessList.CACHED_APP_MIN_ADJ + ? state.getCurRawAdj() : ProcessList.UNKNOWN_ADJ; // Check if this process is in the pending list too, remove from pending list if so. mPendingProcessSet.remove(app); - boolean success = updateOomAdjLocked(app, cachedAdj, topApp, false, + boolean success = updateOomAdjLSP(app, cachedAdj, topApp, false, SystemClock.uptimeMillis()); if (oomAdjAll - && (wasCached != app.isCached() || app.getCurRawAdj() == ProcessList.UNKNOWN_ADJ)) { + && (wasCached != state.isCached() + || state.getCurRawAdj() == ProcessList.UNKNOWN_ADJ)) { // Changed to/from cached state, so apps after it in the LRU // list may also be changed. - updateOomAdjLocked(oomAdjReason); + updateOomAdjLSP(oomAdjReason); } return success; } - @GuardedBy("mService") - private final boolean updateOomAdjLocked(ProcessRecord app, int cachedAdj, + @GuardedBy({"mService", "mProcLock"}) + private boolean updateOomAdjLSP(ProcessRecord app, int cachedAdj, ProcessRecord TOP_APP, boolean doingAll, long now) { - if (app.thread == null) { + if (app.getThread() == null) { return false; } - app.resetCachedInfo(); - UidRecord uidRec = app.uidRecord; + app.mState.resetCachedInfo(); + UidRecord uidRec = app.getUidRecord(); if (uidRec != null) { if (DEBUG_UID_OBSERVERS) { Slog.i(TAG_UID_OBSERVERS, "Starting update of " + uidRec); @@ -466,35 +484,23 @@ public final class OomAdjuster { // Check if this process is in the pending list too, remove from pending list if so. mPendingProcessSet.remove(app); - computeOomAdjLocked(app, cachedAdj, TOP_APP, doingAll, now, false, true); + computeOomAdjLSP(app, cachedAdj, TOP_APP, doingAll, now, false, true); - boolean success = applyOomAdjLocked(app, doingAll, now, SystemClock.elapsedRealtime()); + boolean success = applyOomAdjLSP(app, doingAll, now, SystemClock.elapsedRealtime()); if (uidRec != null) { - // After uidRec.reset() above, for UidRecord that has multiple processes (ProcessRecord) - // , We need to apply all ProcessRecord into UidRecord. - final ArraySet procRecords = app.uidRecord.procRecords; - for (int i = procRecords.size() - 1; i >= 0; i--) { - final ProcessRecord pr = procRecords.valueAt(i); - if (!pr.killedByAm && pr.thread != null) { - if (pr.isolated && pr.numberOfRunningServices() <= 0 - && pr.isolatedEntryPoint == null) { - // No op. - } else { - // Keeping this process, update its uid. - updateAppUidRecLocked(pr); - } - } - } + // After uidRec.reset() above, for UidRecord with multiple processes (ProcessRecord), + // we need to apply all ProcessRecord into UidRecord. + uidRec.forEachProcess(this::updateAppUidRecIfNecessaryLSP); if (uidRec.getCurProcState() != PROCESS_STATE_NONEXISTENT - && (uidRec.setProcState != uidRec.getCurProcState() - || uidRec.setCapability != uidRec.curCapability - || uidRec.mSetAllowlist != uidRec.mCurAllowlist)) { + && (uidRec.getSetProcState() != uidRec.getCurProcState() + || uidRec.getSetCapability() != uidRec.getCurCapability() + || uidRec.isSetAllowListed() != uidRec.isCurAllowListed())) { ActiveUids uids = mTmpUidRecords; uids.clear(); - uids.put(uidRec.uid, uidRec); - updateUidsLocked(uids, SystemClock.elapsedRealtime()); - mProcessList.incrementProcStateSeqAndNotifyAppsLocked(uids); + uids.put(uidRec.getUid(), uidRec); + updateUidsLSP(uids, SystemClock.elapsedRealtime()); + mProcessList.incrementProcStateSeqAndNotifyAppsLOSP(uids); } } @@ -506,11 +512,18 @@ public final class OomAdjuster { */ @GuardedBy("mService") void updateOomAdjLocked(String oomAdjReason) { + synchronized (mProcLock) { + updateOomAdjLSP(oomAdjReason); + } + } + + @GuardedBy({"mService", "mProcLock"}) + private void updateOomAdjLSP(String oomAdjReason) { final ProcessRecord topApp = mService.getTopApp(); // Clear any pending ones because we are doing a full update now. mPendingProcessSet.clear(); mService.mAppProfiler.mHasPreviousProcess = mService.mAppProfiler.mHasHomeProcess = false; - updateOomAdjLockedInner(oomAdjReason, topApp , null, null, true, true); + updateOomAdjInnerLSP(oomAdjReason, topApp , null, null, true, true); } /** @@ -523,8 +536,15 @@ public final class OomAdjuster { */ @GuardedBy("mService") boolean updateOomAdjLocked(ProcessRecord app, String oomAdjReason) { + synchronized (mProcLock) { + return updateOomAdjLSP(app, oomAdjReason); + } + } + + @GuardedBy({"mService", "mProcLock"}) + private boolean updateOomAdjLSP(ProcessRecord app, String oomAdjReason) { if (app == null || !mConstants.OOMADJ_UPDATE_QUICK) { - updateOomAdjLocked(oomAdjReason); + updateOomAdjLSP(oomAdjReason); return true; } @@ -535,20 +555,23 @@ public final class OomAdjuster { mAdjSeq++; // Firstly, try to see if the importance of itself gets changed - final boolean wasCached = app.isCached(); - final int oldAdj = app.getCurRawAdj(); + final ProcessStateRecord state = app.mState; + final boolean wasCached = state.isCached(); + final int oldAdj = state.getCurRawAdj(); final int cachedAdj = oldAdj >= ProcessList.CACHED_APP_MIN_ADJ ? oldAdj : ProcessList.UNKNOWN_ADJ; - final boolean wasBackground = ActivityManager.isProcStateBackground(app.setProcState); - app.containsCycle = false; - app.procStateChanged = false; - app.resetCachedInfo(); + final boolean wasBackground = ActivityManager.isProcStateBackground( + state.getSetProcState()); + state.setContainsCycle(false); + state.setProcStateChanged(false); + state.resetCachedInfo(); // Check if this process is in the pending list too, remove from pending list if so. mPendingProcessSet.remove(app); - boolean success = updateOomAdjLocked(app, cachedAdj, topApp, false, + boolean success = updateOomAdjLSP(app, cachedAdj, topApp, false, SystemClock.uptimeMillis()); - if (!success || (wasCached == app.isCached() && oldAdj != ProcessList.INVALID_ADJ - && wasBackground == ActivityManager.isProcStateBackground(app.setProcState))) { + if (!success || (wasCached == state.isCached() && oldAdj != ProcessList.INVALID_ADJ + && wasBackground == ActivityManager.isProcStateBackground( + state.getSetProcState()))) { // Okay, it's unchanged, it won't impact any service it binds to, we're done here. if (DEBUG_OOM_ADJ) { Slog.i(TAG_OOM_ADJ, "No oomadj changes for " + app); @@ -570,23 +593,25 @@ public final class OomAdjuster { // Track if any of them reachables could include a cycle boolean containsCycle = false; // Scan downstreams of the process record - app.mReachable = true; + state.setReachable(true); for (ProcessRecord pr = app; pr != null; pr = queue.poll()) { if (pr != app) { processes.add(pr); } - if (pr.uidRecord != null) { - uids.put(pr.uidRecord.uid, pr.uidRecord); + final UidRecord uidRec = pr.getUidRecord(); + if (uidRec != null) { + uids.put(uidRec.getUid(), uidRec); } - for (int i = pr.connections.size() - 1; i >= 0; i--) { - ConnectionRecord cr = pr.connections.valueAt(i); + final ProcessServiceRecord psr = pr.mServices; + for (int i = psr.numberOfConnections() - 1; i >= 0; i--) { + ConnectionRecord cr = psr.getConnectionAt(i); ProcessRecord service = (cr.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) != 0 ? cr.binding.service.isolatedProc : cr.binding.service.app; if (service == null || service == pr) { continue; } - containsCycle |= service.mReachable; - if (service.mReachable) { + containsCycle |= service.mState.isReachable(); + if (service.mState.isReachable()) { continue; } if ((cr.flags & (Context.BIND_WAIVE_PRIORITY @@ -596,24 +621,26 @@ public final class OomAdjuster { continue; } queue.offer(service); - service.mReachable = true; + service.mState.setReachable(true); // During scanning the reachable dependants, remove them from the pending oomadj // targets list if it's possible, as they've been added into the immediate // oomadj targets list 'processes' above. mPendingProcessSet.remove(service); } - for (int i = pr.conProviders.size() - 1; i >= 0; i--) { - ContentProviderConnection cpc = pr.conProviders.get(i); + final ProcessProviderRecord ppr = pr.mProviders; + for (int i = ppr.numberOfProviderConnections() - 1; i >= 0; i--) { + ContentProviderConnection cpc = ppr.getProviderConnectionAt(i); ProcessRecord provider = cpc.provider.proc; - if (provider == null || provider == pr || (containsCycle |= provider.mReachable)) { + if (provider == null || provider == pr + || (containsCycle |= provider.mState.isReachable())) { continue; } - containsCycle |= provider.mReachable; - if (provider.mReachable) { + containsCycle |= provider.mState.isReachable(); + if (provider.mState.isReachable()) { continue; } queue.offer(provider); - provider.mReachable = true; + provider.mState.setReachable(true); // During scanning the reachable dependants, remove them from the pending oomadj // targets list if it's possible, as they've been added into the immediate // oomadj targets list 'processes' above. @@ -622,10 +649,10 @@ public final class OomAdjuster { } // Reset the flag - app.mReachable = false; + state.setReachable(false); int size = processes.size(); if (size > 0) { - // Reverse the process list, since the updateOomAdjLockedInner scans from the end of it. + // Reverse the process list, since the updateOomAdjInnerLSP scans from the end of it. for (int l = 0, r = size - 1; l < r; l++, r--) { ProcessRecord t = processes.get(l); processes.set(l, processes.get(r)); @@ -633,13 +660,13 @@ public final class OomAdjuster { } mAdjSeq--; // Update these reachable processes - updateOomAdjLockedInner(oomAdjReason, topApp, processes, uids, containsCycle, false); - } else if (app.getCurRawAdj() == ProcessList.UNKNOWN_ADJ) { + updateOomAdjInnerLSP(oomAdjReason, topApp, processes, uids, containsCycle, false); + } else if (state.getCurRawAdj() == ProcessList.UNKNOWN_ADJ) { // In case the app goes from non-cached to cached but it doesn't have other reachable // processes, its adj could be still unknown as of now, assign one. processes.add(app); assignCachedAdjIfNecessary(processes); - applyOomAdjLocked(app, false, SystemClock.uptimeMillis(), + applyOomAdjLSP(app, false, SystemClock.uptimeMillis(), SystemClock.elapsedRealtime()); } mTmpProcessList.clear(); @@ -684,17 +711,20 @@ public final class OomAdjuster { final ArrayList processes = mTmpProcessList; final ActiveUids uids = mTmpUidRecords; - uids.clear(); - processes.clear(); - for (int i = mPendingProcessSet.size() - 1; i >= 0; i--) { - final ProcessRecord app = mPendingProcessSet.valueAt(i); - if (app.uidRecord != null) { - uids.put(app.uidRecord.uid, app.uidRecord); + synchronized (mProcLock) { + uids.clear(); + processes.clear(); + for (int i = mPendingProcessSet.size() - 1; i >= 0; i--) { + final ProcessRecord app = mPendingProcessSet.valueAt(i); + final UidRecord uidRec = app.getUidRecord(); + if (uidRec != null) { + uids.put(uidRec.getUid(), uidRec); + } + processes.add(app); } - processes.add(app); - } - updateOomAdjLockedInner(oomAdjReason, topApp, processes, uids, true, false); + updateOomAdjInnerLSP(oomAdjReason, topApp, processes, uids, true, false); + } processes.clear(); mPendingProcessSet.clear(); @@ -707,8 +737,8 @@ public final class OomAdjuster { * list if the given list is null; when it's partial update, each process's client proc won't * get evaluated recursively here. */ - @GuardedBy("mService") - private void updateOomAdjLockedInner(String oomAdjReason, final ProcessRecord topApp, + @GuardedBy({"mService", "mProcLock"}) + private void updateOomAdjInnerLSP(String oomAdjReason, final ProcessRecord topApp, ArrayList processes, ActiveUids uids, boolean potentialCycles, boolean startProfiling) { if (startProfiling) { @@ -720,7 +750,7 @@ public final class OomAdjuster { final long oldTime = now - ProcessList.MAX_EMPTY_TIME; final boolean fullUpdate = processes == null; ActiveUids activeUids = uids; - ArrayList activeProcesses = fullUpdate ? mProcessList.mLruProcesses + ArrayList activeProcesses = fullUpdate ? mProcessList.getLruProcessesLOSP() : processes; final int numProc = activeProcesses.size(); @@ -729,8 +759,8 @@ public final class OomAdjuster { activeUids = mTmpUidRecords; activeUids.clear(); for (int i = 0; i < numUids; i++) { - UidRecord r = mActiveUids.valueAt(i); - activeUids.put(r.uid, r); + UidRecord uidRec = mActiveUids.valueAt(i); + activeUids.put(uidRec.getUid(), uidRec); } } @@ -752,36 +782,39 @@ public final class OomAdjuster { boolean retryCycles = false; boolean computeClients = fullUpdate || potentialCycles; - // need to reset cycle state before calling computeOomAdjLocked because of service conns + // need to reset cycle state before calling computeOomAdjLSP because of service conns for (int i = numProc - 1; i >= 0; i--) { ProcessRecord app = activeProcesses.get(i); - app.mReachable = false; + final ProcessStateRecord state = app.mState; + state.setReachable(false); // No need to compute again it has been evaluated in previous iteration - if (app.adjSeq != mAdjSeq) { - app.containsCycle = false; - app.setCurRawProcState(PROCESS_STATE_CACHED_EMPTY); - app.setCurRawAdj(ProcessList.UNKNOWN_ADJ); - app.setCapability = PROCESS_CAPABILITY_NONE; - app.resetCachedInfo(); + if (state.getAdjSeq() != mAdjSeq) { + state.setContainsCycle(false); + state.setCurRawProcState(PROCESS_STATE_CACHED_EMPTY); + state.setCurRawAdj(ProcessList.UNKNOWN_ADJ); + state.setSetCapability(PROCESS_CAPABILITY_NONE); + state.resetCachedInfo(); } } for (int i = numProc - 1; i >= 0; i--) { ProcessRecord app = activeProcesses.get(i); - if (!app.killedByAm && app.thread != null) { - app.procStateChanged = false; - computeOomAdjLocked(app, ProcessList.UNKNOWN_ADJ, topApp, fullUpdate, now, false, + final ProcessStateRecord state = app.mState; + if (!app.isKilledByAm() && app.getThread() != null) { + state.setProcStateChanged(false); + computeOomAdjLSP(app, ProcessList.UNKNOWN_ADJ, topApp, fullUpdate, now, false, computeClients); // It won't enter cycle if not computing clients. // if any app encountered a cycle, we need to perform an additional loop later - retryCycles |= app.containsCycle; + retryCycles |= state.containsCycle(); // Keep the completedAdjSeq to up to date. - app.completedAdjSeq = mAdjSeq; + state.setCompletedAdjSeq(mAdjSeq); } } if (mCacheOomRanker.useOomReranking()) { - mCacheOomRanker.reRankLruCachedApps(mProcessList); + mCacheOomRanker.reRankLruCachedAppsLSP(mProcessList.getLruProcessesLSP(), + mProcessList.getLruProcessServiceStartLOSP()); } - assignCachedAdjIfNecessary(mProcessList.mLruProcesses); + assignCachedAdjIfNecessary(mProcessList.getLruProcessesLOSP()); if (computeClients) { // There won't be cycles if we didn't compute clients above. // Cycle strategy: @@ -795,16 +828,18 @@ public final class OomAdjuster { for (int i = 0; i < numProc; i++) { ProcessRecord app = activeProcesses.get(i); - if (!app.killedByAm && app.thread != null && app.containsCycle) { - app.adjSeq--; - app.completedAdjSeq--; + final ProcessStateRecord state = app.mState; + if (!app.isKilledByAm() && app.getThread() != null && state.containsCycle()) { + state.decAdjSeq(); + state.decCompletedAdjSeq(); } } for (int i = 0; i < numProc; i++) { ProcessRecord app = activeProcesses.get(i); - if (!app.killedByAm && app.thread != null && app.containsCycle) { - if (computeOomAdjLocked(app, app.getCurRawAdj(), topApp, true, now, + final ProcessStateRecord state = app.mState; + if (!app.isKilledByAm() && app.getThread() != null && state.containsCycle()) { + if (computeOomAdjLSP(app, state.getCurRawAdj(), topApp, true, now, true, true)) { retryCycles = true; } @@ -816,7 +851,7 @@ public final class OomAdjuster { mNumNonCachedProcs = 0; mNumCachedHiddenProcs = 0; - boolean allChanged = updateAndTrimProcessLocked(now, nowElapsed, oldTime, activeUids); + boolean allChanged = updateAndTrimProcessLSP(now, nowElapsed, oldTime, activeUids); mNumServiceProcs = mNewNumServiceProcs; if (mService.mAlwaysFinishActivities) { @@ -826,11 +861,11 @@ public final class OomAdjuster { } if (allChanged) { - mService.mAppProfiler.requestPssAllProcsLocked(now, false, + mService.mAppProfiler.requestPssAllProcsLPr(now, false, mService.mProcessStats.isMemFactorLowered()); } - updateUidsLocked(activeUids, nowElapsed); + updateUidsLSP(activeUids, nowElapsed); synchronized (mService.mProcessStats.mLock) { if (mService.mProcessStats.shouldWriteNowLocked(now)) { @@ -857,6 +892,7 @@ public final class OomAdjuster { } } + @GuardedBy({"mService", "mProcLock"}) private void assignCachedAdjIfNecessary(ArrayList lruList) { final int numLru = lruList.size(); @@ -900,23 +936,27 @@ public final class OomAdjuster { for (int i = numLru - 1; i >= 0; i--) { ProcessRecord app = lruList.get(i); + final ProcessStateRecord state = app.mState; // If we haven't yet assigned the final cached adj // to the process, do that now. - if (!app.killedByAm && app.thread != null && app.curAdj + if (!app.isKilledByAm() && app.getThread() != null && state.getCurAdj() >= ProcessList.UNKNOWN_ADJ) { - switch (app.getCurProcState()) { + final ProcessServiceRecord psr = app.mServices; + switch (state.getCurProcState()) { case PROCESS_STATE_CACHED_ACTIVITY: case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT: case ActivityManager.PROCESS_STATE_CACHED_RECENT: // Figure out the next cached level, taking into account groups. boolean inGroup = false; - if (app.connectionGroup != 0) { + final int connectionGroup = psr.getConnectionGroup(); + if (connectionGroup != 0) { + final int connectionImportance = psr.getConnectionImportance(); if (lastCachedGroupUid == app.uid - && lastCachedGroup == app.connectionGroup) { + && lastCachedGroup == connectionGroup) { // This is in the same group as the last process, just tweak // adjustment by importance. - if (app.connectionImportance > lastCachedGroupImportance) { - lastCachedGroupImportance = app.connectionImportance; + if (connectionImportance > lastCachedGroupImportance) { + lastCachedGroupImportance = connectionImportance; if (curCachedAdj < nextCachedAdj && curCachedAdj < ProcessList.CACHED_APP_MAX_ADJ) { curCachedImpAdj++; @@ -925,8 +965,8 @@ public final class OomAdjuster { inGroup = true; } else { lastCachedGroupUid = app.uid; - lastCachedGroup = app.connectionGroup; - lastCachedGroupImportance = app.connectionImportance; + lastCachedGroup = connectionGroup; + lastCachedGroupImportance = connectionImportance; } } if (!inGroup && curCachedAdj != nextCachedAdj) { @@ -944,11 +984,12 @@ public final class OomAdjuster { // This process is a cached process holding activities... // assign it the next cached value for that type, and then // step that cached level. - app.setCurRawAdj(curCachedAdj + curCachedImpAdj); - app.curAdj = app.modifyRawOomAdj(curCachedAdj + curCachedImpAdj); + state.setCurRawAdj(curCachedAdj + curCachedImpAdj); + state.setCurAdj(psr.modifyRawOomAdj(curCachedAdj + curCachedImpAdj)); if (DEBUG_LRU) { Slog.d(TAG_LRU, "Assigning activity LRU #" + i - + " adj: " + app.curAdj + " (curCachedAdj=" + curCachedAdj + + " adj: " + state.getCurAdj() + + " (curCachedAdj=" + curCachedAdj + " curCachedImpAdj=" + curCachedImpAdj + ")"); } break; @@ -970,11 +1011,11 @@ public final class OomAdjuster { // long-running services that have dropped down to the // cached level will be treated as empty (since their process // state is still as a service), which is what we want. - app.setCurRawAdj(curEmptyAdj); - app.curAdj = app.modifyRawOomAdj(curEmptyAdj); + state.setCurRawAdj(curEmptyAdj); + state.setCurAdj(psr.modifyRawOomAdj(curEmptyAdj)); if (DEBUG_LRU) { Slog.d(TAG_LRU, "Assigning empty LRU #" + i - + " adj: " + app.curAdj + " (curEmptyAdj=" + curEmptyAdj + + " adj: " + state.getCurAdj() + " (curEmptyAdj=" + curEmptyAdj + ")"); } break; @@ -983,9 +1024,10 @@ public final class OomAdjuster { } } - private boolean updateAndTrimProcessLocked(final long now, final long nowElapsed, + @GuardedBy({"mService", "mProcLock"}) + private boolean updateAndTrimProcessLSP(final long now, final long nowElapsed, final long oldTime, final ActiveUids activeUids) { - ArrayList lruList = mProcessList.mLruProcesses; + ArrayList lruList = mProcessList.getLruProcessesLOSP(); final int numLru = lruList.size(); final int emptyProcessLimit = mConstants.CUR_MAX_EMPTY_PROCESSES; @@ -1000,34 +1042,37 @@ public final class OomAdjuster { for (int i = numLru - 1; i >= 0; i--) { ProcessRecord app = lruList.get(i); - if (!app.killedByAm && app.thread != null) { + final ProcessStateRecord state = app.mState; + if (!app.isKilledByAm() && app.getThread() != null) { // We don't need to apply the update for the process which didn't get computed - if (app.completedAdjSeq == mAdjSeq) { - applyOomAdjLocked(app, true, now, nowElapsed); + if (state.getCompletedAdjSeq() == mAdjSeq) { + applyOomAdjLSP(app, true, now, nowElapsed); } + final ProcessServiceRecord psr = app.mServices; // Count the number of process types. - switch (app.getCurProcState()) { + switch (state.getCurProcState()) { case PROCESS_STATE_CACHED_ACTIVITY: case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT: mNumCachedHiddenProcs++; numCached++; - if (app.connectionGroup != 0) { + final int connectionGroup = psr.getConnectionGroup(); + if (connectionGroup != 0) { if (lastCachedGroupUid == app.info.uid - && lastCachedGroup == app.connectionGroup) { + && lastCachedGroup == connectionGroup) { // If this process is the next in the same group, we don't // want it to count against our limit of the number of cached // processes, so bump up the group count to account for it. numCachedExtraGroup++; } else { lastCachedGroupUid = app.info.uid; - lastCachedGroup = app.connectionGroup; + lastCachedGroup = connectionGroup; } } else { lastCachedGroupUid = lastCachedGroup = 0; } if ((numCached - numCachedExtraGroup) > cachedProcessLimit) { - app.kill("cached #" + numCached, + app.killLocked("cached #" + numCached, ApplicationExitInfo.REASON_OTHER, ApplicationExitInfo.SUBREASON_TOO_MANY_CACHED, true); @@ -1035,17 +1080,16 @@ public final class OomAdjuster { break; case PROCESS_STATE_CACHED_EMPTY: if (numEmpty > mConstants.CUR_TRIM_EMPTY_PROCESSES - && app.lastActivityTime < oldTime) { - app.kill("empty for " - + ((oldTime + ProcessList.MAX_EMPTY_TIME - app.lastActivityTime) - / 1000) + "s", + && app.getLastActivityTime() < oldTime) { + app.killLocked("empty for " + ((oldTime + ProcessList.MAX_EMPTY_TIME + - app.getLastActivityTime()) / 1000) + "s", ApplicationExitInfo.REASON_OTHER, ApplicationExitInfo.SUBREASON_TRIM_EMPTY, true); } else { numEmpty++; if (numEmpty > emptyProcessLimit) { - app.kill("empty #" + numEmpty, + app.killLocked("empty #" + numEmpty, ApplicationExitInfo.REASON_OTHER, ApplicationExitInfo.SUBREASON_TOO_MANY_EMPTY, true); @@ -1057,8 +1101,8 @@ public final class OomAdjuster { break; } - if (app.isolated && app.numberOfRunningServices() <= 0 - && app.isolatedEntryPoint == null) { + if (app.isolated && psr.numberOfRunningServices() <= 0 + && app.getIsolatedEntryPoint() == null) { // If this is an isolated process, there are no services // running in it, and it's not a special process with a // custom entry point, then the process is no longer @@ -1066,40 +1110,56 @@ public final class OomAdjuster { // definition not re-use the same process again, and it is // good to avoid having whatever code was running in them // left sitting around after no longer needed. - app.kill("isolated not needed", ApplicationExitInfo.REASON_OTHER, + app.killLocked("isolated not needed", ApplicationExitInfo.REASON_OTHER, ApplicationExitInfo.SUBREASON_ISOLATED_NOT_NEEDED, true); } else { // Keeping this process, update its uid. - updateAppUidRecLocked(app); + updateAppUidRecLSP(app); } - if (app.getCurProcState() >= ActivityManager.PROCESS_STATE_HOME - && !app.killedByAm) { + if (state.getCurProcState() >= ActivityManager.PROCESS_STATE_HOME + && !app.isKilledByAm()) { numTrimming++; } } } - mProcessList.incrementProcStateSeqAndNotifyAppsLocked(activeUids); + mProcessList.incrementProcStateSeqAndNotifyAppsLOSP(activeUids); - return mService.mAppProfiler.updateLowMemStateLocked(numCached, numEmpty, numTrimming); + return mService.mAppProfiler.updateLowMemStateLSP(numCached, numEmpty, numTrimming); } - private void updateAppUidRecLocked(ProcessRecord app) { - final UidRecord uidRec = app.uidRecord; - if (uidRec != null) { - uidRec.ephemeral = app.info.isInstantApp(); - if (uidRec.getCurProcState() > app.getCurProcState()) { - uidRec.setCurProcState(app.getCurProcState()); + @GuardedBy({"mService", "mProcLock"}) + private void updateAppUidRecIfNecessaryLSP(final ProcessRecord app) { + if (!app.isKilledByAm() && app.getThread() != null) { + if (app.isolated && app.mServices.numberOfRunningServices() <= 0 + && app.getIsolatedEntryPoint() == null) { + // No op. + } else { + // Keeping this process, update its uid. + updateAppUidRecLSP(app); } - if (app.hasForegroundServices()) { - uidRec.foregroundServices = true; - } - uidRec.curCapability |= app.curCapability; } } - private void updateUidsLocked(ActiveUids activeUids, final long nowElapsed) { + @GuardedBy({"mService", "mProcLock"}) + private void updateAppUidRecLSP(ProcessRecord app) { + final UidRecord uidRec = app.getUidRecord(); + if (uidRec != null) { + final ProcessStateRecord state = app.mState; + uidRec.setEphemeral(app.info.isInstantApp()); + if (uidRec.getCurProcState() > state.getCurProcState()) { + uidRec.setCurProcState(state.getCurProcState()); + } + if (app.mServices.hasForegroundServices()) { + uidRec.setForegroundServices(true); + } + uidRec.setCurCapability(uidRec.getCurCapability() | state.getCurCapability()); + } + } + + @GuardedBy({"mService", "mProcLock"}) + private void updateUidsLSP(ActiveUids activeUids, final long nowElapsed) { ArrayList becameIdle = mTmpBecameIdle; becameIdle.clear(); @@ -1111,22 +1171,22 @@ public final class OomAdjuster { final UidRecord uidRec = activeUids.valueAt(i); int uidChange = UidRecord.CHANGE_PROCSTATE; if (uidRec.getCurProcState() != PROCESS_STATE_NONEXISTENT - && (uidRec.setProcState != uidRec.getCurProcState() - || uidRec.setCapability != uidRec.curCapability - || uidRec.mSetAllowlist != uidRec.mCurAllowlist)) { + && (uidRec.getSetProcState() != uidRec.getCurProcState() + || uidRec.getSetCapability() != uidRec.getCurCapability() + || uidRec.isSetAllowListed() != uidRec.isCurAllowListed())) { if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, "Changes in " + uidRec - + ": proc state from " + uidRec.setProcState + " to " + + ": proc state from " + uidRec.getSetProcState() + " to " + uidRec.getCurProcState() + ", capability from " - + uidRec.setCapability + " to " + uidRec.curCapability - + ", allowlist from " + uidRec.mSetAllowlist - + " to " + uidRec.mCurAllowlist); + + uidRec.getSetCapability() + " to " + uidRec.getCurCapability() + + ", allowlist from " + uidRec.isSetAllowListed() + + " to " + uidRec.isCurAllowListed()); if (ActivityManager.isProcStateBackground(uidRec.getCurProcState()) - && !uidRec.mCurAllowlist) { + && !uidRec.isCurAllowListed()) { // UID is now in the background (and not on the temp allowlist). Was it // previously in the foreground (or on the temp allowlist)? - if (!ActivityManager.isProcStateBackground(uidRec.setProcState) - || uidRec.mSetAllowlist) { - uidRec.lastBackgroundTime = nowElapsed; + if (!ActivityManager.isProcStateBackground(uidRec.getSetProcState()) + || uidRec.isSetAllowListed()) { + uidRec.setLastBackgroundTime(nowElapsed); if (!mService.mHandler.hasMessages(IDLE_UIDS_MSG)) { // Note: the background settle time is in elapsed realtime, while // the handler time base is uptime. All this means is that we may @@ -1136,38 +1196,40 @@ public final class OomAdjuster { mConstants.BACKGROUND_SETTLE_TIME); } } - if (uidRec.idle && !uidRec.setIdle) { + if (uidRec.isIdle() && !uidRec.isSetIdle()) { uidChange = UidRecord.CHANGE_IDLE; becameIdle.add(uidRec); } } else { - if (uidRec.idle) { + if (uidRec.isIdle()) { uidChange = UidRecord.CHANGE_ACTIVE; - EventLogTags.writeAmUidActive(uidRec.uid); - uidRec.idle = false; + EventLogTags.writeAmUidActive(uidRec.getUid()); + uidRec.setIdle(false); } - uidRec.lastBackgroundTime = 0; + uidRec.setLastBackgroundTime(0); } - final boolean wasCached = uidRec.setProcState + final boolean wasCached = uidRec.getSetProcState() > ActivityManager.PROCESS_STATE_RECEIVER; final boolean isCached = uidRec.getCurProcState() > ActivityManager.PROCESS_STATE_RECEIVER; - if (wasCached != isCached || uidRec.setProcState == PROCESS_STATE_NONEXISTENT) { + if (wasCached != isCached + || uidRec.getSetProcState() == PROCESS_STATE_NONEXISTENT) { uidChange |= isCached ? UidRecord.CHANGE_CACHED : UidRecord.CHANGE_UNCACHED; } - uidRec.setProcState = uidRec.getCurProcState(); - uidRec.setCapability = uidRec.curCapability; - uidRec.mSetAllowlist = uidRec.mCurAllowlist; - uidRec.setIdle = uidRec.idle; - mService.mAtmInternal.onUidProcStateChanged(uidRec.uid, uidRec.setProcState); + uidRec.setSetProcState(uidRec.getCurProcState()); + uidRec.setSetCapability(uidRec.getCurCapability()); + uidRec.setSetAllowListed(uidRec.isCurAllowListed()); + uidRec.setSetIdle(uidRec.isIdle()); + mService.mAtmInternal.onUidProcStateChanged( + uidRec.getUid(), uidRec.getSetProcState()); mService.enqueueUidChangeLocked(uidRec, -1, uidChange); - mService.noteUidProcessState(uidRec.uid, uidRec.getCurProcState(), - uidRec.curCapability); - if (uidRec.foregroundServices) { + mService.noteUidProcessState(uidRec.getUid(), uidRec.getCurProcState(), + uidRec.getCurCapability()); + if (uidRec.hasForegroundServices()) { mService.mServices.foregroundServiceProcStateChangedLocked(uidRec); } } - mService.mInternal.deletePendingTopUid(uidRec.uid); + mService.mInternal.deletePendingTopUid(uidRec.getUid()); } if (mLocalPowerManager != null) { mLocalPowerManager.finishUidChanges(); @@ -1178,7 +1240,7 @@ public final class OomAdjuster { // If we have any new uids that became idle this time, we need to make sure // they aren't left with running services. for (int i = size - 1; i >= 0; i--) { - mService.mServices.stopInBackgroundLocked(becameIdle.get(i).uid); + mService.mServices.stopInBackgroundLocked(becameIdle.get(i).getUid()); } } } @@ -1186,7 +1248,7 @@ public final class OomAdjuster { private final ComputeOomAdjWindowCallback mTmpComputeOomAdjWindowCallback = new ComputeOomAdjWindowCallback(); - /** These methods are called inline during computeOomAdjLocked(), on the same thread */ + /** These methods are called inline during computeOomAdjLSP(), on the same thread */ final class ComputeOomAdjWindowCallback implements WindowProcessController.ComputeOomAdjCallback { @@ -1198,6 +1260,7 @@ public final class OomAdjuster { int appUid; int logUid; int processStateCurTop; + ProcessStateRecord mState; void initialize(ProcessRecord app, int adj, boolean foregroundActivities, int procState, int schedGroup, int appUid, int logUid, int processStateCurTop) { @@ -1209,6 +1272,7 @@ public final class OomAdjuster { this.appUid = appUid; this.logUid = logUid; this.processStateCurTop = processStateCurTop; + this.mState = app.mState; } @Override @@ -1216,14 +1280,14 @@ public final class OomAdjuster { // App has a visible activity; only upgrade adjustment. if (adj > ProcessList.VISIBLE_APP_ADJ) { adj = ProcessList.VISIBLE_APP_ADJ; - app.adjType = "vis-activity"; + mState.setAdjType("vis-activity"); if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise adj to vis-activity: " + app); } } if (procState > processStateCurTop) { procState = processStateCurTop; - app.adjType = "vis-activity"; + mState.setAdjType("vis-activity"); if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise procstate to vis-activity (top): " + app); @@ -1232,8 +1296,8 @@ public final class OomAdjuster { if (schedGroup < ProcessList.SCHED_GROUP_DEFAULT) { schedGroup = ProcessList.SCHED_GROUP_DEFAULT; } - app.setCached(false); - app.empty = false; + mState.setCached(false); + mState.setEmpty(false); foregroundActivities = true; } @@ -1241,14 +1305,14 @@ public final class OomAdjuster { public void onPausedActivity() { if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) { adj = ProcessList.PERCEPTIBLE_APP_ADJ; - app.adjType = "pause-activity"; + mState.setAdjType("pause-activity"); if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise adj to pause-activity: " + app); } } if (procState > processStateCurTop) { procState = processStateCurTop; - app.adjType = "pause-activity"; + mState.setAdjType("pause-activity"); if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise procstate to pause-activity (top): " + app); @@ -1257,8 +1321,8 @@ public final class OomAdjuster { if (schedGroup < ProcessList.SCHED_GROUP_DEFAULT) { schedGroup = ProcessList.SCHED_GROUP_DEFAULT; } - app.setCached(false); - app.empty = false; + mState.setCached(false); + mState.setEmpty(false); foregroundActivities = true; } @@ -1266,7 +1330,7 @@ public final class OomAdjuster { public void onStoppingActivity(boolean finishing) { if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) { adj = ProcessList.PERCEPTIBLE_APP_ADJ; - app.adjType = "stop-activity"; + mState.setAdjType("stop-activity"); if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise adj to stop-activity: " + app); @@ -1282,15 +1346,15 @@ public final class OomAdjuster { if (!finishing) { if (procState > PROCESS_STATE_LAST_ACTIVITY) { procState = PROCESS_STATE_LAST_ACTIVITY; - app.adjType = "stop-activity"; + mState.setAdjType("stop-activity"); if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise procstate to stop-activity: " + app); } } } - app.setCached(false); - app.empty = false; + mState.setCached(false); + mState.setEmpty(false); foregroundActivities = true; } @@ -1298,7 +1362,7 @@ public final class OomAdjuster { public void onOtherActivity() { if (procState > PROCESS_STATE_CACHED_ACTIVITY) { procState = PROCESS_STATE_CACHED_ACTIVITY; - app.adjType = "cch-act"; + mState.setAdjType("cch-act"); if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise procstate to cached activity: " + app); @@ -1307,99 +1371,102 @@ public final class OomAdjuster { } } - private final boolean computeOomAdjLocked(ProcessRecord app, int cachedAdj, + @GuardedBy({"mService", "mProcLock"}) + private boolean computeOomAdjLSP(ProcessRecord app, int cachedAdj, ProcessRecord topApp, boolean doingAll, long now, boolean cycleReEval, boolean computeClients) { - if (mAdjSeq == app.adjSeq) { - if (app.adjSeq == app.completedAdjSeq) { + final ProcessStateRecord state = app.mState; + if (mAdjSeq == state.getAdjSeq()) { + if (state.getAdjSeq() == state.getCompletedAdjSeq()) { // This adjustment has already been computed successfully. return false; } else { // The process is being computed, so there is a cycle. We cannot // rely on this process's state. - app.containsCycle = true; + state.setContainsCycle(true); return false; } } - if (app.thread == null) { - app.adjSeq = mAdjSeq; - app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_BACKGROUND); - app.setCurProcState(PROCESS_STATE_CACHED_EMPTY); - app.curAdj = ProcessList.CACHED_APP_MAX_ADJ; - app.setCurRawAdj(ProcessList.CACHED_APP_MAX_ADJ); - app.completedAdjSeq = app.adjSeq; - app.curCapability = PROCESS_CAPABILITY_NONE; + if (app.getThread() == null) { + state.setAdjSeq(mAdjSeq); + state.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_BACKGROUND); + state.setCurProcState(PROCESS_STATE_CACHED_EMPTY); + state.setCurAdj(ProcessList.CACHED_APP_MAX_ADJ); + state.setCurRawAdj(ProcessList.CACHED_APP_MAX_ADJ); + state.setCompletedAdjSeq(state.getAdjSeq()); + state.setCurCapability(PROCESS_CAPABILITY_NONE); return false; } - app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN; - app.adjSource = null; - app.adjTarget = null; - app.empty = false; - app.setCached(false); - app.shouldNotFreeze = false; - - app.resetAllowStartFgs(); + state.setAdjTypeCode(ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN); + state.setAdjSource(null); + state.setAdjTarget(null); + state.setEmpty(false); + state.setCached(false); + state.setAllowStartFgsState(PROCESS_STATE_NONEXISTENT); + state.resetAllowStartFgs(); + app.mOptRecord.setShouldNotFreeze(false); final int appUid = app.info.uid; final int logUid = mService.mCurOomAdjUid; - int prevAppAdj = app.curAdj; - int prevProcState = app.getCurProcState(); - int prevCapability = app.curCapability; + int prevAppAdj = state.getCurAdj(); + int prevProcState = state.getCurProcState(); + int prevCapability = state.getCurCapability(); + final ProcessServiceRecord psr = app.mServices; - if (app.maxAdj <= ProcessList.FOREGROUND_APP_ADJ) { + if (state.getMaxAdj() <= ProcessList.FOREGROUND_APP_ADJ) { // The max adjustment doesn't allow this app to be anything // below foreground, so it is not worth doing work for it. if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making fixed: " + app); } - app.adjType = "fixed"; - app.adjSeq = mAdjSeq; - app.setCurRawAdj(app.maxAdj); - app.setHasForegroundActivities(false); - app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_DEFAULT); - app.curCapability = PROCESS_CAPABILITY_ALL; - app.setCurProcState(ActivityManager.PROCESS_STATE_PERSISTENT); + state.setAdjType("fixed"); + state.setAdjSeq(mAdjSeq); + state.setCurRawAdj(state.getMaxAdj()); + state.setHasForegroundActivities(false); + state.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_DEFAULT); + state.setCurCapability(PROCESS_CAPABILITY_ALL); + state.setCurProcState(ActivityManager.PROCESS_STATE_PERSISTENT); // System processes can do UI, and when they do we want to have // them trim their memory after the user leaves the UI. To // facilitate this, here we need to determine whether or not it // is currently showing UI. - app.systemNoUi = true; + state.setSystemNoUi(true); if (app == topApp) { - app.systemNoUi = false; - app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_TOP_APP); - app.adjType = "pers-top-activity"; - } else if (app.hasTopUi()) { + state.setSystemNoUi(false); + state.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_TOP_APP); + state.setAdjType("pers-top-activity"); + } else if (state.hasTopUi()) { // sched group/proc state adjustment is below - app.systemNoUi = false; - app.adjType = "pers-top-ui"; - } else if (app.getCachedHasVisibleActivities()) { - app.systemNoUi = false; + state.setSystemNoUi(false); + state.setAdjType("pers-top-ui"); + } else if (state.getCachedHasVisibleActivities()) { + state.setSystemNoUi(false); } - if (!app.systemNoUi) { + if (!state.isSystemNoUi()) { if (mService.mWakefulness.get() == PowerManagerInternal.WAKEFULNESS_AWAKE) { // screen on, promote UI - app.setCurProcState(ActivityManager.PROCESS_STATE_PERSISTENT_UI); - app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_TOP_APP); + state.setCurProcState(ActivityManager.PROCESS_STATE_PERSISTENT_UI); + state.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_TOP_APP); } else { // screen off, restrict UI scheduling - app.setCurProcState(PROCESS_STATE_BOUND_FOREGROUND_SERVICE); - app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_RESTRICTED); + state.setCurProcState(PROCESS_STATE_BOUND_FOREGROUND_SERVICE); + state.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_RESTRICTED); } } - app.setCurRawProcState(app.getCurProcState()); - app.curAdj = app.maxAdj; - app.completedAdjSeq = app.adjSeq; - app.bumpAllowStartFgsState(app.getCurProcState()); - app.setAllowStartFgs(); + state.setCurRawProcState(state.getCurProcState()); + state.setCurAdj(state.getMaxAdj()); + state.setCompletedAdjSeq(state.getAdjSeq()); + state.bumpAllowStartFgsState(state.getCurProcState()); + state.setAllowStartFgs(); // if curAdj is less than prevAppAdj, then this process was promoted - return app.curAdj < prevAppAdj || app.getCurProcState() < prevProcState; + return state.getCurAdj() < prevAppAdj || state.getCurProcState() < prevProcState; } - app.systemNoUi = false; + state.setSystemNoUi(false); final int PROCESS_STATE_CUR_TOP = mService.mAtmInternal.getTopProcessState(); @@ -1416,17 +1483,17 @@ public final class OomAdjuster { // The last app on the list is the foreground app. adj = ProcessList.FOREGROUND_APP_ADJ; schedGroup = ProcessList.SCHED_GROUP_TOP_APP; - app.adjType = "top-activity"; + state.setAdjType("top-activity"); foregroundActivities = true; procState = PROCESS_STATE_CUR_TOP; - app.bumpAllowStartFgsState(PROCESS_STATE_TOP); + state.bumpAllowStartFgsState(PROCESS_STATE_TOP); if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making top: " + app); } - } else if (app.runningRemoteAnimation) { + } else if (state.isRunningRemoteAnimation()) { adj = ProcessList.VISIBLE_APP_ADJ; schedGroup = ProcessList.SCHED_GROUP_TOP_APP; - app.adjType = "running-remote-anim"; + state.setAdjType("running-remote-anim"); procState = PROCESS_STATE_CUR_TOP; if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making running remote anim: " + app); @@ -1435,12 +1502,12 @@ public final class OomAdjuster { // Don't want to kill running instrumentation. adj = ProcessList.FOREGROUND_APP_ADJ; schedGroup = ProcessList.SCHED_GROUP_DEFAULT; - app.adjType = "instrumentation"; + state.setAdjType("instrumentation"); procState = PROCESS_STATE_FOREGROUND_SERVICE; if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making instrumentation: " + app); } - } else if (app.getCachedIsReceivingBroadcast(mTmpBroadcastQueue)) { + } else if (state.getCachedIsReceivingBroadcast(mTmpBroadcastQueue)) { // An app that is currently receiving a broadcast also // counts as being in the foreground for OOM killer purposes. // It's placed in a sched group based on the nature of the @@ -1448,27 +1515,26 @@ public final class OomAdjuster { adj = ProcessList.FOREGROUND_APP_ADJ; schedGroup = (mTmpBroadcastQueue.contains(mService.mFgBroadcastQueue)) ? ProcessList.SCHED_GROUP_DEFAULT : ProcessList.SCHED_GROUP_BACKGROUND; - app.adjType = "broadcast"; + state.setAdjType("broadcast"); procState = ActivityManager.PROCESS_STATE_RECEIVER; if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making broadcast: " + app); } - } else if (app.executingServices.size() > 0) { + } else if (psr.numberOfExecutingServices() > 0) { // An app that is currently executing a service callback also // counts as being in the foreground. adj = ProcessList.FOREGROUND_APP_ADJ; - schedGroup = app.execServicesFg ? - ProcessList.SCHED_GROUP_DEFAULT : ProcessList.SCHED_GROUP_BACKGROUND; - app.adjType = "exec-service"; + schedGroup = psr.shouldExecServicesFg() + ? ProcessList.SCHED_GROUP_DEFAULT : ProcessList.SCHED_GROUP_BACKGROUND; + state.setAdjType("exec-service"); procState = PROCESS_STATE_SERVICE; if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making exec-service: " + app); } - //Slog.i(TAG, "EXEC " + (app.execServicesFg ? "FG" : "BG") + ": " + app); } else if (app == topApp) { adj = ProcessList.FOREGROUND_APP_ADJ; schedGroup = ProcessList.SCHED_GROUP_BACKGROUND; - app.adjType = "top-sleeping"; + state.setAdjType("top-sleeping"); foregroundActivities = true; procState = PROCESS_STATE_CUR_TOP; if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { @@ -1481,10 +1547,10 @@ public final class OomAdjuster { // value that the caller wants us to. adj = cachedAdj; procState = PROCESS_STATE_CACHED_EMPTY; - if (!app.containsCycle) { - app.setCached(true); - app.empty = true; - app.adjType = "cch-empty"; + if (!state.containsCycle()) { + state.setCached(true); + state.setEmpty(true); + state.setAdjType("cch-empty"); } if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making empty: " + app); @@ -1492,20 +1558,20 @@ public final class OomAdjuster { } // Examine all activities if not already foreground. - if (!foregroundActivities && app.getCachedHasActivities()) { - app.computeOomAdjFromActivitiesIfNecessary(mTmpComputeOomAdjWindowCallback, + if (!foregroundActivities && state.getCachedHasActivities()) { + state.computeOomAdjFromActivitiesIfNecessary(mTmpComputeOomAdjWindowCallback, adj, foregroundActivities, procState, schedGroup, appUid, logUid, PROCESS_STATE_CUR_TOP); - adj = app.mCachedAdj; - foregroundActivities = app.mCachedForegroundActivities; - procState = app.mCachedProcState; - schedGroup = app.mCachedSchedGroup; + adj = state.getCachedAdj(); + foregroundActivities = state.getCachedForegroundActivities(); + procState = state.getCachedProcState(); + schedGroup = state.getCachedSchedGroup(); } - if (procState > PROCESS_STATE_CACHED_RECENT && app.getCachedHasRecentTasks()) { + if (procState > PROCESS_STATE_CACHED_RECENT && state.getCachedHasRecentTasks()) { procState = PROCESS_STATE_CACHED_RECENT; - app.adjType = "cch-rec"; + state.setAdjType("cch-rec"); if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise procstate to cached recent: " + app); } @@ -1513,24 +1579,24 @@ public final class OomAdjuster { if (adj > ProcessList.PERCEPTIBLE_APP_ADJ || procState > PROCESS_STATE_FOREGROUND_SERVICE) { - if (app.hasForegroundServices()) { + if (psr.hasForegroundServices()) { // The user is aware of this app, so make it visible. adj = ProcessList.PERCEPTIBLE_APP_ADJ; procState = PROCESS_STATE_FOREGROUND_SERVICE; - app.bumpAllowStartFgsState(PROCESS_STATE_FOREGROUND_SERVICE); - app.adjType = "fg-service"; - app.setCached(false); + state.bumpAllowStartFgsState(PROCESS_STATE_FOREGROUND_SERVICE); + state.setAdjType("fg-service"); + state.setCached(false); schedGroup = ProcessList.SCHED_GROUP_DEFAULT; if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { - reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to " + app.adjType + ": " + reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to " + state.getAdjType() + ": " + app + " "); } - } else if (app.hasOverlayUi()) { + } else if (state.hasOverlayUi()) { // The process is display an overlay UI. adj = ProcessList.PERCEPTIBLE_APP_ADJ; procState = PROCESS_STATE_IMPORTANT_FOREGROUND; - app.setCached(false); - app.adjType = "has-overlay-ui"; + state.setCached(false); + state.setAdjType("has-overlay-ui"); schedGroup = ProcessList.SCHED_GROUP_DEFAULT; if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to overlay ui: " + app); @@ -1541,11 +1607,11 @@ public final class OomAdjuster { // If the app was recently in the foreground and moved to a foreground service status, // allow it to get a higher rank in memory for some time, compared to other foreground // services so that it can finish performing any persistence/processing of in-memory state. - if (app.hasForegroundServices() && adj > ProcessList.PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ - && (app.lastTopTime + mConstants.TOP_TO_FGS_GRACE_DURATION > now - || app.setProcState <= PROCESS_STATE_TOP)) { + if (psr.hasForegroundServices() && adj > ProcessList.PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ + && (state.getLastTopTime() + mConstants.TOP_TO_FGS_GRACE_DURATION > now + || state.getSetProcState() <= PROCESS_STATE_TOP)) { adj = ProcessList.PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ; - app.adjType = "fg-service-act"; + state.setAdjType("fg-service-act"); if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to recent fg: " + app); } @@ -1553,15 +1619,15 @@ public final class OomAdjuster { if (adj > ProcessList.PERCEPTIBLE_APP_ADJ || procState > PROCESS_STATE_TRANSIENT_BACKGROUND) { - if (app.forcingToImportant != null) { + if (state.getForcingToImportant() != null) { // This is currently used for toasts... they are not interactive, and // we don't want them to cause the app to become fully foreground (and // thus out of background check), so we yes the best background level we can. adj = ProcessList.PERCEPTIBLE_APP_ADJ; procState = PROCESS_STATE_TRANSIENT_BACKGROUND; - app.setCached(false); - app.adjType = "force-imp"; - app.adjSource = app.forcingToImportant; + state.setCached(false); + state.setAdjType("force-imp"); + state.setAdjSource(state.getForcingToImportant()); schedGroup = ProcessList.SCHED_GROUP_DEFAULT; if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to force imp: " + app); @@ -1569,63 +1635,63 @@ public final class OomAdjuster { } } - if (app.getCachedIsHeavyWeight()) { + if (state.getCachedIsHeavyWeight()) { if (adj > ProcessList.HEAVY_WEIGHT_APP_ADJ) { // We don't want to kill the current heavy-weight process. adj = ProcessList.HEAVY_WEIGHT_APP_ADJ; schedGroup = ProcessList.SCHED_GROUP_BACKGROUND; - app.setCached(false); - app.adjType = "heavy"; + state.setCached(false); + state.setAdjType("heavy"); if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise adj to heavy: " + app); } } if (procState > ActivityManager.PROCESS_STATE_HEAVY_WEIGHT) { procState = ActivityManager.PROCESS_STATE_HEAVY_WEIGHT; - app.adjType = "heavy"; + state.setAdjType("heavy"); if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise procstate to heavy: " + app); } } } - if (app.getCachedIsHomeProcess()) { + if (state.getCachedIsHomeProcess()) { if (adj > ProcessList.HOME_APP_ADJ) { // This process is hosting what we currently consider to be the // home app, so we don't want to let it go into the background. adj = ProcessList.HOME_APP_ADJ; schedGroup = ProcessList.SCHED_GROUP_BACKGROUND; - app.setCached(false); - app.adjType = "home"; + state.setCached(false); + state.setAdjType("home"); if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise adj to home: " + app); } } if (procState > ActivityManager.PROCESS_STATE_HOME) { procState = ActivityManager.PROCESS_STATE_HOME; - app.adjType = "home"; + state.setAdjType("home"); if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise procstate to home: " + app); } } } - if (app.getCachedIsPreviousProcess() && app.getCachedHasActivities()) { + if (state.getCachedIsPreviousProcess() && state.getCachedHasActivities()) { if (adj > ProcessList.PREVIOUS_APP_ADJ) { // This was the previous process that showed UI to the user. // We want to try to keep it around more aggressively, to give // a good experience around switching between two apps. adj = ProcessList.PREVIOUS_APP_ADJ; schedGroup = ProcessList.SCHED_GROUP_BACKGROUND; - app.setCached(false); - app.adjType = "previous"; + state.setCached(false); + state.setAdjType("previous"); if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise adj to prev: " + app); } } if (procState > PROCESS_STATE_LAST_ACTIVITY) { procState = PROCESS_STATE_LAST_ACTIVITY; - app.adjType = "previous"; + state.setAdjType("previous"); if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise procstate to prev: " + app); } @@ -1633,7 +1699,7 @@ public final class OomAdjuster { } if (false) Slog.i(TAG, "OOM " + app + ": initial adj=" + adj - + " reason=" + app.adjType); + + " reason=" + state.getAdjType()); // By default, we use the computed adjustment. It may be changed if // there are applications dependent on our services or providers, but @@ -1641,15 +1707,15 @@ public final class OomAdjuster { // infinite recursion. If we're re-evaluating due to cycles, use the previously computed // values. if (cycleReEval) { - procState = Math.min(procState, app.getCurRawProcState()); - adj = Math.min(adj, app.getCurRawAdj()); - schedGroup = Math.max(schedGroup, app.getCurrentSchedulingGroup()); + procState = Math.min(procState, state.getCurRawProcState()); + adj = Math.min(adj, state.getCurRawAdj()); + schedGroup = Math.max(schedGroup, state.getCurrentSchedulingGroup()); } - app.setCurRawAdj(adj); - app.setCurRawProcState(procState); + state.setCurRawAdj(adj); + state.setCurRawProcState(procState); - app.hasStartedServices = false; - app.adjSeq = mAdjSeq; + state.setHasStartedServices(false); + state.setAdjSeq(mAdjSeq); final BackupRecord backupTarget = mService.mBackupTargets.get(app.userId); if (backupTarget != null && app == backupTarget.app) { @@ -1660,15 +1726,15 @@ public final class OomAdjuster { if (procState > PROCESS_STATE_TRANSIENT_BACKGROUND) { procState = PROCESS_STATE_TRANSIENT_BACKGROUND; } - app.adjType = "backup"; + state.setAdjType("backup"); if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise adj to backup: " + app); } - app.setCached(false); + state.setCached(false); } if (procState > ActivityManager.PROCESS_STATE_BACKUP) { procState = ActivityManager.PROCESS_STATE_BACKUP; - app.adjType = "backup"; + state.setAdjType("backup"); if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise procstate to backup: " + app); } @@ -1676,29 +1742,29 @@ public final class OomAdjuster { } int capabilityFromFGS = 0; // capability from foreground service. - for (int is = app.numberOfRunningServices() - 1; + for (int is = psr.numberOfRunningServices() - 1; is >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ || schedGroup == ProcessList.SCHED_GROUP_BACKGROUND || procState > PROCESS_STATE_TOP); is--) { - ServiceRecord s = app.getRunningServiceAt(is); + ServiceRecord s = psr.getRunningServiceAt(is); if (s.startRequested) { - app.hasStartedServices = true; + state.setHasStartedServices(true); if (procState > PROCESS_STATE_SERVICE) { procState = PROCESS_STATE_SERVICE; - app.adjType = "started-services"; + state.setAdjType("started-services"); if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise procstate to started service: " + app); } } - if (!s.mKeepWarming && app.hasShownUi && !app.getCachedIsHomeProcess()) { + if (!s.mKeepWarming && state.hasShownUi() && !state.getCachedIsHomeProcess()) { // If this process has shown some UI, let it immediately // go to the LRU list because it may be pretty heavy with // UI stuff. We'll tag it with a label just to help // debug and understand what is going on. if (adj > ProcessList.SERVICE_ADJ) { - app.adjType = "cch-started-ui-services"; + state.setAdjType("cch-started-ui-services"); } } else { if (s.mKeepWarming @@ -1708,19 +1774,19 @@ public final class OomAdjuster { // of the background processes. if (adj > ProcessList.SERVICE_ADJ) { adj = ProcessList.SERVICE_ADJ; - app.adjType = "started-services"; + state.setAdjType("started-services"); if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise adj to started service: " + app); } - app.setCached(false); + state.setCached(false); } } // If we have let the service slide into the background // state, still have some text describing what it is doing // even though the service no longer has an impact. if (adj > ProcessList.SERVICE_ADJ) { - app.adjType = "cch-started-services"; + state.setAdjType("cch-started-services"); } } } @@ -1775,30 +1841,31 @@ public final class OomAdjuster { boolean trackedProcState = false; ProcessRecord client = cr.binding.client; + final ProcessStateRecord cstate = client.mState; if (computeClients) { - computeOomAdjLocked(client, cachedAdj, topApp, doingAll, now, + computeOomAdjLSP(client, cachedAdj, topApp, doingAll, now, cycleReEval, true); } else { - client.setCurRawAdj(client.setAdj); - client.setCurRawProcState(client.setProcState); + cstate.setCurRawAdj(cstate.getSetAdj()); + cstate.setCurRawProcState(cstate.getSetProcState()); } - int clientAdj = client.getCurRawAdj(); - int clientProcState = client.getCurRawProcState(); + int clientAdj = cstate.getCurRawAdj(); + int clientProcState = cstate.getCurRawProcState(); // pass client's mAllowStartFgs to the app if client is not persistent process. - if (client.mAllowStartFgs != FGS_FEATURE_DENIED - && client.maxAdj >= ProcessList.FOREGROUND_APP_ADJ) { - app.mAllowStartFgs = client.mAllowStartFgs; + if (cstate.getAllowedStartFgs() != FGS_FEATURE_DENIED + && cstate.getMaxAdj() >= ProcessList.FOREGROUND_APP_ADJ) { + state.setAllowStartFgs(cstate.getAllowedStartFgs()); } if ((cr.flags & Context.BIND_WAIVE_PRIORITY) == 0) { - if (shouldSkipDueToCycle(app, client, procState, adj, cycleReEval)) { + if (shouldSkipDueToCycle(state, cstate, procState, adj, cycleReEval)) { continue; } if (cr.hasFlag(Context.BIND_INCLUDE_CAPABILITIES)) { - capability |= client.curCapability; + capability |= cstate.getCurCapability(); } if (clientProcState >= PROCESS_STATE_CACHED_ACTIVITY) { @@ -1811,7 +1878,7 @@ public final class OomAdjuster { if ((cr.flags&Context.BIND_ALLOW_OOM_MANAGEMENT) != 0) { // Not doing bind OOM management, so treat // this guy more like a started service. - if (app.hasShownUi && !app.getCachedIsHomeProcess()) { + if (state.hasShownUi() && !state.getCachedIsHomeProcess()) { // If this process has shown some UI, let it immediately // go to the LRU list because it may be pretty heavy with // UI stuff. We'll tag it with a label just to help @@ -1819,7 +1886,7 @@ public final class OomAdjuster { if (adj > clientAdj) { adjType = "cch-bound-ui-services"; } - app.setCached(false); + state.setCached(false); clientAdj = adj; clientProcState = procState; } else { @@ -1845,7 +1912,7 @@ public final class OomAdjuster { // about letting this process get into the LRU // list to be killed and restarted if needed for // memory. - if (app.hasShownUi && !app.getCachedIsHomeProcess() + if (state.hasShownUi() && !state.getCachedIsHomeProcess() && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) { if (adj >= ProcessList.CACHED_APP_MIN_ADJ) { adjType = "cch-bound-ui-services"; @@ -1882,12 +1949,12 @@ public final class OomAdjuster { newAdj = adj; } } - if (!client.isCached()) { - app.setCached(false); + if (!cstate.isCached()) { + state.setCached(false); } if (adj > newAdj) { adj = newAdj; - app.setCurRawAdj(adj); + state.setCurRawAdj(adj); adjType = "service"; } } @@ -1897,7 +1964,7 @@ public final class OomAdjuster { // This will treat important bound services identically to // the top app, which may behave differently than generic // foreground work. - final int curSchedGroup = client.getCurrentSchedulingGroup(); + final int curSchedGroup = cstate.getCurrentSchedulingGroup(); if (curSchedGroup > schedGroup) { if ((cr.flags&Context.BIND_IMPORTANT) != 0) { schedGroup = curSchedGroup; @@ -1912,7 +1979,7 @@ public final class OomAdjuster { // give them the best bound state after that. if (cr.hasFlag(Context.BIND_FOREGROUND_SERVICE)) { clientProcState = PROCESS_STATE_BOUND_FOREGROUND_SERVICE; - app.bumpAllowStartFgsState( + state.bumpAllowStartFgsState( PROCESS_STATE_BOUND_FOREGROUND_SERVICE); } else if (mService.mWakefulness.get() == PowerManagerInternal.WAKEFULNESS_AWAKE @@ -1927,7 +1994,7 @@ public final class OomAdjuster { // Go at most to BOUND_TOP, unless requested to elevate // to client's state. clientProcState = PROCESS_STATE_BOUND_TOP; - app.bumpAllowStartFgsState(PROCESS_STATE_BOUND_TOP); + state.bumpAllowStartFgsState(PROCESS_STATE_BOUND_TOP); boolean enabled = false; try { enabled = mPlatformCompatCache.isChangeEnabled( @@ -1971,7 +2038,7 @@ public final class OomAdjuster { if (procState > clientProcState) { procState = clientProcState; - app.setCurRawProcState(procState); + state.setCurRawProcState(procState); if (adjType == null) { adjType = "service"; } @@ -1981,12 +2048,12 @@ public final class OomAdjuster { app.setPendingUiClean(true); } if (adjType != null) { - app.adjType = adjType; - app.adjTypeCode = ActivityManager.RunningAppProcessInfo - .REASON_SERVICE_IN_USE; - app.adjSource = cr.binding.client; - app.adjSourceProcState = clientProcState; - app.adjTarget = s.instanceName; + state.setAdjType(adjType); + state.setAdjTypeCode(ActivityManager.RunningAppProcessInfo + .REASON_SERVICE_IN_USE); + state.setAdjSource(cr.binding.client); + state.setAdjSourceProcState(clientProcState); + state.setAdjTarget(s.instanceName); if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to " + adjType + ": " + app + ", due to " + cr.binding.client @@ -2005,18 +2072,18 @@ public final class OomAdjuster { // bound by an unfrozen app via a WPRI binding has to remain // unfrozen. if (clientAdj < ProcessList.CACHED_APP_MIN_ADJ) { - app.shouldNotFreeze = true; + app.mOptRecord.setShouldNotFreeze(true); } } if ((cr.flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) { - app.treatLikeActivity = true; + psr.setTreatLikeActivity(true); } final ActivityServiceConnectionsHolder a = cr.activity; if ((cr.flags&Context.BIND_ADJUST_WITH_ACTIVITY) != 0) { if (a != null && adj > ProcessList.FOREGROUND_APP_ADJ && a.isActivityVisible()) { adj = ProcessList.FOREGROUND_APP_ADJ; - app.setCurRawAdj(adj); + state.setCurRawAdj(adj); if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) { if ((cr.flags&Context.BIND_IMPORTANT) != 0) { schedGroup = ProcessList.SCHED_GROUP_TOP_APP_BOUND; @@ -2024,13 +2091,13 @@ public final class OomAdjuster { schedGroup = ProcessList.SCHED_GROUP_DEFAULT; } } - app.setCached(false); - app.adjType = "service"; - app.adjTypeCode = ActivityManager.RunningAppProcessInfo - .REASON_SERVICE_IN_USE; - app.adjSource = a; - app.adjSourceProcState = procState; - app.adjTarget = s.instanceName; + state.setCached(false); + state.setAdjType("service"); + state.setAdjTypeCode(ActivityManager.RunningAppProcessInfo + .REASON_SERVICE_IN_USE); + state.setAdjSource(a); + state.setAdjSourceProcState(procState); + state.setAdjTarget(s.instanceName); if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to service w/activity: " + app); @@ -2041,12 +2108,13 @@ public final class OomAdjuster { } } - for (int provi = app.pubProviders.size() - 1; + final ProcessProviderRecord ppr = app.mProviders; + for (int provi = ppr.numberOfProviders() - 1; provi >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ || schedGroup == ProcessList.SCHED_GROUP_BACKGROUND || procState > PROCESS_STATE_TOP); provi--) { - ContentProviderRecord cpr = app.pubProviders.valueAt(provi); + ContentProviderRecord cpr = ppr.getProviderAt(provi); for (int i = cpr.connections.size() - 1; i >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ || schedGroup == ProcessList.SCHED_GROUP_BACKGROUND @@ -2054,24 +2122,24 @@ public final class OomAdjuster { i--) { ContentProviderConnection conn = cpr.connections.get(i); ProcessRecord client = conn.client; + final ProcessStateRecord cstate = client.mState; if (client == app) { // Being our own client is not interesting. continue; } if (computeClients) { - computeOomAdjLocked(client, cachedAdj, topApp, doingAll, now, cycleReEval, - true); + computeOomAdjLSP(client, cachedAdj, topApp, doingAll, now, cycleReEval, true); } else { - client.setCurRawAdj(client.setAdj); - client.setCurRawProcState(client.setProcState); + cstate.setCurRawAdj(cstate.getSetAdj()); + cstate.setCurRawProcState(cstate.getSetProcState()); } - if (shouldSkipDueToCycle(app, client, procState, adj, cycleReEval)) { + if (shouldSkipDueToCycle(state, cstate, procState, adj, cycleReEval)) { continue; } - int clientAdj = client.getCurRawAdj(); - int clientProcState = client.getCurRawProcState(); + int clientAdj = cstate.getCurRawAdj(); + int clientProcState = cstate.getCurRawProcState(); if (clientProcState >= PROCESS_STATE_CACHED_ACTIVITY) { // If the other app is cached for any reason, for purposes here @@ -2080,16 +2148,16 @@ public final class OomAdjuster { } String adjType = null; if (adj > clientAdj) { - if (app.hasShownUi && !app.getCachedIsHomeProcess() + if (state.hasShownUi() && !state.getCachedIsHomeProcess() && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) { adjType = "cch-ui-provider"; } else { adj = clientAdj > ProcessList.FOREGROUND_APP_ADJ ? clientAdj : ProcessList.FOREGROUND_APP_ADJ; - app.setCurRawAdj(adj); + state.setCurRawAdj(adj); adjType = "provider"; } - app.setCached(app.isCached() & client.isCached()); + state.setCached(state.isCached() & cstate.isCached()); } if (clientProcState <= PROCESS_STATE_FOREGROUND_SERVICE) { @@ -2106,18 +2174,18 @@ public final class OomAdjuster { conn.trackProcState(clientProcState, mAdjSeq, now); if (procState > clientProcState) { procState = clientProcState; - app.setCurRawProcState(procState); + state.setCurRawProcState(procState); } - if (client.getCurrentSchedulingGroup() > schedGroup) { + if (cstate.getCurrentSchedulingGroup() > schedGroup) { schedGroup = ProcessList.SCHED_GROUP_DEFAULT; } if (adjType != null) { - app.adjType = adjType; - app.adjTypeCode = ActivityManager.RunningAppProcessInfo - .REASON_PROVIDER_IN_USE; - app.adjSource = client; - app.adjSourceProcState = clientProcState; - app.adjTarget = cpr.name; + state.setAdjType(adjType); + state.setAdjTypeCode(ActivityManager.RunningAppProcessInfo + .REASON_PROVIDER_IN_USE); + state.setAdjSource(client); + state.setAdjSourceProcState(clientProcState); + state.setAdjTarget(cpr.name); if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to " + adjType + ": " + app + ", due to " + client @@ -2132,11 +2200,11 @@ public final class OomAdjuster { if (cpr.hasExternalProcessHandles()) { if (adj > ProcessList.FOREGROUND_APP_ADJ) { adj = ProcessList.FOREGROUND_APP_ADJ; - app.setCurRawAdj(adj); + state.setCurRawAdj(adj); schedGroup = ProcessList.SCHED_GROUP_DEFAULT; - app.setCached(false); - app.adjType = "ext-provider"; - app.adjTarget = cpr.name; + state.setCached(false); + state.setAdjType("ext-provider"); + state.setAdjTarget(cpr.name); if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise adj to external provider: " + app); @@ -2144,7 +2212,7 @@ public final class OomAdjuster { } if (procState > PROCESS_STATE_IMPORTANT_FOREGROUND) { procState = PROCESS_STATE_IMPORTANT_FOREGROUND; - app.setCurRawProcState(procState); + state.setCurRawProcState(procState); if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise procstate to external provider: " + app); @@ -2153,13 +2221,13 @@ public final class OomAdjuster { } } - if (app.lastProviderTime > 0 && - (app.lastProviderTime + mConstants.CONTENT_PROVIDER_RETAIN_TIME) > now) { + if (ppr.getLastProviderTime() > 0 + && (ppr.getLastProviderTime() + mConstants.CONTENT_PROVIDER_RETAIN_TIME) > now) { if (adj > ProcessList.PREVIOUS_APP_ADJ) { adj = ProcessList.PREVIOUS_APP_ADJ; schedGroup = ProcessList.SCHED_GROUP_BACKGROUND; - app.setCached(false); - app.adjType = "recent-provider"; + state.setCached(false); + state.setAdjType("recent-provider"); if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise adj to recent provider: " + app); @@ -2167,7 +2235,7 @@ public final class OomAdjuster { } if (procState > PROCESS_STATE_LAST_ACTIVITY) { procState = PROCESS_STATE_LAST_ACTIVITY; - app.adjType = "recent-provider"; + state.setAdjType("recent-provider"); if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise procstate to recent provider: " + app); @@ -2176,24 +2244,23 @@ public final class OomAdjuster { } if (procState >= PROCESS_STATE_CACHED_EMPTY) { - if (app.hasClientActivities()) { + if (psr.hasClientActivities()) { // This is a cached process, but with client activities. Mark it so. procState = PROCESS_STATE_CACHED_ACTIVITY_CLIENT; - app.adjType = "cch-client-act"; - } else if (app.treatLikeActivity) { + state.setAdjType("cch-client-act"); + } else if (psr.isTreatedLikeActivity()) { // This is a cached process, but somebody wants us to treat it like it has // an activity, okay! procState = PROCESS_STATE_CACHED_ACTIVITY; - app.adjType = "cch-as-act"; + state.setAdjType("cch-as-act"); } } if (adj == ProcessList.SERVICE_ADJ) { if (doingAll && !cycleReEval) { - app.serviceb = mNewNumAServiceProcs > (mNumServiceProcs/3); + state.setServiceB(mNewNumAServiceProcs > (mNumServiceProcs / 3)); mNewNumServiceProcs++; - //Slog.i(TAG, "ADJ " + app + " serviceb=" + app.serviceb); - if (!app.serviceb) { + if (!state.isServiceB()) { // This service isn't far enough down on the LRU list to // normally be a B service, but if we are low on RAM and it // is large we want to force it down since we would prefer to @@ -2201,29 +2268,27 @@ public final class OomAdjuster { if (!mService.mAppProfiler.isLastMemoryLevelNormal() && app.mProfile.getLastPss() >= mProcessList.getCachedRestoreThresholdKb()) { - app.serviceHighRam = true; - app.serviceb = true; + state.setServiceHighRam(true); + state.setServiceB(true); //Slog.i(TAG, "ADJ " + app + " high ram!"); } else { mNewNumAServiceProcs++; //Slog.i(TAG, "ADJ " + app + " not high ram!"); } } else { - app.serviceHighRam = false; + state.setServiceHighRam(false); } } - if (app.serviceb) { + if (state.isServiceB()) { adj = ProcessList.SERVICE_B_ADJ; } } - app.setCurRawAdj(adj); + state.setCurRawAdj(adj); - //Slog.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid + - // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj); - if (adj > app.maxAdj) { - adj = app.maxAdj; - if (app.maxAdj <= ProcessList.PERCEPTIBLE_LOW_APP_ADJ) { + if (adj > state.getMaxAdj()) { + adj = state.getMaxAdj(); + if (adj <= ProcessList.PERCEPTIBLE_LOW_APP_ADJ) { schedGroup = ProcessList.SCHED_GROUP_DEFAULT; } } @@ -2238,31 +2303,32 @@ public final class OomAdjuster { } // apply capability from FGS. - if (app.hasForegroundServices()) { + if (psr.hasForegroundServices()) { capability |= capabilityFromFGS; } - capability |= getDefaultCapability(app, procState); + capability |= getDefaultCapability(psr, procState); // Do final modification to adj. Everything we do between here and applying // the final setAdj must be done in this function, because we will also use // it when computing the final cached adj later. Note that we don't need to // worry about this for max adj above, since max adj will always be used to // keep it out of the cached vaues. - app.curAdj = app.modifyRawOomAdj(adj); - app.curCapability = capability; - app.setCurrentSchedulingGroup(schedGroup); - app.setCurProcState(procState); - app.setCurRawProcState(procState); - app.setHasForegroundActivities(foregroundActivities); - app.completedAdjSeq = mAdjSeq; - app.setAllowStartFgs(); + state.setCurAdj(psr.modifyRawOomAdj(adj)); + state.setCurCapability(capability); + state.setCurrentSchedulingGroup(schedGroup); + state.setCurProcState(procState); + state.setCurRawProcState(procState); + state.setHasForegroundActivities(foregroundActivities); + state.setCompletedAdjSeq(mAdjSeq); + state.setAllowStartFgs(); + // if curAdj or curProcState improved, then this process was promoted - return app.curAdj < prevAppAdj || app.getCurProcState() < prevProcState - || app.curCapability != prevCapability ; + return state.getCurAdj() < prevAppAdj || state.getCurProcState() < prevProcState + || state.getCurCapability() != prevCapability; } - private int getDefaultCapability(ProcessRecord app, int procState) { + private int getDefaultCapability(ProcessServiceRecord psr, int procState) { switch (procState) { case PROCESS_STATE_PERSISTENT: case PROCESS_STATE_PERSISTENT_UI: @@ -2271,7 +2337,7 @@ public final class OomAdjuster { case PROCESS_STATE_BOUND_TOP: return PROCESS_CAPABILITY_NONE; case PROCESS_STATE_FOREGROUND_SERVICE: - if (app.hasForegroundServices()) { + if (psr.hasForegroundServices()) { // Capability from FGS are conditional depending on foreground service type in // manifest file and the mAllowWhileInUsePermissionInFgs flag. return PROCESS_CAPABILITY_NONE; @@ -2299,16 +2365,16 @@ public final class OomAdjuster { * evaluation. * @return whether to skip using the client connection at this time */ - private boolean shouldSkipDueToCycle(ProcessRecord app, ProcessRecord client, + private boolean shouldSkipDueToCycle(ProcessStateRecord app, ProcessStateRecord client, int procState, int adj, boolean cycleReEval) { - if (client.containsCycle) { - // We've detected a cycle. We should retry computeOomAdjLocked later in + if (client.containsCycle()) { + // We've detected a cycle. We should retry computeOomAdjLSP later in // case a later-checked connection from a client would raise its // priority legitimately. - app.containsCycle = true; + app.setContainsCycle(true); // If the client has not been completely evaluated, check if it's worth // using the partial values. - if (client.completedAdjSeq < mAdjSeq) { + if (client.getCompletedAdjSeq() < mAdjSeq) { if (cycleReEval) { // If the partial values are no better, skip until the next // attempt @@ -2327,7 +2393,8 @@ public final class OomAdjuster { } /** Inform the oomadj observer of changes to oomadj. Used by tests. */ - void reportOomAdjMessageLocked(String tag, String msg) { + @GuardedBy("mService") + private void reportOomAdjMessageLocked(String tag, String msg) { Slog.d(tag, msg); synchronized (mService.mOomAdjObserverLock) { if (mService.mCurOomAdjObserver != null) { @@ -2338,13 +2405,14 @@ public final class OomAdjuster { } /** Applies the computed oomadj, procstate and sched group values and freezes them in set* */ - @GuardedBy("mService") - private final boolean applyOomAdjLocked(ProcessRecord app, boolean doingAll, long now, + @GuardedBy({"mService", "mProcLock"}) + private boolean applyOomAdjLSP(ProcessRecord app, boolean doingAll, long now, long nowElapsed) { boolean success = true; + final ProcessStateRecord state = app.mState; - if (app.getCurRawAdj() != app.setRawAdj) { - app.setRawAdj = app.getCurRawAdj(); + if (state.getCurRawAdj() != state.getSetRawAdj()) { + state.setSetRawAdj(state.getCurRawAdj()); } int changes = 0; @@ -2352,22 +2420,22 @@ public final class OomAdjuster { // don't compact during bootup if (mCachedAppOptimizer.useCompaction() && mService.mBooted) { // Cached and prev/home compaction - if (app.curAdj != app.setAdj) { + if (state.getCurAdj() != state.getSetAdj()) { // Perform a minor compaction when a perceptible app becomes the prev/home app // Perform a major compaction when any app enters cached // reminder: here, setAdj is previous state, curAdj is upcoming state - if (app.setAdj <= ProcessList.PERCEPTIBLE_APP_ADJ && - (app.curAdj == ProcessList.PREVIOUS_APP_ADJ || - app.curAdj == ProcessList.HOME_APP_ADJ)) { + if (state.getSetAdj() <= ProcessList.PERCEPTIBLE_APP_ADJ + && (state.getCurAdj() == ProcessList.PREVIOUS_APP_ADJ + || state.getCurAdj() == ProcessList.HOME_APP_ADJ)) { mCachedAppOptimizer.compactAppSome(app); - } else if ((app.setAdj < ProcessList.CACHED_APP_MIN_ADJ - || app.setAdj > ProcessList.CACHED_APP_MAX_ADJ) - && app.curAdj >= ProcessList.CACHED_APP_MIN_ADJ - && app.curAdj <= ProcessList.CACHED_APP_MAX_ADJ) { + } else if ((state.getSetAdj() < ProcessList.CACHED_APP_MIN_ADJ + || state.getSetAdj() > ProcessList.CACHED_APP_MAX_ADJ) + && state.getCurAdj() >= ProcessList.CACHED_APP_MIN_ADJ + && state.getCurAdj() <= ProcessList.CACHED_APP_MAX_ADJ) { mCachedAppOptimizer.compactAppFull(app); } } else if (mService.mWakefulness.get() != PowerManagerInternal.WAKEFULNESS_AWAKE - && app.setAdj < ProcessList.FOREGROUND_APP_ADJ + && state.getSetAdj() < ProcessList.FOREGROUND_APP_ADJ // Because these can fire independent of oom_adj/procstate changes, we need // to throttle the actual dispatch of these requests in addition to the // processing of the requests. As a result, there is throttling both here @@ -2375,36 +2443,36 @@ public final class OomAdjuster { && mCachedAppOptimizer.shouldCompactPersistent(app, now)) { mCachedAppOptimizer.compactAppPersistent(app); } else if (mService.mWakefulness.get() != PowerManagerInternal.WAKEFULNESS_AWAKE - && app.getCurProcState() + && state.getCurProcState() == ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE && mCachedAppOptimizer.shouldCompactBFGS(app, now)) { mCachedAppOptimizer.compactAppBfgs(app); } } - if (app.curAdj != app.setAdj) { - ProcessList.setOomAdj(app.pid, app.uid, app.curAdj); + if (state.getCurAdj() != state.getSetAdj()) { + ProcessList.setOomAdj(app.getPid(), app.uid, state.getCurAdj()); if (DEBUG_SWITCH || DEBUG_OOM_ADJ || mService.mCurOomAdjUid == app.info.uid) { - String msg = "Set " + app.pid + " " + app.processName + " adj " - + app.curAdj + ": " + app.adjType; + String msg = "Set " + app.getPid() + " " + app.processName + " adj " + + state.getCurAdj() + ": " + state.getAdjType(); reportOomAdjMessageLocked(TAG_OOM_ADJ, msg); } - app.setAdj = app.curAdj; - app.verifiedAdj = ProcessList.INVALID_ADJ; + state.setSetAdj(state.getCurAdj()); + state.setVerifiedAdj(ProcessList.INVALID_ADJ); } - final int curSchedGroup = app.getCurrentSchedulingGroup(); - if (app.setSchedGroup != curSchedGroup) { - int oldSchedGroup = app.setSchedGroup; - app.setSchedGroup = curSchedGroup; + final int curSchedGroup = state.getCurrentSchedulingGroup(); + if (state.getSetSchedGroup() != curSchedGroup) { + int oldSchedGroup = state.getSetSchedGroup(); + state.setSetSchedGroup(curSchedGroup); if (DEBUG_SWITCH || DEBUG_OOM_ADJ || mService.mCurOomAdjUid == app.uid) { String msg = "Setting sched group of " + app.processName - + " to " + curSchedGroup + ": " + app.adjType; + + " to " + curSchedGroup + ": " + state.getAdjType(); reportOomAdjMessageLocked(TAG_OOM_ADJ, msg); } - if (app.waitingToKill != null && app.curReceivers.isEmpty() - && app.setSchedGroup == ProcessList.SCHED_GROUP_BACKGROUND) { - app.kill(app.waitingToKill, ApplicationExitInfo.REASON_USER_REQUESTED, + if (app.getWaitingToKill() != null && app.mReceivers.numberOfCurReceivers() == 0 + && state.getSetSchedGroup() == ProcessList.SCHED_GROUP_BACKGROUND) { + app.killLocked(app.getWaitingToKill(), ApplicationExitInfo.REASON_USER_REQUESTED, ApplicationExitInfo.SUBREASON_UNKNOWN, true); success = false; } else { @@ -2425,22 +2493,23 @@ public final class OomAdjuster { break; } mProcessGroupHandler.sendMessage(mProcessGroupHandler.obtainMessage( - 0 /* unused */, app.pid, processGroup, app.processName)); + 0 /* unused */, app.getPid(), processGroup, app.processName)); try { + final int renderThreadTid = app.getRenderThreadTid(); if (curSchedGroup == ProcessList.SCHED_GROUP_TOP_APP) { // do nothing if we already switched to RT if (oldSchedGroup != ProcessList.SCHED_GROUP_TOP_APP) { app.getWindowProcessController().onTopProcChanged(); if (mService.mUseFifoUiScheduling) { // Switch UI pipeline for app to SCHED_FIFO - app.savedPriority = Process.getThreadPriority(app.pid); - mService.scheduleAsFifoPriority(app.pid, /* suppressLogs */true); - if (app.renderThreadTid != 0) { - mService.scheduleAsFifoPriority(app.renderThreadTid, + state.setSavedPriority(Process.getThreadPriority(app.getPid())); + mService.scheduleAsFifoPriority(app.getPid(), true); + if (renderThreadTid != 0) { + mService.scheduleAsFifoPriority(renderThreadTid, /* suppressLogs */true); if (DEBUG_OOM_ADJ) { Slog.d("UI_FIFO", "Set RenderThread (TID " + - app.renderThreadTid + ") to FIFO"); + renderThreadTid + ") to FIFO"); } } else { if (DEBUG_OOM_ADJ) { @@ -2449,10 +2518,10 @@ public final class OomAdjuster { } } else { // Boost priority for top app UI and render threads - setThreadPriority(app.pid, TOP_APP_PRIORITY_BOOST); - if (app.renderThreadTid != 0) { + setThreadPriority(app.getPid(), TOP_APP_PRIORITY_BOOST); + if (renderThreadTid != 0) { try { - setThreadPriority(app.renderThreadTid, + setThreadPriority(renderThreadTid, TOP_APP_PRIORITY_BOOST); } catch (IllegalArgumentException e) { // thread died, ignore @@ -2466,10 +2535,10 @@ public final class OomAdjuster { if (mService.mUseFifoUiScheduling) { try { // Reset UI pipeline to SCHED_OTHER - setThreadScheduler(app.pid, SCHED_OTHER, 0); - setThreadPriority(app.pid, app.savedPriority); - if (app.renderThreadTid != 0) { - setThreadScheduler(app.renderThreadTid, + setThreadScheduler(app.getPid(), SCHED_OTHER, 0); + setThreadPriority(app.getPid(), state.getSavedPriority()); + if (renderThreadTid != 0) { + setThreadScheduler(renderThreadTid, SCHED_OTHER, 0); } } catch (IllegalArgumentException e) { @@ -2481,139 +2550,141 @@ public final class OomAdjuster { } } else { // Reset priority for top app UI and render threads - setThreadPriority(app.pid, 0); + setThreadPriority(app.getPid(), 0); } - if (app.renderThreadTid != 0) { - setThreadPriority(app.renderThreadTid, THREAD_PRIORITY_DISPLAY); + if (renderThreadTid != 0) { + setThreadPriority(renderThreadTid, THREAD_PRIORITY_DISPLAY); } } } catch (Exception e) { if (DEBUG_ALL) { - Slog.w(TAG, "Failed setting thread priority of " + app.pid, e); + Slog.w(TAG, "Failed setting thread priority of " + app.getPid(), e); } } } } - if (app.repForegroundActivities != app.hasForegroundActivities()) { - app.repForegroundActivities = app.hasForegroundActivities(); + if (state.hasRepForegroundActivities() != state.hasForegroundActivities()) { + state.setRepForegroundActivities(state.hasForegroundActivities()); changes |= ActivityManagerService.ProcessChangeItem.CHANGE_ACTIVITIES; } - updateAppFreezeStateLocked(app); + updateAppFreezeStateLSP(app); - if (app.getReportedProcState() != app.getCurProcState()) { - app.setReportedProcState(app.getCurProcState()); - if (app.thread != null) { + if (state.getReportedProcState() != state.getCurProcState()) { + state.setReportedProcState(state.getCurProcState()); + if (app.getThread() != null) { try { if (false) { //RuntimeException h = new RuntimeException("here"); - Slog.i(TAG, "Sending new process state " + app.getReportedProcState() + Slog.i(TAG, "Sending new process state " + state.getReportedProcState() + " to " + app /*, h*/); } - app.thread.setProcessState(app.getReportedProcState()); + app.getThread().setProcessState(state.getReportedProcState()); } catch (RemoteException e) { } } } boolean forceUpdatePssTime = false; - if (app.setProcState == PROCESS_STATE_NONEXISTENT - || ProcessList.procStatesDifferForMem(app.getCurProcState(), app.setProcState)) { - app.lastStateTime = now; + if (state.getSetProcState() == PROCESS_STATE_NONEXISTENT + || ProcessList.procStatesDifferForMem( + state.getCurProcState(), state.getSetProcState())) { + state.setLastStateTime(now); forceUpdatePssTime = true; if (DEBUG_PSS) { Slog.d(TAG_PSS, "Process state change from " - + ProcessList.makeProcStateString(app.setProcState) + " to " - + ProcessList.makeProcStateString(app.getCurProcState()) + " next pss in " + + ProcessList.makeProcStateString(state.getSetProcState()) + " to " + + ProcessList.makeProcStateString(state.getCurProcState()) + " next pss in " + (app.mProfile.getNextPssTime() - now) + ": " + app); } } synchronized (mService.mAppProfiler.mProfilerLock) { - app.mProfile.updateProcState(app); + app.mProfile.updateProcState(app.mState); mService.mAppProfiler.updateNextPssTimeLPf( - app.getCurProcState(), app.mProfile, now, forceUpdatePssTime); + state.getCurProcState(), app.mProfile, now, forceUpdatePssTime); } - if (app.setProcState != app.getCurProcState()) { + if (state.getSetProcState() != state.getCurProcState()) { if (DEBUG_SWITCH || DEBUG_OOM_ADJ || mService.mCurOomAdjUid == app.uid) { String msg = "Proc state change of " + app.processName - + " to " + ProcessList.makeProcStateString(app.getCurProcState()) - + " (" + app.getCurProcState() + ")" + ": " + app.adjType; + + " to " + ProcessList.makeProcStateString(state.getCurProcState()) + + " (" + state.getCurProcState() + ")" + ": " + state.getAdjType(); reportOomAdjMessageLocked(TAG_OOM_ADJ, msg); } - boolean setImportant = app.setProcState < PROCESS_STATE_SERVICE; - boolean curImportant = app.getCurProcState() < PROCESS_STATE_SERVICE; + boolean setImportant = state.getSetProcState() < PROCESS_STATE_SERVICE; + boolean curImportant = state.getCurProcState() < PROCESS_STATE_SERVICE; if (setImportant && !curImportant) { // This app is no longer something we consider important enough to allow to use // arbitrary amounts of battery power. Note its current CPU time to later know to // kill it if it is not behaving well. - app.setWhenUnimportant(now); + state.setWhenUnimportant(now); app.mProfile.mLastCpuTime.set(0); } // Inform UsageStats of important process state change // Must be called before updating setProcState - maybeUpdateUsageStatsLocked(app, nowElapsed); + maybeUpdateUsageStatsLSP(app, nowElapsed); - maybeUpdateLastTopTime(app, now); + maybeUpdateLastTopTime(state, now); - app.setProcState = app.getCurProcState(); - if (app.setProcState >= ActivityManager.PROCESS_STATE_HOME) { - app.notCachedSinceIdle = false; + state.setSetProcState(state.getCurProcState()); + if (state.getSetProcState() >= ActivityManager.PROCESS_STATE_HOME) { + state.setNotCachedSinceIdle(false); } if (!doingAll) { - mService.setProcessTrackerStateLocked(app, + mService.setProcessTrackerStateLOSP(app, mService.mProcessStats.getMemFactorLocked(), now); } else { - app.procStateChanged = true; + state.setProcStateChanged(true); } - } else if (app.reportedInteraction && (nowElapsed - app.getInteractionEventTime()) + } else if (state.hasReportedInteraction() && (nowElapsed - state.getInteractionEventTime()) > mConstants.USAGE_STATS_INTERACTION_INTERVAL) { // For apps that sit around for a long time in the interactive state, we need // to report this at least once a day so they don't go idle. - maybeUpdateUsageStatsLocked(app, nowElapsed); - } else if (!app.reportedInteraction && (nowElapsed - app.getFgInteractionTime()) + maybeUpdateUsageStatsLSP(app, nowElapsed); + } else if (!state.hasReportedInteraction() && (nowElapsed - state.getFgInteractionTime()) > mConstants.SERVICE_USAGE_INTERACTION_TIME) { // For foreground services that sit around for a long time but are not interacted with. - maybeUpdateUsageStatsLocked(app, nowElapsed); + maybeUpdateUsageStatsLSP(app, nowElapsed); } - if (app.curCapability != app.setCapability) { + if (state.getCurCapability() != state.getSetCapability()) { changes |= ActivityManagerService.ProcessChangeItem.CHANGE_CAPABILITY; - app.setCapability = app.curCapability; + state.setSetCapability(state.getCurCapability()); } if (changes != 0) { if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS, "Changes in " + app + ": " + changes); ActivityManagerService.ProcessChangeItem item = - mProcessList.enqueueProcessChangeItemLocked(app.pid, app.info.uid); + mProcessList.enqueueProcessChangeItemLocked(app.getPid(), app.info.uid); item.changes |= changes; - item.foregroundActivities = app.repForegroundActivities; - item.capability = app.setCapability; + item.foregroundActivities = state.hasRepForegroundActivities(); + item.capability = state.getSetCapability(); if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS, "Item " + Integer.toHexString(System.identityHashCode(item)) + " " + app.toShortString() + ": changes=" + item.changes + " foreground=" + item.foregroundActivities - + " type=" + app.adjType + " source=" + app.adjSource - + " target=" + app.adjTarget + " capability=" + item.capability); + + " type=" + state.getAdjType() + " source=" + state.getAdjSource() + + " target=" + state.getAdjTarget() + " capability=" + item.capability); } return success; } - @GuardedBy("mService") - void setAttachingSchedGroupLocked(ProcessRecord app) { + @GuardedBy({"mService", "mProcLock"}) + void setAttachingSchedGroupLSP(ProcessRecord app) { int initialSchedGroup = ProcessList.SCHED_GROUP_DEFAULT; + final ProcessStateRecord state = app.mState; // If the process has been marked as foreground via Zygote.START_FLAG_USE_TOP_APP_PRIORITY, // then verify that the top priority is actually is applied. - if (app.hasForegroundActivities()) { + if (state.hasForegroundActivities()) { String fallbackReason = null; try { - // The priority must be the same as how does {@link #applyOomAdjLocked} set for + // The priority must be the same as how does {@link #applyOomAdjLSP} set for // {@link ProcessList.SCHED_GROUP_TOP_APP}. We don't check render thread because it // is not ready when attaching. - if (Process.getProcessGroup(app.pid) == THREAD_GROUP_TOP_APP) { + if (Process.getProcessGroup(app.getPid()) == THREAD_GROUP_TOP_APP) { app.getWindowProcessController().onTopProcChanged(); - setThreadPriority(app.pid, TOP_APP_PRIORITY_BOOST); + setThreadPriority(app.getPid(), TOP_APP_PRIORITY_BOOST); } else { fallbackReason = "not expected top priority"; } @@ -2629,23 +2700,27 @@ public final class OomAdjuster { } } - app.setCurrentSchedulingGroup(app.setSchedGroup = initialSchedGroup); + state.setSetSchedGroup(initialSchedGroup); + state.setCurrentSchedulingGroup(initialSchedGroup); } // ONLY used for unit testing in OomAdjusterTests.java @VisibleForTesting void maybeUpdateUsageStats(ProcessRecord app, long nowElapsed) { synchronized (mService) { - maybeUpdateUsageStatsLocked(app, nowElapsed); + synchronized (mProcLock) { + maybeUpdateUsageStatsLSP(app, nowElapsed); + } } } - @GuardedBy("mService") - private void maybeUpdateUsageStatsLocked(ProcessRecord app, long nowElapsed) { + @GuardedBy({"mService", "mProcLock"}) + private void maybeUpdateUsageStatsLSP(ProcessRecord app, long nowElapsed) { + final ProcessStateRecord state = app.mState; if (DEBUG_USAGE_STATS) { Slog.d(TAG, "Checking proc [" + Arrays.toString(app.getPackageList()) - + "] state changes: old = " + app.setProcState + ", new = " - + app.getCurProcState()); + + "] state changes: old = " + state.getSetProcState() + ", new = " + + state.getCurProcState()); } if (mService.mUsageStatsService == null) { return; @@ -2654,27 +2729,28 @@ public final class OomAdjuster { // To avoid some abuse patterns, we are going to be careful about what we consider // to be an app interaction. Being the top activity doesn't count while the display // is sleeping, nor do short foreground services. - if (app.getCurProcState() <= PROCESS_STATE_TOP - || app.getCurProcState() == PROCESS_STATE_BOUND_TOP) { + if (state.getCurProcState() <= PROCESS_STATE_TOP + || state.getCurProcState() == PROCESS_STATE_BOUND_TOP) { isInteraction = true; - app.setFgInteractionTime(0); - } else if (app.getCurProcState() <= PROCESS_STATE_FOREGROUND_SERVICE) { - if (app.getFgInteractionTime() == 0) { - app.setFgInteractionTime(nowElapsed); + state.setFgInteractionTime(0); + } else if (state.getCurProcState() <= PROCESS_STATE_FOREGROUND_SERVICE) { + if (state.getFgInteractionTime() == 0) { + state.setFgInteractionTime(nowElapsed); isInteraction = false; } else { - isInteraction = nowElapsed > app.getFgInteractionTime() + isInteraction = nowElapsed > state.getFgInteractionTime() + mConstants.SERVICE_USAGE_INTERACTION_TIME; } } else { isInteraction = - app.getCurProcState() <= PROCESS_STATE_IMPORTANT_FOREGROUND; - app.setFgInteractionTime(0); + state.getCurProcState() <= PROCESS_STATE_IMPORTANT_FOREGROUND; + state.setFgInteractionTime(0); } if (isInteraction - && (!app.reportedInteraction || (nowElapsed - app.getInteractionEventTime()) - > mConstants.USAGE_STATS_INTERACTION_INTERVAL)) { - app.setInteractionEventTime(nowElapsed); + && (!state.hasReportedInteraction() + || (nowElapsed - state.getInteractionEventTime()) + > mConstants.USAGE_STATS_INTERACTION_INTERVAL)) { + state.setInteractionEventTime(nowElapsed); String[] packages = app.getPackageList(); if (packages != null) { for (int i = 0; i < packages.length; i++) { @@ -2683,16 +2759,16 @@ public final class OomAdjuster { } } } - app.reportedInteraction = isInteraction; + state.setReportedInteraction(isInteraction); if (!isInteraction) { - app.setInteractionEventTime(0); + state.setInteractionEventTime(0); } } - private void maybeUpdateLastTopTime(ProcessRecord app, long nowUptime) { - if (app.setProcState <= PROCESS_STATE_TOP - && app.getCurProcState() > PROCESS_STATE_TOP) { - app.lastTopTime = nowUptime; + private void maybeUpdateLastTopTime(ProcessStateRecord state, long nowUptime) { + if (state.getSetProcState() <= PROCESS_STATE_TOP + && state.getCurProcState() > PROCESS_STATE_TOP) { + state.setLastTopTime(nowUptime); } } @@ -2714,13 +2790,15 @@ public final class OomAdjuster { } for (int i = N - 1; i >= 0; i--) { final UidRecord uidRec = mActiveUids.valueAt(i); - final long bgTime = uidRec.lastBackgroundTime; - if (bgTime > 0 && !uidRec.idle) { + final long bgTime = uidRec.getLastBackgroundTime(); + if (bgTime > 0 && !uidRec.isIdle()) { if (bgTime <= maxBgTime) { - EventLogTags.writeAmUidIdle(uidRec.uid); - uidRec.idle = true; - uidRec.setIdle = true; - mService.doStopUidLocked(uidRec.uid, uidRec); + EventLogTags.writeAmUidIdle(uidRec.getUid()); + synchronized (mProcLock) { + uidRec.setIdle(true); + uidRec.setSetIdle(true); + } + mService.doStopUidLocked(uidRec.getUid(), uidRec); } else { if (nextTime == 0 || nextTime > bgTime) { nextTime = bgTime; @@ -2738,35 +2816,35 @@ public final class OomAdjuster { } } - @GuardedBy("mService") - void setAppIdTempAllowlistStateLocked(int uid, boolean onAllowlist) { + @GuardedBy({"mService", "mProcLock"}) + void setAppIdTempAllowlistStateLSP(int uid, boolean onAllowlist) { boolean changed = false; for (int i = mActiveUids.size() - 1; i >= 0; i--) { final UidRecord uidRec = mActiveUids.valueAt(i); - if (uidRec.uid == uid && uidRec.mCurAllowlist != onAllowlist) { - uidRec.mCurAllowlist = onAllowlist; + if (uidRec.getUid() == uid && uidRec.isCurAllowListed() != onAllowlist) { + uidRec.setCurAllowListed(onAllowlist); changed = true; } } if (changed) { - updateOomAdjLocked(OOM_ADJ_REASON_ALLOWLIST); + updateOomAdjLSP(OOM_ADJ_REASON_ALLOWLIST); } } - @GuardedBy("mService") - void setUidTempAllowlistStateLocked(int uid, boolean onAllowlist) { + @GuardedBy({"mService", "mProcLock"}) + void setUidTempAllowlistStateLSP(int uid, boolean onAllowlist) { boolean changed = false; final UidRecord uidRec = mActiveUids.get(uid); - if (uidRec != null && uidRec.mCurAllowlist != onAllowlist) { - uidRec.mCurAllowlist = onAllowlist; - updateOomAdjLocked(OOM_ADJ_REASON_ALLOWLIST); + if (uidRec != null && uidRec.isCurAllowListed() != onAllowlist) { + uidRec.setCurAllowListed(onAllowlist); + updateOomAdjLSP(OOM_ADJ_REASON_ALLOWLIST); } } @GuardedBy("mService") void dumpProcessListVariablesLocked(ProtoOutputStream proto) { proto.write(ActivityManagerServiceDumpProcessesProto.ADJ_SEQ, mAdjSeq); - proto.write(ActivityManagerServiceDumpProcessesProto.LRU_SEQ, mProcessList.mLruSeq); + proto.write(ActivityManagerServiceDumpProcessesProto.LRU_SEQ, mProcessList.getLruSeqLOSP()); proto.write(ActivityManagerServiceDumpProcessesProto.NUM_NON_CACHED_PROCS, mNumNonCachedProcs); proto.write(ActivityManagerServiceDumpProcessesProto.NUM_SERVICE_PROCS, mNumServiceProcs); @@ -2777,19 +2855,19 @@ public final class OomAdjuster { @GuardedBy("mService") void dumpSequenceNumbersLocked(PrintWriter pw) { - pw.println(" mAdjSeq=" + mAdjSeq + " mLruSeq=" + mProcessList.mLruSeq); + pw.println(" mAdjSeq=" + mAdjSeq + " mLruSeq=" + mProcessList.getLruSeqLOSP()); } @GuardedBy("mService") void dumpProcCountsLocked(PrintWriter pw) { pw.println(" mNumNonCachedProcs=" + mNumNonCachedProcs - + " (" + mProcessList.getLruSizeLocked() + " total)" + + " (" + mProcessList.getLruSizeLOSP() + " total)" + " mNumCachedHiddenProcs=" + mNumCachedHiddenProcs + " mNumServiceProcs=" + mNumServiceProcs + " mNewNumServiceProcs=" + mNewNumServiceProcs); } - @GuardedBy("mService") + @GuardedBy("mProcLock") void dumpCachedAppOptimizerSettings(PrintWriter pw) { mCachedAppOptimizer.dump(pw); } @@ -2799,22 +2877,25 @@ public final class OomAdjuster { mCacheOomRanker.dump(pw); } - @GuardedBy("mService") - void updateAppFreezeStateLocked(ProcessRecord app) { + @GuardedBy({"mService", "mProcLock"}) + private void updateAppFreezeStateLSP(ProcessRecord app) { if (!mCachedAppOptimizer.useFreezer()) { return; } + final ProcessCachedOptimizerRecord opt = app.mOptRecord; // if an app is already frozen and shouldNotFreeze becomes true, immediately unfreeze - if (app.frozen && app.shouldNotFreeze) { - mCachedAppOptimizer.unfreezeAppLocked(app); + if (opt.isFrozen() && opt.shouldNotFreeze()) { + mCachedAppOptimizer.unfreezeAppLSP(app); } + final ProcessStateRecord state = app.mState; // Use current adjustment when freezing, set adjustment when unfreezing. - if (app.curAdj >= ProcessList.CACHED_APP_MIN_ADJ && !app.frozen && !app.shouldNotFreeze) { - mCachedAppOptimizer.freezeAppAsync(app); - } else if (app.setAdj < ProcessList.CACHED_APP_MIN_ADJ && app.frozen) { - mCachedAppOptimizer.unfreezeAppLocked(app); + if (state.getCurAdj() >= ProcessList.CACHED_APP_MIN_ADJ && !opt.isFrozen() + && !opt.shouldNotFreeze()) { + mCachedAppOptimizer.freezeAppAsyncLSP(app); + } else if (state.getSetAdj() < ProcessList.CACHED_APP_MIN_ADJ && opt.isFrozen()) { + mCachedAppOptimizer.unfreezeAppLSP(app); } } } diff --git a/services/core/java/com/android/server/am/PackageList.java b/services/core/java/com/android/server/am/PackageList.java index 978bcb7afee45..aa10d52eb48c8 100644 --- a/services/core/java/com/android/server/am/PackageList.java +++ b/services/core/java/com/android/server/am/PackageList.java @@ -16,6 +16,7 @@ package com.android.server.am; +import android.annotation.NonNull; import android.content.pm.VersionedPackage; import android.util.ArrayMap; @@ -73,7 +74,7 @@ final class PackageList { } } - void forEachPackage(Consumer callback) { + void forEachPackage(@NonNull Consumer callback) { synchronized (this) { for (int i = 0, size = mPkgList.size(); i < size; i++) { callback.accept(mPkgList.keyAt(i)); @@ -81,7 +82,7 @@ final class PackageList { } } - void forEachPackage(BiConsumer callback) { + void forEachPackage(@NonNull BiConsumer callback) { synchronized (this) { for (int i = 0, size = mPkgList.size(); i < size; i++) { callback.accept(mPkgList.keyAt(i), mPkgList.valueAt(i)); @@ -89,7 +90,16 @@ final class PackageList { } } - R forEachPackage(Function callback) { + /** + * Search in the package list, invoke the given {@code callback} with each of the package names + * in that list; if the callback returns a non-null object, halt the search, return that + * object as the return value of this search function. + * + * @param callback The callback interface to accept the current package name; if it returns + * a non-null object, the search will be halted and this object will be used + * as the return value of this search function. + */ + R searchEachPackage(@NonNull Function callback) { synchronized (this) { for (int i = 0, size = mPkgList.size(); i < size; i++) { R r = callback.apply(mPkgList.keyAt(i)); @@ -101,7 +111,7 @@ final class PackageList { return null; } - void forEachPackageProcessStats(Consumer callback) { + void forEachPackageProcessStats(@NonNull Consumer callback) { synchronized (this) { for (int i = 0, size = mPkgList.size(); i < size; i++) { callback.accept(mPkgList.valueAt(i)); diff --git a/services/core/java/com/android/server/am/PhantomProcessList.java b/services/core/java/com/android/server/am/PhantomProcessList.java index 37b17411dac58..4f3438fe8706a 100644 --- a/services/core/java/com/android/server/am/PhantomProcessList.java +++ b/services/core/java/com/android/server/am/PhantomProcessList.java @@ -148,13 +148,14 @@ public final class PhantomProcessList { @GuardedBy({"mLock", "mService.mPidsSelfLocked"}) private void lookForPhantomProcessesLocked(ProcessRecord app) { - if (app.appZygote || app.killed || app.killedByAm) { + if (app.appZygote || app.isKilled() || app.isKilledByAm()) { // process forked from app zygote doesn't have its own acct entry return; } - InputStream input = mCgroupProcsFds.get(app.pid); + final int appPid = app.getPid(); + InputStream input = mCgroupProcsFds.get(appPid); if (input == null) { - final String path = getCgroupFilePath(app.info.uid, app.pid); + final String path = getCgroupFilePath(app.info.uid, appPid); try { input = mInjector.openCgroupProcs(path); } catch (FileNotFoundException | SecurityException e) { @@ -164,7 +165,7 @@ public final class PhantomProcessList { return; } // Keep the FD open for better performance - mCgroupProcsFds.put(app.pid, input); + mCgroupProcsFds.put(appPid, input); } final byte[] buf = mDataBuffer; try { @@ -180,7 +181,7 @@ public final class PhantomProcessList { for (int i = 0; i < read; i++) { final byte b = buf[i]; if (b == '\n') { - addChildPidLocked(app, pid); + addChildPidLocked(app, pid, appPid); pid = 0; } else { pid = pid * 10 + (b - '0'); @@ -193,14 +194,14 @@ public final class PhantomProcessList { } } while (true); if (pid != 0) { - addChildPidLocked(app, pid); + addChildPidLocked(app, pid, appPid); } // rewind the fd for the next read input.skip(-totalRead); } catch (IOException e) { Slog.e(TAG, "Error in reading cgroup procs from " + app, e); IoUtils.closeQuietly(input); - mCgroupProcsFds.delete(app.pid); + mCgroupProcsFds.delete(appPid); } } @@ -232,8 +233,8 @@ public final class PhantomProcessList { } @GuardedBy({"mLock", "mService.mPidsSelfLocked"}) - private void addChildPidLocked(final ProcessRecord app, final int pid) { - if (app.pid != pid) { + private void addChildPidLocked(final ProcessRecord app, final int pid, final int appPid) { + if (appPid != pid) { // That's something else... final ProcessRecord r = mService.mPidsSelfLocked.get(pid); if (r != null) { @@ -328,15 +329,16 @@ public final class PhantomProcessList { if (r != null) { // It's a phantom process, bookkeep it try { + final int appPid = r.getPid(); final PhantomProcessRecord proc = new PhantomProcessRecord( - processName, uid, pid, r.pid, mService, + processName, uid, pid, appPid, mService, this::onPhantomProcessKilledLocked); proc.mUpdateSeq = mUpdateSeq; mPhantomProcesses.put(pid, proc); - SparseArray array = mAppPhantomProcessMap.get(r.pid); + SparseArray array = mAppPhantomProcessMap.get(appPid); if (array == null) { array = new SparseArray<>(); - mAppPhantomProcessMap.put(r.pid, array); + mAppPhantomProcessMap.put(appPid, array); } array.put(pid, proc); if (proc.mPidFd != null) { @@ -414,40 +416,42 @@ public final class PhantomProcessList { * order of the oom adjs of their parent process. */ void trimPhantomProcessesIfNecessary() { - synchronized (mLock) { - mTrimPhantomProcessScheduled = false; - if (mService.mConstants.MAX_PHANTOM_PROCESSES < mPhantomProcesses.size()) { - for (int i = mPhantomProcesses.size() - 1; i >= 0; i--) { - mTempPhantomProcesses.add(mPhantomProcesses.valueAt(i)); + synchronized (mService.mProcLock) { + synchronized (mLock) { + mTrimPhantomProcessScheduled = false; + if (mService.mConstants.MAX_PHANTOM_PROCESSES < mPhantomProcesses.size()) { + for (int i = mPhantomProcesses.size() - 1; i >= 0; i--) { + mTempPhantomProcesses.add(mPhantomProcesses.valueAt(i)); + } + synchronized (mService.mPidsSelfLocked) { + Collections.sort(mTempPhantomProcesses, (a, b) -> { + final ProcessRecord ra = mService.mPidsSelfLocked.get(a.mPpid); + if (ra == null) { + // parent is gone, this process should have been killed too + return 1; + } + final ProcessRecord rb = mService.mPidsSelfLocked.get(b.mPpid); + if (rb == null) { + // parent is gone, this process should have been killed too + return -1; + } + if (ra.mState.getCurAdj() != rb.mState.getCurAdj()) { + return ra.mState.getCurAdj() - rb.mState.getCurAdj(); + } + if (a.mKnownSince != b.mKnownSince) { + // In case of identical oom adj, younger one first + return a.mKnownSince < b.mKnownSince ? 1 : -1; + } + return 0; + }); + } + for (int i = mTempPhantomProcesses.size() - 1; + i >= mService.mConstants.MAX_PHANTOM_PROCESSES; i--) { + final PhantomProcessRecord proc = mTempPhantomProcesses.get(i); + proc.killLocked("Trimming phantom processes", true); + } + mTempPhantomProcesses.clear(); } - synchronized (mService.mPidsSelfLocked) { - Collections.sort(mTempPhantomProcesses, (a, b) -> { - final ProcessRecord ra = mService.mPidsSelfLocked.get(a.mPpid); - if (ra == null) { - // parent is gone, this process should have been killed too - return 1; - } - final ProcessRecord rb = mService.mPidsSelfLocked.get(b.mPpid); - if (rb == null) { - // parent is gone, this process should have been killed too - return -1; - } - if (ra.curAdj != rb.curAdj) { - return ra.curAdj - rb.curAdj; - } - if (a.mKnownSince != b.mKnownSince) { - // In case of identical oom adj, younger one first - return a.mKnownSince < b.mKnownSince ? 1 : -1; - } - return 0; - }); - } - for (int i = mTempPhantomProcesses.size() - 1; - i >= mService.mConstants.MAX_PHANTOM_PROCESSES; i--) { - final PhantomProcessRecord proc = mTempPhantomProcesses.get(i); - proc.killLocked("Trimming phantom processes", true); - } - mTempPhantomProcesses.clear(); } } } @@ -498,7 +502,7 @@ public final class PhantomProcessList { } } // Lastly, kill the parent process too - app.kill("Caused by child process: " + msg, reasonCode, subReason, true); + app.killLocked("Caused by child process: " + msg, reasonCode, subReason, true); } /** @@ -508,7 +512,7 @@ public final class PhantomProcessList { void forEachPhantomProcessOfApp(final ProcessRecord app, final Function callback) { synchronized (mLock) { - int index = mAppPhantomProcessMap.indexOfKey(app.pid); + int index = mAppPhantomProcessMap.indexOfKey(app.getPid()); if (index >= 0) { final SparseArray array = mAppPhantomProcessMap.valueAt(index); diff --git a/services/core/java/com/android/server/am/ProcessCachedOptimizerRecord.java b/services/core/java/com/android/server/am/ProcessCachedOptimizerRecord.java new file mode 100644 index 0000000000000..464361076dc80 --- /dev/null +++ b/services/core/java/com/android/server/am/ProcessCachedOptimizerRecord.java @@ -0,0 +1,157 @@ +/* + * 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 com.android.internal.annotations.GuardedBy; + +import java.io.PrintWriter; + +/** + * The state info of app when it's cached, used by the optimizer. + */ +final class ProcessCachedOptimizerRecord { + private final ProcessRecord mApp; + + private final ActivityManagerGlobalLock mProcLock; + + /** + * The last time that this process was compacted. + */ + @GuardedBy("mProcLock") + private long mLastCompactTime; + + /** + * The most recent compaction action requested for this app. + */ + @GuardedBy("mProcLock") + private int mReqCompactAction; + + /** + * The most recent compaction action performed for this app. + */ + @GuardedBy("mProcLock") + private int mLastCompactAction; + + /** + * True when the process is frozen. + */ + @GuardedBy("mProcLock") + private boolean mFrozen; + + /** + * An override on the freeze state is in progress. + */ + @GuardedBy("mProcLock") + boolean mFreezerOverride; + + /** + * Last time the app was (un)frozen, 0 for never. + */ + @GuardedBy("mProcLock") + private long mFreezeUnfreezeTime; + + /** + * True if a process has a WPRI binding from an unfrozen process. + */ + @GuardedBy("mProcLock") + private boolean mShouldNotFreeze; + + @GuardedBy("mProcLock") + long getLastCompactTime() { + return mLastCompactTime; + } + + @GuardedBy("mProcLock") + void setLastCompactTime(long lastCompactTime) { + mLastCompactTime = lastCompactTime; + } + + @GuardedBy("mProcLock") + int getReqCompactAction() { + return mReqCompactAction; + } + + @GuardedBy("mProcLock") + void setReqCompactAction(int reqCompactAction) { + mReqCompactAction = reqCompactAction; + } + + @GuardedBy("mProcLock") + int getLastCompactAction() { + return mLastCompactAction; + } + + @GuardedBy("mProcLock") + void setLastCompactAction(int lastCompactAction) { + mLastCompactAction = lastCompactAction; + } + + @GuardedBy("mProcLock") + boolean isFrozen() { + return mFrozen; + } + + @GuardedBy("mProcLock") + void setFrozen(boolean frozen) { + mFrozen = frozen; + } + + @GuardedBy("mProcLock") + boolean hasFreezerOverride() { + return mFreezerOverride; + } + + @GuardedBy("mProcLock") + void setFreezerOverride(boolean freezerOverride) { + mFreezerOverride = freezerOverride; + } + + @GuardedBy("mProcLock") + long getFreezeUnfreezeTime() { + return mFreezeUnfreezeTime; + } + + @GuardedBy("mProcLock") + void setFreezeUnfreezeTime(long freezeUnfreezeTime) { + mFreezeUnfreezeTime = freezeUnfreezeTime; + } + + @GuardedBy("mProcLock") + boolean shouldNotFreeze() { + return mShouldNotFreeze; + } + + @GuardedBy("mProcLock") + void setShouldNotFreeze(boolean shouldNotFreeze) { + mShouldNotFreeze = shouldNotFreeze; + } + + ProcessCachedOptimizerRecord(ProcessRecord app) { + mApp = app; + mProcLock = app.mService.mProcLock; + } + + void init(long nowUptime) { + mFreezeUnfreezeTime = nowUptime; + } + + @GuardedBy("mProcLock") + void dump(PrintWriter pw, String prefix, long nowUptime) { + pw.print(prefix); pw.print("lastCompactTime="); pw.print(mLastCompactTime); + pw.print(" lastCompactAction="); pw.println(mLastCompactAction); + } +} diff --git a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java new file mode 100644 index 0000000000000..64e307a5f1820 --- /dev/null +++ b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java @@ -0,0 +1,555 @@ +/* + * 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 com.android.server.Watchdog.NATIVE_STACKS_OF_INTEREST; +import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ANR; +import static com.android.server.am.ActivityManagerService.MY_PID; +import static com.android.server.am.ProcessRecord.TAG; + +import android.app.ActivityManager; +import android.app.ApplicationErrorReport; +import android.app.ApplicationExitInfo; +import android.content.ComponentName; +import android.content.pm.ApplicationInfo; +import android.content.pm.IncrementalStatesInfo; +import android.content.pm.PackageManagerInternal; +import android.os.Message; +import android.os.Process; +import android.os.SystemClock; +import android.provider.Settings; +import android.util.EventLog; +import android.util.Slog; +import android.util.SparseArray; + +import com.android.internal.annotations.CompositeRWLock; +import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.os.ProcessCpuTracker; +import com.android.internal.util.FrameworkStatsLog; +import com.android.server.MemoryPressureUtil; +import com.android.server.wm.WindowProcessController; + +import java.io.File; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.ArrayList; + +/** + * The error state of the process, such as if it's crashing/ANR etc. + */ +class ProcessErrorStateRecord { + final ProcessRecord mApp; + private final ActivityManagerService mService; + + private final ActivityManagerGlobalLock mProcLock; + + /** + * True if disabled in the bad process list. + */ + @CompositeRWLock({"mService", "mProcLock"}) + private boolean mBad; + + /** + * Are we in the process of crashing? + */ + @CompositeRWLock({"mService", "mProcLock"}) + private boolean mCrashing; + + /** + * Suppress normal auto-dismiss of crash dialog & report UI? + */ + @CompositeRWLock({"mService", "mProcLock"}) + private boolean mForceCrashReport; + + /** + * Does the app have a not responding dialog? + */ + @CompositeRWLock({"mService", "mProcLock"}) + private boolean mNotResponding; + + /** + * The report about crash of the app, generated & stored when an app gets into a crash. + * Will be "null" when all is OK. + */ + @CompositeRWLock({"mService", "mProcLock"}) + private ActivityManager.ProcessErrorStateInfo mCrashingReport; + + /** + * The report about ANR of the app, generated & stored when an app gets into an ANR. + * Will be "null" when all is OK. + */ + @CompositeRWLock({"mService", "mProcLock"}) + private ActivityManager.ProcessErrorStateInfo mNotRespondingReport; + + /** + * Controller for error dialogs. + */ + @CompositeRWLock({"mService", "mProcLock"}) + private final ErrorDialogController mDialogController; + + /** + * Who will be notified of the error. This is usually an activity in the + * app that installed the package. + */ + @CompositeRWLock({"mService", "mProcLock"}) + private ComponentName mErrorReportReceiver; + + /** + * Optional local handler to be invoked in the process crash. + */ + @CompositeRWLock({"mService", "mProcLock"}) + private Runnable mCrashHandler; + + @GuardedBy(anyOf = {"mService", "mProcLock"}) + boolean isBad() { + return mBad; + } + + @GuardedBy({"mService", "mProcLock"}) + void setBad(boolean bad) { + mBad = bad; + } + + @GuardedBy(anyOf = {"mService", "mProcLock"}) + boolean isCrashing() { + return mCrashing; + } + + @GuardedBy({"mService", "mProcLock"}) + void setCrashing(boolean crashing) { + mCrashing = crashing; + mApp.getWindowProcessController().setCrashing(crashing); + } + + @GuardedBy(anyOf = {"mService", "mProcLock"}) + boolean isForceCrashReport() { + return mForceCrashReport; + } + + @GuardedBy({"mService", "mProcLock"}) + void setForceCrashReport(boolean forceCrashReport) { + mForceCrashReport = forceCrashReport; + } + + @GuardedBy(anyOf = {"mService", "mProcLock"}) + boolean isNotResponding() { + return mNotResponding; + } + + @GuardedBy({"mService", "mProcLock"}) + void setNotResponding(boolean notResponding) { + mNotResponding = notResponding; + mApp.getWindowProcessController().setNotResponding(notResponding); + } + + @GuardedBy(anyOf = {"mService", "mProcLock"}) + Runnable getCrashHandler() { + return mCrashHandler; + } + + @GuardedBy({"mService", "mProcLock"}) + void setCrashHandler(Runnable crashHandler) { + mCrashHandler = crashHandler; + } + + @GuardedBy(anyOf = {"mService", "mProcLock"}) + ActivityManager.ProcessErrorStateInfo getCrashingReport() { + return mCrashingReport; + } + + @GuardedBy({"mService", "mProcLock"}) + void setCrashingReport(ActivityManager.ProcessErrorStateInfo crashingReport) { + mCrashingReport = crashingReport; + } + + @GuardedBy(anyOf = {"mService", "mProcLock"}) + ActivityManager.ProcessErrorStateInfo getNotRespondingReport() { + return mNotRespondingReport; + } + + @GuardedBy({"mService", "mProcLock"}) + void setNotRespondingReport(ActivityManager.ProcessErrorStateInfo notRespondingReport) { + mNotRespondingReport = notRespondingReport; + } + + @GuardedBy(anyOf = {"mService", "mProcLock"}) + ComponentName getErrorReportReceiver() { + return mErrorReportReceiver; + } + + @GuardedBy({"mService", "mProcLock"}) + void setErrorReportReceiver(ComponentName errorReportReceiver) { + mErrorReportReceiver = errorReportReceiver; + } + + @GuardedBy(anyOf = {"mService", "mProcLock"}) + ErrorDialogController getDialogController() { + return mDialogController; + } + + ProcessErrorStateRecord(ProcessRecord app) { + mApp = app; + mService = app.mService; + mProcLock = mService.mProcLock; + mDialogController = new ErrorDialogController(app); + } + + void appNotResponding(String activityShortComponentName, ApplicationInfo aInfo, + String parentShortComponentName, WindowProcessController parentProcess, + boolean aboveSystem, String annotation, boolean onlyDumpSelf) { + ArrayList firstPids = new ArrayList<>(5); + SparseArray lastPids = new SparseArray<>(20); + + mApp.getWindowProcessController().appEarlyNotResponding(annotation, () -> { + synchronized (mService) { + mApp.killLocked("anr", ApplicationExitInfo.REASON_ANR, true); + } + }); + + long anrTime = SystemClock.uptimeMillis(); + if (isMonitorCpuUsage()) { + mService.updateCpuStatsNow(); + } + + final boolean isSilentAnr; + final int pid = mApp.getPid(); + synchronized (mService) { + // PowerManager.reboot() can block for a long time, so ignore ANRs while shutting down. + if (mService.mAtmInternal.isShuttingDown()) { + Slog.i(TAG, "During shutdown skipping ANR: " + this + " " + annotation); + return; + } else if (isNotResponding()) { + Slog.i(TAG, "Skipping duplicate ANR: " + this + " " + annotation); + return; + } else if (isCrashing()) { + Slog.i(TAG, "Crashing app skipping ANR: " + this + " " + annotation); + return; + } else if (mApp.isKilledByAm()) { + Slog.i(TAG, "App already killed by AM skipping ANR: " + this + " " + annotation); + return; + } else if (mApp.isKilled()) { + Slog.i(TAG, "Skipping died app ANR: " + this + " " + annotation); + return; + } + + // In case we come through here for the same app before completing + // this one, mark as anring now so we will bail out. + synchronized (mProcLock) { + setNotResponding(true); + } + + // Log the ANR to the event log. + EventLog.writeEvent(EventLogTags.AM_ANR, mApp.userId, pid, mApp.processName, + mApp.info.flags, annotation); + + // Dump thread traces as quickly as we can, starting with "interesting" processes. + firstPids.add(pid); + + // Don't dump other PIDs if it's a background ANR or is requested to only dump self. + isSilentAnr = isSilentAnr(); + if (!isSilentAnr && !onlyDumpSelf) { + int parentPid = pid; + if (parentProcess != null && parentProcess.getPid() > 0) { + parentPid = parentProcess.getPid(); + } + if (parentPid != pid) firstPids.add(parentPid); + + if (MY_PID != pid && MY_PID != parentPid) firstPids.add(MY_PID); + + final int ppid = parentPid; + mService.mProcessList.forEachLruProcessesLOSP(false, r -> { + if (r != null && r.getThread() != null) { + int myPid = r.getPid(); + if (myPid > 0 && myPid != pid && myPid != ppid && myPid != MY_PID) { + if (r.isPersistent()) { + firstPids.add(myPid); + if (DEBUG_ANR) Slog.i(TAG, "Adding persistent proc: " + r); + } else if (r.mServices.isTreatedLikeActivity()) { + firstPids.add(myPid); + if (DEBUG_ANR) Slog.i(TAG, "Adding likely IME: " + r); + } else { + lastPids.put(myPid, Boolean.TRUE); + if (DEBUG_ANR) Slog.i(TAG, "Adding ANR proc: " + r); + } + } + } + }); + } + } + + // Check if package is still being loaded + boolean isPackageLoading = false; + final PackageManagerInternal packageManagerInternal = mService.getPackageManagerInternal(); + if (aInfo != null && aInfo.packageName != null) { + IncrementalStatesInfo incrementalStatesInfo = + packageManagerInternal.getIncrementalStatesInfo( + aInfo.packageName, mApp.uid, mApp.userId); + if (incrementalStatesInfo != null) { + isPackageLoading = incrementalStatesInfo.isLoading(); + } + } + + // Log the ANR to the main log. + StringBuilder info = new StringBuilder(); + info.setLength(0); + info.append("ANR in ").append(mApp.processName); + if (activityShortComponentName != null) { + info.append(" (").append(activityShortComponentName).append(")"); + } + info.append("\n"); + info.append("PID: ").append(pid).append("\n"); + if (annotation != null) { + info.append("Reason: ").append(annotation).append("\n"); + } + if (parentShortComponentName != null + && parentShortComponentName.equals(activityShortComponentName)) { + info.append("Parent: ").append(parentShortComponentName).append("\n"); + } + + if (isPackageLoading) { + // Report in the main log that the package is still loading + final float loadingProgress = packageManagerInternal.getIncrementalStatesInfo( + aInfo.packageName, mApp.uid, mApp.userId).getProgress(); + info.append("Package is ").append((int) (loadingProgress * 100)).append("% loaded.\n"); + } + + StringBuilder report = new StringBuilder(); + report.append(MemoryPressureUtil.currentPsiState()); + ProcessCpuTracker processCpuTracker = new ProcessCpuTracker(true); + + // don't dump native PIDs for background ANRs unless it is the process of interest + String[] nativeProcs = null; + if (isSilentAnr || onlyDumpSelf) { + for (int i = 0; i < NATIVE_STACKS_OF_INTEREST.length; i++) { + if (NATIVE_STACKS_OF_INTEREST[i].equals(mApp.processName)) { + nativeProcs = new String[] { mApp.processName }; + break; + } + } + } else { + nativeProcs = NATIVE_STACKS_OF_INTEREST; + } + + int[] pids = nativeProcs == null ? null : Process.getPidsForCommands(nativeProcs); + ArrayList nativePids = null; + + if (pids != null) { + nativePids = new ArrayList<>(pids.length); + for (int i : pids) { + nativePids.add(i); + } + } + + // For background ANRs, don't pass the ProcessCpuTracker to + // avoid spending 1/2 second collecting stats to rank lastPids. + StringWriter tracesFileException = new StringWriter(); + // To hold the start and end offset to the ANR trace file respectively. + final long[] offsets = new long[2]; + File tracesFile = ActivityManagerService.dumpStackTraces(firstPids, + isSilentAnr ? null : processCpuTracker, isSilentAnr ? null : lastPids, + nativePids, tracesFileException, offsets); + + if (isMonitorCpuUsage()) { + mService.updateCpuStatsNow(); + mService.mAppProfiler.printCurrentCpuState(report, anrTime); + info.append(processCpuTracker.printCurrentLoad()); + info.append(report); + } + report.append(tracesFileException.getBuffer()); + + info.append(processCpuTracker.printCurrentState(anrTime)); + + Slog.e(TAG, info.toString()); + if (tracesFile == null) { + // There is no trace file, so dump (only) the alleged culprit's threads to the log + Process.sendSignal(pid, Process.SIGNAL_QUIT); + } else if (offsets[1] > 0) { + // We've dumped into the trace file successfully + mService.mProcessList.mAppExitInfoTracker.scheduleLogAnrTrace( + pid, mApp.uid, mApp.getPackageList(), tracesFile, offsets[0], offsets[1]); + } + + FrameworkStatsLog.write(FrameworkStatsLog.ANR_OCCURRED, mApp.uid, mApp.processName, + activityShortComponentName == null ? "unknown" : activityShortComponentName, + annotation, + (mApp.info != null) ? (mApp.info.isInstantApp() + ? FrameworkStatsLog.ANROCCURRED__IS_INSTANT_APP__TRUE + : FrameworkStatsLog.ANROCCURRED__IS_INSTANT_APP__FALSE) + : FrameworkStatsLog.ANROCCURRED__IS_INSTANT_APP__UNAVAILABLE, + mApp.isInterestingToUserLocked() + ? FrameworkStatsLog.ANROCCURRED__FOREGROUND_STATE__FOREGROUND + : FrameworkStatsLog.ANROCCURRED__FOREGROUND_STATE__BACKGROUND, + mApp.getProcessClassEnum(), + (mApp.info != null) ? mApp.info.packageName : "", isPackageLoading); + final ProcessRecord parentPr = parentProcess != null + ? (ProcessRecord) parentProcess.mOwner : null; + mService.addErrorToDropBox("anr", mApp, mApp.processName, activityShortComponentName, + parentShortComponentName, parentPr, annotation, report.toString(), tracesFile, + null); + + if (mApp.getWindowProcessController().appNotResponding(info.toString(), + () -> { + synchronized (mService) { + mApp.killLocked("anr", ApplicationExitInfo.REASON_ANR, true); + } + }, + () -> { + synchronized (mService) { + mService.mServices.scheduleServiceTimeoutLocked(mApp); + } + })) { + return; + } + + synchronized (mService) { + // mBatteryStatsService can be null if the AMS is constructed with injector only. This + // will only happen in tests. + if (mService.mBatteryStatsService != null) { + mService.mBatteryStatsService.noteProcessAnr(mApp.processName, mApp.uid); + } + + if (isSilentAnr() && !mApp.isDebugging()) { + mApp.killLocked("bg anr", ApplicationExitInfo.REASON_ANR, true); + return; + } + + synchronized (mProcLock) { + // Set the app's notResponding state, and look up the errorReportReceiver + makeAppNotRespondingLSP(activityShortComponentName, + annotation != null ? "ANR " + annotation : "ANR", info.toString()); + } + + // Notify package manager service to possibly update package state + if (aInfo != null && aInfo.packageName != null) { + packageManagerInternal.notifyPackageCrashOrAnr(aInfo.packageName); + } + + // mUiHandler can be null if the AMS is constructed with injector only. This will only + // happen in tests. + if (mService.mUiHandler != null) { + // Bring up the infamous App Not Responding dialog + Message msg = Message.obtain(); + msg.what = ActivityManagerService.SHOW_NOT_RESPONDING_UI_MSG; + msg.obj = new AppNotRespondingDialog.Data(mApp, aInfo, aboveSystem); + + mService.mUiHandler.sendMessage(msg); + } + } + } + + @GuardedBy({"mService", "mProcLock"}) + private void makeAppNotRespondingLSP(String activity, String shortMsg, String longMsg) { + setNotResponding(true); + // mAppErrors can be null if the AMS is constructed with injector only. This will only + // happen in tests. + if (mService.mAppErrors != null) { + mNotRespondingReport = mService.mAppErrors.generateProcessError(mApp, + ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING, + activity, shortMsg, longMsg, null); + } + startAppProblemLSP(); + mApp.getWindowProcessController().stopFreezingActivities(); + } + + @GuardedBy({"mService", "mProcLock"}) + void startAppProblemLSP() { + // If this app is not running under the current user, then we can't give it a report button + // because that would require launching the report UI under a different user. + mErrorReportReceiver = null; + + for (int userId : mService.mUserController.getCurrentProfileIds()) { + if (mApp.userId == userId) { + mErrorReportReceiver = ApplicationErrorReport.getErrorReportReceiver( + mService.mContext, mApp.info.packageName, mApp.info.flags); + } + } + mService.skipCurrentReceiverLocked(mApp); + } + + @GuardedBy("mService") + private boolean isInterestingForBackgroundTraces() { + // The system_server is always considered interesting. + if (mApp.getPid() == MY_PID) { + return true; + } + + // A package is considered interesting if any of the following is true : + // + // - It's displaying an activity. + // - It's the SystemUI. + // - It has an overlay or a top UI visible. + // + // NOTE: The check whether a given ProcessRecord belongs to the systemui + // process is a bit of a kludge, but the same pattern seems repeated at + // several places in the system server. + return mApp.isInterestingToUserLocked() + || (mApp.info != null && "com.android.systemui".equals(mApp.info.packageName)) + || (mApp.mState.hasTopUi() || mApp.mState.hasOverlayUi()); + } + + private boolean getShowBackground() { + return Settings.Secure.getInt(mService.mContext.getContentResolver(), + Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0; + } + + /** + * Unless configured otherwise, swallow ANRs in background processes & kill the process. + * Non-private access is for tests only. + */ + @VisibleForTesting + @GuardedBy("mService") + boolean isSilentAnr() { + return !getShowBackground() && !isInterestingForBackgroundTraces(); + } + + /** Non-private access is for tests only. */ + @VisibleForTesting + boolean isMonitorCpuUsage() { + return mService.mAppProfiler.MONITOR_CPU_USAGE; + } + + @GuardedBy({"mService", "mProcLock"}) + void onCleanupApplicationRecordLSP() { + // Dismiss any open dialogs. + getDialogController().clearAllErrorDialogs(); + + setCrashing(false); + setNotResponding(false); + } + + void dump(PrintWriter pw, String prefix, long nowUptime) { + synchronized (mProcLock) { + if (mCrashing || mDialogController.hasCrashDialogs() || mNotResponding + || mDialogController.hasAnrDialogs() || mBad) { + pw.print(prefix); + pw.print(" mCrashing=" + mCrashing); + pw.print(" " + mDialogController.getCrashDialogs()); + pw.print(" mNotResponding=" + mNotResponding); + pw.print(" " + mDialogController.getAnrDialogs()); + pw.print(" bad=" + mBad); + + // mCrashing or mNotResponding is always set before errorReportReceiver + if (mErrorReportReceiver != null) { + pw.print(" errorReportReceiver="); + pw.print(mErrorReportReceiver.flattenToShortString()); + } + pw.println(); + } + } + } +} diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index 8f994591f96c4..81bfde6ecf8e6 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -55,6 +55,7 @@ import static com.android.server.am.ActivityManagerService.TAG_PROCESSES; import static com.android.server.am.ActivityManagerService.TAG_UID_OBSERVERS; import static com.android.server.am.AppProfiler.TAG_PSS; +import android.annotation.NonNull; import android.app.ActivityManager; import android.app.ActivityThread; import android.app.AppGlobals; @@ -114,6 +115,7 @@ import android.util.TimeUtils; import android.util.proto.ProtoOutputStream; import android.view.Display; +import com.android.internal.annotations.CompositeRWLock; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.ProcessMap; @@ -149,6 +151,8 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.function.Consumer; +import java.util.function.Function; /** * Activity manager code dealing with processes. @@ -466,34 +470,41 @@ public final class ProcessList { * List of running applications, sorted by recent usage. * The first entry in the list is the least recently used. */ - final ArrayList mLruProcesses = new ArrayList(); + @CompositeRWLock({"mService", "mProcLock"}) + private final ArrayList mLruProcesses = new ArrayList(); /** * Where in mLruProcesses that the processes hosting activities start. */ - int mLruProcessActivityStart = 0; + @CompositeRWLock({"mService", "mProcLock"}) + private int mLruProcessActivityStart = 0; /** * Where in mLruProcesses that the processes hosting services start. * This is after (lower index) than mLruProcessesActivityStart. */ - int mLruProcessServiceStart = 0; + @CompositeRWLock({"mService", "mProcLock"}) + private int mLruProcessServiceStart = 0; /** * Current sequence id for process LRU updating. */ - int mLruSeq = 0; + @CompositeRWLock({"mService", "mProcLock"}) + private int mLruSeq = 0; + @CompositeRWLock({"mService", "mProcLock"}) ActiveUids mActiveUids; /** * The currently running isolated processes. */ + @GuardedBy("mService") final SparseArray mIsolatedProcesses = new SparseArray<>(); /** * The currently running application zygotes. */ + @GuardedBy("mService") final ProcessMap mAppZygotes = new ProcessMap(); /** @@ -505,6 +516,7 @@ public final class ProcessList { /** * The processes that are forked off an application zygote. */ + @GuardedBy("mService") final ArrayMap> mAppZygoteProcesses = new ArrayMap>(); @@ -532,6 +544,8 @@ public final class ProcessList { */ private final int[] mZygoteSigChldMessage = new int[3]; + ActivityManagerGlobalLock mProcLock; + final class IsolatedUidRange { @VisibleForTesting public final int mFirstUid; @@ -640,6 +654,7 @@ public final class ProcessList { * The available isolated UIDs for processes that are not spawned from an application zygote. */ @VisibleForTesting + @GuardedBy("mService") IsolatedUidRange mGlobalIsolatedUids = new IsolatedUidRange(Process.FIRST_ISOLATED_UID, Process.LAST_ISOLATED_UID); @@ -647,6 +662,7 @@ public final class ProcessList { * An allocator for isolated UID ranges for apps that use an application zygote. */ @VisibleForTesting + @GuardedBy("mService") IsolatedUidRangeAllocator mAppIsolatedUidRangeAllocator = new IsolatedUidRangeAllocator(Process.FIRST_APP_ZYGOTE_ISOLATED_UID, Process.LAST_APP_ZYGOTE_ISOLATED_UID, Process.NUM_UIDS_PER_APP_ZYGOTE); @@ -654,6 +670,7 @@ public final class ProcessList { /** * Processes that are being forcibly torn down. */ + @GuardedBy("mService") final ArrayList mRemovedProcesses = new ArrayList(); // Self locked with the inner lock within the RemoteCallbackList @@ -674,14 +691,14 @@ public final class ProcessList { */ private final Object mProcessChangeLock = new Object(); - /** * All of the applications we currently have running organized by name. * The keys are strings of the application package name (as * returned by the package manager), and the keys are ApplicationRecord * objects. */ - final MyProcessMap mProcessNames = new MyProcessMap(); + @CompositeRWLock({"mService", "mProcLock"}) + private final MyProcessMap mProcessNames = new MyProcessMap(); final class MyProcessMap extends ProcessMap { @Override @@ -749,6 +766,7 @@ public final class ProcessList { mService = service; mActiveUids = activeUids; mPlatformCompat = platformCompat; + mProcLock = service.mProcLock; // Get this after boot, and won't be changed until it's rebooted, as we don't // want some apps enabled while some apps disabled mAppDataIsolationEnabled = @@ -842,13 +860,13 @@ public final class ProcessList { */ Map getProcessesWithPendingBindMounts(int userId) { final Map pidPackageMap = new HashMap<>(); - synchronized (mService) { + synchronized (mProcLock) { for (int i = mLruProcesses.size() - 1; i >= 0; i--) { final ProcessRecord record = mLruProcesses.get(i); - if (record.userId != userId || !record.bindMountPending) { + if (record.userId != userId || !record.isBindMountPending()) { continue; } - final int pid = record.pid; + final int pid = record.getPid(); // It can happen when app process is starting, but zygote work is not done yet so // system does not this pid record yet. if (pid == 0) { @@ -857,8 +875,8 @@ public final class ProcessList { } pidPackageMap.put(pid, record.info.packageName); } - return pidPackageMap; } + return pidPackageMap; } private void updateOomLevels(int displayWidth, int displayHeight, boolean write) { @@ -1534,6 +1552,7 @@ public final class ProcessList { } } + @GuardedBy("mService") final ProcessRecord getProcessRecordLocked(String processName, int uid, boolean keepIfLarge) { if (uid == SYSTEM_UID) { @@ -1554,21 +1573,19 @@ public final class ProcessList { } ProcessRecord proc = mProcessNames.get(processName, uid); if (false && proc != null && !keepIfLarge - && proc.setProcState >= ActivityManager.PROCESS_STATE_CACHED_EMPTY + && proc.mState.getSetProcState() >= ActivityManager.PROCESS_STATE_CACHED_EMPTY && proc.mProfile.getLastCachedPss() >= 4000) { // Turn this condition on to cause killing to happen regularly, for testing. - final long lastCachedPss; synchronized (mService.mAppProfiler.mProfilerLock) { proc.mProfile.reportCachedKill(); - lastCachedPss = proc.mProfile.getLastCachedPss(); } - proc.kill(Long.toString(lastCachedPss) + "k from cached", + proc.killLocked(Long.toString(proc.mProfile.getLastCachedPss()) + "k from cached", ApplicationExitInfo.REASON_OTHER, ApplicationExitInfo.SUBREASON_LARGE_CACHED, true); } else if (proc != null && !keepIfLarge && !mService.mAppProfiler.isLastMemoryLevelNormal() - && proc.setProcState >= ActivityManager.PROCESS_STATE_CACHED_EMPTY) { + && proc.mState.getSetProcState() >= ActivityManager.PROCESS_STATE_CACHED_EMPTY) { final long lastCachedPss; boolean doKilling = false; synchronized (mService.mAppProfiler.mProfilerLock) { @@ -1582,7 +1599,7 @@ public final class ProcessList { Slog.d(TAG_PSS, "May not keep " + proc + ": pss=" + lastCachedPss); } if (doKilling) { - proc.kill(Long.toString(lastCachedPss) + "k from cached", + proc.killLocked(Long.toString(lastCachedPss) + "k from cached", ApplicationExitInfo.REASON_OTHER, ApplicationExitInfo.SUBREASON_LARGE_CACHED, true); @@ -1604,14 +1621,16 @@ public final class ProcessList { outInfo.foregroundAppThreshold = getMemLevel(FOREGROUND_APP_ADJ); } - ProcessRecord findAppProcessLocked(IBinder app, String reason) { + @GuardedBy(anyOf = {"mService", "mProcLock"}) + ProcessRecord findAppProcessLOSP(IBinder app, String reason) { final int NP = mProcessNames.getMap().size(); for (int ip = 0; ip < NP; ip++) { SparseArray apps = mProcessNames.getMap().valueAt(ip); final int NA = apps.size(); for (int ia = 0; ia < NA; ia++) { ProcessRecord p = apps.valueAt(ia); - if (p.thread != null && p.thread.asBinder() == app) { + final IApplicationThread thread = p.getThread(); + if (thread != null && thread.asBinder() == app) { return p; } } @@ -1768,18 +1787,18 @@ public final class ProcessList { @GuardedBy("mService") boolean startProcessLocked(ProcessRecord app, HostingRecord hostingRecord, int zygotePolicyFlags, boolean disableHiddenApiChecks, String abiOverride) { - if (app.pendingStart) { + if (app.isPendingStart()) { return true; } long startTime = SystemClock.uptimeMillis(); - if (app.pid > 0 && app.pid != ActivityManagerService.MY_PID) { + if (app.getPid() > 0 && app.getPid() != ActivityManagerService.MY_PID) { checkSlow(startTime, "startProcess: removing from pids map"); - mService.removePidLocked(app); - app.bindMountPending = false; + mService.removePidLocked(app.getPid(), app); + app.setBindMountPending(false); mService.mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app); checkSlow(startTime, "startProcess: done removing from pids map"); app.setPid(0); - app.startSeq = 0; + app.setStartSeq(0); } if (DEBUG_PROCESSES && mService.mProcessesOnHold.contains(app)) Slog.v( @@ -1834,7 +1853,7 @@ public final class ProcessList { gids = computeGidsForProcess(mountExternal, uid, permGids); } - app.mountMode = mountExternal; + app.setMountMode(mountExternal); checkSlow(startTime, "startProcess: building args"); if (mService.mAtmInternal.isFactoryTestProcess(app.getWindowProcessController())) { uid = 0; @@ -1950,9 +1969,9 @@ public final class ProcessList { instructionSet = VMRuntime.getInstructionSet(requiredAbi); } - app.gids = gids; + app.setGids(gids); app.setRequiredAbi(requiredAbi); - app.instructionSet = instructionSet; + app.setInstructionSet(instructionSet); // If instructionSet is non-null, this indicates that the system_server is spawning a // process with an ISA that may be different from its own. System (kernel and hardware) @@ -2003,23 +2022,26 @@ public final class ProcessList { int uid, int[] gids, int runtimeFlags, int zygotePolicyFlags, int mountExternal, String seInfo, String requiredAbi, String instructionSet, String invokeWith, long startTime) { - app.pendingStart = true; - app.killedByAm = false; - app.removed = false; - app.killed = false; - if (app.startSeq != 0) { - Slog.wtf(TAG, "startProcessLocked processName:" + app.processName - + " with non-zero startSeq:" + app.startSeq); + app.setPendingStart(true); + app.setRemoved(false); + synchronized (mProcLock) { + app.setKilledByAm(false); + app.setKilled(false); } - if (app.pid != 0) { + if (app.getStartSeq() != 0) { Slog.wtf(TAG, "startProcessLocked processName:" + app.processName - + " with non-zero pid:" + app.pid); + + " with non-zero startSeq:" + app.getStartSeq()); } - app.mDisabledCompatChanges = null; + if (app.getPid() != 0) { + Slog.wtf(TAG, "startProcessLocked processName:" + app.processName + + " with non-zero pid:" + app.getPid()); + } + app.setDisabledCompatChanges(null); if (mPlatformCompat != null) { - app.mDisabledCompatChanges = mPlatformCompat.getDisabledChanges(app.info); + app.setDisabledCompatChanges(mPlatformCompat.getDisabledChanges(app.info)); } - final long startSeq = app.startSeq = ++mProcStartSeqCounter; + final long startSeq = ++mProcStartSeqCounter; + app.setStartSeq(startSeq); app.setStartParams(uid, hostingRecord, seInfo, startTime); app.setUsingWrapper(invokeWith != null || Zygote.getWrapProperty(app.processName) != null); @@ -2043,11 +2065,11 @@ public final class ProcessList { } catch (RuntimeException e) { Slog.e(ActivityManagerService.TAG, "Failure starting process " + app.processName, e); - app.pendingStart = false; + app.setPendingStart(false); mService.forceStopPackageLocked(app.info.packageName, UserHandle.getAppId(app.uid), false, false, true, false, false, app.userId, "start failure"); } - return app.pid > 0; + return app.getPid() > 0; } } @@ -2060,11 +2082,11 @@ public final class ProcessList { final int[] gids, final int runtimeFlags, int zygotePolicyFlags, final int mountExternal, final String requiredAbi, final String instructionSet, final String invokeWith, final long startSeq) { - // If there is a precede instance of the process, wait for its death with a timeout. + // If there is a preceding instance of the process, wait for its death with a timeout. // Use local reference since we are not using locks here - final ProcessRecord precedence = app.mPrecedence; - if (precedence != null) { - final int pid = precedence.pid; + final ProcessRecord predecessor = app.mPredecessor; + if (predecessor != null) { + final int pid = predecessor.getPid(); long now = System.currentTimeMillis(); final long end = now + PROC_KILL_TIMEOUT; final int oldPolicy = StrictMode.getThreadPolicyMask(); @@ -2072,34 +2094,34 @@ public final class ProcessList { StrictMode.setThreadPolicyMask(0); Process.waitForProcessDeath(pid, PROC_KILL_TIMEOUT); // It's killed successfully, but we'd make sure the cleanup work is done. - synchronized (precedence) { - if (app.mPrecedence != null) { + synchronized (predecessor) { + if (app.mPredecessor != null) { now = System.currentTimeMillis(); if (now < end) { try { - precedence.wait(end - now); + predecessor.wait(end - now); } catch (InterruptedException e) { } } } - if (app.mPrecedence != null) { + if (app.mPredecessor != null) { // The cleanup work hasn't be done yet, let's log it and continue. - Slog.w(TAG, precedence + " has died, but its cleanup isn't done"); + Slog.w(TAG, predecessor + " has died, but its cleanup isn't done"); } } } catch (Exception e) { // It's still alive... maybe blocked at uninterruptible sleep ? - Slog.wtf(TAG, precedence.toString() + " refused to die, but we need to launch " + Slog.wtf(TAG, predecessor.toString() + " refused to die, but we need to launch " + app, e); } finally { StrictMode.setThreadPolicyMask(oldPolicy); } } try { - final Process.ProcessStartResult startResult = startProcess(app.hostingRecord, - entryPoint, app, app.startUid, gids, runtimeFlags, zygotePolicyFlags, - mountExternal, app.seInfo, requiredAbi, instructionSet, invokeWith, - app.startTime); + final Process.ProcessStartResult startResult = startProcess(app.getHostingRecord(), + entryPoint, app, app.getStartUid(), gids, runtimeFlags, zygotePolicyFlags, + mountExternal, app.getSeInfo(), requiredAbi, instructionSet, invokeWith, + app.getStartTime()); synchronized (mService) { handleProcessStartedLocked(app, startResult, startSeq); @@ -2109,7 +2131,7 @@ public final class ProcessList { Slog.e(ActivityManagerService.TAG, "Failure starting process " + app.processName, e); mPendingStarts.remove(startSeq); - app.pendingStart = false; + app.setPendingStart(false); mService.forceStopPackageLocked(app.info.packageName, UserHandle.getAppId(app.uid), false, false, true, false, false, app.userId, "start failure"); @@ -2135,19 +2157,19 @@ public final class ProcessList { // Free the isolated uid for this process final IsolatedUidRange appUidRange = mAppIsolatedUidRangeAllocator.getIsolatedUidRangeLocked(app.info.processName, - app.hostingRecord.getDefiningUid()); + app.getHostingRecord().getDefiningUid()); if (appUidRange != null) { appUidRange.freeIsolatedUidLocked(app.uid); } final AppZygote appZygote = mAppZygotes.get(app.info.processName, - app.hostingRecord.getDefiningUid()); + app.getHostingRecord().getDefiningUid()); if (appZygote != null) { ArrayList zygoteProcesses = mAppZygoteProcesses.get(appZygote); zygoteProcesses.remove(app); if (zygoteProcesses.size() == 0) { mService.mHandler.removeMessages(KILL_APP_ZYGOTE_MSG); - if (app.removed) { + if (app.isRemoved()) { // If we stopped this process because the package hosting it was removed, // there's no point in delaying the app zygote kill. killAppZygoteIfNeededLocked(appZygote, false /* force */); @@ -2164,7 +2186,7 @@ public final class ProcessList { synchronized (mService) { // The UID for the app zygote should be the UID of the application hosting // the service. - final int uid = app.hostingRecord.getDefiningUid(); + final int uid = app.getHostingRecord().getDefiningUid(); AppZygote appZygote = mAppZygotes.get(app.info.processName, uid); final ArrayList zygoteProcessList; if (appZygote == null) { @@ -2173,7 +2195,7 @@ public final class ProcessList { } final IsolatedUidRange uidRange = mAppIsolatedUidRangeAllocator.getIsolatedUidRangeLocked( - app.info.processName, app.hostingRecord.getDefiningUid()); + app.info.processName, app.getHostingRecord().getDefiningUid()); final int userId = UserHandle.getUserId(uid); // Create the app-zygote and provide it with the UID-range it's allowed // to setresuid/setresgid to. @@ -2186,7 +2208,7 @@ public final class ProcessList { // packageName and uid of the defining application. This is because the // preloading only makes sense in the context of the defining application, // not the calling one. - appInfo.packageName = app.hostingRecord.getDefiningPackageName(); + appInfo.packageName = app.getHostingRecord().getDefiningPackageName(); appInfo.uid = uid; appZygote = new AppZygote(appInfo, uid, firstUid, lastUid); mAppZygotes.put(app.info.processName, uid, appZygote); @@ -2233,14 +2255,15 @@ public final class ProcessList { private boolean needsStorageDataIsolation(StorageManagerInternal storageManagerInternal, ProcessRecord app) { + final int mountMode = app.getMountMode(); return mVoldAppDataIsolationEnabled && UserHandle.isApp(app.uid) && !storageManagerInternal.isExternalStorageService(app.uid) // Special mounting mode doesn't need to have data isolation as they won't // access /mnt/user anyway. - && app.mountMode != Zygote.MOUNT_EXTERNAL_ANDROID_WRITABLE - && app.mountMode != Zygote.MOUNT_EXTERNAL_PASS_THROUGH - && app.mountMode != Zygote.MOUNT_EXTERNAL_INSTALLER - && app.mountMode != Zygote.MOUNT_EXTERNAL_NONE; + && mountMode != Zygote.MOUNT_EXTERNAL_ANDROID_WRITABLE + && mountMode != Zygote.MOUNT_EXTERNAL_PASS_THROUGH + && mountMode != Zygote.MOUNT_EXTERNAL_INSTALLER + && mountMode != Zygote.MOUNT_EXTERNAL_NONE; } private Process.ProcessStartResult startProcess(HostingRecord hostingRecord, String entryPoint, @@ -2256,7 +2279,7 @@ public final class ProcessList { // Use has-foreground-activities as a temporary hint so the current scheduling // group won't be lost when the process is attaching. The actual state will be // refreshed when computing oom-adj. - app.setHasForegroundActivities(true); + app.mState.setHasForegroundActivities(true); } Map> pkgDataInfoMap; @@ -2306,7 +2329,7 @@ public final class ProcessList { app.processName)) { // Cannot prepare Android/app and Android/obb directory or inode == 0, // so we won't mount it in zygote, but resume the mount after unlocking device. - app.bindMountPending = true; + app.setBindMountPending(true); bindMountAppStorageDirs = false; } } @@ -2323,8 +2346,9 @@ public final class ProcessList { startResult = startWebView(entryPoint, app.processName, uid, uid, gids, runtimeFlags, mountExternal, app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet, - app.info.dataDir, null, app.info.packageName, app.mDisabledCompatChanges, - new String[]{PROC_START_SEQ_IDENT + app.startSeq}); + app.info.dataDir, null, app.info.packageName, + app.getDisabledCompatChanges(), + new String[]{PROC_START_SEQ_IDENT + app.getStartSeq()}); } else if (hostingRecord.usesAppZygote()) { final AppZygote appZygote = createAppZygoteForProcessIfNeeded(app); @@ -2334,17 +2358,17 @@ public final class ProcessList { app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet, app.info.dataDir, null, app.info.packageName, /*zygotePolicyFlags=*/ ZYGOTE_POLICY_FLAG_EMPTY, isTopApp, - app.mDisabledCompatChanges, pkgDataInfoMap, allowlistedAppDataInfoMap, + app.getDisabledCompatChanges(), pkgDataInfoMap, allowlistedAppDataInfoMap, false, false, - new String[]{PROC_START_SEQ_IDENT + app.startSeq}); + new String[]{PROC_START_SEQ_IDENT + app.getStartSeq()}); } else { startResult = Process.start(entryPoint, app.processName, uid, uid, gids, runtimeFlags, mountExternal, app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet, app.info.dataDir, invokeWith, app.info.packageName, zygotePolicyFlags, - isTopApp, app.mDisabledCompatChanges, pkgDataInfoMap, + isTopApp, app.getDisabledCompatChanges(), pkgDataInfoMap, allowlistedAppDataInfoMap, bindMountAppsData, bindMountAppStorageDirs, - new String[]{PROC_START_SEQ_IDENT + app.startSeq}); + new String[]{PROC_START_SEQ_IDENT + app.getStartSeq()}); } checkSlow(startTime, "startProcess: returned from zygote!"); return startResult; @@ -2359,14 +2383,14 @@ public final class ProcessList { } @GuardedBy("mService") - final boolean startProcessLocked(ProcessRecord app, HostingRecord hostingRecord, + boolean startProcessLocked(ProcessRecord app, HostingRecord hostingRecord, int zygotePolicyFlags, String abiOverride) { return startProcessLocked(app, hostingRecord, zygotePolicyFlags, false /* disableHiddenApiChecks */, abiOverride); } @GuardedBy("mService") - final ProcessRecord startProcessLocked(String processName, ApplicationInfo info, + ProcessRecord startProcessLocked(String processName, ApplicationInfo info, boolean knownToBeDead, int intentFlags, HostingRecord hostingRecord, int zygotePolicyFlags, boolean allowWhileBooting, boolean isolated, int isolatedUid, boolean keepIfLarge, String abiOverride, String entryPoint, String[] entryPointArgs, @@ -2399,7 +2423,7 @@ public final class ProcessList { info.processName); mService.mAppErrors.clearBadProcess(processName, info.uid); if (app != null) { - app.bad = false; + app.mErrorState.setBad(false); } } } @@ -2416,11 +2440,11 @@ public final class ProcessList { // already running. if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES, "startProcess: name=" + processName + " app=" + app + " knownToBeDead=" + knownToBeDead - + " thread=" + (app != null ? app.thread : null) - + " pid=" + (app != null ? app.pid : -1)); - ProcessRecord precedence = null; - if (app != null && app.pid > 0) { - if ((!knownToBeDead && !app.killed) || app.thread == null) { + + " thread=" + (app != null ? app.getThread() : null) + + " pid=" + (app != null ? app.getPid() : -1)); + ProcessRecord predecessor = null; + if (app != null && app.getPid() > 0) { + if ((!knownToBeDead && !app.isKilled()) || app.getThread() == null) { // We already have the app running, or are waiting for it to // come up (we have a pid but not yet its thread), so keep it. if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES, "App already running: " + app); @@ -2434,12 +2458,12 @@ public final class ProcessList { // clean it up now. if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES, "App died: " + app); checkSlow(startTime, "startProcess: bad proc running, killing"); - ProcessList.killProcessGroup(app.uid, app.pid); + ProcessList.killProcessGroup(app.uid, app.getPid()); checkSlow(startTime, "startProcess: done killing old proc"); - if (!app.killed + if (!app.isKilled() || mService.mAppProfiler.isLastMemoryLevelNormal() - || app.setProcState < ActivityManager.PROCESS_STATE_CACHED_EMPTY + || app.mState.getSetProcState() < ActivityManager.PROCESS_STATE_CACHED_EMPTY || app.mProfile.getLastCachedPss() < getCachedRestoreThresholdKb()) { // Throw a wtf if it's not killed, or killed but not because the system was in // memory pressure + the app was in "cch-empty" and used large amount of memory @@ -2448,8 +2472,8 @@ public final class ProcessList { Slog.w(TAG_PROCESSES, app.toString() + " is attached to a previous process"); } // We are not going to re-use the ProcessRecord, as we haven't dealt with the cleanup - // routine of it yet, but we'd set it as the precedence of the new process. - precedence = app; + // routine of it yet, but we'd set it as the predecessor of the new process. + predecessor = app; app = null; } @@ -2461,12 +2485,12 @@ public final class ProcessList { + processName + "/" + info.uid + " isolated=" + isolated); return null; } - app.crashHandler = crashHandler; - app.isolatedEntryPoint = entryPoint; - app.isolatedEntryPointArgs = entryPointArgs; - if (precedence != null) { - app.mPrecedence = precedence; - precedence.mSuccessor = app; + app.mErrorState.setCrashHandler(crashHandler); + app.setIsolatedEntryPoint(entryPoint); + app.setIsolatedEntryPointArgs(entryPointArgs); + if (predecessor != null) { + app.mPredecessor = predecessor; + predecessor.mSuccessor = app; } checkSlow(startTime, "startProcess: done creating new process record"); } else { @@ -2499,7 +2523,7 @@ public final class ProcessList { @GuardedBy("mService") private String isProcStartValidLocked(ProcessRecord app, long expectedStartSeq) { StringBuilder sb = null; - if (app.killedByAm) { + if (app.isKilledByAm()) { if (sb == null) sb = new StringBuilder(); sb.append("killedByAm=true;"); } @@ -2507,13 +2531,13 @@ public final class ProcessList { if (sb == null) sb = new StringBuilder(); sb.append("No entry in mProcessNames;"); } - if (!app.pendingStart) { + if (!app.isPendingStart()) { if (sb == null) sb = new StringBuilder(); sb.append("pendingStart=false;"); } - if (app.startSeq > expectedStartSeq) { + if (app.getStartSeq() > expectedStartSeq) { if (sb == null) sb = new StringBuilder(); - sb.append("seq=" + app.startSeq + ",expected=" + expectedStartSeq + ";"); + sb.append("seq=" + app.getStartSeq() + ",expected=" + expectedStartSeq + ";"); } try { AppGlobals.getPackageManager().checkPackageStartable(app.info.packageName, app.userId); @@ -2536,7 +2560,7 @@ public final class ProcessList { Process.ProcessStartResult startResult, long expectedStartSeq) { // Indicates that this process start has been taken care of. if (mPendingStarts.get(expectedStartSeq) == null) { - if (pending.pid == startResult.pid) { + if (pending.getPid() == startResult.pid) { pending.setUsingWrapper(startResult.usingWrapper); // TODO: Update already existing clients of usingWrapper } @@ -2555,31 +2579,31 @@ public final class ProcessList { Slog.w(TAG_PROCESSES, app + " start not valid, killing pid=" + pid + ", " + reason); - app.pendingStart = false; + app.setPendingStart(false); killProcessQuiet(pid); - Process.killProcessGroup(app.uid, app.pid); + Process.killProcessGroup(app.uid, app.getPid()); noteAppKill(app, ApplicationExitInfo.REASON_OTHER, ApplicationExitInfo.SUBREASON_INVALID_START, reason); return false; } mService.mBatteryStatsService.noteProcessStart(app.processName, app.info.uid); - checkSlow(app.startTime, "startProcess: done updating battery stats"); + checkSlow(app.getStartTime(), "startProcess: done updating battery stats"); EventLog.writeEvent(EventLogTags.AM_PROC_START, - UserHandle.getUserId(app.startUid), pid, app.startUid, - app.processName, app.hostingRecord.getType(), - app.hostingRecord.getName() != null ? app.hostingRecord.getName() : ""); + UserHandle.getUserId(app.getStartUid()), pid, app.getStartUid(), + app.processName, app.getHostingRecord().getType(), + app.getHostingRecord().getName() != null ? app.getHostingRecord().getName() : ""); try { AppGlobals.getPackageManager().logAppProcessStartIfNeeded(app.info.packageName, - app.processName, app.uid, app.seInfo, app.info.sourceDir, pid); + app.processName, app.uid, app.getSeInfo(), app.info.sourceDir, pid); } catch (RemoteException ex) { // Ignore } Watchdog.getInstance().processStarted(app.processName, pid); - checkSlow(app.startTime, "startProcess: building log message"); + checkSlow(app.getStartTime(), "startProcess: building log message"); StringBuilder buf = mStringBuilder; buf.setLength(0); buf.append("Start proc "); @@ -2587,23 +2611,25 @@ public final class ProcessList { buf.append(':'); buf.append(app.processName); buf.append('/'); - UserHandle.formatUid(buf, app.startUid); - if (app.isolatedEntryPoint != null) { + UserHandle.formatUid(buf, app.getStartUid()); + if (app.getIsolatedEntryPoint() != null) { buf.append(" ["); - buf.append(app.isolatedEntryPoint); + buf.append(app.getIsolatedEntryPoint()); buf.append("]"); } buf.append(" for "); - buf.append(app.hostingRecord.getType()); - if (app.hostingRecord.getName() != null) { + buf.append(app.getHostingRecord().getType()); + if (app.getHostingRecord().getName() != null) { buf.append(" "); - buf.append(app.hostingRecord.getName()); + buf.append(app.getHostingRecord().getName()); } - mService.reportUidInfoMessageLocked(TAG, buf.toString(), app.startUid); - app.setPid(pid); - app.setUsingWrapper(usingWrapper); - app.pendingStart = false; - checkSlow(app.startTime, "startProcess: starting to update pids map"); + mService.reportUidInfoMessageLocked(TAG, buf.toString(), app.getStartUid()); + synchronized (mProcLock) { + app.setPid(pid); + app.setUsingWrapper(usingWrapper); + app.setPendingStart(false); + } + checkSlow(app.getStartTime(), "startProcess: starting to update pids map"); ProcessRecord oldApp; synchronized (mService.mPidsSelfLocked) { oldApp = mService.mPidsSelfLocked.get(pid); @@ -2612,11 +2638,11 @@ public final class ProcessList { if (oldApp != null && !app.isolated) { // Clean up anything relating to this pid first Slog.wtf(TAG, "handleProcessStartedLocked process:" + app.processName - + " startSeq:" + app.startSeq + + " startSeq:" + app.getStartSeq() + " pid:" + pid + " belongs to another existing app:" + oldApp.processName - + " startSeq:" + oldApp.startSeq); - mService.cleanUpApplicationRecordLocked(oldApp, false, false, -1, + + " startSeq:" + oldApp.getStartSeq()); + mService.cleanUpApplicationRecordLocked(oldApp, pid, false, false, -1, true /*replacingPid*/); } mService.addPidLocked(app); @@ -2628,43 +2654,46 @@ public final class ProcessList { ? PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT); } } - checkSlow(app.startTime, "startProcess: done updating pids map"); + checkSlow(app.getStartTime(), "startProcess: done updating pids map"); return true; } - final void removeLruProcessLocked(ProcessRecord app) { + @GuardedBy("mService") + void removeLruProcessLocked(ProcessRecord app) { int lrui = mLruProcesses.lastIndexOf(app); if (lrui >= 0) { - if (!app.killed) { - if (app.isPersistent()) { - Slog.w(TAG, "Removing persistent process that hasn't been killed: " + app); - } else { - Slog.wtfStack(TAG, "Removing process that hasn't been killed: " + app); - if (app.pid > 0) { - killProcessQuiet(app.pid); - ProcessList.killProcessGroup(app.uid, app.pid); - noteAppKill(app, ApplicationExitInfo.REASON_OTHER, - ApplicationExitInfo.SUBREASON_REMOVE_LRU, "hasn't been killed"); + synchronized (mProcLock) { + if (!app.isKilled()) { + if (app.isPersistent()) { + Slog.w(TAG, "Removing persistent process that hasn't been killed: " + app); } else { - app.pendingStart = false; + Slog.wtfStack(TAG, "Removing process that hasn't been killed: " + app); + if (app.getPid() > 0) { + killProcessQuiet(app.getPid()); + ProcessList.killProcessGroup(app.uid, app.getPid()); + noteAppKill(app, ApplicationExitInfo.REASON_OTHER, + ApplicationExitInfo.SUBREASON_REMOVE_LRU, "hasn't been killed"); + } else { + app.setPendingStart(false); + } } } + if (lrui < mLruProcessActivityStart) { + mLruProcessActivityStart--; + } + if (lrui < mLruProcessServiceStart) { + mLruProcessServiceStart--; + } + mLruProcesses.remove(lrui); } - if (lrui < mLruProcessActivityStart) { - mLruProcessActivityStart--; - } - if (lrui < mLruProcessServiceStart) { - mLruProcessServiceStart--; - } - mLruProcesses.remove(lrui); - mService.removeOomAdjTargetLocked(app, true); } + mService.removeOomAdjTargetLocked(app, true); } - @GuardedBy("mService") - boolean killPackageProcessesLocked(String packageName, int appId, int userId, int minOomAdj, + @GuardedBy({"mService", "mProcLock"}) + boolean killPackageProcessesLSP(String packageName, int appId, int userId, int minOomAdj, int reasonCode, int subReason, String reason) { - return killPackageProcessesLocked(packageName, appId, userId, minOomAdj, + return killPackageProcessesLSP(packageName, appId, userId, minOomAdj, false /* callerWillRestart */, true /* allowRestart */, true /* doit */, false /* evenPersistent */, false /* setRemoved */, reasonCode, subReason, reason); @@ -2697,8 +2726,8 @@ public final class ProcessList { } } - @GuardedBy("mService") - final boolean killPackageProcessesLocked(String packageName, int appId, + @GuardedBy({"mService", "mProcLock"}) + boolean killPackageProcessesLSP(String packageName, int appId, int userId, int minOomAdj, boolean callerWillRestart, boolean allowRestart, boolean doit, boolean evenPersistent, boolean setRemoved, int reasonCode, int subReason, String reason) { @@ -2717,7 +2746,7 @@ public final class ProcessList { // we don't kill persistent processes continue; } - if (app.removed) { + if (app.isRemoved()) { if (doit) { procs.add(app); } @@ -2725,7 +2754,7 @@ public final class ProcessList { } // Skip process if it doesn't meet our oom adj requirement. - if (app.setAdj < minOomAdj) { + if (app.mState.getSetAdj() < minOomAdj) { // Note it is still possible to have a process with oom adj 0 in the killed // processes, but it does not mean misjudgment. E.g. a bound service process // and its client activity process are both in the background, so they are @@ -2747,8 +2776,8 @@ public final class ProcessList { // that match it. We need to qualify this by the processes // that are running under the specified app and user ID. } else { - final boolean isDep = app.pkgDeps != null - && app.pkgDeps.contains(packageName); + final boolean isDep = app.getPkgDeps() != null + && app.getPkgDeps().contains(packageName); if (!isDep && UserHandle.getAppId(app.uid) != appId) { continue; } @@ -2765,7 +2794,7 @@ public final class ProcessList { return true; } if (setRemoved) { - app.removed = true; + app.setRemoved(true); } procs.add(app); } @@ -2806,12 +2835,12 @@ public final class ProcessList { mService.mAtmInternal.clearHeavyWeightProcessIfEquals(app.getWindowProcessController()); boolean needRestart = false; - if ((app.pid > 0 && app.pid != ActivityManagerService.MY_PID) || (app.pid == 0 && app - .pendingStart)) { - int pid = app.pid; + final int pid = app.getPid(); + if ((pid > 0 && pid != ActivityManagerService.MY_PID) + || (pid == 0 && app.isPendingStart())) { if (pid > 0) { - mService.removePidLocked(app); - app.bindMountPending = false; + mService.removePidLocked(pid, app); + app.setBindMountPending(false); mService.mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app); mService.mBatteryStatsService.noteProcessFinish(app.processName, app.info.uid); if (app.isolated) { @@ -2827,8 +2856,8 @@ public final class ProcessList { needRestart = true; } } - app.kill(reason, reasonCode, subReason, true); - mService.handleAppDiedLocked(app, willRestart, allowRestart); + app.killLocked(reason, reasonCode, subReason, true); + mService.handleAppDiedLocked(app, pid, willRestart, allowRestart); if (willRestart) { removeLruProcessLocked(app); mService.addAppLocked(app.info, null, false, null /* ABI override */, @@ -2842,48 +2871,51 @@ public final class ProcessList { } @GuardedBy("mService") - final void addProcessNameLocked(ProcessRecord proc) { + void addProcessNameLocked(ProcessRecord proc) { // We shouldn't already have a process under this name, but just in case we // need to clean up whatever may be there now. - ProcessRecord old = removeProcessNameLocked(proc.processName, proc.uid); - if (old == proc && proc.isPersistent()) { - // We are re-adding a persistent process. Whatevs! Just leave it there. - Slog.w(TAG, "Re-adding persistent process " + proc); - } else if (old != null) { - if (old.killed) { - // The old process has been killed, we probably haven't had - // a chance to clean up the old record, just log a warning - Slog.w(TAG, "Existing proc " + old + " was killed " - + (SystemClock.uptimeMillis() - old.mKillTime) - + "ms ago when adding " + proc); - } else { - Slog.wtf(TAG, "Already have existing proc " + old + " when adding " + proc); + synchronized (mProcLock) { + ProcessRecord old = removeProcessNameLocked(proc.processName, proc.uid); + if (old == proc && proc.isPersistent()) { + // We are re-adding a persistent process. Whatevs! Just leave it there. + Slog.w(TAG, "Re-adding persistent process " + proc); + } else if (old != null) { + if (old.isKilled()) { + // The old process has been killed, we probably haven't had + // a chance to clean up the old record, just log a warning + Slog.w(TAG, "Existing proc " + old + " was killed " + + (SystemClock.uptimeMillis() - old.getKillTime()) + + "ms ago when adding " + proc); + } else { + Slog.wtf(TAG, "Already have existing proc " + old + " when adding " + proc); + } } - } - UidRecord uidRec = mActiveUids.get(proc.uid); - if (uidRec == null) { - uidRec = new UidRecord(proc.uid); - // This is the first appearance of the uid, report it now! - if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, - "Creating new process uid: " + uidRec); - if (Arrays.binarySearch(mService.mDeviceIdleTempAllowlist, - UserHandle.getAppId(proc.uid)) >= 0 - || mService.mPendingTempAllowlist.indexOfKey(proc.uid) >= 0) { - uidRec.mSetAllowlist = uidRec.mCurAllowlist = true; + UidRecord uidRec = mActiveUids.get(proc.uid); + if (uidRec == null) { + uidRec = new UidRecord(proc.uid, mService); + // This is the first appearance of the uid, report it now! + if (DEBUG_UID_OBSERVERS) { + Slog.i(TAG_UID_OBSERVERS, "Creating new process uid: " + uidRec); + } + if (Arrays.binarySearch(mService.mDeviceIdleTempAllowlist, + UserHandle.getAppId(proc.uid)) >= 0 + || mService.mPendingTempAllowlist.indexOfKey(proc.uid) >= 0) { + uidRec.setCurAllowListed(true); + uidRec.setSetAllowListed(true); + } + uidRec.updateHasInternetPermission(); + mActiveUids.put(proc.uid, uidRec); + EventLogTags.writeAmUidRunning(uidRec.getUid()); + mService.noteUidProcessState(uidRec.getUid(), uidRec.getCurProcState(), + uidRec.getCurCapability()); } - uidRec.updateHasInternetPermission(); - mActiveUids.put(proc.uid, uidRec); - EventLogTags.writeAmUidRunning(uidRec.uid); - mService.noteUidProcessState(uidRec.uid, uidRec.getCurProcState(), - uidRec.curCapability); - } - proc.uidRecord = uidRec; - uidRec.procRecords.add(proc); + proc.setUidRecord(uidRec); + uidRec.addProcess(proc); - // Reset render thread tid if it was already set, so new process can set it again. - proc.renderThreadTid = 0; - uidRec.numProcs++; - mProcessNames.put(proc.processName, proc.uid, proc); + // Reset render thread tid if it was already set, so new process can set it again. + proc.setRenderThreadTid(0); + mProcessNames.put(proc.processName, proc.uid, proc); + } if (proc.isolated) { mIsolatedProcesses.put(proc.uid, proc); } @@ -2902,7 +2934,7 @@ public final class ProcessList { } @GuardedBy("mService") - final ProcessRecord newProcessRecordLocked(ApplicationInfo info, String customProcess, + ProcessRecord newProcessRecordLocked(ApplicationInfo info, String customProcess, boolean isolated, int isolatedUid, HostingRecord hostingRecord) { String proc = customProcess != null ? customProcess : info.processName; final int userId = UserHandle.getUserId(info.uid); @@ -2936,58 +2968,63 @@ public final class ProcessList { FrameworkStatsLog.ISOLATED_UID_CHANGED__EVENT__CREATED); } final ProcessRecord r = new ProcessRecord(mService, info, proc, uid); + final ProcessStateRecord state = r.mState; if (!mService.mBooted && !mService.mBooting && userId == UserHandle.USER_SYSTEM && (info.flags & PERSISTENT_MASK) == PERSISTENT_MASK) { // The system process is initialized to SCHED_GROUP_DEFAULT in init.rc. - r.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_DEFAULT); - r.setSchedGroup = ProcessList.SCHED_GROUP_DEFAULT; + state.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_DEFAULT); + state.setSetSchedGroup(ProcessList.SCHED_GROUP_DEFAULT); r.setPersistent(true); - r.maxAdj = ProcessList.PERSISTENT_PROC_ADJ; + state.setMaxAdj(ProcessList.PERSISTENT_PROC_ADJ); } if (isolated && isolatedUid != 0) { // Special case for startIsolatedProcess (internal only) - assume the process // is required by the system server to prevent it being killed. - r.maxAdj = ProcessList.PERSISTENT_SERVICE_ADJ; + state.setMaxAdj(ProcessList.PERSISTENT_SERVICE_ADJ); } addProcessNameLocked(r); return r; } @GuardedBy("mService") - final ProcessRecord removeProcessNameLocked(final String name, final int uid) { + ProcessRecord removeProcessNameLocked(final String name, final int uid) { return removeProcessNameLocked(name, uid, null); } @GuardedBy("mService") - final ProcessRecord removeProcessNameLocked(final String name, final int uid, + ProcessRecord removeProcessNameLocked(final String name, final int uid, final ProcessRecord expecting) { ProcessRecord old = mProcessNames.get(name, uid); - // Only actually remove when the currently recorded value matches the - // record that we expected; if it doesn't match then we raced with a - // newly created process and we don't want to destroy the new one. - if ((expecting == null) || (old == expecting)) { - mProcessNames.remove(name, uid); - } final ProcessRecord record = expecting != null ? expecting : old; - if (record != null && record.uidRecord != null) { - final UidRecord uidRecord = record.uidRecord; - uidRecord.numProcs--; - uidRecord.procRecords.remove(record); - if (uidRecord.numProcs == 0) { - // 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); - EventLogTags.writeAmUidStopped(uid); - mActiveUids.remove(uid); - mService.mFgsStartTempAllowList.remove(record.info.uid); - mService.noteUidProcessState(uid, ActivityManager.PROCESS_STATE_NONEXISTENT, - ActivityManager.PROCESS_CAPABILITY_NONE); + synchronized (mProcLock) { + // Only actually remove when the currently recorded value matches the + // record that we expected; if it doesn't match then we raced with a + // newly created process and we don't want to destroy the new one. + if ((expecting == null) || (old == expecting)) { + mProcessNames.remove(name, uid); + } + if (record != null) { + final UidRecord uidRecord = record.getUidRecord(); + if (uidRecord != null) { + uidRecord.removeProcess(record); + if (uidRecord.getNumOfProcs() == 0) { + // 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); + EventLogTags.writeAmUidStopped(uid); + mActiveUids.remove(uid); + mService.mFgsStartTempAllowList.remove(record.info.uid); + mService.noteUidProcessState(uid, ActivityManager.PROCESS_STATE_NONEXISTENT, + ActivityManager.PROCESS_CAPABILITY_NONE); + } + record.setUidRecord(null); + } } - record.uidRecord = null; } mIsolatedProcesses.remove(uid); mGlobalIsolatedUids.freeIsolatedUidLocked(uid); @@ -3000,13 +3037,14 @@ public final class ProcessList { } /** Call setCoreSettings on all LRU processes, with the new settings. */ - @GuardedBy("mService") - void updateCoreSettingsLocked(Bundle settings) { + @GuardedBy(anyOf = {"mService", "mProcLock"}) + void updateCoreSettingsLOSP(Bundle settings) { for (int i = mLruProcesses.size() - 1; i >= 0; i--) { ProcessRecord processRecord = mLruProcesses.get(i); + final IApplicationThread thread = processRecord.getThread(); try { - if (processRecord.thread != null) { - processRecord.thread.setCoreSettings(settings); + if (thread != null) { + thread.setCoreSettings(settings); } } catch (RemoteException re) { /* ignore */ @@ -3020,8 +3058,8 @@ public final class ProcessList { * @param minTargetSdk * @param maxProcState */ - @GuardedBy("mService") - void killAllBackgroundProcessesExceptLocked(int minTargetSdk, int maxProcState) { + @GuardedBy({"mService", "mProcLock"}) + void killAllBackgroundProcessesExceptLSP(int minTargetSdk, int maxProcState) { final ArrayList procs = new ArrayList<>(); final int NP = mProcessNames.getMap().size(); for (int ip = 0; ip < NP; ip++) { @@ -3029,8 +3067,9 @@ public final class ProcessList { final int NA = apps.size(); for (int ia = 0; ia < NA; ia++) { final ProcessRecord app = apps.valueAt(ia); - if (app.removed || ((minTargetSdk < 0 || app.info.targetSdkVersion < minTargetSdk) - && (maxProcState < 0 || app.setProcState > maxProcState))) { + if (app.isRemoved() + || ((minTargetSdk < 0 || app.info.targetSdkVersion < minTargetSdk) + && (maxProcState < 0 || app.mState.getSetProcState() > maxProcState))) { procs.add(app); } } @@ -3047,13 +3086,14 @@ public final class ProcessList { * Call updateTimePrefs on all LRU processes * @param timePref The time pref to pass to each process */ - @GuardedBy("mService") - void updateAllTimePrefsLocked(int timePref) { + @GuardedBy(anyOf = {"mService", "mProcLock"}) + void updateAllTimePrefsLOSP(int timePref) { for (int i = mLruProcesses.size() - 1; i >= 0; i--) { ProcessRecord r = mLruProcesses.get(i); - if (r.thread != null) { + final IApplicationThread thread = r.getThread(); + if (thread != null) { try { - r.thread.updateTimePrefs(timePref); + thread.updateTimePrefs(timePref); } catch (RemoteException ex) { Slog.w(TAG, "Failed to update preferences for: " + r.info.processName); @@ -3064,15 +3104,16 @@ public final class ProcessList { void setAllHttpProxy() { // Update the HTTP proxy for each application thread. - synchronized (mService) { + synchronized (mProcLock) { for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) { ProcessRecord r = mLruProcesses.get(i); + IApplicationThread thread = r.getThread(); // Don't dispatch to isolated processes as they can't access ConnectivityManager and // don't have network privileges anyway. Exclude system server and update it // separately outside the AMS lock, to avoid deadlock with Connectivity Service. - if (r.pid != ActivityManagerService.MY_PID && r.thread != null && !r.isolated) { + if (r.getPid() != ActivityManagerService.MY_PID && thread != null && !r.isolated) { try { - r.thread.updateHttpProxy(); + thread.updateHttpProxy(); } catch (RemoteException ex) { Slog.w(TAG, "Failed to update http proxy for: " + r.info.processName); @@ -3083,13 +3124,14 @@ public final class ProcessList { ActivityThread.updateHttpProxy(mService.mContext); } - @GuardedBy("mService") - void clearAllDnsCacheLocked() { + @GuardedBy(anyOf = {"mService", "mProcLock"}) + void clearAllDnsCacheLOSP() { for (int i = mLruProcesses.size() - 1; i >= 0; i--) { ProcessRecord r = mLruProcesses.get(i); - if (r.thread != null) { + final IApplicationThread thread = r.getThread(); + if (thread != null) { try { - r.thread.clearDnsCache(); + thread.clearDnsCache(); } catch (RemoteException ex) { Slog.w(TAG, "Failed to clear dns cache for: " + r.info.processName); } @@ -3097,13 +3139,14 @@ public final class ProcessList { } } - @GuardedBy("mService") - void handleAllTrustStorageUpdateLocked() { + @GuardedBy(anyOf = {"mService", "mProcLock"}) + void handleAllTrustStorageUpdateLOSP() { for (int i = mLruProcesses.size() - 1; i >= 0; i--) { ProcessRecord r = mLruProcesses.get(i); - if (r.thread != null) { + final IApplicationThread thread = r.getThread(); + if (thread != null) { try { - r.thread.handleTrustStorageUpdate(); + thread.handleTrustStorageUpdate(); } catch (RemoteException ex) { Slog.w(TAG, "Failed to handle trust storage update for: " + r.info.processName); @@ -3112,10 +3155,10 @@ public final class ProcessList { } } - @GuardedBy("mService") - int updateLruProcessInternalLocked(ProcessRecord app, long now, int index, + @GuardedBy({"mService", "mProcLock"}) + private int updateLruProcessInternalLSP(ProcessRecord app, long now, int index, int lruSeq, String what, Object obj, ProcessRecord srcApp) { - app.lastActivityTime = now; + app.setLastActivityTime(now); if (app.hasActivitiesOrRecentTasks()) { // Don't want to touch dependent processes that are hosting activities. @@ -3147,7 +3190,7 @@ public final class ProcessList { if (DEBUG_LRU) Slog.d(TAG_LRU, "Moving dep from " + lrui + " to " + index + " in LRU list: " + app); mLruProcesses.add(index, app); - app.lruSeq = lruSeq; + app.setLruSeq(lruSeq); return index; } @@ -3167,45 +3210,51 @@ public final class ProcessList { * @param endIndex The current end of the top being processed. Typically topI - 1. That is, * where we are going to start potentially adjusting other entries in the list. */ - private void updateClientActivitiesOrdering(final ProcessRecord topApp, final int topI, + @GuardedBy({"mService", "mProcLock"}) + private void updateClientActivitiesOrderingLSP(final ProcessRecord topApp, final int topI, final int bottomI, int endIndex) { - if (topApp.hasActivitiesOrRecentTasks() || topApp.treatLikeActivity - || !topApp.hasClientActivities()) { + final ProcessServiceRecord topPsr = topApp.mServices; + if (topApp.hasActivitiesOrRecentTasks() || topPsr.isTreatedLikeActivity() + || !topPsr.hasClientActivities()) { // If this is not a special process that has client activities, then there is // nothing to do. return; } final int uid = topApp.info.uid; - if (topApp.connectionGroup > 0) { - int endImportance = topApp.connectionImportance; + final int topConnectionGroup = topPsr.getConnectionGroup(); + if (topConnectionGroup > 0) { + int endImportance = topPsr.getConnectionImportance(); for (int i = endIndex; i >= bottomI; i--) { final ProcessRecord subProc = mLruProcesses.get(i); + final ProcessServiceRecord subPsr = subProc.mServices; + final int subConnectionGroup = subPsr.getConnectionGroup(); + final int subConnectionImportance = subPsr.getConnectionImportance(); if (subProc.info.uid == uid - && subProc.connectionGroup == topApp.connectionGroup) { - if (i == endIndex && subProc.connectionImportance >= endImportance) { + && subConnectionGroup == topConnectionGroup) { + if (i == endIndex && subConnectionImportance >= endImportance) { // This process is already in the group, and its importance // is not as strong as the process before it, so keep it // correctly positioned in the group. if (DEBUG_LRU) Slog.d(TAG_LRU, "Keeping in-place above " + subProc + " endImportance=" + endImportance - + " group=" + subProc.connectionGroup - + " importance=" + subProc.connectionImportance); + + " group=" + subConnectionGroup + + " importance=" + subConnectionImportance); endIndex--; - endImportance = subProc.connectionImportance; + endImportance = subConnectionImportance; } else { // We want to pull this up to be with the rest of the group, // and order within the group by importance. if (DEBUG_LRU) Slog.d(TAG_LRU, "Pulling up " + subProc + " to position in group with importance=" - + subProc.connectionImportance); + + subConnectionImportance); boolean moved = false; for (int pos = topI; pos > endIndex; pos--) { final ProcessRecord posProc = mLruProcesses.get(pos); - if (subProc.connectionImportance - <= posProc.connectionImportance) { + if (subConnectionImportance + <= posProc.mServices.getConnectionImportance()) { mLruProcesses.remove(i); mLruProcesses.add(pos, subProc); if (DEBUG_LRU) Slog.d(TAG_LRU, @@ -3226,7 +3275,7 @@ public final class ProcessList { + " from position " + i + " to end of group @ " + endIndex); endIndex--; - endImportance = subProc.connectionImportance; + endImportance = subConnectionImportance; } } } @@ -3238,6 +3287,8 @@ public final class ProcessList { int i = endIndex; while (i >= bottomI) { ProcessRecord subProc = mLruProcesses.get(i); + final ProcessServiceRecord subPsr = subProc.mServices; + final int subConnectionGroup = subPsr.getConnectionGroup(); if (DEBUG_LRU) Slog.d(TAG_LRU, "Looking to spread old procs, at " + subProc + " @ " + i); if (subProc.info.uid != uid) { @@ -3260,7 +3311,8 @@ public final class ProcessList { subProc = mLruProcesses.get(i); if (DEBUG_LRU) Slog.d(TAG_LRU, "Looking at next app at " + i + ": " + subProc); - if (subProc.hasActivitiesOrRecentTasks() || subProc.treatLikeActivity) { + if (subProc.hasActivitiesOrRecentTasks() + || subPsr.isTreatedLikeActivity()) { if (DEBUG_LRU) Slog.d(TAG_LRU, "This is hosting an activity!"); if (hasActivity) { @@ -3270,7 +3322,7 @@ public final class ProcessList { break; } hasActivity = true; - } else if (subProc.hasClientActivities()) { + } else if (subPsr.hasClientActivities()) { if (DEBUG_LRU) Slog.d(TAG_LRU, "This is a client of an activity"); if (hasActivity) { @@ -3281,21 +3333,21 @@ public final class ProcessList { "Already found a different activity: connUid=" + connUid + " uid=" + subProc.info.uid); break; - } else if (connGroup == 0 || connGroup != subProc.connectionGroup) { + } else if (connGroup == 0 || connGroup != subConnectionGroup) { // Previously saw a different group or not from a group, // want to treat these as different things. if (DEBUG_LRU) Slog.d(TAG_LRU, "Already found a different group: connGroup=" - + connGroup + " group=" + subProc.connectionGroup); + + connGroup + " group=" + subConnectionGroup); break; } } else { if (DEBUG_LRU) Slog.d(TAG_LRU, "This is an activity client! uid=" - + subProc.info.uid + " group=" + subProc.connectionGroup); + + subProc.info.uid + " group=" + subConnectionGroup); hasActivity = true; connUid = subProc.info.uid; - connGroup = subProc.connectionGroup; + connGroup = subConnectionGroup; } } endIndex--; @@ -3316,13 +3368,16 @@ public final class ProcessList { } if (endIndex >= bottomI) { final ProcessRecord endProc = mLruProcesses.get(endIndex); + final ProcessServiceRecord endPsr = endProc.mServices; + final int endConnectionGroup = endPsr.getConnectionGroup(); for (endIndex--; endIndex >= bottomI; endIndex--) { final ProcessRecord nextEndProc = mLruProcesses.get(endIndex); + final int nextConnectionGroup = nextEndProc.mServices.getConnectionGroup(); if (nextEndProc.info.uid != uid - || nextEndProc.connectionGroup != endProc.connectionGroup) { + || nextConnectionGroup != endConnectionGroup) { if (DEBUG_LRU) Slog.d(TAG_LRU, "Found next group or app: " + nextEndProc + " @ " - + endIndex + " group=" + nextEndProc.connectionGroup); + + endIndex + " group=" + nextConnectionGroup); break; } } @@ -3336,10 +3391,11 @@ public final class ProcessList { } } - final void updateLruProcessLocked(ProcessRecord app, boolean activityChange, - ProcessRecord client) { - final boolean hasActivity = app.hasActivitiesOrRecentTasks() || app.hasClientActivities() - || app.treatLikeActivity; + @GuardedBy("mService") + void updateLruProcessLocked(ProcessRecord app, boolean activityChange, ProcessRecord client) { + final ProcessServiceRecord psr = app.mServices; + final boolean hasActivity = app.hasActivitiesOrRecentTasks() || psr.hasClientActivities() + || psr.isTreatedLikeActivity(); final boolean hasService = false; // not impl yet. app.services.size() > 0; if (!activityChange && hasActivity) { // The process has activities, so we are only allowing activity-based adjustments @@ -3349,9 +3405,18 @@ public final class ProcessList { return; } + synchronized (mProcLock) { + updateLruProcessLSP(app, client, hasActivity, hasService); + } + } + + @GuardedBy({"mService", "mProcLock"}) + private void updateLruProcessLSP(ProcessRecord app, ProcessRecord client, + boolean hasActivity, boolean hasService) { mLruSeq++; final long now = SystemClock.uptimeMillis(); - app.lastActivityTime = now; + final ProcessServiceRecord psr = app.mServices; + app.setLastActivityTime(now); // First a quick reject: if the app is already at the position we will // put it, then there is nothing to do. @@ -3445,14 +3510,14 @@ public final class ProcessList { if (hasActivity) { final int N = mLruProcesses.size(); nextIndex = mLruProcessServiceStart; - if (!app.hasActivitiesOrRecentTasks() && !app.treatLikeActivity + if (!app.hasActivitiesOrRecentTasks() && !psr.isTreatedLikeActivity() && mLruProcessActivityStart < (N - 1)) { // Process doesn't have activities, but has clients with // activities... move it up, but below the app that is binding to it. if (DEBUG_LRU) Slog.d(TAG_LRU, "Adding to second-top of LRU activity list: " + app - + " group=" + app.connectionGroup - + " importance=" + app.connectionImportance); + + " group=" + psr.getConnectionGroup() + + " importance=" + psr.getConnectionImportance()); int pos = N - 1; while (pos > mLruProcessActivityStart) { final ProcessRecord posproc = mLruProcesses.get(pos); @@ -3472,7 +3537,7 @@ public final class ProcessList { endIndex = mLruProcessActivityStart; } nextActivityIndex = endIndex; - updateClientActivitiesOrdering(app, pos, mLruProcessActivityStart, endIndex); + updateClientActivitiesOrderingLSP(app, pos, mLruProcessActivityStart, endIndex); } else { // Process has activities, put it at the very tipsy-top. if (DEBUG_LRU) Slog.d(TAG_LRU, "Adding to top of LRU activity list: " + app); @@ -3509,46 +3574,48 @@ public final class ProcessList { mLruProcessActivityStart++; mLruProcessServiceStart++; if (index > 1) { - updateClientActivitiesOrdering(app, mLruProcessServiceStart - 1, 0, index - 1); + updateClientActivitiesOrderingLSP(app, mLruProcessServiceStart - 1, 0, index - 1); } } - app.lruSeq = mLruSeq; + app.setLruSeq(mLruSeq); // If the app is currently using a content provider or service, // bump those processes as well. - for (int j = app.connections.size() - 1; j >= 0; j--) { - ConnectionRecord cr = app.connections.valueAt(j); + for (int j = psr.numberOfConnections() - 1; j >= 0; j--) { + ConnectionRecord cr = psr.getConnectionAt(j); if (cr.binding != null && !cr.serviceDead && cr.binding.service != null && cr.binding.service.app != null - && cr.binding.service.app.lruSeq != mLruSeq + && cr.binding.service.app.getLruSeq() != mLruSeq && (cr.flags & Context.BIND_REDUCTION_FLAGS) == 0 && !cr.binding.service.app.isPersistent()) { - if (cr.binding.service.app.hasClientActivities()) { + if (cr.binding.service.app.mServices.hasClientActivities()) { if (nextActivityIndex >= 0) { - nextActivityIndex = updateLruProcessInternalLocked(cr.binding.service.app, + nextActivityIndex = updateLruProcessInternalLSP(cr.binding.service.app, now, nextActivityIndex, mLruSeq, "service connection", cr, app); } } else { - nextIndex = updateLruProcessInternalLocked(cr.binding.service.app, + nextIndex = updateLruProcessInternalLSP(cr.binding.service.app, now, nextIndex, mLruSeq, "service connection", cr, app); } } } - for (int j = app.conProviders.size() - 1; j >= 0; j--) { - ContentProviderRecord cpr = app.conProviders.get(j).provider; - if (cpr.proc != null && cpr.proc.lruSeq != mLruSeq && !cpr.proc.isPersistent()) { - nextIndex = updateLruProcessInternalLocked(cpr.proc, now, nextIndex, mLruSeq, + final ProcessProviderRecord ppr = app.mProviders; + for (int j = ppr.numberOfProviderConnections() - 1; j >= 0; j--) { + ContentProviderRecord cpr = ppr.getProviderConnectionAt(j).provider; + if (cpr.proc != null && cpr.proc.getLruSeq() != mLruSeq && !cpr.proc.isPersistent()) { + nextIndex = updateLruProcessInternalLSP(cpr.proc, now, nextIndex, mLruSeq, "provider reference", cpr, app); } } } - final ProcessRecord getLRURecordForAppLocked(IApplicationThread thread) { + @GuardedBy(anyOf = {"mService", "mProcLock"}) + ProcessRecord getLRURecordForAppLOSP(IApplicationThread thread) { if (thread == null) { return null; } @@ -3556,18 +3623,20 @@ public final class ProcessList { // Find the application record. for (int i = mLruProcesses.size() - 1; i >= 0; i--) { final ProcessRecord rec = mLruProcesses.get(i); - if (rec.thread != null && rec.thread.asBinder() == threadBinder) { + final IApplicationThread t = rec.getThread(); + if (t != null && t.asBinder() == threadBinder) { return rec; } } return null; } - boolean haveBackgroundProcessLocked() { + @GuardedBy(anyOf = {"mService", "mProcLock"}) + boolean haveBackgroundProcessLOSP() { for (int i = mLruProcesses.size() - 1; i >= 0; i--) { final ProcessRecord rec = mLruProcesses.get(i); - if (rec.thread != null - && rec.setProcState >= PROCESS_STATE_CACHED_ACTIVITY) { + if (rec.getThread() != null + && rec.mState.getSetProcState() >= PROCESS_STATE_CACHED_ACTIVITY) { return true; } } @@ -3587,11 +3656,11 @@ public final class ProcessList { return imp; } - @GuardedBy("mService") - void fillInProcMemInfoLocked(ProcessRecord app, + @GuardedBy(anyOf = {"mService", "mProcLock"}) + void fillInProcMemInfoLOSP(ProcessRecord app, ActivityManager.RunningAppProcessInfo outInfo, int clientTargetSdk) { - outInfo.pid = app.pid; + outInfo.pid = app.getPid(); outInfo.uid = app.info.uid; if (app.getWindowProcessController().isHeavyWeightProcess()) { outInfo.flags |= ActivityManager.RunningAppProcessInfo.FLAG_CANT_SAVE_STATE; @@ -3603,49 +3672,53 @@ public final class ProcessList { outInfo.flags |= ActivityManager.RunningAppProcessInfo.FLAG_HAS_ACTIVITIES; } outInfo.lastTrimLevel = app.mProfile.getTrimMemoryLevel(); - int adj = app.curAdj; - int procState = app.getCurProcState(); + final ProcessStateRecord state = app.mState; + int adj = state.getCurAdj(); + int procState = state.getCurProcState(); outInfo.importance = procStateToImportance(procState, adj, outInfo, clientTargetSdk); - outInfo.importanceReasonCode = app.adjTypeCode; - outInfo.processState = app.getCurProcState(); + outInfo.importanceReasonCode = state.getAdjTypeCode(); + outInfo.processState = procState; outInfo.isFocused = (app == mService.getTopApp()); - outInfo.lastActivityTime = app.lastActivityTime; + outInfo.lastActivityTime = app.getLastActivityTime(); } - @GuardedBy("mService") - List getRunningAppProcessesLocked(boolean allUsers, + @GuardedBy(anyOf = {"mService", "mProcLock"}) + List getRunningAppProcessesLOSP(boolean allUsers, int userId, boolean allUids, int callingUid, int clientTargetSdk) { // Lazy instantiation of list List runList = null; for (int i = mLruProcesses.size() - 1; i >= 0; i--) { ProcessRecord app = mLruProcesses.get(i); + final ProcessStateRecord state = app.mState; + final ProcessErrorStateRecord errState = app.mErrorState; if ((!allUsers && app.userId != userId) || (!allUids && app.uid != callingUid)) { continue; } - if ((app.thread != null) && (!app.isCrashing() && !app.isNotResponding())) { + if ((app.getThread() != null) + && (!errState.isCrashing() && !errState.isNotResponding())) { // Generate process state info for running application ActivityManager.RunningAppProcessInfo currApp = new ActivityManager.RunningAppProcessInfo(app.processName, - app.pid, app.getPackageList()); - fillInProcMemInfoLocked(app, currApp, clientTargetSdk); - if (app.adjSource instanceof ProcessRecord) { - currApp.importanceReasonPid = ((ProcessRecord)app.adjSource).pid; + app.getPid(), app.getPackageList()); + fillInProcMemInfoLOSP(app, currApp, clientTargetSdk); + if (state.getAdjSource() instanceof ProcessRecord) { + currApp.importanceReasonPid = ((ProcessRecord) state.getAdjSource()).getPid(); currApp.importanceReasonImportance = ActivityManager.RunningAppProcessInfo.procStateToImportance( - app.adjSourceProcState); - } else if (app.adjSource instanceof ActivityServiceConnectionsHolder) { + state.getAdjSourceProcState()); + } else if (state.getAdjSource() instanceof ActivityServiceConnectionsHolder) { final ActivityServiceConnectionsHolder r = - (ActivityServiceConnectionsHolder) app.adjSource; + (ActivityServiceConnectionsHolder) state.getAdjSource(); final int pid = r.getActivityPid(); if (pid != -1) { currApp.importanceReasonPid = pid; } } - if (app.adjTarget instanceof ComponentName) { - currApp.importanceReasonComponent = (ComponentName)app.adjTarget; + if (state.getAdjTarget() instanceof ComponentName) { + currApp.importanceReasonComponent = (ComponentName) state.getAdjTarget(); } //Slog.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance // + " lru=" + currApp.lru); @@ -3658,11 +3731,110 @@ public final class ProcessList { return runList; } - @GuardedBy("mService") - int getLruSizeLocked() { + @GuardedBy(anyOf = {"mService", "mProfileLock"}) + int getLruSizeLOSP() { return mLruProcesses.size(); } + /** + * Return the reference to the LRU list, call this function for read-only access + */ + @GuardedBy(anyOf = {"mService", "mProfileLock"}) + ArrayList getLruProcessesLOSP() { + return mLruProcesses; + } + + /** + * Return the reference to the LRU list, call this function for read/write access + */ + @GuardedBy({"mService", "mProfileLock"}) + ArrayList getLruProcessesLSP() { + return mLruProcesses; + } + + /** + * For test only + */ + @VisibleForTesting + @GuardedBy({"mService", "mProfileLock"}) + void setLruProcessServiceStartLSP(int pos) { + mLruProcessServiceStart = pos; + } + + @GuardedBy(anyOf = {"mService", "mProfileLock"}) + int getLruProcessServiceStartLOSP() { + return mLruProcessServiceStart; + } + + /** + * Iterate the whole LRU list, invoke the given {@code callback} with each of the ProcessRecord + * in that list. + * + * @param iterateForward If {@code true}, iterate the LRU list from the least recent used + * to most recent used ProcessRecord. + * @param callback The callback interface to accept the current ProcessRecord. + */ + @GuardedBy(anyOf = {"mService", "mProfileLock"}) + void forEachLruProcessesLOSP(boolean iterateForward, + @NonNull Consumer callback) { + if (iterateForward) { + for (int i = 0, size = mLruProcesses.size(); i < size; i++) { + callback.accept(mLruProcesses.get(i)); + } + } else { + for (int i = mLruProcesses.size() - 1; i >= 0; i--) { + callback.accept(mLruProcesses.get(i)); + } + } + } + + /** + * Search in the LRU list, invoke the given {@code callback} with each of the ProcessRecord + * in that list; if the callback returns a non-null object, halt the search, return that + * object as the return value of this search function. + * + * @param iterateForward If {@code true}, iterate the LRU list from the least recent used + * to most recent used ProcessRecord. + * @param callback The callback interface to accept the current ProcessRecord; if it returns + * a non-null object, the search will be halted and this object will be used + * as the return value of this search function. + */ + @GuardedBy(anyOf = {"mService", "mProfileLock"}) + R searchEachLruProcessesLOSP(boolean iterateForward, + @NonNull Function callback) { + if (iterateForward) { + for (int i = 0, size = mLruProcesses.size(); i < size; i++) { + R r; + if ((r = callback.apply(mLruProcesses.get(i))) != null) { + return r; + } + } + } else { + for (int i = mLruProcesses.size() - 1; i >= 0; i--) { + R r; + if ((r = callback.apply(mLruProcesses.get(i))) != null) { + return r; + } + } + } + return null; + } + + @GuardedBy(anyOf = {"mService", "mProfileLock"}) + boolean isInLruListLOSP(ProcessRecord app) { + return mLruProcesses.contains(app); + } + + @GuardedBy(anyOf = {"mService", "mProfileLock"}) + int getLruSeqLOSP() { + return mLruSeq; + } + + @GuardedBy(anyOf = {"mService", "mProfileLock"}) + MyProcessMap getProcessNamesLOSP() { + return mProcessNames; + } + @GuardedBy("mService") void dumpLruListHeaderLocked(PrintWriter pw) { pw.print(" Process LRU list (sorted by oom_adj, "); pw.print(mLruProcesses.size()); @@ -3673,7 +3845,8 @@ public final class ProcessList { pw.println("):"); } - void dumpLruEntryLocked(PrintWriter pw, int index, ProcessRecord proc, String prefix) { + @GuardedBy("mService") + private void dumpLruEntryLocked(PrintWriter pw, int index, ProcessRecord proc, String prefix) { pw.print(prefix); pw.print('#'); if (index < 10) { @@ -3681,15 +3854,16 @@ public final class ProcessList { } pw.print(index); pw.print(": "); - pw.print(makeOomAdjString(proc.setAdj, false)); + pw.print(makeOomAdjString(proc.mState.getSetAdj(), false)); pw.print(' '); - pw.print(makeProcStateString(proc.getCurProcState())); + pw.print(makeProcStateString(proc.mState.getCurProcState())); pw.print(' '); - ActivityManager.printCapabilitiesSummary(pw, proc.curCapability); + ActivityManager.printCapabilitiesSummary(pw, proc.mState.getCurCapability()); pw.print(' '); pw.print(proc.toShortString()); - if (proc.hasActivitiesOrRecentTasks() || proc.hasClientActivities() - || proc.treatLikeActivity) { + final ProcessServiceRecord psr = proc.mServices; + if (proc.hasActivitiesOrRecentTasks() || psr.hasClientActivities() + || psr.isTreatedLikeActivity()) { pw.print(" act:"); boolean printed = false; if (proc.hasActivities()) { @@ -3703,14 +3877,14 @@ public final class ProcessList { pw.print("recents"); printed = true; } - if (proc.hasClientActivities()) { + if (psr.hasClientActivities()) { if (printed) { pw.print("|"); } pw.print("client"); printed = true; } - if (proc.treatLikeActivity) { + if (psr.isTreatedLikeActivity()) { if (printed) { pw.print("|"); } @@ -3720,6 +3894,7 @@ public final class ProcessList { pw.println(); } + @GuardedBy("mService") boolean dumpLruLocked(PrintWriter pw, String dumpPackage, String prefix) { final int lruSize = mLruProcesses.size(); final String innerPrefix; @@ -3786,8 +3961,8 @@ public final class ProcessList { return true; } - @GuardedBy("mService") - void dumpProcessesLocked(FileDescriptor fd, PrintWriter pw, String[] args, + @GuardedBy({"mService", "mProcLock"}) + void dumpProcessesLSP(FileDescriptor fd, PrintWriter pw, String[] args, int opti, boolean dumpAll, String dumpPackage, int dumpAppId) { boolean needSep = false; int numPers = 0; @@ -3861,7 +4036,7 @@ public final class ProcessList { needSep = true; } - if (getLruSizeLocked() > 0) { + if (getLruSizeLOSP() > 0) { if (needSep) { pw.println(); } @@ -3871,12 +4046,12 @@ public final class ProcessList { needSep = true; } - mService.dumpOtherProcessesInfoLocked(fd, pw, dumpAll, dumpPackage, dumpAppId, numPers, + mService.dumpOtherProcessesInfoLSP(fd, pw, dumpAll, dumpPackage, dumpAppId, numPers, needSep); } - @GuardedBy("this") - void writeProcessesToProtoLocked(ProtoOutputStream proto, String dumpPackage) { + @GuardedBy({"mService", "mProcLock"}) + void writeProcessesToProtoLSP(ProtoOutputStream proto, String dumpPackage) { int numPers = 0; final int numOfNames = mProcessNames.getMap().size(); @@ -3910,9 +4085,9 @@ public final class ProcessList { mActiveUids.dumpProto(proto, dumpPackage, dumpAppId, ActivityManagerServiceDumpProcessesProto.ACTIVE_UIDS); - if (getLruSizeLocked() > 0) { + if (getLruSizeLOSP() > 0) { long lruToken = proto.start(ActivityManagerServiceDumpProcessesProto.LRU_PROCS); - int total = getLruSizeLocked(); + int total = getLruSizeLOSP(); proto.write(ActivityManagerServiceDumpProcessesProto.LruProcesses.SIZE, total); proto.write(ActivityManagerServiceDumpProcessesProto.LruProcesses.NON_ACT_AT, total - mLruProcessActivityStart); @@ -3924,7 +4099,7 @@ public final class ProcessList { proto.end(lruToken); } - mService.writeOtherProcessesInfoToProtoLocked(proto, dumpPackage, dumpAppId, numPers); + mService.writeOtherProcessesInfoToProtoLSP(proto, dumpPackage, dumpAppId, numPers); } private static ArrayList> sortProcessOomList( @@ -3944,14 +4119,18 @@ public final class ProcessList { @Override public int compare(Pair object1, Pair object2) { - if (object1.first.setAdj != object2.first.setAdj) { - return object1.first.setAdj > object2.first.setAdj ? -1 : 1; + final int adj = object2.first.mState.getSetAdj() - object1.first.mState.getSetAdj(); + if (adj != 0) { + return adj; } - if (object1.first.setProcState != object2.first.setProcState) { - return object1.first.setProcState > object2.first.setProcState ? -1 : 1; + final int procState = object2.first.mState.getSetProcState() + - object1.first.mState.getSetProcState(); + if (procState != 0) { + return procState; } - if (object1.second.intValue() != object2.second.intValue()) { - return object1.second.intValue() > object2.second.intValue() ? -1 : 1; + final int val = object2.second - object1.second; + if (val != 0) { + return val; } return 0; } @@ -3971,13 +4150,15 @@ public final class ProcessList { for (int i = list.size() - 1; i >= 0; i--) { ProcessRecord r = list.get(i).first; + final ProcessStateRecord state = r.mState; + final ProcessServiceRecord psr = r.mServices; long token = proto.start(fieldId); - String oomAdj = makeOomAdjString(r.setAdj, true); + String oomAdj = makeOomAdjString(state.getSetAdj(), true); proto.write(ProcessOomProto.PERSISTENT, r.isPersistent()); proto.write(ProcessOomProto.NUM, (origList.size() - 1) - list.get(i).second); proto.write(ProcessOomProto.OOM_ADJ, oomAdj); int schedGroup = ProcessOomProto.SCHED_GROUP_UNKNOWN; - switch (r.setSchedGroup) { + switch (state.getSetSchedGroup()) { case SCHED_GROUP_BACKGROUND: schedGroup = ProcessOomProto.SCHED_GROUP_BACKGROUND; break; @@ -3994,52 +4175,52 @@ public final class ProcessList { if (schedGroup != ProcessOomProto.SCHED_GROUP_UNKNOWN) { proto.write(ProcessOomProto.SCHED_GROUP, schedGroup); } - if (r.hasForegroundActivities()) { + if (state.hasForegroundActivities()) { proto.write(ProcessOomProto.ACTIVITIES, true); - } else if (r.hasForegroundServices()) { + } else if (psr.hasForegroundServices()) { proto.write(ProcessOomProto.SERVICES, true); } proto.write(ProcessOomProto.STATE, - makeProcStateProtoEnum(r.getCurProcState())); + makeProcStateProtoEnum(state.getCurProcState())); proto.write(ProcessOomProto.TRIM_MEMORY_LEVEL, r.mProfile.getTrimMemoryLevel()); r.dumpDebug(proto, ProcessOomProto.PROC); - proto.write(ProcessOomProto.ADJ_TYPE, r.adjType); - if (r.adjSource != null || r.adjTarget != null) { - if (r.adjTarget instanceof ComponentName) { - ComponentName cn = (ComponentName) r.adjTarget; + proto.write(ProcessOomProto.ADJ_TYPE, state.getAdjType()); + if (state.getAdjSource() != null || state.getAdjTarget() != null) { + if (state.getAdjTarget() instanceof ComponentName) { + ComponentName cn = (ComponentName) state.getAdjTarget(); cn.dumpDebug(proto, ProcessOomProto.ADJ_TARGET_COMPONENT_NAME); - } else if (r.adjTarget != null) { - proto.write(ProcessOomProto.ADJ_TARGET_OBJECT, r.adjTarget.toString()); + } else if (state.getAdjTarget() != null) { + proto.write(ProcessOomProto.ADJ_TARGET_OBJECT, state.getAdjTarget().toString()); } - if (r.adjSource instanceof ProcessRecord) { - ProcessRecord p = (ProcessRecord) r.adjSource; + if (state.getAdjSource() instanceof ProcessRecord) { + ProcessRecord p = (ProcessRecord) state.getAdjSource(); p.dumpDebug(proto, ProcessOomProto.ADJ_SOURCE_PROC); - } else if (r.adjSource != null) { - proto.write(ProcessOomProto.ADJ_SOURCE_OBJECT, r.adjSource.toString()); + } else if (state.getAdjSource() != null) { + proto.write(ProcessOomProto.ADJ_SOURCE_OBJECT, state.getAdjSource().toString()); } } if (inclDetails) { long detailToken = proto.start(ProcessOomProto.DETAIL); - proto.write(ProcessOomProto.Detail.MAX_ADJ, r.maxAdj); - proto.write(ProcessOomProto.Detail.CUR_RAW_ADJ, r.getCurRawAdj()); - proto.write(ProcessOomProto.Detail.SET_RAW_ADJ, r.setRawAdj); - proto.write(ProcessOomProto.Detail.CUR_ADJ, r.curAdj); - proto.write(ProcessOomProto.Detail.SET_ADJ, r.setAdj); + proto.write(ProcessOomProto.Detail.MAX_ADJ, state.getMaxAdj()); + proto.write(ProcessOomProto.Detail.CUR_RAW_ADJ, state.getCurRawAdj()); + proto.write(ProcessOomProto.Detail.SET_RAW_ADJ, state.getSetRawAdj()); + proto.write(ProcessOomProto.Detail.CUR_ADJ, state.getCurAdj()); + proto.write(ProcessOomProto.Detail.SET_ADJ, state.getSetAdj()); proto.write(ProcessOomProto.Detail.CURRENT_STATE, - makeProcStateProtoEnum(r.getCurProcState())); + makeProcStateProtoEnum(state.getCurProcState())); proto.write(ProcessOomProto.Detail.SET_STATE, - makeProcStateProtoEnum(r.setProcState)); + makeProcStateProtoEnum(state.getSetProcState())); proto.write(ProcessOomProto.Detail.LAST_PSS, DebugUtils.sizeValueToString( r.mProfile.getLastPss() * 1024, new StringBuilder())); proto.write(ProcessOomProto.Detail.LAST_SWAP_PSS, DebugUtils.sizeValueToString( r.mProfile.getLastSwapPss() * 1024, new StringBuilder())); proto.write(ProcessOomProto.Detail.LAST_CACHED_PSS, DebugUtils.sizeValueToString( r.mProfile.getLastCachedPss() * 1024, new StringBuilder())); - proto.write(ProcessOomProto.Detail.CACHED, r.isCached()); - proto.write(ProcessOomProto.Detail.EMPTY, r.empty); - proto.write(ProcessOomProto.Detail.HAS_ABOVE_CLIENT, r.hasAboveClient); + proto.write(ProcessOomProto.Detail.CACHED, state.isCached()); + proto.write(ProcessOomProto.Detail.EMPTY, state.isEmpty()); + proto.write(ProcessOomProto.Detail.HAS_ABOVE_CLIENT, psr.hasAboveClient()); - if (r.setProcState >= ActivityManager.PROCESS_STATE_SERVICE) { + if (state.getSetProcState() >= ActivityManager.PROCESS_STATE_SERVICE) { long lastCpuTime = r.mProfile.mLastCpuTime.get(); if (lastCpuTime != 0) { long uptimeSince = curUptime - service.mLastPowerCheckUptime; @@ -4073,9 +4254,11 @@ public final class ProcessList { for (int i = list.size() - 1; i >= 0; i--) { ProcessRecord r = list.get(i).first; - String oomAdj = makeOomAdjString(r.setAdj, false); + final ProcessStateRecord state = r.mState; + final ProcessServiceRecord psr = r.mServices; + String oomAdj = makeOomAdjString(state.getSetAdj(), false); char schedGroup; - switch (r.setSchedGroup) { + switch (state.getSetSchedGroup()) { case SCHED_GROUP_BACKGROUND: schedGroup = 'b'; break; @@ -4096,14 +4279,14 @@ public final class ProcessList { break; } char foreground; - if (r.hasForegroundActivities()) { + if (state.hasForegroundActivities()) { foreground = 'A'; - } else if (r.hasForegroundServices()) { + } else if (psr.hasForegroundServices()) { foreground = 'S'; } else { foreground = ' '; } - String procState = makeProcStateString(r.getCurProcState()); + String procState = makeProcStateString(state.getCurProcState()); pw.print(prefix); pw.print(r.isPersistent() ? persistentLabel : normalLabel); pw.print(" #"); @@ -4119,7 +4302,7 @@ public final class ProcessList { pw.print('/'); pw.print(procState); pw.print(' '); - ActivityManager.printCapabilitiesSummary(pw, r.curCapability); + ActivityManager.printCapabilitiesSummary(pw, state.getCurCapability()); pw.print(' '); pw.print(" t:"); if (r.mProfile.getTrimMemoryLevel() < 10) pw.print(' '); @@ -4127,25 +4310,25 @@ public final class ProcessList { pw.print(' '); pw.print(r.toShortString()); pw.print(" ("); - pw.print(r.adjType); + pw.print(state.getAdjType()); pw.println(')'); - if (r.adjSource != null || r.adjTarget != null) { + if (state.getAdjSource() != null || state.getAdjTarget() != null) { pw.print(prefix); pw.print(" "); - if (r.adjTarget instanceof ComponentName) { - pw.print(((ComponentName) r.adjTarget).flattenToShortString()); - } else if (r.adjTarget != null) { - pw.print(r.adjTarget.toString()); + if (state.getAdjTarget() instanceof ComponentName) { + pw.print(((ComponentName) state.getAdjTarget()).flattenToShortString()); + } else if (state.getAdjTarget() != null) { + pw.print(state.getAdjTarget().toString()); } else { pw.print("{null}"); } pw.print("<="); - if (r.adjSource instanceof ProcessRecord) { + if (state.getAdjSource() instanceof ProcessRecord) { pw.print("Proc{"); - pw.print(((ProcessRecord) r.adjSource).toShortString()); + pw.print(((ProcessRecord) state.getAdjSource()).toShortString()); pw.println("}"); - } else if (r.adjSource != null) { - pw.println(r.adjSource.toString()); + } else if (state.getAdjSource() != null) { + pw.println(state.getAdjSource().toString()); } else { pw.println("{null}"); } @@ -4153,16 +4336,15 @@ public final class ProcessList { if (inclDetails) { pw.print(prefix); pw.print(" "); - pw.print("oom: max="); pw.print(r.maxAdj); - pw.print(" curRaw="); pw.print(r.getCurRawAdj()); - pw.print(" setRaw="); pw.print(r.setRawAdj); - pw.print(" cur="); pw.print(r.curAdj); - pw.print(" set="); pw.println(r.setAdj); + pw.print("oom: max="); pw.print(state.getMaxAdj()); + pw.print(" curRaw="); pw.print(state.getCurRawAdj()); + pw.print(" setRaw="); pw.print(state.getSetRawAdj()); + pw.print(" cur="); pw.print(state.getCurAdj()); + pw.print(" set="); pw.println(state.getSetAdj()); pw.print(prefix); pw.print(" "); - pw.print("state: cur="); pw.print( - makeProcStateString(r.getCurProcState())); - pw.print(" set="); pw.print(makeProcStateString(r.setProcState)); + pw.print("state: cur="); pw.print(makeProcStateString(state.getCurProcState())); + pw.print(" set="); pw.print(makeProcStateString(state.getSetProcState())); pw.print(" lastPss="); DebugUtils.printSizeValue(pw, r.mProfile.getLastPss() * 1024); pw.print(" lastSwapPss="); @@ -4172,11 +4354,11 @@ public final class ProcessList { pw.println(); pw.print(prefix); pw.print(" "); - pw.print("cached="); pw.print(r.isCached()); - pw.print(" empty="); pw.print(r.empty); - pw.print(" hasAboveClient="); pw.println(r.hasAboveClient); + pw.print("cached="); pw.print(state.isCached()); + pw.print(" empty="); pw.print(state.isEmpty()); + pw.print(" hasAboveClient="); pw.println(psr.hasAboveClient()); - if (r.setProcState >= ActivityManager.PROCESS_STATE_SERVICE) { + if (state.getSetProcState() >= ActivityManager.PROCESS_STATE_SERVICE) { long lastCpuTime = r.mProfile.mLastCpuTime.get(); if (lastCpuTime != 0) { long timeUsed = r.mProfile.mCurCpuTime.get() - lastCpuTime; @@ -4212,9 +4394,10 @@ public final class ProcessList { pw.println(")"); } + @GuardedBy("mService") boolean dumpOomLocked(FileDescriptor fd, PrintWriter pw, boolean needSep, String[] args, int opti, boolean dumpAll, String dumpPackage, boolean inclGc) { - if (getLruSizeLocked() > 0) { + if (getLruSizeLOSP() > 0) { if (needSep) pw.println(); needSep = true; pw.println(" OOM levels:"); @@ -4235,14 +4418,14 @@ public final class ProcessList { printOomLevel(pw, "CACHED_APP_MAX_ADJ", CACHED_APP_MAX_ADJ); if (needSep) pw.println(); - pw.print(" Process OOM control ("); pw.print(getLruSizeLocked()); + pw.print(" Process OOM control ("); pw.print(getLruSizeLOSP()); pw.print(" total, non-act at "); - pw.print(getLruSizeLocked() - mLruProcessActivityStart); + pw.print(getLruSizeLOSP() - mLruProcessActivityStart); pw.print(", non-svc at "); - pw.print(getLruSizeLocked() - mLruProcessServiceStart); + pw.print(getLruSizeLOSP() - mLruProcessServiceStart); pw.println("):"); - dumpProcessOomList(pw, mService, mLruProcesses, " ", "Proc", "PERS", true, - dumpPackage); + dumpProcessOomList(pw, mService, mLruProcesses, + " ", "Proc", "PERS", true, dumpPackage); needSep = true; } @@ -4396,8 +4579,8 @@ public final class ProcessList { mProcessObservers.finishBroadcast(); } - @GuardedBy("mService") - ArrayList collectProcessesLocked(int start, boolean allPkgs, String[] args) { + @GuardedBy(anyOf = {"mService", "mProcLock"}) + ArrayList collectProcessesLOSP(int start, boolean allPkgs, String[] args) { ArrayList procs; if (args != null && args.length > start && args[start].charAt(0) != '-') { @@ -4409,7 +4592,7 @@ public final class ProcessList { } for (int i = mLruProcesses.size() - 1; i >= 0; i--) { ProcessRecord proc = mLruProcesses.get(i); - if (proc.pid > 0 && proc.pid == pid) { + if (proc.getPid() > 0 && proc.getPid() == pid) { procs.add(proc); } else if (allPkgs && proc.getPkgList() != null && proc.getPkgList().containsKey(args[start])) { @@ -4427,12 +4610,12 @@ public final class ProcessList { return procs; } - @GuardedBy("mService") - void updateApplicationInfoLocked(List packagesToUpdate, int userId, + @GuardedBy(anyOf = {"mService", "mProcLock"}) + void updateApplicationInfoLOSP(List packagesToUpdate, int userId, boolean updateFrameworkRes) { for (int i = mLruProcesses.size() - 1; i >= 0; i--) { final ProcessRecord app = mLruProcesses.get(i); - if (app.thread == null) { + if (app.getThread() == null) { continue; } @@ -4446,14 +4629,14 @@ public final class ProcessList { final ApplicationInfo ai = AppGlobals.getPackageManager() .getApplicationInfo(packageName, STOCK_PM_FLAGS, app.userId); if (ai != null) { - app.thread.scheduleApplicationInfoChanged(ai); + app.getThread().scheduleApplicationInfoChanged(ai); if (ai.packageName.equals(app.info.packageName)) { app.info = ai; } } } catch (RemoteException e) { Slog.w(TAG, String.format("Failed to update %s ApplicationInfo for %s", - packageName, app)); + packageName, app)); } } }); @@ -4465,14 +4648,15 @@ public final class ProcessList { boolean foundProcess = false; for (int i = mLruProcesses.size() - 1; i >= 0; i--) { ProcessRecord r = mLruProcesses.get(i); - if (r.thread != null && (userId == UserHandle.USER_ALL || r.userId == userId)) { + final IApplicationThread thread = r.getThread(); + if (thread != null && (userId == UserHandle.USER_ALL || r.userId == userId)) { try { for (int index = packages.length - 1; index >= 0 && !foundProcess; index--) { if (packages[index].equals(r.info.packageName)) { foundProcess = true; } } - r.thread.dispatchPackageBroadcast(cmd, packages); + thread.dispatchPackageBroadcast(cmd, packages); } catch (RemoteException ex) { } } @@ -4487,15 +4671,15 @@ public final class ProcessList { } /** Returns the uid's process state or PROCESS_STATE_NONEXISTENT if not running */ - @GuardedBy("mService") - int getUidProcStateLocked(int uid) { + @GuardedBy(anyOf = {"mService", "mProcLock"}) + int getUidProcStateLOSP(int uid) { UidRecord uidRec = mActiveUids.get(uid); return uidRec == null ? PROCESS_STATE_NONEXISTENT : uidRec.getCurProcState(); } /** Returns the UidRecord for the given uid, if it exists. */ - @GuardedBy("mService") - UidRecord getUidRecordLocked(int uid) { + @GuardedBy(anyOf = {"mService", "mProcLock"}) + UidRecord getUidRecordLOSP(int uid) { return mActiveUids.get(uid); } @@ -4512,10 +4696,10 @@ public final class ProcessList { continue; } final UidRecord uidRec = mActiveUids.valueAt(i); - if (!uidRec.idle) { + if (!uidRec.isIdle()) { continue; } - mService.doStopUidLocked(uidRec.uid, uidRec); + mService.doStopUidLocked(uidRec.getUid(), uidRec); } } @@ -4529,14 +4713,16 @@ public final class ProcessList { * {@link #NETWORK_STATE_NO_CHANGE}. */ @VisibleForTesting + @GuardedBy(anyOf = {"mService", "mProcLock"}) int getBlockStateForUid(UidRecord uidRec) { // Denotes whether uid's process state is currently allowed network access. final boolean isAllowed = isProcStateAllowedWhileIdleOrPowerSaveMode(uidRec.getCurProcState()) || isProcStateAllowedWhileOnRestrictBackground(uidRec.getCurProcState()); // Denotes whether uid's process state was previously allowed network access. - final boolean wasAllowed = isProcStateAllowedWhileIdleOrPowerSaveMode(uidRec.setProcState) - || isProcStateAllowedWhileOnRestrictBackground(uidRec.setProcState); + final boolean wasAllowed = + isProcStateAllowedWhileIdleOrPowerSaveMode(uidRec.getSetProcState()) + || isProcStateAllowedWhileOnRestrictBackground(uidRec.getSetProcState()); // When the uid is coming to foreground, AMS should inform the app thread that it should // block for the network rules to get updated before launching an activity. @@ -4557,8 +4743,8 @@ public final class ProcessList { * {@link ProcessList#mProcStateSeqCounter} and notifies the app if it needs to block. */ @VisibleForTesting - @GuardedBy("mService") - void incrementProcStateSeqAndNotifyAppsLocked(ActiveUids activeUids) { + @GuardedBy(anyOf = {"mService", "mProcLock"}) + void incrementProcStateSeqAndNotifyAppsLOSP(ActiveUids activeUids) { if (mService.mWaitForNetworkTimeoutMs <= 0) { return; } @@ -4567,14 +4753,14 @@ public final class ProcessList { for (int i = activeUids.size() - 1; i >= 0; --i) { final UidRecord uidRec = activeUids.valueAt(i); // If the network is not restricted for uid, then nothing to do here. - if (!mService.mInjector.isNetworkRestrictedForUid(uidRec.uid)) { + if (!mService.mInjector.isNetworkRestrictedForUid(uidRec.getUid())) { continue; } - if (!UserHandle.isApp(uidRec.uid) || !uidRec.hasInternetPermission) { + if (!UserHandle.isApp(uidRec.getUid()) || !uidRec.hasInternetPermission) { continue; } // If process state is not changed, then there's nothing to do. - if (uidRec.setProcState == uidRec.getCurProcState()) { + if (uidRec.getSetProcState() == uidRec.getCurProcState()) { continue; } final int blockState = getBlockStateForUid(uidRec); @@ -4589,7 +4775,7 @@ public final class ProcessList { if (blockingUids == null) { blockingUids = new ArrayList<>(); } - blockingUids.add(uidRec.uid); + blockingUids.add(uidRec.getUid()); } else { if (DEBUG_NETWORK) { Slog.d(TAG_NETWORK, "uid going to background, notifying all blocking" @@ -4612,15 +4798,16 @@ public final class ProcessList { if (!blockingUids.contains(app.uid)) { continue; } - if (!app.killedByAm && app.thread != null) { - final UidRecord uidRec = getUidRecordLocked(app.uid); + final IApplicationThread thread = app.getThread(); + if (!app.isKilledByAm() && thread != null) { + final UidRecord uidRec = getUidRecordLOSP(app.uid); try { if (DEBUG_NETWORK) { Slog.d(TAG_NETWORK, "Informing app thread that it needs to block: " + uidRec); } if (uidRec != null) { - app.thread.setNetworkBlockSeq(uidRec.curProcStateSeq); + thread.setNetworkBlockSeq(uidRec.curProcStateSeq); } } catch (RemoteException ignored) { } @@ -4692,7 +4879,7 @@ public final class ProcessList { Slog.i(TAG, "note: " + app + " died, saving the exit info"); } - Watchdog.getInstance().processDied(app.processName, app.pid); + Watchdog.getInstance().processDied(app.processName, app.getPid()); mAppExitInfoTracker.scheduleNoteProcessDied(app); } @@ -4814,10 +5001,10 @@ public final class ProcessList { } final Bundle bundle = new Bundle(); - bundle.putInt(EXTRA_PID, app.pid); + bundle.putInt(EXTRA_PID, app.getPid()); bundle.putInt(EXTRA_UID, app.uid); // Since the pid could be reused, let's get the actual start time of each process - bundle.putLong(EXTRA_TIMESTAMP, app.startTime); + bundle.putLong(EXTRA_TIMESTAMP, app.getStartTime()); bundle.putString(EXTRA_REASON, reason); bundle.putInt(EXTRA_REQUESTER, requester); List list = mWorkItems.get(app.uid); @@ -4909,13 +5096,14 @@ public final class ProcessList { app = mService.mPidsSelfLocked.get(pid); } - if (app == null || app.pid != pid || app.uid != uid || app.startTime != timestamp) { + if (app == null || app.getPid() != pid || app.uid != uid + || app.getStartTime() != timestamp) { // This process record has been reused for another process, meaning the old process // has been gone. return true; } - if (app.getPkgList().forEachPackage(pkgName -> { + if (app.getPkgList().searchEachPackage(pkgName -> { if (mService.mConstants.IMPERCEPTIBLE_KILL_EXEMPT_PACKAGES.contains(pkgName)) { // One of the packages in this process is exempted return Boolean.TRUE; @@ -4926,12 +5114,12 @@ public final class ProcessList { } if (mService.mConstants.IMPERCEPTIBLE_KILL_EXEMPT_PROC_STATES.contains( - app.getReportedProcState())) { + app.mState.getReportedProcState())) { // We need to reschedule it. return false; } - app.kill(reason, ApplicationExitInfo.REASON_OTHER, + app.killLocked(reason, ApplicationExitInfo.REASON_OTHER, ApplicationExitInfo.SUBREASON_IMPERCEPTIBLE, true); if (!app.isolated) { diff --git a/services/core/java/com/android/server/am/ProcessProfileRecord.java b/services/core/java/com/android/server/am/ProcessProfileRecord.java index 9fd2bd798c044..e533cc3512d35 100644 --- a/services/core/java/com/android/server/am/ProcessProfileRecord.java +++ b/services/core/java/com/android/server/am/ProcessProfileRecord.java @@ -26,6 +26,7 @@ import android.os.SystemClock; import android.util.DebugUtils; import android.util.TimeUtils; +import com.android.internal.annotations.CompositeRWLock; import com.android.internal.annotations.GuardedBy; import com.android.internal.app.procstats.ProcessState; import com.android.internal.app.procstats.ProcessStats; @@ -141,13 +142,13 @@ final class ProcessProfileRecord { /** * Last selected memory trimming level. */ - @GuardedBy("mService") + @CompositeRWLock({"mService", "mProcLock"}) private int mTrimMemoryLevel; /** * Want to clean up resources from showing UI? */ - @GuardedBy("mService") + @GuardedBy("mProcLock") private boolean mPendingUiClean; /** @@ -164,7 +165,7 @@ final class ProcessProfileRecord { /** * When we last told the app that memory is low. */ - @GuardedBy("mService") + @CompositeRWLock({"mService", "mProfilerLock"}) private long mLastLowMemory; /** @@ -193,9 +194,12 @@ final class ProcessProfileRecord { @GuardedBy("mProfilerLock") private long mLastStateTime; + private final ActivityManagerGlobalLock mProcLock; + ProcessProfileRecord(final ProcessRecord app) { mApp = app; mService = app.mService; + mProcLock = mService.mProcLock; mProfilerLock = mService.mAppProfiler.mProfilerLock; } @@ -410,22 +414,22 @@ final class ProcessProfileRecord { mPssStatType = pssStatType; } - @GuardedBy("mService") + @GuardedBy(anyOf = {"mService", "mProcLock"}) int getTrimMemoryLevel() { return mTrimMemoryLevel; } - @GuardedBy("mService") + @GuardedBy({"mService", "mProcLock"}) void setTrimMemoryLevel(int trimMemoryLevel) { mTrimMemoryLevel = trimMemoryLevel; } - @GuardedBy("mService") + @GuardedBy("mProcLock") boolean hasPendingUiClean() { return mPendingUiClean; } - @GuardedBy("mService") + @GuardedBy("mProcLock") void setPendingUiClean(boolean pendingUiClean) { mPendingUiClean = pendingUiClean; mApp.getWindowProcessController().setPendingUiClean(pendingUiClean); @@ -449,12 +453,12 @@ final class ProcessProfileRecord { mLastRequestedGc = lastRequestedGc; } - @GuardedBy("mService") + @GuardedBy(anyOf = {"mService", "mProfilerLock"}) long getLastLowMemory() { return mLastLowMemory; } - @GuardedBy("mService") + @GuardedBy({"mService", "mProfilerLock"}) void setLastLowMemory(long lastLowMemory) { mLastLowMemory = lastLowMemory; } @@ -593,11 +597,11 @@ final class ProcessProfileRecord { } @GuardedBy({"mService", "mProfilerLock"}) - void updateProcState(ProcessRecord app) { - mSetProcState = app.getCurProcState(); - mSetAdj = app.curAdj; - mCurRawAdj = app.getCurRawAdj(); - mLastStateTime = app.lastStateTime; + void updateProcState(ProcessStateRecord state) { + mSetProcState = state.getCurProcState(); + mSetAdj = state.getCurAdj(); + mCurRawAdj = state.getCurRawAdj(); + mLastStateTime = state.getLastStateTime(); } @GuardedBy("mService") diff --git a/services/core/java/com/android/server/am/ProcessProviderRecord.java b/services/core/java/com/android/server/am/ProcessProviderRecord.java new file mode 100644 index 0000000000000..751e8a821ab1f --- /dev/null +++ b/services/core/java/com/android/server/am/ProcessProviderRecord.java @@ -0,0 +1,175 @@ +/* + * 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 android.util.ArrayMap; +import android.util.TimeUtils; + +import com.android.internal.annotations.GuardedBy; + +import java.io.PrintWriter; +import java.util.ArrayList; + +/** + * The state info of all content providers in the process. + */ +final class ProcessProviderRecord { + final ProcessRecord mApp; + private final ActivityManagerService mService; + + /** + * The last time someone else was using a provider in this process. + */ + private long mLastProviderTime; + + /** + * class (String) -> ContentProviderRecord. + */ + private final ArrayMap mPubProviders = new ArrayMap<>(); + + /** + * All ContentProviderRecord process is using. + */ + private final ArrayList mConProviders = new ArrayList<>(); + + long getLastProviderTime() { + return mLastProviderTime; + } + + void setLastProviderTime(long lastProviderTime) { + mLastProviderTime = lastProviderTime; + } + + boolean hasProvider(String name) { + return mPubProviders.containsKey(name); + } + + ContentProviderRecord getProvider(String name) { + return mPubProviders.get(name); + } + + int numberOfProviders() { + return mPubProviders.size(); + } + + ContentProviderRecord getProviderAt(int index) { + return mPubProviders.valueAt(index); + } + + void installProvider(String name, ContentProviderRecord provider) { + mPubProviders.put(name, provider); + } + + void removeProvider(String name) { + mPubProviders.remove(name); + } + + void ensureProviderCapacity(int capacity) { + mPubProviders.ensureCapacity(capacity); + } + + int numberOfProviderConnections() { + return mConProviders.size(); + } + + ContentProviderConnection getProviderConnectionAt(int index) { + return mConProviders.get(index); + } + + void addProviderConnection(ContentProviderConnection connection) { + mConProviders.add(connection); + } + + boolean removeProviderConnection(ContentProviderConnection connection) { + return mConProviders.remove(connection); + } + + ProcessProviderRecord(ProcessRecord app) { + mApp = app; + mService = app.mService; + } + + /** + * @return Should the process restart or not. + */ + @GuardedBy("mService") + boolean onCleanupApplicationRecordLocked(boolean allowRestart) { + boolean restart = false; + // Remove published content providers. + for (int i = mPubProviders.size() - 1; i >= 0; i--) { + final ContentProviderRecord cpr = mPubProviders.valueAt(i); + if (cpr.proc != mApp) { + // If the hosting process record isn't really us, bail out + continue; + } + final boolean alwaysRemove = mApp.mErrorState.isBad() || !allowRestart; + final boolean inLaunching = mService.mCpHelper + .removeDyingProviderLocked(mApp, cpr, alwaysRemove); + if (!alwaysRemove && inLaunching && cpr.hasConnectionOrHandle()) { + // We left the provider in the launching list, need to + // restart it. + restart = true; + } + + cpr.provider = null; + cpr.setProcess(null); + } + mPubProviders.clear(); + + // Take care of any launching providers waiting for this process. + if (mService.mCpHelper.cleanupAppInLaunchingProvidersLocked(mApp, false)) { + mService.mProcessList.noteProcessDiedLocked(mApp); + restart = true; + } + + // Unregister from connected content providers. + if (!mConProviders.isEmpty()) { + for (int i = mConProviders.size() - 1; i >= 0; i--) { + final ContentProviderConnection conn = mConProviders.get(i); + conn.provider.connections.remove(conn); + mService.stopAssociationLocked(mApp.uid, mApp.processName, conn.provider.uid, + conn.provider.appInfo.longVersionCode, conn.provider.name, + conn.provider.info.processName); + } + mConProviders.clear(); + } + + return restart; + } + + void dump(PrintWriter pw, String prefix, long nowUptime) { + if (mLastProviderTime > 0) { + pw.print(prefix); pw.print("lastProviderTime="); + TimeUtils.formatDuration(mLastProviderTime, nowUptime, pw); + pw.println(); + } + if (mPubProviders.size() > 0) { + pw.print(prefix); pw.println("Published Providers:"); + for (int i = 0, size = mPubProviders.size(); i < size; i++) { + pw.print(prefix); pw.print(" - "); pw.println(mPubProviders.keyAt(i)); + pw.print(prefix); pw.print(" -> "); pw.println(mPubProviders.valueAt(i)); + } + } + if (mConProviders.size() > 0) { + pw.print(prefix); pw.println("Connected Providers:"); + for (int i = 0, size = mConProviders.size(); i < size; i++) { + pw.print(prefix); pw.print(" - "); + pw.println(mConProviders.get(i).toShortString()); + } + } + } +} diff --git a/services/core/java/com/android/server/am/ProcessReceiverRecord.java b/services/core/java/com/android/server/am/ProcessReceiverRecord.java new file mode 100644 index 0000000000000..8d3e9669ea004 --- /dev/null +++ b/services/core/java/com/android/server/am/ProcessReceiverRecord.java @@ -0,0 +1,106 @@ +/* + * 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 android.util.ArraySet; + +import com.android.internal.annotations.GuardedBy; + +import java.io.PrintWriter; + +/** + * The state info of all broadcast receivers in the process. + */ +final class ProcessReceiverRecord { + final ProcessRecord mApp; + private final ActivityManagerService mService; + + /** + * mReceivers currently running in the app. + */ + private final ArraySet mCurReceivers = new ArraySet(); + + /** + * All IIntentReceivers that are registered from this process. + */ + private final ArraySet mReceivers = new ArraySet<>(); + + int numberOfCurReceivers() { + return mCurReceivers.size(); + } + + BroadcastRecord getCurReceiverAt(int index) { + return mCurReceivers.valueAt(index); + } + + boolean hasCurReceiver(BroadcastRecord receiver) { + return mCurReceivers.contains(receiver); + } + + void addCurReceiver(BroadcastRecord receiver) { + mCurReceivers.add(receiver); + } + + void removeCurReceiver(BroadcastRecord receiver) { + mCurReceivers.remove(receiver); + } + + int numberOfReceivers() { + return mReceivers.size(); + } + + ReceiverList getReceiverAt(int index) { + return mReceivers.valueAt(index); + } + + void addReceiver(ReceiverList receiver) { + mReceivers.add(receiver); + } + + void removeReceiver(ReceiverList receiver) { + mReceivers.remove(receiver); + } + + ProcessReceiverRecord(ProcessRecord app) { + mApp = app; + mService = app.mService; + } + + @GuardedBy("mService") + void onCleanupApplicationRecordLocked() { + // Unregister any mReceivers. + for (int i = mReceivers.size() - 1; i >= 0; i--) { + mService.removeReceiverLocked(mReceivers.valueAt(i)); + } + mReceivers.clear(); + } + + void dump(PrintWriter pw, String prefix, long nowUptime) { + if (!mCurReceivers.isEmpty()) { + pw.print(prefix); pw.println("Current mReceivers:"); + for (int i = 0, size = mCurReceivers.size(); i < size; i++) { + pw.print(prefix); pw.print(" - "); pw.println(mCurReceivers.valueAt(i)); + } + } + if (mReceivers.size() > 0) { + pw.print(prefix); pw.println("mReceivers:"); + for (int i = 0, size = mReceivers.size(); i < size; i++) { + pw.print(prefix); pw.print(" - "); pw.println(mReceivers.valueAt(i)); + } + } + } +} diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index 52ff427f3c84c..21be93a62173c 100644 --- a/services/core/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java @@ -16,89 +16,50 @@ package com.android.server.am; -import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND; -import static android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND; -import static android.Manifest.permission.SYSTEM_ALERT_WINDOW; -import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE; -import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT; -import static android.content.pm.PackageManager.PERMISSION_GRANTED; -import static android.os.Process.NFC_UID; -import static android.os.Process.ROOT_UID; -import static android.os.Process.SHELL_UID; -import static android.os.Process.SYSTEM_UID; - -import static com.android.server.Watchdog.NATIVE_STACKS_OF_INTEREST; -import static com.android.server.am.ActiveServices.FGS_FEATURE_ALLOWED_BY_BACKGROUND_ACTIVITY_PERMISSION; -import static com.android.server.am.ActiveServices.FGS_FEATURE_ALLOWED_BY_BACKGROUND_FGS_PERMISSION; -import static com.android.server.am.ActiveServices.FGS_FEATURE_ALLOWED_BY_COMPANION_APP; -import static com.android.server.am.ActiveServices.FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST; -import static com.android.server.am.ActiveServices.FGS_FEATURE_ALLOWED_BY_DEVICE_OWNER; -import static com.android.server.am.ActiveServices.FGS_FEATURE_ALLOWED_BY_PROC_STATE; -import static com.android.server.am.ActiveServices.FGS_FEATURE_ALLOWED_BY_PROFILE_OWNER; -import static com.android.server.am.ActiveServices.FGS_FEATURE_ALLOWED_BY_SYSTEM_ALERT_WINDOW_PERMISSION; -import static com.android.server.am.ActiveServices.FGS_FEATURE_ALLOWED_BY_SYSTEM_UID; -import static com.android.server.am.ActiveServices.FGS_FEATURE_DENIED; -import static com.android.server.am.ActiveServices.fgsCodeToString; -import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ANR; -import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_OOM_ADJ; import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.am.ActivityManagerService.MY_PID; import android.annotation.Nullable; import android.app.ActivityManager; -import android.app.ApplicationErrorReport; import android.app.ApplicationExitInfo; import android.app.ApplicationExitInfo.Reason; import android.app.ApplicationExitInfo.SubReason; -import android.app.Dialog; import android.app.IApplicationThread; -import android.content.ComponentName; -import android.content.Context; import android.content.pm.ApplicationInfo; -import android.content.pm.IncrementalStatesInfo; -import android.content.pm.PackageManagerInternal; import android.content.pm.ProcessInfo; -import android.content.pm.ServiceInfo; import android.content.pm.VersionedPackage; import android.content.res.CompatibilityInfo; import android.os.Binder; import android.os.IBinder; -import android.os.Message; import android.os.Process; import android.os.RemoteException; import android.os.SystemClock; import android.os.Trace; import android.os.UserHandle; -import android.provider.Settings; import android.server.ServerProtoEnums; import android.util.ArrayMap; import android.util.ArraySet; import android.util.DebugUtils; import android.util.EventLog; import android.util.Slog; -import android.util.SparseArray; import android.util.TimeUtils; import android.util.proto.ProtoOutputStream; +import com.android.internal.annotations.CompositeRWLock; +import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.procstats.ProcessState; import com.android.internal.app.procstats.ProcessStats; -import com.android.internal.os.ProcessCpuTracker; import com.android.internal.os.Zygote; import com.android.internal.util.FrameworkStatsLog; -import com.android.server.MemoryPressureUtil; import com.android.server.wm.WindowProcessController; import com.android.server.wm.WindowProcessListener; -import java.io.File; import java.io.PrintWriter; -import java.io.StringWriter; -import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Objects; -import java.util.function.Consumer; /** * Full information about a particular process that @@ -108,6 +69,12 @@ class ProcessRecord implements WindowProcessListener { static final String TAG = TAG_WITH_CLASS_NAME ? "ProcessRecord" : TAG_AM; final ActivityManagerService mService; // where we came from + private final ActivityManagerGlobalLock mProcLock; + + // ========================================================= + // Basic info of the process, immutable or semi-immutable over + // the lifecycle of the process + // ========================================================= volatile ApplicationInfo info; // all about the first app in the process final ProcessInfo processInfo; // if non-null, process-specific manifest info final boolean isolated; // true if this is a special isolated process @@ -117,239 +84,288 @@ class ProcessRecord implements WindowProcessListener { final String processName; // name of the process /** - * List of packages running in the process + * Overall state of process's uid. + */ + @CompositeRWLock({"mService", "mProcLock"}) + private UidRecord mUidRecord; + + /** + * List of packages running in the process. */ private final PackageList mPkgList = new PackageList(this); - UidRecord uidRecord; // overall state of process's uid. - ArraySet pkgDeps; // additional packages we have a dependency on - IApplicationThread thread; // the actual proc... may be null only if - // 'persistent' is true (in which case we - // are in the process of launching the app) - int pid; // The process of this application; 0 if none - String procStatFile; // path to /proc//stat - int[] gids; // The gids this process was launched with - private String mRequiredAbi;// The ABI this process was launched with - String instructionSet; // The instruction set this process was launched with - boolean starting; // True if the process is being started - long lastActivityTime; // For managing the LRU list - long lastStateTime; // Last time setProcState changed - int maxAdj; // Maximum OOM adjustment for this process - private int mCurRawAdj; // Current OOM unlimited adjustment for this process - int setRawAdj; // Last set OOM unlimited adjustment for this process - int curAdj; // Current OOM adjustment for this process - int setAdj; // Last set OOM adjustment for this process - int verifiedAdj; // The last adjustment that was verified as actually being set - int curCapability; // Current capability flags of this process. For example, - // PROCESS_CAPABILITY_FOREGROUND_LOCATION is one capability. - int setCapability; // Last set capability flags. - long lastCompactTime; // The last time that this process was compacted - int reqCompactAction; // The most recent compaction action requested for this app. - int lastCompactAction; // The most recent compaction action performed for this app. - boolean frozen; // True when the process is frozen. - boolean freezerOverride; // An override on the freeze state is in progress. - long freezeUnfreezeTime; // Last time the app was (un)frozen, 0 for never - boolean shouldNotFreeze; // True if a process has a WPRI binding from an unfrozen process - private int mCurSchedGroup; // Currently desired scheduling class - int setSchedGroup; // Last set to background scheduling class - private int mCurProcState = PROCESS_STATE_NONEXISTENT; // Currently computed process state - private int mRepProcState = PROCESS_STATE_NONEXISTENT; // Last reported process state - private int mCurRawProcState = PROCESS_STATE_NONEXISTENT; // Temp state during computation - int setProcState = PROCESS_STATE_NONEXISTENT; // Last set process state in process tracker - int savedPriority; // Previous priority value if we're switching to non-SCHED_OTHER - int renderThreadTid; // TID for RenderThread - ServiceRecord connectionService; // Service that applied current connectionGroup/Importance - int connectionGroup; // Last group set by a connection - int connectionImportance; // Last importance set by a connection - boolean serviceb; // Process currently is on the service B list - boolean serviceHighRam; // We are forcing to service B list due to its RAM use - boolean notCachedSinceIdle; // Has this process not been in a cached state since last idle? - private boolean mHasClientActivities; // Are there any client services with activities? - boolean hasStartedServices; // Are there any started services running in this process? - private boolean mHasForegroundServices; // Running any services that are foreground? - private int mFgServiceTypes; // Type of foreground service, if there is a foreground service. - private int mRepFgServiceTypes; // Last reported foreground service types. - private boolean mHasForegroundActivities; // Running any activities that are foreground? - boolean repForegroundActivities; // Last reported foreground activities. - boolean systemNoUi; // This is a system process, but not currently showing UI. - boolean hasShownUi; // Has UI been shown in this process since it was started? - private boolean mHasTopUi; // Is this process currently showing a non-activity UI that the user - // is interacting with? E.g. The status bar when it is expanded, but - // not when it is minimized. When true the - // process will be set to use the ProcessList#SCHED_GROUP_TOP_APP - // scheduling group to boost performance. - private boolean mHasOverlayUi; // Is the process currently showing a non-activity UI that - // overlays on-top of activity UIs on screen. E.g. display a window - // of type - // android.view.WindowManager.LayoutParams#TYPE_APPLICATION_OVERLAY - // When true the process will oom adj score will be set to - // ProcessList#PERCEPTIBLE_APP_ADJ at minimum to reduce the chance - // of the process getting killed. - boolean runningRemoteAnimation; // Is the process currently running a RemoteAnimation? When true - // the process will be set to use the - // ProcessList#SCHED_GROUP_TOP_APP scheduling group to boost - // performance, as well as oom adj score will be set to - // ProcessList#VISIBLE_APP_ADJ at minimum to reduce the chance - // of the process getting killed. - boolean hasAboveClient; // Bound using BIND_ABOVE_CLIENT, so want to be lower - boolean treatLikeActivity; // Bound using BIND_TREAT_LIKE_ACTIVITY - boolean bad; // True if disabled in the bad process list - boolean killedByAm; // True when proc has been killed by activity manager, not for RAM - boolean killed; // True once we know the process has been killed - boolean procStateChanged; // Keep track of whether we changed 'setAdj'. - boolean reportedInteraction;// Whether we have told usage stats about it being an interaction - boolean unlocked; // True when proc was started in user unlocked state - private long mInteractionEventTime; // The time we sent the last interaction event - private long mFgInteractionTime; // When we became foreground for interaction purposes - String waitingToKill; // Process is waiting to be killed when in the bg, and reason - Object forcingToImportant; // Token that is forcing this process to be important - int adjSeq; // Sequence id for identifying oom_adj assignment cycles - int completedAdjSeq; // Sequence id for identifying oom_adj assignment cycles - boolean containsCycle; // Whether this app has encountered a cycle in the most recent update - int lruSeq; // Sequence id for identifying LRU update cycles - CompatibilityInfo compat; // last used compatibility mode - IBinder.DeathRecipient deathRecipient; // Who is watching for the death. - private ActiveInstrumentation mInstr; // Set to currently active instrumentation running in - // process. - private boolean mUsingWrapper; // Set to true when process was launched with a wrapper attached - final ArraySet curReceivers = new ArraySet();// receivers currently running in the app - private long mWhenUnimportant; // When (uptime) the process last became unimportant - long lastProviderTime; // The last time someone else was using a provider in this process. - long lastTopTime; // The last time the process was in the TOP state or greater. - boolean empty; // Is this an empty background process? - private boolean mCached; // Is this a cached process? - String adjType; // Debugging: primary thing impacting oom_adj. - int adjTypeCode; // Debugging: adj code to report to app. - Object adjSource; // Debugging: option dependent object. - int adjSourceProcState; // Debugging: proc state of adjSource's process. - Object adjTarget; // Debugging: target component impacting oom_adj. - Runnable crashHandler; // Optional local handler to be invoked in the process crash. - boolean bindMountPending; // True if Android/obb and Android/data need to be bind mount . + /** + * Additional packages we have a dependency on. + */ + @CompositeRWLock({"mService", "mProcLock"}) + private ArraySet mPkgDeps; - // Controller for error dialogs - private final ErrorDialogController mDialogController = new ErrorDialogController(); - // Controller for driving the process state on the window manager side. + /** + * The process of this application; 0 if none. + */ + @CompositeRWLock({"mService", "mProcLock"}) + int mPid; + + /** + * The gids this process was launched with. + */ + @GuardedBy("mService") + private int[] mGids; + + /** + * The ABI this process was launched with. + */ + @GuardedBy("mService") + private String mRequiredAbi; + + /** + * The instruction set this process was launched with. + */ + @GuardedBy("mService") + private String mInstructionSet; + + /** + * The actual proc... may be null only if 'persistent' is true + * (in which case we are in the process of launching the app). + */ + @CompositeRWLock({"mService", "mProcLock"}) + private IApplicationThread mThread; + + /** + * Always keep this application running? + */ + private volatile boolean mPersistent; + + /** + * Caching of toShortString() result. + *

Note: No lock here, it doesn't matter in case of race condition

+ */ + private String mShortStringName; + + /** + * Caching of toString() result. + *

Note: No lock here, it doesn't matter in case of race condition

+ */ + private String mStringName; + + /** + * Process start is pending. + */ + @GuardedBy("mService") + private boolean mPendingStart; + + /** + * Seq no. Indicating the latest process start associated with this process record. + */ + @GuardedBy("mService") + private long mStartSeq; + + /** + * Params used in starting this process. + */ + private volatile HostingRecord mHostingRecord; + + /** + * Selinux info of this process. + */ + private volatile String mSeInfo; + + /** + * When the process is started. + */ + private volatile long mStartTime; + + /** + * This will be same as {@link #uid} usually except for some apps used during factory testing. + */ + private volatile int mStartUid; + + /** + * Indicates how the external storage was mounted for this process. + */ + private volatile int mMountMode; + + /** + * True if Android/obb and Android/data need to be bind mount. + */ + private volatile boolean mBindMountPending; + + /** + * True when proc was started in user unlocked state. + */ + @GuardedBy("mProcLock") + private boolean mUnlocked; + + /** + * TID for RenderThread. + */ + @GuardedBy("mProcLock") + private int mRenderThreadTid; + + /** + * Last used compatibility mode. + */ + @GuardedBy("mService") + private CompatibilityInfo mCompat; + + /** + * Set of disabled compat changes for the process (all others are enabled). + */ + @GuardedBy("mService") + private long[] mDisabledCompatChanges; + + /** + * Who is watching for the death. + */ + @GuardedBy("mService") + private IBinder.DeathRecipient mDeathRecipient; + + /** + * Set to currently active instrumentation running in process. + */ + @CompositeRWLock({"mService", "mProcLock"}) + private ActiveInstrumentation mInstr; + + /** + * True when proc has been killed by activity manager, not for RAM. + */ + @CompositeRWLock({"mService", "mProcLock"}) + private boolean mKilledByAm; + + /** + * True once we know the process has been killed. + */ + @CompositeRWLock({"mService", "mProcLock"}) + private boolean mKilled; + + /** + * The timestamp in uptime when this process was killed. + */ + @CompositeRWLock({"mService", "mProcLock"}) + private long mKillTime; + + /** + * Process is waiting to be killed when in the bg, and reason. + */ + @GuardedBy("mService") + private String mWaitingToKill; + + /** + * Whether this process should be killed and removed from process list. + * It is set when the package is force-stopped or the process has crashed too many times. + */ + private volatile boolean mRemoved; + + /** + * Was app launched for debugging? + */ + @GuardedBy("mService") + private boolean mDebugging; + + /** + * Has process show wait for debugger dialog? + */ + @GuardedBy("mProcLock") + private boolean mWaitedForDebugger; + + /** + * For managing the LRU list. + */ + @CompositeRWLock({"mService", "mProcLock"}) + private long mLastActivityTime; + + /** + * Set to true when process was launched with a wrapper attached. + */ + @GuardedBy("mService") + private boolean mUsingWrapper; + + /** + * Sequence id for identifying LRU update cycles. + */ + @GuardedBy("mService") + private int mLruSeq; + + /** + * Class to run on start if this is a special isolated process. + */ + @GuardedBy("mService") + private String mIsolatedEntryPoint; + + /** + * Arguments to pass to isolatedEntryPoint's main(). + */ + @GuardedBy("mService") + private String[] mIsolatedEntryPointArgs; + + /** + * Process is currently hosting a backup agent for backup or restore. + */ + @GuardedBy("mService") + private boolean mInFullBackup; + + /** + * Controller for driving the process state on the window manager side. + */ private final WindowProcessController mWindowProcessController; - // all ServiceRecord running in this process - private final ArraySet mServices = new ArraySet<>(); - // services that are currently executing code (need to remain foreground). - final ArraySet executingServices = new ArraySet<>(); - // All ConnectionRecord this process holds - final ArraySet connections = new ArraySet<>(); - // all IIntentReceivers that are registered from this process. - final ArraySet receivers = new ArraySet<>(); - // class (String) -> ContentProviderRecord - final ArrayMap pubProviders = new ArrayMap<>(); - // All ContentProviderRecord process is using - final ArrayList conProviders = new ArrayList<>(); - // a set of UIDs of all bound clients - private ArraySet mBoundClientUids = new ArraySet<>(); - - String isolatedEntryPoint; // Class to run on start if this is a special isolated process. - String[] isolatedEntryPointArgs; // Arguments to pass to isolatedEntryPoint's main(). - - boolean execServicesFg; // do we need to be executing services in the foreground? - private boolean mPersistent;// always keep this application running? - private boolean mCrashing; // are we in the process of crashing? - boolean forceCrashReport; // suppress normal auto-dismiss of crash dialog & report UI? - private boolean mNotResponding; // does the app have a not responding dialog? - volatile boolean removed; // Whether this process should be killed and removed from process - // list. It is set when the package is force-stopped or the process - // has crashed too many times. - private boolean mDebugging; // was app launched for debugging? - boolean waitedForDebugger; // has process show wait for debugger dialog? - - String shortStringName; // caching of toShortString() result. - String stringName; // caching of toString() result. - boolean pendingStart; // Process start is pending. - long startSeq; // Seq no. indicating the latest process start associated with - // this process record. - int mountMode; // Indicates how the external storage was mounted for this process. - - // These reports are generated & stored when an app gets into an error condition. - // They will be "null" when all is OK. - ActivityManager.ProcessErrorStateInfo crashingReport; - ActivityManager.ProcessErrorStateInfo notRespondingReport; - - // Who will be notified of the error. This is usually an activity in the - // app that installed the package. - ComponentName errorReportReceiver; - - // Process is currently hosting a backup agent for backup or restore - public boolean inFullBackup; - // App is allowed to manage allowlists such as temporary Power Save mode allowlist. - boolean mAllowlistManager; - - // Params used in starting this process. - HostingRecord hostingRecord; - String seInfo; - long startTime; - // This will be same as {@link #uid} usually except for some apps used during factory testing. - int startUid; - // set of disabled compat changes for the process (all others are enabled) - long[] mDisabledCompatChanges; - - // The precede instance of the process, which would exist when the previous process is killed - // but not fully dead yet; in this case, the new instance of the process should be held until - // this precede instance is fully dead. - volatile ProcessRecord mPrecedence; - // The succeeding instance of the process, which is going to be started after this process - // is killed successfully. - volatile ProcessRecord mSuccessor; - - // Cached task info for OomAdjuster - private static final int VALUE_INVALID = -1; - private static final int VALUE_FALSE = 0; - private static final int VALUE_TRUE = 1; - private int mCachedHasActivities = VALUE_INVALID; - private int mCachedIsHeavyWeight = VALUE_INVALID; - private int mCachedHasVisibleActivities = VALUE_INVALID; - private int mCachedIsHomeProcess = VALUE_INVALID; - private int mCachedIsPreviousProcess = VALUE_INVALID; - private int mCachedHasRecentTasks = VALUE_INVALID; - private int mCachedIsReceivingBroadcast = VALUE_INVALID; - int mCachedAdj = ProcessList.INVALID_ADJ; - boolean mCachedForegroundActivities = false; - int mCachedProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY; - int mCachedSchedGroup = ProcessList.SCHED_GROUP_BACKGROUND; - - // Approximates the usage count of the app, used for cache re-ranking by CacheOomRanker. - // - // Counts the number of times the process is re-added to the cache (i.e. setCached(false); - // setCached(true)). This over counts, as setCached is sometimes reset while remaining in the - // cache. However, this happens uniformly across processes, so ranking is not affected. - private int mCacheOomRankerUseCount; - - boolean mReachable; // Whether or not this process is reachable from given process - - long mKillTime; // The timestamp in uptime when this process was killed. - - // If the proc state is PROCESS_STATE_BOUND_FOREGROUND_SERVICE or above, it can start FGS. - // It must obtain the proc state from a persistent/top process or FGS, not transitive. - int mAllowStartFgsState = PROCESS_STATE_NONEXISTENT; - - private final ArraySet mBackgroundFgsStartTokens = new ArraySet<>(); - - // Does the process has permission to start FGS from background. - @ActiveServices.FgsFeatureRetCode int mAllowStartFgsByPermission; - // Can this process start FGS from background? - // If this process has the ability to start FGS from background, this ability can be passed to - // another process through service binding. - @ActiveServices.FgsFeatureRetCode int mAllowStartFgs; /** * Profiling info of the process, such as PSS, cpu, etc. */ final ProcessProfileRecord mProfile; + /** + * All about the services in this process. + */ + final ProcessServiceRecord mServices; + + /** + * All about the providers in this process. + */ + final ProcessProviderRecord mProviders; + + /** + * All about the receivers in this process. + */ + final ProcessReceiverRecord mReceivers; + + /** + * All about the error state(crash, ANR) in this process. + */ + final ProcessErrorStateRecord mErrorState; + + /** + * All about the process state info (proc state, oom adj score) in this process. + */ + final ProcessStateRecord mState; + + /** + * All about the state info of the optimizer when the process is cached. + */ + final ProcessCachedOptimizerRecord mOptRecord; + + /** + * The preceding instance of the process, which would exist when the previous process is killed + * but not fully dead yet; in this case, the new instance of the process should be held until + * this preceding instance is fully dead. + */ + volatile ProcessRecord mPredecessor; + + /** + * The succeeding instance of the process, which is going to be started after this process + * is killed successfully. + */ + volatile ProcessRecord mSuccessor; + void setStartParams(int startUid, HostingRecord hostingRecord, String seInfo, long startTime) { - this.startUid = startUid; - this.hostingRecord = hostingRecord; - this.seInfo = seInfo; - this.startTime = startTime; + this.mStartUid = startUid; + this.mHostingRecord = hostingRecord; + this.mSeInfo = seInfo; + this.mStartTime = startTime; } + @GuardedBy({"mService", "mProcLock"}) void dump(PrintWriter pw, String prefix) { final long nowUptime = SystemClock.uptimeMillis(); @@ -359,10 +375,10 @@ class ProcessRecord implements WindowProcessListener { pw.print(" ISOLATED uid="); pw.print(uid); } pw.print(" gids={"); - if (gids != null) { - for (int gi=0; gi 0) pw.print(", "); - pw.print(pkgDeps.valueAt(i)); + pw.print(mPkgDeps.valueAt(i)); } pw.println("}"); } - pw.print(prefix); pw.print("compat="); pw.println(compat); + pw.print(prefix); pw.print("compat="); pw.println(mCompat); if (mInstr != null) { pw.print(prefix); pw.print("mInstr="); pw.println(mInstr); } - pw.print(prefix); pw.print("thread="); pw.println(thread); - pw.print(prefix); pw.print("pid="); pw.print(pid); pw.print(" starting="); - pw.println(starting); + pw.print(prefix); pw.print("thread="); pw.println(mThread); + pw.print(prefix); pw.print("pid="); pw.print(mPid); pw.print(prefix); pw.print("lastActivityTime="); - TimeUtils.formatDuration(lastActivityTime, nowUptime, pw); - pw.println(); - pw.print(prefix); pw.print("adjSeq="); pw.print(adjSeq); - pw.print(" lruSeq="); pw.println(lruSeq); - pw.print(prefix); pw.print("oom adj: max="); pw.print(maxAdj); - pw.print(" curRaw="); pw.print(mCurRawAdj); - pw.print(" setRaw="); pw.print(setRawAdj); - pw.print(" cur="); pw.print(curAdj); - pw.print(" set="); pw.println(setAdj); - pw.print(prefix); pw.print("lastCompactTime="); pw.print(lastCompactTime); - pw.print(" lastCompactAction="); pw.println(lastCompactAction); - pw.print(prefix); pw.print("mCurSchedGroup="); pw.print(mCurSchedGroup); - pw.print(" setSchedGroup="); pw.print(setSchedGroup); - pw.print(" systemNoUi="); pw.print(systemNoUi); - pw.print(prefix); pw.print("curProcState="); pw.print(getCurProcState()); - pw.print(" mRepProcState="); pw.print(mRepProcState); - pw.print(" setProcState="); pw.print(setProcState); - pw.print(" lastStateTime="); - TimeUtils.formatDuration(lastStateTime, nowUptime, pw); - pw.println(); - pw.print(prefix); pw.print("curCapability="); - ActivityManager.printCapabilitiesFull(pw, curCapability); - pw.print(" setCapability="); - ActivityManager.printCapabilitiesFull(pw, setCapability); - pw.println(); - pw.print(prefix); pw.print("allowStartFgsState="); - pw.println(mAllowStartFgsState); - if (mAllowStartFgs != FGS_FEATURE_DENIED) { - pw.print(prefix); pw.print("allowStartFgs="); - pw.println(fgsCodeToString(mAllowStartFgs)); - } - if (hasShownUi || mProfile.hasPendingUiClean() || hasAboveClient || treatLikeActivity) { - pw.print(prefix); pw.print("hasShownUi="); pw.print(hasShownUi); - pw.print(" pendingUiClean="); pw.print(mProfile.hasPendingUiClean()); - pw.print(" hasAboveClient="); pw.print(hasAboveClient); - pw.print(" treatLikeActivity="); pw.println(treatLikeActivity); - } - pw.print(prefix); pw.print("cached="); pw.print(mCached); - pw.print(" empty="); pw.println(empty); - if (serviceb) { - pw.print(prefix); pw.print("serviceb="); pw.print(serviceb); - pw.print(" serviceHighRam="); pw.println(serviceHighRam); - } - if (notCachedSinceIdle) { - pw.print(prefix); pw.print("notCachedSinceIdle="); pw.print(notCachedSinceIdle); - pw.print(" initialIdlePss="); pw.println(mProfile.getInitialIdlePss()); - } - if (connectionService != null || connectionGroup != 0) { - pw.print(prefix); pw.print("connectionGroup="); pw.print(connectionGroup); - pw.print(" Importance="); pw.print(connectionImportance); - pw.print(" Service="); pw.println(connectionService); - } - if (hasTopUi() || hasOverlayUi() || runningRemoteAnimation) { - pw.print(prefix); pw.print("hasTopUi="); pw.print(hasTopUi()); - pw.print(" hasOverlayUi="); pw.print(hasOverlayUi()); - pw.print(" runningRemoteAnimation="); pw.println(runningRemoteAnimation); - } - if (mHasForegroundServices || forcingToImportant != null) { - pw.print(prefix); pw.print("mHasForegroundServices="); pw.print(mHasForegroundServices); - pw.print(" forcingToImportant="); pw.println(forcingToImportant); - } - if (reportedInteraction || mFgInteractionTime != 0) { - pw.print(prefix); pw.print("reportedInteraction="); - pw.print(reportedInteraction); - if (mInteractionEventTime != 0) { - pw.print(" time="); - TimeUtils.formatDuration(mInteractionEventTime, SystemClock.elapsedRealtime(), pw); - } - if (mFgInteractionTime != 0) { - pw.print(" fgInteractionTime="); - TimeUtils.formatDuration(mFgInteractionTime, SystemClock.elapsedRealtime(), pw); - } - pw.println(); - } - if (mPersistent || removed) { + TimeUtils.formatDuration(mLastActivityTime, nowUptime, pw); + if (mPersistent || mRemoved) { pw.print(prefix); pw.print("persistent="); pw.print(mPersistent); - pw.print(" removed="); pw.println(removed); + pw.print(" removed="); pw.println(mRemoved); } - if (mHasClientActivities || mHasForegroundActivities || repForegroundActivities) { - pw.print(prefix); pw.print("hasClientActivities="); pw.print(mHasClientActivities); - pw.print(" foregroundActivities="); pw.print(mHasForegroundActivities); - pw.print(" (rep="); pw.print(repForegroundActivities); pw.println(")"); + if (mDebugging) { + pw.print(prefix); pw.print("mDebugging="); pw.println(mDebugging); } - if (lastProviderTime > 0) { - pw.print(prefix); pw.print("lastProviderTime="); - TimeUtils.formatDuration(lastProviderTime, nowUptime, pw); - pw.println(); + if (mPendingStart) { + pw.print(prefix); pw.print("pendingStart="); pw.println(mPendingStart); } - if (lastTopTime > 0) { - pw.print(prefix); pw.print("lastTopTime="); - TimeUtils.formatDuration(lastTopTime, nowUptime, pw); - pw.println(); - } - if (hasStartedServices) { - pw.print(prefix); pw.print("hasStartedServices="); pw.println(hasStartedServices); - } - if (pendingStart) { - pw.print(prefix); pw.print("pendingStart="); pw.println(pendingStart); - } - pw.print(prefix); pw.print("startSeq="); pw.println(startSeq); + pw.print(prefix); pw.print("startSeq="); pw.println(mStartSeq); pw.print(prefix); pw.print("mountMode="); pw.println( - DebugUtils.valueToString(Zygote.class, "MOUNT_EXTERNAL_", mountMode)); - if (setProcState > ActivityManager.PROCESS_STATE_SERVICE) { + DebugUtils.valueToString(Zygote.class, "MOUNT_EXTERNAL_", mMountMode)); + if (mKilled || mKilledByAm || mWaitingToKill != null) { + pw.print(prefix); pw.print("killed="); pw.print(mKilled); + pw.print(" killedByAm="); pw.print(mKilledByAm); + pw.print(" waitingToKill="); pw.println(mWaitingToKill); + } + if (mIsolatedEntryPoint != null || mIsolatedEntryPointArgs != null) { + pw.print(prefix); pw.print("isolatedEntryPoint="); pw.println(mIsolatedEntryPoint); + pw.print(prefix); pw.print("isolatedEntryPointArgs="); + pw.println(Arrays.toString(mIsolatedEntryPointArgs)); + } + if (mState.getSetProcState() > ActivityManager.PROCESS_STATE_SERVICE) { mProfile.dumpCputime(pw, prefix); - pw.print(" whenUnimportant="); - TimeUtils.formatDuration(mWhenUnimportant - nowUptime, pw); - pw.println(); } mProfile.dumpPss(pw, prefix, nowUptime); - if (killed || killedByAm || waitingToKill != null) { - pw.print(prefix); pw.print("killed="); pw.print(killed); - pw.print(" killedByAm="); pw.print(killedByAm); - pw.print(" waitingToKill="); pw.println(waitingToKill); - } - if (mDebugging || mCrashing || mDialogController.hasCrashDialogs() || mNotResponding - || mDialogController.hasAnrDialogs() || bad) { - pw.print(prefix); pw.print("mDebugging="); pw.print(mDebugging); - pw.print(" mCrashing=" + mCrashing); - pw.print(" " + mDialogController.mCrashDialogs); - pw.print(" mNotResponding=" + mNotResponding); - pw.print(" " + mDialogController.mAnrDialogs); - pw.print(" bad=" + bad); - - // mCrashing or mNotResponding is always set before errorReportReceiver - if (errorReportReceiver != null) { - pw.print(" errorReportReceiver="); - pw.print(errorReportReceiver.flattenToShortString()); - } - pw.println(); - } - if (mAllowlistManager) { - pw.print(prefix); pw.print("allowlistManager="); pw.println(mAllowlistManager); - } - if (isolatedEntryPoint != null || isolatedEntryPointArgs != null) { - pw.print(prefix); pw.print("isolatedEntryPoint="); pw.println(isolatedEntryPoint); - pw.print(prefix); pw.print("isolatedEntryPointArgs="); - pw.println(Arrays.toString(isolatedEntryPointArgs)); - } + mState.dump(pw, prefix, nowUptime); + mErrorState.dump(pw, prefix, nowUptime); + mServices.dump(pw, prefix, nowUptime); + mProviders.dump(pw, prefix, nowUptime); + mReceivers.dump(pw, prefix, nowUptime); + mOptRecord.dump(pw, prefix, nowUptime); mWindowProcessController.dump(pw, prefix); - if (mServices.size() > 0) { - pw.print(prefix); pw.println("Services:"); - for (int i = 0; i < mServices.size(); i++) { - pw.print(prefix); pw.print(" - "); pw.println(mServices.valueAt(i)); - } - } - if (executingServices.size() > 0) { - pw.print(prefix); pw.print("Executing Services (fg="); - pw.print(execServicesFg); pw.println(")"); - for (int i=0; i 0) { - pw.print(prefix); pw.println("Connections:"); - for (int i=0; i 0) { - pw.print(prefix); pw.println("Published Providers:"); - for (int i=0; i "); pw.println(pubProviders.valueAt(i)); - } - } - if (conProviders.size() > 0) { - pw.print(prefix); pw.println("Connected Providers:"); - for (int i=0; i 0) { - pw.print(prefix); pw.println("Receivers:"); - for (int i=0; i getPkgDeps() { + return mPkgDeps; + } + + @GuardedBy({"mService", "mProcLock"}) + void setPkgDeps(ArraySet pkgDeps) { + mPkgDeps = pkgDeps; + } + + @GuardedBy(anyOf = {"mService", "mProcLock"}) + int getPid() { + return mPid; + } + + @GuardedBy({"mService", "mProcLock"}) + void setPid(int pid) { + mPid = pid; mWindowProcessController.setPid(pid); - procStatFile = null; - shortStringName = null; - stringName = null; + mShortStringName = null; + mStringName = null; synchronized (mProfile.mProfilerLock) { mProfile.setPid(pid); } } - public void makeActive(IApplicationThread _thread, ProcessStatsService tracker) { - mProfile.onProcessActive(_thread, tracker); - thread = _thread; + @GuardedBy(anyOf = {"mService", "mProcLock"}) + IApplicationThread getThread() { + return mThread; + } + + @GuardedBy({"mService", "mProcLock"}) + public void makeActive(IApplicationThread thread, ProcessStatsService tracker) { + mProfile.onProcessActive(thread, tracker); + mThread = thread; mWindowProcessController.setThread(thread); } + @GuardedBy({"mService", "mProcLock"}) public void makeInactive(ProcessStatsService tracker) { - thread = null; + mThread = null; mWindowProcessController.setThread(null); mProfile.onProcessInactive(tracker); } - /** - * Records a service as running in the process. Note that this method does not actually start - * the service, but records the service as started for bookkeeping. - * - * @return true if the service was added, false otherwise. - */ - boolean startService(ServiceRecord record) { - if (record == null) { - return false; + @GuardedBy("mService") + int[] getGids() { + return mGids; + } + + @GuardedBy("mService") + void setGids(int[] gids) { + mGids = gids; + } + + @GuardedBy("mService") + String getRequiredAbi() { + return mRequiredAbi; + } + + @GuardedBy("mService") + void setRequiredAbi(String requiredAbi) { + mRequiredAbi = requiredAbi; + mWindowProcessController.setRequiredAbi(requiredAbi); + } + + @GuardedBy("mService") + String getInstructionSet() { + return mInstructionSet; + } + + @GuardedBy("mService") + void setInstructionSet(String instructionSet) { + mInstructionSet = instructionSet; + } + + void setPersistent(boolean persistent) { + mPersistent = persistent; + mWindowProcessController.setPersistent(persistent); + } + + boolean isPersistent() { + return mPersistent; + } + + @GuardedBy("mService") + boolean isPendingStart() { + return mPendingStart; + } + + @GuardedBy("mService") + void setPendingStart(boolean pendingStart) { + mPendingStart = pendingStart; + } + + @GuardedBy("mService") + long getStartSeq() { + return mStartSeq; + } + + @GuardedBy("mService") + void setStartSeq(long startSeq) { + mStartSeq = startSeq; + } + + HostingRecord getHostingRecord() { + return mHostingRecord; + } + + void setHostingRecord(HostingRecord hostingRecord) { + mHostingRecord = hostingRecord; + } + + String getSeInfo() { + return mSeInfo; + } + + void setSeInfo(String seInfo) { + mSeInfo = seInfo; + } + + long getStartTime() { + return mStartTime; + } + + void setStartTime(long startTime) { + mStartTime = startTime; + } + + int getStartUid() { + return mStartUid; + } + + void setStartUid(int startUid) { + mStartUid = startUid; + } + + int getMountMode() { + return mMountMode; + } + + void setMountMode(int mountMode) { + mMountMode = mountMode; + } + + boolean isBindMountPending() { + return mBindMountPending; + } + + void setBindMountPending(boolean bindMountPending) { + mBindMountPending = bindMountPending; + } + + @GuardedBy("mProcLock") + boolean isUnlocked() { + return mUnlocked; + } + + @GuardedBy("mProcLock") + void setUnlocked(boolean unlocked) { + mUnlocked = unlocked; + } + + @GuardedBy("mProcLock") + int getRenderThreadTid() { + return mRenderThreadTid; + } + + @GuardedBy("mProcLock") + void setRenderThreadTid(int renderThreadTid) { + mRenderThreadTid = renderThreadTid; + } + + @GuardedBy("mService") + CompatibilityInfo getCompat() { + return mCompat; + } + + @GuardedBy("mService") + void setCompat(CompatibilityInfo compat) { + mCompat = compat; + } + + @GuardedBy("mService") + long[] getDisabledCompatChanges() { + return mDisabledCompatChanges; + } + + @GuardedBy("mService") + void setDisabledCompatChanges(long[] disabledCompatChanges) { + mDisabledCompatChanges = disabledCompatChanges; + } + + @GuardedBy("mService") + void unlinkDeathRecipient() { + if (mDeathRecipient != null && mThread != null) { + mThread.asBinder().unlinkToDeath(mDeathRecipient, 0); } - boolean added = mServices.add(record); - if (added && record.serviceInfo != null) { - mWindowProcessController.onServiceStarted(record.serviceInfo); - } - return added; + mDeathRecipient = null; } - /** - * Records a service as stopped. Note that like {@link #startService(ServiceRecord)} this method - * does not actually stop the service, but records the service as stopped for bookkeeping. - * - * @return true if the service was removed, false otherwise. - */ - boolean stopService(ServiceRecord record) { - return mServices.remove(record); + @GuardedBy("mService") + void setDeathRecipient(IBinder.DeathRecipient deathRecipient) { + mDeathRecipient = deathRecipient; } - /** - * The same as calling {@link #stopService(ServiceRecord)} on all current running services. - */ - void stopAllServices() { - mServices.clear(); + @GuardedBy({"mService", "mProcLock"}) + void setActiveInstrumentation(ActiveInstrumentation instr) { + mInstr = instr; + boolean isInstrumenting = instr != null; + mWindowProcessController.setInstrumenting( + isInstrumenting, + isInstrumenting ? instr.mSourceUid : -1, + isInstrumenting && instr.mHasBackgroundActivityStartsPermission); } - /** - * Returns the number of services added with {@link #startService(ServiceRecord)} and not yet - * removed by a call to {@link #stopService(ServiceRecord)} or {@link #stopAllServices()}. - * - * @see #startService(ServiceRecord) - * @see #stopService(ServiceRecord) - */ - int numberOfRunningServices() { - return mServices.size(); + @GuardedBy(anyOf = {"mService", "mProcLock"}) + ActiveInstrumentation getActiveInstrumentation() { + return mInstr; } - /** - * Returns the service at the specified {@code index}. - * - * @see #numberOfRunningServices() - */ - ServiceRecord getRunningServiceAt(int index) { - return mServices.valueAt(index); + @GuardedBy(anyOf = {"mService", "mProcLock"}) + boolean isKilledByAm() { + return mKilledByAm; } - void setCached(boolean cached) { - if (mCached != cached) { - mCached = cached; - if (cached) { - ++mCacheOomRankerUseCount; - } - } + @GuardedBy({"mService", "mProcLock"}) + void setKilledByAm(boolean killedByAm) { + mKilledByAm = killedByAm; + } + + @GuardedBy(anyOf = {"mService", "mProcLock"}) + boolean isKilled() { + return mKilled; + } + + @GuardedBy({"mService", "mProcLock"}) + void setKilled(boolean killed) { + mKilled = killed; + } + + @GuardedBy(anyOf = {"mService", "mProcLock"}) + long getKillTime() { + return mKillTime; + } + + @GuardedBy({"mService", "mProcLock"}) + void setKillTime(long killTime) { + mKillTime = killTime; + } + + @GuardedBy("mService") + String getWaitingToKill() { + return mWaitingToKill; + } + + @GuardedBy("mService") + void setWaitingToKill(String waitingToKill) { + mWaitingToKill = waitingToKill; + } + + @Override + public boolean isRemoved() { + return mRemoved; + } + + void setRemoved(boolean removed) { + mRemoved = removed; + } + + @GuardedBy("mService") + boolean isDebugging() { + return mDebugging; + } + + @GuardedBy("mService") + void setDebugging(boolean debugging) { + mDebugging = debugging; + mWindowProcessController.setDebugging(debugging); + } + + @GuardedBy("mProcLock") + boolean hasWaitedForDebugger() { + return mWaitedForDebugger; + } + + @GuardedBy("mProcLock") + void setWaitedForDebugger(boolean waitedForDebugger) { + mWaitedForDebugger = waitedForDebugger; + } + + @GuardedBy(anyOf = {"mService", "mProcLock"}) + long getLastActivityTime() { + return mLastActivityTime; + } + + @GuardedBy({"mService", "mProcLock"}) + void setLastActivityTime(long lastActivityTime) { + mLastActivityTime = lastActivityTime; + } + + @GuardedBy("mService") + boolean isUsingWrapper() { + return mUsingWrapper; + } + + @GuardedBy("mService") + void setUsingWrapper(boolean usingWrapper) { + mUsingWrapper = usingWrapper; + mWindowProcessController.setUsingWrapper(usingWrapper); + } + + @GuardedBy("mService") + int getLruSeq() { + return mLruSeq; + } + + @GuardedBy("mService") + void setLruSeq(int lruSeq) { + mLruSeq = lruSeq; + } + + @GuardedBy("mService") + String getIsolatedEntryPoint() { + return mIsolatedEntryPoint; + } + + @GuardedBy("mService") + void setIsolatedEntryPoint(String isolatedEntryPoint) { + mIsolatedEntryPoint = isolatedEntryPoint; + } + + @GuardedBy("mService") + String[] getIsolatedEntryPointArgs() { + return mIsolatedEntryPointArgs; + } + + @GuardedBy("mService") + void setIsolatedEntryPointArgs(String[] isolatedEntryPointArgs) { + mIsolatedEntryPointArgs = isolatedEntryPointArgs; + } + + @GuardedBy("mService") + boolean isInFullBackup() { + return mInFullBackup; + } + + @GuardedBy("mService") + void setInFullBackup(boolean inFullBackup) { + mInFullBackup = inFullBackup; } @Override public boolean isCached() { - return mCached; - } - - int getCacheOomRankerUseCount() { - return mCacheOomRankerUseCount; + return mState.isCached(); } boolean hasActivities() { @@ -746,6 +888,22 @@ class ProcessRecord implements WindowProcessListener { return mWindowProcessController.hasRecentTasks(); } + @GuardedBy({"mService", "mProcLock"}) + boolean onCleanupApplicationRecordLSP(ProcessStatsService processStats, boolean allowRestart) { + mErrorState.onCleanupApplicationRecordLSP(); + + resetPackageList(processStats); + unlinkDeathRecipient(); + makeInactive(processStats); + setWaitingToKill(null); + + mState.onCleanupApplicationRecordLSP(); + mServices.onCleanupApplicationRecordLocked(); + mReceivers.onCleanupApplicationRecordLocked(); + + return mProviders.onCleanupApplicationRecordLocked(allowRestart); + } + /** * This method returns true if any of the activities within the process record are interesting * to the user. See HistoryRecord.isInterestingToUserLocked() @@ -755,74 +913,26 @@ class ProcessRecord implements WindowProcessListener { return true; } - final int servicesSize = mServices.size(); - for (int i = 0; i < servicesSize; i++) { - ServiceRecord r = mServices.valueAt(i); - if (r.isForeground) { - return true; - } - } - return false; + return mServices.hasForegroundServices(); } - public void unlinkDeathRecipient() { - if (deathRecipient != null && thread != null) { - thread.asBinder().unlinkToDeath(deathRecipient, 0); - } - deathRecipient = null; - } - - void updateHasAboveClientLocked() { - hasAboveClient = false; - for (int i=connections.size()-1; i>=0; i--) { - ConnectionRecord cr = connections.valueAt(i); - if ((cr.flags&Context.BIND_ABOVE_CLIENT) != 0) { - hasAboveClient = true; - break; - } - } - } - - int modifyRawOomAdj(int adj) { - if (hasAboveClient) { - // If this process has bound to any services with BIND_ABOVE_CLIENT, - // then we need to drop its adjustment to be lower than the service's - // in order to honor the request. We want to drop it by one adjustment - // level... but there is special meaning applied to various levels so - // we will skip some of them. - if (adj < ProcessList.FOREGROUND_APP_ADJ) { - // System process will not get dropped, ever - } else if (adj < ProcessList.VISIBLE_APP_ADJ) { - adj = ProcessList.VISIBLE_APP_ADJ; - } else if (adj < ProcessList.PERCEPTIBLE_APP_ADJ) { - adj = ProcessList.PERCEPTIBLE_APP_ADJ; - } else if (adj < ProcessList.PERCEPTIBLE_LOW_APP_ADJ) { - adj = ProcessList.PERCEPTIBLE_LOW_APP_ADJ; - } else if (adj < ProcessList.CACHED_APP_MIN_ADJ) { - adj = ProcessList.CACHED_APP_MIN_ADJ; - } else if (adj < ProcessList.CACHED_APP_MAX_ADJ) { - adj++; - } - } - return adj; - } - - void scheduleCrash(String message) { + @GuardedBy("mService") + void scheduleCrashLocked(String message) { // Checking killedbyAm should keep it from showing the crash dialog if the process // was already dead for a good / normal reason. - if (!killedByAm) { - if (thread != null) { - if (pid == Process.myPid()) { + if (!mKilledByAm) { + if (mThread != null) { + if (mPid == Process.myPid()) { Slog.w(TAG, "scheduleCrash: trying to crash system process!"); return; } final long ident = Binder.clearCallingIdentity(); try { - thread.scheduleCrash(message); + mThread.scheduleCrash(message); } catch (RemoteException e) { // If it's already dead our work is done. If it's wedged just kill it. // We won't get the crash dialog or the error reporting. - kill("scheduleCrash for '" + message + "' failed", + killLocked("scheduleCrash for '" + message + "' failed", ApplicationExitInfo.REASON_CRASH, true); } finally { Binder.restoreCallingIdentity(ident); @@ -831,30 +941,36 @@ class ProcessRecord implements WindowProcessListener { } } - void kill(String reason, @Reason int reasonCode, boolean noisy) { - kill(reason, reasonCode, ApplicationExitInfo.SUBREASON_UNKNOWN, noisy); + @GuardedBy("mService") + void killLocked(String reason, @Reason int reasonCode, boolean noisy) { + killLocked(reason, reasonCode, ApplicationExitInfo.SUBREASON_UNKNOWN, noisy); } - void kill(String reason, @Reason int reasonCode, @SubReason int subReason, boolean noisy) { - if (!killedByAm) { + @GuardedBy("mService") + void killLocked(String reason, @Reason int reasonCode, @SubReason int subReason, + boolean noisy) { + if (!mKilledByAm) { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "kill"); if (mService != null && (noisy || info.uid == mService.mCurOomAdjUid)) { mService.reportUidInfoMessageLocked(TAG, - "Killing " + toShortString() + " (adj " + setAdj + "): " + reason, - info.uid); + "Killing " + toShortString() + " (adj " + mState.getSetAdj() + + "): " + reason, info.uid); } - if (pid > 0) { + if (mPid > 0) { mService.mProcessList.noteAppKill(this, reasonCode, subReason, reason); - EventLog.writeEvent(EventLogTags.AM_KILL, userId, pid, processName, setAdj, reason); - Process.killProcessQuiet(pid); - ProcessList.killProcessGroup(uid, pid); + EventLog.writeEvent(EventLogTags.AM_KILL, + userId, mPid, processName, mState.getSetAdj(), reason); + Process.killProcessQuiet(mPid); + ProcessList.killProcessGroup(uid, mPid); } else { - pendingStart = false; + mPendingStart = false; } if (!mPersistent) { - killed = true; - killedByAm = true; - mKillTime = SystemClock.uptimeMillis(); + synchronized (mProcLock) { + mKilled = true; + mKilledByAm = true; + mKillTime = SystemClock.uptimeMillis(); + } } Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); } @@ -867,7 +983,7 @@ class ProcessRecord implements WindowProcessListener { public void dumpDebug(ProtoOutputStream proto, long fieldId, int lruIndex) { long token = proto.start(fieldId); - proto.write(ProcessRecordProto.PID, pid); + proto.write(ProcessRecordProto.PID, mPid); proto.write(ProcessRecordProto.PROCESS_NAME, processName); proto.write(ProcessRecordProto.UID, info.uid); if (UserHandle.getAppId(info.uid) >= Process.FIRST_APPLICATION_UID) { @@ -885,16 +1001,17 @@ class ProcessRecord implements WindowProcessListener { } public String toShortString() { + final String shortStringName = mShortStringName; if (shortStringName != null) { return shortStringName; } StringBuilder sb = new StringBuilder(128); toShortString(sb); - return shortStringName = sb.toString(); + return mShortStringName = sb.toString(); } void toShortString(StringBuilder sb) { - sb.append(pid); + sb.append(mPid); sb.append(':'); sb.append(processName); sb.append('/'); @@ -919,6 +1036,7 @@ class ProcessRecord implements WindowProcessListener { } public String toString() { + final String stringName = mStringName; if (stringName != null) { return stringName; } @@ -928,33 +1046,7 @@ class ProcessRecord implements WindowProcessListener { sb.append(' '); toShortString(sb); sb.append('}'); - return stringName = sb.toString(); - } - - public String makeAdjReason() { - if (adjSource != null || adjTarget != null) { - StringBuilder sb = new StringBuilder(128); - sb.append(' '); - if (adjTarget instanceof ComponentName) { - sb.append(((ComponentName)adjTarget).flattenToShortString()); - } else if (adjTarget != null) { - sb.append(adjTarget.toString()); - } else { - sb.append("{null}"); - } - sb.append("<="); - if (adjSource instanceof ProcessRecord) { - sb.append("Proc{"); - sb.append(((ProcessRecord)adjSource).toShortString()); - sb.append("}"); - } else if (adjSource != null) { - sb.append(adjSource.toString()); - } else { - sb.append("{null}"); - } - return sb.toString(); - } - return null; + return mStringName = sb.toString(); } /* @@ -984,29 +1076,6 @@ class ProcessRecord implements WindowProcessListener { return false; } - public int getSetAdjWithServices() { - if (setAdj >= ProcessList.CACHED_APP_MIN_ADJ) { - if (hasStartedServices) { - return ProcessList.SERVICE_B_ADJ; - } - } - return setAdj; - } - - public void forceProcessStateUpTo(int newState) { - if (mRepProcState > newState) { - mRepProcState = newState; - setCurProcState(newState); - setCurRawProcState(newState); - getPkgList().forEachPackage((pkgName, holder) -> - FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_STATE_CHANGED, - uid, processName, pkgName, - ActivityManager.processStateAmToProto(mRepProcState), - holder.appVersion) - ); - } - } - /* * Delete all packages from list except the package indicated in info */ @@ -1062,194 +1131,6 @@ class ProcessRecord implements WindowProcessListener { return mWindowProcessController; } - void setCurrentSchedulingGroup(int curSchedGroup) { - mCurSchedGroup = curSchedGroup; - mWindowProcessController.setCurrentSchedulingGroup(curSchedGroup); - } - - int getCurrentSchedulingGroup() { - return mCurSchedGroup; - } - - void setCurProcState(int curProcState) { - mCurProcState = curProcState; - mWindowProcessController.setCurrentProcState(mCurProcState); - } - - int getCurProcState() { - return mCurProcState; - } - - void setCurRawProcState(int curRawProcState) { - mCurRawProcState = curRawProcState; - } - - int getCurRawProcState() { - return mCurRawProcState; - } - - void setReportedProcState(int repProcState) { - mRepProcState = repProcState; - getPkgList().forEachPackage((pkgName, holder) -> - FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_STATE_CHANGED, - uid, processName, pkgName, - ActivityManager.processStateAmToProto(mRepProcState), - holder.appVersion) - ); - mWindowProcessController.setReportedProcState(repProcState); - } - - int getReportedProcState() { - return mRepProcState; - } - - void setCrashing(boolean crashing) { - mCrashing = crashing; - mWindowProcessController.setCrashing(crashing); - } - - boolean isCrashing() { - return mCrashing; - } - - void setNotResponding(boolean notResponding) { - mNotResponding = notResponding; - mWindowProcessController.setNotResponding(notResponding); - } - - boolean isNotResponding() { - return mNotResponding; - } - - void setPersistent(boolean persistent) { - mPersistent = persistent; - mWindowProcessController.setPersistent(persistent); - } - - boolean isPersistent() { - return mPersistent; - } - - public void setRequiredAbi(String requiredAbi) { - mRequiredAbi = requiredAbi; - mWindowProcessController.setRequiredAbi(requiredAbi); - } - - String getRequiredAbi() { - return mRequiredAbi; - } - - void setHasForegroundServices(boolean hasForegroundServices, int fgServiceTypes) { - mHasForegroundServices = hasForegroundServices; - mFgServiceTypes = fgServiceTypes; - mWindowProcessController.setHasForegroundServices(hasForegroundServices); - } - - boolean hasForegroundServices() { - return mHasForegroundServices; - } - - boolean hasLocationForegroundServices() { - return mHasForegroundServices - && (mFgServiceTypes & ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION) != 0; - } - - boolean hasLocationCapability() { - return (setCapability & ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION) != 0; - } - - int getForegroundServiceTypes() { - return mHasForegroundServices ? mFgServiceTypes : 0; - } - - int getReportedForegroundServiceTypes() { - return mRepFgServiceTypes; - } - - void setReportedForegroundServiceTypes(int foregroundServiceTypes) { - mRepFgServiceTypes = foregroundServiceTypes; - } - - void setHasForegroundActivities(boolean hasForegroundActivities) { - mHasForegroundActivities = hasForegroundActivities; - } - - boolean hasForegroundActivities() { - return mHasForegroundActivities; - } - - void setHasClientActivities(boolean hasClientActivities) { - mHasClientActivities = hasClientActivities; - mWindowProcessController.setHasClientActivities(hasClientActivities); - } - - boolean hasClientActivities() { - return mHasClientActivities; - } - - void setHasTopUi(boolean hasTopUi) { - mHasTopUi = hasTopUi; - mWindowProcessController.setHasTopUi(hasTopUi); - } - - boolean hasTopUi() { - return mHasTopUi; - } - - void setHasOverlayUi(boolean hasOverlayUi) { - mHasOverlayUi = hasOverlayUi; - mWindowProcessController.setHasOverlayUi(hasOverlayUi); - } - - boolean hasOverlayUi() { - return mHasOverlayUi; - } - - void setInteractionEventTime(long interactionEventTime) { - mInteractionEventTime = interactionEventTime; - mWindowProcessController.setInteractionEventTime(interactionEventTime); - } - - long getInteractionEventTime() { - return mInteractionEventTime; - } - - void setFgInteractionTime(long fgInteractionTime) { - mFgInteractionTime = fgInteractionTime; - mWindowProcessController.setFgInteractionTime(fgInteractionTime); - } - - long getFgInteractionTime() { - return mFgInteractionTime; - } - - void setWhenUnimportant(long whenUnimportant) { - mWhenUnimportant = whenUnimportant; - mWindowProcessController.setWhenUnimportant(whenUnimportant); - } - - long getWhenUnimportant() { - return mWhenUnimportant; - } - - void setDebugging(boolean debugging) { - mDebugging = debugging; - mWindowProcessController.setDebugging(debugging); - } - - boolean isDebugging() { - return mDebugging; - } - - void setUsingWrapper(boolean usingWrapper) { - mUsingWrapper = usingWrapper; - mWindowProcessController.setUsingWrapper(usingWrapper); - } - - boolean isUsingWrapper() { - return mUsingWrapper; - } - /** * Allows background activity starts using token {@param entity}. Optionally, you can provide * {@param originatingToken} if you have one such originating token, this is useful for tracing @@ -1267,75 +1148,6 @@ class ProcessRecord implements WindowProcessListener { mWindowProcessController.removeAllowBackgroundActivityStartsToken(entity); } - void addBoundClientUid(int clientUid) { - mBoundClientUids.add(clientUid); - mWindowProcessController.setBoundClientUids(mBoundClientUids); - } - - void updateBoundClientUids() { - if (mServices.isEmpty()) { - clearBoundClientUids(); - return; - } - // grab a set of clientUids of all connections of all services - ArraySet boundClientUids = new ArraySet<>(); - final int serviceCount = mServices.size(); - for (int j = 0; j < serviceCount; j++) { - ArrayMap> conns = - mServices.valueAt(j).getConnections(); - final int N = conns.size(); - for (int conni = 0; conni < N; conni++) { - ArrayList c = conns.valueAt(conni); - for (int i = 0; i < c.size(); i++) { - boundClientUids.add(c.get(i).clientUid); - } - } - } - mBoundClientUids = boundClientUids; - mWindowProcessController.setBoundClientUids(mBoundClientUids); - } - - void addBoundClientUidsOfNewService(ServiceRecord sr) { - if (sr == null) { - return; - } - ArrayMap> conns = sr.getConnections(); - for (int conni = conns.size() - 1; conni >= 0; conni--) { - ArrayList c = conns.valueAt(conni); - for (int i = 0; i < c.size(); i++) { - mBoundClientUids.add(c.get(i).clientUid); - } - } - mWindowProcessController.setBoundClientUids(mBoundClientUids); - } - - void clearBoundClientUids() { - mBoundClientUids.clear(); - mWindowProcessController.setBoundClientUids(mBoundClientUids); - } - - void setActiveInstrumentation(ActiveInstrumentation instr) { - mInstr = instr; - boolean isInstrumenting = instr != null; - mWindowProcessController.setInstrumenting( - isInstrumenting, - isInstrumenting ? instr.mSourceUid : -1, - isInstrumenting && instr.mHasBackgroundActivityStartsPermission); - } - - ActiveInstrumentation getActiveInstrumentation() { - return mInstr; - } - - void setCurRawAdj(int curRawAdj) { - mCurRawAdj = curRawAdj; - mWindowProcessController.setPerceptible(curRawAdj <= ProcessList.PERCEPTIBLE_APP_ADJ); - } - - int getCurRawAdj() { - return mCurRawAdj; - } - @Override public void clearProfilerIfNeeded() { synchronized (mService.mAppProfiler.mProfilerLock) { @@ -1346,13 +1158,13 @@ class ProcessRecord implements WindowProcessListener { @Override public void updateServiceConnectionActivities() { synchronized (mService) { - mService.mServices.updateServiceConnectionActivitiesLocked(this); + mService.mServices.updateServiceConnectionActivitiesLocked(mServices); } } @Override public void setPendingUiClean(boolean pendingUiClean) { - synchronized (mService) { + synchronized (mProcLock) { mProfile.setPendingUiClean(pendingUiClean); } } @@ -1361,7 +1173,7 @@ class ProcessRecord implements WindowProcessListener { public void setPendingUiCleanAndForceProcessStateUpTo(int newState) { synchronized (mService) { setPendingUiClean(true); - forceProcessStateUpTo(newState); + mState.forceProcessStateUpTo(newState); } } @@ -1370,40 +1182,35 @@ class ProcessRecord implements WindowProcessListener { boolean updateOomAdj) { synchronized (mService) { if (updateServiceConnectionActivities) { - mService.mServices.updateServiceConnectionActivitiesLocked(this); + mService.mServices.updateServiceConnectionActivitiesLocked(mServices); } - if (thread == null) { + if (mThread == null) { // Only update lru and oom-adj if the process is alive. Because it may be called // when cleaning up the last activity from handling process died, the dead process // should not be added to lru list again. return; } - mService.mProcessList.updateLruProcessLocked(this, activityChange, null /* client */); + mService.updateLruProcessLocked(this, activityChange, null /* client */); if (updateOomAdj) { mService.updateOomAdjLocked(this, OomAdjuster.OOM_ADJ_REASON_ACTIVITY); } } } - @Override - public boolean isRemoved() { - return removed; - } - /** * Returns the total time (in milliseconds) spent executing in both user and system code. * Safe to call without lock held. */ @Override public long getCpuTime() { - return mService.mAppProfiler.getCpuTimeForPid(pid); + return mService.mAppProfiler.getCpuTimeForPid(mPid); } @Override public void onStartActivity(int topProcessState, boolean setProfileProc, String packageName, long versionCode) { synchronized (mService) { - waitingToKill = null; + mWaitingToKill = null; if (setProfileProc) { synchronized (mService.mAppProfiler.mProfilerLock) { mService.mAppProfiler.setProfileProcLPf(this); @@ -1416,9 +1223,9 @@ class ProcessRecord implements WindowProcessListener { // Update oom adj first, we don't want the additional states are involved in this round. updateProcessInfo(false /* updateServiceConnectionActivities */, true /* activityChange */, true /* updateOomAdj */); - hasShownUi = true; setPendingUiClean(true); - forceProcessStateUpTo(topProcessState); + mState.setHasShownUi(true); + mState.forceProcessStateUpTo(topProcessState); } } @@ -1431,20 +1238,12 @@ class ProcessRecord implements WindowProcessListener { @Override public void setRunningRemoteAnimation(boolean runningRemoteAnimation) { - if (pid == Process.myPid()) { + if (mPid == Process.myPid()) { Slog.wtf(TAG, "system can't run remote animation"); return; } synchronized (mService) { - if (this.runningRemoteAnimation == runningRemoteAnimation) { - return; - } - this.runningRemoteAnimation = runningRemoteAnimation; - if (DEBUG_OOM_ADJ) { - Slog.i(TAG, "Setting runningRemoteAnimation=" + runningRemoteAnimation - + " for pid=" + pid); - } - mService.updateOomAdjLocked(this, true, OomAdjuster.OOM_ADJ_REASON_UI_VISIBILITY); + mState.setRunningRemoteAnimation(runningRemoteAnimation); } } @@ -1453,7 +1252,7 @@ class ProcessRecord implements WindowProcessListener { } public int getProcessClassEnum() { - if (pid == MY_PID) { + if (mPid == MY_PID) { return ServerProtoEnums.SYSTEM_SERVER; } if (info == null) { @@ -1463,701 +1262,9 @@ class ProcessRecord implements WindowProcessListener { ServerProtoEnums.DATA_APP; } - /** - * Unless configured otherwise, swallow ANRs in background processes & kill the process. - * Non-private access is for tests only. - */ - @VisibleForTesting - boolean isSilentAnr() { - return !getShowBackground() && !isInterestingForBackgroundTraces(); - } - /** Non-private access is for tests only. */ @VisibleForTesting List getLruProcessList() { - return mService.mProcessList.mLruProcesses; - } - - /** Non-private access is for tests only. */ - @VisibleForTesting - boolean isMonitorCpuUsage() { - return mService.mAppProfiler.MONITOR_CPU_USAGE; - } - - void appNotResponding(String activityShortComponentName, ApplicationInfo aInfo, - String parentShortComponentName, WindowProcessController parentProcess, - boolean aboveSystem, String annotation, boolean onlyDumpSelf) { - ArrayList firstPids = new ArrayList<>(5); - SparseArray lastPids = new SparseArray<>(20); - - mWindowProcessController.appEarlyNotResponding(annotation, () -> kill("anr", - ApplicationExitInfo.REASON_ANR, true)); - - long anrTime = SystemClock.uptimeMillis(); - if (isMonitorCpuUsage()) { - mService.updateCpuStatsNow(); - } - - final boolean isSilentAnr; - synchronized (mService) { - // PowerManager.reboot() can block for a long time, so ignore ANRs while shutting down. - if (mService.mAtmInternal.isShuttingDown()) { - Slog.i(TAG, "During shutdown skipping ANR: " + this + " " + annotation); - return; - } else if (isNotResponding()) { - Slog.i(TAG, "Skipping duplicate ANR: " + this + " " + annotation); - return; - } else if (isCrashing()) { - Slog.i(TAG, "Crashing app skipping ANR: " + this + " " + annotation); - return; - } else if (killedByAm) { - Slog.i(TAG, "App already killed by AM skipping ANR: " + this + " " + annotation); - return; - } else if (killed) { - Slog.i(TAG, "Skipping died app ANR: " + this + " " + annotation); - return; - } - - // In case we come through here for the same app before completing - // this one, mark as anring now so we will bail out. - setNotResponding(true); - - // Log the ANR to the event log. - EventLog.writeEvent(EventLogTags.AM_ANR, userId, pid, processName, info.flags, - annotation); - - // Dump thread traces as quickly as we can, starting with "interesting" processes. - firstPids.add(pid); - - // Don't dump other PIDs if it's a background ANR or is requested to only dump self. - isSilentAnr = isSilentAnr(); - if (!isSilentAnr && !onlyDumpSelf) { - int parentPid = pid; - if (parentProcess != null && parentProcess.getPid() > 0) { - parentPid = parentProcess.getPid(); - } - if (parentPid != pid) firstPids.add(parentPid); - - if (MY_PID != pid && MY_PID != parentPid) firstPids.add(MY_PID); - - for (int i = getLruProcessList().size() - 1; i >= 0; i--) { - ProcessRecord r = getLruProcessList().get(i); - if (r != null && r.thread != null) { - int myPid = r.pid; - if (myPid > 0 && myPid != pid && myPid != parentPid && myPid != MY_PID) { - if (r.isPersistent()) { - firstPids.add(myPid); - if (DEBUG_ANR) Slog.i(TAG, "Adding persistent proc: " + r); - } else if (r.treatLikeActivity) { - firstPids.add(myPid); - if (DEBUG_ANR) Slog.i(TAG, "Adding likely IME: " + r); - } else { - lastPids.put(myPid, Boolean.TRUE); - if (DEBUG_ANR) Slog.i(TAG, "Adding ANR proc: " + r); - } - } - } - } - } - } - - // Check if package is still being loaded - boolean isPackageLoading = false; - final PackageManagerInternal packageManagerInternal = - mService.getPackageManagerInternal(); - if (aInfo != null && aInfo.packageName != null) { - IncrementalStatesInfo incrementalStatesInfo = - packageManagerInternal.getIncrementalStatesInfo( - aInfo.packageName, uid, userId); - if (incrementalStatesInfo != null) { - isPackageLoading = incrementalStatesInfo.isLoading(); - } - } - - // Log the ANR to the main log. - StringBuilder info = new StringBuilder(); - info.setLength(0); - info.append("ANR in ").append(processName); - if (activityShortComponentName != null) { - info.append(" (").append(activityShortComponentName).append(")"); - } - info.append("\n"); - info.append("PID: ").append(pid).append("\n"); - if (annotation != null) { - info.append("Reason: ").append(annotation).append("\n"); - } - if (parentShortComponentName != null - && parentShortComponentName.equals(activityShortComponentName)) { - info.append("Parent: ").append(parentShortComponentName).append("\n"); - } - - if (isPackageLoading) { - // Report in the main log that the package is still loading - final float loadingProgress = packageManagerInternal.getIncrementalStatesInfo( - aInfo.packageName, uid, userId).getProgress(); - info.append("Package is ").append((int) (loadingProgress * 100)).append("% loaded.\n"); - } - - StringBuilder report = new StringBuilder(); - report.append(MemoryPressureUtil.currentPsiState()); - ProcessCpuTracker processCpuTracker = new ProcessCpuTracker(true); - - // don't dump native PIDs for background ANRs unless it is the process of interest - String[] nativeProcs = null; - if (isSilentAnr || onlyDumpSelf) { - for (int i = 0; i < NATIVE_STACKS_OF_INTEREST.length; i++) { - if (NATIVE_STACKS_OF_INTEREST[i].equals(processName)) { - nativeProcs = new String[] { processName }; - break; - } - } - } else { - nativeProcs = NATIVE_STACKS_OF_INTEREST; - } - - int[] pids = nativeProcs == null ? null : Process.getPidsForCommands(nativeProcs); - ArrayList nativePids = null; - - if (pids != null) { - nativePids = new ArrayList<>(pids.length); - for (int i : pids) { - nativePids.add(i); - } - } - - // For background ANRs, don't pass the ProcessCpuTracker to - // avoid spending 1/2 second collecting stats to rank lastPids. - StringWriter tracesFileException = new StringWriter(); - // To hold the start and end offset to the ANR trace file respectively. - final long[] offsets = new long[2]; - File tracesFile = ActivityManagerService.dumpStackTraces(firstPids, - isSilentAnr ? null : processCpuTracker, isSilentAnr ? null : lastPids, - nativePids, tracesFileException, offsets); - - if (isMonitorCpuUsage()) { - mService.updateCpuStatsNow(); - mService.mAppProfiler.printCurrentCpuState(report, anrTime); - info.append(processCpuTracker.printCurrentLoad()); - info.append(report); - } - report.append(tracesFileException.getBuffer()); - - info.append(processCpuTracker.printCurrentState(anrTime)); - - Slog.e(TAG, info.toString()); - if (tracesFile == null) { - // There is no trace file, so dump (only) the alleged culprit's threads to the log - Process.sendSignal(pid, Process.SIGNAL_QUIT); - } else if (offsets[1] > 0) { - // We've dumped into the trace file successfully - mService.mProcessList.mAppExitInfoTracker.scheduleLogAnrTrace( - pid, uid, getPackageList(), tracesFile, offsets[0], offsets[1]); - } - - FrameworkStatsLog.write(FrameworkStatsLog.ANR_OCCURRED, uid, processName, - activityShortComponentName == null ? "unknown": activityShortComponentName, - annotation, - (this.info != null) ? (this.info.isInstantApp() - ? FrameworkStatsLog.ANROCCURRED__IS_INSTANT_APP__TRUE - : FrameworkStatsLog.ANROCCURRED__IS_INSTANT_APP__FALSE) - : FrameworkStatsLog.ANROCCURRED__IS_INSTANT_APP__UNAVAILABLE, - isInterestingToUserLocked() - ? FrameworkStatsLog.ANROCCURRED__FOREGROUND_STATE__FOREGROUND - : FrameworkStatsLog.ANROCCURRED__FOREGROUND_STATE__BACKGROUND, - getProcessClassEnum(), - (this.info != null) ? this.info.packageName : "", isPackageLoading); - final ProcessRecord parentPr = parentProcess != null - ? (ProcessRecord) parentProcess.mOwner : null; - mService.addErrorToDropBox("anr", this, processName, activityShortComponentName, - parentShortComponentName, parentPr, annotation, report.toString(), tracesFile, - null); - - if (mWindowProcessController.appNotResponding(info.toString(), () -> kill("anr", - ApplicationExitInfo.REASON_ANR, true), - () -> { - synchronized (mService) { - mService.mServices.scheduleServiceTimeoutLocked(this); - } - })) { - return; - } - - synchronized (mService) { - // mBatteryStatsService can be null if the AMS is constructed with injector only. This - // will only happen in tests. - if (mService.mBatteryStatsService != null) { - mService.mBatteryStatsService.noteProcessAnr(processName, uid); - } - - if (isSilentAnr() && !isDebugging()) { - kill("bg anr", ApplicationExitInfo.REASON_ANR, true); - return; - } - - // Set the app's notResponding state, and look up the errorReportReceiver - makeAppNotRespondingLocked(activityShortComponentName, - annotation != null ? "ANR " + annotation : "ANR", info.toString()); - - // Notify package manager service to possibly update package state - if (aInfo != null && aInfo.packageName != null) { - packageManagerInternal.notifyPackageCrashOrAnr(aInfo.packageName); - } - - // mUiHandler can be null if the AMS is constructed with injector only. This will only - // happen in tests. - if (mService.mUiHandler != null) { - // Bring up the infamous App Not Responding dialog - Message msg = Message.obtain(); - msg.what = ActivityManagerService.SHOW_NOT_RESPONDING_UI_MSG; - msg.obj = new AppNotRespondingDialog.Data(this, aInfo, aboveSystem); - - mService.mUiHandler.sendMessage(msg); - } - } - } - - private void makeAppNotRespondingLocked(String activity, String shortMsg, String longMsg) { - setNotResponding(true); - // mAppErrors can be null if the AMS is constructed with injector only. This will only - // happen in tests. - if (mService.mAppErrors != null) { - notRespondingReport = mService.mAppErrors.generateProcessError(this, - ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING, - activity, shortMsg, longMsg, null); - } - startAppProblemLocked(); - getWindowProcessController().stopFreezingActivities(); - } - - void startAppProblemLocked() { - // If this app is not running under the current user, then we can't give it a report button - // because that would require launching the report UI under a different user. - errorReportReceiver = null; - - for (int userId : mService.mUserController.getCurrentProfileIds()) { - if (this.userId == userId) { - errorReportReceiver = ApplicationErrorReport.getErrorReportReceiver( - mService.mContext, info.packageName, info.flags); - } - } - mService.skipCurrentReceiverLocked(this); - } - - private boolean isInterestingForBackgroundTraces() { - // The system_server is always considered interesting. - if (pid == MY_PID) { - return true; - } - - // A package is considered interesting if any of the following is true : - // - // - It's displaying an activity. - // - It's the SystemUI. - // - It has an overlay or a top UI visible. - // - // NOTE: The check whether a given ProcessRecord belongs to the systemui - // process is a bit of a kludge, but the same pattern seems repeated at - // several places in the system server. - return isInterestingToUserLocked() || - (info != null && "com.android.systemui".equals(info.packageName)) - || (hasTopUi() || hasOverlayUi()); - } - - private boolean getShowBackground() { - return Settings.Secure.getInt(mService.mContext.getContentResolver(), - Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0; - } - - void resetCachedInfo() { - mCachedHasActivities = VALUE_INVALID; - mCachedIsHeavyWeight = VALUE_INVALID; - mCachedHasVisibleActivities = VALUE_INVALID; - mCachedIsHomeProcess = VALUE_INVALID; - mCachedIsPreviousProcess = VALUE_INVALID; - mCachedHasRecentTasks = VALUE_INVALID; - mCachedIsReceivingBroadcast = VALUE_INVALID; - mCachedAdj = ProcessList.INVALID_ADJ; - mCachedForegroundActivities = false; - mCachedProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY; - mCachedSchedGroup = ProcessList.SCHED_GROUP_BACKGROUND; - } - - boolean getCachedHasActivities() { - if (mCachedHasActivities == VALUE_INVALID) { - mCachedHasActivities = getWindowProcessController().hasActivities() ? VALUE_TRUE - : VALUE_FALSE; - } - return mCachedHasActivities == VALUE_TRUE; - } - - boolean getCachedIsHeavyWeight() { - if (mCachedIsHeavyWeight == VALUE_INVALID) { - mCachedIsHeavyWeight = getWindowProcessController().isHeavyWeightProcess() - ? VALUE_TRUE : VALUE_FALSE; - } - return mCachedIsHeavyWeight == VALUE_TRUE; - } - - boolean getCachedHasVisibleActivities() { - if (mCachedHasVisibleActivities == VALUE_INVALID) { - mCachedHasVisibleActivities = getWindowProcessController().hasVisibleActivities() - ? VALUE_TRUE : VALUE_FALSE; - } - return mCachedHasVisibleActivities == VALUE_TRUE; - } - - boolean getCachedIsHomeProcess() { - if (mCachedIsHomeProcess == VALUE_INVALID) { - if (getWindowProcessController().isHomeProcess()) { - mCachedIsHomeProcess = VALUE_TRUE; - mService.mAppProfiler.mHasHomeProcess = true; - } else { - mCachedIsHomeProcess = VALUE_FALSE; - } - } - return mCachedIsHomeProcess == VALUE_TRUE; - } - - boolean getCachedIsPreviousProcess() { - if (mCachedIsPreviousProcess == VALUE_INVALID) { - if (getWindowProcessController().isPreviousProcess()) { - mCachedIsPreviousProcess = VALUE_TRUE; - mService.mAppProfiler.mHasPreviousProcess = true; - } else { - mCachedIsPreviousProcess = VALUE_FALSE; - } - } - return mCachedIsPreviousProcess == VALUE_TRUE; - } - - boolean getCachedHasRecentTasks() { - if (mCachedHasRecentTasks == VALUE_INVALID) { - mCachedHasRecentTasks = getWindowProcessController().hasRecentTasks() - ? VALUE_TRUE : VALUE_FALSE; - } - return mCachedHasRecentTasks == VALUE_TRUE; - } - - boolean getCachedIsReceivingBroadcast(ArraySet tmpQueue) { - if (mCachedIsReceivingBroadcast == VALUE_INVALID) { - tmpQueue.clear(); - mCachedIsReceivingBroadcast = mService.isReceivingBroadcastLocked(this, tmpQueue) - ? VALUE_TRUE : VALUE_FALSE; - if (mCachedIsReceivingBroadcast == VALUE_TRUE) { - mCachedSchedGroup = tmpQueue.contains(mService.mFgBroadcastQueue) - ? ProcessList.SCHED_GROUP_DEFAULT : ProcessList.SCHED_GROUP_BACKGROUND; - } - } - return mCachedIsReceivingBroadcast == VALUE_TRUE; - } - - void computeOomAdjFromActivitiesIfNecessary(OomAdjuster.ComputeOomAdjWindowCallback callback, - int adj, boolean foregroundActivities, int procState, int schedGroup, int appUid, - int logUid, int processCurTop) { - if (mCachedAdj != ProcessList.INVALID_ADJ) { - return; - } - callback.initialize(this, adj, foregroundActivities, procState, schedGroup, appUid, logUid, - processCurTop); - final int minLayer = Math.min(ProcessList.VISIBLE_APP_LAYER_MAX, - getWindowProcessController().computeOomAdjFromActivities(callback)); - - mCachedAdj = callback.adj; - mCachedForegroundActivities = callback.foregroundActivities; - mCachedProcState = callback.procState; - mCachedSchedGroup = callback.schedGroup; - - if (mCachedAdj == ProcessList.VISIBLE_APP_ADJ) { - mCachedAdj += minLayer; - } - } - - public void addAllowBackgroundFgsStartsToken(Binder entity) { - mBackgroundFgsStartTokens.add(entity); - } - - public void removeAllowBackgroundFgsStartsToken(Binder entity) { - mBackgroundFgsStartTokens.remove(entity); - } - - public boolean areBackgroundFgsStartsAllowedByToken() { - return !mBackgroundFgsStartTokens.isEmpty(); - } - - ErrorDialogController getDialogController() { - return mDialogController; - } - - void resetAllowStartFgs() { - mAllowStartFgsState = PROCESS_STATE_NONEXISTENT; - mAllowStartFgs = mAllowStartFgsByPermission; - } - - void bumpAllowStartFgsState(int newProcState) { - if (newProcState < mAllowStartFgsState) { - mAllowStartFgsState = newProcState; - } - } - - void setAllowStartFgsByPermission() { - int ret = FGS_FEATURE_DENIED; - if (ret == FGS_FEATURE_DENIED) { - boolean isSystem = false; - final int uid = UserHandle.getAppId(info.uid); - switch (uid) { - case ROOT_UID: - case SYSTEM_UID: - case NFC_UID: - case SHELL_UID: - isSystem = true; - break; - default: - isSystem = false; - break; - } - - if (isSystem) { - ret = FGS_FEATURE_ALLOWED_BY_SYSTEM_UID; - } - } - - if (ret == FGS_FEATURE_DENIED) { - if (ActivityManager.checkComponentPermission(START_ACTIVITIES_FROM_BACKGROUND, - info.uid, -1, true) == PERMISSION_GRANTED) { - ret = FGS_FEATURE_ALLOWED_BY_BACKGROUND_ACTIVITY_PERMISSION; - } else if (ActivityManager.checkComponentPermission( - START_FOREGROUND_SERVICES_FROM_BACKGROUND, - info.uid, -1, true) == PERMISSION_GRANTED) { - ret = FGS_FEATURE_ALLOWED_BY_BACKGROUND_FGS_PERMISSION; - } else if (ActivityManager.checkComponentPermission(SYSTEM_ALERT_WINDOW, - info.uid, -1, true) == PERMISSION_GRANTED) { - ret = FGS_FEATURE_ALLOWED_BY_SYSTEM_ALERT_WINDOW_PERMISSION; - } - } - mAllowStartFgs = mAllowStartFgsByPermission = ret; - } - - boolean isAllowedStartFgsState() { - return mAllowStartFgsState <= PROCESS_STATE_BOUND_FOREGROUND_SERVICE; - } - - void setAllowStartFgs() { - if (mAllowStartFgs != FGS_FEATURE_DENIED) { - return; - } - if (mAllowStartFgs == FGS_FEATURE_DENIED) { - if (isAllowedStartFgsState()) { - mAllowStartFgs = FGS_FEATURE_ALLOWED_BY_PROC_STATE; - } - } - - if (mAllowStartFgs == FGS_FEATURE_DENIED) { - // Is the calling UID a device owner app? - if (mService.mInternal != null) { - if (mService.mInternal.isDeviceOwner(info.uid)) { - mAllowStartFgs = FGS_FEATURE_ALLOWED_BY_DEVICE_OWNER; - } - } - } - - if (mAllowStartFgs == FGS_FEATURE_DENIED) { - if (mService.mInternal != null) { - final boolean isCompanionApp = mService.mInternal.isAssociatedCompanionApp( - UserHandle.getUserId(info.uid), info.uid); - if (isCompanionApp) { - mAllowStartFgs = FGS_FEATURE_ALLOWED_BY_COMPANION_APP; - } - } - } - - if (mAllowStartFgs == FGS_FEATURE_DENIED) { - // Is the calling UID a profile owner app? - if (mService.mInternal != null) { - if (mService.mInternal.isProfileOwner(info.uid)) { - mAllowStartFgs = FGS_FEATURE_ALLOWED_BY_PROFILE_OWNER; - } - } - } - - if (mAllowStartFgs == FGS_FEATURE_DENIED) { - // uid is on DeviceIdleController's user/system allowlist - // or AMS's FgsStartTempAllowList. - if (mService.isAllowlistedForFgsStartLocked(info.uid)) { - mAllowStartFgs = FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST; - } - } - } - - /** A controller to generate error dialogs in {@link ProcessRecord} */ - class ErrorDialogController { - /** dialogs being displayed due to crash */ - private List mCrashDialogs; - /** dialogs being displayed due to app not responding */ - private List mAnrDialogs; - /** dialogs displayed due to strict mode violation */ - private List mViolationDialogs; - /** current wait for debugger dialog */ - private AppWaitingForDebuggerDialog mWaitDialog; - - boolean hasCrashDialogs() { - return mCrashDialogs != null; - } - - boolean hasAnrDialogs() { - return mAnrDialogs != null; - } - - boolean hasViolationDialogs() { - return mViolationDialogs != null; - } - - boolean hasDebugWaitingDialog() { - return mWaitDialog != null; - } - - void clearAllErrorDialogs() { - clearCrashDialogs(); - clearAnrDialogs(); - clearViolationDialogs(); - clearWaitingDialog(); - } - - void clearCrashDialogs() { - clearCrashDialogs(true /* needDismiss */); - } - - void clearCrashDialogs(boolean needDismiss) { - if (mCrashDialogs == null) { - return; - } - if (needDismiss) { - forAllDialogs(mCrashDialogs, Dialog::dismiss); - } - mCrashDialogs = null; - } - - void clearAnrDialogs() { - if (mAnrDialogs == null) { - return; - } - forAllDialogs(mAnrDialogs, Dialog::dismiss); - mAnrDialogs = null; - } - - void clearViolationDialogs() { - if (mViolationDialogs == null) { - return; - } - forAllDialogs(mViolationDialogs, Dialog::dismiss); - mViolationDialogs = null; - } - - void clearWaitingDialog() { - if (mWaitDialog == null) { - return; - } - mWaitDialog.dismiss(); - mWaitDialog = null; - } - - void forAllDialogs(List dialogs, Consumer c) { - for (int i = dialogs.size() - 1; i >= 0; i--) { - c.accept(dialogs.get(i)); - } - } - - void showCrashDialogs(AppErrorDialog.Data data) { - List contexts = getDisplayContexts(false /* lastUsedOnly */); - mCrashDialogs = new ArrayList<>(); - for (int i = contexts.size() - 1; i >= 0; i--) { - final Context c = contexts.get(i); - mCrashDialogs.add(new AppErrorDialog(c, mService, data)); - } - mService.mUiHandler.post(() -> { - List dialogs; - synchronized (mService) { - dialogs = mCrashDialogs; - } - if (dialogs != null) { - forAllDialogs(dialogs, Dialog::show); - } - }); - } - - void showAnrDialogs(AppNotRespondingDialog.Data data) { - List contexts = getDisplayContexts(isSilentAnr() /* lastUsedOnly */); - mAnrDialogs = new ArrayList<>(); - for (int i = contexts.size() - 1; i >= 0; i--) { - final Context c = contexts.get(i); - mAnrDialogs.add(new AppNotRespondingDialog(mService, c, data)); - } - mService.mUiHandler.post(() -> { - List dialogs; - synchronized (mService) { - dialogs = mAnrDialogs; - } - if (dialogs != null) { - forAllDialogs(dialogs, Dialog::show); - } - }); - } - - void showViolationDialogs(AppErrorResult res) { - List contexts = getDisplayContexts(false /* lastUsedOnly */); - mViolationDialogs = new ArrayList<>(); - for (int i = contexts.size() - 1; i >= 0; i--) { - final Context c = contexts.get(i); - mViolationDialogs.add( - new StrictModeViolationDialog(c, mService, res, ProcessRecord.this)); - } - mService.mUiHandler.post(() -> { - List dialogs; - synchronized (mService) { - dialogs = mViolationDialogs; - } - if (dialogs != null) { - forAllDialogs(dialogs, Dialog::show); - } - }); - } - - void showDebugWaitingDialogs() { - List contexts = getDisplayContexts(true /* lastUsedOnly */); - final Context c = contexts.get(0); - mWaitDialog = new AppWaitingForDebuggerDialog(mService, c, ProcessRecord.this); - - mService.mUiHandler.post(() -> { - Dialog dialog; - synchronized (mService) { - dialog = mWaitDialog; - } - if (dialog != null) { - dialog.show(); - } - }); - } - - /** - * Helper function to collect contexts from crashed app located displays - * - * @param lastUsedOnly Sets to {@code true} to indicate to only get last used context. - * Sets to {@code false} to collect contexts from crashed app located - * displays. - * - * @return display context list - */ - private List getDisplayContexts(boolean lastUsedOnly) { - List displayContexts = new ArrayList<>(); - if (!lastUsedOnly) { - mWindowProcessController.getDisplayContextsWithErrorDialogs(displayContexts); - } - // If there is no foreground window display, fallback to last used display. - if (displayContexts.isEmpty() || lastUsedOnly) { - displayContexts.add(mService.mWmInternal != null - ? mService.mWmInternal.getTopFocusedDisplayUiContext() - : mService.mUiContext); - } - return displayContexts; - } + return mService.mProcessList.getLruProcessesLOSP(); } } diff --git a/services/core/java/com/android/server/am/ProcessServiceRecord.java b/services/core/java/com/android/server/am/ProcessServiceRecord.java new file mode 100644 index 0000000000000..5c3bf605f71a0 --- /dev/null +++ b/services/core/java/com/android/server/am/ProcessServiceRecord.java @@ -0,0 +1,444 @@ +/* + * 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 android.app.ActivityManager; +import android.content.Context; +import android.os.IBinder; +import android.util.ArrayMap; +import android.util.ArraySet; + +import com.android.internal.annotations.GuardedBy; + +import java.io.PrintWriter; +import java.util.ArrayList; + +/** + * The state info of all services in the process. + */ +final class ProcessServiceRecord { + /** + * Are there any client services with activities? + */ + private boolean mHasClientActivities; + + /** + * Running any services that are foreground? + */ + private boolean mHasForegroundServices; + + /** + * Service that applied current connectionGroup/Importance. + */ + private ServiceRecord mConnectionService; + + /** + * Last group set by a connection. + */ + private int mConnectionGroup; + + /** + * Last importance set by a connection. + */ + private int mConnectionImportance; + + /** + * Type of foreground service, if there is a foreground service. + */ + private int mFgServiceTypes; + + /** + * Last reported foreground service types. + */ + private int mRepFgServiceTypes; + + /** + * Bound using BIND_ABOVE_CLIENT, so want to be lower. + */ + private boolean mHasAboveClient; + + /** + * Bound using BIND_TREAT_LIKE_ACTIVITY. + */ + private boolean mTreatLikeActivity; + + /** + * Do we need to be executing services in the foreground? + */ + private boolean mExecServicesFg; + + /** + * App is allowed to manage allowlists such as temporary Power Save mode allowlist. + */ + boolean mAllowlistManager; + + /** + * All ServiceRecord running in this process. + */ + private final ArraySet mServices = new ArraySet<>(); + + /** + * Services that are currently executing code (need to remain foreground). + */ + private final ArraySet mExecutingServices = new ArraySet<>(); + + /** + * All ConnectionRecord this process holds. + */ + private final ArraySet mConnections = new ArraySet<>(); + + /** + * A set of UIDs of all bound clients. + */ + private ArraySet mBoundClientUids = new ArraySet<>(); + + final ProcessRecord mApp; + + private final ActivityManagerService mService; + + ProcessServiceRecord(ProcessRecord app) { + mApp = app; + mService = app.mService; + } + + void setHasClientActivities(boolean hasClientActivities) { + mHasClientActivities = hasClientActivities; + mApp.getWindowProcessController().setHasClientActivities(hasClientActivities); + } + + boolean hasClientActivities() { + return mHasClientActivities; + } + + void setHasForegroundServices(boolean hasForegroundServices, int fgServiceTypes) { + mHasForegroundServices = hasForegroundServices; + mFgServiceTypes = fgServiceTypes; + mApp.getWindowProcessController().setHasForegroundServices(hasForegroundServices); + } + + boolean hasForegroundServices() { + return mHasForegroundServices; + } + + int getForegroundServiceTypes() { + return mHasForegroundServices ? mFgServiceTypes : 0; + } + + int getReportedForegroundServiceTypes() { + return mRepFgServiceTypes; + } + + void setReportedForegroundServiceTypes(int foregroundServiceTypes) { + mRepFgServiceTypes = foregroundServiceTypes; + } + + ServiceRecord getConnectionService() { + return mConnectionService; + } + + void setConnectionService(ServiceRecord connectionService) { + mConnectionService = connectionService; + } + + int getConnectionGroup() { + return mConnectionGroup; + } + + void setConnectionGroup(int connectionGroup) { + mConnectionGroup = connectionGroup; + } + + int getConnectionImportance() { + return mConnectionImportance; + } + + void setConnectionImportance(int connectionImportance) { + mConnectionImportance = connectionImportance; + } + + void updateHasAboveClientLocked() { + mHasAboveClient = false; + for (int i = mConnections.size() - 1; i >= 0; i--) { + ConnectionRecord cr = mConnections.valueAt(i); + if ((cr.flags & Context.BIND_ABOVE_CLIENT) != 0) { + mHasAboveClient = true; + break; + } + } + } + + void setHasAboveClient(boolean hasAboveClient) { + mHasAboveClient = hasAboveClient; + } + + boolean hasAboveClient() { + return mHasAboveClient; + } + + int modifyRawOomAdj(int adj) { + if (mHasAboveClient) { + // If this process has bound to any services with BIND_ABOVE_CLIENT, + // then we need to drop its adjustment to be lower than the service's + // in order to honor the request. We want to drop it by one adjustment + // level... but there is special meaning applied to various levels so + // we will skip some of them. + if (adj < ProcessList.FOREGROUND_APP_ADJ) { + // System process will not get dropped, ever + } else if (adj < ProcessList.VISIBLE_APP_ADJ) { + adj = ProcessList.VISIBLE_APP_ADJ; + } else if (adj < ProcessList.PERCEPTIBLE_APP_ADJ) { + adj = ProcessList.PERCEPTIBLE_APP_ADJ; + } else if (adj < ProcessList.PERCEPTIBLE_LOW_APP_ADJ) { + adj = ProcessList.PERCEPTIBLE_LOW_APP_ADJ; + } else if (adj < ProcessList.CACHED_APP_MIN_ADJ) { + adj = ProcessList.CACHED_APP_MIN_ADJ; + } else if (adj < ProcessList.CACHED_APP_MAX_ADJ) { + adj++; + } + } + return adj; + } + + boolean isTreatedLikeActivity() { + return mTreatLikeActivity; + } + + void setTreatLikeActivity(boolean treatLikeActivity) { + mTreatLikeActivity = treatLikeActivity; + } + + boolean shouldExecServicesFg() { + return mExecServicesFg; + } + + void setExecServicesFg(boolean execServicesFg) { + mExecServicesFg = execServicesFg; + } + + /** + * Records a service as running in the process. Note that this method does not actually start + * the service, but records the service as started for bookkeeping. + * + * @return true if the service was added, false otherwise. + */ + boolean startService(ServiceRecord record) { + if (record == null) { + return false; + } + boolean added = mServices.add(record); + if (added && record.serviceInfo != null) { + mApp.getWindowProcessController().onServiceStarted(record.serviceInfo); + } + return added; + } + + /** + * Records a service as stopped. Note that like {@link #startService(ServiceRecord)} this method + * does not actually stop the service, but records the service as stopped for bookkeeping. + * + * @return true if the service was removed, false otherwise. + */ + boolean stopService(ServiceRecord record) { + return mServices.remove(record); + } + + /** + * The same as calling {@link #stopService(ServiceRecord)} on all current running services. + */ + void stopAllServices() { + mServices.clear(); + } + + /** + * Returns the number of services added with {@link #startService(ServiceRecord)} and not yet + * removed by a call to {@link #stopService(ServiceRecord)} or {@link #stopAllServices()}. + * + * @see #startService(ServiceRecord) + * @see #stopService(ServiceRecord) + */ + int numberOfRunningServices() { + return mServices.size(); + } + + /** + * Returns the service at the specified {@code index}. + * + * @see #numberOfRunningServices() + */ + ServiceRecord getRunningServiceAt(int index) { + return mServices.valueAt(index); + } + + void startExecutingService(ServiceRecord service) { + mExecutingServices.add(service); + } + + void stopExecutingService(ServiceRecord service) { + mExecutingServices.remove(service); + } + + void stopAllExecutingServices() { + mExecutingServices.clear(); + } + + ServiceRecord getExecutingServiceAt(int index) { + return mExecutingServices.valueAt(index); + } + + int numberOfExecutingServices() { + return mExecutingServices.size(); + } + + void addConnection(ConnectionRecord connection) { + mConnections.add(connection); + } + + void removeConnection(ConnectionRecord connection) { + mConnections.remove(connection); + } + + void removeAllConnections() { + mConnections.clear(); + } + + ConnectionRecord getConnectionAt(int index) { + return mConnections.valueAt(index); + } + + int numberOfConnections() { + return mConnections.size(); + } + + void addBoundClientUid(int clientUid) { + mBoundClientUids.add(clientUid); + mApp.getWindowProcessController().setBoundClientUids(mBoundClientUids); + } + + void updateBoundClientUids() { + if (mServices.isEmpty()) { + clearBoundClientUids(); + return; + } + // grab a set of clientUids of all mConnections of all services + final ArraySet boundClientUids = new ArraySet<>(); + final int serviceCount = mServices.size(); + for (int j = 0; j < serviceCount; j++) { + final ArrayMap> conns = + mServices.valueAt(j).getConnections(); + final int size = conns.size(); + for (int conni = 0; conni < size; conni++) { + ArrayList c = conns.valueAt(conni); + for (int i = 0; i < c.size(); i++) { + boundClientUids.add(c.get(i).clientUid); + } + } + } + mBoundClientUids = boundClientUids; + mApp.getWindowProcessController().setBoundClientUids(mBoundClientUids); + } + + void addBoundClientUidsOfNewService(ServiceRecord sr) { + if (sr == null) { + return; + } + ArrayMap> conns = sr.getConnections(); + for (int conni = conns.size() - 1; conni >= 0; conni--) { + ArrayList c = conns.valueAt(conni); + for (int i = 0; i < c.size(); i++) { + mBoundClientUids.add(c.get(i).clientUid); + } + } + mApp.getWindowProcessController().setBoundClientUids(mBoundClientUids); + } + + void clearBoundClientUids() { + mBoundClientUids.clear(); + mApp.getWindowProcessController().setBoundClientUids(mBoundClientUids); + } + + @GuardedBy("mService") + boolean incServiceCrashCountLocked(long now) { + final boolean procIsBoundForeground = mApp.mState.getCurProcState() + == ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE; + boolean tryAgain = false; + // Bump up the crash count of any services currently running in the proc. + for (int i = numberOfRunningServices() - 1; i >= 0; i--) { + // Any services running in the application need to be placed + // back in the pending list. + ServiceRecord sr = getRunningServiceAt(i); + // If the service was restarted a while ago, then reset crash count, else increment it. + if (now > sr.restartTime + ActivityManagerConstants.MIN_CRASH_INTERVAL) { + sr.crashCount = 1; + } else { + sr.crashCount++; + } + // Allow restarting for started or bound foreground services that are crashing. + // This includes wallpapers. + if (sr.crashCount < mService.mConstants.BOUND_SERVICE_MAX_CRASH_RETRY + && (sr.isForeground || procIsBoundForeground)) { + tryAgain = true; + } + } + return tryAgain; + } + + @GuardedBy("mService") + void onCleanupApplicationRecordLocked() { + mTreatLikeActivity = false; + mHasAboveClient = false; + setHasClientActivities(false); + } + + void dump(PrintWriter pw, String prefix, long nowUptime) { + if (mHasForegroundServices || mApp.mState.getForcingToImportant() != null) { + pw.print(prefix); pw.print("mHasForegroundServices="); pw.print(mHasForegroundServices); + pw.print(" forcingToImportant="); pw.println(mApp.mState.getForcingToImportant()); + } + if (mHasClientActivities || mHasAboveClient || mTreatLikeActivity) { + pw.print(prefix); pw.print("hasClientActivities="); pw.print(mHasClientActivities); + pw.print(" hasAboveClient="); pw.print(mHasAboveClient); + pw.print(" treatLikeActivity="); pw.println(mTreatLikeActivity); + } + if (mConnectionService != null || mConnectionGroup != 0) { + pw.print(prefix); pw.print("connectionGroup="); pw.print(mConnectionGroup); + pw.print(" Importance="); pw.print(mConnectionImportance); + pw.print(" Service="); pw.println(mConnectionService); + } + if (mAllowlistManager) { + pw.print(prefix); pw.print("allowlistManager="); pw.println(mAllowlistManager); + } + if (mServices.size() > 0) { + pw.print(prefix); pw.println("Services:"); + for (int i = 0, size = mServices.size(); i < size; i++) { + pw.print(prefix); pw.print(" - "); pw.println(mServices.valueAt(i)); + } + } + if (mExecutingServices.size() > 0) { + pw.print(prefix); pw.print("Executing Services (fg="); + pw.print(mExecServicesFg); pw.println(")"); + for (int i = 0, size = mExecutingServices.size(); i < size; i++) { + pw.print(prefix); pw.print(" - "); pw.println(mExecutingServices.valueAt(i)); + } + } + if (mConnections.size() > 0) { + pw.print(prefix); pw.println("mConnections:"); + for (int i = 0, size = mConnections.size(); i < size; i++) { + pw.print(prefix); pw.print(" - "); pw.println(mConnections.valueAt(i)); + } + } + } +} diff --git a/services/core/java/com/android/server/am/ProcessStateRecord.java b/services/core/java/com/android/server/am/ProcessStateRecord.java new file mode 100644 index 0000000000000..e1a153dfa9203 --- /dev/null +++ b/services/core/java/com/android/server/am/ProcessStateRecord.java @@ -0,0 +1,1337 @@ +/* + * 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.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND; +import static android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND; +import static android.Manifest.permission.SYSTEM_ALERT_WINDOW; +import static android.app.ActivityManager.PROCESS_CAPABILITY_NONE; +import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE; +import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT; +import static android.content.pm.PackageManager.PERMISSION_GRANTED; +import static android.os.Process.NFC_UID; +import static android.os.Process.ROOT_UID; +import static android.os.Process.SHELL_UID; +import static android.os.Process.SYSTEM_UID; + +import static com.android.server.am.ActiveServices.FGS_FEATURE_ALLOWED_BY_BACKGROUND_ACTIVITY_PERMISSION; +import static com.android.server.am.ActiveServices.FGS_FEATURE_ALLOWED_BY_BACKGROUND_FGS_PERMISSION; +import static com.android.server.am.ActiveServices.FGS_FEATURE_ALLOWED_BY_COMPANION_APP; +import static com.android.server.am.ActiveServices.FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST; +import static com.android.server.am.ActiveServices.FGS_FEATURE_ALLOWED_BY_DEVICE_OWNER; +import static com.android.server.am.ActiveServices.FGS_FEATURE_ALLOWED_BY_PROC_STATE; +import static com.android.server.am.ActiveServices.FGS_FEATURE_ALLOWED_BY_PROFILE_OWNER; +import static com.android.server.am.ActiveServices.FGS_FEATURE_ALLOWED_BY_SYSTEM_ALERT_WINDOW_PERMISSION; +import static com.android.server.am.ActiveServices.FGS_FEATURE_ALLOWED_BY_SYSTEM_UID; +import static com.android.server.am.ActiveServices.FGS_FEATURE_DENIED; +import static com.android.server.am.ActiveServices.fgsCodeToString; +import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_OOM_ADJ; +import static com.android.server.am.ProcessRecord.TAG; + +import android.app.ActivityManager; +import android.content.ComponentName; +import android.os.Binder; +import android.os.SystemClock; +import android.os.UserHandle; +import android.util.ArraySet; +import android.util.Slog; +import android.util.TimeUtils; + +import com.android.internal.annotations.CompositeRWLock; +import com.android.internal.annotations.GuardedBy; +import com.android.internal.util.FrameworkStatsLog; + + +import java.io.PrintWriter; + +/** + * The state info of the process, including proc state, oom adj score, et al. + */ +final class ProcessStateRecord { + private final ProcessRecord mApp; + private final ActivityManagerService mService; + private final ActivityManagerGlobalLock mProcLock; + + /** + * Maximum OOM adjustment for this process. + */ + @GuardedBy("mService") + private int mMaxAdj = ProcessList.UNKNOWN_ADJ; + + /** + * Current OOM unlimited adjustment for this process. + */ + @CompositeRWLock({"mService", "mProcLock"}) + private int mCurRawAdj = ProcessList.INVALID_ADJ; + + /** + * Last set OOM unlimited adjustment for this process. + */ + @CompositeRWLock({"mService", "mProcLock"}) + private int mSetRawAdj = ProcessList.INVALID_ADJ; + + /** + * Current OOM adjustment for this process. + */ + @CompositeRWLock({"mService", "mProcLock"}) + private int mCurAdj = ProcessList.INVALID_ADJ; + + /** + * Last set OOM adjustment for this process. + */ + @CompositeRWLock({"mService", "mProcLock"}) + private int mSetAdj = ProcessList.INVALID_ADJ; + + /** + * The last adjustment that was verified as actually being set. + */ + @GuardedBy("mService") + private int mVerifiedAdj = ProcessList.INVALID_ADJ; + + /** + * Current capability flags of this process. + * For example, PROCESS_CAPABILITY_FOREGROUND_LOCATION is one capability. + */ + @CompositeRWLock({"mService", "mProcLock"}) + private int mCurCapability = PROCESS_CAPABILITY_NONE; + + /** + * Last set capability flags. + */ + @CompositeRWLock({"mService", "mProcLock"}) + private int mSetCapability = PROCESS_CAPABILITY_NONE; + + /** + * Currently desired scheduling class. + */ + @CompositeRWLock({"mService", "mProcLock"}) + private int mCurSchedGroup = ProcessList.SCHED_GROUP_BACKGROUND; + + /** + * Last set to background scheduling class. + */ + @CompositeRWLock({"mService", "mProcLock"}) + private int mSetSchedGroup = ProcessList.SCHED_GROUP_BACKGROUND; + + /** + * Currently computed process state. + */ + @CompositeRWLock({"mService", "mProcLock"}) + private int mCurProcState = PROCESS_STATE_NONEXISTENT; + + /** + * Last reported process state. + */ + @CompositeRWLock({"mService", "mProcLock"}) + private int mRepProcState = PROCESS_STATE_NONEXISTENT; + + /** + * Temp state during computation. + */ + @CompositeRWLock({"mService", "mProcLock"}) + private int mCurRawProcState = PROCESS_STATE_NONEXISTENT; + + /** + * Last set process state in process tracker. + */ + @CompositeRWLock({"mService", "mProcLock"}) + private int mSetProcState = PROCESS_STATE_NONEXISTENT; + + /** + * Last time mSetProcState changed. + */ + @CompositeRWLock({"mService", "mProcLock"}) + private long mLastStateTime; + + /** + * Previous priority value if we're switching to non-SCHED_OTHER. + */ + @CompositeRWLock({"mService", "mProcLock"}) + private int mSavedPriority; + + /** + * Process currently is on the service B list. + */ + @CompositeRWLock({"mService", "mProcLock"}) + private boolean mServiceB; + + /** + * We are forcing to service B list due to its RAM use. + */ + @CompositeRWLock({"mService", "mProcLock"}) + private boolean mServiceHighRam; + + /** + * Has this process not been in a cached state since last idle? + */ + @GuardedBy("mProcLock") + private boolean mNotCachedSinceIdle; + + /** + * Are there any started services running in this process? + */ + @CompositeRWLock({"mService", "mProcLock"}) + private boolean mHasStartedServices; + + /** + * Running any activities that are foreground? + */ + @CompositeRWLock({"mService", "mProcLock"}) + private boolean mHasForegroundActivities; + + /** + * Last reported foreground activities. + */ + @CompositeRWLock({"mService", "mProcLock"}) + private boolean mRepForegroundActivities; + + /** + * Has UI been shown in this process since it was started? + */ + @GuardedBy("mService") + private boolean mHasShownUi; + + /** + * Is this process currently showing a non-activity UI that the user + * is interacting with? E.g. The status bar when it is expanded, but + * not when it is minimized. When true the + * process will be set to use the ProcessList#SCHED_GROUP_TOP_APP + * scheduling group to boost performance. + */ + @GuardedBy("mService") + private boolean mHasTopUi; + + /** + * Is the process currently showing a non-activity UI that + * overlays on-top of activity UIs on screen. E.g. display a window + * of type android.view.WindowManager.LayoutParams#TYPE_APPLICATION_OVERLAY + * When true the process will oom adj score will be set to + * ProcessList#PERCEPTIBLE_APP_ADJ at minimum to reduce the chance + * of the process getting killed. + */ + @GuardedBy("mService") + private boolean mHasOverlayUi; + + /** + * Is the process currently running a RemoteAnimation? When true + * the process will be set to use the + * ProcessList#SCHED_GROUP_TOP_APP scheduling group to boost + * performance, as well as oom adj score will be set to + * ProcessList#VISIBLE_APP_ADJ at minimum to reduce the chance + * of the process getting killed. + */ + @GuardedBy("mService") + private boolean mRunningRemoteAnimation; + + /** + * Keep track of whether we changed 'mSetAdj'. + */ + @CompositeRWLock({"mService", "mProcLock"}) + private boolean mProcStateChanged; + + /** + * Whether we have told usage stats about it being an interaction. + */ + @CompositeRWLock({"mService", "mProcLock"}) + private boolean mReportedInteraction; + + /** + * The time we sent the last interaction event. + */ + @CompositeRWLock({"mService", "mProcLock"}) + private long mInteractionEventTime; + + /** + * When we became foreground for interaction purposes. + */ + @CompositeRWLock({"mService", "mProcLock"}) + private long mFgInteractionTime; + + /** + * Token that is forcing this process to be important. + */ + @GuardedBy("mService") + private Object mForcingToImportant; + + /** + * Sequence id for identifying oom_adj assignment cycles. + */ + @GuardedBy("mService") + private int mAdjSeq; + + /** + * Sequence id for identifying oom_adj assignment cycles. + */ + @GuardedBy("mService") + private int mCompletedAdjSeq; + + /** + * Whether this app has encountered a cycle in the most recent update. + */ + @GuardedBy("mService") + private boolean mContainsCycle; + + /** + * When (uptime) the process last became unimportant. + */ + @CompositeRWLock({"mService", "mProcLock"}) + private long mWhenUnimportant; + + /** + * The last time the process was in the TOP state or greater. + */ + @GuardedBy("mService") + private long mLastTopTime; + + /** + * Is this an empty background process? + */ + @GuardedBy("mService") + private boolean mEmpty; + + /** + * Is this a cached process? + */ + @GuardedBy("mService") + private boolean mCached; + + /** + * This is a system process, but not currently showing UI. + */ + @GuardedBy("mService") + private boolean mSystemNoUi; + + /** + * If the proc state is PROCESS_STATE_BOUND_FOREGROUND_SERVICE or above, it can start FGS. + * It must obtain the proc state from a persistent/top process or FGS, not transitive. + */ + @GuardedBy("mService") + private int mAllowStartFgsState = PROCESS_STATE_NONEXISTENT; + + @GuardedBy("mService") + private final ArraySet mBackgroundFgsStartTokens = new ArraySet<>(); + + /** + * Does the process has permission to start FGS from background. + */ + @GuardedBy("mService") + private @ActiveServices.FgsFeatureRetCode int mAllowStartFgsByPermission; + + /** + * Can this process start FGS from background? + * If this process has the ability to start FGS from background, this ability can be passed to + * another process through service binding. + */ + @GuardedBy("mService") + private @ActiveServices.FgsFeatureRetCode int mAllowStartFgs; + + /** + * Debugging: primary thing impacting oom_adj. + */ + @GuardedBy("mService") + private String mAdjType; + + /** + * Debugging: adj code to report to app. + */ + @CompositeRWLock({"mService", "mProcLock"}) + private int mAdjTypeCode; + + /** + * Debugging: option dependent object. + */ + @CompositeRWLock({"mService", "mProcLock"}) + private Object mAdjSource; + + /** + * Debugging: proc state of mAdjSource's process. + */ + @CompositeRWLock({"mService", "mProcLock"}) + private int mAdjSourceProcState; + + /** + * Debugging: target component impacting oom_adj. + */ + @CompositeRWLock({"mService", "mProcLock"}) + private Object mAdjTarget; + + /** + * Approximates the usage count of the app, used for cache re-ranking by CacheOomRanker. + * + * Counts the number of times the process is re-added to the cache (i.e. setCached(false); + * setCached(true)). This over counts, as setCached is sometimes reset while remaining in the + * cache. However, this happens uniformly across processes, so ranking is not affected. + */ + @GuardedBy("mService") + private int mCacheOomRankerUseCount; + + /** + * Whether or not this process is reachable from given process. + */ + @GuardedBy("mService") + private boolean mReachable; + + // Below are the cached task info for OomAdjuster only + private static final int VALUE_INVALID = -1; + private static final int VALUE_FALSE = 0; + private static final int VALUE_TRUE = 1; + + @GuardedBy("mService") + private int mCachedHasActivities = VALUE_INVALID; + @GuardedBy("mService") + private int mCachedIsHeavyWeight = VALUE_INVALID; + @GuardedBy("mService") + private int mCachedHasVisibleActivities = VALUE_INVALID; + @GuardedBy("mService") + private int mCachedIsHomeProcess = VALUE_INVALID; + @GuardedBy("mService") + private int mCachedIsPreviousProcess = VALUE_INVALID; + @GuardedBy("mService") + private int mCachedHasRecentTasks = VALUE_INVALID; + @GuardedBy("mService") + private int mCachedIsReceivingBroadcast = VALUE_INVALID; + + @GuardedBy("mService") + private int mCachedAdj = ProcessList.INVALID_ADJ; + @GuardedBy("mService") + private boolean mCachedForegroundActivities = false; + @GuardedBy("mService") + private int mCachedProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY; + @GuardedBy("mService") + private int mCachedSchedGroup = ProcessList.SCHED_GROUP_BACKGROUND; + + ProcessStateRecord(ProcessRecord app) { + mApp = app; + mService = app.mService; + mProcLock = mService.mProcLock; + setAllowStartFgsByPermission(); + } + + void init(long now) { + mLastStateTime = now; + } + + @GuardedBy("mService") + void setMaxAdj(int maxAdj) { + mMaxAdj = maxAdj; + } + + @GuardedBy("mService") + int getMaxAdj() { + return mMaxAdj; + } + + @GuardedBy({"mService", "mProcLock"}) + void setCurRawAdj(int curRawAdj) { + mCurRawAdj = curRawAdj; + mApp.getWindowProcessController().setPerceptible( + curRawAdj <= ProcessList.PERCEPTIBLE_APP_ADJ); + } + + @GuardedBy(anyOf = {"mService", "mProcLock"}) + int getCurRawAdj() { + return mCurRawAdj; + } + + @GuardedBy({"mService", "mProcLock"}) + void setSetRawAdj(int setRawAdj) { + mSetRawAdj = setRawAdj; + } + + @GuardedBy(anyOf = {"mService", "mProcLock"}) + int getSetRawAdj() { + return mSetRawAdj; + } + + @GuardedBy({"mService", "mProcLock"}) + void setCurAdj(int curAdj) { + mCurAdj = curAdj; + } + + @GuardedBy(anyOf = {"mService", "mProcLock"}) + int getCurAdj() { + return mCurAdj; + } + + @GuardedBy({"mService", "mProcLock"}) + void setSetAdj(int setAdj) { + mSetAdj = setAdj; + } + + @GuardedBy(anyOf = {"mService", "mProcLock"}) + int getSetAdj() { + return mSetAdj; + } + + @GuardedBy(anyOf = {"mService", "mProcLock"}) + int getSetAdjWithServices() { + if (mSetAdj >= ProcessList.CACHED_APP_MIN_ADJ) { + if (mHasStartedServices) { + return ProcessList.SERVICE_B_ADJ; + } + } + return mSetAdj; + } + + @GuardedBy("mService") + void setVerifiedAdj(int verifiedAdj) { + mVerifiedAdj = verifiedAdj; + } + + @GuardedBy("mService") + int getVerifiedAdj() { + return mVerifiedAdj; + } + + @GuardedBy({"mService", "mProcLock"}) + void setCurCapability(int curCapability) { + mCurCapability = curCapability; + } + + @GuardedBy(anyOf = {"mService", "mProcLock"}) + int getCurCapability() { + return mCurCapability; + } + + @GuardedBy({"mService", "mProcLock"}) + void setSetCapability(int setCapability) { + mSetCapability = setCapability; + } + + @GuardedBy(anyOf = {"mService", "mProcLock"}) + int getSetCapability() { + return mSetCapability; + } + + @GuardedBy({"mService", "mProcLock"}) + void setCurrentSchedulingGroup(int curSchedGroup) { + mCurSchedGroup = curSchedGroup; + mApp.getWindowProcessController().setCurrentSchedulingGroup(curSchedGroup); + } + + @GuardedBy(anyOf = {"mService", "mProcLock"}) + int getCurrentSchedulingGroup() { + return mCurSchedGroup; + } + + @GuardedBy({"mService", "mProcLock"}) + void setSetSchedGroup(int setSchedGroup) { + mSetSchedGroup = setSchedGroup; + } + + @GuardedBy(anyOf = {"mService", "mProcLock"}) + int getSetSchedGroup() { + return mSetSchedGroup; + } + + @GuardedBy({"mService", "mProcLock"}) + void setCurProcState(int curProcState) { + mCurProcState = curProcState; + mApp.getWindowProcessController().setCurrentProcState(mCurProcState); + } + + @GuardedBy(anyOf = {"mService", "mProcLock"}) + int getCurProcState() { + return mCurProcState; + } + + @GuardedBy({"mService", "mProcLock"}) + void setCurRawProcState(int curRawProcState) { + mCurRawProcState = curRawProcState; + } + + @GuardedBy(anyOf = {"mService", "mProcLock"}) + int getCurRawProcState() { + return mCurRawProcState; + } + + @GuardedBy({"mService", "mProcLock"}) + void setReportedProcState(int repProcState) { + mRepProcState = repProcState; + mApp.getPkgList().forEachPackage((pkgName, holder) -> + FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_STATE_CHANGED, + mApp.uid, mApp.processName, pkgName, + ActivityManager.processStateAmToProto(mRepProcState), + holder.appVersion) + ); + mApp.getWindowProcessController().setReportedProcState(repProcState); + } + + @GuardedBy(anyOf = {"mService", "mProcLock"}) + int getReportedProcState() { + return mRepProcState; + } + + @GuardedBy("mService") + void forceProcessStateUpTo(int newState) { + if (mRepProcState > newState) { + synchronized (mProcLock) { + mRepProcState = newState; + setCurProcState(newState); + setCurRawProcState(newState); + mApp.getPkgList().forEachPackage((pkgName, holder) -> + FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_STATE_CHANGED, + mApp.uid, mApp.processName, pkgName, + ActivityManager.processStateAmToProto(mRepProcState), + holder.appVersion) + ); + } + } + } + + @GuardedBy({"mService", "mProcLock"}) + void setSetProcState(int setProcState) { + mSetProcState = setProcState; + } + + @GuardedBy(anyOf = {"mService", "mProcLock"}) + int getSetProcState() { + return mSetProcState; + } + + @GuardedBy({"mService", "mProcLock"}) + void setLastStateTime(long lastStateTime) { + mLastStateTime = lastStateTime; + } + + @GuardedBy(anyOf = {"mService", "mProcLock"}) + long getLastStateTime() { + return mLastStateTime; + } + + @GuardedBy({"mService", "mProcLock"}) + void setSavedPriority(int savedPriority) { + mSavedPriority = savedPriority; + } + + @GuardedBy(anyOf = {"mService", "mProcLock"}) + int getSavedPriority() { + return mSavedPriority; + } + + @GuardedBy({"mService", "mProcLock"}) + void setServiceB(boolean serviceb) { + mServiceB = serviceb; + } + + @GuardedBy(anyOf = {"mService", "mProcLock"}) + boolean isServiceB() { + return mServiceB; + } + + @GuardedBy({"mService", "mProcLock"}) + void setServiceHighRam(boolean serviceHighRam) { + mServiceHighRam = serviceHighRam; + } + + @GuardedBy(anyOf = {"mService", "mProcLock"}) + boolean isServiceHighRam() { + return mServiceHighRam; + } + + @GuardedBy("mProcLock") + void setNotCachedSinceIdle(boolean notCachedSinceIdle) { + mNotCachedSinceIdle = notCachedSinceIdle; + } + + @GuardedBy("mProcLock") + boolean isNotCachedSinceIdle() { + return mNotCachedSinceIdle; + } + + @GuardedBy("mProcLock") + void setHasStartedServices(boolean hasStartedServices) { + mHasStartedServices = hasStartedServices; + } + + @GuardedBy("mProcLock") + boolean hasStartedServices() { + return mHasStartedServices; + } + + @GuardedBy({"mService", "mProcLock"}) + void setHasForegroundActivities(boolean hasForegroundActivities) { + mHasForegroundActivities = hasForegroundActivities; + } + + @GuardedBy(anyOf = {"mService", "mProcLock"}) + boolean hasForegroundActivities() { + return mHasForegroundActivities; + } + + @GuardedBy({"mService", "mProcLock"}) + void setRepForegroundActivities(boolean repForegroundActivities) { + mRepForegroundActivities = repForegroundActivities; + } + + @GuardedBy(anyOf = {"mService", "mProcLock"}) + boolean hasRepForegroundActivities() { + return mRepForegroundActivities; + } + + @GuardedBy("mService") + void setHasShownUi(boolean hasShownUi) { + mHasShownUi = hasShownUi; + } + + @GuardedBy("mService") + boolean hasShownUi() { + return mHasShownUi; + } + + @GuardedBy("mService") + void setHasTopUi(boolean hasTopUi) { + mHasTopUi = hasTopUi; + mApp.getWindowProcessController().setHasTopUi(hasTopUi); + } + + @GuardedBy("mService") + boolean hasTopUi() { + return mHasTopUi; + } + + @GuardedBy("mService") + void setHasOverlayUi(boolean hasOverlayUi) { + mHasOverlayUi = hasOverlayUi; + mApp.getWindowProcessController().setHasOverlayUi(hasOverlayUi); + } + + @GuardedBy("mService") + boolean hasOverlayUi() { + return mHasOverlayUi; + } + + @GuardedBy("mService") + boolean isRunningRemoteAnimation() { + return mRunningRemoteAnimation; + } + + @GuardedBy("mService") + void setRunningRemoteAnimation(boolean runningRemoteAnimation) { + if (mRunningRemoteAnimation == runningRemoteAnimation) { + return; + } + mRunningRemoteAnimation = runningRemoteAnimation; + if (DEBUG_OOM_ADJ) { + Slog.i(TAG, "Setting runningRemoteAnimation=" + runningRemoteAnimation + + " for pid=" + mApp.getPid()); + } + mService.updateOomAdjLocked(mApp, true, OomAdjuster.OOM_ADJ_REASON_UI_VISIBILITY); + } + + @GuardedBy({"mService", "mProcLock"}) + void setProcStateChanged(boolean procStateChanged) { + mProcStateChanged = procStateChanged; + } + + @GuardedBy(anyOf = {"mService", "mProcLock"}) + boolean hasProcStateChanged() { + return mProcStateChanged; + } + + @GuardedBy({"mService", "mProcLock"}) + void setReportedInteraction(boolean reportedInteraction) { + mReportedInteraction = reportedInteraction; + } + + @GuardedBy(anyOf = {"mService", "mProcLock"}) + boolean hasReportedInteraction() { + return mReportedInteraction; + } + + @GuardedBy({"mService", "mProcLock"}) + void setInteractionEventTime(long interactionEventTime) { + mInteractionEventTime = interactionEventTime; + mApp.getWindowProcessController().setInteractionEventTime(interactionEventTime); + } + + @GuardedBy(anyOf = {"mService", "mProcLock"}) + long getInteractionEventTime() { + return mInteractionEventTime; + } + + @GuardedBy({"mService", "mProcLock"}) + void setFgInteractionTime(long fgInteractionTime) { + mFgInteractionTime = fgInteractionTime; + mApp.getWindowProcessController().setFgInteractionTime(fgInteractionTime); + } + + @GuardedBy(anyOf = {"mService", "mProcLock"}) + long getFgInteractionTime() { + return mFgInteractionTime; + } + + @GuardedBy("mService") + void setForcingToImportant(Object forcingToImportant) { + mForcingToImportant = forcingToImportant; + } + + @GuardedBy("mService") + Object getForcingToImportant() { + return mForcingToImportant; + } + + @GuardedBy("mService") + void setAdjSeq(int adjSeq) { + mAdjSeq = adjSeq; + } + + @GuardedBy("mService") + void decAdjSeq() { + mAdjSeq--; + } + + @GuardedBy("mService") + int getAdjSeq() { + return mAdjSeq; + } + + @GuardedBy("mService") + void setCompletedAdjSeq(int completedAdjSeq) { + mCompletedAdjSeq = completedAdjSeq; + } + + @GuardedBy("mService") + void decCompletedAdjSeq() { + mCompletedAdjSeq--; + } + + @GuardedBy("mService") + int getCompletedAdjSeq() { + return mCompletedAdjSeq; + } + + @GuardedBy("mService") + void setContainsCycle(boolean containsCycle) { + mContainsCycle = containsCycle; + } + + @GuardedBy("mService") + boolean containsCycle() { + return mContainsCycle; + } + + @GuardedBy({"mService", "mProcLock"}) + void setWhenUnimportant(long whenUnimportant) { + mWhenUnimportant = whenUnimportant; + mApp.getWindowProcessController().setWhenUnimportant(whenUnimportant); + } + + @GuardedBy(anyOf = {"mService", "mProcLock"}) + long getWhenUnimportant() { + return mWhenUnimportant; + } + + @GuardedBy("mService") + void setLastTopTime(long lastTopTime) { + mLastTopTime = lastTopTime; + } + + @GuardedBy("mService") + long getLastTopTime() { + return mLastTopTime; + } + + @GuardedBy("mService") + void setEmpty(boolean empty) { + mEmpty = empty; + } + + @GuardedBy("mService") + boolean isEmpty() { + return mEmpty; + } + + @GuardedBy("mService") + void setCached(boolean cached) { + if (mCached != cached) { + mCached = cached; + if (cached) { + ++mCacheOomRankerUseCount; + } + } + } + + @GuardedBy("mService") + boolean isCached() { + return mCached; + } + + @GuardedBy("mService") + int getCacheOomRankerUseCount() { + return mCacheOomRankerUseCount; + } + + @GuardedBy("mService") + void setSystemNoUi(boolean systemNoUi) { + mSystemNoUi = systemNoUi; + } + + @GuardedBy("mService") + boolean isSystemNoUi() { + return mSystemNoUi; + } + + @GuardedBy("mService") + void setAdjType(String adjType) { + mAdjType = adjType; + } + + @GuardedBy("mService") + String getAdjType() { + return mAdjType; + } + + @GuardedBy({"mService", "mProcLock"}) + void setAdjTypeCode(int adjTypeCode) { + mAdjTypeCode = adjTypeCode; + } + + @GuardedBy(anyOf = {"mService", "mProcLock"}) + int getAdjTypeCode() { + return mAdjTypeCode; + } + + @GuardedBy({"mService", "mProcLock"}) + void setAdjSource(Object adjSource) { + mAdjSource = adjSource; + } + + @GuardedBy(anyOf = {"mService", "mProcLock"}) + Object getAdjSource() { + return mAdjSource; + } + + @GuardedBy({"mService", "mProcLock"}) + void setAdjSourceProcState(int adjSourceProcState) { + mAdjSourceProcState = adjSourceProcState; + } + + @GuardedBy(anyOf = {"mService", "mProcLock"}) + int getAdjSourceProcState() { + return mAdjSourceProcState; + } + + @GuardedBy({"mService", "mProcLock"}) + void setAdjTarget(Object adjTarget) { + mAdjTarget = adjTarget; + } + + @GuardedBy(anyOf = {"mService", "mProcLock"}) + Object getAdjTarget() { + return mAdjTarget; + } + + @GuardedBy("mService") + boolean isReachable() { + return mReachable; + } + + @GuardedBy("mService") + void setReachable(boolean reachable) { + mReachable = reachable; + } + + @GuardedBy("mService") + void resetCachedInfo() { + mCachedHasActivities = VALUE_INVALID; + mCachedIsHeavyWeight = VALUE_INVALID; + mCachedHasVisibleActivities = VALUE_INVALID; + mCachedIsHomeProcess = VALUE_INVALID; + mCachedIsPreviousProcess = VALUE_INVALID; + mCachedHasRecentTasks = VALUE_INVALID; + mCachedIsReceivingBroadcast = VALUE_INVALID; + mCachedAdj = ProcessList.INVALID_ADJ; + mCachedForegroundActivities = false; + mCachedProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY; + mCachedSchedGroup = ProcessList.SCHED_GROUP_BACKGROUND; + } + + @GuardedBy("mService") + boolean getCachedHasActivities() { + if (mCachedHasActivities == VALUE_INVALID) { + mCachedHasActivities = mApp.getWindowProcessController().hasActivities() ? VALUE_TRUE + : VALUE_FALSE; + } + return mCachedHasActivities == VALUE_TRUE; + } + + @GuardedBy("mService") + boolean getCachedIsHeavyWeight() { + if (mCachedIsHeavyWeight == VALUE_INVALID) { + mCachedIsHeavyWeight = mApp.getWindowProcessController().isHeavyWeightProcess() + ? VALUE_TRUE : VALUE_FALSE; + } + return mCachedIsHeavyWeight == VALUE_TRUE; + } + + @GuardedBy("mService") + boolean getCachedHasVisibleActivities() { + if (mCachedHasVisibleActivities == VALUE_INVALID) { + mCachedHasVisibleActivities = mApp.getWindowProcessController().hasVisibleActivities() + ? VALUE_TRUE : VALUE_FALSE; + } + return mCachedHasVisibleActivities == VALUE_TRUE; + } + + @GuardedBy("mService") + boolean getCachedIsHomeProcess() { + if (mCachedIsHomeProcess == VALUE_INVALID) { + if (mApp.getWindowProcessController().isHomeProcess()) { + mCachedIsHomeProcess = VALUE_TRUE; + mService.mAppProfiler.mHasHomeProcess = true; + } else { + mCachedIsHomeProcess = VALUE_FALSE; + } + } + return mCachedIsHomeProcess == VALUE_TRUE; + } + + @GuardedBy("mService") + boolean getCachedIsPreviousProcess() { + if (mCachedIsPreviousProcess == VALUE_INVALID) { + if (mApp.getWindowProcessController().isPreviousProcess()) { + mCachedIsPreviousProcess = VALUE_TRUE; + mService.mAppProfiler.mHasPreviousProcess = true; + } else { + mCachedIsPreviousProcess = VALUE_FALSE; + } + } + return mCachedIsPreviousProcess == VALUE_TRUE; + } + + @GuardedBy("mService") + boolean getCachedHasRecentTasks() { + if (mCachedHasRecentTasks == VALUE_INVALID) { + mCachedHasRecentTasks = mApp.getWindowProcessController().hasRecentTasks() + ? VALUE_TRUE : VALUE_FALSE; + } + return mCachedHasRecentTasks == VALUE_TRUE; + } + + @GuardedBy("mService") + boolean getCachedIsReceivingBroadcast(ArraySet tmpQueue) { + if (mCachedIsReceivingBroadcast == VALUE_INVALID) { + tmpQueue.clear(); + mCachedIsReceivingBroadcast = mService.isReceivingBroadcastLocked(mApp, tmpQueue) + ? VALUE_TRUE : VALUE_FALSE; + if (mCachedIsReceivingBroadcast == VALUE_TRUE) { + mCachedSchedGroup = tmpQueue.contains(mService.mFgBroadcastQueue) + ? ProcessList.SCHED_GROUP_DEFAULT : ProcessList.SCHED_GROUP_BACKGROUND; + } + } + return mCachedIsReceivingBroadcast == VALUE_TRUE; + } + + @GuardedBy("mService") + void computeOomAdjFromActivitiesIfNecessary(OomAdjuster.ComputeOomAdjWindowCallback callback, + int adj, boolean foregroundActivities, int procState, int schedGroup, int appUid, + int logUid, int processCurTop) { + if (mCachedAdj != ProcessList.INVALID_ADJ) { + return; + } + callback.initialize(mApp, adj, foregroundActivities, procState, schedGroup, appUid, logUid, + processCurTop); + final int minLayer = Math.min(ProcessList.VISIBLE_APP_LAYER_MAX, + mApp.getWindowProcessController().computeOomAdjFromActivities(callback)); + + mCachedAdj = callback.adj; + mCachedForegroundActivities = callback.foregroundActivities; + mCachedProcState = callback.procState; + mCachedSchedGroup = callback.schedGroup; + + if (mCachedAdj == ProcessList.VISIBLE_APP_ADJ) { + mCachedAdj += minLayer; + } + } + + @GuardedBy("mService") + int getCachedAdj() { + return mCachedAdj; + } + + @GuardedBy("mService") + boolean getCachedForegroundActivities() { + return mCachedForegroundActivities; + } + + @GuardedBy("mService") + int getCachedProcState() { + return mCachedProcState; + } + + @GuardedBy("mService") + int getCachedSchedGroup() { + return mCachedSchedGroup; + } + + @GuardedBy(anyOf = {"mService", "mProcLock"}) + public String makeAdjReason() { + if (mAdjSource != null || mAdjTarget != null) { + StringBuilder sb = new StringBuilder(128); + sb.append(' '); + if (mAdjTarget instanceof ComponentName) { + sb.append(((ComponentName) mAdjTarget).flattenToShortString()); + } else if (mAdjTarget != null) { + sb.append(mAdjTarget.toString()); + } else { + sb.append("{null}"); + } + sb.append("<="); + if (mAdjSource instanceof ProcessRecord) { + sb.append("Proc{"); + sb.append(((ProcessRecord) mAdjSource).toShortString()); + sb.append("}"); + } else if (mAdjSource != null) { + sb.append(mAdjSource.toString()); + } else { + sb.append("{null}"); + } + return sb.toString(); + } + return null; + } + + @GuardedBy({"mService", "mProcLock"}) + void onCleanupApplicationRecordLSP() { + setHasForegroundActivities(false); + mHasShownUi = false; + mForcingToImportant = null; + mCurRawAdj = mSetRawAdj = mCurAdj = mSetAdj = mVerifiedAdj = ProcessList.INVALID_ADJ; + mCurCapability = mSetCapability = PROCESS_CAPABILITY_NONE; + mCurSchedGroup = mSetSchedGroup = ProcessList.SCHED_GROUP_BACKGROUND; + mCurProcState = mRepProcState = mCurRawProcState = mSetProcState = mAllowStartFgsState = + PROCESS_STATE_NONEXISTENT; + } + + @GuardedBy("mService") + void addAllowBackgroundFgsStartsToken(Binder entity) { + mBackgroundFgsStartTokens.add(entity); + } + + @GuardedBy("mService") + void removeAllowBackgroundFgsStartsToken(Binder entity) { + mBackgroundFgsStartTokens.remove(entity); + } + + @GuardedBy("mService") + boolean areBackgroundFgsStartsAllowedByToken() { + return !mBackgroundFgsStartTokens.isEmpty(); + } + + @GuardedBy("mService") + void resetAllowStartFgs() { + mAllowStartFgsState = PROCESS_STATE_NONEXISTENT; + mAllowStartFgs = mAllowStartFgsByPermission; + } + + @GuardedBy("mService") + void bumpAllowStartFgsState(int newProcState) { + if (newProcState < mAllowStartFgsState) { + mAllowStartFgsState = newProcState; + } + } + + @GuardedBy("mService") + void setAllowStartFgsState(int allowStartFgsState) { + mAllowStartFgsState = allowStartFgsState; + } + + @GuardedBy("mService") + boolean isAllowedStartFgsState() { + return mAllowStartFgsState <= PROCESS_STATE_BOUND_FOREGROUND_SERVICE; + } + + @GuardedBy("mService") + void setAllowStartFgsByPermission() { + int ret = FGS_FEATURE_DENIED; + if (ret == FGS_FEATURE_DENIED) { + boolean isSystem = false; + final int uid = UserHandle.getAppId(mApp.info.uid); + switch (uid) { + case ROOT_UID: + case SYSTEM_UID: + case NFC_UID: + case SHELL_UID: + isSystem = true; + break; + default: + isSystem = false; + break; + } + + if (isSystem) { + ret = FGS_FEATURE_ALLOWED_BY_SYSTEM_UID; + } + } + + if (ret == FGS_FEATURE_DENIED) { + if (ActivityManager.checkComponentPermission(START_ACTIVITIES_FROM_BACKGROUND, + mApp.info.uid, -1, true) == PERMISSION_GRANTED) { + ret = FGS_FEATURE_ALLOWED_BY_BACKGROUND_ACTIVITY_PERMISSION; + } else if (ActivityManager.checkComponentPermission( + START_FOREGROUND_SERVICES_FROM_BACKGROUND, + mApp.info.uid, -1, true) == PERMISSION_GRANTED) { + ret = FGS_FEATURE_ALLOWED_BY_BACKGROUND_FGS_PERMISSION; + } else if (ActivityManager.checkComponentPermission(SYSTEM_ALERT_WINDOW, + mApp.info.uid, -1, true) == PERMISSION_GRANTED) { + ret = FGS_FEATURE_ALLOWED_BY_SYSTEM_ALERT_WINDOW_PERMISSION; + } + } + mAllowStartFgs = mAllowStartFgsByPermission = ret; + } + + @GuardedBy("mService") + void setAllowStartFgs() { + if (mAllowStartFgs != FGS_FEATURE_DENIED) { + return; + } + if (mAllowStartFgs == FGS_FEATURE_DENIED) { + if (isAllowedStartFgsState()) { + mAllowStartFgs = FGS_FEATURE_ALLOWED_BY_PROC_STATE; + } + } + + if (mAllowStartFgs == FGS_FEATURE_DENIED) { + // Is the calling UID a device owner app? + if (mService.mInternal != null) { + if (mService.mInternal.isDeviceOwner(mApp.info.uid)) { + mAllowStartFgs = FGS_FEATURE_ALLOWED_BY_DEVICE_OWNER; + } + } + } + + if (mAllowStartFgs == FGS_FEATURE_DENIED) { + if (mService.mInternal != null) { + final boolean isCompanionApp = mService.mInternal.isAssociatedCompanionApp( + UserHandle.getUserId(mApp.info.uid), mApp.info.uid); + if (isCompanionApp) { + mAllowStartFgs = FGS_FEATURE_ALLOWED_BY_COMPANION_APP; + } + } + } + + if (mAllowStartFgs == FGS_FEATURE_DENIED) { + // Is the calling UID a profile owner app? + if (mService.mInternal != null) { + if (mService.mInternal.isProfileOwner(mApp.info.uid)) { + mAllowStartFgs = FGS_FEATURE_ALLOWED_BY_PROFILE_OWNER; + } + } + } + + if (mAllowStartFgs == FGS_FEATURE_DENIED) { + // uid is on DeviceIdleController's user/system allowlist + // or AMS's FgsStartTempAllowList. + if (mService.isAllowlistedForFgsStartLOSP(mApp.info.uid)) { + mAllowStartFgs = FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST; + } + } + } + + @GuardedBy("mService") + void setAllowStartFgs(@ActiveServices.FgsFeatureRetCode int allowStartFgs) { + mAllowStartFgs = allowStartFgs; + } + + @GuardedBy("mService") + @ActiveServices.FgsFeatureRetCode int getAllowedStartFgs() { + return mAllowStartFgs; + } + + @GuardedBy({"mService", "mProcLock"}) + void dump(PrintWriter pw, String prefix, long nowUptime) { + if (mReportedInteraction || mFgInteractionTime != 0) { + pw.print(prefix); pw.print("reportedInteraction="); + pw.print(mReportedInteraction); + if (mInteractionEventTime != 0) { + pw.print(" time="); + TimeUtils.formatDuration(mInteractionEventTime, SystemClock.elapsedRealtime(), pw); + } + if (mFgInteractionTime != 0) { + pw.print(" fgInteractionTime="); + TimeUtils.formatDuration(mFgInteractionTime, SystemClock.elapsedRealtime(), pw); + } + pw.println(); + } + pw.print(prefix); pw.print("adjSeq="); pw.print(mAdjSeq); + pw.print(" lruSeq="); pw.println(mApp.getLruSeq()); + pw.print(prefix); pw.print("oom adj: max="); pw.print(mMaxAdj); + pw.print(" curRaw="); pw.print(mCurRawAdj); + pw.print(" setRaw="); pw.print(mSetRawAdj); + pw.print(" cur="); pw.print(mCurAdj); + pw.print(" set="); pw.println(mSetAdj); + pw.print(prefix); pw.print("mCurSchedGroup="); pw.print(mCurSchedGroup); + pw.print(" setSchedGroup="); pw.print(mSetSchedGroup); + pw.print(" systemNoUi="); pw.print(mSystemNoUi); + pw.print(prefix); pw.print("curProcState="); pw.print(getCurProcState()); + pw.print(" mRepProcState="); pw.print(mRepProcState); + pw.print(" setProcState="); pw.print(mSetProcState); + pw.print(" lastStateTime="); + TimeUtils.formatDuration(getLastStateTime(), nowUptime, pw); + pw.println(); + pw.print(prefix); pw.print("curCapability="); + ActivityManager.printCapabilitiesFull(pw, mCurCapability); + pw.print(" setCapability="); + ActivityManager.printCapabilitiesFull(pw, mSetCapability); + pw.println(); + pw.print(prefix); pw.print("allowStartFgsState="); + pw.println(mAllowStartFgsState); + if (mAllowStartFgs != FGS_FEATURE_DENIED) { + pw.print(prefix); pw.print("allowStartFgs="); + pw.println(fgsCodeToString(mAllowStartFgs)); + } + if (mHasShownUi || mApp.mProfile.hasPendingUiClean()) { + pw.print(prefix); pw.print("hasShownUi="); pw.print(mHasShownUi); + pw.print(" pendingUiClean="); pw.print(mApp.mProfile.hasPendingUiClean()); + } + pw.print(prefix); pw.print("cached="); pw.print(mCached); + pw.print(" empty="); pw.println(mEmpty); + if (mServiceB) { + pw.print(prefix); pw.print("serviceb="); pw.print(mServiceB); + pw.print(" serviceHighRam="); pw.println(mServiceHighRam); + } + if (mNotCachedSinceIdle) { + pw.print(prefix); pw.print("notCachedSinceIdle="); pw.print(mNotCachedSinceIdle); + pw.print(" initialIdlePss="); pw.println(mApp.mProfile.getInitialIdlePss()); + } + if (hasTopUi() || hasOverlayUi() || mRunningRemoteAnimation) { + pw.print(prefix); pw.print("hasTopUi="); pw.print(hasTopUi()); + pw.print(" hasOverlayUi="); pw.print(hasOverlayUi()); + pw.print(" runningRemoteAnimation="); pw.println(mRunningRemoteAnimation); + } + if (mHasForegroundActivities || mRepForegroundActivities) { + pw.print(prefix); + pw.print(" foregroundActivities="); pw.print(mHasForegroundActivities); + pw.print(" (rep="); pw.print(mRepForegroundActivities); pw.println(")"); + } + if (mSetProcState > ActivityManager.PROCESS_STATE_SERVICE) { + pw.print(prefix); + pw.print(" whenUnimportant="); + TimeUtils.formatDuration(mWhenUnimportant - nowUptime, pw); + pw.println(); + } + if (mLastTopTime > 0) { + pw.print(prefix); pw.print("lastTopTime="); + TimeUtils.formatDuration(mLastTopTime, nowUptime, pw); + pw.println(); + } + if (mHasStartedServices) { + pw.print(prefix); pw.print("hasStartedServices="); pw.println(mHasStartedServices); + } + } +} diff --git a/services/core/java/com/android/server/am/ProcessStatsService.java b/services/core/java/com/android/server/am/ProcessStatsService.java index c10a07862123b..34a0c1beec09b 100644 --- a/services/core/java/com/android/server/am/ProcessStatsService.java +++ b/services/core/java/com/android/server/am/ProcessStatsService.java @@ -313,8 +313,8 @@ public final class ProcessStatsService extends IProcessStats.Stub { private void scheduleRequestPssAllProcs(boolean always, boolean memLowered) { mAm.mHandler.post(() -> { - synchronized (mAm) { - mAm.mAppProfiler.requestPssAllProcsLocked( + synchronized (mAm.mProcLock) { + mAm.mAppProfiler.requestPssAllProcsLPr( SystemClock.uptimeMillis(), always, memLowered); } }); diff --git a/services/core/java/com/android/server/am/ProviderMap.java b/services/core/java/com/android/server/am/ProviderMap.java index 29c165733808a..072eba5d1205c 100644 --- a/services/core/java/com/android/server/am/ProviderMap.java +++ b/services/core/java/com/android/server/am/ProviderMap.java @@ -16,6 +16,7 @@ package com.android.server.am; +import android.app.IApplicationThread; import android.content.ComponentName; import android.content.ComponentName.WithComponentName; import android.os.Binder; @@ -23,6 +24,7 @@ import android.os.RemoteException; import android.os.UserHandle; import android.util.Slog; import android.util.SparseArray; + import com.android.internal.os.TransferPipe; import com.android.internal.util.CollectionUtils; import com.android.internal.util.DumpUtils; @@ -372,10 +374,11 @@ public final class ProviderMap { */ private void dumpProvider(String prefix, FileDescriptor fd, PrintWriter pw, final ContentProviderRecord r, String[] args, boolean dumpAll) { + final IApplicationThread thread = r.proc != null ? r.proc.getThread() : null; for (String s: args) { if (!dumpAll && s.contains("--proto")) { - if (r.proc != null && r.proc.thread != null) { - dumpToTransferPipe(null , fd, pw, r, args); + if (thread != null) { + dumpToTransferPipe(null , fd, pw, r, thread, args); } return; } @@ -386,7 +389,7 @@ public final class ProviderMap { pw.print(r); pw.print(" pid="); if (r.proc != null) { - pw.println(r.proc.pid); + pw.println(r.proc.getPid()); } else { pw.println("(not running)"); } @@ -394,10 +397,10 @@ public final class ProviderMap { r.dump(pw, innerPrefix, true); } } - if (r.proc != null && r.proc.thread != null) { + if (thread != null) { pw.println(" Client:"); pw.flush(); - dumpToTransferPipe(" ", fd, pw, r, args); + dumpToTransferPipe(" ", fd, pw, r, thread, args); } } @@ -420,8 +423,9 @@ public final class ProviderMap { // Only dump the first provider, since we are dumping in proto format for (int i = 0; i < providers.size(); i++) { final ContentProviderRecord r = providers.get(i); - if (r.proc != null && r.proc.thread != null) { - dumpToTransferPipe(null, fd, pw, r, newArgs); + IApplicationThread thread; + if (r.proc != null && (thread = r.proc.getThread()) != null) { + dumpToTransferPipe(null, fd, pw, r, thread, newArgs); return true; } } @@ -433,11 +437,11 @@ public final class ProviderMap { * any meta string (e.g., provider info, indentation) written to the file descriptor. */ private void dumpToTransferPipe(String prefix, FileDescriptor fd, PrintWriter pw, - final ContentProviderRecord r, String[] args) { + final ContentProviderRecord r, final IApplicationThread thread, String[] args) { try { TransferPipe tp = new TransferPipe(); try { - r.proc.thread.dumpProvider( + thread.dumpProvider( tp.getWriteFd(), r.provider.asBinder(), args); tp.setBufferPrefix(prefix); // Short timeout, since blocking here can diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java index 8a1b4e3e832ed..485087d294223 100644 --- a/services/core/java/com/android/server/am/ServiceRecord.java +++ b/services/core/java/com/android/server/am/ServiceRecord.java @@ -23,6 +23,7 @@ import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; import android.annotation.Nullable; +import android.app.IApplicationThread; import android.app.Notification; import android.app.PendingIntent; import android.content.ComponentName; @@ -281,7 +282,7 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN proto.write(ServiceRecordProto.SHORT_NAME, this.shortInstanceName); proto.write(ServiceRecordProto.IS_RUNNING, app != null); if (app != null) { - proto.write(ServiceRecordProto.PID, app.pid); + proto.write(ServiceRecordProto.PID, app.getPid()); } if (intent != null) { intent.getIntent().dumpDebug(proto, ServiceRecordProto.INTENT, false, true, false, @@ -582,13 +583,14 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN restartTracker.setRestarting(true, memFactor, now); } - public void setProcess(ProcessRecord _proc) { - if (_proc != null) { + public void setProcess(ProcessRecord proc, IApplicationThread thread, int pid, + UidRecord uidRecord) { + if (proc != null) { // We're starting a new process for this service, but a previous one is allowed to start // background activities. Remove that ability now (unless the new process is the same as // the previous one, which is a common case). if (mAppForAllowingBgActivityStartsByStart != null) { - if (mAppForAllowingBgActivityStartsByStart != _proc) { + if (mAppForAllowingBgActivityStartsByStart != proc) { mAppForAllowingBgActivityStartsByStart .removeAllowBackgroundActivityStartsToken(this); ams.mHandler.removeCallbacks(mCleanUpAllowBgActivityStartsByStartCallback); @@ -596,34 +598,35 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN } // Make sure the cleanup callback knows about the new process. mAppForAllowingBgActivityStartsByStart = mIsAllowedBgActivityStartsByStart - ? _proc : null; + ? proc : null; if (mIsAllowedBgActivityStartsByStart || mIsAllowedBgActivityStartsByBinding) { - _proc.addOrUpdateAllowBackgroundActivityStartsToken(this, + proc.addOrUpdateAllowBackgroundActivityStartsToken(this, getExclusiveOriginatingToken()); } else { - _proc.removeAllowBackgroundActivityStartsToken(this); + proc.removeAllowBackgroundActivityStartsToken(this); } if (mIsAllowedBgFgsStartsByBinding) { - _proc.addAllowBackgroundFgsStartsToken(this); + proc.mState.addAllowBackgroundFgsStartsToken(this); } else { - _proc.removeAllowBackgroundFgsStartsToken(this); + proc.mState.removeAllowBackgroundFgsStartsToken(this); } } - if (app != null && app != _proc) { + if (app != null && app != proc) { // If the old app is allowed to start bg activities because of a service start, leave it // that way until the cleanup callback runs. Otherwise we can remove its bg activity // start ability immediately (it can't be bound now). if (!mIsAllowedBgActivityStartsByStart) { app.removeAllowBackgroundActivityStartsToken(this); } - app.updateBoundClientUids(); + app.mServices.updateBoundClientUids(); } - app = _proc; - if (pendingConnectionGroup > 0 && _proc != null) { - _proc.connectionService = this; - _proc.connectionGroup = pendingConnectionGroup; - _proc.connectionImportance = pendingConnectionImportance; + app = proc; + if (pendingConnectionGroup > 0 && proc != null) { + final ProcessServiceRecord psr = proc.mServices; + psr.setConnectionService(this); + psr.setConnectionGroup(pendingConnectionGroup); + psr.setConnectionImportance(pendingConnectionImportance); pendingConnectionGroup = pendingConnectionImportance = 0; } if (ActivityManagerService.TRACK_PROCSTATS_ASSOCIATIONS) { @@ -631,7 +634,7 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN ArrayList cr = connections.valueAt(conni); for (int i = 0; i < cr.size(); i++) { final ConnectionRecord conn = cr.get(i); - if (_proc != null) { + if (proc != null) { conn.startAssociationIfNeeded(); } else { conn.stopAssociation(); @@ -639,8 +642,8 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN } } } - if (_proc != null) { - _proc.updateBoundClientUids(); + if (proc != null) { + proc.mServices.updateBoundClientUids(); } } @@ -658,7 +661,7 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN // if we have a process attached, add bound client uid of this connection to it if (app != null) { - app.addBoundClientUid(c.clientUid); + app.mServices.addBoundClientUid(c.clientUid); } } @@ -666,7 +669,7 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN connections.remove(binder); // if we have a process attached, tell it to update the state of bound clients if (app != null) { - app.updateBoundClientUids(); + app.mServices.updateBoundClientUids(); } } @@ -820,9 +823,9 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN return; } if (mIsAllowedBgFgsStartsByBinding) { - app.addAllowBackgroundFgsStartsToken(this); + app.mState.addAllowBackgroundFgsStartsToken(this); } else { - app.removeAllowBackgroundFgsStartsToken(this); + app.mState.removeAllowBackgroundFgsStartsToken(this); } } @@ -937,7 +940,7 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN public void postNotification() { final int appUid = appInfo.uid; - final int appPid = app.pid; + final int appPid = app.getPid(); if (foregroundId != 0 && foregroundNoti != null) { // Do asynchronous communication with notification manager to // avoid deadlocks. @@ -1057,7 +1060,7 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN final String localPackageName = packageName; final int localForegroundId = foregroundId; final int appUid = appInfo.uid; - final int appPid = app != null ? app.pid : 0; + final int appPid = app != null ? app.getPid() : 0; ams.mHandler.post(new Runnable() { public void run() { NotificationManagerInternal nm = LocalServices.getService( diff --git a/services/core/java/com/android/server/am/StrictModeViolationDialog.java b/services/core/java/com/android/server/am/StrictModeViolationDialog.java index 22e7faa4bad90..4cc1fc1b7d093 100644 --- a/services/core/java/com/android/server/am/StrictModeViolationDialog.java +++ b/services/core/java/com/android/server/am/StrictModeViolationDialog.java @@ -49,7 +49,7 @@ final class StrictModeViolationDialog extends BaseErrorDialog { mProc = app; mResult = result; CharSequence name; - if ((app.getPkgList().size() == 1) + if (app.getPkgList().size() == 1 && (name = context.getPackageManager().getApplicationLabel(app.info)) != null) { setMessage(res.getString( com.android.internal.R.string.smv_application, @@ -67,7 +67,7 @@ final class StrictModeViolationDialog extends BaseErrorDialog { res.getText(com.android.internal.R.string.dlg_ok), mHandler.obtainMessage(ACTION_OK)); - if (app.errorReportReceiver != null) { + if (app.mErrorState.getErrorReportReceiver() != null) { setButton(DialogInterface.BUTTON_NEGATIVE, res.getText(com.android.internal.R.string.report), mHandler.obtainMessage(ACTION_OK_AND_REPORT)); @@ -84,9 +84,9 @@ final class StrictModeViolationDialog extends BaseErrorDialog { private final Handler mHandler = new Handler() { public void handleMessage(Message msg) { - synchronized (mService) { + synchronized (mService.mProcLock) { if (mProc != null) { - mProc.getDialogController().clearViolationDialogs(); + mProc.mErrorState.getDialogController().clearViolationDialogs(); } } mResult.set(msg.what); diff --git a/services/core/java/com/android/server/am/UidObserverController.java b/services/core/java/com/android/server/am/UidObserverController.java index b3150d1489bb7..df65ee6e3a280 100644 --- a/services/core/java/com/android/server/am/UidObserverController.java +++ b/services/core/java/com/android/server/am/UidObserverController.java @@ -204,16 +204,18 @@ public class UidObserverController { } else { UidRecord validateUid = mValidateUids.get(item.uid); if (validateUid == null) { - validateUid = new UidRecord(item.uid); + validateUid = new UidRecord(item.uid, null); mValidateUids.put(item.uid, validateUid); } if ((item.change & UidRecord.CHANGE_IDLE) != 0) { - validateUid.idle = true; + validateUid.setIdle(true); } else if ((item.change & UidRecord.CHANGE_ACTIVE) != 0) { - validateUid.idle = false; + validateUid.setIdle(false); } - validateUid.setCurProcState(validateUid.setProcState = item.procState); - validateUid.curCapability = validateUid.setCapability = item.capability; + validateUid.setSetProcState(item.procState); + validateUid.setCurProcState(item.procState); + validateUid.setSetCapability(item.capability); + validateUid.setCurCapability(item.capability); validateUid.lastDispatchedProcStateSeq = item.procStateSeq; } } diff --git a/services/core/java/com/android/server/am/UidRecord.java b/services/core/java/com/android/server/am/UidRecord.java index 36d22bf0f5da7..2fb662f5ee69b 100644 --- a/services/core/java/com/android/server/am/UidRecord.java +++ b/services/core/java/com/android/server/am/UidRecord.java @@ -26,27 +26,58 @@ import android.util.TimeUtils; import android.util.proto.ProtoOutputStream; import android.util.proto.ProtoUtils; +import com.android.internal.annotations.CompositeRWLock; import com.android.internal.annotations.GuardedBy; import com.android.server.am.UidObserverController.ChangeRecord; +import java.util.function.Consumer; + /** * Overall information about a uid that has actively running processes. */ public final class UidRecord { - final int uid; - int mCurProcState; - int setProcState = ActivityManager.PROCESS_STATE_NONEXISTENT; - int curCapability; - int setCapability; - long lastBackgroundTime; - boolean ephemeral; - boolean foregroundServices; - boolean mCurAllowlist; - boolean mSetAllowlist; - boolean idle; - boolean setIdle; - int numProcs; - ArraySet procRecords = new ArraySet<>(); + private final ActivityManagerService mService; + private final ActivityManagerGlobalLock mProcLock; + private final int mUid; + + @CompositeRWLock({"mService", "mProcLock"}) + private int mCurProcState; + + @CompositeRWLock({"mService", "mProcLock"}) + private int mSetProcState = ActivityManager.PROCESS_STATE_NONEXISTENT; + + @CompositeRWLock({"mService", "mProcLock"}) + private int mCurCapability; + + @CompositeRWLock({"mService", "mProcLock"}) + private int mSetCapability; + + @CompositeRWLock({"mService", "mProcLock"}) + private long mLastBackgroundTime; + + @CompositeRWLock({"mService", "mProcLock"}) + private boolean mEphemeral; + + @CompositeRWLock({"mService", "mProcLock"}) + private boolean mForegroundServices; + + @CompositeRWLock({"mService", "mProcLock"}) + private boolean mCurAllowList;; + + @CompositeRWLock({"mService", "mProcLock"}) + private boolean mSetAllowList; + + @CompositeRWLock({"mService", "mProcLock"}) + private boolean mIdle; + + @CompositeRWLock({"mService", "mProcLock"}) + private boolean mSetIdle; + + @CompositeRWLock({"mService", "mProcLock"}) + private int mNumProcs; + + @CompositeRWLock({"mService", "mProcLock"}) + private ArraySet mProcRecords = new ArraySet<>(); /** * Sequence number associated with the {@link #mCurProcState}. This is incremented using @@ -111,32 +142,168 @@ public final class UidRecord { // UidObserverController is the only thing that should modify this. final ChangeRecord pendingChange = new ChangeRecord(); - int lastReportedChange; + @GuardedBy("mService") + private int mLastReportedChange; - public UidRecord(int _uid) { - uid = _uid; - idle = true; + public UidRecord(int uid, ActivityManagerService service) { + mUid = uid; + mService = service; + mProcLock = service != null ? service.mProcLock : null; + mIdle = true; reset(); } - public int getCurProcState() { + int getUid() { + return mUid; + } + + @GuardedBy(anyOf = {"mService", "mProcLock"}) + int getCurProcState() { return mCurProcState; } - public void setCurProcState(int curProcState) { + @GuardedBy({"mService", "mProcLock"}) + void setCurProcState(int curProcState) { mCurProcState = curProcState; } - public void reset() { - setCurProcState(ActivityManager.PROCESS_STATE_CACHED_EMPTY); - foregroundServices = false; - curCapability = 0; + @GuardedBy(anyOf = {"mService", "mProcLock"}) + int getSetProcState() { + return mSetProcState; + } + @GuardedBy({"mService", "mProcLock"}) + void setSetProcState(int setProcState) { + mSetProcState = setProcState; + } + + @GuardedBy(anyOf = {"mService", "mProcLock"}) + int getCurCapability() { + return mCurCapability; + } + + @GuardedBy({"mService", "mProcLock"}) + void setCurCapability(int curCapability) { + mCurCapability = curCapability; + } + + @GuardedBy(anyOf = {"mService", "mProcLock"}) + int getSetCapability() { + return mSetCapability; + } + + @GuardedBy({"mService", "mProcLock"}) + void setSetCapability(int setCapability) { + mSetCapability = setCapability; + } + + @GuardedBy(anyOf = {"mService", "mProcLock"}) + long getLastBackgroundTime() { + return mLastBackgroundTime; + } + + @GuardedBy({"mService", "mProcLock"}) + void setLastBackgroundTime(long lastBackgroundTime) { + mLastBackgroundTime = lastBackgroundTime; + } + + @GuardedBy(anyOf = {"mService", "mProcLock"}) + boolean isEphemeral() { + return mEphemeral; + } + + @GuardedBy({"mService", "mProcLock"}) + void setEphemeral(boolean ephemeral) { + mEphemeral = ephemeral; + } + + @GuardedBy(anyOf = {"mService", "mProcLock"}) + boolean hasForegroundServices() { + return mForegroundServices; + } + + @GuardedBy({"mService", "mProcLock"}) + void setForegroundServices(boolean foregroundServices) { + mForegroundServices = foregroundServices; + } + + @GuardedBy(anyOf = {"mService", "mProcLock"}) + boolean isCurAllowListed() { + return mCurAllowList; + } + + @GuardedBy({"mService", "mProcLock"}) + void setCurAllowListed(boolean curAllowList) { + mCurAllowList = curAllowList; + } + + @GuardedBy(anyOf = {"mService", "mProcLock"}) + boolean isSetAllowListed() { + return mSetAllowList; + } + + @GuardedBy({"mService", "mProcLock"}) + void setSetAllowListed(boolean setAllowlist) { + mSetAllowList = setAllowlist; + } + + @GuardedBy(anyOf = {"mService", "mProcLock"}) + boolean isIdle() { + return mIdle; + } + + @GuardedBy({"mService", "mProcLock"}) + void setIdle(boolean idle) { + mIdle = idle; + } + + @GuardedBy(anyOf = {"mService", "mProcLock"}) + boolean isSetIdle() { + return mSetIdle; + } + + @GuardedBy({"mService", "mProcLock"}) + void setSetIdle(boolean setIdle) { + mSetIdle = setIdle; + } + + @GuardedBy(anyOf = {"mService", "mProcLock"}) + int getNumOfProcs() { + return mProcRecords.size(); + } + + @GuardedBy(anyOf = {"mService", "mProcLock"}) + void forEachProcess(Consumer callback) { + for (int i = mProcRecords.size() - 1; i >= 0; i--) { + callback.accept(mProcRecords.valueAt(i)); + } + } + + @GuardedBy({"mService", "mProcLock"}) + void addProcess(ProcessRecord app) { + mProcRecords.add(app); + } + + @GuardedBy({"mService", "mProcLock"}) + void removeProcess(ProcessRecord app) { + mProcRecords.remove(app); + } + + @GuardedBy("mService") + void setLastReportedChange(int lastReportedChange) { + mLastReportedChange = lastReportedChange; + } + + @GuardedBy({"mService", "mProcLock"}) + void reset() { + setCurProcState(ActivityManager.PROCESS_STATE_CACHED_EMPTY); + mForegroundServices = false; + mCurCapability = 0; } public void updateHasInternetPermission() { hasInternetPermission = ActivityManager.checkUidPermission(Manifest.permission.INTERNET, - uid) == PackageManager.PERMISSION_GRANTED; + mUid) == PackageManager.PERMISSION_GRANTED; } /** @@ -153,19 +320,19 @@ public final class UidRecord { void dumpDebug(ProtoOutputStream proto, long fieldId) { long token = proto.start(fieldId); - proto.write(UidRecordProto.UID, uid); + proto.write(UidRecordProto.UID, mUid); proto.write(UidRecordProto.CURRENT, ProcessList.makeProcStateProtoEnum(mCurProcState)); - proto.write(UidRecordProto.EPHEMERAL, ephemeral); - proto.write(UidRecordProto.FG_SERVICES, foregroundServices); - proto.write(UidRecordProto.WHILELIST, mCurAllowlist); + proto.write(UidRecordProto.EPHEMERAL, mEphemeral); + proto.write(UidRecordProto.FG_SERVICES, mForegroundServices); + proto.write(UidRecordProto.WHILELIST, mCurAllowList); ProtoUtils.toDuration(proto, UidRecordProto.LAST_BACKGROUND_TIME, - lastBackgroundTime, SystemClock.elapsedRealtime()); - proto.write(UidRecordProto.IDLE, idle); - if (lastReportedChange != 0) { + mLastBackgroundTime, SystemClock.elapsedRealtime()); + proto.write(UidRecordProto.IDLE, mIdle); + if (mLastReportedChange != 0) { ProtoUtils.writeBitWiseFlagsToProtoEnum(proto, UidRecordProto.LAST_REPORTED_CHANGES, - lastReportedChange, ORIG_ENUMS, PROTO_ENUMS); + mLastReportedChange, ORIG_ENUMS, PROTO_ENUMS); } - proto.write(UidRecordProto.NUM_PROCS, numProcs); + proto.write(UidRecordProto.NUM_PROCS, mNumProcs); long seqToken = proto.start(UidRecordProto.NETWORK_STATE_UPDATE); proto.write(UidRecordProto.ProcStateSequence.CURURENT, curProcStateSeq); @@ -182,54 +349,54 @@ public final class UidRecord { sb.append("UidRecord{"); sb.append(Integer.toHexString(System.identityHashCode(this))); sb.append(' '); - UserHandle.formatUid(sb, uid); + UserHandle.formatUid(sb, mUid); sb.append(' '); sb.append(ProcessList.makeProcStateString(mCurProcState)); - if (ephemeral) { + if (mEphemeral) { sb.append(" ephemeral"); } - if (foregroundServices) { + if (mForegroundServices) { sb.append(" fgServices"); } - if (mCurAllowlist) { + if (mCurAllowList) { sb.append(" allowlist"); } - if (lastBackgroundTime > 0) { + if (mLastBackgroundTime > 0) { sb.append(" bg:"); - TimeUtils.formatDuration(SystemClock.elapsedRealtime()-lastBackgroundTime, sb); + TimeUtils.formatDuration(SystemClock.elapsedRealtime() - mLastBackgroundTime, sb); } - if (idle) { + if (mIdle) { sb.append(" idle"); } - if (lastReportedChange != 0) { + if (mLastReportedChange != 0) { sb.append(" change:"); boolean printed = false; - if ((lastReportedChange & CHANGE_GONE) != 0) { + if ((mLastReportedChange & CHANGE_GONE) != 0) { printed = true; sb.append("gone"); } - if ((lastReportedChange & CHANGE_IDLE) != 0) { + if ((mLastReportedChange & CHANGE_IDLE) != 0) { if (printed) { sb.append("|"); } printed = true; sb.append("idle"); } - if ((lastReportedChange & CHANGE_ACTIVE) != 0) { + if ((mLastReportedChange & CHANGE_ACTIVE) != 0) { if (printed) { sb.append("|"); } printed = true; sb.append("active"); } - if ((lastReportedChange & CHANGE_CACHED) != 0) { + if ((mLastReportedChange & CHANGE_CACHED) != 0) { if (printed) { sb.append("|"); } printed = true; sb.append("cached"); } - if ((lastReportedChange & CHANGE_UNCACHED) != 0) { + if ((mLastReportedChange & CHANGE_UNCACHED) != 0) { if (printed) { sb.append("|"); } @@ -237,7 +404,7 @@ public final class UidRecord { } } sb.append(" procs:"); - sb.append(numProcs); + sb.append(mNumProcs); sb.append(" seq("); sb.append(curProcStateSeq); sb.append(","); diff --git a/services/tests/mockingservicestests/src/com/android/server/am/AppChildProcessTest.java b/services/tests/mockingservicestests/src/com/android/server/am/AppChildProcessTest.java index a18632b8d1b2d..961fc1884cfd9 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/AppChildProcessTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/AppChildProcessTest.java @@ -232,8 +232,8 @@ public class AppChildProcessTest { ai.packageName = packageName; ai.uid = uid; ProcessRecord app = new ProcessRecord(mAms, ai, processName, uid); - app.pid = pid; - mAms.mPidsSelfLocked.doAddInternal(app); + app.setPid(pid); + mAms.mPidsSelfLocked.doAddInternal(app.getPid(), app); mPhantomInjector.addToProcess(uid, pid, pid); } diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java index 9441ecf74e830..22b2f7e04069c 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java @@ -798,7 +798,7 @@ public class ApplicationExitInfoTest { final int traceEnd = 8192; createRandomFile(traceFile, traceSize); assertEquals(traceSize, traceFile.length()); - mAppExitInfoTracker.handleLogAnrTrace(app.pid, app.uid, app.getPackageList(), + mAppExitInfoTracker.handleLogAnrTrace(app.getPid(), app.uid, app.getPackageList(), traceFile, traceStart, traceEnd); noteAppKill(app, ApplicationExitInfo.REASON_OTHER, @@ -991,16 +991,16 @@ public class ApplicationExitInfoTest { ApplicationInfo ai = new ApplicationInfo(); ai.packageName = packageName; ProcessRecord app = new ProcessRecord(mAms, ai, processName, uid); - app.pid = pid; + app.setPid(pid); app.info.uid = packageUid; if (definingUid != null) { final String dummyPackageName = "com.android.test"; final String dummyClassName = ".Foo"; - app.hostingRecord = HostingRecord.byAppZygote(new ComponentName( - dummyPackageName, dummyClassName), "", definingUid); + app.setHostingRecord(HostingRecord.byAppZygote(new ComponentName( + dummyPackageName, dummyClassName), "", definingUid)); } - app.connectionGroup = connectionGroup; - app.setProcState = procState; + app.mServices.setConnectionGroup(connectionGroup); + app.mState.setSetProcState(procState); app.mProfile.setLastMemInfo(spy(new Debug.MemoryInfo())); app.mProfile.setLastPss(pss); app.mProfile.setLastRss(rss); diff --git a/services/tests/mockingservicestests/src/com/android/server/am/CacheOomRankerTest.java b/services/tests/mockingservicestests/src/com/android/server/am/CacheOomRankerTest.java index c82db7305bd8d..022fadcc6dd0f 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/CacheOomRankerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/CacheOomRankerTest.java @@ -170,7 +170,7 @@ public class CacheOomRankerTest { /* lruWeight= */1.0f); ProcessList list = new ProcessList(); - ArrayList processList = list.mLruProcesses; + ArrayList processList = list.getLruProcessesLSP(); ProcessRecord lastUsed40MinutesAgo = nextProcessRecord(ProcessList.UNKNOWN_ADJ, Duration.ofMinutes(40).toMillis(), 10 * 1024L, 1000); processList.add(lastUsed40MinutesAgo); @@ -191,7 +191,7 @@ public class CacheOomRankerTest { Duration.ofMinutes(30).toMillis(), 1024L, 20); processList.add(lastUsed30MinutesAgo); - mCacheOomRanker.reRankLruCachedApps(list); + mCacheOomRanker.reRankLruCachedAppsLSP(processList, list.getLruProcessServiceStartLOSP()); // First 5 ordered by least recently used first, then last processes position unchanged. assertThat(processList).containsExactly(lastUsed60MinutesAgo, lastUsed42MinutesAgo, @@ -207,7 +207,7 @@ public class CacheOomRankerTest { /* lruWeight= */ 0.0f); ProcessList list = new ProcessList(); - ArrayList processList = list.mLruProcesses; + ArrayList processList = list.getLruProcessesLSP(); ProcessRecord rss10k = nextProcessRecord(ProcessList.UNKNOWN_ADJ, Duration.ofMinutes(40).toMillis(), 10 * 1024L, 1000); processList.add(rss10k); @@ -231,7 +231,7 @@ public class CacheOomRankerTest { Duration.ofMinutes(30).toMillis(), 16 * 1024L, 20); processList.add(rss16k); - mCacheOomRanker.reRankLruCachedApps(list); + mCacheOomRanker.reRankLruCachedAppsLSP(processList, list.getLruProcessServiceStartLOSP()); // First 6 ordered by largest pss, then last processes position unchanged. assertThat(processList).containsExactly(rss100k, rss20k, rss15k, rss10k, rss2k, rss1k, @@ -246,8 +246,8 @@ public class CacheOomRankerTest { /* lruWeight= */ 0.0f); ProcessList list = new ProcessList(); - list.mLruProcessServiceStart = 1; - ArrayList processList = list.mLruProcesses; + list.setLruProcessServiceStartLSP(1); + ArrayList processList = list.getLruProcessesLSP(); ProcessRecord used1000 = nextProcessRecord(ProcessList.UNKNOWN_ADJ, Duration.ofMinutes(40).toMillis(), 10 * 1024L, 1000); processList.add(used1000); @@ -268,7 +268,7 @@ public class CacheOomRankerTest { Duration.ofMinutes(30).toMillis(), 16 * 1024L, 200); processList.add(used200); - mCacheOomRanker.reRankLruCachedApps(list); + mCacheOomRanker.reRankLruCachedAppsLSP(processList, list.getLruProcessServiceStartLOSP()); // First 4 ordered by uses, then last processes position unchanged. assertThat(processList).containsExactly(used10, used20, used1000, used2000, used500, @@ -283,7 +283,7 @@ public class CacheOomRankerTest { /* lruWeight= */ 0.3f); ProcessList list = new ProcessList(); - ArrayList processList = list.mLruProcesses; + ArrayList processList = list.getLruProcessesLSP(); ProcessRecord unknownAdj1 = nextProcessRecord(ProcessList.UNKNOWN_ADJ, Duration.ofMinutes(40).toMillis(), 10 * 1024L, 1000); processList.add(unknownAdj1); @@ -304,7 +304,7 @@ public class CacheOomRankerTest { processList.add(systemAdj); // 6 Processes but only 3 in eligible for cache so no re-ranking. - mCacheOomRanker.reRankLruCachedApps(list); + mCacheOomRanker.reRankLruCachedAppsLSP(processList, list.getLruProcessServiceStartLOSP()); // All positions unchanged. assertThat(processList).containsExactly(unknownAdj1, unknownAdj2, unknownAdj3, @@ -319,8 +319,8 @@ public class CacheOomRankerTest { /* lruWeight= */ 0.0f); ProcessList list = new ProcessList(); - list.mLruProcessServiceStart = 4; - ArrayList processList = list.mLruProcesses; + list.setLruProcessServiceStartLSP(4); + ArrayList processList = list.getLruProcessesLSP(); ProcessRecord used1000 = nextProcessRecord(ProcessList.UNKNOWN_ADJ, Duration.ofMinutes(40).toMillis(), 10 * 1024L, 1000); processList.add(used1000); @@ -340,7 +340,7 @@ public class CacheOomRankerTest { Duration.ofMinutes(30).toMillis(), 16 * 1024L, 200); processList.add(used200); - mCacheOomRanker.reRankLruCachedApps(list); + mCacheOomRanker.reRankLruCachedAppsLSP(processList, list.getLruProcessServiceStartLOSP()); // All positions unchanged. assertThat(processList).containsExactly(used1000, used2000, used10, used20, used500, @@ -378,17 +378,17 @@ public class CacheOomRankerTest { ApplicationInfo ai = new ApplicationInfo(); ai.packageName = "a.package.name" + mNextPackageName++; ProcessRecord app = new ProcessRecord(mAms, ai, ai.packageName + ":process", mNextUid++); - app.pid = mNextPid++; + app.setPid(mNextPid++); app.info.uid = mNextPackageUid++; // Exact value does not mater, it can be any state for which compaction is allowed. - app.setProcState = PROCESS_STATE_BOUND_FOREGROUND_SERVICE; - app.setAdj = setAdj; - app.lastActivityTime = lastActivityTime; + app.mState.setSetProcState(PROCESS_STATE_BOUND_FOREGROUND_SERVICE); + app.mState.setSetAdj(setAdj); + app.setLastActivityTime(lastActivityTime); app.mProfile.setLastRss(lastRss); - app.setCached(false); + app.mState.setCached(false); for (int i = 0; i < returnedToCacheCount; ++i) { - app.setCached(false); - app.setCached(true); + app.mState.setCached(false); + app.mState.setCached(true); } return app; } diff --git a/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java b/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java index 96a44a46bbafb..d86032622e43d 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java @@ -134,11 +134,11 @@ public final class CachedAppOptimizerTest { ApplicationInfo ai = new ApplicationInfo(); ai.packageName = packageName; ProcessRecord app = new ProcessRecord(mAms, ai, processName, uid); - app.pid = pid; + app.setPid(pid); app.info.uid = packageUid; // Exact value does not mater, it can be any state for which compaction is allowed. - app.setProcState = PROCESS_STATE_BOUND_FOREGROUND_SERVICE; - app.setAdj = 905; + app.mState.setSetProcState(PROCESS_STATE_BOUND_FOREGROUND_SERVICE); + app.mState.setSetAdj(905); return app; } @@ -875,7 +875,8 @@ public final class CachedAppOptimizerTest { mProcessDependencies.setRss(rssBefore2); mProcessDependencies.setRssAfterCompaction(rssAfter2); // This is to avoid throttle of compacting too soon. - processRecord.lastCompactTime = processRecord.lastCompactTime - 10_000; + processRecord.mOptRecord.setLastCompactTime( + processRecord.mOptRecord.getLastCompactTime() - 10_000); // WHEN we try to run compaction. mCachedAppOptimizerUnderTest.compactAppFull(processRecord); waitForHandler(); @@ -890,7 +891,8 @@ public final class CachedAppOptimizerTest { mProcessDependencies.setRss(rssBefore3); mProcessDependencies.setRssAfterCompaction(rssAfter3); // This is to avoid throttle of compacting too soon. - processRecord.lastCompactTime = processRecord.lastCompactTime - 10_000; + processRecord.mOptRecord.setLastCompactTime( + processRecord.mOptRecord.getLastCompactTime() - 10_000); // WHEN we try to run compaction mCachedAppOptimizerUnderTest.compactAppFull(processRecord); waitForHandler(); diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java index 7daf357705bc2..27825a461b40b 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java @@ -176,6 +176,8 @@ public class MockingOomAdjusterTests { setFieldValue(ActivityManagerService.class, sService, "mUserController", mock(UserController.class)); setFieldValue(ActivityManagerService.class, sService, "mAppProfiler", profiler); + setFieldValue(ActivityManagerService.class, sService, "mProcLock", + new ActivityManagerProcLock()); setFieldValue(AppProfiler.class, profiler, "mProfilerLock", new Object()); doReturn(new ActivityManagerService.ProcessChangeItem()).when(pr) .enqueueProcessChangeItemLocked(anyInt(), anyInt()); @@ -207,8 +209,8 @@ public class MockingOomAdjusterTests { public void testUpdateOomAdj_DoOne_Persistent_TopUi_Sleeping() { ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID, MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true)); - app.maxAdj = PERSISTENT_PROC_ADJ; - app.setHasTopUi(true); + app.mState.setMaxAdj(PERSISTENT_PROC_ADJ); + app.mState.setHasTopUi(true); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_ASLEEP); sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); @@ -222,8 +224,8 @@ public class MockingOomAdjusterTests { public void testUpdateOomAdj_DoOne_Persistent_TopUi_Awake() { ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID, MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true)); - app.maxAdj = PERSISTENT_PROC_ADJ; - app.setHasTopUi(true); + app.mState.setMaxAdj(PERSISTENT_PROC_ADJ); + app.mState.setHasTopUi(true); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE); @@ -236,7 +238,7 @@ public class MockingOomAdjusterTests { public void testUpdateOomAdj_DoOne_Persistent_TopApp() { ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID, MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true)); - app.maxAdj = PERSISTENT_PROC_ADJ; + app.mState.setMaxAdj(PERSISTENT_PROC_ADJ); doReturn(app).when(sService).getTopApp(); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE); @@ -266,7 +268,7 @@ public class MockingOomAdjusterTests { ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID, MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true)); doReturn(PROCESS_STATE_TOP_SLEEPING).when(sService.mAtmInternal).getTopProcessState(); - app.runningRemoteAnimation = true; + app.mState.setRunningRemoteAnimation(true); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE); doReturn(PROCESS_STATE_TOP).when(sService.mAtmInternal).getTopProcessState(); @@ -308,7 +310,7 @@ public class MockingOomAdjusterTests { public void testUpdateOomAdj_DoOne_ExecutingService() { ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID, MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true)); - app.executingServices.add(mock(ServiceRecord.class)); + app.mServices.startExecutingService(mock(ServiceRecord.class)); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE); @@ -337,7 +339,7 @@ public class MockingOomAdjusterTests { public void testUpdateOomAdj_DoOne_CachedEmpty() { ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID, MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true)); - app.setCurRawAdj(CACHED_APP_MIN_ADJ); + app.mState.setCurRawAdj(CACHED_APP_MIN_ADJ); doReturn(null).when(sService).getTopApp(); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE); @@ -351,7 +353,6 @@ public class MockingOomAdjusterTests { public void testUpdateOomAdj_DoOne_VisibleActivities() { ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID, MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true)); - doReturn(mock(WindowProcessController.class)).when(app).getWindowProcessController(); WindowProcessController wpc = app.getWindowProcessController(); doReturn(true).when(wpc).hasActivities(); doAnswer(answer(callback -> { @@ -368,7 +369,6 @@ public class MockingOomAdjusterTests { any(WindowProcessController.ComputeOomAdjCallback.class)); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE); - doCallRealMethod().when(app).getWindowProcessController(); assertProcStates(app, PROCESS_STATE_TOP, VISIBLE_APP_ADJ, SCHED_GROUP_TOP_APP); } @@ -378,15 +378,14 @@ public class MockingOomAdjusterTests { public void testUpdateOomAdj_DoOne_RecentTasks() { ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID, MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true)); - doReturn(mock(WindowProcessController.class)).when(app).getWindowProcessController(); WindowProcessController wpc = app.getWindowProcessController(); doReturn(true).when(wpc).hasRecentTasks(); - app.lastTopTime = SystemClock.uptimeMillis(); + app.mState.setLastTopTime(SystemClock.uptimeMillis()); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE); doCallRealMethod().when(wpc).hasRecentTasks(); - assertEquals(PROCESS_STATE_CACHED_RECENT, app.setProcState); + assertEquals(PROCESS_STATE_CACHED_RECENT, app.mState.getSetProcState()); } @SuppressWarnings("GuardedBy") @@ -394,7 +393,7 @@ public class MockingOomAdjusterTests { public void testUpdateOomAdj_DoOne_FgServiceLocation() { ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID, MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true)); - app.setHasForegroundServices(true, ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION); + app.mServices.setHasForegroundServices(true, ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE); @@ -407,7 +406,7 @@ public class MockingOomAdjusterTests { public void testUpdateOomAdj_DoOne_FgService() { ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID, MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true)); - app.setHasForegroundServices(true, 0); + app.mServices.setHasForegroundServices(true, 0); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE); @@ -420,7 +419,7 @@ public class MockingOomAdjusterTests { public void testUpdateOomAdj_DoOne_OverlayUi() { ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID, MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true)); - app.setHasOverlayUi(true); + app.mState.setHasOverlayUi(true); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE); @@ -433,8 +432,8 @@ public class MockingOomAdjusterTests { public void testUpdateOomAdj_DoOne_PerceptibleRecent() { ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID, MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true)); - app.setHasForegroundServices(true, 0); - app.lastTopTime = SystemClock.uptimeMillis(); + app.mServices.setHasForegroundServices(true, 0); + app.mState.setLastTopTime(SystemClock.uptimeMillis()); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE); @@ -447,7 +446,7 @@ public class MockingOomAdjusterTests { public void testUpdateOomAdj_DoOne_Toast() { ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID, MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true)); - app.forcingToImportant = new Object(); + app.mState.setForcingToImportant(new Object()); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE); @@ -460,7 +459,6 @@ public class MockingOomAdjusterTests { public void testUpdateOomAdj_DoOne_HeavyWeight() { ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID, MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true)); - doReturn(mock(WindowProcessController.class)).when(app).getWindowProcessController(); WindowProcessController wpc = app.getWindowProcessController(); doReturn(true).when(wpc).isHeavyWeightProcess(); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); @@ -476,7 +474,6 @@ public class MockingOomAdjusterTests { public void testUpdateOomAdj_DoOne_HomeApp() { ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID, MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true)); - doReturn(mock(WindowProcessController.class)).when(app).getWindowProcessController(); WindowProcessController wpc = app.getWindowProcessController(); doReturn(true).when(wpc).isHomeProcess(); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); @@ -490,7 +487,6 @@ public class MockingOomAdjusterTests { public void testUpdateOomAdj_DoOne_PreviousApp() { ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID, MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true)); - doReturn(mock(WindowProcessController.class)).when(app).getWindowProcessController(); WindowProcessController wpc = app.getWindowProcessController(); doReturn(true).when(wpc).isPreviousProcess(); doReturn(true).when(wpc).hasActivities(); @@ -522,11 +518,11 @@ public class MockingOomAdjusterTests { public void testUpdateOomAdj_DoOne_ClientActivities() { ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID, MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true)); - doReturn(true).when(app).hasClientActivities(); + app.mServices.setHasClientActivities(true); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE); - assertEquals(PROCESS_STATE_CACHED_ACTIVITY_CLIENT, app.setProcState); + assertEquals(PROCESS_STATE_CACHED_ACTIVITY_CLIENT, app.mState.getSetProcState()); } @SuppressWarnings("GuardedBy") @@ -534,11 +530,11 @@ public class MockingOomAdjusterTests { public void testUpdateOomAdj_DoOne_TreatLikeActivity() { ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID, MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true)); - app.treatLikeActivity = true; + app.mServices.setTreatLikeActivity(true); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE); - assertEquals(PROCESS_STATE_CACHED_ACTIVITY, app.setProcState); + assertEquals(PROCESS_STATE_CACHED_ACTIVITY, app.mState.getSetProcState()); } @SuppressWarnings("GuardedBy") @@ -546,12 +542,12 @@ public class MockingOomAdjusterTests { public void testUpdateOomAdj_DoOne_ServiceB() { ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID, MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false)); - app.serviceb = true; + app.mState.setServiceB(true); ServiceRecord s = mock(ServiceRecord.class); doReturn(new ArrayMap>()).when(s).getConnections(); s.startRequested = true; s.lastActivity = SystemClock.uptimeMillis(); - app.startService(s); + app.mServices.startService(s); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE); @@ -563,7 +559,7 @@ public class MockingOomAdjusterTests { public void testUpdateOomAdj_DoOne_MaxAdj() { ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID, MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false)); - app.maxAdj = PERCEPTIBLE_LOW_APP_ADJ; + app.mState.setMaxAdj(PERCEPTIBLE_LOW_APP_ADJ); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE); @@ -576,14 +572,14 @@ public class MockingOomAdjusterTests { public void testUpdateOomAdj_DoOne_NonCachedToCached() { ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID, MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false)); - app.setCached(false); - app.setCurRawAdj(SERVICE_ADJ); + app.mState.setCached(false); + app.mState.setCurRawAdj(SERVICE_ADJ); doReturn(null).when(sService).getTopApp(); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); sService.mOomAdjuster.updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_NONE); - assertTrue(ProcessList.CACHED_APP_MIN_ADJ <= app.setAdj); - assertTrue(ProcessList.CACHED_APP_MAX_ADJ >= app.setAdj); + assertTrue(ProcessList.CACHED_APP_MIN_ADJ <= app.mState.getSetAdj()); + assertTrue(ProcessList.CACHED_APP_MAX_ADJ >= app.mState.getSetAdj()); } @SuppressWarnings("GuardedBy") @@ -595,7 +591,7 @@ public class MockingOomAdjusterTests { doReturn(new ArrayMap>()).when(s).getConnections(); s.startRequested = true; s.lastActivity = SystemClock.uptimeMillis(); - app.startService(s); + app.mServices.startService(s); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE); @@ -633,7 +629,7 @@ public class MockingOomAdjusterTests { sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE); - assertEquals(PROCESS_STATE_CACHED_ACTIVITY, app.setProcState); + assertEquals(PROCESS_STATE_CACHED_ACTIVITY, app.mState.getSetProcState()); } @SuppressWarnings("GuardedBy") @@ -653,8 +649,8 @@ public class MockingOomAdjusterTests { sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE); - assertEquals(FOREGROUND_APP_ADJ, app.setAdj); - assertEquals(SCHED_GROUP_TOP_APP_BOUND, app.setSchedGroup); + assertEquals(FOREGROUND_APP_ADJ, app.mState.getSetAdj()); + assertEquals(SCHED_GROUP_TOP_APP_BOUND, app.mState.getSetSchedGroup()); } @SuppressWarnings("GuardedBy") @@ -676,12 +672,12 @@ public class MockingOomAdjusterTests { MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false)); ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID, MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false)); - client.treatLikeActivity = true; + client.mServices.setTreatLikeActivity(true); bindService(app, client, null, 0, mock(IBinder.class)); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE); - assertEquals(PROCESS_STATE_CACHED_EMPTY, app.setProcState); + assertEquals(PROCESS_STATE_CACHED_EMPTY, app.mState.getSetProcState()); } @SuppressWarnings("GuardedBy") @@ -689,7 +685,6 @@ public class MockingOomAdjusterTests { public void testUpdateOomAdj_DoOne_Service_AllowOomManagement() { ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID, MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true)); - doReturn(mock(WindowProcessController.class)).when(app).getWindowProcessController(); WindowProcessController wpc = app.getWindowProcessController(); doReturn(false).when(wpc).isHomeProcess(); doReturn(true).when(wpc).isPreviousProcess(); @@ -703,7 +698,7 @@ public class MockingOomAdjusterTests { sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE); doReturn(null).when(sService).getTopApp(); - assertEquals(PREVIOUS_APP_ADJ, app.setAdj); + assertEquals(PREVIOUS_APP_ADJ, app.mState.getSetAdj()); } @SuppressWarnings("GuardedBy") @@ -714,8 +709,8 @@ public class MockingOomAdjusterTests { ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID, MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false)); bindService(app, client, null, Context.BIND_FOREGROUND_SERVICE, mock(IBinder.class)); - client.maxAdj = PERSISTENT_PROC_ADJ; - client.setHasTopUi(true); + client.mState.setMaxAdj(PERSISTENT_PROC_ADJ); + client.mState.setHasTopUi(true); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE); @@ -731,11 +726,11 @@ public class MockingOomAdjusterTests { ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID, MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false)); bindService(app, client, null, Context.BIND_IMPORTANT, mock(IBinder.class)); - client.executingServices.add(mock(ServiceRecord.class)); + client.mServices.startExecutingService(mock(ServiceRecord.class)); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE); - assertEquals(FOREGROUND_APP_ADJ, app.setAdj); + assertEquals(FOREGROUND_APP_ADJ, app.mState.getSetAdj()); } @SuppressWarnings("GuardedBy") @@ -763,11 +758,11 @@ public class MockingOomAdjusterTests { ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID, MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false)); bindService(app, client, null, Context.BIND_FOREGROUND_SERVICE, mock(IBinder.class)); - client.maxAdj = PERSISTENT_PROC_ADJ; + client.mState.setMaxAdj(PERSISTENT_PROC_ADJ); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE); - assertEquals(PROCESS_STATE_BOUND_FOREGROUND_SERVICE, app.setProcState); + assertEquals(PROCESS_STATE_BOUND_FOREGROUND_SERVICE, app.mState.getSetProcState()); } @SuppressWarnings("GuardedBy") @@ -778,11 +773,11 @@ public class MockingOomAdjusterTests { ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID, MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false)); bindService(app, client, null, Context.BIND_NOT_FOREGROUND, mock(IBinder.class)); - client.maxAdj = PERSISTENT_PROC_ADJ; + client.mState.setMaxAdj(PERSISTENT_PROC_ADJ); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE); - assertEquals(PROCESS_STATE_TRANSIENT_BACKGROUND, app.setProcState); + assertEquals(PROCESS_STATE_TRANSIENT_BACKGROUND, app.mState.getSetProcState()); } @SuppressWarnings("GuardedBy") @@ -793,11 +788,11 @@ public class MockingOomAdjusterTests { ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID, MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false)); bindService(app, client, null, 0, mock(IBinder.class)); - client.setHasForegroundServices(true, 0); + client.mServices.setHasForegroundServices(true, 0); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE); - assertEquals(PROCESS_STATE_FOREGROUND_SERVICE, app.setProcState); + assertEquals(PROCESS_STATE_FOREGROUND_SERVICE, app.mState.getSetProcState()); } @SuppressWarnings("GuardedBy") @@ -815,12 +810,12 @@ public class MockingOomAdjusterTests { sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE); doReturn(null).when(sService.mBackupTargets).get(anyInt()); - assertEquals(BACKUP_APP_ADJ, app.setAdj); + assertEquals(BACKUP_APP_ADJ, app.mState.getSetAdj()); - client.maxAdj = PERSISTENT_PROC_ADJ; + client.mState.setMaxAdj(PERSISTENT_PROC_ADJ); sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE); - assertEquals(PERSISTENT_SERVICE_ADJ, app.setAdj); + assertEquals(PERSISTENT_SERVICE_ADJ, app.mState.getSetAdj()); } @SuppressWarnings("GuardedBy") @@ -831,11 +826,11 @@ public class MockingOomAdjusterTests { ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID, MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false)); bindService(app, client, null, Context.BIND_NOT_PERCEPTIBLE, mock(IBinder.class)); - client.runningRemoteAnimation = true; + client.mState.setRunningRemoteAnimation(true); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE); - assertEquals(PERCEPTIBLE_LOW_APP_ADJ, app.setAdj); + assertEquals(PERCEPTIBLE_LOW_APP_ADJ, app.mState.getSetAdj()); } @SuppressWarnings("GuardedBy") @@ -846,11 +841,11 @@ public class MockingOomAdjusterTests { ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID, MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false)); bindService(app, client, null, Context.BIND_NOT_VISIBLE, mock(IBinder.class)); - client.runningRemoteAnimation = true; + client.mState.setRunningRemoteAnimation(true); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE); - assertEquals(PERCEPTIBLE_APP_ADJ, app.setAdj); + assertEquals(PERCEPTIBLE_APP_ADJ, app.mState.getSetAdj()); } @SuppressWarnings("GuardedBy") @@ -861,11 +856,11 @@ public class MockingOomAdjusterTests { ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID, MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false)); bindService(app, client, null, 0, mock(IBinder.class)); - client.setHasOverlayUi(true); + client.mState.setHasOverlayUi(true); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE); - assertEquals(PERCEPTIBLE_APP_ADJ, app.setAdj); + assertEquals(PERCEPTIBLE_APP_ADJ, app.mState.getSetAdj()); } @SuppressWarnings("GuardedBy") @@ -876,11 +871,11 @@ public class MockingOomAdjusterTests { ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID, MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false)); bindService(app, client, null, 0, mock(IBinder.class)); - client.runningRemoteAnimation = true; + client.mState.setRunningRemoteAnimation(true); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE); - assertEquals(VISIBLE_APP_ADJ, app.setAdj); + assertEquals(VISIBLE_APP_ADJ, app.mState.getSetAdj()); } @SuppressWarnings("GuardedBy") @@ -891,11 +886,11 @@ public class MockingOomAdjusterTests { ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID, MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false)); bindService(app, client, null, Context.BIND_IMPORTANT_BACKGROUND, mock(IBinder.class)); - client.setHasOverlayUi(true); + client.mState.setHasOverlayUi(true); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE); - assertEquals(PROCESS_STATE_IMPORTANT_BACKGROUND, app.setProcState); + assertEquals(PROCESS_STATE_IMPORTANT_BACKGROUND, app.mState.getSetProcState()); } @SuppressWarnings("GuardedBy") @@ -917,7 +912,7 @@ public class MockingOomAdjusterTests { ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID, MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false)); bindProvider(app, client, null, null, false); - client.treatLikeActivity = true; + client.mServices.setTreatLikeActivity(true); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE); @@ -948,7 +943,7 @@ public class MockingOomAdjusterTests { MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false)); ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID, MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false)); - client.setHasForegroundServices(true, 0); + client.mServices.setHasForegroundServices(true, 0); bindProvider(app, client, null, null, false); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE); @@ -977,7 +972,7 @@ public class MockingOomAdjusterTests { public void testUpdateOomAdj_DoOne_Provider_Retention() { ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID, MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false)); - app.lastProviderTime = SystemClock.uptimeMillis(); + app.mProviders.setLastProviderTime(SystemClock.uptimeMillis()); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE); @@ -1017,7 +1012,7 @@ public class MockingOomAdjusterTests { ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID, MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false)); bindService(app, client2, null, 0, mock(IBinder.class)); - client2.setHasForegroundServices(true, 0); + client2.mServices.setHasForegroundServices(true, 0); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE); @@ -1036,7 +1031,7 @@ public class MockingOomAdjusterTests { ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID, MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false)); bindService(client, client2, null, 0, mock(IBinder.class)); - client2.setHasForegroundServices(true, 0); + client2.mServices.setHasForegroundServices(true, 0); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE); @@ -1055,9 +1050,9 @@ public class MockingOomAdjusterTests { ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID, MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false)); bindService(client, client2, null, 0, mock(IBinder.class)); - client2.setHasForegroundServices(true, 0); + client2.mServices.setHasForegroundServices(true, 0); bindService(client2, app, null, 0, mock(IBinder.class)); - ArrayList lru = sService.mProcessList.mLruProcesses; + ArrayList lru = sService.mProcessList.getLruProcessesLOSP(); lru.clear(); lru.add(app); lru.add(client); @@ -1072,13 +1067,13 @@ public class MockingOomAdjusterTests { assertProcStates(client2, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ, SCHED_GROUP_DEFAULT); - client2.setHasForegroundServices(false, 0); + client2.mServices.setHasForegroundServices(false, 0); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); sService.mOomAdjuster.updateOomAdjLocked(client2, true, OomAdjuster.OOM_ADJ_REASON_NONE); - assertEquals(PROCESS_STATE_CACHED_EMPTY, client2.setProcState); - assertEquals(PROCESS_STATE_CACHED_EMPTY, client.setProcState); - assertEquals(PROCESS_STATE_CACHED_EMPTY, app.setProcState); + assertEquals(PROCESS_STATE_CACHED_EMPTY, client2.mState.getSetProcState()); + assertEquals(PROCESS_STATE_CACHED_EMPTY, client.mState.getSetProcState()); + assertEquals(PROCESS_STATE_CACHED_EMPTY, app.mState.getSetProcState()); } @SuppressWarnings("GuardedBy") @@ -1093,8 +1088,8 @@ public class MockingOomAdjusterTests { ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID, MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false)); bindService(client2, client, null, 0, mock(IBinder.class)); - client.setHasForegroundServices(true, 0); - ArrayList lru = sService.mProcessList.mLruProcesses; + client.mServices.setHasForegroundServices(true, 0); + ArrayList lru = sService.mProcessList.getLruProcessesLOSP(); lru.clear(); lru.add(app); lru.add(client); @@ -1121,11 +1116,11 @@ public class MockingOomAdjusterTests { ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID, MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false)); bindService(client, client2, null, 0, mock(IBinder.class)); - client2.setHasForegroundServices(true, 0); + client2.mServices.setHasForegroundServices(true, 0); bindService(client2, app, null, 0, mock(IBinder.class)); ProcessRecord client3 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID, MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false)); - client3.forcingToImportant = new Object(); + client3.mState.setForcingToImportant(new Object()); bindService(app, client3, null, 0, mock(IBinder.class)); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE); @@ -1146,12 +1141,11 @@ public class MockingOomAdjusterTests { MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false)); bindService(client, client2, null, 0, mock(IBinder.class)); bindService(client2, app, null, 0, mock(IBinder.class)); - doReturn(mock(WindowProcessController.class)).when(client2).getWindowProcessController(); WindowProcessController wpc = client2.getWindowProcessController(); doReturn(true).when(wpc).isHomeProcess(); ProcessRecord client3 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID, MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false)); - client3.forcingToImportant = new Object(); + client3.mState.setForcingToImportant(new Object()); bindService(app, client3, null, 0, mock(IBinder.class)); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE); @@ -1172,14 +1166,13 @@ public class MockingOomAdjusterTests { MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false)); bindService(client, client2, null, 0, mock(IBinder.class)); bindService(client2, app, null, 0, mock(IBinder.class)); - doReturn(mock(WindowProcessController.class)).when(client2).getWindowProcessController(); WindowProcessController wpc = client2.getWindowProcessController(); doReturn(true).when(wpc).isHomeProcess(); ProcessRecord client3 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID, MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false)); ProcessRecord client4 = spy(makeDefaultProcessRecord(MOCKAPP5_PID, MOCKAPP5_UID, MOCKAPP5_PROCESSNAME, MOCKAPP5_PACKAGENAME, false)); - client4.forcingToImportant = new Object(); + client4.mState.setForcingToImportant(new Object()); bindService(app, client4, null, 0, mock(IBinder.class)); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE); @@ -1200,16 +1193,15 @@ public class MockingOomAdjusterTests { MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false)); bindService(client, client2, null, 0, mock(IBinder.class)); bindService(client2, app, null, 0, mock(IBinder.class)); - doReturn(mock(WindowProcessController.class)).when(client2).getWindowProcessController(); WindowProcessController wpc = client2.getWindowProcessController(); doReturn(true).when(wpc).isHomeProcess(); ProcessRecord client3 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID, MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false)); - client3.forcingToImportant = new Object(); + client3.mState.setForcingToImportant(new Object()); bindService(app, client3, null, 0, mock(IBinder.class)); ProcessRecord client4 = spy(makeDefaultProcessRecord(MOCKAPP5_PID, MOCKAPP5_UID, MOCKAPP5_PROCESSNAME, MOCKAPP5_PACKAGENAME, false)); - client4.setHasForegroundServices(true, 0); + client4.mServices.setHasForegroundServices(true, 0); bindService(app, client4, null, 0, mock(IBinder.class)); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE); @@ -1225,17 +1217,16 @@ public class MockingOomAdjusterTests { MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false)); ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID, MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false)); - doReturn(mock(WindowProcessController.class)).when(client).getWindowProcessController(); WindowProcessController wpc = client.getWindowProcessController(); doReturn(true).when(wpc).isHomeProcess(); bindService(app, client, null, 0, mock(IBinder.class)); ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID, MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false)); bindService(app, client2, null, 0, mock(IBinder.class)); - client2.setHasForegroundServices(true, 0); + client2.mServices.setHasForegroundServices(true, 0); ProcessRecord client3 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID, MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false)); - client3.forcingToImportant = new Object(); + client3.mState.setForcingToImportant(new Object()); bindService(app, client3, null, 0, mock(IBinder.class)); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE); @@ -1255,7 +1246,7 @@ public class MockingOomAdjusterTests { ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID, MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false)); bindProvider(client, client2, null, null, false); - client2.setHasForegroundServices(true, 0); + client2.mServices.setHasForegroundServices(true, 0); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE); @@ -1274,7 +1265,7 @@ public class MockingOomAdjusterTests { ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID, MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false)); bindProvider(client, client2, null, null, false); - client2.setHasForegroundServices(true, 0); + client2.mServices.setHasForegroundServices(true, 0); bindService(client2, app, null, 0, mock(IBinder.class)); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE); @@ -1294,7 +1285,7 @@ public class MockingOomAdjusterTests { ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID, MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false)); bindProvider(client, client2, null, null, false); - client2.setHasForegroundServices(true, 0); + client2.mServices.setHasForegroundServices(true, 0); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE); @@ -1313,7 +1304,7 @@ public class MockingOomAdjusterTests { ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID, MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false)); bindProvider(client, client2, null, null, false); - client2.setHasForegroundServices(true, 0); + client2.mServices.setHasForegroundServices(true, 0); bindProvider(client2, app, null, null, false); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE); @@ -1327,11 +1318,11 @@ public class MockingOomAdjusterTests { public void testUpdateOomAdj_DoAll_Unbound() { ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID, MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false)); - app.forcingToImportant = new Object(); + app.mState.setForcingToImportant(new Object()); ProcessRecord app2 = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID, MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false)); - app2.setHasForegroundServices(true, 0); - ArrayList lru = sService.mProcessList.mLruProcesses; + app2.mServices.setHasForegroundServices(true, 0); + ArrayList lru = sService.mProcessList.getLruProcessesLOSP(); lru.clear(); lru.add(app); lru.add(app2); @@ -1350,12 +1341,12 @@ public class MockingOomAdjusterTests { public void testUpdateOomAdj_DoAll_BoundFgService() { ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID, MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false)); - app.forcingToImportant = new Object(); + app.mState.setForcingToImportant(new Object()); ProcessRecord app2 = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID, MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false)); - app2.setHasForegroundServices(true, 0); + app2.mServices.setHasForegroundServices(true, 0); bindService(app, app2, null, 0, mock(IBinder.class)); - ArrayList lru = sService.mProcessList.mLruProcesses; + ArrayList lru = sService.mProcessList.getLruProcessesLOSP(); lru.clear(); lru.add(app); lru.add(app2); @@ -1380,9 +1371,9 @@ public class MockingOomAdjusterTests { ProcessRecord app3 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID, MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false)); bindService(app2, app3, null, 0, mock(IBinder.class)); - app3.setHasForegroundServices(true, 0); + app3.mServices.setHasForegroundServices(true, 0); bindService(app3, app, null, 0, mock(IBinder.class)); - ArrayList lru = sService.mProcessList.mLruProcesses; + ArrayList lru = sService.mProcessList.getLruProcessesLOSP(); lru.clear(); lru.add(app); lru.add(app2); @@ -1397,15 +1388,15 @@ public class MockingOomAdjusterTests { SCHED_GROUP_DEFAULT); assertProcStates(app3, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ, SCHED_GROUP_DEFAULT); - assertEquals("service", app.adjType); - assertEquals("service", app2.adjType); - assertEquals("fg-service", app3.adjType); + assertEquals("service", app.mState.getAdjType()); + assertEquals("service", app2.mState.getAdjType()); + assertEquals("fg-service", app3.mState.getAdjType()); assertEquals(false, app.isCached()); assertEquals(false, app2.isCached()); assertEquals(false, app3.isCached()); - assertEquals(false, app.empty); - assertEquals(false, app2.empty); - assertEquals(false, app3.empty); + assertEquals(false, app.mState.isEmpty()); + assertEquals(false, app2.mState.isEmpty()); + assertEquals(false, app3.mState.isEmpty()); } @SuppressWarnings("GuardedBy") @@ -1420,18 +1411,17 @@ public class MockingOomAdjusterTests { MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false)); bindService(app2, app3, null, 0, mock(IBinder.class)); bindService(app3, app, null, 0, mock(IBinder.class)); - doReturn(mock(WindowProcessController.class)).when(app3).getWindowProcessController(); WindowProcessController wpc = app3.getWindowProcessController(); doReturn(true).when(wpc).isHomeProcess(); ProcessRecord app4 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID, MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false)); - app4.setHasOverlayUi(true); + app4.mState.setHasOverlayUi(true); bindService(app, app4, s, 0, mock(IBinder.class)); ProcessRecord app5 = spy(makeDefaultProcessRecord(MOCKAPP5_PID, MOCKAPP5_UID, MOCKAPP5_PROCESSNAME, MOCKAPP5_PACKAGENAME, false)); - app5.setHasForegroundServices(true, 0); + app5.mServices.setHasForegroundServices(true, 0); bindService(app, app5, s, 0, mock(IBinder.class)); - ArrayList lru = sService.mProcessList.mLruProcesses; + ArrayList lru = sService.mProcessList.getLruProcessesLOSP(); lru.clear(); lru.add(app); lru.add(app2); @@ -1466,18 +1456,17 @@ public class MockingOomAdjusterTests { MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false)); bindService(app2, app3, null, 0, mock(IBinder.class)); bindService(app3, app, null, 0, mock(IBinder.class)); - doReturn(mock(WindowProcessController.class)).when(app3).getWindowProcessController(); WindowProcessController wpc = app3.getWindowProcessController(); doReturn(true).when(wpc).isHomeProcess(); ProcessRecord app4 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID, MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false)); - app4.setHasOverlayUi(true); + app4.mState.setHasOverlayUi(true); bindService(app, app4, s, 0, mock(IBinder.class)); ProcessRecord app5 = spy(makeDefaultProcessRecord(MOCKAPP5_PID, MOCKAPP5_UID, MOCKAPP5_PROCESSNAME, MOCKAPP5_PACKAGENAME, false)); - app5.setHasForegroundServices(true, 0); + app5.mServices.setHasForegroundServices(true, 0); bindService(app, app5, s, 0, mock(IBinder.class)); - ArrayList lru = sService.mProcessList.mLruProcesses; + ArrayList lru = sService.mProcessList.getLruProcessesLOSP(); lru.clear(); lru.add(app5); lru.add(app4); @@ -1512,18 +1501,17 @@ public class MockingOomAdjusterTests { MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false)); bindService(app2, app3, null, 0, mock(IBinder.class)); bindService(app3, app, null, 0, mock(IBinder.class)); - doReturn(mock(WindowProcessController.class)).when(app3).getWindowProcessController(); WindowProcessController wpc = app3.getWindowProcessController(); doReturn(true).when(wpc).isHomeProcess(); ProcessRecord app4 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID, MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false)); - app4.setHasOverlayUi(true); + app4.mState.setHasOverlayUi(true); bindService(app, app4, s, 0, mock(IBinder.class)); ProcessRecord app5 = spy(makeDefaultProcessRecord(MOCKAPP5_PID, MOCKAPP5_UID, MOCKAPP5_PROCESSNAME, MOCKAPP5_PACKAGENAME, false)); - app5.setHasForegroundServices(true, 0); + app5.mServices.setHasForegroundServices(true, 0); bindService(app, app5, s, 0, mock(IBinder.class)); - ArrayList lru = sService.mProcessList.mLruProcesses; + ArrayList lru = sService.mProcessList.getLruProcessesLOSP(); lru.clear(); lru.add(app3); lru.add(app4); @@ -1558,18 +1546,17 @@ public class MockingOomAdjusterTests { MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false)); bindProvider(app2, app3, null, null, false); bindProvider(app3, app, null, null, false); - doReturn(mock(WindowProcessController.class)).when(app3).getWindowProcessController(); WindowProcessController wpc = app3.getWindowProcessController(); doReturn(true).when(wpc).isHomeProcess(); ProcessRecord app4 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID, MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false)); - app4.setHasOverlayUi(true); + app4.mState.setHasOverlayUi(true); bindProvider(app, app4, cr, null, false); ProcessRecord app5 = spy(makeDefaultProcessRecord(MOCKAPP5_PID, MOCKAPP5_UID, MOCKAPP5_PROCESSNAME, MOCKAPP5_PACKAGENAME, false)); - app5.setHasForegroundServices(true, 0); + app5.mServices.setHasForegroundServices(true, 0); bindProvider(app, app5, cr, null, false); - ArrayList lru = sService.mProcessList.mLruProcesses; + ArrayList lru = sService.mProcessList.getLruProcessesLOSP(); lru.clear(); lru.add(app); lru.add(app2); @@ -1612,11 +1599,11 @@ public class MockingOomAdjusterTests { s.app = app3; setFieldValue(ServiceRecord.class, s, "connections", new ArrayMap>()); - app3.startService(s); + app3.mServices.startService(s); doCallRealMethod().when(s).getConnections(); s.startRequested = true; s.lastActivity = now; - ArrayList lru = sService.mProcessList.mLruProcesses; + ArrayList lru = sService.mProcessList.getLruProcessesLOSP(); lru.clear(); lru.add(app3); lru.add(app2); @@ -1626,9 +1613,9 @@ public class MockingOomAdjusterTests { sService.mOomAdjuster.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE); lru.clear(); - assertEquals(SERVICE_B_ADJ, app3.setAdj); - assertEquals(SERVICE_ADJ, app2.setAdj); - assertEquals(SERVICE_ADJ, app.setAdj); + assertEquals(SERVICE_B_ADJ, app3.mState.getSetAdj()); + assertEquals(SERVICE_ADJ, app2.mState.getSetAdj()); + assertEquals(SERVICE_ADJ, app.mState.getSetAdj()); } @SuppressWarnings("GuardedBy") @@ -1644,7 +1631,7 @@ public class MockingOomAdjusterTests { final int cachedAdj2 = cachedAdj1 + ProcessList.CACHED_APP_IMPORTANCE_LEVELS * 2; doReturn(userOwner).when(sService.mUserController).getCurrentUserId(); - final ArrayList lru = sService.mProcessList.mLruProcesses; + final ArrayList lru = sService.mProcessList.getLruProcessesLOSP(); lru.clear(); lru.add(app2); lru.add(app); @@ -1664,9 +1651,9 @@ public class MockingOomAdjusterTests { s.startRequested = true; s.lastActivity = now; - app.setCached(false); - app.startService(s); - app.hasShownUi = true; + app.mState.setCached(false); + app.mServices.startService(s); + app.mState.setHasShownUi(true); final ServiceInfo si2 = mock(ServiceInfo.class); si2.applicationInfo = mock(ApplicationInfo.class); @@ -1677,9 +1664,9 @@ public class MockingOomAdjusterTests { s2.startRequested = true; s2.lastActivity = now - sService.mConstants.MAX_SERVICE_INACTIVITY - 1; - app2.setCached(false); - app2.startService(s2); - app2.hasShownUi = false; + app2.mState.setCached(false); + app2.mServices.startService(s2); + app2.mState.setHasShownUi(false); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); sService.mOomAdjuster.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE); @@ -1687,28 +1674,28 @@ public class MockingOomAdjusterTests { assertProcStates(app, true, PROCESS_STATE_SERVICE, cachedAdj1, "cch-started-ui-services"); assertProcStates(app2, true, PROCESS_STATE_SERVICE, cachedAdj2, "cch-started-services"); - app.setProcState = PROCESS_STATE_NONEXISTENT; - app.adjType = null; - app.setAdj = UNKNOWN_ADJ; - app.hasShownUi = false; + app.mState.setSetProcState(PROCESS_STATE_NONEXISTENT); + app.mState.setAdjType(null); + app.mState.setSetAdj(UNKNOWN_ADJ); + app.mState.setHasShownUi(false); sService.mOomAdjuster.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE); assertProcStates(app, false, PROCESS_STATE_SERVICE, SERVICE_ADJ, "started-services"); - app.setCached(false); - app.setProcState = PROCESS_STATE_NONEXISTENT; - app.adjType = null; - app.setAdj = UNKNOWN_ADJ; + app.mState.setCached(false); + app.mState.setSetProcState(PROCESS_STATE_NONEXISTENT); + app.mState.setAdjType(null); + app.mState.setSetAdj(UNKNOWN_ADJ); s.lastActivity = now - sService.mConstants.MAX_SERVICE_INACTIVITY - 1; sService.mOomAdjuster.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE); assertProcStates(app, true, PROCESS_STATE_SERVICE, cachedAdj1, "cch-started-services"); - app.stopService(s); - app.setProcState = PROCESS_STATE_NONEXISTENT; - app.adjType = null; - app.setAdj = UNKNOWN_ADJ; - app.hasShownUi = true; + app.mServices.stopService(s); + app.mState.setSetProcState(PROCESS_STATE_NONEXISTENT); + app.mState.setAdjType(null); + app.mState.setSetAdj(UNKNOWN_ADJ); + app.mState.setHasShownUi(true); sService.mConstants.KEEP_WARMING_SERVICES.add(cn); sService.mConstants.KEEP_WARMING_SERVICES.add(cn2); s = spy(new ServiceRecord(sService, cn, cn, null, 0, null, @@ -1717,17 +1704,17 @@ public class MockingOomAdjusterTests { s.startRequested = true; s.lastActivity = now; - app.startService(s); + app.mServices.startService(s); sService.mOomAdjuster.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE); assertProcStates(app, false, PROCESS_STATE_SERVICE, SERVICE_ADJ, "started-services"); assertProcStates(app2, true, PROCESS_STATE_SERVICE, cachedAdj1, "cch-started-services"); - app.setCached(true); - app.setProcState = PROCESS_STATE_NONEXISTENT; - app.adjType = null; - app.setAdj = UNKNOWN_ADJ; - app.hasShownUi = false; + app.mState.setCached(true); + app.mState.setSetProcState(PROCESS_STATE_NONEXISTENT); + app.mState.setAdjType(null); + app.mState.setSetAdj(UNKNOWN_ADJ); + app.mState.setHasShownUi(false); s.lastActivity = now - sService.mConstants.MAX_SERVICE_INACTIVITY - 1; sService.mOomAdjuster.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE); @@ -1776,49 +1763,55 @@ public class MockingOomAdjusterTests { ai.longVersionCode = versionCode; ai.targetSdkVersion = targetSdkVersion; ProcessRecord app = new ProcessRecord(service, ai, processName, uid); + final ProcessStateRecord state = app.mState; + final ProcessServiceRecord services = app.mServices; + final ProcessReceiverRecord receivers = app.mReceivers; final ProcessProfileRecord profile = app.mProfile; - app.thread = mock(IApplicationThread.class); - app.lastActivityTime = lastActivityTime; + final ProcessProviderRecord providers = app.mProviders; + app.makeActive(mock(IApplicationThread.class), sService.mProcessStats); + app.setLastActivityTime(lastActivityTime); + app.setKilledByAm(killedByAm); + app.setIsolatedEntryPoint(isolatedEntryPoint); + setFieldValue(ProcessRecord.class, app, "mWindowProcessController", + mock(WindowProcessController.class)); profile.setLastPssTime(lastPssTime); profile.setNextPssTime(nextPssTime); profile.setLastPss(lastPss); - app.maxAdj = maxAdj; - app.setRawAdj = setRawAdj; - app.curAdj = curAdj; - app.setAdj = setAdj; - app.setCurrentSchedulingGroup(curSchedGroup); - app.setSchedGroup = setSchedGroup; - app.setCurProcState(curProcState); - app.setReportedProcState(repProcState); - app.setCurRawProcState(curRawProcState); - app.setProcState = setProcState; - app.connectionGroup = connectionGroup; - app.connectionImportance = connectionImportance; - app.serviceb = serviceb; - app.setHasClientActivities(hasClientActivities); - app.setHasForegroundServices(hasForegroundServices, fgServiceTypes); - app.setHasClientActivities(hasForegroundActivities); - app.repForegroundActivities = repForegroundActivities; - app.systemNoUi = systemNoUi; - app.hasShownUi = hasShownUi; - app.setHasTopUi(hasTopUi); - app.setHasOverlayUi(hasOverlayUi); - app.runningRemoteAnimation = runningRemoteAnimation; - app.hasAboveClient = hasAboveClient; - app.treatLikeActivity = treatLikeActivity; - app.killedByAm = killedByAm; - app.forcingToImportant = forcingToImportant; - for (int i = 0; i < numOfCurReceivers; i++) { - app.curReceivers.add(mock(BroadcastRecord.class)); - } - app.lastProviderTime = lastProviderTime; - app.lastTopTime = lastTopTime; - app.setCached(cached); + state.setMaxAdj(maxAdj); + state.setSetRawAdj(setRawAdj); + state.setCurAdj(curAdj); + state.setSetAdj(setAdj); + state.setCurrentSchedulingGroup(curSchedGroup); + state.setSetSchedGroup(setSchedGroup); + state.setCurProcState(curProcState); + state.setReportedProcState(repProcState); + state.setCurRawProcState(curRawProcState); + state.setSetProcState(setProcState); + state.setServiceB(serviceb); + state.setRepForegroundActivities(repForegroundActivities); + state.setHasForegroundActivities(hasForegroundActivities); + state.setSystemNoUi(systemNoUi); + state.setHasShownUi(hasShownUi); + state.setHasTopUi(hasTopUi); + state.setRunningRemoteAnimation(runningRemoteAnimation); + state.setHasOverlayUi(hasOverlayUi); + state.setCached(cached); + state.setLastTopTime(lastTopTime); + state.setForcingToImportant(forcingToImportant); + services.setConnectionGroup(connectionGroup); + services.setConnectionImportance(connectionImportance); + services.setHasClientActivities(hasClientActivities); + services.setHasForegroundServices(hasForegroundServices, fgServiceTypes); + services.setHasAboveClient(hasAboveClient); + services.setTreatLikeActivity(treatLikeActivity); + services.setExecServicesFg(execServicesFg); for (int i = 0; i < numOfExecutingServices; i++) { - app.executingServices.add(mock(ServiceRecord.class)); + services.startExecutingService(mock(ServiceRecord.class)); } - app.isolatedEntryPoint = isolatedEntryPoint; - app.execServicesFg = execServicesFg; + for (int i = 0; i < numOfCurReceivers; i++) { + receivers.addCurReceiver(mock(BroadcastRecord.class)); + } + providers.setLastProviderTime(lastProviderTime); return app; } @@ -1829,7 +1822,7 @@ public class MockingOomAdjusterTests { record.app = service; setFieldValue(ServiceRecord.class, record, "connections", new ArrayMap>()); - service.startService(record); + service.mServices.startService(record); doCallRealMethod().when(record).getConnections(); } AppBindRecord binding = new AppBindRecord(record, null, client); @@ -1840,7 +1833,7 @@ public class MockingOomAdjusterTests { doCallRealMethod().when(record).addConnection(any(IBinder.class), any(ConnectionRecord.class)); record.addConnection(binder, cr); - client.connections.add(cr); + client.mServices.addConnection(cr); binding.connections.add(cr); doNothing().when(cr).trackProcState(anyInt(), anyInt(), anyLong()); return record; @@ -1850,7 +1843,7 @@ public class MockingOomAdjusterTests { ContentProviderRecord record, String name, boolean hasExternalProviders) { if (record == null) { record = mock(ContentProviderRecord.class); - publisher.pubProviders.put(name, record); + publisher.mProviders.installProvider(name, record); record.proc = publisher; setFieldValue(ContentProviderRecord.class, record, "connections", new ArrayList()); @@ -1859,22 +1852,24 @@ public class MockingOomAdjusterTests { ContentProviderConnection conn = spy(new ContentProviderConnection(record, client, client.info.packageName)); record.connections.add(conn); - client.conProviders.add(conn); + client.mProviders.addProviderConnection(conn); return record; } private void assertProcStates(ProcessRecord app, int expectedProcState, int expectedAdj, int expectedSchedGroup) { - assertEquals(expectedProcState, app.setProcState); - assertEquals(expectedAdj, app.setAdj); - assertEquals(expectedSchedGroup, app.setSchedGroup); + final ProcessStateRecord state = app.mState; + assertEquals(expectedProcState, state.getSetProcState()); + assertEquals(expectedAdj, state.getSetAdj()); + assertEquals(expectedSchedGroup, state.getSetSchedGroup()); } private void assertProcStates(ProcessRecord app, boolean expectedCached, int expectedProcState, int expectedAdj, String expectedAdjType) { - assertEquals(expectedCached, app.isCached()); - assertEquals(expectedProcState, app.setProcState); - assertEquals(expectedAdj, app.setAdj); - assertEquals(expectedAdjType, app.adjType); + final ProcessStateRecord state = app.mState; + assertEquals(expectedCached, state.isCached()); + assertEquals(expectedProcState, state.getSetProcState()); + assertEquals(expectedAdj, state.getSetAdj()); + assertEquals(expectedAdjType, state.getAdjType()); } } diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityManagerInternalTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityManagerInternalTest.java index 3b4699e70aecf..8c21a39c20d1e 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityManagerInternalTest.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityManagerInternalTest.java @@ -134,7 +134,7 @@ public class ActivityManagerInternalTest { private UidRecord addActiveUidRecord(int uid, long curProcStateSeq, long lastNetworkUpdatedProcStateSeq) { - final UidRecord record = new UidRecord(uid); + final UidRecord record = new UidRecord(uid, mAms); record.lastNetworkUpdatedProcStateSeq = lastNetworkUpdatedProcStateSeq; record.curProcStateSeq = curProcStateSeq; record.waitingForNetwork = true; diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java index e119d52daa6c2..f31400853060d 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java @@ -273,7 +273,7 @@ public class ActivityManagerServiceTest { } private UidRecord addUidRecord(int uid) { - final UidRecord uidRec = new UidRecord(uid); + final UidRecord uidRec = new UidRecord(uid, mAms); uidRec.waitingForNetwork = true; uidRec.hasInternetPermission = true; mAms.mProcessList.mActiveUids.put(uid, uidRec); @@ -282,8 +282,9 @@ public class ActivityManagerServiceTest { info.packageName = ""; final ProcessRecord appRec = new ProcessRecord(mAms, info, TAG, uid); - appRec.thread = mock(IApplicationThread.class); - mAms.mProcessList.mLruProcesses.add(appRec); + final ProcessStatsService tracker = new ProcessStatsService(mAms, mContext.getCacheDir()); + appRec.makeActive(mock(IApplicationThread.class), tracker); + mAms.mProcessList.getLruProcessesLSP().add(appRec); return uidRec; } @@ -295,23 +296,23 @@ public class ActivityManagerServiceTest { CustomThread thread = new CustomThread(uidRec.networkStateLock); thread.startAndWait("Unexpected state for " + uidRec); - uidRec.setProcState = prevState; + uidRec.setSetProcState(prevState); uidRec.setCurProcState(curState); - mAms.mProcessList.incrementProcStateSeqAndNotifyAppsLocked(mAms.mProcessList.mActiveUids); + mAms.mProcessList.incrementProcStateSeqAndNotifyAppsLOSP(mAms.mProcessList.mActiveUids); // @SuppressWarnings("GuardedBy") assertEquals(expectedGlobalCounter, mAms.mProcessList.mProcStateSeqCounter); assertEquals(expectedCurProcStateSeq, uidRec.curProcStateSeq); - for (int i = mAms.mProcessList.getLruSizeLocked() - 1; i >= 0; --i) { - final ProcessRecord app = mAms.mProcessList.mLruProcesses.get(i); + for (int i = mAms.mProcessList.getLruSizeLOSP() - 1; i >= 0; --i) { + final ProcessRecord app = mAms.mProcessList.getLruProcessesLOSP().get(i); // AMS should notify apps only for block states other than NETWORK_STATE_NO_CHANGE. - if (app.uid == uidRec.uid && expectedBlockState == NETWORK_STATE_BLOCK) { - verify(app.thread).setNetworkBlockSeq(uidRec.curProcStateSeq); + if (app.uid == uidRec.getUid() && expectedBlockState == NETWORK_STATE_BLOCK) { + verify(app.getThread()).setNetworkBlockSeq(uidRec.curProcStateSeq); } else { - verifyZeroInteractions(app.thread); + verifyZeroInteractions(app.getThread()); } - Mockito.reset(app.thread); + Mockito.reset(app.getThread()); } if (expectNotify) { @@ -446,55 +447,56 @@ public class ActivityManagerServiceTest { @Test public void testBlockStateForUid() { - final UidRecord uidRec = new UidRecord(TEST_UID); + final UidRecord uidRec = new UidRecord(TEST_UID, mAms); int expectedBlockState; final String errorTemplate = "Block state should be %s, prevState: %s, curState: %s"; Function errorMsg = (blockState) -> { return String.format(errorTemplate, valueToString(ActivityManagerService.class, "NETWORK_STATE_", blockState), - valueToString(ActivityManager.class, "PROCESS_STATE_", uidRec.setProcState), + valueToString(ActivityManager.class, "PROCESS_STATE_", + uidRec.getSetProcState()), valueToString(ActivityManager.class, "PROCESS_STATE_", uidRec.getCurProcState()) ); }; // No change in uid state - uidRec.setProcState = PROCESS_STATE_RECEIVER; + uidRec.setSetProcState(PROCESS_STATE_RECEIVER); uidRec.setCurProcState(PROCESS_STATE_RECEIVER); expectedBlockState = NETWORK_STATE_NO_CHANGE; assertEquals(errorMsg.apply(expectedBlockState), expectedBlockState, mAms.mProcessList.getBlockStateForUid(uidRec)); // Foreground to foreground - uidRec.setProcState = PROCESS_STATE_FOREGROUND_SERVICE; + uidRec.setSetProcState(PROCESS_STATE_FOREGROUND_SERVICE); uidRec.setCurProcState(PROCESS_STATE_BOUND_FOREGROUND_SERVICE); expectedBlockState = NETWORK_STATE_NO_CHANGE; assertEquals(errorMsg.apply(expectedBlockState), expectedBlockState, mAms.mProcessList.getBlockStateForUid(uidRec)); // Background to background - uidRec.setProcState = PROCESS_STATE_CACHED_ACTIVITY; + uidRec.setSetProcState(PROCESS_STATE_CACHED_ACTIVITY); uidRec.setCurProcState(PROCESS_STATE_CACHED_EMPTY); expectedBlockState = NETWORK_STATE_NO_CHANGE; assertEquals(errorMsg.apply(expectedBlockState), expectedBlockState, mAms.mProcessList.getBlockStateForUid(uidRec)); // Background to background - uidRec.setProcState = PROCESS_STATE_NONEXISTENT; + uidRec.setSetProcState(PROCESS_STATE_NONEXISTENT); uidRec.setCurProcState(PROCESS_STATE_CACHED_ACTIVITY); expectedBlockState = NETWORK_STATE_NO_CHANGE; assertEquals(errorMsg.apply(expectedBlockState), expectedBlockState, mAms.mProcessList.getBlockStateForUid(uidRec)); // Background to foreground - uidRec.setProcState = PROCESS_STATE_SERVICE; + uidRec.setSetProcState(PROCESS_STATE_SERVICE); uidRec.setCurProcState(PROCESS_STATE_FOREGROUND_SERVICE); expectedBlockState = NETWORK_STATE_BLOCK; assertEquals(errorMsg.apply(expectedBlockState), expectedBlockState, mAms.mProcessList.getBlockStateForUid(uidRec)); // Foreground to background - uidRec.setProcState = PROCESS_STATE_TOP; + uidRec.setSetProcState(PROCESS_STATE_TOP); uidRec.setCurProcState(PROCESS_STATE_LAST_ACTIVITY); expectedBlockState = NETWORK_STATE_UNBLOCK; assertEquals(errorMsg.apply(expectedBlockState), @@ -748,13 +750,13 @@ public class ActivityManagerServiceTest { item.procState, validateUidRecord.getCurProcState()); assertEquals("processState: " + item.procState + " setProcState: " + validateUidRecord.getCurProcState() + " should have been equal", - item.procState, validateUidRecord.setProcState); + item.procState, validateUidRecord.getSetProcState()); if (item.change == UidRecord.CHANGE_IDLE) { assertTrue("UidRecord.idle should be updated to true for CHANGE_IDLE", - validateUidRecord.idle); + validateUidRecord.isIdle()); } else if (item.change == UidRecord.CHANGE_ACTIVE) { assertFalse("UidRecord.idle should be updated to false for CHANGE_ACTIVE", - validateUidRecord.idle); + validateUidRecord.isIdle()); } } } @@ -779,7 +781,7 @@ public class ActivityManagerServiceTest { @Test public void testEnqueueUidChangeLocked_procStateSeqUpdated() { - final UidRecord uidRecord = new UidRecord(TEST_UID); + final UidRecord uidRecord = new UidRecord(TEST_UID, mAms); uidRecord.curProcStateSeq = TEST_PROC_STATE_SEQ1; // Verify with no pending changes for TEST_UID. @@ -823,9 +825,9 @@ public class ActivityManagerServiceTest { @MediumTest @Test public void testEnqueueUidChangeLocked_dispatchUidsChanged() { - final UidRecord uidRecord = new UidRecord(TEST_UID); + final UidRecord uidRecord = new UidRecord(TEST_UID, mAms); final int expectedProcState = PROCESS_STATE_SERVICE; - uidRecord.setProcState = expectedProcState; + uidRecord.setSetProcState(expectedProcState); uidRecord.curProcStateSeq = TEST_PROC_STATE_SEQ1; // Test with no pending uid records. @@ -895,7 +897,7 @@ public class ActivityManagerServiceTest { private void verifyWaitingForNetworkStateUpdate(long curProcStateSeq, long lastDispatchedProcStateSeq, long lastNetworkUpdatedProcStateSeq, final long procStateSeqToWait, boolean expectWait) throws Exception { - final UidRecord record = new UidRecord(Process.myUid()); + final UidRecord record = new UidRecord(Process.myUid(), mAms); record.curProcStateSeq = curProcStateSeq; record.lastDispatchedProcStateSeq = lastDispatchedProcStateSeq; record.lastNetworkUpdatedProcStateSeq = lastNetworkUpdatedProcStateSeq; diff --git a/services/tests/servicestests/src/com/android/server/am/AnrHelperTest.java b/services/tests/servicestests/src/com/android/server/am/AnrHelperTest.java index 52c824a020edc..432f6d6c85a57 100644 --- a/services/tests/servicestests/src/com/android/server/am/AnrHelperTest.java +++ b/services/tests/servicestests/src/com/android/server/am/AnrHelperTest.java @@ -33,6 +33,8 @@ import com.android.server.wm.WindowProcessController; import org.junit.Before; import org.junit.Test; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; import java.util.concurrent.TimeUnit; /** @@ -48,7 +50,26 @@ public class AnrHelperTest { @Before public void setUp() { - runWithDexmakerShareClassLoader(() -> mAnrApp = mock(ProcessRecord.class)); + runWithDexmakerShareClassLoader(() -> { + mAnrApp = mock(ProcessRecord.class); + final ActivityManagerService service = mock(ActivityManagerService.class); + final ProcessErrorStateRecord errorState = mock(ProcessErrorStateRecord.class); + setFieldValue(ProcessErrorStateRecord.class, errorState, "mProcLock", + new ActivityManagerProcLock()); + setFieldValue(ProcessRecord.class, mAnrApp, "mErrorState", errorState); + }); + } + + private static void setFieldValue(Class clazz, Object obj, String fieldName, T val) { + try { + Field field = clazz.getDeclaredField(fieldName); + field.setAccessible(true); + Field mfield = Field.class.getDeclaredField("accessFlags"); + mfield.setAccessible(true); + mfield.setInt(field, mfield.getInt(field) & ~(Modifier.FINAL | Modifier.PRIVATE)); + field.set(obj, val); + } catch (NoSuchFieldException | IllegalAccessException e) { + } } @Test @@ -62,7 +83,7 @@ public class AnrHelperTest { mAnrHelper.appNotResponding(mAnrApp, activityShortComponentName, appInfo, parentShortComponentName, parentProcess, aboveSystem, annotation); - verify(mAnrApp, timeout(TimeUnit.SECONDS.toMillis(5))).appNotResponding( + verify(mAnrApp.mErrorState, timeout(TimeUnit.SECONDS.toMillis(5))).appNotResponding( eq(activityShortComponentName), eq(appInfo), eq(parentShortComponentName), eq(parentProcess), eq(aboveSystem), eq(annotation), eq(false) /* onlyDumpSelf */); } diff --git a/services/tests/servicestests/src/com/android/server/am/OomAdjusterTests.java b/services/tests/servicestests/src/com/android/server/am/OomAdjusterTests.java index 7355b80940a4a..638b1b4c57c46 100644 --- a/services/tests/servicestests/src/com/android/server/am/OomAdjusterTests.java +++ b/services/tests/servicestests/src/com/android/server/am/OomAdjusterTests.java @@ -77,6 +77,8 @@ public class OomAdjusterTests { sService.mActivityTaskManager.initialize(null, null, sContext.getMainLooper()); sService.mAtmInternal = sService.mActivityTaskManager.getAtmInternal(); + setFieldValue(ActivityManagerService.class, sService, "mProcLock", + new ActivityManagerProcLock()); sService.mConstants = new ActivityManagerConstants(sContext, sService, sContext.getMainThreadHandler()); final AppProfiler profiler = mock(AppProfiler.class); @@ -124,7 +126,7 @@ public class OomAdjusterTests { @Test public void testMaybeUpdateUsageStats_ProcStatePersistentUI() { final long elapsedTime = ZERO; - mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_PERSISTENT_UI); + mProcessRecord.mState.setCurProcState(ActivityManager.PROCESS_STATE_PERSISTENT_UI); sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime); assertProcessRecordState(ZERO, true, elapsedTime); @@ -133,7 +135,7 @@ public class OomAdjusterTests { @Test public void testMaybeUpdateUsageStats_ProcStateTop() { final long elapsedTime = ZERO; - mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_TOP); + mProcessRecord.mState.setCurProcState(ActivityManager.PROCESS_STATE_TOP); sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime); assertProcessRecordState(ZERO, true, elapsedTime); @@ -142,8 +144,8 @@ public class OomAdjusterTests { @Test public void testMaybeUpdateUsageStats_ProcStateTop_PreviousInteraction() { final long elapsedTime = ZERO; - mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_TOP); - mProcessRecord.reportedInteraction = true; + mProcessRecord.mState.setCurProcState(ActivityManager.PROCESS_STATE_TOP); + mProcessRecord.mState.setReportedInteraction(true); sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime); assertProcessRecordState(ZERO, true, ZERO); @@ -152,8 +154,8 @@ public class OomAdjusterTests { @Test public void testMaybeUpdateUsageStats_ProcStateTop_PastUsageInterval() { final long elapsedTime = 3 * USAGE_STATS_INTERACTION; - mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_TOP); - mProcessRecord.reportedInteraction = true; + mProcessRecord.mState.setCurProcState(ActivityManager.PROCESS_STATE_TOP); + mProcessRecord.mState.setReportedInteraction(true); sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime); assertProcessRecordState(ZERO, true, elapsedTime); @@ -162,7 +164,7 @@ public class OomAdjusterTests { @Test public void testMaybeUpdateUsageStats_ProcStateBoundTop() { final long elapsedTime = ZERO; - mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_BOUND_TOP); + mProcessRecord.mState.setCurProcState(ActivityManager.PROCESS_STATE_BOUND_TOP); sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime); assertProcessRecordState(ZERO, true, elapsedTime); @@ -171,7 +173,7 @@ public class OomAdjusterTests { @Test public void testMaybeUpdateUsageStats_ProcStateFGS() { final long elapsedTime = ZERO; - mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE); + mProcessRecord.mState.setCurProcState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE); sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime); assertProcessRecordState(elapsedTime, false, ZERO); @@ -181,8 +183,8 @@ public class OomAdjusterTests { public void testMaybeUpdateUsageStats_ProcStateFGS_ShortInteraction() { final long elapsedTime = ZERO; final long fgInteractionTime = 1000L; - mProcessRecord.setFgInteractionTime(fgInteractionTime); - mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE); + mProcessRecord.mState.setFgInteractionTime(fgInteractionTime); + mProcessRecord.mState.setCurProcState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE); sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime); assertProcessRecordState(fgInteractionTime, false, ZERO); @@ -192,8 +194,8 @@ public class OomAdjusterTests { public void testMaybeUpdateUsageStats_ProcStateFGS_LongInteraction() { final long elapsedTime = 2 * SERVICE_USAGE_INTERACTION; final long fgInteractionTime = 1000L; - mProcessRecord.setFgInteractionTime(fgInteractionTime); - mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE); + mProcessRecord.mState.setFgInteractionTime(fgInteractionTime); + mProcessRecord.mState.setCurProcState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE); sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime); assertProcessRecordState(fgInteractionTime, true, elapsedTime); @@ -203,9 +205,9 @@ public class OomAdjusterTests { public void testMaybeUpdateUsageStats_ProcStateFGS_PreviousLongInteraction() { final long elapsedTime = 2 * SERVICE_USAGE_INTERACTION; final long fgInteractionTime = 1000L; - mProcessRecord.setFgInteractionTime(fgInteractionTime); - mProcessRecord.reportedInteraction = true; - mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE); + mProcessRecord.mState.setFgInteractionTime(fgInteractionTime); + mProcessRecord.mState.setReportedInteraction(true); + mProcessRecord.mState.setCurProcState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE); sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime); assertProcessRecordState(fgInteractionTime, true, ZERO); @@ -214,7 +216,7 @@ public class OomAdjusterTests { @Test public void testMaybeUpdateUsageStats_ProcStateFGSLocation() { final long elapsedTime = ZERO; - mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE); + mProcessRecord.mState.setCurProcState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE); sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime); assertProcessRecordState(elapsedTime, false, ZERO); @@ -223,7 +225,8 @@ public class OomAdjusterTests { @Test public void testMaybeUpdateUsageStats_ProcStateBFGS() { final long elapsedTime = ZERO; - mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE); + mProcessRecord.mState.setCurProcState( + ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE); sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime); assertProcessRecordState(ZERO, true, elapsedTime); @@ -232,7 +235,7 @@ public class OomAdjusterTests { @Test public void testMaybeUpdateUsageStats_ProcStateImportantFG() { final long elapsedTime = ZERO; - mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND); + mProcessRecord.mState.setCurProcState(ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND); sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime); assertProcessRecordState(ZERO, true, elapsedTime); @@ -241,8 +244,8 @@ public class OomAdjusterTests { @Test public void testMaybeUpdateUsageStats_ProcStateImportantFG_PreviousInteraction() { final long elapsedTime = ZERO; - mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND); - mProcessRecord.reportedInteraction = true; + mProcessRecord.mState.setCurProcState(ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND); + mProcessRecord.mState.setReportedInteraction(true); sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime); assertProcessRecordState(ZERO, true, ZERO); @@ -251,8 +254,8 @@ public class OomAdjusterTests { @Test public void testMaybeUpdateUsageStats_ProcStateImportantFG_PastUsageInterval() { final long elapsedTime = 3 * USAGE_STATS_INTERACTION; - mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND); - mProcessRecord.reportedInteraction = true; + mProcessRecord.mState.setCurProcState(ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND); + mProcessRecord.mState.setReportedInteraction(true); sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime); assertProcessRecordState(ZERO, true, elapsedTime); @@ -261,7 +264,7 @@ public class OomAdjusterTests { @Test public void testMaybeUpdateUsageStats_ProcStateImportantBG() { final long elapsedTime = ZERO; - mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND); + mProcessRecord.mState.setCurProcState(ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND); sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime); assertProcessRecordState(ZERO, false, ZERO); @@ -270,7 +273,7 @@ public class OomAdjusterTests { @Test public void testMaybeUpdateUsageStats_ProcStateService() { final long elapsedTime = ZERO; - mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_SERVICE); + mProcessRecord.mState.setCurProcState(ActivityManager.PROCESS_STATE_SERVICE); sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime); assertProcessRecordState(ZERO, false, ZERO); @@ -279,10 +282,10 @@ public class OomAdjusterTests { private void assertProcessRecordState(long fgInteractionTime, boolean reportedInteraction, long interactionEventTime) { assertEquals("Foreground interaction time was not updated correctly.", - fgInteractionTime, mProcessRecord.getFgInteractionTime()); + fgInteractionTime, mProcessRecord.mState.getFgInteractionTime()); assertEquals("Interaction was not updated correctly.", - reportedInteraction, mProcessRecord.reportedInteraction); + reportedInteraction, mProcessRecord.mState.hasReportedInteraction()); assertEquals("Interaction event time was not updated correctly.", - interactionEventTime, mProcessRecord.getInteractionEventTime()); + interactionEventTime, mProcessRecord.mState.getInteractionEventTime()); } } diff --git a/services/tests/servicestests/src/com/android/server/am/ProcessRecordTests.java b/services/tests/servicestests/src/com/android/server/am/ProcessRecordTests.java index 263efa670a674..6538a17cf46ab 100644 --- a/services/tests/servicestests/src/com/android/server/am/ProcessRecordTests.java +++ b/services/tests/servicestests/src/com/android/server/am/ProcessRecordTests.java @@ -44,7 +44,6 @@ import org.junit.Test; import java.lang.reflect.Field; import java.lang.reflect.Modifier; -import java.util.Collections; /** * Build/Install/Run: @@ -57,6 +56,7 @@ public class ProcessRecordTests { private static ActivityManagerService sService; private ProcessRecord mProcessRecord; + private ProcessErrorStateRecord mProcessErrorState; @BeforeClass public static void setUpOnce() throws Exception { @@ -72,6 +72,8 @@ public class ProcessRecordTests { final AppProfiler profiler = mock(AppProfiler.class); setFieldValue(AppProfiler.class, profiler, "mProfilerLock", new Object()); setFieldValue(ActivityManagerService.class, sService, "mAppProfiler", profiler); + setFieldValue(ActivityManagerService.class, sService, "mProcLock", + new ActivityManagerProcLock()); final ProcessList processList = new ProcessList(); setFieldValue(ActivityManagerService.class, sService, "mProcessList", processList); }); @@ -104,12 +106,12 @@ public class ProcessRecordTests { public void setUpProcess() throws Exception { // Need to run with dexmaker share class loader to mock package private class. runWithDexmakerShareClassLoader(() -> { - mProcessRecord = spy(new ProcessRecord(sService, sContext.getApplicationInfo(), - "name", 12345)); - doNothing().when(mProcessRecord).startAppProblemLocked(); - doReturn(false).when(mProcessRecord).isSilentAnr(); - doReturn(false).when(mProcessRecord).isMonitorCpuUsage(); - doReturn(Collections.emptyList()).when(mProcessRecord).getLruProcessList(); + mProcessRecord = new ProcessRecord(sService, sContext.getApplicationInfo(), + "name", 12345); + mProcessErrorState = spy(mProcessRecord.mErrorState); + doNothing().when(mProcessErrorState).startAppProblemLSP(); + doReturn(false).when(mProcessErrorState).isSilentAnr(); + doReturn(false).when(mProcessErrorState).isMonitorCpuUsage(); }); } @@ -120,10 +122,10 @@ public class ProcessRecordTests { */ @Test public void testProcessDefaultAnrRelatedStatus() { - assertFalse(mProcessRecord.isNotResponding()); - assertFalse(mProcessRecord.isCrashing()); - assertFalse(mProcessRecord.killedByAm); - assertFalse(mProcessRecord.killed); + assertFalse(mProcessErrorState.isNotResponding()); + assertFalse(mProcessErrorState.isCrashing()); + assertFalse(mProcessRecord.isKilledByAm()); + assertFalse(mProcessRecord.isKilled()); } /** @@ -131,12 +133,12 @@ public class ProcessRecordTests { */ @Test public void testAnrWhenCrash() { - mProcessRecord.setCrashing(true); - assertTrue(mProcessRecord.isCrashing()); - appNotResponding(mProcessRecord, "Test ANR when crash"); - assertFalse(mProcessRecord.isNotResponding()); - assertFalse(mProcessRecord.killedByAm); - assertFalse(mProcessRecord.killed); + mProcessErrorState.setCrashing(true); + assertTrue(mProcessErrorState.isCrashing()); + appNotResponding(mProcessErrorState, "Test ANR when crash"); + assertFalse(mProcessErrorState.isNotResponding()); + assertFalse(mProcessRecord.isKilledByAm()); + assertFalse(mProcessRecord.isKilled()); } /** @@ -144,11 +146,11 @@ public class ProcessRecordTests { */ @Test public void testAnrWhenKilledByAm() { - mProcessRecord.killedByAm = true; - appNotResponding(mProcessRecord, "Test ANR when killed by AM"); - assertFalse(mProcessRecord.isNotResponding()); - assertFalse(mProcessRecord.isCrashing()); - assertFalse(mProcessRecord.killed); + mProcessRecord.setKilledByAm(true); + appNotResponding(mProcessErrorState, "Test ANR when killed by AM"); + assertFalse(mProcessErrorState.isNotResponding()); + assertFalse(mProcessErrorState.isCrashing()); + assertFalse(mProcessRecord.isKilled()); } /** @@ -156,11 +158,11 @@ public class ProcessRecordTests { */ @Test public void testAnrWhenKilled() { - mProcessRecord.killed = true; - appNotResponding(mProcessRecord, "Test ANR when killed"); - assertFalse(mProcessRecord.isNotResponding()); - assertFalse(mProcessRecord.isCrashing()); - assertFalse(mProcessRecord.killedByAm); + mProcessRecord.setKilled(true); + appNotResponding(mProcessErrorState, "Test ANR when killed"); + assertFalse(mProcessErrorState.isNotResponding()); + assertFalse(mProcessErrorState.isCrashing()); + assertFalse(mProcessRecord.isKilledByAm()); } /** @@ -169,11 +171,11 @@ public class ProcessRecordTests { */ @Test public void testNonSilentAnr() { - appNotResponding(mProcessRecord, "Test non-silent ANR"); - assertTrue(mProcessRecord.isNotResponding()); - assertFalse(mProcessRecord.isCrashing()); - assertFalse(mProcessRecord.killedByAm); - assertFalse(mProcessRecord.killed); + appNotResponding(mProcessErrorState, "Test non-silent ANR"); + assertTrue(mProcessErrorState.isNotResponding()); + assertFalse(mProcessErrorState.isCrashing()); + assertFalse(mProcessRecord.isKilledByAm()); + assertFalse(mProcessRecord.isKilled()); } /** @@ -183,16 +185,17 @@ public class ProcessRecordTests { @Test public void testSilentAnr() { // Silent Anr will run through even without a parent process, and directly killed by AM. - doReturn(true).when(mProcessRecord).isSilentAnr(); - appNotResponding(mProcessRecord, "Test silent ANR"); - assertTrue(mProcessRecord.isNotResponding()); - assertFalse(mProcessRecord.isCrashing()); - assertTrue(mProcessRecord.killedByAm); - assertTrue(mProcessRecord.killed); + doReturn(true).when(mProcessErrorState).isSilentAnr(); + appNotResponding(mProcessErrorState, "Test silent ANR"); + assertTrue(mProcessErrorState.isNotResponding()); + assertFalse(mProcessErrorState.isCrashing()); + assertTrue(mProcessRecord.isKilledByAm()); + assertTrue(mProcessRecord.isKilled()); } - private static void appNotResponding(ProcessRecord processRecord, String annotation) { - processRecord.appNotResponding(null /* activityShortComponentName */, null /* aInfo */, + private static void appNotResponding(ProcessErrorStateRecord processErrorState, + String annotation) { + processErrorState.appNotResponding(null /* activityShortComponentName */, null /* aInfo */, null /* parentShortComponentName */, null /* parentProcess */, false /* aboveSystem */, annotation, false /* onlyDumpSelf */); }