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

Commit 39380dcf authored by Riddle Hsu's avatar Riddle Hsu
Browse files

Remove WM lock from WPC#computeOomAdjFromActivities

Since the result of computeOomAdjFromActivities depends on task
layer rank and activity state. It can be calculated once the states
are changed before oom-adjustment calculation. So when activity
manager asks the result from any reason, it can get the computed
states without entering heavy WM lock.

Also remove lock in WPC#hasVisibleActivities because its returned
result is also computed in computeOomAdjFromActivities.

Bug: 159104503
Test: WindowProcessControllerTests#testComputeOomAdjFromActivities
Change-Id: I797c81a5ebe447802cc02ac37736a0464108836f
parent 697f2d91
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -1909,8 +1909,8 @@ class ProcessRecord implements WindowProcessListener {
        }
        callback.initialize(this, adj, foregroundActivities, procState, schedGroup, appUid, logUid,
                processCurTop);
        final int minLayer = getWindowProcessController().computeOomAdjFromActivities(
                ProcessList.VISIBLE_APP_LAYER_MAX, callback);
        final int minLayer = Math.min(ProcessList.VISIBLE_APP_LAYER_MAX,
                getWindowProcessController().computeOomAdjFromActivities(callback));

        mCachedAdj = callback.adj;
        mCachedForegroundActivities = callback.foregroundActivities;
