Merge "Extract native code from split APKs."
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 319559a..a5290aa 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -227,6 +227,48 @@
     }
 
     /**
+     * Lightweight parsed details about a single package.
+     */
+    public static class PackageLite {
+        public final String packageName;
+        public final int versionCode;
+
+        /** Names of any split APKs, ordered by parsed splitName */
+        public final String[] splitNames;
+
+        /**
+         * Path where this package was found on disk. For monolithic packages
+         * this is path to single base APK file; for cluster packages this is
+         * path to the cluster directory.
+         */
+        public final String codePath;
+
+        /** Path of base APK */
+        public final String baseCodePath;
+        /** 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;
+            this.splitNames = splitNames;
+            this.codePath = codePath;
+            this.baseCodePath = baseCodePath;
+            this.splitCodePaths = splitCodePaths;
+        }
+
+        public List<String> getAllCodePaths() {
+            ArrayList<String> paths = new ArrayList<>();
+            paths.add(baseCodePath);
+            if (!ArrayUtils.isEmpty(splitCodePaths)) {
+                Collections.addAll(paths, splitCodePaths);
+            }
+            return paths;
+        }
+    }
+
+    /**
      * Lightweight parsed details about a single APK file.
      */
     public static class ApkLite {
@@ -279,12 +321,8 @@
         mMetrics = metrics;
     }
 
-    public static final boolean isPackageFilename(File file) {
-        return isPackageFilename(file.getName());
-    }
-
-    public static final boolean isPackageFilename(String name) {
-        return name.endsWith(".apk");
+    public static final boolean isApkFile(File file) {
+        return file.isFile() && file.getName().endsWith(".apk");
     }
 
     /*
@@ -543,17 +581,26 @@
         }
     }
 
-    /**
-     * Parse all APKs contained in the given directory, treating them as a
-     * single package. This also performs sanity checking, such as requiring
-     * identical package name and version codes, a single base APK, and unique
-     * split names.
-     * <p>
-     * Note that this <em>does not</em> perform signature verification; that
-     * must be done separately in {@link #collectCertificates(Package, int)}.
-     */
-    public Package parseClusterPackage(File apkDir, int flags) throws PackageParserException {
-        final File[] files = apkDir.listFiles();
+    public static PackageLite parsePackageLite(File packageFile, int flags)
+            throws PackageParserException {
+        if (packageFile.isDirectory()) {
+            return parseClusterPackageLite(packageFile, flags);
+        } else {
+            return parseMonolithicPackageLite(packageFile, flags);
+        }
+    }
+
+    private static PackageLite parseMonolithicPackageLite(File packageFile, int flags)
+            throws PackageParserException {
+        final ApkLite lite = parseApkLite(packageFile, flags);
+        final String packagePath = packageFile.getAbsolutePath();
+        return new PackageLite(lite.packageName, lite.versionCode, null,
+                packagePath, packagePath, null);
+    }
+
+    private static PackageLite parseClusterPackageLite(File packageDir, int flags)
+            throws PackageParserException {
+        final File[] files = packageDir.listFiles();
         if (ArrayUtils.isEmpty(files)) {
             throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
                     "No packages found in split");
@@ -564,8 +611,8 @@
 
         final ArrayMap<String, File> apks = new ArrayMap<>();
         for (File file : files) {
-            if (file.isFile() && isPackageFilename(file)) {
-                final ApkLite lite = parseApkLite(file, 0);
+            if (isApkFile(file)) {
+                final ApkLite lite = parseApkLite(file, flags);
 
                 // Assert that all package names and version codes are
                 // consistent with the first one we encounter.
@@ -594,29 +641,73 @@
             }
         }
 
-        final File baseFile = apks.remove(null);
-        if (baseFile == null) {
+        final File baseApk = apks.remove(null);
+        if (baseApk == null) {
             throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
-                    "Missing base APK in " + apkDir);
-        }
-
-        final Package pkg = parseBaseApk(baseFile, flags);
-        if (pkg == null) {
-            throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
-                    "Failed to parse base APK: " + baseFile);
+                    "Missing base APK in " + packageDir);
         }
 
         // Always apply deterministic ordering based on splitName
         final int size = apks.size();
-        final String[] splitNames = apks.keySet().toArray(new String[size]);
-        Arrays.sort(splitNames, sSplitNameComparator);
 
-        for (String splitName : splitNames) {
-            final File splitFile = apks.get(splitName);
-            parseSplitApk(pkg, splitFile, splitName, flags);
+        String[] splitNames = null;
+        String[] splitCodePaths = null;
+        if (size > 0) {
+            splitNames = new String[size];
+            splitCodePaths = new String[size];
+
+            splitNames = apks.keySet().toArray(splitNames);
+            Arrays.sort(splitNames, sSplitNameComparator);
+
+            for (int i = 0; i < size; i++) {
+                splitCodePaths[i] = apks.get(splitNames[i]).getAbsolutePath();
+            }
         }
 
-        pkg.codePath = apkDir.getAbsolutePath();
+        final String codePath = packageDir.getAbsolutePath();
+        final String baseCodePath = baseApk.getAbsolutePath();
+        return new PackageLite(packageName, versionCode, splitNames, codePath, baseCodePath,
+                splitCodePaths);
+    }
+
+    public Package parsePackage(File packageFile, int flags) throws PackageParserException {
+        if (packageFile.isDirectory()) {
+            return parseClusterPackage(packageFile, flags);
+        } else {
+            return parseMonolithicPackage(packageFile, flags);
+        }
+    }
+
+    /**
+     * Parse all APKs contained in the given directory, treating them as a
+     * single package. This also performs sanity checking, such as requiring
+     * identical package name and version codes, a single base APK, and unique
+     * split names.
+     * <p>
+     * Note that this <em>does not</em> perform signature verification; that
+     * must be done separately in {@link #collectCertificates(Package, int)}.
+     */
+    private Package parseClusterPackage(File packageDir, int flags) throws PackageParserException {
+        final PackageLite lite = parseClusterPackageLite(packageDir, 0);
+
+        final File baseApk = new File(lite.baseCodePath);
+        final Package pkg = parseBaseApk(baseApk, flags);
+        if (pkg == null) {
+            throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
+                    "Failed to parse base APK: " + baseApk);
+        }
+
+        if (!ArrayUtils.isEmpty(lite.splitNames)) {
+            pkg.splitNames = lite.splitNames;
+            pkg.splitCodePaths = lite.splitCodePaths;
+
+            for (String splitCodePath : lite.splitCodePaths) {
+                final File splitApk = new File(splitCodePath);
+                parseSplitApk(pkg, splitApk, flags);
+            }
+        }
+
+        pkg.codePath = packageDir.getAbsolutePath();
         return pkg;
     }
 
@@ -648,8 +739,7 @@
             mParseError = PackageManager.INSTALL_PARSE_FAILED_NOT_APK;
             return null;
         }
-        if (!isPackageFilename(apkFile.getName())
-                && (flags&PARSE_MUST_BE_APK) != 0) {
+        if (!isApkFile(apkFile) && (flags & PARSE_MUST_BE_APK) != 0) {
             if ((flags&PARSE_IS_SYSTEM) == 0) {
                 // We expect to have non-.apk files in the system dir,
                 // so don't warn about them.
@@ -732,16 +822,11 @@
         return pkg;
     }
 
-    private void parseSplitApk(Package pkg, File apkFile, String splitName, int flags)
-            throws PackageParserException {
+    private void parseSplitApk(Package pkg, File apkFile, int flags) throws PackageParserException {
         final String splitCodePath = apkFile.getAbsolutePath();
         mArchiveSourcePath = apkFile.getAbsolutePath();
 
         // TODO: expand split APK parsing
-        // TODO: extract splitName during parse
-        pkg.splitNames = ArrayUtils.appendElement(String.class, pkg.splitNames, splitName);
-        pkg.splitCodePaths = ArrayUtils.appendElement(String.class, pkg.splitCodePaths,
-                splitCodePath);
     }
 
     /**
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index d5d5eb8..4c34d46 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -392,7 +392,10 @@
                 if (file.isDirectory()) {
                     success &= deleteContents(file);
                 }
-                success &= file.delete();
+                if (!file.delete()) {
+                    Log.w(TAG, "Failed to delete " + file);
+                    success = false;
+                }
             }
         }
         return success;
diff --git a/core/java/com/android/internal/content/NativeLibraryHelper.java b/core/java/com/android/internal/content/NativeLibraryHelper.java
index 832829d..af0068e 100644
--- a/core/java/com/android/internal/content/NativeLibraryHelper.java
+++ b/core/java/com/android/internal/content/NativeLibraryHelper.java
@@ -16,12 +16,22 @@
 
 package com.android.internal.content;
 
+import static android.content.pm.PackageManager.INSTALL_FAILED_NO_MATCHING_ABIS;
+import static android.content.pm.PackageManager.INSTALL_SUCCEEDED;
+import static android.content.pm.PackageManager.NO_NATIVE_LIBRARIES;
+
 import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
+import android.content.pm.PackageParser.PackageLite;
+import android.content.pm.PackageParser.PackageParserException;
 import android.util.Slog;
 
+import dalvik.system.CloseGuard;
+
 import java.io.Closeable;
 import java.io.File;
 import java.io.IOException;
+import java.util.List;
 
 /**
  * Native libraries helper.
@@ -34,41 +44,73 @@
     private static final boolean DEBUG_NATIVE = false;
 
     /**
-     * A handle to an opened APK. Used as input to the various NativeLibraryHelper
-     * methods. Allows us to scan and parse the APK exactly once instead of doing
-     * it multiple times.
+     * A handle to an opened package, consisting of one or more APKs. Used as
+     * input to the various NativeLibraryHelper methods. Allows us to scan and
+     * parse the APKs exactly once instead of doing it multiple times.
      *
      * @hide
      */
-    public static class ApkHandle implements Closeable {
-        final String apkPath;
-        final long apkHandle;
+    public static class Handle implements Closeable {
+        private final CloseGuard mGuard = CloseGuard.get();
+        private volatile boolean mClosed;
 
-        public static ApkHandle create(String path) throws IOException {
-            final long handle = nativeOpenApk(path);
-            if (handle == 0) {
-                throw new IOException("Unable to open APK: " + path);
+        final long[] apkHandles;
+
+        public static Handle create(File packageFile) throws IOException {
+            final PackageLite lite;
+            try {
+                lite = PackageParser.parsePackageLite(packageFile, 0);
+            } catch (PackageParserException e) {
+                throw new IOException("Failed to parse package: " + packageFile, e);
             }
 
-            return new ApkHandle(path, handle);
+            final List<String> codePaths = lite.getAllCodePaths();
+            final int size = codePaths.size();
+            final long[] apkHandles = new long[size];
+            for (int i = 0; i < size; i++) {
+                final String path = codePaths.get(i);
+                apkHandles[i] = nativeOpenApk(path);
+                if (apkHandles[i] == 0) {
+                    // Unwind everything we've opened so far
+                    for (int j = 0; j < i; j++) {
+                        nativeClose(apkHandles[j]);
+                    }
+                    throw new IOException("Unable to open APK: " + path);
+                }
+            }
+
+            return new Handle(apkHandles);
         }
 
-        public static ApkHandle create(File path) throws IOException {
-            return create(path.getAbsolutePath());
-        }
-
-        private ApkHandle(String apkPath, long apkHandle) {
-            this.apkPath = apkPath;
-            this.apkHandle = apkHandle;
+        Handle(long[] apkHandles) {
+            this.apkHandles = apkHandles;
+            mGuard.open("close");
         }
 
         @Override
         public void close() {
-            nativeClose(apkHandle);
+            for (long apkHandle : apkHandles) {
+                nativeClose(apkHandle);
+            }
+            mGuard.close();
+            mClosed = true;
+        }
+
+        @Override
+        protected void finalize() throws Throwable {
+            if (mGuard != null) {
+                mGuard.warnIfOpen();
+            }
+            try {
+                if (!mClosed) {
+                    close();
+                }
+            } finally {
+                super.finalize();
+            }
         }
     }
 
-
     private static native long nativeOpenApk(String path);
     private static native void nativeClose(long handle);
 
@@ -79,8 +121,12 @@
      *
      * @return size of all native binary files in bytes
      */
-    public static long sumNativeBinariesLI(ApkHandle handle, String abi) {
-        return nativeSumNativeBinaries(handle.apkHandle, abi);
+    public static long sumNativeBinariesLI(Handle handle, String abi) {
+        long sum = 0;
+        for (long apkHandle : handle.apkHandles) {
+            sum += nativeSumNativeBinaries(apkHandle, abi);
+        }
+        return sum;
     }
 
     private native static int nativeCopyNativeBinaries(long handle,
@@ -94,9 +140,15 @@
      * @return {@link PackageManager#INSTALL_SUCCEEDED} if successful or another
      *         error code from that class if not
      */
-    public static int copyNativeBinariesIfNeededLI(ApkHandle handle, File sharedLibraryDir,
+    public static int copyNativeBinariesIfNeededLI(Handle handle, File sharedLibraryDir,
             String abi) {
-        return nativeCopyNativeBinaries(handle.apkHandle, sharedLibraryDir.getPath(), abi);
+        for (long apkHandle : handle.apkHandles) {
+            int res = nativeCopyNativeBinaries(apkHandle, sharedLibraryDir.getPath(), abi);
+            if (res != INSTALL_SUCCEEDED) {
+                return res;
+            }
+        }
+        return INSTALL_SUCCEEDED;
     }
 
     /**
@@ -106,8 +158,29 @@
      * APK doesn't contain any native code, and
      * {@link PackageManager#INSTALL_FAILED_NO_MATCHING_ABIS} if none of the ABIs match.
      */
-    public static int findSupportedAbi(ApkHandle handle, String[] supportedAbis) {
-        return nativeFindSupportedAbi(handle.apkHandle, supportedAbis);
+    public static int findSupportedAbi(Handle handle, String[] supportedAbis) {
+        int finalRes = NO_NATIVE_LIBRARIES;
+        for (long apkHandle : handle.apkHandles) {
+            final int res = nativeFindSupportedAbi(apkHandle, supportedAbis);
+            if (res == NO_NATIVE_LIBRARIES) {
+                // No native code, keep looking through all APKs.
+            } else if (res == INSTALL_FAILED_NO_MATCHING_ABIS) {
+                // Found some native code, but no ABI match; update our final
+                // result if we haven't found other valid code.
+                if (finalRes < 0) {
+                    finalRes = INSTALL_FAILED_NO_MATCHING_ABIS;
+                }
+            } else if (res >= 0) {
+                // Found valid native code, track the best ABI match
+                if (finalRes < 0 || res < finalRes) {
+                    finalRes = res;
+                }
+            } else {
+                // Unexpected error; bail
+                return res;
+            }
+        }
+        return finalRes;
     }
 
     private native static int nativeFindSupportedAbi(long handle, String[] supportedAbis);
@@ -156,13 +229,16 @@
     // We don't care about the other return values for now.
     private static final int BITCODE_PRESENT = 1;
 
-    public static boolean hasRenderscriptBitcode(ApkHandle handle) throws IOException {
-        final int returnVal = hasRenderscriptBitcode(handle.apkHandle);
-        if (returnVal < 0) {
-            throw new IOException("Error scanning APK, code: " + returnVal);
+    public static boolean hasRenderscriptBitcode(Handle handle) throws IOException {
+        for (long apkHandle : handle.apkHandles) {
+            final int res = hasRenderscriptBitcode(apkHandle);
+            if (res < 0) {
+                throw new IOException("Error scanning APK, code: " + res);
+            } else if (res == BITCODE_PRESENT) {
+                return true;
+            }
         }
-
-        return (returnVal == BITCODE_PRESENT);
+        return false;
     }
 
     private static native int hasRenderscriptBitcode(long apkHandle);
diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
index 74ff3b1..4a61f1f 100644
--- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
+++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
@@ -48,7 +48,7 @@
 
 import com.android.internal.app.IMediaContainerService;
 import com.android.internal.content.NativeLibraryHelper;
-import com.android.internal.content.NativeLibraryHelper.ApkHandle;
+import com.android.internal.content.NativeLibraryHelper.Handle;
 import com.android.internal.content.PackageHelper;
 
 import libcore.io.IoUtils;
@@ -116,9 +116,9 @@
                 }
             }
 
-            ApkHandle handle = null;
+            Handle handle = null;
             try {
-                handle = ApkHandle.create(packagePath);
+                handle = Handle.create(new File(packagePath));
                 return copyResourceInner(packagePath, cid, key, resFileName, publicResFileName,
                         isExternal, isForwardLocked, handle, abiOverride);
             } catch (IOException ioe) {
@@ -349,7 +349,7 @@
 
     private String copyResourceInner(String packagePath, String newCid, String key, String resFileName,
             String publicResFileName, boolean isExternal, boolean isForwardLocked,
-            ApkHandle handle, String abiOverride) {
+            Handle handle, String abiOverride) {
         // The .apk file
         String codePath = packagePath;
         File codeFile = new File(codePath);
@@ -834,9 +834,9 @@
 
     private int calculateContainerSize(File apkFile, boolean forwardLocked,
             String abiOverride) throws IOException {
-        ApkHandle handle = null;
+        Handle handle = null;
         try {
-            handle = ApkHandle.create(apkFile);
+            handle = Handle.create(apkFile);
             final int abi = NativeLibraryHelper.findSupportedAbi(handle,
                     (abiOverride != null) ? new String[] { abiOverride } : Build.SUPPORTED_ABIS);
             return calculateContainerSize(handle, apkFile, abi, forwardLocked);
@@ -852,7 +852,7 @@
      * @return size in megabytes (2^20 bytes)
      * @throws IOException when there is a problem reading the file
      */
-    private int calculateContainerSize(NativeLibraryHelper.ApkHandle apkHandle,
+    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();
@@ -863,7 +863,7 @@
         // Check all the native files that need to be copied and add that to the
         // container size.
         if (abiIndex >= 0) {
-            sizeBytes += NativeLibraryHelper.sumNativeBinariesLI(apkHandle,
+            sizeBytes += NativeLibraryHelper.sumNativeBinariesLI(handle,
                     Build.SUPPORTED_ABIS[abiIndex]);
         }
 
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 11e546f..c011cf9 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -20,7 +20,6 @@
 import static android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
 import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
 import static android.content.pm.PackageManager.INSTALL_FAILED_PACKAGE_CHANGED;
-import static android.content.pm.PackageManager.INSTALL_SUCCEEDED;
 
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageInstallObserver2;
@@ -31,7 +30,6 @@
 import android.content.pm.PackageParser.ApkLite;
 import android.content.pm.PackageParser.PackageParserException;
 import android.content.pm.Signature;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.FileBridge;
 import android.os.FileUtils;
@@ -40,7 +38,6 @@
 import android.os.Message;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
-import android.os.SELinux;
 import android.os.UserHandle;
 import android.system.ErrnoException;
 import android.system.OsConstants;
@@ -48,11 +45,9 @@
 import android.util.ArraySet;
 import android.util.Slog;
 
-import com.android.internal.content.NativeLibraryHelper;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.Preconditions;
 
-import libcore.io.IoUtils;
 import libcore.io.Libcore;
 
 import java.io.File;
@@ -110,7 +105,6 @@
     private Signature[] mSignatures;
 
     private boolean mMutationsAllowed;
-    private boolean mVerifierConfirmed;
     private boolean mPermissionsConfirmed;
     private boolean mInvalid;
 
@@ -238,21 +232,12 @@
         Preconditions.checkNotNull(mPackageName);
         Preconditions.checkNotNull(mSignatures);
 
-        if (!mVerifierConfirmed) {
-            // TODO: async communication with verifier
-            // when they confirm, we'll kick off another install() pass
-            mVerifierConfirmed = true;
-        }
-
         if (!mPermissionsConfirmed) {
             // TODO: async confirm permissions with user
             // when they confirm, we'll kick off another install() pass
             mPermissionsConfirmed = true;
         }
 
-        // Unpack any native libraries contained in this session
-        unpackNativeLibraries();
-
         // Inherit any packages and native libraries from existing install that
         // haven't been overridden.
         if (!params.fullInstall) {
@@ -425,58 +410,6 @@
         }
     }
 
-    private void unpackNativeLibraries() throws InstallFailedException {
-        final File libDir = new File(sessionDir, "lib");
-
-        if (!libDir.mkdir()) {
-            throw new InstallFailedException(INSTALL_FAILED_INTERNAL_ERROR,
-                    "Failed to create " + libDir);
-        }
-
-        try {
-            Libcore.os.chmod(libDir.getAbsolutePath(), 0755);
-        } catch (ErrnoException e) {
-            throw new InstallFailedException(INSTALL_FAILED_INTERNAL_ERROR,
-                    "Failed to prepare " + libDir + ": " + e);
-        }
-
-        if (!SELinux.restorecon(libDir)) {
-            throw new InstallFailedException(INSTALL_FAILED_INTERNAL_ERROR,
-                    "Failed to set context on " + libDir);
-        }
-
-        // Unpack all native libraries under stage
-        final File[] files = sessionDir.listFiles();
-        if (ArrayUtils.isEmpty(files)) {
-            throw new InstallFailedException(INSTALL_FAILED_INVALID_APK, "No packages staged");
-        }
-
-        for (File file : files) {
-            NativeLibraryHelper.ApkHandle handle = null;
-            try {
-                handle = NativeLibraryHelper.ApkHandle.create(file);
-                final int abiIndex = NativeLibraryHelper.findSupportedAbi(handle,
-                        Build.SUPPORTED_ABIS);
-                if (abiIndex >= 0) {
-                    int copyRet = NativeLibraryHelper.copyNativeBinariesIfNeededLI(handle, libDir,
-                            Build.SUPPORTED_ABIS[abiIndex]);
-                    if (copyRet != INSTALL_SUCCEEDED) {
-                        throw new InstallFailedException(copyRet,
-                                "Failed to copy native libraries for " + file);
-                    }
-                } else if (abiIndex != PackageManager.NO_NATIVE_LIBRARIES) {
-                    throw new InstallFailedException(abiIndex,
-                            "Failed to copy native libraries for " + file);
-                }
-            } catch (IOException ioe) {
-                throw new InstallFailedException(INSTALL_FAILED_INTERNAL_ERROR,
-                        "Failed to create handle for " + file);
-            } finally {
-                IoUtils.closeQuietly(handle);
-            }
-        }
-    }
-
     @Override
     public void destroy() {
         try {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 91f119d..27b4843 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -24,7 +24,7 @@
 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.PackageParser.isPackageFilename;
+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.S_IRGRP;
@@ -42,7 +42,6 @@
 import com.android.internal.app.IMediaContainerService;
 import com.android.internal.app.ResolverActivity;
 import com.android.internal.content.NativeLibraryHelper;
-import com.android.internal.content.NativeLibraryHelper.ApkHandle;
 import com.android.internal.content.PackageHelper;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastPrintWriter;
@@ -4096,7 +4095,7 @@
         }
 
         for (File file : files) {
-            if (!isPackageFilename(file)) {
+            if (!isApkFile(file)) {
                 // Ignore entries which are not apk's
                 continue;
             }
@@ -5358,10 +5357,9 @@
          *        only for non-system apps and system app upgrades.
          */
         if (pkg.applicationInfo.nativeLibraryDir != null) {
-            // TODO: extend to extract native code from split APKs
-            ApkHandle handle = null;
+            NativeLibraryHelper.Handle handle = null;
             try {
-                handle = ApkHandle.create(scanFile.getPath());
+                handle = NativeLibraryHelper.Handle.create(scanFile);
                 // Enable gross and lame hacks for apps that are built with old
                 // SDK tools. We must scan their APKs for renderscript bitcode and
                 // not launch them if it's present. Don't bother checking on devices
@@ -6178,7 +6176,7 @@
         }
     }
 
-    private static int copyNativeLibrariesForInternalApp(ApkHandle handle,
+    private static int copyNativeLibrariesForInternalApp(NativeLibraryHelper.Handle handle,
             final File nativeLibraryDir, String[] abiList) throws IOException {
         if (!nativeLibraryDir.isDirectory()) {
             nativeLibraryDir.delete();
@@ -7486,7 +7484,7 @@
                 if (DEBUG_APP_DIR_OBSERVER)
                     Log.v(TAG, "File " + fullPathStr + " changed: " + Integer.toHexString(event));
 
-                if (!isPackageFilename(path)) {
+                if (!isApkFile(fullPath)) {
                     if (DEBUG_APP_DIR_OBSERVER)
                         Log.v(TAG, "Ignoring change of non-package file: " + fullPathStr);
                     return;
@@ -9211,9 +9209,9 @@
 
             String[] abiList = (abiOverride != null) ?
                     new String[] { abiOverride } : Build.SUPPORTED_ABIS;
-            ApkHandle handle = null;
+            NativeLibraryHelper.Handle handle = null;
             try {
-                handle = ApkHandle.create(codeFile);
+                handle = NativeLibraryHelper.Handle.create(codeFile);
                 if (Build.SUPPORTED_64_BIT_ABIS.length > 0 &&
                         abiOverride == null &&
                         NativeLibraryHelper.hasRenderscriptBitcode(handle)) {
@@ -12955,9 +12953,10 @@
                                     final File newNativeDir = new File(newNativePath);
 
                                     if (!isForwardLocked(pkg) && !isExternal(pkg)) {
-                                        ApkHandle handle = null;
+                                        NativeLibraryHelper.Handle handle = null;
                                         try {
-                                            handle = ApkHandle.create(newCodePath);
+                                            handle = NativeLibraryHelper.Handle.create(
+                                                    new File(newCodePath));
                                             final int abi = NativeLibraryHelper.findSupportedAbi(
                                                     handle, Build.SUPPORTED_ABIS);
                                             if (abi >= 0) {