User management and switching

Broadcast intents that get sent out when users are added/removed/switched.

More work on generating user-specific information in package manager queries.
APIs to update user name and query a user by id.
Removed Package.mSetStopped and mSetEnabled, since they're not user specific.

User removal:
- Cleanup ActivityManager, PackageManager, WallpaperManager, AppWidgetService
  and AccountManager.
- Shutdown processes belonging to the user.

Don't show vibrate option in long-press power if there's no vibrator.

Lock the screen when switching users, to force unlocking.

Change-Id: Ib23a721cb75285eef5fd6ba8c7272462764038fa
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java
index a85b605..eb024e9 100644
--- a/services/java/com/android/server/AppWidgetService.java
+++ b/services/java/com/android/server/AppWidgetService.java
@@ -170,6 +170,15 @@
         sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
         sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
         mContext.registerReceiver(mBroadcastReceiver, sdFilter);
+
+        IntentFilter userFilter = new IntentFilter();
+        userFilter.addAction(Intent.ACTION_USER_REMOVED);
+        mContext.registerReceiver(new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                onUserRemoved(intent.getIntExtra(Intent.EXTRA_USERID, -1));
+            }
+        }, userFilter);
     }
 
     @Override
@@ -192,19 +201,6 @@
         getImplForUser().deleteAllHosts();
     }
 
