Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d136b9bd authored by Cosmin Băieș's avatar Cosmin Băieș
Browse files

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
Change-Id: I4d7a062a9abeaf59218505d384f94e04e1a8ed74
parent 03021851
Loading
Loading
Loading
Loading
+6 −19
Original line number Diff line number Diff line
@@ -116,7 +116,6 @@ import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.proto.ProtoOutputStream;
import android.view.IWindowManager;
import android.view.InputChannel;
import android.view.InputDevice;
import android.view.MotionEvent;
@@ -124,7 +123,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;
@@ -2989,9 +2987,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)
@@ -2999,21 +3001,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;
+7 −0
Original line number Diff line number Diff line
@@ -963,4 +963,11 @@ public abstract class WindowManagerInternal {
    public abstract void captureDisplay(int displayId,
                                        @Nullable ScreenCapture.CaptureArgs captureArgs,
                                        ScreenCapture.ScreenCaptureListener listener);

    /**
     * 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);
}
+5 −0
Original line number Diff line number Diff line
@@ -8412,6 +8412,11 @@ public class WindowManagerService extends IWindowManager.Stub
            WindowManagerService.this.captureDisplay(displayId, captureArgs, listener);
        }

        @Override
        public boolean hasNavigationBar(int displayId) {
            return WindowManagerService.this.hasNavigationBar(displayId);
        }

        @Override
        public void setInputMethodTargetChangeListener(@NonNull ImeTargetChangeListener listener) {
            synchronized (mGlobalLock) {