diff options
author | Jeff Brown <jeffbrown@google.com> | 2013-03-26 15:42:39 -0700 |
---|---|---|
committer | Jeff Brown <jeffbrown@google.com> | 2013-03-26 15:42:39 -0700 |
commit | c28867a1d67121ce5963de135e3ae2b1dbd9a33d (patch) | |
tree | 95da9070093882f0b95ee197f45f5b4a5e348d96 /services/java/com/android/server/InputMethodManagerService.java | |
parent | 37f180b4a52e4c1d0b6a7b400b6579b7ff25f307 (diff) | |
download | frameworks_base-c28867a1d67121ce5963de135e3ae2b1dbd9a33d.zip frameworks_base-c28867a1d67121ce5963de135e3ae2b1dbd9a33d.tar.gz frameworks_base-c28867a1d67121ce5963de135e3ae2b1dbd9a33d.tar.bz2 |
Use input transport for communications between app and IME.
The input method manager service now supplies an input channel for
communication while creating an IME session on behalf of the
application.
This change significanly reduces the overhead of IME event dispatch
by using a standard input channel to send input events rather than
using binder. This results in fewer thread context switches
and fewer object allocations.
What's more, the IME may perform additional batching of the motion
events that it receives which may help it catch up if it is
getting behind while processing them.
Bug: 7984576
Bug: 8473020
Change-Id: Ibe26311edd0060cdcae80194f1753482e635786f
Diffstat (limited to 'services/java/com/android/server/InputMethodManagerService.java')
-rw-r--r-- | services/java/com/android/server/InputMethodManagerService.java | 127 |
1 files changed, 81 insertions, 46 deletions
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java index dd081a1..2d53023 100644 --- a/services/java/com/android/server/InputMethodManagerService.java +++ b/services/java/com/android/server/InputMethodManagerService.java @@ -88,6 +88,7 @@ import android.util.Printer; import android.util.Slog; import android.util.Xml; import android.view.IWindowManager; +import android.view.InputChannel; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -170,7 +171,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub private final HardKeyboardListener mHardKeyboardListener; private final WindowManagerService mWindowManagerService; - final InputBindResult mNoBinding = new InputBindResult(null, null, -1); + final InputBindResult mNoBinding = new InputBindResult(null, null, null, -1); // All known input methods. mMethodMap also serves as the global // lock for this class. @@ -202,7 +203,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub class SessionState { final ClientState client; final IInputMethod method; - final IInputMethodSession session; + + IInputMethodSession session; + InputChannel channel; @Override public String toString() { @@ -211,18 +214,20 @@ public class InputMethodManagerService extends IInputMethodManager.Stub System.identityHashCode(method)) + " session " + Integer.toHexString( System.identityHashCode(session)) + + " channel " + channel + "}"; } SessionState(ClientState _client, IInputMethod _method, - IInputMethodSession _session) { + IInputMethodSession _session, InputChannel _channel) { client = _client; method = _method; session = _session; + channel = _channel; } } - class ClientState { + static final class ClientState { final IInputMethodClient client; final IInputContext inputContext; final int uid; @@ -555,18 +560,21 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } } - private static class MethodCallback extends IInputSessionCallback.Stub { - private final IInputMethod mMethod; + private static final class MethodCallback extends IInputSessionCallback.Stub { private final InputMethodManagerService mParentIMMS; + private final IInputMethod mMethod; + private final InputChannel mChannel; - MethodCallback(final IInputMethod method, final InputMethodManagerService imms) { - mMethod = method; + MethodCallback(InputMethodManagerService imms, IInputMethod method, + InputChannel channel) { mParentIMMS = imms; + mMethod = method; + mChannel = channel; } @Override - public void sessionCreated(IInputMethodSession session) throws RemoteException { - mParentIMMS.onSessionCreated(mMethod, session); + public void sessionCreated(IInputMethodSession session) { + mParentIMMS.onSessionCreated(mMethod, session, mChannel); } } @@ -984,7 +992,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub return; } synchronized (mMethodMap) { - mClients.remove(client.asBinder()); + ClientState cs = mClients.remove(client.asBinder()); + if (cs != null) { + clearClientSessionLocked(cs); + } } } @@ -1059,7 +1070,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub if (DEBUG) Slog.v(TAG, "Attach new input asks to show input"); showCurrentInputLocked(getAppShowFlags(), null); } - return new InputBindResult(session.session, mCurId, mCurSeq); + return new InputBindResult(session.session, session.channel, mCurId, mCurSeq); } InputBindResult startInputLocked(IInputMethodClient client, @@ -1137,16 +1148,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } if (mHaveConnection) { if (mCurMethod != null) { - if (!cs.sessionRequested) { - cs.sessionRequested = true; - if (DEBUG) Slog.v(TAG, "Creating new session for client " + cs); - executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO( - MSG_CREATE_SESSION, mCurMethod, - new MethodCallback(mCurMethod, this))); - } // Return to client, and we will get back with it when // we have had a session made for it. - return new InputBindResult(null, mCurId, mCurSeq); + requestClientSessionLocked(cs); + return new InputBindResult(null, null, mCurId, mCurSeq); } else if (SystemClock.uptimeMillis() < (mLastBindTime+TIME_TO_RECONNECT)) { // In this case we have connected to the service, but @@ -1156,7 +1161,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub // 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(null, mCurId, mCurSeq); + return new InputBindResult(null, null, mCurId, mCurSeq); } else { EventLog.writeEvent(EventLogTags.IMF_FORCE_RECONNECT_IME, mCurMethodId, SystemClock.uptimeMillis()-mLastBindTime, 0); @@ -1175,7 +1180,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub if (!mSystemReady) { // If the system is not yet ready, we shouldn't be running third // party code. - return new InputBindResult(null, mCurMethodId, mCurSeq); + return new InputBindResult(null, null, mCurMethodId, mCurSeq); } InputMethodInfo info = mMethodMap.get(mCurMethodId); @@ -1203,7 +1208,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub WindowManager.LayoutParams.TYPE_INPUT_METHOD); } catch (RemoteException e) { } - return new InputBindResult(null, mCurId, mCurSeq); + return new InputBindResult(null, null, mCurId, mCurSeq); } else { mCurIntent = null; Slog.w(TAG, "Failure connecting to input method service: " @@ -1246,32 +1251,34 @@ public class InputMethodManagerService extends IInputMethodManager.Stub executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO( MSG_ATTACH_TOKEN, mCurMethod, mCurToken)); if (mCurClient != null) { - if (DEBUG) Slog.v(TAG, "Creating first session while with client " - + mCurClient); - executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO( - MSG_CREATE_SESSION, mCurMethod, - new MethodCallback(mCurMethod, this))); + clearClientSessionLocked(mCurClient); + requestClientSessionLocked(mCurClient); } } } } - void onSessionCreated(IInputMethod method, IInputMethodSession session) { + void onSessionCreated(IInputMethod method, IInputMethodSession session, + InputChannel channel) { synchronized (mMethodMap) { if (mCurMethod != null && method != null && mCurMethod.asBinder() == method.asBinder()) { if (mCurClient != null) { + clearClientSessionLocked(mCurClient); mCurClient.curSession = new SessionState(mCurClient, - method, session); - mCurClient.sessionRequested = false; + method, session, channel); InputBindResult res = attachNewInputLocked(true); if (res.method != null) { executeOrSendMessage(mCurClient.client, mCaller.obtainMessageOO( MSG_BIND_METHOD, mCurClient.client, res)); } + return; } } } + + // Session abandoned. Close its associated input channel. + channel.dispose(); } void unbindCurrentMethodLocked(boolean reportToClient, boolean savePosition) { @@ -1306,14 +1313,38 @@ public class InputMethodManagerService extends IInputMethodManager.Stub MSG_UNBIND_METHOD, mCurSeq, mCurClient.client)); } } - - private void finishSession(SessionState sessionState) { - if (sessionState != null && sessionState.session != null) { - try { - sessionState.session.finishSession(); - } catch (RemoteException e) { - Slog.w(TAG, "Session failed to close due to remote exception", e); - setImeWindowVisibilityStatusHiddenLocked(); + + void requestClientSessionLocked(ClientState cs) { + if (!cs.sessionRequested) { + 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]))); + } + } + + void clearClientSessionLocked(ClientState cs) { + finishSessionLocked(cs.curSession); + cs.curSession = null; + cs.sessionRequested = false; + } + + private void finishSessionLocked(SessionState sessionState) { + if (sessionState != null) { + if (sessionState.session != null) { + try { + sessionState.session.finishSession(); + } catch (RemoteException e) { + Slog.w(TAG, "Session failed to close due to remote exception", e); + setImeWindowVisibilityStatusHiddenLocked(); + } + sessionState.session = null; + } + if (sessionState.channel != null) { + sessionState.channel.dispose(); + sessionState.channel = null; } } } @@ -1321,12 +1352,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub void clearCurMethodLocked() { if (mCurMethod != null) { for (ClientState cs : mClients.values()) { - cs.sessionRequested = false; - finishSession(cs.curSession); - cs.curSession = null; + clearClientSessionLocked(cs); } - finishSession(mEnabledSession); + finishSessionLocked(mEnabledSession); mEnabledSession = null; mCurMethod = null; } @@ -2325,15 +2354,21 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } args.recycle(); return true; - case MSG_CREATE_SESSION: + case MSG_CREATE_SESSION: { args = (SomeArgs)msg.obj; + InputChannel channel = (InputChannel)args.arg2; try { - ((IInputMethod)args.arg1).createSession( - (IInputSessionCallback)args.arg2); + ((IInputMethod)args.arg1).createSession(channel, + (IInputSessionCallback)args.arg3); } catch (RemoteException e) { + } finally { + if (channel != null) { + channel.dispose(); + } } args.recycle(); return true; + } // --------------------------------------------------------- case MSG_START_INPUT: |