Multi-user - 1st major checkin

Switching activity stacks
Cache ContentProvider per user
Long-press power to switch users (on phone)

Added ServiceMap for separating services by user
Launch PendingIntents on the correct user's uid
Fix task switching from Recents list
AppWidgetService is mostly working.

Commands added to pm and am to allow creating and switching profiles.

Change-Id: I15810e8cfbe50a04bd3323a7ef5a8ff4230870ed
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 9661b9e..d98d87b 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -30,6 +30,7 @@
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.Point;
+import android.os.Binder;
 import android.os.Debug;
 import android.os.Handler;
 import android.os.Parcel;
@@ -975,7 +976,7 @@
     public boolean clearApplicationUserData(String packageName, IPackageDataObserver observer) {
         try {
             return ActivityManagerNative.getDefault().clearApplicationUserData(packageName, 
-                    observer);
+                    observer, Binder.getOrigCallingUser());
         } catch (RemoteException e) {
             return false;
         }
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 7994d7c..d80902d 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -91,7 +91,7 @@
         try {
             getDefault().broadcastIntent(
                 null, intent, null, null, Activity.RESULT_OK, null, null,
-                null /*permission*/, false, true);
+                null /*permission*/, false, true, Binder.getOrigCallingUser());
         } catch (RemoteException ex) {
         }
     }
@@ -306,9 +306,10 @@
             String perm = data.readString();
             boolean serialized = data.readInt() != 0;
             boolean sticky = data.readInt() != 0;
+            int userId = data.readInt();
             int res = broadcastIntent(app, intent, resolvedType, resultTo,
                     resultCode, resultData, resultExtras, perm,
-                    serialized, sticky);
+                    serialized, sticky, userId);
             reply.writeNoException();
             reply.writeInt(res);
             return true;
@@ -320,7 +321,8 @@
             IBinder b = data.readStrongBinder();
             IApplicationThread app = b != null ? ApplicationThreadNative.asInterface(b) : null;
             Intent intent = Intent.CREATOR.createFromParcel(data);
-            unbroadcastIntent(app, intent);
+            int userId = data.readInt();
+            unbroadcastIntent(app, intent, userId);
             reply.writeNoException();
             return true;
         }
@@ -900,7 +902,8 @@
             String packageName = data.readString();
             IPackageDataObserver observer = IPackageDataObserver.Stub.asInterface(
                     data.readStrongBinder());
-            boolean res = clearApplicationUserData(packageName, observer);
+            int userId = data.readInt();
+            boolean res = clearApplicationUserData(packageName, observer, userId);
             reply.writeNoException();
             reply.writeInt(res ? 1 : 0);
             return true;
@@ -1819,7 +1822,7 @@
             Intent intent, String resolvedType,  IIntentReceiver resultTo,
             int resultCode, String resultData, Bundle map,
             String requiredPermission, boolean serialized,
-            boolean sticky) throws RemoteException
+            boolean sticky, int userId) throws RemoteException
     {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
@@ -1834,6 +1837,7 @@
         data.writeString(requiredPermission);
         data.writeInt(serialized ? 1 : 0);
         data.writeInt(sticky ? 1 : 0);
+        data.writeInt(userId);
         mRemote.transact(BROADCAST_INTENT_TRANSACTION, data, reply, 0);
         reply.readException();
         int res = reply.readInt();
@@ -1841,13 +1845,15 @@
         data.recycle();
         return res;
     }
-    public void unbroadcastIntent(IApplicationThread caller, Intent intent) throws RemoteException
+    public void unbroadcastIntent(IApplicationThread caller, Intent intent, int userId)
+            throws RemoteException
     {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeStrongBinder(caller != null ? caller.asBinder() : null);
         intent.writeToParcel(data, 0);
+        data.writeInt(userId);
         mRemote.transact(UNBROADCAST_INTENT_TRANSACTION, data, reply, 0);
         reply.readException();
         data.recycle();
@@ -2651,12 +2657,13 @@
         return res;
     }
     public boolean clearApplicationUserData(final String packageName,
-            final IPackageDataObserver observer) throws RemoteException {        
+            final IPackageDataObserver observer, final int userId) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeString(packageName);
         data.writeStrongBinder(observer.asBinder());
