From cfeb2866a4854263e44210260ff09930aa7f7de0 Mon Sep 17 00:00:00 2001 From: Jing Ji Date: Fri, 15 Jan 2021 22:59:12 -0800 Subject: [PATCH] Add an additional lock in the ActivityManagerService This CL breaks down the ProcessRecord by the characteristic of the fields in it. It's a preparation for future CLs, to let the various components in the ActivityManagerService to access its own correlated data class only. Also introduces an additional semi-global lock in the ActivityManagerService as an effort to reduce the lock contentions. Some of the data fields now requires either the legacy global lock or this new lock to read from it, and both of the lock to write to it. Bug: 162450085 Test: atest CtsAppTestCases Test: atest FrameworksMockingServicesTests Test: atest FrameworksServicesTests Change-Id: I2718dfb8cd5c1852e81280ed11676c567f76d0a2 --- .../internal/annotations/CompositeRWLock.java | 47 + .../internal/annotations/GuardedBy.java | 32 +- services/core/Android.bp | 6 +- .../java/com/android/server/LockGuard.java | 8 +- .../com/android/server/am/ActiveServices.java | 488 ++-- .../com/android/server/am/ActiveUids.java | 38 +- .../server/am/ActivityManagerGlobalLock.java | 24 + .../server/am/ActivityManagerProcLock.java | 28 + .../server/am/ActivityManagerService.java | 2007 +++++++------- .../java/com/android/server/am/AnrHelper.java | 2 +- .../com/android/server/am/AppErrorDialog.java | 10 +- .../java/com/android/server/am/AppErrors.java | 522 ++-- .../android/server/am/AppExitInfoTracker.java | 12 +- .../server/am/AppNotRespondingDialog.java | 15 +- .../com/android/server/am/AppProfiler.java | 178 +- .../com/android/server/am/BroadcastQueue.java | 85 +- .../com/android/server/am/CacheOomRanker.java | 20 +- .../android/server/am/CachedAppOptimizer.java | 220 +- .../server/am/ContentProviderHelper.java | 133 +- .../server/am/ContentProviderRecord.java | 12 +- .../server/am/ErrorDialogController.java | 251 ++ .../server/am/NativeCrashListener.java | 14 +- .../com/android/server/am/OomAdjuster.java | 1237 +++++---- .../com/android/server/am/PackageList.java | 18 +- .../android/server/am/PhantomProcessList.java | 98 +- .../am/ProcessCachedOptimizerRecord.java | 157 ++ .../server/am/ProcessErrorStateRecord.java | 555 ++++ .../com/android/server/am/ProcessList.java | 1062 +++++--- .../server/am/ProcessProfileRecord.java | 32 +- .../server/am/ProcessProviderRecord.java | 175 ++ .../server/am/ProcessReceiverRecord.java | 106 + .../com/android/server/am/ProcessRecord.java | 2335 +++++------------ .../server/am/ProcessServiceRecord.java | 444 ++++ .../android/server/am/ProcessStateRecord.java | 1337 ++++++++++ .../server/am/ProcessStatsService.java | 4 +- .../com/android/server/am/ProviderMap.java | 22 +- .../com/android/server/am/ServiceRecord.java | 53 +- .../server/am/StrictModeViolationDialog.java | 8 +- .../server/am/UidObserverController.java | 12 +- .../java/com/android/server/am/UidRecord.java | 263 +- .../server/am/AppChildProcessTest.java | 4 +- .../server/am/ApplicationExitInfoTest.java | 12 +- .../android/server/am/CacheOomRankerTest.java | 38 +- .../server/am/CachedAppOptimizerTest.java | 12 +- .../server/am/MockingOomAdjusterTests.java | 399 ++- .../am/ActivityManagerInternalTest.java | 2 +- .../server/am/ActivityManagerServiceTest.java | 54 +- .../com/android/server/am/AnrHelperTest.java | 25 +- .../android/server/am/OomAdjusterTests.java | 57 +- .../android/server/am/ProcessRecordTests.java | 83 +- 50 files changed, 7892 insertions(+), 4864 deletions(-) create mode 100644 core/java/com/android/internal/annotations/CompositeRWLock.java create mode 100644 services/core/java/com/android/server/am/ActivityManagerGlobalLock.java create mode 100644 services/core/java/com/android/server/am/ActivityManagerProcLock.java create mode 100644 services/core/java/com/android/server/am/ErrorDialogController.java create mode 100644 services/core/java/com/android/server/am/ProcessCachedOptimizerRecord.java create mode 100644 services/core/java/com/android/server/am/ProcessErrorStateRecord.java create mode 100644 services/core/java/com/android/server/am/ProcessProviderRecord.java create mode 100644 services/core/java/com/android/server/am/ProcessReceiverRecord.java create mode 100644 services/core/java/com/android/server/am/ProcessServiceRecord.java create mode 100644 services/core/java/com/android/server/am/ProcessStateRecord.java 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 cdf5c9851f48c..a4d098e4af162 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; @@ -294,6 +294,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; @@ -396,7 +397,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. @@ -416,7 +417,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; @@ -527,12 +527,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; @@ -548,7 +591,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) { @@ -569,10 +615,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. @@ -643,6 +690,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. */ @@ -663,20 +729,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. @@ -754,24 +823,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); } } @@ -782,18 +851,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()); } /** @@ -801,16 +872,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); } } @@ -819,16 +891,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; } @@ -865,6 +939,7 @@ public class ActivityManagerService extends IActivityManager.Stub proto.end(pToken); } } + @GuardedBy("this") final SparseArray mImportantProcesses = new SparseArray(); /** @@ -872,12 +947,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 = @@ -925,6 +1002,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<>(); /** @@ -977,6 +1055,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>>(); @@ -1016,6 +1095,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; @@ -1067,16 +1147,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 { @@ -1102,11 +1185,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(); /** @@ -1122,11 +1207,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; @@ -1147,6 +1227,7 @@ public class ActivityManagerService extends IActivityManager.Stub /** * Last time (in uptime) at which we checked for power usage. */ + @GuardedBy("mProcLock") long mLastPowerCheckUptime; /** @@ -1162,10 +1243,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; @@ -1183,22 +1268,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; @@ -1343,10 +1444,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); @@ -1368,6 +1471,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; @@ -1405,19 +1509,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". @@ -1427,15 +1531,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; @@ -1486,23 +1590,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: { @@ -1557,8 +1661,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; } @@ -1566,19 +1670,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; @@ -1600,8 +1706,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: { @@ -1641,12 +1747,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) { @@ -2296,16 +2402,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()); } } } @@ -2357,10 +2465,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); } } @@ -2455,21 +2561,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) { @@ -2552,7 +2662,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)) { @@ -2626,19 +2736,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 @@ -2648,11 +2757,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) { @@ -2660,12 +2770,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; } } @@ -2822,10 +2934,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); @@ -2845,24 +2956,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; @@ -2875,7 +2988,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") @@ -2892,26 +3005,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 @@ -2919,11 +3037,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); @@ -2931,14 +3048,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()); @@ -3386,9 +3503,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 { @@ -3413,11 +3532,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); } @@ -3448,7 +3569,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); @@ -3523,11 +3646,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); } } } @@ -3587,12 +3713,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); + } } } @@ -3687,10 +3815,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)) { @@ -3739,9 +3867,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. } @@ -3903,6 +4032,7 @@ public class ActivityManagerService extends IActivityManager.Stub } } + boolean didSomething; if (doit) { if (packageName != null) { Slog.i(TAG, "Force stopping " + packageName + " appid=" + appId @@ -3914,20 +4044,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)) { @@ -3986,26 +4118,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 @@ -4043,7 +4178,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) { @@ -4053,14 +4188,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 { @@ -4071,10 +4206,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; } } @@ -4100,8 +4235,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. @@ -4114,7 +4249,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, @@ -4123,23 +4258,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); @@ -4179,9 +4316,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 @@ -4202,7 +4341,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); @@ -4246,10 +4385,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, @@ -4259,20 +4399,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(); @@ -4281,9 +4421,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) { @@ -4295,8 +4437,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; } @@ -4359,8 +4502,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; } @@ -4372,14 +4516,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; } @@ -4472,11 +4616,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); @@ -4508,8 +4652,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); } } @@ -4944,7 +5088,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); @@ -4970,7 +5114,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; } @@ -4984,7 +5128,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 @@ -5000,13 +5144,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; } } @@ -5017,11 +5160,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 // ========================================================= @@ -5070,20 +5218,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; + } } } } @@ -5261,8 +5412,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; } } @@ -5273,7 +5424,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) { @@ -5302,7 +5454,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"); @@ -5320,7 +5472,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) { @@ -5331,7 +5484,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"); @@ -5340,7 +5493,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"); @@ -5349,25 +5502,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) { @@ -5382,14 +5536,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" @@ -5400,8 +5554,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; @@ -5417,7 +5571,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 @@ -5429,7 +5584,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); } @@ -5438,7 +5594,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; } @@ -5483,8 +5640,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 @@ -5517,8 +5674,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 @@ -5549,9 +5706,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(); @@ -5850,7 +6006,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++) { @@ -5894,11 +6051,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; + } } } @@ -5924,8 +6083,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); } @@ -5941,9 +6100,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), @@ -6014,7 +6173,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; @@ -6141,13 +6300,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; } } @@ -6204,7 +6363,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); @@ -6223,7 +6382,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(); } @@ -6444,8 +6603,8 @@ public class ActivityManagerService extends IActivityManager.Stub "getUidProcessState"); } - synchronized (this) { - return mProcessList.getUidProcStateLocked(uid); + synchronized (mProcLock) { + return mProcessList.getUidProcStateLOSP(uid); } } @@ -6471,17 +6630,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 @@ -6539,7 +6699,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()) { @@ -6548,33 +6708,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); + } } } } @@ -6630,11 +6789,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; } } @@ -6814,42 +6973,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; + } + } } } } @@ -6862,13 +7025,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); } @@ -6881,13 +7046,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); } @@ -6909,17 +7076,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; + } + } } } } @@ -7025,16 +7197,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 "); @@ -7051,13 +7223,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(); @@ -7065,39 +7237,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); } } - } + }); } } @@ -7208,7 +7384,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, @@ -7435,16 +7611,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(); + } } } } @@ -7509,7 +7687,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 @@ -7755,8 +7933,8 @@ public class ActivityManagerService extends IActivityManager.Stub return null; } - synchronized (this) { - return mProcessList.findAppProcessLocked(app, reason); + synchronized (mProcLock) { + return mProcessList.findAppProcessLOSP(app, reason); } } @@ -7765,7 +7943,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 @@ -7779,17 +7957,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) { @@ -7808,7 +7987,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"; @@ -7870,8 +8049,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"); } } @@ -7879,7 +8058,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)) { @@ -7975,47 +8154,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 @@ -8031,9 +8209,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); } } @@ -8144,13 +8322,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); } } } @@ -8196,7 +8374,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) { @@ -8328,7 +8508,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("-------------------------------------------------------------------------------"); @@ -8432,7 +8614,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 @@ -8451,7 +8635,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); } } @@ -8525,8 +8711,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) { @@ -8614,6 +8802,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); } @@ -8863,8 +9053,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<>(); @@ -8872,7 +9062,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; } @@ -8883,7 +9073,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)); } } @@ -8923,8 +9113,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; @@ -8965,7 +9154,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()); @@ -9060,7 +9249,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(); @@ -9077,8 +9266,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); @@ -9095,7 +9284,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; } @@ -9594,8 +9782,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); } } @@ -9614,13 +9802,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(); @@ -9647,13 +9837,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(); @@ -9680,13 +9872,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(); @@ -10149,10 +10343,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) { @@ -10223,8 +10417,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); @@ -10734,10 +10928,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) { @@ -10803,8 +10997,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); @@ -11143,96 +11337,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() { @@ -11249,9 +11373,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) { @@ -11259,13 +11383,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(); @@ -11285,7 +11409,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. @@ -11305,7 +11429,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 @@ -11313,14 +11437,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) { @@ -11659,12 +11782,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 @@ -11672,10 +11795,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) { @@ -11785,14 +11909,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:"); @@ -11887,7 +12012,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 @@ -11901,7 +12026,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(); @@ -11970,8 +12095,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; } @@ -11980,13 +12106,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); @@ -12072,7 +12198,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) { @@ -12371,7 +12497,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"); @@ -12578,12 +12704,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( @@ -12727,7 +12855,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(); } @@ -13112,7 +13240,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(); @@ -13352,27 +13480,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) { @@ -13399,7 +13529,7 @@ public class ActivityManagerService extends IActivityManager.Stub } try { - pr.thread.instrumentWithoutRestart( + pr.getThread().instrumentWithoutRestart( activeInstr.mClass, activeInstr.mArguments, activeInstr.mWatcher, @@ -13459,7 +13589,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; @@ -13481,36 +13611,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, @@ -13546,7 +13678,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; @@ -13652,10 +13784,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; } @@ -13774,6 +13907,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()) { @@ -13786,77 +13920,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) { @@ -13901,19 +14049,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; @@ -13922,7 +14071,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); } @@ -13945,21 +14094,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) { @@ -13985,9 +14134,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; } @@ -14030,7 +14179,6 @@ public class ActivityManagerService extends IActivityManager.Stub } finally { Binder.restoreCallingIdentity(identity); } - } } return r; @@ -14140,17 +14288,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); } } } @@ -14175,11 +14326,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". @@ -14233,7 +14384,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) @@ -14257,13 +14408,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); + } } } @@ -14273,7 +14426,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++) { @@ -14293,25 +14446,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) { @@ -14328,26 +14483,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()) { @@ -14368,7 +14525,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"); } @@ -14379,13 +14536,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); } - } + }); } } @@ -14404,21 +14560,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; @@ -14431,8 +14589,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); @@ -14454,7 +14612,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). @@ -14468,9 +14625,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); } @@ -14492,7 +14650,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; } @@ -14547,8 +14705,8 @@ public class ActivityManagerService extends IActivityManager.Stub } void onCoreSettingsChange(Bundle settings) { - synchronized (this) { - mProcessList.updateCoreSettingsLocked(settings); + synchronized (mProcLock) { + mProcessList.updateCoreSettingsLOSP(settings); } } @@ -14700,8 +14858,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; } @@ -14723,34 +14882,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"); } @@ -14758,9 +14919,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); @@ -14768,7 +14930,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(); @@ -14782,12 +14944,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) { @@ -14832,12 +14994,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); @@ -14845,19 +15007,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"); + } } } } @@ -14903,8 +15069,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; + } } } @@ -14912,13 +15080,15 @@ public class ActivityManagerService extends IActivityManager.Stub public void updateDeviceIdleTempWhitelist(int[] appids, int changingUid, boolean adding, long durationMs, @BroadcastOptions.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); } } @@ -14956,10 +15126,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); } @@ -14977,8 +15147,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 @@ -15041,19 +15211,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; @@ -15093,14 +15265,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"); } } } @@ -15122,18 +15294,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 @@ -15564,7 +15733,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(); } } @@ -15595,19 +15764,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 @@ -15622,7 +15789,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 @@ -15774,8 +15941,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; } @@ -15891,11 +16058,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); @@ -15912,10 +16081,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); } @@ -15934,12 +16103,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 @@ -15968,7 +16138,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); @@ -16005,7 +16175,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; @@ -16039,7 +16209,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; @@ -16085,10 +16255,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); } @@ -16098,7 +16269,7 @@ public class ActivityManagerService extends IActivityManager.Stub } } - proc.thread.attachAgent(path); + thread.attachAgent(path); } } catch (RemoteException e) { throw new IllegalStateException("Process disappeared"); @@ -16167,7 +16338,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)) { @@ -16213,7 +16384,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(); } @@ -16335,7 +16506,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 4de12183e4030..a9ac004773492 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; @@ -221,7 +222,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) { @@ -285,19 +286,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)). @@ -314,10 +317,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; @@ -327,7 +330,7 @@ public final class BroadcastQueue { "Process cur broadcast " + r + ": NOT STARTED!"); r.receiver = null; r.curApp = null; - app.curReceivers.remove(r); + prr.removeCurReceiver(r); } } } @@ -335,7 +338,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); @@ -362,7 +365,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; @@ -502,8 +505,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) { @@ -577,12 +580,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) { @@ -592,8 +597,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; } @@ -723,8 +728,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; @@ -793,7 +798,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); @@ -805,7 +810,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) { @@ -832,7 +837,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); } @@ -855,8 +860,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) { @@ -1017,16 +1022,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 @@ -1496,7 +1501,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"); @@ -1547,14 +1552,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 " @@ -1629,7 +1634,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); @@ -1664,13 +1669,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 */); }