Merge changes Ib00124b3,Ie850a67c

* changes:
  Refine WindowManagerInternal#getDisplayImePolicy
  Reduce potential lock contention during start input
This commit is contained in:
Ming-Shin Lu
2022-01-22 09:48:12 +00:00
committed by Android (Google) Code Review
5 changed files with 112 additions and 55 deletions

View File

@@ -2347,11 +2347,20 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
curId, getSequenceNumberLocked(), suppressesSpellChecker);
}
/**
* Called by {@link #startInputOrWindowGainedFocusInternalLocked} to bind/unbind/attach the
* selected InputMethod to the given focused IME client.
*
* Note that this should be called after validating if the IME client has IME focus.
*
* @see WindowManagerInternal#hasInputMethodClientFocus(IBinder, int, int, int)
*/
@GuardedBy("ImfLock.class")
@NonNull
InputBindResult startInputUncheckedLocked(@NonNull ClientState cs, IInputContext inputContext,
@NonNull EditorInfo attribute, @StartInputFlags int startInputFlags,
@StartInputReason int startInputReason, int unverifiedTargetSdkVersion) {
private InputBindResult startInputUncheckedLocked(@NonNull ClientState cs,
IInputContext inputContext, @NonNull EditorInfo attribute,
@StartInputFlags int startInputFlags, @StartInputReason int startInputReason,
int unverifiedTargetSdkVersion) {
// If no method is currently selected, do nothing.
String selectedMethodId = getSelectedMethodIdLocked();
if (selectedMethodId == null) {
@@ -2373,10 +2382,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
return InputBindResult.INVALID_PACKAGE_NAME;
}
if (!mWindowManagerInternal.isUidAllowedOnDisplay(cs.selfReportedDisplayId, cs.uid)) {
// Wait, the client no longer has access to the display.
return InputBindResult.INVALID_DISPLAY_ID;
}
// Compute the final shown display ID with validated cs.selfReportedDisplayId for this
// session & other conditions.
mDisplayIdToShowIme = computeImeDisplayIdForTarget(cs.selfReportedDisplayId,
@@ -3200,14 +3205,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
// be made before input is started in it.
final ClientState cs = mClients.get(client.asBinder());
if (cs == null) {
throw new IllegalArgumentException(
"unknown client " + client.asBinder());
throw new IllegalArgumentException("unknown client " + client.asBinder());
}
if (!mWindowManagerInternal.isInputMethodClientFocus(cs.uid, cs.pid,
cs.selfReportedDisplayId)) {
if (!isImeClientFocused(windowToken, cs)) {
if (DEBUG) {
Slog.w(TAG,
"Ignoring hideSoftInput of uid " + uid + ": " + client);
Slog.w(TAG, "Ignoring hideSoftInput of uid " + uid + ": " + client);
}
return false;
}
@@ -3277,6 +3279,12 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
return res;
}
private boolean isImeClientFocused(IBinder windowToken, ClientState cs) {
final int imeClientFocus = mWindowManagerInternal.hasInputMethodClientFocus(
windowToken, cs.uid, cs.pid, cs.selfReportedDisplayId);
return imeClientFocus == WindowManagerInternal.ImeClientFocusResult.HAS_IME_FOCUS;
}
@NonNull
@Override
public InputBindResult startInputOrWindowGainedFocus(
@@ -3370,31 +3378,30 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
+ " unverifiedTargetSdkVersion=" + unverifiedTargetSdkVersion);
}
final int windowDisplayId = mWindowManagerInternal.getDisplayIdForWindow(windowToken);
final ClientState cs = mClients.get(client.asBinder());
if (cs == null) {
throw new IllegalArgumentException("unknown client " + client.asBinder());
}
if (cs.selfReportedDisplayId != windowDisplayId) {
Slog.e(TAG, "startInputOrWindowGainedFocusInternal: display ID mismatch."
+ " from client:" + cs.selfReportedDisplayId
+ " from window:" + windowDisplayId);
return InputBindResult.DISPLAY_ID_MISMATCH;
}
if (!mWindowManagerInternal.isInputMethodClientFocus(cs.uid, cs.pid,
cs.selfReportedDisplayId)) {
// Check with the window manager to make sure this client actually
// has a window with focus. If not, reject. This is thread safe
// because if the focus changes some time before or after, the
// next client receiving focus that has any interest in input will
// be calling through here after that change happens.
if (DEBUG) {
Slog.w(TAG, "Focus gain on non-focused client " + cs.client
+ " (uid=" + cs.uid + " pid=" + cs.pid + ")");
}
return InputBindResult.NOT_IME_TARGET_WINDOW;
final int imeClientFocus = mWindowManagerInternal.hasInputMethodClientFocus(
windowToken, cs.uid, cs.pid, cs.selfReportedDisplayId);
switch (imeClientFocus) {
case WindowManagerInternal.ImeClientFocusResult.DISPLAY_ID_MISMATCH:
Slog.e(TAG, "startInputOrWindowGainedFocusInternal: display ID mismatch.");
return InputBindResult.DISPLAY_ID_MISMATCH;
case WindowManagerInternal.ImeClientFocusResult.NOT_IME_TARGET_WINDOW:
// Check with the window manager to make sure this client actually
// has a window with focus. If not, reject. This is thread safe
// because if the focus changes some time before or after, the
// next client receiving focus that has any interest in input will
// be calling through here after that change happens.
if (DEBUG) {
Slog.w(TAG, "Focus gain on non-focused client " + cs.client
+ " (uid=" + cs.uid + " pid=" + cs.pid + ")");
}
return InputBindResult.NOT_IME_TARGET_WINDOW;
case WindowManagerInternal.ImeClientFocusResult.INVALID_DISPLAY_ID:
return InputBindResult.INVALID_DISPLAY_ID;
}
if (mUserSwitchHandlerTask != null) {
@@ -3622,8 +3629,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
if (cs == null) {
throw new IllegalArgumentException("unknown client " + client.asBinder());
}
if (!mWindowManagerInternal.isInputMethodClientFocus(cs.uid, cs.pid,
cs.selfReportedDisplayId)) {
if (!isImeClientFocused(mCurFocusedWindow, cs)) {
Slog.w(TAG, String.format("Ignoring %s of uid %d : %s", methodName, uid, client));
return false;
}

View File

@@ -2001,6 +2001,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
}
void configureDisplayPolicy() {
mRootWindowContainer.updateDisplayImePolicyCache();
mDisplayPolicy.updateConfigurationAndScreenSizeDependentBehaviors();
mDisplayRotation.configure(mBaseDisplayWidth, mBaseDisplayHeight);
}
@@ -3939,6 +3940,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
}
}
// IMPORTANT: When introducing new dependencies in this method, make sure that
// changes to those result in RootWindowContainer.updateDisplayImePolicyCache()
// being called.
@DisplayImePolicy int getImePolicy() {
if (!isTrusted()) {
return DISPLAY_IME_POLICY_FALLBACK_DISPLAY;

View File

@@ -165,6 +165,7 @@ import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Set;
@@ -2530,9 +2531,16 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
// Drop any cached DisplayInfos associated with this display id - the values are now
// out of date given this display changed event.
mWmService.mPossibleDisplayInfoMapper.removePossibleDisplayInfos(displayId);
updateDisplayImePolicyCache();
}
}
void updateDisplayImePolicyCache() {
ArrayMap<Integer, Integer> displayImePolicyMap = new ArrayMap<>();
forAllDisplays(dc -> displayImePolicyMap.put(dc.getDisplayId(), dc.getImePolicy()));
mWmService.mDisplayImePolicyCache = Collections.unmodifiableMap(displayImePolicyMap);
}
/** Update lists of UIDs that are present on displays and have access to them. */
void updateUIDsPresentOnDisplay() {
mDisplayAccessUIDs.clear();

View File

@@ -16,6 +16,9 @@
package com.android.server.wm;
import static java.lang.annotation.RetentionPolicy.SOURCE;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ClipData;
@@ -40,6 +43,7 @@ import com.android.internal.policy.KeyInterceptionInfo;
import com.android.server.input.InputManagerService;
import com.android.server.policy.WindowManagerPolicy;
import java.lang.annotation.Retention;
import java.util.List;
import java.util.Set;
@@ -609,6 +613,7 @@ public abstract class WindowManagerInternal {
/**
* Checks whether the specified IME client has IME focus or not.
*
* @param windowToken The window token of the input method client
* @param uid UID of the process to be queried
* @param pid PID of the process to be queried
* @param displayId Display ID reported from the client. Note that this method also verifies
@@ -616,7 +621,22 @@ public abstract class WindowManagerInternal {
* @return {@code true} if the IME client specified with {@code uid}, {@code pid}, and
* {@code displayId} has IME focus
*/
public abstract boolean isInputMethodClientFocus(int uid, int pid, int displayId);
public abstract @ImeClientFocusResult int hasInputMethodClientFocus(IBinder windowToken,
int uid, int pid, int displayId);
@Retention(SOURCE)
@IntDef({
ImeClientFocusResult.HAS_IME_FOCUS,
ImeClientFocusResult.NOT_IME_TARGET_WINDOW,
ImeClientFocusResult.DISPLAY_ID_MISMATCH,
ImeClientFocusResult.INVALID_DISPLAY_ID
})
public @interface ImeClientFocusResult {
int HAS_IME_FOCUS = 0;
int NOT_IME_TARGET_WINDOW = -1;
int DISPLAY_ID_MISMATCH = -2;
int INVALID_DISPLAY_ID = -3;
}
/**
* Checks whether the given {@code uid} is allowed to use the given {@code displayId} or not.

View File

@@ -586,6 +586,13 @@ public class WindowManagerService extends IWindowManager.Stub
*/
final ArrayList<WindowState> mResizingWindows = new ArrayList<>();
/**
* Mapping of displayId to {@link DisplayImePolicy}.
* Note that this can be accessed without holding the lock.
*/
volatile Map<Integer, Integer> mDisplayImePolicyCache = Collections.unmodifiableMap(
new ArrayMap<>());
/**
* Windows whose surface should be destroyed.
*/
@@ -6897,6 +6904,7 @@ public class WindowManagerService extends IWindowManager.Stub
void setForceDesktopModeOnExternalDisplays(boolean forceDesktopModeOnExternalDisplays) {
synchronized (mGlobalLock) {
mForceDesktopModeOnExternalDisplays = forceDesktopModeOnExternalDisplays;
mRoot.updateDisplayImePolicyCache();
}
}
@@ -7328,16 +7336,14 @@ public class WindowManagerService extends IWindowManager.Stub
if (!checkCallingPermission(INTERNAL_SYSTEM_WINDOW, "getDisplayImePolicy()")) {
throw new SecurityException("Requires INTERNAL_SYSTEM_WINDOW permission");
}
final DisplayContent dc = mRoot.getDisplayContent(displayId);
if (dc == null) {
final Map<Integer, Integer> displayImePolicyCache = mDisplayImePolicyCache;
if (!displayImePolicyCache.containsKey(displayId)) {
ProtoLog.w(WM_ERROR,
"Attempted to get IME policy of a display that does not exist: %d",
displayId);
return DISPLAY_IME_POLICY_FALLBACK_DISPLAY;
}
synchronized (mGlobalLock) {
return dc.getImePolicy();
}
return displayImePolicyCache.get(displayId);
}
@Override
@@ -7686,19 +7692,32 @@ public class WindowManagerService extends IWindowManager.Stub
}
@Override
public boolean isInputMethodClientFocus(int uid, int pid, int displayId) {
public @ImeClientFocusResult int hasInputMethodClientFocus(IBinder windowToken,
int uid, int pid, int displayId) {
if (displayId == Display.INVALID_DISPLAY) {
return false;
return ImeClientFocusResult.INVALID_DISPLAY_ID;
}
synchronized (mGlobalLock) {
final DisplayContent displayContent = mRoot.getTopFocusedDisplayContent();
final WindowState window = mWindowMap.get(windowToken);
if (window == null) {
return ImeClientFocusResult.NOT_IME_TARGET_WINDOW;
}
final int tokenDisplayId = window.getDisplayContent().getDisplayId();
if (tokenDisplayId != displayId) {
Slog.e(TAG, "isInputMethodClientFocus: display ID mismatch."
+ " from client: " + displayId
+ " from window: " + tokenDisplayId);
return ImeClientFocusResult.DISPLAY_ID_MISMATCH;
}
if (displayContent == null
|| displayContent.getDisplayId() != displayId
|| !displayContent.hasAccess(uid)) {
return false;
return ImeClientFocusResult.INVALID_DISPLAY_ID;
}
if (displayContent.isInputMethodClientFocus(uid, pid)) {
return true;
return ImeClientFocusResult.HAS_IME_FOCUS;
}
// Okay, how about this... what is the current focus?
// It seems in some cases we may not have moved the IM
@@ -7711,10 +7730,11 @@ public class WindowManagerService extends IWindowManager.Stub
final WindowState currentFocus = displayContent.mCurrentFocus;
if (currentFocus != null && currentFocus.mSession.mUid == uid
&& currentFocus.mSession.mPid == pid) {
return currentFocus.canBeImeTarget();
return currentFocus.canBeImeTarget() ? ImeClientFocusResult.HAS_IME_FOCUS
: ImeClientFocusResult.NOT_IME_TARGET_WINDOW;
}
}
return false;
return ImeClientFocusResult.NOT_IME_TARGET_WINDOW;
}
@Override
@@ -7813,9 +7833,7 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public @DisplayImePolicy int getDisplayImePolicy(int displayId) {
synchronized (mGlobalLock) {
return WindowManagerService.this.getDisplayImePolicy(displayId);
}
return WindowManagerService.this.getDisplayImePolicy(displayId);
}
@Override
@@ -8710,20 +8728,21 @@ public class WindowManagerService extends IWindowManager.Stub
}
boolean shouldRestoreImeVisibility(IBinder imeTargetWindowToken) {
final Task imeTargetWindowTask;
synchronized (mGlobalLock) {
final WindowState imeTargetWindow = mWindowMap.get(imeTargetWindowToken);
if (imeTargetWindow == null) {
return false;
}
final Task imeTargetWindowTask = imeTargetWindow.getTask();
imeTargetWindowTask = imeTargetWindow.getTask();
if (imeTargetWindowTask == null) {
return false;
}
final TaskSnapshot snapshot = getTaskSnapshot(imeTargetWindowTask.mTaskId,
imeTargetWindowTask.mUserId, false /* isLowResolution */,
false /* restoreFromDisk */);
return snapshot != null && snapshot.hasImeSurface();
}
final TaskSnapshot snapshot = getTaskSnapshot(imeTargetWindowTask.mTaskId,
imeTargetWindowTask.mUserId, false /* isLowResolution */,
false /* restoreFromDisk */);
return snapshot != null && snapshot.hasImeSurface();
}
@Override