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

Commit 1df32c5e authored by Yohei Yukawa's avatar Yohei Yukawa
Browse files

Revert "Instantiate InputMethodManager for each display"

This reverts commit c53d78e9.

Reason for revert:
Caused performance regression in
LatencyTests#testExpandNotificationsLatency.

Fix: 117434607
Bug: 111364446
Bug: 115893206
Test: atest google/perf/app-transition/sysui-latency-test-trace
Change-Id: If0d7a1b8f6d126d5a7c384ec4c2ff44260b8c35f
parent c53d78e9
Loading
Loading
Loading
Loading
+3 −7
Original line number Original line Diff line number Diff line
@@ -377,15 +377,11 @@ final class SystemServiceRegistry {
                return new DisplayManager(ctx.getOuterContext());
                return new DisplayManager(ctx.getOuterContext());
            }});
            }});


        // InputMethodManager has its own cache strategy based on display id to support apps that
        // still assume InputMethodManager is a per-process singleton and it's safe to directly
        // access internal fields via reflection.  Hence directly use ServiceFetcher instead of
        // StaticServiceFetcher/CachedServiceFetcher.
        registerService(Context.INPUT_METHOD_SERVICE, InputMethodManager.class,
        registerService(Context.INPUT_METHOD_SERVICE, InputMethodManager.class,
                new ServiceFetcher<InputMethodManager>() {
                new StaticServiceFetcher<InputMethodManager>() {
            @Override
            @Override
            public InputMethodManager getService(ContextImpl ctx) {
            public InputMethodManager createService() {
                return InputMethodManager.forContext(ctx);
                return InputMethodManager.getInstanceInternal();
            }});
            }});


        registerService(Context.TEXT_SERVICES_MANAGER_SERVICE, TextServicesManager.class,
        registerService(Context.TEXT_SERVICES_MANAGER_SERVICE, TextServicesManager.class,
+15 −155
Original line number Original line Diff line number Diff line
@@ -48,7 +48,6 @@ import android.util.Pools.SimplePool;
import android.util.PrintWriterPrinter;
import android.util.PrintWriterPrinter;
import android.util.Printer;
import android.util.Printer;
import android.util.SparseArray;
import android.util.SparseArray;
import android.view.Display;
import android.view.InputChannel;
import android.view.InputChannel;
import android.view.InputEvent;
import android.view.InputEvent;
import android.view.InputEventSender;
import android.view.InputEventSender;
@@ -266,7 +265,7 @@ public final class InputMethodManager {
     * @hide
     * @hide
     */
     */
    public static void ensureDefaultInstanceForDefaultDisplayIfNecessary() {
    public static void ensureDefaultInstanceForDefaultDisplayIfNecessary() {
        forContextInternal(Display.DEFAULT_DISPLAY, Looper.getMainLooper());
        getInstanceInternal();
    }
    }


    private static final Object sLock = new Object();
    private static final Object sLock = new Object();
@@ -279,17 +278,6 @@ public final class InputMethodManager {
    @UnsupportedAppUsage
    @UnsupportedAppUsage
    static InputMethodManager sInstance;
    static InputMethodManager sInstance;


    /**
     * Global map between display to {@link InputMethodManager}.
     *
     * <p>Currently this map works like a so-called leaky singleton.  Once an instance is registered
     * for the associated display ID, that instance will never be garbage collected.</p>
     *
     * <p>TODO(Bug 116699479): Implement instance clean up mechanism.</p>
     */
    @GuardedBy("sLock")
    private static final SparseArray<InputMethodManager> sInstanceMap = new SparseArray<>();

    /**
    /**
     * @hide Flag for IInputMethodManager.windowGainedFocus: a view in
     * @hide Flag for IInputMethodManager.windowGainedFocus: a view in
     * the window has input focus.
     * the window has input focus.
@@ -347,8 +335,6 @@ public final class InputMethodManager {
    // Our generic input connection if the current target does not have its own.
    // Our generic input connection if the current target does not have its own.
    final IInputContext mIInputContext;
    final IInputContext mIInputContext;


    private final int mDisplayId;

    /**
    /**
     * True if this input method client is active, initially false.
     * True if this input method client is active, initially false.
     */
     */
@@ -466,29 +452,6 @@ public final class InputMethodManager {
        return afm != null && afm.isAutofillUiShowing();
        return afm != null && afm.isAutofillUiShowing();
    }
    }


    /**
     * Checks the consistency between {@link InputMethodManager} state and {@link View} state.
     *
     * @param view {@link View} to be checked
     * @return {@code true} if {@code view} is not {@code null} and there is a {@link Context}
     *         mismatch between {@link InputMethodManager} and {@code view}
     */
    private boolean shouldDispatchToViewContext(@Nullable View view) {
        if (view == null) {
            return false;
        }
        final int viewDisplayId = getDisplayId(view.getContext());
        if (viewDisplayId != mDisplayId) {
            Log.w(TAG, "b/117267690: Context mismatch found. view=" + view + " belongs to"
                    + " displayId=" + viewDisplayId
                    + " but InputMethodManager belongs to displayId=" + mDisplayId
                    + ". Use the right InputMethodManager instance to avoid performance overhead.",
                    new Throwable());
            return true;
        }
        return false;
    }

    private static boolean canStartInput(View servedView) {
    private static boolean canStartInput(View servedView) {
        // We can start input ether the servedView has window focus
        // We can start input ether the servedView has window focus
        // or the activity is showing autofill ui.
        // or the activity is showing autofill ui.
@@ -770,57 +733,33 @@ public final class InputMethodManager {
                });
                });
    }
    }


    InputMethodManager(int displayId, Looper looper) throws ServiceNotFoundException {
    InputMethodManager(Looper looper) throws ServiceNotFoundException {
        mService = getIInputMethodManager();
        mService = getIInputMethodManager();
        mMainLooper = looper;
        mMainLooper = looper;
        mH = new H(looper);
        mH = new H(looper);
        mDisplayId = displayId;
        mIInputContext = new ControlledInputConnectionWrapper(looper,
        mIInputContext = new ControlledInputConnectionWrapper(looper,
                mDummyInputConnection, this);
                mDummyInputConnection, this);
    }
    }


    private static int getDisplayId(Context context) {
        final Display display = context.getDisplay();
        return display != null ? display.getDisplayId() : Display.DEFAULT_DISPLAY;
    }

    /**
    /**
     * Retrieve an instance for the given {@link Context}, creating it if it doesn't already exist.
     * Retrieve the global {@link InputMethodManager} instance, creating it if it doesn't already
     * exist.
     *
     *
     * @param context {@link Context} for which IME APIs need to work
     * @return global {@link InputMethodManager} instance
     * @return {@link InputMethodManager} instance
     * @hide
     * @hide
     */
     */
    @Nullable
    public static InputMethodManager getInstanceInternal() {
    public static InputMethodManager forContext(Context context) {
        final int displayId = getDisplayId(context);
        // For better backward compatibility, we always use Looper.getMainLooper() for the default
        // display case.
        final Looper looper = displayId == Display.DEFAULT_DISPLAY
                ? Looper.getMainLooper() : context.getMainLooper();
        return forContextInternal(displayId, looper);
    }

    @Nullable
    private static InputMethodManager forContextInternal(int displayId, Looper looper) {
        final boolean isDefaultDisplay = displayId == Display.DEFAULT_DISPLAY;
        synchronized (sLock) {
        synchronized (sLock) {
            InputMethodManager instance = sInstanceMap.get(displayId);
            if (sInstance == null) {
            if (instance != null) {
                return instance;
            }
                try {
                try {
                instance = new InputMethodManager(displayId, looper);
                    final InputMethodManager imm = new InputMethodManager(Looper.getMainLooper());
                instance.mService.addClient(instance.mClient, instance.mIInputContext, displayId);
                    imm.mService.addClient(imm.mClient, imm.mIInputContext);
                    sInstance = imm;
                } catch (ServiceNotFoundException | RemoteException e) {
                } catch (ServiceNotFoundException | RemoteException e) {
                    throw new IllegalStateException(e);
                    throw new IllegalStateException(e);
                }
                }
            // For backward compatibility, store the instance also to sInstance for default display.
            if (sInstance == null && isDefaultDisplay) {
                sInstance = instance;
            }
            }
            sInstanceMap.put(displayId, instance);
            return sInstance;
            return instance;
        }
        }
    }
    }


