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 android.view.Display.DEFAULT_DISPLAY; 20 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_TRACE; 21 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS; 22 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; 23 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; 24 import static com.android.server.wm.WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE; 25 import static com.android.server.wm.WindowSurfacePlacer.SET_UPDATE_ROTATION; 26 27 import android.content.Context; 28 import android.os.Trace; 29 import android.util.Slog; 30 import android.util.SparseArray; 31 import android.util.TimeUtils; 32 import android.view.Choreographer; 33 import android.view.SurfaceControl; 34 import android.view.WindowManagerPolicy; 35 36 import com.android.internal.view.SurfaceFlingerVsyncChoreographer; 37 import com.android.server.AnimationThread; 38 39 import java.io.PrintWriter; 40 41 /** 42 * Singleton class that carries out the animations and Surface operations in a separate task 43 * on behalf of WindowManagerService. 44 */ 45 public class WindowAnimator { 46 private static final String TAG = TAG_WITH_CLASS_NAME ? "WindowAnimator" : TAG_WM; 47 48 final WindowManagerService mService; 49 final Context mContext; 50 final WindowManagerPolicy mPolicy; 51 private final WindowSurfacePlacer mWindowPlacerLocked; 52 53 /** Is any window animating? */ 54 private boolean mAnimating; 55 private boolean mLastAnimating; 56 57 /** Is any app window animating? */ 58 boolean mAppWindowAnimating; 59 60 final Choreographer.FrameCallback mAnimationFrameCallback; 61 62 /** Time of current animation step. Reset on each iteration */ 63 long mCurrentTime; 64 65 /** Skip repeated AppWindowTokens initialization. Note that AppWindowsToken's version of this 66 * is a long initialized to Long.MIN_VALUE so that it doesn't match this value on startup. */ 67 int mAnimTransactionSequence; 68 69 /** Window currently running an animation that has requested it be detached 70 * from the wallpaper. This means we need to ensure the wallpaper is 71 * visible behind it in case it animates in a way that would allow it to be 72 * seen. If multiple windows satisfy this, use the lowest window. */ 73 WindowState mWindowDetachedWallpaper = null; 74 75 int mBulkUpdateParams = 0; 76 Object mLastWindowFreezeSource; 77 78 SparseArray<DisplayContentsAnimator> mDisplayContentsAnimators = new SparseArray<>(2); 79 80 boolean mInitialized = false; 81 82 // When set to true the animator will go over all windows after an animation frame is posted and 83 // check if some got replaced and can be removed. 84 private boolean mRemoveReplacedWindows = false; 85 86 private Choreographer mChoreographer; 87 88 /** 89 * Indicates whether we have an animation frame callback scheduled, which will happen at 90 * vsync-app and then schedule the animation tick at the right time (vsync-sf). 91 */ 92 private boolean mAnimationFrameCallbackScheduled; 93 WindowAnimator(final WindowManagerService service)94 WindowAnimator(final WindowManagerService service) { 95 mService = service; 96 mContext = service.mContext; 97 mPolicy = service.mPolicy; 98 mWindowPlacerLocked = service.mWindowPlacerLocked; 99 AnimationThread.getHandler().runWithScissors( 100 () -> mChoreographer = Choreographer.getSfInstance(), 0 /* timeout */); 101 102 mAnimationFrameCallback = frameTimeNs -> { 103 synchronized (mService.mWindowMap) { 104 mAnimationFrameCallbackScheduled = false; 105 } 106 animate(frameTimeNs); 107 }; 108 } 109 addDisplayLocked(final int displayId)110 void addDisplayLocked(final int displayId) { 111 // Create the DisplayContentsAnimator object by retrieving it if the associated 112 // {@link DisplayContent} exists. 113 getDisplayContentsAnimatorLocked(displayId); 114 if (displayId == DEFAULT_DISPLAY) { 115 mInitialized = true; 116 } 117 } 118 removeDisplayLocked(final int displayId)119 void removeDisplayLocked(final int displayId) { 120 final DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.get(displayId); 121 if (displayAnimator != null) { 122 if (displayAnimator.mScreenRotationAnimation != null) { 123 displayAnimator.mScreenRotationAnimation.kill(); 124 displayAnimator.mScreenRotationAnimation = null; 125 } 126 } 127 128 mDisplayContentsAnimators.delete(displayId); 129 } 130 131 /** 132 * DO NOT HOLD THE WINDOW MANAGER LOCK WHILE CALLING THIS METHOD. Reason: the method closes 133 * an animation transaction, that might be blocking until the next sf-vsync, so we want to make 134 * sure other threads can make progress if this happens. 135 */ animate(long frameTimeNs)136 private void animate(long frameTimeNs) { 137 boolean transactionOpen = false; 138 try { 139 synchronized (mService.mWindowMap) { 140 if (!mInitialized) { 141 return; 142 } 143 144 mCurrentTime = frameTimeNs / TimeUtils.NANOS_PER_MS; 145 mBulkUpdateParams = SET_ORIENTATION_CHANGE_COMPLETE; 146 mAnimating = false; 147 mAppWindowAnimating = false; 148 if (DEBUG_WINDOW_TRACE) { 149 Slog.i(TAG, "!!! animate: entry time=" + mCurrentTime); 150 } 151 152 if (SHOW_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION animate"); 153 mService.openSurfaceTransaction(); 154 transactionOpen = true; 155 SurfaceControl.setAnimationTransaction(); 156 157 final AccessibilityController accessibilityController = 158 mService.mAccessibilityController; 159 final int numDisplays = mDisplayContentsAnimators.size(); 160 for (int i = 0; i < numDisplays; i++) { 161 final int displayId = mDisplayContentsAnimators.keyAt(i); 162 final DisplayContent dc = mService.mRoot.getDisplayContentOrCreate(displayId); 163 dc.stepAppWindowsAnimation(mCurrentTime); 164 DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.valueAt(i); 165 166 final ScreenRotationAnimation screenRotationAnimation = 167 displayAnimator.mScreenRotationAnimation; 168 if (screenRotationAnimation != null && screenRotationAnimation.isAnimating()) { 169 if (screenRotationAnimation.stepAnimationLocked(mCurrentTime)) { 170 setAnimating(true); 171 } else { 172 mBulkUpdateParams |= SET_UPDATE_ROTATION; 173 screenRotationAnimation.kill(); 174 displayAnimator.mScreenRotationAnimation = null; 175 176 //TODO (multidisplay): Accessibility supported only for the default 177 // display. 178 if (accessibilityController != null && dc.isDefaultDisplay) { 179 // We just finished rotation animation which means we did not 180 // announce the rotation and waited for it to end, announce now. 181 accessibilityController.onRotationChangedLocked( 182 mService.getDefaultDisplayContentLocked()); 183 } 184 } 185 } 186 187 // Update animations of all applications, including those 188 // associated with exiting/removed apps 189 ++mAnimTransactionSequence; 190 dc.updateWindowsForAnimator(this); 191 dc.updateWallpaperForAnimator(this); 192 dc.prepareWindowSurfaces(); 193 } 194 195 for (int i = 0; i < numDisplays; i++) { 196 final int displayId = mDisplayContentsAnimators.keyAt(i); 197 final DisplayContent dc = mService.mRoot.getDisplayContentOrCreate(displayId); 198 199 dc.checkAppWindowsReadyToShow(); 200 201 final ScreenRotationAnimation screenRotationAnimation = 202 mDisplayContentsAnimators.valueAt(i).mScreenRotationAnimation; 203 if (screenRotationAnimation != null) { 204 screenRotationAnimation.updateSurfacesInTransaction(); 205 } 206 207 orAnimating(dc.animateDimLayers()); 208 orAnimating(dc.getDockedDividerController().animate(mCurrentTime)); 209 //TODO (multidisplay): Magnification is supported only for the default display. 210 if (accessibilityController != null && dc.isDefaultDisplay) { 211 accessibilityController.drawMagnifiedRegionBorderIfNeededLocked(); 212 } 213 } 214 215 if (mService.mDragState != null) { 216 mAnimating |= mService.mDragState.stepAnimationLocked(mCurrentTime); 217 } 218 219 if (mAnimating) { 220 mService.scheduleAnimationLocked(); 221 } 222 223 if (mService.mWatermark != null) { 224 mService.mWatermark.drawIfNeeded(); 225 } 226 } 227 } catch (RuntimeException e) { 228 Slog.wtf(TAG, "Unhandled exception in Window Manager", e); 229 } finally { 230 if (transactionOpen) { 231 232 // Do not hold window manager lock while closing the transaction, as this might be 233 // blocking until the next frame, which can lead to total lock starvation. 234 mService.closeSurfaceTransaction(false /* withLockHeld */); 235 if (SHOW_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION animate"); 236 } 237 } 238 239 synchronized (mService.mWindowMap) { 240 boolean hasPendingLayoutChanges = mService.mRoot.hasPendingLayoutChanges(this); 241 boolean doRequest = false; 242 if (mBulkUpdateParams != 0) { 243 doRequest = mService.mRoot.copyAnimToLayoutParams(); 244 } 245 246 if (hasPendingLayoutChanges || doRequest) { 247 mWindowPlacerLocked.requestTraversal(); 248 } 249 250 if (mAnimating && !mLastAnimating) { 251 252 // Usually app transitions but quite a load onto the system already (with all the 253 // things happening in app), so pause task snapshot persisting to not increase the 254 // load. 255 mService.mTaskSnapshotController.setPersisterPaused(true); 256 Trace.asyncTraceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "animating", 0); 257 } 258 if (!mAnimating && mLastAnimating) { 259 mWindowPlacerLocked.requestTraversal(); 260 mService.mTaskSnapshotController.setPersisterPaused(false); 261 Trace.asyncTraceEnd(Trace.TRACE_TAG_WINDOW_MANAGER, "animating", 0); 262 } 263 264 mLastAnimating = mAnimating; 265 266 if (mRemoveReplacedWindows) { 267 mService.mRoot.removeReplacedWindows(); 268 mRemoveReplacedWindows = false; 269 } 270 271 mService.stopUsingSavedSurfaceLocked(); 272 mService.destroyPreservedSurfaceLocked(); 273 mService.mWindowPlacerLocked.destroyPendingSurfaces(); 274 275 if (DEBUG_WINDOW_TRACE) { 276 Slog.i(TAG, "!!! animate: exit mAnimating=" + mAnimating 277 + " mBulkUpdateParams=" + Integer.toHexString(mBulkUpdateParams) 278 + " mPendingLayoutChanges(DEFAULT_DISPLAY)=" 279 + Integer.toHexString(getPendingLayoutChanges(DEFAULT_DISPLAY))); 280 } 281 } 282 } 283 bulkUpdateParamsToString(int bulkUpdateParams)284 private static String bulkUpdateParamsToString(int bulkUpdateParams) { 285 StringBuilder builder = new StringBuilder(128); 286 if ((bulkUpdateParams & WindowSurfacePlacer.SET_UPDATE_ROTATION) != 0) { 287 builder.append(" UPDATE_ROTATION"); 288 } 289 if ((bulkUpdateParams & WindowSurfacePlacer.SET_WALLPAPER_MAY_CHANGE) != 0) { 290 builder.append(" WALLPAPER_MAY_CHANGE"); 291 } 292 if ((bulkUpdateParams & WindowSurfacePlacer.SET_FORCE_HIDING_CHANGED) != 0) { 293 builder.append(" FORCE_HIDING_CHANGED"); 294 } 295 if ((bulkUpdateParams & WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE) != 0) { 296 builder.append(" ORIENTATION_CHANGE_COMPLETE"); 297 } 298 if ((bulkUpdateParams & WindowSurfacePlacer.SET_TURN_ON_SCREEN) != 0) { 299 builder.append(" TURN_ON_SCREEN"); 300 } 301 return builder.toString(); 302 } 303 dumpLocked(PrintWriter pw, String prefix, boolean dumpAll)304 public void dumpLocked(PrintWriter pw, String prefix, boolean dumpAll) { 305 final String subPrefix = " " + prefix; 306 final String subSubPrefix = " " + subPrefix; 307 308 for (int i = 0; i < mDisplayContentsAnimators.size(); i++) { 309 pw.print(prefix); pw.print("DisplayContentsAnimator #"); 310 pw.print(mDisplayContentsAnimators.keyAt(i)); 311 pw.println(":"); 312 final DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.valueAt(i); 313 final DisplayContent dc = 314 mService.mRoot.getDisplayContentOrCreate(mDisplayContentsAnimators.keyAt(i)); 315 dc.dumpWindowAnimators(pw, subPrefix); 316 if (displayAnimator.mScreenRotationAnimation != null) { 317 pw.print(subPrefix); pw.println("mScreenRotationAnimation:"); 318 displayAnimator.mScreenRotationAnimation.printTo(subSubPrefix, pw); 319 } else if (dumpAll) { 320 pw.print(subPrefix); pw.println("no ScreenRotationAnimation "); 321 } 322 pw.println(); 323 } 324 325 pw.println(); 326 327 if (dumpAll) { 328 pw.print(prefix); pw.print("mAnimTransactionSequence="); 329 pw.print(mAnimTransactionSequence); 330 pw.print(prefix); pw.print("mCurrentTime="); 331 pw.println(TimeUtils.formatUptime(mCurrentTime)); 332 } 333 if (mBulkUpdateParams != 0) { 334 pw.print(prefix); pw.print("mBulkUpdateParams=0x"); 335 pw.print(Integer.toHexString(mBulkUpdateParams)); 336 pw.println(bulkUpdateParamsToString(mBulkUpdateParams)); 337 } 338 if (mWindowDetachedWallpaper != null) { 339 pw.print(prefix); pw.print("mWindowDetachedWallpaper="); 340 pw.println(mWindowDetachedWallpaper); 341 } 342 } 343 getPendingLayoutChanges(final int displayId)344 int getPendingLayoutChanges(final int displayId) { 345 if (displayId < 0) { 346 return 0; 347 } 348 final DisplayContent displayContent = mService.mRoot.getDisplayContentOrCreate(displayId); 349 return (displayContent != null) ? displayContent.pendingLayoutChanges : 0; 350 } 351 setPendingLayoutChanges(final int displayId, final int changes)352 void setPendingLayoutChanges(final int displayId, final int changes) { 353 if (displayId < 0) { 354 return; 355 } 356 final DisplayContent displayContent = mService.mRoot.getDisplayContentOrCreate(displayId); 357 if (displayContent != null) { 358 displayContent.pendingLayoutChanges |= changes; 359 } 360 } 361 getDisplayContentsAnimatorLocked(int displayId)362 private DisplayContentsAnimator getDisplayContentsAnimatorLocked(int displayId) { 363 if (displayId < 0) { 364 return null; 365 } 366 367 DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.get(displayId); 368 369 // It is possible that this underlying {@link DisplayContent} has been removed. In this 370 // case, we do not want to create an animator associated with it as {link #animate} will 371 // fail. 372 if (displayAnimator == null && mService.mRoot.getDisplayContent(displayId) != null) { 373 displayAnimator = new DisplayContentsAnimator(); 374 mDisplayContentsAnimators.put(displayId, displayAnimator); 375 } 376 return displayAnimator; 377 } 378 setScreenRotationAnimationLocked(int displayId, ScreenRotationAnimation animation)379 void setScreenRotationAnimationLocked(int displayId, ScreenRotationAnimation animation) { 380 final DisplayContentsAnimator animator = getDisplayContentsAnimatorLocked(displayId); 381 382 if (animator != null) { 383 animator.mScreenRotationAnimation = animation; 384 } 385 } 386 getScreenRotationAnimationLocked(int displayId)387 ScreenRotationAnimation getScreenRotationAnimationLocked(int displayId) { 388 if (displayId < 0) { 389 return null; 390 } 391 392 DisplayContentsAnimator animator = getDisplayContentsAnimatorLocked(displayId); 393 return animator != null? animator.mScreenRotationAnimation : null; 394 } 395 requestRemovalOfReplacedWindows(WindowState win)396 void requestRemovalOfReplacedWindows(WindowState win) { 397 mRemoveReplacedWindows = true; 398 } 399 scheduleAnimation()400 void scheduleAnimation() { 401 if (!mAnimationFrameCallbackScheduled) { 402 mAnimationFrameCallbackScheduled = true; 403 mChoreographer.postFrameCallback(mAnimationFrameCallback); 404 } 405 } 406 407 private class DisplayContentsAnimator { 408 ScreenRotationAnimation mScreenRotationAnimation = null; 409 } 410 isAnimating()411 boolean isAnimating() { 412 return mAnimating; 413 } 414 isAnimationScheduled()415 boolean isAnimationScheduled() { 416 return mAnimationFrameCallbackScheduled; 417 } 418 getChoreographer()419 Choreographer getChoreographer() { 420 return mChoreographer; 421 } 422 setAnimating(boolean animating)423 void setAnimating(boolean animating) { 424 mAnimating = animating; 425 } 426 orAnimating(boolean animating)427 void orAnimating(boolean animating) { 428 mAnimating |= animating; 429 } 430 } 431