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

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

Suppress recent tasks updates while applying a window container transaction

- Applying a transaction may result in numerous intermediate changes
  to the window hierarchy which can result in numerous intermediate
  recent task list changes. Instead we should only notify after all
  the changes have been applied

Bug: 437981160
Flag: EXEMPT bugfix
Test: atest RecentTasksTest WindowOrganizerTests
Change-Id: I52adfbaf77eda71df1af52ee46b7e2e1c8fcd350
parent 3dc7bbbc
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -1928,6 +1928,8 @@ class RecentTasks {
        if (!mHiddenTasks.isEmpty()) {
            pw.println("mHiddenTasks=" + mHiddenTasks);
        }
        pw.println("mRecentsUpdatesSuppressed="
                + mTaskNotificationController.areRecentsUpdatesSuppressed());
        if (mTasks.isEmpty()) {
            return;
        }
+40 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.server.wm;

import android.annotation.IntDef;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ITaskStackListener;
@@ -198,6 +199,11 @@ class TaskChangeNotificationController {
        l.onLockTaskModeChanged(m.arg1);
    };

    // Whether notifications related to recent tasks are currently suppressed
    private boolean mSuppressRecentsUpdates;
    // Whether any notifications were called while suppressed, to be notified once not suppressed
    private boolean mRecentsUpdatedWhileSuppressed;

    @FunctionalInterface
    public interface TaskStackConsumer {
        void accept(ITaskStackListener t, Message m) throws RemoteException;
@@ -354,6 +360,29 @@ class TaskChangeNotificationController {
        }
    }

    /**
     * Sets whether to suppress recents task list updates.
     */
    void setSuppressRecentsUpdates(boolean suppress) {
        if (mSuppressRecentsUpdates == suppress) {
            throw new IllegalStateException("Recents updates already suppressed");
        }
        mSuppressRecentsUpdates = suppress;
        if (!suppress) {
            // Notify now if the task list was updated while suppressed
            if (mRecentsUpdatedWhileSuppressed) {
                notifyTaskListUpdated();
            }
        }
    }

    /**
     * Returns whether recents task list updates are suppressed.
     */
    boolean areRecentsUpdatesSuppressed() {
        return mSuppressRecentsUpdates;
    }

    /** Notifies all listeners when the task stack has changed. */
    void notifyTaskStackChanged() {
        mTaskSupervisor.getActivityMetricsLogger().logWindowState();
@@ -536,6 +565,17 @@ class TaskChangeNotificationController {
     * Called when any additions or deletions to the recent tasks list have been made.
     */
    void notifyTaskListUpdated() {
        if (areRecentsUpdatesSuppressed()) {
            // Defer until updates are no longer suppressed
            mRecentsUpdatedWhileSuppressed = true;
            return;
        }
        queueTaskListUpdated();
        mRecentsUpdatedWhileSuppressed = false;
    }

    /** Queues a task-list-updated notification. */
    void queueTaskListUpdated() {
        final Message msg = mHandler.obtainMessage(NOTIFY_TASK_LIST_UPDATED_LISTENERS_MSG);
        forAllLocalListeners(mNotifyTaskListUpdated, msg);
        msg.sendToTarget();
+2 −0
Original line number Diff line number Diff line
@@ -650,6 +650,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
        mService.mTaskSupervisor.beginDeferResume();
        boolean deferResume = true;
        mService.mTaskSupervisor.setDeferRootVisibilityUpdate(true /* deferUpdate */);
        mService.getTaskChangeNotificationController().setSuppressRecentsUpdates(true);
        boolean deferTransitionReady = false;
        Transition transition = chain.getTransition();
        if (transition != null && !t.isEmpty() && !chain.isFinishing()) {
@@ -814,6 +815,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
                mService.mTaskSupervisor.endDeferResume();
            }
            mService.continueWindowLayout();
            mService.getTaskChangeNotificationController().setSuppressRecentsUpdates(false);
        }
        return effects;
    }
+24 −0
Original line number Diff line number Diff line
@@ -54,6 +54,7 @@ import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -1387,6 +1388,29 @@ public class RecentTasksTest extends WindowTestsBase {
        verify(controller, times(4)).notifyTaskListUpdated();
    }

    @Test
    public void suppressRecentsUpdates() {
        final Task task1 = createTaskBuilder(".Task").build();
        final TaskChangeNotificationController notifier =
                mAtm.getTaskChangeNotificationController();
        clearInvocations(notifier);

        // Enable suppressing recents updates
        notifier.setSuppressRecentsUpdates(true);

        // Add and remove some tasks
        mRecentTasks.add(task1);
        mRecentTasks.removeAllVisibleTasks(TEST_USER_0_ID);

        // Verify nothing was notified
        verify(notifier, never()).queueTaskListUpdated();

        // Disable suppressing recents updates & verify that we update since there were
        // notifications while suppressed
        notifier.setSuppressRecentsUpdates(false);
        verify(notifier, times(1)).queueTaskListUpdated();
    }

    @Test
    public void testTaskInfo_expectNoExtras() {
        final Bundle data = new Bundle();
+16 −0
Original line number Diff line number Diff line
@@ -2227,6 +2227,22 @@ public class WindowOrganizerTests extends WindowTestsBase {
        assertFalse(WindowOrganizerController.configurationsAreEqualForOrganizer(config1, config3));
    }

    @Test
    public void testSuppressRecentsUpdatesWhileApplyingWCT() {
        final TaskChangeNotificationController notifier =
                mWm.mAtmService.getTaskChangeNotificationController();
        clearInvocations(notifier);

        // Create & apply a WCT
        final WindowContainerTransaction t = new WindowContainerTransaction();
        mWm.mAtmService.mWindowOrganizerController.applyTransaction(t);

        // Verify that we've set and restored suppressing the recent task updates while applying
        verify(notifier, times(1)).setSuppressRecentsUpdates(true);
        verify(notifier, times(1)).setSuppressRecentsUpdates(false);
        assertFalse(notifier.areRecentsUpdatesSuppressed());
    }

    private void testSetAlwaysOnTop(WindowContainer wc) {
        final WindowContainerTransaction t = new WindowContainerTransaction();
        t.setAlwaysOnTop(wc.mRemoteToken.toWindowContainerToken(), true);