Keep track of whether an app is installed for each user.

This add a new per-user state for an app, indicating whether
it is installed for that user.

All system apps are always installed for all users (we still
use disable to "uninstall" them).

Now when you call into the package manager to install an app,
it will only install the app for that user unless you supply
a flag saying to install for all users.  Only being installed
for the user is just the normal install state, but all other
users have marked in their state for that app that it is not
installed.

When you call the package manager APIs for information about
apps, uninstalled apps are treated as really being not visible
(somewhat more-so than disabled apps), unless you use the
GET_UNINSTALLED_PACKAGES flag.

If another user calls to install an app that is already installed,
just not for them, then the normal install process takes place
but in addition that user's installed state is toggled on.

The package manager will not send PACKAGE_ADDED, PACKAGE_REMOVED,
PACKAGE_REPLACED etc broadcasts to users who don't have a package
installed or not being involved in a change in the install state.
There are a few things that are not quite right with this -- for
example if you go through a full install (with a new apk) of an
app for one user who doesn't have it already installed, you will
still get the PACKAGED_REPLACED messages even though this is
technically the first install for your user.  I'm not sure how
much of an issue this is.

When you call the existing API to uninstall an app, this toggles
the installed state of the app for that user to be off.  Only if
that is the last user user that has the app uinstalled will it
actually be removed from the device.  Again there is a new flag
you can pass in to force the app to be uninstalled for all users.

Also fixed issues with cleaning external storage of apps, which
was not dealing with multiple users.  We now keep track of cleaning
each user for each package.

Change-Id: I00e66452b149defc08c5e0183fa673f532465ed5
diff --git a/api/current.txt b/api/current.txt
index d053109..bcb6fab 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -6293,6 +6293,7 @@
     field public static final int FLAG_EXTERNAL_STORAGE = 262144; // 0x40000
     field public static final int FLAG_FACTORY_TEST = 16; // 0x10
     field public static final int FLAG_HAS_CODE = 4; // 0x4
+    field public static final int FLAG_INSTALLED = 8388608; // 0x800000
     field public static final int FLAG_KILL_AFTER_RESTORE = 65536; // 0x10000
     field public static final int FLAG_LARGE_HEAP = 1048576; // 0x100000
     field public static final int FLAG_PERSISTENT = 8; // 0x8
@@ -6629,6 +6630,17 @@
     field public java.lang.String packageName;
   }
 
+  public class PackageUserState {
+    ctor public PackageUserState();
+    ctor public PackageUserState(android.content.pm.PackageUserState);
+    field public java.util.HashSet disabledComponents;
+    field public int enabled;
+    field public java.util.HashSet enabledComponents;
+    field public boolean installed;
+    field public boolean notLaunched;
+    field public boolean stopped;
+  }
+
   public class PathPermission extends android.os.PatternMatcher {
     ctor public PathPermission(java.lang.String, int, java.lang.String, java.lang.String);
     ctor public PathPermission(android.os.Parcel);
@@ -26928,6 +26940,7 @@
     method public synchronized int getDefaultFixedFontSize();
     method public synchronized int getDefaultFontSize();
     method public synchronized java.lang.String getDefaultTextEncodingName();
+    method public static java.lang.String getDefaultUserAgent(android.content.Context);
     method public android.webkit.WebSettings.ZoomDensity getDefaultZoom();
     method public boolean getDisplayZoomControls();
     method public synchronized boolean getDomStorageEnabled();
@@ -26958,7 +26971,6 @@
     method public synchronized boolean getUseWideViewPort();
     method public deprecated synchronized int getUserAgent();
     method public synchronized java.lang.String getUserAgentString();
-    method public static java.lang.String getDefaultUserAgent(android.content.Context);
     method public void setAllowContentAccess(boolean);
     method public void setAllowFileAccess(boolean);
     method public abstract void setAllowFileAccessFromFileURLs(boolean);
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index a79eb14..22fc1ad 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -393,7 +393,7 @@
     private void runStartService() throws Exception {
         Intent intent = makeIntent();
         System.out.println("Starting service: " + intent);
-        ComponentName cn = mAm.startService(null, intent, intent.getType());
+        ComponentName cn = mAm.startService(null, intent, intent.getType(), 0);
         if (cn == null) {
             System.err.println("Error: Not found; no service started.");
         }
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index b34fd05..32865a4 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -776,7 +776,7 @@
     }
 
     private void runInstall() {
-        int installFlags = 0;
+        int installFlags = PackageManager.INSTALL_ALL_USERS;
         String installerPackageName = null;
 
         String opt;
@@ -811,6 +811,8 @@
             } else if (opt.equals("-f")) {
                 // Override if -s option is specified.
                 installFlags |= PackageManager.INSTALL_INTERNAL;
+            } else if (opt.equals("-d")) {
+                installFlags |= PackageManager.INSTALL_ALLOW_DOWNGRADE;
             } else if (opt.equals("--algo")) {
                 algo = nextOptionData();
                 if (algo == null) {
@@ -1105,7 +1107,7 @@
 
         String opt = nextOption();
         if (opt != null && opt.equals("-k")) {
-            unInstallFlags = PackageManager.DONT_DELETE_DATA;
+            unInstallFlags = PackageManager.DELETE_KEEP_DATA;
         }
 
         String pkg = nextArg();
@@ -1525,6 +1527,7 @@
         System.err.println("    -i: specify the installer package name.");
         System.err.println("    -s: install package on sdcard.");
         System.err.println("    -f: install package on internal flash.");
+        System.err.println("    -d: allow version code downgrade.");
         System.err.println("");
         System.err.println("pm uninstall: removes a package from the system. Options:");
         System.err.println("    -k: keep the data and cache directories around after package removal.");
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 3197a63..adc9434 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -697,7 +697,8 @@
             IApplicationThread app = ApplicationThreadNative.asInterface(b);
             Intent service = Intent.CREATOR.createFromParcel(data);
             String resolvedType = data.readString();
-            ComponentName cn = startService(app, service, resolvedType);
+            int userId = data.readInt();
+            ComponentName cn = startService(app, service, resolvedType, userId);
             reply.writeNoException();
             ComponentName.writeToParcel(cn, reply);
             return true;
@@ -709,7 +710,8 @@
             IApplicationThread app = ApplicationThreadNative.asInterface(b);
             Intent service = Intent.CREATOR.createFromParcel(data);
             String resolvedType = data.readString();
-            int res = stopService(app, service, resolvedType);
+            int userId = data.readInt();
+            int res = stopService(app, service, resolvedType, userId);
             reply.writeNoException();
             reply.writeInt(res);
             return true;
@@ -2523,7 +2525,7 @@
     }
     
     public ComponentName startService(IApplicationThread caller, Intent service,
-            String resolvedType) throws RemoteException
+            String resolvedType, int userId) throws RemoteException
     {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
@@ -2531,6 +2533,7 @@
         data.writeStrongBinder(caller != null ? caller.asBinder() : null);
         service.writeToParcel(data, 0);
         data.writeString(resolvedType);
+        data.writeInt(userId);
         mRemote.transact(START_SERVICE_TRANSACTION, data, reply, 0);
         reply.readException();
         ComponentName res = ComponentName.readFromParcel(reply);
@@ -2539,7 +2542,7 @@
         return res;
     }
     public int stopService(IApplicationThread caller, Intent service,
-            String resolvedType) throws RemoteException
+            String resolvedType, int userId) throws RemoteException
     {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
@@ -2547,6 +2550,7 @@
         data.writeStrongBinder(caller != null ? caller.asBinder() : null);
         service.writeToParcel(data, 0);
         data.writeString(resolvedType);
+        data.writeInt(userId);
         mRemote.transact(STOP_SERVICE_TRANSACTION, data, reply, 0);
         reply.readException();
         int res = reply.readInt();
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index f3f75ce..0f10c4f 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -45,6 +45,7 @@
 import android.content.pm.UserInfo;
 import android.content.pm.VerificationParams;
 import android.content.pm.VerifierDeviceIdentity;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
 import android.graphics.drawable.Drawable;
@@ -997,6 +998,21 @@
     }
 
     @Override
+    public int installExistingPackage(String packageName)
+            throws NameNotFoundException {
+        try {
+            int res = mPM.installExistingPackage(packageName);
+            if (res == INSTALL_FAILED_INVALID_URI) {
+                throw new NameNotFoundException("Package " + packageName + " doesn't exist");
+            }
+            return res;
+        } catch (RemoteException e) {
+            // Should never happen!
+            throw new NameNotFoundException("Package " + packageName + " doesn't exist");
+        }
+    }
+
+    @Override
     public void verifyPendingInstall(int id, int response) {
         try {
             mPM.verifyPendingInstall(id, response);
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 0ae4d06..32086d7 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1220,11 +1220,21 @@
 
     @Override
     public ComponentName startService(Intent service) {
+        return startServiceAsUser(service, Process.myUserHandle());
+    }
+
+    @Override
+    public boolean stopService(Intent service) {
+        return stopServiceAsUser(service, Process.myUserHandle());
+    }
+
+    @Override
+    public ComponentName startServiceAsUser(Intent service, UserHandle user) {
         try {
             service.setAllowFds(false);
             ComponentName cn = ActivityManagerNative.getDefault().startService(
                 mMainThread.getApplicationThread(), service,
-                service.resolveTypeIfNeeded(getContentResolver()));
+                service.resolveTypeIfNeeded(getContentResolver()), user.getIdentifier());
             if (cn != null && cn.getPackageName().equals("!")) {
                 throw new SecurityException(
                         "Not allowed to start service " + service
@@ -1237,12 +1247,12 @@
     }
 
     @Override
-    public boolean stopService(Intent service) {
+    public boolean stopServiceAsUser(Intent service, UserHandle user) {
         try {
             service.setAllowFds(false);
             int res = ActivityManagerNative.getDefault().stopService(
                 mMainThread.getApplicationThread(), service,
-                service.resolveTypeIfNeeded(getContentResolver()));
+                service.resolveTypeIfNeeded(getContentResolver()), user.getIdentifier());
             if (res < 0) {
                 throw new SecurityException(
                         "Not allowed to stop service " + service);
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index a6d1995..c3e911e 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -133,9 +133,9 @@
     public PendingIntent getRunningServiceControlPanel(ComponentName service)
             throws RemoteException;
     public ComponentName startService(IApplicationThread caller, Intent service,
-            String resolvedType) throws RemoteException;
+            String resolvedType, int userId) throws RemoteException;
     public int stopService(IApplicationThread caller, Intent service,
-            String resolvedType) throws RemoteException;
+            String resolvedType, int userId) throws RemoteException;
     public boolean stopServiceToken(ComponentName className, IBinder token,
             int startId) throws RemoteException;
     public void setServiceForeground(ComponentName className, IBinder token,
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 1460bf5..dc6d93f 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1414,6 +1414,16 @@
     public abstract boolean stopService(Intent service);
 
     /**
+     * @hide like {@link #startService(Intent)} but for a specific user.
+     */
+    public abstract ComponentName startServiceAsUser(Intent service, UserHandle user);
+
+    /**
+     * @hide like {@link #stopService(Intent)} but for a specific user.
+     */
+    public abstract boolean stopServiceAsUser(Intent service, UserHandle user);
+    
+    /**
      * Connect to an application service, creating it if needed.  This defines
      * a dependency between your application and the service.  The given
      * <var>conn</var> will receive the service object when it is created and be
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 3a13725..4bbe44e 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -410,6 +410,18 @@
         return mBase.stopService(name);
     }
 
+    /** @hide */
+    @Override
+    public ComponentName startServiceAsUser(Intent service, UserHandle user) {
+        return mBase.startServiceAsUser(service, user);
+    }
+
+    /** @hide */
+    @Override
+    public boolean stopServiceAsUser(Intent name, UserHandle user) {
+        return mBase.stopServiceAsUser(name, user);
+    }
+
     @Override
     public boolean bindService(Intent service, ServiceConnection conn,
             int flags) {
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index cbabc7c..1a82d58 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -302,6 +302,12 @@
     public static final int FLAG_SUPPORTS_RTL = 1<<22;
 
     /**
+     * Value for {@link #flags}: true if the application is currently
+     * installed for the calling user.
+     */
+    public static final int FLAG_INSTALLED = 1<<23;
+
+    /**
      * Value for {@link #flags}: Set to true if the application has been
      * installed using the forward lock option.
      *
@@ -334,7 +340,8 @@
      * {@link #FLAG_SUPPORTS_NORMAL_SCREENS},
      * {@link #FLAG_SUPPORTS_LARGE_SCREENS}, {@link #FLAG_SUPPORTS_XLARGE_SCREENS},
      * {@link #FLAG_RESIZEABLE_FOR_SCREENS},
-     * {@link #FLAG_SUPPORTS_SCREEN_DENSITIES}, {@link #FLAG_VM_SAFE_MODE}
+     * {@link #FLAG_SUPPORTS_SCREEN_DENSITIES}, {@link #FLAG_VM_SAFE_MODE},
+     * {@link #FLAG_INSTALLED}.
      */
     public int flags = 0;
     
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 0be8b83..0e1fe3e 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -32,6 +32,7 @@
 import android.content.pm.InstrumentationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.ManifestDigest;
+import android.content.pm.PackageCleanItem;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.ProviderInfo;
 import android.content.pm.PermissionGroupInfo;
@@ -351,7 +352,7 @@
      */
     void updateExternalMediaStatus(boolean mounted, boolean reportStatus);
 
-    String nextPackageToClean(String lastPackage);
+    PackageCleanItem nextPackageToClean(in PackageCleanItem lastPackage);
 
     void movePackage(String packageName, IPackageMoveObserver observer, int flags);
     
@@ -369,6 +370,8 @@
             in VerificationParams verificationParams,
             in ContainerEncryptionParams encryptionParams);
 
+    int installExistingPackage(String packageName);
+
     void verifyPendingInstall(int id, int verificationCode);
     void extendVerificationTimeout(int id, int verificationCodeAtTimeout, long millisecondsToDelay);
 
diff --git a/core/java/android/content/pm/ManifestDigest.java b/core/java/android/content/pm/ManifestDigest.java
index f5e72e0..75505bc 100644
--- a/core/java/android/content/pm/ManifestDigest.java
+++ b/core/java/android/content/pm/ManifestDigest.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package android.content.pm;
 
 import android.os.Parcel;
diff --git a/core/java/android/content/pm/PackageCleanItem.aidl b/core/java/android/content/pm/PackageCleanItem.aidl
new file mode 100644
index 0000000..9bb203e
--- /dev/null
+++ b/core/java/android/content/pm/PackageCleanItem.aidl
@@ -0,0 +1,18 @@
+/* Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.content.pm;
+
+parcelable PackageCleanItem;
diff --git a/core/java/android/content/pm/PackageCleanItem.java b/core/java/android/content/pm/PackageCleanItem.java
new file mode 100644
index 0000000..eea3b9c
--- /dev/null
+++ b/core/java/android/content/pm/PackageCleanItem.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/** @hide */
+public class PackageCleanItem {
+    public final String packageName;
+    public final boolean andCode;
+
+    public PackageCleanItem(String packageName, boolean andCode) {
+        this.packageName = packageName;
+        this.andCode = andCode;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        try {
+            if (obj != null) {
+                PackageCleanItem other = (PackageCleanItem)obj;
+                return packageName.equals(other.packageName) && andCode == other.andCode;
+            }
+        } catch (ClassCastException e) {
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = 17;
+        result = 31 * result + packageName.hashCode();
+        result = 31 * result + (andCode ? 1 : 0);
+        return result;
+    }
+
+    public int describeContents() {
+        return 0;
+    }
+
+    public void writeToParcel(Parcel dest, int parcelableFlags) {
+        dest.writeString(packageName);
+        dest.writeInt(andCode ? 1 : 0);
+    }
+
+    public static final Parcelable.Creator<PackageCleanItem> CREATOR
+            = new Parcelable.Creator<PackageCleanItem>() {
+        public PackageCleanItem createFromParcel(Parcel source) {
+            return new PackageCleanItem(source);
+        }
+
+        public PackageCleanItem[] newArray(int size) {
+            return new PackageCleanItem[size];
+        }
+    };
+
+    private PackageCleanItem(Parcel source) {
+        packageName = source.readString();
+        andCode = source.readInt() != 0;
+    }
+}
diff --git a/core/java/android/content/pm/PackageInfoLite.java b/core/java/android/content/pm/PackageInfoLite.java
index 9625944..a1566da 100644
--- a/core/java/android/content/pm/PackageInfoLite.java
+++ b/core/java/android/content/pm/PackageInfoLite.java
@@ -32,6 +32,11 @@
     public String packageName;
 
     /**
+     * The android:versionCode of the package.
+     */
+    public int versionCode;
+
+    /**
      * Specifies the recommended install location. Can be one of
      * {@link #PackageHelper.RECOMMEND_INSTALL_INTERNAL} to install on internal storage
      * {@link #PackageHelper.RECOMMEND_INSTALL_EXTERNAL} to install on external media
@@ -58,6 +63,7 @@
 
     public void writeToParcel(Parcel dest, int parcelableFlags) {
         dest.writeString(packageName);
+        dest.writeInt(versionCode);
         dest.writeInt(recommendedInstallLocation);
         dest.writeInt(installLocation);
 
@@ -82,6 +88,7 @@
 
     private PackageInfoLite(Parcel source) {
         packageName = source.readString();
+        versionCode = source.readInt();
         recommendedInstallLocation = source.readInt();
         installLocation = source.readInt();
 
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index b3e98e7..0d99d3f 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -310,6 +310,23 @@
     public static final int INSTALL_FROM_ADB = 0x00000020;
 
     /**
+     * Flag parameter for {@link #installPackage} to indicate that this install
+     * should immediately be visible to all users.
+     *
+     * @hide
+     */
+    public static final int INSTALL_ALL_USERS = 0x00000040;
+
+    /**
+     * Flag parameter for {@link #installPackage} to indicate that it is okay
+     * to install an update to an app where the newly installed app has a lower
+     * version code than the currently installed app.
+     *
+     * @hide
+     */
+    public static final int INSTALL_ALLOW_DOWNGRADE = 0x00000080;
+
+    /**
      * Flag parameter for
      * {@link #setComponentEnabledSetting(android.content.ComponentName, int, int)} to indicate
      * that you don't want to kill the app containing the component.  Be careful when you set this
@@ -529,6 +546,14 @@
     public static final int INSTALL_FAILED_UID_CHANGED = -24;
 
     /**
+     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
+     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
+     * the new package has an older version code than the currently installed package.
+     * @hide
+     */
+    public static final int INSTALL_FAILED_VERSION_DOWNGRADE = -25;
+
+    /**
      * Installation parse return code: this is passed to the {@link IPackageInstallObserver} by
      * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
      * if the parser was given a path that is not a file, or does not end with the expected
@@ -625,7 +650,15 @@
      *
      * @hide
      */
-    public static final int DONT_DELETE_DATA = 0x00000001;
+    public static final int DELETE_KEEP_DATA = 0x00000001;
+
+    /**
+     * Flag parameter for {@link #deletePackage} to indicate that you want the
+     * package deleted for all users.
+     *
+     * @hide
+     */
+    public static final int DELETE_ALL_USERS = 0x00000002;
 
     /**
      * Return code for when package deletion succeeds. This is passed to the
@@ -2175,8 +2208,8 @@
         if ((flags & GET_SIGNATURES) != 0) {
             packageParser.collectCertificates(pkg, 0);
         }
-        return PackageParser.generatePackageInfo(pkg, null, flags, 0, 0, null, false,
-                COMPONENT_ENABLED_STATE_DEFAULT);
+        PackageUserState state = new PackageUserState();
+        return PackageParser.generatePackageInfo(pkg, null, flags, 0, 0, null, state);
     }
 
     /**
@@ -2267,6 +2300,14 @@
             ContainerEncryptionParams encryptionParams);
 
     /**
+     * If there is already an application with the given package name installed
+     * on the system for other users, also install it for the calling user.
+     * @hide
+     */
+    public abstract int installExistingPackage(String packageName)
+            throws NameNotFoundException;
+
+    /**
      * Allows a package listening to the
      * {@link Intent#ACTION_PACKAGE_NEEDS_VERIFICATION package verification
      * broadcast} to respond to the package manager. The response must include
@@ -2337,7 +2378,8 @@
      * @param observer An observer callback to get notified when the package deletion is
      * complete. {@link android.content.pm.IPackageDeleteObserver#packageDeleted(boolean)} will be
      * called when that happens.  observer may be null to indicate that no callback is desired.
-     * @param flags - possible values: {@link #DONT_DELETE_DATA}
+     * @param flags - possible values: {@link #DELETE_KEEP_DATA},
+     * {@link #DELETE_ALL_USERS}.
      *
      * @hide
      */
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index ac75040..237f5c5 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -203,11 +203,14 @@
      */
     public static class PackageLite {
         public final String packageName;
+        public final int versionCode;
         public final int installLocation;
         public final VerifierInfo[] verifiers;
 
-        public PackageLite(String packageName, int installLocation, List<VerifierInfo> verifiers) {
+        public PackageLite(String packageName, int versionCode,
+                int installLocation, List<VerifierInfo> verifiers) {
             this.packageName = packageName;
+            this.versionCode = versionCode;
             this.installLocation = installLocation;
             this.verifiers = verifiers.toArray(new VerifierInfo[verifiers.size()]);
         }
@@ -243,14 +246,15 @@
         return name.endsWith(".apk");
     }
 
+    /*
     public static PackageInfo generatePackageInfo(PackageParser.Package p,
             int gids[], int flags, long firstInstallTime, long lastUpdateTime,
             HashSet<String> grantedPermissions) {
-
+        PackageUserState state = new PackageUserState();
         return generatePackageInfo(p, gids, flags, firstInstallTime, lastUpdateTime,
-                grantedPermissions, false, PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
-                UserHandle.getCallingUserId());
+                grantedPermissions, state, UserHandle.getCallingUserId());
     }
+    */
 
     /**
      * Generate and return the {@link PackageInfo} for a parsed package.
@@ -260,23 +264,30 @@
      */
     public static PackageInfo generatePackageInfo(PackageParser.Package p,
             int gids[], int flags, long firstInstallTime, long lastUpdateTime,
-            HashSet<String> grantedPermissions, boolean stopped, int enabledState) {
+            HashSet<String> grantedPermissions, PackageUserState state) {
 
         return generatePackageInfo(p, gids, flags, firstInstallTime, lastUpdateTime,
-                grantedPermissions, stopped, enabledState, UserHandle.getCallingUserId());
+                grantedPermissions, state, UserHandle.getCallingUserId());
+    }
+
+    private static boolean checkUseInstalled(int flags, PackageUserState state) {
+        return state.installed || ((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0);
     }
 
     public static PackageInfo generatePackageInfo(PackageParser.Package p,
             int gids[], int flags, long firstInstallTime, long lastUpdateTime,
-            HashSet<String> grantedPermissions, boolean stopped, int enabledState, int userId) {
+            HashSet<String> grantedPermissions, PackageUserState state, int userId) {
 
+        if (!checkUseInstalled(flags, state)) {
+            return null;
+        }
         PackageInfo pi = new PackageInfo();
         pi.packageName = p.packageName;
         pi.versionCode = p.mVersionCode;
         pi.versionName = p.mVersionName;
         pi.sharedUserId = p.mSharedUserId;
         pi.sharedUserLabel = p.mSharedUserLabel;
-        pi.applicationInfo = generateApplicationInfo(p, flags, stopped, enabledState, userId);
+        pi.applicationInfo = generateApplicationInfo(p, flags, state, userId);
         pi.installLocation = p.installLocation;
         pi.firstInstallTime = firstInstallTime;
         pi.lastUpdateTime = lastUpdateTime;
@@ -312,7 +323,7 @@
                     if (activity.info.enabled
                         || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
                         pi.activities[j++] = generateActivityInfo(p.activities.get(i), flags,
-                                stopped, enabledState, userId);
+                                state, userId);
                     }
                 }
             }
@@ -334,7 +345,7 @@
                     if (activity.info.enabled
                         || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
                         pi.receivers[j++] = generateActivityInfo(p.receivers.get(i), flags,
-                                stopped, enabledState, userId);
+                                state, userId);
                     }
                 }
             }
@@ -355,8 +366,8 @@
                     final Service service = p.services.get(i);
                     if (service.info.enabled
                         || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
-                        pi.services[j++] = generateServiceInfo(p.services.get(i), flags, stopped,
-                                enabledState, userId);
+                        pi.services[j++] = generateServiceInfo(p.services.get(i), flags,
+                                state, userId);
                     }
                 }
             }
@@ -377,8 +388,8 @@
                     final Provider provider = p.providers.get(i);
                     if (provider.info.enabled
                         || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
-                        pi.providers[j++] = generateProviderInfo(p.providers.get(i), flags, stopped,
-                                enabledState, userId);
+                        pi.providers[j++] = generateProviderInfo(p.providers.get(i), flags,
+                                state, userId);
                     }
                 }
             }
