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

Commit e62cb766 authored by Nikolas Havrikov's avatar Nikolas Havrikov Committed by Android (Google) Code Review
Browse files

Merge "Refactor locking in input method framework"

parents 1cd3bfd4 3b5a09c1
Loading
Loading
Loading
Loading
+45 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.inputmethod;

/**
 * The implicit lock of this class serves as the global lock for
 * the {@link InputMethodManagerService} and its controllers,
 * which contain the main logic of the input method framework (IMF).
 *
 * <p>
 * This lock can be used as follows in code:
 * <pre>
 * synchronized (ImfLock.class) {
 *   ...
 * }
 * </pre>
 *
 * <p>
 * For annotations, you can use a similar syntax:
 * <pre>
 * &#64;GuardedBy("ImfLock.class")
 * myMethodDeclaration() {
 *   ...
 * }
 * </pre>
 */
final class ImfLock {
    private ImfLock() {
        // no instances
    }
}
+40 −40
Original line number Original line Diff line number Diff line
@@ -72,16 +72,16 @@ final class InputMethodBindingController {
    @NonNull private final WindowManagerInternal mWindowManagerInternal;
    @NonNull private final WindowManagerInternal mWindowManagerInternal;
    @NonNull private final Resources mRes;
    @NonNull private final Resources mRes;


    @GuardedBy("mMethodMap") private long mLastBindTime;
    @GuardedBy("ImfLock.class") private long mLastBindTime;
    @GuardedBy("mMethodMap") private boolean mHasConnection;
    @GuardedBy("ImfLock.class") private boolean mHasConnection;
    @GuardedBy("mMethodMap") @Nullable private String mCurId;
    @GuardedBy("ImfLock.class") @Nullable private String mCurId;
    @GuardedBy("mMethodMap") @Nullable private String mSelectedMethodId;
    @GuardedBy("ImfLock.class") @Nullable private String mSelectedMethodId;
    @GuardedBy("mMethodMap") @Nullable private Intent mCurIntent;
    @GuardedBy("ImfLock.class") @Nullable private Intent mCurIntent;
    @GuardedBy("mMethodMap") @Nullable private IInputMethod mCurMethod;
    @GuardedBy("ImfLock.class") @Nullable private IInputMethod mCurMethod;
    @GuardedBy("mMethodMap") private int mCurMethodUid = Process.INVALID_UID;
    @GuardedBy("ImfLock.class") private int mCurMethodUid = Process.INVALID_UID;
    @GuardedBy("mMethodMap") private IBinder mCurToken;
    @GuardedBy("ImfLock.class") private IBinder mCurToken;
    @GuardedBy("mMethodMap") private int mCurSeq;
    @GuardedBy("ImfLock.class") private int mCurSeq;
    @GuardedBy("mMethodMap") private boolean mVisibleBound;
    @GuardedBy("ImfLock.class") private boolean mVisibleBound;
    private boolean mSupportsStylusHw;
    private boolean mSupportsStylusHw;


    /**
    /**
@@ -146,7 +146,7 @@ final class InputMethodBindingController {
     * Time that we last initiated a bind to the input method, to determine
     * Time that we last initiated a bind to the input method, to determine
     * if we should try to disconnect and reconnect to it.
     * if we should try to disconnect and reconnect to it.
     */
     */
    @GuardedBy("mMethodMap")
    @GuardedBy("ImfLock.class")
    long getLastBindTime() {
    long getLastBindTime() {
        return mLastBindTime;
        return mLastBindTime;
    }
    }
@@ -155,7 +155,7 @@ final class InputMethodBindingController {
     * Set to true if our ServiceConnection is currently actively bound to
     * Set to true if our ServiceConnection is currently actively bound to
     * a service (whether or not we have gotten its IBinder back yet).
     * a service (whether or not we have gotten its IBinder back yet).
     */
     */
    @GuardedBy("mMethodMap")
    @GuardedBy("ImfLock.class")
    boolean hasConnection() {
    boolean hasConnection() {
        return mHasConnection;
        return mHasConnection;
    }
    }
@@ -168,7 +168,7 @@ final class InputMethodBindingController {
     *
     *
     * @see #getSelectedMethodId()
     * @see #getSelectedMethodId()
     */
     */
    @GuardedBy("mMethodMap")
    @GuardedBy("ImfLock.class")
    @Nullable
    @Nullable
    String getCurId() {
    String getCurId() {
        return mCurId;
        return mCurId;
@@ -187,13 +187,13 @@ final class InputMethodBindingController {
     *
     *
     * @see #getCurId()
     * @see #getCurId()
     */
     */
    @GuardedBy("mMethodMap")
    @GuardedBy("ImfLock.class")
    @Nullable
    @Nullable
    String getSelectedMethodId() {
    String getSelectedMethodId() {
        return mSelectedMethodId;
        return mSelectedMethodId;
    }
    }


    @GuardedBy("mMethodMap")
    @GuardedBy("ImfLock.class")
    void setSelectedMethodId(@Nullable String selectedMethodId) {
    void setSelectedMethodId(@Nullable String selectedMethodId) {
        mSelectedMethodId = selectedMethodId;
        mSelectedMethodId = selectedMethodId;
    }
    }
@@ -202,7 +202,7 @@ final class InputMethodBindingController {
     * The token we have made for the currently active input method, to
     * The token we have made for the currently active input method, to
     * identify it in the future.
     * identify it in the future.
     */
     */
    @GuardedBy("mMethodMap")
    @GuardedBy("ImfLock.class")
    IBinder getCurToken() {
    IBinder getCurToken() {
        return mCurToken;
        return mCurToken;
    }
    }
@@ -210,7 +210,7 @@ final class InputMethodBindingController {
    /**
    /**
     * The Intent used to connect to the current input method.
     * The Intent used to connect to the current input method.
     */
     */
    @GuardedBy("mMethodMap")
    @GuardedBy("ImfLock.class")
    @Nullable
    @Nullable
    Intent getCurIntent() {
    Intent getCurIntent() {
        return mCurIntent;
        return mCurIntent;
@@ -220,7 +220,7 @@ final class InputMethodBindingController {
     * The current binding sequence number, incremented every time there is
     * The current binding sequence number, incremented every time there is
     * a new bind performed.
     * a new bind performed.
     */
     */
    @GuardedBy("mMethodMap")
    @GuardedBy("ImfLock.class")
    int getSequenceNumber() {
    int getSequenceNumber() {
        return mCurSeq;
        return mCurSeq;
    }
    }
@@ -229,7 +229,7 @@ final class InputMethodBindingController {
     * Increase the current binding sequence number by one.
     * Increase the current binding sequence number by one.
     * Reset to 1 on overflow.
     * Reset to 1 on overflow.
     */
     */
    @GuardedBy("mMethodMap")
    @GuardedBy("ImfLock.class")
    void advanceSequenceNumber() {
    void advanceSequenceNumber() {
        mCurSeq += 1;
        mCurSeq += 1;
        if (mCurSeq <= 0) {
        if (mCurSeq <= 0) {
@@ -241,7 +241,7 @@ final class InputMethodBindingController {
     * If non-null, this is the input method service we are currently connected
     * If non-null, this is the input method service we are currently connected
     * to.
     * to.
     */
     */
    @GuardedBy("mMethodMap")
    @GuardedBy("ImfLock.class")
    @Nullable
    @Nullable
    IInputMethod getCurMethod() {
    IInputMethod getCurMethod() {
        return mCurMethod;
        return mCurMethod;
@@ -250,7 +250,7 @@ final class InputMethodBindingController {
    /**
    /**
     * If not {@link Process#INVALID_UID}, then the UID of {@link #getCurIntent()}.
     * If not {@link Process#INVALID_UID}, then the UID of {@link #getCurIntent()}.
     */
     */
    @GuardedBy("mMethodMap")
    @GuardedBy("ImfLock.class")
    int getCurMethodUid() {
    int getCurMethodUid() {
        return mCurMethodUid;
        return mCurMethodUid;
    }
    }
@@ -258,7 +258,7 @@ final class InputMethodBindingController {
    /**
    /**
     * Indicates whether {@link #mVisibleConnection} is currently in use.
     * Indicates whether {@link #mVisibleConnection} is currently in use.
     */
     */
    @GuardedBy("mMethodMap")
    @GuardedBy("ImfLock.class")
    boolean isVisibleBound() {
    boolean isVisibleBound() {
        return mVisibleBound;
        return mVisibleBound;
    }
    }
@@ -266,10 +266,10 @@ final class InputMethodBindingController {
    /**
    /**
     * Used to bring IME service up to visible adjustment while it is being shown.
     * Used to bring IME service up to visible adjustment while it is being shown.
     */
     */
    @GuardedBy("mMethodMap")
    @GuardedBy("ImfLock.class")
    private final ServiceConnection mVisibleConnection = new ServiceConnection() {
    private final ServiceConnection mVisibleConnection = new ServiceConnection() {
        @Override public void onBindingDied(ComponentName name) {
        @Override public void onBindingDied(ComponentName name) {
            synchronized (mMethodMap) {
            synchronized (ImfLock.class) {
                if (mVisibleBound) {
                if (mVisibleBound) {
                    unbindVisibleConnection();
                    unbindVisibleConnection();
                }
                }
@@ -286,12 +286,12 @@ final class InputMethodBindingController {
    /**
    /**
     * Used to bind the IME while it is not currently being shown.
     * Used to bind the IME while it is not currently being shown.
     */
     */
    @GuardedBy("mMethodMap")
    @GuardedBy("ImfLock.class")
    private final ServiceConnection mMainConnection = new ServiceConnection() {
    private final ServiceConnection mMainConnection = new ServiceConnection() {
        @Override
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
        public void onServiceConnected(ComponentName name, IBinder service) {
            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.onServiceConnected");
            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.onServiceConnected");
            synchronized (mMethodMap) {
            synchronized (ImfLock.class) {
                if (mCurIntent != null && name.equals(mCurIntent.getComponent())) {
                if (mCurIntent != null && name.equals(mCurIntent.getComponent())) {
                    mCurMethod = IInputMethod.Stub.asInterface(service);
                    mCurMethod = IInputMethod.Stub.asInterface(service);
                    updateCurrentMethodUid();
                    updateCurrentMethodUid();
@@ -318,7 +318,7 @@ final class InputMethodBindingController {
            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
        }
        }


        @GuardedBy("mMethodMap")
        @GuardedBy("ImfLock.class")
        private void updateCurrentMethodUid() {
        private void updateCurrentMethodUid() {
            final String curMethodPackage = mCurIntent.getComponent().getPackageName();
            final String curMethodPackage = mCurIntent.getComponent().getPackageName();
            final int curMethodUid = mPackageManagerInternal.getPackageUid(
            final int curMethodUid = mPackageManagerInternal.getPackageUid(
@@ -344,7 +344,7 @@ final class InputMethodBindingController {
            // refreshed when this method is called back.  Running
            // refreshed when this method is called back.  Running
            //    adb install -r <APK that implements the current IME>
            //    adb install -r <APK that implements the current IME>
            // would be a good way to trigger such a situation.
            // would be a good way to trigger such a situation.
            synchronized (mMethodMap) {
            synchronized (ImfLock.class) {
                if (DEBUG) {
                if (DEBUG) {
                    Slog.v(TAG, "Service disconnected: " + name + " mCurIntent=" + mCurIntent);
                    Slog.v(TAG, "Service disconnected: " + name + " mCurIntent=" + mCurIntent);
                }
                }
@@ -361,7 +361,7 @@ final class InputMethodBindingController {
        }
        }
    };
    };


    @GuardedBy("mMethodMap")
    @GuardedBy("ImfLock.class")
    void unbindCurrentMethod() {
    void unbindCurrentMethod() {
        if (mVisibleBound) {
        if (mVisibleBound) {
            unbindVisibleConnection();
            unbindVisibleConnection();
@@ -380,14 +380,14 @@ final class InputMethodBindingController {
        clearCurMethodAndSessions();
        clearCurMethodAndSessions();
    }
    }


    @GuardedBy("mMethodMap")
    @GuardedBy("ImfLock.class")
    private void clearCurMethodAndSessions() {
    private void clearCurMethodAndSessions() {
        mService.clearClientSessionsLocked();
        mService.clearClientSessionsLocked();
        mCurMethod = null;
        mCurMethod = null;
        mCurMethodUid = Process.INVALID_UID;
        mCurMethodUid = Process.INVALID_UID;
    }
    }


    @GuardedBy("mMethodMap")
    @GuardedBy("ImfLock.class")
    private void removeCurrentToken() {
    private void removeCurrentToken() {
        int curTokenDisplayId = mService.getCurTokenDisplayIdLocked();
        int curTokenDisplayId = mService.getCurTokenDisplayIdLocked();


@@ -400,7 +400,7 @@ final class InputMethodBindingController {
        mCurToken = null;
        mCurToken = null;
    }
    }


    @GuardedBy("mMethodMap")
    @GuardedBy("ImfLock.class")
    @NonNull
    @NonNull
    InputBindResult bindCurrentMethod() {
    InputBindResult bindCurrentMethod() {
        InputMethodInfo info = mMethodMap.get(mSelectedMethodId);
        InputMethodInfo info = mMethodMap.get(mSelectedMethodId);
@@ -438,7 +438,7 @@ final class InputMethodBindingController {
        return intent;
        return intent;
    }
    }


    @GuardedBy("mMethodMap")
    @GuardedBy("ImfLock.class")
    private void addFreshWindowToken() {
    private void addFreshWindowToken() {
        int displayIdToShowIme = mService.getDisplayIdToShowImeLocked();
        int displayIdToShowIme = mService.getDisplayIdToShowImeLocked();
        mCurToken = new Binder();
        mCurToken = new Binder();
@@ -458,19 +458,19 @@ final class InputMethodBindingController {
        }
        }
    }
    }


    @GuardedBy("mMethodMap")
    @GuardedBy("ImfLock.class")
    private void unbindMainConnection() {
    private void unbindMainConnection() {
        mContext.unbindService(mMainConnection);
        mContext.unbindService(mMainConnection);
        mHasConnection = false;
        mHasConnection = false;
    }
    }


    @GuardedBy("mMethodMap")
    @GuardedBy("ImfLock.class")
    void unbindVisibleConnection() {
    void unbindVisibleConnection() {
        mContext.unbindService(mVisibleConnection);
        mContext.unbindService(mVisibleConnection);
        mVisibleBound = false;
        mVisibleBound = false;
    }
    }


    @GuardedBy("mMethodMap")
    @GuardedBy("ImfLock.class")
    private boolean bindCurrentInputMethodService(ServiceConnection conn, int flags) {
    private boolean bindCurrentInputMethodService(ServiceConnection conn, int flags) {
        if (mCurIntent == null || conn == null) {
        if (mCurIntent == null || conn == null) {
            Slog.e(TAG, "--- bind failed: service = " + mCurIntent + ", conn = " + conn);
            Slog.e(TAG, "--- bind failed: service = " + mCurIntent + ", conn = " + conn);
@@ -480,14 +480,14 @@ final class InputMethodBindingController {
                new UserHandle(mSettings.getCurrentUserId()));
                new UserHandle(mSettings.getCurrentUserId()));
    }
    }


    @GuardedBy("mMethodMap")
    @GuardedBy("ImfLock.class")
    private boolean bindCurrentInputMethodServiceVisibleConnection() {
    private boolean bindCurrentInputMethodServiceVisibleConnection() {
        mVisibleBound = bindCurrentInputMethodService(mVisibleConnection,
        mVisibleBound = bindCurrentInputMethodService(mVisibleConnection,
                IME_VISIBLE_BIND_FLAGS);
                IME_VISIBLE_BIND_FLAGS);
        return mVisibleBound;
        return mVisibleBound;
    }
    }


    @GuardedBy("mMethodMap")
    @GuardedBy("ImfLock.class")
    private boolean bindCurrentInputMethodServiceMainConnection() {
    private boolean bindCurrentInputMethodServiceMainConnection() {
        mHasConnection = bindCurrentInputMethodService(mMainConnection,
        mHasConnection = bindCurrentInputMethodService(mMainConnection,
                mImeConnectionBindFlags);
                mImeConnectionBindFlags);
@@ -500,7 +500,7 @@ final class InputMethodBindingController {
     * <p>
     * <p>
     * Performs a rebind if no binding is achieved in {@link #TIME_TO_RECONNECT} milliseconds.
     * Performs a rebind if no binding is achieved in {@link #TIME_TO_RECONNECT} milliseconds.
     */
     */
    @GuardedBy("mMethodMap")
    @GuardedBy("ImfLock.class")
    void setCurrentMethodVisible() {
    void setCurrentMethodVisible() {
        if (mCurMethod != null) {
        if (mCurMethod != null) {
            if (DEBUG) Slog.d(TAG, "setCurrentMethodVisible: mCurToken=" + mCurToken);
            if (DEBUG) Slog.d(TAG, "setCurrentMethodVisible: mCurToken=" + mCurToken);
@@ -541,7 +541,7 @@ final class InputMethodBindingController {
    /**
    /**
     * Remove the binding needed for the IME to be shown.
     * Remove the binding needed for the IME to be shown.
     */
     */
    @GuardedBy("mMethodMap")
    @GuardedBy("ImfLock.class")
    void setCurrentMethodNotVisible() {
    void setCurrentMethodNotVisible() {
        if (mVisibleBound) {
        if (mVisibleBound) {
            unbindVisibleConnection();
            unbindVisibleConnection();