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