+        data.writeInt(userId);
         mRemote.transact(CLEAR_APP_DATA_TRANSACTION, data, reply, 0);
         reply.readException();
         boolean res = reply.readInt() != 0;
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 3c5f53a..e4cfc99 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -47,6 +47,7 @@
 import android.net.ProxyProperties;
 import android.opengl.GLUtils;
 import android.os.AsyncTask;
+import android.os.Binder;
 import android.os.Bundle;
 import android.os.Debug;
 import android.os.Handler;
@@ -60,6 +61,7 @@
 import android.os.ServiceManager;
 import android.os.StrictMode;
 import android.os.SystemClock;
+import android.os.UserId;
 import android.util.AndroidRuntimeException;
 import android.util.DisplayMetrics;
 import android.util.EventLog;
@@ -132,6 +134,7 @@
     private static final boolean DEBUG_RESULTS = false;
     private static final boolean DEBUG_BACKUP = true;
     private static final boolean DEBUG_CONFIGURATION = false;
+    private static final boolean DEBUG_SERVICE = true;
     private static final long MIN_TIME_BETWEEN_GCS = 5*1000;
     private static final Pattern PATTERN_SEMICOLON = Pattern.compile(";");
     private static final int SQLITE_MEM_RELEASED_EVENT_LOG_TAG = 75003;
@@ -635,6 +638,9 @@
             s.intent = intent;
             s.rebind = rebind;
 
+            if (DEBUG_SERVICE)
+                Slog.v(TAG, "scheduleBindService token=" + token + " intent=" + intent + " uid="
+                        + Binder.getCallingUid() + " pid=" + Binder.getCallingPid());
             queueOrSendMessage(H.BIND_SERVICE, s);
         }
 
