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

Commit 7400289b authored by Chih-Yu Huang's avatar Chih-Yu Huang
Browse files

Move activity OOM adjustment computation to OomAdjuster

The logic for calculating the initial importance of processes with
activities (`computeOomAdjFromActivitiesIfNecessary`) has been
relocated. This functionality, previously in `ProcessStateRecord`,
is now within `OomAdjuster` via the new `OomAdjWindowCalculator`
inner class.

This change reduces the dependency of `ProcessStateRecord` on
`ProcessRecord` and centralizes the OOM adjustment logic within
`OomAdjuster` for better modularity.

Bug: 425766486
Test: atest MockingOomAdjusterTests
Flag: EXEMPT pure refactor

Change-Id: I6a540a50a7f826ca37218566f62afd29d52b93d8
parent 20780af5
Loading
Loading
Loading
Loading
+133 −72
Original line number Diff line number Diff line
@@ -106,6 +106,11 @@ import static com.android.server.am.ProcessList.UNKNOWN_ADJ;
import static com.android.server.am.ProcessList.VISIBLE_APP_ADJ;
import static com.android.server.am.psc.PlatformCompatCache.CACHED_COMPAT_CHANGE_USE_SHORT_FGS_USAGE_INTERACTION_TIME;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
import static com.android.server.wm.WindowProcessController.ACTIVITY_STATE_FLAG_IS_PAUSING_OR_PAUSED;
import static com.android.server.wm.WindowProcessController.ACTIVITY_STATE_FLAG_IS_STOPPING;
import static com.android.server.wm.WindowProcessController.ACTIVITY_STATE_FLAG_IS_STOPPING_FINISHING;
import static com.android.server.wm.WindowProcessController.ACTIVITY_STATE_FLAG_IS_VISIBLE;
import static com.android.server.wm.WindowProcessController.ACTIVITY_STATE_FLAG_MASK_MIN_TASK_LAYER;

