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