Allow splits to declare a classloader type.

Add an attribute android:classLoader which can be set to the name
of the classloader the base or split wishes to use. For now, this can
only be set to "dalvik.system.PathClassLoader" or
"dalvik.system.DelegateLastClassLoader". The current implementation
only allows the classloader to exist in the boot classpath but that
restriction can be loosened in a future change if necessary.

Test: cts-tradefed run cts-dev -m CtsAppSecurityHostTestCases
Bug: 36044779

Change-Id: I5a51f7aa0c8c4c398d2f46129eb06785cc8e3c3f
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 06f7916..0bfe567 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -1005,6 +1005,12 @@
         }
     }
 
+    /** @hide */
+    public String classLoaderName;
+
+    /** @hide */
+    public String[] splitClassLoaderNames;
+
     public void dump(Printer pw, String prefix) {
         dump(pw, prefix, DUMP_FLAG_ALL);
     }
@@ -1056,6 +1062,13 @@
                 pw.println(prefix + "sharedLibraryFiles=" + Arrays.toString(sharedLibraryFiles));
             }
         }
+        if (classLoaderName != null) {
+            pw.println(prefix + "classLoaderName=" + classLoaderName);
+        }
+        if (!ArrayUtils.isEmpty(splitClassLoaderNames)) {
+            pw.println(prefix + "splitClassLoaderNames=" + Arrays.toString(splitClassLoaderNames));
+        }
+
         pw.println(prefix + "enabled=" + enabled
                 + " minSdkVersion=" + minSdkVersion
                 + " targetSdkVersion=" + targetSdkVersion
@@ -1178,6 +1191,8 @@
         networkSecurityConfigRes = orig.networkSecurityConfigRes;
         category = orig.category;
         targetSandboxVersion = orig.targetSandboxVersion;
+        classLoaderName = orig.classLoaderName;
+        splitClassLoaderNames = orig.splitClassLoaderNames;
     }
 
     public String toString() {
@@ -1246,6 +1261,8 @@
         dest.writeInt(networkSecurityConfigRes);
         dest.writeInt(category);
         dest.writeInt(targetSandboxVersion);
+        dest.writeString(classLoaderName);
+        dest.writeStringArray(splitClassLoaderNames);
     }
 
     public static final Parcelable.Creator<ApplicationInfo> CREATOR
@@ -1311,6 +1328,8 @@
         networkSecurityConfigRes = source.readInt();
         category = source.readInt();
         targetSandboxVersion = source.readInt();