@@ -840,11 +851,19 @@
             return null;
         }
         int installLocation = PARSE_DEFAULT_INSTALL_LOCATION;
+        int versionCode = 0;
+        int numFound = 0;
         for (int i = 0; i < attrs.getAttributeCount(); i++) {
             String attr = attrs.getAttributeName(i);
             if (attr.equals("installLocation")) {
                 installLocation = attrs.getAttributeIntValue(i,
                         PARSE_DEFAULT_INSTALL_LOCATION);
+                numFound++;
+            } else if (attr.equals("versionCode")) {
+                versionCode = attrs.getAttributeIntValue(i, 0);
+                numFound++;
+            }
+            if (numFound >= 2) {
                 break;
             }
         }
@@ -867,7 +886,7 @@
             }
         }
 
-        return new PackageLite(pkgName.intern(), installLocation, verifiers);
+        return new PackageLite(pkgName.intern(), versionCode, installLocation, verifiers);
     }
 
     /**
@@ -3458,13 +3477,25 @@
         }
     }
 
-    private static boolean copyNeeded(int flags, Package p, int enabledState, Bundle metaData) {
-        if (enabledState != PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
-            boolean enabled = enabledState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
+    private static boolean copyNeeded(int flags, Package p,
+            PackageUserState state, Bundle metaData, int userId) {
+        if (userId != 0) {
+            // We always need to copy for other users, since we need
+            // to fix up the uid.
+            return true;
+        }
+        if (state.enabled != PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
+            boolean enabled = state.enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
             if (p.applicationInfo.enabled != enabled) {
                 return true;
             }
         }
+        if (!state.installed) {
+            return true;
+        }
+        if (state.stopped) {
+            return true;
+        }
         if ((flags & PackageManager.GET_META_DATA) != 0
                 && (metaData != null || p.mAppMetaData != null)) {
             return true;
@@ -3476,32 +3507,34 @@
         return false;
     }
 
-    public static ApplicationInfo generateApplicationInfo(Package p, int flags, boolean stopped,
-            int enabledState) {
-        return generateApplicationInfo(p, flags, stopped, enabledState, UserHandle.getCallingUserId());
+    public static ApplicationInfo generateApplicationInfo(Package p, int flags,
+            PackageUserState state) {
+        return generateApplicationInfo(p, flags, state, UserHandle.getCallingUserId());
     }
 
     public static ApplicationInfo generateApplicationInfo(Package p, int flags,
-            boolean stopped, int enabledState, int userId) {
+            PackageUserState state, int userId) {
         if (p == null) return null;
-        if (!copyNeeded(flags, p, enabledState, null) && userId == 0) {
+        if (!checkUseInstalled(flags, state)) {
+            return null;
+        }
+        if (!copyNeeded(flags, p, state, null, userId)) {
             // CompatibilityMode is global state. It's safe to modify the instance
             // of the package.
             if (!sCompatibilityModeEnabled) {
                 p.applicationInfo.disableCompatibilityMode();
             }
-            if (stopped) {
-                p.applicationInfo.flags |= ApplicationInfo.FLAG_STOPPED;
-            } else {
-                p.applicationInfo.flags &= ~ApplicationInfo.FLAG_STOPPED;
-            }
-            if (enabledState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
+            // Make sure we report as installed.  Also safe to do, since the
+            // default state should be installed (we will always copy if we
+            // need to report it is not installed).
+            p.applicationInfo.flags |= ApplicationInfo.FLAG_INSTALLED;
+            if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
                 p.applicationInfo.enabled = true;
-            } else if (enabledState == PackageManager.COMPONENT_ENABLED_STATE_DISABLED
-                    || enabledState == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) {
+            } else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED
+                    || state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) {
                 p.applicationInfo.enabled = false;
             }
-            p.applicationInfo.enabledSetting = enabledState;
+            p.applicationInfo.enabledSetting = state.enabled;
             return p.applicationInfo;
         }
 
@@ -3520,18 +3553,23 @@
         if (!sCompatibilityModeEnabled) {
             ai.disableCompatibilityMode();
         }
-        if (stopped) {
+        if (state.stopped) {
             ai.flags |= ApplicationInfo.FLAG_STOPPED;
         } else {
             ai.flags &= ~ApplicationInfo.FLAG_STOPPED;
         }
-        if (enabledState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
+        if (state.installed) {
+            ai.flags |= ApplicationInfo.FLAG_INSTALLED;
+        } else {
+            ai.flags &= ~ApplicationInfo.FLAG_INSTALLED;
+        }
+        if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
             ai.enabled = true;
-        } else if (enabledState == PackageManager.COMPONENT_ENABLED_STATE_DISABLED
-                || enabledState == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) {
+        } else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED
+                || state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) {
             ai.enabled = false;
         }
-        ai.enabledSetting = enabledState;
+        ai.enabledSetting = state.enabled;
         return ai;
     }
 
@@ -3578,16 +3616,19 @@
         }
     }
 
-    public static final ActivityInfo generateActivityInfo(Activity a, int flags, boolean stopped,
-            int enabledState, int userId) {
+    public static final ActivityInfo generateActivityInfo(Activity a, int flags,
+            PackageUserState state, int userId) {
         if (a == null) return null;
-        if (!copyNeeded(flags, a.owner, enabledState, a.metaData) && userId == 0) {
+        if (!checkUseInstalled(flags, state)) {
+            return null;
+        }
+        if (!copyNeeded(flags, a.owner, state, a.metaData, userId)) {
             return a.info;
         }
         // Make shallow copies so we can store the metadata safely
         ActivityInfo ai = new ActivityInfo(a.info);
         ai.metaData = a.metaData;
-        ai.applicationInfo = generateApplicationInfo(a.owner, flags, stopped, enabledState, userId);
+        ai.applicationInfo = generateApplicationInfo(a.owner, flags, state, userId);
         return ai;
     }
 
@@ -3612,17 +3653,19 @@
         }
     }
 
-    public static final ServiceInfo generateServiceInfo(Service s, int flags, boolean stopped,
-            int enabledState, int userId) {
+    public static final ServiceInfo generateServiceInfo(Service s, int flags,
+            PackageUserState state, int userId) {
         if (s == null) return null;
-        if (!copyNeeded(flags, s.owner, enabledState, s.metaData)
-                && userId == UserHandle.getUserId(s.info.applicationInfo.uid)) {
+        if (!checkUseInstalled(flags, state)) {
+            return null;
+        }
+        if (!copyNeeded(flags, s.owner, state, s.metaData, userId)) {
             return s.info;
         }
         // Make shallow copies so we can store the metadata safely
         ServiceInfo si = new ServiceInfo(s.info);
         si.metaData = s.metaData;
-        si.applicationInfo = generateApplicationInfo(s.owner, flags, stopped, enabledState, userId);
+        si.applicationInfo = generateApplicationInfo(s.owner, flags, state, userId);
         return si;
     }
 
@@ -3655,13 +3698,15 @@
         }
     }
 
-    public static final ProviderInfo generateProviderInfo(Provider p, int flags, boolean stopped,
-            int enabledState, int userId) {
+    public static final ProviderInfo generateProviderInfo(Provider p, int flags,
+            PackageUserState state, int userId) {
         if (p == null) return null;
-        if (!copyNeeded(flags, p.owner, enabledState, p.metaData)
+        if (!checkUseInstalled(flags, state)) {
+            return null;
+        }
+        if (!copyNeeded(flags, p.owner, state, p.metaData, userId)
                 && ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) != 0
-                        || p.info.uriPermissionPatterns == null)
-                && userId == 0) {
+                        || p.info.uriPermissionPatterns == null)) {
             return p.info;
         }
         // Make shallow copies so we can store the metadata safely
@@ -3670,7 +3715,7 @@
         if ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) == 0) {
             pi.uriPermissionPatterns = null;
         }
-        pi.applicationInfo = generateApplicationInfo(p.owner, flags, stopped, enabledState, userId);
+        pi.applicationInfo = generateApplicationInfo(p.owner, flags, state, userId);
         return pi;
     }
 
diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java
new file mode 100644
index 0000000..1a71bfb
--- /dev/null
+++ b/core/java/android/content/pm/PackageUserState.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
+
+import java.util.HashSet;
+
+/**
+ * Per-user state information about a package.
+ */
+public class PackageUserState {
+    public boolean stopped;
+    public boolean notLaunched;
+    public boolean installed;
+    public int enabled;
+
+    public HashSet<String> disabledComponents;
+    public HashSet<String> enabledComponents;
+
+    public PackageUserState() {
+        installed = true;
+        enabled = COMPONENT_ENABLED_STATE_DEFAULT;
+    }
+
+    public PackageUserState(PackageUserState o) {
+        installed = o.installed;
+        stopped = o.stopped;
+        notLaunched = o.notLaunched;
+        enabled = o.enabled;
+        disabledComponents = o.disabledComponents != null
+                ? new HashSet<String>(o.disabledComponents) : null;
+        enabledComponents = o.enabledComponents != null
+                ? new HashSet<String>(o.enabledComponents) : null;
+    }
+}
\ No newline at end of file
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index 0843d85..d33bd80 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -28,6 +28,9 @@
     /** @hide A user id to indicate all users on the device */
     public static final int USER_ALL = -1;
 
