Improve PackageInfo parsing for apex files

"meta-data" in AndroidManifest was not getting parsed by the existing logic.

Bug: 129091257
Test: atest android.content.pm.PackageParserTest
Change-Id: I3d1c38ba3b2a0ccef6a0d7d0ee5ab857b62a7b82
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 35d1eac..969dfef 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -4796,7 +4796,7 @@
             // except for watches which always supported 1:1.
             minAspectRatio = owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.Q
                     ? 0
-                    : mCallback.hasFeature(FEATURE_WATCH)
+                    : (mCallback != null && mCallback.hasFeature(FEATURE_WATCH))
                             ? DEFAULT_PRE_Q_MIN_ASPECT_RATIO_WATCH
                             : DEFAULT_PRE_Q_MIN_ASPECT_RATIO;
         }
@@ -8373,71 +8373,36 @@
     }
 
     // TODO(b/129261524): Clean up API
-    public static PackageInfo generatePackageInfoFromApex(File apexFile, boolean collectCerts)
+    /**
+     * PackageInfo parser specifically for apex files.
+     * NOTE: It will collect certificates
+     *
+     * @param apexFile
+     * @return PackageInfo
+     * @throws PackageParserException
+     */
+    public static PackageInfo generatePackageInfoFromApex(File apexFile, int flags)
             throws PackageParserException {
-        PackageInfo pi = new PackageInfo();
-        int parseFlags = 0;
-        if (collectCerts) {
-            parseFlags |= PARSE_COLLECT_CERTIFICATES;
-            try {
-                if (apexFile.getCanonicalPath().startsWith("/system")) {
-                    // Don't need verify the APK integrity of APEXes on /system, just like
-                    // we don't do that for APKs.
-                    // TODO(b/126514108): we may be able to do this for APEXes on /data as well.
-                    parseFlags |= PARSE_IS_SYSTEM_DIR;
-                }
-            } catch (IOException e) {
-                throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
-                        "Failed to get path for " + apexFile.getPath(), e);
-            }
-        }
+        PackageParser pp = new PackageParser();
+        final Package p = pp.parsePackage(apexFile, flags, false);
+        PackageUserState state = new PackageUserState();
+        PackageInfo pi = generatePackageInfo(p, EmptyArray.INT, flags, 0, 0,
+                Collections.emptySet(), state);
 
-        PackageParser.ApkLite apk = PackageParser.parseApkLite(apexFile, parseFlags);
+        pi.applicationInfo.sourceDir = apexFile.getPath();
+        pi.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_INSTALLED;
+        pi.isApex = true;
 
-        // Properly fill in the ApplicationInfo with data from AndroidManifest
-        // Add ApplicationInfo to the PackageInfo.
-        // TODO(b/129267599)
-        ApplicationInfo ai = new ApplicationInfo();
-        ai.packageName = apk.packageName;
-        ai.sourceDir = apexFile.getPath();
-        ai.flags = ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_INSTALLED;
-        ai.enabled = true;
-        ai.minSdkVersion = apk.minSdkVersion;
-        ai.targetSdkVersion = apk.targetSdkVersion;
-        ai.targetSandboxVersion = PARSE_DEFAULT_TARGET_SANDBOX;
-        ai.setVersionCode(apk.getLongVersionCode());
-
-        pi.packageName = apk.packageName;
-        pi.splitNames = new String[]{apk.splitName};
-        pi.setLongVersionCode(apk.getLongVersionCode());
-        pi.applicationInfo = ai;
-        pi.coreApp = apk.coreApp;
-
-
-        if (collectCerts) {
-            if (apk.signingDetails.hasPastSigningCertificates()) {
-                // Package has included signing certificate rotation information.  Return
-                // the oldest cert so that programmatic checks keep working even if unaware
-                // of key rotation.
-                pi.signatures = new Signature[1];
-                pi.signatures[0] = apk.signingDetails.pastSigningCertificates[0];
-            } else if (apk.signingDetails.hasSignatures()) {
-                // otherwise keep old behavior
-                int numberOfSigs = apk.signingDetails.signatures.length;
-                pi.signatures = new Signature[numberOfSigs];
-                System.arraycopy(apk.signingDetails.signatures, 0, pi.signatures, 0,
-                    numberOfSigs);
-            }
-
-            if (apk.signingDetails != SigningDetails.UNKNOWN) {
+        // Collect certificates
+        if ((flags & PackageManager.GET_SIGNING_CERTIFICATES) != 0) {
+            collectCertificates(p, apexFile, false);
+            if (p.mSigningDetails != SigningDetails.UNKNOWN) {
                 // only return a valid SigningInfo if there is signing information to report
-                pi.signingInfo = new SigningInfo(apk.signingDetails);
+                pi.signingInfo = new SigningInfo(p.mSigningDetails);
             } else {
                 pi.signingInfo = null;
             }
         }
-
-        pi.isApex = true;
         return pi;
     }
 }