-    void cancelBroadcasts(Provider p) {
-        if (p.broadcast != null) {
-            mAlarmManager.cancel(p.broadcast);
-            long token = Binder.clearCallingIdentity();
-            try {
-                p.broadcast.cancel();
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-            p.broadcast = null;
-        }
-    }
-
     @Override
     public void bindAppWidgetId(int appWidgetId, ComponentName provider) throws RemoteException {
         getImplForUser().bindAppWidgetId(appWidgetId, provider);
@@ -222,8 +218,15 @@
         return getImplForUser().startListening(host, packageName, hostId, updatedViews);
     }
 
-    // TODO: Call this from PackageManagerService when a user is removed
-    public void removeUser(int userId) {
+    public void onUserRemoved(int userId) {
+        AppWidgetServiceImpl impl = mAppWidgetServices.get(userId);
+        if (userId < 1) return;
+
+        if (impl == null) {
+            AppWidgetServiceImpl.getSettingsFile(userId).delete();
+        } else {
+            impl.onUserRemoved();
+        }
     }
 
     private AppWidgetServiceImpl getImplForUser() {
diff --git a/services/java/com/android/server/AppWidgetServiceImpl.java b/services/java/com/android/server/AppWidgetServiceImpl.java
index 182a884..b24823e 100644
--- a/services/java/com/android/server/AppWidgetServiceImpl.java
+++ b/services/java/com/android/server/AppWidgetServiceImpl.java
@@ -1484,9 +1484,13 @@
         }
     }
 
+    static File getSettingsFile(int userId) {
+        return new File("/data/system/users/" + userId + "/" + SETTINGS_FILENAME);
+    }
+
     AtomicFile savedStateFile() {
         File dir = new File("/data/system/users/" + mUserId);
-        File settingsFile = new File(dir, SETTINGS_FILENAME);
+        File settingsFile = getSettingsFile(mUserId);
         if (!dir.exists()) {
             dir.mkdirs();
             if (mUserId == 0) {
@@ -1500,6 +1504,16 @@
         return new AtomicFile(settingsFile);
     }
 
+    void onUserRemoved() {
+        // prune the ones we don't want to keep
+        int N = mInstalledProviders.size();
+        for (int i = N - 1; i >= 0; i--) {
+            Provider p = mInstalledProviders.get(i);
+            cancelBroadcasts(p);
+        }
+        getSettingsFile(mUserId).delete();
+    }
+
     void addProvidersForPackageLocked(String pkgName) {
         Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
         intent.setPackage(pkgName);
diff --git a/services/java/com/android/server/ClipboardService.java b/services/java/com/android/server/ClipboardService.java
index 062ab74..2e2a278 100644
--- a/services/java/com/android/server/ClipboardService.java
+++ b/services/java/com/android/server/ClipboardService.java
@@ -34,6 +34,7 @@
 import android.os.Process;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
+import android.os.UserId;
 import android.util.Pair;
 import android.util.Slog;
 
@@ -204,7 +205,7 @@
         PackageInfo pi;
         try {
             pi = mPm.getPackageInfo(pkg, 0);
-            if (pi.applicationInfo.uid != uid) {
+            if (!UserId.isSameApp(pi.applicationInfo.uid, uid)) {
                 throw new SecurityException("Calling uid " + uid
                         + " does not own package " + pkg);
             }
diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/WallpaperManagerService.java
index 8ee12bc..6d83f30 100644
--- a/services/java/com/android/server/WallpaperManagerService.java
+++ b/services/java/com/android/server/WallpaperManagerService.java
@@ -25,9 +25,11 @@
 import android.app.WallpaperInfo;
 import android.app.backup.BackupManager;
 import android.app.backup.WallpaperBackupHelper;
+import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.ServiceConnection;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
@@ -36,6 +38,7 @@
 import android.content.res.Resources;
 import android.os.Binder;
 import android.os.Bundle;
+import android.os.Environment;
 import android.os.FileUtils;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -401,41 +404,48 @@
             wallpaper.wallpaperObserver.stopWatching();
         }
     }
-    
+
     public void systemReady() {
         if (DEBUG) Slog.v(TAG, "systemReady");
         WallpaperData wallpaper = mWallpaperMap.get(0);
         switchWallpaper(wallpaper);
         wallpaper.wallpaperObserver = new WallpaperObserver(wallpaper);
         wallpaper.wallpaperObserver.startWatching();
-        ActivityManagerService ams = (ActivityManagerService) ServiceManager
-                .getService(Context.ACTIVITY_SERVICE);
-        ams.addUserListener(new ActivityManagerService.UserListener() {
 
+        IntentFilter userFilter = new IntentFilter();
+        userFilter.addAction(Intent.ACTION_USER_SWITCHED);
+        userFilter.addAction(Intent.ACTION_USER_REMOVED);
+        mContext.registerReceiver(new BroadcastReceiver() {
             @Override
-            public void onUserChanged(int userId) {
-                switchUser(userId);
+            public void onReceive(Context context, Intent intent) {
+                String action = intent.getAction();
+                if (Intent.ACTION_USER_SWITCHED.equals(action)) {
+                    switchUser(intent.getIntExtra(Intent.EXTRA_USERID, 0));
+                } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
+                    removeUser(intent.getIntExtra(Intent.EXTRA_USERID, 0));
+                }
             }
-
-            @Override
-            public void onUserAdded(int userId) {
-            }
-
-            @Override
-            public void onUserRemoved(int userId) {
-            }
-
-            @Override
-            public void onUserLoggedOut(int userId) {
-            }
-
-        });
+        }, userFilter);
     }
 
     String getName() {
         return mWallpaperMap.get(0).name;
     }
 
+    void removeUser(int userId) {
+        synchronized (mLock) {
+            WallpaperData wallpaper = mWallpaperMap.get(userId);
+            if (wallpaper != null) {
+                wallpaper.wallpaperObserver.stopWatching();
+                mWallpaperMap.remove(userId);
+            }
+            File wallpaperFile = new File(getWallpaperDir(userId), WALLPAPER);
+            wallpaperFile.delete();
+            File wallpaperInfoFile = new File(getWallpaperDir(userId), WALLPAPER_INFO);
+            wallpaperInfoFile.delete();
+        }
+    }
+
     void switchUser(int userId) {
         synchronized (mLock) {
             mCurrentUserId = userId;
@@ -861,7 +871,7 @@
     }
 
     private static JournaledFile makeJournaledFile(int userId) {
-        final String base = "/data/system/users/" + userId + "/" + WALLPAPER_INFO;
+        final String base = getWallpaperDir(userId) + "/" + WALLPAPER_INFO;
         return new JournaledFile(new File(base), new File(base + ".tmp"));
     }
 
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 60749b3..467297b 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -152,6 +152,7 @@
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicLong;
@@ -3582,9 +3583,14 @@
                     if (doit) {
                         procs.add(app);
                     }
-                } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
-                        || app.processName.equals(packageName)
-                        || app.processName.startsWith(procNamePrefix)) {
+                // If uid is specified and the uid and process name match
+                // Or, the uid is not specified and the process name matches
+                } else if (((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
+                            && (app.processName.equals(packageName)
+                                || app.processName.startsWith(procNamePrefix)))
+                           || (uid < 0
+                               && (app.processName.equals(packageName)
+                                       || app.processName.startsWith(procNamePrefix)))) {
                     if (app.setAdj >= minOomAdj) {
                         if (!doit) {
                             return true;
@@ -3635,7 +3641,8 @@
         for (i=0; i<mMainStack.mHistory.size(); i++) {
             ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i);
             final boolean samePackage = r.packageName.equals(name);
-            if ((samePackage || r.task == lastTask)
+            if (r.userId == userId
+                    && (samePackage || r.task == lastTask)
                     && (r.app == null || evenPersistent || !r.app.persistent)) {
                 if (!doit) {
                     if (r.finishing) {
@@ -3685,7 +3692,7 @@
         }
 
         ArrayList<ContentProviderRecord> providers = new ArrayList<ContentProviderRecord>();
-        for (ContentProviderRecord provider : mProviderMap.getProvidersByClass(-1).values()) {
+        for (ContentProviderRecord provider : mProviderMap.getProvidersByClass(userId).values()) {
             if (provider.info.packageName.equals(name)
                     && (provider.proc == null || evenPersistent || !provider.proc.persistent)) {
                 if (!doit) {
@@ -4118,7 +4125,16 @@
                 }
             }
         }, pkgFilter);
-        
+
+        IntentFilter userFilter = new IntentFilter();
+        userFilter.addAction(Intent.ACTION_USER_REMOVED);
+        mContext.registerReceiver(new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                onUserRemoved(intent);
+            }
+        }, userFilter);
+
         synchronized (this) {
             // Ensure that any processes we had put on hold are now started
             // up.
@@ -12469,7 +12485,7 @@
 
         if (DEBUG_BROADCAST_LIGHT) Slog.v(
             TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
-            + " ordered=" + ordered);
+            + " ordered=" + ordered + " userid=" + userId);
         if ((resultTo != null) && !ordered) {
             Slog.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
         }
@@ -14593,25 +14609,6 @@
 
     private int mCurrentUserId;
     private SparseIntArray mLoggedInUsers = new SparseIntArray(5);
-    private ArrayList<UserListener> mUserListeners = new ArrayList<UserListener>(3);
-
-    public interface UserListener {
-        public void onUserChanged(int userId);
-
-        public void onUserAdded(int userId);
-
-        public void onUserRemoved(int userId);
-
-        public void onUserLoggedOut(int userId);
-    }
-
-    public void addUserListener(UserListener listener) {
-        synchronized (this) {
-            if (!mUserListeners.contains(listener)) {
-                mUserListeners.add(listener);
-            }
-        }
-    }
 
     public boolean switchUser(int userId) {
         final int callingUid = Binder.getCallingUid();
@@ -14622,8 +14619,6 @@
         if (mCurrentUserId == userId)
             return true;
 
-        ArrayList<UserListener> listeners;
-
         synchronized (this) {
             // Check if user is already logged in, otherwise check if user exists first before
             // adding to the list of logged in users.
@@ -14640,23 +14635,44 @@
                 startHomeActivityLocked(userId);
             }
 
-            listeners = (ArrayList<UserListener>) mUserListeners.clone();
         }
-        // Inform the listeners
-        for (UserListener listener : listeners) {
-            listener.onUserChanged(userId);
-        }
+
+        // Inform of user switch
+        Intent addedIntent = new Intent(Intent.ACTION_USER_SWITCHED);
+        addedIntent.putExtra(Intent.EXTRA_USERID, userId);
+        mContext.sendBroadcast(addedIntent, android.Manifest.permission.MANAGE_ACCOUNTS);
+
         return true;
     }
 
+    private void onUserRemoved(Intent intent) {
+        int extraUserId = intent.getIntExtra(Intent.EXTRA_USERID, -1);
+        if (extraUserId < 1) return;
+
+        // Kill all the processes for the user
+        ArrayList<Pair<String, Integer>> pkgAndUids = new ArrayList<Pair<String,Integer>>();
+        synchronized (this) {
+            HashMap<String,SparseArray<ProcessRecord>> map = mProcessNames.getMap();
+            for (Entry<String, SparseArray<ProcessRecord>> uidMap : map.entrySet()) {
+                SparseArray<ProcessRecord> uids = uidMap.getValue();
+                for (int i = 0; i < uids.size(); i++) {
+                    if (UserId.getUserId(uids.keyAt(i)) == extraUserId) {
+                        pkgAndUids.add(new Pair<String,Integer>(uidMap.getKey(), uids.keyAt(i)));
+                    }
+                }
+            }
+
+            for (Pair<String,Integer> pkgAndUid : pkgAndUids) {
+                forceStopPackageLocked(pkgAndUid.first, pkgAndUid.second,
+                        false, false, true, true, extraUserId);
+            }
+        }
+    }
+
     private boolean userExists(int userId) {
         try {
-            List<UserInfo> users = AppGlobals.getPackageManager().getUsers();
-            for (UserInfo user : users) {
-                if (user.id == userId) {
-                    return true;
-                }
-            }
+            UserInfo user = AppGlobals.getPackageManager().getUser(userId);
+            return user != null;
         } catch (RemoteException re) {
             // Won't happen, in same process
         }
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 067bf28..1593707 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -134,6 +134,7 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.Set;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
@@ -404,7 +405,7 @@
     // Delay time in millisecs
     static final int BROADCAST_DELAY = 10 * 1000;
 
-    final UserManager mUserManager;
+    static UserManager sUserManager;
 
     // Stores a list of users whose package restrictions file needs to be updated
     private HashSet<Integer> mDirtyUsers = new HashSet<Integer>();
@@ -632,7 +633,7 @@
                             packages[i] = ent.getKey();
                             components[i] = ent.getValue();
                             PackageSetting ps = mSettings.mPackages.get(ent.getKey());
-                            uids[i] = (ps != null) ? ps.uid : -1;
+                            uids[i] = (ps != null) ? ps.appId : -1;
                             i++;
                         }
                         size = i;
@@ -676,14 +677,15 @@
                             }
                             sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
                                     res.pkg.applicationInfo.packageName,
-                                    extras, null, null);
+                                    extras, null, null, UserId.USER_ALL);
                             if (update) {
                                 sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
                                         res.pkg.applicationInfo.packageName,
-                                        extras, null, null);
+                                        extras, null, null, UserId.USER_ALL);
                                 sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED,
                                         null, null,
-                                        res.pkg.applicationInfo.packageName, null);
+                                        res.pkg.applicationInfo.packageName, null,
+                                        UserId.USER_ALL);
                             }
                             if (res.removedInfo.args != null) {
                                 // Remove the replaced package's older resources safely now
@@ -820,6 +822,7 @@
     }
 
     void scheduleWritePackageRestrictionsLocked(int userId) {
+        if (!sUserManager.exists(userId)) return;
         mDirtyUsers.add(userId);
         if (!mHandler.hasMessages(WRITE_PACKAGE_RESTRICTIONS)) {
             mHandler.sendEmptyMessageDelayed(WRITE_PACKAGE_RESTRICTIONS, WRITE_SETTINGS_DELAY);
@@ -920,7 +923,7 @@
             mUserAppDataDir = new File(dataDir, "user");
             mDrmAppPrivateInstallDir = new File(dataDir, "app-private");
 
-            mUserManager = new UserManager(mInstaller, mUserAppDataDir);
+            sUserManager = new UserManager(mInstaller, mUserAppDataDir);
 
             readPermissions();
 
@@ -1086,7 +1089,7 @@
                                 + " no longer exists; wiping its data";
                         reportSettingsProblem(Log.WARN, msg);
                         mInstaller.remove(ps.name, 0);
-                        mUserManager.removePackageForAllUsers(ps.name);
+                        sUserManager.removePackageForAllUsers(ps.name);
                     }
                 }
             }
