Allow framework-res APK splits from Apexes
Test: m FrameworkResApkSplitsHostTest Bug: 195732042 Change-Id: I516e6267c661e112c234aed27e2eef2ce9ffaf9a
This commit is contained in:
@@ -218,7 +218,7 @@ public class PackageParsingPerfTest {
|
||||
})
|
||||
|
||||
override fun parseImpl(file: File) =
|
||||
parser.parsePackage(input.get()!!.reset(), file, 0).result
|
||||
parser.parsePackage(input.get()!!.reset(), file, 0, null).result
|
||||
as ParsingPackageImpl
|
||||
}
|
||||
|
||||
|
||||
@@ -78,6 +78,7 @@ public class ApkLiteParseUtils {
|
||||
public static final String ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml";
|
||||
private static final int PARSE_IS_SYSTEM_DIR = 1 << 4;
|
||||
private static final int PARSE_COLLECT_CERTIFICATES = 1 << 5;
|
||||
private static final int PARSE_FRAMEWORK_RES_SPLITS = 1 << 8;
|
||||
private static final String TAG_APPLICATION = "application";
|
||||
private static final String TAG_PACKAGE_VERIFIER = "package-verifier";
|
||||
private static final String TAG_PROFILEABLE = "profileable";
|
||||
@@ -101,7 +102,7 @@ public class ApkLiteParseUtils {
|
||||
public static ParseResult<PackageLite> parsePackageLite(ParseInput input,
|
||||
File packageFile, int flags) {
|
||||
if (packageFile.isDirectory()) {
|
||||
return parseClusterPackageLite(input, packageFile, flags);
|
||||
return parseClusterPackageLite(input, packageFile, /* frameworkSplits= */ null, flags);
|
||||
} else {
|
||||
return parseMonolithicPackageLite(input, packageFile, flags);
|
||||
}
|
||||
@@ -134,21 +135,44 @@ public class ApkLiteParseUtils {
|
||||
|
||||
/**
|
||||
* Parse lightweight details about a directory of APKs.
|
||||
*
|
||||
* @param packageDirOrApk is the folder that contains split apks for a regular app or the
|
||||
* framework-res.apk for framwork-res splits (in which case the
|
||||
* splits come in the <code>frameworkSplits</code> parameter)
|
||||
*/
|
||||
public static ParseResult<PackageLite> parseClusterPackageLite(ParseInput input,
|
||||
File packageDir, int flags) {
|
||||
final File[] files = packageDir.listFiles();
|
||||
if (ArrayUtils.isEmpty(files)) {
|
||||
return input.error(PackageManager.INSTALL_PARSE_FAILED_NOT_APK,
|
||||
"No packages found in split");
|
||||
File packageDirOrApk, List<File> frameworkSplits, int flags) {
|
||||
final File[] files;
|
||||
final boolean parsingFrameworkSplits = (flags & PARSE_FRAMEWORK_RES_SPLITS) != 0;
|
||||
if (parsingFrameworkSplits) {
|
||||
if (ArrayUtils.isEmpty(frameworkSplits)) {
|
||||
return input.error(PackageManager.INSTALL_PARSE_FAILED_NOT_APK,
|
||||
"No packages found in split");
|
||||
}
|
||||
files = frameworkSplits.toArray(new File[frameworkSplits.size() + 1]);
|
||||
// we also want to process the base apk so add it to the array
|
||||
files[files.length - 1] = packageDirOrApk;
|
||||
} else {
|
||||
files = packageDirOrApk.listFiles();
|
||||
if (ArrayUtils.isEmpty(files)) {
|
||||
return input.error(PackageManager.INSTALL_PARSE_FAILED_NOT_APK,
|
||||
"No packages found in split");
|
||||
}
|
||||
// Apk directory is directly nested under the current directory
|
||||
if (files.length == 1 && files[0].isDirectory()) {
|
||||
return parseClusterPackageLite(input, files[0], frameworkSplits, flags);
|
||||
}
|
||||
}
|
||||
// Apk directory is directly nested under the current directory
|
||||
if (files.length == 1 && files[0].isDirectory()) {
|
||||
return parseClusterPackageLite(input, files[0], flags);
|
||||
|
||||
if (parsingFrameworkSplits) {
|
||||
// disable the flag for checking the certificates of the splits. We know they
|
||||
// won't match, but we rely on the mainline apex to be safe if it was installed
|
||||
flags = flags & ~PARSE_COLLECT_CERTIFICATES;
|
||||
}
|
||||
|
||||
String packageName = null;
|
||||
int versionCode = 0;
|
||||
ApkLite baseApk = null;
|
||||
|
||||
final ArrayMap<String, ApkLite> apks = new ArrayMap<>();
|
||||
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parseApkLite");
|
||||
@@ -161,6 +185,10 @@ public class ApkLiteParseUtils {
|
||||
}
|
||||
|
||||
final ApkLite lite = result.getResult();
|
||||
if (parsingFrameworkSplits && file == files[files.length - 1]) {
|
||||
baseApk = lite;
|
||||
break;
|
||||
}
|
||||
// Assert that all package names and version codes are
|
||||
// consistent with the first one we encounter.
|
||||
if (packageName == null) {
|
||||
@@ -172,7 +200,8 @@ public class ApkLiteParseUtils {
|
||||
"Inconsistent package " + lite.getPackageName() + " in " + file
|
||||
+ "; expected " + packageName);
|
||||
}
|
||||
if (versionCode != lite.getVersionCode()) {
|
||||
// we allow version codes that do not match for framework splits
|
||||
if (!parsingFrameworkSplits && versionCode != lite.getVersionCode()) {
|
||||
return input.error(PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST,
|
||||
"Inconsistent version " + lite.getVersionCode() + " in " + file
|
||||
+ "; expected " + versionCode);
|
||||
@@ -187,12 +216,15 @@ public class ApkLiteParseUtils {
|
||||
}
|
||||
}
|
||||
}
|
||||
// baseApk is set in the last iteration of the for each loop when we are parsing
|
||||
// frameworkRes splits or needs to be done now otherwise
|
||||
if (!parsingFrameworkSplits) {
|
||||
baseApk = apks.remove(null);
|
||||
}
|
||||
} finally {
|
||||
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
|
||||
}
|
||||
|
||||
final ApkLite baseApk = apks.remove(null);
|
||||
return composePackageLiteFromApks(input, packageDir, baseApk, apks);
|
||||
return composePackageLiteFromApks(input, packageDirOrApk, baseApk, apks);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -30,8 +30,10 @@ import static com.android.server.pm.PackageManagerService.SCAN_NO_DEX;
|
||||
import static com.android.server.pm.PackageManagerService.SCAN_REQUIRE_KNOWN;
|
||||
import static com.android.server.pm.PackageManagerService.SYSTEM_PARTITIONS;
|
||||
import static com.android.server.pm.PackageManagerService.TAG;
|
||||
import static com.android.server.pm.pkg.parsing.ParsingPackageUtils.PARSE_FRAMEWORK_RES_SPLITS;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.content.pm.parsing.ApkLiteParseUtils;
|
||||
import android.os.Environment;
|
||||
import android.os.SystemClock;
|
||||
import android.os.Trace;
|
||||
@@ -91,6 +93,29 @@ final class InitAndSystemPackageHelper {
|
||||
mSystemScanFlags = scanFlags | SCAN_AS_SYSTEM;
|
||||
}
|
||||
|
||||
private List<File> getFrameworkResApkSplitFiles() {
|
||||
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanFrameworkResApkSplits");
|
||||
try {
|
||||
final List<File> splits = new ArrayList<>();
|
||||
final List<ApexManager.ActiveApexInfo> activeApexInfos =
|
||||
mPm.mApexManager.getActiveApexInfos();
|
||||
for (int i = 0; i < activeApexInfos.size(); i++) {
|
||||
ApexManager.ActiveApexInfo apexInfo = activeApexInfos.get(i);
|
||||
File splitsFolder = new File(apexInfo.apexDirectory, "etc/splits");
|
||||
if (splitsFolder.isDirectory()) {
|
||||
for (File file : splitsFolder.listFiles()) {
|
||||
if (ApkLiteParseUtils.isApkFile(file)) {
|
||||
splits.add(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return splits;
|
||||
} finally {
|
||||
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
|
||||
}
|
||||
}
|
||||
|
||||
private List<ScanPartition> getSystemScanPartitions() {
|
||||
final List<ScanPartition> scanPartitions = new ArrayList<>();
|
||||
scanPartitions.addAll(mPm.mInjector.getSystemPartitions());
|
||||
@@ -184,7 +209,8 @@ final class InitAndSystemPackageHelper {
|
||||
if (!mPm.isOnlyCoreApps()) {
|
||||
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
|
||||
SystemClock.uptimeMillis());
|
||||
scanDirTracedLI(mPm.getAppInstallDir(), 0, mScanFlags | SCAN_REQUIRE_KNOWN, 0,
|
||||
scanDirTracedLI(mPm.getAppInstallDir(), /* frameworkSplits= */ null, 0,
|
||||
mScanFlags | SCAN_REQUIRE_KNOWN, 0,
|
||||
packageParser, executorService);
|
||||
|
||||
}
|
||||
@@ -247,12 +273,14 @@ final class InitAndSystemPackageHelper {
|
||||
if (partition.getOverlayFolder() == null) {
|
||||
continue;
|
||||
}
|
||||
scanDirTracedLI(partition.getOverlayFolder(), mSystemParseFlags,
|
||||
mSystemScanFlags | partition.scanFlag, 0,
|
||||
scanDirTracedLI(partition.getOverlayFolder(), /* frameworkSplits= */ null,
|
||||
mSystemParseFlags, mSystemScanFlags | partition.scanFlag, 0,
|
||||
packageParser, executorService);
|
||||
}
|
||||
|
||||
scanDirTracedLI(frameworkDir, mSystemParseFlags,
|
||||
List<File> frameworkSplits = getFrameworkResApkSplitFiles();
|
||||
scanDirTracedLI(frameworkDir, frameworkSplits,
|
||||
mSystemParseFlags | PARSE_FRAMEWORK_RES_SPLITS,
|
||||
mSystemScanFlags | SCAN_NO_DEX | SCAN_AS_PRIVILEGED, 0,
|
||||
packageParser, executorService);
|
||||
if (!mPm.mPackages.containsKey("android")) {
|
||||
@@ -263,12 +291,13 @@ final class InitAndSystemPackageHelper {
|
||||
for (int i = 0, size = mDirsToScanAsSystem.size(); i < size; i++) {
|
||||
final ScanPartition partition = mDirsToScanAsSystem.get(i);
|
||||
if (partition.getPrivAppFolder() != null) {
|
||||
scanDirTracedLI(partition.getPrivAppFolder(), mSystemParseFlags,
|
||||
scanDirTracedLI(partition.getPrivAppFolder(), /* frameworkSplits= */ null,
|
||||
mSystemParseFlags,
|
||||
mSystemScanFlags | SCAN_AS_PRIVILEGED | partition.scanFlag, 0,
|
||||
packageParser, executorService);
|
||||
}
|
||||
scanDirTracedLI(partition.getAppFolder(), mSystemParseFlags,
|
||||
mSystemScanFlags | partition.scanFlag, 0,
|
||||
scanDirTracedLI(partition.getAppFolder(), /* frameworkSplits= */ null,
|
||||
mSystemParseFlags, mSystemScanFlags | partition.scanFlag, 0,
|
||||
packageParser, executorService);
|
||||
}
|
||||
}
|
||||
@@ -285,12 +314,13 @@ final class InitAndSystemPackageHelper {
|
||||
}
|
||||
|
||||
@GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
|
||||
private void scanDirTracedLI(File scanDir, final int parseFlags, int scanFlags,
|
||||
private void scanDirTracedLI(File scanDir, List<File> frameworkSplits,
|
||||
final int parseFlags, int scanFlags,
|
||||
long currentTime, PackageParser2 packageParser, ExecutorService executorService) {
|
||||
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir [" + scanDir.getAbsolutePath() + "]");
|
||||
try {
|
||||
mInstallPackageHelper.installPackagesFromDir(scanDir, parseFlags, scanFlags,
|
||||
currentTime, packageParser, executorService);
|
||||
mInstallPackageHelper.installPackagesFromDir(scanDir, frameworkSplits, parseFlags,
|
||||
scanFlags, currentTime, packageParser, executorService);
|
||||
} finally {
|
||||
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
|
||||
}
|
||||
|
||||
@@ -3401,8 +3401,9 @@ final class InstallPackageHelper {
|
||||
}
|
||||
|
||||
@GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
|
||||
public void installPackagesFromDir(File scanDir, int parseFlags, int scanFlags,
|
||||
long currentTime, PackageParser2 packageParser, ExecutorService executorService) {
|
||||
public void installPackagesFromDir(File scanDir, List<File> frameworkSplits, int parseFlags,
|
||||
int scanFlags, long currentTime, PackageParser2 packageParser,
|
||||
ExecutorService executorService) {
|
||||
final File[] files = scanDir.listFiles();
|
||||
if (ArrayUtils.isEmpty(files)) {
|
||||
Log.d(TAG, "No files in app dir " + scanDir);
|
||||
@@ -3414,7 +3415,7 @@ final class InstallPackageHelper {
|
||||
+ " flags=0x" + Integer.toHexString(parseFlags));
|
||||
}
|
||||
ParallelPackageParser parallelPackageParser =
|
||||
new ParallelPackageParser(packageParser, executorService);
|
||||
new ParallelPackageParser(packageParser, executorService, frameworkSplits);
|
||||
|
||||
// Submit files for parsing in parallel
|
||||
int fileCount = 0;
|
||||
|
||||
@@ -27,6 +27,7 @@ import com.android.server.pm.parsing.PackageParser2;
|
||||
import com.android.server.pm.parsing.pkg.ParsedPackage;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
@@ -54,9 +55,17 @@ class ParallelPackageParser {
|
||||
|
||||
private final ExecutorService mExecutorService;
|
||||
|
||||
private final List<File> mFrameworkSplits;
|
||||
|
||||
ParallelPackageParser(PackageParser2 packageParser, ExecutorService executorService) {
|
||||
this(packageParser, executorService, /* frameworkSplits= */ null);
|
||||
}
|
||||
|
||||
ParallelPackageParser(PackageParser2 packageParser, ExecutorService executorService,
|
||||
List<File> frameworkSplits) {
|
||||
mPackageParser = packageParser;
|
||||
mExecutorService = executorService;
|
||||
mFrameworkSplits = frameworkSplits;
|
||||
}
|
||||
|
||||
static class ParseResult {
|
||||
@@ -125,6 +134,6 @@ class ParallelPackageParser {
|
||||
@VisibleForTesting
|
||||
protected ParsedPackage parsePackage(File scanFile, int parseFlags)
|
||||
throws PackageManagerException {
|
||||
return mPackageParser.parsePackage(scanFile, parseFlags, true);
|
||||
return mPackageParser.parsePackage(scanFile, parseFlags, true, mFrameworkSplits);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,9 +22,6 @@ import android.annotation.Nullable;
|
||||
import android.app.ActivityThread;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import com.android.server.pm.pkg.parsing.ParsingPackage;
|
||||
import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
|
||||
import com.android.server.pm.pkg.parsing.ParsingUtils;
|
||||
import android.content.pm.parsing.result.ParseInput;
|
||||
import android.content.pm.parsing.result.ParseResult;
|
||||
import android.content.pm.parsing.result.ParseTypeImpl;
|
||||
@@ -41,6 +38,9 @@ import com.android.server.pm.PackageManagerException;
|
||||
import com.android.server.pm.PackageManagerService;
|
||||
import com.android.server.pm.parsing.pkg.PackageImpl;
|
||||
import com.android.server.pm.parsing.pkg.ParsedPackage;
|
||||
import com.android.server.pm.pkg.parsing.ParsingPackage;
|
||||
import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
|
||||
import com.android.server.pm.pkg.parsing.ParsingUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
@@ -147,6 +147,15 @@ public class PackageParser2 implements AutoCloseable {
|
||||
@AnyThread
|
||||
public ParsedPackage parsePackage(File packageFile, int flags, boolean useCaches)
|
||||
throws PackageManagerException {
|
||||
return parsePackage(packageFile, flags, useCaches, /* frameworkSplits= */ null);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO(b/135203078): Document new package parsing
|
||||
*/
|
||||
@AnyThread
|
||||
public ParsedPackage parsePackage(File packageFile, int flags, boolean useCaches,
|
||||
List<File> frameworkSplits) throws PackageManagerException {
|
||||
if (useCaches && mCacher != null) {
|
||||
ParsedPackage parsed = mCacher.getCachedResult(packageFile, flags);
|
||||
if (parsed != null) {
|
||||
@@ -156,7 +165,8 @@ public class PackageParser2 implements AutoCloseable {
|
||||
|
||||
long parseTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0;
|
||||
ParseInput input = mSharedResult.get().reset();
|
||||
ParseResult<ParsingPackage> result = parsingUtils.parsePackage(input, packageFile, flags);
|
||||
ParseResult<ParsingPackage> result = parsingUtils.parsePackage(input, packageFile, flags,
|
||||
frameworkSplits);
|
||||
if (result.isError()) {
|
||||
throw new PackageManagerException(result.getErrorCode(), result.getErrorMessage(),
|
||||
result.getException());
|
||||
|
||||
@@ -65,6 +65,7 @@ import android.content.res.XmlResourceParser;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.os.Parcel;
|
||||
import android.os.RemoteException;
|
||||
import android.os.SystemProperties;
|
||||
@@ -230,6 +231,8 @@ public class ParsingPackageUtils {
|
||||
* of required system property within the overlay tag.
|
||||
*/
|
||||
public static final int PARSE_IGNORE_OVERLAY_REQUIRED_SYSTEM_PROPERTY = 1 << 7;
|
||||
public static final int PARSE_FRAMEWORK_RES_SPLITS = 1 << 8;
|
||||
|
||||
public static final int PARSE_CHATTY = 1 << 31;
|
||||
|
||||
@IntDef(flag = true, prefix = { "PARSE_" }, value = {
|
||||
@@ -241,6 +244,7 @@ public class ParsingPackageUtils {
|
||||
PARSE_IS_SYSTEM_DIR,
|
||||
PARSE_MUST_BE_APK,
|
||||
PARSE_IGNORE_OVERLAY_REQUIRED_SYSTEM_PROPERTY,
|
||||
PARSE_FRAMEWORK_RES_SPLITS
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface ParseFlags {}
|
||||
@@ -289,7 +293,7 @@ public class ParsingPackageUtils {
|
||||
return new ParsingPackageImpl(packageName, baseApkPath, path, manifestArray);
|
||||
}
|
||||
});
|
||||
result = parser.parsePackage(input, file, parseFlags);
|
||||
result = parser.parsePackage(input, file, parseFlags, /* frameworkSplits= */ null);
|
||||
if (result.isError()) {
|
||||
return input.error(result);
|
||||
}
|
||||
@@ -343,26 +347,44 @@ public class ParsingPackageUtils {
|
||||
* not check whether {@code packageFile} has changed since the last parse, it's up to callers to
|
||||
* do so.
|
||||
*/
|
||||
public ParseResult<ParsingPackage> parsePackage(ParseInput input, File packageFile, int flags) {
|
||||
if (packageFile.isDirectory()) {
|
||||
return parseClusterPackage(input, packageFile, flags);
|
||||
public ParseResult<ParsingPackage> parsePackage(ParseInput input, File packageFile, int flags,
|
||||
List<File> frameworkSplits) {
|
||||
if (((flags & PARSE_FRAMEWORK_RES_SPLITS) != 0)
|
||||
&& frameworkSplits.size() > 0
|
||||
&& packageFile.getAbsolutePath().endsWith("/framework-res.apk")) {
|
||||
return parseClusterPackage(input, packageFile, frameworkSplits, flags);
|
||||
} else if (packageFile.isDirectory()) {
|
||||
return parseClusterPackage(input, packageFile, /* frameworkSplits= */null, flags);
|
||||
} else {
|
||||
return parseMonolithicPackage(input, packageFile, flags);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse all APKs contained in the given directory, treating them as a single package. This also
|
||||
* performs validity checking, such as requiring identical package name and version codes, a
|
||||
* single base APK, and unique split names.
|
||||
* Parse all APKs contained in the given directory, treating them as a
|
||||
* single package. This also performs validity checking, such as requiring
|
||||
* identical package name and version codes, a single base APK, and unique
|
||||
* split names.
|
||||
* <p>
|
||||
* Can also be passed the framework-res.apk file and a list of split apks coming from apexes
|
||||
* (via {@code frameworkSplits}) in which case they will be parsed similar to cluster packages
|
||||
* even if they are in different folders. Note that this code path may have other behaviour
|
||||
* differences.
|
||||
* <p>
|
||||
* Note that this <em>does not</em> perform signature verification; that must be done separately
|
||||
* in {@link #getSigningDetails(ParseInput, ParsingPackageRead, boolean)}.
|
||||
*/
|
||||
private ParseResult<ParsingPackage> parseClusterPackage(ParseInput input, File packageDir,
|
||||
int flags) {
|
||||
List<File> frameworkSplits, int flags) {
|
||||
// parseClusterPackageLite should receive no flags (0) for regular splits but we want to
|
||||
// pass the flags for framework splits
|
||||
int liteParseFlags = 0;
|
||||
if ((flags & PARSE_FRAMEWORK_RES_SPLITS) != 0) {
|
||||
liteParseFlags = flags;
|
||||
}
|
||||
final ParseResult<PackageLite> liteResult =
|
||||
ApkLiteParseUtils.parseClusterPackageLite(input, packageDir, 0);
|
||||
ApkLiteParseUtils.parseClusterPackageLite(input, packageDir, frameworkSplits,
|
||||
liteParseFlags);
|
||||
if (liteResult.isError()) {
|
||||
return input.error(liteResult);
|
||||
}
|
||||
@@ -2989,9 +3011,12 @@ public class ParsingPackageUtils {
|
||||
}
|
||||
|
||||
signingDetails = result.getResult();
|
||||
|
||||
final File frameworkRes = new File(Environment.getRootDirectory(),
|
||||
"framework/framework-res.apk");
|
||||
boolean isFrameworkResSplit = frameworkRes.getAbsolutePath()
|
||||
.equals(pkg.getBaseApkPath());
|
||||
String[] splitCodePaths = pkg.getSplitCodePaths();
|
||||
if (!ArrayUtils.isEmpty(splitCodePaths)) {
|
||||
if (!ArrayUtils.isEmpty(splitCodePaths) && !isFrameworkResSplit) {
|
||||
for (int i = 0; i < splitCodePaths.length; i++) {
|
||||
result = getSigningDetails(
|
||||
input,
|
||||
|
||||
@@ -519,6 +519,8 @@ class MockSystem(withSession: (StaticMockitoSessionBuilder) -> Unit = {}) {
|
||||
val parsedPackage = parseResult.hideAsParsed() as ParsedPackage
|
||||
whenever(mocks.packageParser.parsePackage(
|
||||
or(eq(path), eq(basePath)), anyInt(), anyBoolean())) { parsedPackage }
|
||||
whenever(mocks.packageParser.parsePackage(
|
||||
or(eq(path), eq(basePath)), anyInt(), anyBoolean(), any())) { parsedPackage }
|
||||
return parsedPackage
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.JUnit4
|
||||
import org.mockito.ArgumentMatchers.any
|
||||
import org.mockito.ArgumentMatchers.anyBoolean
|
||||
import org.mockito.ArgumentMatchers.anyInt
|
||||
import org.mockito.ArgumentMatchers.argThat
|
||||
@@ -121,7 +122,8 @@ class PackageManagerServiceBootTest {
|
||||
whenever(rule.mocks().packageParser.parsePackage(
|
||||
argThat { path: File -> path.path.contains("a.data.package") },
|
||||
anyInt(),
|
||||
anyBoolean()))
|
||||
anyBoolean(),
|
||||
any()))
|
||||
.thenThrow(PackageManagerException(
|
||||
PackageManager.INSTALL_FAILED_INVALID_APK, "Oh no!"))
|
||||
val pm = createPackageManagerService()
|
||||
|
||||
Reference in New Issue
Block a user