1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.wm; 18 19 import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS; 20 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_ALL; 21 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION; 22 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS; 23 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_SCREEN_ROTATION; 24 import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN; 25 import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION; 26 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_TRACE; 27 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; 28 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; 29 import static com.android.server.wm.WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE; 30 31 import android.content.Context; 32 import android.os.Trace; 33 import android.util.Slog; 34 import android.util.SparseArray; 35 import android.util.TimeUtils; 36 import android.view.Choreographer; 37 import android.view.SurfaceControl; 38 39 import com.android.server.policy.WindowManagerPolicy; 40 import com.android.server.protolog.common.ProtoLog; 41 42 import java.io.PrintWriter; 43 import java.util.ArrayList; 44 45 /** 46 * Singleton class that carries out the animations and Surface operations in a separate task 47 * on behalf of WindowManagerService. 48 */ 49 public class WindowAnimator { 50 private static final String TAG = TAG_WITH_CLASS_NAME ? "WindowAnimator" : TAG_WM; 51 52 final WindowManagerService mService; 53 final Context mContext; 54 final WindowManagerPolicy mPolicy; 55 56 /** Is any window animating? */ 57 private boolean mLastRootAnimating; 58 59 /** True if we are running any animations that require expensive composition. */ 60 private boolean mRunningExpensiveAnimations; 61 62 final Choreographer.FrameCallback mAnimationFrameCallback; 63 64 /** Time of current animation step. Reset on each iteration */ 65 long mCurrentTime; 66 67 int mBulkUpdateParams = 0; 68 Object mLastWindowFreezeSource; 69 70 SparseArray<DisplayContentsAnimator> mDisplayContentsAnimators = new SparseArray<>(2); 71 72 private boolean mInitialized = false; 73 74 // When set to true the animator will go over all windows after an animation frame is posted and 75 // check if some got replaced and can be removed. 76 private boolean mRemoveReplacedWindows = false; 77 78 private Choreographer mChoreographer; 79 80 /** 81 * Indicates whether we have an animation frame callback scheduled, which will happen at 82 * vsync-app and then schedule the animation tick at the right time (vsync-sf). 83 */ 84 private boolean mAnimationFrameCallbackScheduled; 85 boolean mNotifyWhenNoAnimation = false; 86 87 /** 88 * A list of runnable that need to be run after {@link WindowContainer#prepareSurfaces} is 89 * executed and the corresponding transaction is closed and applied. 90 */ 91 private final ArrayList<Runnable> mAfterPrepareSurfacesRunnables = new ArrayList<>(); 92 private boolean mInExecuteAfterPrepareSurfacesRunnables; 93 94 private final SurfaceControl.Transaction mTransaction; 95 WindowAnimator(final WindowManagerService service)96 WindowAnimator(final WindowManagerService service) { 97 mService = service; 98 mContext = service.mContext; 99 mPolicy = service.mPolicy; 100 mTransaction = service.mTransactionFactory.get(); 101 service.mAnimationHandler.runWithScissors( 102 () -> mChoreographer = Choreographer.getSfInstance(), 0 /* timeout */); 103 104 mAnimationFrameCallback = frameTimeNs -> { 105 synchronized (mService.mGlobalLock) { 106 mAnimationFrameCallbackScheduled = false; 107 animate(frameTimeNs); 108 if (mNotifyWhenNoAnimation && !mLastRootAnimating) { 109 mService.mGlobalLock.notifyAll(); 110 } 111 } 112 }; 113 } 114 addDisplayLocked(final int displayId)115 void addDisplayLocked(final int displayId) { 116 // Create the DisplayContentsAnimator object by retrieving it if the associated 117 // {@link DisplayContent} exists. 118 getDisplayContentsAnimatorLocked(displayId); 119 } 120 removeDisplayLocked(final int displayId)121 void removeDisplayLocked(final int displayId) { 122 mDisplayContentsAnimators.delete(displayId); 123 } 124 ready()125 void ready() { 126 mInitialized = true; 127 } 128 animate(long frameTimeNs)129 private void animate(long frameTimeNs) { 130 if (!mInitialized) { 131 return; 132 } 133 134 // Schedule next frame already such that back-pressure happens continuously. 135 scheduleAnimation(); 136 137 mCurrentTime = frameTimeNs / TimeUtils.NANOS_PER_MS; 138 mBulkUpdateParams = SET_ORIENTATION_CHANGE_COMPLETE; 139 if (DEBUG_WINDOW_TRACE) { 140 Slog.i(TAG, "!!! animate: entry time=" + mCurrentTime); 141 } 142 143 ProtoLog.i(WM_SHOW_TRANSACTIONS, ">>> OPEN TRANSACTION animate"); 144 mService.openSurfaceTransaction(); 145 try { 146 // Remove all deferred displays, tasks, and activities. 147 mService.mRoot.handleCompleteDeferredRemoval(); 148 149 final AccessibilityController accessibilityController = 150 mService.mAccessibilityController; 151 final int numDisplays = mDisplayContentsAnimators.size(); 152 for (int i = 0; i < numDisplays; i++) { 153 final int displayId = mDisplayContentsAnimators.keyAt(i); 154 final DisplayContent dc = mService.mRoot.getDisplayContent(displayId); 155 // Update animations of all applications, including those associated with 156 // exiting/removed apps. 157 dc.updateWindowsForAnimator(); 158 dc.prepareSurfaces(); 159 } 160 161 for (int i = 0; i < numDisplays; i++) { 162 final int displayId = mDisplayContentsAnimators.keyAt(i); 163 final DisplayContent dc = mService.mRoot.getDisplayContent(displayId); 164 165 dc.checkAppWindowsReadyToShow(); 166 if (accessibilityController != null) { 167 accessibilityController.drawMagnifiedRegionBorderIfNeededLocked(displayId, 168 mTransaction); 169 } 170 } 171 172 cancelAnimation(); 173 174 if (mService.mWatermark != null) { 175 mService.mWatermark.drawIfNeeded(); 176 } 177 178 } catch (RuntimeException e) { 179 Slog.wtf(TAG, "Unhandled exception in Window Manager", e); 180 } 181 182 final boolean hasPendingLayoutChanges = mService.mRoot.hasPendingLayoutChanges(this); 183 final boolean doRequest = mBulkUpdateParams != 0 && mService.mRoot.copyAnimToLayoutParams(); 184 if (hasPendingLayoutChanges || doRequest) { 185 mService.mWindowPlacerLocked.requestTraversal(); 186 } 187 188 final boolean rootAnimating = mService.mRoot.isAnimating(TRANSITION | CHILDREN /* flags */, 189 ANIMATION_TYPE_ALL /* typesToCheck */); 190 if (rootAnimating && !mLastRootAnimating) { 191 Trace.asyncTraceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "animating", 0); 192 } 193 if (!rootAnimating && mLastRootAnimating) { 194 mService.mWindowPlacerLocked.requestTraversal(); 195 Trace.asyncTraceEnd(Trace.TRACE_TAG_WINDOW_MANAGER, "animating", 0); 196 } 197 mLastRootAnimating = rootAnimating; 198 199 final boolean runningExpensiveAnimations = 200 mService.mRoot.isAnimating(TRANSITION | CHILDREN /* flags */, 201 ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_SCREEN_ROTATION 202 | ANIMATION_TYPE_RECENTS /* typesToCheck */); 203 if (runningExpensiveAnimations && !mRunningExpensiveAnimations) { 204 // Usually app transitions put quite a load onto the system already (with all the things 205 // happening in app), so pause task snapshot persisting to not increase the load. 206 mService.mTaskSnapshotController.setPersisterPaused(true); 207 mTransaction.setEarlyWakeupStart(); 208 } else if (!runningExpensiveAnimations && mRunningExpensiveAnimations) { 209 mService.mTaskSnapshotController.setPersisterPaused(false); 210 mTransaction.setEarlyWakeupEnd(); 211 } 212 mRunningExpensiveAnimations = runningExpensiveAnimations; 213 214 SurfaceControl.mergeToGlobalTransaction(mTransaction); 215 mService.closeSurfaceTransaction("WindowAnimator"); 216 ProtoLog.i(WM_SHOW_TRANSACTIONS, "<<< CLOSE TRANSACTION animate"); 217 218 if (mRemoveReplacedWindows) { 219 mService.mRoot.removeReplacedWindows(); 220 mRemoveReplacedWindows = false; 221 } 222 223 mService.destroyPreservedSurfaceLocked(); 224 225 executeAfterPrepareSurfacesRunnables(); 226 227 if (DEBUG_WINDOW_TRACE) { 228 Slog.i(TAG, "!!! animate: exit" 229 + " mBulkUpdateParams=" + Integer.toHexString(mBulkUpdateParams) 230 + " hasPendingLayoutChanges=" + hasPendingLayoutChanges); 231 } 232 } 233 bulkUpdateParamsToString(int bulkUpdateParams)234 private static String bulkUpdateParamsToString(int bulkUpdateParams) { 235 StringBuilder builder = new StringBuilder(128); 236 if ((bulkUpdateParams & WindowSurfacePlacer.SET_UPDATE_ROTATION) != 0) { 237 builder.append(" UPDATE_ROTATION"); 238 } 239 if ((bulkUpdateParams & WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE) != 0) { 240 builder.append(" ORIENTATION_CHANGE_COMPLETE"); 241 } 242 return builder.toString(); 243 } 244 dumpLocked(PrintWriter pw, String prefix, boolean dumpAll)245 public void dumpLocked(PrintWriter pw, String prefix, boolean dumpAll) { 246 final String subPrefix = " " + prefix; 247 248 for (int i = 0; i < mDisplayContentsAnimators.size(); i++) { 249 pw.print(prefix); pw.print("DisplayContentsAnimator #"); 250 pw.print(mDisplayContentsAnimators.keyAt(i)); 251 pw.println(":"); 252 final DisplayContent dc = 253 mService.mRoot.getDisplayContent(mDisplayContentsAnimators.keyAt(i)); 254 dc.dumpWindowAnimators(pw, subPrefix); 255 pw.println(); 256 } 257 258 pw.println(); 259 260 if (dumpAll) { 261 pw.print(prefix); pw.print("mCurrentTime="); 262 pw.println(TimeUtils.formatUptime(mCurrentTime)); 263 } 264 if (mBulkUpdateParams != 0) { 265 pw.print(prefix); pw.print("mBulkUpdateParams=0x"); 266 pw.print(Integer.toHexString(mBulkUpdateParams)); 267 pw.println(bulkUpdateParamsToString(mBulkUpdateParams)); 268 } 269 } 270 getDisplayContentsAnimatorLocked(int displayId)271 private DisplayContentsAnimator getDisplayContentsAnimatorLocked(int displayId) { 272 if (displayId < 0) { 273 return null; 274 } 275 276 DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.get(displayId); 277 278 // It is possible that this underlying {@link DisplayContent} has been removed. In this 279 // case, we do not want to create an animator associated with it as {link #animate} will 280 // fail. 281 if (displayAnimator == null && mService.mRoot.getDisplayContent(displayId) != null) { 282 displayAnimator = new DisplayContentsAnimator(); 283 mDisplayContentsAnimators.put(displayId, displayAnimator); 284 } 285 return displayAnimator; 286 } 287 requestRemovalOfReplacedWindows(WindowState win)288 void requestRemovalOfReplacedWindows(WindowState win) { 289 mRemoveReplacedWindows = true; 290 } 291 scheduleAnimation()292 void scheduleAnimation() { 293 if (!mAnimationFrameCallbackScheduled) { 294 mAnimationFrameCallbackScheduled = true; 295 mChoreographer.postFrameCallback(mAnimationFrameCallback); 296 } 297 } 298 cancelAnimation()299 private void cancelAnimation() { 300 if (mAnimationFrameCallbackScheduled) { 301 mAnimationFrameCallbackScheduled = false; 302 mChoreographer.removeFrameCallback(mAnimationFrameCallback); 303 } 304 } 305 306 private class DisplayContentsAnimator { 307 } 308 isAnimationScheduled()309 boolean isAnimationScheduled() { 310 return mAnimationFrameCallbackScheduled; 311 } 312 getChoreographer()313 Choreographer getChoreographer() { 314 return mChoreographer; 315 } 316 317 /** 318 * Adds a runnable to be executed after {@link WindowContainer#prepareSurfaces} is called and 319 * the corresponding transaction is closed and applied. 320 */ addAfterPrepareSurfacesRunnable(Runnable r)321 void addAfterPrepareSurfacesRunnable(Runnable r) { 322 // If runnables are already being handled in executeAfterPrepareSurfacesRunnable, then just 323 // immediately execute the runnable passed in. 324 if (mInExecuteAfterPrepareSurfacesRunnables) { 325 r.run(); 326 return; 327 } 328 329 mAfterPrepareSurfacesRunnables.add(r); 330 scheduleAnimation(); 331 } 332 executeAfterPrepareSurfacesRunnables()333 void executeAfterPrepareSurfacesRunnables() { 334 335 // Don't even think about to start recursing! 336 if (mInExecuteAfterPrepareSurfacesRunnables) { 337 return; 338 } 339 mInExecuteAfterPrepareSurfacesRunnables = true; 340 341 // Traverse in order they were added. 342 final int size = mAfterPrepareSurfacesRunnables.size(); 343 for (int i = 0; i < size; i++) { 344 mAfterPrepareSurfacesRunnables.get(i).run(); 345 } 346 mAfterPrepareSurfacesRunnables.clear(); 347 mInExecuteAfterPrepareSurfacesRunnables = false; 348 } 349 } 350