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