make FLP play nicely with multiuser

Frameworks' FusedLocationProvider runs as a specific user so that it
can join a specific process. The solution that works for NLP, run one
copy per user as that user, does not work for FLP.

To make FLP play nicely with multiuser, I've allowed SYSTEM_UID to
operate in the background and included a hardcoded exception to
prevent ServiceWatcher from trying to launch one FLP per user.

Bug: 7279799
Change-Id: I573ea5226d8d00777421b39c5c3fb0899bf09b4d
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index 37dee19..eb833eb 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -405,7 +405,9 @@
             mLastLocation.clear();
             for (LocationProviderInterface p : mProviders) {
                 updateProviderListenersLocked(p.getName(), false, mCurrentUserId);
-                p.switchUser(userId);
+                if (!LocationManager.FUSED_PROVIDER.equals(p.getName())) {
+                    p.switchUser(userId);
+                }
             }
             mCurrentUserId = userId;
             updateProvidersLocked();
@@ -664,9 +666,27 @@
         mProvidersByName.remove(provider.getName());
     }
 
+    /**
+     * Returns true if the specified UID is SYSTEM_UID or matches the current user.
+     *
+     * @param uid the uid
+     * @return true if uid is SYSTEM_UID or matches the current user
+     */
+    private boolean isCurrentUserOrSystemLocked(int uid) {
+        return uid == Process.SYSTEM_UID || UserHandle.getUserId(uid) == mCurrentUserId;
+    }
 
