OSDN Git Service

Teach DCS about cluster packages.
authorJeff Sharkey <jsharkey@android.com>
Sat, 5 Jul 2014 01:23:17 +0000 (18:23 -0700)
committerJeff Sharkey <jsharkey@android.com>
Sun, 6 Jul 2014 02:16:53 +0000 (19:16 -0700)
For the time being, DCS is going to still be doing heavy lifting for
some install tasks, so it need to know how to handle both monolithic
and cluster packages.  This change is mostly plumbing work to
eventually handle any various splits APKs that we may encounter.

Bug: 14975160
Change-Id: I39848d5666f9083cb4eca493e5cdaa868f3f99fb

Android.mk
core/java/android/content/pm/PackageParser.java
core/java/com/android/internal/app/IMediaContainerService.aidl
core/java/com/android/internal/content/NativeLibraryHelper.java
core/java/com/android/internal/content/PackageHelper.java
core/java/com/android/internal/os/IParcelFileDescriptorFactory.aidl [new file with mode: 0644]
packages/DefaultContainerService/AndroidManifest.xml
packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
services/core/java/com/android/server/pm/PackageManagerService.java

index c22bc73..0c5051c 100644 (file)
@@ -259,6 +259,7 @@ LOCAL_SRC_FILES += \
        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 \
