WMS/ViewRoot: Prepare for Async BLAST Sync [1/N]

We would like to make relayoutWindow a non-blocking call,
and of course why not, who likes blocking. However it functions
as a critical path of BLASTSync. To understand why examine the
Guarantee described in BLASTSync.md.

In order to implement this guarantee we need to know
“Which frame has the client finished drawing” when it calls
finishDrawing. The current answer to this question is
“The frame reflecting the state observed in the last call
to relayoutWindow”. The comments on mPending and mCurrentDrawHandlers
also have a lot more context on how this works currently. Since
relayoutWindow has a critical section, it also ensures that changes
to syncable state and preparation of sync will be observed atomically
(since they are both observed over relayoutWindow, which is always
called before any frame drawing updated syncable state).

We design a new protocol described in BLASTSync.md, which uses a seqId
to track which call to finishDrawing reflects which syncable state.
We implement this seqId based system. Unfortunately the WindowManager
doesn’t quite conform to the requirements specified by the protocol,
and a follow up CL ensures that syncable state changes will
always be sent with the seqId.

This CL simply adds the protocol specification and makes some required
interface changes. It can be seen to be a no-op.

Bug: 161810301
Bug: 175861051
Bug: 175861127
Bug: 200285149
Change-Id: If2dea07121fe7de5d2524c5b63678dddf955d4b7
This commit is contained in:
Robert Carr 2022-02-20 20:15:19 -08:00
parent f1b86e8ce3
commit 027b59d90a
16 changed files with 174 additions and 36 deletions

View File

@ -20,6 +20,7 @@ import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentat
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.os.RemoteException;
import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;
@ -153,7 +154,8 @@ public class RelayoutPerfTest extends WindowManagerPerfTestBase
while (state.keepRunning()) {
session.relayout(mWindow, mParams, mWidth, mHeight,
mViewVisibility.getAsInt(), mFlags, mOutFrames,
mOutMergedConfiguration, mOutSurfaceControl, mOutInsetsState, mOutControls);
mOutMergedConfiguration, mOutSurfaceControl, mOutInsetsState, mOutControls,
new Bundle());
}
}
}

View File

