diff options
| author | 2023-09-18 12:04:45 +0200 | |
|---|---|---|
| committer | 2023-09-19 16:12:53 +0000 | |
| commit | 8eb7be5bf222e1f6e3ab17308725dc537e316d41 (patch) | |
| tree | a0418c7c6e0d830e51827a5332e56bd439757305 | |
| parent | c6d3bf6a7f80c503b44d05abf5cc29e6cab1e640 (diff) | |
Fix deadlock in IMMS checking hasNavigationBar
Since allowing IMEs to request hiding the fake IME navigation bar in
[1], we found that this would still be shown on emulator, which has
no system navigation bar, and would thus break some tests. This was
fixed in [2], but it looks like that fix can trigger a deadlock as it
goes through calling WindowManagerGlobal.getWindowManagerService, which
tries to acquire the lock on that class.
Instead, I added a path to call hasNavigationBar through
WindowManagerInternal, which also skips the IPC step. This will still
require the WindowManagerGlobalLock, but the internal class is currently
used throughout InputMethodManagerService, so it should be safe here.
[1]: I8793db69fb846046300d5a56b3b0060138ef4cd5
[2]: Ide89075836a527d806f28cbeeb8d90334b79428f
Test: atest InputMethodServiceTest#testNoNavigationBar_thenImeNoCaptionBar
Bug: 300359571
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:d136b9bd629295c996367ed01f96a5f3fa658dc7)
Merged-In: I4d7a062a9abeaf59218505d384f94e04e1a8ed74
Change-Id: I4d7a062a9abeaf59218505d384f94e04e1a8ed74
3 files changed, 18 insertions, 19 deletions
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 7aea63255dc8..a1d28da5f65e 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -119,7 +119,6 @@ import android.util.SparseArray; import android.util.SparseBooleanArray; import android.util.proto.ProtoOutputStream; import android.view.DisplayInfo; -import android.view.IWindowManager; import android.view.InputChannel; import android.view.InputDevice; import android.view.MotionEvent; @@ -127,7 +126,6 @@ import android.view.WindowManager; import android.view.WindowManager.DisplayImePolicy; import android.view.WindowManager.LayoutParams; import android.view.WindowManager.LayoutParams.SoftInputModeFlags; -import android.view.WindowManagerGlobal; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.ImeTracker; import android.view.inputmethod.InputBinding; @@ -3073,9 +3071,13 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub ConcurrentUtils.waitForFutureNoInterrupt(mImeDrawsImeNavBarResLazyInitFuture, "Waiting for the lazy init of mImeDrawsImeNavBarRes"); } + // Whether the current display has a navigation bar. When this is false (e.g. emulator), + // the IME should not draw the IME navigation bar. + final boolean hasNavigationBar = mWindowManagerInternal + .hasNavigationBar(mCurTokenDisplayId != INVALID_DISPLAY + ? mCurTokenDisplayId : DEFAULT_DISPLAY); final boolean canImeDrawsImeNavBar = - mImeDrawsImeNavBarRes != null && mImeDrawsImeNavBarRes.get() - && hasNavigationBarOnCurrentDisplay(); + mImeDrawsImeNavBarRes != null && mImeDrawsImeNavBarRes.get() && hasNavigationBar; final boolean shouldShowImeSwitcherWhenImeIsShown = shouldShowImeSwitcherLocked( InputMethodService.IME_ACTIVE | InputMethodService.IME_VISIBLE); return (canImeDrawsImeNavBar ? InputMethodNavButtonFlags.IME_DRAWS_IME_NAV_BAR : 0) @@ -3083,21 +3085,6 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub ? InputMethodNavButtonFlags.SHOW_IME_SWITCHER_WHEN_IME_IS_SHOWN : 0); } - /** - * Whether the current display has a navigation bar. When this is {@code false} (e.g. emulator), - * the IME should <em>not</em> draw the IME navigation bar. - */ - @GuardedBy("ImfLock.class") - private boolean hasNavigationBarOnCurrentDisplay() { - final IWindowManager wm = WindowManagerGlobal.getWindowManagerService(); - try { - return wm.hasNavigationBar(mCurTokenDisplayId != INVALID_DISPLAY - ? mCurTokenDisplayId : DEFAULT_DISPLAY); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - @GuardedBy("ImfLock.class") private boolean shouldShowImeSwitcherLocked(int visibility) { if (!mShowOngoingImeSwitcherForPhones) return false; diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java index 805e7ffe7d76..9f1bccb9a27a 100644 --- a/services/core/java/com/android/server/wm/WindowManagerInternal.java +++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java @@ -954,4 +954,11 @@ public abstract class WindowManagerInternal { /** Returns the SurfaceControl accessibility services should use for accessibility overlays. */ public abstract SurfaceControl getA11yOverlayLayer(int displayId); + + /** + * Device has a software navigation bar (separate from the status bar) on specific display. + * + * @param displayId the id of display to check if there is a software navigation bar. + */ + public abstract boolean hasNavigationBar(int displayId); } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index b20be551c114..e6a341fe37e7 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -8380,6 +8380,11 @@ public class WindowManagerService extends IWindowManager.Stub } @Override + public boolean hasNavigationBar(int displayId) { + return WindowManagerService.this.hasNavigationBar(displayId); + } + + @Override public void setInputMethodTargetChangeListener(@NonNull ImeTargetChangeListener listener) { synchronized (mGlobalLock) { mImeTargetChangeListener = listener; |