@@ -1242,7 +1245,7 @@
             Slog.w(TAG, "Couldn't remove app data directory for package: "
                        + ps.name + ", retcode=" + retCode);
         } else {
-            mUserManager.removePackageForAllUsers(ps.name);
+            sUserManager.removePackageForAllUsers(ps.name);
         }
         if (ps.codePath != null) {
             if (!ps.codePath.delete()) {
@@ -1506,29 +1509,39 @@
         return cur;
     }
 
-    PackageInfo generatePackageInfo(PackageParser.Package p, int flags) {
+    PackageInfo generatePackageInfo(PackageParser.Package p, int flags, int userId) {
+        if (!sUserManager.exists(userId)) return null;
+        PackageInfo pi;
         if ((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) {
             // The package has been uninstalled but has retained data and resources.
-            return PackageParser.generatePackageInfo(p, null, flags, 0, 0, null);
+            pi = PackageParser.generatePackageInfo(p, null, flags, 0, 0, null, false, 0, userId);
+        } else {
+            final PackageSetting ps = (PackageSetting) p.mExtras;
+            if (ps == null) {
+                return null;
+            }
+            final GrantedPermissions gp = ps.sharedUser != null ? ps.sharedUser : ps;
+            pi = PackageParser.generatePackageInfo(p, gp.gids, flags,
+                    ps.firstInstallTime, ps.lastUpdateTime, gp.grantedPermissions,
+                    ps.getStopped(userId), ps.getEnabled(userId), userId);
+            pi.applicationInfo.enabledSetting = ps.getEnabled(userId);
+            pi.applicationInfo.enabled =
+                    pi.applicationInfo.enabledSetting == COMPONENT_ENABLED_STATE_DEFAULT
+                    || pi.applicationInfo.enabledSetting == COMPONENT_ENABLED_STATE_ENABLED;
         }
-        final PackageSetting ps = (PackageSetting)p.mExtras;
-        if (ps == null) {
-            return null;
-        }
-        final GrantedPermissions gp = ps.sharedUser != null ? ps.sharedUser : ps;
-        return PackageParser.generatePackageInfo(p, gp.gids, flags,
-                ps.firstInstallTime, ps.lastUpdateTime, gp.grantedPermissions);
+        return pi;
     }
 
     @Override
     public PackageInfo getPackageInfo(String packageName, int flags, int userId) {
+        if (!sUserManager.exists(userId)) return null;
         // reader
         synchronized (mPackages) {
             PackageParser.Package p = mPackages.get(packageName);
             if (DEBUG_PACKAGE_INFO)
                 Log.v(TAG, "getPackageInfo " + packageName + ": " + p);
             if (p != null) {
-                return generatePackageInfo(p, flags);
+                return generatePackageInfo(p, flags, userId);
             }
             if((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) {
                 return generatePackageInfoFromSettingsLPw(packageName, flags, userId);
@@ -1563,6 +1576,7 @@
 
     @Override
     public int getPackageUid(String packageName, int userId) {
+        if (!sUserManager.exists(userId)) return -1;
         // reader
         synchronized (mPackages) {
             PackageParser.Package p = mPackages.get(packageName);
@@ -1673,6 +1687,7 @@
 
     private ApplicationInfo generateApplicationInfoFromSettingsLPw(String packageName, int flags,
             int userId) {
+        if (!sUserManager.exists(userId)) return null;
         PackageSetting ps = mSettings.mPackages.get(packageName);
         if (ps != null) {
             if (ps.pkg == null) {
@@ -1682,15 +1697,18 @@
                 }
                 return null;
             }
-            return PackageParser.generateApplicationInfo(ps.pkg, flags);
+            return PackageParser.generateApplicationInfo(ps.pkg, flags, ps.getStopped(userId),
+                    ps.getEnabled(userId), userId);
         }
         return null;
     }
 
     private PackageInfo generatePackageInfoFromSettingsLPw(String packageName, int flags,
             int userId) {
+        if (!sUserManager.exists(userId)) return null;
         PackageSetting ps = mSettings.mPackages.get(packageName);
         if (ps != null) {
+            PackageParser.Package pkg = new PackageParser.Package(packageName);
             if (ps.pkg == null) {
                 ps.pkg = new PackageParser.Package(packageName);
                 ps.pkg.applicationInfo.packageName = packageName;
@@ -1701,15 +1719,16 @@
                         getDataPathForPackage(ps.pkg.packageName, 0).getPath();
                 ps.pkg.applicationInfo.nativeLibraryDir = ps.nativeLibraryPathString;
             }
-            ps.pkg.mSetEnabled = ps.getEnabled(userId);
-            ps.pkg.mSetStopped = ps.getStopped(userId);
-            return generatePackageInfo(ps.pkg, flags);
+            // ps.pkg.mSetEnabled = ps.getEnabled(userId);
+            // ps.pkg.mSetStopped = ps.getStopped(userId);
+            return generatePackageInfo(ps.pkg, flags, userId);
         }
         return null;
     }
 
     @Override
     public ApplicationInfo getApplicationInfo(String packageName, int flags, int userId) {
+        if (!sUserManager.exists(userId)) return null;
         // writer
         synchronized (mPackages) {
             PackageParser.Package p = mPackages.get(packageName);
@@ -1717,8 +1736,11 @@
                     TAG, "getApplicationInfo " + packageName
                     + ": " + p);
             if (p != null) {
+                PackageSetting ps = mSettings.mPackages.get(packageName);
+                if (ps == null) return null;
                 // Note: isEnabledLP() does not apply here - always return info
-                return PackageParser.generateApplicationInfo(p, flags);
+                return PackageParser.generateApplicationInfo(p, flags, ps.getStopped(userId),
+                        ps.getEnabled(userId));
             }
             if ("android".equals(packageName)||"system".equals(packageName)) {
                 return mAndroidApplication;
@@ -1782,12 +1804,16 @@
 
     @Override
     public ActivityInfo getActivityInfo(ComponentName component, int flags, int userId) {
+        if (!sUserManager.exists(userId)) return null;
         synchronized (mPackages) {
             PackageParser.Activity a = mActivities.mActivities.get(component);
 
             if (DEBUG_PACKAGE_INFO) Log.v(TAG, "getActivityInfo " + component + ": " + a);
             if (a != null && mSettings.isEnabledLPr(a.info, flags, userId)) {
-                return PackageParser.generateActivityInfo(a, flags, userId);
+                PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
+                if (ps == null) return null;
+                return PackageParser.generateActivityInfo(a, flags, ps.getStopped(userId),
+                        ps.getEnabled(userId), userId);
             }
             if (mResolveComponentName.equals(component)) {
                 return mResolveActivity;
@@ -1798,12 +1824,16 @@
 
     @Override
     public ActivityInfo getReceiverInfo(ComponentName component, int flags, int userId) {
+        if (!sUserManager.exists(userId)) return null;
         synchronized (mPackages) {
             PackageParser.Activity a = mReceivers.mActivities.get(component);
             if (DEBUG_PACKAGE_INFO) Log.v(
                 TAG, "getReceiverInfo " + component + ": " + a);
             if (a != null && mSettings.isEnabledLPr(a.info, flags, userId)) {
-                return PackageParser.generateActivityInfo(a, flags, userId);
+                PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
+                if (ps == null) return null;
+                return PackageParser.generateActivityInfo(a, flags, ps.getStopped(userId),
+                        ps.getEnabled(userId), userId);
             }
         }
         return null;
@@ -1811,12 +1841,16 @@
 
     @Override
     public ServiceInfo getServiceInfo(ComponentName component, int flags, int userId) {
+        if (!sUserManager.exists(userId)) return null;
         synchronized (mPackages) {
             PackageParser.Service s = mServices.mServices.get(component);
             if (DEBUG_PACKAGE_INFO) Log.v(
                 TAG, "getServiceInfo " + component + ": " + s);
             if (s != null && mSettings.isEnabledLPr(s.info, flags, userId)) {
-                return PackageParser.generateServiceInfo(s, flags, userId);
+                PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
+                if (ps == null) return null;
+                return PackageParser.generateServiceInfo(s, flags, ps.getStopped(userId),
+                        ps.getEnabled(userId), userId);
             }
         }
         return null;
@@ -1824,12 +1858,16 @@
 
     @Override
     public ProviderInfo getProviderInfo(ComponentName component, int flags, int userId) {
+        if (!sUserManager.exists(userId)) return null;
         synchronized (mPackages) {
             PackageParser.Provider p = mProvidersByComponent.get(component);
             if (DEBUG_PACKAGE_INFO) Log.v(
                 TAG, "getProviderInfo " + component + ": " + p);
             if (p != null && mSettings.isEnabledLPr(p.info, flags, userId)) {
-                return PackageParser.generateProviderInfo(p, flags, userId);
+                PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
+                if (ps == null) return null;
+                return PackageParser.generateProviderInfo(p, flags, ps.getStopped(userId),
+                        ps.getEnabled(userId), userId);
             }
         }
         return null;
@@ -2253,6 +2291,7 @@
     @Override
     public ResolveInfo resolveIntent(Intent intent, String resolvedType,
             int flags, int userId) {
+        if (!sUserManager.exists(userId)) return null;
         List<ResolveInfo> query = queryIntentActivities(intent, resolvedType, flags, userId);
         return chooseBestActivity(intent, resolvedType, flags, query, userId);
     }
@@ -2294,6 +2333,7 @@
 
     ResolveInfo findPreferredActivity(Intent intent, String resolvedType,
             int flags, List<ResolveInfo> query, int priority, int userId) {
+        if (!sUserManager.exists(userId)) return null;
         // writer
         synchronized (mPackages) {
             if (intent.getSelector() != null) {
@@ -2389,6 +2429,7 @@
     @Override
     public List<ResolveInfo> queryIntentActivities(Intent intent,
             String resolvedType, int flags, int userId) {
+        if (!sUserManager.exists(userId)) return null;
         ComponentName comp = intent.getComponent();
         if (comp == null) {
             if (intent.getSelector() != null) {
@@ -2427,6 +2468,7 @@
     public List<ResolveInfo> queryIntentActivityOptions(ComponentName caller,
             Intent[] specifics, String[] specificTypes, Intent intent,
             String resolvedType, int flags, int userId) {
+        if (!sUserManager.exists(userId)) return null;
         final String resultsAction = intent.getAction();
 
         List<ResolveInfo> results = queryIntentActivities(intent, resolvedType, flags
@@ -2596,6 +2638,7 @@
     @Override
     public List<ResolveInfo> queryIntentReceivers(Intent intent, String resolvedType, int flags,
             int userId) {
+        if (!sUserManager.exists(userId)) return null;
         ComponentName comp = intent.getComponent();
         if (comp == null) {
             if (intent.getSelector() != null) {
@@ -2632,6 +2675,7 @@
     @Override
     public ResolveInfo resolveService(Intent intent, String resolvedType, int flags, int userId) {
         List<ResolveInfo> query = queryIntentServices(intent, resolvedType, flags, userId);
+        if (!sUserManager.exists(userId)) return null;
         if (query != null) {
             if (query.size() >= 1) {
                 // If there is more than one service with the same priority,
@@ -2645,6 +2689,7 @@
     @Override
     public List<ResolveInfo> queryIntentServices(Intent intent, String resolvedType, int flags,
             int userId) {
+        if (!sUserManager.exists(userId)) return null;
         ComponentName comp = intent.getComponent();
         if (comp == null) {
             if (intent.getSelector() != null) {
@@ -2723,7 +2768,7 @@
                 } else {
                     final PackageParser.Package p = mPackages.get(packageName);
                     if (p != null) {
-                        pi = generatePackageInfo(p, flags);
+                        pi = generatePackageInfo(p, flags, userId);
                     }
                 }
 
@@ -2743,6 +2788,7 @@
     @Override
     public ParceledListSlice<ApplicationInfo> getInstalledApplications(int flags,
             String lastRead, int userId) {
+        if (!sUserManager.exists(userId)) return null;
         final ParceledListSlice<ApplicationInfo> list = new ParceledListSlice<ApplicationInfo>();
         final boolean listUninstalled = (flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0;
         final String[] keys;
@@ -2763,15 +2809,16 @@
                 final String packageName = keys[i++];
 
                 ApplicationInfo ai = null;
+                final PackageSetting ps = mSettings.mPackages.get(packageName);
                 if (listUninstalled) {
-                    final PackageSetting ps = mSettings.mPackages.get(packageName);
                     if (ps != null) {
                         ai = generateApplicationInfoFromSettingsLPw(ps.name, flags, userId);
                     }
                 } else {
                     final PackageParser.Package p = mPackages.get(packageName);
-                    if (p != null) {
-                        ai = PackageParser.generateApplicationInfo(p, flags, userId);
+                    if (p != null && ps != null) {
+                        ai = PackageParser.generateApplicationInfo(p, flags, ps.getStopped(userId),
+                                ps.getEnabled(userId), userId);
                     }
                 }
 
@@ -2794,13 +2841,17 @@
         // reader
         synchronized (mPackages) {
             final Iterator<PackageParser.Package> i = mPackages.values().iterator();
-            final int userId = UserId.getUserId(Binder.getCallingUid());
+            final int userId = UserId.getCallingUserId();
             while (i.hasNext()) {
                 final PackageParser.Package p = i.next();
                 if (p.applicationInfo != null
                         && (p.applicationInfo.flags&ApplicationInfo.FLAG_PERSISTENT) != 0
                         && (!mSafeMode || isSystemApp(p))) {
-                    finalList.add(PackageParser.generateApplicationInfo(p, flags, userId));
+                    PackageSetting ps = mSettings.mPackages.get(p.packageName);
+                    finalList.add(PackageParser.generateApplicationInfo(p, flags,
+                            ps != null ? ps.getStopped(userId) : false,
+                            ps != null ? ps.getEnabled(userId) : COMPONENT_ENABLED_STATE_DEFAULT,
+                            userId));
                 }
             }
         }
@@ -2810,14 +2861,21 @@
 
     @Override
     public ProviderInfo resolveContentProvider(String name, int flags, int userId) {
+        if (!sUserManager.exists(userId)) return null;
         // reader
         synchronized (mPackages) {
             final PackageParser.Provider provider = mProviders.get(name);
+            PackageSetting ps = provider != null
+                    ? mSettings.mPackages.get(provider.owner.packageName)
+                    : null;
             return provider != null
                     && mSettings.isEnabledLPr(provider.info, flags, userId)
                     && (!mSafeMode || (provider.info.applicationInfo.flags
                             &ApplicationInfo.FLAG_SYSTEM) != 0)
-                    ? PackageParser.generateProviderInfo(provider, flags, userId)
+                    ? PackageParser.generateProviderInfo(provider, flags,
+                            ps != null ? ps.getStopped(userId) : false,
+                            ps != null ? ps.getEnabled(userId) : COMPONENT_ENABLED_STATE_DEFAULT,
+                            userId)
                     : null;
         }
     }
@@ -2831,16 +2889,20 @@
         synchronized (mPackages) {
             final Iterator<Map.Entry<String, PackageParser.Provider>> i = mProviders.entrySet()
                     .iterator();
-            final int userId = UserId.getUserId(Binder.getCallingUid());
+            final int userId = UserId.getCallingUserId();
             while (i.hasNext()) {
                 Map.Entry<String, PackageParser.Provider> entry = i.next();
                 PackageParser.Provider p = entry.getValue();
+                PackageSetting ps = mSettings.mPackages.get(p.owner.packageName);
 
                 if (p.syncable
                         && (!mSafeMode || (p.info.applicationInfo.flags
                                 &ApplicationInfo.FLAG_SYSTEM) != 0)) {
                     outNames.add(entry.getKey());
-                    outInfo.add(PackageParser.generateProviderInfo(p, 0, userId));
+                    outInfo.add(PackageParser.generateProviderInfo(p, 0,
+                            ps != null ? ps.getStopped(userId) : false,
+                            ps != null ? ps.getEnabled(userId) : COMPONENT_ENABLED_STATE_DEFAULT,
+                            userId));
                 }
             }
         }
@@ -2857,6 +2919,7 @@
                     UserId.getUserId(uid) : UserId.getCallingUserId();
             while (i.hasNext()) {
                 final PackageParser.Provider p = i.next();
+                PackageSetting ps = mSettings.mPackages.get(p.owner.packageName);
                 if (p.info.authority != null
                         && (processName == null
                                 || (p.info.processName.equals(processName)
@@ -2867,7 +2930,10 @@
                     if (finalList == null) {
                         finalList = new ArrayList<ProviderInfo>(3);
                     }
-                    finalList.add(PackageParser.generateProviderInfo(p, flags, userId));
+                    finalList.add(PackageParser.generateProviderInfo(p, flags,
+                            ps != null ? ps.getStopped(userId) : false,
+                            ps != null ? ps.getEnabled(userId) : COMPONENT_ENABLED_STATE_DEFAULT,
+                            userId));
                 }
             }
         }
@@ -3511,7 +3577,7 @@
                 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
             }
 
-            pkg.applicationInfo.uid = pkgSetting.uid;
+            pkg.applicationInfo.uid = pkgSetting.appId;
             pkg.mExtras = pkgSetting;
 
             if (!verifySignaturesLP(pkgSetting, pkg)) {
@@ -3618,7 +3684,7 @@
                         if (ret >= 0) {
                             // TODO: Kill the processes first
                             // Remove the data directories for all users
-                            mUserManager.removePackageForAllUsers(pkgName);
+                            sUserManager.removePackageForAllUsers(pkgName);
                             // Old data gone!
                             String msg = "System package " + pkg.packageName
                                     + " has changed from uid: "
@@ -3639,7 +3705,7 @@
                                 return null;
                             }
                             // Create data directories for all users
-                            mUserManager.installPackageForAllUsers(pkgName,
+                            sUserManager.installPackageForAllUsers(pkgName,
                                     pkg.applicationInfo.uid);
                         }
                         if (!recovered) {
@@ -3681,7 +3747,7 @@
                     return null;
                 }
                 // Create data directories for all users
-                mUserManager.installPackageForAllUsers(pkgName, pkg.applicationInfo.uid);
+                sUserManager.installPackageForAllUsers(pkgName, pkg.applicationInfo.uid);
 
                 if (dataPath.exists()) {
                     pkg.applicationInfo.dataDir = dataPath.getPath();
@@ -4510,12 +4576,14 @@
             extends IntentResolver<PackageParser.ActivityIntentInfo, ResolveInfo> {
         public List<ResolveInfo> queryIntent(Intent intent, String resolvedType,
                 boolean defaultOnly, int userId) {
+            if (!sUserManager.exists(userId)) return null;
             mFlags = defaultOnly ? PackageManager.MATCH_DEFAULT_ONLY : 0;
             return super.queryIntent(intent, resolvedType, defaultOnly, userId);
         }
 
         public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, int flags,
                 int userId) {
+            if (!sUserManager.exists(userId)) return null;
             mFlags = flags;
             return super.queryIntent(intent, resolvedType,
                     (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, userId);
@@ -4523,6 +4591,7 @@
 
         public List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType,
                 int flags, ArrayList<PackageParser.Activity> packageActivities, int userId) {
+            if (!sUserManager.exists(userId)) return null;
             if (packageActivities == null) {
                 return null;
             }
@@ -4605,6 +4674,7 @@
 
         @Override
         protected boolean isFilterStopped(PackageParser.ActivityIntentInfo filter, int userId) {
+            if (!sUserManager.exists(userId)) return true;
             PackageParser.Package p = filter.activity.owner;
             if (p != null) {
                 PackageSetting ps = (PackageSetting)p.mExtras;
@@ -4626,6 +4696,7 @@
         @Override
         protected ResolveInfo newResult(PackageParser.ActivityIntentInfo info,
                 int match, int userId) {
+            if (!sUserManager.exists(userId)) return null;
             if (!mSettings.isEnabledLPr(info.activity.info, mFlags, userId)) {
                 return null;
             }
@@ -4635,7 +4706,11 @@
                 return null;
             }
             final ResolveInfo res = new ResolveInfo();
-            res.activityInfo = PackageParser.generateActivityInfo(activity, mFlags, userId);
+            PackageSetting ps = (PackageSetting) activity.owner.mExtras;
+            res.activityInfo = PackageParser.generateActivityInfo(activity, mFlags,
+                    ps != null ? ps.getStopped(userId) : false,
+                    ps != null ? ps.getEnabled(userId) : COMPONENT_ENABLED_STATE_DEFAULT,
+                    userId);
             if ((mFlags&PackageManager.GET_RESOLVED_FILTER) != 0) {
                 res.filter = info;
             }
@@ -4696,6 +4771,7 @@
 
         public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, int flags,
                 int userId) {
+            if (!sUserManager.exists(userId)) return null;
             mFlags = flags;
             return super.queryIntent(intent, resolvedType,
                     (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, userId);
@@ -4703,6 +4779,7 @@
 
         public List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType,
                 int flags, ArrayList<PackageParser.Service> packageServices, int userId) {
+            if (!sUserManager.exists(userId)) return null;
             if (packageServices == null) {
                 return null;
             }
@@ -4780,6 +4857,7 @@
 
         @Override
         protected boolean isFilterStopped(PackageParser.ServiceIntentInfo filter, int userId) {
+            if (!sUserManager.exists(userId)) return true;
             PackageParser.Package p = filter.service.owner;
             if (p != null) {
                 PackageSetting ps = (PackageSetting)p.mExtras;
@@ -4802,6 +4880,7 @@
         @Override
         protected ResolveInfo newResult(PackageParser.ServiceIntentInfo filter,
                 int match, int userId) {
+            if (!sUserManager.exists(userId)) return null;
             final PackageParser.ServiceIntentInfo info = (PackageParser.ServiceIntentInfo)filter;
             if (!mSettings.isEnabledLPr(info.service.info, mFlags, userId)) {
                 return null;
@@ -4812,7 +4891,11 @@
                 return null;
             }
             final ResolveInfo res = new ResolveInfo();
-            res.serviceInfo = PackageParser.generateServiceInfo(service, mFlags, userId);
+            PackageSetting ps = (PackageSetting) service.owner.mExtras;
+            res.serviceInfo = PackageParser.generateServiceInfo(service, mFlags,
+                    ps != null ? ps.getStopped(userId) : false,
+                    ps != null ? ps.getEnabled(userId) : COMPONENT_ENABLED_STATE_DEFAULT,
+                    userId);
             if ((mFlags&PackageManager.GET_RESOLVED_FILTER) != 0) {
                 res.filter = filter;
             }
@@ -4903,23 +4986,32 @@
     };
 
     static final void sendPackageBroadcast(String action, String pkg,
-            Bundle extras, String targetPkg, IIntentReceiver finishedReceiver) {
+            Bundle extras, String targetPkg, IIntentReceiver finishedReceiver, int userId) {
         IActivityManager am = ActivityManagerNative.getDefault();
         if (am != null) {
             try {
-                final Intent intent = new Intent(action,
-                        pkg != null ? Uri.fromParts("package", pkg, null) : null);
-                if (extras != null) {
-                    intent.putExtras(extras);
+                int[] userIds = userId == UserId.USER_ALL
+                        ? sUserManager.getUserIds() 
+                        : new int[] {userId};
+                for (int id : userIds) {
+                    final Intent intent = new Intent(action,
+                            pkg != null ? Uri.fromParts("package", pkg, null) : null);
+                    if (extras != null) {
+                        intent.putExtras(extras);
+                    }
+                    if (targetPkg != null) {
+                        intent.setPackage(targetPkg);
+                    }
+                    // Modify the UID when posting to other users
+                    int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
+                    if (uid > 0 && id > 0) {
+                        uid = UserId.getUid(id, UserId.getAppId(uid));
+                        intent.putExtra(Intent.EXTRA_UID, uid);
+                    }
+                    intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+                    am.broadcastIntent(null, intent, null, finishedReceiver,
+                            0, null, null, null, finishedReceiver != null, false, id);
                 }
-                if (targetPkg != null) {
-                    intent.setPackage(targetPkg);
-                }
-                intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
-                // TODO: Fix the userId argument
-                am.broadcastIntent(null, intent, null, finishedReceiver,
-                        0, null, null, null, finishedReceiver != null, false,
-                        Binder.getOrigCallingUser());
             } catch (RemoteException ex) {
             }
         }
@@ -5062,13 +5154,13 @@
                 extras.putInt(Intent.EXTRA_UID, removedUid);
                 extras.putBoolean(Intent.EXTRA_DATA_REMOVED, false);
                 sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage,
-                        extras, null, null);
+                        extras, null, null, UserId.USER_ALL);
             }
             if (addedPackage != null) {
                 Bundle extras = new Bundle(1);
                 extras.putInt(Intent.EXTRA_UID, addedUid);
                 sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, addedPackage,
-                        extras, null, null);
+                        extras, null, null, UserId.USER_ALL);
             }
         }
 
@@ -7092,11 +7184,11 @@
                 extras.putBoolean(Intent.EXTRA_REPLACING, true);
 
                 sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
-                        extras, null, null);
+                        extras, null, null, UserId.USER_ALL);
                 sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,
-                        extras, null, null);
+                        extras, null, null, UserId.USER_ALL);
                 sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, null,
-                        null, packageName, null);
+                        null, packageName, null, UserId.USER_ALL);
             }
         }
         // Force a gc here.
@@ -7129,14 +7221,15 @@
             }
             if (removedPackage != null) {
                 sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage,
-                        extras, null, null);
+                        extras, null, null, UserId.USER_ALL);
                 if (fullRemove && !replacing) {
                     sendPackageBroadcast(Intent.ACTION_PACKAGE_FULLY_REMOVED, removedPackage,
-                            extras, null, null);
+                            extras, null, null, UserId.USER_ALL);
                 }
             }
             if (removedUid >= 0) {
-                sendPackageBroadcast(Intent.ACTION_UID_REMOVED, null, extras, null, null);
+                sendPackageBroadcast(Intent.ACTION_UID_REMOVED, null, extras, null, null,
+                        UserId.getUserId(removedUid));
             }
         }
     }
@@ -7168,7 +7261,7 @@
                 // we don't consider this to be a failure of the core package deletion
             } else {
                 // TODO: Kill the processes first
-                mUserManager.removePackageForAllUsers(packageName);
+                sUserManager.removePackageForAllUsers(packageName);
             }
             schedulePackageCleaning(packageName);
         }
@@ -7732,12 +7825,14 @@
     @Override
     public void setApplicationEnabledSetting(String appPackageName,
             int newState, int flags, int userId) {
+        if (!sUserManager.exists(userId)) return;
         setEnabledSetting(appPackageName, null, newState, flags, userId);
     }
 
     @Override
     public void setComponentEnabledSetting(ComponentName componentName,
             int newState, int flags, int userId) {
+        if (!sUserManager.exists(userId)) return;
         setEnabledSetting(componentName.getPackageName(),
                 componentName.getClassName(), newState, flags, userId);
     }
@@ -7776,11 +7871,11 @@
                         + "/" + className);
             }
             // Allow root and verify that userId is not being specified by a different user
-            if (!allowedByPermission && !UserId.isSameApp(uid, pkgSetting.uid)) {
+            if (!allowedByPermission && !UserId.isSameApp(uid, pkgSetting.appId)) {
                 throw new SecurityException(
                         "Permission Denial: attempt to change component state from pid="
                         + Binder.getCallingPid()
-                        + ", uid=" + uid + ", package uid=" + pkgSetting.uid);
+                        + ", uid=" + uid + ", package uid=" + pkgSetting.appId);
             }
             if (className == null) {
                 // We're dealing with an application/package level state change
@@ -7789,7 +7884,7 @@
                     return;
                 }
                 pkgSetting.setEnabled(newState, userId);
-                pkgSetting.pkg.mSetEnabled = newState;
+                // pkgSetting.pkg.mSetEnabled = newState;
             } else {
                 // We're dealing with a component level state change
                 // First, verify that this is a valid class name.
@@ -7825,7 +7920,7 @@
                 }
             }
             mSettings.writePackageRestrictionsLPr(userId);
-            packageUid = pkgSetting.uid;
+            packageUid = UserId.getUid(userId, pkgSetting.appId);
             components = mPendingBroadcasts.get(packageName);
             final boolean newPackage = components == null;
             if (newPackage) {
@@ -7873,10 +7968,12 @@
         extras.putStringArray(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST, nameList);
         extras.putBoolean(Intent.EXTRA_DONT_KILL_APP, killFlag);
         extras.putInt(Intent.EXTRA_UID, packageUid);
-        sendPackageBroadcast(Intent.ACTION_PACKAGE_CHANGED,  packageName, extras, null, null);
+        sendPackageBroadcast(Intent.ACTION_PACKAGE_CHANGED,  packageName, extras, null, null,
+                UserId.getUserId(packageUid));
     }
 
     public void setPackageStoppedState(String packageName, boolean stopped, int userId) {
+        if (!sUserManager.exists(userId)) return;
         final int uid = Binder.getCallingUid();
         final int permission = mContext.checkCallingOrSelfPermission(
                 android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE);
@@ -7900,6 +7997,7 @@
 
     @Override
     public int getApplicationEnabledSetting(String packageName, int userId) {
+        if (!sUserManager.exists(userId)) return COMPONENT_ENABLED_STATE_DISABLED;
         int uid = Binder.getCallingUid();
         checkValidCaller(uid, userId);
         // reader
@@ -7910,6 +8008,7 @@
 
     @Override
     public int getComponentEnabledSetting(ComponentName componentName, int userId) {
+        if (!sUserManager.exists(userId)) return COMPONENT_ENABLED_STATE_DISABLED;
         int uid = Binder.getCallingUid();
         checkValidCaller(uid, userId);
         // reader
@@ -8383,7 +8482,7 @@
                                     + " at code path: " + ps.codePathString);
                         // We do have a valid package installed on sdcard
                         processCids.put(args, ps.codePathString);
-                        int uid = ps.uid;
+                        int uid = ps.appId;
                         if (uid != -1) {
                             uidList[num++] = uid;
                         }
@@ -8436,7 +8535,7 @@
             }
             String action = mediaStatus ? Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE
                     : Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE;
-            sendPackageBroadcast(action, null, extras, null, finishedReceiver);
+            sendPackageBroadcast(action, null, extras, null, finishedReceiver, UserId.USER_ALL);
         }
     }
 
@@ -8860,8 +8959,12 @@
         // TODO(kroot): Add a real permission for creating users
         enforceSystemOrRoot("Only the system can create users");
 
-        // TODO(kroot): fix this API
-        UserInfo userInfo = mUserManager.createUser(name, flags, new ArrayList<ApplicationInfo>());
+        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;
     }
 
@@ -8869,13 +8972,34 @@
         // TODO(kroot): Add a real permission for removing users
         enforceSystemOrRoot("Only the system can remove users");
 
-        if (userId == 0) {
+        if (userId == 0 || !sUserManager.exists(userId)) {
             return false;
         }
-        mUserManager.removeUser(userId);
+
+        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) {
+        // 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);
+            }
+            if (mDirtyUsers.remove(userId));
+            mSettings.removeUserLPr(userId);
+        }
+    }
+
     @Override
     public VerifierDeviceIdentity getVerifierDeviceIdentity() throws RemoteException {
         mContext.enforceCallingOrSelfPermission(
@@ -8887,8 +9011,22 @@
         }
     }
 
+    @Override
     public List<UserInfo> getUsers() {
-        return mUserManager.getUsers();
+        enforceSystemOrRoot("Only the system can query users");
+        return sUserManager.getUsers();
+    }
+
+    @Override
+    public UserInfo getUser(int userId) {
+        enforceSystemOrRoot("Only the system can remove users");
+        return sUserManager.getUser(userId);
+    }
+
+    @Override
+    public void updateUserName(int userId, String name) {
+        enforceSystemOrRoot("Only the system can rename users");
+        sUserManager.updateUserName(userId, name);
     }
 
     @Override
diff --git a/services/java/com/android/server/pm/PackageSetting.java b/services/java/com/android/server/pm/PackageSetting.java
index 48ed9bf..f7f0870 100644
--- a/services/java/com/android/server/pm/PackageSetting.java
+++ b/services/java/com/android/server/pm/PackageSetting.java
@@ -24,7 +24,7 @@
  * Settings data for a particular package we know about.
  */
 final class PackageSetting extends PackageSettingBase {
-    int uid;
+    int appId;
     PackageParser.Package pkg;
     SharedUserSetting sharedUser;
 
@@ -41,7 +41,7 @@
     PackageSetting(PackageSetting orig) {
         super(orig);
 
-        uid = orig.uid;
+        appId = orig.appId;
         pkg = orig.pkg;
         sharedUser = orig.sharedUser;
     }
@@ -50,6 +50,6 @@
     public String toString() {
         return "PackageSetting{"
             + Integer.toHexString(System.identityHashCode(this))
-            + " " + name + "/" + uid + "}";
+            + " " + name + "/" + appId + "}";
     }
 }
\ No newline at end of file
diff --git a/services/java/com/android/server/pm/PackageSettingBase.java b/services/java/com/android/server/pm/PackageSettingBase.java
index b7cf8d6..56f2166 100644
--- a/services/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/java/com/android/server/pm/PackageSettingBase.java
@@ -273,4 +273,13 @@
             return COMPONENT_ENABLED_STATE_DEFAULT;
         }
     }
+
+    void removeUser(int userId) {
+        enabled.delete(userId);
+        stopped.delete(userId);
+        enabledComponents.delete(userId);
+        disabledComponents.delete(userId);
+        notLaunched.delete(userId);
+    }
+
 }
diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java
index b541c8c..bb7f4fc 100644
--- a/services/java/com/android/server/pm/Settings.java
+++ b/services/java/com/android/server/pm/Settings.java
@@ -275,7 +275,7 @@
             p.pkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
         }
         PackageSetting ret = addPackageLPw(name, p.realName, p.codePath, p.resourcePath,
-                p.nativeLibraryPathString, p.uid, p.versionCode, p.pkgFlags);
+                p.nativeLibraryPathString, p.appId, p.versionCode, p.pkgFlags);
         mDisabledSysPackages.remove(name);
         return ret;
     }
@@ -284,7 +284,7 @@
             String nativeLibraryPathString, int uid, int vc, int pkgFlags) {
         PackageSetting p = mPackages.get(name);
         if (p != null) {
-            if (p.uid == uid) {
+            if (p.appId == uid) {
                 return p;
             }
             PackageManagerService.reportSettingsProblem(Log.ERROR,
@@ -293,7 +293,7 @@
         }
         p = new PackageSetting(name, realName, codePath, resourcePath, nativeLibraryPathString,
                 vc, pkgFlags);
-        p.uid = uid;
+        p.appId = uid;
         if (addUserIdLPw(uid, p, name)) {
             mPackages.put(name, p);
             return p;
@@ -407,7 +407,7 @@
                 p.copyFrom(origPackage);
                 p.signatures = s;
                 p.sharedUser = origPackage.sharedUser;
-                p.uid = origPackage.uid;
+                p.appId = origPackage.appId;
                 p.origPackage = origPackage;
                 mRenamedPackages.put(name, origPackage.name);
                 name = origPackage.name;
@@ -435,7 +435,7 @@
                     }
                 }
                 if (sharedUser != null) {
-                    p.uid = sharedUser.userId;
+                    p.appId = sharedUser.userId;
                 } else {
                     // Clone the setting here for disabled system packages
                     PackageSetting dis = mDisabledSysPackages.get(name);
@@ -447,7 +447,7 @@
                         if (dis.signatures.mSignatures != null) {
                             p.signatures.mSignatures = dis.signatures.mSignatures.clone();
                         }
-                        p.uid = dis.uid;
+                        p.appId = dis.appId;
                         // Clone permissions
                         p.grantedPermissions = new HashSet<String>(dis.grantedPermissions);
                         // Clone component info
@@ -464,14 +464,14 @@
                             }
                         }
                         // Add new setting to list of user ids
-                        addUserIdLPw(p.uid, p, name);
+                        addUserIdLPw(p.appId, p, name);
                     } else {
                         // Assign new user id
-                        p.uid = newUserIdLPw(p);
+                        p.appId = newUserIdLPw(p);
                     }
                 }
             }
-            if (p.uid < 0) {
+            if (p.appId < 0) {
                 PackageManagerService.reportSettingsProblem(Log.WARN,
                         "Package " + name + " could not be assigned a valid uid");
                 return null;
@@ -539,9 +539,9 @@
                         + p.sharedUser + " but is now " + sharedUser
                         + "; I am not changing its files so it will probably fail!");
                 p.sharedUser.packages.remove(p);
-            } else if (p.uid != sharedUser.userId) {
+            } else if (p.appId != sharedUser.userId) {
                 PackageManagerService.reportSettingsProblem(Log.ERROR,
-                    "Package " + p.name + " was user id " + p.uid
+                    "Package " + p.name + " was user id " + p.appId
                     + " but is now user " + sharedUser
                     + " with id " + sharedUser.userId
                     + "; I am not changing its files so it will probably fail!");
@@ -549,7 +549,7 @@
 
             sharedUser.packages.add(p);
             p.sharedUser = sharedUser;
-            p.uid = sharedUser.userId;
+            p.appId = sharedUser.userId;
         }
     }
 
@@ -614,8 +614,8 @@
                     return p.sharedUser.userId;
                 }
             } else {
-                removeUserIdLPw(p.uid);
-                return p.uid;
+                removeUserIdLPw(p.appId);
+                return p.appId;
             }
         }
         return -1;
@@ -628,7 +628,7 @@
                 p.sharedUser.packages.remove(p);
                 p.sharedUser.packages.add(newp);
             } else {
-                replaceUserIdLPw(p.uid, newp);
+                replaceUserIdLPw(p.appId, newp);
             }
         }
         mPackages.put(name, newp);
@@ -1317,9 +1317,9 @@
             serializer.attribute(null, "nativeLibraryPath", pkg.nativeLibraryPathString);
         }
         if (pkg.sharedUser == null) {
-            serializer.attribute(null, "userId", Integer.toString(pkg.uid));
+            serializer.attribute(null, "userId", Integer.toString(pkg.appId));
         } else {
-            serializer.attribute(null, "sharedUserId", Integer.toString(pkg.uid));
+            serializer.attribute(null, "sharedUserId", Integer.toString(pkg.appId));
         }
         serializer.startTag(null, "perms");
         if (pkg.sharedUser == null) {
@@ -1364,9 +1364,9 @@
         serializer.attribute(null, "ut", Long.toHexString(pkg.lastUpdateTime));
         serializer.attribute(null, "version", String.valueOf(pkg.versionCode));
         if (pkg.sharedUser == null) {
-            serializer.attribute(null, "userId", Integer.toString(pkg.uid));
+            serializer.attribute(null, "userId", Integer.toString(pkg.appId));
         } else {
-            serializer.attribute(null, "sharedUserId", Integer.toString(pkg.uid));
+            serializer.attribute(null, "sharedUserId", Integer.toString(pkg.appId));
         }
         if (pkg.uidError) {
             serializer.attribute(null, "uidError", "true");
@@ -1607,7 +1607,7 @@
         final Iterator<PackageSetting> disabledIt = mDisabledSysPackages.values().iterator();
         while (disabledIt.hasNext()) {
             final PackageSetting disabledPs = disabledIt.next();
-            final Object id = getUserIdLPr(disabledPs.uid);
+            final Object id = getUserIdLPr(disabledPs.appId);
             if (id != null && id instanceof SharedUserSetting) {
                 disabledPs.sharedUser = (SharedUserSetting) id;
             }
@@ -1753,10 +1753,10 @@
             }
         }
         String idStr = parser.getAttributeValue(null, "userId");
-        ps.uid = idStr != null ? Integer.parseInt(idStr) : 0;
-        if (ps.uid <= 0) {
+        ps.appId = idStr != null ? Integer.parseInt(idStr) : 0;
+        if (ps.appId <= 0) {
             String sharedIdStr = parser.getAttributeValue(null, "sharedUserId");
-            ps.uid = sharedIdStr != null ? Integer.parseInt(sharedIdStr) : 0;
+            ps.appId = sharedIdStr != null ? Integer.parseInt(sharedIdStr) : 0;
         }
         int outerDepth = parser.getDepth();
         int type;
@@ -2164,6 +2164,13 @@
         }
     }
 
