User Manager service to manage users and query user details

Moved a bunch of methods from PackageManager to UserManager.

Fix launching of activities from recents to correct user.

Guest creation APIs

Change-Id: I0733405e6eb2829675665e225c759d6baa2b708f
diff --git a/Android.mk b/Android.mk
index 381989c..c2331f2 100644
--- a/Android.mk
+++ b/Android.mk
@@ -139,6 +139,7 @@
 	core/java/android/os/IRemoteCallback.aidl \
 	core/java/android/os/ISchedulingPolicyService.aidl \
 	core/java/android/os/IUpdateLock.aidl \
+        core/java/android/os/IUserManager.aidl \
 	core/java/android/os/IVibratorService.aidl \
 	core/java/android/service/dreams/IDreamManager.aidl \
 	core/java/android/service/dreams/IDreamService.aidl \
diff --git a/api/current.txt b/api/current.txt
index d2f1e4e..9c6c437 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5386,6 +5386,7 @@
     field public static final java.lang.String TEXT_SERVICES_MANAGER_SERVICE = "textservices";
     field public static final java.lang.String UI_MODE_SERVICE = "uimode";
     field public static final java.lang.String USB_SERVICE = "usb";
+    field public static final java.lang.String USER_SERVICE = "user";
     field public static final java.lang.String VIBRATOR_SERVICE = "vibrator";
     field public static final java.lang.String WALLPAPER_SERVICE = "wallpaper";
     field public static final java.lang.String WIFI_P2P_SERVICE = "wifip2p";
@@ -16448,6 +16449,11 @@
     ctor public TransactionTooLargeException();
   }
 
+  public class UserManager {
+    method public java.lang.String getUserName();
+    method public boolean supportsMultipleUsers();
+  }
+
   public abstract class Vibrator {
     method public abstract void cancel();
     method public abstract boolean hasVibrator();
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 4cb5270..eb1f9a2 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -20,6 +20,7 @@
 
 import android.app.ActivityManagerNative;
 import android.content.ComponentName;
+import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ContainerEncryptionParams;
 import android.content.pm.FeatureInfo;
@@ -39,9 +40,11 @@
 import android.content.res.Resources;
 import android.net.Uri;
 import android.os.Binder;
+import android.os.IUserManager;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.UserManager;
 
 import java.io.File;
 import java.lang.reflect.Field;
@@ -59,6 +62,7 @@
 
 public final class Pm {
     IPackageManager mPm;
+    IUserManager mUm;
 
     private WeakHashMap<String, Resources> mResourceCache
             = new WeakHashMap<String, Resources>();
@@ -82,6 +86,7 @@
             return;
         }
 
+        mUm = IUserManager.Stub.asInterface(ServiceManager.getService("user"));
         mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
         if (mPm == null) {
             System.err.println(PM_NOT_RUNNING_ERR);
@@ -985,7 +990,7 @@
         }
         name = arg;
         try {
-            if (mPm.createUser(name, 0) == null) {
+            if (mUm.createUser(name, 0) == null) {
                 System.err.println("Error: couldn't create User.");
                 showUsage();
             }
@@ -1017,7 +1022,7 @@
             return;
         }
         try {
-            if (!mPm.removeUser(userId)) {
+            if (!mUm.removeUser(userId)) {
                 System.err.println("Error: couldn't remove user.");
                 showUsage();
             }
@@ -1034,7 +1039,7 @@
             return;
         }
         try {
-            List<UserInfo> users = mPm.getUsers();
+            List<UserInfo> users = mUm.getUsers();
             if (users == null) {
                 System.err.println("Error: couldn't get users");
             } else {
diff --git a/core/java/android/accounts/AccountManagerService.java b/core/java/android/accounts/AccountManagerService.java
index ba05ee7..935d647 100644
--- a/core/java/android/accounts/AccountManagerService.java
+++ b/core/java/android/accounts/AccountManagerService.java
@@ -51,6 +51,7 @@
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.UserId;
+import android.os.UserManager;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.Pair;
@@ -92,6 +93,7 @@
     private final Context mContext;
 
     private final PackageManager mPackageManager;
+    private UserManager mUserManager;
 
     private HandlerThread mMessageThread;
     private final MessageHandler mMessageHandler;
@@ -245,6 +247,13 @@
         initUser(0);
     }
 
+    private UserManager getUserManager() {
+        if (mUserManager == null) {
+            mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+        }
+        return mUserManager;
+    }
+
     private UserAccounts initUser(int userId) {
         synchronized (mUsers) {
             UserAccounts accounts = mUsers.get(userId);
@@ -382,12 +391,7 @@
     }
 
     private List<UserInfo> getAllUsers() {
-        try {
-            return AppGlobals.getPackageManager().getUsers();
-        } catch (RemoteException re) {
-            // Local to system process, shouldn't happen
-        }
-        return null;
+        return getUserManager().getUsers();
     }
 
     public void onServiceChanged(AuthenticatorDescription desc, boolean removed) {
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 9a50a41..2face4c 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -41,8 +41,8 @@
 import android.content.pm.ProviderInfo;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
-import android.content.pm.UserInfo;
 import android.content.pm.ManifestDigest;
+import android.content.pm.UserInfo;
 import android.content.pm.VerifierDeviceIdentity;
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
@@ -1182,80 +1182,6 @@
         return PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
     }
 
-    // Multi-user support
-
-    /**
-     * @hide
-     */
-    @Override
-    public UserInfo createUser(String name, int flags) {
-        try {
-            return mPM.createUser(name, flags);
-        } catch (RemoteException e) {
-            // Should never happen!
-        }
-        return null;
-    }
-
-    /**
-     * @hide
-     */
-    @Override
-    public List<UserInfo> getUsers() {
-        try {
-            return mPM.getUsers();
-        } catch (RemoteException re) {
-            ArrayList<UserInfo> users = new ArrayList<UserInfo>();
-            UserInfo primary = new UserInfo(0, "Root!", null,
-                    UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY);
-            users.add(primary);
-            return users;
-        }
-    }
-
-    /**
-     * @hide
-     */
-    @Override
-    public UserInfo getUser(int userId) {
-        try {
-            return mPM.getUser(userId);
-        } catch (RemoteException re) {
-            return null;
-        }
-    }
-
-    /**
-     * @hide
-     */
-    @Override
-    public boolean removeUser(int id) {
-        try {
-            return mPM.removeUser(id);
-        } catch (RemoteException e) {
-            return false;
-        }
-    }
-
-    /**
-     * @hide
-     */
-    @Override
-    public void setUserName(int id, String name) {
-        try {
-            mPM.setUserName(id, name);
-        } catch (RemoteException re) {
-        }
-    }
-
-    /**
-     * @hide
-     */
-    @Override
-    public void updateUserFlags(int id, int flags) {
-        // TODO:
-    }
-
     /**
      * @hide
      */
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index d886278..4496ce8 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -80,6 +80,7 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.IPowerManager;
+import android.os.IUserManager;
 import android.os.Looper;
 import android.os.PowerManager;
 import android.os.Process;
@@ -87,6 +88,7 @@
 import android.os.ServiceManager;
 import android.os.UserId;
 import android.os.SystemVibrator;
+import android.os.UserManager;
 import android.os.storage.StorageManager;
 import android.telephony.TelephonyManager;
 import android.content.ClipboardManager;
@@ -498,6 +500,13 @@
                     return WindowManagerImpl.getDefault().makeCompatible(
                             ctx.mPackageInfo.mCompatibilityInfo);
                 }});
+
+        registerService(USER_SERVICE, new ServiceFetcher() {
+            public Object getService(ContextImpl ctx) {
+                IBinder b = ServiceManager.getService(USER_SERVICE);
+                IUserManager service = IUserManager.Stub.asInterface(b);
+                return new UserManager(ctx, service);
+            }});
     }
 
     static ContextImpl getImpl(Context context) {
@@ -918,6 +927,18 @@
             (Activity)null, intent, -1, options);
     }
 