+    /** @hide A user handle to indicate all users on the device */
+    public static final UserHandle ALL = new UserHandle(USER_ALL);
+
     /** @hide A user id to indicate the currently active user */
     public static final int USER_CURRENT = -2;
 
diff --git a/core/java/com/android/internal/content/PackageHelper.java b/core/java/com/android/internal/content/PackageHelper.java
index 246b0c9..c5e7d9d 100644
--- a/core/java/com/android/internal/content/PackageHelper.java
+++ b/core/java/com/android/internal/content/PackageHelper.java
@@ -49,6 +49,7 @@
     public static final int RECOMMEND_FAILED_ALREADY_EXISTS = -4;
     public static final int RECOMMEND_MEDIA_UNAVAILABLE = -5;
     public static final int RECOMMEND_FAILED_INVALID_URI = -6;
+    public static final int RECOMMEND_FAILED_VERSION_DOWNGRADE = -7;
 
     private static final boolean localLOGV = true;
     private static final String TAG = "PackageHelper";
diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
index 6e1b9d6..a1fd14e 100755
--- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
+++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
@@ -864,7 +864,7 @@
 
     public void deleteFromRawResource(int iFlags, int dFlags) {
         InstallParams ip = sampleInstallFromRawResource(iFlags, false);
-        boolean retainData = ((dFlags & PackageManager.DONT_DELETE_DATA) != 0);
+        boolean retainData = ((dFlags & PackageManager.DELETE_KEEP_DATA) != 0);
         GenericReceiver receiver = new DeleteReceiver(ip.pkg.packageName);
         DeleteObserver observer = new DeleteObserver();
         try {
@@ -914,12 +914,12 @@
 
     @LargeTest
     public void testDeleteNormalInternalRetainData() {
-        deleteFromRawResource(0, PackageManager.DONT_DELETE_DATA);
+        deleteFromRawResource(0, PackageManager.DELETE_KEEP_DATA);
     }
 
     @LargeTest
     public void testDeleteFwdLockedInternalRetainData() {
-        deleteFromRawResource(PackageManager.INSTALL_FORWARD_LOCK, PackageManager.DONT_DELETE_DATA);
+        deleteFromRawResource(PackageManager.INSTALL_FORWARD_LOCK, PackageManager.DELETE_KEEP_DATA);
     }
 
     @LargeTest
@@ -929,7 +929,7 @@
             return;
         }
 
-        deleteFromRawResource(PackageManager.INSTALL_EXTERNAL, PackageManager.DONT_DELETE_DATA);
+        deleteFromRawResource(PackageManager.INSTALL_EXTERNAL, PackageManager.DELETE_KEEP_DATA);
     }
 
     /* sdcard mount/unmount tests ******/
@@ -1656,7 +1656,7 @@
                     false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
             // Delete the package now retaining data.
             GenericReceiver receiver = new DeleteReceiver(ip.pkg.packageName);
-            invokeDeletePackage(ip.pkg.packageName, PackageManager.DONT_DELETE_DATA, receiver);
+            invokeDeletePackage(ip.pkg.packageName, PackageManager.DELETE_KEEP_DATA, receiver);
             assertTrue(invokeMovePackageFail(ip.pkg.packageName, moveFlags, result));
         } catch (Exception e) {
             failStr(e);
@@ -2532,7 +2532,7 @@
             GenericReceiver receiver = new DeleteReceiver(ip.pkg.packageName);
 
             try {
-                invokeDeletePackage(ip.pkg.packageName, PackageManager.DONT_DELETE_DATA, receiver);
+                invokeDeletePackage(ip.pkg.packageName, PackageManager.DELETE_KEEP_DATA, receiver);
             } catch (Exception e) {
                 failStr(e);
             }
diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
index a28b8a4..b36bd55 100644
--- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
+++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
@@ -26,6 +26,7 @@
 import android.content.pm.ContainerEncryptionParams;
 import android.content.pm.IPackageManager;
 import android.content.pm.LimitedLengthInputStream;
+import android.content.pm.PackageCleanItem;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageInfoLite;
 import android.content.pm.PackageManager;
@@ -181,6 +182,7 @@
             }
 
             ret.packageName = pkg.packageName;
+            ret.versionCode = pkg.versionCode;
             ret.installLocation = pkg.installLocation;
             ret.verifiers = pkg.verifiers;
 
@@ -268,12 +270,14 @@
         if (PackageManager.ACTION_CLEAN_EXTERNAL_STORAGE.equals(intent.getAction())) {
             IPackageManager pm = IPackageManager.Stub.asInterface(
                     ServiceManager.getService("package"));
-            String pkg = null;
+            PackageCleanItem pkg = null;
             try {
                 while ((pkg=pm.nextPackageToClean(pkg)) != null) {
-                    eraseFiles(Environment.getExternalStorageAppDataDirectory(pkg));
-                    eraseFiles(Environment.getExternalStorageAppMediaDirectory(pkg));
-                    eraseFiles(Environment.getExternalStorageAppObbDirectory(pkg));
+                    eraseFiles(Environment.getExternalStorageAppDataDirectory(pkg.packageName));
+                    eraseFiles(Environment.getExternalStorageAppMediaDirectory(pkg.packageName));
+                    if (pkg.andCode) {
+                        eraseFiles(Environment.getExternalStorageAppObbDirectory(pkg.packageName));
+                    }
                 }
             } catch (RemoteException e) {
             }
diff --git a/services/java/com/android/server/am/ActiveServices.java b/services/java/com/android/server/am/ActiveServices.java
index e222936..e6bcaa1 100644
--- a/services/java/com/android/server/am/ActiveServices.java
+++ b/services/java/com/android/server/am/ActiveServices.java
@@ -210,7 +210,7 @@
 
     ComponentName startServiceLocked(IApplicationThread caller,
             Intent service, String resolvedType,
-            int callingPid, int callingUid) {
+            int callingPid, int callingUid, int userId) {
         if (DEBUG_SERVICE) Slog.v(TAG, "startService: " + service
                 + " type=" + resolvedType + " args=" + service.getExtras());
 
@@ -226,7 +226,7 @@
 
         ServiceLookupResult res =
             retrieveServiceLocked(service, resolvedType,
-                    callingPid, callingUid, UserHandle.getUserId(callingUid), true);
+                    callingPid, callingUid, userId, true);
         if (res == null) {
             return null;
         }
@@ -264,7 +264,7 @@
     }
 
     int stopServiceLocked(IApplicationThread caller, Intent service,
-            String resolvedType) {
+            String resolvedType, int userId) {
         if (DEBUG_SERVICE) Slog.v(TAG, "stopService: " + service
                 + " type=" + resolvedType);
 
@@ -278,9 +278,7 @@
 
         // If this service is active, make sure it is stopped.
         ServiceLookupResult r = retrieveServiceLocked(service, resolvedType,
-                Binder.getCallingPid(), Binder.getCallingUid(),
-                callerApp == null ? UserHandle.getCallingUserId() : callerApp.userId,
-                false);
+                Binder.getCallingPid(), Binder.getCallingUid(), userId, false);
         if (r != null) {
             if (r.record != null) {
                 final long origId = Binder.clearCallingIdentity();
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 8fc12d3..2b4f8b1 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -10554,7 +10554,7 @@
     }
     
     public ComponentName startService(IApplicationThread caller, Intent service,
-            String resolvedType) {
+            String resolvedType, int userId) {
         enforceNotIsolatedCaller("startService");
         // Refuse possible leaked file descriptors
         if (service != null && service.hasFileDescriptors() == true) {
@@ -10566,9 +10566,10 @@
         synchronized(this) {
             final int callingPid = Binder.getCallingPid();
             final int callingUid = Binder.getCallingUid();
+            checkValidCaller(callingUid, userId);
             final long origId = Binder.clearCallingIdentity();
             ComponentName res = mServices.startServiceLocked(caller, service,
-                    resolvedType, callingPid, callingUid);
+                    resolvedType, callingPid, callingUid, userId);
             Binder.restoreCallingIdentity(origId);
             return res;
         }
@@ -10581,22 +10582,24 @@
                 Slog.v(TAG, "startServiceInPackage: " + service + " type=" + resolvedType);
             final long origId = Binder.clearCallingIdentity();
             ComponentName res = mServices.startServiceLocked(null, service,
-                    resolvedType, -1, uid);
+                    resolvedType, -1, uid, UserHandle.getUserId(uid));
             Binder.restoreCallingIdentity(origId);
             return res;
         }
     }
 
     public int stopService(IApplicationThread caller, Intent service,
-            String resolvedType) {
+            String resolvedType, int userId) {
         enforceNotIsolatedCaller("stopService");
         // Refuse possible leaked file descriptors
         if (service != null && service.hasFileDescriptors() == true) {
             throw new IllegalArgumentException("File descriptors passed in Intent");
         }
 
+        checkValidCaller(Binder.getCallingUid(), userId);
+
         synchronized(this) {
-            return mServices.stopServiceLocked(caller, service, resolvedType);
+            return mServices.stopServiceLocked(caller, service, resolvedType, userId);
         }
     }
 
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 4252b90..b0aca21 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -64,11 +64,12 @@
 import android.content.pm.IPackageMoveObserver;
 import android.content.pm.IPackageStatsObserver;
 import android.content.pm.InstrumentationInfo;
+import android.content.pm.PackageCleanItem;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageInfoLite;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageParser;
-import android.content.pm.UserInfo;
+import android.content.pm.PackageUserState;
 import android.content.pm.PackageParser.ActivityIntentInfo;
 import android.content.pm.PackageStats;
 import android.content.pm.ParceledListSlice;
@@ -103,7 +104,6 @@
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UserHandle;
-import android.os.UserManager;
 import android.provider.Settings.Secure;
 import android.security.SystemKeyStore;
 import android.util.DisplayMetrics;
@@ -168,6 +168,7 @@
     static final boolean DEBUG_UPGRADE = false;
     private static final boolean DEBUG_INSTALL = false;
     private static final boolean DEBUG_REMOVE = false;
+    private static final boolean DEBUG_BROADCASTS = false;
     private static final boolean DEBUG_SHOW_INFO = false;
     private static final boolean DEBUG_PACKAGE_INFO = false;
     private static final boolean DEBUG_INTENT_MATCHING = false;
@@ -662,15 +663,21 @@
                     break;
                 }
                 case START_CLEANING_PACKAGE: {
-                    String packageName = (String)msg.obj;
                     Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
+                    PackageCleanItem item = new PackageCleanItem((String)msg.obj,
+                            msg.arg2 != 0);
                     synchronized (mPackages) {
-                        if (!mSettings.mPackagesToBeCleaned.contains(packageName)) {
-                            mSettings.mPackagesToBeCleaned.add(packageName);
+                        if (msg.arg1 == UserHandle.USER_ALL) {
+                            int[] users = sUserManager.getUserIds();
+                            for (int user : users) {
+                                mSettings.addPackageToCleanLPw(user, item);
+                            }
+                        } else {
+                            mSettings.addPackageToCleanLPw(msg.arg1, item);
                         }
                     }
                     Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
-                    startCleaningPackages();
+                    startCleaningPackages(-1);
                 } break;
                 case POST_INSTALL: {
                     if (DEBUG_INSTALL) Log.v(TAG, "Handling post-install for " + msg.arg1);
@@ -692,15 +699,14 @@
                             }
                             sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
                                     res.pkg.applicationInfo.packageName,
-                                    extras, null, null, UserHandle.USER_ALL);
+                                    extras, null, null, res.users);
                             if (update) {
                                 sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
                                         res.pkg.applicationInfo.packageName,
-                                        extras, null, null, UserHandle.USER_ALL);
+                                        extras, null, null, res.users);
                                 sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED,
                                         null, null,
-                                        res.pkg.applicationInfo.packageName, null,
-                                        UserHandle.USER_ALL);
+                                        res.pkg.applicationInfo.packageName, null, res.users);
                             }
                             if (res.removedInfo.args != null) {
                                 // Remove the replaced package's older resources safely now
@@ -1562,19 +1568,17 @@
     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.
-            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);
+        final PackageSetting ps = (PackageSetting) p.mExtras;
+        if (ps == null) {
+            return null;
+        }
+        final GrantedPermissions gp = ps.sharedUser != null ? ps.sharedUser : ps;
+        final PackageUserState state = ps.readUserState(userId);
+        pi = PackageParser.generatePackageInfo(p, gp.gids, flags,
+                ps.firstInstallTime, ps.lastUpdateTime, gp.grantedPermissions,
+                state, userId);
+        if (pi != null) {
+            pi.applicationInfo.enabledSetting = state.enabled;
             pi.applicationInfo.enabled =
                     pi.applicationInfo.enabledSetting == COMPONENT_ENABLED_STATE_DEFAULT
                     || pi.applicationInfo.enabledSetting == COMPONENT_ENABLED_STATE_ENABLED;
@@ -1741,14 +1745,15 @@
         PackageSetting ps = mSettings.mPackages.get(packageName);
         if (ps != null) {
             if (ps.pkg == null) {
-                PackageInfo pInfo = generatePackageInfoFromSettingsLPw(packageName, flags, userId);
+                PackageInfo pInfo = generatePackageInfoFromSettingsLPw(packageName,
+                        flags, userId);
                 if (pInfo != null) {
                     return pInfo.applicationInfo;
                 }
                 return null;
             }
-            return PackageParser.generateApplicationInfo(ps.pkg, flags, ps.getStopped(userId),
-                    ps.getEnabled(userId), userId);
+            return PackageParser.generateApplicationInfo(ps.pkg, flags,
+                    ps.readUserState(userId), userId);
         }
         return null;
     }
@@ -1758,20 +1763,23 @@
         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;
-                ps.pkg.applicationInfo.flags = ps.pkgFlags;
-                ps.pkg.applicationInfo.publicSourceDir = ps.resourcePathString;
-                ps.pkg.applicationInfo.sourceDir = ps.codePathString;
-                ps.pkg.applicationInfo.dataDir =
+            PackageParser.Package pkg = ps.pkg;
+            if (pkg == null) {
+                if ((flags & PackageManager.GET_UNINSTALLED_PACKAGES) == 0) {
+                    return null;
+                }
+                pkg = new PackageParser.Package(packageName);
+                pkg.applicationInfo.packageName = packageName;
+                pkg.applicationInfo.flags = ps.pkgFlags;
+                pkg.applicationInfo.publicSourceDir = ps.resourcePathString;
+                pkg.applicationInfo.sourceDir = ps.codePathString;
+                pkg.applicationInfo.dataDir =
                         getDataPathForPackage(ps.pkg.packageName, 0).getPath();
-                ps.pkg.applicationInfo.nativeLibraryDir = ps.nativeLibraryPathString;
+                pkg.applicationInfo.nativeLibraryDir = ps.nativeLibraryPathString;
             }
-            // ps.pkg.mSetEnabled = ps.getEnabled(userId);
-            // ps.pkg.mSetStopped = ps.getStopped(userId);
-            return generatePackageInfo(ps.pkg, flags, userId);
+            // pkg.mSetEnabled = ps.getEnabled(userId);
+            // pkg.mSetStopped = ps.getStopped(userId);
+            return generatePackageInfo(pkg, flags, userId);
         }
         return null;
     }
@@ -1789,13 +1797,12 @@
                 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, ps.getStopped(userId),
-                        ps.getEnabled(userId));
+                return PackageParser.generateApplicationInfo(p, flags, ps.readUserState(userId));
             }
             if ("android".equals(packageName)||"system".equals(packageName)) {
                 return mAndroidApplication;
             }
