Merge "Bind to the correct default container service when installing/moving/measuring pkgs" into jb-mr1-dev
diff --git a/core/java/android/content/pm/RegisteredServicesCache.java b/core/java/android/content/pm/RegisteredServicesCache.java
index 0bc0f91..7642670 100644
--- a/core/java/android/content/pm/RegisteredServicesCache.java
+++ b/core/java/android/content/pm/RegisteredServicesCache.java
@@ -331,12 +331,16 @@
                 notifyListener(v1, true /* removed */);
             }
             if (changes.length() > 0) {
-                Log.d(TAG, "generateServicesMap(" + mInterfaceName + "): " +
-                        serviceInfos.size() + " services:\n" + changes);
+                if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                    Log.d(TAG, "generateServicesMap(" + mInterfaceName + "): " +
+                            serviceInfos.size() + " services:\n" + changes);
+                }
                 writePersistentServicesLocked();
             } else {
-                Log.d(TAG, "generateServicesMap(" + mInterfaceName + "): " +
-                        serviceInfos.size() + " services unchanged");
+                if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                    Log.d(TAG, "generateServicesMap(" + mInterfaceName + "): " +
+                            serviceInfos.size() + " services unchanged");
+                }
             }
             mPersistentServicesFileDidNotExist = false;
         }
diff --git a/core/java/android/service/dreams/DreamManagerService.java b/core/java/android/service/dreams/DreamManagerService.java
index 4b0f7c5..2cec6c3 100644
--- a/core/java/android/service/dreams/DreamManagerService.java
+++ b/core/java/android/service/dreams/DreamManagerService.java
@@ -105,7 +105,7 @@
     public ComponentName[] getDreamComponents() {
         // TODO(dsandler) don't load this every time, watch the value
         String names = Settings.Secure.getString(mContext.getContentResolver(), SCREENSAVER_COMPONENTS);
-        return componentsFromString(names);
+        return names == null ? null : componentsFromString(names);
     }
 
     // IDreamManager method
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index ac3dee4..9051285 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -357,11 +357,6 @@
 
                         // From the Unicode Line Breaking Algorithm (at least approximately)
                         boolean isLineBreak = isSpaceOrTab ||
-                                // .,:; are class IS breakpoints, except when adjacent to digits
-                                ((c == CHAR_DOT || c == CHAR_COMMA ||
-                                c == CHAR_COLON || c == CHAR_SEMICOLON) &&
-                                (j - 1 < here || !Character.isDigit(chs[j - 1 - paraStart])) &&
-                                (j + 1 >= spanEnd || !Character.isDigit(chs[j + 1 - paraStart]))) ||
                                 // / is class SY and - is class HY, except when followed by a digit
                                 ((c == CHAR_SLASH || c == CHAR_HYPHEN) &&
                                 (j + 1 >= spanEnd || !Character.isDigit(chs[j + 1 - paraStart]))) ||
@@ -959,10 +954,6 @@
     private static final char CHAR_NEW_LINE = '\n';
     private static final char CHAR_TAB = '\t';
     private static final char CHAR_SPACE = ' ';
-    private static final char CHAR_DOT = '.';
-    private static final char CHAR_COMMA = ',';
-    private static final char CHAR_COLON = ':';
-    private static final char CHAR_SEMICOLON = ';';
     private static final char CHAR_SLASH = '/';
     private static final char CHAR_HYPHEN = '-';
 
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 61c942d..423135f 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -973,6 +973,12 @@
 
         // Start selection mode if needed. We don't need to if we're unchecking something.
         if (value && mChoiceMode == CHOICE_MODE_MULTIPLE_MODAL && mChoiceActionMode == null) {
+            if (mMultiChoiceModeCallback == null ||
+                    !mMultiChoiceModeCallback.hasWrappedCallback()) {
+                throw new IllegalStateException("AbsListView: attempted to start selection mode " +
+                        "for CHOICE_MODE_MULTIPLE_MODAL but no choice mode callback was " +
+                        "supplied. Call setMultiChoiceModeListener to set a callback.");
+            }
             mChoiceActionMode = startActionMode(mMultiChoiceModeCallback);
         }
 
