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

Commit aaef7319 authored by Riddle Hsu's avatar Riddle Hsu
Browse files

Ensure force-stopped process do not start again during cleanup

By setting all activities of the removed process as finishing,
those activities haven’t been removed won't be the candidate of
top or visible activity.

Also adjust the conditions to set ProcessRecord.removed to fit the
original meaning a bit. That should be used to indicate the process
is killed for the change of package state. Now ProcessRecord.removed
will only be set when force-stop or crash too many times.

Fixes: 114117787
Fixes: 37070733
Test: atest ActivityManagerTest#testForceStopPackageWontRestartProcess
Test: atest ActivityStackTests

Change-Id: Ia2975c2e4ece8600307b317f124354ecdca55d31
parent 8e519294
Loading
Loading
Loading
Loading
+8 −13
Original line number Diff line number Diff line
@@ -3316,8 +3316,7 @@ public final class ActiveServices {
    }

    private boolean collectPackageServicesLocked(String packageName, Set<String> filterByClasses,
            boolean evenPersistent, boolean doit, boolean killProcess,
            ArrayMap<ComponentName, ServiceRecord> services) {
            boolean evenPersistent, boolean doit, ArrayMap<ComponentName, ServiceRecord> services) {
        boolean didSomething = false;
        for (int i = services.size() - 1; i >= 0; i--) {
            ServiceRecord service = services.valueAt(i);
@@ -3332,15 +3331,12 @@ public final class ActiveServices {
                }
                didSomething = true;
                Slog.i(TAG, "  Force stopping service " + service);
                if (service.app != null) {
                    service.app.removed = killProcess;
                    if (!service.app.isPersistent()) {
                if (service.app != null && !service.app.isPersistent()) {
                    service.app.services.remove(service);
                    if (service.whitelistManager) {
                        updateWhitelistManagerLocked(service.app);
                    }
                }
                }
                service.setProcess(null);
                service.isolatedProc = null;
                if (mTmpCollectionResults == null) {
@@ -3353,7 +3349,7 @@ public final class ActiveServices {
    }

    boolean bringDownDisabledPackageServicesLocked(String packageName, Set<String> filterByClasses,
            int userId, boolean evenPersistent, boolean killProcess, boolean doit) {
            int userId, boolean evenPersistent, boolean doit) {
        boolean didSomething = false;

        if (mTmpCollectionResults != null) {
@@ -3363,8 +3359,7 @@ public final class ActiveServices {
        if (userId == UserHandle.USER_ALL) {
            for (int i = mServiceMap.size() - 1; i >= 0; i--) {
                didSomething |= collectPackageServicesLocked(packageName, filterByClasses,
                        evenPersistent, doit, killProcess,
                        mServiceMap.valueAt(i).mServicesByInstanceName);
                        evenPersistent, doit, mServiceMap.valueAt(i).mServicesByInstanceName);
                if (!doit && didSomething) {
                    return true;
                }
@@ -3377,7 +3372,7 @@ public final class ActiveServices {
            if (smap != null) {
                ArrayMap<ComponentName, ServiceRecord> items = smap.mServicesByInstanceName;
                didSomething = collectPackageServicesLocked(packageName, filterByClasses,
                        evenPersistent, doit, killProcess, items);
                        evenPersistent, doit, items);
            }
            if (doit && filterByClasses == null) {
                forceStopPackageLocked(packageName, userId);
+15 −17
Original line number Diff line number Diff line
@@ -3875,7 +3875,7 @@ public class ActivityManagerService extends IActivityManager.Stub
                }
                synchronized (this) {
                    mProcessList.killPackageProcessesLocked(packageName, appId, targetUserId,
                            ProcessList.SERVICE_ADJ, false, true, true, false, "kill background");
                            ProcessList.SERVICE_ADJ, "kill background");
                }
            }
        } finally {
@@ -4236,7 +4236,7 @@ public class ActivityManagerService extends IActivityManager.Stub
    }
    private void cleanupDisabledPackageComponentsLocked(
            String packageName, int userId, boolean killProcess, String[] changedClasses) {
            String packageName, int userId, String[] changedClasses) {
        Set<String> disabledClasses = null;
        boolean packageDisabled = false;
@@ -4299,7 +4299,7 @@ public class ActivityManagerService extends IActivityManager.Stub
        // Clean-up disabled services.
        mServices.bringDownDisabledPackageServicesLocked(
                packageName, disabledClasses, userId, false, killProcess, true);
                packageName, disabledClasses, userId, false /* evenPersistent */, true /* doIt */);
        // Clean-up disabled providers.
        ArrayList<ContentProviderRecord> providers = new ArrayList<>();
@@ -4356,14 +4356,15 @@ public class ActivityManagerService extends IActivityManager.Stub
        }
        boolean didSomething = mProcessList.killPackageProcessesLocked(packageName, appId, userId,
                ProcessList.INVALID_ADJ, callerWillRestart, true, doit, evenPersistent,
                ProcessList.INVALID_ADJ, callerWillRestart, true /* allowRestart */, doit,
                evenPersistent, true /* setRemoved */,
                packageName == null ? ("stop user " + userId) : ("stop " + packageName));
        didSomething |=
                mAtmInternal.onForceStopPackage(packageName, doit, evenPersistent, userId);
        if (mServices.bringDownDisabledPackageServicesLocked(
                packageName, null, userId, evenPersistent, true, doit)) {
                packageName, null /* filterByClasses */, userId, evenPersistent, doit)) {
            if (!doit) {
                return true;
            }
@@ -8312,9 +8313,10 @@ public class ActivityManagerService extends IActivityManager.Stub
        synchronized (this) {
            final long identity = Binder.clearCallingIdentity();
            try {
                mProcessList.killPackageProcessesLocked(null, appId, userId,
                        ProcessList.PERSISTENT_PROC_ADJ, false, true, true, true,
                        reason != null ? reason : "kill uid");
                mProcessList.killPackageProcessesLocked(null /* packageName */, appId, userId,
                        ProcessList.PERSISTENT_PROC_ADJ, false /* callerWillRestart */,
                        true /* callerWillRestart */, true /* doit */, true /* evenPersistent */,
                        false /* setRemoved */, reason != null ? reason : "kill uid");
            } finally {
                Binder.restoreCallingIdentity(identity);
            }
@@ -14543,10 +14545,9 @@ public class ActivityManagerService extends IActivityManager.Stub
                                                -1);
                                        mProcessList.killPackageProcessesLocked(ssp,
                                                UserHandle.getAppId(extraUid),
                                                userId, ProcessList.INVALID_ADJ,
                                                false, true, true, false, "change " + ssp);
                                                userId, ProcessList.INVALID_ADJ, "change " + ssp);
                                    }
                                    cleanupDisabledPackageComponentsLocked(ssp, userId, killProcess,
                                    cleanupDisabledPackageComponentsLocked(ssp, userId,
                                            intent.getStringArrayExtra(
                                                    Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST));
                                }
@@ -17203,10 +17204,8 @@ public class ActivityManagerService extends IActivityManager.Stub
                            // We don't kill persistent processes.
                            continue;
                        }
                        if (app.removed) {
                            procs.add(app);
                        } else if (app.userId == userHandle && app.hasForegroundActivities()) {
                            app.removed = true;
                        if (app.removed
                                || (app.userId == userHandle && app.hasForegroundActivities())) {
                            procs.add(app);
                        }
                    }
@@ -18051,8 +18050,7 @@ public class ActivityManagerService extends IActivityManager.Stub
        try {
            synchronized(this) {
                mProcessList.killPackageProcessesLocked(packageName, UserHandle.getAppId(pkgUid),
                        userId, ProcessList.FOREGROUND_APP_ADJ, false, true, true, false,
                        "dep: " + packageName);
                        userId, ProcessList.FOREGROUND_APP_ADJ, "dep: " + packageName);
            }
        } finally {
            Binder.restoreCallingIdentity(callingId);
+14 −15
Original line number Diff line number Diff line
@@ -2038,25 +2038,25 @@ public final class ProcessList {
                    // We don't kill persistent processes.
                    continue;
                }
                if (app.removed) {
                    procs.add(app);
                } else if (app.setAdj >= ProcessList.CACHED_APP_MIN_ADJ) {
                    app.removed = true;
                if (app.removed || app.setAdj >= ProcessList.CACHED_APP_MIN_ADJ) {
                    procs.add(app);
                }
            }
        }

        final int N = procs.size();
        for (int i = 0; i < N; i++) {
            removeProcessLocked(procs.get(i), false, true, "kill all background");
    }

    @GuardedBy("mService")
    boolean killPackageProcessesLocked(String packageName, int appId, int userId, int minOomAdj,
            String reason) {
        return killPackageProcessesLocked(packageName, appId, userId, minOomAdj,
                false /* callerWillRestart */, true /* allowRestart */, true /* doit */,
                false /* evenPersistent */, false /* setRemoved */, reason);
    }

    @GuardedBy("mService")
    final boolean killPackageProcessesLocked(String packageName, int appId,
            int userId, int minOomAdj, boolean callerWillRestart, boolean allowRestart,
            boolean doit, boolean evenPersistent, String reason) {
            boolean doit, boolean evenPersistent, boolean setRemoved, String reason) {
        ArrayList<ProcessRecord> procs = new ArrayList<>();

        // Remove all processes this package may have touched: all with the
@@ -2114,7 +2114,9 @@ public final class ProcessList {
                if (!doit) {
                    return true;
                }
                if (setRemoved) {
                    app.removed = true;
                }
                procs.add(app);
            }
        }
