diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java index e59c82cfb6d03..cf9783fb92419 100644 --- a/services/core/java/com/android/server/wm/AccessibilityController.java +++ b/services/core/java/com/android/server/wm/AccessibilityController.java @@ -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 mDisplayMagnifiers = new SparseArray<>(); private SparseArray mWindowsForAccessibilityObserver = new SparseArray<>(); + private SparseArray 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. */ diff --git a/services/core/java/com/android/server/wm/AnrController.java b/services/core/java/com/android/server/wm/AnrController.java index 892db9c33dbde..c881864dff254 100644 --- a/services/core/java/com/android/server/wm/AnrController.java +++ b/services/core/java/com/android/server/wm/AnrController.java @@ -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); } diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 46a4f8a266731..ff4dd46b1f189 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -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; } diff --git a/services/core/java/com/android/server/wm/EmbeddedWindowController.java b/services/core/java/com/android/server/wm/EmbeddedWindowController.java index b08d6e1dff9e3..fc317a1212d5b 100644 --- a/services/core/java/com/android/server/wm/EmbeddedWindowController.java +++ b/services/core/java/com/android/server/wm/EmbeddedWindowController.java @@ -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; + } } } diff --git a/services/core/java/com/android/server/wm/InputTarget.java b/services/core/java/com/android/server/wm/InputTarget.java new file mode 100644 index 0000000000000..c7d328a2b18a2 --- /dev/null +++ b/services/core/java/com/android/server/wm/InputTarget.java @@ -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(); +} + diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index 97ea41c2f2288..1a881f7a62279 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -504,6 +504,7 @@ class RootWindowContainer extends WindowContainer 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; diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 4cf8c97eb1326..776a65db365f6 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -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); } } diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index ad4734f0526c1..d29b2aecf7931 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -273,7 +273,7 @@ import java.util.function.Predicate; /** A window in the window manager. */ class WindowState extends WindowContainer 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 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 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; }