• 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.WindowManager.LayoutParams.PRIVATE_FLAG_EXCLUDE_FROM_SCREEN_MAGNIFICATION;
23 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY;
24 import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY;
25 import static android.view.WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY;
26 import static android.view.WindowManager.TRANSIT_FLAG_IS_RECENTS;
27 
28 import static com.android.internal.util.DumpUtils.dumpSparseArrayValues;
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.AccessibilityTraceFileProto.REAL_TO_ELAPSED_TIME_OFFSET_NANOS;
34 import static com.android.server.accessibility.AccessibilityTraceProto.ACCESSIBILITY_SERVICE;
35 import static com.android.server.accessibility.AccessibilityTraceProto.CALENDAR_TIME;
36 import static com.android.server.accessibility.AccessibilityTraceProto.CALLING_PARAMS;
37 import static com.android.server.accessibility.AccessibilityTraceProto.CALLING_PKG;
38 import static com.android.server.accessibility.AccessibilityTraceProto.CALLING_STACKS;
39 import static com.android.server.accessibility.AccessibilityTraceProto.CPU_STATS;
40 import static com.android.server.accessibility.AccessibilityTraceProto.ELAPSED_REALTIME_NANOS;
41 import static com.android.server.accessibility.AccessibilityTraceProto.LOGGING_TYPE;
42 import static com.android.server.accessibility.AccessibilityTraceProto.PROCESS_NAME;
43 import static com.android.server.accessibility.AccessibilityTraceProto.THREAD_ID_NAME;
44 import static com.android.server.accessibility.AccessibilityTraceProto.WHERE;
45 import static com.android.server.accessibility.AccessibilityTraceProto.WINDOW_MANAGER_SERVICE;
46 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
47 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
48 import static com.android.server.wm.WindowTracingLegacy.WINSCOPE_EXT;
49 
50 import android.accessibilityservice.AccessibilityTrace;
51 import android.annotation.NonNull;
52 import android.annotation.Nullable;
53 import android.app.Application;
54 import android.content.Context;
55 import android.content.pm.PackageManagerInternal;
56 import android.graphics.Insets;
57 import android.graphics.Matrix;
58 import android.graphics.Path;
59 import android.graphics.Point;
60 import android.graphics.Rect;
61 import android.graphics.Region;
62 import android.os.Binder;
63 import android.os.Build;
64 import android.os.Handler;
65 import android.os.HandlerThread;
66 import android.os.IBinder;
67 import android.os.Looper;
68 import android.os.Message;
69 import android.os.Process;
70 import android.os.SystemClock;
71 import android.util.Pair;
72 import android.util.Slog;
73 import android.util.SparseArray;
74 import android.util.SparseBooleanArray;
75 import android.util.proto.ProtoOutputStream;
76 import android.view.Display;
77 import android.view.MagnificationSpec;
78 import android.view.Surface;
79 import android.view.ViewConfiguration;
80 import android.view.WindowManager;
81 import android.view.WindowManager.TransitionFlags;
82 import android.view.WindowManager.TransitionType;
83 
84 import com.android.internal.os.SomeArgs;
85 import com.android.internal.util.TraceBuffer;
86 import com.android.internal.util.function.pooled.PooledLambda;
87 import com.android.server.LocalServices;
88 import com.android.server.policy.WindowManagerPolicy;
89 import com.android.server.wm.AccessibilityWindowsPopulator.AccessibilityWindow;
90 import com.android.server.wm.WindowManagerInternal.AccessibilityControllerInternal;
91 import com.android.server.wm.WindowManagerInternal.MagnificationCallbacks;
92 import com.android.server.wm.WindowManagerInternal.WindowsForAccessibilityCallback;
93 
94 import java.io.File;
95 import java.io.IOException;
96 import java.io.PrintWriter;
97 import java.text.SimpleDateFormat;
98 import java.util.ArrayList;
99 import java.util.Arrays;
100 import java.util.Date;
101 import java.util.HashSet;
102 import java.util.List;
103 import java.util.Set;
104 import java.util.concurrent.TimeUnit;
105 
106 /**
107  * This class contains the accessibility related logic of the window manager.
108  */
109 final class AccessibilityController {
110     private static final String TAG = AccessibilityController.class.getSimpleName();
111 
112     private static final Object STATIC_LOCK = new Object();
113     static AccessibilityControllerInternalImpl
getAccessibilityControllerInternal(WindowManagerService service)114             getAccessibilityControllerInternal(WindowManagerService service) {
115         return AccessibilityControllerInternalImpl.getInstance(service);
116     }
117 
118     private final AccessibilityControllerInternalImpl mAccessibilityTracing;
119     private final WindowManagerService mService;
120     private static final Rect EMPTY_RECT = new Rect();
121     private static final float[] sTempFloats = new float[9];
122 
123     private final SparseArray<DisplayMagnifier> mDisplayMagnifiers = new SparseArray<>();
124     private final SparseArray<WindowsForAccessibilityObserver> mWindowsForAccessibilityObserver =
125             new SparseArray<>();
126     private SparseArray<IBinder> mFocusedWindow = new SparseArray<>();
127     private int mFocusedDisplay = Display.INVALID_DISPLAY;
128     private final SparseBooleanArray mIsImeVisibleArray = new SparseBooleanArray();
129     // Set to true if initializing window population complete.
130     private boolean mAllObserversInitialized = true;
131     private final AccessibilityWindowsPopulator mAccessibilityWindowsPopulator;
132 
AccessibilityController(WindowManagerService service)133     AccessibilityController(WindowManagerService service) {
134         mService = service;
135         mAccessibilityTracing =
136                 AccessibilityController.getAccessibilityControllerInternal(service);
137 
138         mAccessibilityWindowsPopulator = new AccessibilityWindowsPopulator(mService, this);
139     }
140 
setMagnificationCallbacks(int displayId, MagnificationCallbacks callbacks)141     boolean setMagnificationCallbacks(int displayId, MagnificationCallbacks callbacks) {
142         if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
143             mAccessibilityTracing.logTrace(
144                     TAG + ".setMagnificationCallbacks",
145                     FLAGS_MAGNIFICATION_CALLBACK,
146                     "displayId=" + displayId + "; callbacks={" + callbacks + "}");
147         }
148         boolean result = false;
149         if (callbacks != null) {
150             if (mDisplayMagnifiers.get(displayId) != null) {
151                 throw new IllegalStateException("Magnification callbacks already set!");
152             }
153             final DisplayContent dc = mService.mRoot.getDisplayContent(displayId);
154             if (dc != null) {
155                 final Display display = dc.getDisplay();
156                 if (display != null) {
157                     final DisplayMagnifier magnifier = new DisplayMagnifier(
158                             mService, dc, display, callbacks);
159                     magnifier.notifyImeWindowVisibilityChanged(
160                             mIsImeVisibleArray.get(displayId, false));
161                     mDisplayMagnifiers.put(displayId, magnifier);
162                     result = true;
163                 }
164             }
165         } else {
166             final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
167             if (displayMagnifier == null) {
168                 throw new IllegalStateException("Magnification callbacks already cleared!");
169             }
170             displayMagnifier.destroy();
171             mDisplayMagnifiers.remove(displayId);
172             result = true;
173         }
174         return result;
175     }
176 
177     /**
178      * Sets a callback for observing which windows are touchable for the purposes
179      * of accessibility on specified display.
180      *
181      * @param displayId The logical display id.
182      * @param callback The callback.
183      */
setWindowsForAccessibilityCallback(int displayId, WindowsForAccessibilityCallback callback)184     void setWindowsForAccessibilityCallback(int displayId,
185             WindowsForAccessibilityCallback callback) {
186         if (mAccessibilityTracing.isTracingEnabled(FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK)) {
187             mAccessibilityTracing.logTrace(
188                     TAG + ".setWindowsForAccessibilityCallback",
189                     FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK,
190                     "displayId=" + displayId + "; callback={" + callback + "}");
191         }
192 
193         if (callback != null) {
194             WindowsForAccessibilityObserver observer =
195                     mWindowsForAccessibilityObserver.get(displayId);
196             if (observer != null) {
197                 final String errorMessage = "Windows for accessibility callback of display "
198                         + displayId + " already set!";
199                 Slog.e(TAG, errorMessage);
200                 if (Build.IS_DEBUGGABLE) {
201                     throw new IllegalStateException(errorMessage);
202                 }
203                 mWindowsForAccessibilityObserver.remove(displayId);
204             }
205             mAccessibilityWindowsPopulator.setWindowsNotification(true);
206             observer = new WindowsForAccessibilityObserver(mService, displayId, callback,
207                     mAccessibilityWindowsPopulator);
208             mWindowsForAccessibilityObserver.put(displayId, observer);
209             mAllObserversInitialized &= observer.mInitialized;
210         } else {
211             final WindowsForAccessibilityObserver windowsForA11yObserver =
212                     mWindowsForAccessibilityObserver.get(displayId);
213             if (windowsForA11yObserver == null) {
214                 final String errorMessage = "Windows for accessibility callback of display "
215                         + displayId + " already cleared!";
216                 Slog.e(TAG, errorMessage);
217                 if (Build.IS_DEBUGGABLE) {
218                     throw new IllegalStateException(errorMessage);
219                 }
220             }
221             mWindowsForAccessibilityObserver.remove(displayId);
222 
223             if (mWindowsForAccessibilityObserver.size() <= 0) {
224                 mAccessibilityWindowsPopulator.setWindowsNotification(false);
225             }
226         }
227     }
228 
performComputeChangedWindowsNot(int displayId, boolean forceSend)229     void performComputeChangedWindowsNot(int displayId, boolean forceSend) {
230         if (mAccessibilityTracing.isTracingEnabled(FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK)) {
231             mAccessibilityTracing.logTrace(
232                     TAG + ".performComputeChangedWindowsNot",
233                     FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK,
234                     "displayId=" + displayId + "; forceSend=" + forceSend);
235         }
236         WindowsForAccessibilityObserver observer = null;
237         synchronized (mService.mGlobalLock) {
238             final WindowsForAccessibilityObserver windowsForA11yObserver =
239                     mWindowsForAccessibilityObserver.get(displayId);
240             if (windowsForA11yObserver != null) {
241                 observer = windowsForA11yObserver;
242             }
243         }
244         if (observer != null) {
245             observer.performComputeChangedWindows(forceSend);
246         }
247     }
248 
setMagnificationSpec(int displayId, MagnificationSpec spec)249     void setMagnificationSpec(int displayId, MagnificationSpec spec) {
250         if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK
251                 | FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK)) {
252             mAccessibilityTracing.logTrace(TAG + ".setMagnificationSpec",
253                     FLAGS_MAGNIFICATION_CALLBACK | FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK,
254                     "displayId=" + displayId + "; spec={" + spec + "}");
255         }
256         mAccessibilityWindowsPopulator.setMagnificationSpec(displayId, spec);
257 
258         final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
259         if (displayMagnifier != null) {
260             displayMagnifier.setMagnificationSpec(spec);
261         }
262         final WindowsForAccessibilityObserver windowsForA11yObserver =
263                 mWindowsForAccessibilityObserver.get(displayId);
264         if (windowsForA11yObserver != null) {
265             windowsForA11yObserver.scheduleComputeChangedWindows();
266         }
267     }
268 
getMagnificationRegion(int displayId, Region outMagnificationRegion)269     void getMagnificationRegion(int displayId, Region outMagnificationRegion) {
270         if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
271             mAccessibilityTracing.logTrace(TAG + ".getMagnificationRegion",
272                     FLAGS_MAGNIFICATION_CALLBACK,
273                     "displayId=" + displayId + "; outMagnificationRegion={" + outMagnificationRegion
274                             + "}");
275         }
276         final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
277         if (displayMagnifier != null) {
278             displayMagnifier.getMagnificationRegion(outMagnificationRegion);
279         }
280     }
281 
onDisplaySizeChanged(DisplayContent displayContent)282     void onDisplaySizeChanged(DisplayContent displayContent) {
283 
284         if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK
285                 | FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK)) {
286             mAccessibilityTracing.logTrace(TAG + ".onRotationChanged",
287                     FLAGS_MAGNIFICATION_CALLBACK | FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK,
288                     "displayContent={" + displayContent + "}");
289         }
290         final int displayId = displayContent.getDisplayId();
291         final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
292         if (displayMagnifier != null) {
293             displayMagnifier.onDisplaySizeChanged(displayContent);
294         }
295     }
296 
onWMTransition(int displayId, @TransitionType int type, @TransitionFlags int flags)297     void onWMTransition(int displayId, @TransitionType int type, @TransitionFlags int flags) {
298         if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
299             mAccessibilityTracing.logTrace(TAG + ".onWMTransition",
300                     FLAGS_MAGNIFICATION_CALLBACK,
301                     "displayId=" + displayId + "; type=" + type + "; flags=" + flags);
302         }
303         final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
304         if (displayMagnifier != null) {
305             displayMagnifier.onWMTransition(displayId, type, flags);
306         }
307         // Not relevant for the window observer.
308     }
309 
onWindowTransition(WindowState windowState, int transition)310     void onWindowTransition(WindowState windowState, int transition) {
311         if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK
312                 | FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK)) {
313             mAccessibilityTracing.logTrace(TAG + ".onWindowTransition",
314                     FLAGS_MAGNIFICATION_CALLBACK | FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK,
315                     "windowState={" + windowState + "}; transition=" + transition);
316         }
317         final int displayId = windowState.getDisplayId();
318         final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
319         if (displayMagnifier != null) {
320             displayMagnifier.onWindowTransition(windowState, transition);
321         }
322     }
323 
onWindowFocusChangedNot(int displayId)324     void onWindowFocusChangedNot(int displayId) {
325         // Not relevant for the display magnifier.
326         if (mAccessibilityTracing.isTracingEnabled(FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK)) {
327             mAccessibilityTracing.logTrace(TAG + ".onWindowFocusChangedNot",
328                     FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK, "displayId=" + displayId);
329         }
330         WindowsForAccessibilityObserver observer = null;
331         synchronized (mService.mGlobalLock) {
332             final WindowsForAccessibilityObserver windowsForA11yObserver =
333                     mWindowsForAccessibilityObserver.get(displayId);
334             if (windowsForA11yObserver != null) {
335                 observer = windowsForA11yObserver;
336             }
337         }
338         if (observer != null) {
339             observer.performComputeChangedWindows(false);
340         }
341         // Since we abandon initializing observers if no window has focus, make sure all observers
342         // are initialized.
343         sendCallbackToUninitializedObserversIfNeeded();
344     }
345 
sendCallbackToUninitializedObserversIfNeeded()346     private void sendCallbackToUninitializedObserversIfNeeded() {
347         List<WindowsForAccessibilityObserver> unInitializedObservers;
348         synchronized (mService.mGlobalLock) {
349             if (mAllObserversInitialized) {
350                 return;
351             }
352             if (mService.mRoot.getTopFocusedDisplayContent().mCurrentFocus == null) {
353                 return;
354             }
355             unInitializedObservers = new ArrayList<>();
356             for (int i = mWindowsForAccessibilityObserver.size() - 1; i >= 0; --i) {
357                 final WindowsForAccessibilityObserver observer =
358                         mWindowsForAccessibilityObserver.valueAt(i);
359                 if (!observer.mInitialized) {
360                     unInitializedObservers.add(observer);
361                 }
362             }
363             // Reset the flag to record the new added observer.
364             mAllObserversInitialized = true;
365         }
366 
367         boolean areAllObserversInitialized = true;
368         for (int i = unInitializedObservers.size() - 1; i >= 0; --i) {
369             final  WindowsForAccessibilityObserver observer = unInitializedObservers.get(i);
370             observer.performComputeChangedWindows(true);
371             areAllObserversInitialized &= observer.mInitialized;
372         }
373         synchronized (mService.mGlobalLock) {
374             mAllObserversInitialized &= areAllObserversInitialized;
375         }
376     }
377 
378     /**
379      * Called when the location or the size of the window is changed. Moving the window to
380      * another display is also taken into consideration.
381      * @param displayIds the display ids of displays when the situation happens.
382      */
onSomeWindowResizedOrMoved(int... displayIds)383     void onSomeWindowResizedOrMoved(int... displayIds) {
384         onSomeWindowResizedOrMovedWithCallingUid(Binder.getCallingUid(), displayIds);
385     }
386 
onSomeWindowResizedOrMovedWithCallingUid(int callingUid, int... displayIds)387     void onSomeWindowResizedOrMovedWithCallingUid(int callingUid, int... displayIds) {
388         if (mAccessibilityTracing.isTracingEnabled(FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK)) {
389             mAccessibilityTracing.logTrace(TAG + ".onSomeWindowResizedOrMoved",
390                     FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK,
391                     "displayIds={" + Arrays.toString(displayIds) + "}", "".getBytes(), callingUid);
392         }
393         // Not relevant for the display magnifier.
394         for (int i = 0; i < displayIds.length; i++) {
395             final WindowsForAccessibilityObserver windowsForA11yObserver =
396                     mWindowsForAccessibilityObserver.get(displayIds[i]);
397             if (windowsForA11yObserver != null) {
398                 windowsForA11yObserver.scheduleComputeChangedWindows();
399             }
400         }
401     }
402 
recomputeMagnifiedRegionAndDrawMagnifiedRegionBorderIfNeeded(int displayId)403     void recomputeMagnifiedRegionAndDrawMagnifiedRegionBorderIfNeeded(int displayId) {
404         if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
405             mAccessibilityTracing.logTrace(
406                     TAG + ".recomputeMagnifiedRegionAndDrawMagnifiedRegionBorderIfNeeded",
407                     FLAGS_MAGNIFICATION_CALLBACK,
408                     "displayId=" + displayId);
409         }
410 
411         final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
412         if (displayMagnifier != null) {
413             displayMagnifier.recomputeMagnifiedRegionAndDrawMagnifiedRegionBorderIfNeeded();
414         }
415         // Not relevant for the window observer.
416     }
417 
getWindowTransformationMatrixAndMagnificationSpec( IBinder token)418     public Pair<Matrix, MagnificationSpec> getWindowTransformationMatrixAndMagnificationSpec(
419             IBinder token) {
420         synchronized (mService.mGlobalLock) {
421             final Matrix transformationMatrix = new Matrix();
422             final MagnificationSpec magnificationSpec = new MagnificationSpec();
423 
424             final WindowState windowState = mService.mWindowMap.get(token);
425             if (windowState != null) {
426                 windowState.getTransformationMatrix(new float[9], transformationMatrix);
427 
428                 if (hasCallbacks()) {
429                     final MagnificationSpec otherMagnificationSpec =
430                             getMagnificationSpecForWindow(windowState);
431                     if (otherMagnificationSpec != null && !otherMagnificationSpec.isNop()) {
432                         magnificationSpec.setTo(otherMagnificationSpec);
433                     }
434                 }
435             }
436 
437             return new Pair<>(transformationMatrix, magnificationSpec);
438         }
439     }
440 
getMagnificationSpecForWindow(WindowState windowState)441     MagnificationSpec getMagnificationSpecForWindow(WindowState windowState) {
442         if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
443             mAccessibilityTracing.logTrace(TAG + ".getMagnificationSpecForWindow",
444                     FLAGS_MAGNIFICATION_CALLBACK,
445                     "windowState={" + windowState + "}");
446         }
447         final int displayId = windowState.getDisplayId();
448         final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
449         if (displayMagnifier != null) {
450             return displayMagnifier.getMagnificationSpecForWindow(windowState);
451         }
452         return null;
453     }
454 
hasCallbacks()455     boolean hasCallbacks() {
456         if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK
457                 | FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK)) {
458             mAccessibilityTracing.logTrace(TAG + ".hasCallbacks",
459                     FLAGS_MAGNIFICATION_CALLBACK | FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK);
460         }
461         return (mDisplayMagnifiers.size() > 0
462                 || mWindowsForAccessibilityObserver.size() > 0);
463     }
464 
setFullscreenMagnificationActivated(int displayId, boolean activated)465     void setFullscreenMagnificationActivated(int displayId, boolean activated) {
466         if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
467             mAccessibilityTracing.logTrace(TAG + ".setFullscreenMagnificationActivated",
468                     FLAGS_MAGNIFICATION_CALLBACK,
469                     "displayId=" + displayId + "; activated=" + activated);
470         }
471         final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
472         if (displayMagnifier != null) {
473             displayMagnifier.setFullscreenMagnificationActivated(activated);
474         }
475     }
476 
updateImeVisibilityIfNeeded(int displayId, boolean shown)477     void updateImeVisibilityIfNeeded(int displayId, boolean shown) {
478         if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
479             mAccessibilityTracing.logTrace(TAG + ".updateImeVisibilityIfNeeded",
480                     FLAGS_MAGNIFICATION_CALLBACK, "displayId=" + displayId + ";shown=" + shown);
481         }
482 
483         final boolean isDisplayImeVisible = mIsImeVisibleArray.get(displayId, false);
484         if (isDisplayImeVisible == shown) {
485             return;
486         }
487 
488         mIsImeVisibleArray.put(displayId, shown);
489         final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
490         if (displayMagnifier != null) {
491             displayMagnifier.notifyImeWindowVisibilityChanged(shown);
492         }
493     }
494 
populateTransformationMatrix(WindowState windowState, Matrix outMatrix)495     private static void populateTransformationMatrix(WindowState windowState,
496             Matrix outMatrix) {
497         windowState.getTransformationMatrix(sTempFloats, outMatrix);
498     }
499 
dump(PrintWriter pw, String prefix)500     void dump(PrintWriter pw, String prefix) {
501         dumpSparseArrayValues(pw, prefix, mWindowsForAccessibilityObserver,
502                 "windows for accessibility observer");
503         mAccessibilityWindowsPopulator.dump(pw, prefix);
504     }
505 
onFocusChanged(InputTarget lastTarget, InputTarget newTarget)506     void onFocusChanged(InputTarget lastTarget, InputTarget newTarget) {
507         if (lastTarget != null) {
508             mFocusedWindow.remove(lastTarget.getDisplayId());
509             final DisplayMagnifier displayMagnifier =
510                     mDisplayMagnifiers.get(lastTarget.getDisplayId());
511             if (displayMagnifier != null) {
512                 displayMagnifier.onFocusLost(lastTarget);
513             }
514         }
515         if (newTarget != null) {
516             int displayId = newTarget.getDisplayId();
517             IBinder clientBinder = newTarget.getWindowToken();
518             mFocusedWindow.put(displayId, clientBinder);
519         }
520     }
521 
onDisplayRemoved(int displayId)522     public void onDisplayRemoved(int displayId) {
523         mIsImeVisibleArray.delete(displayId);
524         mFocusedWindow.remove(displayId);
525     }
526 
setFocusedDisplay(int focusedDisplayId)527     public void setFocusedDisplay(int focusedDisplayId) {
528         mFocusedDisplay = focusedDisplayId;
529     }
530 
getFocusedWindowToken()531     @Nullable IBinder getFocusedWindowToken() {
532         return mFocusedWindow.get(mFocusedDisplay);
533     }
534 
535     /**
536      * This class encapsulates the functionality related to display magnification.
537      */
538     private static final class DisplayMagnifier {
539 
540         private static final String LOG_TAG = TAG_WITH_CLASS_NAME ? "DisplayMagnifier" : TAG_WM;
541 
542         private static final boolean DEBUG_WINDOW_TRANSITIONS = false;
543         private static final boolean DEBUG_DISPLAY_SIZE = false;
544 
545         private final Rect mTempRect1 = new Rect();
546         private final Rect mTempRect2 = new Rect();
547 
548         private final Region mTempRegion1 = new Region();
549         private final Region mTempRegion2 = new Region();
550         private final Region mTempRegion3 = new Region();
551         private final Region mTempRegion4 = new Region();
552 
553         private final Context mDisplayContext;
554         private final WindowManagerService mService;
555         private final Handler mHandler;
556         private final DisplayContent mDisplayContent;
557         private final Display mDisplay;
558         private final AccessibilityControllerInternalImpl mAccessibilityTracing;
559 
560         private final MagnificationCallbacks mCallbacks;
561         private final UserContextChangedNotifier mUserContextChangedNotifier;
562 
563         private boolean mIsFullscreenMagnificationActivated = false;
564         private final Region mMagnificationRegion = new Region();
565         private final Region mOldMagnificationRegion = new Region();
566 
567         private final MagnificationSpec mMagnificationSpec = new MagnificationSpec();
568 
569         // Following fields are used for computing magnification region
570         private final Path mCircularPath;
571         private int mTempLayer = 0;
572         private final Point mScreenSize = new Point();
573         private final SparseArray<WindowState> mTempWindowStates =
574                 new SparseArray<WindowState>();
575         private final Matrix mTempMatrix = new Matrix();
576 
DisplayMagnifier(WindowManagerService windowManagerService, DisplayContent displayContent, Display display, MagnificationCallbacks callbacks)577         DisplayMagnifier(WindowManagerService windowManagerService,
578                 DisplayContent displayContent,
579                 Display display,
580                 MagnificationCallbacks callbacks) {
581             mDisplayContext = windowManagerService.mContext.createDisplayContext(display);
582             mService = windowManagerService;
583             mCallbacks = callbacks;
584             mDisplayContent = displayContent;
585             mDisplay = display;
586             mHandler = new MyHandler(mService.mH.getLooper());
587             mUserContextChangedNotifier = new UserContextChangedNotifier(mHandler);
588             mAccessibilityTracing =
589                     AccessibilityController.getAccessibilityControllerInternal(mService);
590             if (mDisplayContext.getResources().getConfiguration().isScreenRound()) {
591                 mCircularPath = new Path();
592 
593                 getDisplaySizeLocked(mScreenSize);
594                 final int centerXY = mScreenSize.x / 2;
595                 mCircularPath.addCircle(centerXY, centerXY, centerXY, Path.Direction.CW);
596             } else {
597                 mCircularPath = null;
598             }
599             if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
600                 mAccessibilityTracing.logTrace(LOG_TAG + ".DisplayMagnifier.constructor",
601                         FLAGS_MAGNIFICATION_CALLBACK,
602                         "windowManagerService={" + windowManagerService + "}; displayContent={"
603                                 + displayContent + "}; display={" + display + "}; callbacks={"
604                                 + callbacks + "}");
605             }
606             recomputeBounds();
607         }
608 
setMagnificationSpec(MagnificationSpec spec)609         void setMagnificationSpec(MagnificationSpec spec) {
610             if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
611                 mAccessibilityTracing.logTrace(LOG_TAG + ".setMagnificationSpec",
612                         FLAGS_MAGNIFICATION_CALLBACK, "spec={" + spec + "}");
613             }
614             updateMagnificationSpec(spec);
615             recomputeBounds();
616 
617             mService.applyMagnificationSpecLocked(mDisplay.getDisplayId(), spec);
618             mService.scheduleAnimationLocked();
619         }
620 
updateMagnificationSpec(MagnificationSpec spec)621         void updateMagnificationSpec(MagnificationSpec spec) {
622             if (spec != null) {
623                 mMagnificationSpec.initialize(spec.scale, spec.offsetX, spec.offsetY);
624             } else {
625                 mMagnificationSpec.clear();
626             }
627         }
628 
setFullscreenMagnificationActivated(boolean activated)629         void setFullscreenMagnificationActivated(boolean activated) {
630             if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
631                 mAccessibilityTracing.logTrace(LOG_TAG + ".setFullscreenMagnificationActivated",
632                         FLAGS_MAGNIFICATION_CALLBACK, "activated=" + activated);
633             }
634             mIsFullscreenMagnificationActivated = activated;
635         }
636 
isFullscreenMagnificationActivated()637         boolean isFullscreenMagnificationActivated() {
638             if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
639                 mAccessibilityTracing.logTrace(LOG_TAG + ".isFullscreenMagnificationActivated",
640                         FLAGS_MAGNIFICATION_CALLBACK);
641             }
642             return mIsFullscreenMagnificationActivated;
643         }
644 
onDisplaySizeChanged(DisplayContent displayContent)645         void onDisplaySizeChanged(DisplayContent displayContent) {
646             if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
647                 mAccessibilityTracing.logTrace(LOG_TAG + ".onDisplaySizeChanged",
648                         FLAGS_MAGNIFICATION_CALLBACK, "displayContent={" + displayContent + "}");
649             }
650             if (DEBUG_DISPLAY_SIZE) {
651                 final int rotation = displayContent.getRotation();
652                 Slog.i(LOG_TAG, "Rotation: " + Surface.rotationToString(rotation)
653                         + " displayId: " + displayContent.getDisplayId());
654             }
655 
656             recomputeBounds();
657             mHandler.sendEmptyMessage(MyHandler.MESSAGE_NOTIFY_DISPLAY_SIZE_CHANGED);
658         }
659 
onWMTransition(int displayId, @TransitionType int type, @TransitionFlags int flags)660         void onWMTransition(int displayId, @TransitionType int type, @TransitionFlags int flags) {
661             if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
662                 mAccessibilityTracing.logTrace(LOG_TAG + ".onWMTransition",
663                         FLAGS_MAGNIFICATION_CALLBACK,
664                         "displayId=" + displayId + "; type=" + type + "; flags=" + flags);
665             }
666             if (DEBUG_WINDOW_TRANSITIONS) {
667                 Slog.i(LOG_TAG, "Window transition: " + WindowManager.transitTypeToString(type)
668                         + " displayId: " + displayId);
669             }
670             final boolean isMagnifierActivated = isFullscreenMagnificationActivated();
671             if (!isMagnifierActivated) {
672                 return;
673             }
674             // All opening/closing/recents transitions
675             boolean notify = (flags & TRANSIT_FLAG_IS_RECENTS) != 0;
676             switch (type) {
677                 case WindowManager.TRANSIT_OPEN:
678                 case WindowManager.TRANSIT_TO_FRONT:
679                 case WindowManager.TRANSIT_CLOSE:
680                 case WindowManager.TRANSIT_TO_BACK:
681                     notify = true;
682             }
683             if (notify) {
684                 mUserContextChangedNotifier.onWMTransition(type, flags);
685             }
686         }
687 
onWindowTransition(WindowState windowState, int transition)688         void onWindowTransition(WindowState windowState, int transition) {
689             if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
690                 mAccessibilityTracing.logTrace(LOG_TAG + ".onWindowTransition",
691                         FLAGS_MAGNIFICATION_CALLBACK,
692                         "windowState={" + windowState + "}; transition=" + transition);
693             }
694             if (DEBUG_WINDOW_TRANSITIONS) {
695                 Slog.i(LOG_TAG, "Window transition: "
696                         + WindowManager.transitTypeToString(transition)
697                         + " displayId: " + windowState.getDisplayId());
698             }
699             final boolean isMagnifierActivated = isFullscreenMagnificationActivated();
700             if (!isMagnifierActivated || !windowState.shouldMagnify()) {
701                 return;
702             }
703             mUserContextChangedNotifier.onWindowTransition(windowState, transition);
704             final int type = windowState.mAttrs.type;
705             switch (transition) {
706                 case WindowManagerPolicy.TRANSIT_ENTER:
707                 case WindowManagerPolicy.TRANSIT_SHOW: {
708                     switch (type) {
709                         case WindowManager.LayoutParams.TYPE_APPLICATION:
710                         case WindowManager.LayoutParams.TYPE_DRAWN_APPLICATION:
711                         case WindowManager.LayoutParams.TYPE_APPLICATION_PANEL:
712                         case WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA:
713                         case WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL:
714                         case WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL:
715                         case WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG:
716                         case WindowManager.LayoutParams.TYPE_SEARCH_BAR:
717                         case WindowManager.LayoutParams.TYPE_PHONE:
718                         case WindowManager.LayoutParams.TYPE_SYSTEM_ALERT:
719                         case WindowManager.LayoutParams.TYPE_TOAST:
720                         case WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY:
721                         case WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY:
722                         case WindowManager.LayoutParams.TYPE_PRIORITY_PHONE:
723                         case WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG:
724                         case WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG:
725                         case WindowManager.LayoutParams.TYPE_SYSTEM_ERROR:
726                         case WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY:
727                         case WindowManager.LayoutParams.TYPE_QS_DIALOG:
728                         case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL: {
729                             Rect magnifiedRegionBounds = mTempRect2;
730                             getMagnifiedFrameInContentCoords(magnifiedRegionBounds);
731                             Rect touchableRegionBounds = mTempRect1;
732                             windowState.getTouchableRegion(mTempRegion1);
733                             mTempRegion1.getBounds(touchableRegionBounds);
734                             if (!magnifiedRegionBounds.intersect(touchableRegionBounds)) {
735                                 mCallbacks.onRectangleOnScreenRequested(
736                                         touchableRegionBounds.left,
737                                         touchableRegionBounds.top,
738                                         touchableRegionBounds.right,
739                                         touchableRegionBounds.bottom);
740                             }
741                         } break;
742                     } break;
743                 }
744             }
745         }
746 
onFocusLost(InputTarget target)747         void onFocusLost(InputTarget target) {
748             final boolean isMagnifierActivated = isFullscreenMagnificationActivated();
749             if (!isMagnifierActivated) {
750                 return;
751             }
752             mUserContextChangedNotifier.onFocusLost(target);
753         }
754 
getMagnifiedFrameInContentCoords(Rect rect)755         void getMagnifiedFrameInContentCoords(Rect rect) {
756             mMagnificationRegion.getBounds(rect);
757             rect.offset((int) -mMagnificationSpec.offsetX, (int) -mMagnificationSpec.offsetY);
758             rect.scale(1.0f / mMagnificationSpec.scale);
759         }
760 
notifyImeWindowVisibilityChanged(boolean shown)761         void notifyImeWindowVisibilityChanged(boolean shown) {
762             if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
763                 mAccessibilityTracing.logTrace(LOG_TAG + ".notifyImeWindowVisibilityChanged",
764                         FLAGS_MAGNIFICATION_CALLBACK, "shown=" + shown);
765             }
766             mHandler.obtainMessage(MyHandler.MESSAGE_NOTIFY_IME_WINDOW_VISIBILITY_CHANGED,
767                     shown ? 1 : 0, 0).sendToTarget();
768         }
769 
getMagnificationSpecForWindow(WindowState windowState)770         MagnificationSpec getMagnificationSpecForWindow(WindowState windowState) {
771             if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
772                 mAccessibilityTracing.logTrace(LOG_TAG + ".getMagnificationSpecForWindow",
773                         FLAGS_MAGNIFICATION_CALLBACK, "windowState={" + windowState + "}");
774             }
775 
776             if (mMagnificationSpec != null && !mMagnificationSpec.isNop()) {
777                 if (!windowState.shouldMagnify()) {
778                     return null;
779                 }
780             }
781             return mMagnificationSpec;
782         }
783 
getMagnificationRegion(Region outMagnificationRegion)784         void getMagnificationRegion(Region outMagnificationRegion) {
785             if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
786                 mAccessibilityTracing.logTrace(LOG_TAG + ".getMagnificationRegion",
787                         FLAGS_MAGNIFICATION_CALLBACK,
788                         "outMagnificationRegion={" + outMagnificationRegion + "}");
789             }
790             // Make sure we're working with the most current bounds
791             recomputeBounds();
792             outMagnificationRegion.set(mMagnificationRegion);
793         }
794 
destroy()795         void destroy() {
796             if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
797                 mAccessibilityTracing.logTrace(LOG_TAG + ".destroy", FLAGS_MAGNIFICATION_CALLBACK);
798             }
799         }
800 
recomputeMagnifiedRegionAndDrawMagnifiedRegionBorderIfNeeded()801         void recomputeMagnifiedRegionAndDrawMagnifiedRegionBorderIfNeeded() {
802             if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
803                 mAccessibilityTracing.logTrace(LOG_TAG
804                                 + ".recomputeMagnifiedRegionAndDrawMagnifiedRegionBorderIfNeeded",
805                         FLAGS_MAGNIFICATION_CALLBACK);
806             }
807             recomputeBounds();
808         }
809 
recomputeBounds()810         void recomputeBounds() {
811             getDisplaySizeLocked(mScreenSize);
812             final int screenWidth = mScreenSize.x;
813             final int screenHeight = mScreenSize.y;
814 
815             mMagnificationRegion.set(0, 0, 0, 0);
816             final Region availableBounds = mTempRegion1;
817             availableBounds.set(0, 0, screenWidth, screenHeight);
818 
819             if (mCircularPath != null) {
820                 availableBounds.setPath(mCircularPath, availableBounds);
821             }
822 
823             Region nonMagnifiedBounds = mTempRegion4;
824             nonMagnifiedBounds.set(0, 0, 0, 0);
825 
826             SparseArray<WindowState> visibleWindows = mTempWindowStates;
827             visibleWindows.clear();
828             populateWindowsOnScreen(visibleWindows);
829 
830             final int visibleWindowCount = visibleWindows.size();
831             for (int i = visibleWindowCount - 1; i >= 0; i--) {
832                 WindowState windowState = visibleWindows.valueAt(i);
833                 final int windowType = windowState.mAttrs.type;
834                 if (isExcludedWindowType(windowType)
835                         || ((windowState.mAttrs.privateFlags
836                         & PRIVATE_FLAG_EXCLUDE_FROM_SCREEN_MAGNIFICATION) != 0)
837                         || ((windowState.mAttrs.privateFlags
838                         & PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY) != 0)) {
839                     continue;
840                 }
841 
842                 // Consider the touchable portion of the window
843                 Matrix matrix = mTempMatrix;
844                 populateTransformationMatrix(windowState, matrix);
845                 Region touchableRegion = mTempRegion3;
846                 windowState.getTouchableRegion(touchableRegion);
847                 Region windowBounds = mTempRegion2;
848 
849                 // For b/323366243, if using the bounds from touchableRegion.getBounds, in
850                 // non-magnifiable windowBounds computation, part of the non-touchableRegion
851                 // may be included into nonMagnifiedBounds. This will make users lose
852                 // the magnification control on mis-included areas.
853                 // Therefore, to prevent the above issue, we change to use the window exact
854                 // touchableRegion in magnificationRegion computation.
855                 // Like the original approach, the touchableRegion is in non-magnified display
856                 // space, so first we need to offset the region by the windowFrames bounds, then
857                 // apply the transform matrix to the region to get the exact region in magnified
858                 // display space.
859                 // TODO: For a long-term plan, since touchable regions provided by WindowState
860                 //  doesn't actually reflect the real touchable regions on display, we should
861                 //  delete the WindowState dependency and migrate to use the touchableRegion
862                 //  from WindowInfoListener data. (b/330653961)
863                 touchableRegion.translate(-windowState.getFrame().left,
864                         -windowState.getFrame().top);
865                 applyMatrixToRegion(matrix, touchableRegion);
866                 windowBounds.set(touchableRegion);
867 
868                 // Only update new regions
869                 Region portionOfWindowAlreadyAccountedFor = mTempRegion3;
870                 portionOfWindowAlreadyAccountedFor.set(mMagnificationRegion);
871                 portionOfWindowAlreadyAccountedFor.op(nonMagnifiedBounds, Region.Op.UNION);
872                 windowBounds.op(portionOfWindowAlreadyAccountedFor, Region.Op.DIFFERENCE);
873 
874                 if (windowState.shouldMagnify()) {
875                     mMagnificationRegion.op(windowBounds, Region.Op.UNION);
876                     mMagnificationRegion.op(availableBounds, Region.Op.INTERSECT);
877                 } else {
878                     nonMagnifiedBounds.op(windowBounds, Region.Op.UNION);
879                     availableBounds.op(windowBounds, Region.Op.DIFFERENCE);
880                 }
881 
882                 // If the navigation bar window doesn't have touchable region, count
883                 // navigation bar insets into nonMagnifiedBounds. It happens when
884                 // navigation mode is gestural.
885                 if (isUntouchableNavigationBar(windowState, mTempRegion3)) {
886                     final Rect navBarInsets = getSystemBarInsetsFrame(windowState);
887                     nonMagnifiedBounds.op(navBarInsets, Region.Op.UNION);
888                     availableBounds.op(navBarInsets, Region.Op.DIFFERENCE);
889                 }
890 
891                 // Count letterbox into nonMagnifiedBounds
892                 if (windowState.areAppWindowBoundsLetterboxed()) {
893                     Region letterboxBounds = getLetterboxBounds(windowState);
894                     nonMagnifiedBounds.op(letterboxBounds, Region.Op.UNION);
895                     availableBounds.op(letterboxBounds, Region.Op.DIFFERENCE);
896                 }
897 
898                 // Update accounted bounds
899                 Region accountedBounds = mTempRegion2;
900                 accountedBounds.set(mMagnificationRegion);
901                 accountedBounds.op(nonMagnifiedBounds, Region.Op.UNION);
902                 accountedBounds.op(0, 0, screenWidth, screenHeight, Region.Op.INTERSECT);
903 
904                 if (accountedBounds.isRect()) {
905                     Rect accountedFrame = mTempRect1;
906                     accountedBounds.getBounds(accountedFrame);
907                     if (accountedFrame.width() == screenWidth
908                             && accountedFrame.height() == screenHeight) {
909                         break;
910                     }
911                 }
912             }
913             visibleWindows.clear();
914 
915             final boolean magnifiedChanged =
916                     !mOldMagnificationRegion.equals(mMagnificationRegion);
917             if (magnifiedChanged) {
918                 mOldMagnificationRegion.set(mMagnificationRegion);
919                 final SomeArgs args = SomeArgs.obtain();
920                 args.arg1 = Region.obtain(mMagnificationRegion);
921                 mHandler.obtainMessage(
922                                 MyHandler.MESSAGE_NOTIFY_MAGNIFICATION_REGION_CHANGED, args)
923                         .sendToTarget();
924             }
925         }
926 
getLetterboxBounds(WindowState windowState)927         private Region getLetterboxBounds(WindowState windowState) {
928             final ActivityRecord appToken = windowState.mActivityRecord;
929             if (appToken == null) {
930                 return new Region();
931             }
932 
933             final Rect boundsWithoutLetterbox = windowState.getBounds();
934             final Rect letterboxInsets = appToken.getLetterboxInsets();
935 
936             final Rect boundsIncludingLetterbox = Rect.copyOrNull(boundsWithoutLetterbox);
937             // Letterbox insets from mActivityRecord are positive, so we negate them to grow the
938             // bounds to include the letterbox.
939             boundsIncludingLetterbox.inset(
940                     Insets.subtract(Insets.NONE, Insets.of(letterboxInsets)));
941 
942             final Region letterboxBounds = new Region();
943             letterboxBounds.set(boundsIncludingLetterbox);
944             letterboxBounds.op(boundsWithoutLetterbox, Region.Op.DIFFERENCE);
945             return letterboxBounds;
946         }
947 
isExcludedWindowType(int windowType)948         private boolean isExcludedWindowType(int windowType) {
949             return windowType == TYPE_MAGNIFICATION_OVERLAY
950                     // Omit the touch region of window magnification to avoid the cut out of the
951                     // magnification and the magnified center of window magnification could be
952                     // in the bounds
953                     || windowType == TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY;
954         }
955 
applyMatrixToRegion(Matrix matrix, Region region)956         private void applyMatrixToRegion(Matrix matrix, Region region) {
957             // Since Matrix does not support mapRegion api, so we follow the Matrix#mapRect logic
958             // to apply the matrix to the given region.
959             // In Matrix#mapRect, the internal calculation is applying the transform matrix to
960             // rect's 4 corner points with the below calculation. (see SkMatrix::mapPoints)
961             //      |A B C| |x|                               Ax+By+C   Dx+Ey+F
962             //      |D E F| |y| = |Ax+By+C Dx+Ey+F Gx+Hy+I| = ------- , -------
963             //      |G H I| |1|                               Gx+Hy+I   Gx+Hy+I
964             // For magnification usage, the matrix is created from
965             // WindowState#getTransformationMatrix. We can simplify the matrix calculation to be
966             //      |scale   0   trans_x| |x|
967             //      |  0   scale trans_y| |y| = (scale*x + trans_x, scale*y + trans_y)
968             //      |  0     0      1   | |1|
969             // So, to follow the simplified matrix computation, we first scale the region with
970             // matrix.scale, then translate the region with matrix.trans_x and matrix.trans_y.
971             float[] transformArray = sTempFloats;
972             matrix.getValues(transformArray);
973             // For magnification transform matrix, the scale_x and scale_y are equal.
974             region.scale(transformArray[Matrix.MSCALE_X]);
975             region.translate(
976                     (int) transformArray[Matrix.MTRANS_X],
977                     (int) transformArray[Matrix.MTRANS_Y]);
978         }
979 
populateWindowsOnScreen(SparseArray<WindowState> outWindows)980         private void populateWindowsOnScreen(SparseArray<WindowState> outWindows) {
981             mTempLayer = 0;
982             mDisplayContent.forAllWindows((w) -> {
983                 if (w.isOnScreen() && w.isVisible()
984                         && (w.mAttrs.alpha != 0)) {
985                     mTempLayer++;
986                     outWindows.put(mTempLayer, w);
987                 }
988             }, /* traverseTopToBottom= */ false);
989         }
990 
getDisplaySizeLocked(Point outSize)991         private void getDisplaySizeLocked(Point outSize) {
992             final Rect bounds =
993                     mDisplayContent.getConfiguration().windowConfiguration.getBounds();
994             outSize.set(bounds.width(), bounds.height());
995         }
996 
997         private class MyHandler extends Handler {
998             public static final int MESSAGE_NOTIFY_MAGNIFICATION_REGION_CHANGED = 1;
999             public static final int MESSAGE_NOTIFY_USER_CONTEXT_CHANGED = 3;
1000             public static final int MESSAGE_NOTIFY_DISPLAY_SIZE_CHANGED = 4;
1001             public static final int MESSAGE_NOTIFY_IME_WINDOW_VISIBILITY_CHANGED = 5;
1002 
MyHandler(Looper looper)1003             MyHandler(Looper looper) {
1004                 super(looper);
1005             }
1006 
1007             @Override
handleMessage(Message message)1008             public void handleMessage(Message message) {
1009                 switch (message.what) {
1010                     case MESSAGE_NOTIFY_MAGNIFICATION_REGION_CHANGED: {
1011                         final SomeArgs args = (SomeArgs) message.obj;
1012                         final Region magnifiedBounds = (Region) args.arg1;
1013                         mCallbacks.onMagnificationRegionChanged(magnifiedBounds);
1014                         magnifiedBounds.recycle();
1015                     } break;
1016 
1017                     case MESSAGE_NOTIFY_USER_CONTEXT_CHANGED: {
1018                         mCallbacks.onUserContextChanged();
1019                     } break;
1020 
1021                     case MESSAGE_NOTIFY_DISPLAY_SIZE_CHANGED: {
1022                         mCallbacks.onDisplaySizeChanged();
1023                     } break;
1024 
1025                     case MESSAGE_NOTIFY_IME_WINDOW_VISIBILITY_CHANGED: {
1026                         final boolean shown = message.arg1 == 1;
1027                         mCallbacks.onImeWindowVisibilityChanged(shown);
1028                     } break;
1029                 }
1030             }
1031         }
1032 
1033         private class UserContextChangedNotifier {
1034 
1035             private final Handler mHandler;
1036 
1037             private boolean mHasDelayedNotificationForRecentsToFrontTransition;
1038 
UserContextChangedNotifier(Handler handler)1039             UserContextChangedNotifier(Handler handler) {
1040                 mHandler = handler;
1041             }
1042 
onAppWindowTransition(int transition)1043             void onAppWindowTransition(int transition) {
1044                 sendUserContextChangedNotification();
1045             }
1046 
1047             // For b/324949652, if the onWMTransition callback is triggered when the finger down
1048             // event on navigation bar to bring the recents window to front, we'll delay the
1049             // notifying of the context changed, then send it if there is a following onFocusChanged
1050             // callback triggered. Before the onFocusChanged, if there are some other transitions
1051             // causing the notifying, or the recents/home window is removed, then we won't need the
1052             // delayed notification anymore.
onWMTransition(@ransitionType int type, @TransitionFlags int flags)1053             void onWMTransition(@TransitionType int type, @TransitionFlags int flags) {
1054                 if ((flags & TRANSIT_FLAG_IS_RECENTS) != 0) {
1055                     // Delay the recents to front transition notification then send after if needed.
1056                     mHasDelayedNotificationForRecentsToFrontTransition = true;
1057                 } else {
1058                     sendUserContextChangedNotification();
1059                 }
1060             }
1061 
onWindowTransition(WindowState windowState, int transition)1062             void onWindowTransition(WindowState windowState, int transition) {
1063                 // If there is a delayed notification for recents to front transition but the
1064                 // home/recents window has been removed from screen, the delayed notification is not
1065                 // needed anymore.
1066                 if (transition == WindowManagerPolicy.TRANSIT_EXIT
1067                         && windowState.isActivityTypeHomeOrRecents()
1068                         && mHasDelayedNotificationForRecentsToFrontTransition) {
1069                     mHasDelayedNotificationForRecentsToFrontTransition = false;
1070                 }
1071             }
1072 
onFocusLost(InputTarget target)1073             void onFocusLost(InputTarget target) {
1074                 // If there is a delayed notification for recents to front transition and
1075                 // onFocusLost is triggered, we assume that the users leave current window to
1076                 // the home/recents window, thus we'll need to send the delayed notification.
1077                 if (mHasDelayedNotificationForRecentsToFrontTransition) {
1078                     sendUserContextChangedNotification();
1079                 }
1080             }
1081 
sendUserContextChangedNotification()1082             private void sendUserContextChangedNotification() {
1083                 // Since the context changed will be notified, the delayed notification is
1084                 // not needed anymore.
1085                 mHasDelayedNotificationForRecentsToFrontTransition = false;
1086                 mHandler.sendEmptyMessage(MyHandler.MESSAGE_NOTIFY_USER_CONTEXT_CHANGED);
1087             }
1088         }
1089     }
1090 
isUntouchableNavigationBar(WindowState windowState, Region touchableRegion)1091     static boolean isUntouchableNavigationBar(WindowState windowState,
1092             Region touchableRegion) {
1093         if (windowState.mAttrs.type != WindowManager.LayoutParams.TYPE_NAVIGATION_BAR) {
1094             return false;
1095         }
1096 
1097         // Gets the touchable region.
1098         windowState.getTouchableRegion(touchableRegion);
1099 
1100         return touchableRegion.isEmpty();
1101     }
1102 
getSystemBarInsetsFrame(WindowState win)1103     static Rect getSystemBarInsetsFrame(WindowState win) {
1104         if (win == null) {
1105             return EMPTY_RECT;
1106         }
1107         final InsetsSourceProvider provider = win.getControllableInsetProvider();
1108         return provider != null ? provider.getSource().getFrame() : EMPTY_RECT;
1109     }
1110 
1111     /**
1112      * This class encapsulates the functionality related to computing the windows
1113      * reported for accessibility purposes. These windows are all windows a sighted
1114      * user can see on the screen.
1115      */
1116     private static final class WindowsForAccessibilityObserver {
1117         private static final String LOG_TAG = TAG_WITH_CLASS_NAME ?
1118                 "WindowsForAccessibilityObserver" : TAG_WM;
1119 
1120         private static final boolean DEBUG = false;
1121 
1122         private final WindowManagerService mService;
1123 
1124         private final Handler mHandler;
1125 
1126         private final AccessibilityControllerInternalImpl mAccessibilityTracing;
1127 
1128         private final WindowsForAccessibilityCallback mCallback;
1129 
1130         private final int mDisplayId;
1131 
1132         private final long mRecurringAccessibilityEventsIntervalMillis;
1133 
1134         // Set to true if initializing window population complete.
1135         private boolean mInitialized;
1136         private final AccessibilityWindowsPopulator mA11yWindowsPopulator;
1137 
WindowsForAccessibilityObserver(WindowManagerService windowManagerService, int displayId, WindowsForAccessibilityCallback callback, AccessibilityWindowsPopulator accessibilityWindowsPopulator)1138         WindowsForAccessibilityObserver(WindowManagerService windowManagerService,
1139                 int displayId, WindowsForAccessibilityCallback callback,
1140                 AccessibilityWindowsPopulator accessibilityWindowsPopulator) {
1141             mService = windowManagerService;
1142             mCallback = callback;
1143             mDisplayId = displayId;
1144             mHandler = new MyHandler(mService.mH.getLooper());
1145             mAccessibilityTracing =
1146                     AccessibilityController.getAccessibilityControllerInternal(mService);
1147             mRecurringAccessibilityEventsIntervalMillis = ViewConfiguration
1148                     .getSendRecurringAccessibilityEventsInterval();
1149             mA11yWindowsPopulator = accessibilityWindowsPopulator;
1150             computeChangedWindows(true);
1151         }
1152 
performComputeChangedWindows(boolean forceSend)1153         void performComputeChangedWindows(boolean forceSend) {
1154             if (mAccessibilityTracing.isTracingEnabled(FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK)) {
1155                 mAccessibilityTracing.logTrace(LOG_TAG + ".performComputeChangedWindows",
1156                         FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK, "forceSend=" + forceSend);
1157             }
1158             mHandler.removeMessages(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS);
1159             computeChangedWindows(forceSend);
1160         }
1161 
scheduleComputeChangedWindows()1162         void scheduleComputeChangedWindows() {
1163             if (mAccessibilityTracing.isTracingEnabled(FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK)) {
1164                 mAccessibilityTracing.logTrace(LOG_TAG + ".scheduleComputeChangedWindows",
1165                         FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK);
1166             }
1167             if (!mHandler.hasMessages(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS)) {
1168                 mHandler.sendEmptyMessageDelayed(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS,
1169                         mRecurringAccessibilityEventsIntervalMillis);
1170             }
1171         }
1172 
1173         /**
1174          * Check if windows have changed, and send them to the accessibility subsystem if they have.
1175          *
1176          * @param forceSend Send the windows the accessibility even if they haven't changed.
1177          */
computeChangedWindows(boolean forceSend)1178         void computeChangedWindows(boolean forceSend) {
1179             if (mAccessibilityTracing.isTracingEnabled(FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK)) {
1180                 mAccessibilityTracing.logTrace(LOG_TAG + ".computeChangedWindows",
1181                         FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK, "forceSend=" + forceSend);
1182             }
1183             if (DEBUG) {
1184                 Slog.i(LOG_TAG, "computeChangedWindows()");
1185             }
1186 
1187             final List<AccessibilityWindow> visibleWindows = new ArrayList<>();
1188             final Point screenSize = new Point();
1189             final int topFocusedDisplayId;
1190             final IBinder topFocusedWindowToken;
1191 
1192             synchronized (mService.mGlobalLock) {
1193                 final WindowState topFocusedWindowState = getTopFocusWindow();
1194                 if (topFocusedWindowState == null) {
1195                     if (DEBUG) {
1196                         Slog.d(LOG_TAG, "top focused window is null, compute it again later");
1197                     }
1198                     return;
1199                 }
1200 
1201                 final DisplayContent dc = mService.mRoot.getDisplayContent(mDisplayId);
1202                 if (dc == null) {
1203                     //It should not happen because it is created while adding the callback.
1204                     Slog.w(LOG_TAG, "display content is null, should be created later");
1205                     return;
1206                 }
1207                 final Display display = dc.getDisplay();
1208                 display.getRealSize(screenSize);
1209 
1210                 mA11yWindowsPopulator.populateVisibleWindowsOnScreenLocked(
1211                         mDisplayId, visibleWindows);
1212 
1213                 // Gets the top focused display Id and window token for supporting multi-display.
1214                 topFocusedDisplayId = mService.mRoot.getTopFocusedDisplayContent().getDisplayId();
1215                 topFocusedWindowToken = topFocusedWindowState.mClient.asBinder();
1216             }
1217 
1218             mCallback.onAccessibilityWindowsChanged(forceSend, topFocusedDisplayId,
1219                     topFocusedWindowToken, screenSize, visibleWindows);
1220 
1221             // Recycle the windows as we do not need them.
1222             for (final AccessibilityWindowsPopulator.AccessibilityWindow window : visibleWindows) {
1223                 window.getWindowInfo().recycle();
1224             }
1225             mInitialized = true;
1226         }
1227 
getTopFocusWindow()1228         private WindowState getTopFocusWindow() {
1229             return mService.mRoot.getTopFocusedDisplayContent().mCurrentFocus;
1230         }
1231 
1232         @Override
toString()1233         public String toString() {
1234             return "WindowsForAccessibilityObserver{"
1235                     + "mDisplayId=" + mDisplayId
1236                     + ", mInitialized=" + mInitialized
1237                     + '}';
1238         }
1239 
1240         private class MyHandler extends Handler {
1241             public static final int MESSAGE_COMPUTE_CHANGED_WINDOWS = 1;
1242 
MyHandler(Looper looper)1243             public MyHandler(Looper looper) {
1244                 super(looper, null, false);
1245             }
1246 
1247             @Override
1248             @SuppressWarnings("unchecked")
handleMessage(Message message)1249             public void handleMessage(Message message) {
1250                 switch (message.what) {
1251                     case MESSAGE_COMPUTE_CHANGED_WINDOWS: {
1252                         computeChangedWindows(false);
1253                     } break;
1254                 }
1255             }
1256         }
1257     }
1258 
1259     static final class AccessibilityControllerInternalImpl
1260             implements AccessibilityControllerInternal {
1261 
1262         private static AccessibilityControllerInternalImpl sInstance;
getInstance(WindowManagerService service)1263         static AccessibilityControllerInternalImpl getInstance(WindowManagerService service) {
1264             synchronized (STATIC_LOCK) {
1265                 if (sInstance == null) {
1266                     sInstance = new AccessibilityControllerInternalImpl(service);
1267                 }
1268                 return sInstance;
1269             }
1270         }
1271 
1272         private final AccessibilityTracing mTracing;
1273         private volatile long mEnabledTracingFlags;
1274         private UiChangesForAccessibilityCallbacksDispatcher mCallbacksDispatcher;
1275         private final Looper mLooper;
1276 
AccessibilityControllerInternalImpl(WindowManagerService service)1277         private AccessibilityControllerInternalImpl(WindowManagerService service) {
1278             mLooper = service.mH.getLooper();
1279             mTracing = AccessibilityTracing.getInstance(service);
1280             mEnabledTracingFlags = 0L;
1281         }
1282 
1283         @Override
startTrace(long loggingTypes)1284         public void startTrace(long loggingTypes) {
1285             mEnabledTracingFlags = loggingTypes;
1286             mTracing.startTrace();
1287         }
1288 
1289         @Override
stopTrace()1290         public void stopTrace() {
1291             mTracing.stopTrace();
1292             mEnabledTracingFlags = 0L;
1293         }
1294 
1295         @Override
isAccessibilityTracingEnabled()1296         public boolean isAccessibilityTracingEnabled() {
1297             return mTracing.isEnabled();
1298         }
1299 
isTracingEnabled(long flags)1300         boolean isTracingEnabled(long flags) {
1301             return (flags & mEnabledTracingFlags) != 0L;
1302         }
1303 
logTrace(String where, long loggingTypes)1304         void logTrace(String where, long loggingTypes) {
1305             logTrace(where, loggingTypes, "");
1306         }
1307 
logTrace(String where, long loggingTypes, String callingParams)1308         void logTrace(String where, long loggingTypes, String callingParams) {
1309             logTrace(where, loggingTypes, callingParams, "".getBytes(), Binder.getCallingUid());
1310         }
1311 
logTrace(String where, long loggingTypes, String callingParams, byte[] a11yDump, int callingUid)1312         void logTrace(String where, long loggingTypes, String callingParams, byte[] a11yDump,
1313                 int callingUid) {
1314             mTracing.logState(where, loggingTypes, callingParams, a11yDump, callingUid,
1315                     new HashSet<String>(Arrays.asList("logTrace")));
1316         }
1317 
1318         @Override
logTrace(String where, long loggingTypes, String callingParams, byte[] a11yDump, int callingUid, StackTraceElement[] stackTrace, Set<String> ignoreStackEntries)1319         public void logTrace(String where, long loggingTypes, String callingParams, byte[] a11yDump,
1320                 int callingUid, StackTraceElement[] stackTrace, Set<String> ignoreStackEntries) {
1321             mTracing.logState(where, loggingTypes, callingParams, a11yDump, callingUid, stackTrace,
1322                     ignoreStackEntries);
1323         }
1324 
1325         @Override
logTrace(String where, long loggingTypes, String callingParams, byte[] a11yDump, int callingUid, StackTraceElement[] callStack, long timeStamp, int processId, long threadId, Set<String> ignoreStackEntries)1326         public void logTrace(String where, long loggingTypes, String callingParams, byte[] a11yDump,
1327                 int callingUid, StackTraceElement[] callStack, long timeStamp, int processId,
1328                 long threadId, Set<String> ignoreStackEntries) {
1329             mTracing.logState(where, loggingTypes, callingParams, a11yDump, callingUid, callStack,
1330                     timeStamp, processId, threadId, ignoreStackEntries);
1331         }
1332 
1333         @Override
setUiChangesForAccessibilityCallbacks( UiChangesForAccessibilityCallbacks callbacks)1334         public void setUiChangesForAccessibilityCallbacks(
1335                 UiChangesForAccessibilityCallbacks callbacks) {
1336             if (isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
1337                 logTrace(
1338                         TAG + ".setAccessibilityWindowManagerCallbacks",
1339                         FLAGS_MAGNIFICATION_CALLBACK,
1340                         "callbacks={" + callbacks + "}");
1341             }
1342             if (callbacks != null) {
1343                 if (mCallbacksDispatcher != null) {
1344                     throw new IllegalStateException("Accessibility window manager callback already "
1345                             + "set!");
1346                 }
1347                 mCallbacksDispatcher =
1348                         new UiChangesForAccessibilityCallbacksDispatcher(this, mLooper,
1349                                 callbacks);
1350             } else {
1351                 if (mCallbacksDispatcher == null) {
1352                     throw new IllegalStateException("Accessibility window manager callback already "
1353                             + "cleared!");
1354                 }
1355                 mCallbacksDispatcher = null;
1356             }
1357         }
1358 
hasWindowManagerEventDispatcher()1359         public boolean hasWindowManagerEventDispatcher() {
1360             if (isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK
1361                     | FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK)) {
1362                 logTrace(TAG + ".hasCallbacks",
1363                         FLAGS_MAGNIFICATION_CALLBACK | FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK);
1364             }
1365             return mCallbacksDispatcher != null;
1366         }
1367 
onRectangleOnScreenRequested(int displayId, Rect rectangle)1368         public void onRectangleOnScreenRequested(int displayId, Rect rectangle) {
1369             if (isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
1370                 logTrace(
1371                         TAG + ".onRectangleOnScreenRequested",
1372                         FLAGS_MAGNIFICATION_CALLBACK,
1373                         "rectangle={" + rectangle + "}");
1374             }
1375             if (mCallbacksDispatcher != null) {
1376                 mCallbacksDispatcher.onRectangleOnScreenRequested(displayId, rectangle);
1377             }
1378         }
1379 
1380         private static final class UiChangesForAccessibilityCallbacksDispatcher {
1381 
1382             private static final String LOG_TAG = TAG_WITH_CLASS_NAME
1383                     ? "WindowManagerEventDispatcher" : TAG_WM;
1384 
1385             private static final boolean DEBUG_RECTANGLE_REQUESTED = false;
1386 
1387             private final AccessibilityControllerInternalImpl mAccessibilityTracing;
1388 
1389             @NonNull
1390             private final UiChangesForAccessibilityCallbacks mCallbacks;
1391 
1392             private final Handler mHandler;
1393 
UiChangesForAccessibilityCallbacksDispatcher( AccessibilityControllerInternalImpl accessibilityControllerInternal, Looper looper, @NonNull UiChangesForAccessibilityCallbacks callbacks)1394             UiChangesForAccessibilityCallbacksDispatcher(
1395                     AccessibilityControllerInternalImpl accessibilityControllerInternal,
1396                     Looper looper, @NonNull UiChangesForAccessibilityCallbacks callbacks) {
1397                 mAccessibilityTracing = accessibilityControllerInternal;
1398                 mCallbacks = callbacks;
1399                 mHandler = new Handler(looper);
1400             }
1401 
onRectangleOnScreenRequested(int displayId, Rect rectangle)1402             void onRectangleOnScreenRequested(int displayId, Rect rectangle) {
1403                 if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
1404                     mAccessibilityTracing.logTrace(LOG_TAG + ".onRectangleOnScreenRequested",
1405                             FLAGS_MAGNIFICATION_CALLBACK, "rectangle={" + rectangle + "}");
1406                 }
1407                 if (DEBUG_RECTANGLE_REQUESTED) {
1408                     Slog.i(LOG_TAG, "Rectangle on screen requested: " + rectangle);
1409                 }
1410                 final Message m = PooledLambda.obtainMessage(
1411                         mCallbacks::onRectangleOnScreenRequested, displayId, rectangle.left,
1412                         rectangle.top, rectangle.right, rectangle.bottom);
1413                 mHandler.sendMessage(m);
1414             }
1415         }
1416     }
1417 
1418     private static final class AccessibilityTracing {
1419         private static AccessibilityTracing sInstance;
getInstance(WindowManagerService service)1420         static AccessibilityTracing getInstance(WindowManagerService service) {
1421             synchronized (STATIC_LOCK) {
1422                 if (sInstance == null) {
1423                     sInstance = new AccessibilityTracing(service);
1424                 }
1425                 return sInstance;
1426             }
1427         }
1428 
1429         private static final int CPU_STATS_COUNT = 5;
1430         private static final int BUFFER_CAPACITY = 1024 * 1024 * 12;
1431         private static final String TRACE_FILENAME = "/data/misc/a11ytrace/a11y_trace"
1432                 + WINSCOPE_EXT;
1433         private static final String TAG = "AccessibilityTracing";
1434         private static final long MAGIC_NUMBER_VALUE =
1435                 ((long) MAGIC_NUMBER_H << 32) | MAGIC_NUMBER_L;
1436 
1437         private final Object mLock = new Object();
1438         private final WindowManagerService mService;
1439         private final File mTraceFile;
1440         private final TraceBuffer mBuffer;
1441         private final LogHandler mHandler;
1442         private volatile boolean mEnabled;
1443 
AccessibilityTracing(WindowManagerService service)1444         AccessibilityTracing(WindowManagerService service) {
1445             mService = service;
1446             mTraceFile = new File(TRACE_FILENAME);
1447             mBuffer = new TraceBuffer(BUFFER_CAPACITY);
1448             HandlerThread workThread = new HandlerThread(TAG);
1449             workThread.start();
1450             mHandler = new LogHandler(workThread.getLooper());
1451         }
1452 
1453         /**
1454          * Start the trace.
1455          */
startTrace()1456         void startTrace() {
1457             if (IS_USER) {
1458                 Slog.e(TAG, "Error: Tracing is not supported on user builds.");
1459                 return;
1460             }
1461             synchronized (mLock) {
1462                 mEnabled = true;
1463                 mBuffer.resetBuffer();
1464             }
1465         }
1466 
1467         /**
1468          * Stops the trace and write the current buffer to disk
1469          */
stopTrace()1470         void stopTrace() {
1471             if (IS_USER) {
1472                 Slog.e(TAG, "Error: Tracing is not supported on user builds.");
1473                 return;
1474             }
1475             synchronized (mLock) {
1476                 mEnabled = false;
1477                 if (mEnabled) {
1478                     Slog.e(TAG, "Error: tracing enabled while waiting for flush.");
1479                     return;
1480                 }
1481                 writeTraceToFile();
1482             }
1483         }
1484 
isEnabled()1485         boolean isEnabled() {
1486             return mEnabled;
1487         }
1488 
1489         /**
1490          * Write an accessibility trace log entry.
1491          */
logState(String where, long loggingTypes)1492         void logState(String where, long loggingTypes) {
1493             if (!mEnabled) {
1494                 return;
1495             }
1496             logState(where, loggingTypes, "");
1497         }
1498 
1499         /**
1500          * Write an accessibility trace log entry.
1501          */
logState(String where, long loggingTypes, String callingParams)1502         void logState(String where, long loggingTypes, String callingParams) {
1503             if (!mEnabled) {
1504                 return;
1505             }
1506             logState(where, loggingTypes, callingParams, "".getBytes());
1507         }
1508 
1509         /**
1510          * Write an accessibility trace log entry.
1511          */
logState(String where, long loggingTypes, String callingParams, byte[] a11yDump)1512         void logState(String where, long loggingTypes, String callingParams, byte[] a11yDump) {
1513             if (!mEnabled) {
1514                 return;
1515             }
1516             logState(where, loggingTypes, callingParams, a11yDump, Binder.getCallingUid(),
1517                     new HashSet<String>(Arrays.asList("logState")));
1518         }
1519 
1520         /**
1521          * Write an accessibility trace log entry.
1522          */
logState(String where, long loggingTypes, String callingParams, byte[] a11yDump, int callingUid, Set<String> ignoreStackEntries)1523         void logState(String where, long loggingTypes, String callingParams, byte[] a11yDump,
1524                 int callingUid, Set<String> ignoreStackEntries) {
1525             if (!mEnabled) {
1526                 return;
1527             }
1528             StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
1529             ignoreStackEntries.add("logState");
1530             logState(where, loggingTypes, callingParams, a11yDump, callingUid, stackTraceElements,
1531                     ignoreStackEntries);
1532         }
1533 
1534         /**
1535          * Write an accessibility trace log entry.
1536          */
logState(String where, long loggingTypes, String callingParams, byte[] a11yDump, int callingUid, StackTraceElement[] stackTrace, Set<String> ignoreStackEntries)1537         void logState(String where, long loggingTypes, String callingParams, byte[] a11yDump,
1538                 int callingUid, StackTraceElement[] stackTrace, Set<String> ignoreStackEntries) {
1539             if (!mEnabled) {
1540                 return;
1541             }
1542             log(where, loggingTypes, callingParams, a11yDump, callingUid, stackTrace,
1543                     SystemClock.elapsedRealtimeNanos(),
1544                     Process.myPid() + ":" + Application.getProcessName(),
1545                     Thread.currentThread().getId() + ":" + Thread.currentThread().getName(),
1546                     ignoreStackEntries);
1547         }
1548 
1549         /**
1550          * Write an accessibility trace log entry.
1551          */
logState(String where, long loggingTypes, String callingParams, byte[] a11yDump, int callingUid, StackTraceElement[] callingStack, long timeStamp, int processId, long threadId, Set<String> ignoreStackEntries)1552         void logState(String where, long loggingTypes, String callingParams, byte[] a11yDump,
1553                 int callingUid, StackTraceElement[] callingStack, long timeStamp, int processId,
1554                 long threadId, Set<String> ignoreStackEntries) {
1555             if (!mEnabled) {
1556                 return;
1557             }
1558             log(where, loggingTypes, callingParams, a11yDump, callingUid, callingStack, timeStamp,
1559                     String.valueOf(processId), String.valueOf(threadId), ignoreStackEntries);
1560         }
1561 
toStackTraceString(StackTraceElement[] stackTraceElements, Set<String> ignoreStackEntries)1562         private  String toStackTraceString(StackTraceElement[] stackTraceElements,
1563                 Set<String> ignoreStackEntries) {
1564 
1565             if (stackTraceElements == null) {
1566                 return "";
1567             }
1568 
1569             StringBuilder stringBuilder = new StringBuilder();
1570             int i = 0;
1571 
1572             // Skip the first a few elements until after any ignoreStackEntries
1573             int firstMatch = -1;
1574             while (i < stackTraceElements.length) {
1575                 for (String ele : ignoreStackEntries) {
1576                     if (stackTraceElements[i].toString().contains(ele)) {
1577                         // found the first stack element containing the ignorable stack entries
1578                         firstMatch = i;
1579                         break;
1580                     }
1581                 }
1582                 if (firstMatch < 0) {
1583                     // Haven't found the first match yet, continue
1584                     i++;
1585                 } else {
1586                     break;
1587                 }
1588             }
1589             int lastMatch = firstMatch;
1590             if (i < stackTraceElements.length) {
1591                 i++;
1592                 // Found the first match. Now look for the last match.
1593                 while (i < stackTraceElements.length) {
1594                     for (String ele : ignoreStackEntries) {
1595                         if (stackTraceElements[i].toString().contains(ele)) {
1596                             // This is a match. Look at the next stack element.
1597                             lastMatch = i;
1598                             break;
1599                         }
1600                     }
1601                     if (lastMatch != i) {
1602                         // Found a no-match.
1603                         break;
1604                     }
1605                     i++;
1606                 }
1607             }
1608 
1609             i = lastMatch + 1;
1610             while (i < stackTraceElements.length) {
1611                 stringBuilder.append(stackTraceElements[i].toString()).append("\n");
1612                 i++;
1613             }
1614             return stringBuilder.toString();
1615         }
1616 
1617         /**
1618          * Write the current state to the buffer
1619          */
log(String where, long loggingTypes, String callingParams, byte[] a11yDump, int callingUid, StackTraceElement[] callingStack, long timeStamp, String processName, String threadName, Set<String> ignoreStackEntries)1620         private void log(String where, long loggingTypes, String callingParams, byte[] a11yDump,
1621                 int callingUid, StackTraceElement[] callingStack, long timeStamp,
1622                 String processName, String threadName, Set<String> ignoreStackEntries) {
1623             SomeArgs args = SomeArgs.obtain();
1624             args.argl1 = timeStamp;
1625             args.argl2 = loggingTypes;
1626             args.arg1 = where;
1627             args.arg2 = processName;
1628             args.arg3 = threadName;
1629             args.arg4 = ignoreStackEntries;
1630             args.arg5 = callingParams;
1631             args.arg6 = callingStack;
1632             args.arg7 = a11yDump;
1633 
1634             mHandler.obtainMessage(
1635                     LogHandler.MESSAGE_LOG_TRACE_ENTRY, callingUid, 0, args).sendToTarget();
1636         }
1637 
1638         /**
1639          * Writes the trace buffer to new file for the bugreport.
1640          */
writeTraceToFile()1641         void writeTraceToFile() {
1642             mHandler.sendEmptyMessage(LogHandler.MESSAGE_WRITE_FILE);
1643         }
1644 
1645         private class LogHandler extends Handler {
1646             public static final int MESSAGE_LOG_TRACE_ENTRY = 1;
1647             public static final int MESSAGE_WRITE_FILE = 2;
1648 
LogHandler(Looper looper)1649             LogHandler(Looper looper) {
1650                 super(looper);
1651             }
1652 
1653             @Override
handleMessage(Message message)1654             public void handleMessage(Message message) {
1655                 switch (message.what) {
1656                     case MESSAGE_LOG_TRACE_ENTRY: {
1657                         final SomeArgs args = (SomeArgs) message.obj;
1658                         try {
1659                             ProtoOutputStream os = new ProtoOutputStream();
1660                             PackageManagerInternal pmInternal =
1661                                     LocalServices.getService(PackageManagerInternal.class);
1662 
1663                             long tokenOuter = os.start(ENTRY);
1664 
1665                             long reportedTimeStampNanos = args.argl1;
1666                             long currentElapsedRealtimeNanos = SystemClock.elapsedRealtimeNanos();
1667                             long timeDiffNanos =
1668                                     currentElapsedRealtimeNanos - reportedTimeStampNanos;
1669                             long currentTimeMillis = (new Date()).getTime();
1670                             long reportedTimeMillis =
1671                                     currentTimeMillis - (long) (timeDiffNanos / 1000000);
1672                             SimpleDateFormat fm = new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
1673 
1674                             os.write(ELAPSED_REALTIME_NANOS, reportedTimeStampNanos);
1675                             os.write(CALENDAR_TIME, fm.format(reportedTimeMillis).toString());
1676 
1677                             long loggingTypes = args.argl2;
1678                             List<String> loggingTypeNames =
1679                                     AccessibilityTrace.getNamesOfLoggingTypes(loggingTypes);
1680 
1681                             for (String type : loggingTypeNames) {
1682                                 os.write(LOGGING_TYPE, type);
1683                             }
1684                             os.write(WHERE, (String) args.arg1);
1685                             os.write(PROCESS_NAME, (String) args.arg2);
1686                             os.write(THREAD_ID_NAME, (String) args.arg3);
1687                             os.write(CALLING_PKG, pmInternal.getNameForUid(message.arg1));
1688                             os.write(CALLING_PARAMS, (String) args.arg5);
1689 
1690                             String callingStack = toStackTraceString(
1691                                     (StackTraceElement[]) args.arg6, (Set<String>) args.arg4);
1692 
1693                             os.write(CALLING_STACKS, callingStack);
1694                             os.write(ACCESSIBILITY_SERVICE, (byte[]) args.arg7);
1695 
1696                             long tokenInner = os.start(WINDOW_MANAGER_SERVICE);
1697                             synchronized (mService.mGlobalLock) {
1698                                 mService.dumpDebugLocked(os, WindowTracingLogLevel.ALL);
1699                             }
1700                             os.end(tokenInner);
1701                             os.write(CPU_STATS, printCpuStats(reportedTimeStampNanos));
1702 
1703                             os.end(tokenOuter);
1704                             synchronized (mLock) {
1705                                 mBuffer.add(os);
1706                             }
1707                         } catch (Exception e) {
1708                             Slog.e(TAG, "Exception while tracing state", e);
1709                         }
1710                         break;
1711                     }
1712                     case MESSAGE_WRITE_FILE: {
1713                         synchronized (mLock) {
1714                             writeTraceToFileInternal();
1715                         }
1716                         break;
1717                     }
1718                 }
1719             }
1720         }
1721 
1722         /**
1723          * Writes the trace buffer to disk.
1724          */
writeTraceToFileInternal()1725         private void writeTraceToFileInternal() {
1726             try {
1727                 ProtoOutputStream proto = new ProtoOutputStream();
1728                 proto.write(MAGIC_NUMBER, MAGIC_NUMBER_VALUE);
1729                 long timeOffsetNs =
1730                         TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis())
1731                         - SystemClock.elapsedRealtimeNanos();
1732                 proto.write(REAL_TO_ELAPSED_TIME_OFFSET_NANOS, timeOffsetNs);
1733                 mBuffer.writeTraceToFile(mTraceFile, proto);
1734             } catch (IOException e) {
1735                 Slog.e(TAG, "Unable to write buffer to file", e);
1736             }
1737         }
1738 
1739         /**
1740          * Returns the string of CPU stats.
1741          */
printCpuStats(long timeStampNanos)1742         private String printCpuStats(long timeStampNanos) {
1743             Pair<String, String> stats = mService.mAmInternal.getAppProfileStatsForDebugging(
1744                     timeStampNanos, CPU_STATS_COUNT);
1745 
1746             return stats.first + stats.second;
1747         }
1748     }
1749 }
1750