diff options
Diffstat (limited to 'services/java/com/android/server/TextServicesManagerService.java')
-rw-r--r-- | services/java/com/android/server/TextServicesManagerService.java | 192 |
1 files changed, 151 insertions, 41 deletions
diff --git a/services/java/com/android/server/TextServicesManagerService.java b/services/java/com/android/server/TextServicesManagerService.java index 3e76a3a..837778e 100644 --- a/services/java/com/android/server/TextServicesManagerService.java +++ b/services/java/com/android/server/TextServicesManagerService.java @@ -30,6 +30,7 @@ import android.content.ServiceConnection; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; +import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; import android.os.SystemClock; @@ -72,6 +73,16 @@ public class TextServicesManagerService extends ITextServicesManager.Stub { synchronized (mSpellCheckerMap) { buildSpellCheckerMapLocked(context, mSpellCheckerList, mSpellCheckerMap); } + SpellCheckerInfo sci = getCurrentSpellChecker(null); + if (sci == null) { + sci = findAvailSpellCheckerLocked(null, null); + if (sci != null) { + // Set the current spell checker if there is one or more spell checkers + // available. In this case, "sci" is the first one in the available spell + // checkers. + setCurrentSpellCheckerLocked(sci); + } + } } private class TextServicesMonitor extends PackageMonitor { @@ -86,10 +97,10 @@ public class TextServicesManagerService extends ITextServicesManager.Stub { final int change = isPackageDisappearing(packageName); if (change == PACKAGE_PERMANENT_CHANGE || change == PACKAGE_TEMPORARY_CHANGE) { // Package disappearing - setCurrentSpellChecker(findAvailSpellCheckerLocked(null, packageName)); + setCurrentSpellCheckerLocked(findAvailSpellCheckerLocked(null, packageName)); } else if (isPackageModified(packageName)) { // Package modified - setCurrentSpellChecker(findAvailSpellCheckerLocked(null, packageName)); + setCurrentSpellCheckerLocked(findAvailSpellCheckerLocked(null, packageName)); } } } @@ -159,13 +170,7 @@ public class TextServicesManagerService extends ITextServicesManager.Stub { Slog.w(TAG, "getCurrentSpellChecker: " + curSpellCheckerId); } if (TextUtils.isEmpty(curSpellCheckerId)) { - final SpellCheckerInfo sci = findAvailSpellCheckerLocked(null, null); - if (sci == null) return null; - // Set the current spell checker if there is one or more spell checkers - // available. In this case, "sci" is the first one in the available spell - // checkers. - setCurrentSpellChecker(sci); - return sci; + return null; } return mSpellCheckerMap.get(curSpellCheckerId); } @@ -177,7 +182,7 @@ public class TextServicesManagerService extends ITextServicesManager.Stub { if (!mSystemReady) { return; } - if (info == null || tsListener == null) { + if (info == null || tsListener == null || scListener == null) { Slog.e(TAG, "getSpellCheckerService: Invalid input."); return; } @@ -186,25 +191,80 @@ public class TextServicesManagerService extends ITextServicesManager.Stub { if (!mSpellCheckerMap.containsKey(sciId)) { return; } + final int uid = Binder.getCallingUid(); if (mSpellCheckerBindGroups.containsKey(sciId)) { - mSpellCheckerBindGroups.get(sciId).addListener(tsListener, locale, scListener); - return; + final SpellCheckerBindGroup bindGroup = mSpellCheckerBindGroups.get(sciId); + if (bindGroup != null) { + final InternalDeathRecipient recipient = + mSpellCheckerBindGroups.get(sciId).addListener( + tsListener, locale, scListener, uid); + 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( + recipient.mScLocale, recipient.mScListener); + if (session != null) { + tsListener.onServiceConnected(session); + 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 InternalServiceConnection connection = new InternalServiceConnection( - sciId, locale, scListener); - final Intent serviceIntent = new Intent(SpellCheckerService.SERVICE_INTERFACE); - serviceIntent.setComponent(info.getComponent()); - if (!mContext.bindService(serviceIntent, connection, Context.BIND_AUTO_CREATE)) { - Slog.e(TAG, "Failed to get a spell checker service."); - return; + final long ident = Binder.clearCallingIdentity(); + try { + startSpellCheckerServiceInnerLocked(info, locale, tsListener, scListener, uid); + } finally { + Binder.restoreCallingIdentity(ident); } - final SpellCheckerBindGroup group = new SpellCheckerBindGroup( - connection, tsListener, locale, scListener); - mSpellCheckerBindGroups.put(sciId, group); } return; } + private void startSpellCheckerServiceInnerLocked(SpellCheckerInfo info, String locale, + ITextServicesSessionListener tsListener, ISpellCheckerSessionListener scListener, + int uid) { + if (DBG) { + Slog.w(TAG, "Start spell checker session inner locked."); + } + final String sciId = info.getId(); + final InternalServiceConnection connection = new InternalServiceConnection( + sciId, locale, scListener); + final Intent serviceIntent = new Intent(SpellCheckerService.SERVICE_INTERFACE); + serviceIntent.setComponent(info.getComponent()); + if (DBG) { + Slog.w(TAG, "bind service: " + info.getId()); + } + if (!mContext.bindService(serviceIntent, connection, Context.BIND_AUTO_CREATE)) { + Slog.e(TAG, "Failed to get a spell checker service."); + return; + } + final SpellCheckerBindGroup group = new SpellCheckerBindGroup( + connection, tsListener, locale, scListener, uid); + mSpellCheckerBindGroups.put(sciId, group); + } + @Override public SpellCheckerInfo[] getEnabledSpellCheckers() { if (DBG) { @@ -229,28 +289,51 @@ public class TextServicesManagerService extends ITextServicesManager.Stub { } } - private void setCurrentSpellChecker(SpellCheckerInfo sci) { + @Override + public void setCurrentSpellChecker(SpellCheckerInfo sci) { + synchronized(mSpellCheckerMap) { + if (mContext.checkCallingOrSelfPermission( + android.Manifest.permission.WRITE_SECURE_SETTINGS) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException( + "Requires permission " + + android.Manifest.permission.WRITE_SECURE_SETTINGS); + } + setCurrentSpellCheckerLocked(sci); + } + } + + private void setCurrentSpellCheckerLocked(SpellCheckerInfo sci) { if (DBG) { Slog.w(TAG, "setCurrentSpellChecker: " + sci.getId()); } - if (sci == null || mSpellCheckerMap.containsKey(sci.getId())) return; - Settings.Secure.putString(mContext.getContentResolver(), - Settings.Secure.SPELL_CHECKER_SERVICE, sci == null ? "" : sci.getId()); + if (sci == null || !mSpellCheckerMap.containsKey(sci.getId())) return; + final long ident = Binder.clearCallingIdentity(); + try { + Settings.Secure.putString(mContext.getContentResolver(), + Settings.Secure.SPELL_CHECKER_SERVICE, sci == null ? "" : sci.getId()); + } finally { + Binder.restoreCallingIdentity(ident); + } } // SpellCheckerBindGroup contains active text service session listeners. // If there are no listeners anymore, the SpellCheckerBindGroup instance will be removed from // mSpellCheckerBindGroups private class SpellCheckerBindGroup { - final InternalServiceConnection mInternalConnection; - final ArrayList<InternalDeathRecipient> mListeners = + private final String TAG = SpellCheckerBindGroup.class.getSimpleName(); + private final InternalServiceConnection mInternalConnection; + private final ArrayList<InternalDeathRecipient> mListeners = new ArrayList<InternalDeathRecipient>(); + public ISpellCheckerService mSpellChecker; + public boolean mConnected; public SpellCheckerBindGroup(InternalServiceConnection connection, ITextServicesSessionListener listener, String locale, - ISpellCheckerSessionListener scListener) { + ISpellCheckerSessionListener scListener, int uid) { mInternalConnection = connection; - addListener(listener, locale, scListener); + mConnected = false; + addListener(listener, locale, scListener, uid); } public void onServiceConnected(ISpellCheckerService spellChecker) { @@ -264,40 +347,46 @@ public class TextServicesManagerService extends ITextServicesManager.Stub { listener.mScLocale, listener.mScListener); listener.mTsListener.onServiceConnected(session); } catch (RemoteException e) { + Slog.e(TAG, "Exception in getting the spell checker session: " + e); + removeAll(); + return; } } + mSpellChecker = spellChecker; + mConnected = true; } } - public void addListener(ITextServicesSessionListener tsListener, String locale, - ISpellCheckerSessionListener scListener) { + public InternalDeathRecipient addListener(ITextServicesSessionListener tsListener, + String locale, ISpellCheckerSessionListener scListener, int uid) { if (DBG) { Slog.d(TAG, "addListener: " + locale); } + InternalDeathRecipient recipient = null; synchronized(mSpellCheckerMap) { try { final int size = mListeners.size(); for (int i = 0; i < size; ++i) { if (mListeners.get(i).hasSpellCheckerListener(scListener)) { // do not add the lister if the group already contains this. - return; + return null; } } - final InternalDeathRecipient recipient = new InternalDeathRecipient( - this, tsListener, locale, scListener); + recipient = new InternalDeathRecipient( + this, tsListener, locale, scListener, uid); scListener.asBinder().linkToDeath(recipient, 0); - mListeners.add(new InternalDeathRecipient( - this, tsListener, locale, scListener)); + mListeners.add(recipient); } catch(RemoteException e) { // do nothing } cleanLocked(); } + return recipient; } public void removeListener(ISpellCheckerSessionListener listener) { if (DBG) { - Slog.d(TAG, "remove listener"); + Slog.w(TAG, "remove listener: " + listener.hashCode()); } synchronized(mSpellCheckerMap) { final int size = mListeners.size(); @@ -306,11 +395,17 @@ public class TextServicesManagerService extends ITextServicesManager.Stub { for (int i = 0; i < size; ++i) { final InternalDeathRecipient tempRecipient = mListeners.get(i); if(tempRecipient.hasSpellCheckerListener(listener)) { + if (DBG) { + Slog.w(TAG, "found existing listener."); + } removeList.add(tempRecipient); } } final int removeSize = removeList.size(); for (int i = 0; i < removeSize; ++i) { + if (DBG) { + Slog.w(TAG, "Remove " + removeList.get(i)); + } mListeners.remove(removeList.get(i)); } cleanLocked(); @@ -322,11 +417,21 @@ public class TextServicesManagerService extends ITextServicesManager.Stub { Slog.d(TAG, "cleanLocked"); } if (mListeners.isEmpty()) { - mSpellCheckerBindGroups.remove(this); + if (mSpellCheckerBindGroups.containsKey(this)) { + mSpellCheckerBindGroups.remove(this); + } // Unbind service when there is no active clients. mContext.unbindService(mInternalConnection); } } + + public void removeAll() { + Slog.e(TAG, "Remove the spell checker bind unexpectedly."); + synchronized(mSpellCheckerMap) { + mListeners.clear(); + cleanLocked(); + } + } } private class InternalServiceConnection implements ServiceConnection { @@ -343,6 +448,9 @@ public class TextServicesManagerService extends ITextServicesManager.Stub { @Override public void onServiceConnected(ComponentName name, IBinder service) { synchronized(mSpellCheckerMap) { + if (DBG) { + Slog.w(TAG, "onServiceConnected: " + name); + } ISpellCheckerService spellChecker = ISpellCheckerService.Stub.asInterface(service); final SpellCheckerBindGroup group = mSpellCheckerBindGroups.get(mSciId); if (group != null) { @@ -362,17 +470,19 @@ public class TextServicesManagerService extends ITextServicesManager.Stub { public final ISpellCheckerSessionListener mScListener; public final String mScLocale; private final SpellCheckerBindGroup mGroup; + public final int mUid; public InternalDeathRecipient(SpellCheckerBindGroup group, ITextServicesSessionListener tsListener, String scLocale, - ISpellCheckerSessionListener scListener) { + ISpellCheckerSessionListener scListener, int uid) { mTsListener = tsListener; mScListener = scListener; mScLocale = scLocale; mGroup = group; + mUid = uid; } public boolean hasSpellCheckerListener(ISpellCheckerSessionListener listener) { - return mScListener.equals(listener); + return listener.asBinder().equals(mScListener.asBinder()); } @Override |