+        classLoaderName = source.readString();
+        splitClassLoaderNames = source.readStringArray();
     }
 
     /**
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index e4f2fc1..eb6e0d8 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -88,6 +88,7 @@
 
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.ClassLoaderFactory;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.XmlUtils;
 
@@ -415,9 +416,12 @@
         public final boolean extractNativeLibs;
         public final boolean isolatedSplits;
 
+        public final String classLoaderName;
+        public final String[] splitClassLoaderNames;
+
         public PackageLite(String codePath, ApkLite baseApk, String[] splitNames,
                 boolean[] isFeatureSplits, String[] usesSplitNames, String[] configForSplit,
-                String[] splitCodePaths, int[] splitRevisionCodes) {
+                String[] splitCodePaths, int[] splitRevisionCodes, String[] splitClassLoaderNames) {
             this.packageName = baseApk.packageName;
             this.versionCode = baseApk.versionCode;
             this.installLocation = baseApk.installLocation;
@@ -437,6 +441,9 @@
             this.use32bitAbi = baseApk.use32bitAbi;
             this.extractNativeLibs = baseApk.extractNativeLibs;
             this.isolatedSplits = baseApk.isolatedSplits;
+
+            this.classLoaderName = baseApk.classLoaderName;
+            this.splitClassLoaderNames = splitClassLoaderNames;
         }
 
         public List<String> getAllCodePaths() {
@@ -471,13 +478,14 @@
         public final boolean use32bitAbi;
         public final boolean extractNativeLibs;
         public final boolean isolatedSplits;
+        public final String classLoaderName;
 
         public ApkLite(String codePath, String packageName, String splitName, boolean isFeatureSplit,
                 String configForSplit, String usesSplitName, int versionCode, int revisionCode,
                 int installLocation, List<VerifierInfo> verifiers, Signature[] signatures,
                 Certificate[][] certificates, boolean coreApp, boolean debuggable,
                 boolean multiArch, boolean use32bitAbi, boolean extractNativeLibs,
-                boolean isolatedSplits) {
+                boolean isolatedSplits, String classLoaderName) {
             this.codePath = codePath;
             this.packageName = packageName;
             this.splitName = splitName;
@@ -496,6 +504,7 @@
             this.use32bitAbi = use32bitAbi;
             this.extractNativeLibs = extractNativeLibs;
             this.isolatedSplits = isolatedSplits;
+            this.classLoaderName = classLoaderName;
         }
     }
 
@@ -863,7 +872,7 @@
         final ApkLite baseApk = parseApkLite(packageFile, flags);
         final String packagePath = packageFile.getAbsolutePath();
         Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
-        return new PackageLite(packagePath, baseApk, null, null, null, null, null, null);
+        return new PackageLite(packagePath, baseApk, null, null, null, null, null, null, null);
     }
 
     static PackageLite parseClusterPackageLite(File packageDir, int flags)
@@ -926,6 +935,7 @@
         String[] configForSplits = null;
         String[] splitCodePaths = null;
         int[] splitRevisionCodes = null;
+        String[] splitClassLoaderNames = null;
         if (size > 0) {
             splitNames = new String[size];
             isFeatureSplits = new boolean[size];
@@ -933,6 +943,7 @@
             configForSplits = new String[size];
             splitCodePaths = new String[size];
             splitRevisionCodes = new int[size];
+            splitClassLoaderNames = new String[size];
 
             splitNames = apks.keySet().toArray(splitNames);
             Arrays.sort(splitNames, sSplitNameComparator);
@@ -944,12 +955,13 @@
                 configForSplits[i] = apk.configForSplit;
                 splitCodePaths[i] = apk.codePath;
                 splitRevisionCodes[i] = apk.revisionCode;
+                splitClassLoaderNames[i] = apk.classLoaderName;
             }
         }
 
         final String codePath = packageDir.getAbsolutePath();
         return new PackageLite(codePath, baseApk, splitNames, isFeatureSplits, usesSplitNames,
-                configForSplits, splitCodePaths, splitRevisionCodes);
+                configForSplits, splitCodePaths, splitRevisionCodes, splitClassLoaderNames);
     }
 
     /**
@@ -1187,6 +1199,8 @@
                 pkg.splitPrivateFlags = new int[num];
                 pkg.applicationInfo.splitNames = pkg.splitNames;
                 pkg.applicationInfo.splitDependencies = splitDependencies;
+                pkg.applicationInfo.classLoaderName = lite.classLoaderName;
+                pkg.applicationInfo.splitClassLoaderNames = lite.splitClassLoaderNames;
 
                 for (int i = 0; i < num; i++) {
                     final AssetManager splitAssets = assetLoader.getSplitAssetManager(i);
@@ -1697,7 +1711,7 @@
             }
 
             final AttributeSet attrs = parser;
-            return parseApkLite(apkPath, parser, attrs, flags, signatures, certificates);
+            return parseApkLite(apkPath, parser, attrs, signatures, certificates);
 
         } catch (XmlPullParserException | IOException | RuntimeException e) {
             Slog.w(TAG, "Failed to parse " + apkPath, e);
@@ -1784,7 +1798,7 @@
     }
 
     private static ApkLite parseApkLite(String codePath, XmlPullParser parser, AttributeSet attrs,
-            int flags, Signature[] signatures, Certificate[][] certificates)
+            Signature[] signatures, Certificate[][] certificates)
             throws IOException, XmlPullParserException, PackageParserException {
         final Pair<String, String> packageSplit = parsePackageSplitNames(parser, attrs);
 
@@ -1800,6 +1814,7 @@
         boolean isFeatureSplit = false;
         String configForSplit = null;
         String usesSplitName = null;
+        String classLoaderName = null;
 
         for (int i = 0; i < attrs.getAttributeCount(); i++) {
             final String attr = attrs.getAttributeName(i);
@@ -1856,6 +1871,14 @@
                     if ("extractNativeLibs".equals(attr)) {
                         extractNativeLibs = attrs.getAttributeBooleanValue(i, true);
                     }
+                    if ("classLoader".equals(attr)) {
+                        classLoaderName = attrs.getAttributeValue(i);
+                        if (!ClassLoaderFactory.isValidClassLoaderName(classLoaderName)) {
+                            throw new PackageParserException(
+                                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                                    "Invalid class loader name: " + classLoaderName);
+                        }
+                    }
                 }
             } else if (TAG_USES_SPLIT.equals(parser.getName())) {
                 if (usesSplitName != null) {
@@ -1875,19 +1898,7 @@
         return new ApkLite(codePath, packageSplit.first, packageSplit.second, isFeatureSplit,
                 configForSplit, usesSplitName, versionCode, revisionCode, installLocation,
                 verifiers, signatures, certificates, coreApp, debuggable, multiArch, use32bitAbi,
-                extractNativeLibs, isolatedSplits);
-    }
-
-    /**
-     * Temporary.
-     */
-    static public Signature stringToSignature(String str) {
-        final int N = str.length();
-        byte[] sig = new byte[N];
-        for (int i=0; i<N; i++) {
-            sig[i] = (byte)str.charAt(i);
-        }
-        return new Signature(sig);
+                extractNativeLibs, isolatedSplits, classLoaderName);
     }
 
     /**