From 05293b424ba57bf1e45e526fb4695434095a9b70 Mon Sep 17 00:00:00 2001 From: Nikolas Havrikov Date: Mon, 8 Nov 2021 11:53:13 +0100 Subject: [PATCH 01/43] Remove unused member mIsLowRam Bug: 205676419 Test: make Change-Id: Ie2c00e132052be5da9fe1d582b6e1655444ab2f8 --- .../android/server/inputmethod/InputMethodManagerService.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index cb76d8325c4b9..bd7d41e573362 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -321,7 +321,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub final boolean mHasFeature; private final ArrayMap> mAdditionalSubtypeMap = new ArrayMap<>(); - private final boolean mIsLowRam; private final AppOpsManager mAppOpsManager; private final UserManager mUserManager; private final UserManagerInternal mUserManagerInternal; @@ -1625,7 +1624,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mPlatformCompat = IPlatformCompat.Stub.asInterface( ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE)); mSlotIme = mContext.getString(com.android.internal.R.string.status_bar_ime); - mIsLowRam = ActivityManager.isLowRamDeviceStatic(); Bundle extras = new Bundle(); extras.putBoolean(Notification.EXTRA_ALLOW_DURING_SETUP, true); From 0f69d73b9ccc206f325bfd0374dc95f973c68778 Mon Sep 17 00:00:00 2001 From: Nikolas Havrikov Date: Mon, 8 Nov 2021 11:54:33 +0100 Subject: [PATCH 02/43] Use method references where available Bug: 205676419 Test: make Change-Id: Ida6cb4b49c42af00aaa0968de1cf9921ea6fc511 --- .../server/inputmethod/InputMethodManagerService.java | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index bd7d41e573362..5845f45c4fcaf 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -1609,13 +1609,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class); mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class); mInputManagerInternal = LocalServices.getService(InputManagerInternal.class); - mImeDisplayValidator = displayId -> mWindowManagerInternal.getDisplayImePolicy(displayId); - mCaller = new HandlerCaller(context, thread.getLooper(), new HandlerCaller.Callback() { - @Override - public void executeMessage(Message msg) { - handleMessage(msg); - } - }, true /*asyncHandler*/); + mImeDisplayValidator = mWindowManagerInternal::getDisplayImePolicy; + mCaller = new HandlerCaller(context, thread.getLooper(), this::handleMessage, + true /*asyncHandler*/); mAppOpsManager = mContext.getSystemService(AppOpsManager.class); mUserManager = mContext.getSystemService(UserManager.class); mUserManagerInternal = LocalServices.getService(UserManagerInternal.class); From 69bf6483a3f73c0393d8e2c73b510439bedb0306 Mon Sep 17 00:00:00 2001 From: Nikolas Havrikov Date: Mon, 8 Nov 2021 14:15:32 +0100 Subject: [PATCH 03/43] Make members final in IMMS where appropriate Bug: 205676419 Test: make Change-Id: I2a84254f5ce59f3e6ca230e392742f52c0e96432 --- .../server/inputmethod/InputMethodManagerService.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 5845f45c4fcaf..82902a65d952f 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -373,8 +373,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub private NotificationManager mNotificationManager; KeyguardManager mKeyguardManager; private @Nullable StatusBarManagerService mStatusBar; - private Notification.Builder mImeSwitcherNotification; - private PendingIntent mImeSwitchPendingIntent; + private final Notification.Builder mImeSwitcherNotification; + private final PendingIntent mImeSwitchPendingIntent; private boolean mShowOngoingImeSwitcherForPhones; private boolean mNotificationShown; @@ -647,7 +647,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub */ boolean mIsInteractive = true; - private IPlatformCompat mPlatformCompat; + private final IPlatformCompat mPlatformCompat; int mBackDisposition = InputMethodService.BACK_DISPOSITION_DEFAULT; @@ -757,7 +757,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub private final WeakHashMap mImeTargetWindowMap = new WeakHashMap<>(); private static final class SoftInputShowHideHistory { - private Entry[] mEntries = new Entry[16]; + private final Entry[] mEntries = new Entry[16]; private int mNextIndex = 0; private static final AtomicInteger sSequenceNumber = new AtomicInteger(0); @@ -1511,7 +1511,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub private UserSwitchHandlerTask mUserSwitchHandlerTask; public static final class Lifecycle extends SystemService { - private InputMethodManagerService mService; + private final InputMethodManagerService mService; public Lifecycle(Context context) { super(context); From 67723bf299d79eeb7b88d255ce371f04c926d343 Mon Sep 17 00:00:00 2001 From: Nikolas Havrikov Date: Fri, 5 Nov 2021 13:53:48 +0100 Subject: [PATCH 04/43] Encapsulate IMMS members This is a step in a larger refactoring. Bug: 205676419 Test: make Change-Id: I9cbdd6606f7a44796f6074d0b2e904913bd48e51 --- .../InputMethodManagerService.java | 290 +++++++++++------- 1 file changed, 179 insertions(+), 111 deletions(-) diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 82902a65d952f..8e6b7ad4adbcf 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -462,25 +462,48 @@ public class InputMethodManagerService extends IInputMethodManager.Stub /** * Id obtained with {@link InputMethodInfo#getId()} for the currently selected input method. - * method. This is to be synchronized with the secure settings keyed with + * This is to be synchronized with the secure settings keyed with * {@link Settings.Secure#DEFAULT_INPUT_METHOD}. * *

This can be transiently {@code null} when the system is re-initializing input method * settings, e.g., the system locale is just changed.

* - *

Note that {@link #mCurId} is used to track which IME is being connected to + *

Note that {@link #getCurId()} is used to track which IME is being connected to * {@link InputMethodManagerService}.

* - * @see #mCurId + * @see #getCurId() */ @Nullable - String mCurMethodId; + private String getSelectedMethodId() { + return mSelectedMethodId; + } + + private void setSelectedMethodId(@Nullable String selectedMethodId) { + mSelectedMethodId = selectedMethodId; + } + @Nullable + private String mSelectedMethodId; /** * The current binding sequence number, incremented every time there is * a new bind performed. */ - int mCurSeq; + private int getSequenceNumber() { + return mCurSeq; + } + + /** + * Increase the current binding sequence number by one. + * Reset to 1 on overflow. + */ + private void advanceSequenceNumber() { + mCurSeq += 1; + if (mCurSeq <= 0) { + mCurSeq = 1; + } + } + + private int mCurSeq; /** * {@code true} if the Ime policy has been set to {@link WindowManager#DISPLAY_IME_POLICY_HIDE}. @@ -537,10 +560,19 @@ public class InputMethodManagerService extends IInputMethodManager.Stub * *

This can be {@code null} when no input method is connected.

* - * @see #mCurMethodId + * @see #getSelectedMethodId() */ @Nullable - String mCurId; + private String getCurId() { + return mCurId; + } + + private void setCurId(@Nullable String curId) { + mCurId = curId; + } + + @Nullable + private String mCurId; /** * The current subtype of the current input method. @@ -556,7 +588,14 @@ public class InputMethodManagerService extends IInputMethodManager.Stub * Set to true if our ServiceConnection is currently actively bound to * a service (whether or not we have gotten its IBinder back yet). */ - boolean mHaveConnection; + private boolean hasConnection() { + return mHasConnection; + } + + private void setHasConnection(boolean hasConnection) { + mHasConnection = hasConnection; + } + private boolean mHasConnection; /** * Set if the client has asked for the input method to be shown. @@ -586,13 +625,31 @@ public class InputMethodManagerService extends IInputMethodManager.Stub /** * The Intent used to connect to the current input method. */ - Intent mCurIntent; + @Nullable + private Intent getCurIntent() { + return mCurIntent; + } + + private void setCurIntent(@Nullable Intent curIntent) { + mCurIntent = curIntent; + } + + @Nullable + private Intent mCurIntent; /** * The token we have made for the currently active input method, to * identify it in the future. */ - IBinder mCurToken; + private IBinder getCurToken() { + return mCurToken; + } + + private void setCurToken(IBinder curToken) { + mCurToken = curToken; + } + + private IBinder mCurToken; /** * The displayId of current active input method. @@ -621,7 +678,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub IInputMethod mCurMethod; /** - * If not {@link Process#INVALID_UID}, then the UID of {@link #mCurIntent}. + * If not {@link Process#INVALID_UID}, then the UID of {@link #getCurIntent()}. */ int mCurMethodUid = Process.INVALID_UID; @@ -629,7 +686,15 @@ public class InputMethodManagerService extends IInputMethodManager.Stub * Time that we last initiated a bind to the input method, to determine * if we should try to disconnect and reconnect to it. */ - long mLastBindTime; + private long getLastBindTime() { + return mLastBindTime; + } + + private void setLastBindTime(long lastBindTime) { + mLastBindTime = lastBindTime; + } + + private long mLastBindTime; /** * Have we called mCurMethod.bindInput()? @@ -1675,7 +1740,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub @GuardedBy("mMethodMap") private void resetDefaultImeLocked(Context context) { // Do not reset the default (current) IME when it is a 3rd-party IME - if (mCurMethodId != null && !mMethodMap.get(mCurMethodId).isSystem()) { + if (getSelectedMethodId() != null && !mMethodMap.get(getSelectedMethodId()).isSystem()) { return; } final List suitableImes = InputMethodUtils.getDefaultEnabledImes( @@ -1884,7 +1949,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub if (token == null) { throw new InvalidParameterException("token must not be null."); } - if (token != mCurToken) { + if (token != getCurToken()) { Slog.e(TAG, "Ignoring " + Debug.getCaller() + " due to an invalid token." + " uid:" + Binder.getCallingUid() + " token:" + token); return false; @@ -1983,14 +2048,14 @@ public class InputMethodManagerService extends IInputMethodManager.Stub @GuardedBy("mMethodMap") private void onCreateInlineSuggestionsRequestLocked(@UserIdInt int userId, InlineSuggestionsRequestInfo requestInfo, IInlineSuggestionsRequestCallback callback) { - final InputMethodInfo imi = mMethodMap.get(mCurMethodId); + final InputMethodInfo imi = mMethodMap.get(getSelectedMethodId()); try { if (userId == mSettings.getCurrentUserId() && imi != null && imi.isInlineSuggestionsEnabled() && mCurMethod != null) { executeOrSendMessage(mCurMethod, mCaller.obtainMessageOOO(MSG_INLINE_SUGGESTIONS_REQUEST, mCurMethod, requestInfo, new InlineSuggestionsRequestCallbackDecorator(callback, - imi.getPackageName(), mCurTokenDisplayId, mCurToken, + imi.getPackageName(), mCurTokenDisplayId, getCurToken(), this))); } else { callback.onInlineSuggestionsUnsupported(); @@ -2126,8 +2191,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub boolean allowsImplicitlySelectedSubtypes, @UserIdInt int userId) { if (userId == mSettings.getCurrentUserId()) { final InputMethodInfo imi; - if (imiId == null && mCurMethodId != null) { - imi = mMethodMap.get(mCurMethodId); + if (imiId == null && getSelectedMethodId() != null) { + imi = mMethodMap.get(getSelectedMethodId()); } else { imi = mMethodMap.get(imiId); } @@ -2263,7 +2328,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub scheduleSetActiveToClient(mCurClient, false /* active */, false /* fullscreen */, false /* reportToImeController */); executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIIO( - MSG_UNBIND_CLIENT, mCurSeq, unbindClientReason, mCurClient.client)); + MSG_UNBIND_CLIENT, getSequenceNumber(), unbindClientReason, mCurClient.client)); mCurClient.sessionRequested = false; mCurClient = null; @@ -2304,10 +2369,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } final Binder startInputToken = new Binder(); - final StartInputInfo info = new StartInputInfo(mSettings.getCurrentUserId(), mCurToken, - mCurTokenDisplayId, mCurId, startInputReason, !initial, + final StartInputInfo info = new StartInputInfo(mSettings.getCurrentUserId(), getCurToken(), + mCurTokenDisplayId, getCurId(), startInputReason, !initial, UserHandle.getUserId(mCurClient.uid), mCurClient.selfReportedDisplayId, - mCurFocusedWindow, mCurAttribute, mCurFocusedWindowSoftInputMode, mCurSeq); + mCurFocusedWindow, mCurAttribute, mCurFocusedWindowSoftInputMode, + getSequenceNumber()); mImeTargetWindowMap.put(startInputToken, mCurFocusedWindow); mStartInputHistory.addEntry(info); @@ -2330,12 +2396,12 @@ public class InputMethodManagerService extends IInputMethodManager.Stub showCurrentInputLocked(mCurFocusedWindow, getAppShowFlagsLocked(), null, SoftInputShowHideReason.ATTACH_NEW_INPUT); } - final InputMethodInfo curInputMethodInfo = mMethodMap.get(mCurId); + final InputMethodInfo curInputMethodInfo = mMethodMap.get(getCurId()); final boolean suppressesSpellChecker = curInputMethodInfo != null && curInputMethodInfo.suppressesSpellChecker(); return new InputBindResult(InputBindResult.ResultCode.SUCCESS_WITH_IME_SESSION, session.session, (session.channel != null ? session.channel.dup() : null), - mCurId, mCurSeq, suppressesSpellChecker); + getCurId(), getSequenceNumber(), suppressesSpellChecker); } @GuardedBy("mMethodMap") @@ -2344,7 +2410,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub @NonNull EditorInfo attribute, @StartInputFlags int startInputFlags, @StartInputReason int startInputReason) { // If no method is currently selected, do nothing. - if (mCurMethodId == null) { + if (getSelectedMethodId() == null) { return InputBindResult.NO_IME; } @@ -2353,7 +2419,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub // party code. return new InputBindResult( InputBindResult.ResultCode.ERROR_SYSTEM_NOT_READY, - null, null, mCurMethodId, mCurSeq, false); + null, null, getSelectedMethodId(), getSequenceNumber(), false); } if (!InputMethodUtils.checkIfPackageBelongsToUid(mAppOpsManager, cs.uid, @@ -2392,8 +2458,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } // Bump up the sequence for this client and attach it. - mCurSeq++; - if (mCurSeq <= 0) mCurSeq = 1; + advanceSequenceNumber(); mCurClient = cs; mCurInputContext = inputContext; mCurAttribute = attribute; @@ -2401,7 +2466,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub // Check if the input method is changing. // We expect the caller has already verified that the client is allowed to access this // display ID. - if (mCurId != null && mCurId.equals(mCurMethodId) + if (getCurId() != null && getCurId().equals(getSelectedMethodId()) && displayIdToShowIme == mCurTokenDisplayId) { if (cs.curSession != null) { // Fast case: if we are already connected to the input method, @@ -2409,16 +2474,16 @@ public class InputMethodManagerService extends IInputMethodManager.Stub return attachNewInputLocked(startInputReason, (startInputFlags & StartInputFlags.INITIAL_CONNECTION) != 0); } - if (mHaveConnection) { + if (hasConnection()) { if (mCurMethod != null) { // Return to client, and we will get back with it when // we have had a session made for it. requestClientSessionLocked(cs); return new InputBindResult( InputBindResult.ResultCode.SUCCESS_WAITING_IME_SESSION, - null, null, mCurId, mCurSeq, false); + null, null, getCurId(), getSequenceNumber(), false); } else if (SystemClock.uptimeMillis() - < (mLastBindTime+TIME_TO_RECONNECT)) { + < (getLastBindTime() + TIME_TO_RECONNECT)) { // In this case we have connected to the service, but // don't yet have its interface. If it hasn't been too // long since we did the connection, we'll return to @@ -2428,50 +2493,51 @@ public class InputMethodManagerService extends IInputMethodManager.Stub // to see if we can get back in touch with the service. return new InputBindResult( InputBindResult.ResultCode.SUCCESS_WAITING_IME_BINDING, - null, null, mCurId, mCurSeq, false); + null, null, getCurId(), getSequenceNumber(), false); } else { EventLog.writeEvent(EventLogTags.IMF_FORCE_RECONNECT_IME, - mCurMethodId, SystemClock.uptimeMillis()-mLastBindTime, 0); + getSelectedMethodId(), SystemClock.uptimeMillis() - getLastBindTime(), + 0); } } } - InputMethodInfo info = mMethodMap.get(mCurMethodId); + InputMethodInfo info = mMethodMap.get(getSelectedMethodId()); if (info == null) { - throw new IllegalArgumentException("Unknown id: " + mCurMethodId); + throw new IllegalArgumentException("Unknown id: " + getSelectedMethodId()); } unbindCurrentMethodLocked(); - mCurIntent = new Intent(InputMethod.SERVICE_INTERFACE); - mCurIntent.setComponent(info.getComponent()); - mCurIntent.putExtra(Intent.EXTRA_CLIENT_LABEL, + setCurIntent(new Intent(InputMethod.SERVICE_INTERFACE)); + getCurIntent().setComponent(info.getComponent()); + getCurIntent().putExtra(Intent.EXTRA_CLIENT_LABEL, com.android.internal.R.string.input_method_binding_label); - mCurIntent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity( + getCurIntent().putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity( mContext, 0, new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS), PendingIntent.FLAG_IMMUTABLE)); - if (bindCurrentInputMethodServiceLocked(mCurIntent, this, mImeConnectionBindFlags)) { - mLastBindTime = SystemClock.uptimeMillis(); - mHaveConnection = true; - mCurId = info.getId(); - mCurToken = new Binder(); + if (bindCurrentInputMethodServiceLocked(getCurIntent(), this, mImeConnectionBindFlags)) { + setLastBindTime(SystemClock.uptimeMillis()); + setHasConnection(true); + setCurId(info.getId()); + setCurToken(new Binder()); mCurTokenDisplayId = displayIdToShowIme; try { if (DEBUG) { - Slog.v(TAG, "Adding window token: " + mCurToken + " for display: " + Slog.v(TAG, "Adding window token: " + getCurToken() + " for display: " + mCurTokenDisplayId); } - mIWindowManager.addWindowToken(mCurToken, LayoutParams.TYPE_INPUT_METHOD, + mIWindowManager.addWindowToken(getCurToken(), LayoutParams.TYPE_INPUT_METHOD, mCurTokenDisplayId, null /* options */); } catch (RemoteException e) { } return new InputBindResult( InputBindResult.ResultCode.SUCCESS_WAITING_IME_BINDING, - null, null, mCurId, mCurSeq, false); + null, null, getCurId(), getSequenceNumber(), false); } - mCurIntent = null; - Slog.w(TAG, "Failure connecting to input method service: " + mCurIntent); + setCurIntent(null); + Slog.w(TAG, "Failure connecting to input method service: " + getCurIntent()); return InputBindResult.IME_NOT_CONNECTED; } @@ -2517,9 +2583,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub public void onServiceConnected(ComponentName name, IBinder service) { Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.onServiceConnected"); synchronized (mMethodMap) { - if (mCurIntent != null && name.equals(mCurIntent.getComponent())) { + if (getCurIntent() != null && name.equals(getCurIntent().getComponent())) { mCurMethod = IInputMethod.Stub.asInterface(service); - final String curMethodPackage = mCurIntent.getComponent().getPackageName(); + final String curMethodPackage = getCurIntent().getComponent().getPackageName(); final int curMethodUid = mPackageManagerInternal.getPackageUid( curMethodPackage, 0 /* flags */, mSettings.getCurrentUserId()); if (curMethodUid < 0) { @@ -2528,16 +2594,17 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } else { mCurMethodUid = curMethodUid; } - if (mCurToken == null) { + if (getCurToken() == null) { Slog.w(TAG, "Service connected without a token!"); unbindCurrentMethodLocked(); Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); return; } - if (DEBUG) Slog.v(TAG, "Initiating attach with token: " + mCurToken); + if (DEBUG) Slog.v(TAG, "Initiating attach with token: " + getCurToken()); // Dispatch display id for InputMethodService to update context display. executeOrSendMessage(mCurMethod, mCaller.obtainMessageIOO(MSG_INITIALIZE_IME, - mMethodMap.get(mCurMethodId).getConfigChanges(), mCurMethod, mCurToken)); + mMethodMap.get(getSelectedMethodId()).getConfigChanges(), mCurMethod, + getCurToken())); scheduleNotifyImeUidToAudioService(mCurMethodUid); if (mCurClient != null) { clearClientSessionLocked(mCurClient); @@ -2584,34 +2651,34 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mVisibleBound = false; } - if (mHaveConnection) { + if (hasConnection()) { mContext.unbindService(this); - mHaveConnection = false; + setHasConnection(false); } - if (mCurToken != null) { + if (getCurToken() != null) { if (DEBUG) { - Slog.v(TAG, "Removing window token: " + mCurToken + " for display: " + Slog.v(TAG, "Removing window token: " + getCurToken() + " for display: " + mCurTokenDisplayId); } - mWindowManagerInternal.removeWindowToken(mCurToken, false /* removeWindows */, + mWindowManagerInternal.removeWindowToken(getCurToken(), false /* removeWindows */, false /* animateExit */, mCurTokenDisplayId); // Set IME window status as invisible when unbind current method. mImeWindowVis = 0; mBackDisposition = InputMethodService.BACK_DISPOSITION_DEFAULT; updateSystemUiLocked(mImeWindowVis, mBackDisposition); - mCurToken = null; + setCurToken(null); mCurTokenDisplayId = INVALID_DISPLAY; mCurHostInputToken = null; } - mCurId = null; + setCurId(null); clearCurMethodLocked(); } @GuardedBy("mMethodMap") void resetCurrentMethodAndClientLocked(@UnbindReason int unbindClientReason) { - mCurMethodId = null; + setSelectedMethodId(null); unbindCurrentMethodLocked(); unbindCurrentClientLocked(unbindClientReason); } @@ -2685,13 +2752,13 @@ public class InputMethodManagerService extends IInputMethodManager.Stub // would be a good way to trigger such a situation. synchronized (mMethodMap) { if (DEBUG) Slog.v(TAG, "Service disconnected: " + name - + " mCurIntent=" + mCurIntent); - if (mCurMethod != null && mCurIntent != null - && name.equals(mCurIntent.getComponent())) { + + " mCurIntent=" + getCurIntent()); + if (mCurMethod != null && getCurIntent() != null + && name.equals(getCurIntent().getComponent())) { clearCurMethodLocked(); // We consider this to be a new bind attempt, since the system // should now try to restart the service for us. - mLastBindTime = SystemClock.uptimeMillis(); + setLastBindTime(SystemClock.uptimeMillis()); mShowRequested = mInputShown; mInputShown = false; unbindCurrentClientLocked(UnbindReason.DISCONNECT_IME); @@ -2877,7 +2944,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub // Caution! This method is called in this class. Handle multi-user carefully @GuardedBy("mMethodMap") private void updateSystemUiLocked(int vis, int backDisposition) { - if (mCurToken == null) { + if (getCurToken() == null) { return; } if (DEBUG) { @@ -2897,10 +2964,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub // mImeWindowVis should be updated before calling shouldShowImeSwitcherLocked(). final boolean needsToShowImeSwitcher = shouldShowImeSwitcherLocked(vis); if (mStatusBar != null) { - mStatusBar.setImeWindowStatus(mCurTokenDisplayId, mCurToken, vis, backDisposition, - needsToShowImeSwitcher); + mStatusBar.setImeWindowStatus(mCurTokenDisplayId, getCurToken(), vis, + backDisposition, needsToShowImeSwitcher); } - final InputMethodInfo imi = mMethodMap.get(mCurMethodId); + final InputMethodInfo imi = mMethodMap.get(getSelectedMethodId()); if (imi != null && needsToShowImeSwitcher) { // Used to load label final CharSequence title = mRes.getText( @@ -3008,7 +3075,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } // See if we need to notify a subtype change within the same IME. - if (id.equals(mCurMethodId)) { + if (id.equals(getSelectedMethodId())) { final int subtypeCount = info.getSubtypeCount(); if (subtypeCount <= 0) { return; @@ -3050,7 +3117,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub // mCurMethodId should be updated after setSelectedInputMethodAndSubtypeLocked() // because mCurMethodId is stored as a history in // setSelectedInputMethodAndSubtypeLocked(). - mCurMethodId = id; + setSelectedMethodId(id); if (LocalServices.getService(ActivityManagerInternal.class).isSystemReady()) { Intent intent = new Intent(Intent.ACTION_INPUT_METHOD_CHANGED); @@ -3145,34 +3212,34 @@ public class InputMethodManagerService extends IInputMethodManager.Stub boolean res = false; if (mCurMethod != null) { - if (DEBUG) Slog.d(TAG, "showCurrentInputLocked: mCurToken=" + mCurToken); + if (DEBUG) Slog.d(TAG, "showCurrentInputLocked: mCurToken=" + getCurToken()); // create a placeholder token for IMS so that IMS cannot inject windows into client app. Binder showInputToken = new Binder(); mShowRequestWindowMap.put(showInputToken, windowToken); executeOrSendMessage(mCurMethod, mCaller.obtainMessageIIOOO(MSG_SHOW_SOFT_INPUT, getImeShowFlagsLocked(), reason, mCurMethod, resultReceiver, showInputToken)); mInputShown = true; - if (mHaveConnection && !mVisibleBound) { + if (hasConnection() && !mVisibleBound) { bindCurrentInputMethodServiceLocked( - mCurIntent, mVisibleConnection, IME_VISIBLE_BIND_FLAGS); + getCurIntent(), mVisibleConnection, IME_VISIBLE_BIND_FLAGS); mVisibleBound = true; } res = true; - } else if (mHaveConnection && SystemClock.uptimeMillis() - >= (mLastBindTime+TIME_TO_RECONNECT)) { + } else if (hasConnection() && SystemClock.uptimeMillis() + >= (getLastBindTime() + TIME_TO_RECONNECT)) { // The client has asked to have the input method shown, but // we have been sitting here too long with a connection to the // service and no interface received, so let's disconnect/connect // to try to prod things along. - EventLog.writeEvent(EventLogTags.IMF_FORCE_RECONNECT_IME, mCurMethodId, - SystemClock.uptimeMillis()-mLastBindTime,1); + EventLog.writeEvent(EventLogTags.IMF_FORCE_RECONNECT_IME, getSelectedMethodId(), + SystemClock.uptimeMillis() - getLastBindTime(), 1); Slog.w(TAG, "Force disconnect/connect to the IME in showCurrentInputLocked()"); mContext.unbindService(this); - bindCurrentInputMethodServiceLocked(mCurIntent, this, mImeConnectionBindFlags); + bindCurrentInputMethodServiceLocked(getCurIntent(), this, mImeConnectionBindFlags); } else { if (DEBUG) { - Slog.d(TAG, "Can't show input: connection = " + mHaveConnection + ", time = " - + ((mLastBindTime+TIME_TO_RECONNECT) - SystemClock.uptimeMillis())); + Slog.d(TAG, "Can't show input: connection = " + hasConnection() + ", time = " + + ((getLastBindTime() + TIME_TO_RECONNECT) - SystemClock.uptimeMillis())); } } @@ -3259,7 +3326,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } else { res = false; } - if (mHaveConnection && mVisibleBound) { + if (hasConnection() && mVisibleBound) { mContext.unbindService(mVisibleConnection); mVisibleBound = false; } @@ -3627,10 +3694,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub if (mCurFocusedWindowClient != null && client != null && mCurFocusedWindowClient.client.asBinder() == client.asBinder()) { return true; - } else if (mCurIntent != null && InputMethodUtils.checkIfPackageBelongsToUid( + } else if (getCurIntent() != null && InputMethodUtils.checkIfPackageBelongsToUid( mAppOpsManager, uid, - mCurIntent.getComponent().getPackageName())) { + getCurIntent().getComponent().getPackageName())) { return true; } return false; @@ -3737,7 +3804,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub String targetLastImiId = null; int subtypeId = NOT_A_SUBTYPE_ID; if (lastIme != null && lastImi != null) { - final boolean imiIdIsSame = lastImi.getId().equals(mCurMethodId); + final boolean imiIdIsSame = lastImi.getId().equals(getSelectedMethodId()); final int lastSubtypeHash = Integer.parseInt(lastIme.second); final int currentSubtypeHash = mCurrentSubtype == null ? NOT_A_SUBTYPE_ID : mCurrentSubtype.hashCode(); @@ -3783,7 +3850,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub if (!TextUtils.isEmpty(targetLastImiId)) { if (DEBUG) { Slog.d(TAG, "Switch to: " + lastImi.getId() + ", " + lastIme.second - + ", from: " + mCurMethodId + ", " + subtypeId); + + ", from: " + getSelectedMethodId() + ", " + subtypeId); } setInputMethodWithSubtypeIdLocked(token, targetLastImiId, subtypeId); return true; @@ -3800,7 +3867,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub return false; } final ImeSubtypeListItem nextSubtype = mSwitchingController.getNextInputMethodLocked( - onlyCurrentIme, mMethodMap.get(mCurMethodId), mCurrentSubtype); + onlyCurrentIme, mMethodMap.get(getSelectedMethodId()), mCurrentSubtype); if (nextSubtype == null) { return false; } @@ -3817,7 +3884,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub return false; } final ImeSubtypeListItem nextSubtype = mSwitchingController.getNextInputMethodLocked( - false /* onlyCurrentIme */, mMethodMap.get(mCurMethodId), mCurrentSubtype); + false /* onlyCurrentIme */, mMethodMap.get(getSelectedMethodId()), + mCurrentSubtype); if (nextSubtype == null) { return false; } @@ -4031,8 +4099,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub private void dumpDebug(ProtoOutputStream proto, long fieldId) { synchronized (mMethodMap) { final long token = proto.start(fieldId); - proto.write(CUR_METHOD_ID, mCurMethodId); - proto.write(CUR_SEQ, mCurSeq); + proto.write(CUR_METHOD_ID, getSelectedMethodId()); + proto.write(CUR_SEQ, getSequenceNumber()); proto.write(CUR_CLIENT, Objects.toString(mCurClient)); proto.write(CUR_FOCUSED_WINDOW_NAME, mWindowManagerInternal.getWindowName(mCurFocusedWindow)); @@ -4043,17 +4111,17 @@ public class InputMethodManagerService extends IInputMethodManager.Stub if (mCurAttribute != null) { mCurAttribute.dumpDebug(proto, CUR_ATTRIBUTE); } - proto.write(CUR_ID, mCurId); + proto.write(CUR_ID, getCurId()); proto.write(SHOW_REQUESTED, mShowRequested); proto.write(SHOW_EXPLICITLY_REQUESTED, mShowExplicitlyRequested); proto.write(SHOW_FORCED, mShowForced); proto.write(INPUT_SHOWN, mInputShown); proto.write(IN_FULLSCREEN_MODE, mInFullscreenMode); - proto.write(CUR_TOKEN, Objects.toString(mCurToken)); + proto.write(CUR_TOKEN, Objects.toString(getCurToken())); proto.write(CUR_TOKEN_DISPLAY_ID, mCurTokenDisplayId); proto.write(SYSTEM_READY, mSystemReady); proto.write(LAST_SWITCH_USER_ID, mLastSwitchUserId); - proto.write(HAVE_CONNECTION, mHaveConnection); + proto.write(HAVE_CONNECTION, hasConnection()); proto.write(BOUND_TO_METHOD, mBoundToMethod); proto.write(IS_INTERACTIVE, mIsInteractive); proto.write(BACK_DISPOSITION, mBackDisposition); @@ -4071,14 +4139,14 @@ public class InputMethodManagerService extends IInputMethodManager.Stub Slog.d(TAG, "Got the notification of a user action."); } synchronized (mMethodMap) { - if (mCurToken != token) { + if (getCurToken() != token) { if (DEBUG) { Slog.d(TAG, "Ignoring the user action notification from IMEs that are no longer" + " active."); } return; } - final InputMethodInfo imi = mMethodMap.get(mCurMethodId); + final InputMethodInfo imi = mMethodMap.get(getSelectedMethodId()); if (imi != null) { mSwitchingController.onUserActionLocked(imi, mCurrentSubtype); } @@ -4122,7 +4190,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub "Using null token requires permission " + android.Manifest.permission.WRITE_SECURE_SETTINGS); } - } else if (mCurToken != token) { + } else if (getCurToken() != token) { Slog.w(TAG, "Ignoring setInputMethod of uid " + Binder.getCallingUid() + " token: " + token); return; @@ -4784,7 +4852,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub @GuardedBy("mMethodMap") private void setSelectedInputMethodAndSubtypeLocked(InputMethodInfo imi, int subtypeId, boolean setSubtypeOnly) { - mSettings.saveCurrentInputMethodAndSubtypeToHistory(mCurMethodId, mCurrentSubtype); + mSettings.saveCurrentInputMethodAndSubtypeToHistory(getSelectedMethodId(), mCurrentSubtype); // Set Subtype here if (imi == null || subtypeId < 0) { @@ -4843,17 +4911,17 @@ public class InputMethodManagerService extends IInputMethodManager.Stub @GuardedBy("mMethodMap") InputMethodSubtype getCurrentInputMethodSubtypeLocked() { - if (mCurMethodId == null) { + if (getSelectedMethodId() == null) { return null; } final boolean subtypeIsSelected = mSettings.isSubtypeSelected(); - final InputMethodInfo imi = mMethodMap.get(mCurMethodId); + final InputMethodInfo imi = mMethodMap.get(getSelectedMethodId()); if (imi == null || imi.getSubtypeCount() == 0) { return null; } if (!subtypeIsSelected || mCurrentSubtype == null || !InputMethodUtils.isValidSubtypeId(imi, mCurrentSubtype.hashCode())) { - int subtypeId = mSettings.getSelectedInputMethodSubtypeId(mCurMethodId); + int subtypeId = mSettings.getSelectedInputMethodSubtypeId(getSelectedMethodId()); if (subtypeId == NOT_A_SUBTYPE_ID) { // If there are no selected subtypes, the framework will try to find // the most applicable subtype from explicitly or implicitly enabled @@ -4883,7 +4951,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub @Nullable String getCurrentMethodId() { - return mCurMethodId; + return getSelectedMethodId(); } private List getInputMethodListAsUser(@UserIdInt int userId) { @@ -5057,11 +5125,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub synchronized (mMethodMap) { final int uid = Binder.getCallingUid(); - if (mCurMethodId == null) { + if (getSelectedMethodId() == null) { return null; } - if (mCurToken != token) { - Slog.e(TAG, "Ignoring createInputContentUriToken mCurToken=" + mCurToken + if (getCurToken() != token) { + Slog.e(TAG, "Ignoring createInputContentUriToken mCurToken=" + getCurToken() + " token=" + token); return null; } @@ -5196,21 +5264,21 @@ public class InputMethodManagerService extends IInputMethodManager.Stub p.println(" sessionRequested=" + ci.sessionRequested); p.println(" curSession=" + ci.curSession); } - p.println(" mCurMethodId=" + mCurMethodId); + p.println(" mCurMethodId=" + getSelectedMethodId()); client = mCurClient; - p.println(" mCurClient=" + client + " mCurSeq=" + mCurSeq); + p.println(" mCurClient=" + client + " mCurSeq=" + getSequenceNumber()); p.println(" mCurPerceptible=" + mCurPerceptible); p.println(" mCurFocusedWindow=" + mCurFocusedWindow + " softInputMode=" + InputMethodDebug.softInputModeToString(mCurFocusedWindowSoftInputMode) + " client=" + mCurFocusedWindowClient); focusedWindowClient = mCurFocusedWindowClient; - p.println(" mCurId=" + mCurId + " mHaveConnection=" + mHaveConnection + p.println(" mCurId=" + getCurId() + " mHaveConnection=" + hasConnection() + " mBoundToMethod=" + mBoundToMethod + " mVisibleBound=" + mVisibleBound); - p.println(" mCurToken=" + mCurToken); + p.println(" mCurToken=" + getCurToken()); p.println(" mCurTokenDisplayId=" + mCurTokenDisplayId); p.println(" mCurHostInputToken=" + mCurHostInputToken); - p.println(" mCurIntent=" + mCurIntent); + p.println(" mCurIntent=" + getCurIntent()); method = mCurMethod; p.println(" mCurMethod=" + mCurMethod); p.println(" mEnabledSession=" + mEnabledSession); From 430e1722e3cd3464843be916168b2855e108c45e Mon Sep 17 00:00:00 2001 From: Nikolas Havrikov Date: Mon, 8 Nov 2021 13:41:10 +0100 Subject: [PATCH 05/43] Extract updating binding intent This is a step in a larger refactoring. This also fixes logging of the unsuccessful intent. Bug: 205676419 Test: make Change-Id: I4141939a974064e19009194a19acfd1edea7b3c5 --- .../InputMethodManagerService.java | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 8e6b7ad4adbcf..f8ed35e9afdec 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -2509,15 +2509,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub unbindCurrentMethodLocked(); - setCurIntent(new Intent(InputMethod.SERVICE_INTERFACE)); - getCurIntent().setComponent(info.getComponent()); - getCurIntent().putExtra(Intent.EXTRA_CLIENT_LABEL, - com.android.internal.R.string.input_method_binding_label); - getCurIntent().putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity( - mContext, 0, new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS), - PendingIntent.FLAG_IMMUTABLE)); + Intent intent = createImeBindingIntent(info.getComponent()); + setCurIntent(intent); - if (bindCurrentInputMethodServiceLocked(getCurIntent(), this, mImeConnectionBindFlags)) { + if (bindCurrentInputMethodServiceLocked(intent, this, mImeConnectionBindFlags)) { setLastBindTime(SystemClock.uptimeMillis()); setHasConnection(true); setCurId(info.getId()); @@ -2537,10 +2532,22 @@ public class InputMethodManagerService extends IInputMethodManager.Stub null, null, getCurId(), getSequenceNumber(), false); } setCurIntent(null); - Slog.w(TAG, "Failure connecting to input method service: " + getCurIntent()); + Slog.w(TAG, "Failure connecting to input method service: " + intent); return InputBindResult.IME_NOT_CONNECTED; } + @NonNull + private Intent createImeBindingIntent(ComponentName component) { + Intent intent = new Intent(InputMethod.SERVICE_INTERFACE); + intent.setComponent(component); + intent.putExtra(Intent.EXTRA_CLIENT_LABEL, + com.android.internal.R.string.input_method_binding_label); + intent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity( + mContext, 0, new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS), + PendingIntent.FLAG_IMMUTABLE)); + return intent; + } + @FunctionalInterface interface ImeDisplayValidator { @DisplayImePolicy int getDisplayImePolicy(int displayId); From 8bdeee1ad440f5daf6b1af76286defe20aff1215 Mon Sep 17 00:00:00 2001 From: Nikolas Havrikov Date: Mon, 8 Nov 2021 15:48:50 +0100 Subject: [PATCH 06/43] Extract adding new window token in own method Bug: 205676419 Test: make Change-Id: I90374ed05682057bd56ec44c78be4b56bb10b625 --- .../InputMethodManagerService.java | 36 +++++++++++-------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index f8ed35e9afdec..ec7975c9b6192 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -2513,20 +2513,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub setCurIntent(intent); if (bindCurrentInputMethodServiceLocked(intent, this, mImeConnectionBindFlags)) { - setLastBindTime(SystemClock.uptimeMillis()); - setHasConnection(true); - setCurId(info.getId()); - setCurToken(new Binder()); - mCurTokenDisplayId = displayIdToShowIme; - try { - if (DEBUG) { - Slog.v(TAG, "Adding window token: " + getCurToken() + " for display: " - + mCurTokenDisplayId); - } - mIWindowManager.addWindowToken(getCurToken(), LayoutParams.TYPE_INPUT_METHOD, - mCurTokenDisplayId, null /* options */); - } catch (RemoteException e) { - } + addFreshWindowTokenLocked(displayIdToShowIme, info.getId()); return new InputBindResult( InputBindResult.ResultCode.SUCCESS_WAITING_IME_BINDING, null, null, getCurId(), getSequenceNumber(), false); @@ -2548,6 +2535,27 @@ public class InputMethodManagerService extends IInputMethodManager.Stub return intent; } + @GuardedBy("mMethodMap") + private void addFreshWindowTokenLocked(int displayIdToShowIme, String methodId) { + Binder token = new Binder(); + setCurToken(token); + setLastBindTime(SystemClock.uptimeMillis()); + setHasConnection(true); + setCurId(methodId); + mCurTokenDisplayId = displayIdToShowIme; + try { + if (DEBUG) { + Slog.v(TAG, "Adding window token: " + token + " for display: " + + displayIdToShowIme); + } + mIWindowManager.addWindowToken(token, LayoutParams.TYPE_INPUT_METHOD, + displayIdToShowIme, null /* options */); + } catch (RemoteException e) { + Slog.e(TAG, "Could not add window token " + token + " for display " + + displayIdToShowIme, e); + } + } + @FunctionalInterface interface ImeDisplayValidator { @DisplayImePolicy int getDisplayImePolicy(int displayId); From 017011469631ecfb8734d7a38b48232f8703e5e1 Mon Sep 17 00:00:00 2001 From: Nikolas Havrikov Date: Fri, 5 Nov 2021 14:08:14 +0100 Subject: [PATCH 07/43] Extract part of the client switch logic Bug: 205676419 Test: make Change-Id: If387b0f0d007ca468f3a038693ca2014d8e671d6 --- .../InputMethodManagerService.java | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index ec7975c9b6192..3b95738f5c42c 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -2447,14 +2447,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mImeHiddenByDisplayPolicy = false; if (mCurClient != cs) { - // If the client is changing, we need to switch over to the new - // one. - unbindCurrentClientLocked(UnbindReason.SWITCH_CLIENT); - // If the screen is on, inform the new client it is active - if (mIsInteractive) { - scheduleSetActiveToClient(cs, true /* active */, false /* fullscreen */, - false /* reportToImeController */); - } + prepareClientSwitchLocked(cs); } // Bump up the sequence for this client and attach it. @@ -2523,6 +2516,18 @@ public class InputMethodManagerService extends IInputMethodManager.Stub return InputBindResult.IME_NOT_CONNECTED; } + @GuardedBy("mMethodMap") + private void prepareClientSwitchLocked(ClientState cs) { + // If the client is changing, we need to switch over to the new + // one. + unbindCurrentClientLocked(UnbindReason.SWITCH_CLIENT); + // If the screen is on, inform the new client it is active + if (mIsInteractive) { + scheduleSetActiveToClient(cs, true /* active */, false /* fullscreen */, + false /* reportToImeController */); + } + } + @NonNull private Intent createImeBindingIntent(ComponentName component) { Intent intent = new Intent(InputMethod.SERVICE_INTERFACE); From 95b509ea982a7ddd9ddc2205878406509f549c74 Mon Sep 17 00:00:00 2001 From: Nikolas Havrikov Date: Tue, 9 Nov 2021 12:39:20 +0100 Subject: [PATCH 08/43] Extract reusing current connection logic Bug: 205676419 Test: make Change-Id: Iea3dff8bd25d4404e4164c32db1216418cffbc62 --- .../InputMethodManagerService.java | 60 +++++++++++-------- 1 file changed, 35 insertions(+), 25 deletions(-) diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 3b95738f5c42c..962952a4b4a87 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -2467,31 +2467,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub return attachNewInputLocked(startInputReason, (startInputFlags & StartInputFlags.INITIAL_CONNECTION) != 0); } - if (hasConnection()) { - if (mCurMethod != null) { - // Return to client, and we will get back with it when - // we have had a session made for it. - requestClientSessionLocked(cs); - return new InputBindResult( - InputBindResult.ResultCode.SUCCESS_WAITING_IME_SESSION, - null, null, getCurId(), getSequenceNumber(), false); - } else if (SystemClock.uptimeMillis() - < (getLastBindTime() + TIME_TO_RECONNECT)) { - // In this case we have connected to the service, but - // don't yet have its interface. If it hasn't been too - // long since we did the connection, we'll return to - // the client and wait to get the service interface so - // we can report back. If it has been too long, we want - // to fall through so we can try a disconnect/reconnect - // to see if we can get back in touch with the service. - return new InputBindResult( - InputBindResult.ResultCode.SUCCESS_WAITING_IME_BINDING, - null, null, getCurId(), getSequenceNumber(), false); - } else { - EventLog.writeEvent(EventLogTags.IMF_FORCE_RECONNECT_IME, - getSelectedMethodId(), SystemClock.uptimeMillis() - getLastBindTime(), - 0); - } + + InputBindResult bindResult = tryReuseConnectionLocked(cs); + if (bindResult != null) { + return bindResult; } } @@ -2528,6 +2507,37 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } } + @GuardedBy("mMethodMap") + @Nullable + private InputBindResult tryReuseConnectionLocked(@NonNull ClientState cs) { + if (hasConnection()) { + if (mCurMethod != null) { + // Return to client, and we will get back with it when + // we have had a session made for it. + requestClientSessionLocked(cs); + return new InputBindResult( + InputBindResult.ResultCode.SUCCESS_WAITING_IME_SESSION, + null, null, getCurId(), getSequenceNumber(), false); + } else if (SystemClock.uptimeMillis() + < (getLastBindTime() + TIME_TO_RECONNECT)) { + // In this case we have connected to the service, but + // don't yet have its interface. If it hasn't been too + // long since we did the connection, we'll return to + // the client and wait to get the service interface so + // we can report back. If it has been too long, we want + // to fall through so we can try a disconnect/reconnect + // to see if we can get back in touch with the service. + return new InputBindResult( + InputBindResult.ResultCode.SUCCESS_WAITING_IME_BINDING, + null, null, getCurId(), getSequenceNumber(), false); + } else { + EventLog.writeEvent(EventLogTags.IMF_FORCE_RECONNECT_IME, + getSelectedMethodId(), SystemClock.uptimeMillis() - getLastBindTime(), 0); + } + } + return null; + } + @NonNull private Intent createImeBindingIntent(ComponentName component) { Intent intent = new Intent(InputMethod.SERVICE_INTERFACE); From 9bc49a5abbd45a185ceaf53d8b064a72f9a6d45e Mon Sep 17 00:00:00 2001 From: Nikolas Havrikov Date: Tue, 9 Nov 2021 12:39:54 +0100 Subject: [PATCH 09/43] Extract isSelectedMethodBound method Bug: 205676419 Test: make Change-Id: I0b08f54ee46422980ce8738c12c02cfe6ba29ad8 --- .../server/inputmethod/InputMethodManagerService.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 962952a4b4a87..f3d799183b95a 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -2459,8 +2459,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub // Check if the input method is changing. // We expect the caller has already verified that the client is allowed to access this // display ID. - if (getCurId() != null && getCurId().equals(getSelectedMethodId()) - && displayIdToShowIme == mCurTokenDisplayId) { + if (isSelectedMethodBound(displayIdToShowIme)) { if (cs.curSession != null) { // Fast case: if we are already connected to the input method, // then just return it. @@ -2495,6 +2494,12 @@ public class InputMethodManagerService extends IInputMethodManager.Stub return InputBindResult.IME_NOT_CONNECTED; } + private boolean isSelectedMethodBound(int displayIdToShowIme) { + String curId = getCurId(); + return curId != null && curId.equals(getSelectedMethodId()) + && displayIdToShowIme == mCurTokenDisplayId; + } + @GuardedBy("mMethodMap") private void prepareClientSwitchLocked(ClientState cs) { // If the client is changing, we need to switch over to the new From 91944cecdcde64e115c0f017bbe2ad1345301afd Mon Sep 17 00:00:00 2001 From: Nikolas Havrikov Date: Tue, 9 Nov 2021 17:49:08 +0100 Subject: [PATCH 10/43] Avoid calculating the same time span twice Bug: 205676419 Test: make Change-Id: Iea3dff8bd25d4404e4164c32db1216418cffbc63 --- .../InputMethodManagerService.java | 60 ++++++++++--------- 1 file changed, 32 insertions(+), 28 deletions(-) diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index f3d799183b95a..df550b510772b 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -2523,21 +2523,23 @@ public class InputMethodManagerService extends IInputMethodManager.Stub return new InputBindResult( InputBindResult.ResultCode.SUCCESS_WAITING_IME_SESSION, null, null, getCurId(), getSequenceNumber(), false); - } else if (SystemClock.uptimeMillis() - < (getLastBindTime() + TIME_TO_RECONNECT)) { - // In this case we have connected to the service, but - // don't yet have its interface. If it hasn't been too - // long since we did the connection, we'll return to - // the client and wait to get the service interface so - // we can report back. If it has been too long, we want - // to fall through so we can try a disconnect/reconnect - // to see if we can get back in touch with the service. - return new InputBindResult( - InputBindResult.ResultCode.SUCCESS_WAITING_IME_BINDING, - null, null, getCurId(), getSequenceNumber(), false); } else { - EventLog.writeEvent(EventLogTags.IMF_FORCE_RECONNECT_IME, - getSelectedMethodId(), SystemClock.uptimeMillis() - getLastBindTime(), 0); + long bindingDuration = SystemClock.uptimeMillis() - getLastBindTime(); + if (bindingDuration < TIME_TO_RECONNECT) { + // In this case we have connected to the service, but + // don't yet have its interface. If it hasn't been too + // long since we did the connection, we'll return to + // the client and wait to get the service interface so + // we can report back. If it has been too long, we want + // to fall through so we can try a disconnect/reconnect + // to see if we can get back in touch with the service. + return new InputBindResult( + InputBindResult.ResultCode.SUCCESS_WAITING_IME_BINDING, + null, null, getCurId(), getSequenceNumber(), false); + } else { + EventLog.writeEvent(EventLogTags.IMF_FORCE_RECONNECT_IME, + getSelectedMethodId(), bindingDuration, 0); + } } } return null; @@ -3260,21 +3262,23 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mVisibleBound = true; } res = true; - } else if (hasConnection() && SystemClock.uptimeMillis() - >= (getLastBindTime() + TIME_TO_RECONNECT)) { - // The client has asked to have the input method shown, but - // we have been sitting here too long with a connection to the - // service and no interface received, so let's disconnect/connect - // to try to prod things along. - EventLog.writeEvent(EventLogTags.IMF_FORCE_RECONNECT_IME, getSelectedMethodId(), - SystemClock.uptimeMillis() - getLastBindTime(), 1); - Slog.w(TAG, "Force disconnect/connect to the IME in showCurrentInputLocked()"); - mContext.unbindService(this); - bindCurrentInputMethodServiceLocked(getCurIntent(), this, mImeConnectionBindFlags); } else { - if (DEBUG) { - Slog.d(TAG, "Can't show input: connection = " + hasConnection() + ", time = " - + ((getLastBindTime() + TIME_TO_RECONNECT) - SystemClock.uptimeMillis())); + long bindingDuration = SystemClock.uptimeMillis() - getLastBindTime(); + if (hasConnection() && bindingDuration >= TIME_TO_RECONNECT) { + // The client has asked to have the input method shown, but + // we have been sitting here too long with a connection to the + // service and no interface received, so let's disconnect/connect + // to try to prod things along. + EventLog.writeEvent(EventLogTags.IMF_FORCE_RECONNECT_IME, getSelectedMethodId(), + bindingDuration, 1); + Slog.w(TAG, "Force disconnect/connect to the IME in showCurrentInputLocked()"); + mContext.unbindService(this); + bindCurrentInputMethodServiceLocked(getCurIntent(), this, mImeConnectionBindFlags); + } else { + if (DEBUG) { + Slog.d(TAG, "Can't show input: connection = " + hasConnection() + ", time = " + + (TIME_TO_RECONNECT - bindingDuration)); + } } } From 29e2529ca4b5a0dd1420ef042c7147dade0dfdeb Mon Sep 17 00:00:00 2001 From: Nikolas Havrikov Date: Fri, 5 Nov 2021 11:37:29 +0100 Subject: [PATCH 11/43] Introduce InputMethodBindingController Bug: 205676419 Test: make Change-Id: I29f4969147305674a2bc2204ba2c657f374aaaf3 --- .../InputMethodBindingController.java | 33 +++++++++++++++++++ .../InputMethodManagerService.java | 2 ++ 2 files changed, 35 insertions(+) create mode 100644 services/core/java/com/android/server/inputmethod/InputMethodBindingController.java diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java new file mode 100644 index 0000000000000..cb279876b74fd --- /dev/null +++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java @@ -0,0 +1,33 @@ +/* + * 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; + +import android.annotation.NonNull; + +/** + * A controller managing the state of the input method binding. + */ +final class InputMethodBindingController { + static final boolean DEBUG = false; + private static final String TAG = InputMethodBindingController.class.getSimpleName(); + + private final InputMethodManagerService mService; + + InputMethodBindingController(@NonNull InputMethodManagerService service) { + mService = service; + } +} diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index df550b510772b..0d9d8b697de30 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -325,6 +325,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub private final UserManager mUserManager; private final UserManagerInternal mUserManagerInternal; private final InputMethodMenuController mMenuController; + private final InputMethodBindingController mBindingController; /** * Cache the result of {@code LocalServices.getService(AudioManagerInternal.class)}. @@ -1725,6 +1726,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mSwitchingController = InputMethodSubtypeSwitchingController.createInstanceLocked( mSettings, context); mMenuController = new InputMethodMenuController(this); + mBindingController = new InputMethodBindingController(this); // If configured, use low priority flags to make the IME killable by the lowmemorykiller final boolean lowerIMEPriority = mRes.getBoolean( From 2be64fc4424f2dd7f635416f199342fceeece145 Mon Sep 17 00:00:00 2001 From: Nikolas Havrikov Date: Mon, 8 Nov 2021 11:42:17 +0100 Subject: [PATCH 12/43] Move encapsulated members to binding controller Bug: 205676419 Test: make Change-Id: Ic3d525a4e1bf8f20f6e62ab6bb061f8bad09535d --- .../InputMethodBindingController.java | 119 ++++++++++++++++++ .../InputMethodManagerService.java | 52 +++----- 2 files changed, 136 insertions(+), 35 deletions(-) diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java index cb279876b74fd..39e3501f22d7b 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java @@ -17,6 +17,10 @@ package com.android.server.inputmethod; import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.Intent; +import android.os.IBinder; +import android.view.inputmethod.InputMethodInfo; /** * A controller managing the state of the input method binding. @@ -27,7 +31,122 @@ final class InputMethodBindingController { private final InputMethodManagerService mService; + private long mLastBindTime; + private boolean mHasConnection; + @Nullable private String mCurId; + @Nullable private String mSelectedMethodId; + @Nullable private Intent mCurIntent; + private IBinder mCurToken; + private int mCurSeq; + + InputMethodBindingController(@NonNull InputMethodManagerService service) { mService = service; } + + /** + * Time that we last initiated a bind to the input method, to determine + * if we should try to disconnect and reconnect to it. + */ + long getLastBindTime() { + return mLastBindTime; + } + + void setLastBindTime(long lastBindTime) { + mLastBindTime = lastBindTime; + } + + /** + * Set to true if our ServiceConnection is currently actively bound to + * a service (whether or not we have gotten its IBinder back yet). + */ + boolean hasConnection() { + return mHasConnection; + } + + void setHasConnection(boolean hasConnection) { + mHasConnection = hasConnection; + } + + /** + * Id obtained with {@link InputMethodInfo#getId()} for the input method that we are currently + * connected to or in the process of connecting to. + * + *

This can be {@code null} when no input method is connected.

+ * + * @see #getSelectedMethodId() + */ + @Nullable + String getCurId() { + return mCurId; + } + + void setCurId(@Nullable String curId) { + mCurId = curId; + } + + /** + * Id obtained with {@link InputMethodInfo#getId()} for the currently selected input method. + * This is to be synchronized with the secure settings keyed with + * {@link android.provider.Settings.Secure#DEFAULT_INPUT_METHOD}. + * + *

This can be transiently {@code null} when the system is re-initializing input method + * settings, e.g., the system locale is just changed.

+ * + *

Note that {@link #getCurId()} is used to track which IME is being connected to + * {@link com.android.server.inputmethod.InputMethodManagerService}.

+ * + * @see #getCurId() + */ + @Nullable + String getSelectedMethodId() { + return mSelectedMethodId; + } + + void setSelectedMethodId(@Nullable String selectedMethodId) { + mSelectedMethodId = selectedMethodId; + } + + /** + * The token we have made for the currently active input method, to + * identify it in the future. + */ + IBinder getCurToken() { + return mCurToken; + } + + void setCurToken(IBinder curToken) { + mCurToken = curToken; + } + + /** + * The Intent used to connect to the current input method. + */ + @Nullable + Intent getCurIntent() { + return mCurIntent; + } + + void setCurIntent(@Nullable Intent curIntent) { + mCurIntent = curIntent; + } + + /** + * The current binding sequence number, incremented every time there is + * a new bind performed. + */ + int getSequenceNumber() { + return mCurSeq; + } + + /** + * Increase the current binding sequence number by one. + * Reset to 1 on overflow. + */ + void advanceSequenceNumber() { + mCurSeq += 1; + if (mCurSeq <= 0) { + mCurSeq = 1; + } + } } diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 0d9d8b697de30..3526894e7aa3c 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -469,28 +469,26 @@ public class InputMethodManagerService extends IInputMethodManager.Stub *

This can be transiently {@code null} when the system is re-initializing input method * settings, e.g., the system locale is just changed.

* - *

Note that {@link #getCurId()} is used to track which IME is being connected to - * {@link InputMethodManagerService}.

+ *

Note that {@link InputMethodBindingController#getCurId()} is used to track which IME is + * being connected to {@link InputMethodManagerService}.

* - * @see #getCurId() + * @see InputMethodBindingController#getCurId() */ @Nullable private String getSelectedMethodId() { - return mSelectedMethodId; + return mBindingController.getSelectedMethodId(); } private void setSelectedMethodId(@Nullable String selectedMethodId) { - mSelectedMethodId = selectedMethodId; + mBindingController.setSelectedMethodId(selectedMethodId); } - @Nullable - private String mSelectedMethodId; /** * The current binding sequence number, incremented every time there is * a new bind performed. */ private int getSequenceNumber() { - return mCurSeq; + return mBindingController.getSequenceNumber(); } /** @@ -498,14 +496,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub * Reset to 1 on overflow. */ private void advanceSequenceNumber() { - mCurSeq += 1; - if (mCurSeq <= 0) { - mCurSeq = 1; - } + mBindingController.advanceSequenceNumber(); } - private int mCurSeq; - /** * {@code true} if the Ime policy has been set to {@link WindowManager#DISPLAY_IME_POLICY_HIDE}. * @@ -565,16 +558,13 @@ public class InputMethodManagerService extends IInputMethodManager.Stub */ @Nullable private String getCurId() { - return mCurId; + return mBindingController.getCurId(); } private void setCurId(@Nullable String curId) { - mCurId = curId; + mBindingController.setCurId(curId); } - @Nullable - private String mCurId; - /** * The current subtype of the current input method. */ @@ -590,13 +580,12 @@ public class InputMethodManagerService extends IInputMethodManager.Stub * a service (whether or not we have gotten its IBinder back yet). */ private boolean hasConnection() { - return mHasConnection; + return mBindingController.hasConnection(); } private void setHasConnection(boolean hasConnection) { - mHasConnection = hasConnection; + mBindingController.setHasConnection(hasConnection); } - private boolean mHasConnection; /** * Set if the client has asked for the input method to be shown. @@ -628,30 +617,25 @@ public class InputMethodManagerService extends IInputMethodManager.Stub */ @Nullable private Intent getCurIntent() { - return mCurIntent; + return mBindingController.getCurIntent(); } private void setCurIntent(@Nullable Intent curIntent) { - mCurIntent = curIntent; + mBindingController.setCurIntent(curIntent); } - @Nullable - private Intent mCurIntent; - /** * The token we have made for the currently active input method, to * identify it in the future. */ private IBinder getCurToken() { - return mCurToken; + return mBindingController.getCurToken(); } private void setCurToken(IBinder curToken) { - mCurToken = curToken; + mBindingController.setCurToken(curToken); } - private IBinder mCurToken; - /** * The displayId of current active input method. */ @@ -688,15 +672,13 @@ public class InputMethodManagerService extends IInputMethodManager.Stub * if we should try to disconnect and reconnect to it. */ private long getLastBindTime() { - return mLastBindTime; + return mBindingController.getLastBindTime(); } private void setLastBindTime(long lastBindTime) { - mLastBindTime = lastBindTime; + mBindingController.setLastBindTime(lastBindTime); } - private long mLastBindTime; - /** * Have we called mCurMethod.bindInput()? */ From 66763f371f5065e704a0748033cadfc25158ed52 Mon Sep 17 00:00:00 2001 From: Nikolas Havrikov Date: Wed, 10 Nov 2021 17:58:37 +0100 Subject: [PATCH 13/43] Encapsulate mVisibleConnection in IMMS This is a step in a refactoring and will be superseded by follow-up commits. Bug: 205676419 Test: make Change-Id: Icb98e6e5a0fd517e61e12711a0aaf0a77d52f760 --- .../inputmethod/InputMethodManagerService.java | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 3526894e7aa3c..dd6c22e9b1cd5 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -351,12 +351,18 @@ public class InputMethodManagerService extends IInputMethodManager.Stub @GuardedBy("mMethodMap") private int mMethodMapUpdateCount = 0; - // Used to bring IME service up to visible adjustment while it is being shown. - final ServiceConnection mVisibleConnection = new ServiceConnection() { + /** + * Used to bring IME service up to visible adjustment while it is being shown. + */ + private ServiceConnection getVisibleConnection() { + return mVisibleConnection; + } + + private final ServiceConnection mVisibleConnection = new ServiceConnection() { @Override public void onBindingDied(ComponentName name) { synchronized (mMethodMap) { if (mVisibleBound) { - mContext.unbindService(mVisibleConnection); + mContext.unbindService(getVisibleConnection()); mVisibleBound = false; } } @@ -2668,7 +2674,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub @GuardedBy("mMethodMap") void unbindCurrentMethodLocked() { if (mVisibleBound) { - mContext.unbindService(mVisibleConnection); + mContext.unbindService(getVisibleConnection()); mVisibleBound = false; } @@ -3242,7 +3248,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mInputShown = true; if (hasConnection() && !mVisibleBound) { bindCurrentInputMethodServiceLocked( - getCurIntent(), mVisibleConnection, IME_VISIBLE_BIND_FLAGS); + getCurIntent(), getVisibleConnection(), IME_VISIBLE_BIND_FLAGS); mVisibleBound = true; } res = true; @@ -3350,7 +3356,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub res = false; } if (hasConnection() && mVisibleBound) { - mContext.unbindService(mVisibleConnection); + mContext.unbindService(getVisibleConnection()); mVisibleBound = false; } mInputShown = false; From ff66a00ebba767890a95501b3b8ae4ee7c215447 Mon Sep 17 00:00:00 2001 From: Nikolas Havrikov Date: Wed, 10 Nov 2021 18:03:15 +0100 Subject: [PATCH 14/43] Encapsulate mVisibleBound in IMMS This is a step in a refactoring and will be superseded by follow-up commits. Bug: 205676419 Test: make Change-Id: Ie90aea7b91d4bf2b2e34e587a752e6717b4f84d8 --- .../InputMethodManagerService.java | 31 +++++++++++++------ 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index dd6c22e9b1cd5..9289907b3ed16 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -351,6 +351,18 @@ public class InputMethodManagerService extends IInputMethodManager.Stub @GuardedBy("mMethodMap") private int mMethodMapUpdateCount = 0; + /** + * Indicates whether {@link #getVisibleConnection} is currently in use. + */ + private boolean isVisibleBound() { + return mVisibleBound; + } + + private void setVisibleBound(boolean visibleBound) { + mVisibleBound = visibleBound; + } + private boolean mVisibleBound = false; + /** * Used to bring IME service up to visible adjustment while it is being shown. */ @@ -361,9 +373,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub private final ServiceConnection mVisibleConnection = new ServiceConnection() { @Override public void onBindingDied(ComponentName name) { synchronized (mMethodMap) { - if (mVisibleBound) { + if (isVisibleBound()) { mContext.unbindService(getVisibleConnection()); - mVisibleBound = false; + setVisibleBound(false); } } } @@ -374,7 +386,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub @Override public void onServiceDisconnected(ComponentName name) { } }; - boolean mVisibleBound = false; // Ongoing notification private NotificationManager mNotificationManager; @@ -2673,9 +2684,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub @GuardedBy("mMethodMap") void unbindCurrentMethodLocked() { - if (mVisibleBound) { + if (isVisibleBound()) { mContext.unbindService(getVisibleConnection()); - mVisibleBound = false; + setVisibleBound(false); } if (hasConnection()) { @@ -3246,10 +3257,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub executeOrSendMessage(mCurMethod, mCaller.obtainMessageIIOOO(MSG_SHOW_SOFT_INPUT, getImeShowFlagsLocked(), reason, mCurMethod, resultReceiver, showInputToken)); mInputShown = true; - if (hasConnection() && !mVisibleBound) { + if (hasConnection() && !isVisibleBound()) { bindCurrentInputMethodServiceLocked( getCurIntent(), getVisibleConnection(), IME_VISIBLE_BIND_FLAGS); - mVisibleBound = true; + setVisibleBound(true); } res = true; } else { @@ -3355,9 +3366,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } else { res = false; } - if (hasConnection() && mVisibleBound) { + if (hasConnection() && isVisibleBound()) { mContext.unbindService(getVisibleConnection()); - mVisibleBound = false; + setVisibleBound(false); } mInputShown = false; mShowRequested = false; @@ -5303,7 +5314,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub + " client=" + mCurFocusedWindowClient); focusedWindowClient = mCurFocusedWindowClient; p.println(" mCurId=" + getCurId() + " mHaveConnection=" + hasConnection() - + " mBoundToMethod=" + mBoundToMethod + " mVisibleBound=" + mVisibleBound); + + " mBoundToMethod=" + mBoundToMethod + " mVisibleBound=" + isVisibleBound()); p.println(" mCurToken=" + getCurToken()); p.println(" mCurTokenDisplayId=" + mCurTokenDisplayId); p.println(" mCurHostInputToken=" + mCurHostInputToken); From a275ce8a0c561b3b4309cda7625cf858e4731fdd Mon Sep 17 00:00:00 2001 From: Nikolas Havrikov Date: Wed, 10 Nov 2021 18:19:45 +0100 Subject: [PATCH 15/43] Move visible connection state to ImeBindingController Bug: 205676419 Test: make Change-Id: I47dd41b0295d640effcff80cb0d836ec73b8a40b --- .../InputMethodBindingController.java | 48 ++++++++++++++++++- .../InputMethodManagerService.java | 24 ++-------- 2 files changed, 50 insertions(+), 22 deletions(-) diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java index 39e3501f22d7b..f8eb3e2ef1886 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java @@ -18,8 +18,12 @@ package com.android.server.inputmethod; import android.annotation.NonNull; import android.annotation.Nullable; +import android.content.ComponentName; +import android.content.Context; import android.content.Intent; +import android.content.ServiceConnection; import android.os.IBinder; +import android.util.ArrayMap; import android.view.inputmethod.InputMethodInfo; /** @@ -29,7 +33,9 @@ final class InputMethodBindingController { static final boolean DEBUG = false; private static final String TAG = InputMethodBindingController.class.getSimpleName(); - private final InputMethodManagerService mService; + @NonNull private final InputMethodManagerService mService; + @NonNull private final Context mContext; + @NonNull private final ArrayMap mMethodMap; private long mLastBindTime; private boolean mHasConnection; @@ -38,10 +44,13 @@ final class InputMethodBindingController { @Nullable private Intent mCurIntent; private IBinder mCurToken; private int mCurSeq; + private boolean mVisibleBound; InputMethodBindingController(@NonNull InputMethodManagerService service) { mService = service; + mContext = mService.mContext; + mMethodMap = mService.mMethodMap; } /** @@ -149,4 +158,41 @@ final class InputMethodBindingController { mCurSeq = 1; } } + + /** + * Indicates whether {@link #getVisibleConnection} is currently in use. + */ + boolean isVisibleBound() { + return mVisibleBound; + } + + void setVisibleBound(boolean visibleBound) { + mVisibleBound = visibleBound; + } + + /** + * Used to bring IME service up to visible adjustment while it is being shown. + */ + @NonNull + ServiceConnection getVisibleConnection() { + return mVisibleConnection; + } + + private final ServiceConnection mVisibleConnection = new ServiceConnection() { + @Override public void onBindingDied(ComponentName name) { + synchronized (mMethodMap) { + if (isVisibleBound()) { + mContext.unbindService(getVisibleConnection()); + setVisibleBound(false); + } + } + } + + @Override public void onServiceConnected(ComponentName name, IBinder service) { + } + + @Override public void onServiceDisconnected(ComponentName name) { + } + }; + } diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 9289907b3ed16..c829ee39e48b3 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -355,38 +355,20 @@ public class InputMethodManagerService extends IInputMethodManager.Stub * Indicates whether {@link #getVisibleConnection} is currently in use. */ private boolean isVisibleBound() { - return mVisibleBound; + return mBindingController.isVisibleBound(); } private void setVisibleBound(boolean visibleBound) { - mVisibleBound = visibleBound; + mBindingController.setVisibleBound(visibleBound); } - private boolean mVisibleBound = false; /** * Used to bring IME service up to visible adjustment while it is being shown. */ private ServiceConnection getVisibleConnection() { - return mVisibleConnection; + return mBindingController.getVisibleConnection(); } - private final ServiceConnection mVisibleConnection = new ServiceConnection() { - @Override public void onBindingDied(ComponentName name) { - synchronized (mMethodMap) { - if (isVisibleBound()) { - mContext.unbindService(getVisibleConnection()); - setVisibleBound(false); - } - } - } - - @Override public void onServiceConnected(ComponentName name, IBinder service) { - } - - @Override public void onServiceDisconnected(ComponentName name) { - } - }; - // Ongoing notification private NotificationManager mNotificationManager; KeyguardManager mKeyguardManager; From d739b3cdb3786e1f9454aa8bb06ae2d1c05b5589 Mon Sep 17 00:00:00 2001 From: Nikolas Havrikov Date: Wed, 10 Nov 2021 18:34:32 +0100 Subject: [PATCH 16/43] Encapsulate more IMMS members This is a step in a larger refactoring. Bug: 205676419 Test: make Change-Id: I65cf0e3e69f0b63ccfdf7b92bc4c7d1d1ac3dabb --- .../InputMethodManagerService.java | 107 +++++++++++------- 1 file changed, 64 insertions(+), 43 deletions(-) diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index c829ee39e48b3..cac69791770c6 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -659,12 +659,31 @@ public class InputMethodManagerService extends IInputMethodManager.Stub * If non-null, this is the input method service we are currently connected * to. */ - IInputMethod mCurMethod; + @Nullable + private IInputMethod getCurMethod() { + return mCurMethod; + } + + private void setCurMethod(@Nullable IInputMethod curMethod) { + mCurMethod = curMethod; + } + + @Nullable + private IInputMethod mCurMethod; + /** * If not {@link Process#INVALID_UID}, then the UID of {@link #getCurIntent()}. */ - int mCurMethodUid = Process.INVALID_UID; + private int getCurMethodUid() { + return mCurMethodUid; + } + + private void setCurMethodUid(int curMethodUid) { + mCurMethodUid = curMethodUid; + } + + private int mCurMethodUid = Process.INVALID_UID; /** * Time that we last initiated a bind to the input method, to determine @@ -2034,9 +2053,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub final InputMethodInfo imi = mMethodMap.get(getSelectedMethodId()); try { if (userId == mSettings.getCurrentUserId() && imi != null - && imi.isInlineSuggestionsEnabled() && mCurMethod != null) { - executeOrSendMessage(mCurMethod, - mCaller.obtainMessageOOO(MSG_INLINE_SUGGESTIONS_REQUEST, mCurMethod, + && imi.isInlineSuggestionsEnabled() && getCurMethod() != null) { + executeOrSendMessage(getCurMethod(), + mCaller.obtainMessageOOO(MSG_INLINE_SUGGESTIONS_REQUEST, getCurMethod(), requestInfo, new InlineSuggestionsRequestCallbackDecorator(callback, imi.getPackageName(), mCurTokenDisplayId, getCurToken(), this))); @@ -2272,9 +2291,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mCurFocusedWindow, 0, null, SoftInputShowHideReason.HIDE_REMOVE_CLIENT); if (mBoundToMethod) { mBoundToMethod = false; - if (mCurMethod != null) { - executeOrSendMessage(mCurMethod, mCaller.obtainMessageO( - MSG_UNBIND_INPUT, mCurMethod)); + if (getCurMethod() != null) { + executeOrSendMessage(getCurMethod(), mCaller.obtainMessageO( + MSG_UNBIND_INPUT, getCurMethod())); } } mCurClient = null; @@ -2302,9 +2321,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub + mCurClient.client.asBinder()); if (mBoundToMethod) { mBoundToMethod = false; - if (mCurMethod != null) { - executeOrSendMessage(mCurMethod, mCaller.obtainMessageO( - MSG_UNBIND_INPUT, mCurMethod)); + if (getCurMethod() != null) { + executeOrSendMessage(getCurMethod(), mCaller.obtainMessageO( + MSG_UNBIND_INPUT, getCurMethod())); } } @@ -2346,8 +2365,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub @NonNull InputBindResult attachNewInputLocked(@StartInputReason int startInputReason, boolean initial) { if (!mBoundToMethod) { - executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO( - MSG_BIND_INPUT, mCurMethod, mCurClient.binding)); + executeOrSendMessage(getCurMethod(), mCaller.obtainMessageOO( + MSG_BIND_INPUT, getCurMethod(), mCurClient.binding)); mBoundToMethod = true; } @@ -2367,7 +2386,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub // INTERACT_ACROSS_USERS(_FULL) permissions, which is actually almost always the case. if (mSettings.getCurrentUserId() == UserHandle.getUserId(mCurClient.uid)) { mPackageManagerInternal.grantImplicitAccess(mSettings.getCurrentUserId(), - null /* intent */, UserHandle.getAppId(mCurMethodUid), mCurClient.uid, true); + null /* intent */, UserHandle.getAppId(getCurMethodUid()), mCurClient.uid, + true /* direct */); } final SessionState session = mCurClient.curSession; @@ -2499,7 +2519,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub @Nullable private InputBindResult tryReuseConnectionLocked(@NonNull ClientState cs) { if (hasConnection()) { - if (mCurMethod != null) { + if (getCurMethod() != null) { // Return to client, and we will get back with it when // we have had a session made for it. requestClientSessionLocked(cs); @@ -2604,15 +2624,15 @@ public class InputMethodManagerService extends IInputMethodManager.Stub Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.onServiceConnected"); synchronized (mMethodMap) { if (getCurIntent() != null && name.equals(getCurIntent().getComponent())) { - mCurMethod = IInputMethod.Stub.asInterface(service); + setCurMethod(IInputMethod.Stub.asInterface(service)); final String curMethodPackage = getCurIntent().getComponent().getPackageName(); final int curMethodUid = mPackageManagerInternal.getPackageUid( curMethodPackage, 0 /* flags */, mSettings.getCurrentUserId()); if (curMethodUid < 0) { Slog.e(TAG, "Failed to get UID for package=" + curMethodPackage); - mCurMethodUid = Process.INVALID_UID; + setCurMethodUid(Process.INVALID_UID); } else { - mCurMethodUid = curMethodUid; + setCurMethodUid(curMethodUid); } if (getCurToken() == null) { Slog.w(TAG, "Service connected without a token!"); @@ -2622,10 +2642,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } if (DEBUG) Slog.v(TAG, "Initiating attach with token: " + getCurToken()); // Dispatch display id for InputMethodService to update context display. - executeOrSendMessage(mCurMethod, mCaller.obtainMessageIOO(MSG_INITIALIZE_IME, - mMethodMap.get(getSelectedMethodId()).getConfigChanges(), mCurMethod, + executeOrSendMessage(getCurMethod(), mCaller.obtainMessageIOO(MSG_INITIALIZE_IME, + mMethodMap.get(getSelectedMethodId()).getConfigChanges(), getCurMethod(), getCurToken())); - scheduleNotifyImeUidToAudioService(mCurMethodUid); + scheduleNotifyImeUidToAudioService(getCurMethodUid()); if (mCurClient != null) { clearClientSessionLocked(mCurClient); requestClientSessionLocked(mCurClient); @@ -2643,8 +2663,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub channel.dispose(); return; } - if (mCurMethod != null && method != null - && mCurMethod.asBinder() == method.asBinder()) { + if (getCurMethod() != null && method != null + && getCurMethod().asBinder() == method.asBinder()) { if (mCurClient != null) { clearClientSessionLocked(mCurClient); mCurClient.curSession = new SessionState(mCurClient, @@ -2709,9 +2729,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub if (DEBUG) Slog.v(TAG, "Creating new session for client " + cs); InputChannel[] channels = InputChannel.openInputChannelPair(cs.toString()); cs.sessionRequested = true; - executeOrSendMessage(mCurMethod, mCaller.obtainMessageOOO( - MSG_CREATE_SESSION, mCurMethod, channels[1], - new MethodCallback(this, mCurMethod, channels[0]))); + executeOrSendMessage(getCurMethod(), mCaller.obtainMessageOOO( + MSG_CREATE_SESSION, getCurMethod(), channels[1], + new MethodCallback(this, getCurMethod(), channels[0]))); } } @@ -2743,7 +2763,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub @GuardedBy("mMethodMap") void clearCurMethodLocked() { - if (mCurMethod != null) { + if (getCurMethod() != null) { final int numClients = mClients.size(); for (int i = 0; i < numClients; ++i) { clearClientSessionLocked(mClients.valueAt(i)); @@ -2751,9 +2771,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub finishSessionLocked(mEnabledSession); mEnabledSession = null; - mCurMethod = null; - mCurMethodUid = Process.INVALID_UID; - scheduleNotifyImeUidToAudioService(mCurMethodUid); + setCurMethod(null); + setCurMethodUid(Process.INVALID_UID); + scheduleNotifyImeUidToAudioService(getCurMethodUid()); } if (mStatusBar != null) { mStatusBar.setIconVisibility(mSlotIme, false); @@ -2773,7 +2793,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub synchronized (mMethodMap) { if (DEBUG) Slog.v(TAG, "Service disconnected: " + name + " mCurIntent=" + getCurIntent()); - if (mCurMethod != null && getCurIntent() != null + if (getCurMethod() != null && getCurIntent() != null && name.equals(getCurIntent().getComponent())) { clearCurMethodLocked(); // We consider this to be a new bind attempt, since the system @@ -3116,10 +3136,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } if (newSubtype != oldSubtype) { setSelectedInputMethodAndSubtypeLocked(info, subtypeId, true); - if (mCurMethod != null) { + if (getCurMethod() != null) { try { updateSystemUiLocked(mImeWindowVis, mBackDisposition); - mCurMethod.changeInputMethodSubtype(newSubtype); + getCurMethod().changeInputMethodSubtype(newSubtype); } catch (RemoteException e) { Slog.w(TAG, "Failed to call changeInputMethodSubtype"); } @@ -3231,13 +3251,14 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } boolean res = false; - if (mCurMethod != null) { + if (getCurMethod() != null) { if (DEBUG) Slog.d(TAG, "showCurrentInputLocked: mCurToken=" + getCurToken()); // create a placeholder token for IMS so that IMS cannot inject windows into client app. Binder showInputToken = new Binder(); mShowRequestWindowMap.put(showInputToken, windowToken); - executeOrSendMessage(mCurMethod, mCaller.obtainMessageIIOOO(MSG_SHOW_SOFT_INPUT, - getImeShowFlagsLocked(), reason, mCurMethod, resultReceiver, showInputToken)); + executeOrSendMessage(getCurMethod(), mCaller.obtainMessageIIOOO(MSG_SHOW_SOFT_INPUT, + getImeShowFlagsLocked(), reason, getCurMethod(), resultReceiver, + showInputToken)); mInputShown = true; if (hasConnection() && !isVisibleBound()) { bindCurrentInputMethodServiceLocked( @@ -3332,7 +3353,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub // since Android Eclair. That's why we need to accept IMM#hideSoftInput() even when only // IMMS#InputShown indicates that the software keyboard is shown. // TODO: Clean up, IMMS#mInputShown, IMMS#mImeWindowVis and mShowRequested. - final boolean shouldHideSoftInput = (mCurMethod != null) && (mInputShown + final boolean shouldHideSoftInput = (getCurMethod() != null) && (mInputShown || (mImeWindowVis & InputMethodService.IME_ACTIVE) != 0); boolean res; if (shouldHideSoftInput) { @@ -3342,8 +3363,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub // delivered to the IME process as an IPC. Hence the inconsistency between // IMMS#mInputShown and IMMS#mImeWindowVis should be resolved spontaneously in // the final state. - executeOrSendMessage(mCurMethod, mCaller.obtainMessageIOOO(MSG_HIDE_SOFT_INPUT, - reason, mCurMethod, resultReceiver, hideInputToken)); + executeOrSendMessage(getCurMethod(), mCaller.obtainMessageIOOO(MSG_HIDE_SOFT_INPUT, + reason, getCurMethod(), resultReceiver, hideInputToken)); res = true; } else { res = false; @@ -3805,7 +3826,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub if (!calledFromValidUserLocked()) { return; } - executeOrSendMessage(mCurMethod, mCaller.obtainMessageO( + executeOrSendMessage(getCurMethod(), mCaller.obtainMessageO( MSG_SHOW_IM_SUBTYPE_ENABLER, inputMethodId)); } } @@ -4584,7 +4605,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub boolean reportToImeController = false; try { reportToImeController = mPlatformCompat.isChangeEnabledByUid( - FINISH_INPUT_NO_FALLBACK_CONNECTION, mCurMethodUid); + FINISH_INPUT_NO_FALLBACK_CONNECTION, getCurMethodUid()); } catch (RemoteException e) { } scheduleSetActiveToClient(mCurClient, mIsInteractive, mInFullscreenMode, @@ -5301,8 +5322,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub p.println(" mCurTokenDisplayId=" + mCurTokenDisplayId); p.println(" mCurHostInputToken=" + mCurHostInputToken); p.println(" mCurIntent=" + getCurIntent()); - method = mCurMethod; - p.println(" mCurMethod=" + mCurMethod); + method = getCurMethod(); + p.println(" mCurMethod=" + getCurMethod()); p.println(" mEnabledSession=" + mEnabledSession); p.println(" mShowRequested=" + mShowRequested + " mShowExplicitlyRequested=" + mShowExplicitlyRequested From e82e9f729727c835accf9727939959a6e20dde7f Mon Sep 17 00:00:00 2001 From: Nikolas Havrikov Date: Thu, 11 Nov 2021 10:54:41 +0100 Subject: [PATCH 17/43] Move more encapsulated IMMS members Bug: 205676419 Test: make Change-Id: I005761b1b1aa909c2abe726999be138e3a667510 --- .../InputMethodBindingController.java | 29 +++++++++++++++++++ .../InputMethodManagerService.java | 14 +++------ 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java index f8eb3e2ef1886..8b586ccb5f695 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java @@ -23,9 +23,12 @@ import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.IBinder; +import android.os.Process; import android.util.ArrayMap; import android.view.inputmethod.InputMethodInfo; +import com.android.internal.view.IInputMethod; + /** * A controller managing the state of the input method binding. */ @@ -42,6 +45,8 @@ final class InputMethodBindingController { @Nullable private String mCurId; @Nullable private String mSelectedMethodId; @Nullable private Intent mCurIntent; + @Nullable private IInputMethod mCurMethod; + private int mCurMethodUid = Process.INVALID_UID; private IBinder mCurToken; private int mCurSeq; private boolean mVisibleBound; @@ -159,6 +164,30 @@ final class InputMethodBindingController { } } + /** + * If non-null, this is the input method service we are currently connected + * to. + */ + @Nullable + IInputMethod getCurMethod() { + return mCurMethod; + } + + void setCurMethod(@Nullable IInputMethod curMethod) { + mCurMethod = curMethod; + } + + /** + * If not {@link Process#INVALID_UID}, then the UID of {@link #getCurIntent()}. + */ + int getCurMethodUid() { + return mCurMethodUid; + } + + void setCurMethodUid(int curMethodUid) { + mCurMethodUid = curMethodUid; + } + /** * Indicates whether {@link #getVisibleConnection} is currently in use. */ diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index cac69791770c6..9f56c7655779b 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -661,30 +661,24 @@ public class InputMethodManagerService extends IInputMethodManager.Stub */ @Nullable private IInputMethod getCurMethod() { - return mCurMethod; + return mBindingController.getCurMethod(); } private void setCurMethod(@Nullable IInputMethod curMethod) { - mCurMethod = curMethod; + mBindingController.setCurMethod(curMethod); } - @Nullable - private IInputMethod mCurMethod; - - /** * If not {@link Process#INVALID_UID}, then the UID of {@link #getCurIntent()}. */ private int getCurMethodUid() { - return mCurMethodUid; + return mBindingController.getCurMethodUid(); } private void setCurMethodUid(int curMethodUid) { - mCurMethodUid = curMethodUid; + mBindingController.setCurMethodUid(curMethodUid); } - private int mCurMethodUid = Process.INVALID_UID; - /** * Time that we last initiated a bind to the input method, to determine * if we should try to disconnect and reconnect to it. From 040f7fb393bce5863b9da6b550e412ae0fcdcb7a Mon Sep 17 00:00:00 2001 From: Nikolas Havrikov Date: Thu, 11 Nov 2021 11:49:01 +0100 Subject: [PATCH 18/43] Change IMMS not to implement ServiceConnection Instead, encapsulate the service connection into a member, and use via delegation. Bug: 205676419 Test: make Change-Id: I4244dce35e4025d9ad779672574751728d4f544d --- .../InputMethodManagerService.java | 142 ++++++++++-------- 1 file changed, 82 insertions(+), 60 deletions(-) diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 9f56c7655779b..62d628c0dcf9c 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -208,7 +208,7 @@ import java.util.concurrent.atomic.AtomicInteger; * This class provides a system service that manages input methods. */ public class InputMethodManagerService extends IInputMethodManager.Stub - implements ServiceConnection, Handler.Callback { + implements Handler.Callback { static final boolean DEBUG = false; static final String TAG = "InputMethodManagerService"; public static final String PROTO_ARG = "--proto"; @@ -369,6 +369,14 @@ public class InputMethodManagerService extends IInputMethodManager.Stub return mBindingController.getVisibleConnection(); } + /** + * Used to bind the IME while it is not currently being shown. + */ + @NonNull + private ServiceConnection getMainConnection() { + return mMainConnection; + } + // Ongoing notification private NotificationManager mNotificationManager; KeyguardManager mKeyguardManager; @@ -2480,7 +2488,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub Intent intent = createImeBindingIntent(info.getComponent()); setCurIntent(intent); - if (bindCurrentInputMethodServiceLocked(intent, this, mImeConnectionBindFlags)) { + if (bindCurrentInputMethodServiceLocked(intent, getMainConnection(), + mImeConnectionBindFlags)) { addFreshWindowTokenLocked(displayIdToShowIme, info.getId()); return new InputBindResult( InputBindResult.ResultCode.SUCCESS_WAITING_IME_BINDING, @@ -2613,41 +2622,77 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mCaller.obtainMessageI(MSG_NOTIFY_IME_UID_TO_AUDIO_SERVICE, uid).sendToTarget(); } - @Override - public void onServiceConnected(ComponentName name, IBinder service) { - Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.onServiceConnected"); - synchronized (mMethodMap) { - if (getCurIntent() != null && name.equals(getCurIntent().getComponent())) { - setCurMethod(IInputMethod.Stub.asInterface(service)); - final String curMethodPackage = getCurIntent().getComponent().getPackageName(); - final int curMethodUid = mPackageManagerInternal.getPackageUid( - curMethodPackage, 0 /* flags */, mSettings.getCurrentUserId()); - if (curMethodUid < 0) { - Slog.e(TAG, "Failed to get UID for package=" + curMethodPackage); - setCurMethodUid(Process.INVALID_UID); - } else { - setCurMethodUid(curMethodUid); + private final ServiceConnection mMainConnection = new ServiceConnection() { + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.onServiceConnected"); + synchronized (mMethodMap) { + if (getCurIntent() != null && name.equals(getCurIntent().getComponent())) { + setCurMethod(IInputMethod.Stub.asInterface(service)); + final String curMethodPackage = + getCurIntent().getComponent().getPackageName(); + final int curMethodUid = mPackageManagerInternal.getPackageUid( + curMethodPackage, 0 /* flags */, mSettings.getCurrentUserId()); + if (curMethodUid < 0) { + Slog.e(TAG, "Failed to get UID for package=" + curMethodPackage); + setCurMethodUid(Process.INVALID_UID); + } else { + setCurMethodUid(curMethodUid); + } + if (getCurToken() == null) { + Slog.w(TAG, "Service connected without a token!"); + unbindCurrentMethodLocked(); + Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); + return; + } + if (DEBUG) Slog.v(TAG, "Initiating attach with token: " + getCurToken()); + // Dispatch display id for InputMethodService to update context display. + executeOrSendMessage(getCurMethod(), + mCaller.obtainMessageIOO(MSG_INITIALIZE_IME, + mMethodMap.get(getSelectedMethodId()).getConfigChanges(), + getCurMethod(), getCurToken())); + scheduleNotifyImeUidToAudioService(getCurMethodUid()); + if (mCurClient != null) { + clearClientSessionLocked(mCurClient); + requestClientSessionLocked(mCurClient); + } } - if (getCurToken() == null) { - Slog.w(TAG, "Service connected without a token!"); - unbindCurrentMethodLocked(); - Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); - return; + } + Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); + } + + @Override + public void onServiceDisconnected(ComponentName name) { + // Note that mContext.unbindService(this) does not trigger this. Hence if we are + // here the + // disconnection is not intended by IMMS (e.g. triggered because the current IMS + // crashed), + // which is irregular but can eventually happen for everyone just by continuing + // using the + // device. Thus it is important to make sure that all the internal states are + // properly + // refreshed when this method is called back. Running + // adb install -r + // would be a good way to trigger such a situation. + synchronized (mMethodMap) { + if (DEBUG) { + Slog.v(TAG, "Service disconnected: " + name + + " mCurIntent=" + getCurIntent()); } - if (DEBUG) Slog.v(TAG, "Initiating attach with token: " + getCurToken()); - // Dispatch display id for InputMethodService to update context display. - executeOrSendMessage(getCurMethod(), mCaller.obtainMessageIOO(MSG_INITIALIZE_IME, - mMethodMap.get(getSelectedMethodId()).getConfigChanges(), getCurMethod(), - getCurToken())); - scheduleNotifyImeUidToAudioService(getCurMethodUid()); - if (mCurClient != null) { - clearClientSessionLocked(mCurClient); - requestClientSessionLocked(mCurClient); + if (getCurMethod() != null && getCurIntent() != null + && name.equals(getCurIntent().getComponent())) { + clearCurMethodLocked(); + // We consider this to be a new bind attempt, since the system + // should now try to restart the service for us. + setLastBindTime(SystemClock.uptimeMillis()); + mShowRequested = mInputShown; + mInputShown = false; + unbindCurrentClientLocked(UnbindReason.DISCONNECT_IME); } } } - Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); - } + + }; void onSessionCreated(IInputMethod method, IInputMethodSession session, InputChannel channel) { @@ -2686,7 +2731,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } if (hasConnection()) { - mContext.unbindService(this); + mContext.unbindService(getMainConnection()); setHasConnection(false); } @@ -2775,31 +2820,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mInFullscreenMode = false; } - @Override - public void onServiceDisconnected(ComponentName name) { - // Note that mContext.unbindService(this) does not trigger this. Hence if we are here the - // disconnection is not intended by IMMS (e.g. triggered because the current IMS crashed), - // which is irregular but can eventually happen for everyone just by continuing using the - // device. Thus it is important to make sure that all the internal states are properly - // refreshed when this method is called back. Running - // adb install -r - // would be a good way to trigger such a situation. - synchronized (mMethodMap) { - if (DEBUG) Slog.v(TAG, "Service disconnected: " + name - + " mCurIntent=" + getCurIntent()); - if (getCurMethod() != null && getCurIntent() != null - && name.equals(getCurIntent().getComponent())) { - clearCurMethodLocked(); - // We consider this to be a new bind attempt, since the system - // should now try to restart the service for us. - setLastBindTime(SystemClock.uptimeMillis()); - mShowRequested = mInputShown; - mInputShown = false; - unbindCurrentClientLocked(UnbindReason.DISCONNECT_IME); - } - } - } - @BinderThread private void updateStatusIcon(@NonNull IBinder token, String packageName, @DrawableRes int iconId) { @@ -3270,8 +3290,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub EventLog.writeEvent(EventLogTags.IMF_FORCE_RECONNECT_IME, getSelectedMethodId(), bindingDuration, 1); Slog.w(TAG, "Force disconnect/connect to the IME in showCurrentInputLocked()"); - mContext.unbindService(this); - bindCurrentInputMethodServiceLocked(getCurIntent(), this, mImeConnectionBindFlags); + ServiceConnection connection = getMainConnection(); + mContext.unbindService(connection); + bindCurrentInputMethodServiceLocked(getCurIntent(), connection, + mImeConnectionBindFlags); } else { if (DEBUG) { Slog.d(TAG, "Can't show input: connection = " + hasConnection() + ", time = " From 55f546a95da3546eb626a885a416092fb99227f8 Mon Sep 17 00:00:00 2001 From: Nikolas Havrikov Date: Thu, 11 Nov 2021 12:12:14 +0100 Subject: [PATCH 19/43] Add accessors for client-related members of IMMS While not immediately used, these comprise a preparatory refactoring step. Bug: 205676419 Test: make Change-Id: Iaf6d2f67fdf423365810e9a14637dceeca7a64ee --- .../InputMethodManagerService.java | 30 +++++++++++++++++-- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 62d628c0dcf9c..a35687d579b33 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -513,10 +513,18 @@ public class InputMethodManagerService extends IInputMethodManager.Stub */ boolean mImeHiddenByDisplayPolicy; + ClientState getCurClient() { + return mCurClient; + } + + void setCurClient(ClientState curClient) { + mCurClient = curClient; + } + /** * The client that is currently bound to an input method. */ - ClientState mCurClient; + private ClientState mCurClient; /** * The last window token that we confirmed to be focused. This is always updated upon reports @@ -594,10 +602,18 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mBindingController.setHasConnection(hasConnection); } + boolean isShowRequested() { + return mShowRequested; + } + + void setShowRequested(boolean showRequested) { + mShowRequested = showRequested; + } + /** * Set if the client has asked for the input method to be shown. */ - boolean mShowRequested; + private boolean mShowRequested; /** * Set if we were explicitly told to show the input method. @@ -609,10 +625,18 @@ public class InputMethodManagerService extends IInputMethodManager.Stub */ boolean mShowForced; + boolean isInputShown() { + return mInputShown; + } + + void setInputShown(boolean inputShown) { + mInputShown = inputShown; + } + /** * Set if we last told the input method to show itself. */ - boolean mInputShown; + private boolean mInputShown; /** * {@code true} if the current input method is in fullscreen mode. From 7a987973f2c6f91469108f972ee1d6d9a3ac0dd7 Mon Sep 17 00:00:00 2001 From: Nikolas Havrikov Date: Thu, 11 Nov 2021 13:44:42 +0100 Subject: [PATCH 20/43] Move IMMS service connection to the binding controller Bug: 205676419 Test: make Change-Id: I7e54a579c4ecd42acdde7b66fe583fe46dff2471 --- .../InputMethodBindingController.java | 94 +++++++++++++++++++ .../InputMethodManagerService.java | 77 +-------------- 2 files changed, 96 insertions(+), 75 deletions(-) diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java index 8b586ccb5f695..765672c00bb2e 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java @@ -16,18 +16,28 @@ package com.android.server.inputmethod; +import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; + +import static com.android.server.inputmethod.InputMethodManagerService.MSG_INITIALIZE_IME; + import android.annotation.NonNull; import android.annotation.Nullable; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; +import android.content.pm.PackageManagerInternal; import android.os.IBinder; import android.os.Process; +import android.os.SystemClock; +import android.os.Trace; import android.util.ArrayMap; +import android.util.Slog; import android.view.inputmethod.InputMethodInfo; +import com.android.internal.inputmethod.UnbindReason; import com.android.internal.view.IInputMethod; +import com.android.server.inputmethod.InputMethodManagerService.ClientState; /** * A controller managing the state of the input method binding. @@ -39,6 +49,8 @@ final class InputMethodBindingController { @NonNull private final InputMethodManagerService mService; @NonNull private final Context mContext; @NonNull private final ArrayMap mMethodMap; + @NonNull private final InputMethodUtils.InputMethodSettings mSettings; + @NonNull private final PackageManagerInternal mPackageManagerInternal; private long mLastBindTime; private boolean mHasConnection; @@ -56,6 +68,8 @@ final class InputMethodBindingController { mService = service; mContext = mService.mContext; mMethodMap = mService.mMethodMap; + mSettings = mService.mSettings; + mPackageManagerInternal = mService.mPackageManagerInternal; } /** @@ -224,4 +238,84 @@ final class InputMethodBindingController { } }; + /** + * Used to bind the IME while it is not currently being shown. + */ + @NonNull + ServiceConnection getMainConnection() { + return mMainConnection; + } + + private final ServiceConnection mMainConnection = new ServiceConnection() { + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.onServiceConnected"); + synchronized (mMethodMap) { + if (getCurIntent() != null && name.equals(getCurIntent().getComponent())) { + setCurMethod(IInputMethod.Stub.asInterface(service)); + final String curMethodPackage = + getCurIntent().getComponent().getPackageName(); + final int curMethodUid = mPackageManagerInternal.getPackageUid( + curMethodPackage, 0 /* flags */, mSettings.getCurrentUserId()); + if (curMethodUid < 0) { + Slog.e(TAG, "Failed to get UID for package=" + curMethodPackage); + setCurMethodUid(Process.INVALID_UID); + } else { + setCurMethodUid(curMethodUid); + } + if (getCurToken() == null) { + Slog.w(TAG, "Service connected without a token!"); + mService.unbindCurrentMethodLocked(); + Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); + return; + } + if (DEBUG) Slog.v(TAG, "Initiating attach with token: " + getCurToken()); + // Dispatch display id for InputMethodService to update context display. + mService.executeOrSendMessage(getCurMethod(), + mService.mCaller.obtainMessageIOO(MSG_INITIALIZE_IME, + mMethodMap.get(getSelectedMethodId()).getConfigChanges(), + getCurMethod(), getCurToken())); + mService.scheduleNotifyImeUidToAudioService(getCurMethodUid()); + ClientState curClient = mService.getCurClient(); + if (curClient != null) { + mService.clearClientSessionLocked(curClient); + mService.requestClientSessionLocked(curClient); + } + } + } + Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); + } + + @Override + public void onServiceDisconnected(ComponentName name) { + // Note that mContext.unbindService(this) does not trigger this. Hence if we are + // here the + // disconnection is not intended by IMMS (e.g. triggered because the current IMS + // crashed), + // which is irregular but can eventually happen for everyone just by continuing + // using the + // device. Thus it is important to make sure that all the internal states are + // properly + // refreshed when this method is called back. Running + // adb install -r + // would be a good way to trigger such a situation. + synchronized (mMethodMap) { + if (DEBUG) { + Slog.v(TAG, "Service disconnected: " + name + + " mCurIntent=" + getCurIntent()); + } + if (getCurMethod() != null && getCurIntent() != null + && name.equals(getCurIntent().getComponent())) { + mService.clearCurMethodLocked(); + // We consider this to be a new bind attempt, since the system + // should now try to restart the service for us. + setLastBindTime(SystemClock.uptimeMillis()); + mService.setShowRequested(mService.isInputShown()); + mService.setInputShown(false); + mService.unbindCurrentClientLocked(UnbindReason.DISCONNECT_IME); + } + } + } + }; + } diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index a35687d579b33..05aebcc7b0a86 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -72,7 +72,6 @@ import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.BroadcastReceiver; -import android.content.ComponentName; import android.content.ContentProvider; import android.content.ContentResolver; import android.content.Context; @@ -374,7 +373,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub */ @NonNull private ServiceConnection getMainConnection() { - return mMainConnection; + return mBindingController.getMainConnection(); } // Ongoing notification @@ -2641,83 +2640,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } @AnyThread - private void scheduleNotifyImeUidToAudioService(int uid) { + void scheduleNotifyImeUidToAudioService(int uid) { mCaller.removeMessages(MSG_NOTIFY_IME_UID_TO_AUDIO_SERVICE); mCaller.obtainMessageI(MSG_NOTIFY_IME_UID_TO_AUDIO_SERVICE, uid).sendToTarget(); } - private final ServiceConnection mMainConnection = new ServiceConnection() { - @Override - public void onServiceConnected(ComponentName name, IBinder service) { - Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.onServiceConnected"); - synchronized (mMethodMap) { - if (getCurIntent() != null && name.equals(getCurIntent().getComponent())) { - setCurMethod(IInputMethod.Stub.asInterface(service)); - final String curMethodPackage = - getCurIntent().getComponent().getPackageName(); - final int curMethodUid = mPackageManagerInternal.getPackageUid( - curMethodPackage, 0 /* flags */, mSettings.getCurrentUserId()); - if (curMethodUid < 0) { - Slog.e(TAG, "Failed to get UID for package=" + curMethodPackage); - setCurMethodUid(Process.INVALID_UID); - } else { - setCurMethodUid(curMethodUid); - } - if (getCurToken() == null) { - Slog.w(TAG, "Service connected without a token!"); - unbindCurrentMethodLocked(); - Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); - return; - } - if (DEBUG) Slog.v(TAG, "Initiating attach with token: " + getCurToken()); - // Dispatch display id for InputMethodService to update context display. - executeOrSendMessage(getCurMethod(), - mCaller.obtainMessageIOO(MSG_INITIALIZE_IME, - mMethodMap.get(getSelectedMethodId()).getConfigChanges(), - getCurMethod(), getCurToken())); - scheduleNotifyImeUidToAudioService(getCurMethodUid()); - if (mCurClient != null) { - clearClientSessionLocked(mCurClient); - requestClientSessionLocked(mCurClient); - } - } - } - Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); - } - - @Override - public void onServiceDisconnected(ComponentName name) { - // Note that mContext.unbindService(this) does not trigger this. Hence if we are - // here the - // disconnection is not intended by IMMS (e.g. triggered because the current IMS - // crashed), - // which is irregular but can eventually happen for everyone just by continuing - // using the - // device. Thus it is important to make sure that all the internal states are - // properly - // refreshed when this method is called back. Running - // adb install -r - // would be a good way to trigger such a situation. - synchronized (mMethodMap) { - if (DEBUG) { - Slog.v(TAG, "Service disconnected: " + name - + " mCurIntent=" + getCurIntent()); - } - if (getCurMethod() != null && getCurIntent() != null - && name.equals(getCurIntent().getComponent())) { - clearCurMethodLocked(); - // We consider this to be a new bind attempt, since the system - // should now try to restart the service for us. - setLastBindTime(SystemClock.uptimeMillis()); - mShowRequested = mInputShown; - mInputShown = false; - unbindCurrentClientLocked(UnbindReason.DISCONNECT_IME); - } - } - } - - }; - void onSessionCreated(IInputMethod method, IInputMethodSession session, InputChannel channel) { synchronized (mMethodMap) { From db9b8816804214a729897018d03bfacc7a261753 Mon Sep 17 00:00:00 2001 From: Nikolas Havrikov Date: Thu, 11 Nov 2021 13:53:30 +0100 Subject: [PATCH 21/43] Inline getters and setters in binding controller This is the counterpart step to the encapsulation refactoring. Bug: 205676419 Test: make Change-Id: I3b7d4ceaf62d42af303e3c00d98eb28711cc539c --- .../InputMethodBindingController.java | 40 +++++++++---------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java index 765672c00bb2e..ae5eb21fc0750 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java @@ -224,9 +224,9 @@ final class InputMethodBindingController { private final ServiceConnection mVisibleConnection = new ServiceConnection() { @Override public void onBindingDied(ComponentName name) { synchronized (mMethodMap) { - if (isVisibleBound()) { - mContext.unbindService(getVisibleConnection()); - setVisibleBound(false); + if (mVisibleBound) { + mContext.unbindService(mVisibleConnection); + mVisibleBound = false; } } } @@ -251,31 +251,30 @@ final class InputMethodBindingController { public void onServiceConnected(ComponentName name, IBinder service) { Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.onServiceConnected"); synchronized (mMethodMap) { - if (getCurIntent() != null && name.equals(getCurIntent().getComponent())) { - setCurMethod(IInputMethod.Stub.asInterface(service)); - final String curMethodPackage = - getCurIntent().getComponent().getPackageName(); + if (mCurIntent != null && name.equals(mCurIntent.getComponent())) { + mCurMethod = IInputMethod.Stub.asInterface(service); + final String curMethodPackage = mCurIntent.getComponent().getPackageName(); final int curMethodUid = mPackageManagerInternal.getPackageUid( curMethodPackage, 0 /* flags */, mSettings.getCurrentUserId()); if (curMethodUid < 0) { Slog.e(TAG, "Failed to get UID for package=" + curMethodPackage); - setCurMethodUid(Process.INVALID_UID); + mCurMethodUid = Process.INVALID_UID; } else { - setCurMethodUid(curMethodUid); + mCurMethodUid = curMethodUid; } - if (getCurToken() == null) { + if (mCurToken == null) { Slog.w(TAG, "Service connected without a token!"); mService.unbindCurrentMethodLocked(); Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); return; } - if (DEBUG) Slog.v(TAG, "Initiating attach with token: " + getCurToken()); + if (DEBUG) Slog.v(TAG, "Initiating attach with token: " + mCurToken); // Dispatch display id for InputMethodService to update context display. - mService.executeOrSendMessage(getCurMethod(), + mService.executeOrSendMessage(mCurMethod, mService.mCaller.obtainMessageIOO(MSG_INITIALIZE_IME, - mMethodMap.get(getSelectedMethodId()).getConfigChanges(), - getCurMethod(), getCurToken())); - mService.scheduleNotifyImeUidToAudioService(getCurMethodUid()); + mMethodMap.get(mSelectedMethodId).getConfigChanges(), + mCurMethod, mCurToken)); + mService.scheduleNotifyImeUidToAudioService(mCurMethodUid); ClientState curClient = mService.getCurClient(); if (curClient != null) { mService.clearClientSessionLocked(curClient); @@ -287,7 +286,7 @@ final class InputMethodBindingController { } @Override - public void onServiceDisconnected(ComponentName name) { + public void onServiceDisconnected(@NonNull ComponentName name) { // Note that mContext.unbindService(this) does not trigger this. Hence if we are // here the // disconnection is not intended by IMMS (e.g. triggered because the current IMS @@ -301,15 +300,14 @@ final class InputMethodBindingController { // would be a good way to trigger such a situation. synchronized (mMethodMap) { if (DEBUG) { - Slog.v(TAG, "Service disconnected: " + name - + " mCurIntent=" + getCurIntent()); + Slog.v(TAG, "Service disconnected: " + name + " mCurIntent=" + mCurIntent); } - if (getCurMethod() != null && getCurIntent() != null - && name.equals(getCurIntent().getComponent())) { + if (mCurMethod != null && mCurIntent != null + && name.equals(mCurIntent.getComponent())) { mService.clearCurMethodLocked(); // We consider this to be a new bind attempt, since the system // should now try to restart the service for us. - setLastBindTime(SystemClock.uptimeMillis()); + mLastBindTime = SystemClock.uptimeMillis(); mService.setShowRequested(mService.isInputShown()); mService.setInputShown(false); mService.unbindCurrentClientLocked(UnbindReason.DISCONNECT_IME); From c6fcc924442f19207a8eebc9b6b9ca644ed1dae1 Mon Sep 17 00:00:00 2001 From: Nikolas Havrikov Date: Thu, 11 Nov 2021 14:08:06 +0100 Subject: [PATCH 22/43] Extract setting current method uid Bug: 205676419 Test: make Change-Id: I440fb05b347744620e485f7f63c419864db80a6a --- .../InputMethodBindingController.java | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java index ae5eb21fc0750..94cd448c1b4dd 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java @@ -35,6 +35,7 @@ import android.util.ArrayMap; import android.util.Slog; import android.view.inputmethod.InputMethodInfo; +import com.android.internal.annotations.GuardedBy; import com.android.internal.inputmethod.UnbindReason; import com.android.internal.view.IInputMethod; import com.android.server.inputmethod.InputMethodManagerService.ClientState; @@ -253,15 +254,7 @@ final class InputMethodBindingController { synchronized (mMethodMap) { if (mCurIntent != null && name.equals(mCurIntent.getComponent())) { mCurMethod = IInputMethod.Stub.asInterface(service); - final String curMethodPackage = mCurIntent.getComponent().getPackageName(); - final int curMethodUid = mPackageManagerInternal.getPackageUid( - curMethodPackage, 0 /* flags */, mSettings.getCurrentUserId()); - if (curMethodUid < 0) { - Slog.e(TAG, "Failed to get UID for package=" + curMethodPackage); - mCurMethodUid = Process.INVALID_UID; - } else { - mCurMethodUid = curMethodUid; - } + updateCurrentMethodUidLocked(); if (mCurToken == null) { Slog.w(TAG, "Service connected without a token!"); mService.unbindCurrentMethodLocked(); @@ -285,6 +278,19 @@ final class InputMethodBindingController { Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } + @GuardedBy("mMethodMap") + private void updateCurrentMethodUidLocked() { + final String curMethodPackage = mCurIntent.getComponent().getPackageName(); + final int curMethodUid = mPackageManagerInternal.getPackageUid( + curMethodPackage, 0 /* flags */, mSettings.getCurrentUserId()); + if (curMethodUid < 0) { + Slog.e(TAG, "Failed to get UID for package=" + curMethodPackage); + mCurMethodUid = Process.INVALID_UID; + } else { + mCurMethodUid = curMethodUid; + } + } + @Override public void onServiceDisconnected(@NonNull ComponentName name) { // Note that mContext.unbindService(this) does not trigger this. Hence if we are From 81fa0e6b61d664994ff650d5a3d42eca7c1b5188 Mon Sep 17 00:00:00 2001 From: Nikolas Havrikov Date: Thu, 11 Nov 2021 14:16:35 +0100 Subject: [PATCH 23/43] Extract removing current window token Bug: 205676419 Test: make Change-Id: Ie6ba42d3b2ca86e2f0270bf8190632ec09d5b1da --- .../InputMethodManagerService.java | 31 +++++++++++-------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 05aebcc7b0a86..1570fced1102d 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -2687,25 +2687,30 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } if (getCurToken() != null) { - if (DEBUG) { - Slog.v(TAG, "Removing window token: " + getCurToken() + " for display: " - + mCurTokenDisplayId); - } - mWindowManagerInternal.removeWindowToken(getCurToken(), false /* removeWindows */, - false /* animateExit */, mCurTokenDisplayId); - // Set IME window status as invisible when unbind current method. - mImeWindowVis = 0; - mBackDisposition = InputMethodService.BACK_DISPOSITION_DEFAULT; - updateSystemUiLocked(mImeWindowVis, mBackDisposition); - setCurToken(null); - mCurTokenDisplayId = INVALID_DISPLAY; - mCurHostInputToken = null; + removeCurrentTokenLocked(); } setCurId(null); clearCurMethodLocked(); } + @GuardedBy("mMethodMap") + void removeCurrentTokenLocked() { + IBinder token = getCurToken(); + if (DEBUG) { + Slog.v(TAG, "Removing window token: " + token + " for display: " + mCurTokenDisplayId); + } + mWindowManagerInternal.removeWindowToken(token, false /* removeWindows */, + false /* animateExit */, mCurTokenDisplayId); + // Set IME window status as invisible when unbind current method. + mImeWindowVis = 0; + mBackDisposition = InputMethodService.BACK_DISPOSITION_DEFAULT; + updateSystemUiLocked(mImeWindowVis, mBackDisposition); + setCurToken(null); + mCurTokenDisplayId = INVALID_DISPLAY; + mCurHostInputToken = null; + } + @GuardedBy("mMethodMap") void resetCurrentMethodAndClientLocked(@UnbindReason int unbindClientReason) { setSelectedMethodId(null); From ba37769c2d9cb6cc6a2bf41df9f88d1266d5ca73 Mon Sep 17 00:00:00 2001 From: Nikolas Havrikov Date: Thu, 11 Nov 2021 14:20:39 +0100 Subject: [PATCH 24/43] Move unbinding current method logic to controller Also inline accessors Bug: 205676419 Test: make Change-Id: I5ace23a4539c349aee767bf689d8c8b88df0a39b --- .../InputMethodBindingController.java | 21 ++++++++++++- .../InputMethodManagerService.java | 30 ++++--------------- 2 files changed, 25 insertions(+), 26 deletions(-) diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java index 94cd448c1b4dd..10fcb23b071ad 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java @@ -257,7 +257,7 @@ final class InputMethodBindingController { updateCurrentMethodUidLocked(); if (mCurToken == null) { Slog.w(TAG, "Service connected without a token!"); - mService.unbindCurrentMethodLocked(); + unbindCurrentMethodLocked(); Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); return; } @@ -322,4 +322,23 @@ final class InputMethodBindingController { } }; + @GuardedBy("mMethodMap") + void unbindCurrentMethodLocked() { + if (mVisibleBound) { + mContext.unbindService(mVisibleConnection); + mVisibleBound = false; + } + + if (mHasConnection) { + mContext.unbindService(mNonVisibleConnection); + mHasConnection = false; + } + + if (mCurToken != null) { + mService.removeCurrentTokenLocked(); + } + + mCurId = null; + mService.clearCurMethodLocked(); + } } diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 1570fced1102d..ad78ccd6ab387 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -761,7 +761,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub * * * Do not update this value outside of {@link #setImeWindowStatus(IBinder, int, int)} and - * {@link #unbindCurrentMethodLocked()}. + * {@link InputMethodBindingController#unbindCurrentMethodLocked()}. */ int mImeWindowVis; @@ -2506,7 +2506,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub throw new IllegalArgumentException("Unknown id: " + getSelectedMethodId()); } - unbindCurrentMethodLocked(); + mBindingController.unbindCurrentMethodLocked(); Intent intent = createImeBindingIntent(info.getComponent()); setCurIntent(intent); @@ -2674,26 +2674,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub channel.dispose(); } - @GuardedBy("mMethodMap") - void unbindCurrentMethodLocked() { - if (isVisibleBound()) { - mContext.unbindService(getVisibleConnection()); - setVisibleBound(false); - } - - if (hasConnection()) { - mContext.unbindService(getMainConnection()); - setHasConnection(false); - } - - if (getCurToken() != null) { - removeCurrentTokenLocked(); - } - - setCurId(null); - clearCurMethodLocked(); - } - @GuardedBy("mMethodMap") void removeCurrentTokenLocked() { IBinder token = getCurToken(); @@ -2714,7 +2694,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub @GuardedBy("mMethodMap") void resetCurrentMethodAndClientLocked(@UnbindReason int unbindClientReason) { setSelectedMethodId(null); - unbindCurrentMethodLocked(); + mBindingController.unbindCurrentMethodLocked(); unbindCurrentClientLocked(unbindClientReason); } @@ -3583,7 +3563,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub // Note that we can trust client's display ID as long as it matches // to the display ID obtained from the window. if (cs.selfReportedDisplayId != mCurTokenDisplayId) { - unbindCurrentMethodLocked(); + mBindingController.unbindCurrentMethodLocked(); } } } else if (isTextEditor && doAutoShow @@ -5801,7 +5781,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub if (userId == mSettings.getCurrentUserId()) { hideCurrentInputLocked(mCurFocusedWindow, 0, null, SoftInputShowHideReason.HIDE_RESET_SHELL_COMMAND); - unbindCurrentMethodLocked(); + mBindingController.unbindCurrentMethodLocked(); // Reset the current IME resetSelectedInputMethodAndSubtypeLocked(null); // Also reset the settings of the current IME From 285c6dea7b394ac43ead97751f21e8e583eae0bd Mon Sep 17 00:00:00 2001 From: Nikolas Havrikov Date: Thu, 11 Nov 2021 18:09:40 +0100 Subject: [PATCH 25/43] Remove parameter from current input binding Bug: 205676419 Test: make Change-Id: I331567a5072916d477af6a9ccad99a3a9d7d6cc1 --- .../server/inputmethod/InputMethodManagerService.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index ad78ccd6ab387..b64904d338cbd 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -1985,8 +1985,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } @GuardedBy("mMethodMap") - private boolean bindCurrentInputMethodServiceLocked( - Intent service, ServiceConnection conn, int flags) { + private boolean bindCurrentInputMethodServiceLocked(ServiceConnection conn, int flags) { + Intent service = getCurIntent(); if (service == null || conn == null) { Slog.e(TAG, "--- bind failed: service = " + service + ", conn = " + conn); return false; @@ -3211,8 +3211,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub showInputToken)); mInputShown = true; if (hasConnection() && !isVisibleBound()) { - bindCurrentInputMethodServiceLocked( - getCurIntent(), getVisibleConnection(), IME_VISIBLE_BIND_FLAGS); + bindCurrentInputMethodServiceLocked(getVisibleConnection(), IME_VISIBLE_BIND_FLAGS); setVisibleBound(true); } res = true; @@ -3228,7 +3227,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub Slog.w(TAG, "Force disconnect/connect to the IME in showCurrentInputLocked()"); ServiceConnection connection = getMainConnection(); mContext.unbindService(connection); - bindCurrentInputMethodServiceLocked(getCurIntent(), connection, + bindCurrentInputMethodServiceLocked(connection, mImeConnectionBindFlags); } else { if (DEBUG) { From 5c232e497012011a9cdbb5a6848c53ae5c4d13f6 Mon Sep 17 00:00:00 2001 From: Nikolas Havrikov Date: Thu, 11 Nov 2021 18:15:23 +0100 Subject: [PATCH 26/43] Move binding current method to controller Bug: 205676419 Test: make Change-Id: I53855a72869a608891f55ca99101f0be9b65efde --- .../InputMethodBindingController.java | 12 ++++++++++++ .../inputmethod/InputMethodManagerService.java | 18 ++++-------------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java index 10fcb23b071ad..37ae7f2e3efbc 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java @@ -31,6 +31,7 @@ import android.os.IBinder; import android.os.Process; import android.os.SystemClock; import android.os.Trace; +import android.os.UserHandle; import android.util.ArrayMap; import android.util.Slog; import android.view.inputmethod.InputMethodInfo; @@ -341,4 +342,15 @@ final class InputMethodBindingController { mCurId = null; mService.clearCurMethodLocked(); } + + @GuardedBy("mMethodMap") + boolean bindCurrentInputMethodServiceLocked(ServiceConnection conn, int flags) { + if (mCurIntent == null || conn == null) { + Slog.e(TAG, "--- bind failed: service = " + mCurIntent + ", conn = " + conn); + return false; + } + return mContext.bindServiceAsUser(mCurIntent, conn, flags, + new UserHandle(mSettings.getCurrentUserId())); + } + } diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index b64904d338cbd..6a43b41724623 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -1984,17 +1984,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub return true; } - @GuardedBy("mMethodMap") - private boolean bindCurrentInputMethodServiceLocked(ServiceConnection conn, int flags) { - Intent service = getCurIntent(); - if (service == null || conn == null) { - Slog.e(TAG, "--- bind failed: service = " + service + ", conn = " + conn); - return false; - } - return mContext.bindServiceAsUser(service, conn, flags, - new UserHandle(mSettings.getCurrentUserId())); - } - @Override public List getInputMethodList(@UserIdInt int userId) { if (UserHandle.getCallingUserId() != userId) { @@ -2511,7 +2500,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub Intent intent = createImeBindingIntent(info.getComponent()); setCurIntent(intent); - if (bindCurrentInputMethodServiceLocked(intent, getMainConnection(), + if (mBindingController.bindCurrentInputMethodServiceLocked(intent, getMainConnection(), mImeConnectionBindFlags)) { addFreshWindowTokenLocked(displayIdToShowIme, info.getId()); return new InputBindResult( @@ -3211,7 +3200,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub showInputToken)); mInputShown = true; if (hasConnection() && !isVisibleBound()) { - bindCurrentInputMethodServiceLocked(getVisibleConnection(), IME_VISIBLE_BIND_FLAGS); + mBindingController.bindCurrentInputMethodServiceLocked(getVisibleConnection(), + IME_VISIBLE_BIND_FLAGS); setVisibleBound(true); } res = true; @@ -3227,7 +3217,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub Slog.w(TAG, "Force disconnect/connect to the IME in showCurrentInputLocked()"); ServiceConnection connection = getMainConnection(); mContext.unbindService(connection); - bindCurrentInputMethodServiceLocked(connection, + mBindingController.bindCurrentInputMethodServiceLocked(connection, mImeConnectionBindFlags); } else { if (DEBUG) { From 4deaaf588d3ae0bef3a3a3f54414926ee0d773f9 Mon Sep 17 00:00:00 2001 From: Nikolas Havrikov Date: Thu, 11 Nov 2021 18:26:51 +0100 Subject: [PATCH 27/43] Split binding main and visible connection Bug: 205676419 Test: make Change-Id: I5b80604c52dec6fbfcdf3214a915f8281ec0a73b --- .../InputMethodBindingController.java | 66 ++++++++++++++++++- .../InputMethodManagerService.java | 57 +--------------- 2 files changed, 68 insertions(+), 55 deletions(-) diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java index 37ae7f2e3efbc..be00a16258be7 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java @@ -27,6 +27,8 @@ import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.content.pm.PackageManagerInternal; +import android.content.res.Resources; +import android.inputmethodservice.InputMethodService; import android.os.IBinder; import android.os.Process; import android.os.SystemClock; @@ -53,6 +55,7 @@ final class InputMethodBindingController { @NonNull private final ArrayMap mMethodMap; @NonNull private final InputMethodUtils.InputMethodSettings mSettings; @NonNull private final PackageManagerInternal mPackageManagerInternal; + @NonNull private final Resources mRes; private long mLastBindTime; private boolean mHasConnection; @@ -65,6 +68,41 @@ final class InputMethodBindingController { private int mCurSeq; private boolean mVisibleBound; + /** + * Binding flags for establishing connection to the {@link InputMethodService}. + */ + private static final int IME_CONNECTION_BIND_FLAGS = + Context.BIND_AUTO_CREATE + | Context.BIND_NOT_VISIBLE + | Context.BIND_NOT_FOREGROUND + | Context.BIND_IMPORTANT_BACKGROUND; + /** + * Binding flags for establishing connection to the {@link InputMethodService} when + * config_killableInputMethods is enabled. + */ + private static final int IME_CONNECTION_LOW_PRIORITY_BIND_FLAGS = + Context.BIND_AUTO_CREATE + | Context.BIND_REDUCTION_FLAGS; + /** + * Binding flags used only while the {@link InputMethodService} is showing window. + */ + private static final int IME_VISIBLE_BIND_FLAGS = + Context.BIND_AUTO_CREATE + | Context.BIND_TREAT_LIKE_ACTIVITY + | Context.BIND_FOREGROUND_SERVICE + | Context.BIND_INCLUDE_CAPABILITIES + | Context.BIND_SHOWING_UI + | Context.BIND_SCHEDULE_LIKE_TOP_APP; + + /** + * Binding flags for establishing connection to the {@link InputMethodService}. + * + *

+ * This defaults to {@link InputMethodBindingController#IME_CONNECTION_BIND_FLAGS} unless + * config_killableInputMethods is enabled, in which case this takes the value of + * {@link InputMethodBindingController#IME_CONNECTION_LOW_PRIORITY_BIND_FLAGS}. + */ + private final int mImeConnectionBindFlags; InputMethodBindingController(@NonNull InputMethodManagerService service) { mService = service; @@ -72,6 +110,18 @@ final class InputMethodBindingController { mMethodMap = mService.mMethodMap; mSettings = mService.mSettings; mPackageManagerInternal = mService.mPackageManagerInternal; + mRes = mService.mRes; + + // If configured, use low priority flags to make the IME killable by the lowmemorykiller + final boolean lowerIMEPriority = mRes.getBoolean( + com.android.internal.R.bool.config_killableInputMethods); + + if (lowerIMEPriority) { + mImeConnectionBindFlags = + InputMethodBindingController.IME_CONNECTION_LOW_PRIORITY_BIND_FLAGS; + } else { + mImeConnectionBindFlags = InputMethodBindingController.IME_CONNECTION_BIND_FLAGS; + } } /** @@ -344,7 +394,7 @@ final class InputMethodBindingController { } @GuardedBy("mMethodMap") - boolean bindCurrentInputMethodServiceLocked(ServiceConnection conn, int flags) { + private boolean bindCurrentInputMethodServiceLocked(ServiceConnection conn, int flags) { if (mCurIntent == null || conn == null) { Slog.e(TAG, "--- bind failed: service = " + mCurIntent + ", conn = " + conn); return false; @@ -353,4 +403,18 @@ final class InputMethodBindingController { new UserHandle(mSettings.getCurrentUserId())); } + @GuardedBy("mMethodMap") + boolean bindCurrentInputMethodServiceVisibleConnectionLocked() { + return bindCurrentInputMethodServiceLocked(mVisibleConnection, + IME_VISIBLE_BIND_FLAGS); + } + + @GuardedBy("mMethodMap") + boolean bindCurrentInputMethodServiceMainConnectionLocked() { + return bindCurrentInputMethodServiceLocked(mMainConnection, + mImeConnectionBindFlags); + } + + + } diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 6a43b41724623..c43dc43e35088 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -259,44 +259,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub private static final String TAG_TRY_SUPPRESSING_IME_SWITCHER = "TrySuppressingImeSwitcher"; private static final String HANDLER_THREAD_NAME = "android.imms"; - /** - * Binding flags for establishing connection to the {@link InputMethodService}. - */ - private static final int IME_CONNECTION_BIND_FLAGS = - Context.BIND_AUTO_CREATE - | Context.BIND_NOT_VISIBLE - | Context.BIND_NOT_FOREGROUND - | Context.BIND_IMPORTANT_BACKGROUND; - - /** - * Binding flags for establishing connection to the {@link InputMethodService} when - * config_killableInputMethods is enabled. - */ - private static final int IME_CONNECTION_LOW_PRIORITY_BIND_FLAGS = - Context.BIND_AUTO_CREATE - | Context.BIND_REDUCTION_FLAGS; - - /** - * Binding flags for establishing connection to the {@link InputMethodService}. - * - *

- * This defaults to {@link #IME_CONNECTION_BIND_FLAGS} unless config_killableInputMethods is - * enabled, in which case this takes the value of - * {@link #IME_CONNECTION_LOW_PRIORITY_BIND_FLAGS}. - */ - private final int mImeConnectionBindFlags; - - /** - * Binding flags used only while the {@link InputMethodService} is showing window. - */ - private static final int IME_VISIBLE_BIND_FLAGS = - Context.BIND_AUTO_CREATE - | Context.BIND_TREAT_LIKE_ACTIVITY - | Context.BIND_FOREGROUND_SERVICE - | Context.BIND_INCLUDE_CAPABILITIES - | Context.BIND_SHOWING_UI - | Context.BIND_SCHEDULE_LIKE_TOP_APP; - /** * A protected broadcast intent action for internal use for {@link PendingIntent} in * the notification. @@ -1752,16 +1714,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mSettings, context); mMenuController = new InputMethodMenuController(this); mBindingController = new InputMethodBindingController(this); - - // If configured, use low priority flags to make the IME killable by the lowmemorykiller - final boolean lowerIMEPriority = mRes.getBoolean( - com.android.internal.R.bool.config_killableInputMethods); - - if (lowerIMEPriority) { - mImeConnectionBindFlags = IME_CONNECTION_LOW_PRIORITY_BIND_FLAGS; - } else { - mImeConnectionBindFlags = IME_CONNECTION_BIND_FLAGS; - } } @GuardedBy("mMethodMap") @@ -2500,8 +2452,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub Intent intent = createImeBindingIntent(info.getComponent()); setCurIntent(intent); - if (mBindingController.bindCurrentInputMethodServiceLocked(intent, getMainConnection(), - mImeConnectionBindFlags)) { + if (mBindingController.bindCurrentInputMethodServiceMainConnectionLocked()) { addFreshWindowTokenLocked(displayIdToShowIme, info.getId()); return new InputBindResult( InputBindResult.ResultCode.SUCCESS_WAITING_IME_BINDING, @@ -3200,8 +3151,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub showInputToken)); mInputShown = true; if (hasConnection() && !isVisibleBound()) { - mBindingController.bindCurrentInputMethodServiceLocked(getVisibleConnection(), - IME_VISIBLE_BIND_FLAGS); + mBindingController.bindCurrentInputMethodServiceVisibleConnectionLocked(); setVisibleBound(true); } res = true; @@ -3217,8 +3167,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub Slog.w(TAG, "Force disconnect/connect to the IME in showCurrentInputLocked()"); ServiceConnection connection = getMainConnection(); mContext.unbindService(connection); - mBindingController.bindCurrentInputMethodServiceLocked(connection, - mImeConnectionBindFlags); + mBindingController.bindCurrentInputMethodServiceMainConnectionLocked(); } else { if (DEBUG) { Slog.d(TAG, "Can't show input: connection = " + hasConnection() + ", time = " From 713036b6e2a15134f7ab68387c733b2524ce10ab Mon Sep 17 00:00:00 2001 From: Nikolas Havrikov Date: Thu, 11 Nov 2021 18:30:20 +0100 Subject: [PATCH 28/43] Move connectedness booleans into controller This slightly changes the semantics of the call sites, and thus warrants a more thorough review. Bug: 205676419 Test: make Change-Id: If494009ad161cd065de28550d241b6a2757ecdb1 --- .../inputmethod/InputMethodBindingController.java | 14 ++++---------- .../inputmethod/InputMethodManagerService.java | 6 ------ 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java index be00a16258be7..1fb7eff087afc 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java @@ -144,10 +144,6 @@ final class InputMethodBindingController { return mHasConnection; } - void setHasConnection(boolean hasConnection) { - mHasConnection = hasConnection; - } - /** * Id obtained with {@link InputMethodInfo#getId()} for the input method that we are currently * connected to or in the process of connecting to. @@ -261,10 +257,6 @@ final class InputMethodBindingController { return mVisibleBound; } - void setVisibleBound(boolean visibleBound) { - mVisibleBound = visibleBound; - } - /** * Used to bring IME service up to visible adjustment while it is being shown. */ @@ -405,14 +397,16 @@ final class InputMethodBindingController { @GuardedBy("mMethodMap") boolean bindCurrentInputMethodServiceVisibleConnectionLocked() { - return bindCurrentInputMethodServiceLocked(mVisibleConnection, + mVisibleBound = bindCurrentInputMethodServiceLocked(mVisibleConnection, IME_VISIBLE_BIND_FLAGS); + return mVisibleBound; } @GuardedBy("mMethodMap") boolean bindCurrentInputMethodServiceMainConnectionLocked() { - return bindCurrentInputMethodServiceLocked(mMainConnection, + mHasConnection = bindCurrentInputMethodServiceLocked(mMainConnection, mImeConnectionBindFlags); + return mHasConnection; } diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index c43dc43e35088..d3da4751364ce 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -559,10 +559,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub return mBindingController.hasConnection(); } - private void setHasConnection(boolean hasConnection) { - mBindingController.setHasConnection(hasConnection); - } - boolean isShowRequested() { return mShowRequested; } @@ -2531,7 +2527,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub Binder token = new Binder(); setCurToken(token); setLastBindTime(SystemClock.uptimeMillis()); - setHasConnection(true); setCurId(methodId); mCurTokenDisplayId = displayIdToShowIme; try { @@ -3152,7 +3147,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mInputShown = true; if (hasConnection() && !isVisibleBound()) { mBindingController.bindCurrentInputMethodServiceVisibleConnectionLocked(); - setVisibleBound(true); } res = true; } else { From fa91d1c86c3e0bf7b2d28fb8657e2e1fd5b23874 Mon Sep 17 00:00:00 2001 From: Nikolas Havrikov Date: Fri, 12 Nov 2021 11:23:25 +0100 Subject: [PATCH 29/43] Extract unbinding visible IME connection Bug: 205676419 Test: make Change-Id: I436095d4f2858c67aeed6296c9f70e253798f4b6 --- .../InputMethodBindingController.java | 13 +++++++++---- .../inputmethod/InputMethodManagerService.java | 17 +++-------------- 2 files changed, 12 insertions(+), 18 deletions(-) diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java index 1fb7eff087afc..4f939af201f3e 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java @@ -269,8 +269,7 @@ final class InputMethodBindingController { @Override public void onBindingDied(ComponentName name) { synchronized (mMethodMap) { if (mVisibleBound) { - mContext.unbindService(mVisibleConnection); - mVisibleBound = false; + unbindVisibleConnectionLocked(); } } } @@ -368,8 +367,7 @@ final class InputMethodBindingController { @GuardedBy("mMethodMap") void unbindCurrentMethodLocked() { if (mVisibleBound) { - mContext.unbindService(mVisibleConnection); - mVisibleBound = false; + unbindVisibleConnectionLocked(); } if (mHasConnection) { @@ -385,6 +383,13 @@ final class InputMethodBindingController { mService.clearCurMethodLocked(); } + + @GuardedBy("mMethodMap") + void unbindVisibleConnectionLocked() { + mContext.unbindService(mVisibleConnection); + mVisibleBound = false; + } + @GuardedBy("mMethodMap") private boolean bindCurrentInputMethodServiceLocked(ServiceConnection conn, int flags) { if (mCurIntent == null || conn == null) { diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index d3da4751364ce..1dbdc0d538aba 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -313,23 +313,13 @@ public class InputMethodManagerService extends IInputMethodManager.Stub private int mMethodMapUpdateCount = 0; /** - * Indicates whether {@link #getVisibleConnection} is currently in use. + * Indicates whether {@link InputMethodBindingController#getVisibleConnection} is currently + * in use. */ private boolean isVisibleBound() { return mBindingController.isVisibleBound(); } - private void setVisibleBound(boolean visibleBound) { - mBindingController.setVisibleBound(visibleBound); - } - - /** - * Used to bring IME service up to visible adjustment while it is being shown. - */ - private ServiceConnection getVisibleConnection() { - return mBindingController.getVisibleConnection(); - } - /** * Used to bind the IME while it is not currently being shown. */ @@ -3254,8 +3244,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub res = false; } if (hasConnection() && isVisibleBound()) { - mContext.unbindService(getVisibleConnection()); - setVisibleBound(false); + mBindingController.unbindVisibleConnectionLocked(); } mInputShown = false; mShowRequested = false; From a04859b9f0663ec294b93ea224cc2373412e8139 Mon Sep 17 00:00:00 2001 From: Nikolas Havrikov Date: Fri, 12 Nov 2021 11:47:14 +0100 Subject: [PATCH 30/43] Extract unbinding main IME connection Bug: 205676419 Test: make Change-Id: Ie01d68e7455bcd2d6e40b63687b948992834b51d --- .../inputmethod/InputMethodBindingController.java | 13 ++++++------- .../inputmethod/InputMethodManagerService.java | 12 +----------- 2 files changed, 7 insertions(+), 18 deletions(-) diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java index 4f939af201f3e..d45bfa072dbdb 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java @@ -284,11 +284,6 @@ final class InputMethodBindingController { /** * Used to bind the IME while it is not currently being shown. */ - @NonNull - ServiceConnection getMainConnection() { - return mMainConnection; - } - private final ServiceConnection mMainConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { @@ -371,8 +366,7 @@ final class InputMethodBindingController { } if (mHasConnection) { - mContext.unbindService(mNonVisibleConnection); - mHasConnection = false; + unbindMainConnectionLocked(); } if (mCurToken != null) { @@ -383,6 +377,11 @@ final class InputMethodBindingController { mService.clearCurMethodLocked(); } + @GuardedBy("mMethodMap") + void unbindMainConnectionLocked() { + mContext.unbindService(mMainConnection); + mHasConnection = false; + } @GuardedBy("mMethodMap") void unbindVisibleConnectionLocked() { diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 1dbdc0d538aba..c60e65e160c01 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -77,7 +77,6 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.ServiceConnection; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.PackageManager; @@ -320,14 +319,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub return mBindingController.isVisibleBound(); } - /** - * Used to bind the IME while it is not currently being shown. - */ - @NonNull - private ServiceConnection getMainConnection() { - return mBindingController.getMainConnection(); - } - // Ongoing notification private NotificationManager mNotificationManager; KeyguardManager mKeyguardManager; @@ -3149,8 +3140,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub EventLog.writeEvent(EventLogTags.IMF_FORCE_RECONNECT_IME, getSelectedMethodId(), bindingDuration, 1); Slog.w(TAG, "Force disconnect/connect to the IME in showCurrentInputLocked()"); - ServiceConnection connection = getMainConnection(); - mContext.unbindService(connection); + mBindingController.unbindMainConnectionLocked(); mBindingController.bindCurrentInputMethodServiceMainConnectionLocked(); } else { if (DEBUG) { From ee2c9824f9c4f73833796a24c1d0c52f801e8af4 Mon Sep 17 00:00:00 2001 From: Nikolas Havrikov Date: Fri, 12 Nov 2021 14:26:35 +0100 Subject: [PATCH 31/43] Extract binding current method logic Bug: 205676419 Test: make Change-Id: I9a345c94bea6c7b7183e57b6691ce8d474ce9fac --- .../InputMethodManagerService.java | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index c60e65e160c01..4ff4244f6c336 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -2356,7 +2356,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub @NonNull EditorInfo attribute, @StartInputFlags int startInputFlags, @StartInputReason int startInputReason) { // If no method is currently selected, do nothing. - if (getSelectedMethodId() == null) { + String selectedMethodId = getSelectedMethodId(); + if (selectedMethodId == null) { return InputBindResult.NO_IME; } @@ -2365,7 +2366,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub // party code. return new InputBindResult( InputBindResult.ResultCode.ERROR_SYSTEM_NOT_READY, - null, null, getSelectedMethodId(), getSequenceNumber(), false); + null, null, selectedMethodId, getSequenceNumber(), false); } if (!InputMethodUtils.checkIfPackageBelongsToUid(mAppOpsManager, cs.uid, @@ -2419,13 +2420,21 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } } - InputMethodInfo info = mMethodMap.get(getSelectedMethodId()); - if (info == null) { - throw new IllegalArgumentException("Unknown id: " + getSelectedMethodId()); - } - mBindingController.unbindCurrentMethodLocked(); + return bindCurrentMethodLocked(displayIdToShowIme); + } + + + @GuardedBy("mMethodMap") + @NonNull + private InputBindResult bindCurrentMethodLocked(int displayIdToShowIme) { + String selectedMethodId = getSelectedMethodId(); + InputMethodInfo info = mMethodMap.get(selectedMethodId); + if (info == null) { + throw new IllegalArgumentException("Unknown id: " + selectedMethodId); + } + Intent intent = createImeBindingIntent(info.getComponent()); setCurIntent(intent); @@ -2435,6 +2444,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub InputBindResult.ResultCode.SUCCESS_WAITING_IME_BINDING, null, null, getCurId(), getSequenceNumber(), false); } + setCurIntent(null); Slog.w(TAG, "Failure connecting to input method service: " + intent); return InputBindResult.IME_NOT_CONNECTED; From 7318f9636df2e1dcffedd159c00507a3d55eb608 Mon Sep 17 00:00:00 2001 From: Nikolas Havrikov Date: Mon, 15 Nov 2021 10:45:57 +0100 Subject: [PATCH 32/43] Move binding current method into the controller This is a step in a larger refactoring. Bug: 205676419 Test: make Change-Id: I0c86ea0e1f96070f039d960a2e5ef6e93c4cfab0 --- .../InputMethodBindingController.java | 46 ++++++++++++++++--- .../InputMethodManagerService.java | 45 +----------------- 2 files changed, 42 insertions(+), 49 deletions(-) diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java index d45bfa072dbdb..160cc11c87d56 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java @@ -22,6 +22,7 @@ import static com.android.server.inputmethod.InputMethodManagerService.MSG_INITI import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.PendingIntent; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -34,11 +35,14 @@ import android.os.Process; import android.os.SystemClock; import android.os.Trace; import android.os.UserHandle; +import android.provider.Settings; import android.util.ArrayMap; import android.util.Slog; +import android.view.inputmethod.InputMethod; import android.view.inputmethod.InputMethodInfo; import com.android.internal.annotations.GuardedBy; +import com.android.internal.inputmethod.InputBindResult; import com.android.internal.inputmethod.UnbindReason; import com.android.internal.view.IInputMethod; import com.android.server.inputmethod.InputMethodManagerService.ClientState; @@ -203,10 +207,6 @@ final class InputMethodBindingController { return mCurIntent; } - void setCurIntent(@Nullable Intent curIntent) { - mCurIntent = curIntent; - } - /** * The current binding sequence number, incremented every time there is * a new bind performed. @@ -377,6 +377,42 @@ final class InputMethodBindingController { mService.clearCurMethodLocked(); } + @GuardedBy("mMethodMap") + @NonNull + InputBindResult bindCurrentMethodLocked(int displayIdToShowIme) { + InputMethodInfo info = mMethodMap.get(mSelectedMethodId); + if (info == null) { + throw new IllegalArgumentException("Unknown id: " + mSelectedMethodId); + } + + Intent intent = createImeBindingIntent(info.getComponent()); + mCurIntent = intent; + + if (bindCurrentInputMethodServiceMainConnectionLocked()) { + mService.addFreshWindowTokenLocked(displayIdToShowIme, info.getId()); + return new InputBindResult( + InputBindResult.ResultCode.SUCCESS_WAITING_IME_BINDING, + null, null, mCurId, mCurSeq, false); + } + + mCurIntent = null; + Slog.w(InputMethodManagerService.TAG, + "Failure connecting to input method service: " + intent); + return InputBindResult.IME_NOT_CONNECTED; + } + + @NonNull + private Intent createImeBindingIntent(ComponentName component) { + Intent intent = new Intent(InputMethod.SERVICE_INTERFACE); + intent.setComponent(component); + intent.putExtra(Intent.EXTRA_CLIENT_LABEL, + com.android.internal.R.string.input_method_binding_label); + intent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity( + mContext, 0, new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS), + PendingIntent.FLAG_IMMUTABLE)); + return intent; + } + @GuardedBy("mMethodMap") void unbindMainConnectionLocked() { mContext.unbindService(mMainConnection); @@ -413,6 +449,4 @@ final class InputMethodBindingController { return mHasConnection; } - - } diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 4ff4244f6c336..ecf603bbe9113 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -589,10 +589,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub return mBindingController.getCurIntent(); } - private void setCurIntent(@Nullable Intent curIntent) { - mBindingController.setCurIntent(curIntent); - } - /** * The token we have made for the currently active input method, to * identify it in the future. @@ -2422,32 +2418,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mBindingController.unbindCurrentMethodLocked(); - return bindCurrentMethodLocked(displayIdToShowIme); - } - - - @GuardedBy("mMethodMap") - @NonNull - private InputBindResult bindCurrentMethodLocked(int displayIdToShowIme) { - String selectedMethodId = getSelectedMethodId(); - InputMethodInfo info = mMethodMap.get(selectedMethodId); - if (info == null) { - throw new IllegalArgumentException("Unknown id: " + selectedMethodId); - } - - Intent intent = createImeBindingIntent(info.getComponent()); - setCurIntent(intent); - - if (mBindingController.bindCurrentInputMethodServiceMainConnectionLocked()) { - addFreshWindowTokenLocked(displayIdToShowIme, info.getId()); - return new InputBindResult( - InputBindResult.ResultCode.SUCCESS_WAITING_IME_BINDING, - null, null, getCurId(), getSequenceNumber(), false); - } - - setCurIntent(null); - Slog.w(TAG, "Failure connecting to input method service: " + intent); - return InputBindResult.IME_NOT_CONNECTED; + return mBindingController.bindCurrentMethodLocked(displayIdToShowIme); } private boolean isSelectedMethodBound(int displayIdToShowIme) { @@ -2501,20 +2472,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub return null; } - @NonNull - private Intent createImeBindingIntent(ComponentName component) { - Intent intent = new Intent(InputMethod.SERVICE_INTERFACE); - intent.setComponent(component); - intent.putExtra(Intent.EXTRA_CLIENT_LABEL, - com.android.internal.R.string.input_method_binding_label); - intent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity( - mContext, 0, new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS), - PendingIntent.FLAG_IMMUTABLE)); - return intent; - } - @GuardedBy("mMethodMap") - private void addFreshWindowTokenLocked(int displayIdToShowIme, String methodId) { + void addFreshWindowTokenLocked(int displayIdToShowIme, String methodId) { Binder token = new Binder(); setCurToken(token); setLastBindTime(SystemClock.uptimeMillis()); From 79294b49c7eb3b09c2024f688910686e1df4cde4 Mon Sep 17 00:00:00 2001 From: Nikolas Havrikov Date: Mon, 15 Nov 2021 11:13:08 +0100 Subject: [PATCH 33/43] Remove unwarranted local variable This is a step in a larger refactoring. Bug: 205676419 Test: make Change-Id: I892112f114428af49dae60581dd9ae82ec5ce74a --- .../server/inputmethod/InputMethodBindingController.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java index 160cc11c87d56..a22e7a154ded2 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java @@ -385,8 +385,7 @@ final class InputMethodBindingController { throw new IllegalArgumentException("Unknown id: " + mSelectedMethodId); } - Intent intent = createImeBindingIntent(info.getComponent()); - mCurIntent = intent; + mCurIntent = createImeBindingIntent(info.getComponent()); if (bindCurrentInputMethodServiceMainConnectionLocked()) { mService.addFreshWindowTokenLocked(displayIdToShowIme, info.getId()); @@ -395,9 +394,9 @@ final class InputMethodBindingController { null, null, mCurId, mCurSeq, false); } - mCurIntent = null; Slog.w(InputMethodManagerService.TAG, - "Failure connecting to input method service: " + intent); + "Failure connecting to input method service: " + mCurIntent); + mCurIntent = null; return InputBindResult.IME_NOT_CONNECTED; } From 614cd7282466883a654fd77a7dc7899856d041c2 Mon Sep 17 00:00:00 2001 From: Nikolas Havrikov Date: Mon, 15 Nov 2021 11:41:28 +0100 Subject: [PATCH 34/43] Move adding fresh window token to controller This is a step in a larger refactoring. Bug: 205676419 Test: make Change-Id: I3f5a4c59f8de0b2285defe2c7f0d60f755b0df95 --- .../InputMethodBindingController.java | 38 ++++++++++++++----- .../InputMethodManagerService.java | 32 ++-------------- 2 files changed, 33 insertions(+), 37 deletions(-) diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java index a22e7a154ded2..b787b15a30e15 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java @@ -30,14 +30,18 @@ import android.content.ServiceConnection; import android.content.pm.PackageManagerInternal; import android.content.res.Resources; import android.inputmethodservice.InputMethodService; +import android.os.Binder; import android.os.IBinder; import android.os.Process; +import android.os.RemoteException; import android.os.SystemClock; import android.os.Trace; import android.os.UserHandle; import android.provider.Settings; import android.util.ArrayMap; import android.util.Slog; +import android.view.IWindowManager; +import android.view.WindowManager; import android.view.inputmethod.InputMethod; import android.view.inputmethod.InputMethodInfo; @@ -59,6 +63,7 @@ final class InputMethodBindingController { @NonNull private final ArrayMap mMethodMap; @NonNull private final InputMethodUtils.InputMethodSettings mSettings; @NonNull private final PackageManagerInternal mPackageManagerInternal; + @NonNull private final IWindowManager mIWindowManager; @NonNull private final Resources mRes; private long mLastBindTime; @@ -114,6 +119,7 @@ final class InputMethodBindingController { mMethodMap = mService.mMethodMap; mSettings = mService.mSettings; mPackageManagerInternal = mService.mPackageManagerInternal; + mIWindowManager = mService.mIWindowManager; mRes = mService.mRes; // If configured, use low priority flags to make the IME killable by the lowmemorykiller @@ -136,10 +142,6 @@ final class InputMethodBindingController { return mLastBindTime; } - void setLastBindTime(long lastBindTime) { - mLastBindTime = lastBindTime; - } - /** * Set to true if our ServiceConnection is currently actively bound to * a service (whether or not we have gotten its IBinder back yet). @@ -161,10 +163,6 @@ final class InputMethodBindingController { return mCurId; } - void setCurId(@Nullable String curId) { - mCurId = curId; - } - /** * Id obtained with {@link InputMethodInfo#getId()} for the currently selected input method. * This is to be synchronized with the secure settings keyed with @@ -388,7 +386,7 @@ final class InputMethodBindingController { mCurIntent = createImeBindingIntent(info.getComponent()); if (bindCurrentInputMethodServiceMainConnectionLocked()) { - mService.addFreshWindowTokenLocked(displayIdToShowIme, info.getId()); + addFreshWindowTokenLocked(displayIdToShowIme, info.getId()); return new InputBindResult( InputBindResult.ResultCode.SUCCESS_WAITING_IME_BINDING, null, null, mCurId, mCurSeq, false); @@ -412,6 +410,28 @@ final class InputMethodBindingController { return intent; } + @GuardedBy("mMethodMap") + private void addFreshWindowTokenLocked(int displayIdToShowIme, String methodId) { + Binder token = new Binder(); + mCurToken = token; + mLastBindTime = SystemClock.uptimeMillis(); + mCurId = methodId; + + mService.setCurTokenDisplayId(displayIdToShowIme); + + try { + if (DEBUG) { + Slog.v(TAG, "Adding window token: " + token + " for display: " + + displayIdToShowIme); + } + mIWindowManager.addWindowToken(token, WindowManager.LayoutParams.TYPE_INPUT_METHOD, + displayIdToShowIme, null /* options */); + } catch (RemoteException e) { + Slog.e(TAG, "Could not add window token " + token + " for display " + + displayIdToShowIme, e); + } + } + @GuardedBy("mMethodMap") void unbindMainConnectionLocked() { mContext.unbindService(mMainConnection); diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index ecf603bbe9113..b0e9ab7951c0f 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -518,10 +518,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub return mBindingController.getCurId(); } - private void setCurId(@Nullable String curId) { - mBindingController.setCurId(curId); - } - /** * The current subtype of the current input method. */ @@ -601,6 +597,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mBindingController.setCurToken(curToken); } + void setCurTokenDisplayId(int curTokenDisplayId) { + mCurTokenDisplayId = curTokenDisplayId; + } + /** * The displayId of current active input method. */ @@ -653,10 +653,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub return mBindingController.getLastBindTime(); } - private void setLastBindTime(long lastBindTime) { - mBindingController.setLastBindTime(lastBindTime); - } - /** * Have we called mCurMethod.bindInput()? */ @@ -2472,26 +2468,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub return null; } - @GuardedBy("mMethodMap") - void addFreshWindowTokenLocked(int displayIdToShowIme, String methodId) { - Binder token = new Binder(); - setCurToken(token); - setLastBindTime(SystemClock.uptimeMillis()); - setCurId(methodId); - mCurTokenDisplayId = displayIdToShowIme; - try { - if (DEBUG) { - Slog.v(TAG, "Adding window token: " + token + " for display: " - + displayIdToShowIme); - } - mIWindowManager.addWindowToken(token, LayoutParams.TYPE_INPUT_METHOD, - displayIdToShowIme, null /* options */); - } catch (RemoteException e) { - Slog.e(TAG, "Could not add window token " + token + " for display " - + displayIdToShowIme, e); - } - } - @FunctionalInterface interface ImeDisplayValidator { @DisplayImePolicy int getDisplayImePolicy(int displayId); From 5ae6910b7d966eaa238c41325588fa82c37a8a2a Mon Sep 17 00:00:00 2001 From: Nikolas Havrikov Date: Mon, 15 Nov 2021 13:46:27 +0100 Subject: [PATCH 35/43] Move and split removing window token Bug: 205676419 Test: make Change-Id: Ic3aa02925fe460d4530e9f0cede3aa3a98a109ec --- .../InputMethodBindingController.java | 23 +++++++++++++++---- .../InputMethodManagerService.java | 21 ++++++----------- 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java index b787b15a30e15..46887b6e91a52 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java @@ -50,6 +50,7 @@ import com.android.internal.inputmethod.InputBindResult; import com.android.internal.inputmethod.UnbindReason; import com.android.internal.view.IInputMethod; import com.android.server.inputmethod.InputMethodManagerService.ClientState; +import com.android.server.wm.WindowManagerInternal; /** * A controller managing the state of the input method binding. @@ -64,6 +65,7 @@ final class InputMethodBindingController { @NonNull private final InputMethodUtils.InputMethodSettings mSettings; @NonNull private final PackageManagerInternal mPackageManagerInternal; @NonNull private final IWindowManager mIWindowManager; + @NonNull private final WindowManagerInternal mWindowManagerInternal; @NonNull private final Resources mRes; private long mLastBindTime; @@ -120,6 +122,7 @@ final class InputMethodBindingController { mSettings = mService.mSettings; mPackageManagerInternal = mService.mPackageManagerInternal; mIWindowManager = mService.mIWindowManager; + mWindowManagerInternal = mService.mWindowManagerInternal; mRes = mService.mRes; // If configured, use low priority flags to make the IME killable by the lowmemorykiller @@ -193,10 +196,6 @@ final class InputMethodBindingController { return mCurToken; } - void setCurToken(IBinder curToken) { - mCurToken = curToken; - } - /** * The Intent used to connect to the current input method. */ @@ -368,13 +367,27 @@ final class InputMethodBindingController { } if (mCurToken != null) { - mService.removeCurrentTokenLocked(); + removeCurrentTokenLocked(); + mService.resetSystemUiLocked(); } mCurId = null; mService.clearCurMethodLocked(); } + @GuardedBy("mMethodMap") + private void removeCurrentTokenLocked() { + int curTokenDisplayId = mService.getCurTokenDisplayId(); + + if (DEBUG) { + Slog.v(TAG, + "Removing window token: " + mCurToken + " for display: " + curTokenDisplayId); + } + mWindowManagerInternal.removeWindowToken(mCurToken, false /* removeWindows */, + false /* animateExit */, curTokenDisplayId); + mCurToken = null; + } + @GuardedBy("mMethodMap") @NonNull InputBindResult bindCurrentMethodLocked(int displayIdToShowIme) { diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index b0e9ab7951c0f..05133e3f0f20f 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -593,17 +593,17 @@ public class InputMethodManagerService extends IInputMethodManager.Stub return mBindingController.getCurToken(); } - private void setCurToken(IBinder curToken) { - mBindingController.setCurToken(curToken); + /** + * The displayId of current active input method. + */ + int getCurTokenDisplayId() { + return mCurTokenDisplayId; } void setCurTokenDisplayId(int curTokenDisplayId) { mCurTokenDisplayId = curTokenDisplayId; } - /** - * The displayId of current active input method. - */ int mCurTokenDisplayId = INVALID_DISPLAY; /** @@ -2536,18 +2536,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } @GuardedBy("mMethodMap") - void removeCurrentTokenLocked() { - IBinder token = getCurToken(); - if (DEBUG) { - Slog.v(TAG, "Removing window token: " + token + " for display: " + mCurTokenDisplayId); - } - mWindowManagerInternal.removeWindowToken(token, false /* removeWindows */, - false /* animateExit */, mCurTokenDisplayId); - // Set IME window status as invisible when unbind current method. + void resetSystemUiLocked() { + // Set IME window status as invisible when unbinding current method. mImeWindowVis = 0; mBackDisposition = InputMethodService.BACK_DISPOSITION_DEFAULT; updateSystemUiLocked(mImeWindowVis, mBackDisposition); - setCurToken(null); mCurTokenDisplayId = INVALID_DISPLAY; mCurHostInputToken = null; } From c170229182b0f5551f02c424cbe1224892646abe Mon Sep 17 00:00:00 2001 From: Nikolas Havrikov Date: Mon, 15 Nov 2021 15:40:50 +0100 Subject: [PATCH 36/43] Move setting curId and bindTime for symmetry Bug: 205676419 Test: make Change-Id: I5c24d8e833769a7b1cbd055940a3bca70075bdee --- .../server/inputmethod/InputMethodBindingController.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java index 46887b6e91a52..82d9cdff4fd1b 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java @@ -399,7 +399,10 @@ final class InputMethodBindingController { mCurIntent = createImeBindingIntent(info.getComponent()); if (bindCurrentInputMethodServiceMainConnectionLocked()) { - addFreshWindowTokenLocked(displayIdToShowIme, info.getId()); + mCurId = info.getId(); + mLastBindTime = SystemClock.uptimeMillis(); + + addFreshWindowTokenLocked(displayIdToShowIme); return new InputBindResult( InputBindResult.ResultCode.SUCCESS_WAITING_IME_BINDING, null, null, mCurId, mCurSeq, false); @@ -424,11 +427,9 @@ final class InputMethodBindingController { } @GuardedBy("mMethodMap") - private void addFreshWindowTokenLocked(int displayIdToShowIme, String methodId) { + private void addFreshWindowTokenLocked(int displayIdToShowIme) { Binder token = new Binder(); mCurToken = token; - mLastBindTime = SystemClock.uptimeMillis(); - mCurId = methodId; mService.setCurTokenDisplayId(displayIdToShowIme); From b46604d32be1c9f26334f40eaf0f896698853433 Mon Sep 17 00:00:00 2001 From: Nikolas Havrikov Date: Mon, 15 Nov 2021 15:42:45 +0100 Subject: [PATCH 37/43] Avoid unwarranted local variable Bug: 205676419 Test: make Change-Id: I9a3a184f713bda78f660f0d10dd1500ef5be151d --- .../server/inputmethod/InputMethodBindingController.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java index 82d9cdff4fd1b..f438d944c73af 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java @@ -428,20 +428,19 @@ final class InputMethodBindingController { @GuardedBy("mMethodMap") private void addFreshWindowTokenLocked(int displayIdToShowIme) { - Binder token = new Binder(); - mCurToken = token; + mCurToken = new Binder(); mService.setCurTokenDisplayId(displayIdToShowIme); try { if (DEBUG) { - Slog.v(TAG, "Adding window token: " + token + " for display: " + Slog.v(TAG, "Adding window token: " + mCurToken + " for display: " + displayIdToShowIme); } - mIWindowManager.addWindowToken(token, WindowManager.LayoutParams.TYPE_INPUT_METHOD, + mIWindowManager.addWindowToken(mCurToken, WindowManager.LayoutParams.TYPE_INPUT_METHOD, displayIdToShowIme, null /* options */); } catch (RemoteException e) { - Slog.e(TAG, "Could not add window token " + token + " for display " + Slog.e(TAG, "Could not add window token " + mCurToken + " for display " + displayIdToShowIme, e); } } From 38995552420d89bc5aeafee195340f8ca950c7e4 Mon Sep 17 00:00:00 2001 From: Nikolas Havrikov Date: Mon, 15 Nov 2021 16:39:51 +0100 Subject: [PATCH 38/43] Factor out redundant getter calls Bug: 205676419 Test: make Change-Id: I40e0860ecd9e8db93a7c14699c5fae7c2e4dc735 --- .../InputMethodManagerService.java | 78 +++++++++++-------- 1 file changed, 46 insertions(+), 32 deletions(-) diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 05133e3f0f20f..b9b0501796405 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -1688,7 +1688,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub @GuardedBy("mMethodMap") private void resetDefaultImeLocked(Context context) { // Do not reset the default (current) IME when it is a 3rd-party IME - if (getSelectedMethodId() != null && !mMethodMap.get(getSelectedMethodId()).isSystem()) { + String selectedMethodId = getSelectedMethodId(); + if (selectedMethodId != null && !mMethodMap.get(selectedMethodId).isSystem()) { return; } final List suitableImes = InputMethodUtils.getDefaultEnabledImes( @@ -1987,10 +1988,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub InlineSuggestionsRequestInfo requestInfo, IInlineSuggestionsRequestCallback callback) { final InputMethodInfo imi = mMethodMap.get(getSelectedMethodId()); try { + IInputMethod curMethod = getCurMethod(); if (userId == mSettings.getCurrentUserId() && imi != null - && imi.isInlineSuggestionsEnabled() && getCurMethod() != null) { - executeOrSendMessage(getCurMethod(), - mCaller.obtainMessageOOO(MSG_INLINE_SUGGESTIONS_REQUEST, getCurMethod(), + && imi.isInlineSuggestionsEnabled() && curMethod != null) { + executeOrSendMessage(curMethod, + mCaller.obtainMessageOOO(MSG_INLINE_SUGGESTIONS_REQUEST, curMethod, requestInfo, new InlineSuggestionsRequestCallbackDecorator(callback, imi.getPackageName(), mCurTokenDisplayId, getCurToken(), this))); @@ -2128,8 +2130,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub boolean allowsImplicitlySelectedSubtypes, @UserIdInt int userId) { if (userId == mSettings.getCurrentUserId()) { final InputMethodInfo imi; - if (imiId == null && getSelectedMethodId() != null) { - imi = mMethodMap.get(getSelectedMethodId()); + String selectedMethodId = getSelectedMethodId(); + if (imiId == null && selectedMethodId != null) { + imi = mMethodMap.get(selectedMethodId); } else { imi = mMethodMap.get(imiId); } @@ -2226,9 +2229,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mCurFocusedWindow, 0, null, SoftInputShowHideReason.HIDE_REMOVE_CLIENT); if (mBoundToMethod) { mBoundToMethod = false; - if (getCurMethod() != null) { - executeOrSendMessage(getCurMethod(), mCaller.obtainMessageO( - MSG_UNBIND_INPUT, getCurMethod())); + IInputMethod curMethod = getCurMethod(); + if (curMethod != null) { + executeOrSendMessage(curMethod, mCaller.obtainMessageO( + MSG_UNBIND_INPUT, curMethod)); } } mCurClient = null; @@ -2256,9 +2260,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub + mCurClient.client.asBinder()); if (mBoundToMethod) { mBoundToMethod = false; - if (getCurMethod() != null) { - executeOrSendMessage(getCurMethod(), mCaller.obtainMessageO( - MSG_UNBIND_INPUT, getCurMethod())); + IInputMethod curMethod = getCurMethod(); + if (curMethod != null) { + executeOrSendMessage(curMethod, mCaller.obtainMessageO( + MSG_UNBIND_INPUT, curMethod)); } } @@ -2300,8 +2305,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub @NonNull InputBindResult attachNewInputLocked(@StartInputReason int startInputReason, boolean initial) { if (!mBoundToMethod) { - executeOrSendMessage(getCurMethod(), mCaller.obtainMessageOO( - MSG_BIND_INPUT, getCurMethod(), mCurClient.binding)); + IInputMethod curMethod = getCurMethod(); + executeOrSendMessage(curMethod, mCaller.obtainMessageOO( + MSG_BIND_INPUT, curMethod, mCurClient.binding)); mBoundToMethod = true; } @@ -2334,12 +2340,14 @@ public class InputMethodManagerService extends IInputMethodManager.Stub showCurrentInputLocked(mCurFocusedWindow, getAppShowFlagsLocked(), null, SoftInputShowHideReason.ATTACH_NEW_INPUT); } - final InputMethodInfo curInputMethodInfo = mMethodMap.get(getCurId()); + + String curId = getCurId(); + final InputMethodInfo curInputMethodInfo = mMethodMap.get(curId); final boolean suppressesSpellChecker = curInputMethodInfo != null && curInputMethodInfo.suppressesSpellChecker(); return new InputBindResult(InputBindResult.ResultCode.SUCCESS_WITH_IME_SESSION, session.session, (session.channel != null ? session.channel.dup() : null), - getCurId(), getSequenceNumber(), suppressesSpellChecker); + curId, getSequenceNumber(), suppressesSpellChecker); } @GuardedBy("mMethodMap") @@ -2514,8 +2522,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub channel.dispose(); return; } - if (getCurMethod() != null && method != null - && getCurMethod().asBinder() == method.asBinder()) { + IInputMethod curMethod = getCurMethod(); + if (curMethod != null && method != null + && curMethod.asBinder() == method.asBinder()) { if (mCurClient != null) { clearClientSessionLocked(mCurClient); mCurClient.curSession = new SessionState(mCurClient, @@ -2558,9 +2567,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub if (DEBUG) Slog.v(TAG, "Creating new session for client " + cs); InputChannel[] channels = InputChannel.openInputChannelPair(cs.toString()); cs.sessionRequested = true; - executeOrSendMessage(getCurMethod(), mCaller.obtainMessageOOO( - MSG_CREATE_SESSION, getCurMethod(), channels[1], - new MethodCallback(this, getCurMethod(), channels[0]))); + IInputMethod curMethod = getCurMethod(); + executeOrSendMessage(curMethod, mCaller.obtainMessageOOO( + MSG_CREATE_SESSION, curMethod, channels[1], + new MethodCallback(this, curMethod, channels[0]))); } } @@ -2940,10 +2950,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } if (newSubtype != oldSubtype) { setSelectedInputMethodAndSubtypeLocked(info, subtypeId, true); - if (getCurMethod() != null) { + IInputMethod curMethod = getCurMethod(); + if (curMethod != null) { try { updateSystemUiLocked(mImeWindowVis, mBackDisposition); - getCurMethod().changeInputMethodSubtype(newSubtype); + curMethod.changeInputMethodSubtype(newSubtype); } catch (RemoteException e) { Slog.w(TAG, "Failed to call changeInputMethodSubtype"); } @@ -3055,13 +3066,14 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } boolean res = false; - if (getCurMethod() != null) { + IInputMethod curMethod = getCurMethod(); + if (curMethod != null) { if (DEBUG) Slog.d(TAG, "showCurrentInputLocked: mCurToken=" + getCurToken()); // create a placeholder token for IMS so that IMS cannot inject windows into client app. Binder showInputToken = new Binder(); mShowRequestWindowMap.put(showInputToken, windowToken); - executeOrSendMessage(getCurMethod(), mCaller.obtainMessageIIOOO(MSG_SHOW_SOFT_INPUT, - getImeShowFlagsLocked(), reason, getCurMethod(), resultReceiver, + executeOrSendMessage(curMethod, mCaller.obtainMessageIIOOO(MSG_SHOW_SOFT_INPUT, + getImeShowFlagsLocked(), reason, curMethod, resultReceiver, showInputToken)); mInputShown = true; if (hasConnection() && !isVisibleBound()) { @@ -3155,7 +3167,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub // since Android Eclair. That's why we need to accept IMM#hideSoftInput() even when only // IMMS#InputShown indicates that the software keyboard is shown. // TODO: Clean up, IMMS#mInputShown, IMMS#mImeWindowVis and mShowRequested. - final boolean shouldHideSoftInput = (getCurMethod() != null) && (mInputShown + IInputMethod curMethod = getCurMethod(); + final boolean shouldHideSoftInput = (curMethod != null) && (mInputShown || (mImeWindowVis & InputMethodService.IME_ACTIVE) != 0); boolean res; if (shouldHideSoftInput) { @@ -3165,8 +3178,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub // delivered to the IME process as an IPC. Hence the inconsistency between // IMMS#mInputShown and IMMS#mImeWindowVis should be resolved spontaneously in // the final state. - executeOrSendMessage(getCurMethod(), mCaller.obtainMessageIOOO(MSG_HIDE_SOFT_INPUT, - reason, getCurMethod(), resultReceiver, hideInputToken)); + executeOrSendMessage(curMethod, mCaller.obtainMessageIOOO(MSG_HIDE_SOFT_INPUT, + reason, curMethod, resultReceiver, hideInputToken)); res = true; } else { res = false; @@ -4755,17 +4768,18 @@ public class InputMethodManagerService extends IInputMethodManager.Stub @GuardedBy("mMethodMap") InputMethodSubtype getCurrentInputMethodSubtypeLocked() { - if (getSelectedMethodId() == null) { + String selectedMethodId = getSelectedMethodId(); + if (selectedMethodId == null) { return null; } final boolean subtypeIsSelected = mSettings.isSubtypeSelected(); - final InputMethodInfo imi = mMethodMap.get(getSelectedMethodId()); + final InputMethodInfo imi = mMethodMap.get(selectedMethodId); if (imi == null || imi.getSubtypeCount() == 0) { return null; } if (!subtypeIsSelected || mCurrentSubtype == null || !InputMethodUtils.isValidSubtypeId(imi, mCurrentSubtype.hashCode())) { - int subtypeId = mSettings.getSelectedInputMethodSubtypeId(getSelectedMethodId()); + int subtypeId = mSettings.getSelectedInputMethodSubtypeId(selectedMethodId); if (subtypeId == NOT_A_SUBTYPE_ID) { // If there are no selected subtypes, the framework will try to find // the most applicable subtype from explicitly or implicitly enabled From bf82be54a84f7323be61e172f190990cd2b1e164 Mon Sep 17 00:00:00 2001 From: Nikolas Havrikov Date: Mon, 15 Nov 2021 19:03:52 +0100 Subject: [PATCH 39/43] Reduce binding controller coupling to IMMS This CL extracts direct interactions with accessor methods Bug: 205676419 Test: make Change-Id: If31a2ed79eea0113030ff7f0e2f14195ab57054a --- .../InputMethodBindingController.java | 12 ++---- .../InputMethodManagerService.java | 38 +++++++------------ 2 files changed, 17 insertions(+), 33 deletions(-) diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java index f438d944c73af..755c093498c0f 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java @@ -49,7 +49,6 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.inputmethod.InputBindResult; import com.android.internal.inputmethod.UnbindReason; import com.android.internal.view.IInputMethod; -import com.android.server.inputmethod.InputMethodManagerService.ClientState; import com.android.server.wm.WindowManagerInternal; /** @@ -302,11 +301,7 @@ final class InputMethodBindingController { mMethodMap.get(mSelectedMethodId).getConfigChanges(), mCurMethod, mCurToken)); mService.scheduleNotifyImeUidToAudioService(mCurMethodUid); - ClientState curClient = mService.getCurClient(); - if (curClient != null) { - mService.clearClientSessionLocked(curClient); - mService.requestClientSessionLocked(curClient); - } + mService.reRequestCurrentClientSessionLocked(); } } Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); @@ -344,12 +339,11 @@ final class InputMethodBindingController { } if (mCurMethod != null && mCurIntent != null && name.equals(mCurIntent.getComponent())) { - mService.clearCurMethodLocked(); // We consider this to be a new bind attempt, since the system // should now try to restart the service for us. mLastBindTime = SystemClock.uptimeMillis(); - mService.setShowRequested(mService.isInputShown()); - mService.setInputShown(false); + mService.clearCurMethodLocked(); + mService.clearInputShowRequestLocked(); mService.unbindCurrentClientLocked(UnbindReason.DISCONNECT_IME); } } diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index b9b0501796405..e9c2edb36c2f7 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -455,14 +455,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub */ boolean mImeHiddenByDisplayPolicy; - ClientState getCurClient() { - return mCurClient; - } - - void setCurClient(ClientState curClient) { - mCurClient = curClient; - } - /** * The client that is currently bound to an input method. */ @@ -536,14 +528,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub return mBindingController.hasConnection(); } - boolean isShowRequested() { - return mShowRequested; - } - - void setShowRequested(boolean showRequested) { - mShowRequested = showRequested; - } - /** * Set if the client has asked for the input method to be shown. */ @@ -559,14 +543,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub */ boolean mShowForced; - boolean isInputShown() { - return mInputShown; - } - - void setInputShown(boolean inputShown) { - mInputShown = inputShown; - } - /** * Set if we last told the input method to show itself. */ @@ -2278,6 +2254,12 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } } + @GuardedBy("mMethodMap") + void clearInputShowRequestLocked() { + mShowRequested = mInputShown; + mInputShown = false; + } + @GuardedBy("mMethodMap") private int getImeShowFlagsLocked() { int flags = 0; @@ -2561,6 +2543,14 @@ public class InputMethodManagerService extends IInputMethodManager.Stub unbindCurrentClientLocked(unbindClientReason); } + @GuardedBy("mMethodMap") + void reRequestCurrentClientSessionLocked() { + if (mCurClient != null) { + clearClientSessionLocked(mCurClient); + requestClientSessionLocked(mCurClient); + } + } + @GuardedBy("mMethodMap") void requestClientSessionLocked(ClientState cs) { if (!cs.sessionRequested) { From 8b08a9f7779cd27749123392dd8c511afa98cf87 Mon Sep 17 00:00:00 2001 From: Nikolas Havrikov Date: Thu, 18 Nov 2021 17:26:07 +0100 Subject: [PATCH 40/43] Extract hiding status bar icon Bug: 205676419 Test: make Change-Id: I1afed9f50196eae5acc70379b61b04bddf4a2954 --- .../InputMethodManagerService.java | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index e9c2edb36c2f7..74871dcf26914 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -1780,9 +1780,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mKeyguardManager = mContext.getSystemService(KeyguardManager.class); mNotificationManager = mContext.getSystemService(NotificationManager.class); mStatusBar = statusBar; - if (mStatusBar != null) { - mStatusBar.setIconVisibility(mSlotIme, false); - } + hideStatusBarIconLocked(); updateSystemUiLocked(mImeWindowVis, mBackDisposition); mShowOngoingImeSwitcherForPhones = mRes.getBoolean( com.android.internal.R.bool.show_ongoing_ime_switcher); @@ -2604,9 +2602,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub setCurMethodUid(Process.INVALID_UID); scheduleNotifyImeUidToAudioService(getCurMethodUid()); } - if (mStatusBar != null) { - mStatusBar.setIconVisibility(mSlotIme, false); - } + hideStatusBarIconLocked(); mInFullscreenMode = false; } @@ -2621,9 +2617,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub try { if (iconId == 0) { if (DEBUG) Slog.d(TAG, "hide the small icon for the input method"); - if (mStatusBar != null) { - mStatusBar.setIconVisibility(mSlotIme, false); - } + hideStatusBarIconLocked(); } else if (packageName != null) { if (DEBUG) Slog.d(TAG, "show a small icon for the input method"); CharSequence contentDescription = null; @@ -2649,6 +2643,13 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } } + @GuardedBy("mMethodMap") + private void hideStatusBarIconLocked() { + if (mStatusBar != null) { + mStatusBar.setIconVisibility(mSlotIme, false); + } + } + @GuardedBy("mMethodMap") private boolean shouldShowImeSwitcherLocked(int visibility) { if (!mShowOngoingImeSwitcherForPhones) return false; From 0dc20ab2a08109568d4c835ed003b985f15651b5 Mon Sep 17 00:00:00 2001 From: Nikolas Havrikov Date: Thu, 18 Nov 2021 17:36:58 +0100 Subject: [PATCH 41/43] Rename method clearing sessions appropriately Bug: 205676419 Test: make Change-Id: I92c43548a275f358e382a260314bb6fa4546ab42 --- .../server/inputmethod/InputMethodBindingController.java | 4 ++-- .../android/server/inputmethod/InputMethodManagerService.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java index 755c093498c0f..efc18f8659587 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java @@ -342,7 +342,7 @@ final class InputMethodBindingController { // We consider this to be a new bind attempt, since the system // should now try to restart the service for us. mLastBindTime = SystemClock.uptimeMillis(); - mService.clearCurMethodLocked(); + mService.clearClientSessionsLocked(); mService.clearInputShowRequestLocked(); mService.unbindCurrentClientLocked(UnbindReason.DISCONNECT_IME); } @@ -366,7 +366,7 @@ final class InputMethodBindingController { } mCurId = null; - mService.clearCurMethodLocked(); + mService.clearClientSessionsLocked(); } @GuardedBy("mMethodMap") diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 74871dcf26914..457dc561ed85a 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -2589,7 +2589,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } @GuardedBy("mMethodMap") - void clearCurMethodLocked() { + void clearClientSessionsLocked() { if (getCurMethod() != null) { final int numClients = mClients.size(); for (int i = 0; i < numClients; ++i) { From a1a9ae5392be5c4fb99b256428f1f118a37a96e7 Mon Sep 17 00:00:00 2001 From: Nikolas Havrikov Date: Thu, 18 Nov 2021 17:37:44 +0100 Subject: [PATCH 42/43] Move clearing current method to controller Bug: 205676419 Test: make Change-Id: I11641791abbc4f24d97e2d371900a912c9b6ba41 --- .../inputmethod/InputMethodBindingController.java | 14 ++++++-------- .../inputmethod/InputMethodManagerService.java | 13 ++----------- 2 files changed, 8 insertions(+), 19 deletions(-) diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java index efc18f8659587..05e1bdd11db60 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java @@ -231,10 +231,6 @@ final class InputMethodBindingController { return mCurMethod; } - void setCurMethod(@Nullable IInputMethod curMethod) { - mCurMethod = curMethod; - } - /** * If not {@link Process#INVALID_UID}, then the UID of {@link #getCurIntent()}. */ @@ -242,10 +238,6 @@ final class InputMethodBindingController { return mCurMethodUid; } - void setCurMethodUid(int curMethodUid) { - mCurMethodUid = curMethodUid; - } - /** * Indicates whether {@link #getVisibleConnection} is currently in use. */ @@ -369,6 +361,12 @@ final class InputMethodBindingController { mService.clearClientSessionsLocked(); } + @GuardedBy("mMethodMap") + void clearCurMethodLocked() { + mCurMethod = null; + mCurMethodUid = Process.INVALID_UID; + } + @GuardedBy("mMethodMap") private void removeCurrentTokenLocked() { int curTokenDisplayId = mService.getCurTokenDisplayId(); diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 457dc561ed85a..6bb945c5f0d90 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -606,10 +606,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub return mBindingController.getCurMethod(); } - private void setCurMethod(@Nullable IInputMethod curMethod) { - mBindingController.setCurMethod(curMethod); - } - /** * If not {@link Process#INVALID_UID}, then the UID of {@link #getCurIntent()}. */ @@ -617,10 +613,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub return mBindingController.getCurMethodUid(); } - private void setCurMethodUid(int curMethodUid) { - mBindingController.setCurMethodUid(curMethodUid); - } - /** * Time that we last initiated a bind to the input method, to determine * if we should try to disconnect and reconnect to it. @@ -2598,9 +2590,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub finishSessionLocked(mEnabledSession); mEnabledSession = null; - setCurMethod(null); - setCurMethodUid(Process.INVALID_UID); - scheduleNotifyImeUidToAudioService(getCurMethodUid()); + mBindingController.clearCurMethodLocked(); + scheduleNotifyImeUidToAudioService(Process.INVALID_UID); } hideStatusBarIconLocked(); mInFullscreenMode = false; From 017575ee3ea58fcdc7dfff0c149ccff6cc63440d Mon Sep 17 00:00:00 2001 From: Nikolas Havrikov Date: Thu, 18 Nov 2021 17:51:35 +0100 Subject: [PATCH 43/43] Remove unused method isKeyguardLocked Bug: 202218289 Bug: 205676419 Test: make Change-Id: I6aaf56f058a21aafb1edef03d9693ebc5b6ad513 --- .../server/inputmethod/InputMethodManagerService.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 6bb945c5f0d90..c879e3d792f97 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -2705,11 +2705,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub return false; } - @GuardedBy("mMethodMap") - private boolean isKeyguardLocked() { - return mKeyguardManager != null && mKeyguardManager.isKeyguardLocked(); - } - @BinderThread @SuppressWarnings("deprecation") private void setImeWindowStatus(@NonNull IBinder token, int vis, int backDisposition) {