Continue layout if needed
Sometimes the operations in the deferLayout~continueLayout don't
change significant states related to layout.
This reduces 1~3 times performSurfacePlacement when switching between
activities. Also reduce lots of invocations when resizing task/stack.
Bounds change isn't a layout reason from activity aspect because there
are already many invocations from relayoutWindow, finishDrawingWindow
and animate that will request traversal.
Test: go/wm-smoke
Test: Enable debug log in WindowSurfacePlacer to observe the
invocation of performSurfacePlacement from continueLayout.
Bug: 140407614
Change-Id: I347f1fe1db676dcf320163bed0df693775b5f022
diff --git a/services/core/java/com/android/server/wm/ActivityDisplay.java b/services/core/java/com/android/server/wm/ActivityDisplay.java
index f3e7384..e488cc9 100644
--- a/services/core/java/com/android/server/wm/ActivityDisplay.java
+++ b/services/core/java/com/android/server/wm/ActivityDisplay.java
@@ -740,7 +740,7 @@
}
private void onSplitScreenModeDismissed() {
- mRootActivityContainer.mWindowManager.deferSurfaceLayout();
+ mService.deferWindowLayout();
try {
// Adjust the windowing mode of any stack in secondary split-screen to fullscreen.
for (int i = mStacks.size() - 1; i >= 0; --i) {
@@ -764,12 +764,12 @@
mHomeStack.moveToFront("onSplitScreenModeDismissed");
topFullscreenStack.moveToFront("onSplitScreenModeDismissed");
}
- mRootActivityContainer.mWindowManager.continueSurfaceLayout();
+ mService.continueWindowLayout();
}
}
private void onSplitScreenModeActivated() {
- mRootActivityContainer.mWindowManager.deferSurfaceLayout();
+ mService.deferWindowLayout();
try {
// Adjust the windowing mode of any affected by split-screen to split-screen secondary.
for (int i = mStacks.size() - 1; i >= 0; --i) {
@@ -784,7 +784,7 @@
false /* creating */);
}
} finally {
- mRootActivityContainer.mWindowManager.continueSurfaceLayout();
+ mService.continueWindowLayout();
}
}
@@ -1002,12 +1002,9 @@
Configuration values = new Configuration();
mDisplayContent.computeScreenConfiguration(values);
- if (mService.mWindowManager != null) {
- final Message msg = PooledLambda.obtainMessage(
- ActivityManagerInternal::updateOomLevelsForDisplay, mService.mAmInternal,
- mDisplayId);
- mService.mH.sendMessage(msg);
- }
+ mService.mH.sendMessage(PooledLambda.obtainMessage(
+ ActivityManagerInternal::updateOomLevelsForDisplay, mService.mAmInternal,
+ mDisplayId));
Settings.System.clearConfiguration(values);
updateDisplayOverrideConfigurationLocked(values, null /* starting */,
@@ -1026,9 +1023,7 @@
int changes = 0;
boolean kept = true;
- if (mService.mWindowManager != null) {
- mService.mWindowManager.deferSurfaceLayout();
- }
+ mService.deferWindowLayout();
try {
if (values != null) {
if (mDisplayId == DEFAULT_DISPLAY) {
@@ -1045,9 +1040,7 @@
kept = mService.ensureConfigAndVisibilityAfterUpdate(starting, changes);
} finally {
- if (mService.mWindowManager != null) {
- mService.mWindowManager.continueSurfaceLayout();
- }
+ mService.continueWindowLayout();
}
if (result != null) {
@@ -1096,6 +1089,8 @@
mService.mWindowManager.setNewDisplayOverrideConfiguration(
overrideConfiguration, mDisplayContent);
}
+ mService.addWindowLayoutReasons(
+ ActivityTaskManagerService.LAYOUT_REASON_CONFIG_CHANGED);
}
@Override
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 61bf2ce..7a66731 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -1703,7 +1703,7 @@
// is not visible if it only contains finishing activities.
&& mRootActivityContainer.isTopDisplayFocusedStack(stack);
- mAtmService.mWindowManager.deferSurfaceLayout();
+ mAtmService.deferWindowLayout();
try {
makeFinishingLocked();
final TaskRecord task = getTaskRecord();
@@ -1809,7 +1809,7 @@
return FINISH_RESULT_REQUESTED;
} finally {
- mAtmService.mWindowManager.continueSurfaceLayout();
+ mAtmService.continueWindowLayout();
}
}
@@ -2547,6 +2547,8 @@
return;
}
mAppWindowToken.setVisibility(visible, mDeferHidingClient);
+ mAtmService.addWindowLayoutReasons(
+ ActivityTaskManagerService.LAYOUT_REASON_VISIBILITY_CHANGED);
mStackSupervisor.getActivityMetricsLogger().notifyVisibilityChanged(this);
}
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 29e87b7..8bb37bb 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -757,7 +757,6 @@
return;
}
- final WindowManagerService wm = mService.mWindowManager;
final ActivityRecord topActivity = getTopActivity();
// For now, assume that the Stack's windowing mode is what will actually be used
@@ -779,7 +778,7 @@
topTask.taskId, FORCED_RESIZEABLE_REASON_SPLIT_SCREEN, packageName);
}
- wm.deferSurfaceLayout();
+ mService.deferWindowLayout();
try {
if (!animate && topActivity != null) {
mStackSupervisor.mNoAnimActivities.add(topActivity);
@@ -850,7 +849,7 @@
// If task moved to docked stack - show recents if needed.
mService.mWindowManager.showRecentApps();
}
- wm.continueSurfaceLayout();
+ mService.continueWindowLayout();
}
if (!deferEnsuringVisibility) {
@@ -1750,11 +1749,11 @@
if (mPausingActivity == r) {
if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to PAUSED: " + r
+ (timeout ? " (due to timeout)" : " (pause complete)"));
- mService.mWindowManager.deferSurfaceLayout();
+ mService.deferWindowLayout();
try {
completePauseLocked(true /* resumeNext */, null /* resumingActivity */);
} finally {
- mService.mWindowManager.continueSurfaceLayout();
+ mService.continueWindowLayout();
}
return;
} else {
@@ -4360,7 +4359,7 @@
}
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "stack.resize_" + mStackId);
- mWindowManager.deferSurfaceLayout();
+ mService.deferWindowLayout();
try {
// Update override configurations of all tasks in the stack.
final Rect taskBounds = tempTaskBounds != null ? tempTaskBounds : bounds;
@@ -4384,7 +4383,7 @@
topRunningActivityLocked(), preserveWindows);
}
} finally {
- mWindowManager.continueSurfaceLayout();
+ mService.continueWindowLayout();
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 7a3f022..1aa1d48 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -1495,7 +1495,7 @@
private void moveTasksToFullscreenStackInSurfaceTransaction(ActivityStack fromStack,
int toDisplayId, boolean onTop) {
- mWindowManager.deferSurfaceLayout();
+ mService.deferWindowLayout();
try {
final int windowingMode = fromStack.getWindowingMode();
final boolean inPinnedWindowingMode = windowingMode == WINDOWING_MODE_PINNED;
@@ -1561,7 +1561,7 @@
mRootActivityContainer.resumeFocusedStacksTopActivities();
} finally {
mAllowDockedStackResize = true;
- mWindowManager.continueSurfaceLayout();
+ mService.continueWindowLayout();
}
}
@@ -1630,7 +1630,7 @@
}
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "am.resizeDockedStack");
- mWindowManager.deferSurfaceLayout();
+ mService.deferWindowLayout();
try {
// Don't allow re-entry while resizing. E.g. due to docked stack detaching.
mAllowDockedStackResize = false;
@@ -1694,7 +1694,7 @@
}
} finally {
mAllowDockedStackResize = true;
- mWindowManager.continueSurfaceLayout();
+ mService.continueWindowLayout();
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
}
@@ -1718,9 +1718,8 @@
}
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "am.resizePinnedStack");
- mWindowManager.deferSurfaceLayout();
+ mService.deferWindowLayout();
try {
- ActivityRecord r = stack.topRunningActivityLocked();
Rect insetBounds = null;
if (tempPinnedTaskBounds != null && stack.isAnimatingBoundsToFullscreen()) {
// Use 0,0 as the position for the inset rect because we are headed for fullscreen.
@@ -1739,7 +1738,7 @@
stack.resize(pinnedBounds, tempPinnedTaskBounds, insetBounds, !PRESERVE_WINDOWS,
!DEFER_RESUME);
} finally {
- mWindowManager.continueSurfaceLayout();
+ mService.continueWindowLayout();
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
}
@@ -2731,7 +2730,7 @@
+ taskId + " can't be launch in the home/recents stack.");
}
- mWindowManager.deferSurfaceLayout();
+ mService.deferWindowLayout();
try {
if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
mWindowManager.setDockedStackCreateStateLocked(
@@ -2822,7 +2821,7 @@
mWindowManager.checkSplitScreenMinimizedChanged(false /* animate */);
}
}
- mWindowManager.continueSurfaceLayout();
+ mService.continueWindowLayout();
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 641b00a..55db1a0 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1400,7 +1400,7 @@
int result = START_CANCELED;
final ActivityStack startedActivityStack;
try {
- mService.mWindowManager.deferSurfaceLayout();
+ mService.deferWindowLayout();
result = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor,
startFlags, doResume, options, inTask, outActivity, restrictedBgActivity);
} finally {
@@ -1436,7 +1436,7 @@
startedActivityStack.remove();
}
}
- mService.mWindowManager.continueSurfaceLayout();
+ mService.continueWindowLayout();
}
postStartActivityProcessing(r, result, startedActivityStack);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index ed7e12c..2f7acba 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -124,6 +124,7 @@
import static com.android.server.wm.TaskRecord.REPARENT_LEAVE_STACK_IN_PLACE;
import android.Manifest;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
@@ -598,6 +599,19 @@
*/
int mTopProcessState = ActivityManager.PROCESS_STATE_TOP;
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({
+ LAYOUT_REASON_CONFIG_CHANGED,
+ LAYOUT_REASON_VISIBILITY_CHANGED,
+ })
+ @interface LayoutReason {}
+ static final int LAYOUT_REASON_CONFIG_CHANGED = 0x1;
+ static final int LAYOUT_REASON_VISIBILITY_CHANGED = 0x2;
+
+ /** The reasons to perform surface placement. */
+ @LayoutReason
+ private int mLayoutReasons;
+
// Whether we should show our dialogs (ANR, crash, etc) or just perform their default action
// automatically. Important for devices without direct input devices.
private boolean mShowDialogs = true;
@@ -4388,17 +4402,19 @@
mAmInternal.enforceCallingPermission(CHANGE_CONFIGURATION, "updateConfiguration()");
synchronized (mGlobalLock) {
- if (values == null && mWindowManager != null) {
+ if (mWindowManager == null) {
+ Slog.w(TAG, "Skip updateConfiguration because mWindowManager isn't set");
+ return false;
+ }
+
+ if (values == null) {
// sentinel: fetch the current configuration from the window manager
values = mWindowManager.computeNewConfiguration(DEFAULT_DISPLAY);
}
- if (mWindowManager != null) {
- final Message msg = PooledLambda.obtainMessage(
- ActivityManagerInternal::updateOomLevelsForDisplay, mAmInternal,
- DEFAULT_DISPLAY);
- mH.sendMessage(msg);
- }
+ mH.sendMessage(PooledLambda.obtainMessage(
+ ActivityManagerInternal::updateOomLevelsForDisplay, mAmInternal,
+ DEFAULT_DISPLAY));
final long origId = Binder.clearCallingIdentity();
try {
@@ -5099,9 +5115,7 @@
int changes = 0;
boolean kept = true;
- if (mWindowManager != null) {
- mWindowManager.deferSurfaceLayout();
- }
+ deferWindowLayout();
try {
if (values != null) {
changes = updateGlobalConfigurationLocked(values, initLocale, persistent, userId,
@@ -5110,9 +5124,7 @@
kept = ensureConfigAndVisibilityAfterUpdate(starting, changes);
} finally {
- if (mWindowManager != null) {
- mWindowManager.continueSurfaceLayout();
- }
+ continueWindowLayout();
}
if (result != null) {
@@ -5240,6 +5252,34 @@
return changes;
}
+ /** @see WindowSurfacePlacer#deferLayout */
+ void deferWindowLayout() {
+ if (!mWindowManager.mWindowPlacerLocked.isLayoutDeferred()) {
+ // Reset the reasons at the first entrance because we only care about the changes in the
+ // deferred scope.
+ mLayoutReasons = 0;
+ }
+
+ mWindowManager.mWindowPlacerLocked.deferLayout();
+ }
+
+ /** @see WindowSurfacePlacer#continueLayout */
+ void continueWindowLayout() {
+ mWindowManager.mWindowPlacerLocked.continueLayout(mLayoutReasons != 0);
+ if (DEBUG_ALL && !mWindowManager.mWindowPlacerLocked.isLayoutDeferred()) {
+ Slog.i(TAG, "continueWindowLayout reason=" + mLayoutReasons);
+ }
+ }
+
+ /**
+ * If a reason is added between {@link #deferWindowLayout} and {@link #continueWindowLayout},
+ * it will make sure {@link WindowSurfacePlacer#performSurfacePlacement} is called when the last
+ * defer count is gone.
+ */
+ void addWindowLayoutReasons(@LayoutReason int reasons) {
+ mLayoutReasons |= reasons;
+ }
+
private void updateEventDispatchingLocked(boolean booted) {
mWindowManager.setEventDispatching(booted && !mShuttingDown);
}
@@ -6667,7 +6707,7 @@
}
if (!restarting && hasVisibleActivities) {
- mWindowManager.deferSurfaceLayout();
+ deferWindowLayout();
try {
if (!mRootActivityContainer.resumeFocusedStacksTopActivities()) {
// If there was nothing to resume, and we are not already restarting
@@ -6678,7 +6718,7 @@
!PRESERVE_WINDOWS);
}
} finally {
- mWindowManager.continueSurfaceLayout();
+ continueWindowLayout();
}
}
}
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 422b6e5..d528ef6 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -182,7 +182,7 @@
return;
}
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "keyguardGoingAway");
- mWindowManager.deferSurfaceLayout();
+ mService.deferWindowLayout();
try {
setKeyguardGoingAway(true);
EventLog.writeEvent(EventLogTags.AM_SET_KEYGUARD_SHOWN,
@@ -204,7 +204,7 @@
mWindowManager.executeAppTransition();
} finally {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "keyguardGoingAway: surfaceLayout");
- mWindowManager.continueSurfaceLayout();
+ mService.continueWindowLayout();
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
@@ -330,7 +330,7 @@
mWindowManager.onKeyguardOccludedChanged(isDisplayOccluded(DEFAULT_DISPLAY));
if (isKeyguardLocked()) {
- mWindowManager.deferSurfaceLayout();
+ mService.deferWindowLayout();
try {
mRootActivityContainer.getDefaultDisplay().mDisplayContent
.prepareAppTransition(resolveOccludeTransit(),
@@ -340,7 +340,7 @@
mRootActivityContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
mWindowManager.executeAppTransition();
} finally {
- mWindowManager.continueSurfaceLayout();
+ mService.continueWindowLayout();
}
}
dismissDockedStackIfNeeded();
diff --git a/services/core/java/com/android/server/wm/LaunchParamsController.java b/services/core/java/com/android/server/wm/LaunchParamsController.java
index 59df09b..6de48d1 100644
--- a/services/core/java/com/android/server/wm/LaunchParamsController.java
+++ b/services/core/java/com/android/server/wm/LaunchParamsController.java
@@ -133,7 +133,7 @@
return false;
}
- mService.mWindowManager.deferSurfaceLayout();
+ mService.deferWindowLayout();
try {
if (mTmpParams.hasPreferredDisplay()
@@ -161,7 +161,7 @@
task.setLastNonFullscreenBounds(mTmpParams.mBounds);
return false;
} finally {
- mService.mWindowManager.continueSurfaceLayout();
+ mService.continueWindowLayout();
}
}
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index 1a8944a..5cabbd9 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -196,7 +196,7 @@
mCaller.setRunningRecentsAnimation(true);
}
- mWindowManager.deferSurfaceLayout();
+ mService.deferWindowLayout();
try {
if (hasExistingActivity) {
// Move the recents activity into place for the animation if it is not top most
@@ -260,7 +260,7 @@
Slog.e(TAG, "Failed to start recents activity", e);
throw e;
} finally {
- mWindowManager.continueSurfaceLayout();
+ mService.continueWindowLayout();
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
}
@@ -297,7 +297,7 @@
mWindowManager.inSurfaceTransaction(() -> {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER,
"RecentsAnimation#onAnimationFinished_inSurfaceTransaction");
- mWindowManager.deferSurfaceLayout();
+ mService.deferWindowLayout();
try {
mWindowManager.cleanupRecentsAnimation(reorderMode);
@@ -387,7 +387,7 @@
Slog.e(TAG, "Failed to clean up recents activity", e);
throw e;
} finally {
- mWindowManager.continueSurfaceLayout();
+ mService.continueWindowLayout();
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
});
diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java
index eeea185..d9e30a2 100644
--- a/services/core/java/com/android/server/wm/RootActivityContainer.java
+++ b/services/core/java/com/android/server/wm/RootActivityContainer.java
@@ -945,7 +945,7 @@
void moveActivityToPinnedStack(ActivityRecord r, Rect sourceHintBounds, float aspectRatio,
String reason) {
- mWindowManager.deferSurfaceLayout();
+ mService.deferWindowLayout();
final ActivityDisplay display = r.getActivityStack().getDisplay();
ActivityStack stack = display.getPinnedStack();
@@ -994,7 +994,7 @@
// to the pinned stack
r.supportsEnterPipOnTaskSwitch = false;
} finally {
- mWindowManager.continueSurfaceLayout();
+ mService.continueWindowLayout();
}
// Notify the pinned stack controller to prepare the PiP animation, expect callback
@@ -2060,7 +2060,7 @@
* @param userId user handle for the locked managed profile.
*/
void lockAllProfileTasks(@UserIdInt int userId) {
- mWindowManager.deferSurfaceLayout();
+ mService.deferWindowLayout();
try {
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
final ActivityDisplay display = mActivityDisplays.get(displayNdx);
@@ -2081,7 +2081,7 @@
}
}
} finally {
- mWindowManager.continueSurfaceLayout();
+ mService.continueWindowLayout();
}
}
diff --git a/services/core/java/com/android/server/wm/TaskRecord.java b/services/core/java/com/android/server/wm/TaskRecord.java
index d3f3981..4b3691c8 100644
--- a/services/core/java/com/android/server/wm/TaskRecord.java
+++ b/services/core/java/com/android/server/wm/TaskRecord.java
@@ -545,7 +545,7 @@
}
boolean resize(Rect bounds, int resizeMode, boolean preserveWindow, boolean deferResume) {
- mService.mWindowManager.deferSurfaceLayout();
+ mService.deferWindowLayout();
try {
if (!isResizeable()) {
@@ -619,7 +619,7 @@
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
return kept;
} finally {
- mService.mWindowManager.continueSurfaceLayout();
+ mService.continueWindowLayout();
}
}
@@ -725,7 +725,7 @@
windowManager.setWillReplaceWindow(topActivity.appToken, animate);
}
- windowManager.deferSurfaceLayout();
+ mService.deferWindowLayout();
boolean kept = true;
try {
final ActivityRecord r = topRunningActivityLocked();
@@ -809,7 +809,7 @@
!mightReplaceWindow, deferResume);
}
} finally {
- windowManager.continueSurfaceLayout();
+ mService.continueWindowLayout();
}
if (mightReplaceWindow) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 8d3a107..a7f6688 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2775,21 +2775,6 @@
}
/**
- * Starts deferring layout passes. Useful when doing multiple changes but to optimize
- * performance, only one layout pass should be done. This can be called multiple times, and
- * layouting will be resumed once the last caller has called
- * {@link #continueSurfaceLayout}.
- */
- void deferSurfaceLayout() {
- mWindowPlacerLocked.deferLayout();
- }
-
- /** Resumes layout passes after deferring them. See {@link #deferSurfaceLayout()} */
- void continueSurfaceLayout() {
- mWindowPlacerLocked.continueLayout();
- }
-
- /**
* Notifies activity manager that some Keyguard flags have changed and that it needs to
* reevaluate the visibilities of the activities.
* @param callback Runnable to be called when activity manager is done reevaluating visibilities
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index cc791787..56f6d4b 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -25,7 +25,6 @@
import android.os.Debug;
import android.os.Trace;
import android.util.Slog;
-import android.util.SparseIntArray;
import java.io.PrintWriter;
@@ -50,8 +49,8 @@
private boolean mTraversalScheduled;
private int mDeferDepth = 0;
-
- private final SparseIntArray mTempTransitionReasons = new SparseIntArray();
+ /** The number of layout requests when deferring. */
+ private int mDeferredRequests;
private final Runnable mPerformSurfacePlacement;
@@ -65,19 +64,38 @@
}
/**
- * See {@link WindowManagerService#deferSurfaceLayout()}
+ * Starts deferring layout passes. Useful when doing multiple changes but to optimize
+ * performance, only one layout pass should be done. This can be called multiple times, and
+ * layouting will be resumed once the last caller has called {@link #continueLayout}.
*/
void deferLayout() {
mDeferDepth++;
}
/**
- * See {@link WindowManagerService#continueSurfaceLayout()}
+ * Resumes layout passes after deferring them. If there is a deferred direct invocation of
+ * {@link #performSurfacePlacement} ({@link #mDeferredRequests} > 0), when the defer is
+ * done, it will continue to perform layout.
+ *
+ * @param hasChanges Something has changed. That means whether to call
+ * {@link #performSurfacePlacement} when {@link #mDeferDepth} becomes zero.
+ * @see #deferLayout
*/
- void continueLayout() {
+ void continueLayout(boolean hasChanges) {
mDeferDepth--;
- if (mDeferDepth <= 0) {
+ if (mDeferDepth > 0) {
+ return;
+ }
+
+ if (hasChanges || mDeferredRequests > 0) {
+ if (DEBUG) {
+ Slog.i(TAG, "continueLayout hasChanges=" + hasChanges
+ + " deferredRequests=" + mDeferredRequests + " " + Debug.getCallers(2, 3));
+ }
performSurfacePlacement();
+ mDeferredRequests = 0;
+ } else if (DEBUG) {
+ Slog.i(TAG, "Cancel continueLayout " + Debug.getCallers(2, 3));
}
}
@@ -97,6 +115,7 @@
final void performSurfacePlacement(boolean force) {
if (mDeferDepth > 0 && !force) {
+ mDeferredRequests++;
return;
}
int loopCount = 6;
@@ -195,10 +214,19 @@
}
void requestTraversal() {
- if (!mTraversalScheduled) {
- mTraversalScheduled = true;
- mService.mAnimationHandler.post(mPerformSurfacePlacement);
+ if (mTraversalScheduled) {
+ return;
}
+
+ // Set as scheduled even the request will be deferred because mDeferredRequests is also
+ // increased, then the end of deferring will perform the request.
+ mTraversalScheduled = true;
+ if (mDeferDepth > 0) {
+ mDeferredRequests++;
+ if (DEBUG) Slog.i(TAG, "Defer requestTraversal " + Debug.getCallers(3));
+ return;
+ }
+ mService.mAnimationHandler.post(mPerformSurfacePlacement);
}
public void dump(PrintWriter pw, String prefix) {