• 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.WmProtoLogGroups.WM_SHOW_TRANSACTIONS;
20 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_ALL;
21 import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
22 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_TRACE;
23 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
24 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
25 
26 import android.annotation.IntDef;
27 import android.content.Context;
28 import android.os.HandlerExecutor;
29 import android.os.Trace;
30 import android.util.Slog;
31 import android.util.TimeUtils;
32 import android.view.Choreographer;
33 import android.view.SurfaceControl;
34 
35 import com.android.internal.protolog.ProtoLog;
36 import com.android.server.policy.WindowManagerPolicy;
37 
38 import java.io.PrintWriter;
39 import java.lang.annotation.Retention;
40 import java.lang.annotation.RetentionPolicy;
41 import java.util.ArrayList;
42 
43 /**
44  * Singleton class that carries out the animations and Surface operations in a separate task
45  * on behalf of WindowManagerService.
46  */
47 public class WindowAnimator {
48     private static final String TAG = TAG_WITH_CLASS_NAME ? "WindowAnimator" : TAG_WM;
49 
50     final WindowManagerService mService;
51     final Context mContext;
52     final WindowManagerPolicy mPolicy;
53 
54     /** Is any window animating? */
55     private boolean mLastRootAnimating;
56 
57     final Choreographer.FrameCallback mAnimationFrameCallback;
58 
59     /** Time of current animation step. Reset on each iteration */
60     long mCurrentTime;
61 
62     private boolean mInitialized = false;
63 
64     private Choreographer mChoreographer;
65 
66     private final HandlerExecutor mExecutor;
67 
68     /**
69      * Indicates whether we have an animation frame callback scheduled, which will happen at
70      * vsync-app and then schedule the animation tick at the right time (vsync-sf).
71      */
72     private boolean mAnimationFrameCallbackScheduled;
73     boolean mNotifyWhenNoAnimation = false;
74 
75     /**
76      * A list of runnable that need to be run after {@link WindowContainer#prepareSurfaces} is
77      * executed and the corresponding transaction is closed and applied.
78      */
79     private ArrayList<Runnable> mAfterPrepareSurfacesRunnables = new ArrayList<>();
80 
81     private final SurfaceControl.Transaction mTransaction;
82 
83     /** The pending transaction is applied. */
84     static final int PENDING_STATE_NONE = 0;
85     /** There are some (significant) operations set to the pending transaction. */
86     static final int PENDING_STATE_HAS_CHANGES = 1;
87     /** The pending transaction needs to be applied before sending sync transaction to shell. */
88     static final int PENDING_STATE_NEED_APPLY = 2;
89 
90     @IntDef(prefix = { "PENDING_STATE_" }, value = {
91             PENDING_STATE_NONE,
92             PENDING_STATE_HAS_CHANGES,
93             PENDING_STATE_NEED_APPLY,
94     })
95     @Retention(RetentionPolicy.SOURCE)
96     @interface PendingState {}
97 
98     /** The global state of pending transaction. */
99     @PendingState
100     int mPendingState;
101 
WindowAnimator(final WindowManagerService service)102     WindowAnimator(final WindowManagerService service) {
103         mService = service;
104         mContext = service.mContext;
105         mPolicy = service.mPolicy;
106         mTransaction = service.mTransactionFactory.get();
107         service.mAnimationHandler.runWithScissors(
108                 () -> mChoreographer = Choreographer.getSfInstance(), 0 /* timeout */);
109         mExecutor = new HandlerExecutor(service.mAnimationHandler);
110 
111         mAnimationFrameCallback = frameTimeNs -> {
112             synchronized (mService.mGlobalLock) {
113                 mAnimationFrameCallbackScheduled = false;
114                 animate(frameTimeNs);
115                 if (mNotifyWhenNoAnimation && !mLastRootAnimating) {
116                     mService.mGlobalLock.notifyAll();
117                 }
118             }
119         };
120     }
121 
ready()122     void ready() {
123         mInitialized = true;
124     }
125 
animate(long frameTimeNs)126     private void animate(long frameTimeNs) {
127         if (!mInitialized) {
128             return;
129         }
130 
131         // Schedule next frame already such that back-pressure happens continuously.
132         scheduleAnimation();
133 
134         final RootWindowContainer root = mService.mRoot;
135         boolean rootAnimating = false;
136         mCurrentTime = frameTimeNs / TimeUtils.NANOS_PER_MS;
137         if (DEBUG_WINDOW_TRACE) {
138             Slog.i(TAG, "!!! animate: entry time=" + mCurrentTime);
139         }
140 
141         ProtoLog.i(WM_SHOW_TRANSACTIONS, ">>> OPEN TRANSACTION animate");
142         try {
143             // Remove all deferred displays, tasks, and activities.
144             root.handleCompleteDeferredRemoval();
145 
146             final AccessibilityController accessibilityController =
147                     mService.mAccessibilityController;
148             final int numDisplays = root.getChildCount();
149             for (int i = 0; i < numDisplays; i++) {
150                 final DisplayContent dc = root.getChildAt(i);
151                 // Update animations of all applications, including those associated with
152                 // exiting/removed apps.
153                 dc.updateWindowsForAnimator();
154                 dc.prepareSurfaces();
155             }
156 
157             for (int i = 0; i < numDisplays; i++) {
158                 final DisplayContent dc = root.getChildAt(i);
159                 if (accessibilityController.hasCallbacks()) {
160                     accessibilityController
161                             .recomputeMagnifiedRegionAndDrawMagnifiedRegionBorderIfNeeded(
162                                     dc.mDisplayId);
163                 }
164 
165                 if (dc.isAnimating(CHILDREN, ANIMATION_TYPE_ALL)) {
166                     rootAnimating = true;
167                     if (!dc.mLastContainsRunningSurfaceAnimator) {
168                         dc.mLastContainsRunningSurfaceAnimator = true;
169                         dc.enableHighFrameRate(true);
170                     }
171                 } else if (dc.mLastContainsRunningSurfaceAnimator) {
172                     dc.mLastContainsRunningSurfaceAnimator = false;
173                     dc.enableHighFrameRate(false);
174                 }
175                 mTransaction.merge(dc.getPendingTransaction());
176             }
177 
178             cancelAnimation();
179 
180             if (mService.mWatermark != null) {
181                 mService.mWatermark.drawIfNeeded();
182             }
183 
184         } catch (RuntimeException e) {
185             Slog.wtf(TAG, "Unhandled exception in Window Manager", e);
186         }
187 
188         final boolean hasPendingLayoutChanges = root.hasPendingLayoutChanges(this);
189         if (hasPendingLayoutChanges) {
190             mService.mWindowPlacerLocked.requestTraversal();
191         }
192 
193         if (rootAnimating && !mLastRootAnimating) {
194             Trace.asyncTraceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "animating", 0);
195         }
196         if (!rootAnimating && mLastRootAnimating) {
197             mService.mWindowPlacerLocked.requestTraversal();
198             Trace.asyncTraceEnd(Trace.TRACE_TAG_WINDOW_MANAGER, "animating", 0);
199         }
200         mLastRootAnimating = rootAnimating;
201 
202         final ArrayList<Runnable> afterPrepareSurfacesRunnables = mAfterPrepareSurfacesRunnables;
203         if (!afterPrepareSurfacesRunnables.isEmpty()) {
204             mAfterPrepareSurfacesRunnables = new ArrayList<>();
205             mTransaction.addTransactionCommittedListener(mExecutor, () -> {
206                 synchronized (mService.mGlobalLock) {
207                     // Traverse in order they were added.
208                     for (int i = 0, size = afterPrepareSurfacesRunnables.size(); i < size; i++) {
209                         afterPrepareSurfacesRunnables.get(i).run();
210                     }
211                     afterPrepareSurfacesRunnables.clear();
212                 }
213             });
214         }
215         Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "applyTransaction");
216         mTransaction.apply();
217         Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
218         mPendingState = PENDING_STATE_NONE;
219         mService.mWindowTracing.logState("WindowAnimator");
220         ProtoLog.i(WM_SHOW_TRANSACTIONS, "<<< CLOSE TRANSACTION animate");
221 
222         mService.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
223 
224         if (DEBUG_WINDOW_TRACE) {
225             Slog.i(TAG, "!!! animate: exit"
226                     + " hasPendingLayoutChanges=" + hasPendingLayoutChanges);
227         }
228     }
229 
dumpLocked(PrintWriter pw, String prefix, boolean dumpAll)230     public void dumpLocked(PrintWriter pw, String prefix, boolean dumpAll) {
231         final String subPrefix = "  " + prefix;
232 
233         for (int i = 0; i < mService.mRoot.getChildCount(); i++) {
234             final DisplayContent dc = mService.mRoot.getChildAt(i);
235             pw.print(prefix); pw.print(dc); pw.println(":");
236             dc.dumpWindowAnimators(pw, subPrefix);
237             pw.println();
238         }
239 
240         pw.println();
241 
242         if (dumpAll) {
243             pw.print(prefix); pw.print("mCurrentTime=");
244                     pw.println(TimeUtils.formatUptime(mCurrentTime));
245         }
246     }
247 
scheduleAnimation()248     void scheduleAnimation() {
249         if (!mAnimationFrameCallbackScheduled) {
250             mAnimationFrameCallbackScheduled = true;
251             mChoreographer.postFrameCallback(mAnimationFrameCallback);
252         }
253     }
254 
cancelAnimation()255     private void cancelAnimation() {
256         if (mAnimationFrameCallbackScheduled) {
257             mAnimationFrameCallbackScheduled = false;
258             mChoreographer.removeFrameCallback(mAnimationFrameCallback);
259         }
260     }
261 
isAnimationScheduled()262     boolean isAnimationScheduled() {
263         return mAnimationFrameCallbackScheduled;
264     }
265 
applyPendingTransaction()266     void applyPendingTransaction() {
267         Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "applyPendingTransaction");
268         mPendingState = PENDING_STATE_NONE;
269         final int numDisplays = mService.mRoot.getChildCount();
270         if (numDisplays == 1) {
271             mService.mRoot.getChildAt(0).getPendingTransaction().apply();
272         } else {
273             for (int i = 0; i < numDisplays; i++) {
274                 mTransaction.merge(mService.mRoot.getChildAt(i).getPendingTransaction());
275             }
276             mTransaction.apply();
277         }
278         Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
279     }
280 
281     /**
282      * Adds a runnable to be executed after {@link WindowContainer#prepareSurfaces} is called and
283      * the corresponding transaction is closed, applied, and committed.
284      */
addAfterPrepareSurfacesRunnable(Runnable r)285     void addAfterPrepareSurfacesRunnable(Runnable r) {
286         mAfterPrepareSurfacesRunnables.add(r);
287         scheduleAnimation();
288     }
289 }
290