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