Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c0fb1726 authored by Jing Ji's avatar Jing Ji
Browse files

Don't bother to kill large cached app if it's being launched

Previously for a large cached app, it could get killed by AM while
we're looking for its ProcessRecord, but it'll be unnecessary in case
it's being relaunched (i.e., start service).

Now disable the killing on large cached apps when the system is on
low memory pressure. A follow-up CL may reintroduce it by moving
the killing into different paths.

Bug: 174502269
Test: atest CtsAppTestCases
Change-Id: I38c9179bd1ce28c5cc584d73478b3c914e67ca79
parent b5b5aa24
Loading
Loading
Loading
Loading
+3 −5
Original line number Diff line number Diff line
@@ -20,7 +20,6 @@ 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_PERSISTENT;
import static android.app.ActivityManager.PROCESS_STATE_RECEIVER;
import static android.app.ActivityManager.PROCESS_STATE_TOP;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
@@ -75,7 +74,6 @@ import android.app.ActivityManagerInternal;
import android.app.ActivityThread;
import android.app.AppGlobals;
import android.app.AppOpsManager;
import android.app.BroadcastOptions;
import android.app.ForegroundServiceStartNotAllowedException;
import android.app.IApplicationThread;
import android.app.IServiceConnection;
@@ -799,7 +797,7 @@ public final class ActiveServices {
        boolean addToStarting = false;
        if (!callerFg && !fgRequired && r.app == null
                && mAm.mUserController.hasStartedUserState(r.userId)) {
            ProcessRecord proc = mAm.getProcessRecordLocked(r.processName, r.appInfo.uid, false);
            ProcessRecord proc = mAm.getProcessRecordLocked(r.processName, r.appInfo.uid);
            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
@@ -3348,7 +3346,7 @@ public final class ActiveServices {
        ProcessRecord app;

        if (!isolated) {
            app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
            app = mAm.getProcessRecordLocked(procName, r.appInfo.uid);
            if (DEBUG_MU) Slog.v(TAG_MU, "bringUpServiceLocked: appInfo.uid=" + r.appInfo.uid
                        + " app=" + app);
            if (app != null) {
@@ -3396,7 +3394,7 @@ public final class ActiveServices {
            // 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) {
                        hostingRecord, ZYGOTE_POLICY_FLAG_EMPTY, false, isolated)) == null) {
                String msg = "Unable to launch app "
                        + r.appInfo.packageName + "/"
                        + r.appInfo.uid + " for service "
+13 −16
Original line number Diff line number Diff line
@@ -50,7 +50,6 @@ import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_HIGH;
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
import static android.os.IServiceManager.DUMP_FLAG_PROTO;
import static android.os.PowerWhitelistManager.REASON_SYSTEM_ALLOW_LISTED;
import static android.os.PowerWhitelistManager.REASON_UNKNOWN;
import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
import static android.os.Process.BLUETOOTH_UID;
import static android.os.Process.FIRST_APPLICATION_UID;
@@ -92,6 +91,7 @@ import static android.text.format.DateUtils.DAY_IN_MILLIS;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALLOWLISTS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ANR;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BACKGROUND_CHECK;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BACKUP;
@@ -104,7 +104,6 @@ import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_OOM_ADJ;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_POWER;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESSES;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SERVICE;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALLOWLISTS;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_BACKUP;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_BROADCAST;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CLEANUP;
@@ -2596,8 +2595,8 @@ public class ActivityManagerService extends IActivityManager.Stub
    }
    @GuardedBy("this")
    final ProcessRecord getProcessRecordLocked(String processName, int uid, boolean keepIfLarge) {
        return mProcessList.getProcessRecordLocked(processName, uid, keepIfLarge);
    final ProcessRecord getProcessRecordLocked(String processName, int uid) {
        return mProcessList.getProcessRecordLocked(processName, uid);
    }
    @GuardedBy(anyOf = {"this", "mProcLock"})
@@ -2631,8 +2630,7 @@ public class ActivityManagerService extends IActivityManager.Stub
                    false /* knownToBeDead */, 0 /* intentFlags */,
                    sNullHostingRecord  /* hostingRecord */, ZYGOTE_POLICY_FLAG_EMPTY,
                    true /* allowWhileBooting */, true /* isolated */,
                    uid, true /* keepIfLarge */, abiOverride, entryPoint, entryPointArgs,
                    crashHandler);
                    uid, abiOverride, entryPoint, entryPointArgs, crashHandler);
            return proc != null;
        }
    }