@@ -1592,7 +1598,8 @@
         boolean includeCode = (flags&Context.CONTEXT_INCLUDE_CODE) != 0;
         boolean securityViolation = includeCode && ai.uid != 0
                 && ai.uid != Process.SYSTEM_UID && (mBoundApplication != null
-                        ? ai.uid != mBoundApplication.appInfo.uid : true);
+                        ? !UserId.isSameApp(ai.uid, mBoundApplication.appInfo.uid)
+                        : true);
         if ((flags&(Context.CONTEXT_INCLUDE_CODE
                 |Context.CONTEXT_IGNORE_SECURITY))
                 == Context.CONTEXT_INCLUDE_CODE) {
@@ -2294,6 +2301,8 @@
 
     private void handleBindService(BindServiceData data) {
         Service s = mServices.get(data.token);
+        if (DEBUG_SERVICE)
+            Slog.v(TAG, "handleBindService s=" + s + " rebind=" + data.rebind);
         if (s != null) {
             try {
                 data.intent.setExtrasClassLoader(s.getClassLoader());
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 180a442..fee2beb 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -1177,13 +1177,14 @@
      */
     @Override
     public List<UserInfo> getUsers() {
-        // TODO:
-        // Dummy code, always returns just the primary user
-        ArrayList<UserInfo> users = new ArrayList<UserInfo>();
-        UserInfo primary = new UserInfo(0, "Root!",
-                UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY);
-        users.add(primary);
-        return users;
+        try {
+            return mPM.getUsers();
+        } catch (RemoteException re) {
+            ArrayList<UserInfo> users = new ArrayList<UserInfo>();
+            UserInfo primary = new UserInfo(0, "Root!", UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY);
+            users.add(primary);
+            return users;
+        }
     }
 
     /**
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 2bf1fb7..db5113e 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -75,6 +75,7 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.UserId;
 import android.os.Vibrator;
 import android.os.storage.StorageManager;
 import android.telephony.TelephonyManager;
@@ -896,7 +897,8 @@
             intent.setAllowFds(false);
             ActivityManagerNative.getDefault().broadcastIntent(
                 mMainThread.getApplicationThread(), intent, resolvedType, null,
-                Activity.RESULT_OK, null, null, null, false, false);
+                Activity.RESULT_OK, null, null, null, false, false,
+                Binder.getOrigCallingUser());
         } catch (RemoteException e) {
         }
     }
@@ -908,7 +910,8 @@
             intent.setAllowFds(false);
             ActivityManagerNative.getDefault().broadcastIntent(
                 mMainThread.getApplicationThread(), intent, resolvedType, null,
-                Activity.RESULT_OK, null, null, receiverPermission, false, false);
+                Activity.RESULT_OK, null, null, receiverPermission, false, false,
+                Binder.getOrigCallingUser());
         } catch (RemoteException e) {
         }
     }
@@ -921,7 +924,8 @@
             intent.setAllowFds(false);
             ActivityManagerNative.getDefault().broadcastIntent(
                 mMainThread.getApplicationThread(), intent, resolvedType, null,
-                Activity.RESULT_OK, null, null, receiverPermission, true, false);
+                Activity.RESULT_OK, null, null, receiverPermission, true, false,
+                Binder.getOrigCallingUser());
         } catch (RemoteException e) {
         }
     }
@@ -954,7 +958,7 @@
             ActivityManagerNative.getDefault().broadcastIntent(
                 mMainThread.getApplicationThread(), intent, resolvedType, rd,
                 initialCode, initialData, initialExtras, receiverPermission,
-                true, false);
+                true, false, Binder.getOrigCallingUser());
         } catch (RemoteException e) {
         }
     }
@@ -966,7 +970,8 @@
             intent.setAllowFds(false);
             ActivityManagerNative.getDefault().broadcastIntent(
                 mMainThread.getApplicationThread(), intent, resolvedType, null,
-                Activity.RESULT_OK, null, null, null, false, true);
+                Activity.RESULT_OK, null, null, null, false, true,
+                Binder.getOrigCallingUser());
         } catch (RemoteException e) {
         }
     }
@@ -999,7 +1004,7 @@
             ActivityManagerNative.getDefault().broadcastIntent(
                 mMainThread.getApplicationThread(), intent, resolvedType, rd,
                 initialCode, initialData, initialExtras, null,
-                true, true);
+                true, true, Binder.getOrigCallingUser());
         } catch (RemoteException e) {
         }
     }
@@ -1014,7 +1019,7 @@
         try {
             intent.setAllowFds(false);
             ActivityManagerNative.getDefault().unbroadcastIntent(
-                mMainThread.getApplicationThread(), intent);
+                    mMainThread.getApplicationThread(), intent, Binder.getOrigCallingUser());
         } catch (RemoteException e) {
         }
     }
@@ -1215,8 +1220,7 @@
 
         int pid = Binder.getCallingPid();
         if (pid != Process.myPid()) {
-            return checkPermission(permission, pid,
-                    Binder.getCallingUid());
+            return checkPermission(permission, pid, Binder.getCallingUid());
         }
         return PackageManager.PERMISSION_DENIED;
     }
@@ -1384,7 +1388,8 @@
             Uri uri, int modeFlags, String message) {
         enforceForUri(
                 modeFlags, checkCallingUriPermission(uri, modeFlags),
-                false, Binder.getCallingUid(), uri, message);
+                false,
+                Binder.getCallingUid(), uri, message);
     }
 
     public void enforceCallingOrSelfUriPermission(
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 5222d37..39817ac 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -114,8 +114,8 @@
     public int broadcastIntent(IApplicationThread caller, Intent intent,
             String resolvedType, IIntentReceiver resultTo, int resultCode,
             String resultData, Bundle map, String requiredPermission,
-            boolean serialized, boolean sticky) throws RemoteException;
-    public void unbroadcastIntent(IApplicationThread caller, Intent intent) throws RemoteException;
+            boolean serialized, boolean sticky, int userId) throws RemoteException;
+    public void unbroadcastIntent(IApplicationThread caller, Intent intent, int userId) throws RemoteException;
     /* oneway */
     public void finishReceiver(IBinder who, int resultCode, String resultData, Bundle map, boolean abortBroadcast) throws RemoteException;
     public void attachApplication(IApplicationThread app) throws RemoteException;
@@ -209,7 +209,7 @@
             int flags) throws RemoteException;
     public void cancelIntentSender(IIntentSender sender) throws RemoteException;
     public boolean clearApplicationUserData(final String packageName,
-            final IPackageDataObserver observer) throws RemoteException;
+            final IPackageDataObserver observer, int userId) throws RemoteException;
     public String getPackageForIntentSender(IIntentSender sender) throws RemoteException;
     
     public void setProcessLimit(int max) throws RemoteException;
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 0c6baeb..fcbcd81 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -36,6 +36,7 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.StrictMode;
+import android.os.UserId;
 import android.util.AndroidRuntimeException;
 import android.util.Slog;
 import android.view.CompatibilityInfoHolder;
@@ -67,6 +68,8 @@
  */
 public final class LoadedApk {
 
+    private static final String TAG = "LoadedApk";
+
     private final ActivityThread mActivityThread;
     private final ApplicationInfo mApplicationInfo;
     final String mPackageName;
@@ -113,8 +116,13 @@
         mApplicationInfo = aInfo;
         mPackageName = aInfo.packageName;
         mAppDir = aInfo.sourceDir;
-        mResDir = aInfo.uid == Process.myUid() ? aInfo.sourceDir
+        final int myUid = Process.myUid();
+        mResDir = aInfo.uid == myUid ? aInfo.sourceDir
                 : aInfo.publicSourceDir;
+        if (!UserId.isSameUser(aInfo.uid, myUid)) {
+            aInfo.dataDir = PackageManager.getDataDirForUser(UserId.getUserId(myUid),
+                    mPackageName);
+        }
         mSharedLibraries = aInfo.sharedLibraryFiles;
         mDataDir = aInfo.dataDir;
         mDataDirFile = mDataDir != null ? new File(mDataDir) : null;
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index decb974..bb35c29 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -364,4 +364,6 @@
     VerifierDeviceIdentity getVerifierDeviceIdentity();
 
     boolean isFirstBoot();
+
+    List<UserInfo> getUsers();
 }
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 8541748d..26a9181 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -28,6 +28,7 @@
 import android.content.res.XmlResourceParser;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
+import android.os.Environment;
 import android.util.AndroidException;
 import android.util.DisplayMetrics;
 
@@ -753,13 +754,6 @@
     public static final int VERIFICATION_REJECT = -1;
 
     /**
-     * Range of IDs allocated for a user.
-     *
-     * @hide
-     */
-    public static final int PER_USER_RANGE = 100000;
-
-    /**
      * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device's
      * audio pipeline is low-latency, more suitable for audio applications sensitive to delays or
      * lag in sound input or output.
@@ -2615,39 +2609,6 @@
     public abstract void updateUserFlags(int id, int flags);
 
     /**
-     * Checks to see if the user id is the same for the two uids, i.e., they belong to the same
-     * user.
-     * @hide
-     */
-    public static boolean isSameUser(int uid1, int uid2) {
-        return getUserId(uid1) == getUserId(uid2);
-    }
-
-    /**
-     * Returns the user id for a given uid.
-     * @hide
-     */
-    public static int getUserId(int uid) {
-        return uid / PER_USER_RANGE;
-    }
-
-    /**
-     * Returns the uid that is composed from the userId and the appId.
-     * @hide
-     */
-    public static int getUid(int userId, int appId) {
-        return userId * PER_USER_RANGE + (appId % PER_USER_RANGE);
-    }
-
-    /**
-     * Returns the app id (or base uid) for a given uid, stripping out the user id from it.
-     * @hide
-     */
-    public static int getAppId(int uid) {
-        return uid % PER_USER_RANGE;
-    }
-
-    /**
      * Returns the device identity that verifiers can use to associate their
      * scheme to a particular device. This should not be used by anything other
      * than a package verifier.
@@ -2656,4 +2617,17 @@
      * @hide
      */
     public abstract VerifierDeviceIdentity getVerifierDeviceIdentity();
+
+    /**
+     * Returns the data directory for a particular user and package, given the uid of the package.
+     * @param uid uid of the package, including the userId and appId
+     * @param packageName name of the package
+     * @return the user-specific data directory for the package
+     * @hide
+     */
+    public static String getDataDirForUser(int userId, String packageName) {
+        // TODO: This should be shared with Installer's knowledge of user directory
+        return Environment.getDataDirectory().toString() + "/user/" + userId
+                + "/" + packageName;
+    }
 }
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index e593d5b..faee873 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -24,18 +24,17 @@
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
+import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.PatternMatcher;
+import android.os.UserId;
 import android.util.AttributeSet;
 import android.util.Base64;
 import android.util.DisplayMetrics;
 import android.util.Log;
 import android.util.Slog;
 import android.util.TypedValue;
-import com.android.internal.util.XmlUtils;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.BufferedInputStream;
 import java.io.File;
@@ -59,6 +58,11 @@
 import java.util.jar.JarFile;
 import java.util.jar.Manifest;
 
+import com.android.internal.util.XmlUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
 /**
  * Package archive parsing
  *
@@ -209,6 +213,8 @@
     public static PackageInfo generatePackageInfo(PackageParser.Package p,
             int gids[], int flags, long firstInstallTime, long lastUpdateTime) {
 
+        final int userId = Binder.getOrigCallingUser();
+
         PackageInfo pi = new PackageInfo();
         pi.packageName = p.packageName;
         pi.versionCode = p.mVersionCode;
@@ -250,7 +256,8 @@
                     final Activity activity = p.activities.get(i);
                     if (activity.info.enabled
                         || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
-                        pi.activities[j++] = generateActivityInfo(p.activities.get(i), flags);
+                        pi.activities[j++] = generateActivityInfo(p.activities.get(i), flags,
+                                userId);
                     }
                 }
             }
@@ -271,7 +278,7 @@
                     final Activity activity = p.receivers.get(i);
                     if (activity.info.enabled
                         || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
-                        pi.receivers[j++] = generateActivityInfo(p.receivers.get(i), flags);
+                        pi.receivers[j++] = generateActivityInfo(p.receivers.get(i), flags, userId);
                     }
                 }
             }
@@ -292,7 +299,7 @@
                     final Service service = p.services.get(i);
                     if (service.info.enabled
                         || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
-                        pi.services[j++] = generateServiceInfo(p.services.get(i), flags);
+                        pi.services[j++] = generateServiceInfo(p.services.get(i), flags, userId);
                     }
                 }
             }
@@ -313,7 +320,7 @@
                     final Provider provider = p.providers.get(i);
                     if (provider.info.enabled
                         || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
-                        pi.providers[j++] = generateProviderInfo(p.providers.get(i), flags);
+                        pi.providers[j++] = generateProviderInfo(p.providers.get(i), flags, userId);
                     }
                 }
             }
@@ -3241,8 +3248,12 @@
     }
 
     public static ApplicationInfo generateApplicationInfo(Package p, int flags) {
+        return generateApplicationInfo(p, flags, UserId.getUserId(Binder.getCallingUid()));
+    }
+
+    public static ApplicationInfo generateApplicationInfo(Package p, int flags, int userId) {
         if (p == null) return null;
-        if (!copyNeeded(flags, p, null)) {
+        if (!copyNeeded(flags, p, null) && userId == 0) {
             // CompatibilityMode is global state. It's safe to modify the instance
             // of the package.
             if (!sCompatibilityModeEnabled) {
@@ -3258,6 +3269,10 @@
 
         // Make shallow copy so we can store the metadata/libraries safely
         ApplicationInfo ai = new ApplicationInfo(p.applicationInfo);
+        if (userId != 0) {
+            ai.uid = UserId.getUid(userId, ai.uid);
+            ai.dataDir = PackageManager.getDataDirForUser(userId, ai.packageName);
+        }
         if ((flags & PackageManager.GET_META_DATA) != 0) {
             ai.metaData = p.mAppMetaData;
         }
@@ -3325,16 +3340,15 @@
         }
     }
 
-    public static final ActivityInfo generateActivityInfo(Activity a,
-            int flags) {
+    public static final ActivityInfo generateActivityInfo(Activity a, int flags, int userId) {
         if (a == null) return null;
-        if (!copyNeeded(flags, a.owner, a.metaData)) {
+        if (!copyNeeded(flags, a.owner, a.metaData) && userId == 0) {
             return a.info;
         }
         // Make shallow copies so we can store the metadata safely
         ActivityInfo ai = new ActivityInfo(a.info);
         ai.metaData = a.metaData;
-        ai.applicationInfo = generateApplicationInfo(a.owner, flags);
+        ai.applicationInfo = generateApplicationInfo(a.owner, flags, userId);
         return ai;
     }
 
@@ -3359,15 +3373,15 @@
         }
     }
 
-    public static final ServiceInfo generateServiceInfo(Service s, int flags) {
+    public static final ServiceInfo generateServiceInfo(Service s, int flags, int userId) {
         if (s == null) return null;
-        if (!copyNeeded(flags, s.owner, s.metaData)) {
+        if (!copyNeeded(flags, s.owner, s.metaData) && userId == 0) {
             return s.info;
         }
         // Make shallow copies so we can store the metadata safely
         ServiceInfo si = new ServiceInfo(s.info);
         si.metaData = s.metaData;
-        si.applicationInfo = generateApplicationInfo(s.owner, flags);
+        si.applicationInfo = generateApplicationInfo(s.owner, flags, userId);
         return si;
     }
 
@@ -3400,12 +3414,12 @@
         }
     }
 
-    public static final ProviderInfo generateProviderInfo(Provider p,
-            int flags) {
+    public static final ProviderInfo generateProviderInfo(Provider p, int flags, int userId) {
         if (p == null) return null;
         if (!copyNeeded(flags, p.owner, p.metaData)
                 && ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) != 0
-                        || p.info.uriPermissionPatterns == null)) {
+                        || p.info.uriPermissionPatterns == null)
+                && userId == 0) {
             return p.info;
         }
         // Make shallow copies so we can store the metadata safely
@@ -3414,7 +3428,7 @@
         if ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) == 0) {
             pi.uriPermissionPatterns = null;
         }
-        pi.applicationInfo = generateApplicationInfo(p.owner, flags);
+        pi.applicationInfo = generateApplicationInfo(p.owner, flags, userId);
         return pi;
     }
 
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index 24569fa..577fc43 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -49,6 +49,7 @@
     private static final boolean FIND_POTENTIAL_LEAKS = false;
     private static final String TAG = "Binder";
 
+    /* mObject is used by native code, do not remove or rename */
     private int mObject;
     private IInterface mOwner;
     private String mDescriptor;
@@ -70,7 +71,35 @@
      * incoming transaction, then its own uid is returned.
      */
     public static final native int getCallingUid();
-    
+
+    /**
+     * Return the original ID of the user assigned to the process that sent you the current
+     * transaction that is being processed. This uid can be used with higher-level system services
+     * to determine its identity and check permissions. If the current thread is not currently
+     * executing an incoming transaction, then its own uid is returned.
+     * <p/>
+     * This value cannot be reset by calls to {@link #clearCallingIdentity()}.
+     * @hide
+     */
+    public static final int getOrigCallingUid() {
+        if (UserId.MU_ENABLED) {
+            return getOrigCallingUidNative();
+        } else {
+            return getCallingUid();
+        }
+    }
+
+    private static final native int getOrigCallingUidNative();
+
+    /**
+     * Utility function to return the user id of the calling process.
+     * @return userId of the calling process, extracted from the callingUid
+     * @hide
+     */
+    public static final int getOrigCallingUser() {
+        return UserId.getUserId(getOrigCallingUid());
+    }
+
     /**
      * Reset the identity of the incoming IPC on the current thread.  This can
      * be useful if, while handling an incoming call, you will be calling
diff --git a/core/java/android/os/UserId.java b/core/java/android/os/UserId.java
new file mode 100644
index 0000000..4124d51
--- /dev/null
+++ b/core/java/android/os/UserId.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+/**
+ * @hide
+ */
+public final class UserId {
+    /**
+     * Range of IDs allocated for a user.
+     *
+     * @hide
+     */
+    public static final int PER_USER_RANGE = 100000;
+
+    public static final int USER_ALL = -1;
+
+    /**
+     * Enable multi-user related side effects. Set this to false if there are problems with single
+     * user usecases.
+     * */
+    public static final boolean MU_ENABLED = true;
+
+    /**
+     * Checks to see if the user id is the same for the two uids, i.e., they belong to the same
+     * user.
+     * @hide
+     */
+    public static final boolean isSameUser(int uid1, int uid2) {
+        return getUserId(uid1) == getUserId(uid2);
+    }
+
+    /**
+     * Checks to see if both uids are referring to the same app id, ignoring the user id part of the
+     * uids.
+     * @param uid1 uid to compare
+     * @param uid2 other uid to compare
+     * @return whether the appId is the same for both uids
+     * @hide
+     */
+    public static final boolean isSameApp(int uid1, int uid2) {
+        return getAppId(uid1) == getAppId(uid2);
+    }
+
+    /**
+     * Returns the user id for a given uid.
+     * @hide
+     */
+    public static final int getUserId(int uid) {
+        if (MU_ENABLED) {
+            return uid / PER_USER_RANGE;
+        } else {
+            return 0;
+        }
+    }
+
+    /**
+     * Returns the uid that is composed from the userId and the appId.
+     * @hide
+     */
+    public static final int getUid(int userId, int appId) {
+        if (MU_ENABLED) {
+            return userId * PER_USER_RANGE + (appId % PER_USER_RANGE);
+        } else {
+            return appId;
+        }
+    }
+
+    /**
+     * Returns the app id (or base uid) for a given uid, stripping out the user id from it.
+     * @hide
+     */
+    public static final int getAppId(int uid) {
+        return uid % PER_USER_RANGE;
+    }
+}
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 990a617..e00970a 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -739,6 +739,11 @@
     return IPCThreadState::self()->getCallingUid();
 }
 
