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

Commit 1138012b authored by Oli Lan's avatar Oli Lan Committed by Bill Lin
Browse files

Clean up generatePackageInfoFromApex() API

This changes the API for generatePackageInfoFromApex in PackageParser
in response to review suggestions made in ag/6701090.

The method is renamed to generatePackageInfo with a PackageParser.Package
parameter (as well as an ApexInfo and flags). The implementation is combined
with the main generatePackageInfo method. Callers are changed to perform
the parsing themselves, including the collection of certificates if
necessary.

Note: the method signature and implementation had already changed since
ag/6701090, so the suggestions from that CL may not apply directly.

Bug: 129261524
Test: atest PackageParserTest
Test: atest CtsStagedInstallHostTestCases

Change-Id: Iee213e025583c2201ff9d65c447e4278b925a2f0
Merged-In: I495539679812110f89d5e3d93f2622ba2dab36c0
(cherry picked from commit c2c7a223)
parent 0d167a07
Loading
Loading
Loading
Loading
+57 −73
Original line number Diff line number Diff line
@@ -617,21 +617,6 @@ public class PackageParser {
        return path.endsWith(APK_FILE_EXTENSION);
    }

    /**
     * Generate and return the {@link PackageInfo} for a parsed package.
     *
     * @param p the parsed package.
     * @param flags indicating which optional information is included.
     */
    @UnsupportedAppUsage
    public static PackageInfo generatePackageInfo(PackageParser.Package p,
            int gids[], int flags, long firstInstallTime, long lastUpdateTime,
            Set<String> grantedPermissions, PackageUserState state) {

        return generatePackageInfo(p, gids, flags, firstInstallTime, lastUpdateTime,
                grantedPermissions, state, UserHandle.getCallingUserId());
    }

    /**
     * Returns true if the package is installed and not hidden, or if the caller
     * explicitly wanted all uninstalled and hidden packages as well.
@@ -658,8 +643,45 @@ public class PackageParser {
        return checkUseInstalledOrHidden(0, state, null);
    }

    /**
     * Generate and return the {@link PackageInfo} for a parsed package.
     *
     * @param p the parsed package.
     * @param flags indicating which optional information is included.
     */
    @UnsupportedAppUsage
    public static PackageInfo generatePackageInfo(PackageParser.Package p,
            int[] gids, int flags, long firstInstallTime, long lastUpdateTime,
            Set<String> grantedPermissions, PackageUserState state) {

        return generatePackageInfo(p, gids, flags, firstInstallTime, lastUpdateTime,
                grantedPermissions, state, UserHandle.getCallingUserId());
    }

    @UnsupportedAppUsage
    public static PackageInfo generatePackageInfo(PackageParser.Package p,
            int[] gids, int flags, long firstInstallTime, long lastUpdateTime,
            Set<String> grantedPermissions, PackageUserState state, int userId) {

        return generatePackageInfo(p, null, gids, flags, firstInstallTime, lastUpdateTime,
                grantedPermissions, state, userId);
    }

    /**
     * PackageInfo generator specifically for apex files.
     *
     * @param pkg Package to generate info from. Should be derived from an apex.
     * @param apexInfo Apex info relating to the package.
     * @return PackageInfo
     * @throws PackageParserException
     */
    public static PackageInfo generatePackageInfo(
            PackageParser.Package pkg, ApexInfo apexInfo, int flags) {
        return generatePackageInfo(pkg, apexInfo, EmptyArray.INT, flags, 0, 0,
                Collections.emptySet(), new PackageUserState(), UserHandle.getCallingUserId());
    }

    private static PackageInfo generatePackageInfo(PackageParser.Package p, ApexInfo apexInfo,
            int gids[], int flags, long firstInstallTime, long lastUpdateTime,
            Set<String> grantedPermissions, PackageUserState state, int userId) {
        if (!checkUseInstalledOrHidden(flags, state, p.applicationInfo) || !p.isMatch(flags)) {
@@ -806,6 +828,25 @@ public class PackageParser {
                }
            }
        }

        if (apexInfo != null) {
            File apexFile = new File(apexInfo.modulePath);

            pi.applicationInfo.sourceDir = apexFile.getPath();
            pi.applicationInfo.publicSourceDir = apexFile.getPath();
            if (apexInfo.isFactory) {
                pi.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
            } else {
                pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_SYSTEM;
            }
            if (apexInfo.isActive) {
                pi.applicationInfo.flags |= ApplicationInfo.FLAG_INSTALLED;
            } else {
                pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_INSTALLED;
            }
            pi.isApex = true;
        }

        // deprecated method of getting signing certificates
        if ((flags & PackageManager.GET_SIGNATURES) != 0) {
            if (p.mSigningDetails.hasPastSigningCertificates()) {
@@ -8379,61 +8420,4 @@ public class PackageParser {
        }
    }

    // TODO(b/129261524): Clean up API
    /**
     * PackageInfo parser specifically for apex files.
     * NOTE: It will collect certificates
     *
     * @param apexInfo
     * @return PackageInfo
     * @throws PackageParserException
     */
    public static PackageInfo generatePackageInfoFromApex(ApexInfo apexInfo, int flags)
            throws PackageParserException {
        PackageParser pp = new PackageParser();
        File apexFile = new File(apexInfo.modulePath);
        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.publicSourceDir = apexFile.getPath();
        if (apexInfo.isFactory) {
            pi.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
        } else {
            pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_SYSTEM;
        }
        if (apexInfo.isActive) {
            pi.applicationInfo.flags |= ApplicationInfo.FLAG_INSTALLED;
        } else {
            pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_INSTALLED;
        }
        pi.isApex = true;

        // Collect certificates
        if ((flags & PackageManager.GET_SIGNING_CERTIFICATES) != 0) {
            collectCertificates(p, apexFile, false);
            // Keep legacy mechanism for handling signatures. While this is deprecated, it's
            // still part of the public API and needs to be maintained
            if (p.mSigningDetails.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] = p.mSigningDetails.pastSigningCertificates[0];
            } else if (p.mSigningDetails.hasSignatures()) {
                // otherwise keep old behavior
                int numberOfSigs = p.mSigningDetails.signatures.length;
                pi.signatures = new Signature[numberOfSigs];
                System.arraycopy(p.mSigningDetails.signatures, 0, pi.signatures, 0, numberOfSigs);
            }
            if (p.mSigningDetails != SigningDetails.UNKNOWN) {
                // only return a valid SigningInfo if there is signing information to report
                pi.signingInfo = new SigningInfo(p.mSigningDetails);
            } else {
                pi.signingInfo = null;
            }
        }
        return pi;
    }
}
+6 −1
Original line number Diff line number Diff line
@@ -508,7 +508,12 @@ public class PackageParserTest {
        apexInfo.modulePath = apexFile.getPath();
        apexInfo.versionCode = 191000070;
        int flags = PackageManager.GET_META_DATA | PackageManager.GET_SIGNING_CERTIFICATES;
        PackageInfo pi = PackageParser.generatePackageInfoFromApex(apexInfo, flags);

        PackageParser pp = new PackageParser();
        Package p = pp.parsePackage(apexFile, flags, false);
        PackageParser.collectCertificates(p, false);
        PackageInfo pi = PackageParser.generatePackageInfo(p, apexInfo, flags);

        assertEquals("com.google.android.tzdata", pi.applicationInfo.packageName);
        assertTrue(pi.applicationInfo.enabled);
        assertEquals(28, pi.applicationInfo.targetSdkVersion);
+29 −20
Original line number Diff line number Diff line
@@ -282,30 +282,39 @@ abstract class ApexManager {
                        if ((new File(ai.modulePath)).isDirectory()) {
                            break;
                        }
                        int flags = PackageManager.GET_META_DATA
                                | PackageManager.GET_SIGNING_CERTIFICATES
                                | PackageManager.GET_SIGNATURES;
                        PackageParser.Package pkg;
                        try {
                            final PackageInfo pkg = PackageParser.generatePackageInfoFromApex(
                                    ai, PackageManager.GET_META_DATA
                                            | PackageManager.GET_SIGNING_CERTIFICATES);
                            mAllPackagesCache.add(pkg);
                            File apexFile = new File(ai.modulePath);
                            PackageParser pp = new PackageParser();
                            pkg = pp.parsePackage(apexFile, flags, false);
                            PackageParser.collectCertificates(pkg, false);
                        } catch (PackageParser.PackageParserException pe) {
                            throw new IllegalStateException("Unable to parse: " + ai, pe);
                        }

                        final PackageInfo packageInfo =
                                PackageParser.generatePackageInfo(pkg, ai, flags);
                        mAllPackagesCache.add(packageInfo);
                        if (ai.isActive) {
                                if (activePackagesSet.contains(pkg.packageName)) {
                            if (activePackagesSet.contains(packageInfo.packageName)) {
                                throw new IllegalStateException(
                                        "Two active packages have the same name: "
                                                    + pkg.packageName);
                                                + packageInfo.packageName);
                            }
                                activePackagesSet.add(pkg.packageName);
                            activePackagesSet.add(packageInfo.packageName);
                        }
                        if (ai.isFactory) {
                                if (factoryPackagesSet.contains(pkg.packageName)) {
                            if (factoryPackagesSet.contains(packageInfo.packageName)) {
                                throw new IllegalStateException(
                                        "Two factory packages have the same name: "
                                                    + pkg.packageName);
                                                + packageInfo.packageName);
                            }
                                factoryPackagesSet.add(pkg.packageName);
                            }
                        } catch (PackageParser.PackageParserException pe) {
                            throw new IllegalStateException("Unable to parse: " + ai, pe);
                            factoryPackagesSet.add(packageInfo.packageName);
                        }

                    }
                } catch (RemoteException re) {
                    Slog.e(TAG, "Unable to retrieve packages from apexservice: " + re.toString());
+13 −9
Original line number Diff line number Diff line
@@ -160,25 +160,29 @@ public class StagingManager {
        final ApexInfoList apexInfoList = mApexManager.submitStagedSession(session.sessionId,
                childSessionsIds.toArray());
        final List<PackageInfo> result = new ArrayList<>();
        for (ApexInfo newPackage : apexInfoList.apexInfos) {
            final PackageInfo pkg;
        for (ApexInfo apexInfo : apexInfoList.apexInfos) {
            final PackageInfo packageInfo;
            int flags = PackageManager.GET_META_DATA;
            PackageParser.Package pkg;
            try {
                pkg = PackageParser.generatePackageInfoFromApex(newPackage,
                        PackageManager.GET_META_DATA);
                File apexFile = new File(apexInfo.modulePath);
                PackageParser pp = new PackageParser();
                pkg = pp.parsePackage(apexFile, flags, false);
            } catch (PackageParserException e) {
                throw new PackageManagerException(SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
                        "Failed to parse APEX package " + newPackage.packagePath, e);
                        "Failed to parse APEX package " + apexInfo.modulePath, e);
            }
            final PackageInfo activePackage = mApexManager.getPackageInfo(pkg.packageName,
            packageInfo = PackageParser.generatePackageInfo(pkg, apexInfo, flags);
            final PackageInfo activePackage = mApexManager.getPackageInfo(packageInfo.packageName,
                    ApexManager.MATCH_ACTIVE_PACKAGE);
            if (activePackage == null) {
                Slog.w(TAG, "Attempting to install new APEX package " + pkg.packageName);
                Slog.w(TAG, "Attempting to install new APEX package " + packageInfo.packageName);
                throw new PackageManagerException(SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
                        "It is forbidden to install new APEX packages.");
            }
            checkRequiredVersionCode(session, activePackage);
            checkDowngrade(session, activePackage, pkg);
            result.add(pkg);
            checkDowngrade(session, activePackage, packageInfo);
            result.add(packageInfo);
        }
        return result;
    }