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

Commit dc9385aa authored by Jorim Jaggi's avatar Jorim Jaggi
Browse files

Immediately report drawing

No need to wait on the next relayout - this can only delay the
transition. Makes hot launches a lot more consistent.

However, this made it too fast! We then hit a race condition when
the app transition was already starting but no other layout was
done yet. When another layout was executed we noticed that we need
to report resized for the starting window, clearing it's drawn
state, which set startingDisplayed=false, which jumped the app
window animation to the end.

To fix this, make sure not to report another resized immediately
after the initial layout, as the client already knows the latest
(because it calls relayout at some point before it starts drawing).

Also fix "animating" async systrace for better analysis.

Test: Open/close size-mismatching task snapshot 100 times, ensure
no animation skipped.
Test: Look at app transition logs, ensure more consistent.
Test: Overall system sanity testing (open a couple of apps/dialogs
etc).

Bug: 32668632
Change-Id: Id795cd6a84f22e6a619089cb9554fc5033477ad2
parent 5afccc62
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -411,7 +411,9 @@ public class AppWindowAnimator {
        }

        if (DEBUG_ANIM) Slog.v(TAG, "Animation done in " + mAppToken
                + ": reportedVisible=" + mAppToken.reportedVisible);
                + ": reportedVisible=" + mAppToken.reportedVisible
                + " okToDisplay=" + mService.okToDisplay()
                + " startingDisplayed=" + mAppToken.startingDisplayed);

        transformation.clear();