@@ -5945,6 +5951,10 @@
             mWrapped = wrapped;
         }
 
+        public boolean hasWrappedCallback() {
+            return mWrapped != null;
+        }
+
         public boolean onCreateActionMode(ActionMode mode, Menu menu) {
             if (mWrapped.onCreateActionMode(mode, menu)) {
                 // Initialize checked graphic state?
diff --git a/core/java/android/widget/CheckedTextView.java b/core/java/android/widget/CheckedTextView.java
index f91201a..bc78adc 100644
--- a/core/java/android/widget/CheckedTextView.java
+++ b/core/java/android/widget/CheckedTextView.java
@@ -175,11 +175,7 @@
     @Override
     protected void internalSetPadding(int left, int top, int right, int bottom) {
         super.internalSetPadding(left, top, right, bottom);
-        if (isLayoutRtl()) {
-            mBasePadding = mUserPaddingLeft;
-        } else {
-            mBasePadding = mUserPaddingRight;
-        }
+        setBasePadding(isLayoutRtl());
     }
 
     @Override
@@ -201,13 +197,21 @@
     @Override
     public void setPadding(int left, int top, int right, int bottom) {
         super.setPadding(left, top, right, bottom);
-        mBasePadding = getPaddingEnd();
+        setBasePadding(isLayoutRtl());
     }
 
     @Override
     public void setPaddingRelative(int start, int top, int end, int bottom) {
         super.setPaddingRelative(start, top, end, bottom);
-        mBasePadding = getPaddingEnd();
+        setBasePadding(isLayoutRtl());
+    }
+
+    private void setBasePadding(boolean isLayoutRtl) {
+        if (isLayoutRtl) {
+            mBasePadding = mPaddingLeft;
+        } else {
+            mBasePadding = mPaddingRight;
+        }
     }
 
     @Override
@@ -237,11 +241,11 @@
             final int left;
             final int right;
             if (isLayoutRtl) {
-                right = getPaddingEnd();
-                left = right - mCheckMarkWidth;
-            } else {
-                left = width - getPaddingEnd();
+                left = mBasePadding;
                 right = left + mCheckMarkWidth;
+            } else {
+                right = width - mBasePadding;
+                left = right - mCheckMarkWidth;
             }
             checkMarkDrawable.setBounds( left, top, right, bottom);
             checkMarkDrawable.draw(canvas);
diff --git a/core/java/com/android/internal/widget/ScrollingTabContainerView.java b/core/java/com/android/internal/widget/ScrollingTabContainerView.java
index 08d9f49..b620568 100644
--- a/core/java/com/android/internal/widget/ScrollingTabContainerView.java
+++ b/core/java/com/android/internal/widget/ScrollingTabContainerView.java
@@ -23,7 +23,9 @@
 import android.app.ActionBar;
 import android.content.Context;
 import android.content.res.Configuration;
+import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
+import android.text.TextUtils;
 import android.text.TextUtils.TruncateAt;
 import android.view.Gravity;
 import android.view.View;
@@ -38,6 +40,7 @@
 import android.widget.ListView;
 import android.widget.Spinner;
 import android.widget.TextView;
+import android.widget.Toast;
 
 /**
  * This widget implements the dynamic action bar tab behavior that can change
@@ -352,7 +355,7 @@
         tabView.getTab().select();
     }
 
-    private class TabView extends LinearLayout {
+    private class TabView extends LinearLayout implements OnLongClickListener {
         private ActionBar.Tab mTab;
         private TextView mTextView;
         private ImageView mIconView;
@@ -426,7 +429,8 @@
                     mIconView.setImageDrawable(null);
                 }
 
-                if (text != null) {
+                final boolean hasText = !TextUtils.isEmpty(text);
+                if (hasText) {
                     if (mTextView == null) {
                         TextView textView = new TextView(getContext(), null,
                                 com.android.internal.R.attr.actionBarTabTextStyle);
@@ -448,9 +452,35 @@
                 if (mIconView != null) {
                     mIconView.setContentDescription(tab.getContentDescription());
                 }
+
+                if (!hasText && !TextUtils.isEmpty(tab.getContentDescription())) {
+                    setOnLongClickListener(this);
+                } else {
+                    setOnLongClickListener(null);
+                    setLongClickable(false);
+                }
             }
         }
 
+        public boolean onLongClick(View v) {
+            final int[] screenPos = new int[2];
+            getLocationOnScreen(screenPos);
+
+            final Context context = getContext();
+            final int width = getWidth();
+            final int height = getHeight();
+            final int screenWidth = context.getResources().getDisplayMetrics().widthPixels;
+
+            Toast cheatSheet = Toast.makeText(context, mTab.getContentDescription(),
+                    Toast.LENGTH_SHORT);
+            // Show under the tab
+            cheatSheet.setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL,
+                    (screenPos[0] + width / 2) - screenWidth / 2, height);
+
+            cheatSheet.show();
+            return true;
+        }
+
         public ActionBar.Tab getTab() {
             return mTab;
         }
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index a6af144..7097891 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -197,7 +197,7 @@
             
             Slog.i(TAG, "User Service");
             ServiceManager.addService(Context.USER_SERVICE,
-                    UserManagerService.getInstance(context));
+                    UserManagerService.getInstance());
 
 
             mContentResolver = context.getContentResolver();
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index daef773..0345df1 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -961,8 +961,8 @@
             mUserAppDataDir = new File(dataDir, "user");
             mDrmAppPrivateInstallDir = new File(dataDir, "app-private");
 
-            sUserManager = UserManagerService.getInstance(context);
-            sUserManager.setInstaller(this, mInstaller);
+            sUserManager = new UserManagerService(context, this,
+                    mInstallLock, mPackages);
 
             readPermissions();
 
@@ -1156,8 +1156,7 @@
                         String msg = "System package " + ps.name
                                 + " no longer exists; wiping its data";
                         reportSettingsProblem(Log.WARN, msg);
-                        mInstaller.remove(ps.name, 0);
-                        sUserManager.removePackageForAllUsers(ps.name);
+                        removeDataDirsLI(ps.name);
                     } else {
                         final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(ps.name);
                         if (disabledPs.codePath == null || !disabledPs.codePath.exists()) {
@@ -1206,9 +1205,7 @@
                     if (deletedPkg == null) {
                         msg = "Updated system package " + deletedAppName
                                 + " no longer exists; wiping its data";
-
-                        mInstaller.remove(deletedAppName, 0);
-                        sUserManager.removePackageForAllUsers(deletedAppName);
+                        removeDataDirsLI(deletedAppName);
                     } else {
                         msg = "Updated system app + " + deletedAppName
                                 + " no longer present; removing system privileges for "
@@ -1343,13 +1340,7 @@
 
     void cleanupInstallFailedPackage(PackageSetting ps) {
         Slog.i(TAG, "Cleaning up incompletely installed app: " + ps.name);
-        int retCode = mInstaller.remove(ps.name, 0);
-        if (retCode < 0) {
-            Slog.w(TAG, "Couldn't remove app data directory for package: "
-                       + ps.name + ", retcode=" + retCode);
-        } else {
-            sUserManager.removePackageForAllUsers(ps.name);
-        }
+        removeDataDirsLI(ps.name);
         if (ps.codePath != null) {
             if (!ps.codePath.delete()) {
                 Slog.w(TAG, "Unable to remove old code file: " + ps.codePath);
@@ -1829,9 +1820,11 @@
             public void run() {
                 mHandler.removeCallbacks(this);
                 int retCode = -1;
-                retCode = mInstaller.freeCache(freeStorageSize);
-                if (retCode < 0) {
-                    Slog.w(TAG, "Couldn't clear application caches");
+                synchronized (mInstallLock) {
+                    retCode = mInstaller.freeCache(freeStorageSize);
+                    if (retCode < 0) {
+                        Slog.w(TAG, "Couldn't clear application caches");
+                    }
                 }
                 if (observer != null) {
                     try {
@@ -1852,9 +1845,11 @@
             public void run() {
                 mHandler.removeCallbacks(this);
                 int retCode = -1;
-                retCode = mInstaller.freeCache(freeStorageSize);
-                if (retCode < 0) {
-                    Slog.w(TAG, "Couldn't clear application caches");
+                synchronized (mInstallLock) {
+                    retCode = mInstaller.freeCache(freeStorageSize);
+                    if (retCode < 0) {
+                        Slog.w(TAG, "Couldn't clear application caches");
+                    }
                 }
                 if(pi != null) {
                     try {
@@ -3005,7 +3000,9 @@
                     }
                     ProviderInfo info = PackageParser.generateProviderInfo(p, flags,
                             ps.readUserState(userId), userId);
-                    finalList.add(info);
+                    if (info != null) {
+                        finalList.add(info);
+                    }
                 }
             }
         }
@@ -3038,8 +3035,11 @@
                 final PackageParser.Instrumentation p = i.next();
                 if (targetPackage == null
                         || targetPackage.equals(p.info.targetPackage)) {
-                    finalList.add(PackageParser.generateInstrumentationInfo(p,
-                            flags));
+                    InstrumentationInfo ii = PackageParser.generateInstrumentationInfo(p,
+                            flags);
+                    if (ii != null) {
+                        finalList.add(ii);
+                    }
                 }
             }
         }
@@ -3200,7 +3200,7 @@
 
                     InstallArgs args = createInstallArgs(packageFlagsToInstallFlags(ps),
                             ps.codePathString, ps.resourcePathString, ps.nativeLibraryPathString);
-                    synchronized (mInstaller) {
+                    synchronized (mInstallLock) {
                         args.cleanUpResourcesLI();
                     }
                     synchronized (mPackages) {
@@ -3256,7 +3256,7 @@
                             + " better than installed " + ps.versionCode);
                     InstallArgs args = createInstallArgs(packageFlagsToInstallFlags(ps),
                             ps.codePathString, ps.resourcePathString, ps.nativeLibraryPathString);
-                    synchronized (mInstaller) {
+                    synchronized (mInstallLock) {
                         args.cleanUpResourcesLI();
                     }
                 }
@@ -3490,6 +3490,36 @@
         }
     }
 
+    private int createDataDirsLI(String packageName, int uid) {
+        int[] users = sUserManager.getUserIds();
+        int res = mInstaller.install(packageName, uid, uid);
+        if (res < 0) {
+            return res;
+        }
+        for (int user : users) {
+            if (user != 0) {
+                res = mInstaller.createUserData(packageName,
+                        UserHandle.getUid(user, uid), user);
+                if (res < 0) {
+                    return res;
+                }
+            }
+        }
+        return res;
+    }
+
+    private int removeDataDirsLI(String packageName) {
+        int[] users = sUserManager.getUserIds();
+        int res = 0;
+        for (int user : users) {
+            int resInner = mInstaller.remove(packageName, user);
+            if (resInner < 0) {
+                res = resInner;
+            }
+        }
+        return res;
+    }
+
     private PackageParser.Package scanPackageLI(PackageParser.Package pkg,
             int parseFlags, int scanMode, long currentTime, UserHandle user) {
         File scanFile = new File(pkg.mScanPath);
@@ -3842,11 +3872,9 @@
                             || (scanMode&SCAN_BOOTING) != 0)) {
                         // If this is a system app, we can at least delete its
                         // current data so the application will still work.
-                        int ret = mInstaller.remove(pkgName, 0);
+                        int ret = removeDataDirsLI(pkgName);
                         if (ret >= 0) {
                             // TODO: Kill the processes first
-                            // Remove the data directories for all users
-                            sUserManager.removePackageForAllUsers(pkgName);
                             // Old data gone!
                             String prefix = (parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0
                                     ? "System package " : "Third party package ";
@@ -3858,8 +3886,7 @@
                             recovered = true;
 
                             // And now re-install the app.
-                            ret = mInstaller.install(pkgName, pkg.applicationInfo.uid,
-                                    pkg.applicationInfo.uid);
+                            ret = createDataDirsLI(pkgName, pkg.applicationInfo.uid);
                             if (ret == -1) {
                                 // Ack should not happen!
                                 msg = prefix + pkg.packageName
@@ -3868,9 +3895,6 @@
                                 mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
                                 return null;
                             }
-                            // Create data directories for all users
-                            sUserManager.installPackageForAllUsers(pkgName,
-                                    pkg.applicationInfo.uid);
                         }
                         if (!recovered) {
                             mHasSystemUidErrors = true;
@@ -3908,15 +3932,12 @@
                         Log.v(TAG, "Want this data dir: " + dataPath);
                 }
                 //invoke installer to do the actual installation
-                int ret = mInstaller.install(pkgName, pkg.applicationInfo.uid,
-                        pkg.applicationInfo.uid);
+                int ret = createDataDirsLI(pkgName, pkg.applicationInfo.uid);
                 if (ret < 0) {
                     // Error from installer
                     mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
                     return null;
                 }
-                // Create data directories for all users
-                sUserManager.installPackageForAllUsers(pkgName, pkg.applicationInfo.uid);
 
                 if (dataPath.exists()) {
                     pkg.applicationInfo.dataDir = dataPath.getPath();
@@ -5089,6 +5110,9 @@
             }
             ServiceInfo si = PackageParser.generateServiceInfo(service, mFlags,
                     ps.readUserState(userId), userId);
+            if (si == null) {
+                return null;
+            }
             final ResolveInfo res = new ResolveInfo();
             res.serviceInfo = si;
             if ((mFlags&PackageManager.GET_RESOLVED_FILTER) != 0) {
@@ -7838,15 +7862,7 @@
             }
         }
         if ((flags&PackageManager.DELETE_KEEP_DATA) == 0) {
-            int retCode = mInstaller.remove(packageName, 0);
-            if (retCode < 0) {
-                Slog.w(TAG, "Couldn't remove app data or cache directory for package: "
-                           + packageName + ", retcode=" + retCode);
-                // we don't consider this to be a failure of the core package deletion
-            } else {
-                // TODO: Kill the processes first
-                sUserManager.removePackageForAllUsers(packageName);
-            }
+            removeDataDirsLI(packageName);
             schedulePackageCleaning(packageName, UserHandle.USER_ALL, true);
         }
         // writer
@@ -9765,15 +9781,36 @@
     }
 
     /** Called by UserManagerService */
-    void cleanUpUser(int userHandle) {
+    void cleanUpUserLILPw(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(userHandle);
+        Set<Entry<String, PackageSetting>> entries = mSettings.mPackages.entrySet();
+        for (Entry<String, PackageSetting> entry : entries) {
+            entry.getValue().removeUser(userHandle);
+        }
+        if (mDirtyUsers.remove(userHandle));
+        mSettings.removeUserLPr(userHandle);
+        if (mInstaller != null) {
+            // Technically, we shouldn't be doing this with the package lock
+            // held.  However, this is very rare, and there is already so much
+            // other disk I/O going on, that we'll let it slide for now.
+            mInstaller.removeUserDataDirs(userHandle);
+        }
+    }
+
+    /** Called by UserManagerService */
+    void createNewUserLILPw(int userHandle, File path) {
+        if (mInstaller != null) {
+            path.mkdir();
+            FileUtils.setPermissions(path.toString(), FileUtils.S_IRWXU | FileUtils.S_IRWXG
+                    | FileUtils.S_IXOTH, -1, -1);
+            for (PackageSetting ps : mSettings.mPackages.values()) {
+                // Only system apps are initially installed.
+                ps.setInstalled((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0, userHandle);
+                // Need to create a data directory for all apps under this user.
+                mInstaller.createUserData(ps.name,
+                        UserHandle.getUid(userHandle, ps.appId), userHandle);
             }
-            if (mDirtyUsers.remove(userHandle));
-            mSettings.removeUserLPr(userHandle);
+            mSettings.writePackageRestrictionsLPr(userHandle);
         }
     }
 
diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java
index a341304..68b594a 100644
--- a/services/java/com/android/server/pm/Settings.java
+++ b/services/java/com/android/server/pm/Settings.java
@@ -2476,7 +2476,7 @@
     private List<UserInfo> getAllUsers() {
         long id = Binder.clearCallingIdentity();
         try {
-            return UserManagerService.getInstance(mContext).getUsers();
+            return UserManagerService.getInstance().getUsers();
         } catch (NullPointerException npe) {
             // packagemanager not yet initialized
         } finally {
diff --git a/services/java/com/android/server/pm/UserManagerService.java b/services/java/com/android/server/pm/UserManagerService.java
index 8899ea2..750aa72 100644
--- a/services/java/com/android/server/pm/UserManagerService.java
+++ b/services/java/com/android/server/pm/UserManagerService.java
@@ -25,7 +25,6 @@
 import android.app.ActivityManager;
 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;
@@ -34,10 +33,8 @@
 import android.os.IUserManager;
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
-import android.os.SystemClock;
 import android.os.UserHandle;
 import android.util.AtomicFile;
-import android.util.Log;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.Xml;
@@ -72,59 +69,79 @@
     private static final String USER_LIST_FILENAME = "userlist.xml";
     private static final String USER_PHOTO_FILENAME = "photo.png";
 
-    private SparseArray<UserInfo> mUsers = new SparseArray<UserInfo>();
+    private final Context mContext;
+    private final PackageManagerService mPm;
+    private final Object mInstallLock;
+    private final Object mPackagesLock;
 
     private final File mUsersDir;
     private final File mUserListFile;
+    private final File mBaseUserPath;
+
+    private SparseArray<UserInfo> mUsers = new SparseArray<UserInfo>();
+
     private int[] mUserIds;
     private boolean mGuestEnabled;
     private int mNextSerialNumber;
 
-    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);
+    public static UserManagerService getInstance() {
+        synchronized (UserManagerService.class) {
+            return sInstance;
         }
-        return sInstance;
     }
 
     /**
      * Available for testing purposes.
      */
     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
-        File userZeroDir = new File(mUsersDir, "0");
-        userZeroDir.mkdirs();
-        mBaseUserPath = baseUserPath;
-        FileUtils.setPermissions(mUsersDir.toString(),
-                FileUtils.S_IRWXU|FileUtils.S_IRWXG
-                |FileUtils.S_IROTH|FileUtils.S_IXOTH,
-                -1, -1);
-        mUserListFile = new File(mUsersDir, USER_LIST_FILENAME);
-        readUserList();
+        this(null, null, new Object(), new Object(), dataDir, baseUserPath);
     }
 
-    public UserManagerService(Context context) {
-        this(Environment.getDataDirectory(), new File(Environment.getDataDirectory(), "user"));
-        mContext = context;
+    /**
+     * Called by package manager to create the service.  This is closely
+     * associated with the package manager, and the given lock is the
+     * package manager's own lock.
+     */
+    UserManagerService(Context context, PackageManagerService pm,
+            Object installLock, Object packagesLock) {
+        this(context, pm, installLock, packagesLock,
+                Environment.getDataDirectory(),
+                new File(Environment.getDataDirectory(), "user"));
     }
 
-    void setInstaller(PackageManagerService pm, Installer installer) {
-        mInstaller = installer;
-        mPm = pm;
+    /**
+     * Available for testing purposes.
+     */
+    private UserManagerService(Context context, PackageManagerService pm,
+            Object installLock, Object packagesLock,
+            File dataDir, File baseUserPath) {
+        synchronized (UserManagerService.class) {
+            mContext = context;
+            mPm = pm;
+            mInstallLock = installLock;
+            mPackagesLock = packagesLock;
+            mUsersDir = new File(dataDir, USER_INFO_DIR);
+            mUsersDir.mkdirs();
+            // Make zeroth user directory, for services to migrate their files to that location
+            File userZeroDir = new File(mUsersDir, "0");
+            userZeroDir.mkdirs();
+            mBaseUserPath = baseUserPath;
+            FileUtils.setPermissions(mUsersDir.toString(),
+                    FileUtils.S_IRWXU|FileUtils.S_IRWXG
+                    |FileUtils.S_IROTH|FileUtils.S_IXOTH,
+                    -1, -1);
+            mUserListFile = new File(mUsersDir, USER_LIST_FILENAME);
+            readUserList();
+            sInstance = this;
+        }
     }
 
     @Override
     public List<UserInfo> getUsers() {
         checkManageUsersPermission("query users");
-        synchronized (mUsers) {
+        synchronized (mPackagesLock) {
             ArrayList<UserInfo> users = new ArrayList<UserInfo>(mUsers.size());
             for (int i = 0; i < mUsers.size(); i++) {
                 users.add(mUsers.valueAt(i));
@@ -136,7 +153,7 @@
     @Override
     public UserInfo getUserInfo(int userId) {
         checkManageUsersPermission("query user");
-        synchronized (mUsers) {
+        synchronized (mPackagesLock) {
             return getUserInfoLocked(userId);
         }
     }
@@ -149,7 +166,7 @@
     }
 
     public boolean exists(int userId) {
-        synchronized (mUsers) {
+        synchronized (mPackagesLock) {
             return ArrayUtils.contains(mUserIds, userId);
         }
     }
@@ -157,7 +174,7 @@
     @Override
     public void setUserName(int userId, String name) {
         checkManageUsersPermission("rename users");
-        synchronized (mUsers) {
+        synchronized (mPackagesLock) {
             UserInfo info = mUsers.get(userId);
             if (name != null && !name.equals(info.name)) {
                 info.name = name;
@@ -169,7 +186,7 @@
     @Override
     public ParcelFileDescriptor setUserIcon(int userId) {
         checkManageUsersPermission("update users");
-        synchronized (mUsers) {
+        synchronized (mPackagesLock) {
             UserInfo info = mUsers.get(userId);
             if (info == null) return null;
             ParcelFileDescriptor fd = updateIconBitmapLocked(info);
@@ -183,7 +200,7 @@
     @Override
     public void setGuestEnabled(boolean enable) {
         checkManageUsersPermission("enable guest users");
-        synchronized (mUsers) {
+        synchronized (mPackagesLock) {
             if (mGuestEnabled != enable) {
                 mGuestEnabled = enable;
                 // Erase any guest user that currently exists
@@ -206,7 +223,7 @@
 
     @Override
     public boolean isGuestEnabled() {
-        synchronized (mUsers) {
+        synchronized (mPackagesLock) {
             return mGuestEnabled;
         }
     }
@@ -262,13 +279,17 @@
      * @return the array of user ids.
      */
     int[] getUserIds() {
-        synchronized (mUsers) {
+        synchronized (mPackagesLock) {
             return mUserIds;
         }
     }
 
+    int[] getUserIdsLPr() {
+        return mUserIds;
+    }
+
     private void readUserList() {
-        synchronized (mUsers) {
+        synchronized (mPackagesLock) {
             readUserListLocked();
         }
     }
@@ -501,15 +522,15 @@
         int userId = getNextAvailableId();
         UserInfo userInfo = new UserInfo(userId, name, null, flags);
         File userPath = new File(mBaseUserPath, Integer.toString(userId));
-        if (!createPackageFolders(userId, userPath)) {
-            return null;
-        }
-        synchronized (mUsers) {
-            userInfo.serialNumber = mNextSerialNumber++;
-            mUsers.put(userId, userInfo);
-            writeUserListLocked();
-            writeUserLocked(userInfo);
-            updateUserIdsLocked();
+        synchronized (mInstallLock) {
+            synchronized (mPackagesLock) {
+                userInfo.serialNumber = mNextSerialNumber++;
+                mUsers.put(userId, userInfo);
+                writeUserListLocked();
+                writeUserLocked(userInfo);
+                updateUserIdsLocked();
+                mPm.createNewUserLILPw(userId, userPath);
+            }
         }
         if (userInfo != null) {
             Intent addedIntent = new Intent(Intent.ACTION_USER_ADDED);
@@ -528,24 +549,37 @@
      */
     public boolean removeUser(int userHandle) {
         checkManageUsersPermission("Only the system can remove users");
-        boolean result;
-        synchronized (mUsers) {
-            result = removeUserLocked(userHandle);
-        }
+        synchronized (mInstallLock) {
+            synchronized (mPackagesLock) {
+                final UserInfo user = mUsers.get(userHandle);
+                if (userHandle == 0 || user == null) {
+                    return false;
+                }
 
-        // Cleanup package manager settings
-        mPm.cleanUpUser(userHandle);
+                // Cleanup package manager settings
+                mPm.cleanUpUserLILPw(userHandle);
+
+                // Remove this user from the list
+                mUsers.remove(userHandle);
+                // Remove user file
+                AtomicFile userFile = new AtomicFile(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_USER_HANDLE, userHandle);
         mContext.sendBroadcast(addedIntent, android.Manifest.permission.MANAGE_USERS);
-        return result;
+        return true;
     }
 
     @Override
     public int getUserSerialNumber(int userHandle) {
-        synchronized (mUsers) {
+        synchronized (mPackagesLock) {
             if (!exists(userHandle)) return -1;
             return getUserInfoLocked(userHandle).serialNumber;
         }
@@ -553,7 +587,7 @@
 
     @Override
     public int getUserHandle(int userSerialNumber) {
-        synchronized (mUsers) {
+        synchronized (mPackagesLock) {
             for (int userId : mUserIds) {
                 if (getUserInfoLocked(userId).serialNumber == userSerialNumber) return userId;
             }
@@ -562,53 +596,6 @@
         }
     }
 
-    private boolean removeUserLocked(int userHandle) {
-        final UserInfo user = mUsers.get(userHandle);
-        if (userHandle == 0 || user == null) {
-            return false;
-        }
-
-        // Remove this user from the list
-        mUsers.remove(userHandle);
-        // Remove user file
-        AtomicFile userFile = new AtomicFile(new File(mUsersDir, userHandle + ".xml"));
-        userFile.delete();
-        // Update the user list
-        writeUserListLocked();
-        updateUserIdsLocked();
-
-        removePackageFolders(userHandle);
-        return true;
-    }
-
-    public void installPackageForAllUsers(String packageName, int uid) {
-        for (int userId : mUserIds) {
-            // Don't do it for the primary user, it will become recursive.
-            if (userId == 0)
-                continue;
-            mInstaller.createUserData(packageName, UserHandle.getUid(userId, uid),
-                    userId);
-        }
-    }
-
-    public void clearUserDataForAllUsers(String packageName) {
-        for (int userId : mUserIds) {
-            // Don't do it for the primary user, it will become recursive.
-            if (userId == 0)
-                continue;
-            mInstaller.clearUserData(packageName, userId);
-        }
-    }
-
-    public void removePackageForAllUsers(String packageName) {
-        for (int userId : mUserIds) {
-            // Don't do it for the primary user, it will become recursive.
-            if (userId == 0)
-                continue;
-            mInstaller.remove(packageName, userId);
-        }
-    }
-
     /**
      * Caches the list of user ids in an array, adjusting the array size when necessary.
      */
@@ -627,7 +614,7 @@
      * @return
      */
     private int getNextAvailableId() {
-        synchronized (mUsers) {
+        synchronized (mPackagesLock) {
             int i = 0;
             while (i < Integer.MAX_VALUE) {
                 if (mUsers.indexOfKey(i) < 0) {
@@ -638,26 +625,4 @@
             return i;
         }
     }
-
-    private boolean createPackageFolders(int id, File userPath) {
-        // mInstaller may not be available for unit-tests.
-        if (mInstaller == null) return true;
-
-        // Create the user path
-        userPath.mkdir();
-        FileUtils.setPermissions(userPath.toString(), FileUtils.S_IRWXU | FileUtils.S_IRWXG
-                | FileUtils.S_IXOTH, -1, -1);
-
-        mInstaller.cloneUserData(0, id, false);
-
-        return true;
-    }
-
-    boolean removePackageFolders(int id) {
-        // mInstaller may not be available for unit-tests.
-        if (mInstaller == null) return true;
-
-        mInstaller.removeUserDataDirs(id);
-        return true;
-    }
 }