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

Commit 28197484 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Add ProcessStateController batching API for Activity state changes" into main

parents d80d3350 ba70b09f
Loading
Loading
Loading
Loading
+178 −55
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ import com.android.server.ServiceThread;
import com.android.server.wm.WindowProcessController;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.function.BiConsumer;
import java.util.function.Consumer;

@@ -777,14 +778,37 @@ public class ProcessStateController {
     * ProcessStateController. Because ProcessStateController is guarded by a lock WindowManager
     * avoids acquiring, all of the work will posted to the provided Looper's thread with the
     * provided lock object.
     *
     * ActivityStateAsyncUpdater is not thread-safe and its usage should always be guarded by the
     * WindowManagerGlobalLock.
     */
    public static class ActivityStateAsyncUpdater {
        private final ProcessStateController mPsc;
        private final Handler mHandler;
        private final Looper mLooper;
        private AsyncBatchSession mBatchSession;

        private ActivityStateAsyncUpdater(ProcessStateController psc, Looper looper) {
            mPsc = psc;
            mHandler = new Handler(looper);
            mLooper = looper;
        }

        /**
         * Start a batch session. Any async work will not be posted to the Handler thread until
         * the returned AsyncBatchSession is closed.
         */
        public AsyncBatchSession startBatchSession() {
            if (!Flags.pushActivityStateToOomadjuster()) return null;

            final AsyncBatchSession session = getBatchSession();
            session.start();
            return session;
        }

        /**
         * Trigger an OomAdjuster full update.
         */
        public void runUpdateAsync() {
            getBatchSession().runUpdate();
        }

        /**
@@ -802,11 +826,7 @@ public class ProcessStateController {
        public void setExpandedNotificationShadeAsync(boolean expandedShade) {
            if (!Flags.pushActivityStateToOomadjuster()) return;

            mHandler.post(() -> {
                synchronized (mPsc.mLock) {
                    mPsc.setExpandedNotificationShade(expandedShade);
                }
            });
            getBatchSession().enqueue(() -> mPsc.setExpandedNotificationShade(expandedShade));
        }

        /**
@@ -817,8 +837,7 @@ public class ProcessStateController {
            if (!Flags.pushActivityStateToOomadjuster()) return;

            final ProcessRecord top = wpc != null ? (ProcessRecord) wpc.mOwner : null;
            mHandler.post(() -> {
                synchronized (mPsc.mLock) {
            getBatchSession().enqueue(() -> {
                mPsc.setTopProcess(top);
                if (clearPrev) {
                    mPsc.setPreviousProcess(null);
@@ -826,7 +845,6 @@ public class ProcessStateController {
                if (cancelExpandedShade) {
                    mPsc.setExpandedNotificationShade(false);
                }
                }
            });
        }

@@ -836,11 +854,7 @@ public class ProcessStateController {
        public void setTopProcessStateAsync(@ActivityManager.ProcessState int procState) {
            if (!Flags.pushActivityStateToOomadjuster()) return;

            mHandler.post(() -> {
                synchronized (mPsc.mLock) {
                    mPsc.setTopProcessState(procState);
                }
            });
            getBatchSession().enqueue(() -> mPsc.setTopProcessState(procState));
        }

        /**
@@ -850,13 +864,10 @@ public class ProcessStateController {
            if (!Flags.pushActivityStateToOomadjuster()) return;

            final ProcessRecord prev = wpc != null ? (ProcessRecord) wpc.mOwner : null;
            mHandler.post(() -> {
                synchronized (mPsc.mLock) {
                    mPsc.setPreviousProcess(prev);
                }
            });
            getBatchSession().enqueue(() -> mPsc.setPreviousProcess(prev));
        }


        /**
         * Set which process is considered the Home process, if any.
         */
@@ -864,13 +875,10 @@ public class ProcessStateController {
            if (!Flags.pushActivityStateToOomadjuster()) return;

            final ProcessRecord home = wpc != null ? (ProcessRecord) wpc.mOwner : null;
            mHandler.post(() -> {
                synchronized (mPsc.mLock) {
                    mPsc.setHomeProcess(home);
                }
            });
            getBatchSession().enqueue(() -> mPsc.setHomeProcess(home));
        }


        /**
         * Set which process is considered the Heavy Weight process, if any.
         */
@@ -878,11 +886,7 @@ public class ProcessStateController {
            if (!Flags.pushActivityStateToOomadjuster()) return;

            final ProcessRecord heavy = wpc != null ? (ProcessRecord) wpc.mOwner : null;
            mHandler.post(() -> {
                synchronized (mPsc.mLock) {
                    mPsc.setHeavyWeightProcess(heavy);
                }
            });
            getBatchSession().enqueue(() -> mPsc.setHeavyWeightProcess(heavy));
        }

        /**
@@ -892,11 +896,7 @@ public class ProcessStateController {
            if (!Flags.pushActivityStateToOomadjuster()) return;

            final ProcessRecord dozeUi = wpc != null ? (ProcessRecord) wpc.mOwner : null;
            mHandler.post(() -> {
                synchronized (mPsc.mLock) {
                    mPsc.setVisibleDozeUiProcess(dozeUi);
                }
            });
            getBatchSession().enqueue(() -> mPsc.setVisibleDozeUiProcess(dozeUi));
        }

        /**
@@ -906,11 +906,7 @@ public class ProcessStateController {
            if (!Flags.pushActivityStateToOomadjuster()) return;

            final ProcessRecord activity = (ProcessRecord) wpc.mOwner;
            mHandler.post(() -> {
                synchronized (mPsc.mLock) {
                    mPsc.setHasActivity(activity, hasActivity);
                }
            });
            getBatchSession().enqueue(() -> mPsc.setHasActivity(activity, hasActivity));
        }

        /**
@@ -921,11 +917,9 @@ public class ProcessStateController {
            if (!Flags.pushActivityStateToOomadjuster()) return;

            final ProcessRecord activity = (ProcessRecord) wpc.mOwner;
            mHandler.post(() -> {
                synchronized (mPsc.mLock) {
            getBatchSession().enqueue(() -> {
                mPsc.setActivityStateFlags(activity, flags);
                mPsc.setPerceptibleTaskStoppedTimeMillis(activity, perceptibleStopTimeMs);
                }
            });
        }

@@ -937,14 +931,143 @@ public class ProcessStateController {
            if (!Flags.pushActivityStateToOomadjuster()) return;

            final ProcessRecord proc = (ProcessRecord) wpc.mOwner;
            getBatchSession().enqueue(() -> mPsc.setHasRecentTasks(proc, hasRecentTasks));
        }

        private AsyncBatchSession getBatchSession() {
            if (mBatchSession == null) {
                final Handler h = new Handler(mLooper);
                final Runnable update = () -> mPsc.runFullUpdate(
                        ActivityManagerInternal.OOM_ADJ_REASON_ACTIVITY);
                mBatchSession = new AsyncBatchSession(h, mPsc.mLock, update);
            }
            return mBatchSession;
        }
    }

    public static class AsyncBatchSession implements AutoCloseable {
        final Handler mHandler;
        final Object mLock;
        private final Runnable mUpdateRunnable;
        private final Runnable mLockedUpdateRunnable;
        private boolean mRunUpdate = false;
        private boolean mBoostPriority = false;
        private int mNestedStartCount = 0;

        private ArrayList<Runnable> mBatchList = new ArrayList<>();

        AsyncBatchSession(Handler handler, Object lock, Runnable updateRunnable) {
            mHandler = handler;
            mLock = lock;
            mUpdateRunnable = updateRunnable;
            mLockedUpdateRunnable = () -> {
                synchronized (lock) {
                    updateRunnable.run();
                }
            };
        }

        /**
         * If the BatchSession is currently active, posting the batched work to the front of the
         * Handler queue when the session is closed.
         */
        public void postToHead() {
            if (isActive()) {
                mBoostPriority = true;
            }
        }

        /**
         * Enqueue the work to be run asynchronously done on a Handler thread.
         * If batch session is currently active, queue up the work to be run when the session ends.
         * Otherwise, the work will be immediately enqueued on to the Handler thread.
         */
        public void enqueue(Runnable runnable) {
            if (isActive()) {
                mBatchList.add(runnable);
            } else {
                // Not in session, just post to the handler immediately.
                mHandler.post(() -> {
                synchronized (mPsc.mLock) {
                    mPsc.setHasRecentTasks(proc, hasRecentTasks);
                    synchronized (mLock) {
                        runnable.run();
                    }
                });
            }
        }

        /**
         * Trigger an update to be asynchronously done on a Handler thread.
         * If batch session is currently active, the update will be run at the end of the batched
         * work.
         * Otherwise, the update will be immediately enqueued on to the Handler thread (and any
         * previously posted update will be removed in favor of this most recent trigger).
         */
        public void runUpdate() {
            if (isActive()) {
                // Mark that an update should be done after the batched work is done.
                mRunUpdate = true;
            } else {
                // Not in session, just post to the handler immediately (and clear any existing
                // posted update).
                mHandler.removeCallbacks(mLockedUpdateRunnable);
                mHandler.post(mLockedUpdateRunnable);
            }
        }

        void start() {
            mNestedStartCount++;
        }

        private boolean isActive() {
            return mNestedStartCount > 0;
        }

        @Override
        public void close() {
            if (mNestedStartCount == 0) {
                Slog.wtfStack(TAG, "close() called on an unstarted BatchSession!");
                return;
            }

            mNestedStartCount--;

            if (isActive()) {
                // Still in an active batch session.
                return;
            }

            final ArrayList<Runnable> list = new ArrayList<>(mBatchList);
            final boolean runUpdate = mRunUpdate;

            // Return if there is nothing to do.
            if (list.isEmpty() && !runUpdate) return;

            mBatchList.clear();
            mRunUpdate = false;

            // offload all of the queued up work to the ActivityStateHandler thread.
            final Runnable batchedWorkload = () -> {
                synchronized (mLock) {
                    for (int i = 0, size = list.size(); i < size; i++) {
                        list.get(i).run();
                    }
                    if (runUpdate) {
                        mUpdateRunnable.run();
                    }
                }
            };

            if (mBoostPriority) {
                // The priority of this BatchSession has been boosted. Post to the front of the
                // Handler queue.
                mBoostPriority = false;
                mHandler.postAtFrontOfQueue(batchedWorkload);
            } else {
                mHandler.post(batchedWorkload);
            }
        }
    }

    /**
     * Builder for ProcessStateController.
     */
+9 −7
Original line number Diff line number Diff line
@@ -621,14 +621,16 @@ class ActivityClientController extends IActivityClientController.Stub {
                final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token);
                if (r == null) return;

                // TODO: This should probably only loop over the task since you need to be in the
                // same task to return results.
                try (var unused = mService.mActivityStateUpdater.startBatchSession()) {
                    // TODO: This should probably only loop over the task since you need to be in
                    //  the same task to return results.
                    r.getRootTask().forAllActivities(activity -> {
                        activity.finishIfSubActivity(r /* parent */, resultWho, requestCode);
                    }, true /* traverseTopToBottom */);

                    mService.updateOomAdj();
                }
            }
        } finally {
            Binder.restoreCallingIdentity(origId);
        }
