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.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 import static com.android.server.wm.WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE;
30 
31 import android.content.Context;
32 import android.os.Trace;
33 import android.util.Slog;
34 import android.util.SparseArray;
35 import android.util.TimeUtils;
36 import android.view.Choreographer;
37 import android.view.SurfaceControl;
38 
39 import com.android.server.policy.WindowManagerPolicy;
40 import com.android.server.protolog.common.ProtoLog;
41 
42 import java.io.PrintWriter;
43 import java.util.ArrayList;
44 
45 /**
46  * Singleton class that carries out the animations and Surface operations in a separate task
47  * on behalf of WindowManagerService.
48  */
49 public class WindowAnimator {
50     private static final String TAG = TAG_WITH_CLASS_NAME ? "WindowAnimator" : TAG_WM;
51 
52     final WindowManagerService mService;
53     final Context mContext;
54     final WindowManagerPolicy mPolicy;
55 
56     /** Is any window animating? */
57     private boolean mLastRootAnimating;
58 
59     /** True if we are running any animations that require expensive composition. */
60     private boolean mRunningExpensiveAnimations;
61 
62     final Choreographer.FrameCallback mAnimationFrameCallback;
63 
64     /** Time of current animation step. Reset on each iteration */
65     long mCurrentTime;
66 
67     int mBulkUpdateParams = 0;
68     Object mLastWindowFreezeSource;
69 
70     SparseArray<DisplayContentsAnimator> mDisplayContentsAnimators = new SparseArray<>(2);
71 
72     private boolean mInitialized = false;
73 
74     // When set to true the animator will go over all windows after an animation frame is posted and
75     // check if some got replaced and can be removed.
76     private boolean mRemoveReplacedWindows = false;
77 
78     private Choreographer mChoreographer;
79 
80     /**
81      * Indicates whether we have an animation frame callback scheduled, which will happen at
82      * vsync-app and then schedule the animation tick at the right time (vsync-sf).
83      */
84     private boolean mAnimationFrameCallbackScheduled;
85     boolean mNotifyWhenNoAnimation = false;
86 
87     /**
88      * A list of runnable that need to be run after {@link WindowContainer#prepareSurfaces} is
89      * executed and the corresponding transaction is closed and applied.
90      */
91     private final ArrayList<Runnable> mAfterPrepareSurfacesRunnables = new ArrayList<>();
92     private boolean mInExecuteAfterPrepareSurfacesRunnables;
93 
94     private final SurfaceControl.Transaction mTransaction;
95 
WindowAnimator(final WindowManagerService service)96     WindowAnimator(final WindowManagerService service) {
97         mService = service;
98         mContext = service.mContext;
99         mPolicy = service.mPolicy;
100         mTransaction = service.mTransactionFactory.get();
101         service.mAnimationHandler.runWithScissors(
102                 () -> mChoreographer = Choreographer.getSfInstance(), 0 /* timeout */);
103 
104         mAnimationFrameCallback = frameTimeNs -> {
105             synchronized (mService.mGlobalLock) {
106                 mAnimationFrameCallbackScheduled = false;
107                 animate(frameTimeNs);
108                 if (mNotifyWhenNoAnimation && !mLastRootAnimating) {
109                     mService.mGlobalLock.notifyAll();
110                 }
111             }
112         };
113     }
114 
addDisplayLocked(final int displayId)115     void addDisplayLocked(final int displayId) {
116         // Create the DisplayContentsAnimator object by retrieving it if the associated
117         // {@link DisplayContent} exists.
118         getDisplayContentsAnimatorLocked(displayId);
119     }
120 
removeDisplayLocked(final int displayId)121     void removeDisplayLocked(final int displayId) {
122         mDisplayContentsAnimators.delete(displayId);
123     }
124 
ready()125     void ready() {
126         mInitialized = true;
127     }
128 
animate(long frameTimeNs)129     private void animate(long frameTimeNs) {
130         if (!mInitialized) {
131             return;
132         }
133 
134         // Schedule next frame already such that back-pressure happens continuously.
135         scheduleAnimation();
136 
137         mCurrentTime = frameTimeNs / TimeUtils.NANOS_PER_MS;
138         mBulkUpdateParams = SET_ORIENTATION_CHANGE_COMPLETE;
139         if (DEBUG_WINDOW_TRACE) {
140             Slog.i(TAG, "!!! animate: entry time=" + mCurrentTime);
141         }
142 
143         ProtoLog.i(WM_SHOW_TRANSACTIONS, ">>> OPEN TRANSACTION animate");
144         mService.openSurfaceTransaction();
145         try {
146             final AccessibilityController accessibilityController =
147                     mService.mAccessibilityController;
148             final int numDisplays = mDisplayContentsAnimators.size();
149             for (int i = 0; i < numDisplays; i++) {
150                 final int displayId = mDisplayContentsAnimators.keyAt(i);
151                 final DisplayContent dc = mService.mRoot.getDisplayContent(displayId);
152                 // Update animations of all applications, including those associated with
153                 // exiting/removed apps.
154                 dc.updateWindowsForAnimator();
155                 dc.prepareSurfaces();
156             }
157 
158             for (int i = 0; i < numDisplays; i++) {
159                 final int displayId = mDisplayContentsAnimators.keyAt(i);
160                 final DisplayContent dc = mService.mRoot.getDisplayContent(displayId);
161 
162                 dc.checkAppWindowsReadyToShow();
163                 if (accessibilityController != null) {
164                     accessibilityController.drawMagnifiedRegionBorderIfNeededLocked(displayId,
165                             mTransaction);
166                 }
167             }
168 
169             cancelAnimation();
170 
171             if (mService.mWatermark != null) {
172                 mService.mWatermark.drawIfNeeded();
173             }
174 
175         } catch (RuntimeException e) {
176             Slog.wtf(TAG, "Unhandled exception in Window Manager", e);
177         }
178 
179         final boolean hasPendingLayoutChanges = mService.mRoot.hasPendingLayoutChanges(this);
180         final boolean doRequest = mBulkUpdateParams != 0 && mService.mRoot.copyAnimToLayoutParams();
181         if (hasPendingLayoutChanges || doRequest) {
182             mService.mWindowPlacerLocked.requestTraversal();
183         }
184 
185         final boolean rootAnimating = mService.mRoot.isAnimating(TRANSITION | CHILDREN /* flags */,
186                 ANIMATION_TYPE_ALL /* typesToCheck */);
187         if (rootAnimating && !mLastRootAnimating) {
188             Trace.asyncTraceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "animating", 0);
189         }
190         if (!rootAnimating && mLastRootAnimating) {
191             mService.mWindowPlacerLocked.requestTraversal();
192             Trace.asyncTraceEnd(Trace.TRACE_TAG_WINDOW_MANAGER, "animating", 0);
193         }
194         mLastRootAnimating = rootAnimating;
195 
196         final boolean runningExpensiveAnimations =
197                 mService.mRoot.isAnimating(TRANSITION | CHILDREN /* flags */,
198                         ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_SCREEN_ROTATION
199                                 | ANIMATION_TYPE_RECENTS /* typesToCheck */);
200         if (runningExpensiveAnimations && !mRunningExpensiveAnimations) {
201             // Usually app transitions put quite a load onto the system already (with all the things
202             // happening in app), so pause task snapshot persisting to not increase the load.
203             mService.mTaskSnapshotController.setPersisterPaused(true);
204             mTransaction.setEarlyWakeupStart();
205         } else if (!runningExpensiveAnimations && mRunningExpensiveAnimations) {
206             mService.mTaskSnapshotController.setPersisterPaused(false);
207             mTransaction.setEarlyWakeupEnd();
208         }
209         mRunningExpensiveAnimations = runningExpensiveAnimations;
210 
211         SurfaceControl.mergeToGlobalTransaction(mTransaction);
212         mService.closeSurfaceTransaction("WindowAnimator");
213         ProtoLog.i(WM_SHOW_TRANSACTIONS, "<<< CLOSE TRANSACTION animate");
214 
215         if (mRemoveReplacedWindows) {
216             mService.mRoot.removeReplacedWindows();
217             mRemoveReplacedWindows = false;
218         }
219 
220         mService.destroyPreservedSurfaceLocked();
221 
222         executeAfterPrepareSurfacesRunnables();
223 
224         if (DEBUG_WINDOW_TRACE) {
225             Slog.i(TAG, "!!! animate: exit"
226                     + " mBulkUpdateParams=" + Integer.toHexString(mBulkUpdateParams)
227                     + " hasPendingLayoutChanges=" + hasPendingLayoutChanges);
228         }
229     }
230 
bulkUpdateParamsToString(int bulkUpdateParams)231     private static String bulkUpdateParamsToString(int bulkUpdateParams) {
232         StringBuilder builder = new StringBuilder(128);
233         if ((bulkUpdateParams & WindowSurfacePlacer.SET_UPDATE_ROTATION) != 0) {
234             builder.append(" UPDATE_ROTATION");
235         }
236         if ((bulkUpdateParams & WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE) != 0) {
237             builder.append(" ORIENTATION_CHANGE_COMPLETE");
238         }
239         return builder.toString();
240     }
241 
dumpLocked(PrintWriter pw, String prefix, boolean dumpAll)242     public void dumpLocked(PrintWriter pw, String prefix, boolean dumpAll) {
243         final String subPrefix = "  " + prefix;
244 
245         for (int i = 0; i < mDisplayContentsAnimators.size(); i++) {
246             pw.print(prefix); pw.print("DisplayContentsAnimator #");
247                     pw.print(mDisplayContentsAnimators.keyAt(i));
248                     pw.println(":");
249             final DisplayContent dc =
250                     mService.mRoot.getDisplayContent(mDisplayContentsAnimators.keyAt(i));
251             dc.dumpWindowAnimators(pw, subPrefix);
252             pw.println();
253         }
254 
255         pw.println();
256 
257         if (dumpAll) {
258             pw.print(prefix); pw.print("mCurrentTime=");
259                     pw.println(TimeUtils.formatUptime(mCurrentTime));
260         }
261         if (mBulkUpdateParams != 0) {
262             pw.print(prefix); pw.print("mBulkUpdateParams=0x");
263                     pw.print(Integer.toHexString(mBulkUpdateParams));
264                     pw.println(bulkUpdateParamsToString(mBulkUpdateParams));
265         }
266     }
267 
getDisplayContentsAnimatorLocked(int displayId)268     private DisplayContentsAnimator getDisplayContentsAnimatorLocked(int displayId) {
269         if (displayId < 0) {
270             return null;
271         }
272 
273         DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.get(displayId);
274 
275         // It is possible that this underlying {@link DisplayContent} has been removed. In this
276         // case, we do not want to create an animator associated with it as {link #animate} will
277         // fail.
278         if (displayAnimator == null && mService.mRoot.getDisplayContent(displayId) != null) {
279             displayAnimator = new DisplayContentsAnimator();
280             mDisplayContentsAnimators.put(displayId, displayAnimator);
281         }
282         return displayAnimator;
283     }
284 
requestRemovalOfReplacedWindows(WindowState win)285     void requestRemovalOfReplacedWindows(WindowState win) {
286         mRemoveReplacedWindows = true;
287     }
288 
scheduleAnimation()289     void scheduleAnimation() {
290         if (!mAnimationFrameCallbackScheduled) {
291             mAnimationFrameCallbackScheduled = true;
292             mChoreographer.postFrameCallback(mAnimationFrameCallback);
293         }
294     }
295 
cancelAnimation()296     private void cancelAnimation() {
297         if (mAnimationFrameCallbackScheduled) {
298             mAnimationFrameCallbackScheduled = false;
299             mChoreographer.removeFrameCallback(mAnimationFrameCallback);
300         }
301     }
302 
303     private class DisplayContentsAnimator {
304     }
305 
isAnimationScheduled()306     boolean isAnimationScheduled() {
307         return mAnimationFrameCallbackScheduled;
308     }
309 
getChoreographer()310     Choreographer getChoreographer() {
311         return mChoreographer;
312     }
313 
314     /**
315      * Adds a runnable to be executed after {@link WindowContainer#prepareSurfaces} is called and
316      * the corresponding transaction is closed and applied.
317      */
addAfterPrepareSurfacesRunnable(Runnable r)318     void addAfterPrepareSurfacesRunnable(Runnable r) {
319         // If runnables are already being handled in executeAfterPrepareSurfacesRunnable, then just
320         // immediately execute the runnable passed in.
321         if (mInExecuteAfterPrepareSurfacesRunnables) {
322             r.run();
323             return;
324         }
325 
326         mAfterPrepareSurfacesRunnables.add(r);
327         scheduleAnimation();
328     }
329 
executeAfterPrepareSurfacesRunnables()330     void executeAfterPrepareSurfacesRunnables() {
331 
332         // Don't even think about to start recursing!
333         if (mInExecuteAfterPrepareSurfacesRunnables) {
334             return;
335         }
336         mInExecuteAfterPrepareSurfacesRunnables = true;
337 
338         // Traverse in order they were added.
339         final int size = mAfterPrepareSurfacesRunnables.size();
340         for (int i = 0; i < size; i++) {
341             mAfterPrepareSurfacesRunnables.get(i).run();
342         }
343         mAfterPrepareSurfacesRunnables.clear();
344         mInExecuteAfterPrepareSurfacesRunnables = false;
345     }
346 }
347