-    private boolean isAllowedBySettingsLocked(String provider, int userId) {
-        if (userId != mCurrentUserId) {
+    /**
+     * Returns the first UID in the current user's range.
+     *
+     * @return the first UID in the current user's range
+     */
+    private int getCurrentUidBaseLocked() {
+        return UserHandle.getUid(mCurrentUserId, 0);
+    }
+
+    private boolean isAllowedBySettingsLocked(String provider, int uid) {
+        if (!isCurrentUserOrSystemLocked(uid)) {
             return false;
         }
         if (mEnabledProviders.contains(provider)) {
@@ -675,6 +695,10 @@
         if (mDisabledProviders.contains(provider)) {
             return false;
         }
+        if (uid == Process.SYSTEM_UID) {
+            return true;
+        }
+
         // Use system settings
         ContentResolver resolver = mContext.getContentResolver();
 
@@ -828,8 +852,8 @@
     public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
         int allowedResolutionLevel = getCallerAllowedResolutionLevel();
         ArrayList<String> out;
-        int callingUserId = UserHandle.getCallingUserId();
-        long identity = Binder.clearCallingIdentity();
+        final int callingUid = Binder.getCallingUid();
+        final long identity = Binder.clearCallingIdentity();
         try {
             synchronized (mLock) {
                 out = new ArrayList<String>(mProviders.size());
@@ -839,7 +863,7 @@
                         continue;
                     }
                     if (allowedResolutionLevel >= getMinimumResolutionLevelForProviderUse(name)) {
-                        if (enabledOnly && !isAllowedBySettingsLocked(name, callingUserId)) {
+                        if (enabledOnly && !isAllowedBySettingsLocked(name, callingUid)) {
                             continue;
                         }
                         if (criteria != null && !LocationProvider.propertiesMeetCriteria(
@@ -915,7 +939,7 @@
             LocationProviderInterface p = mProviders.get(i);
             boolean isEnabled = p.isEnabled();
             String name = p.getName();
-            boolean shouldBeEnabled = isAllowedBySettingsLocked(name, mCurrentUserId);
+            boolean shouldBeEnabled = isAllowedBySettingsLocked(name, getCurrentUidBaseLocked());
             if (isEnabled && !shouldBeEnabled) {
                 updateProviderListenersLocked(name, false, mCurrentUserId);
                 changesMade = true;
@@ -943,7 +967,7 @@
             final int N = records.size();
             for (int i = 0; i < N; i++) {
                 UpdateRecord record = records.get(i);
-                if (UserHandle.getUserId(record.mReceiver.mUid) == userId) {
+                if (isCurrentUserOrSystemLocked(record.mReceiver.mUid)) {
                     // Sends a notification message to the receiver
                     if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
                         if (deadReceivers == null) {
@@ -982,7 +1006,7 @@
 
         if (records != null) {
             for (UpdateRecord record : records) {
-                if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) {
+                if (isCurrentUserOrSystemLocked(record.mReceiver.mUid)) {
                     LocationRequest locationRequest = record.mRequest;
                     providerRequest.locationRequests.add(locationRequest);
                     if (locationRequest.getInterval() < providerRequest.interval) {
@@ -1000,7 +1024,7 @@
                 // under that threshold.
                 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
                 for (UpdateRecord record : records) {
-                    if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) {
+                    if (isCurrentUserOrSystemLocked(record.mReceiver.mUid)) {
                         LocationRequest locationRequest = record.mRequest;
                         if (locationRequest.getInterval() <= thresholdInterval) {
                             worksource.add(record.mReceiver.mUid);
@@ -1223,7 +1247,7 @@
             oldRecord.disposeLocked(false);
         }
 
-        boolean isProviderEnabled = isAllowedBySettingsLocked(name, UserHandle.getUserId(uid));
+        boolean isProviderEnabled = isAllowedBySettingsLocked(name, uid);
         if (isProviderEnabled) {
             applyRequirementsLocked(name);
         } else {
@@ -1278,9 +1302,10 @@
         }
 
         // update provider
+        int currentUidBase = getCurrentUidBaseLocked();
         for (String provider : providers) {
             // If provider is already disabled, don't need to do anything
-            if (!isAllowedBySettingsLocked(provider, mCurrentUserId)) {
+            if (!isAllowedBySettingsLocked(provider, currentUidBase)) {
                 continue;
             }
 
@@ -1298,7 +1323,8 @@
                 request.getProvider());
         // no need to sanitize this request, as only the provider name is used
 
-        long identity = Binder.clearCallingIdentity();
+        final int callingUid = Binder.getCallingUid();
+        final long identity = Binder.clearCallingIdentity();
         try {
             if (mBlacklist.isBlacklisted(packageName)) {
                 if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
@@ -1314,7 +1340,9 @@
                 LocationProviderInterface provider = mProvidersByName.get(name);
                 if (provider == null) return null;
 
-                if (!isAllowedBySettingsLocked(name, mCurrentUserId)) return null;
+                if (!isAllowedBySettingsLocked(name, callingUid)) {
+                    return null;
+                }
 
                 Location location = mLastLocation.get(name);
                 if (location == null) {
@@ -1471,13 +1499,14 @@
                 provider);
         if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
 
-        long identity = Binder.clearCallingIdentity();
+        final int callingUid = Binder.getCallingUid();
+        final long identity = Binder.clearCallingIdentity();
         try {
             synchronized (mLock) {
                 LocationProviderInterface p = mProvidersByName.get(provider);
                 if (p == null) return false;
 
-                return isAllowedBySettingsLocked(provider, mCurrentUserId);
+                return isAllowedBySettingsLocked(provider, callingUid);
             }
         } finally {
             Binder.restoreCallingIdentity(identity);
@@ -1616,10 +1645,10 @@
             Receiver receiver = r.mReceiver;
             boolean receiverDead = false;
 
-            int receiverUserId = UserHandle.getUserId(receiver.mUid);
-            if (receiverUserId != mCurrentUserId) {
+            final int receiverUid = receiver.mUid;
+            if (!isCurrentUserOrSystemLocked(receiverUid)) {
                 if (D) {
-                    Log.d(TAG, "skipping loc update for background user " + receiverUserId +
+                    Log.d(TAG, "skipping loc update for background uid " + receiverUid +
                             " (current user: " + mCurrentUserId + ", app: " +
                             receiver.mPackageName + ")");
                 }
@@ -1716,7 +1745,7 @@
         }
 
         synchronized (mLock) {
-            if (isAllowedBySettingsLocked(provider, mCurrentUserId)) {
+            if (isAllowedBySettingsLocked(provider, getCurrentUidBaseLocked())) {
                 handleLocationChangedLocked(location, passive);
             }
         }