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

Commit a567e657 authored by Tim Murray's avatar Tim Murray Committed by Android (Google) Code Review
Browse files

Merge "ActivityManagerService: compact background apps"

parents 78c2a0de 0b1c8aa3
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -69,6 +69,7 @@ final class ActivityManagerConstants extends ContentObserver {
    static final String KEY_PROCESS_START_ASYNC = "process_start_async";
    static final String KEY_MEMORY_INFO_THROTTLE_TIME = "memory_info_throttle_time";
    static final String KEY_TOP_TO_FGS_GRACE_DURATION = "top_to_fgs_grace_duration";
    static final String KEY_USE_COMPACTION = "use_compaction";

    private static final int DEFAULT_MAX_CACHED_PROCESSES = 32;
    private static final long DEFAULT_BACKGROUND_SETTLE_TIME = 60*1000;
@@ -99,6 +100,7 @@ final class ActivityManagerConstants extends ContentObserver {
    private static final boolean DEFAULT_PROCESS_START_ASYNC = true;
    private static final long DEFAULT_MEMORY_INFO_THROTTLE_TIME = 5*60*1000;
    private static final long DEFAULT_TOP_TO_FGS_GRACE_DURATION = 15 * 1000;
    private static final boolean DEFAULT_USE_COMPACTION = false;

    // Maximum number of cached processes we will allow.
    public int MAX_CACHED_PROCESSES = DEFAULT_MAX_CACHED_PROCESSES;
@@ -218,6 +220,9 @@ final class ActivityManagerConstants extends ContentObserver {
    // this long.
    public long TOP_TO_FGS_GRACE_DURATION = DEFAULT_TOP_TO_FGS_GRACE_DURATION;

    // Use compaction for background apps.
    public boolean USE_COMPACTION = DEFAULT_USE_COMPACTION;

    // Indicates whether the activity starts logging is enabled.
    // Controlled by Settings.Global.ACTIVITY_STARTS_LOGGING_ENABLED
    volatile boolean mFlagActivityStartsLoggingEnabled;
@@ -375,6 +380,7 @@ final class ActivityManagerConstants extends ContentObserver {
                    DEFAULT_MEMORY_INFO_THROTTLE_TIME);
            TOP_TO_FGS_GRACE_DURATION = mParser.getDurationMillis(KEY_TOP_TO_FGS_GRACE_DURATION,
                    DEFAULT_TOP_TO_FGS_GRACE_DURATION);
            USE_COMPACTION = mParser.getBoolean(KEY_USE_COMPACTION, DEFAULT_USE_COMPACTION);

            updateMaxCachedProcesses();
        }
@@ -465,6 +471,8 @@ final class ActivityManagerConstants extends ContentObserver {
        pw.println(MEMORY_INFO_THROTTLE_TIME);
        pw.print("  "); pw.print(KEY_TOP_TO_FGS_GRACE_DURATION); pw.print("=");
        pw.println(TOP_TO_FGS_GRACE_DURATION);
        pw.print("  "); pw.print(KEY_USE_COMPACTION); pw.print("=");
        pw.println(USE_COMPACTION);

        pw.println();
        if (mOverrideMaxCachedProcesses >= 0) {
+117 −2
Original line number Diff line number Diff line
@@ -795,6 +795,11 @@ public class ActivityManagerService extends IActivityManager.Stub
     */
    final ArrayList<ProcessRecord> mPendingPssProcesses = new ArrayList<ProcessRecord>();
    /**
     * Processes to compact.
     */
    final ArrayList<ProcessRecord> mPendingCompactionProcesses = new ArrayList<ProcessRecord>();
    private boolean mBinderTransactionTrackingEnabled = false;
    /**
@@ -1452,6 +1457,7 @@ public class ActivityManagerService extends IActivityManager.Stub
    final Handler mUiHandler;
    final ServiceThread mProcStartHandlerThread;
    final Handler mProcStartHandler;
    final ServiceThread mCompactionThread;
    final ActivityManagerConstants mConstants;
@@ -1789,6 +1795,11 @@ public class ActivityManagerService extends IActivityManager.Stub
        }
    };
    static final int COMPACT_PROCESS_SOME = 1;
    static final int COMPACT_PROCESS_FULL = 2;
    static final int COMPACT_PROCESS_MSG = 1;
    final Handler mCompactionHandler;
    static final int COLLECT_PSS_BG_MSG = 1;
    final Handler mBgHandler = new Handler(BackgroundThread.getHandler().getLooper()) {
@@ -2224,6 +2235,8 @@ public class ActivityManagerService extends IActivityManager.Stub
                ? new PendingIntentController(handlerThread.getLooper(), mUserController) : null;
        mProcStartHandlerThread = null;
        mProcStartHandler = null;
        mCompactionThread = null;
        mCompactionHandler = null;
        mHiddenApiBlacklist = null;
        mFactoryTest = FACTORY_TEST_OFF;
    }
@@ -2252,6 +2265,88 @@ public class ActivityManagerService extends IActivityManager.Stub
        mProcStartHandlerThread.start();
        mProcStartHandler = new Handler(mProcStartHandlerThread.getLooper());
        mCompactionThread = new ServiceThread("CompactionThread",
                THREAD_PRIORITY_FOREGROUND, true);
        mCompactionThread.start();
        mCompactionHandler = new Handler(mCompactionThread.getLooper()) {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
            case COMPACT_PROCESS_MSG: {
                long start = SystemClock.uptimeMillis();
                ProcessRecord proc;
                int pid;
                String action;
                final String name;
                int pendingAction, lastCompactAction;
                long lastCompactTime;
                synchronized(ActivityManagerService.this) {
                    proc = mPendingCompactionProcesses.remove(0);
                    // don't compact if the process has returned to perceptible
                    if (proc.setAdj <= ProcessList.PERCEPTIBLE_APP_ADJ) {
                        return;
                    }
                    pid = proc.pid;
                    name = proc.processName;
                    pendingAction = proc.reqCompactAction;
                    lastCompactAction = proc.lastCompactAction;
                    lastCompactTime = proc.lastCompactTime;
                }
                if (pid == 0) {
                    // not a real process, either one being launched or one being killed
                    return;
                }
                // basic throttling
                if (pendingAction == COMPACT_PROCESS_SOME) {
                    // if we're compacting some, then compact if >10s after last full
                    // or >5s after last some
                    if ((lastCompactAction == COMPACT_PROCESS_SOME && (start - lastCompactTime < 5000)) ||
                        (lastCompactAction == COMPACT_PROCESS_FULL && (start - lastCompactTime < 10000)))
                        return;
                } else {
                    // if we're compacting full, then compact if >10s after last full
                    // or >.5s after last some
                    if ((lastCompactAction == COMPACT_PROCESS_SOME && (start - lastCompactTime < 500)) ||
                        (lastCompactAction == COMPACT_PROCESS_FULL && (start - lastCompactTime < 10000)))
                        return;
                }
                try {
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Compact " +
                                     ((pendingAction == COMPACT_PROCESS_SOME) ? "some" : "full") +
                                     ": " + name);
                    long[] rssBefore = Process.getRss(pid);
                    FileOutputStream fos = new FileOutputStream("/proc/" + pid + "/reclaim");
                    if (pendingAction == COMPACT_PROCESS_SOME) {
                        action = "file";
                    } else {
                        action = "all";
                    }
                    fos.write(action.getBytes());
                    fos.close();
                    long[] rssAfter = Process.getRss(pid);
                    long end = SystemClock.uptimeMillis();
                    EventLog.writeEvent(EventLogTags.AM_COMPACT, pid, name, action,
                            rssBefore[0], rssBefore[1], rssBefore[2], rssBefore[3],
                            rssAfter[0], rssAfter[1], rssAfter[2], rssAfter[3], end-start);
                    synchronized(ActivityManagerService.this) {
                        proc.lastCompactTime = end;
                        proc.lastCompactAction = pendingAction;
                    }
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                } catch (Exception e) {
                    // nothing to do, presumably the process died
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                }
            }
            }
        }
        };
        mConstants = new ActivityManagerConstants(this, mHandler);
        mProcessList.init(this);
@@ -2345,13 +2440,15 @@ public class ActivityManagerService extends IActivityManager.Stub
        Watchdog.getInstance().addMonitor(this);
        Watchdog.getInstance().addThread(mHandler);
        // bind background thread to little cores
        // bind background threads to little cores
        // this is expected to fail inside of framework tests because apps can't touch cpusets directly
        // make sure we've already adjusted system_server's internal view of itself first
        updateOomAdjLocked();
        try {
            Process.setThreadGroupAndCpuset(BackgroundThread.get().getThreadId(),
                    Process.THREAD_GROUP_BG_NONINTERACTIVE);
                    Process.THREAD_GROUP_SYSTEM);
            Process.setThreadGroupAndCpuset(mCompactionThread.getThreadId(),
                    Process.THREAD_GROUP_SYSTEM);
        } catch (Exception e) {
            Slog.w(TAG, "Setting background thread cpuset failed");
        }
@@ -16921,6 +17018,24 @@ public class ActivityManagerService extends IActivityManager.Stub
        int changes = 0;
        if (app.curAdj != app.setAdj) {
            // don't compact during bootup
            if (mConstants.USE_COMPACTION && mBooted) {
                // Perform a minor compaction when a perceptible app becomes the prev/home app
                // Perform a major compaction when any app enters cached
                // reminder: here, setAdj is previous state, curAdj is upcoming state
                if (app.setAdj <= ProcessList.PERCEPTIBLE_APP_ADJ &&
                    (app.curAdj == ProcessList.PREVIOUS_APP_ADJ ||
                     app.curAdj == ProcessList.HOME_APP_ADJ)) {
                    app.reqCompactAction = COMPACT_PROCESS_SOME;
                    mPendingCompactionProcesses.add(app);
                    mCompactionHandler.sendEmptyMessage(COMPACT_PROCESS_MSG);
                } else if (app.setAdj < ProcessList.CACHED_APP_MIN_ADJ &&
                           app.curAdj >= ProcessList.CACHED_APP_MIN_ADJ) {
                    app.reqCompactAction = COMPACT_PROCESS_FULL;
                    mPendingCompactionProcesses.add(app);
                    mCompactionHandler.sendEmptyMessage(COMPACT_PROCESS_MSG);
                }
            }
            ProcessList.setOomAdj(app.pid, app.uid, app.curAdj);
            if (DEBUG_SWITCH || DEBUG_OOM_ADJ || mCurOomAdjUid == app.info.uid) {
                String msg = "Set " + app.pid + " " + app.processName + " adj "
+4 −1
Original line number Diff line number Diff line
@@ -136,3 +136,6 @@ option java_package com.android.server.am

# The task is being removed from its parent stack
30061 am_remove_task (Task ID|1|5), (Stack ID|1|5)

# The task is being compacted
30063 am_compact (Pid|1|5),(Process Name|3),(Action|3),(BeforeRssTotal|2|2),(BeforeRssFile|2|2),(BeforeRssAnon|2|2),(BeforeRssSwap|2|2),(AfterRssTotal|2|2),(AfterRssFile|2|2),(AfterRssAnon|2|2),(AfterRssSwap|2|2),(Time|2|3)
 No newline at end of file
+5 −0
Original line number Diff line number Diff line
@@ -145,6 +145,9 @@ final class ProcessRecord implements WindowProcessListener {
    int curAdj;                 // Current OOM adjustment for this process
    int setAdj;                 // Last set OOM adjustment for this process
    int verifiedAdj;            // The last adjustment that was verified as actually being set
    long lastCompactTime;       // The last time that this process was compacted
    int reqCompactAction;       // The most recent compaction action requested for this app.
    int lastCompactAction;      // The most recent compaction action performed for this app.
    private int mCurSchedGroup; // Currently desired scheduling class
    int setSchedGroup;          // Last set to background scheduling class
    int trimMemoryLevel;        // Last selected memory trimming level
@@ -382,6 +385,8 @@ final class ProcessRecord implements WindowProcessListener {
                pw.print(" setRaw="); pw.print(setRawAdj);
                pw.print(" cur="); pw.print(curAdj);
                pw.print(" set="); pw.println(setAdj);
        pw.print(prefix); pw.print("lastCompactTime="); pw.print(lastCompactTime);
                pw.print(" lastCompactAction="); pw.print(lastCompactAction);
        pw.print(prefix); pw.print("mCurSchedGroup="); pw.print(mCurSchedGroup);
                pw.print(" setSchedGroup="); pw.print(setSchedGroup);
                pw.print(" systemNoUi="); pw.print(systemNoUi);