am 22cbf54c: Merge "Conditionally allow non-primay profiles to use TextServices" into lmp-mr1-dev
* commit '22cbf54ca0c64344cd28590446a02e521ca914f7':
Conditionally allow non-primay profiles to use TextServices
diff --git a/services/core/java/com/android/server/TextServicesManagerService.java b/services/core/java/com/android/server/TextServicesManagerService.java
index d4c436f..5add88e 100644
--- a/services/core/java/com/android/server/TextServicesManagerService.java
+++ b/services/core/java/com/android/server/TextServicesManagerService.java
@@ -16,6 +16,7 @@
package com.android.server;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.content.PackageMonitor;
import com.android.internal.textservice.ISpellCheckerService;
import com.android.internal.textservice.ISpellCheckerSession;
@@ -28,14 +29,18 @@
import android.app.ActivityManagerNative;
import android.app.AppGlobals;
import android.app.IUserSwitchObserver;
+import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.ServiceConnection;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
+import android.content.pm.UserInfo;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
@@ -43,6 +48,7 @@
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.os.UserManager;
import android.provider.Settings;
import android.service.textservice.SpellCheckerService;
import android.text.TextUtils;
@@ -84,6 +90,12 @@
public TextServicesManagerService(Context context) {
mSystemReady = false;
mContext = context;
+
+ final IntentFilter broadcastFilter = new IntentFilter();
+ broadcastFilter.addAction(Intent.ACTION_USER_ADDED);
+ broadcastFilter.addAction(Intent.ACTION_USER_REMOVED);
+ mContext.registerReceiver(new TextServicesBroadcastReceiver(), broadcastFilter);
+
int userId = UserHandle.USER_OWNER;
try {
ActivityManagerNative.getDefault().registerUserSwitchObserver(
@@ -119,6 +131,7 @@
private void switchUserLocked(int userId) {
mSettings.setCurrentUserId(userId);
+ updateCurrentProfileIds();
unbindServiceLocked();
buildSpellCheckerMapLocked(mContext, mSpellCheckerList, mSpellCheckerMap, mSettings);
SpellCheckerInfo sci = getCurrentSpellChecker(null);
@@ -133,6 +146,16 @@
}
}
+ void updateCurrentProfileIds() {
+ List<UserInfo> profiles =
+ UserManager.get(mContext).getProfiles(mSettings.getCurrentUserId());
+ int[] currentProfileIds = new int[profiles.size()]; // profiles will not be null
+ for (int i = 0; i < currentProfileIds.length; i++) {
+ currentProfileIds[i] = profiles.get(i).id;
+ }
+ mSettings.setCurrentProfileIds(currentProfileIds);
+ }
+
private class TextServicesMonitor extends PackageMonitor {
private boolean isChangingPackagesOfCurrentUser() {
final int userId = getChangingUserId();
@@ -171,6 +194,19 @@
}
}
+ class TextServicesBroadcastReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ if (Intent.ACTION_USER_ADDED.equals(action)
+ || Intent.ACTION_USER_REMOVED.equals(action)) {
+ updateCurrentProfileIds();
+ return;
+ }
+ Slog.w(TAG, "Unexpected intent " + intent);
+ }
+ }
+
private static void buildSpellCheckerMapLocked(Context context,
ArrayList<SpellCheckerInfo> list, HashMap<String, SpellCheckerInfo> map,
TextServicesSettings settings) {
@@ -223,7 +259,7 @@
Slog.d(TAG, "--- calledFromForegroundUserOrSystemProcess ? "
+ "calling uid = " + uid + " system uid = " + Process.SYSTEM_UID
+ " calling userId = " + userId + ", foreground user id = "
- + mSettings.getCurrentUserId());
+ + mSettings.getCurrentUserId() + ", calling pid = " + Binder.getCallingPid());
try {
final String[] packageNames = AppGlobals.getPackageManager().getPackagesForUid(uid);
for (int i = 0; i < packageNames.length; ++i) {
@@ -237,10 +273,40 @@
if (uid == Process.SYSTEM_UID || userId == mSettings.getCurrentUserId()) {
return true;
- } else {
- Slog.w(TAG, "--- IPC called from background users. Ignore. \n" + getStackTrace());
- return false;
}
+
+ // Permits current profile to use TSFM as long as the current text service is the system's
+ // one. This is a tentative solution and should be replaced with fully functional multiuser
+ // support.
+ // TODO: Implement multiuser support in TSMS.
+ final boolean isCurrentProfile = mSettings.isCurrentProfile(userId);
+ if (DBG) {
+ Slog.d(TAG, "--- userId = "+ userId + " isCurrentProfile = " + isCurrentProfile);
+ }
+ if (mSettings.isCurrentProfile(userId)) {
+ final SpellCheckerInfo spellCheckerInfo = getCurrentSpellCheckerWithoutVerification();
+ if (spellCheckerInfo != null) {
+ final ServiceInfo serviceInfo = spellCheckerInfo.getServiceInfo();
+ final boolean isSystemSpellChecker =
+ (serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+ if (DBG) {
+ Slog.d(TAG, "--- current spell checker = "+ spellCheckerInfo.getPackageName()
+ + " isSystem = " + isSystemSpellChecker);
+ }
+ if (isSystemSpellChecker) {
+ return true;
+ }
+ }
+ }
+
+ // Unlike InputMethodManagerService#calledFromValidUser, INTERACT_ACROSS_USERS_FULL isn't
+ // taken into account here. Anyway this method is supposed to be removed once multiuser
+ // support is implemented.
+ if (DBG) {
+ Slog.d(TAG, "--- IPC from userId:" + userId + " is being ignored. \n"
+ + getStackTrace());
+ }
+ return false;
}
private boolean bindCurrentSpellCheckerService(
@@ -292,6 +358,10 @@
if (!calledFromValidUser()) {
return null;
}
+ return getCurrentSpellCheckerWithoutVerification();
+ }
+
+ private SpellCheckerInfo getCurrentSpellCheckerWithoutVerification() {
synchronized (mSpellCheckerMap) {
final String curSpellCheckerId = mSettings.getSelectedSpellChecker();
if (DBG) {
@@ -914,6 +984,10 @@
private static class TextServicesSettings {
private final ContentResolver mResolver;
private int mCurrentUserId;
+ @GuardedBy("mLock")
+ private int[] mCurrentProfileIds = new int[0];
+ private Object mLock = new Object();
+
public TextServicesSettings(ContentResolver resolver, int userId) {
mResolver = resolver;
mCurrentUserId = userId;
@@ -928,6 +1002,22 @@
mCurrentUserId = userId;
}
+ public void setCurrentProfileIds(int[] currentProfileIds) {
+ synchronized (mLock) {
+ mCurrentProfileIds = currentProfileIds;
+ }
+ }
+
+ public boolean isCurrentProfile(int userId) {
+ synchronized (mLock) {
+ if (userId == mCurrentUserId) return true;
+ for (int i = 0; i < mCurrentProfileIds.length; i++) {
+ if (userId == mCurrentProfileIds[i]) return true;
+ }
+ return false;
+ }
+ }
+
public int getCurrentUserId() {
return mCurrentUserId;
}