summaryrefslogtreecommitdiffstats
path: root/services/java/com/android/server/TextServicesManagerService.java
diff options
context:
space:
mode:
Diffstat (limited to 'services/java/com/android/server/TextServicesManagerService.java')
-rw-r--r--services/java/com/android/server/TextServicesManagerService.java192
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