diff options
Diffstat (limited to 'services/java/com/android/server')
17 files changed, 1113 insertions, 756 deletions
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java index 385681e..9be7045 100644 --- a/services/java/com/android/server/AppWidgetService.java +++ b/services/java/com/android/server/AppWidgetService.java @@ -16,6 +16,7 @@ package com.android.server; +import android.app.ActivityManagerNative; import android.app.AlarmManager; import android.app.PendingIntent; import android.appwidget.AppWidgetManager; @@ -27,6 +28,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.ServiceConnection; import android.content.pm.PackageManager; +import android.os.Binder; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; @@ -193,31 +195,44 @@ class AppWidgetService extends IAppWidgetService.Stub }, UserHandle.ALL, userFilter, null, null); } + private int getCallingOrCurrentUserId() { + int callingUid = Binder.getCallingUid(); + if (callingUid == android.os.Process.myUid()) { + try { + return ActivityManagerNative.getDefault().getCurrentUser().id; + } catch (RemoteException re) { + return UserHandle.getUserId(callingUid); + } + } else { + return UserHandle.getUserId(callingUid); + } + } + @Override public int allocateAppWidgetId(String packageName, int hostId) throws RemoteException { - return getImplForUser(UserHandle.getCallingUserId()).allocateAppWidgetId( + return getImplForUser(getCallingOrCurrentUserId()).allocateAppWidgetId( packageName, hostId); } @Override public void deleteAppWidgetId(int appWidgetId) throws RemoteException { - getImplForUser(UserHandle.getCallingUserId()).deleteAppWidgetId(appWidgetId); + getImplForUser(getCallingOrCurrentUserId()).deleteAppWidgetId(appWidgetId); } @Override public void deleteHost(int hostId) throws RemoteException { - getImplForUser(UserHandle.getCallingUserId()).deleteHost(hostId); + getImplForUser(getCallingOrCurrentUserId()).deleteHost(hostId); } @Override public void deleteAllHosts() throws RemoteException { - getImplForUser(UserHandle.getCallingUserId()).deleteAllHosts(); + getImplForUser(getCallingOrCurrentUserId()).deleteAllHosts(); } @Override public void bindAppWidgetId(int appWidgetId, ComponentName provider, Bundle options) throws RemoteException { - getImplForUser(UserHandle.getCallingUserId()).bindAppWidgetId(appWidgetId, provider, + getImplForUser(getCallingOrCurrentUserId()).bindAppWidgetId(appWidgetId, provider, options); } @@ -225,34 +240,34 @@ class AppWidgetService extends IAppWidgetService.Stub public boolean bindAppWidgetIdIfAllowed( String packageName, int appWidgetId, ComponentName provider, Bundle options) throws RemoteException { - return getImplForUser(UserHandle.getCallingUserId()).bindAppWidgetIdIfAllowed( + return getImplForUser(getCallingOrCurrentUserId()).bindAppWidgetIdIfAllowed( packageName, appWidgetId, provider, options); } @Override public boolean hasBindAppWidgetPermission(String packageName) throws RemoteException { - return getImplForUser(UserHandle.getCallingUserId()).hasBindAppWidgetPermission( + return getImplForUser(getCallingOrCurrentUserId()).hasBindAppWidgetPermission( packageName); } @Override public void setBindAppWidgetPermission(String packageName, boolean permission) throws RemoteException { - getImplForUser(UserHandle.getCallingUserId()).setBindAppWidgetPermission( + getImplForUser(getCallingOrCurrentUserId()).setBindAppWidgetPermission( packageName, permission); } @Override public void bindRemoteViewsService(int appWidgetId, Intent intent, IBinder connection) throws RemoteException { - getImplForUser(UserHandle.getCallingUserId()).bindRemoteViewsService( + getImplForUser(getCallingOrCurrentUserId()).bindRemoteViewsService( appWidgetId, intent, connection); } @Override public int[] startListening(IAppWidgetHost host, String packageName, int hostId, List<RemoteViews> updatedViews) throws RemoteException { - return getImplForUser(UserHandle.getCallingUserId()).startListening(host, + return getImplForUser(getCallingOrCurrentUserId()).startListening(host, packageName, hostId, updatedViews); } @@ -287,27 +302,27 @@ class AppWidgetService extends IAppWidgetService.Stub @Override public int[] getAppWidgetIds(ComponentName provider) throws RemoteException { - return getImplForUser(UserHandle.getCallingUserId()).getAppWidgetIds(provider); + return getImplForUser(getCallingOrCurrentUserId()).getAppWidgetIds(provider); } @Override public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) throws RemoteException { - return getImplForUser(UserHandle.getCallingUserId()).getAppWidgetInfo(appWidgetId); + return getImplForUser(getCallingOrCurrentUserId()).getAppWidgetInfo(appWidgetId); } @Override public RemoteViews getAppWidgetViews(int appWidgetId) throws RemoteException { - return getImplForUser(UserHandle.getCallingUserId()).getAppWidgetViews(appWidgetId); + return getImplForUser(getCallingOrCurrentUserId()).getAppWidgetViews(appWidgetId); } @Override public void updateAppWidgetOptions(int appWidgetId, Bundle options) { - getImplForUser(UserHandle.getCallingUserId()).updateAppWidgetOptions(appWidgetId, options); + getImplForUser(getCallingOrCurrentUserId()).updateAppWidgetOptions(appWidgetId, options); } @Override public Bundle getAppWidgetOptions(int appWidgetId) { - return getImplForUser(UserHandle.getCallingUserId()).getAppWidgetOptions(appWidgetId); + return getImplForUser(getCallingOrCurrentUserId()).getAppWidgetOptions(appWidgetId); } static int[] getAppWidgetIds(Provider p) { @@ -321,43 +336,43 @@ class AppWidgetService extends IAppWidgetService.Stub @Override public List<AppWidgetProviderInfo> getInstalledProviders() throws RemoteException { - return getImplForUser(UserHandle.getCallingUserId()).getInstalledProviders(); + return getImplForUser(getCallingOrCurrentUserId()).getInstalledProviders(); } @Override public void notifyAppWidgetViewDataChanged(int[] appWidgetIds, int viewId) throws RemoteException { - getImplForUser(UserHandle.getCallingUserId()).notifyAppWidgetViewDataChanged( + getImplForUser(getCallingOrCurrentUserId()).notifyAppWidgetViewDataChanged( appWidgetIds, viewId); } @Override public void partiallyUpdateAppWidgetIds(int[] appWidgetIds, RemoteViews views) throws RemoteException { - getImplForUser(UserHandle.getCallingUserId()).partiallyUpdateAppWidgetIds( + getImplForUser(getCallingOrCurrentUserId()).partiallyUpdateAppWidgetIds( appWidgetIds, views); } @Override public void stopListening(int hostId) throws RemoteException { - getImplForUser(UserHandle.getCallingUserId()).stopListening(hostId); + getImplForUser(getCallingOrCurrentUserId()).stopListening(hostId); } @Override public void unbindRemoteViewsService(int appWidgetId, Intent intent) throws RemoteException { - getImplForUser(UserHandle.getCallingUserId()).unbindRemoteViewsService( + getImplForUser(getCallingOrCurrentUserId()).unbindRemoteViewsService( appWidgetId, intent); } @Override public void updateAppWidgetIds(int[] appWidgetIds, RemoteViews views) throws RemoteException { - getImplForUser(UserHandle.getCallingUserId()).updateAppWidgetIds(appWidgetIds, views); + getImplForUser(getCallingOrCurrentUserId()).updateAppWidgetIds(appWidgetIds, views); } @Override public void updateAppWidgetProvider(ComponentName provider, RemoteViews views) throws RemoteException { - getImplForUser(UserHandle.getCallingUserId()).updateAppWidgetProvider(provider, views); + getImplForUser(getCallingOrCurrentUserId()).updateAppWidgetProvider(provider, views); } @Override diff --git a/services/java/com/android/server/AppWidgetServiceImpl.java b/services/java/com/android/server/AppWidgetServiceImpl.java index 815ee24..fcc8a06 100644 --- a/services/java/com/android/server/AppWidgetServiceImpl.java +++ b/services/java/com/android/server/AppWidgetServiceImpl.java @@ -1627,22 +1627,22 @@ class AppWidgetServiceImpl { Integer.parseInt(minWidthString, 16)); } String minHeightString = parser.getAttributeValue(null, "min_height"); - if (minWidthString != null) { + if (minHeightString != null) { options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT, Integer.parseInt(minHeightString, 16)); } - String maxWidthString = parser.getAttributeValue(null, "max_height"); - if (minWidthString != null) { + String maxWidthString = parser.getAttributeValue(null, "max_width"); + if (maxWidthString != null) { options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH, Integer.parseInt(maxWidthString, 16)); } String maxHeightString = parser.getAttributeValue(null, "max_height"); - if (minWidthString != null) { + if (maxHeightString != null) { options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT, Integer.parseInt(maxHeightString, 16)); } String categoryString = parser.getAttributeValue(null, "host_category"); - if (minWidthString != null) { + if (categoryString != null) { options.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY, Integer.parseInt(categoryString, 16)); } diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java index aec5d6e..83fa55b 100644 --- a/services/java/com/android/server/DevicePolicyManagerService.java +++ b/services/java/com/android/server/DevicePolicyManagerService.java @@ -212,8 +212,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { static final long DEF_PASSWORD_EXPIRATION_DATE = 0; long passwordExpirationDate = DEF_PASSWORD_EXPIRATION_DATE; - static final int DEF_KEYGUARD_WIDGET_DISABLED = 0; // none - int disableKeyguardWidgets = DEF_KEYGUARD_WIDGET_DISABLED; + static final int DEF_KEYGUARD_FEATURES_DISABLED = 0; // none + int disabledKeyguardFeatures = DEF_KEYGUARD_FEATURES_DISABLED; boolean encryptionRequested = false; boolean disableCamera = false; @@ -328,10 +328,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { out.attribute(null, "value", Boolean.toString(disableCamera)); out.endTag(null, "disable-camera"); } - if (disableKeyguardWidgets != DEF_KEYGUARD_WIDGET_DISABLED) { - out.startTag(null, "disable-keyguard-widgets"); - out.attribute(null, "value", Integer.toString(disableKeyguardWidgets)); - out.endTag(null, "disable-keyguard-widgets"); + if (disabledKeyguardFeatures != DEF_KEYGUARD_FEATURES_DISABLED) { + out.startTag(null, "disable-keyguard-features"); + out.attribute(null, "value", Integer.toString(disabledKeyguardFeatures)); + out.endTag(null, "disable-keyguard-features"); } } @@ -2300,18 +2300,18 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } /** - * Selectively disable keyguard widgets. + * Selectively disable keyguard features. */ - public void setKeyguardWidgetsDisabled(ComponentName who, int which, int userHandle) { + public void setKeyguardDisabledFeatures(ComponentName who, int which, int userHandle) { enforceCrossUserPermission(userHandle); synchronized (this) { if (who == null) { throw new NullPointerException("ComponentName is null"); } ActiveAdmin ap = getActiveAdminForCallerLocked(who, - DeviceAdminInfo.USES_POLICY_DISABLE_KEYGUARD_WIDGETS); - if ((ap.disableKeyguardWidgets & which) != which) { - ap.disableKeyguardWidgets |= which; + DeviceAdminInfo.USES_POLICY_DISABLE_KEYGUARD_FEATURES); + if (ap.disabledKeyguardFeatures != which) { + ap.disabledKeyguardFeatures = which; saveSettingsLocked(userHandle); } syncDeviceCapabilitiesLocked(getUserData(userHandle)); @@ -2319,24 +2319,24 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } /** - * Gets the disabled state for widgets in keyguard for the given admin, + * Gets the disabled state for features in keyguard for the given admin, * or the aggregate of all active admins if who is null. */ - public int getKeyguardWidgetsDisabled(ComponentName who, int userHandle) { + public int getKeyguardDisabledFeatures(ComponentName who, int userHandle) { enforceCrossUserPermission(userHandle); synchronized (this) { if (who != null) { ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle); - return (admin != null) ? admin.disableKeyguardWidgets : 0; + return (admin != null) ? admin.disabledKeyguardFeatures : 0; } - // Determine whether or not keyguard widgets are disabled for any active admins. + // Determine which keyguard features are disabled for any active admins. DevicePolicyData policy = getUserData(userHandle); final int N = policy.mAdminList.size(); int which = 0; for (int i = 0; i < N; i++) { ActiveAdmin admin = policy.mAdminList.get(i); - which |= admin.disableKeyguardWidgets; + which |= admin.disabledKeyguardFeatures; } return which; } diff --git a/services/java/com/android/server/IntentResolver.java b/services/java/com/android/server/IntentResolver.java index d4769e8..9b19008 100644 --- a/services/java/com/android/server/IntentResolver.java +++ b/services/java/com/android/server/IntentResolver.java @@ -46,6 +46,7 @@ public abstract class IntentResolver<F extends IntentFilter, R extends Object> { final private static String TAG = "IntentResolver"; final private static boolean DEBUG = false; final private static boolean localLOGV = DEBUG || false; + final private static boolean VALIDATE = false; public void addFilter(F f) { if (localLOGV) { @@ -67,16 +68,20 @@ public abstract class IntentResolver<F extends IntentFilter, R extends Object> { mTypedActionToFilter, " TypedAction: "); } - mOldResolver.addFilter(f); - verifyDataStructures(f); + if (VALIDATE) { + mOldResolver.addFilter(f); + verifyDataStructures(f); + } } public void removeFilter(F f) { removeFilterInternal(f); mFilters.remove(f); - mOldResolver.removeFilter(f); - verifyDataStructures(f); + if (VALIDATE) { + mOldResolver.removeFilter(f); + verifyDataStructures(f); + } } void removeFilterInternal(F f) { @@ -314,12 +319,14 @@ public abstract class IntentResolver<F extends IntentFilter, R extends Object> { } sortResults(finalList); - List<R> oldList = mOldResolver.queryIntent(intent, resolvedType, defaultOnly, userId); - if (oldList.size() != finalList.size()) { - ValidationFailure here = new ValidationFailure(); - here.fillInStackTrace(); - Log.wtf(TAG, "Query result " + intent + " size is " + finalList.size() - + "; old implementation is " + oldList.size(), here); + if (VALIDATE) { + List<R> oldList = mOldResolver.queryIntent(intent, resolvedType, defaultOnly, userId); + if (oldList.size() != finalList.size()) { + ValidationFailure here = new ValidationFailure(); + here.fillInStackTrace(); + Log.wtf(TAG, "Query result " + intent + " size is " + finalList.size() + + "; old implementation is " + oldList.size(), here); + } } if (debug) { diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java index 197f6ab..840d432 100644 --- a/services/java/com/android/server/LocationManagerService.java +++ b/services/java/com/android/server/LocationManagerService.java @@ -900,25 +900,41 @@ public class LocationManagerService extends ILocationManager.Stub implements Run return receiver; } + private boolean isProviderAllowedByCoarsePermission(String provider) { + if (LocationManager.FUSED_PROVIDER.equals(provider)) { + return true; + } + if (LocationManager.PASSIVE_PROVIDER.equals(provider)) { + return true; + } + if (LocationManager.NETWORK_PROVIDER.equals(provider)) { + return true; + } + return false; + } + private String checkPermissionAndRequest(LocationRequest request) { String perm = checkPermission(); if (ACCESS_COARSE_LOCATION.equals(perm)) { - switch (request.getQuality()) { - case LocationRequest.ACCURACY_FINE: - request.setQuality(LocationRequest.ACCURACY_BLOCK); - break; - case LocationRequest.POWER_HIGH: - request.setQuality(LocationRequest.POWER_LOW); - break; - } - // throttle - if (request.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) { - request.setInterval(LocationFudger.FASTEST_INTERVAL_MS); - } - if (request.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) { - request.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS); - } + if (!isProviderAllowedByCoarsePermission(request.getProvider())) { + throw new SecurityException("Requires ACCESS_FINE_LOCATION permission"); + } + switch (request.getQuality()) { + case LocationRequest.ACCURACY_FINE: + request.setQuality(LocationRequest.ACCURACY_BLOCK); + break; + case LocationRequest.POWER_HIGH: + request.setQuality(LocationRequest.POWER_LOW); + break; + } + // throttle + if (request.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) { + request.setInterval(LocationFudger.FASTEST_INTERVAL_MS); + } + if (request.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) { + request.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS); + } } // make getFastestInterval() the minimum of interval and fastest interval if (request.getFastestInterval() > request.getInterval()) { @@ -990,7 +1006,9 @@ public class LocationManagerService extends ILocationManager.Stub implements Run // use the fused provider if (request == null) request = DEFAULT_LOCATION_REQUEST; String name = request.getProvider(); - if (name == null) name = LocationManager.FUSED_PROVIDER; + if (name == null) { + throw new IllegalArgumentException("provider name must not be null"); + } LocationProviderInterface provider = mProvidersByName.get(name); if (provider == null) { throw new IllegalArgumentException("provider doesn't exisit: " + provider); @@ -1094,12 +1112,19 @@ public class LocationManagerService extends ILocationManager.Stub implements Run if (!isAllowedBySettingsLocked(name)) return null; Location location = mLastLocation.get(name); + if (location == null) { + return null; + } if (ACCESS_FINE_LOCATION.equals(perm)) { return location; } else { - return mLocationFudger.getOrCreate(location); + Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION); + if (noGPSLocation != null) { + return mLocationFudger.getOrCreate(noGPSLocation); + } } } + return null; } @Override @@ -1329,17 +1354,29 @@ public class LocationManagerService extends ILocationManager.Stub implements Run LocationProviderInterface p = mProvidersByName.get(provider); if (p == null) return; - // Add the coarse location as an extra - Location coarse = mLocationFudger.getOrCreate(location); - // Update last known locations + Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION); + Location lastNoGPSLocation = null; Location lastLocation = mLastLocation.get(provider); if (lastLocation == null) { lastLocation = new Location(provider); mLastLocation.put(provider, lastLocation); + } else { + lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION); + if (noGPSLocation == null && lastNoGPSLocation != null) { + // New location has no no-GPS location: adopt last no-GPS location. This is set + // directly into location because we do not want to notify COARSE clients. + location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation); + } } lastLocation.set(location); + // Fetch coarse location + Location coarseLocation = null; + if (noGPSLocation != null && !noGPSLocation.equals(lastNoGPSLocation)) { + coarseLocation = mLocationFudger.getOrCreate(noGPSLocation); + } + // Fetch latest status update time long newStatusUpdateTime = p.getStatusUpdateTime(); @@ -1361,29 +1398,31 @@ public class LocationManagerService extends ILocationManager.Stub implements Run continue; } + Location notifyLocation = null; if (ACCESS_FINE_LOCATION.equals(receiver.mPermission)) { - location = lastLocation; // use fine location + notifyLocation = lastLocation; // use fine location } else { - location = coarse; // use coarse location - } - - Location lastLoc = r.mLastFixBroadcast; - if ((lastLoc == null) || shouldBroadcastSafe(location, lastLoc, r)) { - if (lastLoc == null) { - lastLoc = new Location(location); - r.mLastFixBroadcast = lastLoc; - } else { - lastLoc.set(location); - } - if (!receiver.callLocationChangedLocked(location)) { - Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver); - receiverDead = true; + notifyLocation = coarseLocation; // use coarse location if available + } + if (notifyLocation != null) { + Location lastLoc = r.mLastFixBroadcast; + if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r)) { + if (lastLoc == null) { + lastLoc = new Location(notifyLocation); + r.mLastFixBroadcast = lastLoc; + } else { + lastLoc.set(notifyLocation); + } + if (!receiver.callLocationChangedLocked(notifyLocation)) { + Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver); + receiverDead = true; + } } } long prevStatusUpdateTime = r.mLastStatusBroadcast; if ((newStatusUpdateTime > prevStatusUpdateTime) && - (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) { + (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) { r.mLastStatusBroadcast = newStatusUpdateTime; if (!receiver.callStatusChangedLocked(provider, status, extras)) { diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java index 3caba1f..71e6e66 100755 --- a/services/java/com/android/server/NotificationManagerService.java +++ b/services/java/com/android/server/NotificationManagerService.java @@ -63,6 +63,7 @@ import android.util.Slog; import android.util.Xml; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; +import android.widget.RemoteViews; import android.widget.Toast; import com.android.internal.statusbar.StatusBarNotification; @@ -877,7 +878,6 @@ public class NotificationManagerService extends INotificationManager.Stub return (x < low) ? low : ((x > high) ? high : x); } - // Not exposed via Binder; for system use only (otherwise malicious apps could spoof the // uid/pid of another application) public void enqueueNotificationInternal(String pkg, int callingUid, int callingPid, @@ -992,8 +992,9 @@ public class NotificationManagerService extends INotificationManager.Stub } if (notification.icon != 0) { - StatusBarNotification n = new StatusBarNotification(pkg, id, tag, - r.uid, r.initialPid, score, notification); + final UserHandle user = new UserHandle(userId); + final StatusBarNotification n = new StatusBarNotification( + pkg, id, tag, r.uid, r.initialPid, score, notification, user); if (old != null && old.statusBarKey != null) { r.statusBarKey = old.statusBarKey; long identity = Binder.clearCallingIdentity(); diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java index e7f3599..20c89ad 100644 --- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -50,9 +50,12 @@ import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.Message; +import android.os.Process; +import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; +import android.os.UserHandle; import android.provider.Settings; import android.text.TextUtils; import android.text.TextUtils.SimpleStringSplitter; @@ -76,6 +79,7 @@ import android.view.accessibility.IAccessibilityManagerClient; import com.android.internal.R; import com.android.internal.content.PackageMonitor; +import com.android.internal.os.SomeArgs; import com.android.internal.statusbar.IStatusBarService; import org.xmlpull.v1.XmlPullParserException; @@ -89,6 +93,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.CopyOnWriteArrayList; /** * This class is instantiated by the system as a system level service and can be @@ -111,69 +116,62 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { private static final int OWN_PROCESS_ID = android.os.Process.myPid(); - private static final int MSG_SHOW_ENABLE_TOUCH_EXPLORATION_DIALOG = 1; - - private static final int MSG_TOGGLE_TOUCH_EXPLORATION = 2; - - private static final int MSG_SEND_ACCESSIBILITY_EVENT_TO_INPUT_FILTER = 3; - - private static final int MSG_SEND_UPDATE_INPUT_FILTER = 4; - private static int sIdCounter = 0; private static int sNextWindowId; - final Context mContext; - - final Object mLock = new Object(); - - final List<Service> mServices = new ArrayList<Service>(); + private final Context mContext; - final List<IAccessibilityManagerClient> mClients = - new ArrayList<IAccessibilityManagerClient>(); + private final Object mLock = new Object(); - final Map<ComponentName, Service> mComponentNameToServiceMap = new HashMap<ComponentName, Service>(); + private final SimpleStringSplitter mStringColonSplitter = + new SimpleStringSplitter(COMPONENT_NAME_SEPARATOR); - private final List<AccessibilityServiceInfo> mInstalledServices = new ArrayList<AccessibilityServiceInfo>(); + private final List<AccessibilityServiceInfo> mEnabledServicesForFeedbackTempList = + new ArrayList<AccessibilityServiceInfo>(); - private final Set<ComponentName> mEnabledServices = new HashSet<ComponentName>(); + private final PackageManager mPackageManager; - private final Set<ComponentName> mTouchExplorationGrantedServices = new HashSet<ComponentName>(); + private final IWindowManager mWindowManagerService; - private final SparseArray<AccessibilityConnectionWrapper> mWindowIdToInteractionConnectionWrapperMap = - new SparseArray<AccessibilityConnectionWrapper>(); - - private final SparseArray<IBinder> mWindowIdToWindowTokenMap = new SparseArray<IBinder>(); + private final SecurityPolicy mSecurityPolicy; - private final SimpleStringSplitter mStringColonSplitter = new SimpleStringSplitter(COMPONENT_NAME_SEPARATOR); + private final MainHandler mMainHandler; - private PackageManager mPackageManager; + private Service mUiAutomationService; - private int mHandledFeedbackTypes = 0; + private Service mQueryBridge; - private boolean mIsAccessibilityEnabled; + private AlertDialog mEnableTouchExplorationDialog; private AccessibilityInputFilter mInputFilter; private boolean mHasInputFilter; - private final List<AccessibilityServiceInfo> mEnabledServicesForFeedbackTempList = new ArrayList<AccessibilityServiceInfo>(); - - private boolean mIsTouchExplorationEnabled; + private final RemoteCallbackList<IAccessibilityManagerClient> mGlobalClients = + new RemoteCallbackList<IAccessibilityManagerClient>(); - private boolean mIsScreenMagnificationEnabled; + private final SparseArray<AccessibilityConnectionWrapper> mGlobalInteractionConnections = + new SparseArray<AccessibilityConnectionWrapper>(); - private final IWindowManager mWindowManager; + private final SparseArray<IBinder> mGlobalWindowTokens = new SparseArray<IBinder>(); - private final SecurityPolicy mSecurityPolicy; - - private final MainHandler mMainHandler; + private final SparseArray<UserState> mUserStates = new SparseArray<UserState>(); - private Service mUiAutomationService; + private int mCurrentUserId = UserHandle.USER_NULL; - private Service mQueryBridge; + private UserState getCurrentUserStateLocked() { + return getUserStateLocked(mCurrentUserId); + } - private AlertDialog mEnableTouchExplorationDialog; + private UserState getUserStateLocked(int userId) { + UserState state = mUserStates.get(userId); + if (state == null) { + state = new UserState(userId); + mUserStates.put(userId, state); + } + return state; + } /** * Creates a new instance. @@ -183,28 +181,27 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { public AccessibilityManagerService(Context context) { mContext = context; mPackageManager = mContext.getPackageManager(); - mWindowManager = (IWindowManager) ServiceManager.getService(Context.WINDOW_SERVICE); + mWindowManagerService = (IWindowManager) ServiceManager.getService(Context.WINDOW_SERVICE); mSecurityPolicy = new SecurityPolicy(); mMainHandler = new MainHandler(mContext.getMainLooper()); - registerPackageChangeAndBootCompletedBroadcastReceiver(); - registerSettingsContentObservers(); + registerBroadcastReceivers(); + new AccessibilityContentObserver(mMainHandler).register( + context.getContentResolver()); } - /** - * Registers a {@link BroadcastReceiver} for the events of - * adding/changing/removing/restarting a package and boot completion. - */ - private void registerPackageChangeAndBootCompletedBroadcastReceiver() { - Context context = mContext; - + private void registerBroadcastReceivers() { PackageMonitor monitor = new PackageMonitor() { @Override public void onSomePackagesChanged() { synchronized (mLock) { + if (getChangingUserId() != mCurrentUserId) { + return; + } // We will update when the automation service dies. if (mUiAutomationService == null) { - populateInstalledAccessibilityServiceLocked(); - manageServicesLocked(); + UserState userState = getCurrentUserStateLocked(); + populateInstalledAccessibilityServiceLocked(userState); + manageServicesLocked(userState); } } } @@ -212,7 +209,12 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { @Override public void onPackageRemoved(String packageName, int uid) { synchronized (mLock) { - Iterator<ComponentName> it = mEnabledServices.iterator(); + final int userId = getChangingUserId(); + if (userId != mCurrentUserId) { + return; + } + UserState state = getUserStateLocked(userId); + Iterator<ComponentName> it = state.mEnabledServices.iterator(); while (it.hasNext()) { ComponentName comp = it.next(); String compPkg = comp.getPackageName(); @@ -221,13 +223,13 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { // Update the enabled services setting. persistComponentNamesToSettingLocked( Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, - mEnabledServices); + state.mEnabledServices, userId); // Update the touch exploration granted services setting. - mTouchExplorationGrantedServices.remove(comp); + state.mTouchExplorationGrantedServices.remove(comp); persistComponentNamesToSettingLocked( Settings.Secure. TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES, - mEnabledServices); + state.mEnabledServices, userId); return; } } @@ -238,7 +240,12 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) { synchronized (mLock) { - Iterator<ComponentName> it = mEnabledServices.iterator(); + final int userId = getChangingUserId(); + if (userId != mCurrentUserId) { + return false; + } + UserState state = getUserStateLocked(userId); + Iterator<ComponentName> it = state.mEnabledServices.iterator(); while (it.hasNext()) { ComponentName comp = it.next(); String compPkg = comp.getPackageName(); @@ -250,179 +257,97 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { it.remove(); persistComponentNamesToSettingLocked( Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, - mEnabledServices); + state.mEnabledServices, userId); } } } return false; } } - - @Override - public void onReceive(Context context, Intent intent) { - if (intent.getAction() == Intent.ACTION_BOOT_COMPLETED) { - synchronized (mLock) { - // We will update when the automation service dies. - if (mUiAutomationService == null) { - updateInternalStateLocked(); - } - } - return; - } - super.onReceive(context, intent); - } }; // package changes - monitor.register(context, null, true); + monitor.register(mContext, null, UserHandle.ALL, true); - // boot completed - IntentFilter bootFiler = new IntentFilter(Intent.ACTION_BOOT_COMPLETED); - mContext.registerReceiver(monitor, bootFiler, null, monitor.getRegisteredHandler()); - } - - /** - * {@link ContentObserver}s for {@link Settings.Secure#ACCESSIBILITY_ENABLED} - * and {@link Settings.Secure#ENABLED_ACCESSIBILITY_SERVICES} settings. - */ - private void registerSettingsContentObservers() { - ContentResolver contentResolver = mContext.getContentResolver(); - - Uri accessibilityEnabledUri = Settings.Secure.getUriFor( - Settings.Secure.ACCESSIBILITY_ENABLED); - contentResolver.registerContentObserver(accessibilityEnabledUri, false, - new ContentObserver(new Handler()) { - @Override - public void onChange(boolean selfChange) { - super.onChange(selfChange); - synchronized (mLock) { - // We will update when the automation service dies. - if (mUiAutomationService == null) { - handleAccessibilityEnabledSettingChangedLocked(); - updateInputFilterLocked(); - sendStateToClientsLocked(); - } - } - } - }); + // user change + IntentFilter userFilter = new IntentFilter(); + userFilter.addAction(Intent.ACTION_USER_SWITCHED); + userFilter.addAction(Intent.ACTION_USER_REMOVED); - Uri touchExplorationRequestedUri = Settings.Secure.getUriFor( - Settings.Secure.TOUCH_EXPLORATION_ENABLED); - contentResolver.registerContentObserver(touchExplorationRequestedUri, false, - new ContentObserver(new Handler()) { - @Override - public void onChange(boolean selfChange) { - super.onChange(selfChange); - synchronized (mLock) { - // We will update when the automation service dies. - if (mUiAutomationService == null) { - handleTouchExplorationEnabledSettingChangedLocked(); - updateInputFilterLocked(); - sendStateToClientsLocked(); - } - } - } - }); - - Uri accessibilityScreenMagnificationEnabledUri = Settings.Secure.getUriFor( - Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED); - contentResolver.registerContentObserver(accessibilityScreenMagnificationEnabledUri, false, - new ContentObserver(new Handler()) { - @Override - public void onChange(boolean selfChange) { - super.onChange(selfChange); - synchronized (mLock) { - // We will update when the automation service dies. - if (mUiAutomationService == null) { - handleScreenMagnificationEnabledSettingChangedLocked(); - updateInputFilterLocked(); - sendStateToClientsLocked(); - } - } - } - }); - - Uri accessibilityServicesUri = - Settings.Secure.getUriFor(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES); - contentResolver.registerContentObserver(accessibilityServicesUri, false, - new ContentObserver(new Handler()) { - @Override - public void onChange(boolean selfChange) { - super.onChange(selfChange); - synchronized (mLock) { - // We will update when the automation service dies. - if (mUiAutomationService == null) { - populateEnabledAccessibilityServicesLocked(); - manageServicesLocked(); - } - } - } - }); - - Uri touchExplorationGrantedServicesUri = Settings.Secure.getUriFor( - Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES); - contentResolver.registerContentObserver(touchExplorationGrantedServicesUri, false, - new ContentObserver(new Handler()) { - @Override - public void onChange(boolean selfChange) { - super.onChange(selfChange); - synchronized (mLock) { - // We will update when the automation service dies. - if (mUiAutomationService == null) { - populateTouchExplorationGrantedAccessibilityServicesLocked(); - handleTouchExplorationGrantedAccessibilityServicesChangedLocked(); - } - } + mContext.registerReceiver(new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (Intent.ACTION_USER_SWITCHED.equals(action)) { + switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0)); + } else if (Intent.ACTION_USER_REMOVED.equals(action)) { + removeUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0)); } - }); + } + }, userFilter); } - public int addClient(IAccessibilityManagerClient client) throws RemoteException { + public int addClient(IAccessibilityManagerClient client, int userId) { synchronized (mLock) { - final IAccessibilityManagerClient addedClient = client; - mClients.add(addedClient); - // Clients are registered all the time until their process is - // killed, therefore we do not have a corresponding unlinkToDeath. - client.asBinder().linkToDeath(new DeathRecipient() { - public void binderDied() { - synchronized (mLock) { - addedClient.asBinder().unlinkToDeath(this, 0); - mClients.remove(addedClient); - } - } - }, 0); - return getState(); + final int resolvedUserId = mSecurityPolicy + .resolveCallingUserIdEnforcingPermissionsLocked(userId); + // If the client is from a process that runs across users such as + // the system UI or the system we add it to the global state that + // is shared across users. + UserState userState = getUserStateLocked(resolvedUserId); + if (mSecurityPolicy.isCallerInteractingAcrossUsers(userId)) { + mGlobalClients.register(client); + return getClientState(userState); + } else { + userState.mClients.register(client); + // If this client is not for the current user we do not + // return a state since it is not for the foreground user. + // We will send the state to the client on a user switch. + return (resolvedUserId == mCurrentUserId) ? getClientState(userState) : 0; + } } } - public boolean sendAccessibilityEvent(AccessibilityEvent event) { + public boolean sendAccessibilityEvent(AccessibilityEvent event, int userId) { synchronized (mLock) { + final int resolvedUserId = mSecurityPolicy + .resolveCallingUserIdEnforcingPermissionsLocked(userId); + // This method does nothing for a background user. + if (resolvedUserId != mCurrentUserId) { + return true; // yes, recycle the event + } if (mSecurityPolicy.canDispatchAccessibilityEvent(event)) { mSecurityPolicy.updateActiveWindowAndEventSourceLocked(event); notifyAccessibilityServicesDelayedLocked(event, false); notifyAccessibilityServicesDelayedLocked(event, true); } if (mHasInputFilter && mInputFilter != null) { - mMainHandler.obtainMessage(MSG_SEND_ACCESSIBILITY_EVENT_TO_INPUT_FILTER, + mMainHandler.obtainMessage(MainHandler.MSG_SEND_ACCESSIBILITY_EVENT_TO_INPUT_FILTER, AccessibilityEvent.obtain(event)).sendToTarget(); } event.recycle(); - mHandledFeedbackTypes = 0; + getUserStateLocked(resolvedUserId).mHandledFeedbackTypes = 0; } return (OWN_PROCESS_ID != Binder.getCallingPid()); } - public List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList() { + public List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList(int userId) { synchronized (mLock) { - return mInstalledServices; + final int resolvedUserId = mSecurityPolicy + .resolveCallingUserIdEnforcingPermissionsLocked(userId); + return getUserStateLocked(resolvedUserId).mInstalledServices; } } - public List<AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int feedbackType) { - List<AccessibilityServiceInfo> result = mEnabledServicesForFeedbackTempList; - result.clear(); - List<Service> services = mServices; + public List<AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int feedbackType, + int userId) { + List<AccessibilityServiceInfo> result = null; synchronized (mLock) { + final int resolvedUserId = mSecurityPolicy + .resolveCallingUserIdEnforcingPermissionsLocked(userId); + result = mEnabledServicesForFeedbackTempList; + result.clear(); + List<Service> services = getUserStateLocked(resolvedUserId).mServices; while (feedbackType != 0) { final int feedbackTypeBit = (1 << Integer.numberOfTrailingZeros(feedbackType)); feedbackType &= ~feedbackTypeBit; @@ -438,30 +363,51 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { return result; } - public void interrupt() { + public void interrupt(int userId) { + CopyOnWriteArrayList<Service> services; synchronized (mLock) { - for (int i = 0, count = mServices.size(); i < count; i++) { - Service service = mServices.get(i); - try { - service.mServiceInterface.onInterrupt(); - } catch (RemoteException re) { - Slog.e(LOG_TAG, "Error during sending interrupt request to " - + service.mService, re); - } + final int resolvedUserId = mSecurityPolicy + .resolveCallingUserIdEnforcingPermissionsLocked(userId); + // This method does nothing for a background user. + if (resolvedUserId != mCurrentUserId) { + return; + } + services = getUserStateLocked(resolvedUserId).mServices; + } + for (int i = 0, count = services.size(); i < count; i++) { + Service service = services.get(i); + try { + service.mServiceInterface.onInterrupt(); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error during sending interrupt request to " + + service.mService, re); } } } public int addAccessibilityInteractionConnection(IWindow windowToken, - IAccessibilityInteractionConnection connection) throws RemoteException { + IAccessibilityInteractionConnection connection, int userId) throws RemoteException { synchronized (mLock) { - final IWindow addedWindowToken = windowToken; + final int resolvedUserId = mSecurityPolicy + .resolveCallingUserIdEnforcingPermissionsLocked(userId); final int windowId = sNextWindowId++; - AccessibilityConnectionWrapper wrapper = new AccessibilityConnectionWrapper(windowId, - connection); - wrapper.linkToDeath(); - mWindowIdToWindowTokenMap.put(windowId, addedWindowToken.asBinder()); - mWindowIdToInteractionConnectionWrapperMap.put(windowId, wrapper); + // If the window is from a process that runs across users such as + // the system UI or the system we add it to the global state that + // is shared across users. + if (mSecurityPolicy.isCallerInteractingAcrossUsers(userId)) { + AccessibilityConnectionWrapper wrapper = new AccessibilityConnectionWrapper( + windowId, connection, UserHandle.USER_ALL); + wrapper.linkToDeath(); + mGlobalInteractionConnections.put(windowId, wrapper); + mGlobalWindowTokens.put(windowId, windowToken.asBinder()); + } else { + AccessibilityConnectionWrapper wrapper = new AccessibilityConnectionWrapper( + windowId, connection, resolvedUserId); + wrapper.linkToDeath(); + UserState userState = getUserStateLocked(resolvedUserId); + userState.mInteractionConnections.put(windowId, wrapper); + userState.mWindowTokens.put(windowId, windowToken.asBinder()); + } if (DEBUG) { Slog.i(LOG_TAG, "Adding interaction connection to windowId: " + windowId); } @@ -469,22 +415,47 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } } - public void removeAccessibilityInteractionConnection(IWindow windowToken) { + public void removeAccessibilityInteractionConnection(IWindow window) { synchronized (mLock) { - final int count = mWindowIdToWindowTokenMap.size(); - for (int i = 0; i < count; i++) { - if (mWindowIdToWindowTokenMap.valueAt(i) == windowToken.asBinder()) { - final int windowId = mWindowIdToWindowTokenMap.keyAt(i); - AccessibilityConnectionWrapper wrapper = - mWindowIdToInteractionConnectionWrapperMap.get(windowId); - wrapper.unlinkToDeath(); - removeAccessibilityInteractionConnectionLocked(windowId); + mSecurityPolicy.resolveCallingUserIdEnforcingPermissionsLocked( + UserHandle.getCallingUserId()); + IBinder token = window.asBinder(); + final boolean removedGlobal = + removeAccessibilityInteractionConnectionInternalLocked( + token, mGlobalWindowTokens, mGlobalInteractionConnections); + if (removedGlobal) { + return; + } + final int userCount = mUserStates.size(); + for (int i = 0; i < userCount; i++) { + UserState userState = mUserStates.valueAt(i); + final boolean removedForUser = + removeAccessibilityInteractionConnectionInternalLocked( + token, userState.mWindowTokens, userState.mInteractionConnections); + if (removedForUser) { return; } } } } + private boolean removeAccessibilityInteractionConnectionInternalLocked(IBinder windowToken, + SparseArray<IBinder> windowTokens, + SparseArray<AccessibilityConnectionWrapper> interactionConnections) { + final int count = windowTokens.size(); + for (int i = 0; i < count; i++) { + if (windowTokens.valueAt(i) == windowToken) { + final int windowId = windowTokens.keyAt(i); + windowTokens.removeAt(i); + AccessibilityConnectionWrapper wrapper = interactionConnections.get(windowId); + wrapper.unlinkToDeath(); + interactionConnections.remove(windowId); + return true; + } + } + return false; + } + public void registerUiTestAutomationService(IAccessibilityServiceClient serviceClient, AccessibilityServiceInfo accessibilityServiceInfo) { mSecurityPolicy.enforceCallingPermission(Manifest.permission.RETRIEVE_WINDOW_CONTENT, @@ -495,21 +466,18 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { // If an automation services is connected to the system all services are stopped // so the automation one is the only one running. Settings are not changed so when // the automation service goes away the state is restored from the settings. + UserState userState = getCurrentUserStateLocked(); + unbindAllServicesLocked(userState); - // Disable all services. - final int runningServiceCount = mServices.size(); - for (int i = 0; i < runningServiceCount; i++) { - Service runningService = mServices.get(i); - runningService.unbind(); - } // If necessary enable accessibility and announce that. - if (!mIsAccessibilityEnabled) { - mIsAccessibilityEnabled = true; - sendStateToClientsLocked(); + if (!userState.mIsAccessibilityEnabled) { + userState.mIsAccessibilityEnabled = true; + scheduleSendStateToClientsLocked(userState); } } // Hook the automation service up. - mUiAutomationService = new Service(componentName, accessibilityServiceInfo, true); + mUiAutomationService = new Service(mCurrentUserId, componentName, + accessibilityServiceInfo, true); mUiAutomationService.onServiceConnected(componentName, serviceClient.asBinder()); } @@ -572,30 +540,80 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { * @param outBounds The output to which to write the bounds. */ boolean getActiveWindowBounds(Rect outBounds) { + IBinder token; synchronized (mLock) { final int windowId = mSecurityPolicy.mActiveWindowId; - IBinder token = mWindowIdToWindowTokenMap.get(windowId); - try { - WindowInfo info = mWindowManager.getWindowInfo(token); - if (info != null) { - outBounds.set(info.frame); - return true; - } - } catch (RemoteException re) { - /* ignore */ + token = mGlobalWindowTokens.get(windowId); + if (token == null) { + token = getCurrentUserStateLocked().mWindowTokens.get(windowId); + } + } + WindowInfo info = null; + try { + info = mWindowManagerService.getWindowInfo(token); + if (info != null) { + outBounds.set(info.frame); + return true; + } + } catch (RemoteException re) { + /* ignore */ + } finally { + if (info != null) { + info.recycle(); } - return false; } + return false; } - public int getActiveWindowId() { + int getActiveWindowId() { return mSecurityPolicy.mActiveWindowId; } + private void switchUser(int userId) { + synchronized (mLock) { + if (userId == mCurrentUserId) { + return; + } + + // Disconnect from services for the old user. + UserState oldUserState = getUserStateLocked(mCurrentUserId); + unbindAllServicesLocked(oldUserState); + + // Disable the local managers for the old user. + if (oldUserState.mClients.getRegisteredCallbackCount() > 0) { + mMainHandler.obtainMessage(MainHandler.MSG_SEND_CLEARED_STATE_TO_CLIENTS_FOR_USER, + oldUserState.mUserId, 0).sendToTarget(); + } + + // The user changed. + mCurrentUserId = userId; + + // Recreate the internal state for the new user. + mMainHandler.obtainMessage(MainHandler.MSG_SEND_RECREATE_INTERNAL_STATE, + mCurrentUserId, 0).sendToTarget(); + + // Re-register the test automation service after the new state is recreated. + if (mUiAutomationService != null) { + unregisterUiTestAutomationService(mUiAutomationService.mServiceInterface); + SomeArgs args = SomeArgs.obtain(); + args.arg1 = mUiAutomationService.mServiceInterface; + args.arg2 = mUiAutomationService.mAccessibilityServiceInfo; + mMainHandler.obtainMessage(MainHandler.MSG_REGISTER_UI_TEST_AUTOMATION_SERVICE, + args).sendToTarget(); + } + } + } + + private void removeUser(int userId) { + synchronized (mLock) { + mUserStates.remove(userId); + } + } + private Service getQueryBridge() { if (mQueryBridge == null) { AccessibilityServiceInfo info = new AccessibilityServiceInfo(); - mQueryBridge = new Service(null, info, true); + mQueryBridge = new Service(UserHandle.USER_NULL, null, info, true); } return mQueryBridge; } @@ -610,8 +628,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { // gestures to avoid user frustration when different // behavior is observed from different combinations of // enabled accessibility services. - for (int i = mServices.size() - 1; i >= 0; i--) { - Service service = mServices.get(i); + UserState state = getCurrentUserStateLocked(); + for (int i = state.mServices.size() - 1; i >= 0; i--) { + Service service = state.mServices.get(i); if (service.mRequestTouchExplorationMode && service.mIsDefault == isDefault) { service.notifyGesture(gestureId); return true; @@ -624,29 +643,36 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { * Removes an AccessibilityInteractionConnection. * * @param windowId The id of the window to which the connection is targeted. + * @param userId The id of the user owning the connection. UserHandle.USER_ALL + * if global. */ - private void removeAccessibilityInteractionConnectionLocked(int windowId) { - mWindowIdToWindowTokenMap.remove(windowId); - mWindowIdToInteractionConnectionWrapperMap.remove(windowId); + private void removeAccessibilityInteractionConnectionLocked(int windowId, int userId) { + if (userId == UserHandle.USER_ALL) { + mGlobalWindowTokens.remove(windowId); + mGlobalInteractionConnections.remove(windowId); + } else { + UserState userState = getCurrentUserStateLocked(); + userState.mWindowTokens.remove(windowId); + userState.mInteractionConnections.remove(windowId); + } if (DEBUG) { Slog.i(LOG_TAG, "Removing interaction connection to windowId: " + windowId); } } - /** - * Populates the cached list of installed {@link AccessibilityService}s. - */ - private void populateInstalledAccessibilityServiceLocked() { - mInstalledServices.clear(); + private void populateInstalledAccessibilityServiceLocked(UserState userState) { + userState.mInstalledServices.clear(); - List<ResolveInfo> installedServices = mPackageManager.queryIntentServices( + List<ResolveInfo> installedServices = mPackageManager.queryIntentServicesAsUser( new Intent(AccessibilityService.SERVICE_INTERFACE), - PackageManager.GET_SERVICES | PackageManager.GET_META_DATA); + PackageManager.GET_SERVICES | PackageManager.GET_META_DATA, + mCurrentUserId); for (int i = 0, count = installedServices.size(); i < count; i++) { ResolveInfo resolveInfo = installedServices.get(i); ServiceInfo serviceInfo = resolveInfo.serviceInfo; - if (!android.Manifest.permission.BIND_ACCESSIBILITY_SERVICE.equals(serviceInfo.permission)) { + if (!android.Manifest.permission.BIND_ACCESSIBILITY_SERVICE.equals( + serviceInfo.permission)) { Slog.w(LOG_TAG, "Skipping accessibilty service " + new ComponentName( serviceInfo.packageName, serviceInfo.name).flattenToShortString() + ": it does not require the permission " @@ -656,7 +682,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { AccessibilityServiceInfo accessibilityServiceInfo; try { accessibilityServiceInfo = new AccessibilityServiceInfo(resolveInfo, mContext); - mInstalledServices.add(accessibilityServiceInfo); + userState.mInstalledServices.add(accessibilityServiceInfo); } catch (XmlPullParserException xppe) { Slog.e(LOG_TAG, "Error while initializing AccessibilityServiceInfo", xppe); } catch (IOException ioe) { @@ -665,16 +691,19 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } } - private void populateEnabledAccessibilityServicesLocked() { + private void populateEnabledAccessibilityServicesLocked(UserState userState) { populateComponentNamesFromSettingLocked( Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, - mEnabledServices); + userState.mUserId, + userState.mEnabledServices); } - private void populateTouchExplorationGrantedAccessibilityServicesLocked() { + private void populateTouchExplorationGrantedAccessibilityServicesLocked( + UserState userState) { populateComponentNamesFromSettingLocked( Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES, - mTouchExplorationGrantedServices); + userState.mUserId, + userState.mTouchExplorationGrantedServices); } /** @@ -687,12 +716,13 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { private void notifyAccessibilityServicesDelayedLocked(AccessibilityEvent event, boolean isDefault) { try { - for (int i = 0, count = mServices.size(); i < count; i++) { - Service service = mServices.get(i); + UserState state = getCurrentUserStateLocked(); + for (int i = 0, count = state.mServices.size(); i < count; i++) { + Service service = state.mServices.get(i); if (service.mIsDefault == isDefault) { - if (canDispathEventLocked(service, event, mHandledFeedbackTypes)) { - mHandledFeedbackTypes |= service.mFeedbackType; + if (canDispathEventLocked(service, event, state.mHandledFeedbackTypes)) { + state.mHandledFeedbackTypes |= service.mFeedbackType; service.notifyAccessibilityEvent(event); } } @@ -706,19 +736,21 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } /** - * Adds a service. + * Adds a service for a user. * * @param service The service to add. + * @param userId The user id. */ - private void tryAddServiceLocked(Service service) { + private void tryAddServiceLocked(Service service, int userId) { try { - if (mServices.contains(service) || !service.isConfigured()) { + UserState userState = getUserStateLocked(userId); + if (userState.mServices.contains(service) || !service.isConfigured()) { return; } service.linkToOwnDeath(); - mServices.add(service); - mComponentNameToServiceMap.put(service.mComponentName, service); - updateInputFilterLocked(); + userState.mServices.add(service); + userState.mComponentNameToServiceMap.put(service.mComponentName, service); + updateInputFilterLocked(userState); tryEnableTouchExplorationLocked(service); } catch (RemoteException e) { /* do nothing */ @@ -732,14 +764,15 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { * @return True if the service was removed, false otherwise. */ private boolean tryRemoveServiceLocked(Service service) { - final boolean removed = mServices.remove(service); + UserState userState = getUserStateLocked(service.mUserId); + final boolean removed = userState.mServices.remove(service); if (!removed) { return false; } - mComponentNameToServiceMap.remove(service.mComponentName); + userState.mComponentNameToServiceMap.remove(service.mComponentName); service.unlinkToOwnDeath(); service.dispose(); - updateInputFilterLocked(); + updateInputFilterLocked(userState); tryDisableTouchExplorationLocked(service); return removed; } @@ -791,23 +824,23 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { /** * Manages services by starting enabled ones and stopping disabled ones. */ - private void manageServicesLocked() { - final int enabledInstalledServicesCount = updateServicesStateLocked(mInstalledServices, - mEnabledServices); + private void manageServicesLocked(UserState userState) { + final int enabledInstalledServicesCount = updateServicesStateLocked(userState); // No enabled installed services => disable accessibility to avoid // sending accessibility events with no recipient across processes. - if (mIsAccessibilityEnabled && enabledInstalledServicesCount == 0) { - Settings.Secure.putInt(mContext.getContentResolver(), - Settings.Secure.ACCESSIBILITY_ENABLED, 0); + if (userState.mIsAccessibilityEnabled && enabledInstalledServicesCount == 0) { + Settings.Secure.putIntForUser(mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_ENABLED, 0, userState.mUserId); } } /** - * Unbinds all bound services. + * Unbinds all bound services for a user. + * + * @param userState The user state. */ - private void unbindAllServicesLocked() { - List<Service> services = mServices; - + private void unbindAllServicesLocked(UserState userState) { + List<Service> services = userState.mServices; for (int i = 0, count = services.size(); i < count; i++) { Service service = services.get(i); if (service.unbind()) { @@ -819,17 +852,17 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { /** * Populates a set with the {@link ComponentName}s stored in a colon - * separated value setting. + * separated value setting for a given user. * * @param settingName The setting to parse. + * @param userId The user id. * @param outComponentNames The output component names. */ - private void populateComponentNamesFromSettingLocked(String settingName, + private void populateComponentNamesFromSettingLocked(String settingName, int userId, Set<ComponentName> outComponentNames) { + String settingValue = Settings.Secure.getStringForUser(mContext.getContentResolver(), + settingName, userId); outComponentNames.clear(); - - String settingValue = Settings.Secure.getString(mContext.getContentResolver(), settingName); - if (settingValue != null) { TextUtils.SimpleStringSplitter splitter = mStringColonSplitter; splitter.setString(settingValue); @@ -854,7 +887,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { * @param componentNames The component names. */ private void persistComponentNamesToSettingLocked(String settingName, - Set<ComponentName> componentNames) { + Set<ComponentName> componentNames, int userId) { StringBuilder builder = new StringBuilder(); for (ComponentName componentName : componentNames) { if (builder.length() > 0) { @@ -862,34 +895,34 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } builder.append(componentName.flattenToShortString()); } - Settings.Secure.putString(mContext.getContentResolver(), settingName, builder.toString()); + Settings.Secure.putStringForUser(mContext.getContentResolver(), + settingName, builder.toString(), userId); } /** * Updates the state of each service by starting (or keeping running) enabled ones and * stopping the rest. * - * @param installedServices All installed {@link AccessibilityService}s. - * @param enabledServices The {@link ComponentName}s of the enabled services. + * @param userState The user state for which to do that. * @return The number of enabled installed services. */ - private int updateServicesStateLocked(List<AccessibilityServiceInfo> installedServices, - Set<ComponentName> enabledServices) { - - Map<ComponentName, Service> componentNameToServiceMap = mComponentNameToServiceMap; - boolean isEnabled = mIsAccessibilityEnabled; + private int updateServicesStateLocked(UserState userState) { + Map<ComponentName, Service> componentNameToServiceMap = + userState.mComponentNameToServiceMap; + boolean isEnabled = userState.mIsAccessibilityEnabled; int enabledInstalledServices = 0; - for (int i = 0, count = installedServices.size(); i < count; i++) { - AccessibilityServiceInfo installedService = installedServices.get(i); + for (int i = 0, count = userState.mInstalledServices.size(); i < count; i++) { + AccessibilityServiceInfo installedService = userState.mInstalledServices.get(i); ComponentName componentName = ComponentName.unflattenFromString( installedService.getId()); Service service = componentNameToServiceMap.get(componentName); if (isEnabled) { - if (enabledServices.contains(componentName)) { + if (userState.mEnabledServices.contains(componentName)) { if (service == null) { - service = new Service(componentName, installedService, false); + service = new Service(userState.mUserId, componentName, + installedService, false); } service.bind(); enabledInstalledServices++; @@ -908,145 +941,206 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { return enabledInstalledServices; } - /** - * Sends the state to the clients. - */ - private void sendStateToClientsLocked() { - final int state = getState(); - for (int i = 0, count = mClients.size(); i < count; i++) { + private void scheduleSendStateToClientsLocked(UserState userState) { + if (mGlobalClients.getRegisteredCallbackCount() > 0 + || userState.mClients.getRegisteredCallbackCount() > 0) { + final int clientState = getClientState(userState); + mMainHandler.obtainMessage(MainHandler.MSG_SEND_STATE_TO_CLIENTS, + clientState, userState.mUserId) .sendToTarget(); + } + } + + private void updateInputFilterLocked(UserState userState) { + boolean setInputFilter = false; + AccessibilityInputFilter inputFilter = null; + synchronized (mLock) { + if ((userState.mIsAccessibilityEnabled && userState.mIsTouchExplorationEnabled) + || userState.mIsDisplayMagnificationEnabled) { + if (!mHasInputFilter) { + mHasInputFilter = true; + if (mInputFilter == null) { + mInputFilter = new AccessibilityInputFilter(mContext, + AccessibilityManagerService.this); + } + inputFilter = mInputFilter; + setInputFilter = true; + } + int flags = 0; + if (userState.mIsDisplayMagnificationEnabled) { + flags |= AccessibilityInputFilter.FLAG_FEATURE_SCREEN_MAGNIFIER; + } + if (userState.mIsTouchExplorationEnabled) { + flags |= AccessibilityInputFilter.FLAG_FEATURE_TOUCH_EXPLORATION; + } + mInputFilter.setEnabledFeatures(flags); + } else { + if (mHasInputFilter) { + mHasInputFilter = false; + mInputFilter.setEnabledFeatures(0); + inputFilter = null; + setInputFilter = true; + } + } + } + if (setInputFilter) { try { - mClients.get(i).setState(state); + mWindowManagerService.setInputFilter(inputFilter); } catch (RemoteException re) { - mClients.remove(i); - count--; - i--; + /* ignore */ } } } - /** - * Gets the current state as a set of flags. - * - * @return The state. - */ - private int getState() { - int state = 0; - if (mIsAccessibilityEnabled) { - state |= AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED; - } - // Touch exploration relies on enabled accessibility. - if (mIsAccessibilityEnabled && mIsTouchExplorationEnabled) { - state |= AccessibilityManager.STATE_FLAG_TOUCH_EXPLORATION_ENABLED; + private void showEnableTouchExplorationDialog(final Service service) { + String label = service.mResolveInfo.loadLabel( + mContext.getPackageManager()).toString(); + synchronized (mLock) { + final UserState state = getCurrentUserStateLocked(); + if (state.mIsTouchExplorationEnabled) { + return; + } + if (mEnableTouchExplorationDialog != null + && mEnableTouchExplorationDialog.isShowing()) { + return; + } + mEnableTouchExplorationDialog = new AlertDialog.Builder(mContext) + .setIcon(android.R.drawable.ic_dialog_alert) + .setPositiveButton(android.R.string.ok, new OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + // The user allowed the service to toggle touch exploration. + state.mTouchExplorationGrantedServices.add(service.mComponentName); + persistComponentNamesToSettingLocked( + Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES, + state.mTouchExplorationGrantedServices, state.mUserId); + // Enable touch exploration. + Settings.Secure.putIntForUser(mContext.getContentResolver(), + Settings.Secure.TOUCH_EXPLORATION_ENABLED, 1, + service.mUserId); + } + }) + .setNegativeButton(android.R.string.cancel, new OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + } + }) + .setTitle(R.string.enable_explore_by_touch_warning_title) + .setMessage(mContext.getString( + R.string.enable_explore_by_touch_warning_message, label)) + .create(); + mEnableTouchExplorationDialog.getWindow().setType( + WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG); + mEnableTouchExplorationDialog.setCanceledOnTouchOutside(true); + mEnableTouchExplorationDialog.show(); } - return state; } - /** - * Updates the state of the input filter. - */ - private void updateInputFilterLocked() { - mMainHandler.obtainMessage(MSG_SEND_UPDATE_INPUT_FILTER).sendToTarget(); + private int getClientState(UserState userState) { + int clientState = 0; + if (userState.mIsAccessibilityEnabled) { + clientState |= AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED; + } + // Touch exploration relies on enabled accessibility. + if (userState.mIsAccessibilityEnabled && userState.mIsTouchExplorationEnabled) { + clientState |= AccessibilityManager.STATE_FLAG_TOUCH_EXPLORATION_ENABLED; + } + return clientState; } - /** - * Updated the internal state of this service to match the current settings. - */ - private void updateInternalStateLocked() { - populateInstalledAccessibilityServiceLocked(); - populateEnabledAccessibilityServicesLocked(); - populateTouchExplorationGrantedAccessibilityServicesLocked(); + private void recreateInternalStateLocked(UserState userState) { + populateInstalledAccessibilityServiceLocked(userState); + populateEnabledAccessibilityServicesLocked(userState); + populateTouchExplorationGrantedAccessibilityServicesLocked(userState); - handleTouchExplorationEnabledSettingChangedLocked(); - handleScreenMagnificationEnabledSettingChangedLocked(); - handleAccessibilityEnabledSettingChangedLocked(); + handleTouchExplorationEnabledSettingChangedLocked(userState); + handleDisplayMagnificationEnabledSettingChangedLocked(userState); + handleAccessibilityEnabledSettingChangedLocked(userState); - updateInputFilterLocked(); - sendStateToClientsLocked(); + updateInputFilterLocked(userState); + scheduleSendStateToClientsLocked(userState); } - /** - * Updated the state based on the accessibility enabled setting. - */ - private void handleAccessibilityEnabledSettingChangedLocked() { - mIsAccessibilityEnabled = Settings.Secure.getInt( - mContext.getContentResolver(), - Settings.Secure.ACCESSIBILITY_ENABLED, 0) == 1; - if (mIsAccessibilityEnabled) { - manageServicesLocked(); + private void handleAccessibilityEnabledSettingChangedLocked(UserState userState) { + userState.mIsAccessibilityEnabled = Settings.Secure.getIntForUser( + mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_ENABLED, 0, userState.mUserId) == 1; + if (userState.mIsAccessibilityEnabled ) { + manageServicesLocked(userState); } else { - unbindAllServicesLocked(); + unbindAllServicesLocked(userState); } } - /** - * Updates the state based on the touch exploration enabled setting. - */ - private void handleTouchExplorationEnabledSettingChangedLocked() { - mIsTouchExplorationEnabled = Settings.Secure.getInt( + private void handleTouchExplorationEnabledSettingChangedLocked(UserState userState) { + userState.mIsTouchExplorationEnabled = Settings.Secure.getIntForUser( mContext.getContentResolver(), - Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0) == 1; + Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0, userState.mUserId) == 1; } - /** - * Updates the state based on the screen magnification enabled setting. - */ - private void handleScreenMagnificationEnabledSettingChangedLocked() { - mIsScreenMagnificationEnabled = Settings.Secure.getInt( + private void handleDisplayMagnificationEnabledSettingChangedLocked(UserState userState) { + userState.mIsDisplayMagnificationEnabled = Settings.Secure.getIntForUser( mContext.getContentResolver(), - Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, 0) == 1; + Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, + 0, userState.mUserId) == 1; } - private void handleTouchExplorationGrantedAccessibilityServicesChangedLocked() { - final int serviceCount = mServices.size(); + private void handleTouchExplorationGrantedAccessibilityServicesChangedLocked( + UserState userState) { + final int serviceCount = userState.mServices.size(); for (int i = 0; i < serviceCount; i++) { - Service service = mServices.get(i); + Service service = userState.mServices.get(i); if (service.mRequestTouchExplorationMode - && mTouchExplorationGrantedServices.contains(service.mComponentName)) { + && userState.mTouchExplorationGrantedServices.contains( + service.mComponentName)) { tryEnableTouchExplorationLocked(service); return; } } - if (mIsTouchExplorationEnabled) { - mMainHandler.obtainMessage(MSG_TOGGLE_TOUCH_EXPLORATION, 0, - 0).sendToTarget(); + if (userState.mIsTouchExplorationEnabled) { + Settings.Secure.putIntForUser(mContext.getContentResolver(), + Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0, userState.mUserId); } } private void tryEnableTouchExplorationLocked(final Service service) { - if (!mIsTouchExplorationEnabled && service.mRequestTouchExplorationMode) { - final boolean canToggleTouchExploration = mTouchExplorationGrantedServices.contains( - service.mComponentName); + UserState userState = getUserStateLocked(service.mUserId); + if (!userState.mIsTouchExplorationEnabled && service.mRequestTouchExplorationMode) { + final boolean canToggleTouchExploration = + userState.mTouchExplorationGrantedServices.contains(service.mComponentName); if (!service.mIsAutomation && !canToggleTouchExploration) { - mMainHandler.obtainMessage(MSG_SHOW_ENABLE_TOUCH_EXPLORATION_DIALOG, - service).sendToTarget(); + showEnableTouchExplorationDialog(service); } else { - mMainHandler.obtainMessage(MSG_TOGGLE_TOUCH_EXPLORATION, 1, 0).sendToTarget(); + Settings.Secure.putIntForUser(mContext.getContentResolver(), + Settings.Secure.TOUCH_EXPLORATION_ENABLED, 1, userState.mUserId); } } } private void tryDisableTouchExplorationLocked(Service service) { - if (mIsTouchExplorationEnabled) { - synchronized (mLock) { - final int serviceCount = mServices.size(); - for (int i = 0; i < serviceCount; i++) { - Service other = mServices.get(i); - if (other != service && other.mRequestTouchExplorationMode) { - return; - } + UserState userState = getUserStateLocked(service.mUserId); + if (userState.mIsTouchExplorationEnabled) { + final int serviceCount = userState.mServices.size(); + for (int i = 0; i < serviceCount; i++) { + Service other = userState.mServices.get(i); + if (other != service && other.mRequestTouchExplorationMode) { + return; } - mMainHandler.obtainMessage(MSG_TOGGLE_TOUCH_EXPLORATION, 0, 0).sendToTarget(); } + Settings.Secure.putIntForUser(mContext.getContentResolver(), + Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0, userState.mUserId); } } private class AccessibilityConnectionWrapper implements DeathRecipient { private final int mWindowId; + private final int mUserId; private final IAccessibilityInteractionConnection mConnection; public AccessibilityConnectionWrapper(int windowId, - IAccessibilityInteractionConnection connection) { + IAccessibilityInteractionConnection connection, int userId) { mWindowId = windowId; + mUserId = userId; mConnection = connection; } @@ -1062,12 +1156,17 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { public void binderDied() { unlinkToDeath(); synchronized (mLock) { - removeAccessibilityInteractionConnectionLocked(mWindowId); + removeAccessibilityInteractionConnectionLocked(mWindowId, mUserId); } } } - private class MainHandler extends Handler { + private final class MainHandler extends Handler { + public static final int MSG_SEND_ACCESSIBILITY_EVENT_TO_INPUT_FILTER = 1; + public static final int MSG_SEND_STATE_TO_CLIENTS = 2; + public static final int MSG_SEND_CLEARED_STATE_TO_CLIENTS_FOR_USER = 3; + public static final int MSG_SEND_RECREATE_INTERNAL_STATE = 4; + public static final int MSG_REGISTER_UI_TEST_AUTOMATION_SERVICE = 5; public MainHandler(Looper looper) { super(looper); @@ -1077,104 +1176,70 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { public void handleMessage(Message msg) { final int type = msg.what; switch (type) { - case MSG_TOGGLE_TOUCH_EXPLORATION: { - final int value = msg.arg1; - Settings.Secure.putInt(mContext.getContentResolver(), - Settings.Secure.TOUCH_EXPLORATION_ENABLED, value); - } break; - case MSG_SHOW_ENABLE_TOUCH_EXPLORATION_DIALOG: { - final Service service = (Service) msg.obj; - String label = service.mResolveInfo.loadLabel( - mContext.getPackageManager()).toString(); - synchronized (mLock) { - if (mIsTouchExplorationEnabled) { - return; - } - if (mEnableTouchExplorationDialog != null - && mEnableTouchExplorationDialog.isShowing()) { - return; - } - mEnableTouchExplorationDialog = new AlertDialog.Builder(mContext) - .setIcon(android.R.drawable.ic_dialog_alert) - .setPositiveButton(android.R.string.ok, new OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - // The user allowed the service to toggle touch exploration. - mTouchExplorationGrantedServices.add(service.mComponentName); - persistComponentNamesToSettingLocked( - Settings.Secure. - TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES, - mTouchExplorationGrantedServices); - // Enable touch exploration. - Settings.Secure.putInt(mContext.getContentResolver(), - Settings.Secure.TOUCH_EXPLORATION_ENABLED, 1); - } - }) - .setNegativeButton(android.R.string.cancel, new OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - dialog.dismiss(); - } - }) - .setTitle(R.string.enable_explore_by_touch_warning_title) - .setMessage(mContext.getString( - R.string.enable_explore_by_touch_warning_message, label)) - .create(); - mEnableTouchExplorationDialog.getWindow().setType( - WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG); - mEnableTouchExplorationDialog.setCanceledOnTouchOutside(true); - mEnableTouchExplorationDialog.show(); - } - } break; case MSG_SEND_ACCESSIBILITY_EVENT_TO_INPUT_FILTER: { AccessibilityEvent event = (AccessibilityEvent) msg.obj; - if (mHasInputFilter && mInputFilter != null) { - mInputFilter.notifyAccessibilityEvent(event); + synchronized (mLock) { + if (mHasInputFilter && mInputFilter != null) { + mInputFilter.notifyAccessibilityEvent(event); + } } event.recycle(); } break; - case MSG_SEND_UPDATE_INPUT_FILTER: { - boolean setInputFilter = false; - AccessibilityInputFilter inputFilter = null; + case MSG_SEND_STATE_TO_CLIENTS: { + final int clientState = msg.arg1; + final int userId = msg.arg2; + sendStateToClients(clientState, mGlobalClients); + sendStateToClientsForUser(clientState, userId); + } break; + case MSG_SEND_CLEARED_STATE_TO_CLIENTS_FOR_USER: { + final int userId = msg.arg1; + sendStateToClientsForUser(0, userId); + } break; + case MSG_SEND_RECREATE_INTERNAL_STATE: { + final int userId = msg.arg1; synchronized (mLock) { - if ((mIsAccessibilityEnabled && mIsTouchExplorationEnabled) - || mIsScreenMagnificationEnabled) { - if (!mHasInputFilter) { - mHasInputFilter = true; - if (mInputFilter == null) { - mInputFilter = new AccessibilityInputFilter(mContext, - AccessibilityManagerService.this); - } - inputFilter = mInputFilter; - setInputFilter = true; - } - int flags = 0; - if (mIsScreenMagnificationEnabled) { - flags |= AccessibilityInputFilter.FLAG_FEATURE_SCREEN_MAGNIFIER; - } - if (mIsTouchExplorationEnabled) { - flags |= AccessibilityInputFilter.FLAG_FEATURE_TOUCH_EXPLORATION; - } - mInputFilter.setEnabledFeatures(flags); - } else { - if (mHasInputFilter) { - mHasInputFilter = false; - mInputFilter.setEnabledFeatures(0); - inputFilter = null; - setInputFilter = true; - } - } + UserState userState = getUserStateLocked(userId); + recreateInternalStateLocked(userState); } - if (setInputFilter) { - try { - mWindowManager.setInputFilter(inputFilter); - } catch (RemoteException re) { - /* ignore */ - } + } break; + case MSG_REGISTER_UI_TEST_AUTOMATION_SERVICE: { + SomeArgs args = (SomeArgs) msg.obj; + try { + IAccessibilityServiceClient client = + (IAccessibilityServiceClient) args.arg1; + AccessibilityServiceInfo info = (AccessibilityServiceInfo) args.arg2; + registerUiTestAutomationService(client, info); + } finally { + args.recycle(); } } break; } } + + private void sendStateToClientsForUser(int clientState, int userId) { + final UserState userState; + synchronized (mLock) { + userState = getUserStateLocked(userId); + } + sendStateToClients(clientState, userState.mClients); + } + + private void sendStateToClients(int clientState, + RemoteCallbackList<IAccessibilityManagerClient> clients) { + try { + final int userClientCount = clients.beginBroadcast(); + for (int i = 0; i < userClientCount; i++) { + IAccessibilityManagerClient client = clients.getBroadcastItem(i); + try { + client.setState(clientState); + } catch (RemoteException re) { + /* ignore */ + } + } + } finally { + clients.finishBroadcast(); + } + } } /** @@ -1192,6 +1257,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { // used as message types allowing us to remove messages per event type. private static final int MSG_ON_GESTURE = 0x80000000; + final int mUserId; + int mId = 0; AccessibilityServiceInfo mAccessibilityServiceInfo; @@ -1250,8 +1317,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } }; - public Service(ComponentName componentName, + public Service(int userId, ComponentName componentName, AccessibilityServiceInfo accessibilityServiceInfo, boolean isAutomation) { + mUserId = userId; mResolveInfo = accessibilityServiceInfo.getResolveInfo(); mId = sIdCounter++; mComponentName = componentName; @@ -1312,7 +1380,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { */ public boolean bind() { if (!mIsAutomation && mService == null) { - return mContext.bindService(mIntent, this, Context.BIND_AUTO_CREATE); + return mContext.bindService(mIntent, this, Context.BIND_AUTO_CREATE, mUserId); } return false; } @@ -1355,17 +1423,22 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { @Override public void setServiceInfo(AccessibilityServiceInfo info) { - synchronized (mLock) { - // If the XML manifest had data to configure the service its info - // should be already set. In such a case update only the dynamically - // configurable properties. - AccessibilityServiceInfo oldInfo = mAccessibilityServiceInfo; - if (oldInfo != null) { - oldInfo.updateDynamicallyConfigurableProperties(info); - setDynamicallyConfigurableProperties(oldInfo); - } else { - setDynamicallyConfigurableProperties(info); + final long identity = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + // If the XML manifest had data to configure the service its info + // should be already set. In such a case update only the dynamically + // configurable properties. + AccessibilityServiceInfo oldInfo = mAccessibilityServiceInfo; + if (oldInfo != null) { + oldInfo.updateDynamicallyConfigurableProperties(info); + setDynamicallyConfigurableProperties(oldInfo); + } else { + setDynamicallyConfigurableProperties(info); + } } + } finally { + Binder.restoreCallingIdentity(identity); } } @@ -1376,7 +1449,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { try { mServiceInterface.setConnection(this, mId); synchronized (mLock) { - tryAddServiceLocked(this); + tryAddServiceLocked(this, mUserId); } } catch (RemoteException re) { Slog.w(LOG_TAG, "Error while setting Controller for service: " + service, re); @@ -1388,14 +1461,21 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { long accessibilityNodeId, int viewId, int interactionId, IAccessibilityInteractionConnectionCallback callback, long interrogatingTid) throws RemoteException { - final int resolvedWindowId = resolveAccessibilityWindowId(accessibilityWindowId); + final int resolvedWindowId; IAccessibilityInteractionConnection connection = null; synchronized (mLock) { + final int resolvedUserId = mSecurityPolicy + .resolveCallingUserIdEnforcingPermissionsLocked( + UserHandle.getCallingUserId()); + if (resolvedUserId != mCurrentUserId) { + return -1; + } mSecurityPolicy.enforceCanRetrieveWindowContent(this); final boolean permissionGranted = mSecurityPolicy.canRetrieveWindowContent(this); if (!permissionGranted) { return 0; } else { + resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId); connection = getConnectionLocked(resolvedWindowId); if (connection == null) { return 0; @@ -1425,10 +1505,17 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { long accessibilityNodeId, String text, int interactionId, IAccessibilityInteractionConnectionCallback callback, long interrogatingTid) throws RemoteException { - final int resolvedWindowId = resolveAccessibilityWindowId(accessibilityWindowId); + final int resolvedWindowId; IAccessibilityInteractionConnection connection = null; synchronized (mLock) { + final int resolvedUserId = mSecurityPolicy + .resolveCallingUserIdEnforcingPermissionsLocked( + UserHandle.getCallingUserId()); + if (resolvedUserId != mCurrentUserId) { + return -1; + } mSecurityPolicy.enforceCanRetrieveWindowContent(this); + resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId); final boolean permissionGranted = mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId); if (!permissionGranted) { @@ -1464,10 +1551,17 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { long accessibilityNodeId, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, long interrogatingTid) throws RemoteException { - final int resolvedWindowId = resolveAccessibilityWindowId(accessibilityWindowId); + final int resolvedWindowId; IAccessibilityInteractionConnection connection = null; synchronized (mLock) { + final int resolvedUserId = mSecurityPolicy + .resolveCallingUserIdEnforcingPermissionsLocked( + UserHandle.getCallingUserId()); + if (resolvedUserId != mCurrentUserId) { + return -1; + } mSecurityPolicy.enforceCanRetrieveWindowContent(this); + resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId); final boolean permissionGranted = mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId); if (!permissionGranted) { @@ -1502,10 +1596,17 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { int focusType, int interactionId, IAccessibilityInteractionConnectionCallback callback, long interrogatingTid) throws RemoteException { - final int resolvedWindowId = resolveAccessibilityWindowId(accessibilityWindowId); + final int resolvedWindowId; IAccessibilityInteractionConnection connection = null; synchronized (mLock) { + final int resolvedUserId = mSecurityPolicy + .resolveCallingUserIdEnforcingPermissionsLocked( + UserHandle.getCallingUserId()); + if (resolvedUserId != mCurrentUserId) { + return -1; + } mSecurityPolicy.enforceCanRetrieveWindowContent(this); + resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId); final boolean permissionGranted = mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId); if (!permissionGranted) { @@ -1540,10 +1641,17 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { int direction, int interactionId, IAccessibilityInteractionConnectionCallback callback, long interrogatingTid) throws RemoteException { - final int resolvedWindowId = resolveAccessibilityWindowId(accessibilityWindowId); + final int resolvedWindowId; IAccessibilityInteractionConnection connection = null; synchronized (mLock) { + final int resolvedUserId = mSecurityPolicy + .resolveCallingUserIdEnforcingPermissionsLocked( + UserHandle.getCallingUserId()); + if (resolvedUserId != mCurrentUserId) { + return -1; + } mSecurityPolicy.enforceCanRetrieveWindowContent(this); + resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId); final boolean permissionGranted = mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId); if (!permissionGranted) { @@ -1576,10 +1684,19 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { @Override public boolean performAccessibilityAction(int accessibilityWindowId, long accessibilityNodeId, int action, Bundle arguments, int interactionId, - IAccessibilityInteractionConnectionCallback callback, long interrogatingTid) { - final int resolvedWindowId = resolveAccessibilityWindowId(accessibilityWindowId); + IAccessibilityInteractionConnectionCallback callback, long interrogatingTid) + throws RemoteException { + final int resolvedWindowId; IAccessibilityInteractionConnection connection = null; synchronized (mLock) { + final int resolvedUserId = mSecurityPolicy + .resolveCallingUserIdEnforcingPermissionsLocked( + UserHandle.getCallingUserId()); + if (resolvedUserId != mCurrentUserId) { + return false; + } + mSecurityPolicy.enforceCanRetrieveWindowContent(this); + resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId); final boolean permissionGranted = mSecurityPolicy.canPerformActionLocked(this, resolvedWindowId, action, arguments); if (!permissionGranted) { @@ -1608,22 +1725,35 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { return true; } - public boolean performGlobalAction(int action) { - switch (action) { - case AccessibilityService.GLOBAL_ACTION_BACK: { - sendDownAndUpKeyEvents(KeyEvent.KEYCODE_BACK); - } return true; - case AccessibilityService.GLOBAL_ACTION_HOME: { - sendDownAndUpKeyEvents(KeyEvent.KEYCODE_HOME); - } return true; - case AccessibilityService.GLOBAL_ACTION_RECENTS: { - openRecents(); - } return true; - case AccessibilityService.GLOBAL_ACTION_NOTIFICATIONS: { - expandStatusBar(); - } return true; + public boolean performGlobalAction(int action) throws RemoteException { + synchronized (mLock) { + final int resolvedUserId = mSecurityPolicy + .resolveCallingUserIdEnforcingPermissionsLocked( + UserHandle.getCallingUserId()); + if (resolvedUserId != mCurrentUserId) { + return false; + } + } + final long identity = Binder.clearCallingIdentity(); + try { + switch (action) { + case AccessibilityService.GLOBAL_ACTION_BACK: { + sendDownAndUpKeyEvents(KeyEvent.KEYCODE_BACK); + } return true; + case AccessibilityService.GLOBAL_ACTION_HOME: { + sendDownAndUpKeyEvents(KeyEvent.KEYCODE_HOME); + } return true; + case AccessibilityService.GLOBAL_ACTION_RECENTS: { + openRecents(); + } return true; + case AccessibilityService.GLOBAL_ACTION_NOTIFICATIONS: { + expandStatusBar(); + } return true; + } + return false; + } finally { + Binder.restoreCallingIdentity(identity); } - return false; } public void onServiceDisconnected(ComponentName componentName) { @@ -1658,7 +1788,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { // the state based on values in the settings database. if (mIsAutomation) { mUiAutomationService = null; - updateInternalStateLocked(); + recreateInternalStateLocked(getUserStateLocked(mUserId)); } } } @@ -1817,8 +1947,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { if (DEBUG) { Slog.i(LOG_TAG, "Trying to get interaction connection to windowId: " + windowId); } - AccessibilityConnectionWrapper wrapper = mWindowIdToInteractionConnectionWrapperMap.get( - windowId); + AccessibilityConnectionWrapper wrapper = mGlobalInteractionConnections.get(windowId); + if (wrapper == null) { + wrapper = getCurrentUserStateLocked().mInteractionConnections.get(windowId); + } if (wrapper != null && wrapper.mConnection != null) { return wrapper.mConnection; } @@ -1828,7 +1960,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { return null; } - private int resolveAccessibilityWindowId(int accessibilityWindowId) { + private int resolveAccessibilityWindowIdLocked(int accessibilityWindowId) { if (accessibilityWindowId == AccessibilityNodeInfo.ACTIVE_WINDOW_ID) { return mSecurityPolicy.mActiveWindowId; } @@ -1836,9 +1968,15 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } private float getCompatibilityScale(int windowId) { - IBinder windowToken = mWindowIdToWindowTokenMap.get(windowId); try { - return mWindowManager.getWindowCompatibilityScale(windowToken); + IBinder windowToken = mGlobalWindowTokens.get(windowId); + if (windowToken != null) { + return mWindowManagerService.getWindowCompatibilityScale(windowToken); + } + windowToken = getCurrentUserStateLocked().mWindowTokens.get(windowId); + if (windowToken != null) { + return mWindowManagerService.getWindowCompatibilityScale(windowToken); + } } catch (RemoteException re) { /* ignore */ } @@ -1941,6 +2079,38 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } } + public int resolveCallingUserIdEnforcingPermissionsLocked(int userId) { + final int callingUid = Binder.getCallingUid(); + if (callingUid == Process.SYSTEM_UID + || callingUid == Process.SHELL_UID) { + return mCurrentUserId; + } + final int callingUserId = UserHandle.getUserId(callingUid); + if (callingUserId == userId) { + return userId; + } + if (!hasPermission(Manifest.permission.INTERACT_ACROSS_USERS) + && !hasPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL)) { + throw new SecurityException("Call from user " + callingUserId + " as user " + + userId + " without permission INTERACT_ACROSS_USERS or " + + "INTERACT_ACROSS_USERS_FULL not allowed."); + } + if (userId == UserHandle.USER_CURRENT + || userId == UserHandle.USER_CURRENT_OR_SELF) { + return mCurrentUserId; + } + throw new IllegalArgumentException("Calling user can be changed to only " + + "UserHandle.USER_CURRENT or UserHandle.USER_CURRENT_OR_SELF."); + } + + public boolean isCallerInteractingAcrossUsers(int userId) { + final int callingUid = Binder.getCallingUid(); + return (callingUid == Process.SYSTEM_UID + || callingUid == Process.SHELL_UID + || userId == UserHandle.USER_CURRENT + || userId == UserHandle.USER_CURRENT_OR_SELF); + } + private boolean isRetrievalAllowingWindow(int windowId) { return (mActiveWindowId == windowId); } @@ -1953,22 +2123,25 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { if (OWN_PROCESS_ID == Binder.getCallingPid()) { return; } - final int permissionStatus = mContext.checkCallingPermission(permission); - if (permissionStatus != PackageManager.PERMISSION_GRANTED) { + if (!hasPermission(permission)) { throw new SecurityException("You do not have " + permission + " required to call " + function); } } + private boolean hasPermission(String permission) { + return mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED; + } + private int getFocusedWindowId() { final long identity = Binder.clearCallingIdentity(); try { // We call this only on window focus change or after touch // exploration gesture end and the shown windows are not that // many, so the linear look up is just fine. - IBinder token = mWindowManager.getFocusedWindowToken(); + IBinder token = mWindowManagerService.getFocusedWindowToken(); if (token != null) { - SparseArray<IBinder> windows = mWindowIdToWindowTokenMap; + SparseArray<IBinder> windows = getCurrentUserStateLocked().mWindowTokens; final int windowCount = windows.size(); for (int i = 0; i < windowCount; i++) { if (windows.valueAt(i) == token) { @@ -1984,4 +2157,129 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { return -1; } } + + private class UserState { + public final int mUserId; + + public final CopyOnWriteArrayList<Service> mServices = new CopyOnWriteArrayList<Service>(); + + public final RemoteCallbackList<IAccessibilityManagerClient> mClients = + new RemoteCallbackList<IAccessibilityManagerClient>(); + + public final Map<ComponentName, Service> mComponentNameToServiceMap = + new HashMap<ComponentName, Service>(); + + public final List<AccessibilityServiceInfo> mInstalledServices = + new ArrayList<AccessibilityServiceInfo>(); + + public final Set<ComponentName> mEnabledServices = new HashSet<ComponentName>(); + + public final Set<ComponentName> mTouchExplorationGrantedServices = + new HashSet<ComponentName>(); + + public final SparseArray<AccessibilityConnectionWrapper> + mInteractionConnections = + new SparseArray<AccessibilityConnectionWrapper>(); + + public final SparseArray<IBinder> mWindowTokens = new SparseArray<IBinder>(); + + public int mHandledFeedbackTypes = 0; + + public boolean mIsAccessibilityEnabled; + public boolean mIsTouchExplorationEnabled; + public boolean mIsDisplayMagnificationEnabled; + + public UserState(int userId) { + mUserId = userId; + } + } + + private final class AccessibilityContentObserver extends ContentObserver { + + private final Uri mAccessibilityEnabledUri = Settings.Secure.getUriFor( + Settings.Secure.ACCESSIBILITY_ENABLED); + + private final Uri mTouchExplorationEnabledUri = Settings.Secure.getUriFor( + Settings.Secure.TOUCH_EXPLORATION_ENABLED); + + private final Uri mDisplayMagnificationEnabledUri = Settings.Secure.getUriFor( + Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED); + + private final Uri mEnabledAccessibilityServicesUri = Settings.Secure.getUriFor( + Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES); + + private final Uri mTouchExplorationGrantedAccessibilityServicesUri = Settings.Secure + .getUriFor(Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES); + + public AccessibilityContentObserver(Handler handler) { + super(handler); + } + + public void register(ContentResolver contentResolver) { + contentResolver.registerContentObserver(mAccessibilityEnabledUri, + false, this, UserHandle.USER_ALL); + contentResolver.registerContentObserver(mTouchExplorationEnabledUri, + false, this, UserHandle.USER_ALL); + contentResolver.registerContentObserver(mDisplayMagnificationEnabledUri, + false, this, UserHandle.USER_ALL); + contentResolver.registerContentObserver(mEnabledAccessibilityServicesUri, + false, this, UserHandle.USER_ALL); + contentResolver.registerContentObserver( + mTouchExplorationGrantedAccessibilityServicesUri, + false, this, UserHandle.USER_ALL); + } + + @Override + public void onChange(boolean selfChange, Uri uri) { + if (mAccessibilityEnabledUri.equals(uri)) { + synchronized (mLock) { + // We will update when the automation service dies. + if (mUiAutomationService == null) { + UserState userState = getCurrentUserStateLocked(); + handleAccessibilityEnabledSettingChangedLocked(userState); + updateInputFilterLocked(userState); + scheduleSendStateToClientsLocked(userState); + } + } + } else if (mTouchExplorationEnabledUri.equals(uri)) { + synchronized (mLock) { + // We will update when the automation service dies. + if (mUiAutomationService == null) { + UserState userState = getCurrentUserStateLocked(); + handleTouchExplorationEnabledSettingChangedLocked(userState); + updateInputFilterLocked(userState); + scheduleSendStateToClientsLocked(userState); + } + } + } else if (mDisplayMagnificationEnabledUri.equals(uri)) { + synchronized (mLock) { + // We will update when the automation service dies. + if (mUiAutomationService == null) { + UserState userState = getCurrentUserStateLocked(); + handleDisplayMagnificationEnabledSettingChangedLocked(userState); + updateInputFilterLocked(userState); + scheduleSendStateToClientsLocked(userState); + } + } + } else if (mEnabledAccessibilityServicesUri.equals(uri)) { + synchronized (mLock) { + // We will update when the automation service dies. + if (mUiAutomationService == null) { + UserState userState = getCurrentUserStateLocked(); + populateEnabledAccessibilityServicesLocked(userState); + manageServicesLocked(userState); + } + } + } else if (mTouchExplorationGrantedAccessibilityServicesUri.equals(uri)) { + synchronized (mLock) { + // We will update when the automation service dies. + if (mUiAutomationService == null) { + UserState userState = getCurrentUserStateLocked(); + populateTouchExplorationGrantedAccessibilityServicesLocked(userState); + handleTouchExplorationGrantedAccessibilityServicesChangedLocked(userState); + } + } + } + } + } } diff --git a/services/java/com/android/server/accessibility/TouchExplorer.java b/services/java/com/android/server/accessibility/TouchExplorer.java index cb6b31a..c84f988 100644 --- a/services/java/com/android/server/accessibility/TouchExplorer.java +++ b/services/java/com/android/server/accessibility/TouchExplorer.java @@ -1150,20 +1150,9 @@ class TouchExplorer implements EventStreamTransformation { return; } - if (Build.IS_DEBUGGABLE) { - if (mSendHoverEnterDelayed.isPending()) { - throw new IllegalStateException("mSendHoverEnterDelayed must not be pending."); - } - if (mSendHoverExitDelayed.isPending()) { - throw new IllegalStateException("mSendHoverExitDelayed must not be pending."); - } - if (!mPerformLongPressDelayed.isPending()) { - throw new IllegalStateException( - "mPerformLongPressDelayed must not be pending."); - } - } - // Remove pending event deliveries. + mSendHoverEnterDelayed.remove(); + mSendHoverExitDelayed.remove(); mPerformLongPressDelayed.remove(); // The touch interaction has ended since we will send a click. diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index f162dae..a6f2974 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -6414,10 +6414,6 @@ public final class ActivityManagerService extends ActivityManagerNative + " (pid=" + Binder.getCallingPid() + ") when getting content provider " + name); } - if (r.userId != userId) { - throw new SecurityException("Calling requested user " + userId - + " but app is user " + r.userId); - } } // First check if this content provider has been published... @@ -6666,7 +6662,7 @@ public final class ActivityManagerService extends ActivityManagerNative } public final ContentProviderHolder getContentProvider( - IApplicationThread caller, String name, boolean stable) { + IApplicationThread caller, String name, int userId, boolean stable) { enforceNotIsolatedCaller("getContentProvider"); if (caller == null) { String msg = "null IApplicationThread when getting content provider " @@ -6675,14 +6671,18 @@ public final class ActivityManagerService extends ActivityManagerNative throw new SecurityException(msg); } - return getContentProviderImpl(caller, name, null, stable, - UserHandle.getCallingUserId()); + userId = handleIncomingUserLocked(Binder.getCallingPid(), Binder.getCallingUid(), userId, + false, true, "getContentProvider", null); + return getContentProviderImpl(caller, name, null, stable, userId); } - public ContentProviderHolder getContentProviderExternal(String name, IBinder token) { + public ContentProviderHolder getContentProviderExternal( + String name, int userId, IBinder token) { enforceCallingPermission(android.Manifest.permission.ACCESS_CONTENT_PROVIDERS_EXTERNALLY, "Do not have permission in call getContentProviderExternal()"); - return getContentProviderExternalUnchecked(name, token, UserHandle.getCallingUserId()); + userId = handleIncomingUserLocked(Binder.getCallingPid(), Binder.getCallingUid(), userId, + false, true, "getContentProvider", null); + return getContentProviderExternalUnchecked(name, token, userId); } private ContentProviderHolder getContentProviderExternalUnchecked(String name, diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java index 05ff379..1707ff0 100755 --- a/services/java/com/android/server/am/ActivityStack.java +++ b/services/java/com/android/server/am/ActivityStack.java @@ -4329,6 +4329,9 @@ final class ActivityStack { if (resumed != null && resumed.thumbHolder == tr) { info.mainThumbnail = resumed.stack.screenshotActivities(resumed); } + if (info.mainThumbnail == null) { + info.mainThumbnail = tr.lastThumbnail; + } return info; } @@ -4343,7 +4346,7 @@ final class ActivityStack { // thumbnail to return. TaskAccessInfo info = getTaskAccessInfoLocked(tr.taskId, true); if (info.numSubThumbbails <= 0) { - return info.mainThumbnail; + return info.mainThumbnail != null ? info.mainThumbnail : tr.lastThumbnail; } else { return info.subtasks.get(info.numSubThumbbails-1).holder.lastThumbnail; } @@ -4387,6 +4390,8 @@ final class ActivityStack { while (j < NA) { ActivityRecord ar = mHistory.get(j); if (!ar.finishing && ar.task.taskId == taskId) { + thumbs.root = ar; + thumbs.rootIndex = j; holder = ar.thumbHolder; if (holder != null) { thumbs.mainThumbnail = holder.lastThumbnail; @@ -4401,9 +4406,6 @@ final class ActivityStack { return thumbs; } - thumbs.root = mHistory.get(j); - thumbs.rootIndex = j; - ArrayList<TaskAccessInfo.SubTask> subtasks = new ArrayList<TaskAccessInfo.SubTask>(); thumbs.subtasks = subtasks; while (j < NA) { diff --git a/services/java/com/android/server/display/DisplayManagerService.java b/services/java/com/android/server/display/DisplayManagerService.java index b109f2a..85f3b56 100644 --- a/services/java/com/android/server/display/DisplayManagerService.java +++ b/services/java/com/android/server/display/DisplayManagerService.java @@ -536,6 +536,8 @@ public final class DisplayManagerService extends IDisplayManager.Stub { return; } + Slog.i(TAG, "Display device added: " + device.getDisplayDeviceInfoLocked()); + mDisplayDevices.add(device); addLogicalDisplayLocked(device); scheduleTraversalLocked(); @@ -550,6 +552,8 @@ public final class DisplayManagerService extends IDisplayManager.Stub { return; } + Slog.i(TAG, "Display device changed: " + device.getDisplayDeviceInfoLocked()); + device.applyPendingDisplayDeviceInfoChangesLocked(); if (updateLogicalDisplaysLocked()) { scheduleTraversalLocked(); @@ -565,6 +569,8 @@ public final class DisplayManagerService extends IDisplayManager.Stub { return; } + Slog.i(TAG, "Display device removed: " + device.getDisplayDeviceInfoLocked()); + mRemovedDisplayDevices.add(device); updateLogicalDisplaysLocked(); scheduleTraversalLocked(); diff --git a/services/java/com/android/server/display/LocalDisplayAdapter.java b/services/java/com/android/server/display/LocalDisplayAdapter.java index eab4c9a..9c51463 100644 --- a/services/java/com/android/server/display/LocalDisplayAdapter.java +++ b/services/java/com/android/server/display/LocalDisplayAdapter.java @@ -19,7 +19,9 @@ package com.android.server.display; import android.content.Context; import android.os.Handler; import android.os.IBinder; +import android.os.Looper; import android.util.SparseArray; +import android.view.DisplayEventReceiver; import android.view.Surface; import android.view.Surface.PhysicalDisplayInfo; @@ -41,12 +43,14 @@ final class LocalDisplayAdapter extends DisplayAdapter { private final SparseArray<LocalDisplayDevice> mDevices = new SparseArray<LocalDisplayDevice>(); + private final HotplugDisplayEventReceiver mHotplugReceiver; private final PhysicalDisplayInfo mTempPhys = new PhysicalDisplayInfo(); public LocalDisplayAdapter(DisplayManagerService.SyncRoot syncRoot, Context context, Handler handler, Listener listener) { super(syncRoot, context, handler, listener, TAG); + mHotplugReceiver = new HotplugDisplayEventReceiver(handler.getLooper()); } @Override @@ -148,4 +152,17 @@ final class LocalDisplayAdapter extends DisplayAdapter { pw.println("mPhys=" + mPhys); } } -} + + private final class HotplugDisplayEventReceiver extends DisplayEventReceiver { + public HotplugDisplayEventReceiver(Looper looper) { + super(looper); + } + + @Override + public void onHotplug(long timestampNanos, int builtInDisplayId, boolean connected) { + synchronized (getSyncRoot()) { + scanDisplaysLocked(); + } + } + } +}
\ No newline at end of file diff --git a/services/java/com/android/server/display/WifiDisplayController.java b/services/java/com/android/server/display/WifiDisplayController.java index 58f0445..d533c94 100644 --- a/services/java/com/android/server/display/WifiDisplayController.java +++ b/services/java/com/android/server/display/WifiDisplayController.java @@ -73,7 +73,7 @@ final class WifiDisplayController implements DumpUtils.Dump { private static final int DEFAULT_CONTROL_PORT = 7236; private static final int MAX_THROUGHPUT = 50; - private static final int CONNECTION_TIMEOUT_SECONDS = 30; + private static final int CONNECTION_TIMEOUT_SECONDS = 60; private static final int RTSP_TIMEOUT_SECONDS = 15; private static final int DISCOVER_PEERS_MAX_RETRIES = 10; diff --git a/services/java/com/android/server/location/LocationFudger.java b/services/java/com/android/server/location/LocationFudger.java index 84fd255..2a68743 100644 --- a/services/java/com/android/server/location/LocationFudger.java +++ b/services/java/com/android/server/location/LocationFudger.java @@ -22,6 +22,7 @@ import java.security.SecureRandom; import android.content.Context; import android.database.ContentObserver; import android.location.Location; +import android.location.LocationManager; import android.os.Bundle; import android.os.Handler; import android.os.Parcelable; @@ -40,8 +41,6 @@ public class LocationFudger { private static final boolean D = false; private static final String TAG = "LocationFudge"; - private static final String EXTRA_COARSE_LOCATION = "coarseLocation"; - /** * Default coarse accuracy in meters. */ @@ -168,18 +167,10 @@ public class LocationFudger { */ public Location getOrCreate(Location location) { synchronized (mLock) { - Bundle extras = location.getExtras(); - if (extras == null) { - return addCoarseLocationExtraLocked(location); - } - Parcelable parcel = extras.getParcelable(EXTRA_COARSE_LOCATION); - if (parcel == null) { - return addCoarseLocationExtraLocked(location); - } - if (!(parcel instanceof Location)) { + Location coarse = location.getExtraLocation(Location.EXTRA_COARSE_LOCATION); + if (coarse == null) { return addCoarseLocationExtraLocked(location); } - Location coarse = (Location) parcel; if (coarse.getAccuracy() < mAccuracyInMeters) { return addCoarseLocationExtraLocked(location); } @@ -188,11 +179,8 @@ public class LocationFudger { } private Location addCoarseLocationExtraLocked(Location location) { - Bundle extras = location.getExtras(); - if (extras == null) extras = new Bundle(); Location coarse = createCoarseLocked(location); - extras.putParcelable(EXTRA_COARSE_LOCATION, coarse); - location.setExtras(extras); + location.setExtraLocation(Location.EXTRA_COARSE_LOCATION, coarse); return coarse; } diff --git a/services/java/com/android/server/location/PassiveProvider.java b/services/java/com/android/server/location/PassiveProvider.java index 0ce21b7..71bae07 100644 --- a/services/java/com/android/server/location/PassiveProvider.java +++ b/services/java/com/android/server/location/PassiveProvider.java @@ -114,6 +114,6 @@ public class PassiveProvider implements LocationProviderInterface { @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - pw.println("mReportLocaiton=" + mReportLocation); + pw.println("mReportLocation=" + mReportLocation); } } diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java index 739caa0..4800e7db 100644 --- a/services/java/com/android/server/pm/PackageManagerService.java +++ b/services/java/com/android/server/pm/PackageManagerService.java @@ -413,7 +413,6 @@ public class PackageManagerService extends IPackageManager.Stub { // package uri's from external media onto secure containers // or internal storage. private IMediaContainerService mContainerService = null; - private int mContainerServiceUserId; static final int SEND_PENDING_BROADCAST = 1; static final int MCS_BOUND = 3; @@ -482,15 +481,8 @@ public class PackageManagerService extends IPackageManager.Stub { " DefaultContainerService"); Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT); Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT); - mContainerServiceUserId = 0; - if (mPendingInstalls.size() > 0) { - mContainerServiceUserId = mPendingInstalls.get(0).getUser().getIdentifier(); - if (mContainerServiceUserId == UserHandle.USER_ALL) { - mContainerServiceUserId = 0; - } - } if (mContext.bindService(service, mDefContainerConn, - Context.BIND_AUTO_CREATE, mContainerServiceUserId)) { + Context.BIND_AUTO_CREATE, UserHandle.USER_OWNER)) { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); mBound = true; return true; @@ -567,15 +559,6 @@ public class PackageManagerService extends IPackageManager.Stub { } else if (mPendingInstalls.size() > 0) { HandlerParams params = mPendingInstalls.get(0); if (params != null) { - // Check if we're connected to the correct service, if it's an install - // request. - final int installFor = params.getUser().getIdentifier(); - if (installFor != mContainerServiceUserId - && (installFor == UserHandle.USER_ALL - && mContainerServiceUserId != 0)) { - mHandler.sendEmptyMessage(MCS_RECONNECT); - return; - } if (params.startCopy()) { // We are done... look for more work or to // go idle. @@ -693,20 +676,23 @@ public class PackageManagerService extends IPackageManager.Stub { } case START_CLEANING_PACKAGE: { Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT); - PackageCleanItem item = new PackageCleanItem((String)msg.obj, - msg.arg2 != 0); + final String packageName = (String)msg.obj; + final int userId = msg.arg1; + final boolean andCode = msg.arg2 != 0; synchronized (mPackages) { - if (msg.arg1 == UserHandle.USER_ALL) { + if (userId == UserHandle.USER_ALL) { int[] users = sUserManager.getUserIds(); for (int user : users) { - mSettings.addPackageToCleanLPw(user, item); + mSettings.addPackageToCleanLPw( + new PackageCleanItem(user, packageName, andCode)); } } else { - mSettings.addPackageToCleanLPw(msg.arg1, item); + mSettings.addPackageToCleanLPw( + new PackageCleanItem(userId, packageName, andCode)); } } Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); - startCleaningPackages(-1); + startCleaningPackages(); } break; case POST_INSTALL: { if (DEBUG_INSTALL) Log.v(TAG, "Handling post-install for " + msg.arg1); @@ -1715,6 +1701,7 @@ public class PackageManagerService extends IPackageManager.Stub { } public int[] getPackageGids(String packageName) { + final boolean enforcedDefault = isPermissionEnforcedDefault(READ_EXTERNAL_STORAGE); // reader synchronized (mPackages) { PackageParser.Package p = mPackages.get(packageName); @@ -1726,7 +1713,7 @@ public class PackageManagerService extends IPackageManager.Stub { int[] gids = suid != null ? suid.gids : ps.gids; // include GIDs for any unenforced permissions - if (!isPermissionEnforcedLocked(READ_EXTERNAL_STORAGE)) { + if (!isPermissionEnforcedLocked(READ_EXTERNAL_STORAGE, enforcedDefault)) { final BasePermission basePerm = mSettings.mPermissions.get( READ_EXTERNAL_STORAGE); gids = appendInts(gids, basePerm.gids); @@ -2054,6 +2041,7 @@ public class PackageManagerService extends IPackageManager.Stub { } public int checkPermission(String permName, String pkgName) { + final boolean enforcedDefault = isPermissionEnforcedDefault(permName); synchronized (mPackages) { PackageParser.Package p = mPackages.get(pkgName); if (p != null && p.mExtras != null) { @@ -2066,7 +2054,7 @@ public class PackageManagerService extends IPackageManager.Stub { return PackageManager.PERMISSION_GRANTED; } } - if (!isPermissionEnforcedLocked(permName)) { + if (!isPermissionEnforcedLocked(permName, enforcedDefault)) { return PackageManager.PERMISSION_GRANTED; } } @@ -2074,6 +2062,7 @@ public class PackageManagerService extends IPackageManager.Stub { } public int checkUidPermission(String permName, int uid) { + final boolean enforcedDefault = isPermissionEnforcedDefault(permName); synchronized (mPackages) { Object obj = mSettings.getUserIdLPr(UserHandle.getAppId(uid)); if (obj != null) { @@ -2087,7 +2076,7 @@ public class PackageManagerService extends IPackageManager.Stub { return PackageManager.PERMISSION_GRANTED; } } - if (!isPermissionEnforcedLocked(permName)) { + if (!isPermissionEnforcedLocked(permName, enforcedDefault)) { return PackageManager.PERMISSION_GRANTED; } } @@ -2488,6 +2477,15 @@ public class PackageManagerService extends IPackageManager.Stub { if (ri != null) { return ri; } + if (userId != 0) { + ri = new ResolveInfo(mResolveInfo); + ri.activityInfo = new ActivityInfo(ri.activityInfo); + ri.activityInfo.applicationInfo = new ApplicationInfo( + ri.activityInfo.applicationInfo); + ri.activityInfo.applicationInfo.uid = UserHandle.getUid(userId, + UserHandle.getAppId(ri.activityInfo.applicationInfo.uid)); + return ri; + } return mResolveInfo; } } @@ -3668,7 +3666,7 @@ public class PackageManagerService extends IPackageManager.Stub { mResolveActivity.applicationInfo = mAndroidApplication; mResolveActivity.name = ResolverActivity.class.getName(); mResolveActivity.packageName = mAndroidApplication.packageName; - mResolveActivity.processName = mAndroidApplication.processName; + mResolveActivity.processName = "system:ui"; mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE; mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS; mResolveActivity.theme = com.android.internal.R.style.Theme_Holo_Dialog_Alert; @@ -4181,10 +4179,14 @@ public class PackageManagerService extends IPackageManager.Stub { // Add the new setting to mPackages mPackages.put(pkg.applicationInfo.packageName, pkg); // Make sure we don't accidentally delete its data. - for (int i=0; i<mSettings.mPackagesToBeCleaned.size(); i++) { - mSettings.mPackagesToBeCleaned.valueAt(i).remove(pkgName); + final Iterator<PackageCleanItem> iter = mSettings.mPackagesToBeCleaned.iterator(); + while (iter.hasNext()) { + PackageCleanItem item = iter.next(); + if (pkgName.equals(item.packageName)) { + iter.remove(); + } } - + // Take care of first install / last update times. if (currentTime != 0) { if (pkgSetting.firstInstallTime == 0) { @@ -5431,7 +5433,6 @@ public class PackageManagerService extends IPackageManager.Stub { public PackageCleanItem nextPackageToClean(PackageCleanItem lastPackage) { // writer - final int userId = UserHandle.getCallingUserId(); synchronized (mPackages) { if (!isExternalMediaAvailable()) { // If the external storage is no longer mounted at this point, @@ -5439,23 +5440,13 @@ public class PackageManagerService extends IPackageManager.Stub { // packages files and can not delete any more. Bail. return null; } - ArrayList<PackageCleanItem> pkgs = mSettings.mPackagesToBeCleaned.get(userId); - if (pkgs != null) { - if (lastPackage != null) { - pkgs.remove(lastPackage); - } - if (pkgs.size() > 0) { - return pkgs.get(0); - } + final ArrayList<PackageCleanItem> pkgs = mSettings.mPackagesToBeCleaned; + if (lastPackage != null) { + pkgs.remove(lastPackage); + } + if (pkgs.size() > 0) { + return pkgs.get(0); } - mSettings.mPackagesToBeCleaned.remove(userId); - } - // Move on to the next user to clean. - long ident = Binder.clearCallingIdentity(); - try { - startCleaningPackages(userId); - } finally { - Binder.restoreCallingIdentity(ident); } return null; } @@ -5471,34 +5462,22 @@ public class PackageManagerService extends IPackageManager.Stub { userId, andCode ? 1 : 0, packageName)); } - void startCleaningPackages(int lastUser) { + void startCleaningPackages() { // reader - int nextUser = -1; synchronized (mPackages) { if (!isExternalMediaAvailable()) { return; } - final int N = mSettings.mPackagesToBeCleaned.size(); - if (N <= 0) { + if (mSettings.mPackagesToBeCleaned.isEmpty()) { return; } - for (int i=0; i<N; i++) { - int user = mSettings.mPackagesToBeCleaned.keyAt(i); - if (user > lastUser) { - nextUser = user; - break; - } - } - if (nextUser < 0) { - nextUser = mSettings.mPackagesToBeCleaned.keyAt(0); - } } Intent intent = new Intent(PackageManager.ACTION_CLEAN_EXTERNAL_STORAGE); intent.setComponent(DEFAULT_CONTAINER_COMPONENT); IActivityManager am = ActivityManagerNative.getDefault(); if (am != null) { try { - am.startService(null, intent, null, nextUser); + am.startService(null, intent, null, UserHandle.USER_OWNER); } catch (RemoteException e) { } } @@ -5904,11 +5883,20 @@ public class PackageManagerService extends IPackageManager.Stub { * * @return true if verification should be performed */ - private boolean isVerificationEnabled() { + private boolean isVerificationEnabled(int flags) { if (!DEFAULT_VERIFY_ENABLE) { return false; } + // Check if installing from ADB + if ((flags & PackageManager.INSTALL_FROM_ADB) != 0) { + // Check if the developer does not want package verification for ADB installs + if (android.provider.Settings.Global.getInt(mContext.getContentResolver(), + android.provider.Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB, 1) == 0) { + return false; + } + } + return android.provider.Settings.Global.getInt(mContext.getContentResolver(), android.provider.Settings.Global.PACKAGE_VERIFIER_ENABLE, 1) == 1; } @@ -6406,7 +6394,7 @@ public class PackageManagerService extends IPackageManager.Stub { */ final int requiredUid = mRequiredVerifierPackage == null ? -1 : getPackageUid(mRequiredVerifierPackage, 0); - if (requiredUid != -1 && isVerificationEnabled()) { + if (requiredUid != -1 && isVerificationEnabled(flags)) { final Intent verification = new Intent( Intent.ACTION_PACKAGE_NEEDS_VERIFICATION); verification.setDataAndType(getPackageUri(), PACKAGE_MIME_TYPE); @@ -8378,10 +8366,11 @@ public class PackageManagerService extends IPackageManager.Stub { } else { users = new int[] { userId }; } - for (int curUser : users) { - ClearStorageConnection conn = new ClearStorageConnection(); - if (mContext.bindService(containerIntent, conn, Context.BIND_AUTO_CREATE, curUser)) { - try { + final ClearStorageConnection conn = new ClearStorageConnection(); + if (mContext.bindService( + containerIntent, conn, Context.BIND_AUTO_CREATE, UserHandle.USER_OWNER)) { + try { + for (int curUser : users) { long timeout = SystemClock.uptimeMillis() + 5000; synchronized (conn) { long now = SystemClock.uptimeMillis(); @@ -8417,9 +8406,9 @@ public class PackageManagerService extends IPackageManager.Stub { } catch (RemoteException e) { } } - } finally { - mContext.unbindService(conn); } + } finally { + mContext.unbindService(conn); } } } @@ -9575,7 +9564,7 @@ public class PackageManagerService extends IPackageManager.Stub { if (DEBUG_SD_INSTALL) Log.i(TAG, "Loading packages"); loadMediaPackages(processCids, uidArr, removeCids); - startCleaningPackages(-1); + startCleaningPackages(); } else { if (DEBUG_SD_INSTALL) Log.i(TAG, "Unloading packages"); @@ -10115,19 +10104,36 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public boolean isPermissionEnforced(String permission) { + final boolean enforcedDefault = isPermissionEnforcedDefault(permission); synchronized (mPackages) { - return isPermissionEnforcedLocked(permission); + return isPermissionEnforcedLocked(permission, enforcedDefault); } } - private boolean isPermissionEnforcedLocked(String permission) { + /** + * Check if given permission should be enforced by default. Should always be + * called outside of {@link #mPackages} lock. + */ + private boolean isPermissionEnforcedDefault(String permission) { + if (READ_EXTERNAL_STORAGE.equals(permission)) { + return Secure.getInt(mContext.getContentResolver(), + Secure.READ_EXTERNAL_STORAGE_ENFORCED_DEFAULT, 0) != 0; + } else { + return true; + } + } + + /** + * Check if user has requested that given permission be enforced, using + * given default if undefined. + */ + private boolean isPermissionEnforcedLocked(String permission, boolean enforcedDefault) { if (READ_EXTERNAL_STORAGE.equals(permission)) { if (mSettings.mReadExternalStorageEnforced != null) { return mSettings.mReadExternalStorageEnforced; } else { - // if user hasn't defined, fall back to secure default - return Secure.getInt(mContext.getContentResolver(), - Secure.READ_EXTERNAL_STORAGE_ENFORCED_DEFAULT, 0) != 0; + // User hasn't defined; fall back to secure default + return enforcedDefault; } } else { return true; diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java index 23e54678..2fb853a 100644 --- a/services/java/com/android/server/pm/Settings.java +++ b/services/java/com/android/server/pm/Settings.java @@ -159,8 +159,7 @@ final class Settings { // Packages that have been uninstalled and still need their external // storage data deleted. - final SparseArray<ArrayList<PackageCleanItem>> mPackagesToBeCleaned - = new SparseArray<ArrayList<PackageCleanItem>>(); + final ArrayList<PackageCleanItem> mPackagesToBeCleaned = new ArrayList<PackageCleanItem>(); // Packages that have been renamed since they were first installed. // Keys are the new names of the packages, values are the original @@ -1257,18 +1256,13 @@ final class Settings { } if (mPackagesToBeCleaned.size() > 0) { - for (int i=0; i<mPackagesToBeCleaned.size(); i++) { - final int userId = mPackagesToBeCleaned.keyAt(i); - final String userStr = Integer.toString(userId); - final ArrayList<PackageCleanItem> pkgs = mPackagesToBeCleaned.valueAt(i); - for (int j=0; j<pkgs.size(); j++) { - serializer.startTag(null, "cleaning-package"); - PackageCleanItem item = pkgs.get(j); - serializer.attribute(null, ATTR_NAME, item.packageName); - serializer.attribute(null, ATTR_CODE, item.andCode ? "true" : "false"); - serializer.attribute(null, ATTR_USER, userStr); - serializer.endTag(null, "cleaning-package"); - } + for (PackageCleanItem item : mPackagesToBeCleaned) { + final String userStr = Integer.toString(item.userId); + serializer.startTag(null, "cleaning-package"); + serializer.attribute(null, ATTR_NAME, item.packageName); + serializer.attribute(null, ATTR_CODE, item.andCode ? "true" : "false"); + serializer.attribute(null, ATTR_USER, userStr); + serializer.endTag(null, "cleaning-package"); } } @@ -1524,14 +1518,9 @@ final class Settings { return ret; } - void addPackageToCleanLPw(int userId, PackageCleanItem pkg) { - ArrayList<PackageCleanItem> pkgs = mPackagesToBeCleaned.get(userId); - if (pkgs == null) { - pkgs = new ArrayList<PackageCleanItem>(); - mPackagesToBeCleaned.put(userId, pkgs); - } - if (!pkgs.contains(pkg)) { - pkgs.add(pkg); + void addPackageToCleanLPw(PackageCleanItem pkg) { + if (!mPackagesToBeCleaned.contains(pkg)) { + mPackagesToBeCleaned.add(pkg); } } @@ -1615,18 +1604,18 @@ final class Settings { String userStr = parser.getAttributeValue(null, ATTR_USER); String codeStr = parser.getAttributeValue(null, ATTR_CODE); if (name != null) { - int user = 0; + int userId = 0; boolean andCode = true; try { if (userStr != null) { - user = Integer.parseInt(userStr); + userId = Integer.parseInt(userStr); } } catch (NumberFormatException e) { } if (codeStr != null) { andCode = Boolean.parseBoolean(codeStr); } - addPackageToCleanLPw(user, new PackageCleanItem(name, andCode)); + addPackageToCleanLPw(new PackageCleanItem(userId, name, andCode)); } } else if (tagName.equals("renamed-package")) { String nname = parser.getAttributeValue(null, "new"); |