Merge "Teach DCS about cluster packages."
diff --git a/Android.mk b/Android.mk
index c22bc73..0c5051c 100644
--- a/Android.mk
+++ b/Android.mk
@@ -259,6 +259,7 @@
 	core/java/com/android/internal/policy/IKeyguardExitCallback.aidl \
 	core/java/com/android/internal/policy/IKeyguardService.aidl \
 	core/java/com/android/internal/os/IDropBoxManagerService.aidl \
+	core/java/com/android/internal/os/IParcelFileDescriptorFactory.aidl \
 	core/java/com/android/internal/os/IResultReceiver.aidl \
 	core/java/com/android/internal/statusbar/IStatusBar.aidl \
 	core/java/com/android/internal/statusbar/IStatusBarService.aidl \
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index a5290aa..bb47124 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -232,6 +232,8 @@
     public static class PackageLite {
         public final String packageName;
         public final int versionCode;
+        public final int installLocation;
+        public final VerifierInfo[] verifiers;
 
         /** Names of any split APKs, ordered by parsed splitName */
         public final String[] splitNames;
@@ -248,13 +250,15 @@
         /** Paths of any split APKs, ordered by parsed splitName */
         public final String[] splitCodePaths;
 
-        private PackageLite(String packageName, int versionCode, String[] splitNames,
-                String codePath, String baseCodePath, String[] splitCodePaths) {
-            this.packageName = packageName;
-            this.versionCode = versionCode;
+        private PackageLite(String codePath, ApkLite baseApk, String[] splitNames,
+                String[] splitCodePaths) {
+            this.packageName = baseApk.packageName;
+            this.versionCode = baseApk.versionCode;
+            this.installLocation = baseApk.installLocation;
+            this.verifiers = baseApk.verifiers;
             this.splitNames = splitNames;
             this.codePath = codePath;
-            this.baseCodePath = baseCodePath;
+            this.baseCodePath = baseApk.codePath;
             this.splitCodePaths = splitCodePaths;
         }
 
@@ -272,6 +276,7 @@
      * Lightweight parsed details about a single APK file.
      */
     public static class ApkLite {
+        public final String codePath;
         public final String packageName;
         public final String splitName;
         public final int versionCode;
@@ -279,8 +284,9 @@
         public final VerifierInfo[] verifiers;
         public final Signature[] signatures;
 
-        public ApkLite(String packageName, String splitName, int versionCode,
+        public ApkLite(String codePath, String packageName, String splitName, int versionCode,
                 int installLocation, List<VerifierInfo> verifiers, Signature[] signatures) {
+            this.codePath = codePath;
             this.packageName = packageName;
             this.splitName = splitName;
             this.versionCode = versionCode;
@@ -592,10 +598,9 @@
 
     private static PackageLite parseMonolithicPackageLite(File packageFile, int flags)
             throws PackageParserException {
-        final ApkLite lite = parseApkLite(packageFile, flags);
+        final ApkLite baseApk = parseApkLite(packageFile, flags);
         final String packagePath = packageFile.getAbsolutePath();
-        return new PackageLite(lite.packageName, lite.versionCode, null,
-                packagePath, packagePath, null);
+        return new PackageLite(packagePath, baseApk, null, null);
     }
 
     private static PackageLite parseClusterPackageLite(File packageDir, int flags)
@@ -609,7 +614,7 @@
         String packageName = null;
         int versionCode = 0;
 
-        final ArrayMap<String, File> apks = new ArrayMap<>();
+        final ArrayMap<String, ApkLite> apks = new ArrayMap<>();
         for (File file : files) {
             if (isApkFile(file)) {
                 final ApkLite lite = parseApkLite(file, flags);
@@ -633,7 +638,7 @@
                 }
 
                 // Assert that each split is defined only once
-                if (apks.put(lite.splitName, file) != null) {
+                if (apks.put(lite.splitName, lite) != null) {
                     throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
                             "Split name " + lite.splitName
                             + " defined more than once; most recent was " + file);
@@ -641,7 +646,7 @@
             }
         }
 
-        final File baseApk = apks.remove(null);
+        final ApkLite baseApk = apks.remove(null);
         if (baseApk == null) {
             throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
                     "Missing base APK in " + packageDir);
@@ -660,14 +665,12 @@
             Arrays.sort(splitNames, sSplitNameComparator);
 
             for (int i = 0; i < size; i++) {
-                splitCodePaths[i] = apks.get(splitNames[i]).getAbsolutePath();
+                splitCodePaths[i] = apks.get(splitNames[i]).codePath;
             }
         }
 
         final String codePath = packageDir.getAbsolutePath();
-        final String baseCodePath = baseApk.getAbsolutePath();
-        return new PackageLite(packageName, versionCode, splitNames, codePath, baseCodePath,
-                splitCodePaths);
+        return new PackageLite(codePath, baseApk, splitNames, splitCodePaths);
     }
 
     public Package parsePackage(File packageFile, int flags) throws PackageParserException {
@@ -1020,7 +1023,7 @@
             }
 
             final AttributeSet attrs = parser;
-            return parseApkLite(res, parser, attrs, flags, signatures);
+            return parseApkLite(apkPath, res, parser, attrs, flags, signatures);
 
         } catch (XmlPullParserException | IOException | RuntimeException e) {
             throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
@@ -1101,7 +1104,7 @@
                 (splitName != null) ? splitName.intern() : splitName);
     }
 
-    private static ApkLite parseApkLite(Resources res, XmlPullParser parser,
+    private static ApkLite parseApkLite(String codePath, Resources res, XmlPullParser parser,
             AttributeSet attrs, int flags, Signature[] signatures) throws IOException,
             XmlPullParserException, PackageParserException {
         final Pair<String, String> packageSplit = parsePackageSplitNames(parser, attrs, flags);
@@ -1143,7 +1146,7 @@
             }
         }
 
-        return new ApkLite(packageSplit.first, packageSplit.second, versionCode,
+        return new ApkLite(codePath, packageSplit.first, packageSplit.second, versionCode,
                 installLocation, verifiers, signatures);
     }
 
diff --git a/core/java/com/android/internal/app/IMediaContainerService.aidl b/core/java/com/android/internal/app/IMediaContainerService.aidl
index 7904cba..7a3ffdf 100644
--- a/core/java/com/android/internal/app/IMediaContainerService.aidl
+++ b/core/java/com/android/internal/app/IMediaContainerService.aidl
@@ -16,15 +16,15 @@
 
 package com.android.internal.app;
 
-import android.os.ParcelFileDescriptor;
+import com.android.internal.os.IParcelFileDescriptorFactory;
 import android.content.pm.PackageInfoLite;
 import android.content.res.ObbInfo;
 
 interface IMediaContainerService {
-    String copyResourceToContainer(String packagePath, String containerId, String key,
-            String resFileName, String publicResFileName, boolean isExternal,
-            boolean isForwardLocked, String abiOverride);
-    int copyResource(String packagePath, in ParcelFileDescriptor outStream);
+    String copyPackageToContainer(String packagePath, String containerId, String key,
+            boolean isExternal, boolean isForwardLocked, String abiOverride);
+    int copyPackage(String packagePath, in IParcelFileDescriptorFactory target);
+
     PackageInfoLite getMinimalPackageInfo(String packagePath, int flags, long threshold,
             String abiOverride);
     boolean checkInternalFreeStorage(String packagePath, boolean isForwardLocked, long threshold);
diff --git a/core/java/com/android/internal/content/NativeLibraryHelper.java b/core/java/com/android/internal/content/NativeLibraryHelper.java
index af0068e..b4352f8 100644
--- a/core/java/com/android/internal/content/NativeLibraryHelper.java
+++ b/core/java/com/android/internal/content/NativeLibraryHelper.java
@@ -57,13 +57,15 @@
         final long[] apkHandles;
 
         public static Handle create(File packageFile) throws IOException {
-            final PackageLite lite;
             try {
-                lite = PackageParser.parsePackageLite(packageFile, 0);
+                final PackageLite lite = PackageParser.parsePackageLite(packageFile, 0);
+                return create(lite);
             } catch (PackageParserException e) {
                 throw new IOException("Failed to parse package: " + packageFile, e);
             }
+        }
 
+        public static Handle create(PackageLite lite) throws IOException {
             final List<String> codePaths = lite.getAllCodePaths();
             final int size = codePaths.size();
             final long[] apkHandles = new long[size];
diff --git a/core/java/com/android/internal/content/PackageHelper.java b/core/java/com/android/internal/content/PackageHelper.java
index 1a4835b..eff6684 100644
--- a/core/java/com/android/internal/content/PackageHelper.java
+++ b/core/java/com/android/internal/content/PackageHelper.java
@@ -207,7 +207,10 @@
        return false;
    }
 
-    public static int extractPublicFiles(String packagePath, File publicZipFile)
+    /**
+     * Extract public files for the single given APK.
+     */
+    public static int extractPublicFiles(String apkPath, File publicZipFile)
             throws IOException {
         final FileOutputStream fstr;
         final ZipOutputStream publicZipOutStream;
@@ -223,7 +226,7 @@
         int size = 0;
 
         try {
-            final ZipFile privateZip = new ZipFile(packagePath);
+            final ZipFile privateZip = new ZipFile(apkPath);
             try {
                 // Copy manifest, resources.arsc and res directory to public zip
                 for (final ZipEntry zipEntry : Collections.list(privateZip.entries())) {
diff --git a/core/java/com/android/internal/os/IParcelFileDescriptorFactory.aidl b/core/java/com/android/internal/os/IParcelFileDescriptorFactory.aidl
new file mode 100644
index 0000000..c9dcd06
--- /dev/null
+++ b/core/java/com/android/internal/os/IParcelFileDescriptorFactory.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2014 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 com.android.internal.os;
+
+import android.os.ParcelFileDescriptor;
+
+/** {@hide} */
+interface IParcelFileDescriptorFactory {
+    // NOTE: implementors should carefully sanitize the incoming name
+    // using something like FileUtils.isValidExtFilename()
+    ParcelFileDescriptor open(String name, int mode);
+}
diff --git a/packages/DefaultContainerService/AndroidManifest.xml b/packages/DefaultContainerService/AndroidManifest.xml
index 57c87e4..14777a9 100644
--- a/packages/DefaultContainerService/AndroidManifest.xml
+++ b/packages/DefaultContainerService/AndroidManifest.xml
@@ -1,7 +1,5 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
         package="com.android.defcontainer" coreApp="true">
-    <uses-permission android:name="android.permission.ACCESS_DOWNLOAD_MANAGER"/>
-    <uses-permission android:name="android.permission.ACCESS_ALL_DOWNLOADS"/>
     <uses-permission android:name="android.permission.ASEC_ACCESS"/>
     <uses-permission android:name="android.permission.ASEC_CREATE"/>
     <uses-permission android:name="android.permission.ASEC_DESTROY"/>
diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
index 1a4bbaa..7a21b92 100644
--- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
+++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
@@ -19,13 +19,12 @@
 import android.app.IntentService;
 import android.content.Intent;
 import android.content.pm.IPackageManager;
-import android.content.pm.LimitedLengthInputStream;
-import android.content.pm.MacAuthenticatedInputStream;
 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.PackageParser.PackageLite;
 import android.content.pm.PackageParser.PackageParserException;
 import android.content.res.ObbInfo;
 import android.content.res.ObbScanner;
@@ -47,36 +46,25 @@
 
 import com.android.internal.app.IMediaContainerService;
 import com.android.internal.content.NativeLibraryHelper;
-import com.android.internal.content.NativeLibraryHelper.Handle;
 import com.android.internal.content.PackageHelper;
+import com.android.internal.os.IParcelFileDescriptorFactory;
+import com.android.internal.util.ArrayUtils;
 
 import libcore.io.IoUtils;
 import libcore.io.Streams;
 
-import java.io.BufferedInputStream;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.security.DigestException;
-import java.security.GeneralSecurityException;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.InvalidKeyException;
-import java.security.NoSuchAlgorithmException;
 
-import javax.crypto.Cipher;
-import javax.crypto.CipherInputStream;
-import javax.crypto.Mac;
-import javax.crypto.NoSuchPaddingException;
-
-/*
- * This service copies a downloaded apk to a file passed in as
- * a ParcelFileDescriptor or to a newly created container specified
- * by parameters. The DownloadManager gives access to this process
- * based on its uid. This process also needs the ACCESS_DOWNLOAD_MANAGER
- * permission to access apks downloaded via the download manager.
+/**
+ * Service that offers to inspect and copy files that may reside on removable
+ * storage. This is designed to prevent the system process from holding onto
+ * open files that cause the kernel to kill it when the underlying device is
+ * removed.
  */
 public class DefaultContainerService extends IntentService {
     private static final String TAG = "DefContainer";
@@ -84,25 +72,26 @@
 
     private static final String LIB_DIR_NAME = "lib";
 
+    // TODO: migrate native code unpacking to always be a derivative work
+
     private IMediaContainerService.Stub mBinder = new IMediaContainerService.Stub() {
         /**
-         * Creates a new container and copies resource there.
-         * @param packageURI the uri of resource to be copied. Can be either
-         * a content uri or a file uri
-         * @param cid the id of the secure container that should
-         * be used for creating a secure container into which the resource
-         * will be copied.
-         * @param key Refers to key used for encrypting the secure container
-         * @param resFileName Name of the target resource file(relative to newly
-         * created secure container)
-         * @return Returns the new cache path where the resource has been copied into
+         * Creates a new container and copies package there.
          *
+         * @param packagePath absolute path to the package to be copied. Can be
+         *            a single monolithic APK file or a cluster directory
+         *            containing one or more APKs.
+         * @param containerId the id of the secure container that should be used
+         *            for creating a secure container into which the resource
+         *            will be copied.
+         * @param key Refers to key used for encrypting the secure container
+         * @return Returns the new cache path where the resource has been copied
+         *         into
          */
         @Override
-        public String copyResourceToContainer(final String packagePath, final String cid,
-                final String key, final String resFileName, final String publicResFileName,
+        public String copyPackageToContainer(String packagePath, String containerId, String key,
                 boolean isExternal, boolean isForwardLocked, String abiOverride) {
-            if (packagePath == null || cid == null) {
+            if (packagePath == null || containerId == null) {
                 return null;
             }
 
@@ -115,13 +104,16 @@
                 }
             }
 
-            Handle handle = null;
+            PackageLite pkg = null;
+            NativeLibraryHelper.Handle handle = null;
             try {
-                handle = Handle.create(new File(packagePath));
-                return copyResourceInner(packagePath, cid, key, resFileName, publicResFileName,
-                        isExternal, isForwardLocked, handle, abiOverride);
-            } catch (IOException ioe) {
-                Slog.w(TAG, "Problem opening APK: " + packagePath);
+                final File packageFile = new File(packagePath);
+                pkg = PackageParser.parsePackageLite(packageFile, 0);
+                handle = NativeLibraryHelper.Handle.create(pkg);
+                return copyPackageToContainerInner(pkg, handle, containerId, key, isExternal,
+                        isForwardLocked, abiOverride);
+            } catch (PackageParserException | IOException e) {
+                Slog.w(TAG, "Failed to parse package at " + packagePath);
                 return null;
             } finally {
                 IoUtils.closeQuietly(handle);
@@ -129,44 +121,37 @@
         }
 
         /**
-         * Copy specified resource to output stream
+         * Copy package to the target location.
          *
-         * @param packageURI the uri of resource to be copied. Should be a file
-         *            uri
-         * @param encryptionParams parameters describing the encryption used for
-         *            this file
-         * @param outStream Remote file descriptor to be used for copying
+         * @param packagePath absolute path to the package to be copied. Can be
+         *            a single monolithic APK file or a cluster directory
+         *            containing one or more APKs.
          * @return returns status code according to those in
          *         {@link PackageManager}
          */
         @Override
-        public int copyResource(final String packagePath, ParcelFileDescriptor outStream) {
-            if (packagePath == null || outStream == null) {
+        public int copyPackage(String packagePath, IParcelFileDescriptorFactory target) {
+            if (packagePath == null || target == null) {
                 return PackageManager.INSTALL_FAILED_INVALID_URI;
             }
 
-            InputStream in = null;
-            OutputStream out = null;
+            PackageLite pkg = null;
             try {
-                in = new FileInputStream(packagePath);
-                out = new ParcelFileDescriptor.AutoCloseOutputStream(outStream);
-                Streams.copy(in, out);
-                return PackageManager.INSTALL_SUCCEEDED;
-            } catch (IOException e) {
-                Slog.e(TAG, "Failed to copy " + packagePath, e);
+                final File packageFile = new File(packagePath);
+                pkg = PackageParser.parsePackageLite(packageFile, 0);
+                return copyPackageInner(pkg, target);
+            } catch (PackageParserException | IOException | RemoteException e) {
+                Slog.w(TAG, "Failed to copy package at " + packagePath + ": " + e);
                 return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
-            } finally {
-                IoUtils.closeQuietly(out);
-                IoUtils.closeQuietly(in);
             }
         }
 
         /**
-         * Determine the recommended install location for package
-         * specified by file uri location.
+         * Parse given package and return minimal details.
          *
-         * @return Returns PackageInfoLite object containing
-         * the package info and recommended app location.
+         * @param packagePath absolute path to the package to be copied. Can be
+         *            a single monolithic APK file or a cluster directory
+         *            containing one or more APKs.
          */
         @Override
         public PackageInfoLite getMinimalPackageInfo(final String packagePath, int flags,
@@ -179,14 +164,14 @@
                 return ret;
             }
 
-            final File apkFile = new File(packagePath);
-            final PackageParser.ApkLite pkg;
+            final File packageFile = new File(packagePath);
+            final PackageParser.PackageLite pkg;
             try {
-                pkg = PackageParser.parseApkLite(apkFile, 0);
+                pkg = PackageParser.parsePackageLite(packageFile, 0);
             } catch (PackageParserException e) {
-                Slog.w(TAG, "Failed to parse package");
+                Slog.w(TAG, "Failed to parse package at " + packagePath);
 
-                if (!apkFile.exists()) {
+                if (!packageFile.exists()) {
                     ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_URI;
                 } else {
                     ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_APK;
@@ -199,32 +184,51 @@
             ret.versionCode = pkg.versionCode;
             ret.installLocation = pkg.installLocation;
             ret.verifiers = pkg.verifiers;
-
-            ret.recommendedInstallLocation = recommendAppInstallLocation(pkg.installLocation,
-                    packagePath, flags, threshold, abiOverride);
+            ret.recommendedInstallLocation = recommendAppInstallLocation(pkg, flags, threshold,
+                    abiOverride);
 
             return ret;
         }
 
+        /**
+         * Determine if package will fit on internal storage.
+         *
+         * @param packagePath absolute path to the package to be copied. Can be
+         *            a single monolithic APK file or a cluster directory
+         *            containing one or more APKs.
+         */
         @Override
         public boolean checkInternalFreeStorage(String packagePath, boolean isForwardLocked,
                 long threshold) throws RemoteException {
-            final File apkFile = new File(packagePath);
+            final File packageFile = new File(packagePath);
+            final PackageParser.PackageLite pkg;
             try {
-                return isUnderInternalThreshold(apkFile, isForwardLocked, threshold);
-            } catch (IOException e) {
-                return true;
+                pkg = PackageParser.parsePackageLite(packageFile, 0);
+                return isUnderInternalThreshold(pkg, isForwardLocked, threshold);
+            } catch (PackageParserException | IOException e) {
+                Slog.w(TAG, "Failed to parse package at " + packagePath);
+                return false;
             }
         }
 
+        /**
+         * Determine if package will fit on external storage.
+         *
+         * @param packagePath absolute path to the package to be copied. Can be
+         *            a single monolithic APK file or a cluster directory
+         *            containing one or more APKs.
+         */
         @Override
         public boolean checkExternalFreeStorage(String packagePath, boolean isForwardLocked,
                 String abiOverride) throws RemoteException {
-            final File apkFile = new File(packagePath);
+            final File packageFile = new File(packagePath);
+            final PackageParser.PackageLite pkg;
             try {
-                return isUnderExternalThreshold(apkFile, isForwardLocked, abiOverride);
-            } catch (IOException e) {
-                return true;
+                pkg = PackageParser.parsePackageLite(packageFile, 0);
+                return isUnderExternalThreshold(pkg, isForwardLocked, abiOverride);
+            } catch (PackageParserException | IOException e) {
+                Slog.w(TAG, "Failed to parse package at " + packagePath);
+                return false;
             }
         }
 
@@ -275,13 +279,22 @@
             }
         }
 
+        /**
+         * Calculate estimated footprint of given package post-installation.
+         *
+         * @param packagePath absolute path to the package to be copied. Can be
+         *            a single monolithic APK file or a cluster directory
+         *            containing one or more APKs.
+         */
         @Override
         public long calculateInstalledSize(String packagePath, boolean isForwardLocked,
                 String abiOverride) throws RemoteException {
             final File packageFile = new File(packagePath);
+            final PackageParser.PackageLite pkg;
             try {
-                return calculateContainerSize(packageFile, isForwardLocked, abiOverride) * 1024 * 1024;
-            } catch (IOException e) {
+                pkg = PackageParser.parsePackageLite(packageFile, 0);
+                return calculateContainerSize(pkg, isForwardLocked, abiOverride) * 1024 * 1024;
+            } catch (PackageParserException | IOException e) {
                 /*
                  * Okay, something failed, so let's just estimate it to be 2x
                  * the file size. Note this will be 0 if the file doesn't exist.
@@ -333,16 +346,25 @@
         }
         path.delete();
     }
-    
+
+    @Override
     public IBinder onBind(Intent intent) {
         return mBinder;
     }
 
-    private String copyResourceInner(String packagePath, String newCid, String key, String resFileName,
-            String publicResFileName, boolean isExternal, boolean isForwardLocked,
-            Handle handle, String abiOverride) {
+    private String copyPackageToContainerInner(PackageLite pkg, NativeLibraryHelper.Handle handle,
+            String newCid, String key, boolean isExternal, boolean isForwardLocked,
+            String abiOverride) {
+        // TODO: extend to support copying all split APKs
+        if (!ArrayUtils.isEmpty(pkg.splitNames)) {
+            throw new UnsupportedOperationException("Copying split APKs not yet supported");
+        }
+
+        final String resFileName = "pkg.apk";
+        final String publicResFileName = "res.zip";
+
         // The .apk file
-        String codePath = packagePath;
+        String codePath = pkg.baseCodePath;
         File codeFile = new File(codePath);
 
         String[] abiList = Build.SUPPORTED_ABIS;
@@ -360,12 +382,12 @@
             }
         }
 
-        final int abi = NativeLibraryHelper.findSupportedAbi(handle, abiList);
+        final int abiIndex = NativeLibraryHelper.findSupportedAbi(handle, abiList);
 
         // Calculate size of container needed to hold base APK.
         final int sizeMb;
         try {
-            sizeMb = calculateContainerSize(handle, codeFile, abi, isForwardLocked);
+            sizeMb = calculateContainerSize(pkg, handle, isForwardLocked, abiIndex);
         } catch (IOException e) {
             Slog.w(TAG, "Problem when trying to copy " + codeFile.getPath());
             return null;
@@ -429,11 +451,11 @@
         final File sharedLibraryDir = new File(newCachePath, LIB_DIR_NAME);
         if (sharedLibraryDir.mkdir()) {
             int ret = PackageManager.INSTALL_SUCCEEDED;
-            if (abi >= 0) {
+            if (abiIndex >= 0) {
                 ret = NativeLibraryHelper.copyNativeBinariesIfNeededLI(handle,
-                        sharedLibraryDir, abiList[abi]);
-            } else if (abi != PackageManager.NO_NATIVE_LIBRARIES) {
-                ret = abi;
+                        sharedLibraryDir, abiList[abiIndex]);
+            } else if (abiIndex != PackageManager.NO_NATIVE_LIBRARIES) {
+                ret = abiIndex;
             }
 
             if (ret != PackageManager.INSTALL_SUCCEEDED) {
@@ -475,11 +497,32 @@
         return newCachePath;
     }
 
+    private int copyPackageInner(PackageLite pkg, IParcelFileDescriptorFactory target)
+            throws IOException, RemoteException {
+        // TODO: extend to support copying all split APKs
+        if (!ArrayUtils.isEmpty(pkg.splitNames)) {
+            throw new UnsupportedOperationException("Copying split APKs not yet supported");
+        }
+
+        InputStream in = null;
+        OutputStream out = null;
+        try {
+            in = new FileInputStream(pkg.baseCodePath);
+            out = new ParcelFileDescriptor.AutoCloseOutputStream(
+                    target.open(null, ParcelFileDescriptor.MODE_READ_WRITE));
+            Streams.copy(in, out);
+            return PackageManager.INSTALL_SUCCEEDED;
+        } finally {
+            IoUtils.closeQuietly(out);
+            IoUtils.closeQuietly(in);
+        }
+    }
+
     private static final int PREFER_INTERNAL = 1;
     private static final int PREFER_EXTERNAL = 2;
 
-    private int recommendAppInstallLocation(int installLocation, String archiveFilePath, int flags,
-            long threshold, String abiOverride) {
+    private int recommendAppInstallLocation(PackageLite pkg, int flags, long threshold,
+            String abiOverride) {
         int prefer;
         boolean checkBoth = false;
 
@@ -498,14 +541,14 @@
             }
 
             /* No install flags. Check for manifest option. */
-            if (installLocation == PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY) {
+            if (pkg.installLocation == PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY) {
                 prefer = PREFER_INTERNAL;
                 break check_inner;
-            } else if (installLocation == PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL) {
+            } else if (pkg.installLocation == PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL) {
                 prefer = PREFER_EXTERNAL;
                 checkBoth = true;
                 break check_inner;
-            } else if (installLocation == PackageInfo.INSTALL_LOCATION_AUTO) {
+            } else if (pkg.installLocation == PackageInfo.INSTALL_LOCATION_AUTO) {
                 // We default to preferring internal storage.
                 prefer = PREFER_INTERNAL;
                 checkBoth = true;
@@ -534,12 +577,10 @@
 
         final boolean emulated = Environment.isExternalStorageEmulated();
 
-        final File apkFile = new File(archiveFilePath);
-
         boolean fitsOnInternal = false;
         if (checkBoth || prefer == PREFER_INTERNAL) {
             try {
-                fitsOnInternal = isUnderInternalThreshold(apkFile, isForwardLocked, threshold);
+                fitsOnInternal = isUnderInternalThreshold(pkg, isForwardLocked, threshold);
             } catch (IOException e) {
                 return PackageHelper.RECOMMEND_FAILED_INVALID_URI;
             }
@@ -548,7 +589,7 @@
         boolean fitsOnSd = false;
         if (!emulated && (checkBoth || prefer == PREFER_EXTERNAL)) {
             try {
-                fitsOnSd = isUnderExternalThreshold(apkFile, isForwardLocked, abiOverride);
+                fitsOnSd = isUnderExternalThreshold(pkg, isForwardLocked, abiOverride);
             } catch (IOException e) {
                 return PackageHelper.RECOMMEND_FAILED_INVALID_URI;
             }
@@ -588,44 +629,39 @@
     /**
      * Measure a file to see if it fits within the free space threshold.
      *
-     * @param apkFile file to check
      * @param threshold byte threshold to compare against
      * @return true if file fits under threshold
      * @throws FileNotFoundException when APK does not exist
      */
-    private boolean isUnderInternalThreshold(File apkFile, boolean isForwardLocked, long threshold)
-            throws IOException {
-        long size = apkFile.length();
-        if (size == 0 && !apkFile.exists()) {
-            throw new FileNotFoundException();
+    private boolean isUnderInternalThreshold(PackageLite pkg, boolean isForwardLocked,
+            long threshold) throws IOException {
+        long sizeBytes = 0;
+        for (String codePath : pkg.getAllCodePaths()) {
+            sizeBytes += new File(codePath).length();
+
+            if (isForwardLocked) {
+                sizeBytes += PackageHelper.extractPublicFiles(codePath, null);
+            }
         }
 
-        if (isForwardLocked) {
-            size += PackageHelper.extractPublicFiles(apkFile.getAbsolutePath(), null);
-        }
-
-        final StatFs internalStats = new StatFs(Environment.getDataDirectory().getPath());
-        final long availInternalSize = (long) internalStats.getAvailableBlocks()
-                * (long) internalStats.getBlockSize();
-
-        return (availInternalSize - size) > threshold;
+        final StatFs stat = new StatFs(Environment.getDataDirectory().getPath());
+        final long availBytes = stat.getAvailableBytes();
+        return (availBytes - sizeBytes) > threshold;
     }
 
-
     /**
      * Measure a file to see if it fits in the external free space.
      *
-     * @param apkFile file to check
      * @return true if file fits
      * @throws IOException when file does not exist
      */
-    private boolean isUnderExternalThreshold(File apkFile, boolean isForwardLocked, String abiOverride)
-            throws IOException {
+    private boolean isUnderExternalThreshold(PackageLite pkg, boolean isForwardLocked,
+            String abiOverride) throws IOException {
         if (Environment.isExternalStorageEmulated()) {
             return false;
         }
 
-        final int sizeMb = calculateContainerSize(apkFile, isForwardLocked, abiOverride);
+        final int sizeMb = calculateContainerSize(pkg, isForwardLocked, abiOverride);
 
         final int availSdMb;
         if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
@@ -639,32 +675,35 @@
         return availSdMb > sizeMb;
     }
 
-    private int calculateContainerSize(File apkFile, boolean forwardLocked,
-            String abiOverride) throws IOException {
-        Handle handle = null;
+    private int calculateContainerSize(PackageLite pkg, boolean isForwardLocked, String abiOverride)
+            throws IOException {
+        NativeLibraryHelper.Handle handle = null;
         try {
-            handle = Handle.create(apkFile);
+            handle = NativeLibraryHelper.Handle.create(pkg);
             final int abi = NativeLibraryHelper.findSupportedAbi(handle,
                     (abiOverride != null) ? new String[] { abiOverride } : Build.SUPPORTED_ABIS);
-            return calculateContainerSize(handle, apkFile, abi, forwardLocked);
+            return calculateContainerSize(pkg, handle, isForwardLocked, abi);
         } finally {
             IoUtils.closeQuietly(handle);
         }
     }
 
     /**
-     * Calculate the container size for an APK. Takes into account the
+     * Calculate the container size for a package.
      * 
-     * @param apkFile file from which to calculate size
      * @return size in megabytes (2^20 bytes)
      * @throws IOException when there is a problem reading the file
      */
-    private int calculateContainerSize(NativeLibraryHelper.Handle handle,
-            File apkFile, int abiIndex, boolean forwardLocked) throws IOException {
-        // Calculate size of container needed to hold base APK.
-        long sizeBytes = apkFile.length();
-        if (sizeBytes == 0 && !apkFile.exists()) {
-            throw new FileNotFoundException();
+    private int calculateContainerSize(PackageLite pkg, NativeLibraryHelper.Handle handle,
+            boolean isForwardLocked, int abiIndex) throws IOException {
+        // Calculate size of container needed to hold APKs.
+        long sizeBytes = 0;
+        for (String codePath : pkg.getAllCodePaths()) {
+            sizeBytes += new File(codePath).length();
+
+            if (isForwardLocked) {
+                sizeBytes += PackageHelper.extractPublicFiles(codePath, null);
+            }
         }
 
         // Check all the native files that need to be copied and add that to the
@@ -674,10 +713,6 @@
                     Build.SUPPORTED_ABIS[abiIndex]);
         }
 
-        if (forwardLocked) {
-            sizeBytes += PackageHelper.extractPublicFiles(apkFile.getPath(), null);
-        }
-
         int sizeMb = (int) (sizeBytes >> 20);
         if ((sizeBytes - (sizeMb * 1024 * 1024)) > 0) {
             sizeMb++;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 7675f54..7a8eb58 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -24,9 +24,14 @@
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
+import static android.content.pm.PackageManager.INSTALL_EXTERNAL;
+import static android.content.pm.PackageManager.INSTALL_FORWARD_LOCK;
 import static android.content.pm.PackageParser.isApkFile;
 import static android.os.Process.PACKAGE_INFO_GID;
 import static android.os.Process.SYSTEM_UID;
+import static android.system.OsConstants.O_CREAT;
+import static android.system.OsConstants.O_EXCL;
+import static android.system.OsConstants.O_RDWR;
 import static android.system.OsConstants.S_IRGRP;
 import static android.system.OsConstants.S_IROTH;
 import static android.system.OsConstants.S_IRWXU;
@@ -44,6 +49,7 @@
 import com.android.internal.app.ResolverActivity;
 import com.android.internal.content.NativeLibraryHelper;
 import com.android.internal.content.PackageHelper;
+import com.android.internal.os.IParcelFileDescriptorFactory;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastPrintWriter;
 import com.android.internal.util.FastXmlSerializer;
@@ -193,6 +199,7 @@
 import dalvik.system.VMRuntime;
 
 import libcore.io.IoUtils;
+import libcore.io.Libcore;
 
 /**
  * Keep track of all those .apks everywhere.
@@ -1148,18 +1155,18 @@
 
                     if ((state != null) && !state.timeoutExtended()) {
                         final InstallArgs args = state.getInstallArgs();
-                        final Uri fromUri = Uri.fromFile(args.fromFile);
+                        final Uri originUri = Uri.fromFile(args.originFile);
 
-                        Slog.i(TAG, "Verification timed out for " + fromUri);
+                        Slog.i(TAG, "Verification timed out for " + originUri);
                         mPendingVerification.remove(verificationId);
 
                         int ret = PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE;
 
                         if (getDefaultVerificationResponse() == PackageManager.VERIFICATION_ALLOW) {
-                            Slog.i(TAG, "Continuing with installation of " + fromUri);
+                            Slog.i(TAG, "Continuing with installation of " + originUri);
                             state.setVerifierResponse(Binder.getCallingUid(),
                                     PackageManager.VERIFICATION_ALLOW_WITHOUT_SUFFICIENT);
-                            broadcastPackageVerified(verificationId, fromUri,
+                            broadcastPackageVerified(verificationId, originUri,
                                     PackageManager.VERIFICATION_ALLOW,
                                     state.getInstallArgs().getUser());
                             try {
@@ -1168,7 +1175,7 @@
                                 Slog.e(TAG, "Could not contact the ContainerService");
                             }
                         } else {
-                            broadcastPackageVerified(verificationId, fromUri,
+                            broadcastPackageVerified(verificationId, originUri,
                                     PackageManager.VERIFICATION_REJECT,
                                     state.getInstallArgs().getUser());
                         }
@@ -1195,12 +1202,12 @@
                         mPendingVerification.remove(verificationId);
 
                         final InstallArgs args = state.getInstallArgs();
-                        final Uri fromUri = Uri.fromFile(args.fromFile);
+                        final Uri originUri = Uri.fromFile(args.originFile);
 
                         int ret;
                         if (state.isInstallAllowed()) {
                             ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
-                            broadcastPackageVerified(verificationId, fromUri,
+                            broadcastPackageVerified(verificationId, originUri,
                                     response.code, state.getInstallArgs().getUser());
                             try {
                                 ret = args.copyApk(mContainerService, true);
@@ -8421,7 +8428,13 @@
          * copied/renamed into place. This could be a single monolithic APK
          * file, or a cluster directory. This location may be untrusted.
          */
-        private final File mFromFile;
+        final File originFile;
+
+        /**
+         * Flag indicating that {@link #originFile} lives in a trusted location,
+         * meaning downstream users don't need to defensively copy the contents.
+         */
+        boolean originTrusted;
 
         final IPackageInstallObserver observer;
         final IPackageInstallObserver2 observer2;
@@ -8433,11 +8446,12 @@
         final String packageAbiOverride;
         final String packageInstructionSetOverride;
 
-        InstallParams(File fromFile, IPackageInstallObserver observer,
+        InstallParams(File originFile, IPackageInstallObserver observer,
                 IPackageInstallObserver2 observer2, int flags, String installerPackageName,
                 VerificationParams verificationParams, UserHandle user, String packageAbiOverride) {
             super(user);
-            mFromFile = Preconditions.checkNotNull(fromFile);
+            this.originFile = Preconditions.checkNotNull(originFile);
+            this.originTrusted = false;
             this.observer = observer;
             this.observer2 = observer2;
             this.flags = flags;
@@ -8452,7 +8466,7 @@
         public String toString() {
             return "InstallParams{"
                 + Integer.toHexString(System.identityHashCode(this))
-                + " " + mFromFile + "}";
+                + " " + originFile + "}";
         }
 
         public ManifestDigest getManifestDigest() {
@@ -8553,8 +8567,8 @@
                 }
 
                 // Remote call to find out default install location
-                final String fromPath = getFromFile().getAbsolutePath();
-                pkgLite = mContainerService.getMinimalPackageInfo(fromPath, flags, lowThreshold,
+                final String originPath = originFile.getAbsolutePath();
+                pkgLite = mContainerService.getMinimalPackageInfo(originPath, flags, lowThreshold,
                         packageAbiOverride);
 
                 /*
@@ -8564,10 +8578,10 @@
                 if (pkgLite.recommendedInstallLocation
                         == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
                     final long size = mContainerService.calculateInstalledSize(
-                            fromPath, isForwardLocked(), packageAbiOverride);
+                            originPath, isForwardLocked(), packageAbiOverride);
                     if (mInstaller.freeCache(size + lowThreshold) >= 0) {
-                        pkgLite = mContainerService.getMinimalPackageInfo(fromPath,
-                                flags, lowThreshold, packageAbiOverride);
+                        pkgLite = mContainerService.getMinimalPackageInfo(originPath, flags,
+                                lowThreshold, packageAbiOverride);
                     }
                     /*
                      * The cache free must have deleted the file we
@@ -8643,7 +8657,7 @@
                     // TODO: send verifier the install session instead of uri
                     final Intent verification = new Intent(
                             Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
-                    verification.setDataAndType(Uri.fromFile(getFromFile()), PACKAGE_MIME_TYPE);
+                    verification.setDataAndType(Uri.fromFile(originFile), PACKAGE_MIME_TYPE);
                     verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
 
                     final List<ResolveInfo> receivers = queryIntentReceivers(verification,
@@ -8782,10 +8796,6 @@
         public boolean isForwardLocked() {
             return (flags & PackageManager.INSTALL_FORWARD_LOCK) != 0;
         }
-
-        public File getFromFile() {
-            return mFromFile;
-        }
     }
 
     /*
@@ -8805,8 +8815,7 @@
         int mRet;
 
         MoveParams(InstallArgs srcArgs, IPackageMoveObserver observer, int flags,
-                String packageName, String dataDir, String instructionSet,
-                int uid, UserHandle user) {
+                String packageName, String instructionSet, int uid, UserHandle user) {
             super(user);
             this.srcArgs = srcArgs;
             this.observer = observer;
@@ -8815,7 +8824,7 @@
             this.uid = uid;
             if (srcArgs != null) {
                 final String codePath = srcArgs.getCodePath();
-                targetArgs = createInstallArgsForMoveTarget(codePath, flags, packageName, dataDir,
+                targetArgs = createInstallArgsForMoveTarget(codePath, flags, packageName,
                         instructionSet);
             } else {
                 targetArgs = null;
@@ -8956,7 +8965,7 @@
     }
 
     private InstallArgs createInstallArgsForMoveTarget(String codePath, int flags, String pkgName,
-            String dataDir, String instructionSet) {
+            String instructionSet) {
         final File codeFile = new File(codePath);
         if (installOnSd(flags) || installForwardLocked(flags)) {
             String cid = getNextCodePath(codePath, pkgName, "/"
@@ -8964,17 +8973,17 @@
             return new AsecInstallArgs(codeFile, cid, instructionSet, installOnSd(flags),
                     installForwardLocked(flags));
         } else {
-            return new FileInstallArgs(codeFile, pkgName, dataDir, instructionSet);
+            return new FileInstallArgs(codeFile, pkgName, instructionSet);
         }
     }
 
     static abstract class InstallArgs {
-        /**
-         * Location where install is coming from, before it has been
-         * copied/renamed into place. This could be a single monolithic APK
-         * file, or a cluster directory. This location is typically untrusted.
-         */
-        final File fromFile;
+        /** @see InstallParams#originFile */
+        final File originFile;
+        /** @see InstallParams#originTrusted */
+        final boolean originTrusted;
+
+        // TODO: define inherit location
 
         final IPackageInstallObserver observer;
         final IPackageInstallObserver2 observer2;
@@ -8986,11 +8995,12 @@
         final String instructionSet;
         final String abiOverride;
 
-        InstallArgs(File fromFile, IPackageInstallObserver observer,
+        InstallArgs(File originFile, boolean originTrusted, IPackageInstallObserver observer,
                 IPackageInstallObserver2 observer2, int flags, String installerPackageName,
                 ManifestDigest manifestDigest, UserHandle user, String instructionSet,
                 String abiOverride) {
-            this.fromFile = fromFile;
+            this.originFile = originFile;
+            this.originTrusted = originTrusted;
             this.flags = flags;
             this.observer = observer;
             this.observer2 = observer2;
@@ -9062,15 +9072,16 @@
 
         /** New install */
         FileInstallArgs(InstallParams params) {
-            super(params.getFromFile(), params.observer, params.observer2, params.flags,
-                    params.installerPackageName, params.getManifestDigest(), params.getUser(),
-                    params.packageInstructionSetOverride, params.packageAbiOverride);
+            super(params.originFile, params.originTrusted, params.observer, params.observer2,
+                    params.flags, params.installerPackageName, params.getManifestDigest(),
+                    params.getUser(), params.packageInstructionSetOverride,
+                    params.packageAbiOverride);
         }
 
         /** Existing install */
         FileInstallArgs(String fullCodePath, String fullResourcePath, String nativeLibraryPath,
                 String instructionSet) {
-            super(null, null, null, 0, null, null, null, instructionSet, null);
+            super(null, false, null, null, 0, null, null, null, instructionSet, null);
             File codeFile = new File(fullCodePath);
             installDir = codeFile.getParentFile();
             codeFileName = fullCodePath;
@@ -9079,8 +9090,8 @@
         }
 
         /** New install from existing */
-        FileInstallArgs(File fromFile, String pkgName, String dataDir, String instructionSet) {
-            super(fromFile, null, null, 0, null, null, null, instructionSet, null);
+        FileInstallArgs(File originFile, String pkgName, String instructionSet) {
+            super(originFile, true, null, null, 0, null, null, null, instructionSet, null);
             installDir = isFwdLocked() ? mDrmAppPrivateInstallDir : mAppInstallDir;
             String apkName = getNextCodePath(null, pkgName, ".apk");
             codeFileName = new File(installDir, apkName + ".apk").getPath();
@@ -9105,7 +9116,7 @@
                 lowThreshold = dsm.getMemoryLowThreshold();
             }
 
-            return imcs.checkInternalFreeStorage(fromFile.getAbsolutePath(), isFwdLocked(),
+            return imcs.checkInternalFreeStorage(originFile.getAbsolutePath(), isFwdLocked(),
                     lowThreshold);
         }
 
@@ -9123,7 +9134,7 @@
                 createCopyFile();
             }
             // Get a ParcelFileDescriptor to write to the output file
-            File codeFile = new File(codeFileName);
+            final File codeFile = new File(codeFileName);
             if (!created) {
                 try {
                     codeFile.createNewFile();
@@ -9137,20 +9148,22 @@
                    return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
                 }
             }
-            ParcelFileDescriptor out = null;
-            try {
-                out = ParcelFileDescriptor.open(codeFile, ParcelFileDescriptor.MODE_READ_WRITE);
-            } catch (FileNotFoundException e) {
-                Slog.e(TAG, "Failed to create file descriptor for : " + codeFileName);
-                return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
-            }
+
+            // TODO: extend to support copying into clusters
+            final IParcelFileDescriptorFactory target = new IParcelFileDescriptorFactory.Stub() {
+                @Override
+                public ParcelFileDescriptor open(String name, int mode) throws RemoteException {
+                    try {
+                        return ParcelFileDescriptor.open(codeFile,
+                                ParcelFileDescriptor.MODE_READ_WRITE);
+                    } catch (FileNotFoundException e) {
+                        throw new RemoteException(e.getMessage());
+                    }
+                }
+            };
+
             // Copy the resource now
-            int ret = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
-            try {
-                ret = imcs.copyResource(fromFile.getAbsolutePath(), out);
-            } finally {
-                IoUtils.closeQuietly(out);
-            }
+            int ret = imcs.copyPackage(originFile.getAbsolutePath(), target);
 
             if (isFwdLocked()) {
                 final File destResourceFile = new File(getResourcePath());
@@ -9418,17 +9431,18 @@
 
         /** New install */
         AsecInstallArgs(InstallParams params) {
-            super(params.getFromFile(), params.observer, params.observer2, params.flags,
-                    params.installerPackageName, params.getManifestDigest(), params.getUser(),
-                    params.packageInstructionSetOverride, params.packageAbiOverride);
+            super(params.originFile, params.originTrusted, params.observer, params.observer2,
+                    params.flags, params.installerPackageName, params.getManifestDigest(),
+                    params.getUser(), params.packageInstructionSetOverride,
+                    params.packageAbiOverride);
         }
 
         /** Existing install */
         AsecInstallArgs(String fullCodePath, String fullResourcePath, String nativeLibraryPath,
                 String instructionSet, boolean isExternal, boolean isForwardLocked) {
-            super(null, null, null, (isExternal ? PackageManager.INSTALL_EXTERNAL : 0)
-                    | (isForwardLocked ? PackageManager.INSTALL_FORWARD_LOCK : 0),
-                    null, null, null, instructionSet, null);
+            super(null, false, null, null, (isExternal ? INSTALL_EXTERNAL : 0)
+                    | (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null,
+                    instructionSet, null);
             // Extract cid from fullCodePath
             int eidx = fullCodePath.lastIndexOf("/");
             String subStr1 = fullCodePath.substring(0, eidx);
@@ -9438,19 +9452,19 @@
         }
 
         AsecInstallArgs(String cid, String instructionSet, boolean isForwardLocked) {
-            super(null, null, null, (isAsecExternal(cid) ? PackageManager.INSTALL_EXTERNAL : 0)
-                    | (isForwardLocked ? PackageManager.INSTALL_FORWARD_LOCK : 0),
-                    null, null, null, instructionSet, null);
+            super(null, false, null, null, (isAsecExternal(cid) ? INSTALL_EXTERNAL : 0)
+                    | (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null,
+                    instructionSet, null);
             this.cid = cid;
             setCachePath(PackageHelper.getSdDir(cid));
         }
 
         /** New install from existing */
-        AsecInstallArgs(File fromFile, String cid, String instructionSet,
+        AsecInstallArgs(File originPackageFile, String cid, String instructionSet,
                 boolean isExternal, boolean isForwardLocked) {
-            super(fromFile, null, null, (isExternal ? PackageManager.INSTALL_EXTERNAL : 0)
-                    | (isForwardLocked ? PackageManager.INSTALL_FORWARD_LOCK : 0),
-                    null, null, null, instructionSet, null);
+            super(originPackageFile, true, null, null, (isExternal ? INSTALL_EXTERNAL : 0)
+                    | (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null,
+                    instructionSet, null);
             this.cid = cid;
         }
 
@@ -9459,7 +9473,7 @@
         }
 
         boolean checkFreeStorage(IMediaContainerService imcs) throws RemoteException {
-            return imcs.checkExternalFreeStorage(fromFile.getAbsolutePath(), isFwdLocked(),
+            return imcs.checkExternalFreeStorage(originFile.getAbsolutePath(), isFwdLocked(),
                     abiOverride);
         }
 
@@ -9478,8 +9492,8 @@
                 PackageHelper.destroySdDir(cid);
             }
 
-            final String newCachePath = imcs.copyResourceToContainer(fromFile.getAbsolutePath(),
-                    cid, getEncryptKey(), RES_FILE_NAME, PUBLIC_RES_FILE_NAME, isExternal(),
+            final String newCachePath = imcs.copyPackageToContainer(
+                    originFile.getAbsolutePath(), cid, getEncryptKey(), isExternal(),
                     isFwdLocked(), abiOverride);
 
             if (newCachePath != null) {
@@ -12842,8 +12856,7 @@
              * anyway.
              */
             if (returnCode != PackageManager.MOVE_SUCCEEDED) {
-                processPendingMove(new MoveParams(null, observer, 0, packageName, null,
-                        null, -1, user),
+                processPendingMove(new MoveParams(null, observer, 0, packageName, null, -1, user),
                         returnCode);
             } else {
                 Message msg = mHandler.obtainMessage(INIT_COPY);
@@ -12852,7 +12865,7 @@
                         pkg.applicationInfo.sourceDir, pkg.applicationInfo.publicSourceDir,
                         pkg.applicationInfo.nativeLibraryDir, instructionSet);
                 MoveParams mp = new MoveParams(srcArgs, observer, newFlags, packageName,
-                        pkg.applicationInfo.dataDir, instructionSet, pkg.applicationInfo.uid, user);
+                        instructionSet, pkg.applicationInfo.uid, user);
                 msg.obj = mp;
                 mHandler.sendMessage(msg);
             }