index a5290aa..bb47124 100644 (file)
@@ -232,6 +232,8 @@ public class PackageParser {
     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 @@ public class PackageParser {
         /** 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 @@ public class PackageParser {
      * 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 class PackageParser {
         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 @@ public class PackageParser {
 
     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 @@ public class PackageParser {
         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 @@ public class PackageParser {
                 }
 
                 // 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 @@ public class PackageParser {
             }
         }
 
-        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 @@ public class PackageParser {
             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 @@ public class PackageParser {
             }
 
             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 @@ public class PackageParser {
                 (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 @@ public class PackageParser {
             }
         }
 
-        return new ApkLite(packageSplit.first, packageSplit.second, versionCode,
+        return new ApkLite(codePath, packageSplit.first, packageSplit.second, versionCode,
                 installLocation, verifiers, signatures);
     }
 
index 7904cba..7a3ffdf 100644 (file)
 
 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);
index af0068e..b4352f8 100644 (file)
@@ -57,13 +57,15 @@ public class NativeLibraryHelper {
         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];
index 1a4835b..eff6684 100644 (file)
@@ -207,7 +207,10 @@ public class PackageHelper {
        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 @@ public class PackageHelper {
         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 (file)
index 0000000..c9dcd06
--- /dev/null
@@ -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);
+}
index 57c87e4..14777a9 100644 (file)
@@ -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"/>
index 1a4bbaa..7a21b92 100644 (file)
@@ -19,13 +19,12 @@ package com.android.defcontainer;
 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 android.util.Slog;
 
 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 @@ public class DefaultContainerService extends IntentService {
 
     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 @@ public class DefaultContainerService extends IntentService {
                 }
             }
 
-            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 @@ public class DefaultContainerService extends IntentService {
         }
 
         /**
-         * 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 @@ public class DefaultContainerService extends IntentService {
                 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 @@ public class DefaultContainerService extends IntentService {
             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 @@ public class DefaultContainerService extends IntentService {
             }
         }
 
+        /**
+         * 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 @@ public class DefaultContainerService extends IntentService {
         }
         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 @@ public class DefaultContainerService extends IntentService {
             }
         }
 
-        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 @@ public class DefaultContainerService extends IntentService {
         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 @@ public class DefaultContainerService extends IntentService {
         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 @@ public class DefaultContainerService extends IntentService {
             }
 
             /* 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 @@ public class DefaultContainerService extends IntentService {
 
         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 @@ public class DefaultContainerService extends IntentService {
         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 @@ public class DefaultContainerService extends IntentService {
     /**
      * 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) {
-            size += PackageHelper.extractPublicFiles(apkFile.getAbsolutePath(), null);
+            if (isForwardLocked) {
+                sizeBytes += PackageHelper.extractPublicFiles(codePath, 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 @@ public class DefaultContainerService extends IntentService {
         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 @@ public class DefaultContainerService extends IntentService {
                     Build.SUPPORTED_ABIS[abiIndex]);
         }
 
-        if (forwardLocked) {
-            sizeBytes += PackageHelper.extractPublicFiles(apkFile.getPath(), null);
-        }
-
         int sizeMb = (int) (sizeBytes >> 20);
         if ((sizeBytes - (sizeMb * 1024 * 1024)) > 0) {
             sizeMb++;
index 7675f54..7a8eb58 100644 (file)
@@ -24,9 +24,14 @@ import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED
 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.IMediaContainerService;
 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.StaleDexCacheError;
 import dalvik.system.VMRuntime;
 
 import libcore.io.IoUtils;
+import libcore.io.Libcore;
 
 /**
  * Keep track of all those .apks everywhere.
@@ -1148,18 +1155,18 @@ public class PackageManagerService extends IPackageManager.Stub {
 
                     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 @@ public class PackageManagerService extends IPackageManager.Stub {
                                 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 @@ public class PackageManagerService extends IPackageManager.Stub {
                         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 @@ public class PackageManagerService extends IPackageManager.Stub {
          * 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 @@ public class PackageManagerService extends IPackageManager.Stub {
         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 class PackageManagerService extends IPackageManager.Stub {
         public String toString() {
             return "InstallParams{"
                 + Integer.toHexString(System.identityHashCode(this))
-                + " " + mFromFile + "}";
+                + " " + originFile + "}";
         }
 
         public ManifestDigest getManifestDigest() {
@@ -8553,8 +8567,8 @@ public class PackageManagerService extends IPackageManager.Stub {
                 }
 
                 // 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 @@ public class PackageManagerService extends IPackageManager.Stub {
                 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 @@ public class PackageManagerService extends IPackageManager.Stub {
                     // 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 class PackageManagerService extends IPackageManager.Stub {
         public boolean isForwardLocked() {
             return (flags & PackageManager.INSTALL_FORWARD_LOCK) != 0;
         }
-
-        public File getFromFile() {
-            return mFromFile;
-        }
     }
 
     /*
@@ -8805,8 +8815,7 @@ public class PackageManagerService extends IPackageManager.Stub {
         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 @@ public class PackageManagerService extends IPackageManager.Stub {
             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 @@ public class PackageManagerService extends IPackageManager.Stub {
     }
 
     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 @@ public class PackageManagerService extends IPackageManager.Stub {
             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 @@ public class PackageManagerService extends IPackageManager.Stub {
         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 @@ public class PackageManagerService extends IPackageManager.Stub {
 
         /** 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 @@ public class PackageManagerService extends IPackageManager.Stub {
         }
 
         /** 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 @@ public class PackageManagerService extends IPackageManager.Stub {
                 lowThreshold = dsm.getMemoryLowThreshold();
             }
 
-            return imcs.checkInternalFreeStorage(fromFile.getAbsolutePath(), isFwdLocked(),
+            return imcs.checkInternalFreeStorage(originFile.getAbsolutePath(), isFwdLocked(),
                     lowThreshold);
         }
 
@@ -9123,7 +9134,7 @@ public class PackageManagerService extends IPackageManager.Stub {
                 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 @@ public class PackageManagerService extends IPackageManager.Stub {
                    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 @@ public class PackageManagerService extends IPackageManager.Stub {
 
         /** 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 @@ public class PackageManagerService extends IPackageManager.Stub {
         }
 
         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 @@ public class PackageManagerService extends IPackageManager.Stub {
         }
 
         boolean checkFreeStorage(IMediaContainerService imcs) throws RemoteException {
-            return imcs.checkExternalFreeStorage(fromFile.getAbsolutePath(), isFwdLocked(),
+            return imcs.checkExternalFreeStorage(originFile.getAbsolutePath(), isFwdLocked(),
                     abiOverride);
         }
 
@@ -9478,8 +9492,8 @@ public class PackageManagerService extends IPackageManager.Stub {
                 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 @@ public class PackageManagerService extends IPackageManager.Stub {
              * 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 @@ public class PackageManagerService extends IPackageManager.Stub {
                         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);
             }