diff --git a/core/java/android/view/textservice/TextServicesManager.java b/core/java/android/view/textservice/TextServicesManager.java
index e31eabb083e51..0b63c179d0420 100644
--- a/core/java/android/view/textservice/TextServicesManager.java
+++ b/core/java/android/view/textservice/TextServicesManager.java
@@ -303,6 +303,10 @@ public final class TextServicesManager {
/**
* Retrieve the list of currently enabled spell checkers.
*
+ *
Note: The results are filtered by the rules of
+ * package visibility, except for
+ * the currently active spell checker.
+ *
* @return The list of currently enabled spell checkers.
*/
@UserHandleAware
diff --git a/services/core/java/com/android/server/textservices/TextServicesManagerService.java b/services/core/java/com/android/server/textservices/TextServicesManagerService.java
index cd2b8943ce117..8431f1cc0b4cb 100644
--- a/services/core/java/com/android/server/textservices/TextServicesManagerService.java
+++ b/services/core/java/com/android/server/textservices/TextServicesManagerService.java
@@ -28,6 +28,7 @@ import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.UserInfo;
@@ -583,10 +584,17 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
return;
}
final SpellCheckerInfo sci = spellCheckerMap.get(sciId);
+ final int uid = Binder.getCallingUid();
+ if (!canCallerAccessSpellChecker(sci, uid, userId)) {
+ if (DBG) {
+ Slog.d(TAG, "Spell checker " + sci.getId()
+ + " is not visible to the caller " + uid);
+ }
+ return;
+ }
HashMap spellCheckerBindGroups =
tsd.mSpellCheckerBindGroups;
SpellCheckerBindGroup bindGroup = spellCheckerBindGroups.get(sciId);
- final int uid = Binder.getCallingUid();
if (bindGroup == null) {
final long ident = Binder.clearCallingIdentity();
try {
@@ -649,20 +657,28 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
public SpellCheckerInfo[] getEnabledSpellCheckers(@UserIdInt int userId) {
verifyUser(userId);
+ final ArrayList spellCheckerList;
synchronized (mLock) {
final TextServicesData tsd = getDataFromCallingUserIdLocked(userId);
if (tsd == null) return null;
- ArrayList spellCheckerList = tsd.mSpellCheckerList;
- if (DBG) {
- Slog.d(TAG, "getEnabledSpellCheckers: " + spellCheckerList.size());
- for (int i = 0; i < spellCheckerList.size(); ++i) {
- Slog.d(TAG,
- "EnabledSpellCheckers: " + spellCheckerList.get(i).getPackageName());
- }
- }
- return spellCheckerList.toArray(new SpellCheckerInfo[spellCheckerList.size()]);
+ spellCheckerList = new ArrayList<>(tsd.mSpellCheckerList);
}
+ int size = spellCheckerList.size();
+ final int callingUid = Binder.getCallingUid();
+ for (int i = size - 1; i >= 0; i--) {
+ if (canCallerAccessSpellChecker(spellCheckerList.get(i), callingUid, userId)) {
+ continue;
+ }
+ if (DBG) {
+ Slog.d(TAG, "Spell checker " + spellCheckerList.get(i).getPackageName()
+ + " is not visible to the caller " + callingUid);
+ }
+ spellCheckerList.remove(i);
+ }
+
+ return spellCheckerList.isEmpty() ? null
+ : spellCheckerList.toArray(new SpellCheckerInfo[spellCheckerList.size()]);
}
@Override
@@ -701,6 +717,26 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
}
}
+ /**
+ * Filter the access to spell checkers by rules of the package visibility. Return {@code true}
+ * if the given spell checker is the currently selected one or visible to the caller.
+ *
+ * @param sci The spell checker to check.
+ * @param callingUid The caller that is going to access the spell checker.
+ * @param userId The user id where the spell checker resides.
+ * @return {@code true} if caller is able to access the spell checker.
+ */
+ private boolean canCallerAccessSpellChecker(@NonNull SpellCheckerInfo sci, int callingUid,
+ @UserIdInt int userId) {
+ final SpellCheckerInfo currentSci = getCurrentSpellCheckerForUser(userId);
+ if (currentSci != null && currentSci.getId().equals(sci.getId())) {
+ return true;
+ }
+ final PackageManagerInternal pmInternal =
+ LocalServices.getService(PackageManagerInternal.class);
+ return !pmInternal.filterAppAccess(sci.getPackageName(), callingUid, userId);
+ }
+
private void setCurrentSpellCheckerLocked(@Nullable SpellCheckerInfo sci, TextServicesData tsd) {
final String sciId = (sci != null) ? sci.getId() : "";
if (DBG) {