+static jint android_os_Binder_getOrigCallingUid(JNIEnv* env, jobject clazz)
+{
+    return IPCThreadState::self()->getOrigCallingUid();
+}
+
 static jlong android_os_Binder_clearCallingIdentity(JNIEnv* env, jobject clazz)
 {
     return IPCThreadState::self()->clearCallingIdentity();
@@ -810,6 +815,7 @@
      /* name, signature, funcPtr */
     { "getCallingPid", "()I", (void*)android_os_Binder_getCallingPid },
     { "getCallingUid", "()I", (void*)android_os_Binder_getCallingUid },
+    { "getOrigCallingUidNative", "()I", (void*)android_os_Binder_getOrigCallingUid },
     { "clearCallingIdentity", "()J", (void*)android_os_Binder_clearCallingIdentity },
     { "restoreCallingIdentity", "(J)V", (void*)android_os_Binder_restoreCallingIdentity },
     { "setThreadStrictModePolicy", "(I)V", (void*)android_os_Binder_setThreadStrictModePolicy },
diff --git a/core/tests/coretests/src/android/app/activity/BroadcastTest.java b/core/tests/coretests/src/android/app/activity/BroadcastTest.java
index 4b1f9fd..d527c0d 100644
--- a/core/tests/coretests/src/android/app/activity/BroadcastTest.java
+++ b/core/tests/coretests/src/android/app/activity/BroadcastTest.java
@@ -303,7 +303,8 @@
     public void testSetSticky() throws Exception {
         Intent intent = new Intent(LaunchpadActivity.BROADCAST_STICKY1, null);
         intent.putExtra("test", LaunchpadActivity.DATA_1);
-        ActivityManagerNative.getDefault().unbroadcastIntent(null, intent);
+        ActivityManagerNative.getDefault().unbroadcastIntent(null, intent,
+                Binder.getOrigCallingUser());
 
         ActivityManagerNative.broadcastStickyIntent(intent, null);
         addIntermediate("finished-broadcast");
@@ -320,7 +321,8 @@
         ActivityManagerNative.broadcastStickyIntent(intent, null);
 
         ActivityManagerNative.getDefault().unbroadcastIntent(
-                null, new Intent(LaunchpadActivity.BROADCAST_STICKY1, null));
+                null, new Intent(LaunchpadActivity.BROADCAST_STICKY1, null),
+                Binder.getOrigCallingUser());
         addIntermediate("finished-unbroadcast");
 
         IntentFilter filter = new IntentFilter(LaunchpadActivity.BROADCAST_STICKY1);