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