-            if((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) {
+            if ((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) {
                 return generateApplicationInfoFromSettingsLPw(packageName, flags, userId);
             }
         }
@@ -1862,8 +1869,8 @@
             if (a != null && mSettings.isEnabledLPr(a.info, 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 PackageParser.generateActivityInfo(a, flags, ps.readUserState(userId),
+                        userId);
             }
             if (mResolveComponentName.equals(component)) {
                 return mResolveActivity;
@@ -1882,8 +1889,8 @@
             if (a != null && mSettings.isEnabledLPr(a.info, 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 PackageParser.generateActivityInfo(a, flags, ps.readUserState(userId),
+                        userId);
             }
         }
         return null;
@@ -1899,8 +1906,8 @@
             if (s != null && mSettings.isEnabledLPr(s.info, 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 PackageParser.generateServiceInfo(s, flags, ps.readUserState(userId),
+                        userId);
             }
         }
         return null;
@@ -1916,8 +1923,8 @@
             if (p != null && mSettings.isEnabledLPr(p.info, 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 PackageParser.generateProviderInfo(p, flags, ps.readUserState(userId),
+                        userId);
             }
         }
         return null;
@@ -2870,8 +2877,8 @@
                 } else {
                     final PackageParser.Package p = mPackages.get(packageName);
                     if (p != null && ps != null) {
-                        ai = PackageParser.generateApplicationInfo(p, flags, ps.getStopped(userId),
-                                ps.getEnabled(userId), userId);
+                        ai = PackageParser.generateApplicationInfo(p, flags,
+                                ps.readUserState(userId), userId);
                     }
                 }
 
@@ -2901,10 +2908,13 @@
                         && (p.applicationInfo.flags&ApplicationInfo.FLAG_PERSISTENT) != 0
                         && (!mSafeMode || isSystemApp(p))) {
                     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));
+                    if (ps != null) {
+                        ApplicationInfo ai = PackageParser.generateApplicationInfo(p, flags,
+                                ps.readUserState(userId), userId);
+                        if (ai != null) {
+                            finalList.add(ai);
+                        }
+                    }
                 }
             }
         }
@@ -2921,14 +2931,12 @@
             PackageSetting ps = provider != null
                     ? mSettings.mPackages.get(provider.owner.packageName)
                     : null;
-            return provider != null
+            return ps != null
                     && mSettings.isEnabledLPr(provider.info, flags, userId)
                     && (!mSafeMode || (provider.info.applicationInfo.flags
                             &ApplicationInfo.FLAG_SYSTEM) != 0)
                     ? PackageParser.generateProviderInfo(provider, flags,
-                            ps != null ? ps.getStopped(userId) : false,
-                            ps != null ? ps.getEnabled(userId) : COMPONENT_ENABLED_STATE_DEFAULT,
-                            userId)
+                            ps.readUserState(userId), userId)
                     : null;
         }
     }
@@ -2948,14 +2956,15 @@
                 PackageParser.Provider p = entry.getValue();
                 PackageSetting ps = mSettings.mPackages.get(p.owner.packageName);
 
-                if (p.syncable
+                if (ps != null && p.syncable
                         && (!mSafeMode || (p.info.applicationInfo.flags
                                 &ApplicationInfo.FLAG_SYSTEM) != 0)) {
-                    outNames.add(entry.getKey());
-                    outInfo.add(PackageParser.generateProviderInfo(p, 0,
-                            ps != null ? ps.getStopped(userId) : false,
-                            ps != null ? ps.getEnabled(userId) : COMPONENT_ENABLED_STATE_DEFAULT,
-                            userId));
+                    ProviderInfo info = PackageParser.generateProviderInfo(p, 0,
+                            ps.readUserState(userId), userId);
+                    if (info != null) {
+                        outNames.add(entry.getKey());
+                        outInfo.add(info);
+                    }
                 }
             }
         }
@@ -2973,7 +2982,7 @@
             while (i.hasNext()) {
                 final PackageParser.Provider p = i.next();
                 PackageSetting ps = mSettings.mPackages.get(p.owner.packageName);
-                if (p.info.authority != null
+                if (ps != null && p.info.authority != null
                         && (processName == null
                                 || (p.info.processName.equals(processName)
                                         && UserHandle.isSameApp(p.info.applicationInfo.uid, uid)))
@@ -2983,10 +2992,9 @@
                     if (finalList == null) {
                         finalList = new ArrayList<ProviderInfo>(3);
                     }
-                    finalList.add(PackageParser.generateProviderInfo(p, flags,
-                            ps != null ? ps.getStopped(userId) : false,
-                            ps != null ? ps.getEnabled(userId) : COMPONENT_ENABLED_STATE_DEFAULT,
-                            userId));
+                    ProviderInfo info = PackageParser.generateProviderInfo(p, flags,
+                            ps.readUserState(userId), userId);
+                    finalList.add(info);
                 }
             }
         }
