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

Commit f3cfa89d authored by Winson Chung's avatar Winson Chung
Browse files

Move RecentsImpl task stack listener to background.

- In RecentsTaskLoader, synchronize on anything that might use the
  thumbnail cache
- In RecentsLoadPlan, remove synchronization when preloading/executing
  since that is done in the loader now
- In RecentsImpl, synchronize on anything that might use the dummy stack
  view

Bug: 37550083
Test: Launch Overview and some other tasks, ensure everything still works

Change-Id: I36d04566ebb04296f67a3233730c1dc5bc1569f4
parent 094996a2
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -192,8 +192,9 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
                        // and the old last stack active time, they were not visible and in the
                        // TaskStack so we don't need to remove any associated TaskViews but we do
                        // need to load the task id's from the system
                        RecentsTaskLoadPlan loadPlan = Recents.getTaskLoader().createLoadPlan(ctx);
                        loadPlan.preloadRawTasks(false /* includeFrontMostExcludedTask */);
                        RecentsTaskLoader loader = Recents.getTaskLoader();
                        RecentsTaskLoadPlan loadPlan = loader.createLoadPlan(ctx);
                        loader.preloadRawTasks(loadPlan, false /* includeFrontMostExcludedTask */);
                        List<ActivityManager.RecentTaskInfo> tasks = loadPlan.getRawTasks();
                        for (int i = tasks.size() - 1; i >= 0; i--) {
                            ActivityManager.RecentTaskInfo task = tasks.get(i);
+92 −76
Original line number Diff line number Diff line
@@ -108,36 +108,39 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
     * task stacks and update recents accordingly.
     */
    class TaskStackListenerImpl extends TaskStackListener {

        @Override
        public void onTaskStackChanged() {
        public void onTaskStackChangedBackground() {
            // Preloads the next task
            RecentsConfiguration config = Recents.getConfiguration();
            if (config.svelteLevel == RecentsConfiguration.SVELTE_NONE) {
                RecentsTaskLoader loader = Recents.getTaskLoader();
                SystemServicesProxy ssp = Recents.getSystemServices();
                ActivityManager.RunningTaskInfo runningTaskInfo = ssp.getRunningTask();

                // Load the next task only if we aren't svelte
                SystemServicesProxy ssp = Recents.getSystemServices();
                ActivityManager.RunningTaskInfo runningTaskInfo = ssp.getRunningTask();
                RecentsTaskLoader loader = Recents.getTaskLoader();
                RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext);
                loader.preloadTasks(plan, -1, false /* includeFrontMostExcludedTask */);
                RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options();

                // This callback is made when a new activity is launched and the old one is paused
                // so ignore the current activity and try and preload the thumbnail for the
                // previous one.
                if (runningTaskInfo != null) {
                    launchOpts.runningTaskId = runningTaskInfo.id;
                }
                VisibilityReport visibilityReport;
                synchronized (mDummyStackView) {
                    mDummyStackView.setTasks(plan.getTaskStack(), false /* allowNotify */);
                    updateDummyStackViewLayout(plan.getTaskStack(),
                            getWindowRect(null /* windowRectOverride */));

                // Launched from app is always the worst case (in terms of how many thumbnails/tasks
                // visible)
                    // Launched from app is always the worst case (in terms of how many
                    // thumbnails/tasks visible)
                    RecentsActivityLaunchState launchState = new RecentsActivityLaunchState();
                    launchState.launchedFromApp = true;
                    mDummyStackView.updateLayoutAlgorithm(true /* boundScroll */, launchState);
                    visibilityReport = mDummyStackView.computeStackVisibilityReport();
                }

                VisibilityReport visibilityReport = mDummyStackView.computeStackVisibilityReport();
                RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options();
                launchOpts.runningTaskId = runningTaskInfo != null ? runningTaskInfo.id : -1;
                launchOpts.numVisibleTasks = visibilityReport.numVisibleTasks;
                launchOpts.numVisibleTaskThumbnails = visibilityReport.numVisibleThumbnails;
                launchOpts.onlyLoadForCache = true;
@@ -221,10 +224,11 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
    }

    public void onConfigurationChanged() {
        Resources res = mContext.getResources();
        reloadResources();
        synchronized (mDummyStackView) {
            mDummyStackView.reloadOnConfigurationChange();
        }
    }

    /**
     * This is only called from the system user's Recents.  Secondary users will instead proxy their
@@ -393,7 +397,6 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener

            RecentsTaskLoader loader = Recents.getTaskLoader();
            sInstanceLoadPlan = loader.createLoadPlan(mContext);
            sInstanceLoadPlan.preloadRawTasks(!isHomeStackVisible.value);
            loader.preloadTasks(sInstanceLoadPlan, runningTask.id, !isHomeStackVisible.value);
            TaskStack stack = sInstanceLoadPlan.getTaskStack();
            if (stack.getTaskCount() > 0) {
@@ -633,6 +636,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
        calculateWindowStableInsets(systemInsets, windowRect);
        windowRect.offsetTo(0, 0);

        synchronized (mDummyStackView) {
            TaskStackLayoutAlgorithm stackLayout = mDummyStackView.getStackAlgorithm();

            // Rebind the header bar and draw it for the transition
@@ -645,6 +649,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
                        TaskStackLayoutAlgorithm.StackState.getStackStateForStack(stack));
            }
        }
    }

    private Rect getWindowRect(Rect windowRectOverride) {
       return windowRectOverride != null
@@ -663,29 +668,35 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
     */
    private void updateHeaderBarLayout(TaskStack stack, Rect windowRectOverride) {
        Rect windowRect = getWindowRect(windowRectOverride);
        int taskViewWidth = 0;
        boolean useGridLayout = false;
        synchronized (mDummyStackView) {
            useGridLayout = mDummyStackView.useGridLayout();
            updateDummyStackViewLayout(stack, windowRect);
            if (stack != null) {
                TaskStackLayoutAlgorithm stackLayout = mDummyStackView.getStackAlgorithm();
                mDummyStackView.setTasks(stack, false /* allowNotifyStackChanges */);
                // Get the width of a task view so that we know how wide to draw the header bar.
            int taskViewWidth = 0;
            if (mDummyStackView.useGridLayout()) {
                if (useGridLayout) {
                    TaskGridLayoutAlgorithm gridLayout = mDummyStackView.getGridAlgorithm();
                    gridLayout.initialize(windowRect);
                    taskViewWidth = (int) gridLayout.getTransform(0 /* taskIndex */,
                        stack.getTaskCount(), new TaskViewTransform(), stackLayout).rect.width();
                            stack.getTaskCount(), new TaskViewTransform(),
                            stackLayout).rect.width();
                } else {
                    Rect taskViewBounds = stackLayout.getUntransformedTaskViewBounds();
                    if (!taskViewBounds.isEmpty()) {
                        taskViewWidth = taskViewBounds.width();
                    }
                }
            }
        }

            if (taskViewWidth > 0) {
        if (stack != null && taskViewWidth > 0) {
            synchronized (mHeaderBarLock) {
                if (mHeaderBar.getMeasuredWidth() != taskViewWidth ||
                        mHeaderBar.getMeasuredHeight() != mTaskBarHeight) {
                        if (mDummyStackView.useGridLayout()) {
                    if (useGridLayout) {
                        mHeaderBar.setShouldDarkenBackgroundColor(true);
                        mHeaderBar.setNoUserInteractionState();
                    }
@@ -706,7 +717,6 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
            }
        }
    }
    }

    /**
     * Given the stable insets and the rect for our window, calculates the insets that affect our
@@ -764,16 +774,21 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
     * Creates the activity options for an app->recents transition.
     */
    private ActivityOptions getThumbnailTransitionActivityOptions(
            ActivityManager.RunningTaskInfo runningTask, TaskStackView stackView,
                    Rect windowOverrideRect) {
            ActivityManager.RunningTaskInfo runningTask, Rect windowOverrideRect) {
        if (runningTask != null && runningTask.stackId == FREEFORM_WORKSPACE_STACK_ID) {
            ArrayList<AppTransitionAnimationSpec> specs = new ArrayList<>();
            ArrayList<Task> tasks = stackView.getStack().getStackTasks();
            TaskStackLayoutAlgorithm stackLayout = stackView.getStackAlgorithm();
            TaskStackViewScroller stackScroller = stackView.getScroller();
            ArrayList<Task> tasks;
            TaskStackLayoutAlgorithm stackLayout;
            TaskStackViewScroller stackScroller;

            stackView.updateLayoutAlgorithm(true /* boundScroll */);
            stackView.updateToInitialState();
            synchronized (mDummyStackView) {
                tasks = mDummyStackView.getStack().getStackTasks();
                stackLayout = mDummyStackView.getStackAlgorithm();
                stackScroller = mDummyStackView.getScroller();

                mDummyStackView.updateLayoutAlgorithm(true /* boundScroll */);
                mDummyStackView.updateToInitialState();
            }

            for (int i = tasks.size() - 1; i >= 0; i--) {
                Task task = tasks.get(i);
@@ -795,7 +810,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
        } else {
            // Update the destination rect
            Task toTask = new Task();
            TaskViewTransform toTransform = getThumbnailTransitionTransform(stackView, toTask,
            TaskViewTransform toTransform = getThumbnailTransitionTransform(mDummyStackView, toTask,
                    windowOverrideRect);
            Bitmap thumbnail = drawThumbnailTransitionBitmap(toTask, toTransform,
                            mThumbTransitionBitmapCache);
@@ -919,8 +934,10 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
        updateHeaderBarLayout(stack, windowOverrideRect);

        // Prepare the dummy stack for the transition
        TaskStackLayoutAlgorithm.VisibilityReport stackVr =
                mDummyStackView.computeStackVisibilityReport();
        TaskStackLayoutAlgorithm.VisibilityReport stackVr;
        synchronized (mDummyStackView) {
            stackVr = mDummyStackView.computeStackVisibilityReport();
        }

        // Update the remaining launch state
        launchState.launchedNumVisibleTasks = stackVr.numVisibleTasks;
@@ -936,8 +953,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
            opts = getUnknownTransitionActivityOptions();
        } else if (useThumbnailTransition) {
            // Try starting with a thumbnail transition
            opts = getThumbnailTransitionActivityOptions(runningTask, mDummyStackView,
                    windowOverrideRect);
            opts = getThumbnailTransitionActivityOptions(runningTask, windowOverrideRect);
        } else {
            // If there is no thumbnail transition, but is launching from home into recents, then
            // use a quick home transition
+85 −68
Original line number Diff line number Diff line
@@ -149,6 +149,10 @@ public class SystemServicesProxy {
     * to reduce IPC calls from system services. These callbacks will be called on the main thread.
     */
    public abstract static class TaskStackListener {
        /**
         * NOTE: This call is made of the thread that the binder call comes in on.
         */
        public void onTaskStackChangedBackground() { }
        public void onTaskStackChanged() { }
        public void onTaskSnapshotChanged(int taskId, TaskSnapshot snapshot) { }
        public void onActivityPinned(String packageName) { }
@@ -187,8 +191,20 @@ public class SystemServicesProxy {
     * This simply passes callbacks to listeners through {@link H}.
     * */
    private android.app.TaskStackListener mTaskStackListener = new android.app.TaskStackListener() {

        private final List<SystemServicesProxy.TaskStackListener> mTmpListeners = new ArrayList<>();

        @Override
        public void onTaskStackChanged() throws RemoteException {
            // Call the task changed callback for the non-ui thread listeners first
            synchronized (mTaskStackListeners) {
                mTmpListeners.clear();
                mTmpListeners.addAll(mTaskStackListeners);
            }
            for (int i = mTmpListeners.size() - 1; i >= 0; i--) {
                mTmpListeners.get(i).onTaskStackChangedBackground();
            }

            mHandler.removeMessages(H.ON_TASK_STACK_CHANGED);
            mHandler.sendEmptyMessage(H.ON_TASK_STACK_CHANGED);
        }
@@ -309,10 +325,7 @@ public class SystemServicesProxy {
     * Returns the single instance of the {@link SystemServicesProxy}.
     * This should only be called on the main thread.
     */
    public static SystemServicesProxy getInstance(Context context) {
        if (!Looper.getMainLooper().isCurrentThread()) {
            throw new RuntimeException("Must be called on the UI thread");
        }
    public static synchronized SystemServicesProxy getInstance(Context context) {
        if (sSystemServicesProxy == null) {
            sSystemServicesProxy = new SystemServicesProxy(context);
        }
@@ -1136,6 +1149,7 @@ public class SystemServicesProxy {
    public void registerTaskStackListener(TaskStackListener listener) {
        if (mIam == null) return;

        synchronized (mTaskStackListeners) {
            mTaskStackListeners.add(listener);
            if (mTaskStackListeners.size() == 1) {
                // Register mTaskStackListener to IActivityManager only once if needed.
@@ -1146,6 +1160,7 @@ public class SystemServicesProxy {
                }
            }
        }
    }

    public void endProlongedAnimations() {
        if (mWm == null) {
@@ -1245,6 +1260,7 @@ public class SystemServicesProxy {

        @Override
        public void handleMessage(Message msg) {
            synchronized (mTaskStackListeners) {
                switch (msg.what) {
                    case ON_TASK_STACK_CHANGED: {
                        for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
@@ -1318,3 +1334,4 @@ public class SystemServicesProxy {
            }
        }
    }
}
+11 −3
Original line number Diff line number Diff line
@@ -103,8 +103,10 @@ public class RecentsTaskLoadPlan {
    /**
     * An optimization to preload the raw list of tasks. The raw tasks are saved in least-recent
     * to most-recent order.
     *
     * Note: Do not lock, callers should synchronize on the loader before making this call.
     */
    public synchronized void preloadRawTasks(boolean includeFrontMostExcludedTask) {
    void preloadRawTasks(boolean includeFrontMostExcludedTask) {
        int currentUserId = UserHandle.USER_CURRENT;
        updateCurrentQuietProfilesCache(currentUserId);
        SystemServicesProxy ssp = Recents.getSystemServices();
@@ -123,8 +125,11 @@ public class RecentsTaskLoadPlan {
     * The tasks will be ordered by:
     * - least-recent to most-recent stack tasks
     * - least-recent to most-recent freeform tasks
     *
     * Note: Do not lock, since this can be calling back to the loader, which separately also drives
     * this call (callers should synchronize on the loader before making this call).
     */
    public synchronized void preloadPlan(RecentsTaskLoader loader, int runningTaskId,
    void preloadPlan(RecentsTaskLoader loader, int runningTaskId,
            boolean includeFrontMostExcludedTask) {
        Resources res = mContext.getResources();
        ArrayList<Task> allTasks = new ArrayList<>();
@@ -223,8 +228,11 @@ public class RecentsTaskLoadPlan {

    /**
     * Called to apply the actual loading based on the specified conditions.
     *
     * Note: Do not lock, since this can be calling back to the loader, which separately also drives
     * this call (callers should synchronize on the loader before making this call).
     */
    public synchronized void executePlan(Options opts, RecentsTaskLoader loader) {
    void executePlan(Options opts, RecentsTaskLoader loader) {
        Resources res = mContext.getResources();

        // Iterate through each of the tasks and load them according to the load conditions.
+14 −6
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ import android.os.Looper;
import android.util.Log;
import android.util.LruCache;

import com.android.internal.annotations.GuardedBy;
import com.android.systemui.R;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsConfiguration;
@@ -243,7 +244,9 @@ public class RecentsTaskLoader {
    private final TaskResourceLoadQueue mLoadQueue;
    private final BackgroundTaskLoader mLoader;
    private final HighResThumbnailLoader mHighResThumbnailLoader;
    @GuardedBy("this")
    private final TaskKeyStrongCache<ThumbnailData> mThumbnailCache = new TaskKeyStrongCache<>();
    @GuardedBy("this")
    private final TaskKeyStrongCache<ThumbnailData> mTempCache = new TaskKeyStrongCache<>();
    private final int mMaxThumbnailCacheSize;
    private final int mMaxIconCacheSize;
@@ -318,14 +321,20 @@ public class RecentsTaskLoader {
        return plan;
    }

    /** Preloads raw recents tasks using the specified plan to store the output. */
    public synchronized void preloadRawTasks(RecentsTaskLoadPlan plan,
            boolean includeFrontMostExcludedTask) {
        plan.preloadRawTasks(includeFrontMostExcludedTask);
    }

    /** Preloads recents tasks using the specified plan to store the output. */
    public void preloadTasks(RecentsTaskLoadPlan plan, int runningTaskId,
    public synchronized void preloadTasks(RecentsTaskLoadPlan plan, int runningTaskId,
            boolean includeFrontMostExcludedTask) {
        plan.preloadPlan(this, runningTaskId, includeFrontMostExcludedTask);
    }

    /** Begins loading the heavy task data according to the specified options. */
    public void loadTasks(Context context, RecentsTaskLoadPlan plan,
    public synchronized void loadTasks(Context context, RecentsTaskLoadPlan plan,
            RecentsTaskLoadPlan.Options opts) {
        if (opts == null) {
            throw new RuntimeException("Requires load options");
@@ -380,8 +389,7 @@ public class RecentsTaskLoader {
     * Handles signals from the system, trimming memory when requested to prevent us from running
     * out of memory.
     */
    public void onTrimMemory(int level) {
        RecentsConfiguration config = Recents.getConfiguration();
    public synchronized void onTrimMemory(int level) {
        switch (level) {
            case ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN:
                // Stop the loader immediately when the UI is no longer visible
@@ -516,7 +524,7 @@ public class RecentsTaskLoader {
    /**
     * Returns the cached thumbnail if the task key is not expired, updating the cache if it is.
     */
    ThumbnailData getAndUpdateThumbnail(Task.TaskKey taskKey, boolean loadIfNotCached,
    synchronized ThumbnailData getAndUpdateThumbnail(Task.TaskKey taskKey, boolean loadIfNotCached,
            boolean storeInCache) {
        SystemServicesProxy ssp = Recents.getSystemServices();

@@ -616,7 +624,7 @@ public class RecentsTaskLoader {
        }
    }

    public void dump(String prefix, PrintWriter writer) {
    public synchronized void dump(String prefix, PrintWriter writer) {
        String innerPrefix = prefix + "  ";

        writer.print(prefix); writer.println(TAG);