@@ -2348,11 +2350,8 @@ 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) {
                    procs.add(app);
                } else if ((minTargetSdk < 0 || app.info.targetSdkVersion < minTargetSdk)
                        && (maxProcState < 0 || app.setProcState > maxProcState)) {
                    app.removed = true;
                if (app.removed || ((minTargetSdk < 0 || app.info.targetSdkVersion < minTargetSdk)
                        && (maxProcState < 0 || app.setProcState > maxProcState))) {
                    procs.add(app);
                }
            }
+5 −5
Original line number Diff line number Diff line
@@ -264,7 +264,9 @@ final class ProcessRecord implements WindowProcessListener {
    boolean forceCrashReport;   // suppress normal auto-dismiss of crash dialog & report UI?
    private boolean mNotResponding; // does the app have a not responding dialog?
    Dialog anrDialog;           // dialog being displayed due to app not resp.
    boolean removed;            // has app package been removed from device?
    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?
    Dialog waitDialog;          // current wait for debugger dialog
@@ -1228,10 +1230,8 @@ final class ProcessRecord implements WindowProcessListener {
    }

    @Override
    public void setRemoved(boolean removed) {
        synchronized (mService) {
            this.removed = removed;
        }
    public boolean isRemoved() {
        return removed;
    }

    /**
+9 −7
Original line number Diff line number Diff line
@@ -4673,6 +4673,14 @@ class ActivityStack extends ConfigurationContainer {
        removeHistoryRecordsForAppLocked(mStackSupervisor.mFinishingActivities, app,
                "mFinishingActivities");

        final boolean isProcessRemoved = app.isRemoved();
        if (isProcessRemoved) {
            // The package of the died process should be force-stopped, so make its activities as
            // finishing to prevent the process from being started again if the next top (or being
            // visible) activity also resides in the same process.
            app.makeFinishingForProcessRemoved();
        }

        boolean hasVisibleActivities = false;

        // Clean out the history list.
@@ -4725,7 +4733,7 @@ class ActivityStack extends ConfigurationContainer {
                                + " stateNotNeeded=" + r.stateNotNeeded
                                + " finishing=" + r.finishing
                                + " state=" + r.getState() + " callers=" + Debug.getCallers(5));
                        if (!r.finishing) {
                        if (!r.finishing || isProcessRemoved) {
                            Slog.w(TAG, "Force removing " + r + ": app died, no saved state");
                            EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY,
                                    r.mUserId, System.identityHashCode(r),
@@ -5130,12 +5138,6 @@ class ActivityStack extends ConfigurationContainer {
                    }
                    didSomething = true;
                    Slog.i(TAG, "  Force finishing activity " + r);
                    if (sameComponent) {
                        if (r.hasProcess()) {
                            r.app.setRemoved(true);
                        }
                        r.app = null;
                    }
                    lastTask = r.getTaskRecord();
                    finishActivityLocked(r, Activity.RESULT_CANCELED, null, "force-stop",
                            true);
Loading