@@ -977,11 +916,6 @@ public final class InputMethodManager {
     * input method.
     * input method.
     */
     */
    public boolean isActive(View view) {
    public boolean isActive(View view) {
        // Re-dispatch if there is a context mismatch.
        if (shouldDispatchToViewContext(view)) {
            return view.getContext().getSystemService(InputMethodManager.class).isActive(view);
        }

        checkFocus();
        checkFocus();
        synchronized (mH) {
        synchronized (mH) {
            return (mServedView == view
            return (mServedView == view
@@ -1072,13 +1006,6 @@ public final class InputMethodManager {
    }
    }


    public void displayCompletions(View view, CompletionInfo[] completions) {
    public void displayCompletions(View view, CompletionInfo[] completions) {
        // Re-dispatch if there is a context mismatch.
        if (shouldDispatchToViewContext(view)) {
            view.getContext().getSystemService(InputMethodManager.class)
                    .displayCompletions(view, completions);
            return;
        }

        checkFocus();
        checkFocus();
        synchronized (mH) {
        synchronized (mH) {
            if (mServedView != view && (mServedView == null
            if (mServedView != view && (mServedView == null
@@ -1097,13 +1024,6 @@ public final class InputMethodManager {
    }
    }


    public void updateExtractedText(View view, int token, ExtractedText text) {
    public void updateExtractedText(View view, int token, ExtractedText text) {
        // Re-dispatch if there is a context mismatch.
        if (shouldDispatchToViewContext(view)) {
            view.getContext().getSystemService(InputMethodManager.class)
                    .updateExtractedText(view, token, text);
            return;
        }

        checkFocus();
        checkFocus();
        synchronized (mH) {
        synchronized (mH) {
            if (mServedView != view && (mServedView == null
            if (mServedView != view && (mServedView == null
@@ -1145,12 +1065,6 @@ public final class InputMethodManager {
     * 0 or have the {@link #SHOW_IMPLICIT} bit set.
     * 0 or have the {@link #SHOW_IMPLICIT} bit set.
     */
     */
    public boolean showSoftInput(View view, int flags) {
    public boolean showSoftInput(View view, int flags) {
        // Re-dispatch if there is a context mismatch.
        if (shouldDispatchToViewContext(view)) {
            return view.getContext().getSystemService(InputMethodManager.class)
                    .showSoftInput(view, flags);
        }

        return showSoftInput(view, flags, null);
        return showSoftInput(view, flags, null);
    }
    }


@@ -1213,12 +1127,6 @@ public final class InputMethodManager {
     * {@link #RESULT_HIDDEN}.
     * {@link #RESULT_HIDDEN}.
     */
     */
    public boolean showSoftInput(View view, int flags, ResultReceiver resultReceiver) {
    public boolean showSoftInput(View view, int flags, ResultReceiver resultReceiver) {
        // Re-dispatch if there is a context mismatch.
        if (shouldDispatchToViewContext(view)) {
            return view.getContext().getSystemService(InputMethodManager.class)
                    .showSoftInput(view, flags, resultReceiver);
        }

        checkFocus();
        checkFocus();
        synchronized (mH) {
        synchronized (mH) {
            if (mServedView != view && (mServedView == null
            if (mServedView != view && (mServedView == null
@@ -1382,12 +1290,6 @@ public final class InputMethodManager {
     * @param view The view whose text has changed.
     * @param view The view whose text has changed.
     */
     */
    public void restartInput(View view) {
    public void restartInput(View view) {
        // Re-dispatch if there is a context mismatch.
        if (shouldDispatchToViewContext(view)) {
            view.getContext().getSystemService(InputMethodManager.class).restartInput(view);
            return;
        }

        checkFocus();
        checkFocus();
        synchronized (mH) {
        synchronized (mH) {
            if (mServedView != view && (mServedView == null
            if (mServedView != view && (mServedView == null
@@ -1812,13 +1714,6 @@ public final class InputMethodManager {
     */
     */
    public void updateSelection(View view, int selStart, int selEnd,
    public void updateSelection(View view, int selStart, int selEnd,
            int candidatesStart, int candidatesEnd) {
            int candidatesStart, int candidatesEnd) {
        // Re-dispatch if there is a context mismatch.
        if (shouldDispatchToViewContext(view)) {
            view.getContext().getSystemService(InputMethodManager.class)
                    .updateSelection(view, selStart, selEnd, candidatesStart, candidatesEnd);
            return;
        }

        checkFocus();
        checkFocus();
        synchronized (mH) {
        synchronized (mH) {
            if ((mServedView != view && (mServedView == null
            if ((mServedView != view && (mServedView == null
@@ -1856,12 +1751,6 @@ public final class InputMethodManager {
     * Notify the event when the user tapped or clicked the text view.
     * Notify the event when the user tapped or clicked the text view.
     */
     */
    public void viewClicked(View view) {
    public void viewClicked(View view) {
        // Re-dispatch if there is a context mismatch.
        if (shouldDispatchToViewContext(view)) {
            view.getContext().getSystemService(InputMethodManager.class).viewClicked(view);
            return;
        }

        final boolean focusChanged = mServedView != mNextServedView;
        final boolean focusChanged = mServedView != mNextServedView;
        checkFocus();
        checkFocus();
        synchronized (mH) {
        synchronized (mH) {
@@ -1926,13 +1815,6 @@ public final class InputMethodManager {
     */
     */
    @Deprecated
    @Deprecated
    public void updateCursor(View view, int left, int top, int right, int bottom) {
    public void updateCursor(View view, int left, int top, int right, int bottom) {
        // Re-dispatch if there is a context mismatch.
        if (shouldDispatchToViewContext(view)) {
            view.getContext().getSystemService(InputMethodManager.class)
                    .updateCursor(view, left, top, right, bottom);
            return;
        }

        checkFocus();
        checkFocus();
        synchronized (mH) {
        synchronized (mH) {
            if ((mServedView != view && (mServedView == null
            if ((mServedView != view && (mServedView == null
@@ -1964,13 +1846,6 @@ public final class InputMethodManager {
        if (view == null || cursorAnchorInfo == null) {
        if (view == null || cursorAnchorInfo == null) {
            return;
            return;
        }
        }
        // Re-dispatch if there is a context mismatch.
        if (shouldDispatchToViewContext(view)) {
            view.getContext().getSystemService(InputMethodManager.class)
                    .updateCursorAnchorInfo(view, cursorAnchorInfo);
            return;
        }

        checkFocus();
        checkFocus();
        synchronized (mH) {
        synchronized (mH) {
            if ((mServedView != view &&
            if ((mServedView != view &&
@@ -2016,13 +1891,6 @@ public final class InputMethodManager {
     * @param data Any data to include with the command.
     * @param data Any data to include with the command.
     */
     */
    public void sendAppPrivateCommand(View view, String action, Bundle data) {
    public void sendAppPrivateCommand(View view, String action, Bundle data) {
        // Re-dispatch if there is a context mismatch.
        if (shouldDispatchToViewContext(view)) {
            view.getContext().getSystemService(InputMethodManager.class)
                    .sendAppPrivateCommand(view, action, data);
            return;
        }

        checkFocus();
        checkFocus();
        synchronized (mH) {
        synchronized (mH) {
            if ((mServedView != view && (mServedView == null
            if ((mServedView != view && (mServedView == null
@@ -2194,13 +2062,6 @@ public final class InputMethodManager {
     */
     */
    public void dispatchKeyEventFromInputMethod(@Nullable View targetView,
    public void dispatchKeyEventFromInputMethod(@Nullable View targetView,
            @NonNull KeyEvent event) {
            @NonNull KeyEvent event) {
        // Re-dispatch if there is a context mismatch.
        if (shouldDispatchToViewContext(targetView)) {
            targetView.getContext().getSystemService(InputMethodManager.class)
                    .dispatchKeyEventFromInputMethod(targetView, event);
            return;
        }

        synchronized (mH) {
        synchronized (mH) {
            ViewRootImpl viewRootImpl = targetView != null ? targetView.getViewRootImpl() : null;
            ViewRootImpl viewRootImpl = targetView != null ? targetView.getViewRootImpl() : null;
            if (viewRootImpl == null) {
            if (viewRootImpl == null) {
@@ -2690,7 +2551,6 @@ public final class InputMethodManager {
        sb.append(",windowFocus=" + view.hasWindowFocus());
        sb.append(",windowFocus=" + view.hasWindowFocus());
        sb.append(",autofillUiShowing=" + isAutofillUIShowing(view));
        sb.append(",autofillUiShowing=" + isAutofillUIShowing(view));
        sb.append(",window=" + view.getWindowToken());
        sb.append(",window=" + view.getWindowToken());
        sb.append(",displayId=" + getDisplayId(view.getContext()));
        sb.append(",temporaryDetach=" + view.isTemporarilyDetached());
        sb.append(",temporaryDetach=" + view.isTemporarilyDetached());
        return sb.toString();
        return sb.toString();
    }
    }
+1 −2
Original line number Original line Diff line number Diff line
@@ -31,8 +31,7 @@ import com.android.internal.view.IInputMethodClient;
 * applications.
 * applications.
 */
 */
interface IInputMethodManager {
interface IInputMethodManager {
    void addClient(in IInputMethodClient client, in IInputContext inputContext,
    void addClient(in IInputMethodClient client, in IInputContext inputContext);
            int untrustedDisplayId);


    // TODO: Use ParceledListSlice instead
    // TODO: Use ParceledListSlice instead
    List<InputMethodInfo> getInputMethodList();
    List<InputMethodInfo> getInputMethodList();
+1 −28
Original line number Original line Diff line number Diff line
@@ -51,9 +51,6 @@ public final class InputBindResult implements Parcelable {
            ResultCode.ERROR_INVALID_USER,
            ResultCode.ERROR_INVALID_USER,
            ResultCode.ERROR_NULL_EDITOR_INFO,
            ResultCode.ERROR_NULL_EDITOR_INFO,
            ResultCode.ERROR_NOT_IME_TARGET_WINDOW,
            ResultCode.ERROR_NOT_IME_TARGET_WINDOW,
            ResultCode.ERROR_NO_EDITOR,
            ResultCode.ERROR_DISPLAY_ID_MISMATCH,
            ResultCode.ERROR_INVALID_DISPLAY_ID,
    })
    })
    public @interface ResultCode {
    public @interface ResultCode {
        /**
        /**
@@ -142,22 +139,13 @@ public final class InputBindResult implements Parcelable {
         * The client should try to restart input when its {@link android.view.Window} is focused
         * The client should try to restart input when its {@link android.view.Window} is focused
         * again.</p>
         * again.</p>
         *
         *
         * @see com.android.server.wm.WindowManagerInternal#isInputMethodClientFocus(int, int, int)
         * @see com.android.server.wm.WindowManagerInternal#isInputMethodClientFocus(int, int)
         */
         */
        int ERROR_NOT_IME_TARGET_WINDOW = 11;
        int ERROR_NOT_IME_TARGET_WINDOW = 11;
        /**
        /**
         * Indicates that focused view in the current window is not an editor.
         * Indicates that focused view in the current window is not an editor.
         */
         */
        int ERROR_NO_EDITOR = 12;
        int ERROR_NO_EDITOR = 12;
        /**
         * Indicates that there is a mismatch in display ID between IME client and focused Window.
         */
        int ERROR_DISPLAY_ID_MISMATCH = 13;
        /**
         * Indicates that current IME client is no longer allowed to access to the associated
         * display.
         */
        int ERROR_INVALID_DISPLAY_ID = 14;
    }
    }


    @ResultCode
    @ResultCode
@@ -283,10 +271,6 @@ public final class InputBindResult implements Parcelable {
                return "ERROR_NULL_EDITOR_INFO";
                return "ERROR_NULL_EDITOR_INFO";
            case ResultCode.ERROR_NOT_IME_TARGET_WINDOW:
            case ResultCode.ERROR_NOT_IME_TARGET_WINDOW:
                return "ERROR_NOT_IME_TARGET_WINDOW";
                return "ERROR_NOT_IME_TARGET_WINDOW";
            case ResultCode.ERROR_DISPLAY_ID_MISMATCH:
                return "ERROR_DISPLAY_ID_MISMATCH";
            case ResultCode.ERROR_INVALID_DISPLAY_ID:
                return "ERROR_INVALID_DISPLAY_ID";
            default:
            default:
                return "Unknown(" + result + ")";
                return "Unknown(" + result + ")";
        }
        }
@@ -332,15 +316,4 @@ public final class InputBindResult implements Parcelable {
     */
     */
    public static final InputBindResult INVALID_USER = error(ResultCode.ERROR_INVALID_USER);
    public static final InputBindResult INVALID_USER = error(ResultCode.ERROR_INVALID_USER);


    /**
     * Predefined error object for {@link ResultCode#ERROR_DISPLAY_ID_MISMATCH}.
     */
    public static final InputBindResult DISPLAY_ID_MISMATCH =
            error(ResultCode.ERROR_DISPLAY_ID_MISMATCH);

    /**
     * Predefined error object for {@link ResultCode#ERROR_INVALID_DISPLAY_ID}.
     */
    public static final InputBindResult INVALID_DISPLAY_ID =
            error(ResultCode.ERROR_INVALID_DISPLAY_ID);
}
}
+16 −58
Original line number Original line Diff line number Diff line
@@ -421,7 +421,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
        final IInputContext inputContext;
        final IInputContext inputContext;
        final int uid;
        final int uid;
        final int pid;
        final int pid;
        final int selfReportedDisplayId;
        final InputBinding binding;
        final InputBinding binding;
        final ClientDeathRecipient clientDeathRecipient;
        final ClientDeathRecipient clientDeathRecipient;


@@ -431,18 +430,16 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
        @Override
        @Override
        public String toString() {
        public String toString() {
            return "ClientState{" + Integer.toHexString(
            return "ClientState{" + Integer.toHexString(
                    System.identityHashCode(this)) + " uid=" + uid
                    System.identityHashCode(this)) + " uid " + uid
                    + " pid=" + pid + " displayId=" + selfReportedDisplayId + "}";
                    + " pid " + pid + "}";
        }
        }


        ClientState(IInputMethodClient _client, IInputContext _inputContext,
        ClientState(IInputMethodClient _client, IInputContext _inputContext,
                int _uid, int _pid, int _selfReportedDisplayId,
                int _uid, int _pid, ClientDeathRecipient _clientDeathRecipient) {
                ClientDeathRecipient _clientDeathRecipient) {
            client = _client;
            client = _client;
            inputContext = _inputContext;
            inputContext = _inputContext;
            uid = _uid;
            uid = _uid;
            pid = _pid;
            pid = _pid;
            selfReportedDisplayId = _selfReportedDisplayId;
            binding = new InputBinding(null, inputContext.asBinder(), uid, pid);
            binding = new InputBinding(null, inputContext.asBinder(), uid, pid);
            clientDeathRecipient = _clientDeathRecipient;
            clientDeathRecipient = _clientDeathRecipient;
        }
        }
@@ -1748,21 +1745,15 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
     *               process
     *               process
     * @param inputContext communication channel for the dummy
     * @param inputContext communication channel for the dummy
     *                     {@link android.view.inputmethod.InputConnection}
     *                     {@link android.view.inputmethod.InputConnection}
     * @param selfReportedDisplayId self-reported display ID to which the client is associated.
     *                              Whether the client is still allowed to access to this display
     *                              or not needs to be evaluated every time the client interacts
     *                              with the display
     */
     */
    @Override
    @Override
    public void addClient(IInputMethodClient client, IInputContext inputContext,
    public void addClient(IInputMethodClient client, IInputContext inputContext) {
            int selfReportedDisplayId) {
        final int callerUid = Binder.getCallingUid();
        final int callerUid = Binder.getCallingUid();
        final int callerPid = Binder.getCallingPid();
        final int callerPid = Binder.getCallingPid();
        synchronized (mMethodMap) {
        synchronized (mMethodMap) {
            // TODO: Optimize this linear search.
            // TODO: Optimize this linear search.
            for (ClientState state : mClients.values()) {
            for (ClientState state : mClients.values()) {
                if (state.uid == callerUid && state.pid == callerPid
                if (state.uid == callerUid && state.pid == callerPid) {
                        && state.selfReportedDisplayId == selfReportedDisplayId) {
                    throw new SecurityException("uid=" + callerUid + "/pid=" + callerPid
                    throw new SecurityException("uid=" + callerUid + "/pid=" + callerPid
                            + " is already registered");
                            + " is already registered");
                }
                }
@@ -1773,25 +1764,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
            } catch (RemoteException e) {
            } catch (RemoteException e) {
                throw new IllegalStateException(e);
                throw new IllegalStateException(e);
            }
            }
            // We cannot fully avoid race conditions where the client UID already lost the access to
            mClients.put(client.asBinder(),
            // the given self-reported display ID, even if the client is not maliciously reporting
                    new ClientState(client, inputContext, callerUid, callerPid, deathRecipient));
            // a fake display ID. Unconditionally returning SecurityException just because the
            // client doesn't pass display ID verification can cause many test failures hence not an
            // option right now.  At the same time
            //    context.getSystemService(InputMethodManager.class)
            // is expected to return a valid non-null instance at any time if we do not choose to
            // have the client crash.  Thus we do not verify the display ID at all here.  Instead we
            // later check the display ID every time the client needs to interact with the specified
            // display.
            mClients.put(client.asBinder(), new ClientState(client, inputContext, callerUid,
                    callerPid, selfReportedDisplayId, deathRecipient));
        }
        }
    }
    }


    private boolean verifyDisplayId(ClientState cs) {
        return mWindowManagerInternal.isUidAllowedOnDisplay(cs.selfReportedDisplayId, cs.uid);
    }

    void removeClient(IInputMethodClient client) {
    void removeClient(IInputMethodClient client) {
        synchronized (mMethodMap) {
        synchronized (mMethodMap) {
            ClientState cs = mClients.remove(client.asBinder());
            ClientState cs = mClients.remove(client.asBinder());
@@ -1941,9 +1918,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
        mCurAttribute = attribute;
        mCurAttribute = attribute;


        // Check if the input method is changing.
        // Check if the input method is changing.
        // We expect the caller has already verified that the client is allowed to access this
        final int displayId = mWindowManagerInternal.getDisplayIdForWindow(
        // display ID.
                mCurFocusedWindow);
        final int displayId = mCurFocusedWindowClient.selfReportedDisplayId;
        if (mCurId != null && mCurId.equals(mCurMethodId) && displayId == mCurTokenDisplayId) {
        if (mCurId != null && mCurId.equals(mCurMethodId) && displayId == mCurTokenDisplayId) {
            if (cs.curSession != null) {
            if (cs.curSession != null) {
                // Fast case: if we are already connected to the input method,
                // Fast case: if we are already connected to the input method,
@@ -2008,11 +1984,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
                com.android.internal.R.string.input_method_binding_label);
                com.android.internal.R.string.input_method_binding_label);
        mCurIntent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity(
        mCurIntent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity(
                mContext, 0, new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS), 0));
                mContext, 0, new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS), 0));
        if (!verifyDisplayId(mCurFocusedWindowClient)) {
        final int displayId = mWindowManagerInternal.getDisplayIdForWindow(mCurFocusedWindow);
            // Wait, the client no longer has access to the display.
            return InputBindResult.INVALID_DISPLAY_ID;
        }
        final int displayId = mCurFocusedWindowClient.selfReportedDisplayId;
        mCurTokenDisplayId = (displayId != INVALID_DISPLAY) ? displayId : DEFAULT_DISPLAY;
        mCurTokenDisplayId = (displayId != INVALID_DISPLAY) ? displayId : DEFAULT_DISPLAY;


        if (bindCurrentInputMethodServiceLocked(mCurIntent, this, IME_CONNECTION_BIND_FLAGS)) {
        if (bindCurrentInputMethodServiceLocked(mCurIntent, this, IME_CONNECTION_BIND_FLAGS)) {
@@ -2612,8 +2584,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
                    if (cs == null) {
                    if (cs == null) {
                        throw new IllegalArgumentException("unknown client " + client.asBinder());
                        throw new IllegalArgumentException("unknown client " + client.asBinder());
                    }
                    }
                    if (!mWindowManagerInternal.isInputMethodClientFocus(cs.uid, cs.pid,
                    if (!mWindowManagerInternal.isInputMethodClientFocus(cs.uid, cs.pid)) {
                            cs.selfReportedDisplayId)) {
                        Slog.w(TAG, "Ignoring showSoftInput of uid " + uid + ": " + client);
                        Slog.w(TAG, "Ignoring showSoftInput of uid " + uid + ": " + client);
                        return false;
                        return false;
                    }
                    }
@@ -2697,8 +2668,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
                    if (cs == null) {
                    if (cs == null) {
                        throw new IllegalArgumentException("unknown client " + client.asBinder());
                        throw new IllegalArgumentException("unknown client " + client.asBinder());
                    }
                    }
                    if (!mWindowManagerInternal.isInputMethodClientFocus(cs.uid, cs.pid,
                    if (!mWindowManagerInternal.isInputMethodClientFocus(cs.uid, cs.pid)) {
                            cs.selfReportedDisplayId)) {
                        if (DEBUG) {
                        if (DEBUG) {
                            Slog.w(TAG, "Ignoring hideSoftInput of uid " + uid + ": " + client);
                            Slog.w(TAG, "Ignoring hideSoftInput of uid " + uid + ": " + client);
                        }
                        }
@@ -2797,8 +2767,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
        InputBindResult res = null;
        InputBindResult res = null;
        long ident = Binder.clearCallingIdentity();
        long ident = Binder.clearCallingIdentity();
        try {
        try {
            final int windowDisplayId =
                    mWindowManagerInternal.getDisplayIdForWindow(windowToken);
            synchronized (mMethodMap) {
            synchronized (mMethodMap) {
                if (DEBUG) Slog.v(TAG, "startInputOrWindowGainedFocusInternal: reason="
                if (DEBUG) Slog.v(TAG, "startInputOrWindowGainedFocusInternal: reason="
                        + InputMethodClient.getStartInputReason(startInputReason)
                        + InputMethodClient.getStartInputReason(startInputReason)
@@ -2817,15 +2785,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
                    throw new IllegalArgumentException("unknown client "
                    throw new IllegalArgumentException("unknown client "
                            + client.asBinder());
                            + 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,
                if (!mWindowManagerInternal.isInputMethodClientFocus(cs.uid, cs.pid)) {
                        cs.selfReportedDisplayId)) {
                    // Check with the window manager to make sure this client actually
                    // Check with the window manager to make sure this client actually
                    // has a window with focus.  If not, reject.  This is thread safe
                    // has a window with focus.  If not, reject.  This is thread safe
                    // because if the focus changes some time before or after, the
                    // because if the focus changes some time before or after, the
@@ -2897,9 +2858,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
                                // If focused display changed, we should unbind current method
                                // If focused display changed, we should unbind current method
                                // to make app window in previous display relayout after Ime
                                // to make app window in previous display relayout after Ime
                                // window token removed.
                                // window token removed.
                                // Note that we can trust client's display ID as long as it matches
                                final int newFocusDisplayId =
                                // to the display ID obtained from the window.
                                        mWindowManagerInternal.getDisplayIdForWindow(windowToken);
                                if (cs.selfReportedDisplayId != mCurTokenDisplayId) {
                                if (newFocusDisplayId != mCurTokenDisplayId) {
                                    unbindCurrentMethodLocked();
                                    unbindCurrentMethodLocked();
                                }
                                }
                            }
                            }
@@ -2997,7 +2958,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
    }
    }


    private boolean canShowInputMethodPickerLocked(IInputMethodClient client) {
    private boolean canShowInputMethodPickerLocked(IInputMethodClient client) {
        // TODO(yukawa): multi-display support.
        final int uid = Binder.getCallingUid();
        final int uid = Binder.getCallingUid();
        if (UserHandle.getAppId(uid) == Process.SYSTEM_UID) {
        if (UserHandle.getAppId(uid) == Process.SYSTEM_UID) {
            return true;
            return true;
@@ -3074,7 +3034,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
    @Override
    @Override
    public void showInputMethodAndSubtypeEnablerFromClient(
    public void showInputMethodAndSubtypeEnablerFromClient(
            IInputMethodClient client, String inputMethodId) {
            IInputMethodClient client, String inputMethodId) {
        // TODO(yukawa): Should we verify the display ID?
        if (!calledFromValidUser()) {
        if (!calledFromValidUser()) {
            return;
            return;
        }
        }
@@ -3270,7 +3229,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
     */
     */
    @Override
    @Override
    public int getInputMethodWindowVisibleHeight() {
    public int getInputMethodWindowVisibleHeight() {
        // TODO(yukawa): Should we verify the display ID?
        return mWindowManagerInternal.getInputMethodWindowVisibleHeight(mCurTokenDisplayId);
        return mWindowManagerInternal.getInputMethodWindowVisibleHeight(mCurTokenDisplayId);
    }
    }


Loading