Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7aa7d2ee authored by Mohammad Samiul Islam's avatar Mohammad Samiul Islam
Browse files

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
parent 8c84b92e
Loading
Loading
Loading
Loading
+24 −59
Original line number Diff line number Diff line
@@ -4796,7 +4796,7 @@ public class PackageParser {
            // 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 @@ public class PackageParser {
    }

    // 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.ApkLite apk = PackageParser.parseApkLite(apexFile, parseFlags);

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

        pi.applicationInfo.sourceDir = apexFile.getPath();
        pi.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_INSTALLED;
        pi.isApex = true;

            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;
    }
}
+8 −18
Original line number Diff line number Diff line
@@ -499,30 +499,20 @@ public class PackageParserTest {
    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);
    }
+3 −1
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import android.content.Context;
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 @@ class ApexManager {
                    }
                    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);
                    }