Multiuser love for LocationManager

LocationManagerService now keeps track of the current user ID and
denies location requests made by all but the foreground user.

Additionally, location settings are now user-specific, rather than
global to the device. Location provider services now run as specific
users, and when the device's foreground user changes, we rebind to
appropriately-owned providers.

Bug: 6926385
Bug: 7247203
Change-Id: I346074959e96e52bcc77eeb188dffe322b690879
diff --git a/services/java/com/android/server/ServiceWatcher.java b/services/java/com/android/server/ServiceWatcher.java
index e99949b..5598b0a 100644
--- a/services/java/com/android/server/ServiceWatcher.java
+++ b/services/java/com/android/server/ServiceWatcher.java
@@ -27,6 +27,7 @@
 import android.content.pm.Signature;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.UserHandle;
 import android.util.Log;
 
 import com.android.internal.content.PackageMonitor;
@@ -58,15 +59,17 @@
     private IBinder mBinder;   // connected service
     private String mPackageName;  // current best package
     private int mVersion;  // current best version
+    private int mCurrentUserId;
 
     public ServiceWatcher(Context context, String logTag, String action,
-            List<String> initialPackageNames, Runnable newServiceWork, Handler handler) {
+            List<String> initialPackageNames, Runnable newServiceWork, Handler handler, int userId) {
         mContext = context;
         mTag = logTag;
         mAction = action;
         mPm = mContext.getPackageManager();
         mNewServiceWork = newServiceWork;
         mHandler = handler;
+        mCurrentUserId = userId;
 
         mSignatureSets = new ArrayList<HashSet<Signature>>();
         for (int i=0; i < initialPackageNames.size(); i++) {
@@ -85,9 +88,11 @@
     }
 
     public boolean start() {
-        if (!bindBestPackage(null)) return false;
+        synchronized (mLock) {
+            if (!bindBestPackageLocked(null)) return false;
+        }
 
-        mPackageMonitor.register(mContext, null, true);
+        mPackageMonitor.register(mContext, null, UserHandle.ALL, true);
         return true;
     }
 
@@ -98,13 +103,13 @@
      * is null.
      * Return true if a new package was found to bind to.
      */
-    private boolean bindBestPackage(String justCheckThisPackage) {
+    private boolean bindBestPackageLocked(String justCheckThisPackage) {
         Intent intent = new Intent(mAction);
         if (justCheckThisPackage != null) {
             intent.setPackage(justCheckThisPackage);
         }
-        List<ResolveInfo> rInfos = mPm.queryIntentServices(new Intent(mAction),
-                PackageManager.GET_META_DATA);
+        List<ResolveInfo> rInfos = mPm.queryIntentServicesAsUser(new Intent(mAction),
+                PackageManager.GET_META_DATA, mCurrentUserId);
         int bestVersion = Integer.MIN_VALUE;
         String bestPackage = null;
         for (ResolveInfo rInfo : rInfos) {
@@ -141,36 +146,32 @@
                 (bestPackage == null ? "no new best package" : "new best packge: " + bestPackage)));
 
         if (bestPackage != null) {
-            bindToPackage(bestPackage, bestVersion);
+            bindToPackageLocked(bestPackage, bestVersion);
             return true;
         }
         return false;
     }
 
-    private void unbind() {
+    private void unbindLocked() {
         String pkg;
-        synchronized (mLock) {
-            pkg = mPackageName;
-            mPackageName = null;
-            mVersion = Integer.MIN_VALUE;
-        }
+        pkg = mPackageName;
+        mPackageName = null;
+        mVersion = Integer.MIN_VALUE;
         if (pkg != null) {
             if (D) Log.d(mTag, "unbinding " + pkg);
             mContext.unbindService(this);
         }
     }
 
-    private void bindToPackage(String packageName, int version) {
-        unbind();
+    private void bindToPackageLocked(String packageName, int version) {
+        unbindLocked();
         Intent intent = new Intent(mAction);
         intent.setPackage(packageName);
-        synchronized (mLock) {
-            mPackageName = packageName;
-            mVersion = version;
-        }
+        mPackageName = packageName;
+        mVersion = version;
         if (D) Log.d(mTag, "binding " + packageName + " (version " + version + ")");
         mContext.bindService(intent, this, Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND
-                | Context.BIND_ALLOW_OOM_MANAGEMENT | Context.BIND_NOT_VISIBLE);
+                | Context.BIND_ALLOW_OOM_MANAGEMENT | Context.BIND_NOT_VISIBLE, mCurrentUserId);
     }
 
     private boolean isSignatureMatch(Signature[] signatures) {
@@ -197,31 +198,37 @@
          */
         @Override
         public void onPackageUpdateFinished(String packageName, int uid) {
-            if (packageName.equals(mPackageName)) {
-                // package updated, make sure to rebind
-                unbind();
+            synchronized (mLock) {
+                if (packageName.equals(mPackageName)) {
+                    // package updated, make sure to rebind
+                    unbindLocked();
+                }
+                // check the updated package in case it is better
+                bindBestPackageLocked(packageName);
             }
-            // check the updated package in case it is better
-            bindBestPackage(packageName);
         }
 
         @Override
         public void onPackageAdded(String packageName, int uid) {
-            if (packageName.equals(mPackageName)) {
-                // package updated, make sure to rebind
-                unbind();
+            synchronized (mLock) {
+                if (packageName.equals(mPackageName)) {
+                    // package updated, make sure to rebind
+                    unbindLocked();
+                }
+                // check the new package is case it is better
+                bindBestPackageLocked(packageName);
             }
-            // check the new package is case it is better
-            bindBestPackage(packageName);
         }
 
         @Override
         public void onPackageRemoved(String packageName, int uid) {
-            if (packageName.equals(mPackageName)) {
-                unbind();
-                // the currently bound package was removed,
-                // need to search for a new package
-                bindBestPackage(null);
+            synchronized (mLock) {
+                if (packageName.equals(mPackageName)) {
+                    unbindLocked();
+                    // the currently bound package was removed,
+                    // need to search for a new package
+                    bindBestPackageLocked(null);
+                }
             }
         }
     };
@@ -271,4 +278,12 @@
             return mBinder;
         }
     }
+
+    public void switchUser(int userId) {
+        synchronized (mLock) {
+            unbindLocked();
+            mCurrentUserId = userId;
+            bindBestPackageLocked(null);
+        }
+    }
 }