记录frameworks SpellChecker从IME端获取单词提示的过程

部分调用栈信息:

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}


针对mSpellCheckerBindGroups还没有的情况,要进行bind IME Spell Checker服务:
-----------------------------------------------------------------
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


你可能感兴趣的:(记录frameworks SpellChecker从IME端获取单词提示的过程)