部分调用栈信息:
01-01 04:59:23.234 W/System.err( 930): java.lang.Throwable: stack dump
01-01 04:59:23.235 W/System.err( 930): at java.lang.Thread.dumpStack(Thread.java:489)
01-01 04:59:23.235 W/System.err( 930): at android.service.textservice.SpellCheckerService$InternalISpellCheckerSession.onGetSentenceSuggestionsMultiple(SpellCheckerService.java:271)
01-01 04:59:23.235 W/System.err( 930): at com.android.internal.textservice.ISpellCheckerSession$Stub.onTransact(ISpellCheckerSession.java:67)
01-01 04:59:23.235 W/System.err( 930): at android.os.Binder.execTransact(Binder.java:404)
01-01 04:59:23.235 W/System.err( 930): at dalvik.system.NativeStart.run(Native Method)
01-01 04:59:23.506 W/System.err( 1415): java.lang.Throwable: stack dump
01-01 04:59:23.506 W/System.err( 1415): at java.lang.Thread.dumpStack(Thread.java:489)
01-01 04:59:23.507 W/System.err( 1415): at android.widget.SpellChecker.onGetSentenceSuggestions(SpellChecker.java:413)
01-01 04:59:23.507 W/System.err( 1415): at android.view.textservice.SpellCheckerSession.handleOnGetSentenceSuggestionsMultiple(SpellCheckerSession.java:221)
01-01 04:59:23.507 W/System.err( 1415): at android.view.textservice.SpellCheckerSession.access$100(SpellCheckerSession.java:86)
01-01 04:59:23.507 W/System.err( 1415): at android.view.textservice.SpellCheckerSession$1.handleMessage(SpellCheckerSession.java:116)
01-01 04:59:23.507 W/System.err( 1415): at android.os.Handler.dispatchMessage(Handler.java:110)
01-01 04:59:23.508 W/System.err( 1415): at android.os.Looper.loop(Looper.java:193)
01-01 04:59:23.508 W/System.err( 1415): at android.app.ActivityThread.main(ActivityThread.java:5299)
01-01 04:59:23.508 W/System.err( 1415): at java.lang.reflect.Method.invokeNative(Native Method)
01-01 04:59:23.508 W/System.err( 1415): at java.lang.reflect.Method.invoke(Method.java:515)
01-01 04:59:23.509 W/System.err( 1415): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:825)
01-01 04:59:23.511 W/System.err( 1415): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:641)
01-01 04:59:23.511 W/System.err( 1415): at dalvik.system.NativeStart.main(Native Method)
SpellChecker/SpellCheckerSession/TextServicesManager/SpellCheckerService/TextServicesManagerService 之间的关系
SpellChecker的主要工作是将自己作为callback,注册到新建的SpellCheckerSession中去,它实现了SpellCheckerSessionListener
在SpellChecker中遇到需要分析的单词,使用SpellCheckerSession来异步的获取SuggestionsInfo,通过callback中获取结果然后传递给Editor最总显示到界面上去
SpellCheckerSession通过TextServicesManager来获取(同时注册SpellChecker作为callback),这个过程没有IPC发生;
SpellCheckerSession实际上是一个Wrapper,由SpellCheckerSessionListenerImpl来负责具体的工作,而其中包含一个ISpellCheckerSession,
工作实际上又是由ISpellCheckerSession进行处理的,ISpellCheckerSession需要IPC来进行初始化。
SpellCheckerSessionListenerImpl实现ISpellCheckerSessionListener,根据dumpStack即是SpellCheckerSessionListenerImpl的方法被调用
最终SpellChecker的callback被调用。
InternalListener实现了ITextServicesSessionListener并将SpellCheckerSessionListenerImpl包含在其中,ISpellCheckerSession的初始化就由它来做。<<- initialize here
而具体过程在TextServicesManager中
TextServicesManager有以下作用
* The text services manager as expressed by this class
* is the central point of the system that manages interaction between all
* other parts. It is expressed as the client-side API here which exists
* in each application context and communicates with a global system service
* that manages the interaction across all processes.
* A text service implements a particular
* interaction model allowing the client application to retrieve information of text.
* The system binds to the current text service that is in use, causing it to be created and run.
* <li> Multiple <strong>client applications</strong> arbitrate with the text service
* manager for connections to text services.
*
* <h3>Text services sessions</h3>
* <ul>
* <li>The <strong>spell checker session</strong> is one of the text services.
private static ITextServicesManager sService;
...
private TextServicesManager() {
if (sService == null) {
IBinder b = ServiceManager.getService(Context.TEXT_SERVICES_MANAGER_SERVICE);
sService = ITextServicesManager.Stub.asInterface(b);
}
}
...
final SpellCheckerSession session = new SpellCheckerSession(
sci, sService, listener, subtypeInUse);
try {
sService.getSpellCheckerService(sci.getId(), subtypeInUse.getLocale(),
session.getTextServicesSessionListener(),
session.getSpellCheckerSessionListener(), bundle);
} catch (RemoteException e) {
return null;
}
所以ITextServicesManager就是frameworks/base/services/java/com/android/server/TextServicesManagerService.java
这里看到getSpellCheckerService是IPC,所以session.getTextServicesSessionListener()和session.getSpellCheckerSessionListener()
就对应你看到ITextServicesSessionListener mInternalListener和ISpellCheckerSessionListener mSpellCheckerSessionListenerImpl都是IPC
@Override
public void getSpellCheckerService(String sciId, String locale,
ITextServicesSessionListener tsListener, ISpellCheckerSessionListener scListener,
Bundle bundle) {
if (!calledFromValidUser()) {
return;
}
if (!mSystemReady) {
return;
}
if (TextUtils.isEmpty(sciId) || tsListener == null || scListener == null) {
Slog.e(TAG, "getSpellCheckerService: Invalid input.");
return;
}
synchronized(mSpellCheckerMap) {
if (!mSpellCheckerMap.containsKey(sciId)) {
return;
}
final SpellCheckerInfo sci = mSpellCheckerMap.get(sciId);
final int uid = Binder.getCallingUid();
if (mSpellCheckerBindGroups.containsKey(sciId)) {
final SpellCheckerBindGroup bindGroup = mSpellCheckerBindGroups.get(sciId);
if (bindGroup != null) {
final InternalDeathRecipient recipient =
mSpellCheckerBindGroups.get(sciId).addListener(
tsListener, locale, scListener, uid, bundle);
if (recipient == null) {
if (DBG) {
Slog.w(TAG, "Didn't create a death recipient.");
}
return;
}
if (bindGroup.mSpellChecker == null & bindGroup.mConnected) {
Slog.e(TAG, "The state of the spell checker bind group is illegal.");
bindGroup.removeAll();
} else if (bindGroup.mSpellChecker != null) {
if (DBG) {
Slog.w(TAG, "Existing bind found. Return a spell checker session now. "
+ "Listeners count = " + bindGroup.mListeners.size());
}
try {
final ISpellCheckerSession session =
bindGroup.mSpellChecker.getISpellCheckerSession( <<- 针对mSpellCheckerBindGroups能找到对应IME Spell Checker服务,就从缓存中获取
recipient.mScLocale, recipient.mScListener, bundle);
if (session != null) {
tsListener.onServiceConnected(session); <<- 针对mSpellCheckerBindGroups能找到对应IME Spell Checker服务,同时去初始化SpellCheckerSession中的mISpellCheckerSession
return;
} else {
if (DBG) {
Slog.w(TAG, "Existing bind already expired. ");
}
bindGroup.removeAll();
}
} catch (RemoteException e) {
Slog.e(TAG, "Exception in getting spell checker session: " + e);
bindGroup.removeAll();
}
}
}
}
final long ident = Binder.clearCallingIdentity();
try {
startSpellCheckerServiceInnerLocked( <<- 针对mSpellCheckerBindGroups还没有的情况,要进行bind IME Spell Checker服务
sci, locale, tsListener, scListener, uid, bundle);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
return;
}
针对mSpellCheckerBindGroups能找到对应IME Spell Checker服务,调用顺序是:
-----------------------------------------------------------------
tsListener.onServiceConnected(session) -> tsListener实际是mInternalListener -> mParentSpellCheckerSessionListenerImpl.onServiceConnected(session) ->
mSpellCheckerSessionListenerImpl.onServiceConnected(session) -> mISpellCheckerSession被初始化,mThread线程启动,mAsyncHandler运行在mThread线程中
W/TextServicesManagerService( 703): Start spell checker session inner locked.
W/TextServicesManagerService( 703): bind service: com.android.inputmethod.latin/.spellcheck.AndroidSpellCheckerService
W/SpellCheckerService( 880): onBind
W/TextServicesManagerService( 703): onServiceConnected: ComponentInfo{com.android.inputmethod.latin/com.android.inputmethod.latin.spellcheck.AndroidSpellCheckerService}
-----------------------------------------------------------------
IME的Spell Checker在被onBind后会返回一个SpellCheckerServiceBinder,通过它可以获得IME那边对应的ISpellCheckerSession,最终SpellCheckerSession中的mISpellCheckerSession就初始化完成了;
具体如下:
startSpellCheckerServiceInnerLocked -> InternalServiceConnection.onServiceConnected -> InternalServiceConnection.onServiceConnectedInnerLocked -> SpellCheckerBindGroup.onServiceConnected -> ITextServicesSessionListener.onServiceConnected(ISpellCheckerService session) -> 然后就同上面的调用顺序一直了,最终mISpellCheckerSession被初始化,mThread线程启动,mAsyncHandler运行在mThread线程中
SpellCheckerService是一个spell checker的抽象类,每一个IME中都应该有一自己的Spell Checker来实现它,然后在上面的代码中被onbind到TextServicesManagerService中去;使用哪个IME的Spell Checker是在Settings-》Language-》Spell Checker中去选择的,不是说换一个IME然后Spell Checker就自己跟着变,需要设置;但是如果不配套的话可能有问题。
向IME Spell Checker服务注册ISpellCheckerSessionListener的过程:
IME的Spell Checker在被onBind后会返回一个SpellCheckerServiceBinder -> TextServicesManagerService.InternalServiceConnection.onServiceConnected -> InternalServiceConnection.onServiceConnectedInnerLocked -> SpellCheckerBindGroup.onServiceConnected -> 将ISpellCheckerSessionListener注册过去,即SpellCheckerSession中的SpellCheckerSessionListenerImpl