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