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

Commit 4e9c5b44 authored by Chris Li's avatar Chris Li
Browse files

Wait for TaskFragmentOrganizer to finish handling transaction

When a TaskFragmentTransaction is sent to the organizer during a
transition, have the transition wait for the organizer to finish
handling the transaction.

Bug: 207070762
Test: atest WmTests:TaskFragmentOrganizerControllerTest
Change-Id: I4b7955171cd8ce386686ff2cd64b7c04a6436ddf
parent c3cad7c7
Loading
Loading
Loading
Loading
+12 −3
Original line number Diff line number Diff line
@@ -16,8 +16,10 @@

package android.window;

import android.os.IBinder;
import android.view.RemoteAnimationDefinition;
import android.window.ITaskFragmentOrganizer;
import android.window.WindowContainerTransaction;

/** @hide */
interface ITaskFragmentOrganizerController {
@@ -50,4 +52,11 @@ interface ITaskFragmentOrganizerController {
     * only occupies a portion of Task bounds.
     */
    boolean isActivityEmbedded(in IBinder activityToken);

    /**
     * Notifies the server that the organizer has finished handling the given transaction. The
     * server should apply the given {@link WindowContainerTransaction} for the necessary changes.
     */
    void onTransactionHandled(in ITaskFragmentOrganizer organizer, in IBinder transactionToken,
        in WindowContainerTransaction wct);
}
+25 −7
Original line number Diff line number Diff line
@@ -26,7 +26,6 @@ import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_VANISHED
import android.annotation.CallSuper;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.annotation.TestApi;
import android.content.Intent;
import android.content.res.Configuration;
@@ -148,6 +147,28 @@ public class TaskFragmentOrganizer extends WindowOrganizer {
        }
    }

    /**
     * Notifies the server that the organizer has finished handling the given transaction. The
     * server should apply the given {@link WindowContainerTransaction} for the necessary changes.
     *
     * @param transactionToken  {@link TaskFragmentTransaction#getTransactionToken()} from
     *                          {@link #onTransactionReady(TaskFragmentTransaction)}
     * @param wct               {@link WindowContainerTransaction} that the server should apply for
     *                          update of the transaction.
     * @see com.android.server.wm.WindowOrganizerController#enforceTaskPermission for permission
     * requirement.
     * @hide
     */
    public void onTransactionHandled(@NonNull IBinder transactionToken,
            @NonNull WindowContainerTransaction wct) {
        wct.setTaskFragmentOrganizer(mInterface);
        try {
            getController().onTransactionHandled(mInterface, transactionToken, wct);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Called when a TaskFragment is created and organized by this organizer.
     *
@@ -318,12 +339,8 @@ public class TaskFragmentOrganizer extends WindowOrganizer {
    /**
     * Called when the transaction is ready so that the organizer can update the TaskFragments based
     * on the changes in transaction.
     * Note: {@link WindowOrganizer#applyTransaction} permission requirement is conditional for
     * {@link TaskFragmentOrganizer}.
     * @see com.android.server.wm.WindowOrganizerController#enforceTaskPermission
     * @hide
     */
    @SuppressLint("AndroidFrameworkRequiresPermission")
    public void onTransactionReady(@NonNull TaskFragmentTransaction transaction) {
        final WindowContainerTransaction wct = new WindowContainerTransaction();
        final List<TaskFragmentTransaction.Change> changes = transaction.getChanges();
@@ -389,8 +406,9 @@ public class TaskFragmentOrganizer extends WindowOrganizer {
                            "Unknown TaskFragmentEvent=" + change.getType());
            }
        }
        // TODO(b/240519866): notify TaskFragmentOrganizerController that the transition is done.
        applyTransaction(wct);

        // Notify the server, and the server should apply the WindowContainerTransaction.
        onTransactionHandled(transaction.getTransactionToken(), wct);
    }

    @Override
+17 −2
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcel;
@@ -41,19 +42,31 @@ import java.util.List;
 */
public final class TaskFragmentTransaction implements Parcelable {

    /** Unique token to represent this transaction. */
    private final IBinder mTransactionToken;

    /** Changes in this transaction. */
    private final ArrayList<Change> mChanges = new ArrayList<>();

    public TaskFragmentTransaction() {}
    public TaskFragmentTransaction() {
        mTransactionToken = new Binder();
    }

    private TaskFragmentTransaction(Parcel in) {
        mTransactionToken = in.readStrongBinder();
        in.readTypedList(mChanges, Change.CREATOR);
    }

    @Override
    public void writeToParcel(@NonNull Parcel dest, int flags) {
        dest.writeStrongBinder(mTransactionToken);
        dest.writeTypedList(mChanges);
    }

    public IBinder getTransactionToken() {
        return mTransactionToken;
    }

    /** Adds a {@link Change} to this transaction. */
    public void addChange(@Nullable Change change) {
        if (change != null) {
@@ -74,7 +87,9 @@ public final class TaskFragmentTransaction implements Parcelable {
    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("TaskFragmentTransaction{changes=[");
        sb.append("TaskFragmentTransaction{token=");
        sb.append(mTransactionToken);
        sb.append(" changes=[");
        for (int i = 0; i < mChanges.size(); ++i) {
            if (i > 0) {
                sb.append(',');
+12 −0
Original line number Diff line number Diff line
@@ -2041,6 +2041,12 @@
      "group": "WM_DEBUG_CONFIGURATION",
      "at": "com\/android\/server\/wm\/ActivityRecord.java"
    },
    "-108248992": {
      "message": "Defer transition ready for TaskFragmentTransaction=%s",
      "level": "VERBOSE",
      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
    },
    "-106400104": {
      "message": "Preload recents with %s",
      "level": "DEBUG",
@@ -2089,6 +2095,12 @@
      "group": "WM_DEBUG_STATES",
      "at": "com\/android\/server\/wm\/TaskFragment.java"
    },
    "-79016993": {
      "message": "Continue transition ready for TaskFragmentTransaction=%s",
      "level": "VERBOSE",
      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
    },
    "-70719599": {
      "message": "Unregister remote animations for organizer=%s uid=%d pid=%d",
      "level": "VERBOSE",
+78 −26
Original line number Diff line number Diff line
@@ -49,7 +49,9 @@ import android.window.ITaskFragmentOrganizer;
import android.window.ITaskFragmentOrganizerController;
import android.window.TaskFragmentInfo;
import android.window.TaskFragmentTransaction;
import android.window.WindowContainerTransaction;

import com.android.internal.protolog.ProtoLogGroup;
import com.android.internal.protolog.common.ProtoLog;

import java.lang.annotation.Retention;
@@ -68,6 +70,8 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr

    private final ActivityTaskManagerService mAtmService;
    private final WindowManagerGlobalLock mGlobalLock;
    private final WindowOrganizerController mWindowOrganizerController;

    /**
     * A Map which manages the relationship between
     * {@link ITaskFragmentOrganizer} and {@link TaskFragmentOrganizerState}
@@ -82,9 +86,11 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr

    private final ArraySet<Task> mTmpTaskSet = new ArraySet<>();

    TaskFragmentOrganizerController(ActivityTaskManagerService atm) {
        mAtmService = atm;
    TaskFragmentOrganizerController(@NonNull ActivityTaskManagerService atm,
            @NonNull WindowOrganizerController windowOrganizerController) {
        mAtmService = requireNonNull(atm);
        mGlobalLock = atm.mGlobalLock;
        mWindowOrganizerController = requireNonNull(windowOrganizerController);
    }

    /**
@@ -131,6 +137,14 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
        private final SparseArray<RemoteAnimationDefinition> mRemoteAnimationDefinitions =
                new SparseArray<>();

        /**
         * List of {@link TaskFragmentTransaction#getTransactionToken()} that have been sent to the
         * organizer. If the transaction is sent during a transition, the
         * {@link TransitionController} will wait until the transaction is finished.
         * @see #onTransactionFinished(IBinder)
         */
        private final List<IBinder> mRunningTransactions = new ArrayList<>();

        TaskFragmentOrganizerState(ITaskFragmentOrganizer organizer, int pid, int uid) {
            mOrganizer = organizer;
            mOrganizerPid = pid;
@@ -176,6 +190,10 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
                taskFragment.removeImmediately();
                mOrganizedTaskFragments.remove(taskFragment);
            }
            for (int i = mRunningTransactions.size() - 1; i >= 0; i--) {
                // Cleanup any running transaction to unblock the current transition.
                onTransactionFinished(mRunningTransactions.get(i));
            }
            mOrganizer.asBinder().unlinkToDeath(this, 0 /*flags*/);
        }

@@ -320,6 +338,40 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
                    .setActivityIntent(activity.intent)
                    .setActivityToken(activityToken);
        }

        void dispatchTransaction(@NonNull TaskFragmentTransaction transaction) {
            if (transaction.isEmpty()) {
                return;
            }
            try {
                mOrganizer.onTransactionReady(transaction);
            } catch (RemoteException e) {
                Slog.d(TAG, "Exception sending TaskFragmentTransaction", e);
                return;
            }
            onTransactionStarted(transaction.getTransactionToken());
        }

        /** Called when the transaction is sent to the organizer. */
        void onTransactionStarted(@NonNull IBinder transactionToken) {
            if (!mWindowOrganizerController.getTransitionController().isCollecting()) {
                return;
            }
            ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
                    "Defer transition ready for TaskFragmentTransaction=%s", transactionToken);
            mRunningTransactions.add(transactionToken);
            mWindowOrganizerController.getTransitionController().deferTransitionReady();
        }

        /** Called when the transaction is finished. */
        void onTransactionFinished(@NonNull IBinder transactionToken) {
            if (!mRunningTransactions.remove(transactionToken)) {
                return;
            }
            ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
                    "Continue transition ready for TaskFragmentTransaction=%s", transactionToken);
            mWindowOrganizerController.getTransitionController().continueTransitionReady();
        }
    }

    @Nullable
@@ -336,7 +388,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
    }

    @Override
    public void registerOrganizer(ITaskFragmentOrganizer organizer) {
    public void registerOrganizer(@NonNull ITaskFragmentOrganizer organizer) {
        final int pid = Binder.getCallingPid();
        final int uid = Binder.getCallingUid();
        synchronized (mGlobalLock) {
@@ -354,7 +406,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
    }

    @Override
    public void unregisterOrganizer(ITaskFragmentOrganizer organizer) {
    public void unregisterOrganizer(@NonNull ITaskFragmentOrganizer organizer) {
        validateAndGetState(organizer);
        final int pid = Binder.getCallingPid();
        final long uid = Binder.getCallingUid();
@@ -372,8 +424,8 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
    }

    @Override
    public void registerRemoteAnimations(ITaskFragmentOrganizer organizer, int taskId,
            RemoteAnimationDefinition definition) {
    public void registerRemoteAnimations(@NonNull ITaskFragmentOrganizer organizer, int taskId,
            @NonNull RemoteAnimationDefinition definition) {
        final int pid = Binder.getCallingPid();
        final int uid = Binder.getCallingUid();
        synchronized (mGlobalLock) {
@@ -398,7 +450,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
    }

    @Override
    public void unregisterRemoteAnimations(ITaskFragmentOrganizer organizer, int taskId) {
    public void unregisterRemoteAnimations(@NonNull ITaskFragmentOrganizer organizer, int taskId) {
        final int pid = Binder.getCallingPid();
        final long uid = Binder.getCallingUid();
        synchronized (mGlobalLock) {
@@ -416,6 +468,17 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
        }
    }

    @Override
    public void onTransactionHandled(@NonNull ITaskFragmentOrganizer organizer,
            @NonNull IBinder transactionToken, @NonNull WindowContainerTransaction wct) {
        synchronized (mGlobalLock) {
            // Keep the calling identity to avoid unsecure change.
            mWindowOrganizerController.applyTransaction(wct);
            final TaskFragmentOrganizerState state = validateAndGetState(organizer);
            state.onTransactionFinished(transactionToken);
        }
    }

    /**
     * Gets the {@link RemoteAnimationDefinition} set on the given organizer if exists. Returns
     * {@code null} if it doesn't, or if the organizer has activity(ies) embedded in untrusted mode.
@@ -775,13 +838,13 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
        }
        final int organizerNum = mPendingTaskFragmentEvents.size();
        for (int i = 0; i < organizerNum; i++) {
            final ITaskFragmentOrganizer organizer = mTaskFragmentOrganizerState.get(
                    mPendingTaskFragmentEvents.keyAt(i)).mOrganizer;
            dispatchPendingEvents(organizer, mPendingTaskFragmentEvents.valueAt(i));
            final TaskFragmentOrganizerState state =
                    mTaskFragmentOrganizerState.get(mPendingTaskFragmentEvents.keyAt(i));
            dispatchPendingEvents(state, mPendingTaskFragmentEvents.valueAt(i));
        }
    }

    void dispatchPendingEvents(@NonNull ITaskFragmentOrganizer organizer,
    void dispatchPendingEvents(@NonNull TaskFragmentOrganizerState state,
            @NonNull List<PendingTaskFragmentEvent> pendingEvents) {
        if (pendingEvents.isEmpty()) {
            return;
@@ -817,7 +880,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
                if (mTmpTaskSet.add(task)) {
                    // Make sure the organizer know about the Task config.
                    transaction.addChange(prepareChange(new PendingTaskFragmentEvent.Builder(
                            PendingTaskFragmentEvent.EVENT_PARENT_INFO_CHANGED, organizer)
                            PendingTaskFragmentEvent.EVENT_PARENT_INFO_CHANGED, state.mOrganizer)
                            .setTask(task)
                            .build()));
                }
@@ -825,7 +888,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
            transaction.addChange(prepareChange(event));
        }
        mTmpTaskSet.clear();
        dispatchTransactionInfo(organizer, transaction);
        state.dispatchTransaction(transaction);
        pendingEvents.removeAll(candidateEvents);
    }

@@ -855,6 +918,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
        }

        final ITaskFragmentOrganizer organizer = taskFragment.getTaskFragmentOrganizer();
        final TaskFragmentOrganizerState state = validateAndGetState(organizer);
        final TaskFragmentTransaction transaction = new TaskFragmentTransaction();
        // Make sure the organizer know about the Task config.
        transaction.addChange(prepareChange(new PendingTaskFragmentEvent.Builder(
@@ -862,22 +926,10 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
                .setTask(taskFragment.getTask())
                .build()));
        transaction.addChange(prepareChange(event));
        dispatchTransactionInfo(event.mTaskFragmentOrg, transaction);
        state.dispatchTransaction(transaction);
        mPendingTaskFragmentEvents.get(organizer.asBinder()).remove(event);
    }

    private void dispatchTransactionInfo(@NonNull ITaskFragmentOrganizer organizer,
            @NonNull TaskFragmentTransaction transaction) {
        if (transaction.isEmpty()) {
            return;
        }
        try {
            organizer.onTransactionReady(transaction);
        } catch (RemoteException e) {
            Slog.d(TAG, "Exception sending TaskFragmentTransaction", e);
        }
    }

    @Nullable
    private TaskFragmentTransaction.Change prepareChange(
            @NonNull PendingTaskFragmentEvent event) {
Loading