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         mCurrentTime = frameTimeNs / TimeUtils.NANOS_PER_MS;
121         mBulkUpdateParams = 0;
122         root.mOrientationChangeComplete = true;
123         if (DEBUG_WINDOW_TRACE) {
124             Slog.i(TAG, "!!! animate: entry time=" + mCurrentTime);
125         }
126 
127         ProtoLog.i(WM_SHOW_TRANSACTIONS, ">>> OPEN TRANSACTION animate");
128         mService.openSurfaceTransaction();
129         try {
130             // Remove all deferred displays, tasks, and activities.
131             root.handleCompleteDeferredRemoval();
132 
133             final AccessibilityController accessibilityController =
134                     mService.mAccessibilityController;
135             final int numDisplays = root.getChildCount();
136             for (int i = 0; i < numDisplays; i++) {
137                 final DisplayContent dc = root.getChildAt(i);
138                 // Update animations of all applications, including those associated with
139                 // exiting/removed apps.
140                 dc.updateWindowsForAnimator();
141                 dc.prepareSurfaces();
142             }
143 
144             for (int i = 0; i < numDisplays; i++) {
145                 final DisplayContent dc = root.getChildAt(i);
146 
147                 dc.checkAppWindowsReadyToShow();
148                 if (accessibilityController.hasCallbacks()) {
149                     accessibilityController.drawMagnifiedRegionBorderIfNeeded(dc.mDisplayId,
150                             mTransaction);
151                 }
152             }
153 
154             cancelAnimation();
155 
156             if (mService.mWatermark != null) {
157                 mService.mWatermark.drawIfNeeded();
158             }
159 
160         } catch (RuntimeException e) {
161             Slog.wtf(TAG, "Unhandled exception in Window Manager", e);
162         }
163 
164         final boolean hasPendingLayoutChanges = root.hasPendingLayoutChanges(this);
165         final boolean doRequest = (mBulkUpdateParams != 0 || root.mOrientationChangeComplete)
166                 && root.copyAnimToLayoutParams();
167         if (hasPendingLayoutChanges || doRequest) {
168             mService.mWindowPlacerLocked.requestTraversal();
169         }
170 
171         final boolean rootAnimating = root.isAnimating(TRANSITION | CHILDREN /* flags */,
172                 ANIMATION_TYPE_ALL /* typesToCheck */);
173         if (rootAnimating && !mLastRootAnimating) {
174             Trace.asyncTraceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "animating", 0);
175         }
176         if (!rootAnimating && mLastRootAnimating) {
177             mService.mWindowPlacerLocked.requestTraversal();
178             Trace.asyncTraceEnd(Trace.TRACE_TAG_WINDOW_MANAGER, "animating", 0);
179         }
180         mLastRootAnimating = rootAnimating;
181 
182         final boolean runningExpensiveAnimations =
183                 root.isAnimating(TRANSITION | CHILDREN /* flags */,
184                         ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_SCREEN_ROTATION
185                                 | ANIMATION_TYPE_RECENTS /* typesToCheck */);
186         if (runningExpensiveAnimations && !mRunningExpensiveAnimations) {
187             // Usually app transitions put quite a load onto the system already (with all the things
188             // happening in app), so pause snapshot persisting to not increase the load.
189             mService.mSnapshotController.setPause(true);
190             mTransaction.setEarlyWakeupStart();
191         } else if (!runningExpensiveAnimations && mRunningExpensiveAnimations) {
192             mService.mSnapshotController.setPause(false);
193             mTransaction.setEarlyWakeupEnd();
194         }
195         mRunningExpensiveAnimations = runningExpensiveAnimations;
196 
197         SurfaceControl.mergeToGlobalTransaction(mTransaction);
198         mService.closeSurfaceTransaction("WindowAnimator");
199         ProtoLog.i(WM_SHOW_TRANSACTIONS, "<<< CLOSE TRANSACTION animate");
200 
201         mService.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
202         executeAfterPrepareSurfacesRunnables();
203 
204         if (DEBUG_WINDOW_TRACE) {
205             Slog.i(TAG, "!!! animate: exit"
206                     + " mBulkUpdateParams=" + Integer.toHexString(mBulkUpdateParams)
207                     + " hasPendingLayoutChanges=" + hasPendingLayoutChanges);
208         }
209     }
210 
bulkUpdateParamsToString(int bulkUpdateParams)211     private static String bulkUpdateParamsToString(int bulkUpdateParams) {
212         StringBuilder builder = new StringBuilder(128);
213         if ((bulkUpdateParams & WindowSurfacePlacer.SET_UPDATE_ROTATION) != 0) {
214             builder.append(" UPDATE_ROTATION");
215         }
216         if ((bulkUpdateParams & WindowSurfacePlacer.SET_WALLPAPER_ACTION_PENDING) != 0) {
217             builder.append(" SET_WALLPAPER_ACTION_PENDING");
218         }
219         return builder.toString();
220     }
221 
dumpLocked(PrintWriter pw, String prefix, boolean dumpAll)222     public void dumpLocked(PrintWriter pw, String prefix, boolean dumpAll) {
223         final String subPrefix = "  " + prefix;
224 
225         for (int i = 0; i < mService.mRoot.getChildCount(); i++) {
226             final DisplayContent dc = mService.mRoot.getChildAt(i);
227             pw.print(prefix); pw.print(dc); pw.println(":");
228             dc.dumpWindowAnimators(pw, subPrefix);
229             pw.println();
230         }
231 
232         pw.println();
233 
234         if (dumpAll) {
235             pw.print(prefix); pw.print("mCurrentTime=");
236                     pw.println(TimeUtils.formatUptime(mCurrentTime));
237         }
238         if (mBulkUpdateParams != 0) {
239             pw.print(prefix); pw.print("mBulkUpdateParams=0x");
240                     pw.print(Integer.toHexString(mBulkUpdateParams));
241                     pw.println(bulkUpdateParamsToString(mBulkUpdateParams));
242         }
243     }
244 
scheduleAnimation()245     void scheduleAnimation() {
246         if (!mAnimationFrameCallbackScheduled) {
247             mAnimationFrameCallbackScheduled = true;
248             mChoreographer.postFrameCallback(mAnimationFrameCallback);
249         }
250     }
251 
cancelAnimation()252     private void cancelAnimation() {
253         if (mAnimationFrameCallbackScheduled) {
254             mAnimationFrameCallbackScheduled = false;
255             mChoreographer.removeFrameCallback(mAnimationFrameCallback);
256         }
257     }
258 
isAnimationScheduled()259     boolean isAnimationScheduled() {
260         return mAnimationFrameCallbackScheduled;
261     }
262 
getChoreographer()263     Choreographer getChoreographer() {
264         return mChoreographer;
265     }
266 
267     /**
268      * Adds a runnable to be executed after {@link WindowContainer#prepareSurfaces} is called and
269      * the corresponding transaction is closed and applied.
270      */
addAfterPrepareSurfacesRunnable(Runnable r)271     void addAfterPrepareSurfacesRunnable(Runnable r) {
272         // If runnables are already being handled in executeAfterPrepareSurfacesRunnable, then just
273         // immediately execute the runnable passed in.
274         if (mInExecuteAfterPrepareSurfacesRunnables) {
275             r.run();
276             return;
277         }
278 
279         mAfterPrepareSurfacesRunnables.add(r);
280         scheduleAnimation();
281     }
282 
executeAfterPrepareSurfacesRunnables()283     void executeAfterPrepareSurfacesRunnables() {
284 
285         // Don't even think about to start recursing!
286         if (mInExecuteAfterPrepareSurfacesRunnables) {
287             return;
288         }
289         mInExecuteAfterPrepareSurfacesRunnables = true;
290 
291         // Traverse in order they were added.
292         final int size = mAfterPrepareSurfacesRunnables.size();
293         for (int i = 0; i < size; i++) {
294             mAfterPrepareSurfacesRunnables.get(i).run();
295         }
296         mAfterPrepareSurfacesRunnables.clear();
297         mInExecuteAfterPrepareSurfacesRunnables = false;
298     }
299 }
300