More mult-user API work.

- You can now use android:singleUser with receivers and providers.
- New API to send ordered broadcasts as a user.
- New Process.myUserHandle() API.

For now I am trying out "user handle" as the name for the numbers
representing users.

Change-Id: I754c713ab172494bb4251bc7a37a17324a2e235e
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 98d3482..05f38a5 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -5936,15 +5936,26 @@
             Slog.v(TAG_MU, "generateApplicationProvidersLocked, app.info.uid = " + app.uid);
         int userId = app.userId;
         if (providers != null) {
-            final int N = providers.size();
+            int N = providers.size();
             for (int i=0; i<N; i++) {
                 ProviderInfo cpi =
                     (ProviderInfo)providers.get(i);
+                boolean singleton = isSingleton(cpi.processName, cpi.applicationInfo,
+                        cpi.name, cpi.flags);
+                if (singleton && UserId.getUserId(app.uid) != 0) {
+                    // This is a singleton provider, but a user besides the
+                    // default user is asking to initialize a process it runs
+                    // in...  well, no, it doesn't actually run in this process,
+                    // it runs in the process of the default user.  Get rid of it.
+                    providers.remove(i);
+                    N--;
+                    continue;
+                }
 
                 ComponentName comp = new ComponentName(cpi.packageName, cpi.name);
                 ContentProviderRecord cpr = mProviderMap.getProviderByClass(comp, userId);
                 if (cpr == null) {
-                    cpr = new ContentProviderRecord(this, cpi, app.info, comp);
+                    cpr = new ContentProviderRecord(this, cpi, app.info, comp, singleton);
                     mProviderMap.putProviderByClass(comp, cpr);
                 }
                 if (DEBUG_MU)
@@ -6177,6 +6188,7 @@
                 Binder.restoreCallingIdentity(origId);
             }
 
+            boolean singleton;
             if (!providerRunning) {
                 try {
                     cpi = AppGlobals.getPackageManager().
@@ -6187,7 +6199,9 @@
                 if (cpi == null) {
                     return null;
                 }
-                if (isSingleton(cpi.processName, cpi.applicationInfo)) {
+                singleton = isSingleton(cpi.processName, cpi.applicationInfo,
+                        cpi.name, cpi.flags); 
+                if (singleton) {
                     userId = 0;
                 }
                 cpi.applicationInfo = getAppInfoForUser(cpi.applicationInfo, userId);
@@ -6222,7 +6236,7 @@
                             return null;
                         }
                         ai = getAppInfoForUser(ai, userId);
-                        cpr = new ContentProviderRecord(this, cpi, ai, comp);
+                        cpr = new ContentProviderRecord(this, cpi, ai, comp, singleton);
                     } catch (RemoteException ex) {
                         // pm is in same process, this will never happen.
                     }
@@ -10515,17 +10529,31 @@
         }
     }
 
-    boolean isSingleton(String componentProcessName, ApplicationInfo aInfo) {
+    boolean isSingleton(String componentProcessName, ApplicationInfo aInfo,
+            String className, int flags) {
         boolean result = false;
         if (UserId.getAppId(aInfo.uid) >= Process.FIRST_APPLICATION_UID) {
-            result = false;
+            if ((flags&ServiceInfo.FLAG_SINGLE_USER) != 0) {
+                if (ActivityManager.checkUidPermission(
+                        android.Manifest.permission.INTERACT_ACROSS_USERS,
+                        aInfo.uid) != PackageManager.PERMISSION_GRANTED) {
+                    ComponentName comp = new ComponentName(aInfo.packageName, className);
+                    String msg = "Permission Denial: Component " + comp.flattenToShortString()
+                            + " requests FLAG_SINGLE_USER, but app does not hold "
+                            + android.Manifest.permission.INTERACT_ACROSS_USERS;
+                    Slog.w(TAG, msg);
+                    throw new SecurityException(msg);
+                }
+                result = true;
+            }
         } else if (componentProcessName == aInfo.packageName) {
             result = (aInfo.flags & ApplicationInfo.FLAG_PERSISTENT) != 0;
         } else if ("system".equals(componentProcessName)) {
             result = true;
         }
         if (DEBUG_MU) {
-            Slog.v(TAG, "isSingleton(" + componentProcessName + ", " + aInfo + ") = " + result);
+            Slog.v(TAG, "isSingleton(" + componentProcessName + ", " + aInfo
+                    + ", " + className + ", 0x" + Integer.toHexString(flags) + ") = " + result);
         }
         return result;
     }
@@ -11131,30 +11159,15 @@
         List receivers = null;
         List<BroadcastFilter> registeredReceivers = null;
         try {
-            if (intent.getComponent() != null) {
-                // Broadcast is going to one specific receiver class...
-                ActivityInfo ai = AppGlobals.getPackageManager().
-                        getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS, userId);
-                if (ai != null) {
-                    receivers = new ArrayList();
-                    ResolveInfo ri = new ResolveInfo();
-                    if (isSingleton(ai.processName, ai.applicationInfo)) {
-                        ri.activityInfo = getActivityInfoForUser(ai, 0);
-                    } else {
-                        ri.activityInfo = getActivityInfoForUser(ai, userId);
-                    }
-                    receivers.add(ri);
-                }
-            } else {
-                // Need to resolve the intent to interested receivers...
-                if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
-                         == 0) {
-                    receivers =
-                        AppGlobals.getPackageManager().queryIntentReceivers(
-                                    intent, resolvedType, STOCK_PM_FLAGS, userId);
-                }
-                registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false,
-                        userId);
+            // Need to resolve the intent to interested receivers...
+            if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
+                     == 0) {
+                receivers = AppGlobals.getPackageManager().queryIntentReceivers(
+                        intent, resolvedType, STOCK_PM_FLAGS, userId);
+            }
+            if (intent.getComponent() == null) {
+                registeredReceivers = mReceiverResolver.queryIntent(intent,
+                        resolvedType, false, userId);
             }
         } catch (RemoteException ex) {
             // pm is in same process, this will never happen.