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

Commit 731a5331 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Add activitymanager debug option to freeze a process" into udc-dev

parents db809725 9dbe8e97
Loading
Loading
Loading
Loading
+103 −14
Original line number Original line Diff line number Diff line
@@ -247,6 +247,10 @@ final class ActivityManagerShellCommand extends ShellCommand {
                    return runSendBroadcast(pw);
                    return runSendBroadcast(pw);
                case "compact":
                case "compact":
                    return runCompact(pw);
                    return runCompact(pw);
                case "freeze":
                    return runFreeze(pw);
                case "unfreeze":
                    return runUnfreeze(pw);
                case "instrument":
                case "instrument":
                    getOutPrintWriter().println("Error: must be invoked through 'am instrument'.");
                    getOutPrintWriter().println("Error: must be invoked through 'am instrument'.");
                    return -1;
                    return -1;
@@ -1074,20 +1078,10 @@ final class ActivityManagerShellCommand extends ShellCommand {
        boolean isFullCompact = op.equals("full");
        boolean isFullCompact = op.equals("full");
        boolean isSomeCompact = op.equals("some");
        boolean isSomeCompact = op.equals("some");
        if (isFullCompact || isSomeCompact) {
        if (isFullCompact || isSomeCompact) {
            String processName = getNextArgRequired();
            app = getProcessFromShell();
            synchronized (mInternal.mProcLock) {
            if (app == null) {
                // Default to current user
                getErrPrintWriter().println("Error: could not find process");
                int userId = mInterface.getCurrentUserId();
                return -1;
                String userOpt = getNextOption();
                if (userOpt != null && "--user".equals(userOpt)) {
                    int inputUserId = UserHandle.parseUserArg(getNextArgRequired());
                    if (inputUserId != UserHandle.USER_CURRENT) {
                        userId = inputUserId;
                    }
                }
                final int uid =
                        mInternal.getPackageManagerInternal().getPackageUid(processName, 0, userId);
                app = mInternal.getProcessRecordLocked(processName, uid);
            }
            }
            pw.println("Process record found pid: " + app.mPid);
            pw.println("Process record found pid: " + app.mPid);
            if (isFullCompact) {
            if (isFullCompact) {
@@ -1143,6 +1137,93 @@ final class ActivityManagerShellCommand extends ShellCommand {
        return 0;
        return 0;
    }
    }


    @NeverCompile
    int runFreeze(PrintWriter pw) throws RemoteException {
        String freezerOpt = getNextOption();
        boolean isSticky = false;
        if (freezerOpt != null) {
            isSticky = freezerOpt.equals("--sticky");
        }
        ProcessRecord app = getProcessFromShell();
        if (app == null) {
            getErrPrintWriter().println("Error: could not find process");
            return -1;
        }
        pw.println("Freezing pid: " + app.mPid + " sticky=" + isSticky);
        synchronized (mInternal) {
            synchronized (mInternal.mProcLock) {
                app.mOptRecord.setFreezeSticky(isSticky);
                mInternal.mOomAdjuster.mCachedAppOptimizer.freezeAppAsyncInternalLSP(app, 0, true);
            }
        }
        return 0;
    }

    @NeverCompile
    int runUnfreeze(PrintWriter pw) throws RemoteException {
        String freezerOpt = getNextOption();
        boolean isSticky = false;
        if (freezerOpt != null) {
            isSticky = freezerOpt.equals("--sticky");
        }
        ProcessRecord app = getProcessFromShell();
        if (app == null) {
            getErrPrintWriter().println("Error: could not find process");
            return -1;
        }
        pw.println("Unfreezing pid: " + app.mPid);
        synchronized (mInternal) {
            synchronized (mInternal.mProcLock) {
                synchronized (mInternal.mOomAdjuster.mCachedAppOptimizer.mFreezerLock) {
                    app.mOptRecord.setFreezeSticky(isSticky);
                    mInternal.mOomAdjuster.mCachedAppOptimizer.unfreezeAppInternalLSP(app, 0,
                            false);
                }
            }
        }
        return 0;
    }

    /**
     * Parses from the shell the process name and user id if provided and provides the corresponding
     * {@link ProcessRecord)} If no user is provided, it will fallback to current user.
     * Example usage: {@code <processname> --user current} or {@code <processname>}
     * @return process record of process, null if none found.
     * @throws RemoteException
     */
    @NeverCompile
    ProcessRecord getProcessFromShell() throws RemoteException {
        ProcessRecord app;
        String processName = getNextArgRequired();
        synchronized (mInternal.mProcLock) {
            // Default to current user
            int userId = getUserIdFromShellOrFallback();
            final int uid =
                    mInternal.getPackageManagerInternal().getPackageUid(processName, 0, userId);
            app = mInternal.getProcessRecordLocked(processName, uid);
        }
        return app;
    }

    /**
     * @return User id from command line provided in the form of
     *  {@code --user <userid|current|all>} and if the argument is not found it will fallback
     *  to current user.
     * @throws RemoteException
     */
    @NeverCompile
    int getUserIdFromShellOrFallback() throws RemoteException {
        int userId = mInterface.getCurrentUserId();
        String userOpt = getNextOption();
        if (userOpt != null && "--user".equals(userOpt)) {
            int inputUserId = UserHandle.parseUserArg(getNextArgRequired());
            if (inputUserId != UserHandle.USER_CURRENT) {
                userId = inputUserId;
            }
        }
        return userId;
    }

    int runDumpHeap(PrintWriter pw) throws RemoteException {
    int runDumpHeap(PrintWriter pw) throws RemoteException {
        final PrintWriter err = getErrPrintWriter();
        final PrintWriter err = getErrPrintWriter();
        boolean managed = true;
        boolean managed = true;
@@ -4061,6 +4142,14 @@ final class ActivityManagerShellCommand extends ShellCommand {
            pw.println("      Perform a native compaction for process with <pid>.");
            pw.println("      Perform a native compaction for process with <pid>.");
            pw.println("      some: execute file compaction.");
            pw.println("      some: execute file compaction.");
            pw.println("      full: execute anon + file compaction.");
            pw.println("      full: execute anon + file compaction.");
            pw.println("  freeze [--sticky] <processname> [--user <USER_ID>]");
            pw.println("      Freeze a process.");
            pw.println("        --sticky: persists the frozen state for the process lifetime or");
            pw.println("                  until an unfreeze is triggered via shell");
            pw.println("  unfreeze [--sticky] <processname> [--user <USER_ID>]");
            pw.println("      Unfreeze a process.");
            pw.println("        --sticky: persists the unfrozen state for the process lifetime or");
            pw.println("                  until a freeze is triggered via shell");
            pw.println("  instrument [-r] [-e <NAME> <VALUE>] [-p <FILE>] [-w]");
            pw.println("  instrument [-r] [-e <NAME> <VALUE>] [-p <FILE>] [-w]");
            pw.println("          [--user <USER_ID> | current]");
            pw.println("          [--user <USER_ID> | current]");
            pw.println("          [--no-hidden-api-checks [--no-test-api-access]]");
            pw.println("          [--no-hidden-api-checks [--no-test-api-access]]");
+32 −17
Original line number Original line Diff line number Diff line
@@ -342,7 +342,7 @@ public final class CachedAppOptimizer {


    private final ActivityManagerGlobalLock mProcLock;
    private final ActivityManagerGlobalLock mProcLock;


    private final Object mFreezerLock = new Object();
    public final Object mFreezerLock = new Object();


    private final OnPropertiesChangedListener mOnFlagsChangedListener =
    private final OnPropertiesChangedListener mOnFlagsChangedListener =
            new OnPropertiesChangedListener() {
            new OnPropertiesChangedListener() {
@@ -763,8 +763,9 @@ public final class CachedAppOptimizer {
                pw.println("  Apps frozen: " + size);
                pw.println("  Apps frozen: " + size);
                for (int i = 0; i < size; i++) {
                for (int i = 0; i < size; i++) {
                    ProcessRecord app = mFrozenProcesses.valueAt(i);
                    ProcessRecord app = mFrozenProcesses.valueAt(i);
                    pw.println("    " + app.mOptRecord.getFreezeUnfreezeTime()
                    pw.println("    " + app.mOptRecord.getFreezeUnfreezeTime() + ": " + app.getPid()
                            + ": " + app.getPid() + " " + app.processName);
                            + " " + app.processName
                            + (app.mOptRecord.isFreezeSticky() ? " (sticky)" : ""));
                }
                }


                if (!mPendingCompactionProcesses.isEmpty()) {
                if (!mPendingCompactionProcesses.isEmpty()) {
@@ -1283,12 +1284,26 @@ public final class CachedAppOptimizer {


    @GuardedBy({"mAm", "mProcLock"})
    @GuardedBy({"mAm", "mProcLock"})
    void freezeAppAsyncLSP(ProcessRecord app) {
    void freezeAppAsyncLSP(ProcessRecord app) {
        freezeAppAsyncInternalLSP(app, mFreezerDebounceTimeout, false);
    }

    @GuardedBy({"mAm", "mProcLock"})
    void freezeAppAsyncInternalLSP(ProcessRecord app, long delayMillis, boolean force) {
        final ProcessCachedOptimizerRecord opt = app.mOptRecord;
        final ProcessCachedOptimizerRecord opt = app.mOptRecord;
        if (opt.isPendingFreeze()) {
        if (opt.isPendingFreeze()) {
            // Skip redundant DO_FREEZE message
            // Skip redundant DO_FREEZE message
            return;
            return;
        }
        }


        if (opt.isFreezeSticky() && !force) {
            if (DEBUG_FREEZER) {
                Slog.d(TAG_AM,
                        "Skip freezing because unfrozen state is sticky pid=" + app.getPid() + " "
                                + app.processName);
            }
            return;
        }

        if (mAm.mConstants.USE_MODERN_TRIM
        if (mAm.mConstants.USE_MODERN_TRIM
                && app.mState.getSetAdj() >= ProcessList.CACHED_APP_MIN_ADJ) {
                && app.mState.getSetAdj() >= ProcessList.CACHED_APP_MIN_ADJ) {
            final IApplicationThread thread = app.getThread();
            final IApplicationThread thread = app.getThread();
@@ -1301,9 +1316,8 @@ public final class CachedAppOptimizer {
            }
            }
        }
        }
        mFreezeHandler.sendMessageDelayed(
        mFreezeHandler.sendMessageDelayed(
                mFreezeHandler.obtainMessage(
                mFreezeHandler.obtainMessage(SET_FROZEN_PROCESS_MSG, DO_FREEZE, 0, app),
                    SET_FROZEN_PROCESS_MSG, DO_FREEZE, 0, app),
                delayMillis);
                mFreezerDebounceTimeout);
        opt.setPendingFreeze(true);
        opt.setPendingFreeze(true);
        if (DEBUG_FREEZER) {
        if (DEBUG_FREEZER) {
            Slog.d(TAG_AM, "Async freezing " + app.getPid() + " " + app.processName);
            Slog.d(TAG_AM, "Async freezing " + app.getPid() + " " + app.processName);
@@ -1311,9 +1325,19 @@ public final class CachedAppOptimizer {
    }
    }


    @GuardedBy({"mAm", "mProcLock", "mFreezerLock"})
    @GuardedBy({"mAm", "mProcLock", "mFreezerLock"})
    void unfreezeAppInternalLSP(ProcessRecord app, @UnfreezeReason int reason) {
    void unfreezeAppInternalLSP(ProcessRecord app, @UnfreezeReason int reason, boolean force) {
        final int pid = app.getPid();
        final int pid = app.getPid();
        final ProcessCachedOptimizerRecord opt = app.mOptRecord;
        final ProcessCachedOptimizerRecord opt = app.mOptRecord;
        boolean sticky = opt.isFreezeSticky();
        if (sticky && !force) {
            // Sticky freezes will not change their state unless forced out of it.
            if (DEBUG_FREEZER) {
                Slog.d(TAG_AM,
                        "Skip unfreezing because frozen state is sticky pid=" + pid + " "
                                + app.processName);
            }
            return;
        }
        if (opt.isPendingFreeze()) {
        if (opt.isPendingFreeze()) {
            // Remove pending DO_FREEZE message
            // Remove pending DO_FREEZE message
            mFreezeHandler.removeMessages(SET_FROZEN_PROCESS_MSG, app);
            mFreezeHandler.removeMessages(SET_FROZEN_PROCESS_MSG, app);
@@ -1406,7 +1430,7 @@ public final class CachedAppOptimizer {
    @GuardedBy({"mAm", "mProcLock"})
    @GuardedBy({"mAm", "mProcLock"})
    void unfreezeAppLSP(ProcessRecord app, @UnfreezeReason int reason) {
    void unfreezeAppLSP(ProcessRecord app, @UnfreezeReason int reason) {
        synchronized (mFreezerLock) {
        synchronized (mFreezerLock) {
            unfreezeAppInternalLSP(app, reason);
            unfreezeAppInternalLSP(app, reason, false);
        }
        }
    }
    }


@@ -2080,15 +2104,6 @@ public final class CachedAppOptimizer {


            synchronized (mProcLock) {
            synchronized (mProcLock) {
                pid = proc.getPid();
                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.mState.getCurAdj()
                                + ", shouldNotFreeze = " + opt.shouldNotFreeze());
                    }
                    return;
                }


                if (mFreezerOverride) {
                if (mFreezerOverride) {
                    opt.setFreezerOverride(true);
                    opt.setFreezerOverride(true);
+18 −0
Original line number Original line Diff line number Diff line
@@ -74,6 +74,15 @@ final class ProcessCachedOptimizerRecord {
    @GuardedBy("mProcLock")
    @GuardedBy("mProcLock")
    private boolean mFrozen;
    private boolean mFrozen;


    /**
     * If set to true it will make the (un)freeze decision sticky which means that the freezer
     * decision will remain the same unless a freeze is forced via {@link #mForceFreezeOps}.
     * This property is usually set to true when external user wants to maintain a (un)frozen state
     * after being applied.
     */
    @GuardedBy("mProcLock")
    private boolean mFreezeSticky;

    /**
    /**
     * Set to false after the process has been frozen.
     * Set to false after the process has been frozen.
     * Set to true after we have collected PSS for the frozen process.
     * Set to true after we have collected PSS for the frozen process.
@@ -195,6 +204,15 @@ final class ProcessCachedOptimizerRecord {
    void setFrozen(boolean frozen) {
    void setFrozen(boolean frozen) {
        mFrozen = frozen;
        mFrozen = frozen;
    }
    }
    @GuardedBy("mProcLock")
    void setFreezeSticky(boolean sticky) {
        mFreezeSticky = sticky;
    }

    @GuardedBy("mProcLock")
    boolean isFreezeSticky() {
        return mFreezeSticky;
    }


    boolean skipPSSCollectionBecauseFrozen() {
    boolean skipPSSCollectionBecauseFrozen() {
        boolean collected = mHasCollectedFrozenPSS;
        boolean collected = mHasCollectedFrozenPSS;