+    void removeUserLPr(int userId) {
+        File file = getUserPackagesStateFile(userId);
+        file.delete();
+        file = getUserPackagesStateBackupFile(userId);
+        file.delete();
+    }
+
     // Returns -1 if we could not find an available UserId to assign
     private int newUserIdLPw(Object obj) {
         // Let's be stupidly inefficient for now...
@@ -2265,11 +2272,11 @@
         if (pkgSetting == null) {
             throw new IllegalArgumentException("Unknown package: " + packageName);
         }
-        if (!allowedByPermission && (appId != pkgSetting.uid)) {
+        if (!allowedByPermission && (appId != pkgSetting.appId)) {
             throw new SecurityException(
                     "Permission Denial: attempt to change stopped state from pid="
                     + Binder.getCallingPid()
-                    + ", uid=" + uid + ", package uid=" + pkgSetting.uid);
+                    + ", uid=" + uid + ", package uid=" + pkgSetting.appId);
         }
         if (DEBUG_STOPPED) {
             if (stopped) {
@@ -2285,7 +2292,7 @@
                 if (pkgSetting.installerPackageName != null) {
                     PackageManagerService.sendPackageBroadcast(Intent.ACTION_PACKAGE_FIRST_LAUNCH,
                             pkgSetting.name, null,
-                            pkgSetting.installerPackageName, null);
+                            pkgSetting.installerPackageName, null, userId);
                 }
                 pkgSetting.setNotLaunched(false, userId);
             }
@@ -2369,7 +2376,7 @@
                 pw.println(ps.name);
             }
 
