Merge "PM: Load all splits when parsing an app manifest" into lmp-dev
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 142206a..b09d3ac 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -354,7 +354,11 @@
     }
 
     public static final boolean isApkFile(File file) {
-        return file.getName().endsWith(".apk");
+        return isApkPath(file.getName());
+    }
+
+    private static boolean isApkPath(String path) {
+        return path.endsWith(".apk");
     }
 
     /*
@@ -754,26 +758,41 @@
                     "Not a coreApp: " + packageDir);
         }
 
-        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);
-        }
+        final AssetManager assets = new AssetManager();
+        try {
+            // Load the base and all splits into the AssetManager
+            // so that resources can be overriden when parsing the manifests.
+            loadApkIntoAssetManager(assets, lite.baseCodePath, flags);
 
-        if (!ArrayUtils.isEmpty(lite.splitNames)) {
-            final int num = lite.splitNames.length;
-            pkg.splitNames = lite.splitNames;
-            pkg.splitCodePaths = lite.splitCodePaths;
-            pkg.splitFlags = new int[num];
-
-            for (int i = 0; i < num; i++) {
-                parseSplitApk(pkg, i, flags);
+            if (!ArrayUtils.isEmpty(lite.splitCodePaths)) {
+                for (String path : lite.splitCodePaths) {
+                    loadApkIntoAssetManager(assets, path, flags);
+                }
             }
-        }
 
-        pkg.codePath = packageDir.getAbsolutePath();
-        return pkg;
+            final File baseApk = new File(lite.baseCodePath);
+            final Package pkg = parseBaseApk(baseApk, assets, flags);
+            if (pkg == null) {
+                throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
+                        "Failed to parse base APK: " + baseApk);
+            }
+
+            if (!ArrayUtils.isEmpty(lite.splitNames)) {
+                final int num = lite.splitNames.length;
+                pkg.splitNames = lite.splitNames;
+                pkg.splitCodePaths = lite.splitCodePaths;
+                pkg.splitFlags = new int[num];
+
+                for (int i = 0; i < num; i++) {
+                    parseSplitApk(pkg, i, assets, flags);
+                }
+            }
+
+            pkg.codePath = packageDir.getAbsolutePath();
+            return pkg;
+        } finally {
+            IoUtils.closeQuietly(assets);
+        }
     }
 
     /**
@@ -796,35 +815,48 @@
             }
         }
 
-        final Package pkg = parseBaseApk(apkFile, flags);
-        pkg.codePath = apkFile.getAbsolutePath();
-        return pkg;
+        final AssetManager assets = new AssetManager();
+        try {
+            final Package pkg = parseBaseApk(apkFile, assets, flags);
+            pkg.codePath = apkFile.getAbsolutePath();
+            return pkg;
+        } finally {
+            IoUtils.closeQuietly(assets);
+        }
     }
 
-    private Package parseBaseApk(File apkFile, int flags) throws PackageParserException {
+    private static int loadApkIntoAssetManager(AssetManager assets, String apkPath, int flags)
+            throws PackageParserException {
+        if ((flags & PARSE_MUST_BE_APK) != 0 && !isApkPath(apkPath)) {
+            throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
+                    "Invalid package file: " + apkPath);
+        }
+
+        // The AssetManager guarantees uniqueness for asset paths, so if this asset path
+        // already exists in the AssetManager, addAssetPath will only return the cookie
+        // assigned to it.
+        int cookie = assets.addAssetPath(apkPath);
+        if (cookie == 0) {
+            throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
+                    "Failed adding asset path: " + apkPath);
+        }
+        return cookie;
+    }
+
+    private Package parseBaseApk(File apkFile, AssetManager assets, int flags)
+            throws PackageParserException {
         final String apkPath = apkFile.getAbsolutePath();
 
         mParseError = PackageManager.INSTALL_SUCCEEDED;
         mArchiveSourcePath = apkFile.getAbsolutePath();
 
-        if ((flags & PARSE_MUST_BE_APK) != 0 && !isApkFile(apkFile)) {
-            throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
-                    "Invalid package file: " + apkPath);
-        }
-
         if (DEBUG_JAR) Slog.d(TAG, "Scanning base APK: " + apkPath);
 
-        AssetManager assets = null;
+        final int cookie = loadApkIntoAssetManager(assets, apkPath, flags);
+
         Resources res = null;
         XmlResourceParser parser = null;
         try {
-            assets = new AssetManager();
-            int cookie = assets.addAssetPath(apkPath);
-            if (cookie == 0) {
-                throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
-                        "Failed adding asset path: " + apkPath);
-            }
-
             res = new Resources(assets, mMetrics, null);
             assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                     Build.VERSION.RESOURCES_SDK_INT);
@@ -849,11 +881,10 @@
                     "Failed to read manifest from " + apkPath, e);
         } finally {
             IoUtils.closeQuietly(parser);
-            IoUtils.closeQuietly(assets);
         }
     }
 
-    private void parseSplitApk(Package pkg, int splitIndex, int flags)
+    private void parseSplitApk(Package pkg, int splitIndex, AssetManager assets, int flags)
             throws PackageParserException {
         final String apkPath = pkg.splitCodePaths[splitIndex];
         final File apkFile = new File(apkPath);
@@ -861,24 +892,13 @@
         mParseError = PackageManager.INSTALL_SUCCEEDED;
         mArchiveSourcePath = apkPath;
 
-        if ((flags & PARSE_MUST_BE_APK) != 0 && !isApkFile(apkFile)) {
-            throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
-                    "Invalid package file: " + apkPath);
-        }
-
         if (DEBUG_JAR) Slog.d(TAG, "Scanning split APK: " + apkPath);
 
-        AssetManager assets = null;
+        final int cookie = loadApkIntoAssetManager(assets, apkPath, flags);
+
         Resources res = null;
         XmlResourceParser parser = null;
         try {
-            assets = new AssetManager();
-            int cookie = assets.addAssetPath(apkPath);
-            if (cookie == 0) {
-                throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
-                        "Failed adding asset path: " + apkPath);
-            }
-
             res = new Resources(assets, mMetrics, null);
             assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                     Build.VERSION.RESOURCES_SDK_INT);
@@ -898,7 +918,6 @@
                     "Failed to read manifest from " + apkPath, e);
         } finally {
             IoUtils.closeQuietly(parser);
-            IoUtils.closeQuietly(assets);
         }
     }
 
diff --git a/tests/Split/res/values-xxhdpi/values.xml b/tests/Split/res/values-xxhdpi/values.xml
new file mode 100644
index 0000000..0b5f2d8
--- /dev/null
+++ b/tests/Split/res/values-xxhdpi/values.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <string name="app_title">Split APK XX-HDPI</string>
+</resources>