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