-            pw.print("    userId="); pw.print(ps.uid);
+            pw.print("    userId="); pw.print(ps.appId);
             pw.print(" gids="); pw.println(PackageManagerService.arrayToString(ps.gids));
             pw.print("    sharedUser="); pw.println(ps.sharedUser);
             pw.print("    pkg="); pw.println(ps.pkg);
@@ -2513,7 +2520,7 @@
                     pw.println(ps.name);
                 }
                 pw.print("    userId=");
-                pw.println(ps.uid);
+                pw.println(ps.appId);
                 pw.print("    sharedUser=");
                 pw.println(ps.sharedUser);
                 pw.print("    codePath=");
diff --git a/services/java/com/android/server/pm/UserManager.java b/services/java/com/android/server/pm/UserManager.java
index 959e570..4e9e666 100644
--- a/services/java/com/android/server/pm/UserManager.java
+++ b/services/java/com/android/server/pm/UserManager.java
@@ -16,6 +16,7 @@
 
 package com.android.server.pm;
 
+import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastXmlSerializer;
 
 import android.content.pm.ApplicationInfo;
@@ -58,7 +59,7 @@
     private static final String USER_INFO_DIR = "system" + File.separator + "users";
     private static final String USER_LIST_FILENAME = "userlist.xml";
 
