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