1 package com.android.server.wm; 2 3 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; 4 import static android.view.Display.DEFAULT_DISPLAY; 5 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; 6 7 import static com.android.server.wm.ActivityRecord.INVALID_PID; 8 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT; 9 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; 10 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; 11 import static com.android.server.wm.WindowManagerService.H.ON_POINTER_DOWN_OUTSIDE_FOCUS; 12 13 import android.os.Build; 14 import android.os.Debug; 15 import android.os.IBinder; 16 import android.os.Process; 17 import android.os.RemoteException; 18 import android.os.SystemClock; 19 import android.util.ArrayMap; 20 import android.util.Slog; 21 import android.view.IWindow; 22 import android.view.InputApplicationHandle; 23 import android.view.KeyEvent; 24 import android.view.WindowManager; 25 26 import com.android.server.am.ActivityManagerService; 27 import com.android.server.input.InputManagerService; 28 import com.android.server.wm.EmbeddedWindowController.EmbeddedWindow; 29 30 import java.io.File; 31 import java.io.PrintWriter; 32 import java.util.ArrayList; 33 import java.util.concurrent.CountDownLatch; 34 import java.util.concurrent.TimeUnit; 35 import java.util.concurrent.atomic.AtomicReference; 36 37 final class InputManagerCallback implements InputManagerService.WindowManagerCallbacks { 38 private static final String TAG = TAG_WITH_CLASS_NAME ? "InputManagerCallback" : TAG_WM; 39 40 /** Prevent spamming the traces because pre-dump cannot aware duplicated ANR. */ 41 private static final long PRE_DUMP_MIN_INTERVAL_MS = TimeUnit.SECONDS.toMillis(20); 42 /** The timeout to detect if a monitor is held for a while. */ 43 private static final long PRE_DUMP_MONITOR_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(1); 44 /** The last time pre-dump was executed. */ 45 private volatile long mLastPreDumpTimeMs; 46 47 private final WindowManagerService mService; 48 49 // Set to true when the first input device configuration change notification 50 // is received to indicate that the input devices are ready. 51 private final Object mInputDevicesReadyMonitor = new Object(); 52 private boolean mInputDevicesReady; 53 54 // When true, prevents input dispatch from proceeding until set to false again. 55 private boolean mInputDispatchFrozen; 56 57 // The reason the input is currently frozen or null if the input isn't frozen. 58 private String mInputFreezeReason = null; 59 60 // When true, input dispatch proceeds normally. Otherwise all events are dropped. 61 // Initially false, so that input does not get dispatched until boot is finished at 62 // which point the ActivityManager will enable dispatching. 63 private boolean mInputDispatchEnabled; 64 65 // TODO(b/141749603)) investigate if this can be part of client focus change dispatch 66 // Tracks the currently focused window used to update pointer capture state in clients 67 private AtomicReference<IWindow> mFocusedWindow = new AtomicReference<>(); 68 69 // Tracks focused window pointer capture state 70 private boolean mFocusedWindowHasCapture; 71 InputManagerCallback(WindowManagerService service)72 public InputManagerCallback(WindowManagerService service) { 73 mService = service; 74 } 75 76 /** 77 * Notifies the window manager about a broken input channel. 78 * 79 * Called by the InputManager. 80 */ 81 @Override notifyInputChannelBroken(IBinder token)82 public void notifyInputChannelBroken(IBinder token) { 83 if (token == null) { 84 return; 85 } 86 87 synchronized (mService.mGlobalLock) { 88 WindowState windowState = mService.mInputToWindowMap.get(token); 89 if (windowState != null) { 90 Slog.i(TAG_WM, "WINDOW DIED " + windowState); 91 windowState.removeIfPossible(); 92 } 93 } 94 } 95 96 /** 97 * Pre-dump stack trace if the locks of activity manager or window manager (they may be locked 98 * in the path of reporting ANR) cannot be acquired in time. That provides the stack traces 99 * before the real blocking symptom has gone. 100 * <p> 101 * Do not hold the {@link WindowManagerGlobalLock} while calling this method. 102 */ preDumpIfLockTooSlow()103 private void preDumpIfLockTooSlow() { 104 if (!Build.IS_DEBUGGABLE) { 105 return; 106 } 107 final long now = SystemClock.uptimeMillis(); 108 if (mLastPreDumpTimeMs > 0 && now - mLastPreDumpTimeMs < PRE_DUMP_MIN_INTERVAL_MS) { 109 return; 110 } 111 112 final boolean[] shouldDumpSf = { true }; 113 final ArrayMap<String, Runnable> monitors = new ArrayMap<>(2); 114 monitors.put(TAG_WM, mService::monitor); 115 monitors.put("ActivityManager", mService.mAmInternal::monitor); 116 final CountDownLatch latch = new CountDownLatch(monitors.size()); 117 // The pre-dump will execute if one of the monitors doesn't complete within the timeout. 118 for (int i = 0; i < monitors.size(); i++) { 119 final String name = monitors.keyAt(i); 120 final Runnable monitor = monitors.valueAt(i); 121 // Always create new thread to avoid noise of existing threads. Suppose here won't 122 // create too many threads because it means that watchdog will be triggered first. 123 new Thread() { 124 @Override 125 public void run() { 126 monitor.run(); 127 latch.countDown(); 128 final long elapsed = SystemClock.uptimeMillis() - now; 129 if (elapsed > PRE_DUMP_MONITOR_TIMEOUT_MS) { 130 Slog.i(TAG_WM, "Pre-dump acquired " + name + " in " + elapsed + "ms"); 131 } else if (TAG_WM.equals(name)) { 132 // Window manager is the main client of SurfaceFlinger. If window manager 133 // is responsive, the stack traces of SurfaceFlinger may not be important. 134 shouldDumpSf[0] = false; 135 } 136 }; 137 }.start(); 138 } 139 try { 140 if (latch.await(PRE_DUMP_MONITOR_TIMEOUT_MS, TimeUnit.MILLISECONDS)) { 141 return; 142 } 143 } catch (InterruptedException ignored) { } 144 mLastPreDumpTimeMs = now; 145 Slog.i(TAG_WM, "Pre-dump for unresponsive"); 146 147 final ArrayList<Integer> firstPids = new ArrayList<>(1); 148 firstPids.add(ActivityManagerService.MY_PID); 149 ArrayList<Integer> nativePids = null; 150 final int[] pids = shouldDumpSf[0] 151 ? Process.getPidsForCommands(new String[] { "/system/bin/surfaceflinger" }) 152 : null; 153 if (pids != null) { 154 nativePids = new ArrayList<>(1); 155 for (int pid : pids) { 156 nativePids.add(pid); 157 } 158 } 159 160 final File tracesFile = ActivityManagerService.dumpStackTraces(firstPids, 161 null /* processCpuTracker */, null /* lastPids */, nativePids, 162 null /* logExceptionCreatingFile */); 163 if (tracesFile != null) { 164 tracesFile.renameTo(new File(tracesFile.getParent(), tracesFile.getName() + "_pre")); 165 } 166 } 167 168 /** 169 * Notifies the window manager about an application that is not responding. 170 * Returns a new timeout to continue waiting in nanoseconds, or 0 to abort dispatch. 171 * 172 * Called by the InputManager. 173 */ 174 @Override notifyANR(InputApplicationHandle inputApplicationHandle, IBinder token, String reason)175 public long notifyANR(InputApplicationHandle inputApplicationHandle, IBinder token, 176 String reason) { 177 final long startTime = SystemClock.uptimeMillis(); 178 try { 179 return notifyANRInner(inputApplicationHandle, token, reason); 180 } finally { 181 // Log the time because the method is called from InputDispatcher thread. It shouldn't 182 // take too long that may affect input response time. 183 Slog.d(TAG_WM, "notifyANR took " + (SystemClock.uptimeMillis() - startTime) + "ms"); 184 } 185 } 186 notifyANRInner(InputApplicationHandle inputApplicationHandle, IBinder token, String reason)187 private long notifyANRInner(InputApplicationHandle inputApplicationHandle, IBinder token, 188 String reason) { 189 ActivityRecord activity = null; 190 WindowState windowState = null; 191 boolean aboveSystem = false; 192 int windowPid = INVALID_PID; 193 194 preDumpIfLockTooSlow(); 195 196 //TODO(b/141764879) Limit scope of wm lock when input calls notifyANR 197 synchronized (mService.mGlobalLock) { 198 199 // Check if we can blame a window 200 if (token != null) { 201 windowState = mService.mInputToWindowMap.get(token); 202 if (windowState != null) { 203 activity = windowState.mActivityRecord; 204 windowPid = windowState.mSession.mPid; 205 // Figure out whether this window is layered above system windows. 206 // We need to do this here to help the activity manager know how to 207 // layer its ANR dialog. 208 aboveSystem = isWindowAboveSystem(windowState); 209 } 210 } 211 212 // Check if we can blame an embedded window 213 if (token != null && windowState == null) { 214 EmbeddedWindow embeddedWindow = mService.mEmbeddedWindowController.get(token); 215 if (embeddedWindow != null) { 216 windowPid = embeddedWindow.mOwnerPid; 217 WindowState hostWindowState = embeddedWindow.mHostWindowState; 218 if (hostWindowState == null) { 219 // The embedded window has no host window and we cannot easily determine 220 // its z order. Try to place the anr dialog as high as possible. 221 aboveSystem = true; 222 } else { 223 aboveSystem = isWindowAboveSystem(hostWindowState); 224 } 225 } 226 } 227 228 // Check if we can blame an activity. If we don't have an activity to blame, pull out 229 // the token passed in via input application handle. This can happen if there are no 230 // focused windows but input dispatcher knows the focused app. 231 if (activity == null && inputApplicationHandle != null) { 232 activity = ActivityRecord.forTokenLocked(inputApplicationHandle.token); 233 } 234 235 if (windowState != null) { 236 Slog.i(TAG_WM, "Input event dispatching timed out " 237 + "sending to " + windowState.mAttrs.getTitle() 238 + ". Reason: " + reason); 239 } else if (activity != null) { 240 Slog.i(TAG_WM, "Input event dispatching timed out " 241 + "sending to application " + activity.stringName 242 + ". Reason: " + reason); 243 } else { 244 Slog.i(TAG_WM, "Input event dispatching timed out " 245 + ". Reason: " + reason); 246 } 247 248 mService.saveANRStateLocked(activity, windowState, reason); 249 } 250 251 // All the calls below need to happen without the WM lock held since they call into AM. 252 mService.mAtmInternal.saveANRState(reason); 253 254 if (activity != null && activity.appToken != null) { 255 // Notify the activity manager about the timeout and let it decide whether 256 // to abort dispatching or keep waiting. 257 final boolean abort = activity.keyDispatchingTimedOut(reason, windowPid); 258 if (!abort) { 259 // The activity manager declined to abort dispatching. 260 // Wait a bit longer and timeout again later. 261 return activity.mInputDispatchingTimeoutNanos; 262 } 263 } else if (windowState != null || windowPid != INVALID_PID) { 264 // Notify the activity manager about the timeout and let it decide whether 265 // to abort dispatching or keep waiting. 266 long timeout = mService.mAmInternal.inputDispatchingTimedOut(windowPid, aboveSystem, 267 reason); 268 if (timeout >= 0) { 269 // The activity manager declined to abort dispatching. 270 // Wait a bit longer and timeout again later. 271 return timeout * 1000000L; // nanoseconds 272 } 273 } 274 return 0; // abort dispatching 275 } 276 isWindowAboveSystem(WindowState windowState)277 private boolean isWindowAboveSystem(WindowState windowState) { 278 int systemAlertLayer = mService.mPolicy.getWindowLayerFromTypeLw( 279 TYPE_APPLICATION_OVERLAY, windowState.mOwnerCanAddInternalSystemWindow); 280 return windowState.mBaseLayer > systemAlertLayer; 281 } 282 283 /** Notifies that the input device configuration has changed. */ 284 @Override notifyConfigurationChanged()285 public void notifyConfigurationChanged() { 286 // TODO(multi-display): Notify proper displays that are associated with this input device. 287 288 synchronized (mService.mGlobalLock) { 289 mService.getDefaultDisplayContentLocked().sendNewConfiguration(); 290 } 291 292 synchronized (mInputDevicesReadyMonitor) { 293 if (!mInputDevicesReady) { 294 mInputDevicesReady = true; 295 mInputDevicesReadyMonitor.notifyAll(); 296 } 297 } 298 } 299 300 /** Notifies that the lid switch changed state. */ 301 @Override notifyLidSwitchChanged(long whenNanos, boolean lidOpen)302 public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen) { 303 mService.mPolicy.notifyLidSwitchChanged(whenNanos, lidOpen); 304 } 305 306 /** Notifies that the camera lens cover state has changed. */ 307 @Override notifyCameraLensCoverSwitchChanged(long whenNanos, boolean lensCovered)308 public void notifyCameraLensCoverSwitchChanged(long whenNanos, boolean lensCovered) { 309 mService.mPolicy.notifyCameraLensCoverSwitchChanged(whenNanos, lensCovered); 310 } 311 312 /** 313 * Provides an opportunity for the window manager policy to intercept early key 314 * processing as soon as the key has been read from the device. 315 */ 316 @Override interceptKeyBeforeQueueing(KeyEvent event, int policyFlags)317 public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) { 318 return mService.mPolicy.interceptKeyBeforeQueueing(event, policyFlags); 319 } 320 321 /** {@inheritDoc} */ 322 @Override interceptMotionBeforeQueueingNonInteractive(int displayId, long whenNanos, int policyFlags)323 public int interceptMotionBeforeQueueingNonInteractive(int displayId, long whenNanos, 324 int policyFlags) { 325 return mService.mPolicy.interceptMotionBeforeQueueingNonInteractive( 326 displayId, whenNanos, policyFlags); 327 } 328 329 /** 330 * Provides an opportunity for the window manager policy to process a key before 331 * ordinary dispatch. 332 */ 333 @Override interceptKeyBeforeDispatching( IBinder focusedToken, KeyEvent event, int policyFlags)334 public long interceptKeyBeforeDispatching( 335 IBinder focusedToken, KeyEvent event, int policyFlags) { 336 return mService.mPolicy.interceptKeyBeforeDispatching(focusedToken, event, policyFlags); 337 } 338 339 /** 340 * Provides an opportunity for the window manager policy to process a key that 341 * the application did not handle. 342 */ 343 @Override dispatchUnhandledKey( IBinder focusedToken, KeyEvent event, int policyFlags)344 public KeyEvent dispatchUnhandledKey( 345 IBinder focusedToken, KeyEvent event, int policyFlags) { 346 return mService.mPolicy.dispatchUnhandledKey(focusedToken, event, policyFlags); 347 } 348 349 /** Callback to get pointer layer. */ 350 @Override getPointerLayer()351 public int getPointerLayer() { 352 return mService.mPolicy.getWindowLayerFromTypeLw(WindowManager.LayoutParams.TYPE_POINTER) 353 * WindowManagerService.TYPE_LAYER_MULTIPLIER 354 + WindowManagerService.TYPE_LAYER_OFFSET; 355 } 356 357 /** Callback to get pointer display id. */ 358 @Override getPointerDisplayId()359 public int getPointerDisplayId() { 360 synchronized (mService.mGlobalLock) { 361 // If desktop mode is not enabled, show on the default display. 362 if (!mService.mForceDesktopModeOnExternalDisplays) { 363 return DEFAULT_DISPLAY; 364 } 365 366 // Look for the topmost freeform display. 367 int firstExternalDisplayId = DEFAULT_DISPLAY; 368 for (int i = mService.mRoot.mChildren.size() - 1; i >= 0; --i) { 369 final DisplayContent displayContent = mService.mRoot.mChildren.get(i); 370 // Heuristic solution here. Currently when "Freeform windows" developer option is 371 // enabled we automatically put secondary displays in freeform mode and emulating 372 // "desktop mode". It also makes sense to show the pointer on the same display. 373 if (displayContent.getWindowingMode() == WINDOWING_MODE_FREEFORM) { 374 return displayContent.getDisplayId(); 375 } 376 377 if (firstExternalDisplayId == DEFAULT_DISPLAY 378 && displayContent.getDisplayId() != DEFAULT_DISPLAY) { 379 firstExternalDisplayId = displayContent.getDisplayId(); 380 } 381 } 382 383 // Look for the topmost non-default display 384 return firstExternalDisplayId; 385 } 386 } 387 388 @Override onPointerDownOutsideFocus(IBinder touchedToken)389 public void onPointerDownOutsideFocus(IBinder touchedToken) { 390 mService.mH.obtainMessage(ON_POINTER_DOWN_OUTSIDE_FOCUS, touchedToken).sendToTarget(); 391 } 392 393 @Override notifyFocusChanged(IBinder oldToken, IBinder newToken)394 public boolean notifyFocusChanged(IBinder oldToken, IBinder newToken) { 395 boolean requestRefreshConfiguration = false; 396 final IWindow newFocusedWindow; 397 final WindowState win; 398 399 // TODO(b/141749603) investigate if this can be part of client focus change dispatch 400 synchronized (mService.mGlobalLock) { 401 win = mService.mInputToWindowMap.get(newToken); 402 } 403 newFocusedWindow = (win != null) ? win.mClient : null; 404 405 final IWindow focusedWindow = mFocusedWindow.get(); 406 if (focusedWindow != null) { 407 if (newFocusedWindow != null 408 && newFocusedWindow.asBinder() == focusedWindow.asBinder()) { 409 Slog.w(TAG, "notifyFocusChanged called with unchanged mFocusedWindow=" 410 + focusedWindow); 411 return false; 412 } 413 requestRefreshConfiguration = dispatchPointerCaptureChanged(focusedWindow, false); 414 } 415 mFocusedWindow.set(newFocusedWindow); 416 return requestRefreshConfiguration; 417 } 418 419 @Override requestPointerCapture(IBinder windowToken, boolean enabled)420 public boolean requestPointerCapture(IBinder windowToken, boolean enabled) { 421 final IWindow focusedWindow = mFocusedWindow.get(); 422 if (focusedWindow == null || focusedWindow.asBinder() != windowToken) { 423 Slog.e(TAG, "requestPointerCapture called for a window that has no focus: " 424 + windowToken); 425 return false; 426 } 427 if (mFocusedWindowHasCapture == enabled) { 428 Slog.i(TAG, "requestPointerCapture: already " + (enabled ? "enabled" : "disabled")); 429 return false; 430 } 431 return dispatchPointerCaptureChanged(focusedWindow, enabled); 432 } 433 dispatchPointerCaptureChanged(IWindow focusedWindow, boolean enabled)434 private boolean dispatchPointerCaptureChanged(IWindow focusedWindow, boolean enabled) { 435 if (mFocusedWindowHasCapture != enabled) { 436 mFocusedWindowHasCapture = enabled; 437 try { 438 focusedWindow.dispatchPointerCaptureChanged(enabled); 439 } catch (RemoteException ex) { 440 /* ignore */ 441 } 442 return true; 443 } 444 return false; 445 } 446 447 /** Waits until the built-in input devices have been configured. */ waitForInputDevicesReady(long timeoutMillis)448 public boolean waitForInputDevicesReady(long timeoutMillis) { 449 synchronized (mInputDevicesReadyMonitor) { 450 if (!mInputDevicesReady) { 451 try { 452 mInputDevicesReadyMonitor.wait(timeoutMillis); 453 } catch (InterruptedException ex) { 454 } 455 } 456 return mInputDevicesReady; 457 } 458 } 459 freezeInputDispatchingLw()460 public void freezeInputDispatchingLw() { 461 if (!mInputDispatchFrozen) { 462 if (DEBUG_INPUT) { 463 Slog.v(TAG_WM, "Freezing input dispatching"); 464 } 465 466 mInputDispatchFrozen = true; 467 468 if (DEBUG_INPUT) { 469 mInputFreezeReason = Debug.getCallers(6); 470 } 471 updateInputDispatchModeLw(); 472 } 473 } 474 thawInputDispatchingLw()475 public void thawInputDispatchingLw() { 476 if (mInputDispatchFrozen) { 477 if (DEBUG_INPUT) { 478 Slog.v(TAG_WM, "Thawing input dispatching"); 479 } 480 481 mInputDispatchFrozen = false; 482 mInputFreezeReason = null; 483 updateInputDispatchModeLw(); 484 } 485 } 486 setEventDispatchingLw(boolean enabled)487 public void setEventDispatchingLw(boolean enabled) { 488 if (mInputDispatchEnabled != enabled) { 489 if (DEBUG_INPUT) { 490 Slog.v(TAG_WM, "Setting event dispatching to " + enabled); 491 } 492 493 mInputDispatchEnabled = enabled; 494 updateInputDispatchModeLw(); 495 } 496 } 497 updateInputDispatchModeLw()498 private void updateInputDispatchModeLw() { 499 mService.mInputManager.setInputDispatchMode(mInputDispatchEnabled, mInputDispatchFrozen); 500 } 501 dump(PrintWriter pw, String prefix)502 void dump(PrintWriter pw, String prefix) { 503 if (mInputFreezeReason != null) { 504 pw.println(prefix + "mInputFreezeReason=" + mInputFreezeReason); 505 } 506 } 507 } 508