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/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);