4343import android .view .textservice .SpellCheckerInfo ;
4444import android .view .textservice .SpellCheckerSubtype ;
4545
46+ import java .io .FileDescriptor ;
4647import java .io .IOException ;
48+ import java .io .PrintWriter ;
4749import java .util .ArrayList ;
4850import java .util .HashMap ;
4951import java .util .List ;
52+ import java .util .Map ;
5053
5154public class TextServicesManagerService extends ITextServicesManager .Stub {
5255 private static final String TAG = TextServicesManagerService .class .getSimpleName ();
@@ -480,6 +483,66 @@ private boolean isSpellCheckerEnabledLocked() {
480483 }
481484 }
482485
486+ @ Override
487+ protected void dump (FileDescriptor fd , PrintWriter pw , String [] args ) {
488+ if (mContext .checkCallingOrSelfPermission (android .Manifest .permission .DUMP )
489+ != PackageManager .PERMISSION_GRANTED ) {
490+
491+ pw .println ("Permission Denial: can't dump TextServicesManagerService from from pid="
492+ + Binder .getCallingPid ()
493+ + ", uid=" + Binder .getCallingUid ());
494+ return ;
495+ }
496+
497+ synchronized (mSpellCheckerMap ) {
498+ pw .println ("Current Text Services Manager state:" );
499+ pw .println (" Spell Checker Map:" );
500+ for (Map .Entry <String , SpellCheckerInfo > ent : mSpellCheckerMap .entrySet ()) {
501+ pw .print (" " ); pw .print (ent .getKey ()); pw .println (":" );
502+ SpellCheckerInfo info = ent .getValue ();
503+ pw .print (" " ); pw .print ("id=" ); pw .println (info .getId ());
504+ pw .print (" " ); pw .print ("comp=" );
505+ pw .println (info .getComponent ().toShortString ());
506+ int NS = info .getSubtypeCount ();
507+ for (int i =0 ; i <NS ; i ++) {
508+ SpellCheckerSubtype st = info .getSubtypeAt (i );
509+ pw .print (" " ); pw .print ("Subtype #" ); pw .print (i ); pw .println (":" );
510+ pw .print (" " ); pw .print ("locale=" ); pw .println (st .getLocale ());
511+ pw .print (" " ); pw .print ("extraValue=" );
512+ pw .println (st .getExtraValue ());
513+ }
514+ }
515+ pw .println ("" );
516+ pw .println (" Spell Checker Bind Groups:" );
517+ for (Map .Entry <String , SpellCheckerBindGroup > ent
518+ : mSpellCheckerBindGroups .entrySet ()) {
519+ SpellCheckerBindGroup grp = ent .getValue ();
520+ pw .print (" " ); pw .print (ent .getKey ()); pw .print (" " );
521+ pw .print (grp ); pw .println (":" );
522+ pw .print (" " ); pw .print ("mInternalConnection=" );
523+ pw .println (grp .mInternalConnection );
524+ pw .print (" " ); pw .print ("mSpellChecker=" );
525+ pw .println (grp .mSpellChecker );
526+ pw .print (" " ); pw .print ("mBound=" ); pw .print (grp .mBound );
527+ pw .print (" mConnected=" ); pw .println (grp .mConnected );
528+ int NL = grp .mListeners .size ();
529+ for (int i =0 ; i <NL ; i ++) {
530+ InternalDeathRecipient listener = grp .mListeners .get (i );
531+ pw .print (" " ); pw .print ("Listener #" ); pw .print (i ); pw .println (":" );
532+ pw .print (" " ); pw .print ("mTsListener=" );
533+ pw .println (listener .mTsListener );
534+ pw .print (" " ); pw .print ("mScListener=" );
535+ pw .println (listener .mScListener );
536+ pw .print (" " ); pw .print ("mGroup=" );
537+ pw .println (listener .mGroup );
538+ pw .print (" " ); pw .print ("mScLocale=" );
539+ pw .print (listener .mScLocale );
540+ pw .print (" mUid=" ); pw .println (listener .mUid );
541+ }
542+ }
543+ }
544+ }
545+
483546 // SpellCheckerBindGroup contains active text service session listeners.
484547 // If there are no listeners anymore, the SpellCheckerBindGroup instance will be removed from
485548 // mSpellCheckerBindGroups
@@ -488,13 +551,15 @@ private class SpellCheckerBindGroup {
488551 private final InternalServiceConnection mInternalConnection ;
489552 private final ArrayList <InternalDeathRecipient > mListeners =
490553 new ArrayList <InternalDeathRecipient >();
554+ public boolean mBound ;
491555 public ISpellCheckerService mSpellChecker ;
492556 public boolean mConnected ;
493557
494558 public SpellCheckerBindGroup (InternalServiceConnection connection ,
495559 ITextServicesSessionListener listener , String locale ,
496560 ISpellCheckerSessionListener scListener , int uid , Bundle bundle ) {
497561 mInternalConnection = connection ;
562+ mBound = true ;
498563 mConnected = false ;
499564 addListener (listener , locale , scListener , uid , bundle );
500565 }
@@ -580,15 +645,18 @@ private void cleanLocked() {
580645 if (DBG ) {
581646 Slog .d (TAG , "cleanLocked" );
582647 }
583- if (mListeners .isEmpty ()) {
648+ // If there are no more active listeners, clean up. Only do this
649+ // once.
650+ if (mBound && mListeners .isEmpty ()) {
651+ mBound = false ;
584652 final String sciId = mInternalConnection .mSciId ;
585- if (mSpellCheckerBindGroups .containsKey (sciId )) {
653+ SpellCheckerBindGroup cur = mSpellCheckerBindGroups .get (sciId );
654+ if (cur == this ) {
586655 if (DBG ) {
587656 Slog .d (TAG , "Remove bind group." );
588657 }
589658 mSpellCheckerBindGroups .remove (sciId );
590659 }
591- // Unbind service when there is no active clients.
592660 mContext .unbindService (mInternalConnection );
593661 }
594662 }
@@ -623,15 +691,20 @@ public void onServiceConnected(ComponentName name, IBinder service) {
623691 }
624692 ISpellCheckerService spellChecker = ISpellCheckerService .Stub .asInterface (service );
625693 final SpellCheckerBindGroup group = mSpellCheckerBindGroups .get (mSciId );
626- if (group != null ) {
694+ if (this == group . mInternalConnection ) {
627695 group .onServiceConnected (spellChecker );
628696 }
629697 }
630698 }
631699
632700 @ Override
633701 public void onServiceDisconnected (ComponentName name ) {
634- mSpellCheckerBindGroups .remove (mSciId );
702+ synchronized (mSpellCheckerMap ) {
703+ final SpellCheckerBindGroup group = mSpellCheckerBindGroups .get (mSciId );
704+ if (this == group .mInternalConnection ) {
705+ mSpellCheckerBindGroups .remove (mSciId );
706+ }
707+ }
635708 }
636709 }
637710
0 commit comments