+7 −0
Original line number Diff line number Diff line
@@ -520,9 +520,16 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
                }
                w.mLayoutNeeded = false;
                w.prelayout();
                final boolean firstLayout = !w.isLaidOut();
                mService.mPolicy.layoutWindowLw(w, null);
                w.mLayoutSeq = mService.mLayoutSeq;

                // If this is the first layout, we need to initialize the last inset values as
                // otherwise we'd immediately cause an unnecessary resize.
                if (firstLayout) {
                    w.updateLastInsetValues();
                }

                // Window frames may have changed. Update dim layer with the new bounds.
                final Task task = w.getTask();
                if (task != null) {
+1 −12
Original line number Diff line number Diff line
@@ -116,7 +116,6 @@ class TaskSnapshotSurface implements StartingSurface {
    private final TaskSnapshot mSnapshot;
    private final CharSequence mTitle;
    private boolean mHasDrawn;
    private boolean mReportNextDraw;
    private long mShownTime;
    private final Handler mHandler;
    private boolean mSizeMismatch;
@@ -263,16 +262,12 @@ class TaskSnapshotSurface implements StartingSurface {
        } else {
            drawSizeMatchSnapshot(buffer);
        }
        final boolean reportNextDraw;
        synchronized (mService.mWindowMap) {
            mShownTime = SystemClock.uptimeMillis();
            mHasDrawn = true;
            reportNextDraw = mReportNextDraw;
        }
        if (reportNextDraw) {
        reportDrawn();
    }
    }

    private void drawSizeMatchSnapshot(GraphicBuffer buffer) {
        mSurface.attachAndQueueBuffer(buffer);
@@ -356,9 +351,6 @@ class TaskSnapshotSurface implements StartingSurface {
    }

    private void reportDrawn() {
        synchronized (mService.mWindowMap) {
            mReportNextDraw = false;
        }
        try {
            mSession.finishDrawing(mWindow);
        } catch (RemoteException e) {
@@ -376,9 +368,6 @@ class TaskSnapshotSurface implements StartingSurface {
                    final TaskSnapshotSurface surface = (TaskSnapshotSurface) msg.obj;
                    synchronized (surface.mService.mWindowMap) {
                        hasDrawn = surface.mHasDrawn;
                        if (!hasDrawn) {
                            surface.mReportNextDraw = true;
                        }
                    }
                    if (hasDrawn) {
                        surface.reportDrawn();
+8 −12
Original line number Diff line number Diff line
@@ -52,6 +52,7 @@ public class WindowAnimator {

    /** Is any window animating? */
    private boolean mAnimating;
    private boolean mLastAnimating;

    /** Is any app window animating? */
    boolean mAppWindowAnimating;
@@ -158,7 +159,6 @@ public class WindowAnimator {
     */
    private void animate(long frameTimeNs) {
        boolean transactionOpen = false;
        boolean wasAnimating = false;
        try {
            synchronized (mService.mWindowMap) {
                if (!mInitialized) {
@@ -167,8 +167,7 @@ public class WindowAnimator {

                mCurrentTime = frameTimeNs / TimeUtils.NANOS_PER_MS;
                mBulkUpdateParams = SET_ORIENTATION_CHANGE_COMPLETE;
                wasAnimating = mAnimating;
                setAnimating(false);
                mAnimating = false;
                mAppWindowAnimating = false;
                if (DEBUG_WINDOW_TRACE) {
                    Slog.i(TAG, "!!! animate: entry time=" + mCurrentTime);
@@ -269,24 +268,21 @@ public class WindowAnimator {
                mWindowPlacerLocked.requestTraversal();
            }

            if (mAnimating && !wasAnimating) {
            if (mAnimating && !mLastAnimating) {

                // Usually app transitions but quite a load onto the system already (with all the
                // things happening in app), so pause task snapshot persisting to not increase the
                // load.
                mService.mTaskSnapshotController.setPersisterPaused(true);
                if (Trace.isTagEnabled(Trace.TRACE_TAG_WINDOW_MANAGER)) {
                Trace.asyncTraceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "animating", 0);
            }
            }

            if (!mAnimating && wasAnimating) {
            if (!mAnimating && mLastAnimating) {
                mWindowPlacerLocked.requestTraversal();
                mService.mTaskSnapshotController.setPersisterPaused(false);
                if (Trace.isTagEnabled(Trace.TRACE_TAG_WINDOW_MANAGER)) {
                Trace.asyncTraceEnd(Trace.TRACE_TAG_WINDOW_MANAGER, "animating", 0);
            }
            }

            mLastAnimating = mAnimating;

            if (mRemoveReplacedWindows) {
                mService.mRoot.removeReplacedWindows();
+20 −6
Original line number Diff line number Diff line
@@ -208,7 +208,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
    boolean mHidden;    // Used to determine if to show child windows.
    boolean mWallpaperVisible;  // for wallpaper, what was last vis report?
    private boolean mDragResizing;
    private boolean mDragResizingChangeReported;
    private boolean mDragResizingChangeReported = true;
    private int mResizeMode;

    private RemoteCallbackList<IWindowFocusObserver> mFocusCallbacks;
@@ -1155,11 +1155,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
                return;
            }

            mLastOverscanInsets.set(mOverscanInsets);
            mLastContentInsets.set(mContentInsets);
            mLastVisibleInsets.set(mVisibleInsets);
            mLastStableInsets.set(mStableInsets);
            mLastOutsets.set(mOutsets);
            updateLastInsetValues();
            mService.makeWindowFreezingScreenIfNeededLocked(this);

            // If the orientation is changing, or we're starting or ending a drag resizing action,
@@ -4404,6 +4400,24 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
        return result;
    }

    /**
     * @return True if this window has been laid out at least once; false otherwise.
     */
    boolean isLaidOut() {
        return mLayoutSeq != -1;
    }

    /**
     * Updates the last inset values to the current ones.
     */
    void updateLastInsetValues() {
        mLastOverscanInsets.set(mOverscanInsets);
        mLastContentInsets.set(mContentInsets);
        mLastVisibleInsets.set(mVisibleInsets);
        mLastStableInsets.set(mStableInsets);
        mLastOutsets.set(mOutsets);
    }

    // TODO: Hack to work around the number of states AppWindowToken needs to access without having
    // access to its windows children. Need to investigate re-writing
    // {@link AppWindowToken#updateReportedVisibilityLocked} so this can be removed.