-    private SparseArray<UserInfo> mUsers;
+    private SparseArray<UserInfo> mUsers = new SparseArray<UserInfo>();
 
     private final File mUsersDir;
     private final File mUserListFile;
@@ -91,11 +92,36 @@
     }
 
     public List<UserInfo> getUsers() {
-        ArrayList<UserInfo> users = new ArrayList<UserInfo>(mUsers.size());
-        for (int i = 0; i < mUsers.size(); i++) {
-            users.add(mUsers.valueAt(i));
+        synchronized (mUsers) {
+            ArrayList<UserInfo> users = new ArrayList<UserInfo>(mUsers.size());
+            for (int i = 0; i < mUsers.size(); i++) {
+                users.add(mUsers.valueAt(i));
+            }
+            return users;
         }
-        return users;
+    }
+
+    public UserInfo getUser(int userId) {
+        synchronized (mUsers) {
+            UserInfo info = mUsers.get(userId);
+            return info;
+        }
+    }
+
+    public boolean exists(int userId) {
+        synchronized (mUsers) {
+            return ArrayUtils.contains(mUserIds, userId);
+        }
+    }
+
+    public void updateUserName(int userId, String name) {
+        synchronized (mUsers) {
+            UserInfo info = mUsers.get(userId);
+            if (name != null && !name.equals(info.name)) {
+                info.name = name;
+                writeUserLocked(info);
+            }
+        }
     }
 
     /**
@@ -108,9 +134,14 @@
     }
 
     private void readUserList() {
-        mUsers = new SparseArray<UserInfo>();
+        synchronized (mUsers) {
+            readUserListLocked();
+        }
+    }
+
+    private void readUserListLocked() {
         if (!mUserListFile.exists()) {
-            fallbackToSingleUser();
+            fallbackToSingleUserLocked();
             return;
         }
         FileInputStream fis = null;
@@ -126,7 +157,7 @@
 
             if (type != XmlPullParser.START_TAG) {
                 Slog.e(LOG_TAG, "Unable to read user list");
-                fallbackToSingleUser();
+                fallbackToSingleUserLocked();
                 return;
             }
 
@@ -139,11 +170,11 @@
                     }
                 }
             }
-            updateUserIds();
+            updateUserIdsLocked();
         } catch (IOException ioe) {
-            fallbackToSingleUser();
+            fallbackToSingleUserLocked();
         } catch (XmlPullParserException pe) {
-            fallbackToSingleUser();
+            fallbackToSingleUserLocked();
         } finally {
             if (fis != null) {
                 try {
@@ -154,15 +185,15 @@
         }
     }
 
-    private void fallbackToSingleUser() {
+    private void fallbackToSingleUserLocked() {
         // Create the primary user
         UserInfo primary = new UserInfo(0, "Primary",
                 UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY);
         mUsers.put(0, primary);
-        updateUserIds();
+        updateUserIdsLocked();
 
-        writeUserList();
-        writeUser(primary);
+        writeUserListLocked();
+        writeUserLocked(primary);
     }
 
     /*
@@ -172,7 +203,7 @@
      *   <name>Primary</name>
      * </user>
      */
-    private void writeUser(UserInfo userInfo) {
+    private void writeUserLocked(UserInfo userInfo) {
         FileOutputStream fos = null;
         try {
             final File mUserFile = new File(mUsersDir, userInfo.id + ".xml");
@@ -216,7 +247,7 @@
      *   <user id="2"></user>
      * </users>
      */
-    private void writeUserList() {
+    private void writeUserListLocked() {
         FileOutputStream fos = null;
         try {
             fos = new FileOutputStream(mUserListFile);
@@ -309,17 +340,19 @@
         return null;
     }
 
-    public UserInfo createUser(String name, int flags, List<ApplicationInfo> apps) {
+    public UserInfo createUser(String name, int flags) {
         int userId = getNextAvailableId();
         UserInfo userInfo = new UserInfo(userId, name, flags);
         File userPath = new File(mBaseUserPath, Integer.toString(userId));
-        if (!createPackageFolders(userId, userPath, apps)) {
+        if (!createPackageFolders(userId, userPath)) {
             return null;
         }
-        mUsers.put(userId, userInfo);
-        writeUserList();
-        writeUser(userInfo);
-        updateUserIds();
+        synchronized (mUsers) {
+            mUsers.put(userId, userInfo);
+            writeUserListLocked();
+            writeUserLocked(userInfo);
+            updateUserIdsLocked();
+        }
         return userInfo;
     }
 
@@ -328,7 +361,13 @@
      * after the user's processes have been terminated.
      * @param id the user's id
      */
-    public void removeUser(int id) {
+    public boolean removeUser(int id) {
+        synchronized (mUsers) {
+            return removeUserLocked(id);
+        }
+    }
+
+    private boolean removeUserLocked(int id) {
         // Remove from the list
         UserInfo userInfo = mUsers.get(id);
         if (userInfo != null) {
@@ -338,11 +377,11 @@
             File userFile = new File(mUsersDir, id + ".xml");
             userFile.delete();
             // Update the user list
-            writeUserList();
-            // Remove the data directories for all packages for this user
-            removePackageFolders(id);
-            updateUserIds();
+            writeUserListLocked();
+            updateUserIdsLocked();
+            return true;
         }
+        return false;
     }
 
     public void installPackageForAllUsers(String packageName, int uid) {
@@ -376,7 +415,7 @@
     /**
      * Caches the list of user ids in an array, adjusting the array size when necessary.
      */
-    private void updateUserIds() {
+    private void updateUserIdsLocked() {
         if (mUserIds == null || mUserIds.length != mUsers.size()) {
             mUserIds = new int[mUsers.size()];
         }
@@ -402,11 +441,10 @@
         return i;
     }
 
-    private boolean createPackageFolders(int id, File userPath, final List<ApplicationInfo> apps) {
+    private boolean createPackageFolders(int id, File userPath) {
         // mInstaller may not be available for unit-tests.
-        if (mInstaller == null || apps == null) return true;
+        if (mInstaller == null) return true;
 
-        final long startTime = SystemClock.elapsedRealtime();
         // Create the user path
         userPath.mkdir();
         FileUtils.setPermissions(userPath.toString(), FileUtils.S_IRWXU | FileUtils.S_IRWXG
@@ -414,13 +452,10 @@
 
         mInstaller.cloneUserData(0, id, false);
 
-        final long stopTime = SystemClock.elapsedRealtime();
-        Log.i(LOG_TAG,
-                "Time to create " + apps.size() + " packages = " + (stopTime - startTime) + "ms");
         return true;
     }
 
-    private boolean removePackageFolders(int id) {
+    boolean removePackageFolders(int id) {
         // mInstaller may not be available for unit-tests.
         if (mInstaller == null) return true;