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