Move IMMS service connection to the binding controller
Bug: 205676419
Test: make
Change-Id: I7e54a579c4ecd42acdde7b66fe583fe46dff2471
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
index 8b586cc..765672c 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 @@
@NonNull private final InputMethodManagerService mService;
@NonNull private final Context mContext;
@NonNull private final ArrayMap<String, InputMethodInfo> mMethodMap;
+ @NonNull private final InputMethodUtils.InputMethodSettings mSettings;
+ @NonNull private final PackageManagerInternal mPackageManagerInternal;
private long mLastBindTime;
private boolean mHasConnection;
@@ -56,6 +68,8 @@
mService = service;
mContext = mService.mContext;
mMethodMap = mService.mMethodMap;
+ mSettings = mService.mSettings;
+ mPackageManagerInternal = mService.mPackageManagerInternal;
}
/**
@@ -224,4 +238,84 @@
}
};
+ /**
+ * 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 <APK that implements the current IME>
+ // 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 a35687d..05aebcc 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.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 @@
*/
@NonNull
private ServiceConnection getMainConnection() {
- return mMainConnection;
+ return mBindingController.getMainConnection();
}
// Ongoing notification
@@ -2641,83 +2640,11 @@
}
@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 <APK that implements the current IME>
- // 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) {