+3 −0
Original line number Diff line number Diff line
@@ -4465,6 +4465,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
            }
            detachChildren();
        }
        if (app != null) {
            app.invalidateOomScoreReferenceState(false /* computeNow */);
        }

        switch (state) {
            case RESUMED:
+15 −0
Original line number Diff line number Diff line
@@ -276,6 +276,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
    // Whether tasks have moved and we need to rank the tasks before next OOM scoring
    private boolean mTaskLayersChanged = true;
    private int mTmpTaskLayerRank;
    private final ArraySet<WindowProcessController> mTmpTaskLayerChangedProcs = new ArraySet<>();
    private final LockedScheduler mRankTaskLayersScheduler;

    private boolean mTmpBoolean;
@@ -2717,13 +2718,27 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
        mTmpTaskLayerRank = 0;
        // Only rank for leaf tasks because the score of activity is based on immediate parent.
        forAllLeafTasks(task -> {
            final int oldRank = task.mLayerRank;
            final ActivityRecord r = task.topRunningActivityLocked();
            if (r != null && r.mVisibleRequested) {
                task.mLayerRank = ++mTmpTaskLayerRank;
            } else {
                task.mLayerRank = Task.LAYER_RANK_INVISIBLE;
            }
            if (task.mLayerRank != oldRank) {
                task.forAllActivities(activity -> {
                    if (activity.hasProcess()) {
                        mTmpTaskLayerChangedProcs.add(activity.app);
                    }
                });
            }
        }, true /* traverseTopToBottom */);

        for (int i = mTmpTaskLayerChangedProcs.size() - 1; i >= 0; i--) {
            mTmpTaskLayerChangedProcs.valueAt(i).invalidateOomScoreReferenceState(
                    true /* computeNow */);
        }
        mTmpTaskLayerChangedProcs.clear();
    }

    void clearOtherAppTimeTrackers(AppTimeTracker except) {
+117 −55
Original line number Diff line number Diff line
@@ -221,6 +221,9 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
    @Nullable
    private BackgroundActivityStartCallback mBackgroundActivityStartCallback;

    /** The state for oom-adjustment calculation. */
    private final OomScoreReferenceState mOomRefState;

    public WindowProcessController(@NonNull ActivityTaskManagerService atm, ApplicationInfo info,
            String name, int uid, int userId, Object owner, WindowProcessListener listener) {
        mInfo = info;
@@ -232,6 +235,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
        mAtm = atm;
        mDisplayId = INVALID_DISPLAY;
        mBackgroundActivityStartCallback = mAtm.getBackgroundActivityStartCallback();
        mOomRefState = new OomScoreReferenceState(this);

        boolean isSysUiPackage = info.packageName.equals(
                mAtm.getSysUiServiceComponentLocked().getPackageName());
@@ -688,15 +692,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio

    @HotPath(caller = HotPath.OOM_ADJUSTMENT)
    public boolean hasVisibleActivities() {
        synchronized (mAtm.mGlobalLockWithoutBoost) {
            for (int i = mActivities.size() - 1; i >= 0; --i) {
                final ActivityRecord r = mActivities.get(i);
                if (r.mVisibleRequested) {
                    return true;
                }
            }
        }
        return false;
        return (mOomRefState.mActivityStateFlags & OomScoreReferenceState.FLAG_IS_VISIBLE) != 0;
    }

    @HotPath(caller = HotPath.LRU_UPDATE)
@@ -991,6 +987,34 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
        mHostActivities.remove(r);
    }

    private static class OomScoreReferenceState extends RootWindowContainer.LockedScheduler {
        private static final int FLAG_IS_VISIBLE = 0x10000000;
        private static final int FLAG_IS_PAUSING = 0x20000000;
        private static final int FLAG_IS_STOPPING = 0x40000000;
        private static final int FLAG_IS_STOPPING_FINISHING = 0x80000000;
        /** @see Task#mLayerRank */
        private static final int MASK_MIN_TASK_LAYER = 0x0000ffff;

        private final WindowProcessController mOwner;
        boolean mChanged;

        /**
         * The higher 16 bits are the activity states, and the lower 16 bits are the task layer
         * rank. This field is written by window manager and read by activity manager.
         */
        volatile int mActivityStateFlags = MASK_MIN_TASK_LAYER;

        OomScoreReferenceState(WindowProcessController owner) {
            super(owner.mAtm);
            mOwner = owner;
        }

        @Override
        public void execute() {
            mOwner.computeOomScoreReferenceStateIfNeeded();
        }
    }

    public interface ComputeOomAdjCallback {
        void onVisibleActivity();
        void onPausedActivity();
@@ -998,23 +1022,46 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
        void onOtherActivity();
    }

    /**
     * Returns the minimum task layer rank. It should only be called if {@link #hasActivities}
     * returns {@code true}.
     */
    @HotPath(caller = HotPath.OOM_ADJUSTMENT)
    public int computeOomAdjFromActivities(int minTaskLayer, ComputeOomAdjCallback callback) {
    public int computeOomAdjFromActivities(ComputeOomAdjCallback callback) {
        final int flags = mOomRefState.mActivityStateFlags;
        if ((flags & OomScoreReferenceState.FLAG_IS_VISIBLE) != 0) {
            callback.onVisibleActivity();
        } else if ((flags & OomScoreReferenceState.FLAG_IS_PAUSING) != 0) {
            callback.onPausedActivity();
        } else if ((flags & OomScoreReferenceState.FLAG_IS_STOPPING) != 0) {
            callback.onStoppingActivity(
                    (flags & OomScoreReferenceState.FLAG_IS_STOPPING_FINISHING) != 0);
        } else {
            callback.onOtherActivity();
        }
        return flags & OomScoreReferenceState.MASK_MIN_TASK_LAYER;
    }

    void computeOomScoreReferenceStateIfNeeded() {
        if (!mOomRefState.mChanged) {
            return;
        }
        mOomRefState.mChanged = false;

        // Since there could be more than one activities in a process record, we don't need to
        // compute the OomAdj with each of them, just need to find out the activity with the
        // "best" state, the order would be visible, pausing, stopping...
        Task.ActivityState best = DESTROYED;
        boolean finishing = true;
        boolean visible = false;
        synchronized (mAtm.mGlobalLockWithoutBoost) {
            final int activitiesSize = mActivities.size();
            for (int j = 0; j < activitiesSize; j++) {
                final ActivityRecord r = mActivities.get(j);
        int minTaskLayer = Integer.MAX_VALUE;
        for (int i = mActivities.size() - 1; i >= 0; i--) {
            final ActivityRecord r = mActivities.get(i);
            if (r.app != this) {
                    Log.e(TAG, "Found activity " + r + " in proc activity list using " + r.app
                Slog.e(TAG, "Found activity " + r + " in proc activity list using " + r.app
                        + " instead of expected " + this);
                if (r.app == null || (r.app.mUid == mUid)) {
                        // Only fix things up when they look sane
                    // Only fix things up when they look valid.
                    r.setProcess(this);
                } else {
                    continue;
@@ -1032,8 +1079,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
                // continue the loop, in case there are multiple visible activities in
                // this process, we'd find out the one with the minimal layer, thus it'll
                // get a higher adj score.
                } else {
                    if (best != PAUSING && best != PAUSED) {
            } else if (best != PAUSING && best != PAUSED) {
                if (r.isState(PAUSING, PAUSED)) {
                    best = PAUSING;
                } else if (r.isState(STOPPING)) {
@@ -1042,20 +1088,36 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
                    finishing &= r.finishing;
                }
            }
                }
            }
        }

            int stateFlags = minTaskLayer & OomScoreReferenceState.MASK_MIN_TASK_LAYER;
            if (visible) {
            callback.onVisibleActivity();
                stateFlags |= OomScoreReferenceState.FLAG_IS_VISIBLE;
            } else if (best == PAUSING) {
            callback.onPausedActivity();
                stateFlags |= OomScoreReferenceState.FLAG_IS_PAUSING;
            } else if (best == STOPPING) {
            callback.onStoppingActivity(finishing);
        } else {
            callback.onOtherActivity();
                stateFlags |= OomScoreReferenceState.FLAG_IS_STOPPING;
                if (finishing) {
                    stateFlags |= OomScoreReferenceState.FLAG_IS_STOPPING_FINISHING;
                }
            }
            mOomRefState.mActivityStateFlags = stateFlags;
        }
    }

        return minTaskLayer;
    void invalidateOomScoreReferenceState(boolean computeNow) {
        mOomRefState.mChanged = true;
        if (computeNow) {
            computeOomScoreReferenceStateIfNeeded();
            return;
        }
        mOomRefState.scheduleIfNeeded();
    }

    /** Called when the process has some oom related changes and it is going to update oom-adj. */
    private void prepareOomAdjustment() {
        mAtm.mRootWindowContainer.rankTaskLayersIfNeeded();
        // The task layer may not change but the activity state in the same task may change.
        computeOomScoreReferenceStateIfNeeded();
    }

    public int computeRelaunchReason() {
@@ -1098,7 +1160,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
            mAtm.mAmInternal.addPendingTopUid(mUid, mPid);
        }
        if (updateOomAdj) {
            mAtm.mRootWindowContainer.rankTaskLayersIfNeeded();
            prepareOomAdjustment();
        }
        // Posting on handler so WM lock isn't held when we call into AM.
        final Message m = PooledLambda.obtainMessage(WindowProcessListener::updateProcessInfo,
@@ -1161,7 +1223,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
        if (topProcessState == ActivityManager.PROCESS_STATE_TOP) {
            mAtm.mAmInternal.addPendingTopUid(mUid, mPid);
        }
        mAtm.mRootWindowContainer.rankTaskLayersIfNeeded();
        prepareOomAdjustment();
        // Posting the message at the front of queue so WM lock isn't held when we call into AM,
        // and the process state of starting activity can be updated quicker which will give it a
        // higher scheduling group.
+2 −2
Original line number Diff line number Diff line
@@ -351,7 +351,7 @@ public class MockingOomAdjusterTests {
        doReturn(mock(WindowProcessController.class)).when(app).getWindowProcessController();
        WindowProcessController wpc = app.getWindowProcessController();
        doReturn(true).when(wpc).hasActivities();
        doAnswer(answer((minTaskLayer, callback) -> {
        doAnswer(answer(callback -> {
            Field field = callback.getClass().getDeclaredField("adj");
            field.set(callback, VISIBLE_APP_ADJ);
            field = callback.getClass().getDeclaredField("foregroundActivities");
@@ -361,7 +361,7 @@ public class MockingOomAdjusterTests {
            field = callback.getClass().getDeclaredField("schedGroup");
            field.set(callback, SCHED_GROUP_TOP_APP);
            return 0;
        })).when(wpc).computeOomAdjFromActivities(anyInt(),
        })).when(wpc).computeOomAdjFromActivities(
                any(WindowProcessController.ComputeOomAdjCallback.class));
        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
Loading