Merge "WM: Track focus changes in AccessibilityController" into sc-v2-dev

This commit is contained in:
Vishnu Nair
2021-10-08 21:15:05 +00:00
committed by Android (Google) Code Review
8 changed files with 177 additions and 61 deletions

View File

@@ -50,6 +50,7 @@ import android.accessibilityservice.AccessibilityTrace;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Application;
import android.content.Context;
import android.content.pm.PackageManagerInternal;
@@ -134,6 +135,8 @@ final class AccessibilityController {
private SparseArray<DisplayMagnifier> mDisplayMagnifiers = new SparseArray<>();
private SparseArray<WindowsForAccessibilityObserver> mWindowsForAccessibilityObserver =
new SparseArray<>();
private SparseArray<IBinder> mFocusedWindow = new SparseArray<>();
private int mFocusedDisplay = -1;
// Set to true if initializing window population complete.
private boolean mAllObserversInitialized = true;
@@ -603,6 +606,29 @@ final class AccessibilityController {
return display.getType() == Display.TYPE_VIRTUAL && dc.getParentWindow() != null;
}
void onFocusChanged(InputTarget lastTarget, InputTarget newTarget) {
if (lastTarget != null) {
mFocusedWindow.remove(lastTarget.getDisplayId());
}
if (newTarget != null) {
int displayId = newTarget.getDisplayId();
IBinder clientBinder = newTarget.getIWindow().asBinder();
mFocusedWindow.put(displayId, clientBinder);
}
}
public void onDisplayRemoved(int displayId) {
mFocusedWindow.remove(displayId);
}
public void setFocusedDisplay(int focusedDisplayId) {
mFocusedDisplay = focusedDisplayId;
}
@Nullable IBinder getFocusedWindowToken() {
return mFocusedWindow.get(mFocusedDisplay);
}
/**
* This class encapsulates the functionality related to display magnification.
*/

View File

@@ -31,7 +31,6 @@ import android.util.SparseArray;
import android.view.InputApplicationHandle;
import com.android.server.am.ActivityManagerService;
import com.android.server.wm.EmbeddedWindowController.EmbeddedWindow;
import java.io.File;
import java.util.ArrayList;
@@ -81,21 +80,19 @@ class AnrController {
final boolean aboveSystem;
final ActivityRecord activity;
synchronized (mService.mGlobalLock) {
WindowState windowState = mService.mInputToWindowMap.get(inputToken);
if (windowState != null) {
pid = windowState.mSession.mPid;
activity = windowState.mActivityRecord;
Slog.i(TAG_WM, "ANR in " + windowState.mAttrs.getTitle() + ". Reason:" + reason);
} else {
EmbeddedWindow embeddedWindow = mService.mEmbeddedWindowController.get(inputToken);
if (embeddedWindow == null) {
Slog.e(TAG_WM, "Unknown token, dropping notifyConnectionUnresponsive request");
return;
}
pid = embeddedWindow.mOwnerPid;
windowState = embeddedWindow.mHostWindowState;
activity = null; // Don't blame the host process, instead blame the embedded pid.
InputTarget target = mService.getInputTargetFromToken(inputToken);
if (target == null) {
Slog.e(TAG_WM, "Unknown token, dropping notifyConnectionUnresponsive request");
return;
}
WindowState windowState = target.getWindowState();
pid = target.getPid();
// Blame the activity if the input token belongs to the window. If the target is
// embedded, then we will blame the pid instead.
activity = (windowState.mInputChannelToken == inputToken)
? windowState.mActivityRecord : null;
Slog.i(TAG_WM, "ANR in " + target + ". Reason:" + reason);
aboveSystem = isWindowAboveSystem(windowState);
dumpAnrStateLocked(activity, windowState, reason);
}
@@ -109,19 +106,12 @@ class AnrController {
void notifyWindowResponsive(IBinder inputToken) {
final int pid;
synchronized (mService.mGlobalLock) {
WindowState windowState = mService.mInputToWindowMap.get(inputToken);
if (windowState != null) {
pid = windowState.mSession.mPid;
} else {
// Check if the token belongs to an embedded window.
EmbeddedWindow embeddedWindow = mService.mEmbeddedWindowController.get(inputToken);
if (embeddedWindow == null) {
Slog.e(TAG_WM,
"Unknown token, dropping notifyWindowConnectionResponsive request");
return;
}
pid = embeddedWindow.mOwnerPid;
InputTarget target = mService.getInputTargetFromToken(inputToken);
if (target == null) {
Slog.e(TAG_WM, "Unknown token, dropping notifyWindowConnectionResponsive request");
return;
}
pid = target.getPid();
}
mService.mAmInternal.inputDispatchingResumed(pid);
}

View File

@@ -3099,6 +3099,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
mOverlayLayer.release();
mInputMonitor.onDisplayRemoved();
mWmService.mDisplayNotificationController.dispatchDisplayRemoved(this);
mWmService.mAccessibilityController.onDisplayRemoved(mDisplayId);
} finally {
mDisplayReady = false;
}

View File

@@ -127,7 +127,7 @@ class EmbeddedWindowController {
}
}
static class EmbeddedWindow {
static class EmbeddedWindow implements InputTarget {
final IWindow mClient;
@Nullable final WindowState mHostWindowState;
@Nullable final ActivityRecord mHostActivityRecord;
@@ -166,7 +166,8 @@ class EmbeddedWindowController {
mDisplayId = displayId;
}
String getName() {
@Override
public String toString() {
final String hostWindowName = (mHostWindowState != null)
? mHostWindowState.getWindowTag().toString() : "Internal";
return "EmbeddedWindow{ u" + UserHandle.getUserId(mOwnerUid) + " " + hostWindowName
@@ -183,7 +184,7 @@ class EmbeddedWindowController {
}
InputChannel openInputChannel() {
final String name = getName();
final String name = toString();
mInputChannel = mWmService.mInputManager.createInputChannel(name);
return mInputChannel;
}
@@ -195,5 +196,25 @@ class EmbeddedWindowController {
mInputChannel = null;
}
}
@Override
public WindowState getWindowState() {
return mHostWindowState;
}
@Override
public int getDisplayId() {
return mDisplayId;
}
@Override
public IWindow getIWindow() {
return mClient;
}
@Override
public int getPid() {
return mOwnerPid;
}
}
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.wm;
import android.view.IWindow;
/**
* Common interface between focusable objects.
*
* Both WindowState and EmbeddedWindows can receive input. This consolidates some common properties
* of both targets.
*/
interface InputTarget {
/* Get the WindowState associated with the target. */
WindowState getWindowState();
/* Display id of the target. */
int getDisplayId();
/* Client IWindow for the target. */
IWindow getIWindow();
/* Owning pid of the target. */
int getPid();
}

View File

@@ -504,6 +504,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
mTopFocusedDisplayId = topFocusedDisplayId;
mWmService.mInputManager.setFocusedDisplay(topFocusedDisplayId);
mWmService.mPolicy.setTopFocusedDisplay(topFocusedDisplayId);
mWmService.mAccessibilityController.setFocusedDisplay(topFocusedDisplayId);
ProtoLog.d(WM_DEBUG_FOCUS_LIGHT, "New topFocusedDisplayId=%d", topFocusedDisplayId);
}
return changed;

View File

@@ -4981,23 +4981,49 @@ public class WindowManagerService extends IWindowManager.Stub
return Surface.ROTATION_0;
}
void reportFocusChanged(IBinder oldToken, IBinder newToken) {
WindowState lastFocus;
WindowState newFocus;
synchronized (mGlobalLock) {
lastFocus = mInputToWindowMap.get(oldToken);
newFocus = mInputToWindowMap.get(newToken);
ProtoLog.i(WM_DEBUG_FOCUS_LIGHT, "Focus changing: %s -> %s", lastFocus, newFocus);
// Returns an input target which is mapped to the given input token. This can be a WindowState
// or an embedded window.
@Nullable InputTarget getInputTargetFromToken(IBinder inputToken) {
WindowState windowState = mInputToWindowMap.get(inputToken);
if (windowState != null) {
return windowState;
}
if (newFocus != null) {
mAnrController.onFocusChanged(newFocus);
newFocus.reportFocusChangedSerialized(true);
EmbeddedWindowController.EmbeddedWindow embeddedWindow =
mEmbeddedWindowController.get(inputToken);
if (embeddedWindow != null) {
return embeddedWindow;
}
return null;
}
void reportFocusChanged(IBinder oldToken, IBinder newToken) {
InputTarget lastTarget;
InputTarget newTarget;
synchronized (mGlobalLock) {
lastTarget = getInputTargetFromToken(oldToken);
newTarget = getInputTargetFromToken(newToken);
if (newTarget == null && lastTarget == null) {
Slog.v(TAG_WM, "Unknown focus tokens, dropping reportFocusChanged");
return;
}
mAccessibilityController.onFocusChanged(lastTarget, newTarget);
ProtoLog.i(WM_DEBUG_FOCUS_LIGHT, "Focus changing: %s -> %s", lastTarget, newTarget);
}
// Call WindowState focus change observers
WindowState newFocusedWindow = newTarget != null ? newTarget.getWindowState() : null;
if (newFocusedWindow != null && newFocusedWindow.mInputChannelToken == newToken) {
mAnrController.onFocusChanged(newFocusedWindow);
newFocusedWindow.reportFocusChangedSerialized(true);
notifyFocusChanged();
}
if (lastFocus != null) {
lastFocus.reportFocusChangedSerialized(false);
WindowState lastFocusedWindow = lastTarget != null ? lastTarget.getWindowState() : null;
if (lastFocusedWindow != null && lastFocusedWindow.mInputChannelToken == oldToken) {
lastFocusedWindow.reportFocusChangedSerialized(false);
}
}
@@ -7522,11 +7548,7 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public IBinder getFocusedWindowToken() {
synchronized (mGlobalLock) {
WindowState windowState = getFocusedWindowLocked();
if (windowState != null) {
return windowState.mClient.asBinder();
}
return null;
return mAccessibilityController.getFocusedWindowToken();
}
}
@@ -8267,7 +8289,7 @@ public class WindowManagerService extends IWindowManager.Stub
clientChannel = win.openInputChannel();
mEmbeddedWindowController.add(clientChannel.getToken(), win);
applicationHandle = win.getApplicationHandle();
name = win.getName();
name = win.toString();
}
updateInputChannel(clientChannel.getToken(), callingUid, callingPid, displayId, surface,
@@ -8333,7 +8355,7 @@ public class WindowManagerService extends IWindowManager.Stub
Slog.e(TAG, "Couldn't find window for provided channelToken.");
return;
}
name = win.getName();
name = win.toString();
applicationHandle = win.getApplicationHandle();
}
@@ -8542,10 +8564,9 @@ public class WindowManagerService extends IWindowManager.Stub
SurfaceControl.Transaction t = mTransactionFactory.get();
final int displayId = embeddedWindow.mDisplayId;
if (grantFocus) {
t.setFocusedWindow(inputToken, embeddedWindow.getName(), displayId).apply();
t.setFocusedWindow(inputToken, embeddedWindow.toString(), displayId).apply();
EventLog.writeEvent(LOGTAG_INPUT_FOCUS,
"Focus request " + embeddedWindow.getName(),
"reason=grantEmbeddedWindowFocus(true)");
"Focus request " + embeddedWindow, "reason=grantEmbeddedWindowFocus(true)");
} else {
// Search for a new focus target
DisplayContent displayContent = mRoot.getDisplayContent(displayId);
@@ -8554,18 +8575,18 @@ public class WindowManagerService extends IWindowManager.Stub
if (newFocusTarget == null) {
ProtoLog.v(WM_DEBUG_FOCUS, "grantEmbeddedWindowFocus remove request for "
+ "win=%s dropped since no candidate was found",
embeddedWindow.getName());
embeddedWindow);
return;
}
t.requestFocusTransfer(newFocusTarget.mInputChannelToken, newFocusTarget.getName(),
inputToken, embeddedWindow.getName(),
inputToken, embeddedWindow.toString(),
displayId).apply();
EventLog.writeEvent(LOGTAG_INPUT_FOCUS,
"Transfer focus request " + newFocusTarget,
"reason=grantEmbeddedWindowFocus(false)");
}
ProtoLog.v(WM_DEBUG_FOCUS, "grantEmbeddedWindowFocus win=%s grantFocus=%s",
embeddedWindow.getName(), grantFocus);
embeddedWindow, grantFocus);
}
}
@@ -8594,24 +8615,24 @@ public class WindowManagerService extends IWindowManager.Stub
}
SurfaceControl.Transaction t = mTransactionFactory.get();
if (grantFocus) {
t.requestFocusTransfer(targetInputToken, embeddedWindow.getName(),
t.requestFocusTransfer(targetInputToken, embeddedWindow.toString(),
hostWindow.mInputChannel.getToken(),
hostWindow.getName(),
hostWindow.getDisplayId()).apply();
EventLog.writeEvent(LOGTAG_INPUT_FOCUS,
"Transfer focus request " + embeddedWindow.getName(),
"Transfer focus request " + embeddedWindow,
"reason=grantEmbeddedWindowFocus(true)");
} else {
t.requestFocusTransfer(hostWindow.mInputChannel.getToken(), hostWindow.getName(),
targetInputToken,
embeddedWindow.getName(),
embeddedWindow.toString(),
hostWindow.getDisplayId()).apply();
EventLog.writeEvent(LOGTAG_INPUT_FOCUS,
"Transfer focus request " + hostWindow,
"reason=grantEmbeddedWindowFocus(false)");
}
ProtoLog.v(WM_DEBUG_FOCUS, "grantEmbeddedWindowFocus win=%s grantFocus=%s",
embeddedWindow.getName(), grantFocus);
embeddedWindow, grantFocus);
}
}

View File

@@ -273,7 +273,7 @@ import java.util.function.Predicate;
/** A window in the window manager. */
class WindowState extends WindowContainer<WindowState> implements WindowManagerPolicy.WindowState,
InsetsControlTarget {
InsetsControlTarget, InputTarget {
static final String TAG = TAG_WITH_CLASS_NAME ? "WindowState" : TAG_WM;
// The minimal size of a window within the usable area of the freeform root task.
@@ -1727,7 +1727,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return state;
}
int getDisplayId() {
@Override
public int getDisplayId() {
final DisplayContent displayContent = getDisplayContent();
if (displayContent == null) {
return Display.INVALID_DISPLAY;
@@ -1735,6 +1736,21 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return displayContent.getDisplayId();
}
@Override
public WindowState getWindowState() {
return this;
}
@Override
public IWindow getIWindow() {
return mClient;
}
@Override
public int getPid() {
return mSession.mPid;
}
Task getTask() {
return mActivityRecord != null ? mActivityRecord.getTask() : null;
}