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

Commit b0ef1944 authored by Edgar Arriaga's avatar Edgar Arriaga
Browse files

Improve compaction debugging with extra adb command to force compaction

This CL adds am compact command that allows forcing compactions
this is specially useful for debugging compaction flows as well
and it also allows for instrumentation to manually trigger compactions
if needed and it also reduces some technical debt to allow
forcing compaction code to be manageable.

Bug: 226463719
Test: adb shell am compact <process_name> <uid> some|full

Change-Id: I67af76a212611260bb226e74e48eb7f495341f12
parent 720a6a5a
Loading
Loading
Loading
Loading
+36 −0
Original line number Diff line number Diff line
@@ -219,6 +219,8 @@ final class ActivityManagerShellCommand extends ShellCommand {
                    return runStopService(pw);
                case "broadcast":
                    return runSendBroadcast(pw);
                case "compact":
                    return runCompact(pw);
                case "instrument":
                    getOutPrintWriter().println("Error: must be invoked through 'am instrument'.");
                    return -1;
@@ -966,6 +968,36 @@ final class ActivityManagerShellCommand extends ShellCommand {
        return 0;
    }

    @NeverCompile
    int runCompact(PrintWriter pw) {
        String processName = getNextArgRequired();
        String uid = getNextArgRequired();
        String op = getNextArgRequired();
        ProcessRecord app;
        synchronized (mInternal.mProcLock) {
            app = mInternal.getProcessRecordLocked(processName, Integer.parseInt(uid));
        }
        pw.println("Process record found pid: " + app.mPid);
        if (op.equals("full")) {
            pw.println("Executing full compaction for " + app.mPid);
            synchronized (mInternal.mProcLock) {
                mInternal.mOomAdjuster.mCachedAppOptimizer.compactAppFull(app, true);
            }
            pw.println("Finished full compaction for " + app.mPid);
        } else if (op.equals("some")) {
            pw.println("Executing some compaction for " + app.mPid);
            synchronized (mInternal.mProcLock) {
                mInternal.mOomAdjuster.mCachedAppOptimizer.compactAppSome(app, true);
            }
            pw.println("Finished some compaction for " + app.mPid);
        } else {
            getErrPrintWriter().println("Error: unknown compact command '" + op + "'");
            return -1;
        }

        return 0;
    }

    int runDumpHeap(PrintWriter pw) throws RemoteException {
        final PrintWriter err = getErrPrintWriter();
        boolean managed = true;
@@ -3435,6 +3467,10 @@ final class ActivityManagerShellCommand extends ShellCommand {
            pw.println("      --allow-background-activity-starts: The receiver may start activities");
            pw.println("          even if in the background.");
            pw.println("      --async: Send without waiting for the completion of the receiver.");
            pw.println("  compact <process_name> <Package UID> [some|full]");
            pw.println("      Force process compaction.");
            pw.println("      some: execute file compaction.");
            pw.println("      full: execute anon + file compaction.");
            pw.println("  instrument [-r] [-e <NAME> <VALUE>] [-p <FILE>] [-w]");
            pw.println("          [--user <USER_ID> | current]");
            pw.println("          [--no-hidden-api-checks [--no-test-api-access]]");
+291 −181

File changed.

Preview size limit exceeded, changes collapsed.

+15 −0
Original line number Diff line number Diff line
@@ -56,6 +56,8 @@ final class ProcessCachedOptimizerRecord {
    @GuardedBy("mProcLock")
    private boolean mPendingCompact;

    @GuardedBy("mProcLock") private boolean mForceCompact;

    /**
     * True when the process is frozen.
     */
@@ -132,6 +134,16 @@ final class ProcessCachedOptimizerRecord {
        mPendingCompact = pendingCompact;
    }

    @GuardedBy("mProcLock")
    boolean isForceCompact() {
        return mForceCompact;
    }

    @GuardedBy("mProcLock")
    void setForceCompact(boolean forceCompact) {
        mForceCompact = forceCompact;
    }

    @GuardedBy("mProcLock")
    boolean isFrozen() {
        return mFrozen;
@@ -205,6 +217,9 @@ final class ProcessCachedOptimizerRecord {
    void dump(PrintWriter pw, String prefix, long nowUptime) {
        pw.print(prefix); pw.print("lastCompactTime="); pw.print(mLastCompactTime);
        pw.print(" lastCompactAction="); pw.println(mLastCompactAction);
        pw.print(prefix);
        pw.print("hasPendingCompaction=");
        pw.print(mPendingCompact);
        pw.print(prefix); pw.print("isFreezeExempt="); pw.print(mFreezeExempt);
        pw.print(" isPendingFreeze="); pw.print(mPendingFreeze);
        pw.print(" " + IS_FROZEN + "="); pw.println(mFrozen);
+71 −12
Original line number Diff line number Diff line
@@ -857,6 +857,7 @@ public final class CachedAppOptimizerTest {
                .containsExactlyElementsIn(expected);
    }

    @SuppressWarnings("GuardedBy")
    @Test
    public void processWithDeltaRSSTooSmall_notFullCompacted() throws Exception {
        // Initialize CachedAppOptimizer and set flags to (1) enable compaction, (2) set RSS
@@ -892,7 +893,7 @@ public final class CachedAppOptimizerTest {
        mProcessDependencies.setRss(rssBefore1);
        mProcessDependencies.setRssAfterCompaction(rssAfter1); //
        // WHEN we try to run compaction
        mCachedAppOptimizerUnderTest.compactAppFull(processRecord);
        mCachedAppOptimizerUnderTest.compactAppFull(processRecord, false);
        waitForHandler();
        // THEN process IS compacted.
        assertThat(mCachedAppOptimizerUnderTest.mLastCompactionStats.get(pid)).isNotNull();
@@ -907,7 +908,7 @@ public final class CachedAppOptimizerTest {
        processRecord.mOptRecord.setLastCompactTime(
                processRecord.mOptRecord.getLastCompactTime() - 10_000);
        // WHEN we try to run compaction.
        mCachedAppOptimizerUnderTest.compactAppFull(processRecord);
        mCachedAppOptimizerUnderTest.compactAppFull(processRecord, false);
        waitForHandler();
        // THEN process IS NOT compacted - values after compaction for process 1 should remain the
        // same as from the last compaction.
@@ -923,7 +924,7 @@ public final class CachedAppOptimizerTest {
        processRecord.mOptRecord.setLastCompactTime(
                processRecord.mOptRecord.getLastCompactTime() - 10_000);
        // WHEN we try to run compaction
        mCachedAppOptimizerUnderTest.compactAppFull(processRecord);
        mCachedAppOptimizerUnderTest.compactAppFull(processRecord, false);
        waitForHandler();
        // THEN process IS compacted - values after compaction for process 1 should be updated.
        assertThat(mCachedAppOptimizerUnderTest.mLastCompactionStats.get(pid)).isNotNull();
@@ -932,6 +933,7 @@ public final class CachedAppOptimizerTest {
        assertThat(valuesAfter).isEqualTo(rssAfter3);
    }

    @SuppressWarnings("GuardedBy")
    @Test
    public void processWithAnonRSSTooSmall_notFullCompacted() throws Exception {
        // Initialize CachedAppOptimizer and set flags to (1) enable compaction, (2) set RSS
@@ -963,7 +965,7 @@ public final class CachedAppOptimizerTest {
        mProcessDependencies.setRss(rssBelowThreshold);
        mProcessDependencies.setRssAfterCompaction(rssBelowThresholdAfter);
        // WHEN we try to run compaction
        mCachedAppOptimizerUnderTest.compactAppFull(processRecord);
        mCachedAppOptimizerUnderTest.compactAppFull(processRecord, false);
        waitForHandler();
        // THEN process IS NOT compacted.
        assertThat(mCachedAppOptimizerUnderTest.mLastCompactionStats.get(pid)).isNull();
@@ -972,7 +974,7 @@ public final class CachedAppOptimizerTest {
        mProcessDependencies.setRss(rssAboveThreshold);
        mProcessDependencies.setRssAfterCompaction(rssAboveThresholdAfter);
        // WHEN we try to run compaction
        mCachedAppOptimizerUnderTest.compactAppFull(processRecord);
        mCachedAppOptimizerUnderTest.compactAppFull(processRecord, false);
        waitForHandler();
        // THEN process IS compacted.
        assertThat(mCachedAppOptimizerUnderTest.mLastCompactionStats.get(pid)).isNotNull();
@@ -981,6 +983,7 @@ public final class CachedAppOptimizerTest {
        assertThat(valuesAfter).isEqualTo(rssAboveThresholdAfter);
    }

    @SuppressWarnings("GuardedBy")
    @Test
    public void processWithOomAdjTooSmall_notFullCompacted() throws Exception {
        // Initialize CachedAppOptimizer and set flags to (1) enable compaction, (2) set Min and
@@ -996,7 +999,8 @@ public final class CachedAppOptimizerTest {
                new long[]{/*Total RSS*/ 15000, /*File RSS*/ 15000, /*Anon RSS*/ 15000,
                        /*Swap*/ 10000};
        long[] rssAfter =
            new long[]{/*Total RSS*/ 8000, /*File RSS*/ 9000, /*Anon RSS*/ 6000, /*Swap*/5000};
                new long[]{/*Total RSS*/ 8000, /*File RSS*/ 9000, /*Anon RSS*/ 6000, /*Swap*/
                        5000};
        // Process that passes properties.
        int pid = 1;
        ProcessRecord processRecord =
@@ -1010,7 +1014,7 @@ public final class CachedAppOptimizerTest {
        processRecord.mState.setSetAdj(899);
        processRecord.mState.setCurAdj(970);
        // WHEN we try to run compaction
        mCachedAppOptimizerUnderTest.compactAppFull(processRecord);
        mCachedAppOptimizerUnderTest.compactAppFull(processRecord, false);
        waitForHandler();
        // THEN process IS NOT compacted.
        assertThat(mCachedAppOptimizerUnderTest.mLastCompactionStats.get(pid)).isNull();
@@ -1019,7 +1023,7 @@ public final class CachedAppOptimizerTest {
        processRecord.mState.setSetAdj(910);
        processRecord.mState.setCurAdj(930);
        // WHEN we try to run compaction
        mCachedAppOptimizerUnderTest.compactAppFull(processRecord);
        mCachedAppOptimizerUnderTest.compactAppFull(processRecord, false);
        waitForHandler();
        // THEN process IS compacted.
        assertThat(mCachedAppOptimizerUnderTest.mLastCompactionStats.get(pid)).isNotNull();
@@ -1029,6 +1033,61 @@ public final class CachedAppOptimizerTest {
        assertThat(valuesAfter).isEqualTo(rssAfter);
    }

    @SuppressWarnings("GuardedBy")
    @Test
    public void process_forceCompacted() throws Exception {
        mCachedAppOptimizerUnderTest.init();
        setFlag(CachedAppOptimizer.KEY_USE_COMPACTION, "true", true);
        setFlag(CachedAppOptimizer.KEY_COMPACT_THROTTLE_MIN_OOM_ADJ, Long.toString(920), true);
        setFlag(CachedAppOptimizer.KEY_COMPACT_THROTTLE_MAX_OOM_ADJ, Long.toString(950), true);
        initActivityManagerService();

        long[] rssBefore = new long[] {/*Total RSS*/ 15000, /*File RSS*/ 15000, /*Anon RSS*/ 15000,
                /*Swap*/ 10000};
        long[] rssAfter = new long[] {
                /*Total RSS*/ 8000, /*File RSS*/ 9000, /*Anon RSS*/ 6000, /*Swap*/ 5000};
        // Process that passes properties.
        int pid = 1;
        ProcessRecord processRecord = makeProcessRecord(pid, 2, 3, "p1", "app1");
        mProcessDependencies.setRss(rssBefore);
        mProcessDependencies.setRssAfterCompaction(rssAfter);

        // Use an OOM Adjust value that usually avoids compaction
        processRecord.mState.setSetAdj(100);
        processRecord.mState.setCurAdj(100);

        // Compact process full
        mCachedAppOptimizerUnderTest.compactAppFull(processRecord, false);
        waitForHandler();
        // the process is not compacted
        assertThat(mCachedAppOptimizerUnderTest.mLastCompactionStats.get(pid)).isNull();

        // Compact process some
        mCachedAppOptimizerUnderTest.compactAppSome(processRecord, false);
        waitForHandler();
        // the process is not compacted
        assertThat(mCachedAppOptimizerUnderTest.mLastCompactionStats.get(pid)).isNull();

        processRecord.mState.setSetAdj(100);
        processRecord.mState.setCurAdj(100);

        // We force a full compaction
        mCachedAppOptimizerUnderTest.compactAppFull(processRecord, true);
        waitForHandler();
        // then process is compacted.
        assertThat(mCachedAppOptimizerUnderTest.mLastCompactionStats.get(pid)).isNotNull();

        mCachedAppOptimizerUnderTest.mLastCompactionStats.clear();

        // We force a some compaction
        mCachedAppOptimizerUnderTest.compactAppSome(processRecord, true);
        waitForHandler();
        // then process is compacted.
        String executedCompactAction =
                compactActionIntToString(processRecord.mOptRecord.getLastCompactAction());
        assertThat(executedCompactAction)
                .isEqualTo(mCachedAppOptimizerUnderTest.mCompactActionSome);
    }

    private void setFlag(String key, String value, boolean defaultValue) throws Exception {
        mCountDown = new CountDownLatch(1);