import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -1503,114 +1508,170 @@ public abstract class OomAdjuster {
        return true;
    }

    protected final ComputeOomAdjWindowCallback mTmpComputeOomAdjWindowCallback =
            new ComputeOomAdjWindowCallback();
    protected final OomAdjWindowCalculator mTmpOomAdjWindowCalculator =
            new OomAdjWindowCalculator();

    /** These methods are called inline during computeOomAdjLSP(), on the same thread */
    final class ComputeOomAdjWindowCallback {
    /**
     * The computeOomAdjFromActivitiesIfNecessary method computes the initial importance of the
     * process which contains activities and is not the global top. The importance are stored at the
     * ProcessStateRecord's cached fields.
     * The method is called during computeOomAdjLSP(), on the same thread.
     */
    final class OomAdjWindowCalculator {
        private ProcessRecord mApp;
        private int mAdj;
        private boolean mForegroundActivities;
        private boolean mHasVisibleActivities;
        private int mProcState;
        private int mSchedGroup;
        private int mAppUid;
        private int mLogUid;
        private int mProcessStateCurTop;
        private String mAdjType;
        private ProcessStateRecord mState;

        @GuardedBy("this.OomAdjuster.mService")
        int getAdj() {
            return mAdj;
        }

        @GuardedBy("this.OomAdjuster.mService")
        void computeOomAdjFromActivitiesIfNecessary(ProcessRecord app, int adj,
                boolean foregroundActivities, boolean hasVisibleActivities, int procState,
                int schedGroup, int appUid, int logUid, int processCurTop) {
            if (app.mState.getCachedAdj() != ProcessList.INVALID_ADJ) {
                return;
            }
            initialize(app, adj, foregroundActivities, hasVisibleActivities, procState,
                    schedGroup, appUid, logUid, processCurTop);

        ProcessRecord app;
        int adj;
        boolean foregroundActivities;
        boolean mHasVisibleActivities;
        int procState;
        int schedGroup;
        int appUid;
        int logUid;
        int processStateCurTop;
        String mAdjType;
        ProcessStateRecord mState;
            final int flags;
            if (Flags.pushActivityStateToOomadjuster()) {
                flags = mState.getActivityStateFlags();
            } else {
                flags = mApp.getWindowProcessController().getActivityStateFlags();
            }

            if ((flags & ACTIVITY_STATE_FLAG_IS_VISIBLE) != 0) {
                onVisibleActivity(flags);
            } else if ((flags & ACTIVITY_STATE_FLAG_IS_PAUSING_OR_PAUSED) != 0) {
                onPausedActivity();
            } else if ((flags & ACTIVITY_STATE_FLAG_IS_STOPPING) != 0) {
                onStoppingActivity((flags & ACTIVITY_STATE_FLAG_IS_STOPPING_FINISHING) != 0);
            } else {
                final long ts;
                if (Flags.pushActivityStateToOomadjuster()) {
                    ts = mState.getPerceptibleTaskStoppedTimeMillis();
                } else {
                    ts = mApp.getWindowProcessController().getPerceptibleTaskStoppedTimeMillis();
                }
                onOtherActivity(ts);
            }

            if (mAdj == ProcessList.VISIBLE_APP_ADJ) {
                final int taskLayer = flags & ACTIVITY_STATE_FLAG_MASK_MIN_TASK_LAYER;
                final int minLayer = Math.min(ProcessList.VISIBLE_APP_LAYER_MAX, taskLayer);
                mAdj += minLayer;
            }

            mState.setCachedAdj(mAdj);
            mState.setCachedForegroundActivities(mForegroundActivities);
            mState.setCachedHasVisibleActivities(mHasVisibleActivities);
            mState.setCachedProcState(mProcState);
            mState.setCachedSchedGroup(mSchedGroup);
            mState.setCachedAdjType(mAdjType);
        }

        void initialize(ProcessRecord app, int adj, boolean foregroundActivities,
                boolean hasVisibleActivities, int procState, int schedGroup, int appUid,
                int logUid, int processStateCurTop) {
            this.app = app;
            this.adj = adj;
            this.foregroundActivities = foregroundActivities;
            this.mApp = app;
            this.mAdj = adj;
            this.mForegroundActivities = foregroundActivities;
            this.mHasVisibleActivities = hasVisibleActivities;
            this.procState = procState;
            this.schedGroup = schedGroup;
            this.appUid = appUid;
            this.logUid = logUid;
            this.processStateCurTop = processStateCurTop;
            mAdjType = app.mState.getAdjType();
            this.mProcState = procState;
            this.mSchedGroup = schedGroup;
            this.mAppUid = appUid;
            this.mLogUid = logUid;
            this.mProcessStateCurTop = processStateCurTop;
            this.mAdjType = app.mState.getAdjType();
            this.mState = app.mState;
        }

        void onVisibleActivity(int flags) {
            // App has a visible activity; only upgrade adjustment.
            if (adj > VISIBLE_APP_ADJ) {
                adj = VISIBLE_APP_ADJ;
            if (mAdj > VISIBLE_APP_ADJ) {
                mAdj = VISIBLE_APP_ADJ;
                mAdjType = "vis-activity";
                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
                    reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise adj to vis-activity: " + app);
                if (DEBUG_OOM_ADJ_REASON || mLogUid == mAppUid) {
                    reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise adj to vis-activity: " + mApp);
                }
            }
            if (procState > processStateCurTop) {
                procState = processStateCurTop;
            if (mProcState > mProcessStateCurTop) {
                mProcState = mProcessStateCurTop;
                mAdjType = "vis-activity";
                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
                if (DEBUG_OOM_ADJ_REASON || mLogUid == mAppUid) {
                    reportOomAdjMessageLocked(TAG_OOM_ADJ,
                            "Raise procstate to vis-activity (top): " + app);
                            "Raise procstate to vis-activity (top): " + mApp);
                }
            }
            if (schedGroup < SCHED_GROUP_DEFAULT) {
                schedGroup = SCHED_GROUP_DEFAULT;
            if (mSchedGroup < SCHED_GROUP_DEFAULT) {
                mSchedGroup = SCHED_GROUP_DEFAULT;
            }
            if ((flags & WindowProcessController.ACTIVITY_STATE_FLAG_RESUMED_SPLIT_SCREEN) != 0) {
                // Another side of split should be the current global top. Use the same top
                // priority for this non-top split.
                schedGroup = SCHED_GROUP_TOP_APP;
                mSchedGroup = SCHED_GROUP_TOP_APP;
                mAdjType = "resumed-split-screen-activity";
            } else if ((flags
                    & WindowProcessController.ACTIVITY_STATE_FLAG_PERCEPTIBLE_FREEFORM) != 0) {
                // The recently used non-top visible freeform app.
                schedGroup = SCHED_GROUP_TOP_APP;
                mSchedGroup = SCHED_GROUP_TOP_APP;
                mAdjType = "perceptible-freeform-activity";
            } else if ((flags
                    & WindowProcessController.ACTIVITY_STATE_FLAG_VISIBLE_MULTI_WINDOW_MODE) != 0) {
                // Currently the only case is from freeform apps which are not close to top.
                schedGroup = SCHED_GROUP_FOREGROUND_WINDOW;
                mSchedGroup = SCHED_GROUP_FOREGROUND_WINDOW;
                mAdjType = "vis-multi-window-activity";
            } else if ((flags
                    & WindowProcessController.ACTIVITY_STATE_FLAG_OCCLUDED_FREEFORM) != 0) {
                schedGroup = SCHED_GROUP_BACKGROUND;
                mSchedGroup = SCHED_GROUP_BACKGROUND;
                mAdjType = "occluded-freeform-activity";
            }
            foregroundActivities = true;
            mForegroundActivities = true;
            mHasVisibleActivities = true;
        }

        void onPausedActivity() {
            if (adj > PERCEPTIBLE_APP_ADJ) {
                adj = PERCEPTIBLE_APP_ADJ;
            if (mAdj > PERCEPTIBLE_APP_ADJ) {
                mAdj = PERCEPTIBLE_APP_ADJ;
                mAdjType = "pause-activity";
                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
                    reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise adj to pause-activity: "  + app);
                if (DEBUG_OOM_ADJ_REASON || mLogUid == mAppUid) {
                    reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise adj to pause-activity: "  + mApp);
                }
            }
            if (procState > processStateCurTop) {
                procState = processStateCurTop;
            if (mProcState > mProcessStateCurTop) {
                mProcState = mProcessStateCurTop;
                mAdjType = "pause-activity";
                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
                if (DEBUG_OOM_ADJ_REASON || mLogUid == mAppUid) {
                    reportOomAdjMessageLocked(TAG_OOM_ADJ,
                            "Raise procstate to pause-activity (top): "  + app);
                            "Raise procstate to pause-activity (top): "  + mApp);
                }
            }
            if (schedGroup < SCHED_GROUP_DEFAULT) {
                schedGroup = SCHED_GROUP_DEFAULT;
            if (mSchedGroup < SCHED_GROUP_DEFAULT) {
                mSchedGroup = SCHED_GROUP_DEFAULT;
            }
            foregroundActivities = true;
            mForegroundActivities = true;
            mHasVisibleActivities = false;
        }

        void onStoppingActivity(boolean finishing) {
            if (adj > PERCEPTIBLE_APP_ADJ) {
                adj = PERCEPTIBLE_APP_ADJ;
            if (mAdj > PERCEPTIBLE_APP_ADJ) {
                mAdj = PERCEPTIBLE_APP_ADJ;
                mAdjType = "stop-activity";
                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
                if (DEBUG_OOM_ADJ_REASON || mLogUid == mAppUid) {
                    reportOomAdjMessageLocked(TAG_OOM_ADJ,
                            "Raise adj to stop-activity: "  + app);
                            "Raise adj to stop-activity: "  + mApp);
                }
            }

@@ -1621,46 +1682,46 @@ public abstract class OomAdjuster {
            // since there can be an arbitrary number of stopping processes and they should soon all
            // go into the cached state.
            if (!finishing) {
                if (procState > PROCESS_STATE_LAST_ACTIVITY) {
                    procState = PROCESS_STATE_LAST_ACTIVITY;
                if (mProcState > PROCESS_STATE_LAST_ACTIVITY) {
                    mProcState = PROCESS_STATE_LAST_ACTIVITY;
                    mAdjType = "stop-activity";
                    if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
                    if (DEBUG_OOM_ADJ_REASON || mLogUid == mAppUid) {
                        reportOomAdjMessageLocked(TAG_OOM_ADJ,
                                "Raise procstate to stop-activity: " + app);
                                "Raise procstate to stop-activity: " + mApp);
                    }
                }
            }
            foregroundActivities = true;
            mForegroundActivities = true;
            mHasVisibleActivities = false;
        }

        void onOtherActivity(long perceptibleTaskStoppedTimeMillis) {
            if (procState > PROCESS_STATE_CACHED_ACTIVITY) {
                procState = PROCESS_STATE_CACHED_ACTIVITY;
            if (mProcState > PROCESS_STATE_CACHED_ACTIVITY) {
                mProcState = PROCESS_STATE_CACHED_ACTIVITY;
                mAdjType = "cch-act";
                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
                if (DEBUG_OOM_ADJ_REASON || mLogUid == mAppUid) {
                    reportOomAdjMessageLocked(TAG_OOM_ADJ,
                            "Raise procstate to cached activity: " + app);
                            "Raise procstate to cached activity: " + mApp);
                }
            }
            if (Flags.perceptibleTasks() && adj > PERCEPTIBLE_MEDIUM_APP_ADJ) {
            if (Flags.perceptibleTasks() && mAdj > PERCEPTIBLE_MEDIUM_APP_ADJ) {
                if (perceptibleTaskStoppedTimeMillis >= 0) {
                    final long now = mInjector.getUptimeMillis();
                    if (now - perceptibleTaskStoppedTimeMillis < PERCEPTIBLE_TASK_TIMEOUT_MILLIS) {
                        adj = PERCEPTIBLE_MEDIUM_APP_ADJ;
                        mAdj = PERCEPTIBLE_MEDIUM_APP_ADJ;
                        mAdjType = "perceptible-act";
                        if (procState > PROCESS_STATE_IMPORTANT_BACKGROUND) {
                            procState = PROCESS_STATE_IMPORTANT_BACKGROUND;
                        if (mProcState > PROCESS_STATE_IMPORTANT_BACKGROUND) {
                            mProcState = PROCESS_STATE_IMPORTANT_BACKGROUND;
                        }

                        maybeSetProcessFollowUpUpdateLocked(app,
                        maybeSetProcessFollowUpUpdateLocked(mApp,
                                perceptibleTaskStoppedTimeMillis + PERCEPTIBLE_TASK_TIMEOUT_MILLIS,
                                now);
                    } else if (adj > PREVIOUS_APP_ADJ) {
                        adj = PREVIOUS_APP_ADJ;
                    } else if (mAdj > PREVIOUS_APP_ADJ) {
                        mAdj = PREVIOUS_APP_ADJ;
                        mAdjType = "stale-perceptible-act";
                        if (procState > PROCESS_STATE_LAST_ACTIVITY) {
                            procState = PROCESS_STATE_LAST_ACTIVITY;
                        if (mProcState > PROCESS_STATE_LAST_ACTIVITY) {
                            mProcState = PROCESS_STATE_LAST_ACTIVITY;
                        }
                    }
                }
+3 −3
Original line number Diff line number Diff line
@@ -1339,9 +1339,9 @@ public class OomAdjusterImpl extends OomAdjuster {
        // Examine all non-top activities.
        boolean foregroundActivities = app == topApp;
        if (!foregroundActivities && state.getHasActivities()) {
            state.computeOomAdjFromActivitiesIfNecessary(mTmpComputeOomAdjWindowCallback,
                    adj, foregroundActivities, hasVisibleActivities, procState, schedGroup,
                    appUid, logUid, PROCESS_STATE_CUR_TOP);
            mTmpOomAdjWindowCalculator.computeOomAdjFromActivitiesIfNecessary(app, adj,
                    foregroundActivities, hasVisibleActivities, procState, schedGroup, appUid,
                    logUid, PROCESS_STATE_CUR_TOP);

            adj = state.getCachedAdj();
            foregroundActivities = state.getCachedForegroundActivities();
+40 −52
Original line number Diff line number Diff line
@@ -23,9 +23,6 @@ import static android.app.ProcessMemoryState.HOSTING_COMPONENT_TYPE_ACTIVITY;
import static android.app.ProcessMemoryState.HOSTING_COMPONENT_TYPE_BROADCAST_RECEIVER;

import static com.android.server.am.ProcessList.CACHED_APP_MIN_ADJ;
import static com.android.server.wm.WindowProcessController.ACTIVITY_STATE_FLAG_IS_PAUSING_OR_PAUSED;
import static com.android.server.wm.WindowProcessController.ACTIVITY_STATE_FLAG_IS_STOPPING;
import static com.android.server.wm.WindowProcessController.ACTIVITY_STATE_FLAG_IS_STOPPING_FINISHING;
import static com.android.server.wm.WindowProcessController.ACTIVITY_STATE_FLAG_IS_VISIBLE;
import static com.android.server.wm.WindowProcessController.ACTIVITY_STATE_FLAG_MASK_MIN_TASK_LAYER;

@@ -1060,11 +1057,21 @@ public final class ProcessStateRecord {
        mHasActivities = hasActivities;
    }

    @GuardedBy("mService")
    int getActivityStateFlags() {
        return mActivityStateFlags;
    }

    @GuardedBy("mService")
    void setActivityStateFlags(int flags) {
        mActivityStateFlags = flags;
    }

    @GuardedBy("mService")
    long getPerceptibleTaskStoppedTimeMillis() {
        return mPerceptibleTaskStoppedTimeMillis;
    }

    @GuardedBy("mService")
    void setPerceptibleTaskStoppedTimeMillis(long uptimeMs) {
        mPerceptibleTaskStoppedTimeMillis = uptimeMs;
@@ -1126,12 +1133,16 @@ public final class ProcessStateRecord {
    @GuardedBy("mService")
    private boolean getCachedHasVisibleActivities() {
        if (mCachedHasVisibleActivities == VALUE_INVALID) {
            mCachedHasVisibleActivities = mApp.getWindowProcessController().hasVisibleActivities()
                    ? VALUE_TRUE : VALUE_FALSE;
            setCachedHasVisibleActivities(mApp.getWindowProcessController().hasVisibleActivities());
        }
        return mCachedHasVisibleActivities == VALUE_TRUE;
    }

    @GuardedBy("mService")
    void setCachedHasVisibleActivities(boolean cachedHasVisibleActivities) {
        mCachedHasVisibleActivities = cachedHasVisibleActivities ? VALUE_TRUE : VALUE_FALSE;
    }

    @GuardedBy("mService")
    boolean getHasVisibleActivities() {
        if (Flags.pushActivityStateToOomadjuster()) {
@@ -1208,57 +1219,14 @@ public final class ProcessStateRecord {
        return mCachedCompatChanges[cachedCompatChangeId] == VALUE_TRUE;
    }

    /** This is only called if the process contains activities and is not the global top. */
    @GuardedBy("mService")
    void computeOomAdjFromActivitiesIfNecessary(OomAdjuster.ComputeOomAdjWindowCallback callback,
            int adj, boolean foregroundActivities, boolean hasVisibleActivities, int procState,
            int schedGroup, int appUid, int logUid, int processCurTop) {
        if (mCachedAdj != ProcessList.INVALID_ADJ) {
            return;
        }
        callback.initialize(mApp, adj, foregroundActivities, hasVisibleActivities, procState,
                schedGroup, appUid, logUid, processCurTop);
        final int flags;
        if (Flags.pushActivityStateToOomadjuster()) {
            flags = mActivityStateFlags;
        } else {
            flags = mApp.getWindowProcessController().getActivityStateFlags();
        }

        if ((flags & ACTIVITY_STATE_FLAG_IS_VISIBLE) != 0) {
            callback.onVisibleActivity(flags);
        } else if ((flags & ACTIVITY_STATE_FLAG_IS_PAUSING_OR_PAUSED) != 0) {
            callback.onPausedActivity();
        } else if ((flags & ACTIVITY_STATE_FLAG_IS_STOPPING) != 0) {
            callback.onStoppingActivity((flags & ACTIVITY_STATE_FLAG_IS_STOPPING_FINISHING) != 0);
        } else {
            final long ts;
            if (Flags.pushActivityStateToOomadjuster()) {
                ts = mPerceptibleTaskStoppedTimeMillis;
            } else {
                ts = mApp.getWindowProcessController().getPerceptibleTaskStoppedTimeMillis();
            }

            callback.onOtherActivity(ts);
        }

        mCachedAdj = callback.adj;
        mCachedForegroundActivities = callback.foregroundActivities;
        mCachedHasVisibleActivities = callback.mHasVisibleActivities ? VALUE_TRUE : VALUE_FALSE;
        mCachedProcState = callback.procState;
        mCachedSchedGroup = callback.schedGroup;
        mCachedAdjType = callback.mAdjType;

        if (mCachedAdj == ProcessList.VISIBLE_APP_ADJ) {
            final int taskLayer = flags & ACTIVITY_STATE_FLAG_MASK_MIN_TASK_LAYER;
            final int minLayer = Math.min(ProcessList.VISIBLE_APP_LAYER_MAX, taskLayer);
            mCachedAdj += minLayer;
        }
    int getCachedAdj() {
        return mCachedAdj;
    }

    @GuardedBy("mService")
    int getCachedAdj() {
        return mCachedAdj;
    void setCachedAdj(int cachedAdj) {
        mCachedAdj = cachedAdj;
    }

    @GuardedBy("mService")
@@ -1266,21 +1234,41 @@ public final class ProcessStateRecord {
        return mCachedForegroundActivities;
    }

    @GuardedBy("mService")
    void setCachedForegroundActivities(boolean cachedForegroundActivities) {
        mCachedForegroundActivities = cachedForegroundActivities;
    }

    @GuardedBy("mService")
    int getCachedProcState() {
        return mCachedProcState;
    }

    @GuardedBy("mService")
    void setCachedProcState(int cachedProcState) {
        mCachedProcState = cachedProcState;
    }

    @GuardedBy("mService")
    int getCachedSchedGroup() {
        return mCachedSchedGroup;
    }

    @GuardedBy("mService")
    void setCachedSchedGroup(int cachedSchedGroup) {
        mCachedSchedGroup = cachedSchedGroup;
    }

    @GuardedBy("mService")
    String getCachedAdjType() {
        return mCachedAdjType;
    }

    @GuardedBy("mService")
    void setCachedAdjType(String cachedAdjType) {
        mCachedAdjType = cachedAdjType;
    }

    @GuardedBy("mService")
    boolean shouldScheduleLikeTopApp() {
        return mScheduleLikeTopApp;
+9 −9
Original line number Diff line number Diff line
@@ -3497,35 +3497,35 @@ public class MockingOomAdjusterTests {
        // GIVEN: perceptible adjustment is NOT enabled (perceptible stop time is not set)
        // EXPECT: zero adjustment
        // TLDR: App is not set as a perceptible task and hence no oom_adj boosting.
        mService.mOomAdjuster.mTmpComputeOomAdjWindowCallback.initialize(app, CACHED_APP_MIN_ADJ,
        mService.mOomAdjuster.mTmpOomAdjWindowCalculator.initialize(app, CACHED_APP_MIN_ADJ,
                false, false, PROCESS_STATE_CACHED_ACTIVITY,
                SCHED_GROUP_DEFAULT, 0, 0, PROCESS_STATE_IMPORTANT_FOREGROUND);
        mService.mOomAdjuster.mTmpComputeOomAdjWindowCallback.onOtherActivity(-1);
        assertEquals(CACHED_APP_MIN_ADJ, mService.mOomAdjuster.mTmpComputeOomAdjWindowCallback.adj);
        mService.mOomAdjuster.mTmpOomAdjWindowCalculator.onOtherActivity(-1);
        assertEquals(CACHED_APP_MIN_ADJ, mService.mOomAdjuster.mTmpOomAdjWindowCalculator.getAdj());

        // GIVEN: perceptible adjustment is enabled (perceptible stop time is set) and
        //        elapsed time < PERCEPTIBLE_TASK_TIMEOUT
        // EXPECT: adjustment to PERCEPTIBLE_MEDIUM_APP_ADJ
        // TLDR: App is a perceptible task (e.g. opened from launcher) and has oom_adj boosting.
        mService.mOomAdjuster.mTmpComputeOomAdjWindowCallback.initialize(app, CACHED_APP_MIN_ADJ,
        mService.mOomAdjuster.mTmpOomAdjWindowCalculator.initialize(app, CACHED_APP_MIN_ADJ,
                false, false, PROCESS_STATE_CACHED_ACTIVITY,
                SCHED_GROUP_DEFAULT, 0, 0, PROCESS_STATE_IMPORTANT_FOREGROUND);
        mInjector.reset();
        mService.mOomAdjuster.mTmpComputeOomAdjWindowCallback.onOtherActivity(now);
        mService.mOomAdjuster.mTmpOomAdjWindowCalculator.onOtherActivity(now);
        assertEquals(PERCEPTIBLE_MEDIUM_APP_ADJ,
                mService.mOomAdjuster.mTmpComputeOomAdjWindowCallback.adj);
                mService.mOomAdjuster.mTmpOomAdjWindowCalculator.getAdj());

        // GIVEN: perceptible adjustment is enabled (perceptible stop time is set) and
        //        elapsed time >  PERCEPTIBLE_TASK_TIMEOUT
        // EXPECT: adjustment to PREVIOUS_APP_ADJ
        // TLDR: App is a perceptible task (e.g. opened from launcher) and has oom_adj boosting, but
        //       time has elapsed and has dropped to a lower boosting of PREVIOUS_APP_ADJ
        mService.mOomAdjuster.mTmpComputeOomAdjWindowCallback.initialize(app, CACHED_APP_MIN_ADJ,
        mService.mOomAdjuster.mTmpOomAdjWindowCalculator.initialize(app, CACHED_APP_MIN_ADJ,
                false, false, PROCESS_STATE_CACHED_ACTIVITY,
                SCHED_GROUP_DEFAULT, 0, 0, PROCESS_STATE_IMPORTANT_FOREGROUND);
        mInjector.jumpUptimeAheadTo(OomAdjuster.PERCEPTIBLE_TASK_TIMEOUT_MILLIS + 1000);
        mService.mOomAdjuster.mTmpComputeOomAdjWindowCallback.onOtherActivity(0);
        assertEquals(PREVIOUS_APP_ADJ, mService.mOomAdjuster.mTmpComputeOomAdjWindowCallback.adj);
        mService.mOomAdjuster.mTmpOomAdjWindowCalculator.onOtherActivity(0);
        assertEquals(PREVIOUS_APP_ADJ, mService.mOomAdjuster.mTmpOomAdjWindowCalculator.getAdj());
    }

    /**