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());