Always bind to DefaultContainerService as OWNER.

When PackageManagerService deals with external storage, always bind
to DefaultContainerService as USER_OWNER.  This avoids binding to a
stopped user, which would fail.

Bug: 7203111
Change-Id: I8e303c7558e8b5cbe4fea0acc9a472b598df0caa
diff --git a/core/java/android/content/pm/PackageCleanItem.java b/core/java/android/content/pm/PackageCleanItem.java
index eea3b9c..b1896aa 100644
--- a/core/java/android/content/pm/PackageCleanItem.java
+++ b/core/java/android/content/pm/PackageCleanItem.java
@@ -21,10 +21,12 @@
 
 /** @hide */
 public class PackageCleanItem {
+    public final int userId;
     public final String packageName;
     public final boolean andCode;
 
-    public PackageCleanItem(String packageName, boolean andCode) {
+    public PackageCleanItem(int userId, String packageName, boolean andCode) {
+        this.userId = userId;
         this.packageName = packageName;
         this.andCode = andCode;
     }
@@ -37,7 +39,8 @@
         try {
             if (obj != null) {
                 PackageCleanItem other = (PackageCleanItem)obj;
-                return packageName.equals(other.packageName) && andCode == other.andCode;
+                return userId == other.userId && packageName.equals(other.packageName)
+                        && andCode == other.andCode;
             }
         } catch (ClassCastException e) {
         }
@@ -47,6 +50,7 @@
     @Override
     public int hashCode() {
         int result = 17;
+        result = 31 * result + userId;
         result = 31 * result + packageName.hashCode();
         result = 31 * result + (andCode ? 1 : 0);
         return result;
@@ -57,6 +61,7 @@
     }
 
     public void writeToParcel(Parcel dest, int parcelableFlags) {
+        dest.writeInt(userId);
         dest.writeString(packageName);
         dest.writeInt(andCode ? 1 : 0);
     }
@@ -73,6 +78,7 @@
     };
 
     private PackageCleanItem(Parcel source) {
+        userId = source.readInt();
         packageName = source.readString();
         andCode = source.readInt() != 0;
     }
diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
index b36bd55..24a9d71 100644
--- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
+++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
@@ -35,6 +35,7 @@
 import android.content.res.ObbScanner;
 import android.net.Uri;
 import android.os.Environment;
+import android.os.Environment.UserEnvironment;
 import android.os.FileUtils;
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
@@ -268,15 +269,16 @@
     @Override
     protected void onHandleIntent(Intent intent) {
         if (PackageManager.ACTION_CLEAN_EXTERNAL_STORAGE.equals(intent.getAction())) {
-            IPackageManager pm = IPackageManager.Stub.asInterface(
+            final IPackageManager pm = IPackageManager.Stub.asInterface(
                     ServiceManager.getService("package"));
-            PackageCleanItem pkg = null;
+            PackageCleanItem item = null;
             try {
-                while ((pkg=pm.nextPackageToClean(pkg)) != null) {
-                    eraseFiles(Environment.getExternalStorageAppDataDirectory(pkg.packageName));
-                    eraseFiles(Environment.getExternalStorageAppMediaDirectory(pkg.packageName));
-                    if (pkg.andCode) {
-                        eraseFiles(Environment.getExternalStorageAppObbDirectory(pkg.packageName));
+                while ((item = pm.nextPackageToClean(item)) != null) {
+                    final UserEnvironment userEnv = new UserEnvironment(item.userId);
+                    eraseFiles(userEnv.getExternalStorageAppDataDirectory(item.packageName));
+                    eraseFiles(userEnv.getExternalStorageAppMediaDirectory(item.packageName));
+                    if (item.andCode) {
+                        eraseFiles(userEnv.getExternalStorageAppObbDirectory(item.packageName));
                     }
                 }
             } catch (RemoteException e) {
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 4b4febd..4800e7db 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -413,7 +413,6 @@
     // package uri's from external media onto secure containers
     // or internal storage.
     private IMediaContainerService mContainerService = null;
-    private int mContainerServiceUserId;
 
     static final int SEND_PENDING_BROADCAST = 1;
     static final int MCS_BOUND = 3;
@@ -482,15 +481,8 @@
                     " DefaultContainerService");
             Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
             Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
-            mContainerServiceUserId = 0;
-            if (mPendingInstalls.size() > 0) {
-                mContainerServiceUserId = mPendingInstalls.get(0).getUser().getIdentifier();
-                if (mContainerServiceUserId == UserHandle.USER_ALL) {
-                    mContainerServiceUserId = 0;
-                }
-            }
             if (mContext.bindService(service, mDefContainerConn,
-                    Context.BIND_AUTO_CREATE, mContainerServiceUserId)) {
+                    Context.BIND_AUTO_CREATE, UserHandle.USER_OWNER)) {
                 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                 mBound = true;
                 return true;
@@ -567,15 +559,6 @@
                     } else if (mPendingInstalls.size() > 0) {
                         HandlerParams params = mPendingInstalls.get(0);
                         if (params != null) {
-                            // Check if we're connected to the correct service, if it's an install
-                            // request.
-                            final int installFor = params.getUser().getIdentifier();
-                            if (installFor != mContainerServiceUserId
-                                    && (installFor == UserHandle.USER_ALL
-                                            && mContainerServiceUserId != 0)) {
-                                mHandler.sendEmptyMessage(MCS_RECONNECT);
-                                return;
-                            }
                             if (params.startCopy()) {
                                 // We are done...  look for more work or to
                                 // go idle.
@@ -693,20 +676,23 @@
                 }
                 case START_CLEANING_PACKAGE: {
                     Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
-                    PackageCleanItem item = new PackageCleanItem((String)msg.obj,
-                            msg.arg2 != 0);
+                    final String packageName = (String)msg.obj;
+                    final int userId = msg.arg1;
+                    final boolean andCode = msg.arg2 != 0;
                     synchronized (mPackages) {
-                        if (msg.arg1 == UserHandle.USER_ALL) {
+                        if (userId == UserHandle.USER_ALL) {
                             int[] users = sUserManager.getUserIds();
                             for (int user : users) {
-                                mSettings.addPackageToCleanLPw(user, item);
+                                mSettings.addPackageToCleanLPw(
+                                        new PackageCleanItem(user, packageName, andCode));
                             }
                         } else {
-                            mSettings.addPackageToCleanLPw(msg.arg1, item);
+                            mSettings.addPackageToCleanLPw(
+                                    new PackageCleanItem(userId, packageName, andCode));
                         }
                     }
                     Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
-                    startCleaningPackages(-1);
+                    startCleaningPackages();
                 } break;
                 case POST_INSTALL: {
                     if (DEBUG_INSTALL) Log.v(TAG, "Handling post-install for " + msg.arg1);
@@ -4193,10 +4179,14 @@
             // Add the new setting to mPackages
             mPackages.put(pkg.applicationInfo.packageName, pkg);
             // Make sure we don't accidentally delete its data.
-            for (int i=0; i<mSettings.mPackagesToBeCleaned.size(); i++) {
-                mSettings.mPackagesToBeCleaned.valueAt(i).remove(pkgName);
+            final Iterator<PackageCleanItem> iter = mSettings.mPackagesToBeCleaned.iterator();
+            while (iter.hasNext()) {
+                PackageCleanItem item = iter.next();
+                if (pkgName.equals(item.packageName)) {
+                    iter.remove();
+                }
             }
-            
+
             // Take care of first install / last update times.
             if (currentTime != 0) {
                 if (pkgSetting.firstInstallTime == 0) {
@@ -5443,7 +5433,6 @@
 
     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,
@@ -5451,23 +5440,13 @@
                 // packages files and can not delete any more.  Bail.
                 return null;
             }
-            ArrayList<PackageCleanItem> pkgs = mSettings.mPackagesToBeCleaned.get(userId);
-            if (pkgs != null) {
-                if (lastPackage != null) {
-                    pkgs.remove(lastPackage);
-                }
-                if (pkgs.size() > 0) {
-                    return pkgs.get(0);
-                }
+            final ArrayList<PackageCleanItem> pkgs = mSettings.mPackagesToBeCleaned;
+            if (lastPackage != null) {
+                pkgs.remove(lastPackage);
             }
-            mSettings.mPackagesToBeCleaned.remove(userId);
-        }
-        // Move on to the next user to clean.
-        long ident = Binder.clearCallingIdentity();
-        try {
-            startCleaningPackages(userId);
-        } finally {
-            Binder.restoreCallingIdentity(ident);
+            if (pkgs.size() > 0) {
+                return pkgs.get(0);
+            }
         }
         return null;
     }
@@ -5483,34 +5462,22 @@
                 userId, andCode ? 1 : 0, packageName));
     }
     
-    void startCleaningPackages(int lastUser) {
+    void startCleaningPackages() {
         // reader
-        int nextUser = -1;
         synchronized (mPackages) {
             if (!isExternalMediaAvailable()) {
                 return;
             }
-            final int N = mSettings.mPackagesToBeCleaned.size();
-            if (N <= 0) {
+            if (mSettings.mPackagesToBeCleaned.isEmpty()) {
                 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, nextUser);
+                am.startService(null, intent, null, UserHandle.USER_OWNER);
             } catch (RemoteException e) {
             }
         }
@@ -8399,10 +8366,11 @@
         } else {
             users = new int[] { userId };
         }
-        for (int curUser : users) {
-            ClearStorageConnection conn = new ClearStorageConnection();
-            if (mContext.bindService(containerIntent, conn, Context.BIND_AUTO_CREATE, curUser)) {
-                try {
+        final ClearStorageConnection conn = new ClearStorageConnection();
+        if (mContext.bindService(
+                containerIntent, conn, Context.BIND_AUTO_CREATE, UserHandle.USER_OWNER)) {
+            try {
+                for (int curUser : users) {
                     long timeout = SystemClock.uptimeMillis() + 5000;
                     synchronized (conn) {
                         long now = SystemClock.uptimeMillis();
@@ -8438,9 +8406,9 @@
                         } catch (RemoteException e) {
                         }
                     }
-                } finally {
-                    mContext.unbindService(conn);
                 }
+            } finally {
+                mContext.unbindService(conn);
             }
         }
     }
@@ -9596,7 +9564,7 @@
             if (DEBUG_SD_INSTALL)
                 Log.i(TAG, "Loading packages");
             loadMediaPackages(processCids, uidArr, removeCids);
-            startCleaningPackages(-1);
+            startCleaningPackages();
         } else {
             if (DEBUG_SD_INSTALL)
                 Log.i(TAG, "Unloading packages");
diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java
index 23e54678..2fb853a 100644
--- a/services/java/com/android/server/pm/Settings.java
+++ b/services/java/com/android/server/pm/Settings.java
@@ -159,8 +159,7 @@
 
     // Packages that have been uninstalled and still need their external
     // storage data deleted.
-    final SparseArray<ArrayList<PackageCleanItem>> mPackagesToBeCleaned
-            = new SparseArray<ArrayList<PackageCleanItem>>();
+    final ArrayList<PackageCleanItem> mPackagesToBeCleaned = new ArrayList<PackageCleanItem>();
     
     // Packages that have been renamed since they were first installed.
     // Keys are the new names of the packages, values are the original
@@ -1257,18 +1256,13 @@
             }
 
             if (mPackagesToBeCleaned.size() > 0) {
-                for (int i=0; i<mPackagesToBeCleaned.size(); i++) {
-                    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(j);
-                        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");
-                    }
+                for (PackageCleanItem item : mPackagesToBeCleaned) {
+                    final String userStr = Integer.toString(item.userId);
+                    serializer.startTag(null, "cleaning-package");
+                    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");
                 }
             }
             
@@ -1524,14 +1518,9 @@
         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);
+    void addPackageToCleanLPw(PackageCleanItem pkg) {
+        if (!mPackagesToBeCleaned.contains(pkg)) {
+            mPackagesToBeCleaned.add(pkg);
         }
     }
 
@@ -1615,18 +1604,18 @@
                     String userStr = parser.getAttributeValue(null, ATTR_USER);
                     String codeStr = parser.getAttributeValue(null, ATTR_CODE);
                     if (name != null) {
-                        int user = 0;
+                        int userId = 0;
                         boolean andCode = true;
                         try {
                             if (userStr != null) {
-                                user = Integer.parseInt(userStr);
+                                userId = Integer.parseInt(userStr);
                             }
                         } catch (NumberFormatException e) {
                         }
                         if (codeStr != null) {
                             andCode = Boolean.parseBoolean(codeStr);
                         }
-                        addPackageToCleanLPw(user, new PackageCleanItem(name, andCode));
+                        addPackageToCleanLPw(new PackageCleanItem(userId, name, andCode));
                     }
                 } else if (tagName.equals("renamed-package")) {
                     String nname = parser.getAttributeValue(null, "new");