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
This commit is contained in:
Rhed Jao
2020-03-30 13:23:14 +08:00
parent bde104f8be
commit 269616bed2
6 changed files with 52 additions and 16 deletions

View File

@@ -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,

View File

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

View File

@@ -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 "

View File

@@ -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<PackageParser2> 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() {

View File

@@ -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<PackageParser2> apexParserSupplier = () -> new PackageParser2(
mSeparateProcesses, mOnlyCore, mMetrics, mCacheDir, mPackageParserCallback);
mInstallerService = new PackageInstallerService(mContext, this, apexParserSupplier);
final Pair<ComponentName, String> instantAppResolverComponent =
getInstantAppResolverLPr();
if (instantAppResolverComponent != null) {

View File

@@ -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<PackageParser2> mPackageParserSupplier;
@GuardedBy("mStagedSessions")
private final SparseArray<PackageInstallerSession> mStagedSessions = new SparseArray<>();
@@ -105,9 +109,11 @@ public class StagingManager {
private final List<String> mFailedPackageNames = new ArrayList<>();
private String mNativeFailureReason;
StagingManager(PackageInstallerService pi, Context context) {
StagingManager(PackageInstallerService pi, Context context,
Supplier<PackageParser2> 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<String> 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) {