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

Commit 018f47a2 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Revert "Instantiate InputMethodManager for each display""

parents cd317f42 1df32c5e
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