Merge cherrypicks of [6101029, 6097918, 6101068, 6101069, 6101070, 6101071, 6097919] into qt-release

Change-Id: I572073c39161a1d2f5a6aeca796fb3b4f9ccde61
diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java
index b8d7889..33d8da7 100644
--- a/core/java/android/content/pm/PackageInfo.java
+++ b/core/java/android/content/pm/PackageInfo.java
@@ -18,7 +18,6 @@
 
 import android.annotation.Nullable;
 import android.annotation.UnsupportedAppUsage;
-import android.apex.ApexInfo;
 import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -573,15 +572,6 @@
         }
     }
 
-    /**
-     * @hide
-     */
-    public PackageInfo(ApexInfo apexInfo) {
-        packageName = apexInfo.packageName;
-        setLongVersionCode(apexInfo.versionCode);
-        isApex = true;
-    }
-
     private void propagateApplicationInfo(ApplicationInfo appInfo, ComponentInfo[] components) {
         if (components != null) {
             for (ComponentInfo ci : components) {
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index dbf3574..486edf0 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -8484,4 +8484,42 @@
             this.error = error;
         }
     }
+
+    public static PackageInfo generatePackageInfoFromApex(File apexFile, boolean collectCerts)
+            throws PackageParserException {
+        PackageInfo pi = new PackageInfo();
+        // TODO(b/123052859): We should avoid these repeated calls to parseApkLite each time
+        // we want to generate information for APEX modules.
+        PackageParser.ApkLite apk = PackageParser.parseApkLite(apexFile,
+            collectCerts ? PackageParser.PARSE_COLLECT_CERTIFICATES : 0);
+
+        pi.packageName = apk.packageName;
+        pi.setLongVersionCode(apk.getLongVersionCode());
+
+        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) {
+                // only return a valid SigningInfo if there is signing information to report
+                pi.signingInfo = new SigningInfo(apk.signingDetails);
+            } 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
new file mode 100644
index 0000000..72294de
--- /dev/null
+++ 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 be1b1ce..c5454a6 100644
--- a/core/tests/coretests/src/android/content/pm/PackageParserTest.java
+++ b/core/tests/coretests/src/android/content/pm/PackageParserTest.java
@@ -330,6 +330,28 @@
     }
 
     /**
+     * Copies a specified {@code resourceId} to a file. Returns a non-null file if the copy
+     * succeeded, or {@code null} otherwise.
+     */
+    File copyRawResourceToFile(String baseName, int resourceId) throws Exception {
+        // Copy the resource to a file.
+        Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+        InputStream is = context.getResources().openRawResource(resourceId);
+        File outFile = null;
+        try {
+            outFile = new File(context.getFilesDir(), baseName);
+            assertTrue(FileUtils.copyToFile(is, outFile));
+            return outFile;
+        } catch (Exception e) {
+            if (outFile != null) {
+                outFile.delete();
+            }
+
+            return null;
+        }
+    }
+
+    /**
      * Attempts to parse a package.
      *
      * APKs are put into coretests/apks/packageparser_*.
@@ -340,14 +362,14 @@
     Package parsePackage(String apkFileName, int apkResourceId,
             Function<Package, Package> converter) throws Exception {
         // Copy the resource to a file.
-        Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
-        File outFile = new File(context.getFilesDir(), apkFileName);
+        File outFile = null;
         try {
-            InputStream is = context.getResources().openRawResource(apkResourceId);
-            assertTrue(FileUtils.copyToFile(is, outFile));
+            outFile = copyRawResourceToFile(apkFileName, apkResourceId);
             return converter.apply(new PackageParser().parsePackage(outFile, 0 /* flags */));
         } finally {
-            outFile.delete();
+            if (outFile != null) {
+                outFile.delete();
+            }
         }
     }
 
@@ -498,4 +520,20 @@
                         "android.permission.READ_CONTACTS"),
                 secondChild.requestedPermissions);
     }
+
+    @Test
+    public void testApexPackageInfoGeneration() throws Exception {
+        File apexFile = copyRawResourceToFile("com.android.tzdata.apex",
+                R.raw.com_android_tzdata);
+        PackageInfo pi = PackageParser.generatePackageInfoFromApex(apexFile, false);
+        assertEquals("com.google.android.tzdata", pi.packageName);
+        assertEquals(1, pi.getLongVersionCode());
+        assertNull(pi.signingInfo);
+
+        pi = PackageParser.generatePackageInfoFromApex(apexFile, true);
+        assertEquals("com.google.android.tzdata", pi.packageName);
+        assertEquals(1, pi.getLongVersionCode());
+        assertNotNull(pi.signingInfo);
+        assertTrue(pi.signingInfo.getApkContentsSigners().length > 0);
+    }
 }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 70ead41..e7c8770 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -7872,8 +7872,13 @@
                 if (apex != null) {
                     try {
                         final ApexInfo[] activePkgs = apex.getActivePackages();
-                        for (ApexInfo apexInfo : activePkgs) {
-                            list.add(new PackageInfo(apexInfo));
+                        for (ApexInfo ai : activePkgs) {
+                            try {
+                                 list.add(PackageParser.generatePackageInfoFromApex(
+                                         new File(ai.packagePath), true /* collect certs */));
+                            } catch (PackageParserException pe) {
+                                 throw new IllegalStateException("Unable to parse: " + ai, pe);
+                            }
                         }
                     } catch (RemoteException e) {
                         Log.e(TAG, "Unable to retrieve packages from apexservice: " + e.toString());