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.accessibilityservice.AccessibilityTrace.FLAGS_MAGNIFICATION_CALLBACK;
20 import static android.accessibilityservice.AccessibilityTrace.FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK;
21 import static android.os.Build.IS_USER;
22 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_EXCLUDE_FROM_SCREEN_MAGNIFICATION;
23 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY;
24 import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY;
25 import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
26 import static android.view.WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY;
27 
28 import static com.android.internal.util.DumpUtils.dumpSparseArray;
29 import static com.android.internal.util.DumpUtils.dumpSparseArrayValues;
30 import static com.android.server.accessibility.AccessibilityTraceFileProto.ENTRY;
31 import static com.android.server.accessibility.AccessibilityTraceFileProto.MAGIC_NUMBER;
32 import static com.android.server.accessibility.AccessibilityTraceFileProto.MAGIC_NUMBER_H;
33 import static com.android.server.accessibility.AccessibilityTraceFileProto.MAGIC_NUMBER_L;
34 import static com.android.server.accessibility.AccessibilityTraceFileProto.REAL_TO_ELAPSED_TIME_OFFSET_NANOS;
35 import static com.android.server.accessibility.AccessibilityTraceProto.ACCESSIBILITY_SERVICE;
36 import static com.android.server.accessibility.AccessibilityTraceProto.CALENDAR_TIME;
37 import static com.android.server.accessibility.AccessibilityTraceProto.CALLING_PARAMS;
38 import static com.android.server.accessibility.AccessibilityTraceProto.CALLING_PKG;
39 import static com.android.server.accessibility.AccessibilityTraceProto.CALLING_STACKS;
40 import static com.android.server.accessibility.AccessibilityTraceProto.CPU_STATS;
41 import static com.android.server.accessibility.AccessibilityTraceProto.ELAPSED_REALTIME_NANOS;
42 import static com.android.server.accessibility.AccessibilityTraceProto.LOGGING_TYPE;
43 import static com.android.server.accessibility.AccessibilityTraceProto.PROCESS_NAME;
44 import static com.android.server.accessibility.AccessibilityTraceProto.THREAD_ID_NAME;
45 import static com.android.server.accessibility.AccessibilityTraceProto.WHERE;
46 import static com.android.server.accessibility.AccessibilityTraceProto.WINDOW_MANAGER_SERVICE;
47 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
48 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
49 import static com.android.server.wm.WindowTracing.WINSCOPE_EXT;
50 
51 import android.accessibilityservice.AccessibilityTrace;
52 import android.animation.ObjectAnimator;
53 import android.animation.ValueAnimator;
54 import android.annotation.NonNull;
55 import android.annotation.Nullable;
56 import android.app.Application;
57 import android.content.Context;
58 import android.content.pm.PackageManagerInternal;
59 import android.graphics.BLASTBufferQueue;
60 import android.graphics.Canvas;
61 import android.graphics.Color;
62 import android.graphics.Insets;
63 import android.graphics.Matrix;
64 import android.graphics.Paint;
65 import android.graphics.Path;
66 import android.graphics.PixelFormat;
67 import android.graphics.Point;
68 import android.graphics.PorterDuff.Mode;
69 import android.graphics.Rect;
70 import android.graphics.RectF;
71 import android.graphics.Region;
72 import android.os.Binder;
73 import android.os.Build;
74 import android.os.Handler;
75 import android.os.HandlerThread;
76 import android.os.IBinder;
77 import android.os.Looper;
78 import android.os.Message;
79 import android.os.Process;
80 import android.os.SystemClock;
81 import android.util.ArraySet;
82 import android.util.Pair;
83 import android.util.Slog;
84 import android.util.SparseArray;
85 import android.util.SparseBooleanArray;
86 import android.util.TypedValue;
87 import android.util.proto.ProtoOutputStream;
88 import android.view.Display;
89 import android.view.MagnificationSpec;
90 import android.view.Surface;
91 import android.view.Surface.OutOfResourcesException;
92 import android.view.SurfaceControl;
93 import android.view.ViewConfiguration;
94 import android.view.WindowInfo;
95 import android.view.WindowManager;
96 import android.view.WindowManagerPolicyConstants;
97 import android.view.animation.DecelerateInterpolator;
98 import android.view.animation.Interpolator;
99 
100 import com.android.internal.R;
101 import com.android.internal.os.SomeArgs;
102 import com.android.internal.util.TraceBuffer;
103 import com.android.internal.util.function.pooled.PooledLambda;
104 import com.android.server.LocalServices;
105 import com.android.server.policy.WindowManagerPolicy;
106 import com.android.server.wm.AccessibilityWindowsPopulator.AccessibilityWindow;
107 import com.android.server.wm.WindowManagerInternal.AccessibilityControllerInternal;
108 import com.android.server.wm.WindowManagerInternal.MagnificationCallbacks;
109 import com.android.server.wm.WindowManagerInternal.WindowsForAccessibilityCallback;
110 
111 import java.io.File;
112 import java.io.IOException;
113 import java.io.PrintWriter;
114 import java.text.SimpleDateFormat;
115 import java.util.ArrayList;
116 import java.util.Arrays;
117 import java.util.Date;
118 import java.util.HashSet;
119 import java.util.List;
120 import java.util.Set;
121 import java.util.concurrent.TimeUnit;
122 
123 /**
124  * This class contains the accessibility related logic of the window manager.
125  */
126 final class AccessibilityController {
127     private static final String TAG = AccessibilityController.class.getSimpleName();
128 
129     private static final Object STATIC_LOCK = new Object();
130     static AccessibilityControllerInternalImpl
getAccessibilityControllerInternal(WindowManagerService service)131             getAccessibilityControllerInternal(WindowManagerService service) {
132         return AccessibilityControllerInternalImpl.getInstance(service);
133     }
134 
135     private final AccessibilityControllerInternalImpl mAccessibilityTracing;
136     private final WindowManagerService mService;
137     private static final Rect EMPTY_RECT = new Rect();
138     private static final float[] sTempFloats = new float[9];
139 
140     private final SparseArray<DisplayMagnifier> mDisplayMagnifiers = new SparseArray<>();
141     private final SparseArray<WindowsForAccessibilityObserver> mWindowsForAccessibilityObserver =
142             new SparseArray<>();
143     private SparseArray<IBinder> mFocusedWindow = new SparseArray<>();
144     private int mFocusedDisplay = Display.INVALID_DISPLAY;
145     private final SparseBooleanArray mIsImeVisibleArray = new SparseBooleanArray();
146     // Set to true if initializing window population complete.
147     private boolean mAllObserversInitialized = true;
148     private final AccessibilityWindowsPopulator mAccessibilityWindowsPopulator;
149 
AccessibilityController(WindowManagerService service)150     AccessibilityController(WindowManagerService service) {
151         mService = service;
152         mAccessibilityTracing =
153                 AccessibilityController.getAccessibilityControllerInternal(service);
154 
155         mAccessibilityWindowsPopulator = new AccessibilityWindowsPopulator(mService, this);
156     }
157 
setMagnificationCallbacks(int displayId, MagnificationCallbacks callbacks)158     boolean setMagnificationCallbacks(int displayId, MagnificationCallbacks callbacks) {
159         if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
160             mAccessibilityTracing.logTrace(
161                     TAG + ".setMagnificationCallbacks",
162                     FLAGS_MAGNIFICATION_CALLBACK,
163                     "displayId=" + displayId + "; callbacks={" + callbacks + "}");
164         }
165         boolean result = false;
166         if (callbacks != null) {
167             if (mDisplayMagnifiers.get(displayId) != null) {
168                 throw new IllegalStateException("Magnification callbacks already set!");
169             }
170             final DisplayContent dc = mService.mRoot.getDisplayContent(displayId);
171             if (dc != null) {
172                 final Display display = dc.getDisplay();
173                 if (display != null && display.getType() != Display.TYPE_OVERLAY) {
174                     final DisplayMagnifier magnifier = new DisplayMagnifier(
175                             mService, dc, display, callbacks);
176                     magnifier.notifyImeWindowVisibilityChanged(
177                             mIsImeVisibleArray.get(displayId, false));
178                     mDisplayMagnifiers.put(displayId, magnifier);
179                     result = true;
180                 }
181             }
182         } else {
183             final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
184             if (displayMagnifier == null) {
185                 throw new IllegalStateException("Magnification callbacks already cleared!");
186             }
187             displayMagnifier.destroy();
188             mDisplayMagnifiers.remove(displayId);
189             result = true;
190         }
191         return result;
192     }
193 
194     /**
195      * Sets a callback for observing which windows are touchable for the purposes
196      * of accessibility on specified display.
197      *
198      * @param displayId The logical display id.
199      * @param callback The callback.
200      */
setWindowsForAccessibilityCallback(int displayId, WindowsForAccessibilityCallback callback)201     void setWindowsForAccessibilityCallback(int displayId,
202             WindowsForAccessibilityCallback callback) {
203         if (mAccessibilityTracing.isTracingEnabled(FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK)) {
204             mAccessibilityTracing.logTrace(
205                     TAG + ".setWindowsForAccessibilityCallback",
206                     FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK,
207                     "displayId=" + displayId + "; callback={" + callback + "}");
208         }
209 
210         if (callback != null) {
211             WindowsForAccessibilityObserver observer =
212                     mWindowsForAccessibilityObserver.get(displayId);
213             if (observer != null) {
214                 final String errorMessage = "Windows for accessibility callback of display "
215                         + displayId + " already set!";
216                 Slog.e(TAG, errorMessage);
217                 if (Build.IS_DEBUGGABLE) {
218                     throw new IllegalStateException(errorMessage);
219                 }
220                 mWindowsForAccessibilityObserver.remove(displayId);
221             }
222             mAccessibilityWindowsPopulator.setWindowsNotification(true);
223             observer = new WindowsForAccessibilityObserver(mService, displayId, callback,
224                     mAccessibilityWindowsPopulator);
225             mWindowsForAccessibilityObserver.put(displayId, observer);
226             mAllObserversInitialized &= observer.mInitialized;
227         } else {
228             final WindowsForAccessibilityObserver windowsForA11yObserver =
229                     mWindowsForAccessibilityObserver.get(displayId);
230             if (windowsForA11yObserver == null) {
231                 final String errorMessage = "Windows for accessibility callback of display "
232                         + displayId + " already cleared!";
233                 Slog.e(TAG, errorMessage);
234                 if (Build.IS_DEBUGGABLE) {
235                     throw new IllegalStateException(errorMessage);
236                 }
237             }
238             mWindowsForAccessibilityObserver.remove(displayId);
239 
240             if (mWindowsForAccessibilityObserver.size() <= 0) {
241                 mAccessibilityWindowsPopulator.setWindowsNotification(false);
242             }
243         }
244     }
245 
performComputeChangedWindowsNot(int displayId, boolean forceSend)246     void performComputeChangedWindowsNot(int displayId, boolean forceSend) {
247         if (mAccessibilityTracing.isTracingEnabled(FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK)) {
248             mAccessibilityTracing.logTrace(
249                     TAG + ".performComputeChangedWindowsNot",
250                     FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK,
251                     "displayId=" + displayId + "; forceSend=" + forceSend);
252         }
253         WindowsForAccessibilityObserver observer = null;
254         synchronized (mService.mGlobalLock) {
255             final WindowsForAccessibilityObserver windowsForA11yObserver =
256                     mWindowsForAccessibilityObserver.get(displayId);
257             if (windowsForA11yObserver != null) {
258                 observer = windowsForA11yObserver;
259             }
260         }
261         if (observer != null) {
262             observer.performComputeChangedWindows(forceSend);
263         }
264     }
265 
setMagnificationSpec(int displayId, MagnificationSpec spec)266     void setMagnificationSpec(int displayId, MagnificationSpec spec) {
267         if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK
268                 | FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK)) {
269             mAccessibilityTracing.logTrace(TAG + ".setMagnificationSpec",
270                     FLAGS_MAGNIFICATION_CALLBACK | FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK,
271                     "displayId=" + displayId + "; spec={" + spec + "}");
272         }
273         mAccessibilityWindowsPopulator.setMagnificationSpec(displayId, spec);
274 
275         final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
276         if (displayMagnifier != null) {
277             displayMagnifier.setMagnificationSpec(spec);
278         }
279         final WindowsForAccessibilityObserver windowsForA11yObserver =
280                 mWindowsForAccessibilityObserver.get(displayId);
281         if (windowsForA11yObserver != null) {
282             windowsForA11yObserver.scheduleComputeChangedWindows();
283         }
284     }
285 
getMagnificationRegion(int displayId, Region outMagnificationRegion)286     void getMagnificationRegion(int displayId, Region outMagnificationRegion) {
287         if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
288             mAccessibilityTracing.logTrace(TAG + ".getMagnificationRegion",
289                     FLAGS_MAGNIFICATION_CALLBACK,
290                     "displayId=" + displayId + "; outMagnificationRegion={" + outMagnificationRegion
291                             + "}");
292         }
293         final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
294         if (displayMagnifier != null) {
295             displayMagnifier.getMagnificationRegion(outMagnificationRegion);
296         }
297     }
298 
onWindowLayersChanged(int displayId)299     void onWindowLayersChanged(int displayId) {
300         if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK
301                 | FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK)) {
302             mAccessibilityTracing.logTrace(TAG + ".onWindowLayersChanged",
303                     FLAGS_MAGNIFICATION_CALLBACK | FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK,
304                     "displayId=" + displayId);
305         }
306         final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
307         if (displayMagnifier != null) {
308             displayMagnifier.onWindowLayersChanged();
309         }
310         final WindowsForAccessibilityObserver windowsForA11yObserver =
311                 mWindowsForAccessibilityObserver.get(displayId);
312         if (windowsForA11yObserver != null) {
313             windowsForA11yObserver.scheduleComputeChangedWindows();
314         }
315     }
316 
onDisplaySizeChanged(DisplayContent displayContent)317     void onDisplaySizeChanged(DisplayContent displayContent) {
318 
319         if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK
320                 | FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK)) {
321             mAccessibilityTracing.logTrace(TAG + ".onRotationChanged",
322                     FLAGS_MAGNIFICATION_CALLBACK | FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK,
323                     "displayContent={" + displayContent + "}");
324         }
325         final int displayId = displayContent.getDisplayId();
326         final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
327         if (displayMagnifier != null) {
328             displayMagnifier.onDisplaySizeChanged(displayContent);
329         }
330     }
331 
onAppWindowTransition(int displayId, int transition)332     void onAppWindowTransition(int displayId, int transition) {
333         if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
334             mAccessibilityTracing.logTrace(TAG + ".onAppWindowTransition",
335                     FLAGS_MAGNIFICATION_CALLBACK,
336                     "displayId=" + displayId + "; transition=" + transition);
337         }
338         final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
339         if (displayMagnifier != null) {
340             displayMagnifier.onAppWindowTransition(displayId, transition);
341         }
342         // Not relevant for the window observer.
343     }
344 
onWMTransition(int displayId, @WindowManager.TransitionType int type)345     void onWMTransition(int displayId, @WindowManager.TransitionType int type) {
346         if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
347             mAccessibilityTracing.logTrace(TAG + ".onAppWindowTransition",
348                     FLAGS_MAGNIFICATION_CALLBACK, "displayId=" + displayId + "; type=" + type);
349         }
350         final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
351         if (displayMagnifier != null) {
352             displayMagnifier.onWMTransition(displayId, type);
353         }
354         // Not relevant for the window observer.
355     }
356 
onWindowTransition(WindowState windowState, int transition)357     void onWindowTransition(WindowState windowState, int transition) {
358         if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK
359                 | FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK)) {
360             mAccessibilityTracing.logTrace(TAG + ".onWindowTransition",
361                     FLAGS_MAGNIFICATION_CALLBACK | FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK,
362                     "windowState={" + windowState + "}; transition=" + transition);
363         }
364         final int displayId = windowState.getDisplayId();
365         final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
366         if (displayMagnifier != null) {
367             displayMagnifier.onWindowTransition(windowState, transition);
368         }
369     }
370 
onWindowFocusChangedNot(int displayId)371     void onWindowFocusChangedNot(int displayId) {
372         // Not relevant for the display magnifier.
373         if (mAccessibilityTracing.isTracingEnabled(FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK)) {
374             mAccessibilityTracing.logTrace(TAG + ".onWindowFocusChangedNot",
375                     FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK, "displayId=" + displayId);
376         }
377         WindowsForAccessibilityObserver observer = null;
378         synchronized (mService.mGlobalLock) {
379             final WindowsForAccessibilityObserver windowsForA11yObserver =
380                     mWindowsForAccessibilityObserver.get(displayId);
381             if (windowsForA11yObserver != null) {
382                 observer = windowsForA11yObserver;
383             }
384         }
385         if (observer != null) {
386             observer.performComputeChangedWindows(false);
387         }
388         // Since we abandon initializing observers if no window has focus, make sure all observers
389         // are initialized.
390         sendCallbackToUninitializedObserversIfNeeded();
391     }
392 
sendCallbackToUninitializedObserversIfNeeded()393     private void sendCallbackToUninitializedObserversIfNeeded() {
394         List<WindowsForAccessibilityObserver> unInitializedObservers;
395         synchronized (mService.mGlobalLock) {
396             if (mAllObserversInitialized) {
397                 return;
398             }
399             if (mService.mRoot.getTopFocusedDisplayContent().mCurrentFocus == null) {
400                 return;
401             }
402             unInitializedObservers = new ArrayList<>();
403             for (int i = mWindowsForAccessibilityObserver.size() - 1; i >= 0; --i) {
404                 final WindowsForAccessibilityObserver observer =
405                         mWindowsForAccessibilityObserver.valueAt(i);
406                 if (!observer.mInitialized) {
407                     unInitializedObservers.add(observer);
408                 }
409             }
410             // Reset the flag to record the new added observer.
411             mAllObserversInitialized = true;
412         }
413 
414         boolean areAllObserversInitialized = true;
415         for (int i = unInitializedObservers.size() - 1; i >= 0; --i) {
416             final  WindowsForAccessibilityObserver observer = unInitializedObservers.get(i);
417             observer.performComputeChangedWindows(true);
418             areAllObserversInitialized &= observer.mInitialized;
419         }
420         synchronized (mService.mGlobalLock) {
421             mAllObserversInitialized &= areAllObserversInitialized;
422         }
423     }
424 
425     /**
426      * Called when the location or the size of the window is changed. Moving the window to
427      * another display is also taken into consideration.
428      * @param displayIds the display ids of displays when the situation happens.
429      */
onSomeWindowResizedOrMoved(int... displayIds)430     void onSomeWindowResizedOrMoved(int... displayIds) {
431         onSomeWindowResizedOrMovedWithCallingUid(Binder.getCallingUid(), displayIds);
432     }
433 
onSomeWindowResizedOrMovedWithCallingUid(int callingUid, int... displayIds)434     void onSomeWindowResizedOrMovedWithCallingUid(int callingUid, int... displayIds) {
435         if (mAccessibilityTracing.isTracingEnabled(FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK)) {
436             mAccessibilityTracing.logTrace(TAG + ".onSomeWindowResizedOrMoved",
437                     FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK,
438                     "displayIds={" + Arrays.toString(displayIds) + "}", "".getBytes(), callingUid);
439         }
440         // Not relevant for the display magnifier.
441         for (int i = 0; i < displayIds.length; i++) {
442             final WindowsForAccessibilityObserver windowsForA11yObserver =
443                     mWindowsForAccessibilityObserver.get(displayIds[i]);
444             if (windowsForA11yObserver != null) {
445                 windowsForA11yObserver.scheduleComputeChangedWindows();
446             }
447         }
448     }
449 
drawMagnifiedRegionBorderIfNeeded(int displayId, SurfaceControl.Transaction t)450     void drawMagnifiedRegionBorderIfNeeded(int displayId, SurfaceControl.Transaction t) {
451         if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
452             mAccessibilityTracing.logTrace(
453                     TAG + ".drawMagnifiedRegionBorderIfNeeded",
454                     FLAGS_MAGNIFICATION_CALLBACK,
455                     "displayId=" + displayId + "; transaction={" + t + "}");
456         }
457         final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
458         if (displayMagnifier != null) {
459             displayMagnifier.drawMagnifiedRegionBorderIfNeeded(t);
460         }
461         // Not relevant for the window observer.
462     }
463 
getWindowTransformationMatrixAndMagnificationSpec( IBinder token)464     public Pair<Matrix, MagnificationSpec> getWindowTransformationMatrixAndMagnificationSpec(
465             IBinder token) {
466         synchronized (mService.mGlobalLock) {
467             final Matrix transformationMatrix = new Matrix();
468             final MagnificationSpec magnificationSpec = new MagnificationSpec();
469 
470             final WindowState windowState = mService.mWindowMap.get(token);
471             if (windowState != null) {
472                 windowState.getTransformationMatrix(new float[9], transformationMatrix);
473 
474                 if (hasCallbacks()) {
475                     final MagnificationSpec otherMagnificationSpec =
476                             getMagnificationSpecForWindow(windowState);
477                     if (otherMagnificationSpec != null && !otherMagnificationSpec.isNop()) {
478                         magnificationSpec.setTo(otherMagnificationSpec);
479                     }
480                 }
481             }
482 
483             return new Pair<>(transformationMatrix, magnificationSpec);
484         }
485     }
486 
getMagnificationSpecForWindow(WindowState windowState)487     MagnificationSpec getMagnificationSpecForWindow(WindowState windowState) {
488         if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
489             mAccessibilityTracing.logTrace(TAG + ".getMagnificationSpecForWindow",
490                     FLAGS_MAGNIFICATION_CALLBACK,
491                     "windowState={" + windowState + "}");
492         }
493         final int displayId = windowState.getDisplayId();
494         final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
495         if (displayMagnifier != null) {
496             return displayMagnifier.getMagnificationSpecForWindow(windowState);
497         }
498         return null;
499     }
500 
hasCallbacks()501     boolean hasCallbacks() {
502         if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK
503                 | FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK)) {
504             mAccessibilityTracing.logTrace(TAG + ".hasCallbacks",
505                     FLAGS_MAGNIFICATION_CALLBACK | FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK);
506         }
507         return (mDisplayMagnifiers.size() > 0
508                 || mWindowsForAccessibilityObserver.size() > 0);
509     }
510 
setForceShowMagnifiableBounds(int displayId, boolean show)511     void setForceShowMagnifiableBounds(int displayId, boolean show) {
512         if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
513             mAccessibilityTracing.logTrace(TAG + ".setForceShowMagnifiableBounds",
514                     FLAGS_MAGNIFICATION_CALLBACK, "displayId=" + displayId + "; show=" + show);
515         }
516         final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
517         if (displayMagnifier != null) {
518             displayMagnifier.setForceShowMagnifiableBounds(show);
519             displayMagnifier.showMagnificationBoundsIfNeeded();
520         }
521     }
522 
updateImeVisibilityIfNeeded(int displayId, boolean shown)523     void updateImeVisibilityIfNeeded(int displayId, boolean shown) {
524         if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
525             mAccessibilityTracing.logTrace(TAG + ".updateImeVisibilityIfNeeded",
526                     FLAGS_MAGNIFICATION_CALLBACK, "displayId=" + displayId + ";shown=" + shown);
527         }
528 
529         final boolean isDisplayImeVisible = mIsImeVisibleArray.get(displayId, false);
530         if (isDisplayImeVisible == shown) {
531             return;
532         }
533 
534         mIsImeVisibleArray.put(displayId, shown);
535         final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
536         if (displayMagnifier != null) {
537             displayMagnifier.notifyImeWindowVisibilityChanged(shown);
538         }
539     }
540 
populateTransformationMatrix(WindowState windowState, Matrix outMatrix)541     private static void populateTransformationMatrix(WindowState windowState,
542             Matrix outMatrix) {
543         windowState.getTransformationMatrix(sTempFloats, outMatrix);
544     }
545 
dump(PrintWriter pw, String prefix)546     void dump(PrintWriter pw, String prefix) {
547         dumpSparseArray(pw, prefix, mDisplayMagnifiers, "magnification display",
548                 (index, key) -> pw.printf("%sDisplay #%d:", prefix + "  ", key),
549                 dm -> dm.dump(pw, ""));
550         dumpSparseArrayValues(pw, prefix, mWindowsForAccessibilityObserver,
551                 "windows for accessibility observer");
552         mAccessibilityWindowsPopulator.dump(pw, prefix);
553     }
554 
onFocusChanged(InputTarget lastTarget, InputTarget newTarget)555     void onFocusChanged(InputTarget lastTarget, InputTarget newTarget) {
556         if (lastTarget != null) {
557             mFocusedWindow.remove(lastTarget.getDisplayId());
558         }
559         if (newTarget != null) {
560             int displayId = newTarget.getDisplayId();
561             IBinder clientBinder = newTarget.getIWindow().asBinder();
562             mFocusedWindow.put(displayId, clientBinder);
563         }
564     }
565 
onDisplayRemoved(int displayId)566     public void onDisplayRemoved(int displayId) {
567         mIsImeVisibleArray.delete(displayId);
568         mFocusedWindow.remove(displayId);
569     }
570 
setFocusedDisplay(int focusedDisplayId)571     public void setFocusedDisplay(int focusedDisplayId) {
572         mFocusedDisplay = focusedDisplayId;
573     }
574 
getFocusedWindowToken()575     @Nullable IBinder getFocusedWindowToken() {
576         return mFocusedWindow.get(mFocusedDisplay);
577     }
578 
579     /**
580      * This class encapsulates the functionality related to display magnification.
581      */
582     private static final class DisplayMagnifier {
583 
584         private static final String LOG_TAG = TAG_WITH_CLASS_NAME ? "DisplayMagnifier" : TAG_WM;
585 
586         private static final boolean DEBUG_WINDOW_TRANSITIONS = false;
587         private static final boolean DEBUG_DISPLAY_SIZE = false;
588         private static final boolean DEBUG_LAYERS = false;
589         private static final boolean DEBUG_RECTANGLE_REQUESTED = false;
590         private static final boolean DEBUG_VIEWPORT_WINDOW = false;
591 
592         private final Rect mTempRect1 = new Rect();
593         private final Rect mTempRect2 = new Rect();
594 
595         private final Region mTempRegion1 = new Region();
596         private final Region mTempRegion2 = new Region();
597         private final Region mTempRegion3 = new Region();
598         private final Region mTempRegion4 = new Region();
599 
600         private final Context mDisplayContext;
601         private final WindowManagerService mService;
602         private final MagnifiedViewport mMagnifedViewport;
603         private final Handler mHandler;
604         private final DisplayContent mDisplayContent;
605         private final Display mDisplay;
606         private final AccessibilityControllerInternalImpl mAccessibilityTracing;
607 
608         private final MagnificationCallbacks mCallbacks;
609 
610         private final long mLongAnimationDuration;
611 
612         private boolean mForceShowMagnifiableBounds = false;
613 
DisplayMagnifier(WindowManagerService windowManagerService, DisplayContent displayContent, Display display, MagnificationCallbacks callbacks)614         DisplayMagnifier(WindowManagerService windowManagerService,
615                 DisplayContent displayContent,
616                 Display display,
617                 MagnificationCallbacks callbacks) {
618             mDisplayContext = windowManagerService.mContext.createDisplayContext(display);
619             mService = windowManagerService;
620             mCallbacks = callbacks;
621             mDisplayContent = displayContent;
622             mDisplay = display;
623             mHandler = new MyHandler(mService.mH.getLooper());
624             mMagnifedViewport = new MagnifiedViewport();
625             mAccessibilityTracing =
626                     AccessibilityController.getAccessibilityControllerInternal(mService);
627             mLongAnimationDuration = mDisplayContext.getResources().getInteger(
628                     com.android.internal.R.integer.config_longAnimTime);
629             if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
630                 mAccessibilityTracing.logTrace(LOG_TAG + ".DisplayMagnifier.constructor",
631                         FLAGS_MAGNIFICATION_CALLBACK,
632                         "windowManagerService={" + windowManagerService + "}; displayContent={"
633                                 + displayContent + "}; display={" + display + "}; callbacks={"
634                                 + callbacks + "}");
635             }
636         }
637 
setMagnificationSpec(MagnificationSpec spec)638         void setMagnificationSpec(MagnificationSpec spec) {
639             if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
640                 mAccessibilityTracing.logTrace(LOG_TAG + ".setMagnificationSpec",
641                         FLAGS_MAGNIFICATION_CALLBACK, "spec={" + spec + "}");
642             }
643             mMagnifedViewport.updateMagnificationSpec(spec);
644             mMagnifedViewport.recomputeBounds();
645 
646             mService.applyMagnificationSpecLocked(mDisplay.getDisplayId(), spec);
647             mService.scheduleAnimationLocked();
648         }
649 
setForceShowMagnifiableBounds(boolean show)650         void setForceShowMagnifiableBounds(boolean show) {
651             if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
652                 mAccessibilityTracing.logTrace(LOG_TAG + ".setForceShowMagnifiableBounds",
653                         FLAGS_MAGNIFICATION_CALLBACK, "show=" + show);
654             }
655             mForceShowMagnifiableBounds = show;
656             mMagnifedViewport.setMagnifiedRegionBorderShown(show, true);
657         }
658 
isForceShowingMagnifiableBounds()659         boolean isForceShowingMagnifiableBounds() {
660             if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
661                 mAccessibilityTracing.logTrace(LOG_TAG + ".isForceShowingMagnifiableBounds",
662                         FLAGS_MAGNIFICATION_CALLBACK);
663             }
664             return mForceShowMagnifiableBounds;
665         }
666 
onWindowLayersChanged()667         void onWindowLayersChanged() {
668             if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
669                 mAccessibilityTracing.logTrace(
670                         LOG_TAG + ".onWindowLayersChanged", FLAGS_MAGNIFICATION_CALLBACK);
671             }
672             if (DEBUG_LAYERS) {
673                 Slog.i(LOG_TAG, "Layers changed.");
674             }
675             mMagnifedViewport.recomputeBounds();
676             mService.scheduleAnimationLocked();
677         }
678 
onDisplaySizeChanged(DisplayContent displayContent)679         void onDisplaySizeChanged(DisplayContent displayContent) {
680             if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
681                 mAccessibilityTracing.logTrace(LOG_TAG + ".onDisplaySizeChanged",
682                         FLAGS_MAGNIFICATION_CALLBACK, "displayContent={" + displayContent + "}");
683             }
684             if (DEBUG_DISPLAY_SIZE) {
685                 final int rotation = displayContent.getRotation();
686                 Slog.i(LOG_TAG, "Rotation: " + Surface.rotationToString(rotation)
687                         + " displayId: " + displayContent.getDisplayId());
688             }
689             mMagnifedViewport.onDisplaySizeChanged();
690             mHandler.sendEmptyMessage(MyHandler.MESSAGE_NOTIFY_DISPLAY_SIZE_CHANGED);
691         }
692 
onAppWindowTransition(int displayId, int transition)693         void onAppWindowTransition(int displayId, int transition) {
694             if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
695                 mAccessibilityTracing.logTrace(LOG_TAG + ".onAppWindowTransition",
696                         FLAGS_MAGNIFICATION_CALLBACK,
697                         "displayId=" + displayId + "; transition=" + transition);
698             }
699             if (DEBUG_WINDOW_TRANSITIONS) {
700                 Slog.i(LOG_TAG, "Window transition: "
701                         + AppTransition.appTransitionOldToString(transition)
702                         + " displayId: " + displayId);
703             }
704             final boolean isMagnifierActivated = isForceShowingMagnifiableBounds();
705             if (isMagnifierActivated) {
706                 switch (transition) {
707                     case WindowManager.TRANSIT_OLD_ACTIVITY_OPEN:
708                     case WindowManager.TRANSIT_OLD_TASK_FRAGMENT_OPEN:
709                     case WindowManager.TRANSIT_OLD_TASK_OPEN:
710                     case WindowManager.TRANSIT_OLD_TASK_TO_FRONT:
711                     case WindowManager.TRANSIT_OLD_WALLPAPER_OPEN:
712                     case WindowManager.TRANSIT_OLD_WALLPAPER_CLOSE:
713                     case WindowManager.TRANSIT_OLD_WALLPAPER_INTRA_OPEN: {
714                         mHandler.sendEmptyMessage(MyHandler.MESSAGE_NOTIFY_USER_CONTEXT_CHANGED);
715                     }
716                 }
717             }
718         }
719 
onWMTransition(int displayId, @WindowManager.TransitionType int type)720         void onWMTransition(int displayId, @WindowManager.TransitionType int type) {
721             if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
722                 mAccessibilityTracing.logTrace(LOG_TAG + ".onWMTransition",
723                         FLAGS_MAGNIFICATION_CALLBACK, "displayId=" + displayId + "; type=" + type);
724             }
725             if (DEBUG_WINDOW_TRANSITIONS) {
726                 Slog.i(LOG_TAG, "Window transition: " + WindowManager.transitTypeToString(type)
727                         + " displayId: " + displayId);
728             }
729             final boolean isMagnifierActivated = isForceShowingMagnifiableBounds();
730             if (isMagnifierActivated) {
731                 // All opening/closing situations.
732                 switch (type) {
733                     case WindowManager.TRANSIT_OPEN:
734                     case WindowManager.TRANSIT_TO_FRONT:
735                     case WindowManager.TRANSIT_CLOSE:
736                     case WindowManager.TRANSIT_TO_BACK:
737                         mHandler.sendEmptyMessage(MyHandler.MESSAGE_NOTIFY_USER_CONTEXT_CHANGED);
738                 }
739             }
740         }
741 
onWindowTransition(WindowState windowState, int transition)742         void onWindowTransition(WindowState windowState, int transition) {
743             if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
744                 mAccessibilityTracing.logTrace(LOG_TAG + ".onWindowTransition",
745                         FLAGS_MAGNIFICATION_CALLBACK,
746                         "windowState={" + windowState + "}; transition=" + transition);
747             }
748             if (DEBUG_WINDOW_TRANSITIONS) {
749                 Slog.i(LOG_TAG, "Window transition: "
750                         + AppTransition.appTransitionOldToString(transition)
751                         + " displayId: " + windowState.getDisplayId());
752             }
753             final boolean isMagnifierActivated = isForceShowingMagnifiableBounds();
754             final int type = windowState.mAttrs.type;
755             switch (transition) {
756                 case WindowManagerPolicy.TRANSIT_ENTER:
757                 case WindowManagerPolicy.TRANSIT_SHOW: {
758                     if (!isMagnifierActivated) {
759                         break;
760                     }
761                     switch (type) {
762                         case WindowManager.LayoutParams.TYPE_APPLICATION:
763                         case WindowManager.LayoutParams.TYPE_DRAWN_APPLICATION:
764                         case WindowManager.LayoutParams.TYPE_APPLICATION_PANEL:
765                         case WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA:
766                         case WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL:
767                         case WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL:
768                         case WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG:
769                         case WindowManager.LayoutParams.TYPE_SEARCH_BAR:
770                         case WindowManager.LayoutParams.TYPE_PHONE:
771                         case WindowManager.LayoutParams.TYPE_SYSTEM_ALERT:
772                         case WindowManager.LayoutParams.TYPE_TOAST:
773                         case WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY:
774                         case WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY:
775                         case WindowManager.LayoutParams.TYPE_PRIORITY_PHONE:
776                         case WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG:
777                         case WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG:
778                         case WindowManager.LayoutParams.TYPE_SYSTEM_ERROR:
779                         case WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY:
780                         case WindowManager.LayoutParams.TYPE_QS_DIALOG:
781                         case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL: {
782                             Rect magnifiedRegionBounds = mTempRect2;
783                             mMagnifedViewport.getMagnifiedFrameInContentCoords(
784                                     magnifiedRegionBounds);
785                             Rect touchableRegionBounds = mTempRect1;
786                             windowState.getTouchableRegion(mTempRegion1);
787                             mTempRegion1.getBounds(touchableRegionBounds);
788                             if (!magnifiedRegionBounds.intersect(touchableRegionBounds)) {
789                                 mCallbacks.onRectangleOnScreenRequested(
790                                         touchableRegionBounds.left,
791                                         touchableRegionBounds.top,
792                                         touchableRegionBounds.right,
793                                         touchableRegionBounds.bottom);
794                             }
795                         } break;
796                     } break;
797                 }
798             }
799         }
800 
notifyImeWindowVisibilityChanged(boolean shown)801         void notifyImeWindowVisibilityChanged(boolean shown) {
802             if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
803                 mAccessibilityTracing.logTrace(LOG_TAG + ".notifyImeWindowVisibilityChanged",
804                         FLAGS_MAGNIFICATION_CALLBACK, "shown=" + shown);
805             }
806             mHandler.obtainMessage(MyHandler.MESSAGE_NOTIFY_IME_WINDOW_VISIBILITY_CHANGED,
807                     shown ? 1 : 0, 0).sendToTarget();
808         }
809 
getMagnificationSpecForWindow(WindowState windowState)810         MagnificationSpec getMagnificationSpecForWindow(WindowState windowState) {
811             if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
812                 mAccessibilityTracing.logTrace(LOG_TAG + ".getMagnificationSpecForWindow",
813                         FLAGS_MAGNIFICATION_CALLBACK, "windowState={" + windowState + "}");
814             }
815             MagnificationSpec spec = mMagnifedViewport.getMagnificationSpec();
816             if (spec != null && !spec.isNop()) {
817                 if (!windowState.shouldMagnify()) {
818                     return null;
819                 }
820             }
821             return spec;
822         }
823 
getMagnificationRegion(Region outMagnificationRegion)824         void getMagnificationRegion(Region outMagnificationRegion) {
825             if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
826                 mAccessibilityTracing.logTrace(LOG_TAG + ".getMagnificationRegion",
827                         FLAGS_MAGNIFICATION_CALLBACK,
828                         "outMagnificationRegion={" + outMagnificationRegion + "}");
829             }
830             // Make sure we're working with the most current bounds
831             mMagnifedViewport.recomputeBounds();
832             mMagnifedViewport.getMagnificationRegion(outMagnificationRegion);
833         }
834 
destroy()835         void destroy() {
836             if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
837                 mAccessibilityTracing.logTrace(LOG_TAG + ".destroy", FLAGS_MAGNIFICATION_CALLBACK);
838             }
839             mMagnifedViewport.destroyWindow();
840         }
841 
842         // Can be called outside of a surface transaction
showMagnificationBoundsIfNeeded()843         void showMagnificationBoundsIfNeeded() {
844             if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
845                 mAccessibilityTracing.logTrace(LOG_TAG + ".showMagnificationBoundsIfNeeded",
846                         FLAGS_MAGNIFICATION_CALLBACK);
847             }
848             mHandler.obtainMessage(MyHandler.MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED)
849                     .sendToTarget();
850         }
851 
drawMagnifiedRegionBorderIfNeeded(SurfaceControl.Transaction t)852         void drawMagnifiedRegionBorderIfNeeded(SurfaceControl.Transaction t) {
853             if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
854                 mAccessibilityTracing.logTrace(LOG_TAG + ".drawMagnifiedRegionBorderIfNeeded",
855                         FLAGS_MAGNIFICATION_CALLBACK, "transition={" + t + "}");
856             }
857             mMagnifedViewport.drawWindowIfNeeded(t);
858         }
859 
dump(PrintWriter pw, String prefix)860         void dump(PrintWriter pw, String prefix) {
861             mMagnifedViewport.dump(pw, prefix);
862         }
863 
864         private final class MagnifiedViewport {
865 
866             private final SparseArray<WindowState> mTempWindowStates =
867                     new SparseArray<WindowState>();
868 
869             private final RectF mTempRectF = new RectF();
870 
871             private final Point mScreenSize = new Point();
872 
873             private final Matrix mTempMatrix = new Matrix();
874 
875             private final Region mMagnificationRegion = new Region();
876             private final Region mOldMagnificationRegion = new Region();
877 
878             private final Path mCircularPath;
879 
880             private final MagnificationSpec mMagnificationSpec = new MagnificationSpec();
881 
882             private final float mBorderWidth;
883             private final int mHalfBorderWidth;
884             private final int mDrawBorderInset;
885 
886             private final ViewportWindow mWindow;
887 
888             private boolean mFullRedrawNeeded;
889             private int mTempLayer = 0;
890 
MagnifiedViewport()891             MagnifiedViewport() {
892                 mBorderWidth = mDisplayContext.getResources().getDimension(
893                         com.android.internal.R.dimen.accessibility_magnification_indicator_width);
894                 mHalfBorderWidth = (int) Math.ceil(mBorderWidth / 2);
895                 mDrawBorderInset = (int) mBorderWidth / 2;
896                 mWindow = new ViewportWindow(mDisplayContext);
897 
898                 if (mDisplayContext.getResources().getConfiguration().isScreenRound()) {
899                     mCircularPath = new Path();
900 
901                     getDisplaySizeLocked(mScreenSize);
902                     final int centerXY = mScreenSize.x / 2;
903                     mCircularPath.addCircle(centerXY, centerXY, centerXY, Path.Direction.CW);
904                 } else {
905                     mCircularPath = null;
906                 }
907 
908                 recomputeBounds();
909             }
910 
getMagnificationRegion(@onNull Region outMagnificationRegion)911             void getMagnificationRegion(@NonNull Region outMagnificationRegion) {
912                 outMagnificationRegion.set(mMagnificationRegion);
913             }
914 
updateMagnificationSpec(MagnificationSpec spec)915             void updateMagnificationSpec(MagnificationSpec spec) {
916                 if (spec != null) {
917                     mMagnificationSpec.initialize(spec.scale, spec.offsetX, spec.offsetY);
918                 } else {
919                     mMagnificationSpec.clear();
920                 }
921                 // If this message is pending we are in a rotation animation and do not want
922                 // to show the border. We will do so when the pending message is handled.
923                 if (!mHandler.hasMessages(
924                         MyHandler.MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED)) {
925                     setMagnifiedRegionBorderShown(isForceShowingMagnifiableBounds(), true);
926                 }
927             }
928 
recomputeBounds()929             void recomputeBounds() {
930                 getDisplaySizeLocked(mScreenSize);
931                 final int screenWidth = mScreenSize.x;
932                 final int screenHeight = mScreenSize.y;
933 
934                 mMagnificationRegion.set(0, 0, 0, 0);
935                 final Region availableBounds = mTempRegion1;
936                 availableBounds.set(0, 0, screenWidth, screenHeight);
937 
938                 if (mCircularPath != null) {
939                     availableBounds.setPath(mCircularPath, availableBounds);
940                 }
941 
942                 Region nonMagnifiedBounds = mTempRegion4;
943                 nonMagnifiedBounds.set(0, 0, 0, 0);
944 
945                 SparseArray<WindowState> visibleWindows = mTempWindowStates;
946                 visibleWindows.clear();
947                 populateWindowsOnScreen(visibleWindows);
948 
949                 final int visibleWindowCount = visibleWindows.size();
950                 for (int i = visibleWindowCount - 1; i >= 0; i--) {
951                     WindowState windowState = visibleWindows.valueAt(i);
952                     final int windowType = windowState.mAttrs.type;
953                     if (isExcludedWindowType(windowType)
954                             || ((windowState.mAttrs.privateFlags
955                             & PRIVATE_FLAG_EXCLUDE_FROM_SCREEN_MAGNIFICATION) != 0)
956                             || ((windowState.mAttrs.privateFlags
957                             & PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY) != 0)) {
958                         continue;
959                     }
960 
961                     // Consider the touchable portion of the window
962                     Matrix matrix = mTempMatrix;
963                     populateTransformationMatrix(windowState, matrix);
964                     Region touchableRegion = mTempRegion3;
965                     windowState.getTouchableRegion(touchableRegion);
966                     Rect touchableFrame = mTempRect1;
967                     touchableRegion.getBounds(touchableFrame);
968                     RectF windowFrame = mTempRectF;
969                     windowFrame.set(touchableFrame);
970                     windowFrame.offset(-windowState.getFrame().left,
971                             -windowState.getFrame().top);
972                     matrix.mapRect(windowFrame);
973                     Region windowBounds = mTempRegion2;
974                     windowBounds.set((int) windowFrame.left, (int) windowFrame.top,
975                             (int) windowFrame.right, (int) windowFrame.bottom);
976                     // Only update new regions
977                     Region portionOfWindowAlreadyAccountedFor = mTempRegion3;
978                     portionOfWindowAlreadyAccountedFor.set(mMagnificationRegion);
979                     portionOfWindowAlreadyAccountedFor.op(nonMagnifiedBounds, Region.Op.UNION);
980                     windowBounds.op(portionOfWindowAlreadyAccountedFor, Region.Op.DIFFERENCE);
981 
982                     if (windowState.shouldMagnify()) {
983                         mMagnificationRegion.op(windowBounds, Region.Op.UNION);
984                         mMagnificationRegion.op(availableBounds, Region.Op.INTERSECT);
985                     } else {
986                         nonMagnifiedBounds.op(windowBounds, Region.Op.UNION);
987                         availableBounds.op(windowBounds, Region.Op.DIFFERENCE);
988                     }
989 
990                     // If the navigation bar window doesn't have touchable region, count
991                     // navigation bar insets into nonMagnifiedBounds. It happens when
992                     // navigation mode is gestural.
993                     if (isUntouchableNavigationBar(windowState, mTempRegion3)) {
994                         final Rect navBarInsets = getSystemBarInsetsFrame(windowState);
995                         nonMagnifiedBounds.op(navBarInsets, Region.Op.UNION);
996                         availableBounds.op(navBarInsets, Region.Op.DIFFERENCE);
997                     }
998 
999                     // Count letterbox into nonMagnifiedBounds
1000                     if (windowState.areAppWindowBoundsLetterboxed()) {
1001                         Region letterboxBounds = getLetterboxBounds(windowState);
1002                         nonMagnifiedBounds.op(letterboxBounds, Region.Op.UNION);
1003                         availableBounds.op(letterboxBounds, Region.Op.DIFFERENCE);
1004                     }
1005 
1006                     // Update accounted bounds
1007                     Region accountedBounds = mTempRegion2;
1008                     accountedBounds.set(mMagnificationRegion);
1009                     accountedBounds.op(nonMagnifiedBounds, Region.Op.UNION);
1010                     accountedBounds.op(0, 0, screenWidth, screenHeight, Region.Op.INTERSECT);
1011 
1012                     if (accountedBounds.isRect()) {
1013                         Rect accountedFrame = mTempRect1;
1014                         accountedBounds.getBounds(accountedFrame);
1015                         if (accountedFrame.width() == screenWidth
1016                                 && accountedFrame.height() == screenHeight) {
1017                             break;
1018                         }
1019                     }
1020                 }
1021                 visibleWindows.clear();
1022 
1023                 mMagnificationRegion.op(mDrawBorderInset, mDrawBorderInset,
1024                         screenWidth - mDrawBorderInset, screenHeight - mDrawBorderInset,
1025                         Region.Op.INTERSECT);
1026 
1027                 final boolean magnifiedChanged =
1028                         !mOldMagnificationRegion.equals(mMagnificationRegion);
1029                 if (magnifiedChanged) {
1030                     mWindow.setBounds(mMagnificationRegion);
1031                     final Rect dirtyRect = mTempRect1;
1032                     if (mFullRedrawNeeded) {
1033                         mFullRedrawNeeded = false;
1034                         dirtyRect.set(mDrawBorderInset, mDrawBorderInset,
1035                                 screenWidth - mDrawBorderInset,
1036                                 screenHeight - mDrawBorderInset);
1037                         mWindow.invalidate(dirtyRect);
1038                     } else {
1039                         final Region dirtyRegion = mTempRegion3;
1040                         dirtyRegion.set(mMagnificationRegion);
1041                         dirtyRegion.op(mOldMagnificationRegion, Region.Op.XOR);
1042                         dirtyRegion.getBounds(dirtyRect);
1043                         mWindow.invalidate(dirtyRect);
1044                     }
1045 
1046                     mOldMagnificationRegion.set(mMagnificationRegion);
1047                     final SomeArgs args = SomeArgs.obtain();
1048                     args.arg1 = Region.obtain(mMagnificationRegion);
1049                     mHandler.obtainMessage(
1050                             MyHandler.MESSAGE_NOTIFY_MAGNIFICATION_REGION_CHANGED, args)
1051                             .sendToTarget();
1052                 }
1053             }
1054 
getLetterboxBounds(WindowState windowState)1055             private Region getLetterboxBounds(WindowState windowState) {
1056                 final ActivityRecord appToken = windowState.mActivityRecord;
1057                 if (appToken == null) {
1058                     return new Region();
1059                 }
1060 
1061                 final Rect boundsWithoutLetterbox = windowState.getBounds();
1062                 final Rect letterboxInsets = appToken.getLetterboxInsets();
1063 
1064                 final Rect boundsIncludingLetterbox = Rect.copyOrNull(boundsWithoutLetterbox);
1065                 // Letterbox insets from mActivityRecord are positive, so we negate them to grow the
1066                 // bounds to include the letterbox.
1067                 boundsIncludingLetterbox.inset(
1068                         Insets.subtract(Insets.NONE, Insets.of(letterboxInsets)));
1069 
1070                 final Region letterboxBounds = new Region();
1071                 letterboxBounds.set(boundsIncludingLetterbox);
1072                 letterboxBounds.op(boundsWithoutLetterbox, Region.Op.DIFFERENCE);
1073                 return letterboxBounds;
1074             }
1075 
isExcludedWindowType(int windowType)1076             private boolean isExcludedWindowType(int windowType) {
1077                 return windowType == TYPE_MAGNIFICATION_OVERLAY
1078                         // Omit the touch region of window magnification to avoid the cut out of the
1079                         // magnification and the magnified center of window magnification could be
1080                         // in the bounds
1081                         || windowType == TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY;
1082             }
1083 
onDisplaySizeChanged()1084             void onDisplaySizeChanged() {
1085                 // If we are showing the magnification border, hide it immediately so
1086                 // the user does not see strange artifacts during display size changed caused by
1087                 // rotation or folding/unfolding the device. In the rotation case, the screenshot
1088                 // used for rotation already has the border. After the rotation is complete
1089                 // we will show the border.
1090                 if (isForceShowingMagnifiableBounds()) {
1091                     setMagnifiedRegionBorderShown(false, false);
1092                     final long delay = (long) (mLongAnimationDuration
1093                             * mService.getWindowAnimationScaleLocked());
1094                     Message message = mHandler.obtainMessage(
1095                             MyHandler.MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED);
1096                     mHandler.sendMessageDelayed(message, delay);
1097                 }
1098                 recomputeBounds();
1099                 mWindow.updateSize();
1100             }
1101 
setMagnifiedRegionBorderShown(boolean shown, boolean animate)1102             void setMagnifiedRegionBorderShown(boolean shown, boolean animate) {
1103                 if (shown) {
1104                     mFullRedrawNeeded = true;
1105                     mOldMagnificationRegion.set(0, 0, 0, 0);
1106                 }
1107                 mWindow.setShown(shown, animate);
1108             }
1109 
getMagnifiedFrameInContentCoords(Rect rect)1110             void getMagnifiedFrameInContentCoords(Rect rect) {
1111                 MagnificationSpec spec = mMagnificationSpec;
1112                 mMagnificationRegion.getBounds(rect);
1113                 rect.offset((int) -spec.offsetX, (int) -spec.offsetY);
1114                 rect.scale(1.0f / spec.scale);
1115             }
1116 
isMagnifying()1117             boolean isMagnifying() {
1118                 return mMagnificationSpec.scale > 1.0f;
1119             }
1120 
getMagnificationSpec()1121             MagnificationSpec getMagnificationSpec() {
1122                 return mMagnificationSpec;
1123             }
1124 
drawWindowIfNeeded(SurfaceControl.Transaction t)1125             void drawWindowIfNeeded(SurfaceControl.Transaction t) {
1126                 recomputeBounds();
1127                 mWindow.drawIfNeeded(t);
1128             }
1129 
destroyWindow()1130             void destroyWindow() {
1131                 mWindow.releaseSurface();
1132             }
1133 
populateWindowsOnScreen(SparseArray<WindowState> outWindows)1134             private void populateWindowsOnScreen(SparseArray<WindowState> outWindows) {
1135                 mTempLayer = 0;
1136                 mDisplayContent.forAllWindows((w) -> {
1137                     if (w.isOnScreen() && w.isVisible()
1138                             && (w.mAttrs.alpha != 0)) {
1139                         mTempLayer++;
1140                         outWindows.put(mTempLayer, w);
1141                     }
1142                 }, false /* traverseTopToBottom */ );
1143             }
1144 
getDisplaySizeLocked(Point outSize)1145             private void getDisplaySizeLocked(Point outSize) {
1146                 final Rect bounds =
1147                         mDisplayContent.getConfiguration().windowConfiguration.getBounds();
1148                 outSize.set(bounds.width(), bounds.height());
1149             }
1150 
dump(PrintWriter pw, String prefix)1151             void dump(PrintWriter pw, String prefix) {
1152                 mWindow.dump(pw, prefix);
1153             }
1154 
1155             private final class ViewportWindow {
1156                 private static final String SURFACE_TITLE = "Magnification Overlay";
1157 
1158                 private final Region mBounds = new Region();
1159                 private final Rect mDirtyRect = new Rect();
1160                 private final Paint mPaint = new Paint();
1161 
1162                 private final SurfaceControl mSurfaceControl;
1163                 private final BLASTBufferQueue mBlastBufferQueue;
1164                 private final Surface mSurface;
1165 
1166                 private final AnimationController mAnimationController;
1167 
1168                 private boolean mShown;
1169                 private int mAlpha;
1170 
1171                 private boolean mInvalidated;
1172 
ViewportWindow(Context context)1173                 ViewportWindow(Context context) {
1174                     SurfaceControl surfaceControl = null;
1175                     try {
1176                         surfaceControl = mDisplayContent
1177                                 .makeOverlay()
1178                                 .setName(SURFACE_TITLE)
1179                                 .setBLASTLayer()
1180                                 .setFormat(PixelFormat.TRANSLUCENT)
1181                                 .setCallsite("ViewportWindow")
1182                                 .build();
1183                     } catch (OutOfResourcesException oore) {
1184                         /* ignore */
1185                     }
1186                     mSurfaceControl = surfaceControl;
1187                     mDisplay.getRealSize(mScreenSize);
1188                     mBlastBufferQueue = new BLASTBufferQueue(SURFACE_TITLE, mSurfaceControl,
1189                             mScreenSize.x, mScreenSize.y, PixelFormat.RGBA_8888);
1190 
1191                     final SurfaceControl.Transaction t = mService.mTransactionFactory.get();
1192                     final int layer =
1193                             mService.mPolicy.getWindowLayerFromTypeLw(TYPE_MAGNIFICATION_OVERLAY) *
1194                                     WindowManagerPolicyConstants.TYPE_LAYER_MULTIPLIER;
1195                     t.setLayer(mSurfaceControl, layer).setPosition(mSurfaceControl, 0, 0);
1196                     InputMonitor.setTrustedOverlayInputInfo(mSurfaceControl, t,
1197                             mDisplayContent.getDisplayId(), "Magnification Overlay");
1198                     t.apply();
1199                     mSurface = mBlastBufferQueue.createSurface();
1200 
1201                     mAnimationController = new AnimationController(context,
1202                             mService.mH.getLooper());
1203 
1204                     TypedValue typedValue = new TypedValue();
1205                     context.getTheme().resolveAttribute(R.attr.colorActivatedHighlight,
1206                             typedValue, true);
1207                     final int borderColor = context.getColor(typedValue.resourceId);
1208 
1209                     mPaint.setStyle(Paint.Style.STROKE);
1210                     mPaint.setStrokeWidth(mBorderWidth);
1211                     mPaint.setColor(borderColor);
1212 
1213                     mInvalidated = true;
1214                 }
1215 
setShown(boolean shown, boolean animate)1216                 void setShown(boolean shown, boolean animate) {
1217                     synchronized (mService.mGlobalLock) {
1218                         if (mShown == shown) {
1219                             return;
1220                         }
1221                         mShown = shown;
1222                         mAnimationController.onFrameShownStateChanged(shown, animate);
1223                         if (DEBUG_VIEWPORT_WINDOW) {
1224                             Slog.i(LOG_TAG, "ViewportWindow shown: " + mShown);
1225                         }
1226                     }
1227                 }
1228 
1229                 @SuppressWarnings("unused")
1230                 // Called reflectively from an animator.
getAlpha()1231                 int getAlpha() {
1232                     synchronized (mService.mGlobalLock) {
1233                         return mAlpha;
1234                     }
1235                 }
1236 
setAlpha(int alpha)1237                 void setAlpha(int alpha) {
1238                     synchronized (mService.mGlobalLock) {
1239                         if (mAlpha == alpha) {
1240                             return;
1241                         }
1242                         mAlpha = alpha;
1243                         invalidate(null);
1244                         if (DEBUG_VIEWPORT_WINDOW) {
1245                             Slog.i(LOG_TAG, "ViewportWindow set alpha: " + alpha);
1246                         }
1247                     }
1248                 }
1249 
setBounds(Region bounds)1250                 void setBounds(Region bounds) {
1251                     synchronized (mService.mGlobalLock) {
1252                         if (mBounds.equals(bounds)) {
1253                             return;
1254                         }
1255                         mBounds.set(bounds);
1256                         invalidate(mDirtyRect);
1257                         if (DEBUG_VIEWPORT_WINDOW) {
1258                             Slog.i(LOG_TAG, "ViewportWindow set bounds: " + bounds);
1259                         }
1260                     }
1261                 }
1262 
updateSize()1263                 void updateSize() {
1264                     synchronized (mService.mGlobalLock) {
1265                         getDisplaySizeLocked(mScreenSize);
1266                         mBlastBufferQueue.update(mSurfaceControl, mScreenSize.x, mScreenSize.y,
1267                                 PixelFormat.RGBA_8888);
1268                         invalidate(mDirtyRect);
1269                     }
1270                 }
1271 
invalidate(Rect dirtyRect)1272                 void invalidate(Rect dirtyRect) {
1273                     if (dirtyRect != null) {
1274                         mDirtyRect.set(dirtyRect);
1275                     } else {
1276                         mDirtyRect.setEmpty();
1277                     }
1278                     mInvalidated = true;
1279                     mService.scheduleAnimationLocked();
1280                 }
1281 
drawIfNeeded(SurfaceControl.Transaction t)1282                 void drawIfNeeded(SurfaceControl.Transaction t) {
1283                     // Drawing variables (alpha, dirty rect, and bounds) access is synchronized
1284                     // using WindowManagerGlobalLock. Grab copies of these values before
1285                     // drawing on the canvas so that drawing can be performed outside of the lock.
1286                     int alpha;
1287                     Rect drawingRect = null;
1288                     Region drawingBounds = null;
1289                     synchronized (mService.mGlobalLock) {
1290                         if (!mInvalidated) {
1291                             return;
1292                         }
1293                         mInvalidated = false;
1294 
1295                         alpha = mAlpha;
1296                         if (alpha > 0) {
1297                             drawingBounds = new Region(mBounds);
1298                             // Empty dirty rectangle means unspecified.
1299                             if (mDirtyRect.isEmpty()) {
1300                                 mBounds.getBounds(mDirtyRect);
1301                             }
1302                             mDirtyRect.inset(-mHalfBorderWidth, -mHalfBorderWidth);
1303                             drawingRect = new Rect(mDirtyRect);
1304                             if (DEBUG_VIEWPORT_WINDOW) {
1305                                 Slog.i(LOG_TAG, "ViewportWindow bounds: " + mBounds);
1306                                 Slog.i(LOG_TAG, "ViewportWindow dirty rect: " + mDirtyRect);
1307                             }
1308                         }
1309                     }
1310 
1311                     // Draw without holding WindowManagerGlobalLock.
1312                     if (alpha > 0) {
1313                         Canvas canvas = null;
1314                         try {
1315                             canvas = mSurface.lockCanvas(drawingRect);
1316                         } catch (IllegalArgumentException | OutOfResourcesException e) {
1317                             /* ignore */
1318                         }
1319                         if (canvas == null) {
1320                             return;
1321                         }
1322                         canvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);
1323                         mPaint.setAlpha(alpha);
1324                         canvas.drawPath(drawingBounds.getBoundaryPath(), mPaint);
1325                         mSurface.unlockCanvasAndPost(canvas);
1326                         t.show(mSurfaceControl);
1327                     } else {
1328                         t.hide(mSurfaceControl);
1329                     }
1330                 }
1331 
releaseSurface()1332                 void releaseSurface() {
1333                     if (mBlastBufferQueue != null) {
1334                         mBlastBufferQueue.destroy();
1335                     }
1336                     mService.mTransactionFactory.get().remove(mSurfaceControl).apply();
1337                     mSurface.release();
1338                 }
1339 
dump(PrintWriter pw, String prefix)1340                 void dump(PrintWriter pw, String prefix) {
1341                     pw.println(prefix
1342                             + " mBounds= " + mBounds
1343                             + " mDirtyRect= " + mDirtyRect
1344                             + " mWidth= " + mScreenSize.x
1345                             + " mHeight= " + mScreenSize.y);
1346                 }
1347 
1348                 private final class AnimationController extends Handler {
1349                     private static final String PROPERTY_NAME_ALPHA = "alpha";
1350 
1351                     private static final int MIN_ALPHA = 0;
1352                     private static final int MAX_ALPHA = 255;
1353 
1354                     private static final int MSG_FRAME_SHOWN_STATE_CHANGED = 1;
1355 
1356                     private final ValueAnimator mShowHideFrameAnimator;
1357 
AnimationController(Context context, Looper looper)1358                     AnimationController(Context context, Looper looper) {
1359                         super(looper);
1360                         mShowHideFrameAnimator = ObjectAnimator.ofInt(ViewportWindow.this,
1361                                 PROPERTY_NAME_ALPHA, MIN_ALPHA, MAX_ALPHA);
1362 
1363                         Interpolator interpolator = new DecelerateInterpolator(2.5f);
1364                         final long longAnimationDuration = context.getResources().getInteger(
1365                                 com.android.internal.R.integer.config_longAnimTime);
1366 
1367                         mShowHideFrameAnimator.setInterpolator(interpolator);
1368                         mShowHideFrameAnimator.setDuration(longAnimationDuration);
1369                     }
1370 
onFrameShownStateChanged(boolean shown, boolean animate)1371                     void onFrameShownStateChanged(boolean shown, boolean animate) {
1372                         obtainMessage(MSG_FRAME_SHOWN_STATE_CHANGED,
1373                                 shown ? 1 : 0, animate ? 1 : 0).sendToTarget();
1374                     }
1375 
1376                     @Override
handleMessage(Message message)1377                     public void handleMessage(Message message) {
1378                         switch (message.what) {
1379                             case MSG_FRAME_SHOWN_STATE_CHANGED: {
1380                                 final boolean shown = message.arg1 == 1;
1381                                 final boolean animate = message.arg2 == 1;
1382 
1383                                 if (animate) {
1384                                     if (mShowHideFrameAnimator.isRunning()) {
1385                                         mShowHideFrameAnimator.reverse();
1386                                     } else {
1387                                         if (shown) {
1388                                             mShowHideFrameAnimator.start();
1389                                         } else {
1390                                             mShowHideFrameAnimator.reverse();
1391                                         }
1392                                     }
1393                                 } else {
1394                                     mShowHideFrameAnimator.cancel();
1395                                     if (shown) {
1396                                         setAlpha(MAX_ALPHA);
1397                                     } else {
1398                                         setAlpha(MIN_ALPHA);
1399                                     }
1400                                 }
1401                             } break;
1402                         }
1403                     }
1404                 }
1405             }
1406         }
1407 
1408         private class MyHandler extends Handler {
1409             public static final int MESSAGE_NOTIFY_MAGNIFICATION_REGION_CHANGED = 1;
1410             public static final int MESSAGE_NOTIFY_USER_CONTEXT_CHANGED = 3;
1411             public static final int MESSAGE_NOTIFY_DISPLAY_SIZE_CHANGED = 4;
1412             public static final int MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED = 5;
1413             public static final int MESSAGE_NOTIFY_IME_WINDOW_VISIBILITY_CHANGED = 6;
1414 
MyHandler(Looper looper)1415             MyHandler(Looper looper) {
1416                 super(looper);
1417             }
1418 
1419             @Override
handleMessage(Message message)1420             public void handleMessage(Message message) {
1421                 switch (message.what) {
1422                     case MESSAGE_NOTIFY_MAGNIFICATION_REGION_CHANGED: {
1423                         final SomeArgs args = (SomeArgs) message.obj;
1424                         final Region magnifiedBounds = (Region) args.arg1;
1425                         mCallbacks.onMagnificationRegionChanged(magnifiedBounds);
1426                         magnifiedBounds.recycle();
1427                     } break;
1428 
1429                     case MESSAGE_NOTIFY_USER_CONTEXT_CHANGED: {
1430                         mCallbacks.onUserContextChanged();
1431                     } break;
1432 
1433                     case MESSAGE_NOTIFY_DISPLAY_SIZE_CHANGED: {
1434                         mCallbacks.onDisplaySizeChanged();
1435                     } break;
1436 
1437                     case MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED : {
1438                         synchronized (mService.mGlobalLock) {
1439                             if (isForceShowingMagnifiableBounds()) {
1440                                 mMagnifedViewport.setMagnifiedRegionBorderShown(true, true);
1441                                 mService.scheduleAnimationLocked();
1442                             }
1443                         }
1444                     } break;
1445 
1446                     case MESSAGE_NOTIFY_IME_WINDOW_VISIBILITY_CHANGED: {
1447                         final boolean shown = message.arg1 == 1;
1448                         mCallbacks.onImeWindowVisibilityChanged(shown);
1449                     } break;
1450                 }
1451             }
1452         }
1453     }
1454 
isUntouchableNavigationBar(WindowState windowState, Region touchableRegion)1455     static boolean isUntouchableNavigationBar(WindowState windowState,
1456             Region touchableRegion) {
1457         if (windowState.mAttrs.type != WindowManager.LayoutParams.TYPE_NAVIGATION_BAR) {
1458             return false;
1459         }
1460 
1461         // Gets the touchable region.
1462         windowState.getTouchableRegion(touchableRegion);
1463 
1464         return touchableRegion.isEmpty();
1465     }
1466 
getSystemBarInsetsFrame(WindowState win)1467     static Rect getSystemBarInsetsFrame(WindowState win) {
1468         if (win == null) {
1469             return EMPTY_RECT;
1470         }
1471         final InsetsSourceProvider provider = win.getControllableInsetProvider();
1472         return provider != null ? provider.getSource().getFrame() : EMPTY_RECT;
1473     }
1474 
1475     /**
1476      * This class encapsulates the functionality related to computing the windows
1477      * reported for accessibility purposes. These windows are all windows a sighted
1478      * user can see on the screen.
1479      */
1480     private static final class WindowsForAccessibilityObserver {
1481         private static final String LOG_TAG = TAG_WITH_CLASS_NAME ?
1482                 "WindowsForAccessibilityObserver" : TAG_WM;
1483 
1484         private static final boolean DEBUG = false;
1485 
1486         private final List<AccessibilityWindow> mTempA11yWindows = new ArrayList<>();
1487 
1488         private final Set<IBinder> mTempBinderSet = new ArraySet<>();
1489 
1490         private final Point mTempPoint = new Point();
1491 
1492         private final Region mTempRegion = new Region();
1493 
1494         private final Region mTempRegion1 = new Region();
1495 
1496         private final Region mTempRegion2 = new Region();
1497 
1498         private final WindowManagerService mService;
1499 
1500         private final Handler mHandler;
1501 
1502         private final AccessibilityControllerInternalImpl mAccessibilityTracing;
1503 
1504         private final WindowsForAccessibilityCallback mCallback;
1505 
1506         private final int mDisplayId;
1507 
1508         private final long mRecurringAccessibilityEventsIntervalMillis;
1509 
1510         // Set to true if initializing window population complete.
1511         private boolean mInitialized;
1512         private final AccessibilityWindowsPopulator mA11yWindowsPopulator;
1513 
WindowsForAccessibilityObserver(WindowManagerService windowManagerService, int displayId, WindowsForAccessibilityCallback callback, AccessibilityWindowsPopulator accessibilityWindowsPopulator)1514         WindowsForAccessibilityObserver(WindowManagerService windowManagerService,
1515                 int displayId, WindowsForAccessibilityCallback callback,
1516                 AccessibilityWindowsPopulator accessibilityWindowsPopulator) {
1517             mService = windowManagerService;
1518             mCallback = callback;
1519             mDisplayId = displayId;
1520             mHandler = new MyHandler(mService.mH.getLooper());
1521             mAccessibilityTracing =
1522                     AccessibilityController.getAccessibilityControllerInternal(mService);
1523             mRecurringAccessibilityEventsIntervalMillis = ViewConfiguration
1524                     .getSendRecurringAccessibilityEventsInterval();
1525             mA11yWindowsPopulator = accessibilityWindowsPopulator;
1526             computeChangedWindows(true);
1527         }
1528 
performComputeChangedWindows(boolean forceSend)1529         void performComputeChangedWindows(boolean forceSend) {
1530             if (mAccessibilityTracing.isTracingEnabled(FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK)) {
1531                 mAccessibilityTracing.logTrace(LOG_TAG + ".performComputeChangedWindows",
1532                         FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK, "forceSend=" + forceSend);
1533             }
1534             mHandler.removeMessages(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS);
1535             computeChangedWindows(forceSend);
1536         }
1537 
scheduleComputeChangedWindows()1538         void scheduleComputeChangedWindows() {
1539             if (mAccessibilityTracing.isTracingEnabled(FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK)) {
1540                 mAccessibilityTracing.logTrace(LOG_TAG + ".scheduleComputeChangedWindows",
1541                         FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK);
1542             }
1543             if (!mHandler.hasMessages(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS)) {
1544                 mHandler.sendEmptyMessageDelayed(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS,
1545                         mRecurringAccessibilityEventsIntervalMillis);
1546             }
1547         }
1548 
1549         /**
1550          * Check if windows have changed, and send them to the accessibility subsystem if they have.
1551          *
1552          * @param forceSend Send the windows the accessibility even if they haven't changed.
1553          */
computeChangedWindows(boolean forceSend)1554         void computeChangedWindows(boolean forceSend) {
1555             if (mAccessibilityTracing.isTracingEnabled(FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK)) {
1556                 mAccessibilityTracing.logTrace(LOG_TAG + ".computeChangedWindows",
1557                         FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK, "forceSend=" + forceSend);
1558             }
1559             if (DEBUG) {
1560                 Slog.i(LOG_TAG, "computeChangedWindows()");
1561             }
1562 
1563             List<WindowInfo> windows = new ArrayList<>();
1564             final int topFocusedDisplayId;
1565             IBinder topFocusedWindowToken = null;
1566 
1567             synchronized (mService.mGlobalLock) {
1568                 // If there is a recents animation running, then use the animation target as the
1569                 // top window state. Otherwise,do not send the windows if there is no top focus as
1570                 // the window manager is still looking for where to put it. We will do the work when
1571                 // we get a focus change callback.
1572                 final RecentsAnimationController controller =
1573                         mService.getRecentsAnimationController();
1574                 final WindowState topFocusedWindowState = controller != null
1575                         ? controller.getTargetAppMainWindow()
1576                         : getTopFocusWindow();
1577                 if (topFocusedWindowState == null) {
1578                     if (DEBUG) {
1579                         Slog.d(LOG_TAG, "top focused window is null, compute it again later");
1580                     }
1581                     return;
1582                 }
1583 
1584                 final DisplayContent dc = mService.mRoot.getDisplayContent(mDisplayId);
1585                 if (dc == null) {
1586                     //It should not happen because it is created while adding the callback.
1587                     Slog.w(LOG_TAG, "display content is null, should be created later");
1588                     return;
1589                 }
1590                 final Display display = dc.getDisplay();
1591                 display.getRealSize(mTempPoint);
1592                 final int screenWidth = mTempPoint.x;
1593                 final int screenHeight = mTempPoint.y;
1594 
1595                 Region unaccountedSpace = mTempRegion;
1596                 unaccountedSpace.set(0, 0, screenWidth, screenHeight);
1597 
1598                 final List<AccessibilityWindow> visibleWindows = mTempA11yWindows;
1599                 mA11yWindowsPopulator.populateVisibleWindowsOnScreenLocked(
1600                         mDisplayId, visibleWindows);
1601                 Set<IBinder> addedWindows = mTempBinderSet;
1602                 addedWindows.clear();
1603 
1604                 boolean focusedWindowAdded = false;
1605 
1606                 final int visibleWindowCount = visibleWindows.size();
1607 
1608                 // Iterate until we figure out what is touchable for the entire screen.
1609                 for (int i = 0; i < visibleWindowCount; i++) {
1610                     final AccessibilityWindow a11yWindow = visibleWindows.get(i);
1611                     final Region regionInWindow = new Region();
1612                     a11yWindow.getTouchableRegionInWindow(regionInWindow);
1613                     if (windowMattersToAccessibility(a11yWindow, regionInWindow,
1614                             unaccountedSpace)) {
1615                         addPopulatedWindowInfo(a11yWindow, regionInWindow, windows, addedWindows);
1616                         if (windowMattersToUnaccountedSpaceComputation(a11yWindow)) {
1617                             updateUnaccountedSpace(a11yWindow, unaccountedSpace);
1618                         }
1619                         focusedWindowAdded |= a11yWindow.isFocused();
1620                     } else if (a11yWindow.isUntouchableNavigationBar()) {
1621                         // If this widow is navigation bar without touchable region, accounting the
1622                         // region of navigation bar inset because all touch events from this region
1623                         // would be received by launcher, i.e. this region is a un-touchable one
1624                         // for the application.
1625                         unaccountedSpace.op(
1626                                 getSystemBarInsetsFrame(
1627                                         mService.mWindowMap.get(a11yWindow.getWindowInfo().token)),
1628                                 unaccountedSpace,
1629                                 Region.Op.REVERSE_DIFFERENCE);
1630                     }
1631 
1632                     if (unaccountedSpace.isEmpty() && focusedWindowAdded) {
1633                         break;
1634                     }
1635                 }
1636 
1637                 // Remove child/parent references to windows that were not added.
1638                 final int windowCount = windows.size();
1639                 for (int i = 0; i < windowCount; i++) {
1640                     WindowInfo window = windows.get(i);
1641                     if (!addedWindows.contains(window.parentToken)) {
1642                         window.parentToken = null;
1643                     }
1644                     if (window.childTokens != null) {
1645                         final int childTokenCount = window.childTokens.size();
1646                         for (int j = childTokenCount - 1; j >= 0; j--) {
1647                             if (!addedWindows.contains(window.childTokens.get(j))) {
1648                                 window.childTokens.remove(j);
1649                             }
1650                         }
1651                         // Leave the child token list if empty.
1652                     }
1653                 }
1654 
1655                 visibleWindows.clear();
1656                 addedWindows.clear();
1657 
1658                 // Gets the top focused display Id and window token for supporting multi-display.
1659                 topFocusedDisplayId = mService.mRoot.getTopFocusedDisplayContent().getDisplayId();
1660                 topFocusedWindowToken = topFocusedWindowState.mClient.asBinder();
1661             }
1662             mCallback.onWindowsForAccessibilityChanged(forceSend, topFocusedDisplayId,
1663                     topFocusedWindowToken, windows);
1664 
1665             // Recycle the windows as we do not need them.
1666             clearAndRecycleWindows(windows);
1667             mInitialized = true;
1668         }
1669 
1670         // Some windows should be excluded from unaccounted space computation, though they still
1671         // should be reported
windowMattersToUnaccountedSpaceComputation(AccessibilityWindow a11yWindow)1672         private boolean windowMattersToUnaccountedSpaceComputation(AccessibilityWindow a11yWindow) {
1673             // Do not account space of trusted non-touchable windows, except the split-screen
1674             // divider.
1675             // If it's not trusted, touch events are not sent to the windows behind it.
1676             if (!a11yWindow.isTouchable()
1677                     && (a11yWindow.getType() != TYPE_DOCK_DIVIDER)
1678                     && a11yWindow.isTrustedOverlay()) {
1679                 return false;
1680             }
1681 
1682             if (a11yWindow.getType() == WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY) {
1683                 return false;
1684             }
1685             return true;
1686         }
1687 
windowMattersToAccessibility(AccessibilityWindow a11yWindow, Region regionInScreen, Region unaccountedSpace)1688         private boolean windowMattersToAccessibility(AccessibilityWindow a11yWindow,
1689                 Region regionInScreen, Region unaccountedSpace) {
1690             if (a11yWindow.ignoreRecentsAnimationForAccessibility()) {
1691                 return false;
1692             }
1693 
1694             if (a11yWindow.isFocused()) {
1695                 return true;
1696             }
1697 
1698             // Ignore non-touchable windows, except the split-screen divider, which is
1699             // occasionally non-touchable but still useful for identifying split-screen
1700             // mode and the PIP menu.
1701             if (!a11yWindow.isTouchable()
1702                     && (a11yWindow.getType() != TYPE_DOCK_DIVIDER
1703                     && !a11yWindow.isPIPMenu())) {
1704                 return false;
1705             }
1706 
1707             // If the window is completely covered by other windows - ignore.
1708             if (unaccountedSpace.quickReject(regionInScreen)) {
1709                 return false;
1710             }
1711 
1712             // Add windows of certain types not covered by modal windows.
1713             if (isReportedWindowType(a11yWindow.getType())) {
1714                 return true;
1715             }
1716 
1717             return false;
1718         }
1719 
updateUnaccountedSpace(AccessibilityWindow a11yWindow, Region unaccountedSpace)1720         private void updateUnaccountedSpace(AccessibilityWindow a11yWindow,
1721                 Region unaccountedSpace) {
1722             if (a11yWindow.getType()
1723                     != WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY) {
1724                 // Account for the space this window takes if the window
1725                 // is not an accessibility overlay which does not change
1726                 // the reported windows.
1727                 final Region touchableRegion = mTempRegion2;
1728                 a11yWindow.getTouchableRegionInScreen(touchableRegion);
1729                 unaccountedSpace.op(touchableRegion, unaccountedSpace,
1730                         Region.Op.REVERSE_DIFFERENCE);
1731             }
1732         }
1733 
addPopulatedWindowInfo(AccessibilityWindow a11yWindow, Region regionInScreen, List<WindowInfo> out, Set<IBinder> tokenOut)1734         private static void addPopulatedWindowInfo(AccessibilityWindow a11yWindow,
1735                 Region regionInScreen, List<WindowInfo> out, Set<IBinder> tokenOut) {
1736             final WindowInfo window = a11yWindow.getWindowInfo();
1737             if (window.token == null) {
1738                 // The window was used in calculating visible windows but does not have an
1739                 // associated IWindow token, so exclude it from the list returned to accessibility.
1740                 return;
1741             }
1742             window.regionInScreen.set(regionInScreen);
1743             window.layer = tokenOut.size();
1744             out.add(window);
1745             tokenOut.add(window.token);
1746         }
1747 
clearAndRecycleWindows(List<WindowInfo> windows)1748         private static void clearAndRecycleWindows(List<WindowInfo> windows) {
1749             final int windowCount = windows.size();
1750             for (int i = windowCount - 1; i >= 0; i--) {
1751                 windows.remove(i).recycle();
1752             }
1753         }
1754 
isReportedWindowType(int windowType)1755         private static boolean isReportedWindowType(int windowType) {
1756             return (windowType != WindowManager.LayoutParams.TYPE_WALLPAPER
1757                     && windowType != WindowManager.LayoutParams.TYPE_BOOT_PROGRESS
1758                     && windowType != WindowManager.LayoutParams.TYPE_DISPLAY_OVERLAY
1759                     && windowType != WindowManager.LayoutParams.TYPE_DRAG
1760                     && windowType != WindowManager.LayoutParams.TYPE_INPUT_CONSUMER
1761                     && windowType != WindowManager.LayoutParams.TYPE_POINTER
1762                     && windowType != TYPE_MAGNIFICATION_OVERLAY
1763                     && windowType != WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY
1764                     && windowType != WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY
1765                     && windowType != WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION);
1766         }
1767 
getTopFocusWindow()1768         private WindowState getTopFocusWindow() {
1769             return mService.mRoot.getTopFocusedDisplayContent().mCurrentFocus;
1770         }
1771 
1772         @Override
toString()1773         public String toString() {
1774             return "WindowsForAccessibilityObserver{"
1775                     + "mDisplayId=" + mDisplayId
1776                     + ", mInitialized=" + mInitialized
1777                     + '}';
1778         }
1779 
1780         private class MyHandler extends Handler {
1781             public static final int MESSAGE_COMPUTE_CHANGED_WINDOWS = 1;
1782 
MyHandler(Looper looper)1783             public MyHandler(Looper looper) {
1784                 super(looper, null, false);
1785             }
1786 
1787             @Override
1788             @SuppressWarnings("unchecked")
handleMessage(Message message)1789             public void handleMessage(Message message) {
1790                 switch (message.what) {
1791                     case MESSAGE_COMPUTE_CHANGED_WINDOWS: {
1792                         computeChangedWindows(false);
1793                     } break;
1794                 }
1795             }
1796         }
1797     }
1798 
1799     static final class AccessibilityControllerInternalImpl
1800             implements AccessibilityControllerInternal {
1801 
1802         private static AccessibilityControllerInternalImpl sInstance;
getInstance(WindowManagerService service)1803         static AccessibilityControllerInternalImpl getInstance(WindowManagerService service) {
1804             synchronized (STATIC_LOCK) {
1805                 if (sInstance == null) {
1806                     sInstance = new AccessibilityControllerInternalImpl(service);
1807                 }
1808                 return sInstance;
1809             }
1810         }
1811 
1812         private final AccessibilityTracing mTracing;
1813         private volatile long mEnabledTracingFlags;
1814         private UiChangesForAccessibilityCallbacksDispatcher mCallbacksDispatcher;
1815         private final Looper mLooper;
1816 
AccessibilityControllerInternalImpl(WindowManagerService service)1817         private AccessibilityControllerInternalImpl(WindowManagerService service) {
1818             mLooper = service.mH.getLooper();
1819             mTracing = AccessibilityTracing.getInstance(service);
1820             mEnabledTracingFlags = 0L;
1821         }
1822 
1823         @Override
startTrace(long loggingTypes)1824         public void startTrace(long loggingTypes) {
1825             mEnabledTracingFlags = loggingTypes;
1826             mTracing.startTrace();
1827         }
1828 
1829         @Override
stopTrace()1830         public void stopTrace() {
1831             mTracing.stopTrace();
1832             mEnabledTracingFlags = 0L;
1833         }
1834 
1835         @Override
isAccessibilityTracingEnabled()1836         public boolean isAccessibilityTracingEnabled() {
1837             return mTracing.isEnabled();
1838         }
1839 
isTracingEnabled(long flags)1840         boolean isTracingEnabled(long flags) {
1841             return (flags & mEnabledTracingFlags) != 0L;
1842         }
1843 
logTrace(String where, long loggingTypes)1844         void logTrace(String where, long loggingTypes) {
1845             logTrace(where, loggingTypes, "");
1846         }
1847 
logTrace(String where, long loggingTypes, String callingParams)1848         void logTrace(String where, long loggingTypes, String callingParams) {
1849             logTrace(where, loggingTypes, callingParams, "".getBytes(), Binder.getCallingUid());
1850         }
1851 
logTrace(String where, long loggingTypes, String callingParams, byte[] a11yDump, int callingUid)1852         void logTrace(String where, long loggingTypes, String callingParams, byte[] a11yDump,
1853                 int callingUid) {
1854             mTracing.logState(where, loggingTypes, callingParams, a11yDump, callingUid,
1855                     new HashSet<String>(Arrays.asList("logTrace")));
1856         }
1857 
1858         @Override
logTrace(String where, long loggingTypes, String callingParams, byte[] a11yDump, int callingUid, StackTraceElement[] stackTrace, Set<String> ignoreStackEntries)1859         public void logTrace(String where, long loggingTypes, String callingParams, byte[] a11yDump,
1860                 int callingUid, StackTraceElement[] stackTrace, Set<String> ignoreStackEntries) {
1861             mTracing.logState(where, loggingTypes, callingParams, a11yDump, callingUid, stackTrace,
1862                     ignoreStackEntries);
1863         }
1864 
1865         @Override
logTrace(String where, long loggingTypes, String callingParams, byte[] a11yDump, int callingUid, StackTraceElement[] callStack, long timeStamp, int processId, long threadId, Set<String> ignoreStackEntries)1866         public void logTrace(String where, long loggingTypes, String callingParams, byte[] a11yDump,
1867                 int callingUid, StackTraceElement[] callStack, long timeStamp, int processId,
1868                 long threadId, Set<String> ignoreStackEntries) {
1869             mTracing.logState(where, loggingTypes, callingParams, a11yDump, callingUid, callStack,
1870                     timeStamp, processId, threadId, ignoreStackEntries);
1871         }
1872 
1873         @Override
setUiChangesForAccessibilityCallbacks( UiChangesForAccessibilityCallbacks callbacks)1874         public void setUiChangesForAccessibilityCallbacks(
1875                 UiChangesForAccessibilityCallbacks callbacks) {
1876             if (isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
1877                 logTrace(
1878                         TAG + ".setAccessibilityWindowManagerCallbacks",
1879                         FLAGS_MAGNIFICATION_CALLBACK,
1880                         "callbacks={" + callbacks + "}");
1881             }
1882             if (callbacks != null) {
1883                 if (mCallbacksDispatcher != null) {
1884                     throw new IllegalStateException("Accessibility window manager callback already "
1885                             + "set!");
1886                 }
1887                 mCallbacksDispatcher =
1888                         new UiChangesForAccessibilityCallbacksDispatcher(this, mLooper,
1889                                 callbacks);
1890             } else {
1891                 if (mCallbacksDispatcher == null) {
1892                     throw new IllegalStateException("Accessibility window manager callback already "
1893                             + "cleared!");
1894                 }
1895                 mCallbacksDispatcher = null;
1896             }
1897         }
1898 
hasWindowManagerEventDispatcher()1899         public boolean hasWindowManagerEventDispatcher() {
1900             if (isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK
1901                     | FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK)) {
1902                 logTrace(TAG + ".hasCallbacks",
1903                         FLAGS_MAGNIFICATION_CALLBACK | FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK);
1904             }
1905             return mCallbacksDispatcher != null;
1906         }
1907 
onRectangleOnScreenRequested(int displayId, Rect rectangle)1908         public void onRectangleOnScreenRequested(int displayId, Rect rectangle) {
1909             if (isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
1910                 logTrace(
1911                         TAG + ".onRectangleOnScreenRequested",
1912                         FLAGS_MAGNIFICATION_CALLBACK,
1913                         "rectangle={" + rectangle + "}");
1914             }
1915             if (mCallbacksDispatcher != null) {
1916                 mCallbacksDispatcher.onRectangleOnScreenRequested(displayId, rectangle);
1917             }
1918         }
1919 
1920         private static final class UiChangesForAccessibilityCallbacksDispatcher {
1921 
1922             private static final String LOG_TAG = TAG_WITH_CLASS_NAME
1923                     ? "WindowManagerEventDispatcher" : TAG_WM;
1924 
1925             private static final boolean DEBUG_RECTANGLE_REQUESTED = false;
1926 
1927             private final AccessibilityControllerInternalImpl mAccessibilityTracing;
1928 
1929             @NonNull
1930             private final UiChangesForAccessibilityCallbacks mCallbacks;
1931 
1932             private final Handler mHandler;
1933 
UiChangesForAccessibilityCallbacksDispatcher( AccessibilityControllerInternalImpl accessibilityControllerInternal, Looper looper, @NonNull UiChangesForAccessibilityCallbacks callbacks)1934             UiChangesForAccessibilityCallbacksDispatcher(
1935                     AccessibilityControllerInternalImpl accessibilityControllerInternal,
1936                     Looper looper, @NonNull UiChangesForAccessibilityCallbacks callbacks) {
1937                 mAccessibilityTracing = accessibilityControllerInternal;
1938                 mCallbacks = callbacks;
1939                 mHandler = new Handler(looper);
1940             }
1941 
onRectangleOnScreenRequested(int displayId, Rect rectangle)1942             void onRectangleOnScreenRequested(int displayId, Rect rectangle) {
1943                 if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
1944                     mAccessibilityTracing.logTrace(LOG_TAG + ".onRectangleOnScreenRequested",
1945                             FLAGS_MAGNIFICATION_CALLBACK, "rectangle={" + rectangle + "}");
1946                 }
1947                 if (DEBUG_RECTANGLE_REQUESTED) {
1948                     Slog.i(LOG_TAG, "Rectangle on screen requested: " + rectangle);
1949                 }
1950                 final Message m = PooledLambda.obtainMessage(
1951                         mCallbacks::onRectangleOnScreenRequested, displayId, rectangle.left,
1952                         rectangle.top, rectangle.right, rectangle.bottom);
1953                 mHandler.sendMessage(m);
1954             }
1955         }
1956     }
1957 
1958     private static final class AccessibilityTracing {
1959         private static AccessibilityTracing sInstance;
getInstance(WindowManagerService service)1960         static AccessibilityTracing getInstance(WindowManagerService service) {
1961             synchronized (STATIC_LOCK) {
1962                 if (sInstance == null) {
1963                     sInstance = new AccessibilityTracing(service);
1964                 }
1965                 return sInstance;
1966             }
1967         }
1968 
1969         private static final int CPU_STATS_COUNT = 5;
1970         private static final int BUFFER_CAPACITY = 1024 * 1024 * 12;
1971         private static final String TRACE_FILENAME = "/data/misc/a11ytrace/a11y_trace"
1972                 + WINSCOPE_EXT;
1973         private static final String TAG = "AccessibilityTracing";
1974         private static final long MAGIC_NUMBER_VALUE =
1975                 ((long) MAGIC_NUMBER_H << 32) | MAGIC_NUMBER_L;
1976 
1977         private final Object mLock = new Object();
1978         private final WindowManagerService mService;
1979         private final File mTraceFile;
1980         private final TraceBuffer mBuffer;
1981         private final LogHandler mHandler;
1982         private volatile boolean mEnabled;
1983 
AccessibilityTracing(WindowManagerService service)1984         AccessibilityTracing(WindowManagerService service) {
1985             mService = service;
1986             mTraceFile = new File(TRACE_FILENAME);
1987             mBuffer = new TraceBuffer(BUFFER_CAPACITY);
1988             HandlerThread workThread = new HandlerThread(TAG);
1989             workThread.start();
1990             mHandler = new LogHandler(workThread.getLooper());
1991         }
1992 
1993         /**
1994          * Start the trace.
1995          */
startTrace()1996         void startTrace() {
1997             if (IS_USER) {
1998                 Slog.e(TAG, "Error: Tracing is not supported on user builds.");
1999                 return;
2000             }
2001             synchronized (mLock) {
2002                 mEnabled = true;
2003                 mBuffer.resetBuffer();
2004             }
2005         }
2006 
2007         /**
2008          * Stops the trace and write the current buffer to disk
2009          */
stopTrace()2010         void stopTrace() {
2011             if (IS_USER) {
2012                 Slog.e(TAG, "Error: Tracing is not supported on user builds.");
2013                 return;
2014             }
2015             synchronized (mLock) {
2016                 mEnabled = false;
2017                 if (mEnabled) {
2018                     Slog.e(TAG, "Error: tracing enabled while waiting for flush.");
2019                     return;
2020                 }
2021                 writeTraceToFile();
2022             }
2023         }
2024 
isEnabled()2025         boolean isEnabled() {
2026             return mEnabled;
2027         }
2028 
2029         /**
2030          * Write an accessibility trace log entry.
2031          */
logState(String where, long loggingTypes)2032         void logState(String where, long loggingTypes) {
2033             if (!mEnabled) {
2034                 return;
2035             }
2036             logState(where, loggingTypes, "");
2037         }
2038 
2039         /**
2040          * Write an accessibility trace log entry.
2041          */
logState(String where, long loggingTypes, String callingParams)2042         void logState(String where, long loggingTypes, String callingParams) {
2043             if (!mEnabled) {
2044                 return;
2045             }
2046             logState(where, loggingTypes, callingParams, "".getBytes());
2047         }
2048 
2049         /**
2050          * Write an accessibility trace log entry.
2051          */
logState(String where, long loggingTypes, String callingParams, byte[] a11yDump)2052         void logState(String where, long loggingTypes, String callingParams, byte[] a11yDump) {
2053             if (!mEnabled) {
2054                 return;
2055             }
2056             logState(where, loggingTypes, callingParams, a11yDump, Binder.getCallingUid(),
2057                     new HashSet<String>(Arrays.asList("logState")));
2058         }
2059 
2060         /**
2061          * Write an accessibility trace log entry.
2062          */
logState(String where, long loggingTypes, String callingParams, byte[] a11yDump, int callingUid, Set<String> ignoreStackEntries)2063         void logState(String where, long loggingTypes, String callingParams, byte[] a11yDump,
2064                 int callingUid, Set<String> ignoreStackEntries) {
2065             if (!mEnabled) {
2066                 return;
2067             }
2068             StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
2069             ignoreStackEntries.add("logState");
2070             logState(where, loggingTypes, callingParams, a11yDump, callingUid, stackTraceElements,
2071                     ignoreStackEntries);
2072         }
2073 
2074         /**
2075          * Write an accessibility trace log entry.
2076          */
logState(String where, long loggingTypes, String callingParams, byte[] a11yDump, int callingUid, StackTraceElement[] stackTrace, Set<String> ignoreStackEntries)2077         void logState(String where, long loggingTypes, String callingParams, byte[] a11yDump,
2078                 int callingUid, StackTraceElement[] stackTrace, Set<String> ignoreStackEntries) {
2079             if (!mEnabled) {
2080                 return;
2081             }
2082             log(where, loggingTypes, callingParams, a11yDump, callingUid, stackTrace,
2083                     SystemClock.elapsedRealtimeNanos(),
2084                     Process.myPid() + ":" + Application.getProcessName(),
2085                     Thread.currentThread().getId() + ":" + Thread.currentThread().getName(),
2086                     ignoreStackEntries);
2087         }
2088 
2089         /**
2090          * Write an accessibility trace log entry.
2091          */
logState(String where, long loggingTypes, String callingParams, byte[] a11yDump, int callingUid, StackTraceElement[] callingStack, long timeStamp, int processId, long threadId, Set<String> ignoreStackEntries)2092         void logState(String where, long loggingTypes, String callingParams, byte[] a11yDump,
2093                 int callingUid, StackTraceElement[] callingStack, long timeStamp, int processId,
2094                 long threadId, Set<String> ignoreStackEntries) {
2095             if (!mEnabled) {
2096                 return;
2097             }
2098             log(where, loggingTypes, callingParams, a11yDump, callingUid, callingStack, timeStamp,
2099                     String.valueOf(processId), String.valueOf(threadId), ignoreStackEntries);
2100         }
2101 
toStackTraceString(StackTraceElement[] stackTraceElements, Set<String> ignoreStackEntries)2102         private  String toStackTraceString(StackTraceElement[] stackTraceElements,
2103                 Set<String> ignoreStackEntries) {
2104 
2105             if (stackTraceElements == null) {
2106                 return "";
2107             }
2108 
2109             StringBuilder stringBuilder = new StringBuilder();
2110             int i = 0;
2111 
2112             // Skip the first a few elements until after any ignoreStackEntries
2113             int firstMatch = -1;
2114             while (i < stackTraceElements.length) {
2115                 for (String ele : ignoreStackEntries) {
2116                     if (stackTraceElements[i].toString().contains(ele)) {
2117                         // found the first stack element containing the ignorable stack entries
2118                         firstMatch = i;
2119                         break;
2120                     }
2121                 }
2122                 if (firstMatch < 0) {
2123                     // Haven't found the first match yet, continue
2124                     i++;
2125                 } else {
2126                     break;
2127                 }
2128             }
2129             int lastMatch = firstMatch;
2130             if (i < stackTraceElements.length) {
2131                 i++;
2132                 // Found the first match. Now look for the last match.
2133                 while (i < stackTraceElements.length) {
2134                     for (String ele : ignoreStackEntries) {
2135                         if (stackTraceElements[i].toString().contains(ele)) {
2136                             // This is a match. Look at the next stack element.
2137                             lastMatch = i;
2138                             break;
2139                         }
2140                     }
2141                     if (lastMatch != i) {
2142                         // Found a no-match.
2143                         break;
2144                     }
2145                     i++;
2146                 }
2147             }
2148 
2149             i = lastMatch + 1;
2150             while (i < stackTraceElements.length) {
2151                 stringBuilder.append(stackTraceElements[i].toString()).append("\n");
2152                 i++;
2153             }
2154             return stringBuilder.toString();
2155         }
2156 
2157         /**
2158          * Write the current state to the buffer
2159          */
log(String where, long loggingTypes, String callingParams, byte[] a11yDump, int callingUid, StackTraceElement[] callingStack, long timeStamp, String processName, String threadName, Set<String> ignoreStackEntries)2160         private void log(String where, long loggingTypes, String callingParams, byte[] a11yDump,
2161                 int callingUid, StackTraceElement[] callingStack, long timeStamp,
2162                 String processName, String threadName, Set<String> ignoreStackEntries) {
2163             SomeArgs args = SomeArgs.obtain();
2164             args.argl1 = timeStamp;
2165             args.argl2 = loggingTypes;
2166             args.arg1 = where;
2167             args.arg2 = processName;
2168             args.arg3 = threadName;
2169             args.arg4 = ignoreStackEntries;
2170             args.arg5 = callingParams;
2171             args.arg6 = callingStack;
2172             args.arg7 = a11yDump;
2173 
2174             mHandler.obtainMessage(
2175                     LogHandler.MESSAGE_LOG_TRACE_ENTRY, callingUid, 0, args).sendToTarget();
2176         }
2177 
2178         /**
2179          * Writes the trace buffer to new file for the bugreport.
2180          */
writeTraceToFile()2181         void writeTraceToFile() {
2182             mHandler.sendEmptyMessage(LogHandler.MESSAGE_WRITE_FILE);
2183         }
2184 
2185         private class LogHandler extends Handler {
2186             public static final int MESSAGE_LOG_TRACE_ENTRY = 1;
2187             public static final int MESSAGE_WRITE_FILE = 2;
2188 
LogHandler(Looper looper)2189             LogHandler(Looper looper) {
2190                 super(looper);
2191             }
2192 
2193             @Override
handleMessage(Message message)2194             public void handleMessage(Message message) {
2195                 switch (message.what) {
2196                     case MESSAGE_LOG_TRACE_ENTRY: {
2197                         final SomeArgs args = (SomeArgs) message.obj;
2198                         try {
2199                             ProtoOutputStream os = new ProtoOutputStream();
2200                             PackageManagerInternal pmInternal =
2201                                     LocalServices.getService(PackageManagerInternal.class);
2202 
2203                             long tokenOuter = os.start(ENTRY);
2204 
2205                             long reportedTimeStampNanos = args.argl1;
2206                             long currentElapsedRealtimeNanos = SystemClock.elapsedRealtimeNanos();
2207                             long timeDiffNanos =
2208                                     currentElapsedRealtimeNanos - reportedTimeStampNanos;
2209                             long currentTimeMillis = (new Date()).getTime();
2210                             long reportedTimeMillis =
2211                                     currentTimeMillis - (long) (timeDiffNanos / 1000000);
2212                             SimpleDateFormat fm = new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
2213 
2214                             os.write(ELAPSED_REALTIME_NANOS, reportedTimeStampNanos);
2215                             os.write(CALENDAR_TIME, fm.format(reportedTimeMillis).toString());
2216 
2217                             long loggingTypes = args.argl2;
2218                             List<String> loggingTypeNames =
2219                                     AccessibilityTrace.getNamesOfLoggingTypes(loggingTypes);
2220 
2221                             for (String type : loggingTypeNames) {
2222                                 os.write(LOGGING_TYPE, type);
2223                             }
2224                             os.write(WHERE, (String) args.arg1);
2225                             os.write(PROCESS_NAME, (String) args.arg2);
2226                             os.write(THREAD_ID_NAME, (String) args.arg3);
2227                             os.write(CALLING_PKG, pmInternal.getNameForUid(message.arg1));
2228                             os.write(CALLING_PARAMS, (String) args.arg5);
2229 
2230                             String callingStack = toStackTraceString(
2231                                     (StackTraceElement[]) args.arg6, (Set<String>) args.arg4);
2232 
2233                             os.write(CALLING_STACKS, callingStack);
2234                             os.write(ACCESSIBILITY_SERVICE, (byte[]) args.arg7);
2235 
2236                             long tokenInner = os.start(WINDOW_MANAGER_SERVICE);
2237                             synchronized (mService.mGlobalLock) {
2238                                 mService.dumpDebugLocked(os, WindowTraceLogLevel.ALL);
2239                             }
2240                             os.end(tokenInner);
2241                             os.write(CPU_STATS, printCpuStats(reportedTimeStampNanos));
2242 
2243                             os.end(tokenOuter);
2244                             synchronized (mLock) {
2245                                 mBuffer.add(os);
2246                             }
2247                         } catch (Exception e) {
2248                             Slog.e(TAG, "Exception while tracing state", e);
2249                         }
2250                         break;
2251                     }
2252                     case MESSAGE_WRITE_FILE: {
2253                         synchronized (mLock) {
2254                             writeTraceToFileInternal();
2255                         }
2256                         break;
2257                     }
2258                 }
2259             }
2260         }
2261 
2262         /**
2263          * Writes the trace buffer to disk.
2264          */
writeTraceToFileInternal()2265         private void writeTraceToFileInternal() {
2266             try {
2267                 ProtoOutputStream proto = new ProtoOutputStream();
2268                 proto.write(MAGIC_NUMBER, MAGIC_NUMBER_VALUE);
2269                 long timeOffsetNs =
2270                         TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis())
2271                         - SystemClock.elapsedRealtimeNanos();
2272                 proto.write(REAL_TO_ELAPSED_TIME_OFFSET_NANOS, timeOffsetNs);
2273                 mBuffer.writeTraceToFile(mTraceFile, proto);
2274             } catch (IOException e) {
2275                 Slog.e(TAG, "Unable to write buffer to file", e);
2276             }
2277         }
2278 
2279         /**
2280          * Returns the string of CPU stats.
2281          */
printCpuStats(long timeStampNanos)2282         private String printCpuStats(long timeStampNanos) {
2283             Pair<String, String> stats = mService.mAmInternal.getAppProfileStatsForDebugging(
2284                     timeStampNanos, CPU_STATS_COUNT);
2285 
2286             return stats.first + stats.second;
2287         }
2288     }
2289 }
2290