Move IMMS service connection to the binding controller

Bug: 205676419
Test: make
Change-Id: I7e54a579c4ecd42acdde7b66fe583fe46dff2471
This commit is contained in:
Nikolas Havrikov
2021-11-11 13:44:42 +01:00
parent 55f546a95d
commit 7a987973f2
2 changed files with 96 additions and 75 deletions

View File

@@ -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<String, InputMethodInfo> 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 <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);
}
}
}
};
}

View File

@@ -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 <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) {