From 269616bed2cc6bf91696c10c535cbeae7fb2c969 Mon Sep 17 00:00:00 2001 From: Rhed Jao Date: Mon, 30 Mar 2020 13:23:14 +0800 Subject: [PATCH] Fix an exception while scanning apex packages Package parser throws an exception while it's in the onlyCoreApp state and parsing an non-core app. Catching the parser exception during scanning apex packages, if the apex is without coreApp attribute and device is in minimal boot state. Also, updates package parser to V2 for the staging manager. Bug: 151296698 Test: atest ApexManagerTest Test: atest StagedInstallTest Change-Id: I098e08d4064812465a29086c3fde1a55348bcae5 --- .../android/content/pm/PackageManager.java | 8 ++++++ .../pm/parsing/ParsingPackageUtils.java | 7 +++-- .../com/android/server/pm/ApexManager.java | 13 +++++++--- .../server/pm/PackageInstallerService.java | 7 +++-- .../server/pm/PackageManagerService.java | 7 ++++- .../com/android/server/pm/StagingManager.java | 26 +++++++++++++------ 6 files changed, 52 insertions(+), 16 deletions(-) diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index f48d78ac9cc3e..9a2e07e9cfbd9 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -1542,6 +1542,14 @@ public abstract class PackageManager { */ public static final int INSTALL_FAILED_PROCESS_NOT_DEFINED = -122; + /** + * Installation parse return code: system is in a minimal boot state, and the parser only + * allows the package with {@code coreApp} manifest attribute to be a valid application. + * + * @hide + */ + public static final int INSTALL_PARSE_FAILED_ONLY_COREAPP_ALLOWED = -123; + /** @hide */ @IntDef(flag = true, prefix = { "DELETE_" }, value = { DELETE_KEEP_DATA, diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java index 12328cf32fb34..c94d428f44750 100644 --- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java +++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java @@ -22,6 +22,7 @@ import static android.content.pm.PackageManager.FEATURE_WATCH; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK; +import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_ONLY_COREAPP_ALLOWED; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION; import static android.os.Build.VERSION_CODES.DONUT; import static android.os.Build.VERSION_CODES.O; @@ -229,7 +230,8 @@ public class ParsingPackageUtils { final PackageParser.PackageLite lite = ApkLiteParseUtils.parseClusterPackageLite(packageDir, 0); if (mOnlyCoreApps && !lite.coreApp) { - return input.error("Not a coreApp: " + packageDir); + return input.error(INSTALL_PARSE_FAILED_ONLY_COREAPP_ALLOWED, + "Not a coreApp: " + packageDir); } // Build the split dependency tree. @@ -291,7 +293,8 @@ public class ParsingPackageUtils { final PackageParser.PackageLite lite = ApkLiteParseUtils.parseMonolithicPackageLite(apkFile, flags); if (mOnlyCoreApps && !lite.coreApp) { - return input.error("Not a coreApp: " + apkFile); + return input.error(INSTALL_PARSE_FAILED_ONLY_COREAPP_ALLOWED, + "Not a coreApp: " + apkFile); } final SplitAssetLoader assetLoader = new DefaultSplitAssetLoader(lite, flags); diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java index b9d656181b55c..46dd8feccbf10 100644 --- a/services/core/java/com/android/server/pm/ApexManager.java +++ b/services/core/java/com/android/server/pm/ApexManager.java @@ -30,7 +30,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageInstaller; import android.content.pm.PackageManager; -import android.content.pm.PackageParser; +import android.content.pm.PackageParser.PackageParserException; import android.content.pm.parsing.PackageInfoWithoutStateUtils; import android.os.Binder; import android.os.Environment; @@ -137,7 +137,8 @@ public abstract class ApexManager { /** * Called by package manager service to scan apex package files when device boots up. * - * @param packageParser The package parser which supports caches. + * @param packageParser The package parser to support apex package parsing and caching parsed + * results. * @param executorService An executor to support parallel package parsing. */ abstract void scanApexPackagesTraced(@NonNull PackageParser2 packageParser, @@ -505,7 +506,13 @@ public abstract class ApexManager { } factoryPackagesSet.add(packageInfo.packageName); } - } else if (throwable instanceof PackageParser.PackageParserException) { + } else if (throwable instanceof PackageParserException) { + final PackageParserException e = (PackageParserException) throwable; + // Skip parsing non-coreApp apex file if system is in minimal boot state. + if (e.error == PackageManager.INSTALL_PARSE_FAILED_ONLY_COREAPP_ALLOWED) { + Slog.w(TAG, "Scan apex failed, not a coreApp:" + ai.modulePath); + continue; + } throw new IllegalStateException("Unable to parse: " + ai.modulePath, throwable); } else { throw new IllegalStateException("Unexpected exception occurred while parsing " diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index 8ff7ea9d61dd2..57908f3a4dacd 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -82,6 +82,7 @@ import com.android.internal.util.ImageUtils; import com.android.internal.util.IndentingPrintWriter; import com.android.server.IoThread; import com.android.server.LocalServices; +import com.android.server.pm.parsing.PackageParser2; import com.android.server.pm.permission.PermissionManagerServiceInternal; import libcore.io.IoUtils; @@ -105,6 +106,7 @@ import java.util.List; import java.util.Objects; import java.util.Random; import java.util.function.IntPredicate; +import java.util.function.Supplier; /** The service responsible for installing packages. */ public class PackageInstallerService extends IPackageInstaller.Stub implements @@ -194,7 +196,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements } }; - public PackageInstallerService(Context context, PackageManagerService pm) { + public PackageInstallerService(Context context, PackageManagerService pm, + Supplier apexParserSupplier) { mContext = context; mPm = pm; mPermissionManager = LocalServices.getService(PermissionManagerServiceInternal.class); @@ -213,7 +216,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements mSessionsDir.mkdirs(); mApexManager = ApexManager.getInstance(); - mStagingManager = new StagingManager(this, context); + mStagingManager = new StagingManager(this, context, apexParserSupplier); } boolean okToSendBroadcasts() { diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 8850f29e9bc26..984d41440315c 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -417,6 +417,7 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Predicate; +import java.util.function.Supplier; /** * Keep track of all those APKs everywhere. @@ -3436,7 +3437,11 @@ public class PackageManagerService extends IPackageManager.Stub } } - mInstallerService = new PackageInstallerService(mContext, this); + // Prepare a supplier of package parser for the staging manager to parse apex file + // during the staging installation. + final Supplier apexParserSupplier = () -> new PackageParser2( + mSeparateProcesses, mOnlyCore, mMetrics, mCacheDir, mPackageParserCallback); + mInstallerService = new PackageInstallerService(mContext, this, apexParserSupplier); final Pair instantAppResolverComponent = getInstantAppResolverLPr(); if (instantAppResolverComponent != null) { diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java index 60292b45c0eeb..58be06098b08c 100644 --- a/services/core/java/com/android/server/pm/StagingManager.java +++ b/services/core/java/com/android/server/pm/StagingManager.java @@ -35,11 +35,11 @@ import android.content.pm.PackageInstaller; import android.content.pm.PackageInstaller.SessionInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; -import android.content.pm.PackageParser; import android.content.pm.PackageParser.PackageParserException; import android.content.pm.PackageParser.SigningDetails; import android.content.pm.PackageParser.SigningDetails.SignatureSchemeVersion; import android.content.pm.ParceledListSlice; +import android.content.pm.parsing.PackageInfoWithoutStateUtils; import android.content.rollback.IRollbackManager; import android.content.rollback.RollbackInfo; import android.content.rollback.RollbackManager; @@ -68,8 +68,10 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.content.PackageHelper; import com.android.internal.os.BackgroundThread; import com.android.server.LocalServices; +import com.android.server.pm.parsing.PackageParser2; import com.android.server.pm.parsing.pkg.AndroidPackage; import com.android.server.pm.parsing.pkg.AndroidPackageUtils; +import com.android.server.pm.parsing.pkg.ParsedPackage; import com.android.server.rollback.WatchdogRollbackLogger; import java.io.File; @@ -80,6 +82,7 @@ import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; import java.util.function.Predicate; +import java.util.function.Supplier; /** * This class handles staged install sessions, i.e. install sessions that require packages to @@ -94,6 +97,7 @@ public class StagingManager { private final PowerManager mPowerManager; private final Context mContext; private final PreRebootVerificationHandler mPreRebootVerificationHandler; + private final Supplier mPackageParserSupplier; @GuardedBy("mStagedSessions") private final SparseArray mStagedSessions = new SparseArray<>(); @@ -105,9 +109,11 @@ public class StagingManager { private final List mFailedPackageNames = new ArrayList<>(); private String mNativeFailureReason; - StagingManager(PackageInstallerService pi, Context context) { + StagingManager(PackageInstallerService pi, Context context, + Supplier packageParserSupplier) { mPi = pi; mContext = context; + mPackageParserSupplier = packageParserSupplier; mApexManager = ApexManager.getInstance(); mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); @@ -223,17 +229,21 @@ public class StagingManager { final List apexPackageNames = new ArrayList<>(); for (ApexInfo apexInfo : apexInfoList.apexInfos) { final PackageInfo packageInfo; - int flags = PackageManager.GET_META_DATA; - PackageParser.Package pkg; - try { + final int flags = PackageManager.GET_META_DATA; + try (PackageParser2 packageParser = mPackageParserSupplier.get()) { File apexFile = new File(apexInfo.modulePath); - PackageParser pp = new PackageParser(); - pkg = pp.parsePackage(apexFile, flags, false); + final ParsedPackage parsedPackage = packageParser.parsePackage( + apexFile, flags, false); + packageInfo = PackageInfoWithoutStateUtils.generate(parsedPackage, apexInfo, flags); + if (packageInfo == null) { + throw new PackageManagerException( + SessionInfo.STAGED_SESSION_VERIFICATION_FAILED, + "Unable to generate package info: " + apexInfo.modulePath); + } } catch (PackageParserException e) { throw new PackageManagerException(SessionInfo.STAGED_SESSION_VERIFICATION_FAILED, "Failed to parse APEX package " + apexInfo.modulePath, e); } - packageInfo = PackageParser.generatePackageInfo(pkg, apexInfo, flags); final PackageInfo activePackage = mApexManager.getPackageInfo(packageInfo.packageName, ApexManager.MATCH_ACTIVE_PACKAGE); if (activePackage == null) {