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

Commit 8b5cdef0 authored by Marco Ballesio's avatar Marco Ballesio
Browse files

CachedAppOptimizer: adapt freezer to uid/pid hiearchy.

The uid/pid hierarchy freezer is supported if the cgroup.freeze file is
present under any uid cgroup. Check on uid_0 which is granted to exist.

Also handle binder when enabling/disabling freezer. Freeze the binder interfaces
for all froze processes after enabling the app freezer. Similarly, unfreeze the
interfaces of frozen processes when the app freezer is enabled.

Bug: 168907513
Bug: 173173405
Test: verified proper functioning of the freezer after boot on devices
supporting the uid/pid hierarchy.
Test: ran "adb shell am dumpsys meminfo -a", verified that no processes
were killed by ActivityManager and that the command did not hang.

Change-Id: Ia7fa25cb6c59da73d34460ead4833cec69f7f6bc
parent d23e0827
Loading
Loading
Loading
Loading
+52 −22
Original line number Diff line number Diff line
@@ -232,6 +232,8 @@ public final class CachedAppOptimizer {
    @VisibleForTesting
    Handler mCompactionHandler;
    private Handler mFreezeHandler;
    @GuardedBy("mAm")
    private boolean mFreezerOverride = false;

    // Maps process ID to last compaction statistics for processes that we've fully compacted. Used
    // when evaluating throttles that we only consider for "full" compaction, so we don't store
@@ -454,21 +456,35 @@ public final class CachedAppOptimizer {
            }
        }

        try {
            enableFreezerInternal(enable);
            return true;
        } catch (java.lang.RuntimeException e) {
            if (enable) {
                mFreezerDisableCount = 0;
            } else {
                mFreezerDisableCount = 1;
        // Override is applied immediately, restore is delayed
        synchronized (mAm) {
            int processCount = mAm.mProcessList.mLruProcesses.size();

            mFreezerOverride = !enable;
            Slog.d(TAG_AM, "freezer override set to " + mFreezerOverride);

            for (int i = 0; i < processCount; i++) {
                ProcessRecord process = mAm.mProcessList.mLruProcesses.get(i);

                if (process == null) {
                    continue;
                }

            Slog.e(TAG_AM, "Exception handling freezer state (enable: " + enable + "): "
                    + e.toString());
                if (enable && process.freezerOverride) {
                    freezeAppAsync(process);
                    process.freezerOverride = false;
                }

        return false;
                if (!enable && process.frozen) {
                    unfreezeAppLocked(process);

                    // Set freezerOverride *after* calling unfreezeAppLocked (it resets the flag)
                    process.freezerOverride = true;
                }
            }
        }

        return true;
    }

    /**
@@ -515,7 +531,7 @@ public final class CachedAppOptimizer {
        FileReader fr = null;

        try {
            fr = new FileReader("/sys/fs/cgroup/freezer/cgroup.freeze");
            fr = new FileReader("/sys/fs/cgroup/uid_0/cgroup.freeze");
            char state = (char) fr.read();

            if (state == '1' || state == '0') {
@@ -744,6 +760,8 @@ public final class CachedAppOptimizer {
    void unfreezeAppLocked(ProcessRecord app) {
        mFreezeHandler.removeMessages(SET_FROZEN_PROCESS_MSG, app);

        app.freezerOverride = false;

        if (!app.frozen) {
            if (DEBUG_FREEZER) {
                Slog.d(TAG_AM,
@@ -753,6 +771,8 @@ public final class CachedAppOptimizer {
            return;
        }

        // Unfreeze the binder interface first, to avoid transactions triggered by timers fired
        // right after unfreezing the process to fail
        boolean processKilled = false;

        try {
@@ -1131,12 +1151,31 @@ public final class CachedAppOptimizer {
                    return;
                }

                if (mFreezerOverride) {
                    proc.freezerOverride = true;
                    Slog.d(TAG_AM, "Skipping freeze for process " + pid
                            + " " + name + " curAdj = " + proc.curAdj
                            + "(override)");
                    return;
                }

                if (pid == 0 || proc.frozen) {
                    // Already frozen or not a real process, either one being
                    // launched or one being killed
                    return;
                }

                // Freeze binder interface before the process, to flush any
                // transactions that might be pending.
                try {
                    freezeBinder(pid, true);
                } catch (RuntimeException e) {
                    Slog.e(TAG_AM, "Unable to freeze binder for " + pid + " " + name);
                    proc.kill("Unable to freeze binder interface",
                            ApplicationExitInfo.REASON_OTHER,
                            ApplicationExitInfo.SUBREASON_INVALID_STATE, true);
                }

                long unfreezeTime = proc.freezeUnfreezeTime;

                try {
@@ -1163,15 +1202,6 @@ public final class CachedAppOptimizer {

            EventLog.writeEvent(EventLogTags.AM_FREEZE, pid, name);

            try {
                freezeBinder(pid, true);
            } catch (RuntimeException e) {
                Slog.e(TAG_AM, "Unable to freeze binder for " + pid + " " + name);
                proc.kill("Unable to freeze binder interface",
                        ApplicationExitInfo.REASON_OTHER,
                        ApplicationExitInfo.SUBREASON_INVALID_STATE, true);
            }

            // See above for why we're not taking mPhenotypeFlagLock here
            if (mRandom.nextFloat() < mFreezerStatsdSampleRate) {
                FrameworkStatsLog.write(FrameworkStatsLog.APP_FREEZE_CHANGED,
+1 −0
Original line number Diff line number Diff line
@@ -179,6 +179,7 @@ class ProcessRecord implements WindowProcessListener {
    int reqCompactAction;       // The most recent compaction action requested for this app.
    int lastCompactAction;      // The most recent compaction action performed for this app.
    boolean frozen;             // True when the process is frozen.
    boolean freezerOverride;     // An override on the freeze state is in progress.
    long freezeUnfreezeTime;    // Last time the app was (un)frozen, 0 for never
    boolean shouldNotFreeze;    // True if a process has a WPRI binding from an unfrozen process
    private int mCurSchedGroup; // Currently desired scheduling class