@@ -2641,10 +2639,10 @@ public class ActivityManagerService extends IActivityManager.Stub
    final ProcessRecord startProcessLocked(String processName,
            ApplicationInfo info, boolean knownToBeDead, int intentFlags,
            HostingRecord hostingRecord, int zygotePolicyFlags, boolean allowWhileBooting,
            boolean isolated, boolean keepIfLarge) {
            boolean isolated) {
        return mProcessList.startProcessLocked(processName, info, knownToBeDead, intentFlags,
                hostingRecord, zygotePolicyFlags, allowWhileBooting, isolated, 0 /* isolatedUid */,
                keepIfLarge, null /* ABI override */, null /* entryPoint */,
                null /* ABI override */, null /* entryPoint */,
                null /* entryPointArgs */, null /* crashHandler */);
    }
@@ -3890,7 +3888,7 @@ public class ActivityManagerService extends IActivityManager.Stub
        // Only the system server can kill an application
        if (callerUid == SYSTEM_UID) {
            synchronized (this) {
                ProcessRecord app = getProcessRecordLocked(processName, uid, true);
                ProcessRecord app = getProcessRecordLocked(processName, uid);
                IApplicationThread thread;
                if (app != null && (thread = app.getThread()) != null) {
                    try {
@@ -6086,7 +6084,7 @@ public class ActivityManagerService extends IActivityManager.Stub
        ProcessRecord app;
        if (!isolated) {
            app = getProcessRecordLocked(customProcess != null ? customProcess : info.processName,
                    info.uid, true);
                    info.uid);
        } else {
            app = null;
        }
@@ -11877,7 +11875,7 @@ public class ActivityManagerService extends IActivityManager.Stub
            ProcessRecord proc = startProcessLocked(app.processName, app,
                    false, 0,
                    new HostingRecord("backup", hostingName),
                    ZYGOTE_POLICY_FLAG_SYSTEM_PROCESS, false, false, false);
                    ZYGOTE_POLICY_FLAG_SYSTEM_PROCESS, false, false);
            if (proc == null) {
                Slog.e(TAG, "Unable to start backup agent process " + r);
                return false;
@@ -13587,7 +13585,7 @@ public class ActivityManagerService extends IActivityManager.Stub
            ProcessRecord app;
            synchronized (mProcLock) {
                if (noRestart) {
                    app = getProcessRecordLocked(ai.processName, ai.uid, true);
                    app = getProcessRecordLocked(ai.processName, ai.uid);
                } else {
                    // Instrumentation can kill and relaunch even persistent processes
                    forceStopPackageLocked(ii.targetPackage, -1, true, false, true, true, false,
@@ -13630,7 +13628,7 @@ public class ActivityManagerService extends IActivityManager.Stub
            ApplicationInfo targetInfo) {
        ProcessRecord pr;
        synchronized (this) {
            pr = getProcessRecordLocked(targetInfo.processName, targetInfo.uid, true);
            pr = getProcessRecordLocked(targetInfo.processName, targetInfo.uid);
        }
        try {
@@ -15374,8 +15372,7 @@ public class ActivityManagerService extends IActivityManager.Stub
        @Override
        public void killProcess(String processName, int uid, String reason) {
            synchronized (ActivityManagerService.this) {
                final ProcessRecord proc = getProcessRecordLocked(processName, uid,
                        true /* keepIfLarge */);
                final ProcessRecord proc = getProcessRecordLocked(processName, uid);
                if (proc != null) {
                    mProcessList.removeProcessLocked(proc, false /* callerWillRestart */,
                            true /* allowRestart */,  ApplicationExitInfo.REASON_OTHER, reason);
@@ -15782,7 +15779,7 @@ public class ActivityManagerService extends IActivityManager.Stub
                    startProcessLocked(processName, info, knownToBeDead, 0 /* intentFlags */,
                            new HostingRecord(hostingType, hostingName, isTop),
                            ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE, false /* allowWhileBooting */,
                            false /* isolated */, true /* keepIfLarge */);
                            false /* isolated */);
                }
            } finally {
                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+2 −2
Original line number Diff line number Diff line
@@ -1558,7 +1558,7 @@ public final class BroadcastQueue {
        }
        String targetProcess = info.activityInfo.processName;
        ProcessRecord app = mService.getProcessRecordLocked(targetProcess,
                info.activityInfo.applicationInfo.uid, false);
                info.activityInfo.applicationInfo.uid);

        if (!skip) {
            final int allowed = mService.getAppStartModeLOSP(
@@ -1685,7 +1685,7 @@ public final class BroadcastQueue {
                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);
                (r.intent.getFlags() & Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false);
        if (r.curApp == null) {
            // Ah, this recipient is unavailable.  Finish it if necessary,
            // and mark the broadcast record as ready for the next.
+2 −2
Original line number Diff line number Diff line
@@ -428,7 +428,7 @@ public class ContentProviderHelper {
                        // Use existing process if already started
                        checkTime(startTime, "getContentProviderImpl: looking for process record");
                        ProcessRecord proc = mService.getProcessRecordLocked(
                                cpi.processName, cpr.appInfo.uid, false);
                                cpi.processName, cpr.appInfo.uid);
                        IApplicationThread thread;
                        if (proc != null && (thread = proc.getThread()) != null
                                && !proc.isKilled()) {
@@ -451,7 +451,7 @@ public class ContentProviderHelper {
                                    new HostingRecord("content provider",
                                        new ComponentName(
                                                cpi.applicationInfo.packageName, cpi.name)),
                                    Process.ZYGOTE_POLICY_FLAG_EMPTY, false, false, false);
                                    Process.ZYGOTE_POLICY_FLAG_EMPTY, false, false);
                            checkTime(startTime, "getContentProviderImpl: after start process");
                            if (proc == null) {
                                Slog.w(TAG, "Unable to launch app "
+6 −48
Original line number Diff line number Diff line
@@ -36,7 +36,6 @@ import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LRU;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_NETWORK;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESSES;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESS_OBSERVERS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PSS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_UID_OBSERVERS;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PROCESS_OBSERVERS;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
@@ -54,7 +53,6 @@ import static com.android.server.am.ActivityManagerService.TAG_LRU;
import static com.android.server.am.ActivityManagerService.TAG_NETWORK;
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;
@@ -1501,8 +1499,7 @@ public final class ProcessList {
    }

    @GuardedBy("mService")
    final ProcessRecord getProcessRecordLocked(String processName, int uid, boolean
            keepIfLarge) {
    ProcessRecord getProcessRecordLocked(String processName, int uid) {
        if (uid == SYSTEM_UID) {
            // The system gets to run in any process.  If there are multiple
            // processes with the same uid, just pick the first (this
@@ -1519,41 +1516,7 @@ public final class ProcessList {
                return procs.valueAt(i);
            }
        }
        ProcessRecord proc = mProcessNames.get(processName, uid);
        if (false && proc != null && !keepIfLarge
                && proc.mState.getSetProcState() >= ActivityManager.PROCESS_STATE_CACHED_EMPTY
                && proc.mProfile.getLastCachedPss() >= 4000) {
            // Turn this condition on to cause killing to happen regularly, for testing.
            synchronized (mService.mAppProfiler.mProfilerLock) {
                proc.mProfile.reportCachedKill();
            }
            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.mState.getSetProcState() >= ActivityManager.PROCESS_STATE_CACHED_EMPTY) {
            final long lastCachedPss;
            boolean doKilling = false;
            synchronized (mService.mAppProfiler.mProfilerLock) {
                lastCachedPss = proc.mProfile.getLastCachedPss();
                if (lastCachedPss >= getCachedRestoreThresholdKb()) {
                    proc.mProfile.reportCachedKill();
                    doKilling = true;
                }
            }
            if (DEBUG_PSS) {
                Slog.d(TAG_PSS, "May not keep " + proc + ": pss=" + lastCachedPss);
            }
            if (doKilling) {
                proc.killLocked(Long.toString(lastCachedPss) + "k from cached",
                        ApplicationExitInfo.REASON_OTHER,
                        ApplicationExitInfo.SUBREASON_LARGE_CACHED,
                        true);
            }
        }
        return proc;
        return mProcessNames.get(processName, uid);
    }

    void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
@@ -2391,12 +2354,11 @@ public final class ProcessList {
    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,
            Runnable crashHandler) {
            String abiOverride, String entryPoint, String[] entryPointArgs, Runnable crashHandler) {
        long startTime = SystemClock.uptimeMillis();
        ProcessRecord app;
        if (!isolated) {
            app = getProcessRecordLocked(processName, info.uid, keepIfLarge);
            app = getProcessRecordLocked(processName, info.uid);
            checkSlow(startTime, "startProcess: after getProcessRecord");

            if ((intentFlags & Intent.FLAG_FROM_BACKGROUND) != 0) {
@@ -2459,12 +2421,8 @@ public final class ProcessList {
            ProcessList.killProcessGroup(app.uid, app.getPid());
            checkSlow(startTime, "startProcess: done killing old proc");

            if (!app.isKilled()
                    || mService.mAppProfiler.isLastMemoryLevelNormal()
                    || 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
            if (!app.isKilled()) {
                // Throw a wtf if it's not killed
                Slog.wtf(TAG_PROCESSES, app.toString() + " is attached to a previous process");
            } else {
                Slog.w(TAG_PROCESSES, app.toString() + " is attached to a previous process");