From c2c7a22333b828cd3a630fe9efb1b18b0e6af289 Mon Sep 17 00:00:00 2001 From: Oli Lan Date: Wed, 31 Jul 2019 15:27:22 +0100 Subject: [PATCH] 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: I495539679812110f89d5e3d93f2622ba2dab36c0 --- .../android/content/pm/PackageParser.java | 130 ++++++++---------- .../android/content/pm/PackageParserTest.java | 7 +- .../com/android/server/pm/ApexManager.java | 49 ++++--- .../com/android/server/pm/StagingManager.java | 22 +-- 4 files changed, 105 insertions(+), 103 deletions(-) diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index a4933ef1703f6..ef08bf53f5b0c 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -620,21 +620,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 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. @@ -661,8 +646,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 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 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 grantedPermissions, PackageUserState state, int userId) { if (!checkUseInstalledOrHidden(flags, state, p.applicationInfo) || !p.isMatch(flags)) { @@ -809,8 +831,27 @@ 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 ((flags & PackageManager.GET_SIGNATURES) != 0) { 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. @@ -8461,61 +8502,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; - } } diff --git a/core/tests/coretests/src/android/content/pm/PackageParserTest.java b/core/tests/coretests/src/android/content/pm/PackageParserTest.java index eb61e9cba64d0..5c7f2af782b9d 100644 --- a/core/tests/coretests/src/android/content/pm/PackageParserTest.java +++ b/core/tests/coretests/src/android/content/pm/PackageParserTest.java @@ -520,7 +520,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); diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java index dd099b15a4647..a1b6d492a4a39 100644 --- a/services/core/java/com/android/server/pm/ApexManager.java +++ b/services/core/java/com/android/server/pm/ApexManager.java @@ -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); - if (ai.isActive) { - if (activePackagesSet.contains(pkg.packageName)) { - throw new IllegalStateException( - "Two active packages have the same name: " - + pkg.packageName); - } - activePackagesSet.add(pkg.packageName); - } - if (ai.isFactory) { - if (factoryPackagesSet.contains(pkg.packageName)) { - throw new IllegalStateException( - "Two factory packages have the same name: " - + pkg.packageName); - } - factoryPackagesSet.add(pkg.packageName); - } + 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(packageInfo.packageName)) { + throw new IllegalStateException( + "Two active packages have the same name: " + + packageInfo.packageName); + } + activePackagesSet.add(packageInfo.packageName); + } + if (ai.isFactory) { + if (factoryPackagesSet.contains(packageInfo.packageName)) { + throw new IllegalStateException( + "Two factory packages have the same name: " + + packageInfo.packageName); + } + factoryPackagesSet.add(packageInfo.packageName); + } + } } catch (RemoteException re) { Slog.e(TAG, "Unable to retrieve packages from apexservice: " + re.toString()); diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java index bdeaf028bac89..6d3424cf39429 100644 --- a/services/core/java/com/android/server/pm/StagingManager.java +++ b/services/core/java/com/android/server/pm/StagingManager.java @@ -160,25 +160,29 @@ public class StagingManager { final ApexInfoList apexInfoList = mApexManager.submitStagedSession(session.sessionId, childSessionsIds.toArray()); final List 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.modulePath, 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); } Slog.d(TAG, "Session " + session.sessionId + " has following APEX packages: [" + result.stream().map(p -> p.packageName).collect(Collectors.joining(",")) + "]");