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