• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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             // Remove all deferred displays, tasks, and activities.
147             mService.mRoot.handleCompleteDeferredRemoval();
148 
149             final AccessibilityController accessibilityController =
150                     mService.mAccessibilityController;
151             final int numDisplays = mDisplayContentsAnimators.size();
152             for (int i = 0; i < numDisplays; i++) {
153                 final int displayId = mDisplayContentsAnimators.keyAt(i);
154                 final DisplayContent dc = mService.mRoot.getDisplayContent(displayId);
155                 // Update animations of all applications, including those associated with
156                 // exiting/removed apps.
157                 dc.updateWindowsForAnimator();
158                 dc.prepareSurfaces();
159             }
160 
161             for (int i = 0; i < numDisplays; i++) {
162                 final int displayId = mDisplayContentsAnimators.keyAt(i);
163                 final DisplayContent dc = mService.mRoot.getDisplayContent(displayId);
164 
165                 dc.checkAppWindowsReadyToShow();
166                 if (accessibilityController != null) {
167                     accessibilityController.drawMagnifiedRegionBorderIfNeededLocked(displayId,
168                             mTransaction);
169                 }
170             }
171 
172             cancelAnimation();
173 
174             if (mService.mWatermark != null) {
175                 mService.mWatermark.drawIfNeeded();
176             }
177 
178         } catch (RuntimeException e) {
179             Slog.wtf(TAG, "Unhandled exception in Window Manager", e);
180         }
181 
182         final boolean hasPendingLayoutChanges = mService.mRoot.hasPendingLayoutChanges(this);
183         final boolean doRequest = mBulkUpdateParams != 0 && mService.mRoot.copyAnimToLayoutParams();
184         if (hasPendingLayoutChanges || doRequest) {
185             mService.mWindowPlacerLocked.requestTraversal();
186         }
187 
188         final boolean rootAnimating = mService.mRoot.isAnimating(TRANSITION | CHILDREN /* flags */,
189                 ANIMATION_TYPE_ALL /* typesToCheck */);
190         if (rootAnimating && !mLastRootAnimating) {
191             Trace.asyncTraceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "animating", 0);
192         }
193         if (!rootAnimating && mLastRootAnimating) {
194             mService.mWindowPlacerLocked.requestTraversal();
195             Trace.asyncTraceEnd(Trace.TRACE_TAG_WINDOW_MANAGER, "animating", 0);
196         }
197         mLastRootAnimating = rootAnimating;
198 
199         final boolean runningExpensiveAnimations =
200                 mService.mRoot.isAnimating(TRANSITION | CHILDREN /* flags */,
201                         ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_SCREEN_ROTATION
202                                 | ANIMATION_TYPE_RECENTS /* typesToCheck */);
203         if (runningExpensiveAnimations && !mRunningExpensiveAnimations) {
204             // Usually app transitions put quite a load onto the system already (with all the things
205             // happening in app), so pause task snapshot persisting to not increase the load.
206             mService.mTaskSnapshotController.setPersisterPaused(true);
207             mTransaction.setEarlyWakeupStart();
208         } else if (!runningExpensiveAnimations && mRunningExpensiveAnimations) {
209             mService.mTaskSnapshotController.setPersisterPaused(false);
210             mTransaction.setEarlyWakeupEnd();
211         }
212         mRunningExpensiveAnimations = runningExpensiveAnimations;
213 
214         SurfaceControl.mergeToGlobalTransaction(mTransaction);
215         mService.closeSurfaceTransaction("WindowAnimator");
216         ProtoLog.i(WM_SHOW_TRANSACTIONS, "<<< CLOSE TRANSACTION animate");
217 
218         if (mRemoveReplacedWindows) {
219             mService.mRoot.removeReplacedWindows();
220             mRemoveReplacedWindows = false;
221         }
222 
223         mService.destroyPreservedSurfaceLocked();
224 
225         executeAfterPrepareSurfacesRunnables();
226 
227         if (DEBUG_WINDOW_TRACE) {
228             Slog.i(TAG, "!!! animate: exit"
229                     + " mBulkUpdateParams=" + Integer.toHexString(mBulkUpdateParams)
230                     + " hasPendingLayoutChanges=" + hasPendingLayoutChanges);
231         }
232     }
233 
bulkUpdateParamsToString(int bulkUpdateParams)234     private static String bulkUpdateParamsToString(int bulkUpdateParams) {
235         StringBuilder builder = new StringBuilder(128);
236         if ((bulkUpdateParams & WindowSurfacePlacer.SET_UPDATE_ROTATION) != 0) {
237             builder.append(" UPDATE_ROTATION");
238         }
239         if ((bulkUpdateParams & WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE) != 0) {
240             builder.append(" ORIENTATION_CHANGE_COMPLETE");
241         }
242         return builder.toString();
243     }
244 
dumpLocked(PrintWriter pw, String prefix, boolean dumpAll)245     public void dumpLocked(PrintWriter pw, String prefix, boolean dumpAll) {
246         final String subPrefix = "  " + prefix;
247 
248         for (int i = 0; i < mDisplayContentsAnimators.size(); i++) {
249             pw.print(prefix); pw.print("DisplayContentsAnimator #");
250                     pw.print(mDisplayContentsAnimators.keyAt(i));
251                     pw.println(":");
252             final DisplayContent dc =
253                     mService.mRoot.getDisplayContent(mDisplayContentsAnimators.keyAt(i));
254             dc.dumpWindowAnimators(pw, subPrefix);
255             pw.println();
256         }
257 
258         pw.println();
259 
260         if (dumpAll) {
261             pw.print(prefix); pw.print("mCurrentTime=");
262                     pw.println(TimeUtils.formatUptime(mCurrentTime));
263         }
264         if (mBulkUpdateParams != 0) {
265             pw.print(prefix); pw.print("mBulkUpdateParams=0x");
266                     pw.print(Integer.toHexString(mBulkUpdateParams));
267                     pw.println(bulkUpdateParamsToString(mBulkUpdateParams));
268         }
269     }
270 
getDisplayContentsAnimatorLocked(int displayId)271     private DisplayContentsAnimator getDisplayContentsAnimatorLocked(int displayId) {
272         if (displayId < 0) {
273             return null;
274         }
275 
276         DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.get(displayId);
277 
278         // It is possible that this underlying {@link DisplayContent} has been removed. In this
279         // case, we do not want to create an animator associated with it as {link #animate} will
280         // fail.
281         if (displayAnimator == null && mService.mRoot.getDisplayContent(displayId) != null) {
282             displayAnimator = new DisplayContentsAnimator();
283             mDisplayContentsAnimators.put(displayId, displayAnimator);
284         }
285         return displayAnimator;
286     }
287 
requestRemovalOfReplacedWindows(WindowState win)288     void requestRemovalOfReplacedWindows(WindowState win) {
289         mRemoveReplacedWindows = true;
290     }
291 
scheduleAnimation()292     void scheduleAnimation() {
293         if (!mAnimationFrameCallbackScheduled) {
294             mAnimationFrameCallbackScheduled = true;
295             mChoreographer.postFrameCallback(mAnimationFrameCallback);
296         }
297     }
298 
cancelAnimation()299     private void cancelAnimation() {
300         if (mAnimationFrameCallbackScheduled) {
301             mAnimationFrameCallbackScheduled = false;
302             mChoreographer.removeFrameCallback(mAnimationFrameCallback);
303         }
304     }
305 
306     private class DisplayContentsAnimator {
307     }
308 
isAnimationScheduled()309     boolean isAnimationScheduled() {
310         return mAnimationFrameCallbackScheduled;
311     }
312 
getChoreographer()313     Choreographer getChoreographer() {
314         return mChoreographer;
315     }
316 
317     /**
318      * Adds a runnable to be executed after {@link WindowContainer#prepareSurfaces} is called and
319      * the corresponding transaction is closed and applied.
320      */
addAfterPrepareSurfacesRunnable(Runnable r)321     void addAfterPrepareSurfacesRunnable(Runnable r) {
322         // If runnables are already being handled in executeAfterPrepareSurfacesRunnable, then just
323         // immediately execute the runnable passed in.
324         if (mInExecuteAfterPrepareSurfacesRunnables) {
325             r.run();
326             return;
327         }
328 
329         mAfterPrepareSurfacesRunnables.add(r);
330         scheduleAnimation();
331     }
332 
executeAfterPrepareSurfacesRunnables()333     void executeAfterPrepareSurfacesRunnables() {
334 
335         // Don't even think about to start recursing!
336         if (mInExecuteAfterPrepareSurfacesRunnables) {
337             return;
338         }
339         mInExecuteAfterPrepareSurfacesRunnables = true;
340 
341         // Traverse in order they were added.
342         final int size = mAfterPrepareSurfacesRunnables.size();
343         for (int i = 0; i < size; i++) {
344             mAfterPrepareSurfacesRunnables.get(i).run();
345         }
346         mAfterPrepareSurfacesRunnables.clear();
347         mInExecuteAfterPrepareSurfacesRunnables = false;
348     }
349 }
350