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.WindowManagerDebugConfig.DEBUG_WINDOW_TRACE;
20 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
21 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
22 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
23 import static com.android.server.wm.WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE;
24 import static com.android.server.wm.WindowSurfacePlacer.SET_UPDATE_ROTATION;
25 
26 import android.content.Context;
27 import android.os.Trace;
28 import android.util.Slog;
29 import android.util.SparseArray;
30 import android.util.TimeUtils;
31 import android.view.Choreographer;
32 import android.view.SurfaceControl;
33 
34 import com.android.server.AnimationThread;
35 import com.android.server.policy.WindowManagerPolicy;
36 
37 import java.io.PrintWriter;
38 import java.util.ArrayList;
39 
40 /**
41  * Singleton class that carries out the animations and Surface operations in a separate task
42  * on behalf of WindowManagerService.
43  */
44 public class WindowAnimator {
45     private static final String TAG = TAG_WITH_CLASS_NAME ? "WindowAnimator" : TAG_WM;
46 
47     final WindowManagerService mService;
48     final Context mContext;
49     final WindowManagerPolicy mPolicy;
50 
51     /** Is any window animating? */
52     private boolean mAnimating;
53     private boolean mLastRootAnimating;
54 
55     final Choreographer.FrameCallback mAnimationFrameCallback;
56 
57     /** Time of current animation step. Reset on each iteration */
58     long mCurrentTime;
59 
60     int mBulkUpdateParams = 0;
61     Object mLastWindowFreezeSource;
62 
63     SparseArray<DisplayContentsAnimator> mDisplayContentsAnimators = new SparseArray<>(2);
64 
65     private boolean mInitialized = false;
66 
67     // When set to true the animator will go over all windows after an animation frame is posted and
68     // check if some got replaced and can be removed.
69     private boolean mRemoveReplacedWindows = false;
70 
71     private Choreographer mChoreographer;
72 
73     /**
74      * Indicates whether we have an animation frame callback scheduled, which will happen at
75      * vsync-app and then schedule the animation tick at the right time (vsync-sf).
76      */
77     private boolean mAnimationFrameCallbackScheduled;
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 = new SurfaceControl.Transaction();
87 
WindowAnimator(final WindowManagerService service)88     WindowAnimator(final WindowManagerService service) {
89         mService = service;
90         mContext = service.mContext;
91         mPolicy = service.mPolicy;
92         AnimationThread.getHandler().runWithScissors(
93                 () -> mChoreographer = Choreographer.getSfInstance(), 0 /* timeout */);
94 
95         mAnimationFrameCallback = frameTimeNs -> {
96             synchronized (mService.mGlobalLock) {
97                 mAnimationFrameCallbackScheduled = false;
98             }
99             animate(frameTimeNs);
100         };
101     }
102 
addDisplayLocked(final int displayId)103     void addDisplayLocked(final int displayId) {
104         // Create the DisplayContentsAnimator object by retrieving it if the associated
105         // {@link DisplayContent} exists.
106         getDisplayContentsAnimatorLocked(displayId);
107     }
108 
removeDisplayLocked(final int displayId)109     void removeDisplayLocked(final int displayId) {
110         final DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.get(displayId);
111         if (displayAnimator != null) {
112             if (displayAnimator.mScreenRotationAnimation != null) {
113                 displayAnimator.mScreenRotationAnimation.kill();
114                 displayAnimator.mScreenRotationAnimation = null;
115             }
116         }
117 
118         mDisplayContentsAnimators.delete(displayId);
119     }
120 
ready()121     void ready() {
122         mInitialized = true;
123     }
124 
125     /**
126      * DO NOT HOLD THE WINDOW MANAGER LOCK WHILE CALLING THIS METHOD. Reason: the method closes
127      * an animation transaction, that might be blocking until the next sf-vsync, so we want to make
128      * sure other threads can make progress if this happens.
129      */
animate(long frameTimeNs)130     private void animate(long frameTimeNs) {
131 
132         synchronized (mService.mGlobalLock) {
133             if (!mInitialized) {
134                 return;
135             }
136 
137             // Schedule next frame already such that back-pressure happens continuously
138             scheduleAnimation();
139         }
140 
141         synchronized (mService.mGlobalLock) {
142             mCurrentTime = frameTimeNs / TimeUtils.NANOS_PER_MS;
143             mBulkUpdateParams = SET_ORIENTATION_CHANGE_COMPLETE;
144             mAnimating = false;
145             if (DEBUG_WINDOW_TRACE) {
146                 Slog.i(TAG, "!!! animate: entry time=" + mCurrentTime);
147             }
148 
149             if (SHOW_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION animate");
150             mService.openSurfaceTransaction();
151             try {
152                 final AccessibilityController accessibilityController =
153                         mService.mAccessibilityController;
154                 final int numDisplays = mDisplayContentsAnimators.size();
155                 for (int i = 0; i < numDisplays; i++) {
156                     final int displayId = mDisplayContentsAnimators.keyAt(i);
157                     final DisplayContent dc = mService.mRoot.getDisplayContent(displayId);
158                     DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.valueAt(i);
159 
160                     final ScreenRotationAnimation screenRotationAnimation =
161                             displayAnimator.mScreenRotationAnimation;
162                     if (screenRotationAnimation != null && screenRotationAnimation.isAnimating()) {
163                         if (screenRotationAnimation.stepAnimationLocked(mCurrentTime)) {
164                             setAnimating(true);
165                         } else {
166                             mBulkUpdateParams |= SET_UPDATE_ROTATION;
167                             screenRotationAnimation.kill();
168                             displayAnimator.mScreenRotationAnimation = null;
169 
170                             // display.
171                             if (accessibilityController != null) {
172                                 // We just finished rotation animation which means we did not
173                                 // announce the rotation and waited for it to end, announce now.
174                                 accessibilityController.onRotationChangedLocked(dc);
175                             }
176                         }
177                     }
178 
179                     // Update animations of all applications, including those
180                     // associated with exiting/removed apps
181                     dc.updateWindowsForAnimator();
182                     dc.updateBackgroundForAnimator();
183                     dc.prepareSurfaces();
184                 }
185 
186                 for (int i = 0; i < numDisplays; i++) {
187                     final int displayId = mDisplayContentsAnimators.keyAt(i);
188                     final DisplayContent dc = mService.mRoot.getDisplayContent(displayId);
189 
190                     dc.checkAppWindowsReadyToShow();
191 
192                     final ScreenRotationAnimation screenRotationAnimation =
193                             mDisplayContentsAnimators.valueAt(i).mScreenRotationAnimation;
194                     if (screenRotationAnimation != null) {
195                         screenRotationAnimation.updateSurfaces(mTransaction);
196                     }
197                     orAnimating(dc.getDockedDividerController().animate(mCurrentTime));
198                     if (accessibilityController != null) {
199                         accessibilityController.drawMagnifiedRegionBorderIfNeededLocked(displayId);
200                     }
201                 }
202 
203                 if (!mAnimating) {
204                     cancelAnimation();
205                 }
206 
207                 if (mService.mWatermark != null) {
208                     mService.mWatermark.drawIfNeeded();
209                 }
210 
211                 SurfaceControl.mergeToGlobalTransaction(mTransaction);
212             } catch (RuntimeException e) {
213                 Slog.wtf(TAG, "Unhandled exception in Window Manager", e);
214             } finally {
215                 mService.closeSurfaceTransaction("WindowAnimator");
216                 if (SHOW_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION animate");
217             }
218 
219             boolean hasPendingLayoutChanges = mService.mRoot.hasPendingLayoutChanges(this);
220             boolean doRequest = false;
221             if (mBulkUpdateParams != 0) {
222                 doRequest = mService.mRoot.copyAnimToLayoutParams();
223             }
224 
225             if (hasPendingLayoutChanges || doRequest) {
226                 mService.mWindowPlacerLocked.requestTraversal();
227             }
228 
229             final boolean rootAnimating = mService.mRoot.isSelfOrChildAnimating();
230             if (rootAnimating && !mLastRootAnimating) {
231 
232                 // Usually app transitions but quite a load onto the system already (with all the
233                 // things happening in app), so pause task snapshot persisting to not increase the
234                 // load.
235                 mService.mTaskSnapshotController.setPersisterPaused(true);
236                 Trace.asyncTraceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "animating", 0);
237             }
238             if (!rootAnimating && mLastRootAnimating) {
239                 mService.mWindowPlacerLocked.requestTraversal();
240                 mService.mTaskSnapshotController.setPersisterPaused(false);
241                 Trace.asyncTraceEnd(Trace.TRACE_TAG_WINDOW_MANAGER, "animating", 0);
242             }
243 
244             mLastRootAnimating = rootAnimating;
245 
246             if (mRemoveReplacedWindows) {
247                 mService.mRoot.removeReplacedWindows();
248                 mRemoveReplacedWindows = false;
249             }
250 
251             mService.destroyPreservedSurfaceLocked();
252 
253             executeAfterPrepareSurfacesRunnables();
254 
255             if (DEBUG_WINDOW_TRACE) {
256                 Slog.i(TAG, "!!! animate: exit mAnimating=" + mAnimating
257                         + " mBulkUpdateParams=" + Integer.toHexString(mBulkUpdateParams)
258                         + " hasPendingLayoutChanges=" + hasPendingLayoutChanges);
259             }
260         }
261     }
262 
bulkUpdateParamsToString(int bulkUpdateParams)263     private static String bulkUpdateParamsToString(int bulkUpdateParams) {
264         StringBuilder builder = new StringBuilder(128);
265         if ((bulkUpdateParams & WindowSurfacePlacer.SET_UPDATE_ROTATION) != 0) {
266             builder.append(" UPDATE_ROTATION");
267         }
268         if ((bulkUpdateParams & WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE) != 0) {
269             builder.append(" ORIENTATION_CHANGE_COMPLETE");
270         }
271         return builder.toString();
272     }
273 
dumpLocked(PrintWriter pw, String prefix, boolean dumpAll)274     public void dumpLocked(PrintWriter pw, String prefix, boolean dumpAll) {
275         final String subPrefix = "  " + prefix;
276         final String subSubPrefix = "  " + subPrefix;
277 
278         for (int i = 0; i < mDisplayContentsAnimators.size(); i++) {
279             pw.print(prefix); pw.print("DisplayContentsAnimator #");
280                     pw.print(mDisplayContentsAnimators.keyAt(i));
281                     pw.println(":");
282             final DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.valueAt(i);
283             final DisplayContent dc =
284                     mService.mRoot.getDisplayContent(mDisplayContentsAnimators.keyAt(i));
285             dc.dumpWindowAnimators(pw, subPrefix);
286             if (displayAnimator.mScreenRotationAnimation != null) {
287                 pw.print(subPrefix); pw.println("mScreenRotationAnimation:");
288                 displayAnimator.mScreenRotationAnimation.printTo(subSubPrefix, pw);
289             } else if (dumpAll) {
290                 pw.print(subPrefix); pw.println("no ScreenRotationAnimation ");
291             }
292             pw.println();
293         }
294 
295         pw.println();
296 
297         if (dumpAll) {
298             pw.print(prefix); pw.print("mCurrentTime=");
299                     pw.println(TimeUtils.formatUptime(mCurrentTime));
300         }
301         if (mBulkUpdateParams != 0) {
302             pw.print(prefix); pw.print("mBulkUpdateParams=0x");
303                     pw.print(Integer.toHexString(mBulkUpdateParams));
304                     pw.println(bulkUpdateParamsToString(mBulkUpdateParams));
305         }
306     }
307 
getPendingLayoutChanges(final int displayId)308     int getPendingLayoutChanges(final int displayId) {
309         if (displayId < 0) {
310             return 0;
311         }
312         final DisplayContent displayContent = mService.mRoot.getDisplayContent(displayId);
313         return (displayContent != null) ? displayContent.pendingLayoutChanges : 0;
314     }
315 
setPendingLayoutChanges(final int displayId, final int changes)316     void setPendingLayoutChanges(final int displayId, final int changes) {
317         if (displayId < 0) {
318             return;
319         }
320         final DisplayContent displayContent = mService.mRoot.getDisplayContent(displayId);
321         if (displayContent != null) {
322             displayContent.pendingLayoutChanges |= changes;
323         }
324     }
325 
getDisplayContentsAnimatorLocked(int displayId)326     private DisplayContentsAnimator getDisplayContentsAnimatorLocked(int displayId) {
327         if (displayId < 0) {
328             return null;
329         }
330 
331         DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.get(displayId);
332 
333         // It is possible that this underlying {@link DisplayContent} has been removed. In this
334         // case, we do not want to create an animator associated with it as {link #animate} will
335         // fail.
336         if (displayAnimator == null && mService.mRoot.getDisplayContent(displayId) != null) {
337             displayAnimator = new DisplayContentsAnimator();
338             mDisplayContentsAnimators.put(displayId, displayAnimator);
339         }
340         return displayAnimator;
341     }
342 
setScreenRotationAnimationLocked(int displayId, ScreenRotationAnimation animation)343     void setScreenRotationAnimationLocked(int displayId, ScreenRotationAnimation animation) {
344         final DisplayContentsAnimator animator = getDisplayContentsAnimatorLocked(displayId);
345 
346         if (animator != null) {
347             animator.mScreenRotationAnimation = animation;
348         }
349     }
350 
getScreenRotationAnimationLocked(int displayId)351     ScreenRotationAnimation getScreenRotationAnimationLocked(int displayId) {
352         if (displayId < 0) {
353             return null;
354         }
355 
356         DisplayContentsAnimator animator = getDisplayContentsAnimatorLocked(displayId);
357         return animator != null? animator.mScreenRotationAnimation : null;
358     }
359 
requestRemovalOfReplacedWindows(WindowState win)360     void requestRemovalOfReplacedWindows(WindowState win) {
361         mRemoveReplacedWindows = true;
362     }
363 
scheduleAnimation()364     void scheduleAnimation() {
365         if (!mAnimationFrameCallbackScheduled) {
366             mAnimationFrameCallbackScheduled = true;
367             mChoreographer.postFrameCallback(mAnimationFrameCallback);
368         }
369     }
370 
cancelAnimation()371     private void cancelAnimation() {
372         if (mAnimationFrameCallbackScheduled) {
373             mAnimationFrameCallbackScheduled = false;
374             mChoreographer.removeFrameCallback(mAnimationFrameCallback);
375         }
376     }
377 
378     private class DisplayContentsAnimator {
379         ScreenRotationAnimation mScreenRotationAnimation = null;
380     }
381 
isAnimating()382     boolean isAnimating() {
383         return mAnimating;
384     }
385 
isAnimationScheduled()386     boolean isAnimationScheduled() {
387         return mAnimationFrameCallbackScheduled;
388     }
389 
getChoreographer()390     Choreographer getChoreographer() {
391         return mChoreographer;
392     }
393 
setAnimating(boolean animating)394     void setAnimating(boolean animating) {
395         mAnimating = animating;
396     }
397 
orAnimating(boolean animating)398     void orAnimating(boolean animating) {
399         mAnimating |= animating;
400     }
401 
402     /**
403      * Adds a runnable to be executed after {@link WindowContainer#prepareSurfaces} is called and
404      * the corresponding transaction is closed and applied.
405      */
addAfterPrepareSurfacesRunnable(Runnable r)406     void addAfterPrepareSurfacesRunnable(Runnable r) {
407         // If runnables are already being handled in executeAfterPrepareSurfacesRunnable, then just
408         // immediately execute the runnable passed in.
409         if (mInExecuteAfterPrepareSurfacesRunnables) {
410             r.run();
411             return;
412         }
413 
414         mAfterPrepareSurfacesRunnables.add(r);
415         scheduleAnimation();
416     }
417 
executeAfterPrepareSurfacesRunnables()418     void executeAfterPrepareSurfacesRunnables() {
419 
420         // Don't even think about to start recursing!
421         if (mInExecuteAfterPrepareSurfacesRunnables) {
422             return;
423         }
424         mInExecuteAfterPrepareSurfacesRunnables = true;
425 
426         // Traverse in order they were added.
427         final int size = mAfterPrepareSurfacesRunnables.size();
428         for (int i = 0; i < size; i++) {
429             mAfterPrepareSurfacesRunnables.get(i).run();
430         }
431         mAfterPrepareSurfacesRunnables.clear();
432         mInExecuteAfterPrepareSurfacesRunnables = false;
433     }
434 }
435