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/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();
}
}
}