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

Commit d2a8494a authored by Evan Rosky's avatar Evan Rosky Committed by Android (Google) Code Review
Browse files

Merge "Add fallback transition player" into main

parents 169f225d 4c35de32
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -480,3 +480,10 @@ flag {
        purpose: PURPOSE_BUGFIX
    }
}

flag {
    name: "fallback_transition_player"
    namespace: "windowing_frontend"
    description: "Use a fallback transition-player while sysui is starting or crashed."
    bug: "365884835"
}
+93 −25
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import static android.view.WindowManager.TRANSIT_FLAG_DISPLAY_LEVEL_TRANSITION;
import static android.view.WindowManager.TRANSIT_NONE;
import static android.window.DesktopExperienceFlags.ENABLE_PARALLEL_CD_TRANSITIONS_DURING_RECENTS;

import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_WINDOW_TRANSITIONS_MIN;
import static com.android.server.wm.ActivityTaskManagerService.POWER_MODE_REASON_CHANGE_DISPLAY;

import android.annotation.ColorInt;
@@ -47,10 +48,12 @@ import android.util.SparseArray;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
import android.view.Display;
import android.view.SurfaceControl;
import android.view.WindowManager;
import android.window.ITransitionMetricsReporter;
import android.window.ITransitionPlayer;
import android.window.RemoteTransition;
import android.window.StartingWindowRemovalInfo;
import android.window.TransitionInfo;
import android.window.TransitionRequestInfo;
import android.window.WindowContainerTransaction;
@@ -247,6 +250,10 @@ class TransitionController {
    TransitionController(ActivityTaskManagerService atm) {
        mAtm = atm;
        mRemotePlayer = new RemotePlayer(atm);
        if (Flags.fallbackTransitionPlayer()) {
            mTransitionPlayers.add(
                    new TransitionPlayerRecord(new FallbackPlayer(atm), null /* proc */));
        }
    }

    void setWindowManager(WindowManagerService wms) {
@@ -302,7 +309,7 @@ class TransitionController {
    Transition createTransition(@WindowManager.TransitionType int type,
            @WindowManager.TransitionFlags int flags) {
        if (mTransitionPlayers.isEmpty()) {
            throw new IllegalStateException("Shell Transitions not enabled");
            throw new IllegalStateException("Somehow creating a transition while flushing");
        }
        if (mCollectingTransition != null) {
            throw new IllegalStateException("Trying to directly start transition collection while "
@@ -322,8 +329,7 @@ class TransitionController {
            throw new IllegalStateException("Simultaneous transition collection not supported.");
        }
        if (mTransitionPlayers.isEmpty()) {
            // If sysui has been killed (by a test) or crashed, we can temporarily have no player
            // In this case, abort the transition.
            // This means transitions are being "flushed" due to switching players.
            transition.abort();
            return;
        }
@@ -338,15 +344,15 @@ class TransitionController {

    void registerTransitionPlayer(@Nullable ITransitionPlayer player,
            @Nullable WindowProcessController playerProc) {
        if (!mTransitionPlayers.isEmpty()) {
            ProtoLog.v(WmProtoLogGroups.WM_DEBUG_WINDOW_TRANSITIONS_MIN, "Registering transition "
        if (!mTransitionPlayers.isEmpty() || Flags.fallbackTransitionPlayer()) {
            ProtoLog.v(WM_DEBUG_WINDOW_TRANSITIONS_MIN, "Registering transition "
                    + "player %s over %d other players", player.asBinder(),
                    mTransitionPlayers.size());
            // flush currently running transitions so that the new player doesn't get
            // intermediate state
            flushRunningTransitions();
        } else {
            ProtoLog.v(WmProtoLogGroups.WM_DEBUG_WINDOW_TRANSITIONS_MIN, "Registering transition "
            ProtoLog.v(WM_DEBUG_WINDOW_TRANSITIONS_MIN, "Registering transition "
                    + "player %s ", player.asBinder());
        }
        mTransitionPlayers.add(new TransitionPlayerRecord(player, playerProc));
@@ -359,18 +365,18 @@ class TransitionController {
            if (mTransitionPlayers.get(idx).mPlayer.asBinder() == player.asBinder()) break;
        }
        if (idx < 0) {
            ProtoLog.w(WmProtoLogGroups.WM_DEBUG_WINDOW_TRANSITIONS_MIN, "Attempt to unregister "
            ProtoLog.w(WM_DEBUG_WINDOW_TRANSITIONS_MIN, "Attempt to unregister "
                    + "transition player %s but it isn't registered", player.asBinder());
            return;
        }
        final boolean needsFlush = idx == (mTransitionPlayers.size() - 1);
        final TransitionPlayerRecord record = mTransitionPlayers.remove(idx);
        if (needsFlush) {
            ProtoLog.v(WmProtoLogGroups.WM_DEBUG_WINDOW_TRANSITIONS_MIN, "Unregistering active "
            ProtoLog.v(WM_DEBUG_WINDOW_TRANSITIONS_MIN, "Unregistering active "
                    + "transition player %s at index=%d leaving %d in stack", player.asBinder(),
                    idx, mTransitionPlayers.size());
        } else {
            ProtoLog.v(WmProtoLogGroups.WM_DEBUG_WINDOW_TRANSITIONS_MIN, "Unregistering transition "
            ProtoLog.v(WM_DEBUG_WINDOW_TRANSITIONS_MIN, "Unregistering transition "
                    + "player %s at index=%d leaving %d in stack", player.asBinder(), idx,
                    mTransitionPlayers.size());
        }
@@ -383,11 +389,12 @@ class TransitionController {
    }

    @Nullable ITransitionPlayer getTransitionPlayer() {
        return mTransitionPlayers.isEmpty() ? null : mTransitionPlayers.getLast().mPlayer;
        if (!Flags.fallbackTransitionPlayer() && mTransitionPlayers.isEmpty()) return null;
        return mTransitionPlayers.getLast().mPlayer;
    }

    boolean isShellTransitionsEnabled() {
        return !mTransitionPlayers.isEmpty();
        return !mTransitionPlayers.isEmpty() || Flags.fallbackTransitionPlayer();
    }

    /** @return {@code true} if using shell-transitions rotation instead of fixed-rotation. */
@@ -782,6 +789,9 @@ class TransitionController {
            @WindowManager.TransitionFlags int flags, @Nullable WindowContainer trigger,
            @NonNull WindowContainer readyGroupRef, @NonNull ActionChain chain) {
        if (mTransitionPlayers.isEmpty()) {
            if (Flags.fallbackTransitionPlayer()) {
                throw new IllegalStateException("Somehow requesting transition while flushing");
            }
            return null;
        }
        Transition newTransition = null;
@@ -851,8 +861,7 @@ class TransitionController {
            return transition;
        }
        if (mTransitionPlayers.isEmpty() || transition.isAborted()) {
            // Apparently, some tests will kill(and restart) systemui, so there is a chance that
            // the player might be transiently null.
            // Either flushing or already flushed, so abort here.
            if (transition.isCollecting()) {
                transition.abort();
            }
@@ -891,7 +900,7 @@ class TransitionController {

            transition.mLogger.mRequestTimeNs = SystemClock.elapsedRealtimeNanos();
            transition.mLogger.mRequest = request;
            mTransitionPlayers.getLast().mPlayer.requestStartTransition(
            getTransitionPlayer().requestStartTransition(
                    transition.getToken(), request);
            if (remoteTransition != null) {
                transition.setRemoteAnimationApp(remoteTransition.getAppThread());
@@ -908,7 +917,8 @@ class TransitionController {
     * @return the new transition if it was created for this request, `null` otherwise.
     */
    Transition requestCloseTransitionIfNeeded(@NonNull WindowContainer<?> wc) {
        if (mTransitionPlayers.isEmpty() || isCollecting()) return null;
        if (!Flags.fallbackTransitionPlayer() && mTransitionPlayers.isEmpty()) return null;
        if (isCollecting()) return null;
        if (!wc.isVisibleRequested()) return null;
        return requestStartTransition(createTransition(TRANSIT_CLOSE, 0 /* flags */), wc.asTask(),
                null /* remoteTransition */, null /* displayChange */);
@@ -1174,7 +1184,7 @@ class TransitionController {
            // If it's a legacy sync, then it needs to wait until there is no collecting transition.
            if (queued.mTransition == null) return;
            if (!canStartCollectingNow(queued.mTransition)) return;
            ProtoLog.v(WmProtoLogGroups.WM_DEBUG_WINDOW_TRANSITIONS_MIN,
            ProtoLog.v(WM_DEBUG_WINDOW_TRANSITIONS_MIN,
                    "Moving #%d from collecting to waiting.", mCollectingTransition.getSyncId());
            mWaitingTransitions.add(mCollectingTransition);
            mCollectingTransition = null;
@@ -1202,7 +1212,7 @@ class TransitionController {
            // the incoming transition's changes stale (e.g. display change transition had not
            // been formally started). So send this transition to Shell before applying any changes
            // to report it as a no-op.
            ProtoLog.w(WmProtoLogGroups.WM_DEBUG_WINDOW_TRANSITIONS_MIN,
            ProtoLog.w(WM_DEBUG_WINDOW_TRANSITIONS_MIN,
                    "Formerly queued #%d force-reported as no-op", queued.mTransition.getSyncId());
            queued.mTransition.playNow();
        } else {
@@ -1566,7 +1576,7 @@ class TransitionController {
        }

        mQueuedTransitions.add(queuedTransition);
        ProtoLog.v(WmProtoLogGroups.WM_DEBUG_WINDOW_TRANSITIONS_MIN,
        ProtoLog.v(WM_DEBUG_WINDOW_TRANSITIONS_MIN,
                "Queueing transition: %s", transit);
    }

@@ -1582,7 +1592,7 @@ class TransitionController {
                // Check if we can run in parallel here.
                if (canStartCollectingNow(transit)) {
                    // start running in parallel.
                    ProtoLog.v(WmProtoLogGroups.WM_DEBUG_WINDOW_TRANSITIONS_MIN, "Moving #%d from"
                    ProtoLog.v(WM_DEBUG_WINDOW_TRANSITIONS_MIN, "Moving #%d from"
                            + " collecting to waiting.", mCollectingTransition.getSyncId());
                    mWaitingTransitions.add(mCollectingTransition);
                    mCollectingTransition = null;
@@ -1610,6 +1620,9 @@ class TransitionController {
    @Nullable
    Transition createAndStartCollecting(int type) {
        if (mTransitionPlayers.isEmpty()) {
            if (Flags.fallbackTransitionPlayer()) {
                throw new IllegalStateException("Can't create transition while flushing");
            }
            return null;
        }
        if (!mQueuedTransitions.isEmpty()) {
@@ -1621,7 +1634,7 @@ class TransitionController {
                // Check if we can run in parallel here.
                if (canStartCollectingNow(null /* transit */)) {
                    // create and collect in parallel.
                    ProtoLog.v(WmProtoLogGroups.WM_DEBUG_WINDOW_TRANSITIONS_MIN, "Moving #%d from"
                    ProtoLog.v(WM_DEBUG_WINDOW_TRANSITIONS_MIN, "Moving #%d from"
                            + " collecting to waiting.", mCollectingTransition.getSyncId());
                    mWaitingTransitions.add(mCollectingTransition);
                    mCollectingTransition = null;
@@ -1645,7 +1658,7 @@ class TransitionController {
            // Just add to queue since we already have a queue.
            mQueuedTransitions.add(new QueuedTransition(syncGroup,
                    (deferred) -> applySync.accept(true /* deferred */)));
            ProtoLog.v(WmProtoLogGroups.WM_DEBUG_WINDOW_TRANSITIONS_MIN,
            ProtoLog.v(WM_DEBUG_WINDOW_TRANSITIONS_MIN,
                    "Queueing legacy sync-set: %s", syncGroup.mSyncId);
            return;
        }
@@ -1842,10 +1855,10 @@ class TransitionController {
        }

        void logOnSend() {
            ProtoLog.v(WmProtoLogGroups.WM_DEBUG_WINDOW_TRANSITIONS_MIN, "%s", buildOnSendLog());
            ProtoLog.v(WmProtoLogGroups.WM_DEBUG_WINDOW_TRANSITIONS_MIN,
            ProtoLog.v(WM_DEBUG_WINDOW_TRANSITIONS_MIN, "%s", buildOnSendLog());
            ProtoLog.v(WM_DEBUG_WINDOW_TRANSITIONS_MIN,
                    "    startWCT=%s", mStartWCT);
            ProtoLog.v(WmProtoLogGroups.WM_DEBUG_WINDOW_TRANSITIONS_MIN, "    info=%s",
            ProtoLog.v(WM_DEBUG_WINDOW_TRANSITIONS_MIN, "    info=%s",
                    mInfo.toString("    " /* prefix */));
        }

@@ -1871,7 +1884,7 @@ class TransitionController {
        }

        void logOnFinish() {
            ProtoLog.v(WmProtoLogGroups.WM_DEBUG_WINDOW_TRANSITIONS_MIN, "%s", buildOnFinishLog());
            ProtoLog.v(WM_DEBUG_WINDOW_TRANSITIONS_MIN, "%s", buildOnFinishLog());
        }
    }

@@ -1935,4 +1948,59 @@ class TransitionController {
            }
        }
    }

    /** Fallback player used during time periods where a real player is not registered. */
    private static class FallbackPlayer implements ITransitionPlayer {
        final ActivityTaskManagerService mAtm;

        FallbackPlayer(ActivityTaskManagerService atm) {
            mAtm = atm;
        }

        @Override
        public IBinder asBinder() {
            return null;
        }

        @Override
        public void onTransitionReady(IBinder transitionToken, TransitionInfo info,
                SurfaceControl.Transaction t, SurfaceControl.Transaction finishT)
                throws RemoteException {
            ProtoLog.v(WM_DEBUG_WINDOW_TRANSITIONS_MIN, "Playing [FALLBACK] "
                    + "animation for #%d @%d", info.getDebugId(), info.getTrack());
            t.apply();
            finishT.apply();
            mAtm.mH.post(() -> {
                try {
                    ProtoLog.v(WM_DEBUG_WINDOW_TRANSITIONS_MIN, "Transition animation [FALLBACK] "
                            + "finished #%d @%d", info.getDebugId(), info.getTrack());
                    mAtm.getWindowOrganizerController().finishTransition(transitionToken,
                            null /* wct */);
                } catch (RemoteException e) {
                    Slog.e(TAG, "Error finishing transition from fallback", e);
                }
            });
        }

        @Override
        public void requestStartTransition(IBinder transitionToken, TransitionRequestInfo request)
                throws RemoteException {
            mAtm.mH.post(() -> {
                try {
                    ProtoLog.v(WM_DEBUG_WINDOW_TRANSITIONS_MIN,
                            "Transition requested [FALLBACK] (#%d): %s %s", request.getDebugId(),
                            transitionToken, request);
                    mAtm.getWindowOrganizerController().startTransition(transitionToken,
                            null /* wct */);
                } catch (RemoteException e) {
                    Slog.e(TAG, "Error starting transition from fallback", e);
                }
            });
        }

        @Override
        public void removeStartingWindow(StartingWindowRemovalInfo removalInfo)
                throws RemoteException {
        }
    }
}