@ -252,6 +252,7 @@ public abstract class WallpaperService extends Service {
final InsetsVisibilities mRequestedVisibilities = new InsetsVisibilities();
final InsetsSourceControl[] mTempControls = new InsetsSourceControl[0];
final MergedConfiguration mMergedConfiguration = new MergedConfiguration();
final Bundle mSyncSeqIdBundle = new Bundle();
private final Point mSurfaceSize = new Point();
private final Point mLastSurfaceSize = new Point();
private final Matrix mTmpMatrix = new Matrix();
@ -391,7 +392,7 @@ public abstract class WallpaperService extends Service {
@Override
public void resized(ClientWindowFrames frames, boolean reportDraw,
MergedConfiguration mergedConfiguration, boolean forceLayout,
boolean alwaysConsumeSystemBars, int displayId) {
boolean alwaysConsumeSystemBars, int displayId, int syncSeqId) {
Message msg = mCaller.obtainMessageIO(MSG_WINDOW_RESIZED,
reportDraw ? 1 : 0,
mergedConfiguration);
@ -1151,7 +1152,7 @@ public abstract class WallpaperService extends Service {
final int relayoutResult = mSession.relayout(
mWindow, mLayout, mWidth, mHeight,
View.VISIBLE, 0, mWinFrames, mMergedConfiguration, mSurfaceControl,
mInsetsState, mTempControls);
mInsetsState, mTempControls, mSyncSeqIdBundle);
final int transformHint = SurfaceControl.rotationToBufferTransform(
(mDisplayInstallOrientation + mDisplay.getRotation()) % 4);
@ -1338,7 +1339,8 @@ public abstract class WallpaperService extends Service {
mSurfaceCreated = true;
if (redrawNeeded) {
resetWindowPages();
mSession.finishDrawing(mWindow, null /* postDrawTransaction */);
mSession.finishDrawing(mWindow, null /* postDrawTransaction */,
Integer.MAX_VALUE);
processLocalColors(mPendingXOffset, mPendingXOffsetStep);
notifyColorsChanged();
}

View File

@ -55,7 +55,8 @@ oneway interface IWindow {
void resized(in ClientWindowFrames frames, boolean reportDraw,
in MergedConfiguration newMergedConfiguration,
boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId);
boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId,
int syncSeqId);
/**
* Called when the window insets configuration has changed.

View File

@ -104,7 +104,8 @@ interface IWindowSession {
int requestedWidth, int requestedHeight, int viewVisibility,
int flags, out ClientWindowFrames outFrames,
out MergedConfiguration outMergedConfiguration, out SurfaceControl outSurfaceControl,
out InsetsState insetsState, out InsetsSourceControl[] activeControls);
out InsetsState insetsState, out InsetsSourceControl[] activeControls,
out Bundle bundle);
/*
* Notify the window manager that an application is relaunching and
@ -142,7 +143,8 @@ interface IWindowSession {
* is null if there is no sync required.
*/
@UnsupportedAppUsage
oneway void finishDrawing(IWindow window, in SurfaceControl.Transaction postDrawTransaction);
oneway void finishDrawing(IWindow window, in SurfaceControl.Transaction postDrawTransaction,
int seqId);
@UnsupportedAppUsage
oneway void setInTouchMode(boolean showFocus);

View File

@ -830,6 +830,24 @@ public final class ViewRootImpl implements ViewParent,
private int mLastTransformHint = Integer.MIN_VALUE;
/**
* A temporary object used so relayoutWindow can return the latest SyncSeqId
* system. The SyncSeqId system was designed to work without synchronous relayout
* window, and actually synchronous relayout window presents a problem. We could have
* a sequence like this:
* 1. We send MSG_RESIZED to the client with a new syncSeqId to begin a new sync
* 2. Due to scheduling the client executes performTraversals before calling MSG_RESIZED
* 3. Coincidentally for some random reason it also calls relayout
* 4. It observes the new state from relayout, and so the next frame will contain the state
* However it hasn't received the seqId yet, and so under the designed operation of
* seqId flowing through MSG_RESIZED, the next frame wouldn't be synced. Since it
* contains our target sync state, we need to sync it! This problem won't come up once
* we get rid of synchronous relayout, until then, we use this bundle to channel the
* integer back over relayout.
*/
private Bundle mRelayoutBundle = new Bundle();
private int mSyncSeqId;
private String mTag = TAG;
public ViewRootImpl(Context context, Display display) {
@ -1711,6 +1729,7 @@ public final class ViewRootImpl implements ViewParent,
mPendingBackDropFrame.set(backdropFrame);
mForceNextWindowRelayout = forceNextWindowRelayout;
mPendingAlwaysConsumeSystemBars = args.argi2 != 0;
mSyncSeqId = args.argi4;
if (msg == MSG_RESIZED_REPORT) {
reportNextDraw();
@ -4128,7 +4147,7 @@ public final class ViewRootImpl implements ViewParent,
mDrawsNeededToReport = 0;
try {
mWindowSession.finishDrawing(mWindow, mSurfaceChangedTransaction);
mWindowSession.finishDrawing(mWindow, mSurfaceChangedTransaction, Integer.MAX_VALUE);
} catch (RemoteException e) {
Log.e(mTag, "Unable to report draw finished", e);
mSurfaceChangedTransaction.apply();
@ -8071,7 +8090,7 @@ public final class ViewRootImpl implements ViewParent,
requestedWidth, requestedHeight, viewVisibility,
insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0,
mTmpFrames, mPendingMergedConfiguration, mSurfaceControl, mTempInsets,
mTempControls);
mTempControls, mRelayoutBundle);
final int transformHint = SurfaceControl.rotationToBufferTransform(
(mDisplayInstallOrientation + mDisplay.getRotation()) % 4);
@ -8497,7 +8516,7 @@ public final class ViewRootImpl implements ViewParent,
if ((relayoutWindow(mWindowAttributes, viewVisibility, false)
& WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
mWindowSession.finishDrawing(
mWindow, null /* postDrawTransaction */);
mWindow, null /* postDrawTransaction */, Integer.MAX_VALUE);
}
} catch (RemoteException e) {
}
@ -8571,7 +8590,7 @@ public final class ViewRootImpl implements ViewParent,
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
private void dispatchResized(ClientWindowFrames frames, boolean reportDraw,
MergedConfiguration mergedConfiguration, boolean forceLayout,
boolean alwaysConsumeSystemBars, int displayId) {
boolean alwaysConsumeSystemBars, int displayId, int seqId) {
final Rect frame = frames.frame;
final Rect backDropFrame = frames.backdropFrame;
if (DEBUG_LAYOUT) Log.v(mTag, "Resizing " + this + ": frame=" + frame.toShortString()
@ -8602,6 +8621,7 @@ public final class ViewRootImpl implements ViewParent,
args.argi1 = forceLayout ? 1 : 0;
args.argi2 = alwaysConsumeSystemBars ? 1 : 0;
args.argi3 = displayId;
args.argi4 = seqId;
msg.obj = args;
mHandler.sendMessage(msg);
}
@ -9986,11 +10006,11 @@ public final class ViewRootImpl implements ViewParent,
@Override
public void resized(ClientWindowFrames frames, boolean reportDraw,
MergedConfiguration mergedConfiguration, boolean forceLayout,
boolean alwaysConsumeSystemBars, int displayId) {
boolean alwaysConsumeSystemBars, int displayId, int seqId) {
final ViewRootImpl viewAncestor = mViewAncestor.get();
if (viewAncestor != null) {
viewAncestor.dispatchResized(frames, reportDraw, mergedConfiguration, forceLayout,
alwaysConsumeSystemBars, displayId);
alwaysConsumeSystemBars, displayId, seqId);
}
}

View File

@ -22,6 +22,7 @@ import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.Region;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteCallback;
import android.os.RemoteException;
@ -277,7 +278,7 @@ public class WindowlessWindowManager implements IWindowSession {
int requestedWidth, int requestedHeight, int viewFlags, int flags,
ClientWindowFrames outFrames, MergedConfiguration mergedConfiguration,
SurfaceControl outSurfaceControl, InsetsState outInsetsState,
InsetsSourceControl[] outActiveControls) {
InsetsSourceControl[] outActiveControls, Bundle outSyncSeqIdBundle) {
final State state;
synchronized (this) {
state = mStateForWindow.get(window.asBinder());
@ -354,7 +355,7 @@ public class WindowlessWindowManager implements IWindowSession {
@Override
public void finishDrawing(android.view.IWindow window,
android.view.SurfaceControl.Transaction postDrawTransaction) {
android.view.SurfaceControl.Transaction postDrawTransaction, int seqId) {
synchronized (this) {
final ResizeCompleteCallback c =
mResizeCompletionForWindow.get(window.asBinder());

View File

@ -51,10 +51,10 @@ public class BaseIWindow extends IWindow.Stub {
@Override
public void resized(ClientWindowFrames frames, boolean reportDraw,
MergedConfiguration mergedConfiguration, boolean forceLayout,
boolean alwaysConsumeSystemBars, int displayId) {
boolean alwaysConsumeSystemBars, int displayId, int seqId) {
if (reportDraw) {
try {
mSession.finishDrawing(this, null /* postDrawTransaction */);
mSession.finishDrawing(this, null /* postDrawTransaction */, seqId);
} catch (RemoteException e) {
}
}

View File

@ -344,7 +344,7 @@ public class SystemWindows {
@Override
public void resized(ClientWindowFrames frames, boolean reportDraw,
MergedConfiguration newMergedConfiguration, boolean forceLayout,
boolean alwaysConsumeSystemBars, int displayId) {}
boolean alwaysConsumeSystemBars, int displayId, int syncSeqId) {}
@Override
public void insetsChanged(InsetsState insetsState, boolean willMove, boolean willResize) {}

View File

@ -62,6 +62,7 @@ import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.RectF;
import android.hardware.HardwareBuffer;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.Trace;
@ -243,7 +244,7 @@ public class TaskSnapshotWindow {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "TaskSnapshot#relayout");
session.relayout(window, layoutParams, -1, -1, View.VISIBLE, 0,
tmpFrames, tmpMergedConfiguration, surfaceControl, tmpInsetsState,
tmpControls);
tmpControls, new Bundle());
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
} catch (RemoteException e) {
snapshotSurface.clearWindowSynced();
@ -517,7 +518,7 @@ public class TaskSnapshotWindow {
private void reportDrawn() {
try {
mSession.finishDrawing(mWindow, null /* postDrawTransaction */);
mSession.finishDrawing(mWindow, null /* postDrawTransaction */, Integer.MAX_VALUE);
} catch (RemoteException e) {
clearWindowSynced();
}
@ -534,7 +535,7 @@ public class TaskSnapshotWindow {
@Override
public void resized(ClientWindowFrames frames, boolean reportDraw,
MergedConfiguration mergedConfiguration, boolean forceLayout,
boolean alwaysConsumeSystemBars, int displayId) {
boolean alwaysConsumeSystemBars, int displayId, int seqId) {
if (mOuter != null) {
mOuter.mSplashScreenExecutor.execute(() -> {
if (mergedConfiguration != null

View File

@ -0,0 +1,108 @@
= What does it mean for BLAST Sync to work? =
There are two BLAST sync primitives on the server side, BLASTSyncEngine and applyWithNextDraw.
Both of them are used to solve subclasses of this category of problem:
1. You have some server side changes, which will trigger both WM/SysUI initiated SurfaceControl.Transactions,
and also trigger a client redraw/update
2. You want to synchronize the redraw of those clients with the application of those WM/SysUI side changes.
Put simply, you would like to synchronize the graphical effects of some WM changes with the graphical output of various windows
observing those changes.
To talk about exactly what the primitives guarantee, we need to clarify what we mean by server side changes.
In this document we will use a term syncable state to refer to any state mutated under the WindowManager lock
which when observed by the client, produces a visible outcome in the produced frame.
For example the current Configuration.
The guarantee provided by Server-side BLAST Sync Primitives is thus:
Guarantee 1: If you make a set of changes to syncable state, at the same time that you begin a sync,
then the first frame drawn by the client after observing the syncable state will be sent in a transaction
to the consumer of the sync which was begun, rather than directly sent to SurfaceFlinger.
Here "at the same time" means in the same critical section (while holding the WM lock)
For example this guarantee means that you can write code like:
window.performConfigurationChange(someConfiguration)
window.applyOnNextDraw(consumer)
And the consumer will always be passed the first frame containing the configuration change. This can work with any
syncable state not just Configuration.
The following is the protocol and additional requirements for BLAST sync, and an analysis of why it is correct. Due to time
constraints we analyze it for a single window only (as this is actually the hard part).
Protocol requirements:
Server protocol, precondition, begin a syncSeqId integer per window at 0:
SA: Enter the critical section
SB: Change syncable state, any number of times, prepare any number of syncs (and
increment the seqId if a sync was prepared, assosciate it with the sync)
SC: Leave the critical section
SD: Send syncable state updates to the client, always paired with the current seqId
SE: When the client calls finishDrawing, execute the consumer for each sync with
seqId <= the seqId which the client passed to finishDrawing
Client protocol:
CA: Observe state and seqid changes up until a fixed frame deadline, then execute performTraversals
CB: If the seqId is incremeneted at the time of the frame deadline, configure the renderer to
redirect the next draw in to a transaction, record the seqId at the time
CC: When the draw is finished, send the transaction containing the draw to WM with the
previously recorded seqId
Additional requirements/assumptions:
1. The server may only send changes to the syncable state paired with the seqId. The client may
only receive them together (e.g. not from other sources)
2. In between changing and sending syncable state, the lock must be released and acquired again
3. The client wont draw a frame reflecting syncable state changes without passing through "performTraversals"
4. Drawing never fails
5. There are no blocking calls between the client or the server
Note that the server can begin the protocol at any time, so it may be possible for the client to proceed through
phases SA, SB, SC, and SD multiple times before the client receives any messages.
To show that the guarantee can't be violated, we use a notation of sequences, where we describe interleaving
of protocol events. For duplicate events, we attach a number, e.g. SA_1, SA_2.
We proceed by contradiction, imagine there was some sequence (..., SA_N, ...) for which the guarantee was
not upheld. This means that either
1. finishDrawing with the assosciate seqId was never sent to the server OR
2. It was sent too late (after the first frame was sent to SF instead of WM) OR
3. It was sent too early (not containing the state changes originating with SA_N)
If it was sent neither too late, nor too early, and contained the assosciated seqId, then protocol step SE
says that the frame will be passed to the consumer and we uphold our guarantee.
The first case is impossible because step SD says that the server always sends the seqId if a sync was prepared.
If we send it the client must receive it. Since we only increment the seqId, and the client only takes the
seqId from us (requirement 1, protocol step SB), the received ID must be higher than the clients previous seqId.
CA says that performTraversals will execute, and CB says that when it does, if the seqId is higher than before
it will schedule the render to sync. Requirement 4 says drawing never fails, so CC must execute, and so we will always
eventually send every seqId (or a seqId > than it) back to the server.
It also can't be sent too late. By requirement 2 we must release and acquire the lock
after after changing and before emitting syncable state changes. This means it's guaranteed
that even in an ordering like AcquireLock, ChangeState, PrepareSync, Release lock we can't
send the state changes before prepareSync, and so they can always include at least the seqId
assosciated with changestate (or a later one).
Since we only receive the SeqId with the State changes (requirement 1),
and we wont draw state changes without passing through perform traversals (requirement 3) the first frame
containing the state change must have been generated by a call to performTraversals which also observed
the seqId change, and so it will appropriately configure the renderer.
By the same argument it can't be sent too early! Since we only send seqIds we receive from the server,
and we only send seqIds after completing a drawing pass of the assosciated state.
So we can see that no matter at what time the server makes syncable state changes, the first frame will
always be delivered to the draw handler. Assuming that the client and server uphold this protocol and these
requirements.
The trickiest part of the implementation at the moment is due to assosciating seqId. Currently we send one of the most
most important pieces of syncable state (configuration) over multiple channels. Namely ClientTransaction
and MSG_RESIZED. The ordering of these relative to sync preparation in server code is undefined, in fact we have cases like
this all the time:
acquireLock()
changeConfiguration()
// time passes, but still in critical section
prepareSync()
releaseLock()
This is exactly the kind of case Guarantee 1 mentions as an example. In previous incarnations of the code this worked
because relayoutWindow needed to acquire the same lock and relayoutWindow was a necessary part of completing sync.
Now that we have no barrier, that could create issues, because at the time we change configuration (and send the change
to the client via ClientTransaction), we haven't even incremented the seqId yet, and so how can the client observe it
at the same time as the state? We solve this by pushing all client communication through a handler thread that has to
acquire the lock. This ensures we uphold requirement 2.

View File

@ -232,14 +232,14 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
int requestedWidth, int requestedHeight, int viewFlags, int flags,
ClientWindowFrames outFrames, MergedConfiguration mergedConfiguration,
SurfaceControl outSurfaceControl, InsetsState outInsetsState,
InsetsSourceControl[] outActiveControls) {
InsetsSourceControl[] outActiveControls, Bundle outSyncSeqIdBundle) {
if (false) Slog.d(TAG_WM, ">>>>>> ENTERED relayout from "
+ Binder.getCallingPid());
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, mRelayoutTag);
int res = mService.relayoutWindow(this, window, attrs,
requestedWidth, requestedHeight, viewFlags, flags,
outFrames, mergedConfiguration, outSurfaceControl, outInsetsState,
outActiveControls);
outActiveControls, outSyncSeqIdBundle);
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
if (false) Slog.d(TAG_WM, "<<<<<< EXITING relayout to "
+ Binder.getCallingPid());
@ -265,9 +265,9 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
@Override
public void finishDrawing(IWindow window,
@Nullable SurfaceControl.Transaction postDrawTransaction) {
@Nullable SurfaceControl.Transaction postDrawTransaction, int seqId) {
if (DEBUG) Slog.v(TAG_WM, "IWindow finishDrawing called for " + window);
mService.finishDrawingWindow(this, window, postDrawTransaction);
mService.finishDrawingWindow(this, window, postDrawTransaction, seqId);
}
@Override

View File

@ -2192,7 +2192,7 @@ public class WindowManagerService extends IWindowManager.Stub
int requestedWidth, int requestedHeight, int viewVisibility, int flags,
ClientWindowFrames outFrames, MergedConfiguration mergedConfiguration,
SurfaceControl outSurfaceControl, InsetsState outInsetsState,
InsetsSourceControl[] outActiveControls) {
InsetsSourceControl[] outActiveControls, Bundle outSyncIdBundle) {
Arrays.fill(outActiveControls, null);
int result = 0;
boolean configChanged;
@ -2617,7 +2617,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
void finishDrawingWindow(Session session, IWindow client,
@Nullable SurfaceControl.Transaction postDrawTransaction) {
@Nullable SurfaceControl.Transaction postDrawTransaction, int seqId) {
if (postDrawTransaction != null) {
postDrawTransaction.sanitize();
}
@ -2628,7 +2628,7 @@ public class WindowManagerService extends IWindowManager.Stub
WindowState win = windowForClientLocked(session, client, false);
ProtoLog.d(WM_DEBUG_ADD_REMOVE, "finishDrawingWindow: %s mDrawState=%s",
win, (win != null ? win.mWinAnimator.drawStateToString() : "null"));
if (win != null && win.finishDrawing(postDrawTransaction)) {
if (win != null && win.finishDrawing(postDrawTransaction, seqId)) {
if (win.hasWallpaper()) {
win.getDisplayContent().pendingLayoutChanges |=
WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;

View File

@ -3946,7 +3946,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
try {
mClient.resized(mClientWindowFrames, reportDraw, mLastReportedConfiguration,
forceRelayout, alwaysConsumeSystemBars, displayId);
forceRelayout, alwaysConsumeSystemBars, displayId, Integer.MAX_VALUE);
if (drawPending && reportOrientation && mOrientationChanging) {
mOrientationChangeRedrawRequestTime = SystemClock.elapsedRealtime();
ProtoLog.v(WM_DEBUG_ORIENTATION,
@ -5938,7 +5938,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
super.finishSync(outMergedTransaction, cancel);
}
boolean finishDrawing(SurfaceControl.Transaction postDrawTransaction) {
boolean finishDrawing(SurfaceControl.Transaction postDrawTransaction, int syncSeqId) {
if (mOrientationChangeRedrawRequestTime > 0) {
final long duration =
SystemClock.elapsedRealtime() - mOrientationChangeRedrawRequestTime;
@ -5985,7 +5985,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
void immediatelyNotifyBlastSync() {
prepareDrawHandlers();
finishDrawing(null);
finishDrawing(null, Integer.MAX_VALUE);
mWmService.mH.removeMessages(WINDOW_STATE_BLAST_SYNC_TIMEOUT, this);
if (!useBLASTSync()) return;
}

View File

@ -44,7 +44,7 @@ public class TestIWindow extends IWindow.Stub {
@Override
public void resized(ClientWindowFrames frames, boolean reportDraw,
MergedConfiguration mergedConfig, boolean forceLayout, boolean alwaysConsumeSystemBars,
int displayId) throws RemoteException {
int displayId, int seqId) throws RemoteException {
}
@Override

View File

@ -692,7 +692,8 @@ public class TransitionTests extends WindowTestsBase {
statusBar.mWinAnimator.mDrawState = WindowStateAnimator.DRAW_PENDING;
final SurfaceControl.Transaction postDrawTransaction =
mock(SurfaceControl.Transaction.class);
final boolean layoutNeeded = statusBar.finishDrawing(postDrawTransaction);
final boolean layoutNeeded = statusBar.finishDrawing(postDrawTransaction,
Integer.MAX_VALUE);
assertFalse(layoutNeeded);
transactionCommittedListener.onTransactionCommitted();
@ -742,7 +743,7 @@ public class TransitionTests extends WindowTestsBase {
player.finish();
// The controller should be cleared if the target windows are drawn.
statusBar.finishDrawing(mWm.mTransactionFactory.get());
statusBar.finishDrawing(mWm.mTransactionFactory.get(), Integer.MAX_VALUE);
statusBar.setOrientationChanging(false);
assertNull(mDisplayContent.getAsyncRotationController());
}

View File

@ -504,7 +504,7 @@ public class WindowStateTests extends WindowTestsBase {
assertTrue(win.useBLASTSync());
final SurfaceControl.Transaction drawT = new StubTransaction();
win.prepareDrawHandlers();
assertTrue(win.finishDrawing(drawT));
assertTrue(win.finishDrawing(drawT, Integer.MAX_VALUE));
assertEquals(drawT, handledT[0]);
assertFalse(win.useBLASTSync());
@ -693,7 +693,7 @@ public class WindowStateTests extends WindowTestsBase {
doThrow(new RemoteException("test")).when(win.mClient).resized(any() /* frames */,
anyBoolean() /* reportDraw */, any() /* mergedConfig */,
anyBoolean() /* forceLayout */, anyBoolean() /* alwaysConsumeSystemBars */,
anyInt() /* displayId */);
anyInt() /* displayId */, anyInt() /* seqId */);
} catch (RemoteException ignored) {
}
win.reportResized();