diff --git a/core/tests/coretests/res/raw/com_android_tzdata.apex b/core/tests/coretests/res/raw/com_android_tzdata.apex
index 06ea8fa..ca89bf6 100644
--- a/core/tests/coretests/res/raw/com_android_tzdata.apex
+++ b/core/tests/coretests/res/raw/com_android_tzdata.apex
Binary files differ
diff --git a/core/tests/coretests/src/android/content/pm/PackageParserTest.java b/core/tests/coretests/src/android/content/pm/PackageParserTest.java
index 0798c0c..50e915d 100644
--- a/core/tests/coretests/src/android/content/pm/PackageParserTest.java
+++ b/core/tests/coretests/src/android/content/pm/PackageParserTest.java
@@ -499,30 +499,20 @@
     public void testApexPackageInfoGeneration() throws Exception {
         File apexFile = copyRawResourceToFile("com.android.tzdata.apex",
                 R.raw.com_android_tzdata);
-        PackageInfo pi = PackageParser.generatePackageInfoFromApex(apexFile, false);
+        int flags = PackageManager.GET_META_DATA | PackageManager.GET_SIGNING_CERTIFICATES;
+        PackageInfo pi = PackageParser.generatePackageInfoFromApex(apexFile, flags);
         assertEquals("com.google.android.tzdata", pi.applicationInfo.packageName);
         assertTrue(pi.applicationInfo.enabled);
         assertEquals(28, pi.applicationInfo.targetSdkVersion);
-        assertEquals(1, pi.applicationInfo.longVersionCode);
+        assertEquals(191000070, pi.applicationInfo.longVersionCode);
+        assertNotNull(pi.applicationInfo.metaData);
+        assertEquals(apexFile.getPath(), pi.applicationInfo.sourceDir);
+        assertEquals("Bundle[{com.android.vending.derived.apk.id=1}]",
+                pi.applicationInfo.metaData.toString());
 
         assertEquals("com.google.android.tzdata", pi.packageName);
-        assertTrue(pi.splitNames.length > 0);
-        assertEquals(1, pi.getLongVersionCode());
-        assertNull(pi.signingInfo);
-        assertNull(pi.signatures);
-        assertTrue(pi.isApex);
-
-        pi = PackageParser.generatePackageInfoFromApex(apexFile, true);
-        assertEquals("com.google.android.tzdata", pi.applicationInfo.packageName);
-        assertTrue(pi.applicationInfo.enabled);
-        assertEquals(28, pi.applicationInfo.targetSdkVersion);
-        assertEquals(1, pi.applicationInfo.longVersionCode);
-
-        assertEquals("com.google.android.tzdata", pi.packageName);
-        assertTrue(pi.splitNames.length > 0);
-        assertEquals(1, pi.getLongVersionCode());
+        assertEquals(191000070, pi.getLongVersionCode());
         assertNotNull(pi.signingInfo);
-        assertNotNull(pi.signatures);
         assertTrue(pi.signingInfo.getApkContentsSigners().length > 0);
         assertTrue(pi.isApex);
     }
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index 5fdd872..944aef5 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -27,6 +27,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
 import android.content.pm.PackageParser;
 import android.content.pm.PackageParser.PackageParserException;
 import android.os.RemoteException;
@@ -95,7 +96,8 @@
                     }
                     try {
                         list.add(PackageParser.generatePackageInfoFromApex(
-                                new File(ai.packagePath), true /* collect certs */));
+                                new File(ai.packagePath), PackageManager.GET_META_DATA
+                                | PackageManager.GET_SIGNING_CERTIFICATES));
                     } catch (PackageParserException pe) {
                         throw new IllegalStateException("Unable to parse: " + ai, pe);
                     }