@@ -3047,7 +3055,7 @@
                 continue;
             }
             PackageParser.Package pkg = scanPackageLI(file,
-                    flags|PackageParser.PARSE_MUST_BE_APK, scanMode, currentTime);
+                    flags|PackageParser.PARSE_MUST_BE_APK, scanMode, currentTime, null);
             // Don't mess around with apps in system partition.
             if (pkg == null && (flags & PackageParser.PARSE_IS_SYSTEM) == 0 &&
                     mLastScanError == PackageManager.INSTALL_FAILED_INVALID_APK) {
@@ -3115,7 +3123,7 @@
      *  Returns null in case of errors and the error code is stored in mLastScanError
      */
     private PackageParser.Package scanPackageLI(File scanFile,
-            int parseFlags, int scanMode, long currentTime) {
+            int parseFlags, int scanMode, long currentTime, UserHandle user) {
         mLastScanError = PackageManager.INSTALL_SUCCEEDED;
         String scanPath = scanFile.getPath();
         parseFlags |= mDefParseFlags;
@@ -3215,7 +3223,7 @@
              */
             if (compareSignatures(ps.signatures.mSignatures, pkg.mSignatures)
                     != PackageManager.SIGNATURE_MATCH) {
-                deletePackageLI(pkg.packageName, true, 0, null, false);
+                deletePackageLI(pkg.packageName, null, true, 0, null, false);
                 ps = null;
             } else {
                 /*
@@ -3268,7 +3276,7 @@
         setApplicationInfoPaths(pkg, codePath, resPath);
         // Note that we invoke the following method only if we are about to unpack an application
         PackageParser.Package scannedPkg = scanPackageLI(pkg, parseFlags, scanMode
-                | SCAN_UPDATE_SIGNATURE, currentTime);
+                | SCAN_UPDATE_SIGNATURE, currentTime, user);
 
         /*
          * If the system app should be overridden by a previously installed
@@ -3472,7 +3480,7 @@
     }
 
     private PackageParser.Package scanPackageLI(PackageParser.Package pkg,
-            int parseFlags, int scanMode, long currentTime) {
+            int parseFlags, int scanMode, long currentTime, UserHandle user) {
         File scanFile = new File(pkg.mScanPath);
         if (scanFile == null || pkg.applicationInfo.sourceDir == null ||
                 pkg.applicationInfo.publicSourceDir == null) {
@@ -3664,7 +3672,7 @@
             // the PkgSetting exists already and doesn't have to be created.
             pkgSetting = mSettings.getPackageLPw(pkg, origPackage, realName, suid, destCodeFile,
                     destResourceFile, pkg.applicationInfo.nativeLibraryDir,
-                    pkg.applicationInfo.flags, true, false);
+                    pkg.applicationInfo.flags, user, false);
             if (pkgSetting == null) {
                 Slog.w(TAG, "Creating application package " + pkg.packageName + " failed");
                 mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
@@ -4024,7 +4032,9 @@
             // Add the new setting to mPackages
             mPackages.put(pkg.applicationInfo.packageName, pkg);
             // Make sure we don't accidentally delete its data.
-            mSettings.mPackagesToBeCleaned.remove(pkgName);
+            for (int i=0; i<mSettings.mPackagesToBeCleaned.size(); i++) {
+                mSettings.mPackagesToBeCleaned.valueAt(i).remove(pkgName);
+            }
             
             // Take care of first install / last update times.
             if (currentTime != 0) {
@@ -4840,7 +4850,8 @@
                     // System apps are never considered stopped for purposes of
                     // filtering, because there may be no way for the user to
                     // actually re-launch them.
-                    return ps.getStopped(userId) && (ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0;
+                    return (ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0
+                            && ps.getStopped(userId);
                 }
             }
             return false;
@@ -4863,12 +4874,17 @@
                     &ApplicationInfo.FLAG_SYSTEM) == 0) {
                 return null;
             }
-            final ResolveInfo res = new ResolveInfo();
             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 (ps == null) {
+                return null;
+            }
+            ActivityInfo ai = PackageParser.generateActivityInfo(activity, mFlags,
+                    ps.readUserState(userId), userId);
+            if (ai == null) {
+                return null;
+            }
+            final ResolveInfo res = new ResolveInfo();
+            res.activityInfo = ai;
             if ((mFlags&PackageManager.GET_RESOLVED_FILTER) != 0) {
                 res.filter = info;
             }
@@ -5031,8 +5047,8 @@
                     // System apps are never considered stopped for purposes of
                     // filtering, because there may be no way for the user to
                     // actually re-launch them.
-                    return ps.getStopped(userId)
-                            && (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0;
+                    return (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0
+                            && ps.getStopped(userId);
                 }
             }
             return false;
@@ -5056,12 +5072,14 @@
                     &ApplicationInfo.FLAG_SYSTEM) == 0) {
                 return null;
             }
-            final ResolveInfo res = new ResolveInfo();
             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 (ps == null) {
+                return null;
+            }
+            ServiceInfo si = PackageParser.generateServiceInfo(service, mFlags,
+                    ps.readUserState(userId), userId);
+            final ResolveInfo res = new ResolveInfo();
+            res.serviceInfo = si;
             if ((mFlags&PackageManager.GET_RESOLVED_FILTER) != 0) {
                 res.filter = filter;
             }
@@ -5152,13 +5170,14 @@
     };
 
     static final void sendPackageBroadcast(String action, String pkg,
-            Bundle extras, String targetPkg, IIntentReceiver finishedReceiver, int userId) {
+            Bundle extras, String targetPkg, IIntentReceiver finishedReceiver,
+            int[] userIds) {
         IActivityManager am = ActivityManagerNative.getDefault();
         if (am != null) {
             try {
-                int[] userIds = userId == UserHandle.USER_ALL
-                        ? sUserManager.getUserIds() 
-                        : new int[] {userId};
+                if (userIds == null) {
+                    userIds = sUserManager.getUserIds();
+                }
                 for (int id : userIds) {
                     final Intent intent = new Intent(action,
                             pkg != null ? Uri.fromParts("package", pkg, null) : null);
@@ -5170,11 +5189,18 @@
                     }
                     // Modify the UID when posting to other users
                     int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
-                    if (uid > 0 && id > 0) {
+                    if (uid > 0 && UserHandle.getUserId(uid) != id) {
                         uid = UserHandle.getUid(id, UserHandle.getAppId(uid));
                         intent.putExtra(Intent.EXTRA_UID, uid);
                     }
                     intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+                    if (DEBUG_BROADCASTS) {
+                        RuntimeException here = new RuntimeException("here");
+                        here.fillInStackTrace();
+                        Slog.d(TAG, "Sending to user " + id + ": "
+                                + intent.toShortString(false, true, false, false)
+                                + " " + intent.getExtras(), here);
+                    }
                     am.broadcastIntent(null, intent, null, finishedReceiver,
                             0, null, null, null, finishedReceiver != null, false, id);
                 }
@@ -5192,8 +5218,9 @@
         return mMediaMounted || Environment.isExternalStorageEmulated();
     }
 
-    public String nextPackageToClean(String lastPackage) {
+    public PackageCleanItem nextPackageToClean(PackageCleanItem lastPackage) {
         // writer
+        final int userId = UserHandle.getCallingUserId();
         synchronized (mPackages) {
             if (!isExternalMediaAvailable()) {
                 // If the external storage is no longer mounted at this point,
@@ -5201,34 +5228,65 @@
                 // packages files and can not delete any more.  Bail.
                 return null;
             }
-            if (lastPackage != null) {
-                mSettings.mPackagesToBeCleaned.remove(lastPackage);
+            ArrayList<PackageCleanItem> pkgs = mSettings.mPackagesToBeCleaned.get(userId);
+            if (pkgs != null) {
+                if (lastPackage != null) {
+                    pkgs.remove(lastPackage);
+                }
+                if (pkgs.size() > 0) {
+                    return pkgs.get(0);
+                }
             }
-            return mSettings.mPackagesToBeCleaned.size() > 0
-                    ? mSettings.mPackagesToBeCleaned.get(0) : null;
         }
+        // Move on to the next user to clean.
+        long ident = Binder.clearCallingIdentity();
+        try {
+            startCleaningPackages(userId);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+        return null;
     }
 
-    void schedulePackageCleaning(String packageName) {
-        mHandler.sendMessage(mHandler.obtainMessage(START_CLEANING_PACKAGE, packageName));
+    void schedulePackageCleaning(String packageName, int userId, boolean andCode) {
+        if (false) {
+            RuntimeException here = new RuntimeException("here");
+            here.fillInStackTrace();
+            Slog.d(TAG, "Schedule cleaning " + packageName + " user=" + userId
+                    + " andCode=" + andCode, here);
+        }
+        mHandler.sendMessage(mHandler.obtainMessage(START_CLEANING_PACKAGE,
+                userId, andCode ? 1 : 0, packageName));
     }
     
-    void startCleaningPackages() {
+    void startCleaningPackages(int lastUser) {
         // reader
+        int nextUser = -1;
         synchronized (mPackages) {
             if (!isExternalMediaAvailable()) {
                 return;
             }
-            if (mSettings.mPackagesToBeCleaned.size() <= 0) {
+            final int N = mSettings.mPackagesToBeCleaned.size();
+            if (N <= 0) {
                 return;
             }
+            for (int i=0; i<N; i++) {
+                int user = mSettings.mPackagesToBeCleaned.keyAt(i);
+                if (user > lastUser) {
+                    nextUser = user;
+                    break;
+                }
+            }
+            if (nextUser < 0) {
+                nextUser = mSettings.mPackagesToBeCleaned.keyAt(0);
+            }
         }
         Intent intent = new Intent(PackageManager.ACTION_CLEAN_EXTERNAL_STORAGE);
         intent.setComponent(DEFAULT_CONTAINER_COMPONENT);
         IActivityManager am = ActivityManagerNative.getDefault();
         if (am != null) {
             try {
-                am.startService(null, intent, null);
+                am.startService(null, intent, null, nextUser);
             } catch (RemoteException e) {
             }
         }
@@ -5291,7 +5349,7 @@
                                 PackageParser.PARSE_CHATTY |
                                 PackageParser.PARSE_MUST_BE_APK,
                                 SCAN_MONITOR | SCAN_NO_PATHS | SCAN_UPDATE_TIME,
-                                System.currentTimeMillis());
+                                System.currentTimeMillis(), null);
                         if (p != null) {
                             /*
                              * TODO this seems dangerous as the package may have
@@ -5320,13 +5378,13 @@
                 extras.putInt(Intent.EXTRA_UID, removedUid);
                 extras.putBoolean(Intent.EXTRA_DATA_REMOVED, false);
                 sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage,
-                        extras, null, null, UserHandle.USER_ALL);
+                        extras, null, null, null);
             }
             if (addedPackage != null) {
                 Bundle extras = new Bundle(1);
                 extras.putInt(Intent.EXTRA_UID, addedUid);
                 sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, addedPackage,
-                        extras, null, null, UserHandle.USER_ALL);
+                        extras, null, null, null);
             }
         }
 
@@ -5365,6 +5423,12 @@
                 null);
 
         final int uid = Binder.getCallingUid();
+        UserHandle user;
+        if ((flags&PackageManager.INSTALL_ALL_USERS) != 0) {
+            user = UserHandle.ALL;
+        } else {
+            user = Process.myUserHandle();
+        }
 
         final int filteredFlags;
 
@@ -5379,10 +5443,51 @@
 
         final Message msg = mHandler.obtainMessage(INIT_COPY);
         msg.obj = new InstallParams(packageURI, observer, filteredFlags, installerPackageName,
-                verificationParams, encryptionParams);
+                verificationParams, encryptionParams, user);
         mHandler.sendMessage(msg);
     }
 
+    /**
+     * @hide
+     */
+    @Override
+    public int installExistingPackage(String packageName) {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES,
+                null);
+        PackageSetting pkgSetting;
+        final int uid = Binder.getCallingUid();
+        final int userId = UserHandle.getUserId(uid);
+
+        long callingId = Binder.clearCallingIdentity();
+        try {
+            boolean sendAdded = false;
+            Bundle extras = new Bundle(1);
+
+            // writer
+            synchronized (mPackages) {
+                pkgSetting = mSettings.mPackages.get(packageName);
+                if (pkgSetting == null) {
+                    return PackageManager.INSTALL_FAILED_INVALID_URI;
+                }
+                if (!pkgSetting.getInstalled(userId)) {
+                    pkgSetting.setInstalled(true, userId);
+                    mSettings.writePackageRestrictionsLPr(userId);
+                    extras.putInt(Intent.EXTRA_UID, UserHandle.getUid(userId, pkgSetting.appId));
+                    sendAdded = true;
+                }
+            }
+
+            if (sendAdded) {
+                sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
+                        packageName, extras, null, null, new int[] {userId});
+            }
+        } finally {
+            Binder.restoreCallingIdentity(callingId);
+        }
+
+        return PackageManager.INSTALL_SUCCEEDED;
+    }
+    
     @Override
     public void verifyPendingInstall(int id, int verificationCode) throws RemoteException {
         final Message msg = mHandler.obtainMessage(PACKAGE_VERIFIED);
@@ -5840,17 +5945,19 @@
         private int mRet;
         private File mTempPackage;
         final ContainerEncryptionParams encryptionParams;
+        final UserHandle user;
 
         InstallParams(Uri packageURI,
                 IPackageInstallObserver observer, int flags,
                 String installerPackageName, VerificationParams verificationParams,
-                ContainerEncryptionParams encryptionParams) {
+                ContainerEncryptionParams encryptionParams, UserHandle user) {
             this.mPackageURI = packageURI;
             this.flags = flags;
             this.observer = observer;
             this.installerPackageName = installerPackageName;
             this.verificationParams = verificationParams;
             this.encryptionParams = encryptionParams;
+            this.user = user;
         }
 
         public ManifestDigest getManifestDigest() {
@@ -5860,6 +5967,10 @@
             return verificationParams.getManifestDigest();
         }
 
+        public UserHandle getUser() {
+            return user;
+        }
+
         private int installLocationPolicy(PackageInfoLite pkgLite, int flags) {
             String packageName = pkgLite.packageName;
             int installLocation = pkgLite.installLocation;
@@ -5869,6 +5980,16 @@
                 PackageParser.Package pkg = mPackages.get(packageName);
                 if (pkg != null) {
                     if ((flags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
+                        // Check for downgrading.
+                        if ((flags & PackageManager.INSTALL_ALLOW_DOWNGRADE) == 0) {
+                            if (pkgLite.versionCode < pkg.mVersionCode) {
+                                Slog.w(TAG, "Can't install update of " + packageName
+                                        + " update version " + pkgLite.versionCode
+                                        + " is older than installed version "
+                                        + pkg.mVersionCode);
+                                return PackageHelper.RECOMMEND_FAILED_VERSION_DOWNGRADE;
+                            }
+                        }
                         // Check for updated system application.
                         if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
                             if (onSd) {
@@ -5995,6 +6116,8 @@
                     ret = PackageManager.INSTALL_FAILED_INVALID_URI;
                 } else if (loc == PackageHelper.RECOMMEND_MEDIA_UNAVAILABLE) {
                     ret = PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE;
+                } else if (loc == PackageHelper.RECOMMEND_FAILED_VERSION_DOWNGRADE) {
+                    ret = PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;
                 } else {
                     // Override with defaults if needed.
                     loc = installLocationPolicy(pkgLite, flags);
@@ -6338,14 +6461,17 @@
         final Uri packageURI;
         final String installerPackageName;
         final ManifestDigest manifestDigest;
+        final UserHandle user;
 
         InstallArgs(Uri packageURI, IPackageInstallObserver observer, int flags,
-                String installerPackageName, ManifestDigest manifestDigest) {
+                String installerPackageName, ManifestDigest manifestDigest,
+                UserHandle user) {
             this.packageURI = packageURI;
             this.flags = flags;
             this.observer = observer;
             this.installerPackageName = installerPackageName;
             this.manifestDigest = manifestDigest;
+            this.user = user;
         }
 
         abstract void createCopyFile();
@@ -6396,11 +6522,12 @@
 
         FileInstallArgs(InstallParams params) {
             super(params.getPackageUri(), params.observer, params.flags,
-                    params.installerPackageName, params.getManifestDigest());
+                    params.installerPackageName, params.getManifestDigest(),
+                    params.getUser());
         }
 
         FileInstallArgs(String fullCodePath, String fullResourcePath, String nativeLibraryPath) {
-            super(null, null, 0, null, null);
+            super(null, null, 0, null, null, null);
             File codeFile = new File(fullCodePath);
             installDir = codeFile.getParentFile();
             codeFileName = fullCodePath;
@@ -6409,7 +6536,7 @@
         }
 
         FileInstallArgs(Uri packageURI, String pkgName, String dataDir) {
-            super(packageURI, null, 0, null, null);
+            super(packageURI, null, 0, null, null, null);
             installDir = isFwdLocked() ? mDrmAppPrivateInstallDir : mAppInstallDir;
             String apkName = getNextCodePath(null, pkgName, ".apk");
             codeFileName = new File(installDir, apkName + ".apk").getPath();
@@ -6683,13 +6810,15 @@
 
         AsecInstallArgs(InstallParams params) {
             super(params.getPackageUri(), params.observer, params.flags,
-                    params.installerPackageName, params.getManifestDigest());
+                    params.installerPackageName, params.getManifestDigest(),
+                    params.getUser());
         }
 
         AsecInstallArgs(String fullCodePath, String fullResourcePath, String nativeLibraryPath,
                 boolean isExternal, boolean isForwardLocked) {
             super(null, null, (isExternal ? PackageManager.INSTALL_EXTERNAL : 0)
-                    | (isForwardLocked ? PackageManager.INSTALL_FORWARD_LOCK : 0), null, null);
+                    | (isForwardLocked ? PackageManager.INSTALL_FORWARD_LOCK : 0),
+                    null, null, null);
             // Extract cid from fullCodePath
             int eidx = fullCodePath.lastIndexOf("/");
             String subStr1 = fullCodePath.substring(0, eidx);
@@ -6700,14 +6829,16 @@
 
         AsecInstallArgs(String cid, boolean isForwardLocked) {
             super(null, null, (isAsecExternal(cid) ? PackageManager.INSTALL_EXTERNAL : 0)
-                    | (isForwardLocked ? PackageManager.INSTALL_FORWARD_LOCK : 0), null, null);
+                    | (isForwardLocked ? PackageManager.INSTALL_FORWARD_LOCK : 0),
+                    null, null, null);
             this.cid = cid;
             setCachePath(PackageHelper.getSdDir(cid));
         }
 
         AsecInstallArgs(Uri packageURI, String cid, boolean isExternal, boolean isForwardLocked) {
             super(packageURI, null, (isExternal ? PackageManager.INSTALL_EXTERNAL : 0)
-                    | (isForwardLocked ? PackageManager.INSTALL_FORWARD_LOCK : 0), null, null);
+                    | (isForwardLocked ? PackageManager.INSTALL_FORWARD_LOCK : 0),
+                    null, null, null);
             this.cid = cid;
         }
 
@@ -7031,6 +7162,7 @@
     class PackageInstalledInfo {
         String name;
         int uid;
+        int[] users;
         PackageParser.Package pkg;
         int returnCode;
         PackageRemovedInfo removedInfo;
@@ -7040,14 +7172,12 @@
      * Install a non-existing package.
      */
     private void installNewPackageLI(PackageParser.Package pkg,
-            int parseFlags,
-            int scanMode,
+            int parseFlags, int scanMode, UserHandle user,
             String installerPackageName, PackageInstalledInfo res) {
         // Remember this for later, in case we need to rollback this install
         String pkgName = pkg.packageName;
 
         boolean dataDirExists = getDataPathForPackage(pkg.packageName, 0).exists();
-        res.name = pkgName;
         synchronized(mPackages) {
             if (mSettings.mRenamedPackages.containsKey(pkgName)) {
                 // A package with the same name is already installed, though
@@ -7070,7 +7200,7 @@
         }
         mLastScanError = PackageManager.INSTALL_SUCCEEDED;
         PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanMode,
-                System.currentTimeMillis());
+                System.currentTimeMillis(), user);
         if (newPackage == null) {
             Slog.w(TAG, "Package couldn't be installed in " + pkg.mPath);
             if ((res.returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) {
@@ -7087,17 +7217,15 @@
                 // delete the package data and cache directories that it created in
                 // scanPackageLocked, unless those directories existed before we even tried to
                 // install.
-                deletePackageLI(
-                        pkgName, false,
-                        dataDirExists ? PackageManager.DONT_DELETE_DATA : 0,
+                deletePackageLI(pkgName, UserHandle.ALL, false,
+                        dataDirExists ? PackageManager.DELETE_KEEP_DATA : 0,
                                 res.removedInfo, true);
             }
         }
     }
 
     private void replacePackageLI(PackageParser.Package pkg,
-            int parseFlags,
-            int scanMode,
+            int parseFlags, int scanMode, UserHandle user,
             String installerPackageName, PackageInstalledInfo res) {
 
         PackageParser.Package oldPackage;
@@ -7114,15 +7242,16 @@
         }
         boolean sysPkg = (isSystemApp(oldPackage));
         if (sysPkg) {
-            replaceSystemPackageLI(oldPackage, pkg, parseFlags, scanMode, installerPackageName, res);
+            replaceSystemPackageLI(oldPackage, pkg, parseFlags, scanMode,
+                    user, installerPackageName, res);
         } else {
-            replaceNonSystemPackageLI(oldPackage, pkg, parseFlags, scanMode, installerPackageName, res);
+            replaceNonSystemPackageLI(oldPackage, pkg, parseFlags, scanMode,
+                    user, installerPackageName, res);
         }
     }
 
     private void replaceNonSystemPackageLI(PackageParser.Package deletedPackage,
-            PackageParser.Package pkg,
-            int parseFlags, int scanMode,
+            PackageParser.Package pkg, int parseFlags, int scanMode, UserHandle user,
             String installerPackageName, PackageInstalledInfo res) {
         PackageParser.Package newPackage = null;
         String pkgName = deletedPackage.packageName;
@@ -7137,7 +7266,7 @@
         }
 
         // First delete the existing package while retaining the data directory
-        if (!deletePackageLI(pkgName, true, PackageManager.DONT_DELETE_DATA,
+        if (!deletePackageLI(pkgName, null, true, PackageManager.DELETE_KEEP_DATA,
                 res.removedInfo, true)) {
             // If the existing package wasn't successfully deleted
             res.returnCode = PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE;
@@ -7146,7 +7275,7 @@
             // Successfully deleted the old package. Now proceed with re-installation
             mLastScanError = PackageManager.INSTALL_SUCCEEDED;
             newPackage = scanPackageLI(pkg, parseFlags, scanMode | SCAN_UPDATE_TIME,
-                    System.currentTimeMillis());
+                    System.currentTimeMillis(), user);
             if (newPackage == null) {
                 Slog.w(TAG, "Package couldn't be installed in " + pkg.mPath);
                 if ((res.returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) {
@@ -7167,8 +7296,8 @@
             // install.
             if(updatedSettings) {
                 deletePackageLI(
-                        pkgName, true,
-                        PackageManager.DONT_DELETE_DATA,
+                        pkgName, null, true,
+                        PackageManager.DELETE_KEEP_DATA,
                                 res.removedInfo, true);
             }
             // Since we failed to install the new package we need to restore the old
@@ -7183,7 +7312,7 @@
                 int oldScanMode = (oldOnSd ? 0 : SCAN_MONITOR) | SCAN_UPDATE_SIGNATURE
                         | SCAN_UPDATE_TIME;
                 if (scanPackageLI(restoreFile, oldParseFlags, oldScanMode,
-                        origUpdateTime) == null) {
+                        origUpdateTime, user) == null) {
                     Slog.e(TAG, "Failed to restore package : " + pkgName + " after failed upgrade");
                     return;
                 }
@@ -7201,8 +7330,7 @@
     }
 
     private void replaceSystemPackageLI(PackageParser.Package deletedPackage,
-            PackageParser.Package pkg,
-            int parseFlags, int scanMode,
+            PackageParser.Package pkg, int parseFlags, int scanMode, UserHandle user,
             String installerPackageName, PackageInstalledInfo res) {
         PackageParser.Package newPackage = null;
         boolean updatedSettings = false;
@@ -7251,7 +7379,7 @@
         // Successfully disabled the old package. Now proceed with re-installation
         mLastScanError = PackageManager.INSTALL_SUCCEEDED;
         pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
-        newPackage = scanPackageLI(pkg, parseFlags, scanMode, 0);
+        newPackage = scanPackageLI(pkg, parseFlags, scanMode, 0, user);
         if (newPackage == null) {
             Slog.w(TAG, "Package couldn't be installed in " + pkg.mPath);
             if ((res.returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) {
@@ -7274,7 +7402,7 @@
                 removePackageLI(newPackage, true);
             }
             // Add back the old system package
-            scanPackageLI(oldPkg, parseFlags, SCAN_MONITOR | SCAN_UPDATE_SIGNATURE, 0);
+            scanPackageLI(oldPkg, parseFlags, SCAN_MONITOR | SCAN_UPDATE_SIGNATURE, 0, user);
             // Restore the old system information in Settings
             synchronized(mPackages) {
                 if (updatedSettings) {
@@ -7333,6 +7461,10 @@
                     UPDATE_PERMISSIONS_REPLACE_PKG | (newPackage.permissions.size() > 0
                             ? UPDATE_PERMISSIONS_ALL : 0));
             res.name = pkgName;
+            PackageSetting ps = mSettings.mPackages.get(pkgName);
+            if (ps != null) {
+                res.users = ps.getInstalledUsers(sUserManager.getUserIds());
+            }
             res.uid = newPackage.applicationInfo.uid;
             res.pkg = newPackage;
             mSettings.setInstallStatus(pkgName, PackageSettingBase.PKG_INSTALL_COMPLETE);
@@ -7448,12 +7580,18 @@
         setApplicationInfoPaths(pkg, args.getCodePath(), args.getResourcePath());
         pkg.applicationInfo.nativeLibraryDir = args.getNativeLibraryPath();
         if (replace) {
-            replacePackageLI(pkg, parseFlags, scanMode,
+            replacePackageLI(pkg, parseFlags, scanMode, args.user,
                     installerPackageName, res);
         } else {
-            installNewPackageLI(pkg, parseFlags, scanMode,
+            installNewPackageLI(pkg, parseFlags, scanMode, args.user,
                     installerPackageName,res);
         }
+        synchronized (mPackages) {
+            PackageSetting ps = mSettings.mPackages.get(pkgName);
+            if (ps != null) {
+                res.users = ps.getInstalledUsers(sUserManager.getUserIds());
+            }
+        }
     }
 
     private static boolean isForwardLocked(PackageParser.Package pkg) {
@@ -7544,10 +7682,11 @@
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.DELETE_PACKAGES, null);
         // Queue up an async operation since the package deletion may take a little while.
+        final int uid = Binder.getCallingUid();
         mHandler.post(new Runnable() {
             public void run() {
                 mHandler.removeCallbacks(this);
-                final int returnCode = deletePackageX(packageName, true, true, flags);
+                final int returnCode = deletePackageX(packageName, uid, flags);
                 if (observer != null) {
                     try {
                         observer.packageDeleted(packageName, returnCode);
@@ -7573,8 +7712,7 @@
      *  persisting settings for later use
      *  sending a broadcast if necessary
      */
-    private int deletePackageX(String packageName, boolean sendBroadCast,
-                                   boolean deleteCodeAndResources, int flags) {
+    private int deletePackageX(String packageName, int uid, int flags) {
         final PackageRemovedInfo info = new PackageRemovedInfo();
         final boolean res;
 
@@ -7589,27 +7727,30 @@
         }
         
         synchronized (mInstallLock) {
-            res = deletePackageLI(packageName, deleteCodeAndResources,
-                    flags | REMOVE_CHATTY, info, true);
+            res = deletePackageLI(packageName,
+                    (flags & PackageManager.DELETE_ALL_USERS) != 0
+                            ? UserHandle.ALL : new UserHandle(UserHandle.getUserId(uid)),
+                    true, flags | REMOVE_CHATTY, info, true);
         }
 
-        if (res && sendBroadCast) {
+        if (res) {
             boolean systemUpdate = info.isRemovedPackageSystemUpdate;
-            info.sendBroadcast(deleteCodeAndResources, systemUpdate);
+            info.sendBroadcast(true, systemUpdate);
 
             // If the removed package was a system update, the old system packaged
             // was re-enabled; we need to broadcast this information
             if (systemUpdate) {
                 Bundle extras = new Bundle(1);
-                extras.putInt(Intent.EXTRA_UID, info.removedUid >= 0 ? info.removedUid : info.uid);
+                extras.putInt(Intent.EXTRA_UID, info.removedAppId >= 0
+                        ? info.removedAppId : info.uid);
                 extras.putBoolean(Intent.EXTRA_REPLACING, true);
 
                 sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
-                        extras, null, null, UserHandle.USER_ALL);
+                        extras, null, null, null);
                 sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,
-                        extras, null, null, UserHandle.USER_ALL);
+                        extras, null, null, null);
                 sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, null,
-                        null, packageName, null, UserHandle.USER_ALL);
+                        null, packageName, null, null);
             }
         }
         // Force a gc here.
@@ -7618,7 +7759,7 @@
         // other processes clean up before deleting resources.
         if (info.args != null) {
             synchronized (mInstallLock) {
-                info.args.doPostDeleteLI(deleteCodeAndResources);
+                info.args.doPostDeleteLI(true);
             }
         }
 
@@ -7628,29 +7769,30 @@
     static class PackageRemovedInfo {
         String removedPackage;
         int uid = -1;
-        int removedUid = -1;
+        int removedAppId = -1;
+        int[] removedUsers = null;
         boolean isRemovedPackageSystemUpdate = false;
         // Clean up resources deleted packages.
         InstallArgs args = null;
 
         void sendBroadcast(boolean fullRemove, boolean replacing) {
             Bundle extras = new Bundle(1);
-            extras.putInt(Intent.EXTRA_UID, removedUid >= 0 ? removedUid : uid);
+            extras.putInt(Intent.EXTRA_UID, removedAppId >= 0 ? removedAppId : uid);
             extras.putBoolean(Intent.EXTRA_DATA_REMOVED, fullRemove);
             if (replacing) {
                 extras.putBoolean(Intent.EXTRA_REPLACING, true);
             }
             if (removedPackage != null) {
                 sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage,
-                        extras, null, null, UserHandle.USER_ALL);
+                        extras, null, null, removedUsers);
                 if (fullRemove && !replacing) {
                     sendPackageBroadcast(Intent.ACTION_PACKAGE_FULLY_REMOVED, removedPackage,
-                            extras, null, null, UserHandle.USER_ALL);
+                            extras, null, null, removedUsers);
                 }
             }
-            if (removedUid >= 0) {
+            if (removedAppId >= 0) {
                 sendPackageBroadcast(Intent.ACTION_UID_REMOVED, null, extras, null, null,
-                        UserHandle.getUserId(removedUid));
+                        removedUsers);
             }
         }
     }
@@ -7664,17 +7806,19 @@
     private void removePackageDataLI(PackageParser.Package p, PackageRemovedInfo outInfo,
             int flags, boolean writeSettings) {
         String packageName = p.packageName;
-        if (outInfo != null) {
-            outInfo.removedPackage = packageName;
-        }
         removePackageLI(p, (flags&REMOVE_CHATTY) != 0);
         // Retrieve object to delete permissions for shared user later on
         final PackageSetting deletedPs;
         // reader
         synchronized (mPackages) {
             deletedPs = mSettings.mPackages.get(packageName);
+            if (outInfo != null) {
+                outInfo.removedPackage = packageName;
+                outInfo.removedUsers = deletedPs != null
+                        ? deletedPs.getInstalledUsers(sUserManager.getUserIds()) : null;
+            }
         }
-        if ((flags&PackageManager.DONT_DELETE_DATA) == 0) {
+        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: "
@@ -7684,14 +7828,14 @@
                 // TODO: Kill the processes first
                 sUserManager.removePackageForAllUsers(packageName);
             }
-            schedulePackageCleaning(packageName);
+            schedulePackageCleaning(packageName, UserHandle.USER_ALL, true);
         }
         // writer
         synchronized (mPackages) {
             if (deletedPs != null) {
-                if ((flags&PackageManager.DONT_DELETE_DATA) == 0) {
+                if ((flags&PackageManager.DELETE_KEEP_DATA) == 0) {
                     if (outInfo != null) {
-                        outInfo.removedUid = mSettings.removePackageLPw(packageName);
+                        outInfo.removedAppId = mSettings.removePackageLPw(packageName);
                     }
                     if (deletedPs != null) {
                         updatePermissionsLPw(deletedPs.name, null, 0);
@@ -7740,10 +7884,10 @@
         outInfo.isRemovedPackageSystemUpdate = true;
         if (ps.versionCode < p.mVersionCode) {
             // Delete data for downgrades
-            flags &= ~PackageManager.DONT_DELETE_DATA;
+            flags &= ~PackageManager.DELETE_KEEP_DATA;
         } else {
             // Preserve data by setting flag
-            flags |= PackageManager.DONT_DELETE_DATA;
+            flags |= PackageManager.DELETE_KEEP_DATA;
         }
         boolean ret = deleteInstalledPackageLI(p, true, flags, outInfo,
                 writeSettings);
@@ -7760,7 +7904,7 @@
         // Install the system package
         PackageParser.Package newPkg = scanPackageLI(ps.codePath,
                 PackageParser.PARSE_MUST_BE_APK | PackageParser.PARSE_IS_SYSTEM,
-                SCAN_MONITOR | SCAN_NO_PATHS, 0);
+                SCAN_MONITOR | SCAN_NO_PATHS, 0, null);
 
         if (newPkg == null) {
             Slog.w(TAG, "Failed to restore system package:"+p.packageName+" with error:" + mLastScanError);
@@ -7807,7 +7951,7 @@
     /*
      * This method handles package deletion in general
      */
-    private boolean deletePackageLI(String packageName,
+    private boolean deletePackageLI(String packageName, UserHandle user,
             boolean deleteCodeAndResources, int flags, PackageRemovedInfo outInfo,
             boolean writeSettings) {
         if (packageName == null) {
@@ -7816,6 +7960,8 @@
         }
         PackageParser.Package p;
         boolean dataOnly = false;
+        int removeUser = -1;
+        int appId = -1;
         synchronized (mPackages) {
             p = mPackages.get(packageName);
             if (p == null) {
@@ -7823,15 +7969,53 @@
                 dataOnly = true;
                 PackageSetting ps = mSettings.mPackages.get(packageName);
                 if (ps == null) {
-                    Slog.w(TAG, "Package named '" + packageName +"' doesn't exist.");
+                    Slog.w(TAG, "Package named '" + packageName + "' doesn't exist.");
                     return false;
                 }
                 p = ps.pkg;
             }
+            if (p == null) {
+                Slog.w(TAG, "Package named '" + packageName + "' doesn't exist.");
+                return false;
+            }
+            final PackageSetting ps = (PackageSetting)p.mExtras;
+            if (!isSystemApp(p) && ps != null && user != null
+                    && user.getIdentifier() != UserHandle.USER_ALL) {
+                // The caller is asking that the package only be deleted for a single
+                // user.  To do this, we just mark its uninstalled state and delete
+                // its data.
+                ps.setUserState(user.getIdentifier(),
+                        COMPONENT_ENABLED_STATE_DEFAULT,
+                        false, //installed
+                        true,  //stopped
+                        true,  //notLaunched
+                        null, null);
+                if (ps.isAnyInstalled(sUserManager.getUserIds())) {
+                    // Other user still have this package installed, so all
+                    // we need to do is clear this user's data and save that
+                    // it is uninstalled.
+                    removeUser = user.getIdentifier();
+                    appId = ps.appId;
+                    mSettings.writePackageRestrictionsLPr(removeUser);
+                } else {
+                    // We need to set it back to 'installed' so the uninstall
+                    // broadcasts will be sent correctly.
+                    ps.setInstalled(true, user.getIdentifier());
+                }
+            }
         }
-        if (p == null) {
-            Slog.w(TAG, "Package named '" + packageName +"' doesn't exist.");
-            return false;
+
+        if (removeUser >= 0) {
+            // From above, we determined that we are deleting this only
+            // for a single user.  Continue the work here.
+            if (outInfo != null) {
+                outInfo.removedPackage = packageName;
+                outInfo.removedAppId = appId;
+                outInfo.removedUsers = new int[] {removeUser};
+            }
+            mInstaller.clearUserData(packageName, removeUser);
+            schedulePackageCleaning(packageName, removeUser, false);
+            return true;
         }
 
         if (dataOnly) {
@@ -7876,7 +8060,7 @@
         }
     }
 
-    private void clearExternalStorageDataSync(String packageName, boolean allData) {
+    private void clearExternalStorageDataSync(String packageName, int userId, boolean allData) {
         final boolean mounted;
         if (Environment.isExternalStorageEmulated()) {
             mounted = true;
@@ -7892,44 +8076,52 @@
         }
 
         final Intent containerIntent = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
-        ClearStorageConnection conn = new ClearStorageConnection();
-        if (mContext.bindService(containerIntent, conn, Context.BIND_AUTO_CREATE)) {
-            try {
-                long timeout = SystemClock.uptimeMillis() + 5000;
-                synchronized (conn) {
-                    long now = SystemClock.uptimeMillis();
-                    while (conn.mContainerService == null && now < timeout) {
-                        try {
-                            conn.wait(timeout - now);
-                        } catch (InterruptedException e) {
+        int[] users;
+        if (userId == UserHandle.USER_ALL) {
+            users = sUserManager.getUserIds();
+        } else {
+            users = new int[] { userId };
+        }
+        for (int curUser : users) {
+            ClearStorageConnection conn = new ClearStorageConnection();
+            if (mContext.bindService(containerIntent, conn, Context.BIND_AUTO_CREATE, curUser)) {
+                try {
+                    long timeout = SystemClock.uptimeMillis() + 5000;
+                    synchronized (conn) {
+                        long now = SystemClock.uptimeMillis();
+                        while (conn.mContainerService == null && now < timeout) {
+                            try {
+                                conn.wait(timeout - now);
+                            } catch (InterruptedException e) {
+                            }
                         }
                     }
-                }
-                if (conn.mContainerService == null) {
-                    return;
-                }
-                final File externalCacheDir = Environment
-                        .getExternalStorageAppCacheDirectory(packageName);
-                try {
-                    conn.mContainerService.clearDirectory(externalCacheDir.toString());
-                } catch (RemoteException e) {
-                }
-                if (allData) {
-                    final File externalDataDir = Environment
-                            .getExternalStorageAppDataDirectory(packageName);
+                    if (conn.mContainerService == null) {
+                        return;
+                    }
+                    final File externalCacheDir = Environment
+                            .getExternalStorageAppCacheDirectory(packageName);
                     try {
-                        conn.mContainerService.clearDirectory(externalDataDir.toString());
+                        conn.mContainerService.clearDirectory(externalCacheDir.toString());
                     } catch (RemoteException e) {
                     }
-                    final File externalMediaDir = Environment
-                            .getExternalStorageAppMediaDirectory(packageName);
-                    try {
-                        conn.mContainerService.clearDirectory(externalMediaDir.toString());
-                    } catch (RemoteException e) {
+                    if (allData) {
+                        final File externalDataDir = Environment
+                                .getExternalStorageAppDataDirectory(packageName);
+                        try {
+                            conn.mContainerService.clearDirectory(externalDataDir.toString());
+                        } catch (RemoteException e) {
+                        }
+                        final File externalMediaDir = Environment
+                                .getExternalStorageAppMediaDirectory(packageName);
+                        try {
+                            conn.mContainerService.clearDirectory(externalMediaDir.toString());
+                        } catch (RemoteException e) {
+                        }
                     }
+                } finally {
+                    mContext.unbindService(conn);
                 }
-            } finally {
-                mContext.unbindService(conn);
             }
         }
     }
@@ -7948,7 +8140,7 @@
                 synchronized (mInstallLock) {
                     succeeded = clearApplicationUserDataLI(packageName, userId);
                 }
-                clearExternalStorageDataSync(packageName, true);
+                clearExternalStorageDataSync(packageName, userId, true);
                 if (succeeded) {
                     // invoke DeviceStorageMonitor's update method to clear any notifications
                     DeviceStorageMonitorService dsm = (DeviceStorageMonitorService)
@@ -8022,7 +8214,7 @@
                 synchronized (mInstallLock) {
                     succeded = deleteApplicationCacheFilesLI(packageName, userId);
                 }
-                clearExternalStorageDataSync(packageName, false);
+                clearExternalStorageDataSync(packageName, userId, false);
                 if(observer != null) {
                     try {
                         observer.onRemoveCompleted(packageName, succeded);
@@ -8480,7 +8672,7 @@
         extras.putBoolean(Intent.EXTRA_DONT_KILL_APP, killFlag);
         extras.putInt(Intent.EXTRA_UID, packageUid);
         sendPackageBroadcast(Intent.ACTION_PACKAGE_CHANGED,  packageName, extras, null, null,
-                UserHandle.getUserId(packageUid));
+                new int[] {UserHandle.getUserId(packageUid)});
     }
 
     public void setPackageStoppedState(String packageName, boolean stopped, int userId) {
@@ -9085,7 +9277,7 @@
             if (DEBUG_SD_INSTALL)
                 Log.i(TAG, "Loading packages");
             loadMediaPackages(processCids, uidArr, removeCids);
-            startCleaningPackages();
+            startCleaningPackages(-1);
         } else {
             if (DEBUG_SD_INSTALL)
                 Log.i(TAG, "Unloading packages");
@@ -9106,7 +9298,7 @@
             }
             String action = mediaStatus ? Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE
                     : Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE;
-            sendPackageBroadcast(action, null, extras, null, finishedReceiver, UserHandle.USER_ALL);
+            sendPackageBroadcast(action, null, extras, null, finishedReceiver, null);
         }
     }
 
@@ -9151,7 +9343,7 @@
                 doGc = true;
                 synchronized (mInstallLock) {
                     final PackageParser.Package pkg = scanPackageLI(new File(codePath), parseFlags,
-                            0, 0);
+                            0, 0, null);
                     // Scan the package
                     if (pkg != null) {
                         /*
@@ -9260,8 +9452,8 @@
             // Delete package internally
             PackageRemovedInfo outInfo = new PackageRemovedInfo();
             synchronized (mInstallLock) {
-                boolean res = deletePackageLI(pkgName, false, PackageManager.DONT_DELETE_DATA,
-                        outInfo, false);
+                boolean res = deletePackageLI(pkgName, null, false,
+                        PackageManager.DELETE_KEEP_DATA, outInfo, false);
                 if (res) {
                     pkgList.add(pkgName);
                 } else {
diff --git a/services/java/com/android/server/pm/PackageSettingBase.java b/services/java/com/android/server/pm/PackageSettingBase.java
index 56f2166..6d31f0e 100644
--- a/services/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/java/com/android/server/pm/PackageSettingBase.java
@@ -20,11 +20,13 @@
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
 
+import android.content.pm.PackageUserState;
+import android.content.pm.UserInfo;
 import android.util.SparseArray;
-import android.util.SparseIntArray;
 
 import java.io.File;
 import java.util.HashSet;
+import java.util.List;
 
 /**
  * Settings base class for pending and resolved classes.
@@ -62,19 +64,11 @@
     boolean permissionsFixed;
     boolean haveGids;
 
+    private static final PackageUserState DEFAULT_USER_STATE = new PackageUserState();
+
     // Whether this package is currently stopped, thus can not be
     // started until explicitly launched by the user.
-    private SparseArray<Boolean> stopped = new SparseArray<Boolean>();
-
-    // Set to true if we have never launched this app.
-    private SparseArray<Boolean> notLaunched = new SparseArray<Boolean>();
-
-    /* Explicitly disabled components */
-    private SparseArray<HashSet<String>> disabledComponents = new SparseArray<HashSet<String>>();
-    /* Explicitly enabled components */
-    private SparseArray<HashSet<String>> enabledComponents = new SparseArray<HashSet<String>>();
-    /* Enabled state */
-    private SparseIntArray enabled = new SparseIntArray();
+    private final SparseArray<PackageUserState> userState = new SparseArray<PackageUserState>();
 
     int installStatus = PKG_INSTALL_COMPLETE;
 
@@ -115,12 +109,11 @@
 
         permissionsFixed = base.permissionsFixed;
         haveGids = base.haveGids;
-        notLaunched = base.notLaunched;
-
-        disabledComponents = (SparseArray<HashSet<String>>) base.disabledComponents.clone();
-        enabledComponents = (SparseArray<HashSet<String>>) base.enabledComponents.clone();
-        enabled = (SparseIntArray) base.enabled.clone();
-        stopped = (SparseArray<Boolean>) base.stopped.clone();
+        userState.clear();
+        for (int i=0; i<base.userState.size(); i++) {
+            userState.put(base.userState.keyAt(i),
+                    new PackageUserState(base.userState.valueAt(i)));
+        }
         installStatus = base.installStatus;
 
         origPackage = base.origPackage;
@@ -171,103 +164,174 @@
         signatures = base.signatures;
         permissionsFixed = base.permissionsFixed;
         haveGids = base.haveGids;
-        stopped = base.stopped;
-        notLaunched = base.notLaunched;
-        disabledComponents = base.disabledComponents;
-        enabledComponents = base.enabledComponents;
-        enabled = base.enabled;
+        userState.clear();
+        for (int i=0; i<base.userState.size(); i++) {
+            userState.put(base.userState.keyAt(i), base.userState.valueAt(i));
+        }
         installStatus = base.installStatus;
     }
 
+    private PackageUserState modifyUserState(int userId) {
+        PackageUserState state = userState.get(userId);
+        if (state == null) {
+            state = new PackageUserState();
+            userState.put(userId, state);
+        }
+        return state;
+    }
+
+    public PackageUserState readUserState(int userId) {
+        PackageUserState state = userState.get(userId);
+        return state != null ? state : DEFAULT_USER_STATE;
+    }
+
     void setEnabled(int state, int userId) {
-        enabled.put(userId, state);
+        modifyUserState(userId).enabled = state;
     }
 
     int getEnabled(int userId) {
-        return enabled.get(userId, COMPONENT_ENABLED_STATE_DEFAULT);
+        return readUserState(userId).enabled;
+    }
+
+    void setInstalled(boolean inst, int userId) {
+        modifyUserState(userId).installed = inst;
+    }
+
+    boolean getInstalled(int userId) {
+        return readUserState(userId).installed;
+    }
+
+    boolean isAnyInstalled(int[] users) {
+        for (int user: users) {
+            if (readUserState(user).installed) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    int[] getInstalledUsers(int[] users) {
+        int num = 0;
+        for (int user : users) {
+            if (getInstalled(user)) {
+                num++;
+            }
+        }
+        int[] res = new int[num];
+        num = 0;
+        for (int user : users) {
+            if (getInstalled(user)) {
+                res[num] = user;
+                num++;
+            }
+        }
+        return res;
     }
 
     boolean getStopped(int userId) {
-        return stopped.get(userId, false);
+        return readUserState(userId).stopped;
     }
 
     void setStopped(boolean stop, int userId) {
-        stopped.put(userId, stop);
+        modifyUserState(userId).stopped = stop;
     }
 
     boolean getNotLaunched(int userId) {
-        return notLaunched.get(userId, false);
+        return readUserState(userId).notLaunched;
     }
 
     void setNotLaunched(boolean stop, int userId) {
-        notLaunched.put(userId, stop);
+        modifyUserState(userId).notLaunched = stop;
+    }
+
+    void setUserState(int userId, int enabled, boolean installed, boolean stopped,
+            boolean notLaunched, HashSet<String> enabledComponents,
+            HashSet<String> disabledComponents) {
+        PackageUserState state = modifyUserState(userId);
+        state.enabled = enabled;
+        state.installed = installed;
+        state.stopped = stopped;
+        state.notLaunched = notLaunched;
+        state.enabledComponents = enabledComponents;
+        state.disabledComponents = disabledComponents;
     }
 
     HashSet<String> getEnabledComponents(int userId) {
-        return getComponentHashSet(enabledComponents, userId);
+        return readUserState(userId).enabledComponents;
     }
 
     HashSet<String> getDisabledComponents(int userId) {
-        return getComponentHashSet(disabledComponents, userId);
+        return readUserState(userId).disabledComponents;
     }
 
     void setEnabledComponents(HashSet<String> components, int userId) {
-        enabledComponents.put(userId, components);
+        modifyUserState(userId).enabledComponents = components;
     }
 
     void setDisabledComponents(HashSet<String> components, int userId) {
-        disabledComponents.put(userId, components);
+        modifyUserState(userId).disabledComponents = components;
     }
 
-    private HashSet<String> getComponentHashSet(SparseArray<HashSet<String>> setArray, int userId) {
-        HashSet<String> set = setArray.get(userId);
-        if (set == null) {
-            set = new HashSet<String>(1);
-            setArray.put(userId, set);
+    void setEnabledComponentsCopy(HashSet<String> components, int userId) {
+        modifyUserState(userId).enabledComponents = components != null
+                ? new HashSet<String>(components) : null;
+    }
+
+    void setDisabledComponentsCopy(HashSet<String> components, int userId) {
+        modifyUserState(userId).disabledComponents = components != null
+                ? new HashSet<String>(components) : null;
+    }
+
+    PackageUserState modifyUserStateComponents(int userId, boolean disabled, boolean enabled) {
+        PackageUserState state = modifyUserState(userId);
+        if (disabled && state.disabledComponents == null) {
+            state.disabledComponents = new HashSet<String>(1);
         }
-        return set;
+        if (enabled && state.enabledComponents == null) {
+            state.enabledComponents = new HashSet<String>(1);
+        }
+        return state;
     }
 
     void addDisabledComponent(String componentClassName, int userId) {
-        HashSet<String> disabled = getComponentHashSet(disabledComponents, userId);
-        disabled.add(componentClassName);
+        modifyUserStateComponents(userId, true, false).disabledComponents.add(componentClassName);
     }
 
     void addEnabledComponent(String componentClassName, int userId) {
-        HashSet<String> enabled = getComponentHashSet(enabledComponents, userId);
-        enabled.add(componentClassName);
+        modifyUserStateComponents(userId, false, true).enabledComponents.add(componentClassName);
     }
 
     boolean enableComponentLPw(String componentClassName, int userId) {
-        HashSet<String> disabled = getComponentHashSet(disabledComponents, userId);
-        HashSet<String> enabled = getComponentHashSet(enabledComponents, userId);
-        boolean changed = disabled.remove(componentClassName);
-        changed |= enabled.add(componentClassName);
+        PackageUserState state = modifyUserStateComponents(userId, false, true);
+        boolean changed = state.disabledComponents != null
+                ? state.disabledComponents.remove(componentClassName) : false;
+        changed |= state.enabledComponents.add(componentClassName);
         return changed;
     }
 
     boolean disableComponentLPw(String componentClassName, int userId) {
-        HashSet<String> disabled = getComponentHashSet(disabledComponents, userId);
-        HashSet<String> enabled = getComponentHashSet(enabledComponents, userId);
-        boolean changed = enabled.remove(componentClassName);
-        changed |= disabled.add(componentClassName);
+        PackageUserState state = modifyUserStateComponents(userId, true, false);
+        boolean changed = state.enabledComponents != null
+                ? state.enabledComponents.remove(componentClassName) : false;
+        changed |= state.disabledComponents.add(componentClassName);
         return changed;
     }
 
     boolean restoreComponentLPw(String componentClassName, int userId) {
-        HashSet<String> disabled = getComponentHashSet(disabledComponents, userId);
-        HashSet<String> enabled = getComponentHashSet(enabledComponents, userId);
-        boolean changed = enabled.remove(componentClassName);
-        changed |= disabled.remove(componentClassName);
+        PackageUserState state = modifyUserStateComponents(userId, true, true);
+        boolean changed = state.disabledComponents != null
+                ? state.disabledComponents.remove(componentClassName) : false;
+        changed |= state.enabledComponents != null
+                ? state.enabledComponents.remove(componentClassName) : false;
         return changed;
     }
 
     int getCurrentEnabledStateLPr(String componentName, int userId) {
-        HashSet<String> disabled = getComponentHashSet(disabledComponents, userId);
-        HashSet<String> enabled = getComponentHashSet(enabledComponents, userId);
-        if (enabled.contains(componentName)) {
+        PackageUserState state = readUserState(userId);
+        if (state.enabledComponents != null && state.enabledComponents.contains(componentName)) {
             return COMPONENT_ENABLED_STATE_ENABLED;
-        } else if (disabled.contains(componentName)) {
+        } else if (state.disabledComponents != null
+                && state.disabledComponents.contains(componentName)) {
             return COMPONENT_ENABLED_STATE_DISABLED;
         } else {
             return COMPONENT_ENABLED_STATE_DEFAULT;
@@ -275,11 +339,6 @@
     }
 
     void removeUser(int userId) {
-        enabled.delete(userId);
-        stopped.delete(userId);
-        enabledComponents.delete(userId);
-        disabledComponents.delete(userId);
-        notLaunched.delete(userId);
+        userState.delete(userId);
     }
-
 }
diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java
index cfc0f5c..a341304 100644
--- a/services/java/com/android/server/pm/Settings.java
+++ b/services/java/com/android/server/pm/Settings.java
@@ -38,11 +38,13 @@
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ComponentInfo;
+import android.content.pm.PackageCleanItem;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageParser;
 import android.content.pm.PermissionInfo;
 import android.content.pm.Signature;
 import android.content.pm.UserInfo;
+import android.content.pm.PackageUserState;
 import android.content.pm.VerifierDeviceIdentity;
 import android.os.Binder;
 import android.os.Environment;
@@ -92,9 +94,12 @@
     private static final String TAG_PACKAGE = "pkg";
 
     private static final String ATTR_NAME = "name";
+    private static final String ATTR_USER = "user";
+    private static final String ATTR_CODE = "code";
     private static final String ATTR_NOT_LAUNCHED = "nl";
     private static final String ATTR_ENABLED = "enabled";
     private static final String ATTR_STOPPED = "stopped";
+    private static final String ATTR_INSTALLED = "inst";
 
     private final File mSettingsFilename;
     private final File mBackupSettingsFilename;
@@ -156,7 +161,8 @@
 
     // Packages that have been uninstalled and still need their external
     // storage data deleted.
-    final ArrayList<String> mPackagesToBeCleaned = new ArrayList<String>();
+    final SparseArray<ArrayList<PackageCleanItem>> mPackagesToBeCleaned
+            = new SparseArray<ArrayList<PackageCleanItem>>();
     
     // Packages that have been renamed since they were first installed.
     // Keys are the new names of the packages, values are the original
@@ -200,10 +206,11 @@
 
     PackageSetting getPackageLPw(PackageParser.Package pkg, PackageSetting origPackage,
             String realName, SharedUserSetting sharedUser, File codePath, File resourcePath,
-            String nativeLibraryPathString, int pkgFlags, boolean create, boolean add) {
+            String nativeLibraryPathString, int pkgFlags, UserHandle user, boolean add) {
         final String name = pkg.packageName;
         PackageSetting p = getPackageLPw(name, origPackage, realName, sharedUser, codePath,
-                resourcePath, nativeLibraryPathString, pkg.mVersionCode, pkgFlags, create, add);
+                resourcePath, nativeLibraryPathString, pkg.mVersionCode, pkgFlags,
+                user, add);
         return p;
     }
 
@@ -364,7 +371,8 @@
 
     private PackageSetting getPackageLPw(String name, PackageSetting origPackage,
             String realName, SharedUserSetting sharedUser, File codePath, File resourcePath,
-            String nativeLibraryPathString, int vc, int pkgFlags, boolean create, boolean add) {
+            String nativeLibraryPathString, int vc, int pkgFlags,
+            UserHandle installUser, boolean add) {
         PackageSetting p = mPackages.get(name);
         if (p != null) {
             if (!p.codePath.equals(codePath)) {
@@ -407,11 +415,6 @@
             }
         }
         if (p == null) {
-            // Create a new PackageSettings entry. this can end up here because
-            // of code path mismatch or user id mismatch of an updated system partition
-            if (!create) {
-                return null;
-            }
             if (origPackage != null) {
                 // We are consuming the data from an existing package.
                 p = new PackageSetting(origPackage.name, name, codePath, resourcePath,
@@ -445,8 +448,20 @@
                     List<UserInfo> users = getAllUsers();
                     if (users != null) {
                         for (UserInfo user : users) {
-                            p.setStopped(true, user.id);
-                            p.setNotLaunched(true, user.id);
+                            // By default we consider this app to be installed
+                            // for the user if no user has been specified (which
+                            // means to leave it at its original value, and the
+                            // original default value is true), or we are being
+                            // asked to install for all users, or this is the
+                            // user we are installing for.
+                            final boolean installed = installUser == null
+                                    || installUser.getIdentifier() == UserHandle.USER_ALL
+                                    || installUser.getIdentifier() == user.id;
+                            p.setUserState(user.id, COMPONENT_ENABLED_STATE_DEFAULT,
+                                    installed,
+                                    true, // stopped,
+                                    true, // notLaunched
+                                    null, null);
                             writePackageRestrictionsLPr(user.id);
                         }
                     }
@@ -472,12 +487,10 @@
                         if (users != null) {
                             for (UserInfo user : users) {
                                 int userId = user.id;
-                                p.setDisabledComponents(
-                                        new HashSet<String>(dis.getDisabledComponents(userId)),
-                                        userId);
-                                p.setEnabledComponents(
-                                        new HashSet<String>(dis.getEnabledComponents(userId)),
-                                        userId);
+                                p.setDisabledComponentsCopy(
+                                        dis.getDisabledComponents(userId), userId);
+                                p.setEnabledComponentsCopy(
+                                        dis.getEnabledComponents(userId), userId);
                             }
                         }
                         // Add new setting to list of user ids
@@ -498,6 +511,25 @@
                 // user preferences
                 addPackageSettingLPw(p, name, sharedUser);
             }
+        } else {
+            if (installUser != null) {
+                // The caller has explicitly specified the user they want this
+                // package installed for, and the package already exists.
+                // Make sure it conforms to the new request.
+                List<UserInfo> users = getAllUsers();
+                if (users != null) {
+                    for (UserInfo user : users) {
+                        if (installUser.getIdentifier() == UserHandle.USER_ALL
+                                || installUser.getIdentifier() == user.id) {
+                            boolean installed = p.getInstalled(user.id);
+                            if (!installed) {
+                                p.setInstalled(true, user.id);
+                                writePackageRestrictionsLPr(user.id);
+                            }
+                        }
+                    }
+                }
+            }
         }
         return p;
     }
@@ -778,10 +810,14 @@
                             + "assuming all started");
                     // At first boot, make sure no packages are stopped.
                     // We usually want to have third party apps initialize
-                    // in the stopped state, but not at first boot.
+                    // in the stopped state, but not at first boot.  Also
+                    // consider all applications to be installed.
                     for (PackageSetting pkg : mPackages.values()) {
-                        pkg.setStopped(false, userId);
-                        pkg.setNotLaunched(false, userId);
+                        pkg.setUserState(userId, COMPONENT_ENABLED_STATE_DEFAULT,
+                                true,   // installed
+                                false,  // stopped
+                                false,  // notLaunched
+                                null, null);
                     }
                     return;
                 }
@@ -823,17 +859,21 @@
                         XmlUtils.skipCurrentTag(parser);
                         continue;
                     }
-                    String enabledStr = parser.getAttributeValue(null, ATTR_ENABLED);
-                    int enabled = enabledStr == null ? COMPONENT_ENABLED_STATE_DEFAULT
-                            : Integer.parseInt(enabledStr);
-                    ps.setEnabled(enabled, userId);
-                    String stoppedStr = parser.getAttributeValue(null, ATTR_STOPPED);
-                    boolean stopped = stoppedStr == null ? false : Boolean.parseBoolean(stoppedStr);
-                    ps.setStopped(stopped, userId);
-                    String notLaunchedStr = parser.getAttributeValue(null, ATTR_NOT_LAUNCHED);
-                    boolean notLaunched = stoppedStr == null ? false
-                            : Boolean.parseBoolean(notLaunchedStr);
-                    ps.setNotLaunched(notLaunched, userId);
+                    final String enabledStr = parser.getAttributeValue(null, ATTR_ENABLED);
+                    final int enabled = enabledStr == null
+                            ? COMPONENT_ENABLED_STATE_DEFAULT : Integer.parseInt(enabledStr);
+                    final String installedStr = parser.getAttributeValue(null, ATTR_INSTALLED);
+                    final boolean installed = installedStr == null
+                            ? true : Boolean.parseBoolean(installedStr);
+                    final String stoppedStr = parser.getAttributeValue(null, ATTR_STOPPED);
+                    final boolean stopped = stoppedStr == null
+                            ? false : Boolean.parseBoolean(stoppedStr);
+                    final String notLaunchedStr = parser.getAttributeValue(null, ATTR_NOT_LAUNCHED);
+                    final boolean notLaunched = stoppedStr == null
+                            ? false : Boolean.parseBoolean(notLaunchedStr);
+
+                    HashSet<String> enabledComponents = null;
+                    HashSet<String> disabledComponents = null;
 
                     int packageDepth = parser.getDepth();
                     while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
@@ -845,13 +885,14 @@
                         }
                         tagName = parser.getName();
                         if (tagName.equals(TAG_ENABLED_COMPONENTS)) {
-                            HashSet<String> components = readComponentsLPr(parser);
-                            ps.setEnabledComponents(components, userId);
+                            enabledComponents = readComponentsLPr(parser);
                         } else if (tagName.equals(TAG_DISABLED_COMPONENTS)) {
-                            HashSet<String> components = readComponentsLPr(parser);
-                            ps.setDisabledComponents(components, userId);
+                            disabledComponents = readComponentsLPr(parser);
                         }
                     }
+
+                    ps.setUserState(userId, enabled, installed, stopped, notLaunched,
+                            enabledComponents, disabledComponents);
                 } else {
                     Slog.w(PackageManagerService.TAG, "Unknown element under <stopped-packages>: "
                           + parser.getName());
@@ -876,7 +917,7 @@
 
     private HashSet<String> readComponentsLPr(XmlPullParser parser)
             throws IOException, XmlPullParserException {
-        HashSet<String> components = new HashSet<String>();
+        HashSet<String> components = null;
         int type;
         int outerDepth = parser.getDepth();
         String tagName;
@@ -891,6 +932,9 @@
             if (tagName.equals(TAG_ITEM)) {
                 String componentName = parser.getAttributeValue(null, ATTR_NAME);
                 if (componentName != null) {
+                    if (components == null) {
+                        components = new HashSet<String>();
+                    }
                     components.add(componentName);
                 }
             }
@@ -936,41 +980,44 @@
             serializer.startTag(null, TAG_PACKAGE_RESTRICTIONS);
 
             for (final PackageSetting pkg : mPackages.values()) {
-                if (pkg.getStopped(userId)
-                        || pkg.getNotLaunched(userId)
-                        || pkg.getEnabled(userId) != COMPONENT_ENABLED_STATE_DEFAULT
-                        || pkg.getEnabledComponents(userId).size() > 0
-                        || pkg.getDisabledComponents(userId).size() > 0) {
+                PackageUserState ustate = pkg.readUserState(userId);
+                if (ustate.stopped || ustate.notLaunched || !ustate.installed
+                        || ustate.enabled != COMPONENT_ENABLED_STATE_DEFAULT
+                        || (ustate.enabledComponents != null
+                                && ustate.enabledComponents.size() > 0)
+                        || (ustate.disabledComponents != null
+                                && ustate.disabledComponents.size() > 0)) {
                     serializer.startTag(null, TAG_PACKAGE);
                     serializer.attribute(null, ATTR_NAME, pkg.name);
-                    boolean stopped = pkg.getStopped(userId);
-                    boolean notLaunched = pkg.getNotLaunched(userId);
-                    int enabled = pkg.getEnabled(userId);
-                    if (DEBUG_MU) Log.i(TAG, "  pkg=" + pkg.name + ", state=" + enabled);
-                    HashSet<String> enabledComponents = pkg.getEnabledComponents(userId);
-                    HashSet<String> disabledComponents = pkg.getDisabledComponents(userId);
+                    if (DEBUG_MU) Log.i(TAG, "  pkg=" + pkg.name + ", state=" + ustate.enabled);
 
-                    if (stopped) {
+                    if (!ustate.installed) {
+                        serializer.attribute(null, ATTR_INSTALLED, "false");
+                    }
+                    if (ustate.stopped) {
                         serializer.attribute(null, ATTR_STOPPED, "true");
                     }
-                    if (notLaunched) {
+                    if (ustate.notLaunched) {
                         serializer.attribute(null, ATTR_NOT_LAUNCHED, "true");
                     }
-                    if (enabled != COMPONENT_ENABLED_STATE_DEFAULT) {
-                        serializer.attribute(null, ATTR_ENABLED, Integer.toString(enabled));
+                    if (ustate.enabled != COMPONENT_ENABLED_STATE_DEFAULT) {
+                        serializer.attribute(null, ATTR_ENABLED,
+                                Integer.toString(ustate.enabled));
                     }
-                    if (enabledComponents.size() > 0) {
+                    if (ustate.enabledComponents != null
+                            && ustate.enabledComponents.size() > 0) {
                         serializer.startTag(null, TAG_ENABLED_COMPONENTS);
-                        for (final String name : enabledComponents) {
+                        for (final String name : ustate.enabledComponents) {
                             serializer.startTag(null, TAG_ITEM);
                             serializer.attribute(null, ATTR_NAME, name);
                             serializer.endTag(null, TAG_ITEM);
                         }
                         serializer.endTag(null, TAG_ENABLED_COMPONENTS);
                     }
-                    if (disabledComponents.size() > 0) {
+                    if (ustate.disabledComponents != null
+                            && ustate.disabledComponents.size() > 0) {
                         serializer.startTag(null, TAG_DISABLED_COMPONENTS);
-                        for (final String name : disabledComponents) {
+                        for (final String name : ustate.disabledComponents) {
                             serializer.startTag(null, TAG_ITEM);
                             serializer.attribute(null, ATTR_NAME, name);
                             serializer.endTag(null, TAG_ITEM);
@@ -1210,9 +1257,17 @@
 
             if (mPackagesToBeCleaned.size() > 0) {
                 for (int i=0; i<mPackagesToBeCleaned.size(); i++) {
-                    serializer.startTag(null, "cleaning-package");
-                    serializer.attribute(null, ATTR_NAME, mPackagesToBeCleaned.get(i));
-                    serializer.endTag(null, "cleaning-package");
+                    final int userId = mPackagesToBeCleaned.keyAt(i);
+                    final String userStr = Integer.toString(userId);
+                    final ArrayList<PackageCleanItem> pkgs = mPackagesToBeCleaned.valueAt(i);
+                    for (int j=0; j<pkgs.size(); j++) {
+                        serializer.startTag(null, "cleaning-package");
+                        PackageCleanItem item = pkgs.get(i);
+                        serializer.attribute(null, ATTR_NAME, item.packageName);
+                        serializer.attribute(null, ATTR_CODE, item.andCode ? "true" : "false");
+                        serializer.attribute(null, ATTR_USER, userStr);
+                        serializer.endTag(null, "cleaning-package");
+                    }
                 }
             }
             
@@ -1468,6 +1523,17 @@
         return ret;
     }
 
+    void addPackageToCleanLPw(int userId, PackageCleanItem pkg) {
+        ArrayList<PackageCleanItem> pkgs = mPackagesToBeCleaned.get(userId);
+        if (pkgs == null) {
+            pkgs = new ArrayList<PackageCleanItem>();
+            mPackagesToBeCleaned.put(userId, pkgs);
+        }
+        if (!pkgs.contains(pkg)) {
+            pkgs.add(pkg);
+        }
+    }
+
     boolean readLPw(List<UserInfo> users) {
         FileInputStream str = null;
         if (mBackupSettingsFilename.exists()) {
@@ -1545,8 +1611,21 @@
                     readDisabledSysPackageLPw(parser);
                 } else if (tagName.equals("cleaning-package")) {
                     String name = parser.getAttributeValue(null, ATTR_NAME);
+                    String userStr = parser.getAttributeValue(null, ATTR_USER);
+                    String codeStr = parser.getAttributeValue(null, ATTR_CODE);
                     if (name != null) {
-                        mPackagesToBeCleaned.add(name);
+                        int user = 0;
+                        boolean andCode = true;
+                        try {
+                            if (userStr != null) {
+                                user = Integer.parseInt(userStr);
+                            }
+                        } catch (NumberFormatException e) {
+                        }
+                        if (codeStr != null) {
+                            andCode = Boolean.parseBoolean(codeStr);
+                        }
+                        addPackageToCleanLPw(user, new PackageCleanItem(name, andCode));
                     }
                 } else if (tagName.equals("renamed-package")) {
                     String nname = parser.getAttributeValue(null, "new");
@@ -1623,7 +1702,8 @@
             if (idObj != null && idObj instanceof SharedUserSetting) {
                 PackageSetting p = getPackageLPw(pp.name, null, pp.realName,
                         (SharedUserSetting) idObj, pp.codePath, pp.resourcePath,
-                        pp.nativeLibraryPathString, pp.versionCode, pp.pkgFlags, true, true);
+                        pp.nativeLibraryPathString, pp.versionCode, pp.pkgFlags,
+                        UserHandle.ALL, true);
                 if (p == null) {
                     PackageManagerService.reportSettingsProblem(Log.WARN,
                             "Unable to create application package for " + pp.name);
@@ -2292,6 +2372,10 @@
         return ps;
     }
 
+    private String compToString(HashSet<String> cmp) {
+        return cmp != null ? Arrays.toString(cmp.toArray()) : "[]";
+    }
+ 
     boolean isEnabledLPr(ComponentInfo componentInfo, int flags, int userId) {
         if ((flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
             return true;
@@ -2302,24 +2386,26 @@
             Log.v(PackageManagerService.TAG, "isEnabledLock - packageName = "
                     + componentInfo.packageName + " componentName = " + componentInfo.name);
             Log.v(PackageManagerService.TAG, "enabledComponents: "
-                    + Arrays.toString(packageSettings.getEnabledComponents(userId).toArray()));
+                    + compToString(packageSettings.getEnabledComponents(userId)));
             Log.v(PackageManagerService.TAG, "disabledComponents: "
-                    + Arrays.toString(packageSettings.getDisabledComponents(userId).toArray()));
+                    + compToString(packageSettings.getDisabledComponents(userId)));
         }
         if (packageSettings == null) {
             return false;
         }
-        final int enabled = packageSettings.getEnabled(userId);
-        if (enabled == COMPONENT_ENABLED_STATE_DISABLED
-                || enabled == COMPONENT_ENABLED_STATE_DISABLED_USER
+        PackageUserState ustate = packageSettings.readUserState(userId);
+        if (ustate.enabled == COMPONENT_ENABLED_STATE_DISABLED
+                || ustate.enabled == COMPONENT_ENABLED_STATE_DISABLED_USER
                 || (packageSettings.pkg != null && !packageSettings.pkg.applicationInfo.enabled
-                    && enabled == COMPONENT_ENABLED_STATE_DEFAULT)) {
+                    && ustate.enabled == COMPONENT_ENABLED_STATE_DEFAULT)) {
             return false;
         }
-        if (packageSettings.getEnabledComponents(userId).contains(componentInfo.name)) {
+        if (ustate.enabledComponents != null
+                && ustate.enabledComponents.contains(componentInfo.name)) {
             return true;
         }
-        if (packageSettings.getDisabledComponents(userId).contains(componentInfo.name)) {
+        if (ustate.disabledComponents != null
+                && ustate.disabledComponents.contains(componentInfo.name)) {
             return false;
         }
         return componentInfo.enabled;
@@ -2378,7 +2464,7 @@
                 if (pkgSetting.installerPackageName != null) {
                     PackageManagerService.sendPackageBroadcast(Intent.ACTION_PACKAGE_FIRST_LAUNCH,
                             pkgSetting.name, null,
-                            pkgSetting.installerPackageName, null, userId);
+                            pkgSetting.installerPackageName, null, new int[] {userId});
                 }
                 pkgSetting.setNotLaunched(false, userId);
             }
@@ -2427,7 +2513,6 @@
         ApplicationInfo.FLAG_RESTORE_ANY_VERSION, "RESTORE_ANY_VERSION",
         ApplicationInfo.FLAG_EXTERNAL_STORAGE, "EXTERNAL_STORAGE",
         ApplicationInfo.FLAG_LARGE_HEAP, "LARGE_HEAP",
-        ApplicationInfo.FLAG_STOPPED, "STOPPED",
         ApplicationInfo.FLAG_FORWARD_LOCK, "FORWARD_LOCK",
         ApplicationInfo.FLAG_CANT_SAVE_STATE, "CANT_SAVE_STATE",
     };
@@ -2537,22 +2622,28 @@
             pw.print("    permissionsFixed="); pw.print(ps.permissionsFixed);
             pw.print(" haveGids="); pw.println(ps.haveGids);
             pw.print("    pkgFlags=0x"); pw.print(Integer.toHexString(ps.pkgFlags));
-            pw.print(" installStatus="); pw.print(ps.installStatus);
+            pw.print(" installStatus="); pw.println(ps.installStatus);
             for (UserInfo user : users) {
-                pw.print(" User "); pw.print(user.id); pw.print(": ");
+                pw.print("    User "); pw.print(user.id); pw.print(": ");
+                pw.print(" installed=");
+                pw.print(ps.getInstalled(user.id));
                 pw.print(" stopped=");
                 pw.print(ps.getStopped(user.id));
+                pw.print(" notLaunched=");
+                pw.print(ps.getNotLaunched(user.id));
                 pw.print(" enabled=");
                 pw.println(ps.getEnabled(user.id));
-                if (ps.getDisabledComponents(user.id).size() > 0) {
-                    pw.println("    disabledComponents:");
-                    for (String s : ps.getDisabledComponents(user.id)) {
+                HashSet<String> cmp = ps.getDisabledComponents(user.id);
+                if (cmp != null && cmp.size() > 0) {
+                    pw.println("      disabledComponents:");
+                    for (String s : cmp) {
                         pw.print("      "); pw.println(s);
                     }
                 }
-                if (ps.getEnabledComponents(user.id).size() > 0) {
-                    pw.println("    enabledComponents:");
-                    for (String s : ps.getEnabledComponents(user.id)) {
+                cmp = ps.getEnabledComponents(user.id);
+                if (cmp != null && cmp.size() > 0) {
+                    pw.println("      enabledComponents:");
+                    for (String s : cmp) {
                         pw.print("      "); pw.println(s);
                     }
                 }
diff --git a/services/java/com/android/server/pm/UserManagerService.java b/services/java/com/android/server/pm/UserManagerService.java
index 6a76c5d..8899ea2 100644
--- a/services/java/com/android/server/pm/UserManagerService.java
+++ b/services/java/com/android/server/pm/UserManagerService.java
@@ -262,7 +262,9 @@
      * @return the array of user ids.
      */
     int[] getUserIds() {
-        return mUserIds;
+        synchronized (mUsers) {
+            return mUserIds;
+        }
     }
 
     private void readUserList() {
@@ -611,12 +613,11 @@
      * Caches the list of user ids in an array, adjusting the array size when necessary.
      */
     private void updateUserIdsLocked() {
-        if (mUserIds == null || mUserIds.length != mUsers.size()) {
-            mUserIds = new int[mUsers.size()];
-        }
+        int[] newUsers = new int[mUsers.size()];
         for (int i = 0; i < mUsers.size(); i++) {
-            mUserIds[i] = mUsers.keyAt(i);
+            newUsers[i] = mUsers.keyAt(i);
         }
+        mUserIds = newUsers;
     }
 
     /**
diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java
index 12ad4fea..6047cda 100644
--- a/test-runner/src/android/test/mock/MockContext.java
+++ b/test-runner/src/android/test/mock/MockContext.java
@@ -360,6 +360,18 @@
         throw new UnsupportedOperationException();
     }
 
+    /** @hide */
+    @Override
+    public ComponentName startServiceAsUser(Intent service, UserHandle user) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public boolean stopServiceAsUser(Intent service, UserHandle user) {
+        throw new UnsupportedOperationException();
+    }
+
     @Override
     public boolean bindService(Intent service, ServiceConnection conn, int flags) {
         throw new UnsupportedOperationException();
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index ac40fc6b..562f286 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -41,6 +41,7 @@
 import android.content.pm.UserInfo;
 import android.content.pm.VerificationParams;
 import android.content.pm.VerifierDeviceIdentity;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
 import android.graphics.drawable.Drawable;
@@ -531,6 +532,15 @@
         throw new UnsupportedOperationException();
     }
 
+    /**
+     * @hide
+     */
+    @Override
+    public int installExistingPackage(String packageName)
+            throws NameNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
     @Override
     public void verifyPendingInstall(int id, int verificationCode) {
         throw new UnsupportedOperationException();
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index 3d45bff..76033d4 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -1281,6 +1281,18 @@
     }
 
     @Override
+    public ComponentName startServiceAsUser(Intent arg0, UserHandle arg1) {
+        // pass
+        return null;
+    }
+
+    @Override
+    public boolean stopServiceAsUser(Intent arg0, UserHandle arg1) {
+        // pass
+        return false;
+    }
+
+    @Override
     public void unbindService(ServiceConnection arg0) {
         // pass