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

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

Merge "Make it possible to register/unregister players as a stack" into main

parents 344a9e10 598f8a5b
Loading
Loading
Loading
Loading
+8 −2
Original line number Diff line number Diff line
@@ -93,11 +93,17 @@ interface IWindowOrganizerController {
    ITaskFragmentOrganizerController getTaskFragmentOrganizerController();

    /**
     * Registers a transition player with Core. There is only one of these at a time and calling
     * this will replace the existing one if set.
     * Registers a transition player with Core. There is only one of these active at a time so
     * calling this will replace the existing one (if set) until it is unregistered.
     */
    void registerTransitionPlayer(in ITransitionPlayer player);

    /**
     * Un-registers a transition player from Core. This will restore whichever player was active
     * prior to registering this one.
     */
    void unregisterTransitionPlayer(in ITransitionPlayer player);

    /** @return An interface enabling the transition players to report its metrics. */
    ITransitionMetricsReporter getTransitionMetricsReporter();

+14 −1
Original line number Diff line number Diff line
@@ -155,7 +155,7 @@ public class WindowOrganizer {
     * @hide
     */
    @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)
    public void registerTransitionPlayer(@Nullable ITransitionPlayer player) {
    public void registerTransitionPlayer(@NonNull ITransitionPlayer player) {
        try {
            getWindowOrganizerController().registerTransitionPlayer(player);
        } catch (RemoteException e) {
@@ -163,6 +163,19 @@ public class WindowOrganizer {
        }
    }

    /**
     * Unregister a previously-registered ITransitionPlayer.
     * @hide
     */
    @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)
    public void unregisterTransitionPlayer(@NonNull ITransitionPlayer player) {
        try {
            getWindowOrganizerController().unregisterTransitionPlayer(player);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * @see TransitionMetrics
     * @hide
+284 B (53 KiB)

File changed.

No diff preview for this file type.

+30 −0
Original line number Diff line number Diff line
@@ -3223,6 +3223,36 @@
      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
      "at": "com\/android\/server\/wm\/TransitionController.java"
    },
    "-4546322749928357965": {
      "message": "Registering transition player %s over %d other players",
      "level": "VERBOSE",
      "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN",
      "at": "com\/android\/server\/wm\/TransitionController.java"
    },
    "-4250307779892136611": {
      "message": "Registering transition player %s ",
      "level": "VERBOSE",
      "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN",
      "at": "com\/android\/server\/wm\/TransitionController.java"
    },
    "3242771541905259983": {
      "message": "Attempt to unregister transition player %s but it isn't registered",
      "level": "WARN",
      "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN",
      "at": "com\/android\/server\/wm\/TransitionController.java"
    },
    "3691912781236221027": {
      "message": "Unregistering active transition player %s at index=%d leaving %d in stack",
      "level": "VERBOSE",
      "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN",
      "at": "com\/android\/server\/wm\/TransitionController.java"
    },
    "-2879980134100946679": {
      "message": "Unregistering transition player %s at index=%d leaving %d in stack",
      "level": "VERBOSE",
      "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN",
      "at": "com\/android\/server\/wm\/TransitionController.java"
    },
    "-4235778637051052061": {
      "message": "Disabling player for transition #%d because display isn't enabled yet",
      "level": "VERBOSE",
+97 −42
Original line number Diff line number Diff line
@@ -113,10 +113,9 @@ class TransitionController {
    private static final int LEGACY_STATE_READY = 1;
    private static final int LEGACY_STATE_RUNNING = 2;

    private ITransitionPlayer mTransitionPlayer;
    private final ArrayList<TransitionPlayerRecord> mTransitionPlayers = new ArrayList<>();
    final TransitionMetricsReporter mTransitionMetricsReporter = new TransitionMetricsReporter();

    private WindowProcessController mTransitionPlayerProc;
    final ActivityTaskManagerService mAtm;
    BLASTSyncEngine mSyncEngine;

@@ -175,8 +174,6 @@ class TransitionController {

    final Lock mRunningLock = new Lock();

    private final IBinder.DeathRecipient mTransitionPlayerDeath;

    static class QueuedTransition {
        final Transition mTransition;
        final OnStartCollect mOnStartCollect;
@@ -243,11 +240,6 @@ class TransitionController {
    TransitionController(ActivityTaskManagerService atm) {
        mAtm = atm;
        mRemotePlayer = new RemotePlayer(atm);
        mTransitionPlayerDeath = () -> {
            synchronized (mAtm.mGlobalLock) {
                detachPlayer();
            }
        };
    }

    void setWindowManager(WindowManagerService wms) {
@@ -266,11 +258,10 @@ class TransitionController {
        mSyncEngine.addOnIdleListener(this::tryStartCollectFromQueue);
    }

    @VisibleForTesting
    void detachPlayer() {
        if (mTransitionPlayer == null) return;
        // Immediately set to null so that nothing inadvertently starts/queues.
        mTransitionPlayer = null;
    void flushRunningTransitions() {
        // Temporarily clear so that nothing gets started/queued while flushing
        final ArrayList<TransitionPlayerRecord> temp = new ArrayList<>(mTransitionPlayers);
        mTransitionPlayers.clear();
        // Clean-up/finish any playing transitions. Backwards since they can remove themselves.
        for (int i = mPlayingTransitions.size() - 1; i >= 0; --i) {
            mPlayingTransitions.get(i).cleanUpOnFailure();
@@ -285,9 +276,10 @@ class TransitionController {
        if (mCollectingTransition != null) {
            mCollectingTransition.abort();
        }
        mTransitionPlayerProc = null;
        mRemotePlayer.clear();
        mRunningLock.doNotifyLocked();
        // Restore the rest of the player stack
        mTransitionPlayers.addAll(temp);
    }

    /** @see #createTransition(int, int) */
@@ -302,7 +294,7 @@ class TransitionController {
    @NonNull
    Transition createTransition(@WindowManager.TransitionType int type,
            @WindowManager.TransitionFlags int flags) {
        if (mTransitionPlayer == null) {
        if (mTransitionPlayers.isEmpty()) {
            throw new IllegalStateException("Shell Transitions not enabled");
        }
        if (mCollectingTransition != null) {
@@ -321,7 +313,7 @@ class TransitionController {
        if (mCollectingTransition != null) {
            throw new IllegalStateException("Simultaneous transition collection not supported.");
        }
        if (mTransitionPlayer == null) {
        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.
            transition.abort();
@@ -339,30 +331,56 @@ class TransitionController {

    void registerTransitionPlayer(@Nullable ITransitionPlayer player,
            @Nullable WindowProcessController playerProc) {
        try {
            // Note: asBinder() can be null if player is same process (likely in a test).
            if (mTransitionPlayer != null) {
                if (mTransitionPlayer.asBinder() != null) {
                    mTransitionPlayer.asBinder().unlinkToDeath(mTransitionPlayerDeath, 0);
        if (!mTransitionPlayers.isEmpty()) {
            ProtoLog.v(ProtoLogGroup.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(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS_MIN, "Registering transition "
                    + "player %s ", player.asBinder());
        }
                detachPlayer();
        mTransitionPlayers.add(new TransitionPlayerRecord(player, playerProc));
    }
            if (player.asBinder() != null) {
                player.asBinder().linkToDeath(mTransitionPlayerDeath, 0);

    @VisibleForTesting
    void unregisterTransitionPlayer(@NonNull ITransitionPlayer player) {
        int idx = mTransitionPlayers.size() - 1;
        for (; idx >= 0; --idx) {
            if (mTransitionPlayers.get(idx).mPlayer.asBinder() == player.asBinder()) break;
        }
        if (idx < 0) {
            ProtoLog.w(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS_MIN, "Attempt to unregister "
                    + "transition player %s but it isn't registered", player.asBinder());
            return;
        }
            mTransitionPlayer = player;
            mTransitionPlayerProc = playerProc;
        } catch (RemoteException e) {
            throw new RuntimeException("Unable to set transition player");
        final boolean needsFlush = idx == (mTransitionPlayers.size() - 1);
        final TransitionPlayerRecord record = mTransitionPlayers.remove(idx);
        if (needsFlush) {
            ProtoLog.v(ProtoLogGroup.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(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS_MIN, "Unregistering transition "
                    + "player %s at index=%d leaving %d in stack", player.asBinder(), idx,
                    mTransitionPlayers.size());
        }
        record.unlinkToDeath();
        if (!needsFlush) {
            // Not the active player, so no need to flush transitions.
            return;
        }
        flushRunningTransitions();
    }

    @Nullable ITransitionPlayer getTransitionPlayer() {
        return mTransitionPlayer;
        return mTransitionPlayers.isEmpty() ? null : mTransitionPlayers.getLast().mPlayer;
    }

    boolean isShellTransitionsEnabled() {
        return mTransitionPlayer != null;
        return !mTransitionPlayers.isEmpty();
    }

    /** @return {@code true} if using shell-transitions rotation instead of fixed-rotation. */
@@ -677,7 +695,7 @@ class TransitionController {
    Transition requestTransitionIfNeeded(@WindowManager.TransitionType int type,
            @WindowManager.TransitionFlags int flags, @Nullable WindowContainer trigger,
            @NonNull WindowContainer readyGroupRef) {
        if (mTransitionPlayer == null) {
        if (mTransitionPlayers.isEmpty()) {
            return null;
        }
        Transition newTransition = null;
@@ -728,7 +746,7 @@ class TransitionController {
                    transition.getToken(), null));
            return transition;
        }
        if (mTransitionPlayer == null || transition.isAborted()) {
        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.
            if (transition.isCollecting()) {
@@ -757,7 +775,8 @@ class TransitionController {

            transition.mLogger.mRequestTimeNs = SystemClock.elapsedRealtimeNanos();
            transition.mLogger.mRequest = request;
            mTransitionPlayer.requestStartTransition(transition.getToken(), request);
            mTransitionPlayers.getLast().mPlayer.requestStartTransition(
                    transition.getToken(), request);
            if (remoteTransition != null) {
                transition.setRemoteAnimationApp(remoteTransition.getAppThread());
            }
@@ -773,7 +792,7 @@ class TransitionController {
     * @return the new transition if it was created for this request, `null` otherwise.
     */
    Transition requestCloseTransitionIfNeeded(@NonNull WindowContainer<?> wc) {
        if (mTransitionPlayer == null || isCollecting()) return null;
        if (mTransitionPlayers.isEmpty() || isCollecting()) return null;
        if (!wc.isVisibleRequested()) return null;
        return requestStartTransition(createTransition(TRANSIT_CLOSE, 0 /* flags */), wc.asTask(),
                null /* remoteTransition */, null /* displayChange */);
@@ -1250,11 +1269,13 @@ class TransitionController {

    /** Updates the process state of animation player. */
    private void updateRunningRemoteAnimation(Transition transition, boolean isPlaying) {
        if (mTransitionPlayerProc == null) return;
        if (mTransitionPlayers.isEmpty()) return;
        final TransitionPlayerRecord record = mTransitionPlayers.getLast();
        if (record.mPlayerProc == null) return;
        if (isPlaying) {
            mTransitionPlayerProc.setRunningRemoteAnimation(true);
            record.mPlayerProc.setRunningRemoteAnimation(true);
        } else if (mPlayingTransitions.isEmpty()) {
            mTransitionPlayerProc.setRunningRemoteAnimation(false);
            record.mPlayerProc.setRunningRemoteAnimation(false);
            mRemotePlayer.clear();
        }
    }
@@ -1416,7 +1437,7 @@ class TransitionController {
     */
    @NonNull
    Transition createAndStartCollecting(int type) {
        if (mTransitionPlayer == null) {
        if (mTransitionPlayers.isEmpty()) {
            return null;
        }
        if (!mQueuedTransitions.isEmpty()) {
@@ -1477,6 +1498,40 @@ class TransitionController {
        void onCollectStarted(boolean deferred);
    }

    private class TransitionPlayerRecord {
        final ITransitionPlayer mPlayer;
        IBinder.DeathRecipient mDeath = null;
        private WindowProcessController mPlayerProc;

        TransitionPlayerRecord(@NonNull ITransitionPlayer player,
                @Nullable WindowProcessController playerProc) {
            mPlayer = player;
            mPlayerProc = playerProc;
            try {
                linkToDeath();
            } catch (RemoteException e) {
                throw new RuntimeException("Unable to set transition player");
            }
        }

        private void linkToDeath() throws RemoteException {
            // Note: asBinder() can be null if player is same process (likely in a test).
            if (mPlayer.asBinder() == null) return;
            mDeath = () -> {
                synchronized (mAtm.mGlobalLock) {
                    unregisterTransitionPlayer(mPlayer);
                }
            };
            mPlayer.asBinder().linkToDeath(mDeath, 0);
        }

        void unlinkToDeath() {
            if (mPlayer.asBinder() == null || mDeath == null) return;
            mPlayer.asBinder().unlinkToDeath(mDeath, 0);
            mDeath = null;
        }
    }

    /**
     * This manages the animating state of processes that are running remote animations for
     * {@link #mTransitionPlayerProc}.
Loading