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