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.internal.protolog.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 30 import android.content.Context; 31 import android.os.Trace; 32 import android.util.Slog; 33 import android.util.TimeUtils; 34 import android.view.Choreographer; 35 import android.view.SurfaceControl; 36 37 import com.android.internal.protolog.common.ProtoLog; 38 import com.android.server.policy.WindowManagerPolicy; 39 40 import java.io.PrintWriter; 41 import java.util.ArrayList; 42 43 /** 44 * Singleton class that carries out the animations and Surface operations in a separate task 45 * on behalf of WindowManagerService. 46 */ 47 public class WindowAnimator { 48 private static final String TAG = TAG_WITH_CLASS_NAME ? "WindowAnimator" : TAG_WM; 49 50 final WindowManagerService mService; 51 final Context mContext; 52 final WindowManagerPolicy mPolicy; 53 54 /** Is any window animating? */ 55 private boolean mLastRootAnimating; 56 57 /** True if we are running any animations that require expensive composition. */ 58 private boolean mRunningExpensiveAnimations; 59 60 final Choreographer.FrameCallback mAnimationFrameCallback; 61 62 /** Time of current animation step. Reset on each iteration */ 63 long mCurrentTime; 64 65 int mBulkUpdateParams = 0; 66 Object mLastWindowFreezeSource; 67 68 private boolean mInitialized = false; 69 70 private Choreographer mChoreographer; 71 72 /** 73 * Indicates whether we have an animation frame callback scheduled, which will happen at 74 * vsync-app and then schedule the animation tick at the right time (vsync-sf). 75 */ 76 private boolean mAnimationFrameCallbackScheduled; 77 boolean mNotifyWhenNoAnimation = false; 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; 87 WindowAnimator(final WindowManagerService service)88 WindowAnimator(final WindowManagerService service) { 89 mService = service; 90 mContext = service.mContext; 91 mPolicy = service.mPolicy; 92 mTransaction = service.mTransactionFactory.get(); 93 service.mAnimationHandler.runWithScissors( 94 () -> mChoreographer = Choreographer.getSfInstance(), 0 /* timeout */); 95 96 mAnimationFrameCallback = frameTimeNs -> { 97 synchronized (mService.mGlobalLock) { 98 mAnimationFrameCallbackScheduled = false; 99 animate(frameTimeNs); 100 if (mNotifyWhenNoAnimation && !mLastRootAnimating) { 101 mService.mGlobalLock.notifyAll(); 102 } 103 } 104 }; 105 } 106 ready()107 void ready() { 108 mInitialized = true; 109 } 110 animate(long frameTimeNs)111 private void animate(long frameTimeNs) { 112 if (!mInitialized) { 113 return; 114 } 115 116 // Schedule next frame already such that back-pressure happens continuously. 117 scheduleAnimation(); 118 119 final RootWindowContainer root = mService.mRoot; 120 final boolean useShellTransition = root.mTransitionController.isShellTransitionsEnabled(); 121 final int animationFlags = useShellTransition ? CHILDREN : (TRANSITION | CHILDREN); 122 boolean rootAnimating = false; 123 mCurrentTime = frameTimeNs / TimeUtils.NANOS_PER_MS; 124 mBulkUpdateParams = 0; 125 root.mOrientationChangeComplete = true; 126 if (DEBUG_WINDOW_TRACE) { 127 Slog.i(TAG, "!!! animate: entry time=" + mCurrentTime); 128 } 129 130 ProtoLog.i(WM_SHOW_TRANSACTIONS, ">>> OPEN TRANSACTION animate"); 131 try { 132 // Remove all deferred displays, tasks, and activities. 133 root.handleCompleteDeferredRemoval(); 134 135 final AccessibilityController accessibilityController = 136 mService.mAccessibilityController; 137 final int numDisplays = root.getChildCount(); 138 for (int i = 0; i < numDisplays; i++) { 139 final DisplayContent dc = root.getChildAt(i); 140 // Update animations of all applications, including those associated with 141 // exiting/removed apps. 142 dc.updateWindowsForAnimator(); 143 dc.prepareSurfaces(); 144 } 145 146 for (int i = 0; i < numDisplays; i++) { 147 final DisplayContent dc = root.getChildAt(i); 148 149 if (!useShellTransition) { 150 dc.checkAppWindowsReadyToShow(); 151 } 152 if (accessibilityController.hasCallbacks()) { 153 accessibilityController 154 .recomputeMagnifiedRegionAndDrawMagnifiedRegionBorderIfNeeded( 155 dc.mDisplayId); 156 } 157 158 if (dc.isAnimating(animationFlags, ANIMATION_TYPE_ALL)) { 159 rootAnimating = true; 160 if (!dc.mLastContainsRunningSurfaceAnimator) { 161 dc.mLastContainsRunningSurfaceAnimator = true; 162 dc.enableHighFrameRate(true); 163 } 164 } else if (dc.mLastContainsRunningSurfaceAnimator) { 165 dc.mLastContainsRunningSurfaceAnimator = false; 166 dc.enableHighFrameRate(false); 167 } 168 mTransaction.merge(dc.getPendingTransaction()); 169 } 170 171 cancelAnimation(); 172 173 if (mService.mWatermark != null) { 174 mService.mWatermark.drawIfNeeded(); 175 } 176 177 } catch (RuntimeException e) { 178 Slog.wtf(TAG, "Unhandled exception in Window Manager", e); 179 } 180 181 final boolean hasPendingLayoutChanges = root.hasPendingLayoutChanges(this); 182 final boolean doRequest = (mBulkUpdateParams != 0 || root.mOrientationChangeComplete) 183 && root.copyAnimToLayoutParams(); 184 if (hasPendingLayoutChanges || doRequest) { 185 mService.mWindowPlacerLocked.requestTraversal(); 186 } 187 188 if (rootAnimating && !mLastRootAnimating) { 189 Trace.asyncTraceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "animating", 0); 190 } 191 if (!rootAnimating && mLastRootAnimating) { 192 mService.mWindowPlacerLocked.requestTraversal(); 193 Trace.asyncTraceEnd(Trace.TRACE_TAG_WINDOW_MANAGER, "animating", 0); 194 } 195 mLastRootAnimating = rootAnimating; 196 197 // APP_TRANSITION, SCREEN_ROTATION, TYPE_RECENTS are handled by shell transition. 198 if (!useShellTransition) { 199 updateRunningExpensiveAnimationsLegacy(); 200 } 201 202 Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "applyTransaction"); 203 mTransaction.apply(); 204 Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); 205 mService.mWindowTracing.logState("WindowAnimator"); 206 ProtoLog.i(WM_SHOW_TRANSACTIONS, "<<< CLOSE TRANSACTION animate"); 207 208 mService.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 209 executeAfterPrepareSurfacesRunnables(); 210 211 if (DEBUG_WINDOW_TRACE) { 212 Slog.i(TAG, "!!! animate: exit" 213 + " mBulkUpdateParams=" + Integer.toHexString(mBulkUpdateParams) 214 + " hasPendingLayoutChanges=" + hasPendingLayoutChanges); 215 } 216 } 217 updateRunningExpensiveAnimationsLegacy()218 private void updateRunningExpensiveAnimationsLegacy() { 219 final boolean runningExpensiveAnimations = 220 mService.mRoot.isAnimating(TRANSITION | CHILDREN /* flags */, 221 ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_SCREEN_ROTATION 222 | ANIMATION_TYPE_RECENTS /* typesToCheck */); 223 if (runningExpensiveAnimations && !mRunningExpensiveAnimations) { 224 mService.mSnapshotController.setPause(true); 225 mTransaction.setEarlyWakeupStart(); 226 } else if (!runningExpensiveAnimations && mRunningExpensiveAnimations) { 227 mService.mSnapshotController.setPause(false); 228 mTransaction.setEarlyWakeupEnd(); 229 } 230 mRunningExpensiveAnimations = runningExpensiveAnimations; 231 } 232 bulkUpdateParamsToString(int bulkUpdateParams)233 private static String bulkUpdateParamsToString(int bulkUpdateParams) { 234 StringBuilder builder = new StringBuilder(128); 235 if ((bulkUpdateParams & WindowSurfacePlacer.SET_UPDATE_ROTATION) != 0) { 236 builder.append(" UPDATE_ROTATION"); 237 } 238 if ((bulkUpdateParams & WindowSurfacePlacer.SET_WALLPAPER_ACTION_PENDING) != 0) { 239 builder.append(" SET_WALLPAPER_ACTION_PENDING"); 240 } 241 return builder.toString(); 242 } 243 dumpLocked(PrintWriter pw, String prefix, boolean dumpAll)244 public void dumpLocked(PrintWriter pw, String prefix, boolean dumpAll) { 245 final String subPrefix = " " + prefix; 246 247 for (int i = 0; i < mService.mRoot.getChildCount(); i++) { 248 final DisplayContent dc = mService.mRoot.getChildAt(i); 249 pw.print(prefix); pw.print(dc); pw.println(":"); 250 dc.dumpWindowAnimators(pw, subPrefix); 251 pw.println(); 252 } 253 254 pw.println(); 255 256 if (dumpAll) { 257 pw.print(prefix); pw.print("mCurrentTime="); 258 pw.println(TimeUtils.formatUptime(mCurrentTime)); 259 } 260 if (mBulkUpdateParams != 0) { 261 pw.print(prefix); pw.print("mBulkUpdateParams=0x"); 262 pw.print(Integer.toHexString(mBulkUpdateParams)); 263 pw.println(bulkUpdateParamsToString(mBulkUpdateParams)); 264 } 265 } 266 scheduleAnimation()267 void scheduleAnimation() { 268 if (!mAnimationFrameCallbackScheduled) { 269 mAnimationFrameCallbackScheduled = true; 270 mChoreographer.postFrameCallback(mAnimationFrameCallback); 271 } 272 } 273 cancelAnimation()274 private void cancelAnimation() { 275 if (mAnimationFrameCallbackScheduled) { 276 mAnimationFrameCallbackScheduled = false; 277 mChoreographer.removeFrameCallback(mAnimationFrameCallback); 278 } 279 } 280 isAnimationScheduled()281 boolean isAnimationScheduled() { 282 return mAnimationFrameCallbackScheduled; 283 } 284 getChoreographer()285 Choreographer getChoreographer() { 286 return mChoreographer; 287 } 288 289 /** 290 * Adds a runnable to be executed after {@link WindowContainer#prepareSurfaces} is called and 291 * the corresponding transaction is closed and applied. 292 */ addAfterPrepareSurfacesRunnable(Runnable r)293 void addAfterPrepareSurfacesRunnable(Runnable r) { 294 // If runnables are already being handled in executeAfterPrepareSurfacesRunnable, then just 295 // immediately execute the runnable passed in. 296 if (mInExecuteAfterPrepareSurfacesRunnables) { 297 r.run(); 298 return; 299 } 300 301 mAfterPrepareSurfacesRunnables.add(r); 302 scheduleAnimation(); 303 } 304 executeAfterPrepareSurfacesRunnables()305 void executeAfterPrepareSurfacesRunnables() { 306 307 // Don't even think about to start recursing! 308 if (mInExecuteAfterPrepareSurfacesRunnables) { 309 return; 310 } 311 mInExecuteAfterPrepareSurfacesRunnables = true; 312 313 // Traverse in order they were added. 314 final int size = mAfterPrepareSurfacesRunnables.size(); 315 for (int i = 0; i < size; i++) { 316 mAfterPrepareSurfacesRunnables.get(i).run(); 317 } 318 mAfterPrepareSurfacesRunnables.clear(); 319 mInExecuteAfterPrepareSurfacesRunnables = false; 320 } 321 } 322