From 167bbfac24b1e78576b18c0522218838dfdf57bb Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Thu, 31 Mar 2016 09:44:34 -0700 Subject: [PATCH] Avoid extra relaunch when rotating side-by-side apps Update configuration with WM first and check if the stacks need to be resized due to the update. If so, let activity manager resize the stacks inline, instead of letting WM schedule another pass of resizeStack. This way the configuration will be updated to the latest before ensureActivity- ConfigurationLocked, and we don't need another relaunch there. bug: 27834014 Change-Id: Ib761a96cada0c3247b0480f18370670c593159da --- core/java/android/view/IWindowManager.aidl | 7 +++- .../com/android/internal/util/ArrayUtils.java | 8 ++++ .../server/am/ActivityManagerService.java | 23 ++++++++++-- .../java/com/android/server/wm/TaskStack.java | 37 +++++++++++++------ .../server/wm/WindowManagerService.java | 27 +++++++++++--- .../src/android/view/IWindowManagerImpl.java | 7 +++- 6 files changed, 87 insertions(+), 22 deletions(-) diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 5bcf1027f3848..4ba97d5f8bea3 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -180,7 +180,12 @@ interface IWindowManager // caller must call setNewConfiguration() sometime later. Configuration updateOrientationFromAppTokens(in Configuration currentConfig, IBinder freezeThisOneIfNeeded); - void setNewConfiguration(in Configuration config); + // Notify window manager of the new configuration. Returns an array of stack ids that's + // affected by the update, ActivityManager should resize these stacks. + int[] setNewConfiguration(in Configuration config); + + // Retrieves the new bounds after the configuration update evaluated by window manager. + Rect getBoundsForNewConfiguration(int stackId); void startFreezingScreen(int exitAnim, int enterAnim); void stopFreezingScreen(); diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java index ee73b90097af3..bed5a2e219aef 100644 --- a/core/java/com/android/internal/util/ArrayUtils.java +++ b/core/java/com/android/internal/util/ArrayUtils.java @@ -238,6 +238,14 @@ public class ArrayUtils { return total; } + public static int[] convertToIntArray(List list) { + int[] array = new int[list.size()]; + for (int i = 0; i < list.size(); i++) { + array[i] = list.get(i); + } + return array; + } + /** * Adds value to given array if not already present, providing set-like * behavior. diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index e82c6c7a22a45..46a5abb66019f 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -18044,6 +18044,9 @@ public final class ActivityManagerService extends ActivityManagerNative ActivityRecord starting, boolean initLocale, boolean persistent, int userId) { int changes = 0; + if (mWindowManager != null) { + mWindowManager.deferSurfaceLayout(); + } if (values != null) { Configuration newConfig = new Configuration(mConfiguration); changes = newConfig.updateFrom(values); @@ -18144,6 +18147,20 @@ public final class ActivityManagerService extends ActivityManagerNative null, false, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL); } } + // Update the configuration with WM first and check if any of the stacks need to be + // resized due to the configuration change. If so, resize the stacks now and do any + // relaunches if necessary. This way we don't need to relaunch again below in + // ensureActivityConfigurationLocked(). + if (mWindowManager != null) { + final int[] resizedStacks = mWindowManager.setNewConfiguration(mConfiguration); + if (resizedStacks != null) { + for (int stackId : resizedStacks) { + final Rect newBounds = mWindowManager.getBoundsForNewConfiguration(stackId); + mStackSupervisor.resizeStackLocked( + stackId, newBounds, null, null, false, false); + } + } + } } boolean kept = true; @@ -18165,11 +18182,9 @@ public final class ActivityManagerService extends ActivityManagerNative !PRESERVE_WINDOWS); } } - - if (values != null && mWindowManager != null) { - mWindowManager.setNewConfiguration(mConfiguration); + if (mWindowManager != null) { + mWindowManager.continueSurfaceLayout(); } - return kept; } diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java index 0bf7102ddeb87..b05cfb8e406d5 100644 --- a/services/core/java/com/android/server/wm/TaskStack.java +++ b/services/core/java/com/android/server/wm/TaskStack.java @@ -128,6 +128,10 @@ public class TaskStack implements DimLayer.DimLayerUser, // in which case a second window animation would cause jitter. private boolean mFreezeMovementAnimations = false; + // Temporary storage for the new bounds that should be used after the configuration change. + // Will be cleared once the client retrieves the new bounds via getBoundsForNewConfiguration(). + private final Rect mBoundsAfterRotation = new Rect(); + TaskStack(WindowManagerService service, int stackId) { mService = service; mStackId = stackId; @@ -343,28 +347,28 @@ public class TaskStack implements DimLayer.DimLayerUser, setBounds(mTmpRect2); } else { mLastUpdateDisplayInfoRotation = newRotation; - updateBoundsAfterRotation(); + updateBoundsAfterRotation(true); } } - void onConfigurationChanged() { + boolean onConfigurationChanged() { mLastConfigChangedRotation = getDisplayInfo().rotation; - updateBoundsAfterRotation(); + return updateBoundsAfterRotation(false); } - void updateBoundsAfterRotation() { + boolean updateBoundsAfterRotation(boolean scheduleResize) { if (mLastConfigChangedRotation != mLastUpdateDisplayInfoRotation) { // We wait for the rotation values after configuration change and display info. update // to be equal before updating the bounds due to rotation change otherwise things might // get out of alignment... - return; + return false; } final int newRotation = getDisplayInfo().rotation; if (mRotation == newRotation) { // Nothing to do here if the rotation didn't change - return; + return false; } mDisplayContent.rotateBounds(mRotation, newRotation, mTmpRect2); @@ -373,11 +377,22 @@ public class TaskStack implements DimLayer.DimLayerUser, snapDockedStackAfterRotation(mTmpRect2); } - // Post message to inform activity manager of the bounds change simulating - // a one-way call. We do this to prevent a deadlock between window manager - // lock and activity manager lock been held. - mService.mH.obtainMessage( - RESIZE_STACK, mStackId, 0 /*allowResizeInDockedMode*/, mTmpRect2).sendToTarget(); + if (scheduleResize) { + // Post message to inform activity manager of the bounds change simulating + // a one-way call. We do this to prevent a deadlock between window manager + // lock and activity manager lock been held. + mService.mH.obtainMessage(RESIZE_STACK, mStackId, + 0 /*allowResizeInDockedMode*/, mTmpRect2).sendToTarget(); + } else { + mBoundsAfterRotation.set(mTmpRect2); + } + + return true; + } + + void getBoundsForNewConfiguration(Rect outBounds) { + outBounds.set(mBoundsAfterRotation); + mBoundsAfterRotation.setEmpty(); } /** diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index dcb4a63a560ae..192ba7b879e48 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -125,6 +125,7 @@ import com.android.internal.R; import com.android.internal.app.IAssistScreenshotReceiver; import com.android.internal.os.IResultReceiver; import com.android.internal.policy.IShortcutService; +import com.android.internal.util.ArrayUtils; import com.android.internal.util.FastPrintWriter; import com.android.internal.view.IInputContext; import com.android.internal.view.IInputMethodClient; @@ -515,6 +516,8 @@ public class WindowManagerService extends IWindowManager.Stub private final SparseIntArray mTmpTaskIds = new SparseIntArray(); + private final ArrayList mChangedStackList = new ArrayList(); + boolean mForceResizableTasks = false; int getDragLayerLocked() { @@ -3580,7 +3583,7 @@ public class WindowManagerService extends IWindowManager.Stub } @Override - public void setNewConfiguration(Configuration config) { + public int[] setNewConfiguration(Configuration config) { if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, "setNewConfiguration()")) { throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); @@ -3592,16 +3595,30 @@ public class WindowManagerService extends IWindowManager.Stub mWaitingForConfig = false; mLastFinishedFreezeSource = "new-config"; } - onConfigurationChanged(); - mWindowPlacerLocked.performSurfacePlacement(); + return onConfigurationChanged(); } } - private void onConfigurationChanged() { + @Override + public Rect getBoundsForNewConfiguration(int stackId) { + synchronized(mWindowMap) { + final TaskStack stack = mStackIdToStack.get(stackId); + final Rect outBounds = new Rect(); + stack.getBoundsForNewConfiguration(outBounds); + return outBounds; + } + } + + private int[] onConfigurationChanged() { + mChangedStackList.clear(); for (int stackNdx = mStackIdToStack.size() - 1; stackNdx >= 0; stackNdx--) { final TaskStack stack = mStackIdToStack.valueAt(stackNdx); - stack.onConfigurationChanged(); + if (stack.onConfigurationChanged()) { + mChangedStackList.add(stack.mStackId); + } } + return mChangedStackList.isEmpty() ? + null : ArrayUtils.convertToIntArray(mChangedStackList); } @Override diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java index 7faee1b3d1740..0abc3c5d1c0f1 100644 --- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java +++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java @@ -403,7 +403,12 @@ public class IWindowManagerImpl implements IWindowManager { } @Override - public void setNewConfiguration(Configuration arg0) throws RemoteException { + public int[] setNewConfiguration(Configuration arg0) throws RemoteException { + // TODO Auto-generated method stub + } + + @Override + public Rect getBoundsForNewConfiguration(int stackId) throws RemoteException { // TODO Auto-generated method stub }