+    /** @hide */
+    @Override
+    public void startActivityAsUser(Intent intent, Bundle options, int userId) {
+        try {
+            ActivityManagerNative.getDefault().startActivityAsUser(
+                mMainThread.getApplicationThread(), intent,
+                intent.resolveTypeIfNeeded(getContentResolver()),
+                null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null, null, options, userId);
+        } catch (RemoteException re) {
+        }
+    }
+
     @Override
     public void startActivities(Intent[] intents) {
         startActivities(intents, null);
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 5a7a989..bf60a96 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -890,6 +890,22 @@
     public abstract void startActivity(Intent intent, Bundle options);
 
     /**
+     * Same as {@link #startActivity(Intent, Bundle)}, but for a specific user. It requires holding
+     * the {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permission.
+     * @param intent The description of the activity to start.
+     * @param options Additional options for how the Activity should be started.
+     * May be null if there are no options.  See {@link android.app.ActivityOptions}
+     * for how to build the Bundle supplied here; there are no supported definitions
+     * for building it manually.
+     * @param userId The user id of the user to start this activity for.
+     * @throws ActivityNotFoundException
+     * @hide
+     */
+    public void startActivityAsUser(Intent intent, Bundle options, int userId) {
+        throw new RuntimeException("Not implemented. Must override in a subclass.");
+    }
+
+    /**
      * Same as {@link #startActivities(Intent[], Bundle)} with no options
      * specified.
      *
@@ -2018,6 +2034,15 @@
     public static final String SCHEDULING_POLICY_SERVICE = "scheduling_policy";
 
     /**
+     * Use with {@link #getSystemService} to retrieve a
+     * {@link android.os.UserManager} for managing users on devices that support multiple users.
+     *
+     * @see #getSystemService
+     * @see android.os.UserManager
+     */
+    public static final String USER_SERVICE = "user";
+
+    /**
      * Determine whether the given permission is allowed for a particular
      * process and user ID running in the system.
      *
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index f007720..ff4c9a1 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -287,6 +287,12 @@
         mBase.startActivity(intent, options);
     }
 
+    /** @hide */
+    @Override
+    public void startActivityAsUser(Intent intent, Bundle options, int userId) {
+        mBase.startActivityAsUser(intent, options, userId);
+    }
+
     @Override
     public void startActivities(Intent[] intents) {
         mBase.startActivities(intents);
diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java
index badcb03..e6303b9 100644
--- a/core/java/android/content/SyncManager.java
+++ b/core/java/android/content/SyncManager.java
@@ -53,6 +53,7 @@
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UserId;
+import android.os.UserManager;
 import android.os.WorkSource;
 import android.provider.Settings;
 import android.text.format.DateUtils;
@@ -206,16 +207,20 @@
     // Use this as a random offset to seed all periodic syncs
     private int mSyncRandomOffsetMillis;
 
+    private UserManager mUserManager;
+
     private static final long SYNC_ALARM_TIMEOUT_MIN = 30 * 1000; // 30 seconds
     private static final long SYNC_ALARM_TIMEOUT_MAX = 2 * 60 * 60 * 1000; // two hours
 
-    private List<UserInfo> getAllUsers() {
-        try {
-            return AppGlobals.getPackageManager().getUsers();
-        } catch (RemoteException re) {
-            // Local to system process, shouldn't happen
+    private UserManager getUserManager() {
+        if (mUserManager == null) {
+            mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
         }
-        return null;
+        return mUserManager;
+    }
+
+    private List<UserInfo> getAllUsers() {
+        return getUserManager().getUsers();
     }
 
     private boolean containsAccountAndUser(AccountAndUser[] accounts, Account account, int userId) {
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 0d87df5..22807a4 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -358,11 +358,6 @@
     boolean setInstallLocation(int loc);
     int getInstallLocation();
 
-    UserInfo createUser(in String name, int flags);
-    boolean removeUser(int userId);
-    void setUserName(int userId, String name);
-    ParcelFileDescriptor setUserIcon(int userId);
-
     void installPackageWithVerification(in Uri packageURI, in IPackageInstallObserver observer,
             int flags, in String installerPackageName, in Uri verificationURI,
             in ManifestDigest manifestDigest, in ContainerEncryptionParams encryptionParams);
@@ -373,9 +368,6 @@
 
     boolean isFirstBoot();
 
-    List<UserInfo> getUsers();
-    UserInfo getUser(int userId);
-
     void setPermissionEnforced(String permission, boolean enforced);
     boolean isPermissionEnforced(String permission);
 
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index cd7ef0e..f287ca5 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2616,56 +2616,6 @@
             String packageName, IPackageMoveObserver observer, int flags);
 
     /**
-     * Creates a user with the specified name and options.
-     *
-     * @param name the user's name
-     * @param flags flags that identify the type of user and other properties.
-     * @see UserInfo
-     *
-     * @return the UserInfo object for the created user, or null if the user could not be created.
-     * @hide
-     */
-    public abstract UserInfo createUser(String name, int flags);
-
-    /**
-     * @return the list of users that were created
-     * @hide
-     */
-    public abstract List<UserInfo> getUsers();
-
-    /**
-     * @param id the ID of the user, where 0 is the primary user.
-     * @hide
-     */
-    public abstract boolean removeUser(int id);
-
-    /**
-     * Updates the user's name.
-     *
-     * @param id the user's id
-     * @param name the new name for the user
-     * @hide
-     */
-    public abstract void setUserName(int id, String name);
-
-    /**
-     * Changes the user's properties specified by the flags.
-     *
-     * @param id the user's id
-     * @param flags the new flags for the user
-     * @hide
-     */
-    public abstract void updateUserFlags(int id, int flags);
-
-    /**
-     * Returns the details for the user specified by userId.
-     * @param userId the user id of the user
-     * @return UserInfo for the specified user, or null if no such user exists.
-     * @hide
-     */
-    public abstract UserInfo getUser(int userId);
-
-    /**
      * 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.
      * 
diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java
index 68a7257..638e273 100644
--- a/core/java/android/content/pm/UserInfo.java
+++ b/core/java/android/content/pm/UserInfo.java
@@ -18,12 +18,17 @@
 
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.Parcelable.Creator;
 
 /**
  * Per-user information.
  * @hide
  */
 public class UserInfo implements Parcelable {
+
+    /** 6 bits for user type */
+    public static final int FLAG_MASK_USER_TYPE = 0x0000003F;
+
     /**
      * Primary user. Only one user can have this flag set. Meaning of this
      * flag TBD.
@@ -41,6 +46,12 @@
      */
     public static final int FLAG_GUEST   = 0x00000004;
 
+    /**
+     * Indicates the user has restrictions in privileges, in addition to those for normal users.
+     * Exact meaning TBD. For instance, maybe they can't install apps or administer WiFi access pts.
+     */
+    public static final int FLAG_RESTRICTED = 0x00000008;
+
     public int id;
     public String name;
     public String iconPath;
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
new file mode 100644
index 0000000..cb1b962
--- /dev/null
+++ b/core/java/android/os/IUserManager.aidl
@@ -0,0 +1,36 @@
+/*
+**
+** Copyright 2012, 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;
+
+import android.os.ParcelFileDescriptor;
+import android.content.pm.UserInfo;
+
+/**
+ *  {@hide}
+ */
+interface IUserManager {
+    UserInfo createUser(in String name, int flags);
+    boolean removeUser(int userHandle);
+    void setUserName(int userHandle, String name);
+    ParcelFileDescriptor setUserIcon(int userHandle);
+    List<UserInfo> getUsers();
+    UserInfo getUserInfo(int userHandle);
+    void setGuestEnabled(boolean enable);
+    boolean isGuestEnabled();
+    void wipeUser(int userHandle);
+}
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
new file mode 100644
index 0000000..9c73392
--- /dev/null
+++ b/core/java/android/os/UserManager.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2012 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;
+
+import com.android.internal.R;
+import android.content.Context;
+import android.content.pm.UserInfo;
+import android.util.Log;
+
+import java.util.List;
+
+/**
+ * Manages users and user details on a multi-user system.
+ */
+public class UserManager {
+
+    private static String TAG = "UserManager";
+    private final IUserManager mService;
+    private final Context mContext;
+
+    /** @hide */
+    public UserManager(Context context, IUserManager service) {
+        mService = service;
+        mContext = context;
+    }
+
+    /**
+     * Returns whether the system supports multiple users.
+     * @return true if multiple users can be created, false if it is a single user device.
+     */
+    public boolean supportsMultipleUsers() {
+        return getMaxSupportedUsers() > 1;
+    }
+
+    /** 
+     * Returns the user handle for the user that this application is running for.
+     * @return the user handle of the user making this call.
+     * @hide
+     * */
+    public int getUserHandle() {
+        return Process.myUserHandle();
+    }
+
+    /**
+     * Returns the user name of the user making this call.
+     * @return the user name
+     */
+    public String getUserName() {
+        try {
+            return mService.getUserInfo(getUserHandle()).name;
+        } catch (RemoteException re) {
+            Log.w(TAG, "Could not get user name", re);
+            return "";
+        }
+    }
+
+    /**
+     * Returns the UserInfo object describing a specific user.
+     * @param userHandle the user handle of the user whose information is being requested.
+     * @return the UserInfo object for a specific user.
+     * @hide
+     * */
+    public UserInfo getUserInfo(int userHandle) {
+        try {
+            return mService.getUserInfo(userHandle);
+        } catch (RemoteException re) {
+            Log.w(TAG, "Could not get user info", re);
+            return null;
+        }
+    }
+
+    /**
+     * Creates a user with the specified name and options.
+     *
+     * @param name the user's name
+     * @param flags flags that identify the type of user and other properties.
+     * @see UserInfo
+     *
+     * @return the UserInfo object for the created user, or null if the user could not be created.
+     * @hide
+     */
+    public UserInfo createUser(String name, int flags) {
+        try {
+            return mService.createUser(name, flags);
+        } catch (RemoteException re) {
+            Log.w(TAG, "Could not create a user", re);
+            return null;
+        }
+    }
+
+    /**
+     * Returns information for all users on this device.
+     * @return the list of users that were created.
+     * @hide
+     */
+    public List<UserInfo> getUsers() {
+        try {
+            return mService.getUsers();
+        } catch (RemoteException re) {
+            Log.w(TAG, "Could not get user list", re);
+            return null;
+        }
+    }
+
+    /**
+     * Removes a user and all associated data.
+     * @param userHandle the integer handle of the user, where 0 is the primary user.
+     * @hide
+     */
+    public boolean removeUser(int userHandle) {
+        try {
+            return mService.removeUser(userHandle);
+        } catch (RemoteException re) {
+            Log.w(TAG, "Could not remove user ", re);
+            return false;
+        }
+    }
+
+    /**
+     * Updates the user's name.
+     *
+     * @param userHandle the user's integer handle
+     * @param name the new name for the user
+     * @hide
+     */
+    public void setUserName(int userHandle, String name) {
+        try {
+            mService.setUserName(userHandle, name);
+        } catch (RemoteException re) {
+            Log.w(TAG, "Could not set the user name ", re);
+        }
+    }
+
+    /**
+     * Returns a file descriptor for the user's photo. PNG data can be written into this file.
+     * @param userHandle the user for whom to change the photo.
+     * @return a {@link ParcelFileDescriptor} to which to write the photo.
+     * @hide
+     */
+    public ParcelFileDescriptor setUserIcon(int userHandle) {
+        try {
+            return mService.setUserIcon(userHandle);
+        } catch (RemoteException re) {
+            Log.w(TAG, "Could not set the user icon ", re);
+            return null;
+        }
+    }
+
+    /**
+     * Enable or disable the use of a guest account. If disabled, the existing guest account
+     * will be wiped.
+     * @param enable whether to enable a guest account.
+     * @hide
+     */
+    public void setGuestEnabled(boolean enable) {
+        try {
+            mService.setGuestEnabled(enable);
+        } catch (RemoteException re) {
+            Log.w(TAG, "Could not change guest account availability to " + enable);
+        }
+    }
+
+    /**
+     * Checks if a guest user is enabled for this device.
+     * @return whether a guest user is enabled
+     * @hide
+     */
+    public boolean isGuestEnabled() {
+        try {
+            return mService.isGuestEnabled();
+        } catch (RemoteException re) {
+            Log.w(TAG, "Could not retrieve guest enabled state");
+            return false;
+        }
+    }
+
+    /**
+     * Wipes all the data for a user, but doesn't remove the user.
+     * @param userHandle
+     * @hide
+     */
+    public void wipeUser(int userHandle) {
+        try {
+            mService.wipeUser(userHandle);
+        } catch (RemoteException re) {
+            Log.w(TAG, "Could not wipe user " + userHandle);
+        }
+    }
+
+    /**
+     * Returns the maximum number of users that can be created on this device. A return value
+     * of 1 means that it is a single user device.
+     * @hide
+     * @return a value greater than or equal to 1 
+     */
+    public int getMaxSupportedUsers() {
+        return mContext.getResources().getInteger(R.integer.config_multiuserMaximumUsers);
+    }
+}
diff --git a/core/java/android/server/search/SearchManagerService.java b/core/java/android/server/search/SearchManagerService.java
index 2411cec..a1f6735 100644
--- a/core/java/android/server/search/SearchManagerService.java
+++ b/core/java/android/server/search/SearchManagerService.java
@@ -32,6 +32,7 @@
 import android.os.Binder;
 import android.os.Process;
 import android.os.UserId;
+import android.os.UserManager;
 import android.provider.Settings;
 import android.util.Log;
 import android.util.SparseArray;
@@ -77,7 +78,8 @@
         Searchables searchables = mSearchables.get(userId);
 
         long origId = Binder.clearCallingIdentity();
-        boolean userExists = mContext.getPackageManager().getUser(userId) != null;
+        boolean userExists = ((UserManager) mContext.getSystemService(Context.USER_SERVICE))
+                .getUserInfo(userId) != null;
         Binder.restoreCallingIdentity(origId);
 
         if (searchables == null && userExists) {
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 6ab323e..ee0ff8e 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -890,4 +890,7 @@
 
     <!-- Set to true to add links to Cell Broadcast app from Settings and MMS app. -->
     <bool name="config_cellBroadcastAppLinks">false</bool>
+
+    <!--  Maximum number of supported users -->
+    <integer name="config_multiuserMaximumUsers">10</integer>
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 5b86db5..38a431f 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -280,6 +280,7 @@
   <java-symbol type="integer" name="config_wifi_driver_stop_delay" />
   <java-symbol type="integer" name="config_soundEffectVolumeDb" />
   <java-symbol type="integer" name="config_lockSoundVolumeDb" />
+  <java-symbol type="integer" name="config_multiuserMaximumUsers" />
 
   <java-symbol type="color" name="tab_indicator_text_v4" />
 
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index cb69660..bb647c3 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -36,6 +36,7 @@
 import android.net.Uri;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.UserId;
 import android.provider.Settings;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -789,7 +790,7 @@
                     | Intent.FLAG_ACTIVITY_TASK_ON_HOME
                     | Intent.FLAG_ACTIVITY_NEW_TASK);
             if (DEBUG) Log.v(TAG, "Starting activity " + intent);
-            context.startActivity(intent, opts.toBundle());
+            context.startActivityAsUser(intent, opts.toBundle(), UserId.USER_CURRENT);
         }
         if (usingDrawingCache) {
             holder.thumbnailViewImage.setDrawingCacheEnabled(false);
diff --git a/policy/src/com/android/internal/policy/impl/GlobalActions.java b/policy/src/com/android/internal/policy/impl/GlobalActions.java
index 6c50f1c..a0e3e3c 100644
--- a/policy/src/com/android/internal/policy/impl/GlobalActions.java
+++ b/policy/src/com/android/internal/policy/impl/GlobalActions.java
@@ -38,6 +38,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemProperties;
+import android.os.UserManager;
 import android.os.Vibrator;
 import android.provider.Settings;
 import android.telephony.PhoneStateListener;
@@ -278,7 +279,8 @@
             mItems.add(mSilentModeAction);
         }
 
-        List<UserInfo> users = mContext.getPackageManager().getUsers();
+        List<UserInfo> users = ((UserManager) mContext.getSystemService(Context.USER_SERVICE))
+                .getUsers();
         if (users.size() > 1) {
             UserInfo currentUser;
             try {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 96cf3d3..e8350c1 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -55,6 +55,7 @@
 import com.android.server.net.NetworkPolicyManagerService;
 import com.android.server.net.NetworkStatsService;
 import com.android.server.pm.PackageManagerService;
+import com.android.server.pm.UserManagerService;
 import com.android.server.power.PowerManagerService;
 import com.android.server.power.ShutdownThread;
 import com.android.server.usb.UsbService;
@@ -192,6 +193,11 @@
             }
 
             ActivityManagerService.setSystemProcess();
+            
+            Slog.i(TAG, "User Service");
+            ServiceManager.addService(Context.USER_SERVICE,
+                    UserManagerService.getInstance(context));
+
 
             mContentResolver = context.getContentResolver();
 
diff --git a/services/java/com/android/server/am/ActiveServices.java b/services/java/com/android/server/am/ActiveServices.java
index df6c51e..533c2cd 100644
--- a/services/java/com/android/server/am/ActiveServices.java
+++ b/services/java/com/android/server/am/ActiveServices.java
@@ -1835,7 +1835,7 @@
 
         pw.println("ACTIVITY MANAGER SERVICES (dumpsys activity services)");
         try {
-            List<UserInfo> users = AppGlobals.getPackageManager().getUsers();
+            List<UserInfo> users = mAm.getUserManager().getUsers();
             for (UserInfo user : users) {
                 if (mServiceMap.getAllServices(user.id).size() > 0) {
                     boolean printed = false;
@@ -1913,8 +1913,8 @@
                     needSep = printed;
                 }
             }
-        } catch (RemoteException re) {
-
+        } catch (Exception e) {
+            Log.w(TAG, "Exception in dumpServicesLocked: " + e);
         }
 
         if (mPendingServices.size() > 0) {
@@ -2028,16 +2028,13 @@
             int opti, boolean dumpAll) {
         ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
 
+        List<UserInfo> users = mAm.getUserManager().getUsers();
         if ("all".equals(name)) {
             synchronized (this) {
-                try {
-                    List<UserInfo> users = AppGlobals.getPackageManager().getUsers();
-                    for (UserInfo user : users) {
-                        for (ServiceRecord r1 : mServiceMap.getAllServices(user.id)) {
-                            services.add(r1);
-                        }
+                for (UserInfo user : users) {
+                    for (ServiceRecord r1 : mServiceMap.getAllServices(user.id)) {
+                        services.add(r1);
                     }
-                } catch (RemoteException re) {
                 }
             }
         } else {
@@ -2055,24 +2052,20 @@
             }
 
             synchronized (this) {
-                try {
-                    List<UserInfo> users = AppGlobals.getPackageManager().getUsers();
-                    for (UserInfo user : users) {
-                        for (ServiceRecord r1 : mServiceMap.getAllServices(user.id)) {
-                            if (componentName != null) {
-                                if (r1.name.equals(componentName)) {
-                                    services.add(r1);
-                                }
-                            } else if (name != null) {
-                                if (r1.name.flattenToString().contains(name)) {
-                                    services.add(r1);
-                                }
-                            } else if (System.identityHashCode(r1) == objectId) {
+                for (UserInfo user : users) {
+                    for (ServiceRecord r1 : mServiceMap.getAllServices(user.id)) {
+                        if (componentName != null) {
+                            if (r1.name.equals(componentName)) {
                                 services.add(r1);
                             }
+                        } else if (name != null) {
+                            if (r1.name.flattenToString().contains(name)) {
+                                services.add(r1);
+                            }
+                        } else if (System.identityHashCode(r1) == objectId) {
+                            services.add(r1);
                         }
                     }
-                } catch (RemoteException re) {
                 }
             }
         }
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 5bed015..d3ec9f7 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -27,6 +27,7 @@
 import com.android.server.SystemServer;
 import com.android.server.Watchdog;
 import com.android.server.am.ActivityStack.ActivityState;
+import com.android.server.pm.UserManagerService;
 import com.android.server.wm.WindowManagerService;
 
 import dalvik.system.Zygote;
@@ -76,12 +77,12 @@
 import android.content.pm.InstrumentationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.PathPermission;
 import android.content.pm.ProviderInfo;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
-import android.content.pm.UserInfo;
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
@@ -111,6 +112,7 @@
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UserId;
+import android.os.UserManager;
 import android.provider.Settings;
 import android.text.format.Time;
 import android.util.EventLog;
@@ -778,6 +780,10 @@
     static ActivityManagerService mSelf;
     static ActivityThread mSystemThread;
 
+    private int mCurrentUserId;
+    private SparseIntArray mLoggedInUsers = new SparseIntArray(5);
+    private UserManager mUserManager;
+
     private final class AppDeathRecipient implements IBinder.DeathRecipient {
         final ProcessRecord mApp;
         final int mPid;
@@ -4197,19 +4203,14 @@
                 // Tell anyone interested that we are done booting!
                 SystemProperties.set("sys.boot_completed", "1");
                 SystemProperties.set("dev.bootcomplete", "1");
-                try {
-                    List<UserInfo> users = AppGlobals.getPackageManager().getUsers();
-                    for (UserInfo user : users) {
-                        broadcastIntentLocked(null, null,
-                                new Intent(Intent.ACTION_BOOT_COMPLETED, null),
-                                null, null, 0, null, null,
-                                android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
-                                false, false, MY_PID, Process.SYSTEM_UID, user.id);
-                    }
-                } catch (RemoteException re) {
-                    // Won't happen, in same process
+                List<UserInfo> users = getUserManager().getUsers();
+                for (UserInfo user : users) {
+                    broadcastIntentLocked(null, null,
+                            new Intent(Intent.ACTION_BOOT_COMPLETED, null),
+                            null, null, 0, null, null,
+                            android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
+                            false, false, MY_PID, Process.SYSTEM_UID, user.id);
                 }
-
             }
         }
     }
@@ -13358,9 +13359,6 @@
 
     // Multi-user methods
 
-    private int mCurrentUserId;
-    private SparseIntArray mLoggedInUsers = new SparseIntArray(5);
-
     public boolean switchUser(int userId) {
         final int callingUid = Binder.getCallingUid();
         if (callingUid != 0 && callingUid != Process.myUid()) {
@@ -13403,7 +13401,7 @@
             Slog.e(TAG, "Trying to get user from unauthorized app");
             return null;
         }
-        return AppGlobals.getPackageManager().getUser(mCurrentUserId);
+        return getUserManager().getUserInfo(mCurrentUserId);
     }
 
     private void onUserRemoved(Intent intent) {
@@ -13431,14 +13429,15 @@
     }
 
     private boolean userExists(int userId) {
-        try {
-            UserInfo user = AppGlobals.getPackageManager().getUser(userId);
-            return user != null;
-        } catch (RemoteException re) {
-            // Won't happen, in same process
-        }
+        UserInfo user = getUserManager().getUserInfo(userId);
+        return user != null;
+    }
 
-        return false;
+    UserManager getUserManager() {
+        if (mUserManager == null) {
+            mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+        }
+        return mUserManager;
     }
 
     private void checkValidCaller(int uid, int userId) {
diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java
index 7e5f8cf..46c24b0 100644
--- a/services/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -113,6 +113,7 @@
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.UserId;
+import android.os.UserManager;
 import android.provider.Settings;
 import android.telephony.TelephonyManager;
 import android.text.format.Formatter;
@@ -1707,7 +1708,8 @@
     }
 
     private void updateRulesForAppLocked(int appId) {
-        for (UserInfo user : mContext.getPackageManager().getUsers()) {
+        UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+        for (UserInfo user : um.getUsers()) {
             final int uid = UserId.getUid(user.id, appId);
             updateRulesForUidLocked(uid);
         }
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 180081b..f257203 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -68,6 +68,7 @@
 import android.content.pm.PackageInfoLite;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageParser;
+import android.content.pm.UserInfo;
 import android.content.pm.PackageParser.ActivityIntentInfo;
 import android.content.pm.PackageStats;
 import android.content.pm.ParceledListSlice;
@@ -77,7 +78,6 @@
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.content.pm.Signature;
-import android.content.pm.UserInfo;
 import android.content.pm.ManifestDigest;
 import android.content.pm.VerifierDeviceIdentity;
 import android.content.pm.VerifierInfo;
@@ -101,6 +101,7 @@
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UserId;
+import android.os.UserManager;
 import android.provider.Settings.Secure;
 import android.security.SystemKeyStore;
 import android.util.DisplayMetrics;
@@ -420,7 +421,7 @@
     // Delay time in millisecs
     static final int BROADCAST_DELAY = 10 * 1000;
 
-    static UserManager sUserManager;
+    static UserManagerService sUserManager;
 
     // Stores a list of users whose package restrictions file needs to be updated
     private HashSet<Integer> mDirtyUsers = new HashSet<Integer>();
@@ -899,7 +900,7 @@
         mOnlyCore = onlyCore;
         mNoDexOpt = "eng".equals(SystemProperties.get("ro.build.type"));
         mMetrics = new DisplayMetrics();
-        mSettings = new Settings();
+        mSettings = new Settings(context);
         mSettings.addSharedUserLPw("android.uid.system",
                 Process.SYSTEM_UID, ApplicationInfo.FLAG_SYSTEM);
         mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID, ApplicationInfo.FLAG_SYSTEM);
@@ -942,11 +943,12 @@
             mUserAppDataDir = new File(dataDir, "user");
             mDrmAppPrivateInstallDir = new File(dataDir, "app-private");
 
-            sUserManager = new UserManager(mInstaller, mUserAppDataDir);
+            sUserManager = UserManagerService.getInstance(context);
+            sUserManager.setInstaller(this, mInstaller);
 
             readPermissions();
 
-            mRestoredSettings = mSettings.readLPw(getUsers());
+            mRestoredSettings = mSettings.readLPw(sUserManager.getUsers());
             long startTime = SystemClock.uptimeMillis();
 
             EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START,
@@ -9459,48 +9461,16 @@
                 PackageHelper.APP_INSTALL_AUTO);
     }
 
-    public UserInfo createUser(String name, int flags) {
-        // TODO(kroot): Add a real permission for creating users
-        enforceSystemOrRoot("Only the system can create users");
-
-        UserInfo userInfo = sUserManager.createUser(name, flags);
-        if (userInfo != null) {
-            Intent addedIntent = new Intent(Intent.ACTION_USER_ADDED);
-            addedIntent.putExtra(Intent.EXTRA_USERID, userInfo.id);
-            mContext.sendBroadcast(addedIntent, android.Manifest.permission.MANAGE_ACCOUNTS);
-        }
-        return userInfo;
-    }
-
-    public boolean removeUser(int userId) {
-        // TODO(kroot): Add a real permission for removing users
-        enforceSystemOrRoot("Only the system can remove users");
-
-        if (userId == 0 || !sUserManager.exists(userId)) {
-            return false;
-        }
-
-        cleanUpUser(userId);
-
-        if (sUserManager.removeUser(userId)) {
-            // Let other services shutdown any activity
-            Intent addedIntent = new Intent(Intent.ACTION_USER_REMOVED);
-            addedIntent.putExtra(Intent.EXTRA_USERID, userId);
-            mContext.sendBroadcast(addedIntent, android.Manifest.permission.MANAGE_ACCOUNTS);
-        }
-        sUserManager.removePackageFolders(userId);
-        return true;
-    }
-
-    private void cleanUpUser(int userId) {
+    /** Called by UserManagerService */
+    void cleanUpUser(int userHandle) {
         // Disable all the packages for the user first
         synchronized (mPackages) {
             Set<Entry<String, PackageSetting>> entries = mSettings.mPackages.entrySet();
             for (Entry<String, PackageSetting> entry : entries) {
-                entry.getValue().removeUser(userId);
+                entry.getValue().removeUser(userHandle);
             }
-            if (mDirtyUsers.remove(userId));
-            mSettings.removeUserLPr(userId);
+            if (mDirtyUsers.remove(userHandle));
+            mSettings.removeUserLPr(userHandle);
         }
     }
 
@@ -9516,30 +9486,6 @@
     }
 
     @Override
-    public List<UserInfo> getUsers() {
-        enforceSystemOrRoot("Only the system can query users");
-        return sUserManager.getUsers();
-    }
-
-    @Override
-    public UserInfo getUser(int userId) {
-        enforceSystemOrRoot("Only the system can query user");
-        return sUserManager.getUser(userId);
-    }
-
-    @Override
-    public void setUserName(int userId, String name) {
-        enforceSystemOrRoot("Only the system can rename users");
-        sUserManager.setUserName(userId, name);
-    }
-
-    @Override
-    public ParcelFileDescriptor setUserIcon(int userId) {
-        enforceSystemOrRoot("Only the system can update users");
-        return sUserManager.setUserIcon(userId);
-    }
-
-    @Override
     public void setPermissionEnforced(String permission, boolean enforced) {
         mContext.enforceCallingOrSelfPermission(GRANT_REVOKE_PERMISSIONS, null);
         if (READ_EXTERNAL_STORAGE.equals(permission)) {
diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java
index def1696..add91d3 100644
--- a/services/java/com/android/server/pm/Settings.java
+++ b/services/java/com/android/server/pm/Settings.java
@@ -34,6 +34,7 @@
 
 import android.app.AppGlobals;
 import android.content.ComponentName;
+import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ComponentInfo;
@@ -79,6 +80,7 @@
     private static final String TAG = "PackageSettings";
 
     private static final boolean DEBUG_STOPPED = false;
+    private static final boolean DEBUG_MU = false;
 
     private static final String TAG_READ_EXTERNAL_STORAGE = "read-external-storage";
     private static final String ATTR_ENFORCEMENT = "enforcement";
@@ -173,12 +175,15 @@
      */
     private final ArrayList<PendingPackage> mPendingPackages = new ArrayList<PendingPackage>();
 
+    private final Context mContext;
+
     private final File mSystemDir;
-    Settings() {
-        this(Environment.getDataDirectory());
+    Settings(Context context) {
+        this(context, Environment.getDataDirectory());
     }
 
-    Settings(File dataDir) {
+    Settings(Context context, File dataDir) {
+        mContext = context;
         mSystemDir = new File(dataDir, "system");
         mSystemDir.mkdirs();
         FileUtils.setPermissions(mSystemDir.toString(),
@@ -739,6 +744,9 @@
     }
 
     void readPackageRestrictionsLPr(int userId) {
+        if (DEBUG_MU) {
+            Log.i(TAG, "Reading package restrictions for user=" + userId);
+        }
         FileInputStream str = null;
         File userPackagesStateFile = getUserPackagesStateFile(userId);
         File backupFile = getUserPackagesStateBackupFile(userId);
@@ -891,6 +899,9 @@
     }
 
     void writePackageRestrictionsLPr(int userId) {
+        if (DEBUG_MU) {
+            Log.i(TAG, "Writing package restrictions for user=" + userId);
+        }
         // Keep the old stopped packages around until we know the new ones have
         // been successfully written.
         File userPackagesStateFile = getUserPackagesStateFile(userId);
@@ -935,6 +946,7 @@
                     boolean stopped = pkg.getStopped(userId);
                     boolean notLaunched = pkg.getNotLaunched(userId);
                     int enabled = pkg.getEnabled(userId);
+                    if (DEBUG_MU) Log.i(TAG, "  pkg=" + pkg.name + ", state=" + enabled);
                     HashSet<String> enabledComponents = pkg.getEnabledComponents(userId);
                     HashSet<String> disabledComponents = pkg.getDisabledComponents(userId);
 
@@ -1584,7 +1596,24 @@
             mReadMessages.append("Error reading: " + e.toString());
             PackageManagerService.reportSettingsProblem(Log.ERROR, "Error reading settings: " + e);
             Log.wtf(PackageManagerService.TAG, "Error reading package manager settings", e);
+        }
 
+        if (mBackupStoppedPackagesFilename.exists()
+                || mStoppedPackagesFilename.exists()) {
+            // Read old file
+            readStoppedLPw();
+            mBackupStoppedPackagesFilename.delete();
+            mStoppedPackagesFilename.delete();
+            // Migrate to new file format
+            writePackageRestrictionsLPr(0);
+        } else {
+            if (users == null) {
+                readPackageRestrictionsLPr(0);
+            } else {
+                for (UserInfo user : users) {
+                    readPackageRestrictionsLPr(user.id);
+                }
+            }
         }
 
         final int N = mPendingPackages.size();
@@ -1628,23 +1657,6 @@
             }
         }
 
-        if (mBackupStoppedPackagesFilename.exists()
-                || mStoppedPackagesFilename.exists()) {
-            // Read old file
-            readStoppedLPw();
-            mBackupStoppedPackagesFilename.delete();
-            mStoppedPackagesFilename.delete();
-            // Migrate to new file format
-            writePackageRestrictionsLPr(0);
-        } else {
-            if (users == null) {
-                readPackageRestrictionsLPr(0);
-            } else {
-                for (UserInfo user : users) {
-                    readPackageRestrictionsLPr(user.id);
-                }
-            }
-        }
         mReadMessages.append("Read completed successfully: " + mPackages.size() + " packages, "
                 + mSharedUsers.size() + " shared uids\n");
 
@@ -2378,9 +2390,7 @@
     private List<UserInfo> getAllUsers() {
         long id = Binder.clearCallingIdentity();
         try {
-            return AppGlobals.getPackageManager().getUsers();
-        } catch (RemoteException re) {
-            // Local to system process, shouldn't happen
+            return UserManagerService.getInstance(mContext).getUsers();
         } catch (NullPointerException npe) {
             // packagemanager not yet initialized
         } finally {
diff --git a/services/java/com/android/server/pm/UserManager.java b/services/java/com/android/server/pm/UserManagerService.java
similarity index 78%
rename from services/java/com/android/server/pm/UserManager.java
rename to services/java/com/android/server/pm/UserManagerService.java
index 738ab08..b55dd24 100644
--- a/services/java/com/android/server/pm/UserManager.java
+++ b/services/java/com/android/server/pm/UserManagerService.java
@@ -22,12 +22,17 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastXmlSerializer;
 
+import android.content.Context;
+import android.content.Intent;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
+import android.os.Binder;
 import android.os.Environment;
 import android.os.FileUtils;
+import android.os.IUserManager;
 import android.os.ParcelFileDescriptor;
+import android.os.Process;
 import android.os.SystemClock;
 import android.os.UserId;
 import android.util.Log;
@@ -48,9 +53,9 @@
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
 
-public class UserManager {
+public class UserManagerService extends IUserManager.Stub {
 
-    private static final String TAG = "UserManager";
+    private static final String TAG = "UserManagerService";
 
     private static final String TAG_NAME = "name";
 
@@ -75,14 +80,25 @@
     private final File mUsersDir;
     private final File mUserListFile;
     private int[] mUserIds;
+    private boolean mGuestEnabled;
 
     private Installer mInstaller;
     private File mBaseUserPath;
+    private Context mContext;
+    private static UserManagerService sInstance;
+    private PackageManagerService mPm;
+
+    public synchronized static UserManagerService getInstance(Context context) {
+        if (sInstance == null) {
+            sInstance = new UserManagerService(context);
+        }
+        return sInstance;
+    }
 
     /**
      * Available for testing purposes.
      */
-    UserManager(File dataDir, File baseUserPath) {
+    UserManagerService(File dataDir, File baseUserPath) {
         mUsersDir = new File(dataDir, USER_INFO_DIR);
         mUsersDir.mkdirs();
         // Make zeroth user directory, for services to migrate their files to that location
@@ -97,12 +113,19 @@
         readUserList();
     }
 
-    public UserManager(Installer installer, File baseUserPath) {
-        this(Environment.getDataDirectory(), baseUserPath);
-        mInstaller = installer;
+    public UserManagerService(Context context) {
+        this(Environment.getDataDirectory(), new File(Environment.getDataDirectory(), "user"));
+        mContext = context;
     }
 
+    void setInstaller(PackageManagerService pm, Installer installer) {
+        mInstaller = installer;
+        mPm = pm;
+    }
+
+    @Override
     public List<UserInfo> getUsers() {
+        enforceSystemOrRoot("Only the system can query users");
         synchronized (mUsers) {
             ArrayList<UserInfo> users = new ArrayList<UserInfo>(mUsers.size());
             for (int i = 0; i < mUsers.size(); i++) {
@@ -112,7 +135,9 @@
         }
     }
 
-    public UserInfo getUser(int userId) {
+    @Override
+    public UserInfo getUserInfo(int userId) {
+        enforceSystemOrRoot("Only the system can query user");
         synchronized (mUsers) {
             UserInfo info = mUsers.get(userId);
             return info;
@@ -125,7 +150,9 @@
         }
     }
 
+    @Override
     public void setUserName(int userId, String name) {
+        enforceSystemOrRoot("Only the system can rename users");
         synchronized (mUsers) {
             UserInfo info = mUsers.get(userId);
             if (name != null && !name.equals(info.name)) {
@@ -135,7 +162,9 @@
         }
     }
 
+    @Override
     public ParcelFileDescriptor setUserIcon(int userId) {
+        enforceSystemOrRoot("Only the system can update users");
         synchronized (mUsers) {
             UserInfo info = mUsers.get(userId);
             if (info == null) return null;
@@ -147,6 +176,57 @@
         }
     }
 
+    @Override
+    public void setGuestEnabled(boolean enable) {
+        enforceSystemOrRoot("Only the system can enable guest users");
+        synchronized (mUsers) {
+            if (mGuestEnabled != enable) {
+                mGuestEnabled = enable;
+                // Erase any guest user that currently exists
+                for (int i = 0; i < mUsers.size(); i++) {
+                    UserInfo user = mUsers.valueAt(i);
+                    if (user.isGuest()) {
+                        if (!enable) {
+                            removeUser(user.id);
+                        }
+                        return;
+                    }
+                }
+                // No guest was found
+                if (enable) {
+                    createUser("Guest", UserInfo.FLAG_GUEST);
+                }
+            }
+        }
+    }
+
+    @Override
+    public boolean isGuestEnabled() {
+        synchronized (mUsers) {
+            return mGuestEnabled;
+        }
+    }
+
+    @Override
+    public void wipeUser(int userHandle) {
+        enforceSystemOrRoot("Only the system can wipe users");
+        // TODO:
+    }
+
+    /**
+     * Enforces that only the system UID or root's UID can call a method exposed
+     * via Binder.
+     *
+     * @param message used as message if SecurityException is thrown
+     * @throws SecurityException if the caller is not system or root
+     */
+    private static final void enforceSystemOrRoot(String message) {
+        final int uid = Binder.getCallingUid();
+        if (uid != Process.SYSTEM_UID && uid != 0) {
+            throw new SecurityException(message);
+        }
+    }
+
     private ParcelFileDescriptor updateIconBitmapLocked(UserInfo info) {
         try {
             File dir = new File(mUsersDir, Integer.toString(info.id));
@@ -184,6 +264,7 @@
     }
 
     private void readUserListLocked() {
+        mGuestEnabled = false;
         if (!mUserListFile.exists()) {
             fallbackToSingleUserLocked();
             return;
@@ -212,6 +293,9 @@
                     if (user != null) {
                         mUsers.put(user.id, user);
                     }
+                    if (user.isGuest()) {
+                        mGuestEnabled = true;
+                    }
                 }
             }
             updateUserIdsLocked();
@@ -389,7 +473,9 @@
         return null;
     }
 
+    @Override
     public UserInfo createUser(String name, int flags) {
+        enforceSystemOrRoot("Only the system can create users");
         int userId = getNextAvailableId();
         UserInfo userInfo = new UserInfo(userId, name, null, flags);
         File userPath = new File(mBaseUserPath, Integer.toString(userId));
@@ -402,6 +488,11 @@
             writeUserLocked(userInfo);
             updateUserIdsLocked();
         }
+        if (userInfo != null) {
+            Intent addedIntent = new Intent(Intent.ACTION_USER_ADDED);
+            addedIntent.putExtra(Intent.EXTRA_USERID, userInfo.id);
+            mContext.sendBroadcast(addedIntent, android.Manifest.permission.MANAGE_ACCOUNTS);
+        }
         return userInfo;
     }
 
@@ -410,27 +501,37 @@
      * after the user's processes have been terminated.
      * @param id the user's id
      */
-    public boolean removeUser(int id) {
+    public boolean removeUser(int userHandle) {
+        enforceSystemOrRoot("Only the system can remove users");
         synchronized (mUsers) {
-            return removeUserLocked(id);
+            return removeUserLocked(userHandle);
         }
     }
 
-    private boolean removeUserLocked(int id) {
-        // Remove from the list
-        UserInfo userInfo = mUsers.get(id);
-        if (userInfo != null) {
-            // Remove this user from the list
-            mUsers.remove(id);
-            // Remove user file
-            File userFile = new File(mUsersDir, id + ".xml");
-            userFile.delete();
-            // Update the user list
-            writeUserListLocked();
-            updateUserIdsLocked();
-            return true;
+    private boolean removeUserLocked(int userHandle) {
+        final UserInfo user = mUsers.get(userHandle);
+        if (userHandle == 0 || user == null) {
+            return false;
         }
-        return false;
+
+        mPm.cleanUpUser(userHandle);
+
+        // Remove this user from the list
+        mUsers.remove(userHandle);
+        // Remove user file
+        File userFile = new File(mUsersDir, userHandle + ".xml");
+        userFile.delete();
+        // Update the user list
+        writeUserListLocked();
+        updateUserIdsLocked();
+
+        // Let other services shutdown any activity
+        Intent addedIntent = new Intent(Intent.ACTION_USER_REMOVED);
+        addedIntent.putExtra(Intent.EXTRA_USERID, userHandle);
+        mContext.sendBroadcast(addedIntent, android.Manifest.permission.MANAGE_ACCOUNTS);
+
+        removePackageFolders(userHandle);
+        return true;
     }
 
     public void installPackageForAllUsers(String packageName, int uid) {
diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index 416900f8..f6f9aa0 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
@@ -176,13 +176,6 @@
                         return info;
                     }
 
-                    @Override
-                    public List<UserInfo> getUsers() {
-                        final ArrayList<UserInfo> users = new ArrayList<UserInfo>();
-                        users.add(new UserInfo(USER_ID, "Primary", null, UserInfo.FLAG_PRIMARY));
-                        users.add(new UserInfo(USER_ID_GUEST, "Guest", 0));
-                        return users;
-                    }
                 };
             }
 
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index 796372d..5f93e6f 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -138,7 +138,7 @@
 
         // Write the package files and make sure they're parsed properly the first time
         writeOldFiles();
-        Settings settings = new Settings(getContext().getFilesDir());
+        Settings settings = new Settings(getContext(), getContext().getFilesDir());
         assertEquals(true, settings.readLPw(null));
         assertNotNull(settings.peekPackageLPr(PACKAGE_NAME_3));
         assertNotNull(settings.peekPackageLPr(PACKAGE_NAME_1));
@@ -156,11 +156,11 @@
     public void testNewPackageRestrictionsFile() {
         // Write the package files and make sure they're parsed properly the first time
         writeOldFiles();
-        Settings settings = new Settings(getContext().getFilesDir());
+        Settings settings = new Settings(getContext(), getContext().getFilesDir());
         assertEquals(true, settings.readLPw(null));
 
         // Create Settings again to make it read from the new files
-        settings = new Settings(getContext().getFilesDir());
+        settings = new Settings(getContext(), getContext().getFilesDir());
         assertEquals(true, settings.readLPw(null));
 
         PackageSetting ps = settings.peekPackageLPr(PACKAGE_NAME_2);
@@ -171,7 +171,7 @@
     public void testEnableDisable() {
         // Write the package files and make sure they're parsed properly the first time
         writeOldFiles();
-        Settings settings = new Settings(getContext().getFilesDir());
+        Settings settings = new Settings(getContext(), getContext().getFilesDir());
         assertEquals(true, settings.readLPw(null));
 
         // Enable/Disable a package
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index d736ac1..bc3649c 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -16,7 +16,7 @@
 
 package com.android.server.pm;
 
-import com.android.server.pm.UserManager;
+import com.android.server.pm.UserManagerService;
 
 import android.content.pm.UserInfo;
 import android.os.Debug;
@@ -25,14 +25,14 @@
 
 import java.util.List;
 
-/** Test {@link UserManager} functionality. */
+/** Test {@link UserManagerService} functionality. */
 public class UserManagerTest extends AndroidTestCase {
 
-    UserManager mUserManager = null;
+    UserManagerService mUserManager = null;
 
     @Override
     public void setUp() throws Exception {
-        mUserManager = new UserManager(Environment.getExternalStorageDirectory(),
+        mUserManager = new UserManagerService(Environment.getExternalStorageDirectory(),
                 Environment.getExternalStorageDirectory());
     }
 
@@ -52,7 +52,7 @@
     }
 
     public void testAddUser() throws Exception {
-        final UserManager details = mUserManager;
+        final UserManagerService details = mUserManager;
 
         UserInfo userInfo = details.createUser("Guest 1", UserInfo.FLAG_GUEST);
         assertTrue(userInfo != null);
@@ -71,7 +71,7 @@
     }
 
     public void testAdd2Users() throws Exception {
-        final UserManager details = mUserManager;
+        final UserManagerService details = mUserManager;
 
         UserInfo user1 = details.createUser("Guest 1", UserInfo.FLAG_GUEST);
         UserInfo user2 = details.createUser("User 2", UserInfo.FLAG_ADMIN);
@@ -85,7 +85,7 @@
     }
 
     public void testRemoveUser() throws Exception {
-        final UserManager details = mUserManager;
+        final UserManagerService details = mUserManager;
 
         UserInfo userInfo = details.createUser("Guest 1", UserInfo.FLAG_GUEST);
 
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index 0399b3b..ef14404 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -513,54 +513,6 @@
      * @hide
      */
     @Override
-    public UserInfo createUser(String name, int flags) {
-        throw new UnsupportedOperationException();
-    }
-
-    /**
-     * @hide
-     */
-    @Override
-    public List<UserInfo> getUsers() {
-        throw new UnsupportedOperationException();
-    }
-
-    /**
-     * @hide
-     */
-    @Override
-    public UserInfo getUser(int userId) {
-        throw new UnsupportedOperationException();
-    }
-
-    /**
-     * @hide
-     */
-    @Override
-    public boolean removeUser(int id) {
-        throw new UnsupportedOperationException();
-    }
-
-    /**
-     * @hide
-     */
-    @Override
-    public void setUserName(int id, String name) {
-        throw new UnsupportedOperationException();
-    }
-
-    /**
-     * @hide
-     */
-    @Override
-    public void updateUserFlags(int id, int flags) {
-        throw new UnsupportedOperationException();
-    }
-
-    /**
-     * @hide
-     */
-    @Override
     public void installPackageWithVerification(Uri packageURI, IPackageInstallObserver observer,
             int flags, String installerPackageName, Uri verificationURI,
             ManifestDigest manifestDigest, ContainerEncryptionParams encryptionParams) {