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

Commit 94a13790 authored by Jing Ji's avatar Jing Ji
Browse files

Don't starting new app instance if failed to kill its old instance

If we've killed an app process but it's not dead, meanwhile we'd need
to start a new instance of this app, we'll hold the creation until
the old instance is gone. If it's been waited for more than 10s,
cancel the creation of the new instance. Also make the waiting here
asynchronized to unblock the process start thread.

Bug: 195955563
Test: Manual - Loop start camera, sleep 1, stop camera app
Test: Manual - Freeze app, then kill & restart & unfreeze
Test: atest CtsAppTestCases
Test: atest FrameworksServicesTests
Test: atest FrameworksMockingServicesTests
Change-Id: I036020366b29cc6da99aebb2e0bc12bf5c337613
parent fdd87b87
Loading
Loading
Loading
Loading
+21 −0
Original line number Diff line number Diff line
@@ -169,6 +169,7 @@ final class ActivityManagerConstants extends ContentObserver {
    private static final float DEFAULT_FGS_ATOM_SAMPLE_RATE = 1; // 100 %
    private static final float DEFAULT_FGS_START_ALLOWED_LOG_SAMPLE_RATE = 0.25f; // 25%
    private static final float DEFAULT_FGS_START_DENIED_LOG_SAMPLE_RATE = 1; // 100%
    private static final long DEFAULT_PROCESS_KILL_TIMEOUT_MS = 10 * 1000;

    static final long DEFAULT_BACKGROUND_SETTLE_TIME = 60 * 1000;
    static final long DEFAULT_KILL_BG_RESTRICTED_CACHED_IDLE_SETTLE_TIME_MS = 60 * 1000;
@@ -286,6 +287,11 @@ final class ActivityManagerConstants extends ContentObserver {
    private static final String KEY_PUSH_MESSAGING_OVER_QUOTA_BEHAVIOR =
            "push_messaging_over_quota_behavior";

    /**
     * Time in milliseconds; the allowed duration from a process is killed until it's really gone.
     */
    private static final String KEY_PROCESS_KILL_TIMEOUT = "process_kill_timeout";

    // Maximum number of cached processes we will allow.
    public int MAX_CACHED_PROCESSES = DEFAULT_MAX_CACHED_PROCESSES;

@@ -565,6 +571,11 @@ final class ActivityManagerConstants extends ContentObserver {
    volatile long mKillBgRestrictedAndCachedIdleSettleTimeMs =
            DEFAULT_KILL_BG_RESTRICTED_CACHED_IDLE_SETTLE_TIME_MS;

    /**
     * The allowed duration from a process is killed until it's really gone.
     */
    volatile long mProcessKillTimeoutMs = DEFAULT_PROCESS_KILL_TIMEOUT_MS;

    /**
     * Whether to allow "opt-out" from the foreground service restrictions.
     * (https://developer.android.com/about/versions/12/foreground-services)
@@ -828,6 +839,9 @@ final class ActivityManagerConstants extends ContentObserver {
                            case KEY_COMPONENT_ALIAS_OVERRIDES:
                                updateComponentAliases();
                                break;
                            case KEY_PROCESS_KILL_TIMEOUT:
                                updateProcessKillTimeout();
                                break;
                            default:
                                break;
                        }
@@ -1271,6 +1285,13 @@ final class ActivityManagerConstants extends ContentObserver {
        mService.mComponentAliasResolver.update(mEnableComponentAlias, mComponentAliasOverrides);
    }

    private void updateProcessKillTimeout() {
        mProcessKillTimeoutMs = DeviceConfig.getLong(
                DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
                KEY_PROCESS_KILL_TIMEOUT,
                DEFAULT_PROCESS_KILL_TIMEOUT_MS);
    }

    private void updateImperceptibleKillExemptions() {
        IMPERCEPTIBLE_KILL_EXEMPT_PACKAGES.clear();
        IMPERCEPTIBLE_KILL_EXEMPT_PACKAGES.addAll(mDefaultImperceptibleKillExemptPackages);
+53 −16
Original line number Diff line number Diff line
@@ -121,6 +121,7 @@ import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_UID_OBSER
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.MemoryStatUtil.hasMemcg;
import static com.android.server.am.ProcessList.ProcStartHandler;
import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
@@ -1502,7 +1503,7 @@ public class ActivityManagerService extends IActivityManager.Stub
    final MainHandler mHandler;
    final Handler mUiHandler;
    final ServiceThread mProcStartHandlerThread;
    final Handler mProcStartHandler;
    final ProcStartHandler mProcStartHandler;
    ActivityManagerConstants mConstants;
@@ -1691,7 +1692,7 @@ public class ActivityManagerService extends IActivityManager.Stub
            case PROC_START_TIMEOUT_MSG: {
                ProcessRecord app = (ProcessRecord) msg.obj;
                synchronized (ActivityManagerService.this) {
                    processStartTimedOutLocked(app);
                    handleProcessStartOrKillTimeoutLocked(app, /* isKillTimeout */ false);
                }
            } break;
            case CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG: {
@@ -2261,7 +2262,7 @@ public class ActivityManagerService extends IActivityManager.Stub
        mProcStartHandlerThread = new ServiceThread(TAG + ":procStart",
                THREAD_PRIORITY_FOREGROUND, false /* allowIo */);
        mProcStartHandlerThread.start();
        mProcStartHandler = new Handler(mProcStartHandlerThread.getLooper());
        mProcStartHandler = new ProcStartHandler(this, mProcStartHandlerThread.getLooper());
        mConstants = new ActivityManagerConstants(mContext, this, mHandler);
        final ActiveUids activeUids = new ActiveUids(this, true /* postChangesToAtm */);
@@ -4254,48 +4255,78 @@ public class ActivityManagerService extends IActivityManager.Stub
    }
    @GuardedBy("this")
    private final void processStartTimedOutLocked(ProcessRecord app) {
    void handleProcessStartOrKillTimeoutLocked(ProcessRecord app, boolean isKillTimeout) {
        final int pid = app.getPid();
        boolean gone = removePidIfNoThreadLocked(app);
        boolean gone = isKillTimeout || removePidIfNoThreadLocked(app);
        if (gone) {
            if (isKillTimeout) {
                // It's still alive... maybe blocked at uninterruptible sleep ?
                final ProcessRecord successor = app.mSuccessor;
                Slog.wtf(TAG, app.toString() + " " + app.getDyingPid()
                        + " refused to die while trying to launch " + successor
                        + ", cancelling the process start");
                // It doesn't make sense to proceed with launching the new instance while the old
                // instance is still alive, abort the launch.
                app.mSuccessorStartRunnable = null;
                app.mSuccessor = null;
                successor.mPredecessor = null;
                // We're going to cleanup the successor process record, which wasn't started at all.
                app = successor;
            } else {
                Slog.w(TAG, "Process " + app + " failed to attach");
                EventLogTags.writeAmProcessStartTimeout(app.userId, pid, app.uid, app.processName);
            }
            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 (!isKillTimeout) {
                    mBatteryStatsService.noteProcessFinish(app.processName, app.info.uid);
                    app.killLocked("start timeout",
                            ApplicationExitInfo.REASON_INITIALIZATION_FAILURE, true);
                    removeLruProcessLocked(app);
                }
                if (app.isolated) {
                    mBatteryStatsService.removeIsolatedUid(app.uid, app.info.uid);
                    mProcessList.mAppExitInfoTracker.mIsolatedUidRecords.removeIsolatedUid(
                            app.uid, app.info.uid);
                    getPackageManagerInternal().removeIsolatedUid(app.uid);
                }
                removeLruProcessLocked(app);
            }
            final BackupRecord backupTarget = mBackupTargets.get(app.userId);
            if (backupTarget != null && backupTarget.app.getPid() == pid) {
            if (!isKillTimeout && backupTarget != null && backupTarget.app.getPid() == pid) {
                Slog.w(TAG, "Unattached app died before backup, skipping");
                final int userId = app.userId;
                final String packageName = app.info.packageName;
                mHandler.post(new Runnable() {
                @Override
                    public void run(){
                        try {
                            IBackupManager bm = IBackupManager.Stub.asInterface(
                                    ServiceManager.getService(Context.BACKUP_SERVICE));
                            bm.agentDisconnectedForUser(app.userId, app.info.packageName);
                            bm.agentDisconnectedForUser(userId, packageName);
                        } catch (RemoteException e) {
                            // Can't happen; the backup manager is local
                        }
                    }
                });
            }
            if (!isKillTimeout) {
                if (isPendingBroadcastProcessLocked(pid)) {
                    Slog.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
                    skipPendingBroadcastLocked(pid);
                }
            } else {
                if (isPendingBroadcastProcessLocked(app)) {
                    skipCurrentReceiverLocked(app);
                }
            }
        } else {
            Slog.w(TAG, "Spurious process start timeout - pid not known for " + app);
        }
@@ -12394,6 +12425,12 @@ public class ActivityManagerService extends IActivityManager.Stub
                || mOffloadBroadcastQueue.isPendingBroadcastProcessLocked(pid);
    }
    boolean isPendingBroadcastProcessLocked(ProcessRecord app) {
        return mFgBroadcastQueue.isPendingBroadcastProcessLocked(app)
                || mBgBroadcastQueue.isPendingBroadcastProcessLocked(app)
                || mOffloadBroadcastQueue.isPendingBroadcastProcessLocked(app);
    }
    void skipPendingBroadcastLocked(int pid) {
            Slog.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
            for (BroadcastQueue queue : mBroadcastQueues) {
+14 −0
Original line number Diff line number Diff line
@@ -1507,6 +1507,20 @@ public final class AppExitInfoTracker {
            }
        }

        void removeIsolatedUid(int isolatedUid, int uid) {
            synchronized (mLock) {
                final int index = mUidToIsolatedUidMap.indexOfKey(uid);
                if (index >= 0) {
                    final ArraySet<Integer> set = mUidToIsolatedUidMap.valueAt(index);
                    set.remove(isolatedUid);
                    if (set.isEmpty()) {
                        mUidToIsolatedUidMap.removeAt(index);
                    }
                }
                mIsolatedUidToUidMap.remove(isolatedUid);
            }
        }

        @GuardedBy("mLock")
        Integer getUidByIsolatedUid(int isolatedUid) {
            if (UserHandle.isIsolated(isolatedUid)) {
+4 −0
Original line number Diff line number Diff line
@@ -230,6 +230,10 @@ public final class BroadcastQueue {
        return mPendingBroadcast != null && mPendingBroadcast.curApp.getPid() == pid;
    }

    boolean isPendingBroadcastProcessLocked(ProcessRecord app) {
        return mPendingBroadcast != null && mPendingBroadcast.curApp == app;
    }

    public void enqueueParallelBroadcastLocked(BroadcastRecord r) {
        mParallelBroadcasts.add(r);
        enqueueBroadcastHelper(r);
+2 −2
Original line number Diff line number Diff line
@@ -122,7 +122,7 @@ public final class PhantomProcessRecord {
                    // We'll notify the listener when we're notified it's dead.
                    // Meanwhile, we'd also need handle the case of zombie processes.
                    mKillHandler.postDelayed(mProcKillTimer, this,
                            ProcessList.PROC_KILL_TIMEOUT);
                            mService.mConstants.mProcessKillTimeoutMs);
                }
                Process.killProcessQuiet(mPid);
                ProcessList.killProcessGroup(mUid, mPid);
@@ -138,7 +138,7 @@ public final class PhantomProcessRecord {
            synchronized (mLock) {
                // The process is maybe in either D or Z state.
                Slog.w(TAG, "Process " + toString() + " is still alive after "
                        + ProcessList.PROC_KILL_TIMEOUT + "ms");
                        + mService.mConstants.mProcessKillTimeoutMs + "ms");
                // Force a cleanup as we can't keep the fd open forever
                mZombie = true;
                onProcDied(false);
Loading