+34 −40
Original line number Diff line number Diff line
@@ -871,13 +871,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
        int caller() default NONE;
    }

    private final Runnable mUpdateOomAdjRunnable = new Runnable() {
        @Override
        public void run() {
            mAmInternal.updateOomAdj(ActivityManagerInternal.OOM_ADJ_REASON_ACTIVITY);
        }
    };

    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
    public ActivityTaskManagerService(Context context) {
        mContext = context;
@@ -5523,8 +5516,9 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
    void updateSleepIfNeededLocked() {
        final boolean shouldSleep = !mRootWindowContainer.hasAwakeDisplay();
        final boolean wasSleeping = mSleeping;
        boolean updateOomAdj = false;

        try (var unused = mActivityStateUpdater.startBatchSession()) {
            boolean updateOomAdj = false;
            if (!shouldSleep) {
                // If wasSleeping is true, we need to wake up activity manager state from when
                // we started sleeping. In either case, we need to apply the sleep tokens, which
@@ -5562,10 +5556,10 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
                updateOomAdj();
            }
        }
    }

    void updateOomAdj() {
        mH.removeCallbacks(mUpdateOomAdjRunnable);
        mH.post(mUpdateOomAdjRunnable);
        mActivityStateUpdater.runUpdateAsync();
    }

    void updateCpuStats() {
+5 −1
Original line number Diff line number Diff line
@@ -2649,9 +2649,13 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
    void endActivityVisibilityUpdate() {
        mVisibilityTransactionDepth--;
        if (mVisibilityTransactionDepth == 0) {
            // Multiple OomAdjuster affecting state changes can occur, wrap those state changes in
            // a BatchSession.
            try (var unused = mService.mActivityStateUpdater.startBatchSession()) {
                computeProcessActivityStateBatch();
            }
        }
    }

    /** Returns {@code true} if the caller is on the path to update visibility. */
    boolean inActivityVisibilityUpdate() {
+12 −8
Original line number Diff line number Diff line
@@ -2968,6 +2968,9 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
        if (mTmpOccludingRegion != null) {
            mTmpOccludingRegion.setEmpty();
        }
        // Multiple OomAdjuster affecting state changes can occur, wrap those state changes in a
        // BatchSession.
        try (var unused = mService.mActivityStateUpdater.startBatchSession()) {
            boolean changed = false;
            if (!mTaskSupervisor.inActivityVisibilityUpdate()) {
                changed = mTaskSupervisor.computeProcessActivityStateBatch();
@@ -2979,6 +2982,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
                }
            }
        }
    }

    /** This method is called for visible freeform task from top to bottom. */
    private void computeNonOccludedFreeformAreaRatio(@NonNull Task task) {
Loading