Loading services/core/java/com/android/server/wm/WindowManagerService.java +6 −5 Original line number Original line Diff line number Diff line Loading @@ -2235,11 +2235,6 @@ public class WindowManagerService extends IWindowManager.Stub win.mPendingPositionChanged = null; win.mPendingPositionChanged = null; } } if (mUseBLASTSync && win.useBLASTSync() && viewVisibility != View.GONE) { win.prepareDrawHandlers(); result |= RELAYOUT_RES_BLAST_SYNC; } int attrChanges = 0; int attrChanges = 0; int flagChanges = 0; int flagChanges = 0; int privateFlagChanges = 0; int privateFlagChanges = 0; Loading Loading @@ -2512,6 +2507,12 @@ public class WindowManagerService extends IWindowManager.Stub } } win.mInRelayout = false; win.mInRelayout = false; if (mUseBLASTSync && win.useBLASTSync() && viewVisibility != View.GONE) { win.prepareDrawHandlers(); win.markRedrawForSyncReported(); result |= RELAYOUT_RES_BLAST_SYNC; } if (configChanged) { if (configChanged) { Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "relayoutWindow: postNewConfigurationToHandler"); "relayoutWindow: postNewConfigurationToHandler"); Loading services/core/java/com/android/server/wm/WindowState.java +70 −6 Original line number Original line Diff line number Diff line Loading @@ -763,6 +763,56 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP * into mReadyDrawHandlers. Finally once we get to finishDrawing we know everything in * into mReadyDrawHandlers. Finally once we get to finishDrawing we know everything in * mReadyDrawHandlers corresponds to state which was observed by the client and we can * mReadyDrawHandlers corresponds to state which was observed by the client and we can * invoke the consumers. * invoke the consumers. * * To see in more detail that this works, we can look at it like this: * * The client is in one of these states: * * 1. Asleep * 2. Traversal scheduled * 3. Starting traversal * 4. In relayout * 5. Already drawing * * The property we want to implement with the draw handlers is: * If WM code makes a change to client observable state (e.g. configuration), * and registers a draw handler (without releasing the WM lock in between), * the FIRST frame reflecting that change, will be in the Transaction passed * to the draw handler. * * We describe the expected sequencing in each of the possible client states. * We aim to "prove" that the WM can call applyWithNextDraw() with the client * starting in any state, and achieve the desired result. * * 1. Asleep: The client will wake up in response to MSG_RESIZED, call relayout, * observe the changes. Relayout will return BLAST_SYNC, and the client will * send the transaction to finishDrawing. Since the client was asleep. This * will be the first finishDrawing reflecting the change. * 2, 3: traversal scheduled/starting traversal: These two states can be considered * together. Each has two sub-states: * a) Traversal will call relayout. In this case we proceed like the starting * from asleep case. * b) Traversal will not call relayout. In this case, the client produced * frame will not include the change. Because there is no call to relayout * there is no call to prepareDrawHandlers() and even if the client calls * finish drawing the draw handler will not be invoked. We have to wait * on the client to receive MSG_RESIZED, and will sync on the next frame * 4. In relayout. In this case we are careful to prepare draw handlers and check * whether to return the BLAST flag at the end of relayoutWindow. This means if you * add a draw handler while the client is in relayout, BLAST_SYNC will be * immediately returned, and the client will submit the frame corresponding * to what returns from layout. When we prepare the draw handlers we clear the * flag which would later cause us to report draw for sync. Since we reported * sync through relayout (by luck the client was calling relayout perhaps) * there is no need for a MSG_RESIZED. * 5. Already drawing. This works much like cases 2 and 3. If there is no call to * finishDrawing then of course the draw handlers will not be invoked and we just * wait on the next frame for sync. If there is a call to finishDrawing, * the draw handler will not have been prepared (since we did not call relayout) * and we will have to wait on the next frame. * * By this logic we can see no matter which of the client states we are in when the * draw handler is added, it will always execute on the expected frame. */ */ private final List<Consumer<SurfaceControl.Transaction>> mPendingDrawHandlers private final List<Consumer<SurfaceControl.Transaction>> mPendingDrawHandlers = new ArrayList<>(); = new ArrayList<>(); Loading Loading @@ -3706,7 +3756,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP final int displayId = getDisplayId(); final int displayId = getDisplayId(); fillClientWindowFrames(mClientWindowFrames); fillClientWindowFrames(mClientWindowFrames); mRedrawForSyncReported = true; markRedrawForSyncReported(); try { try { mClient.resized(mClientWindowFrames, reportDraw, mergedConfiguration, forceRelayout, mClient.resized(mClientWindowFrames, reportDraw, mergedConfiguration, forceRelayout, Loading Loading @@ -5850,7 +5900,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP * "in relayout", the results may be undefined but at all other times the function * "in relayout", the results may be undefined but at all other times the function * should sort of transparently work like this: * should sort of transparently work like this: * 1. Make changes to WM hierarchy (say change app configuration) * 1. Make changes to WM hierarchy (say change app configuration) * 2. Call apply with next draw. * 2. Call applyWithNextDraw * 3. After finishDrawing, our consumer will be passed the Transaction * 3. After finishDrawing, our consumer will be passed the Transaction * containing the buffer, and we can merge in additional operations. * containing the buffer, and we can merge in additional operations. * See {@link WindowState#mPendingDrawHandlers} * See {@link WindowState#mPendingDrawHandlers} Loading Loading @@ -5879,16 +5929,26 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP * See {@link WindowState#mPendingDrawHandlers} * See {@link WindowState#mPendingDrawHandlers} */ */ boolean executeDrawHandlers(SurfaceControl.Transaction t) { boolean executeDrawHandlers(SurfaceControl.Transaction t) { if (t == null) t = mTmpTransaction; boolean hadHandlers = false; boolean hadHandlers = false; boolean applyHere = false; if (t == null) { t = mTmpTransaction; applyHere = true; } for (int i = 0; i < mReadyDrawHandlers.size(); i++) { for (int i = 0; i < mReadyDrawHandlers.size(); i++) { mReadyDrawHandlers.get(i).accept(t); mReadyDrawHandlers.get(i).accept(t); hadHandlers = true; hadHandlers = true; } } if (hadHandlers) { mReadyDrawHandlers.clear(); mReadyDrawHandlers.clear(); mWmService.mH.removeMessages(WINDOW_STATE_BLAST_SYNC_TIMEOUT, this); mWmService.mH.removeMessages(WINDOW_STATE_BLAST_SYNC_TIMEOUT, this); } if (applyHere) { t.apply(); t.apply(); } return hadHandlers; return hadHandlers; } } Loading @@ -5906,4 +5966,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP @WindowManager.LayoutParams.WindowType int getWindowType() { @WindowManager.LayoutParams.WindowType int getWindowType() { return mAttrs.type; return mAttrs.type; } } void markRedrawForSyncReported() { mRedrawForSyncReported = true; } } } services/core/java/com/android/server/wm/WindowStateAnimator.java +6 −5 Original line number Original line Diff line number Diff line Loading @@ -272,15 +272,16 @@ class WindowStateAnimator { } } mDrawState = COMMIT_DRAW_PENDING; mDrawState = COMMIT_DRAW_PENDING; layoutNeeded = true; layoutNeeded = true; } if (postDrawTransaction != null) { if (postDrawTransaction != null) { if (mLastHidden) { mPostDrawTransaction.merge(postDrawTransaction); mPostDrawTransaction.merge(postDrawTransaction); } layoutNeeded = true; } else if (postDrawTransaction != null) { } else { // If draw state is not pending we may delay applying this transaction from the client, // so apply it now. postDrawTransaction.apply(); postDrawTransaction.apply(); } } } return layoutNeeded; return layoutNeeded; } } Loading Loading
services/core/java/com/android/server/wm/WindowManagerService.java +6 −5 Original line number Original line Diff line number Diff line Loading @@ -2235,11 +2235,6 @@ public class WindowManagerService extends IWindowManager.Stub win.mPendingPositionChanged = null; win.mPendingPositionChanged = null; } } if (mUseBLASTSync && win.useBLASTSync() && viewVisibility != View.GONE) { win.prepareDrawHandlers(); result |= RELAYOUT_RES_BLAST_SYNC; } int attrChanges = 0; int attrChanges = 0; int flagChanges = 0; int flagChanges = 0; int privateFlagChanges = 0; int privateFlagChanges = 0; Loading Loading @@ -2512,6 +2507,12 @@ public class WindowManagerService extends IWindowManager.Stub } } win.mInRelayout = false; win.mInRelayout = false; if (mUseBLASTSync && win.useBLASTSync() && viewVisibility != View.GONE) { win.prepareDrawHandlers(); win.markRedrawForSyncReported(); result |= RELAYOUT_RES_BLAST_SYNC; } if (configChanged) { if (configChanged) { Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "relayoutWindow: postNewConfigurationToHandler"); "relayoutWindow: postNewConfigurationToHandler"); Loading
services/core/java/com/android/server/wm/WindowState.java +70 −6 Original line number Original line Diff line number Diff line Loading @@ -763,6 +763,56 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP * into mReadyDrawHandlers. Finally once we get to finishDrawing we know everything in * into mReadyDrawHandlers. Finally once we get to finishDrawing we know everything in * mReadyDrawHandlers corresponds to state which was observed by the client and we can * mReadyDrawHandlers corresponds to state which was observed by the client and we can * invoke the consumers. * invoke the consumers. * * To see in more detail that this works, we can look at it like this: * * The client is in one of these states: * * 1. Asleep * 2. Traversal scheduled * 3. Starting traversal * 4. In relayout * 5. Already drawing * * The property we want to implement with the draw handlers is: * If WM code makes a change to client observable state (e.g. configuration), * and registers a draw handler (without releasing the WM lock in between), * the FIRST frame reflecting that change, will be in the Transaction passed * to the draw handler. * * We describe the expected sequencing in each of the possible client states. * We aim to "prove" that the WM can call applyWithNextDraw() with the client * starting in any state, and achieve the desired result. * * 1. Asleep: The client will wake up in response to MSG_RESIZED, call relayout, * observe the changes. Relayout will return BLAST_SYNC, and the client will * send the transaction to finishDrawing. Since the client was asleep. This * will be the first finishDrawing reflecting the change. * 2, 3: traversal scheduled/starting traversal: These two states can be considered * together. Each has two sub-states: * a) Traversal will call relayout. In this case we proceed like the starting * from asleep case. * b) Traversal will not call relayout. In this case, the client produced * frame will not include the change. Because there is no call to relayout * there is no call to prepareDrawHandlers() and even if the client calls * finish drawing the draw handler will not be invoked. We have to wait * on the client to receive MSG_RESIZED, and will sync on the next frame * 4. In relayout. In this case we are careful to prepare draw handlers and check * whether to return the BLAST flag at the end of relayoutWindow. This means if you * add a draw handler while the client is in relayout, BLAST_SYNC will be * immediately returned, and the client will submit the frame corresponding * to what returns from layout. When we prepare the draw handlers we clear the * flag which would later cause us to report draw for sync. Since we reported * sync through relayout (by luck the client was calling relayout perhaps) * there is no need for a MSG_RESIZED. * 5. Already drawing. This works much like cases 2 and 3. If there is no call to * finishDrawing then of course the draw handlers will not be invoked and we just * wait on the next frame for sync. If there is a call to finishDrawing, * the draw handler will not have been prepared (since we did not call relayout) * and we will have to wait on the next frame. * * By this logic we can see no matter which of the client states we are in when the * draw handler is added, it will always execute on the expected frame. */ */ private final List<Consumer<SurfaceControl.Transaction>> mPendingDrawHandlers private final List<Consumer<SurfaceControl.Transaction>> mPendingDrawHandlers = new ArrayList<>(); = new ArrayList<>(); Loading Loading @@ -3706,7 +3756,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP final int displayId = getDisplayId(); final int displayId = getDisplayId(); fillClientWindowFrames(mClientWindowFrames); fillClientWindowFrames(mClientWindowFrames); mRedrawForSyncReported = true; markRedrawForSyncReported(); try { try { mClient.resized(mClientWindowFrames, reportDraw, mergedConfiguration, forceRelayout, mClient.resized(mClientWindowFrames, reportDraw, mergedConfiguration, forceRelayout, Loading Loading @@ -5850,7 +5900,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP * "in relayout", the results may be undefined but at all other times the function * "in relayout", the results may be undefined but at all other times the function * should sort of transparently work like this: * should sort of transparently work like this: * 1. Make changes to WM hierarchy (say change app configuration) * 1. Make changes to WM hierarchy (say change app configuration) * 2. Call apply with next draw. * 2. Call applyWithNextDraw * 3. After finishDrawing, our consumer will be passed the Transaction * 3. After finishDrawing, our consumer will be passed the Transaction * containing the buffer, and we can merge in additional operations. * containing the buffer, and we can merge in additional operations. * See {@link WindowState#mPendingDrawHandlers} * See {@link WindowState#mPendingDrawHandlers} Loading Loading @@ -5879,16 +5929,26 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP * See {@link WindowState#mPendingDrawHandlers} * See {@link WindowState#mPendingDrawHandlers} */ */ boolean executeDrawHandlers(SurfaceControl.Transaction t) { boolean executeDrawHandlers(SurfaceControl.Transaction t) { if (t == null) t = mTmpTransaction; boolean hadHandlers = false; boolean hadHandlers = false; boolean applyHere = false; if (t == null) { t = mTmpTransaction; applyHere = true; } for (int i = 0; i < mReadyDrawHandlers.size(); i++) { for (int i = 0; i < mReadyDrawHandlers.size(); i++) { mReadyDrawHandlers.get(i).accept(t); mReadyDrawHandlers.get(i).accept(t); hadHandlers = true; hadHandlers = true; } } if (hadHandlers) { mReadyDrawHandlers.clear(); mReadyDrawHandlers.clear(); mWmService.mH.removeMessages(WINDOW_STATE_BLAST_SYNC_TIMEOUT, this); mWmService.mH.removeMessages(WINDOW_STATE_BLAST_SYNC_TIMEOUT, this); } if (applyHere) { t.apply(); t.apply(); } return hadHandlers; return hadHandlers; } } Loading @@ -5906,4 +5966,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP @WindowManager.LayoutParams.WindowType int getWindowType() { @WindowManager.LayoutParams.WindowType int getWindowType() { return mAttrs.type; return mAttrs.type; } } void markRedrawForSyncReported() { mRedrawForSyncReported = true; } } }
services/core/java/com/android/server/wm/WindowStateAnimator.java +6 −5 Original line number Original line Diff line number Diff line Loading @@ -272,15 +272,16 @@ class WindowStateAnimator { } } mDrawState = COMMIT_DRAW_PENDING; mDrawState = COMMIT_DRAW_PENDING; layoutNeeded = true; layoutNeeded = true; } if (postDrawTransaction != null) { if (postDrawTransaction != null) { if (mLastHidden) { mPostDrawTransaction.merge(postDrawTransaction); mPostDrawTransaction.merge(postDrawTransaction); } layoutNeeded = true; } else if (postDrawTransaction != null) { } else { // If draw state is not pending we may delay applying this transaction from the client, // so apply it now. postDrawTransaction.apply(); postDrawTransaction.apply(); } } } return layoutNeeded; return layoutNeeded; } } Loading