Remove support for PackageDexUsage version 1
PackageVersion version 1 was indroduce in Nougat. Since then, all devices should have updated to version 2 which was introduced in O. This simplifies the logic in preparation for adding support for system server jars. Test: atest DexManagerTests PackageDexUsageTests Bug: 148774920 Change-Id: Ib546ed12c5341d01fb12545cd98598b4cf2c5051
This commit is contained in:
@@ -401,7 +401,8 @@ public class PackageDexOptimizer {
|
||||
return DEX_OPT_FAILED;
|
||||
}
|
||||
String classLoaderContext = null;
|
||||
if (dexUseInfo.isUnknownClassLoaderContext() || dexUseInfo.isVariableClassLoaderContext()) {
|
||||
if (dexUseInfo.isUnsupportedClassLoaderContext()
|
||||
|| dexUseInfo.isVariableClassLoaderContext()) {
|
||||
// If we have an unknown (not yet set), or a variable class loader chain. Just extract
|
||||
// the dex file.
|
||||
compilerFilter = "extract";
|
||||
|
||||
@@ -563,7 +563,7 @@ public class DexManager {
|
||||
boolean newUpdate = mPackageDexUsage.record(searchResult.mOwningPackageName,
|
||||
dexPath, userId, isa, isUsedByOtherApps, /*primaryOrSplit*/ false,
|
||||
searchResult.mOwningPackageName,
|
||||
PackageDexUsage.UNKNOWN_CLASS_LOADER_CONTEXT);
|
||||
PackageDexUsage.VARIABLE_CLASS_LOADER_CONTEXT);
|
||||
update |= newUpdate;
|
||||
}
|
||||
if (update) {
|
||||
|
||||
@@ -51,25 +51,21 @@ import java.util.Set;
|
||||
* Stat file which store usage information about dex files.
|
||||
*/
|
||||
public class PackageDexUsage extends AbstractStatsBase<Void> {
|
||||
private final static String TAG = "PackageDexUsage";
|
||||
private static final String TAG = "PackageDexUsage";
|
||||
|
||||
// We support previous version to ensure that the usage list remains valid cross OTAs.
|
||||
private final static int PACKAGE_DEX_USAGE_SUPPORTED_VERSION_1 = 1;
|
||||
// Version 2 added:
|
||||
// - the list of packages that load the dex files
|
||||
// - class loader contexts for secondary dex files
|
||||
// - usage for all code paths (including splits)
|
||||
private final static int PACKAGE_DEX_USAGE_SUPPORTED_VERSION_2 = 2;
|
||||
// We are currently at version 2.
|
||||
// Version 1 was introduced in Nougat and Version 2 in Oreo.
|
||||
// We dropped version 1 support in R since all devices should have updated
|
||||
// already.
|
||||
private static final int PACKAGE_DEX_USAGE_VERSION = 2;
|
||||
|
||||
private final static int PACKAGE_DEX_USAGE_VERSION = PACKAGE_DEX_USAGE_SUPPORTED_VERSION_2;
|
||||
|
||||
private final static String PACKAGE_DEX_USAGE_VERSION_HEADER =
|
||||
private static final String PACKAGE_DEX_USAGE_VERSION_HEADER =
|
||||
"PACKAGE_MANAGER__PACKAGE_DEX_USAGE__";
|
||||
|
||||
private final static String SPLIT_CHAR = ",";
|
||||
private final static String CODE_PATH_LINE_CHAR = "+";
|
||||
private final static String DEX_LINE_CHAR = "#";
|
||||
private final static String LOADING_PACKAGE_CHAR = "@";
|
||||
private static final String SPLIT_CHAR = ",";
|
||||
private static final String CODE_PATH_LINE_CHAR = "+";
|
||||
private static final String DEX_LINE_CHAR = "#";
|
||||
private static final String LOADING_PACKAGE_CHAR = "@";
|
||||
|
||||
// One of the things we record about dex files is the class loader context that was used to
|
||||
// load them. That should be stable but if it changes we don't keep track of variable contexts.
|
||||
@@ -77,10 +73,6 @@ public class PackageDexUsage extends AbstractStatsBase<Void> {
|
||||
// skip optimizations on that dex files.
|
||||
/*package*/ static final String VARIABLE_CLASS_LOADER_CONTEXT =
|
||||
"=VariableClassLoaderContext=";
|
||||
// The markers used for unknown class loader contexts. This can happen if the dex file was
|
||||
// recorded in a previous version and we didn't have a chance to update its usage.
|
||||
/*package*/ static final String UNKNOWN_CLASS_LOADER_CONTEXT =
|
||||
"=UnknownClassLoaderContext=";
|
||||
|
||||
// The marker used for unsupported class loader contexts (no longer written, may occur in old
|
||||
// files so discarded on read). Note: this matches
|
||||
@@ -339,7 +331,9 @@ public class PackageDexUsage extends AbstractStatsBase<Void> {
|
||||
version = Integer.parseInt(
|
||||
versionLine.substring(PACKAGE_DEX_USAGE_VERSION_HEADER.length()));
|
||||
if (!isSupportedVersion(version)) {
|
||||
throw new IllegalStateException("Unexpected version: " + version);
|
||||
Slog.w(TAG, "Unexpected package-dex-use version: " + version
|
||||
+ ". Not reading from it");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -377,9 +371,8 @@ public class PackageDexUsage extends AbstractStatsBase<Void> {
|
||||
throw new IllegalStateException("Invalid PackageDexUsage line: " + line);
|
||||
}
|
||||
|
||||
// In version 2 we added the loading packages and class loader context.
|
||||
Set<String> loadingPackages = maybeReadLoadingPackages(in, version);
|
||||
String classLoaderContext = maybeReadClassLoaderContext(in, version);
|
||||
Set<String> loadingPackages = readLoadingPackages(in, version);
|
||||
String classLoaderContext = readClassLoaderContext(in, version);
|
||||
|
||||
if (UNSUPPORTED_CLASS_LOADER_CONTEXT.equals(classLoaderContext)) {
|
||||
// We used to record use of unsupported class loaders, but we no longer do.
|
||||
@@ -410,34 +403,16 @@ public class PackageDexUsage extends AbstractStatsBase<Void> {
|
||||
}
|
||||
currentPackageData.mDexUseInfoMap.put(dexPath, dexUseInfo);
|
||||
} else if (line.startsWith(CODE_PATH_LINE_CHAR)) {
|
||||
// This is a code path used by other apps line.
|
||||
if (version < PACKAGE_DEX_USAGE_SUPPORTED_VERSION_2) {
|
||||
throw new IllegalArgumentException("Unexpected code path line when parsing " +
|
||||
"PackageDexUseData: " + line);
|
||||
}
|
||||
|
||||
// Expects 2 lines:
|
||||
// +code_paths
|
||||
// @loading_packages
|
||||
String codePath = line.substring(CODE_PATH_LINE_CHAR.length());
|
||||
Set<String> loadingPackages = maybeReadLoadingPackages(in, version);
|
||||
Set<String> loadingPackages = readLoadingPackages(in, version);
|
||||
currentPackageData.mCodePathsUsedByOtherApps.put(codePath, loadingPackages);
|
||||
} else {
|
||||
// This is a package line.
|
||||
if (version >= PACKAGE_DEX_USAGE_SUPPORTED_VERSION_2) {
|
||||
currentPackage = line;
|
||||
currentPackageData = new PackageUseInfo();
|
||||
} else {
|
||||
// Old version (<2)
|
||||
// We expect it to be: `packageName,isUsedByOtherApps`.
|
||||
String[] elems = line.split(SPLIT_CHAR);
|
||||
if (elems.length != 2) {
|
||||
throw new IllegalStateException("Invalid PackageDexUsage line: " + line);
|
||||
}
|
||||
currentPackage = elems[0];
|
||||
currentPackageData = new PackageUseInfo();
|
||||
currentPackageData.mUsedByOtherAppsBeforeUpgrade = readBoolean(elems[1]);
|
||||
}
|
||||
currentPackage = line;
|
||||
currentPackageData = new PackageUseInfo();
|
||||
data.put(currentPackage, currentPackageData);
|
||||
}
|
||||
}
|
||||
@@ -449,45 +424,33 @@ public class PackageDexUsage extends AbstractStatsBase<Void> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the class loader context encoding from the buffer {@code in} if
|
||||
* {@code version} is at least {PACKAGE_DEX_USAGE_VERSION}.
|
||||
* Reads the class loader context encoding from the buffer {@code in}.
|
||||
*/
|
||||
private String maybeReadClassLoaderContext(BufferedReader in, int version) throws IOException {
|
||||
String context = null;
|
||||
if (version >= PACKAGE_DEX_USAGE_SUPPORTED_VERSION_2) {
|
||||
context = in.readLine();
|
||||
if (context == null) {
|
||||
throw new IllegalStateException("Could not find the classLoaderContext line.");
|
||||
}
|
||||
private String readClassLoaderContext(BufferedReader in, int version) throws IOException {
|
||||
String context = in.readLine();
|
||||
if (context == null) {
|
||||
throw new IllegalStateException("Could not find the classLoaderContext line.");
|
||||
}
|
||||
// The context might be empty if we didn't have the chance to update it after a version
|
||||
// upgrade. In this case return the special marker so that we recognize this is an unknown
|
||||
// context.
|
||||
return context == null ? UNKNOWN_CLASS_LOADER_CONTEXT : context;
|
||||
return context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the list of loading packages from the buffer {@code in} if
|
||||
* {@code version} is at least {PACKAGE_DEX_USAGE_SUPPORTED_VERSION_2}.
|
||||
* Reads the list of loading packages from the buffer {@code in}.
|
||||
*/
|
||||
private Set<String> maybeReadLoadingPackages(BufferedReader in, int version)
|
||||
private Set<String> readLoadingPackages(BufferedReader in, int version)
|
||||
throws IOException {
|
||||
if (version >= PACKAGE_DEX_USAGE_SUPPORTED_VERSION_2) {
|
||||
String line = in.readLine();
|
||||
if (line == null) {
|
||||
throw new IllegalStateException("Could not find the loadingPackages line.");
|
||||
}
|
||||
// We expect that most of the times the list of loading packages will be empty.
|
||||
if (line.length() == LOADING_PACKAGE_CHAR.length()) {
|
||||
return Collections.emptySet();
|
||||
} else {
|
||||
Set<String> result = new HashSet<>();
|
||||
Collections.addAll(result,
|
||||
line.substring(LOADING_PACKAGE_CHAR.length()).split(SPLIT_CHAR));
|
||||
return result;
|
||||
}
|
||||
} else {
|
||||
String line = in.readLine();
|
||||
if (line == null) {
|
||||
throw new IllegalStateException("Could not find the loadingPackages line.");
|
||||
}
|
||||
// We expect that most of the times the list of loading packages will be empty.
|
||||
if (line.length() == LOADING_PACKAGE_CHAR.length()) {
|
||||
return Collections.emptySet();
|
||||
} else {
|
||||
Set<String> result = new HashSet<>();
|
||||
Collections.addAll(result,
|
||||
line.substring(LOADING_PACKAGE_CHAR.length()).split(SPLIT_CHAR));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -501,8 +464,7 @@ public class PackageDexUsage extends AbstractStatsBase<Void> {
|
||||
}
|
||||
|
||||
private boolean isSupportedVersion(int version) {
|
||||
return version == PACKAGE_DEX_USAGE_SUPPORTED_VERSION_1
|
||||
|| version == PACKAGE_DEX_USAGE_SUPPORTED_VERSION_2;
|
||||
return version == PACKAGE_DEX_USAGE_VERSION;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -544,14 +506,7 @@ public class PackageDexUsage extends AbstractStatsBase<Void> {
|
||||
}
|
||||
}
|
||||
|
||||
// In case the package was marked as used by other apps in a previous version
|
||||
// propagate the flag to all the code paths.
|
||||
// See mUsedByOtherAppsBeforeUpgrade docs on why it is important to do it.
|
||||
if (packageUseInfo.mUsedByOtherAppsBeforeUpgrade) {
|
||||
for (String codePath : codePaths) {
|
||||
packageUseInfo.mergeCodePathUsedByOtherApps(codePath, true, null, null);
|
||||
}
|
||||
} else if (!packageUseInfo.isAnyCodePathUsedByOtherApps()
|
||||
if (!packageUseInfo.isAnyCodePathUsedByOtherApps()
|
||||
&& packageUseInfo.mDexUseInfoMap.isEmpty()) {
|
||||
// The package is not used by other apps and we removed all its dex files
|
||||
// records. Remove the entire package record as well.
|
||||
@@ -718,19 +673,6 @@ public class PackageDexUsage extends AbstractStatsBase<Void> {
|
||||
// Map dex paths to their data (isUsedByOtherApps, owner id, loader isa).
|
||||
private final Map<String, DexUseInfo> mDexUseInfoMap;
|
||||
|
||||
// Keeps track of whether or not this package was used by other apps before
|
||||
// we upgraded to VERSION 4 which records the info for each code path separately.
|
||||
// This is unwanted complexity but without it we risk to profile guide compile
|
||||
// something that supposed to be shared. For example:
|
||||
// 1) we determine that chrome is used by another app
|
||||
// 2) we take an OTA which upgrades the way we keep track of usage data
|
||||
// 3) chrome doesn't get used until the background job executes
|
||||
// 4) as part of the backgound job we now think that chrome is not used by others
|
||||
// and we speed-profile.
|
||||
// 5) as a result the next time someone uses chrome it will extract from apk since
|
||||
// the compiled code will be private.
|
||||
private boolean mUsedByOtherAppsBeforeUpgrade;
|
||||
|
||||
/*package*/ PackageUseInfo() {
|
||||
mCodePathsUsedByOtherApps = new HashMap<>();
|
||||
mDexUseInfoMap = new HashMap<>();
|
||||
@@ -790,10 +732,6 @@ public class PackageDexUsage extends AbstractStatsBase<Void> {
|
||||
* Returns whether or not there was an update.
|
||||
*/
|
||||
/*package*/ boolean clearCodePathUsedByOtherApps() {
|
||||
// Update mUsedByOtherAppsBeforeUpgrade as well to be consistent with
|
||||
// the new data. This is not saved to disk so we don't need to return it.
|
||||
mUsedByOtherAppsBeforeUpgrade = true;
|
||||
|
||||
if (mCodePathsUsedByOtherApps.isEmpty()) {
|
||||
return false;
|
||||
} else {
|
||||
@@ -847,11 +785,9 @@ public class PackageDexUsage extends AbstractStatsBase<Void> {
|
||||
boolean updateLoadingPackages = mLoadingPackages.addAll(dexUseInfo.mLoadingPackages);
|
||||
|
||||
String oldClassLoaderContext = mClassLoaderContext;
|
||||
if (isUnknownOrUnsupportedContext(mClassLoaderContext)) {
|
||||
// Can happen if we read a previous version.
|
||||
if (isUnsupportedContext(mClassLoaderContext)) {
|
||||
mClassLoaderContext = dexUseInfo.mClassLoaderContext;
|
||||
} else if (!isUnknownOrUnsupportedContext(dexUseInfo.mClassLoaderContext)
|
||||
&& !Objects.equals(mClassLoaderContext, dexUseInfo.mClassLoaderContext)) {
|
||||
} else if (!Objects.equals(mClassLoaderContext, dexUseInfo.mClassLoaderContext)) {
|
||||
// We detected a context change.
|
||||
mClassLoaderContext = VARIABLE_CLASS_LOADER_CONTEXT;
|
||||
}
|
||||
@@ -862,11 +798,8 @@ public class PackageDexUsage extends AbstractStatsBase<Void> {
|
||||
|| !Objects.equals(oldClassLoaderContext, mClassLoaderContext);
|
||||
}
|
||||
|
||||
private static boolean isUnknownOrUnsupportedContext(String context) {
|
||||
// TODO: Merge UNKNOWN_CLASS_LOADER_CONTEXT & UNSUPPORTED_CLASS_LOADER_CONTEXT cases
|
||||
// into UNSUPPORTED_CLASS_LOADER_CONTEXT.
|
||||
return UNKNOWN_CLASS_LOADER_CONTEXT.equals(context)
|
||||
|| UNSUPPORTED_CLASS_LOADER_CONTEXT.equals(context);
|
||||
private static boolean isUnsupportedContext(String context) {
|
||||
return UNSUPPORTED_CLASS_LOADER_CONTEXT.equals(context);
|
||||
}
|
||||
|
||||
public boolean isUsedByOtherApps() {
|
||||
@@ -887,10 +820,8 @@ public class PackageDexUsage extends AbstractStatsBase<Void> {
|
||||
|
||||
public String getClassLoaderContext() { return mClassLoaderContext; }
|
||||
|
||||
public boolean isUnknownClassLoaderContext() {
|
||||
// The class loader context may be unknown if we loaded the data from a previous version
|
||||
// which didn't save the context.
|
||||
return isUnknownOrUnsupportedContext(mClassLoaderContext);
|
||||
public boolean isUnsupportedClassLoaderContext() {
|
||||
return isUnsupportedContext(mClassLoaderContext);
|
||||
}
|
||||
|
||||
public boolean isVariableClassLoaderContext() {
|
||||
|
||||
@@ -420,45 +420,19 @@ public class PackageDexUsageTests {
|
||||
assertPackageDexUsage(null, expectedContext);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRecordClassLoaderContextTransitionFromUnknown() {
|
||||
// Record a secondary dex file.
|
||||
TestData unknownContext = mFooSecondary1User0.updateClassLoaderContext(
|
||||
PackageDexUsage.UNKNOWN_CLASS_LOADER_CONTEXT);
|
||||
assertTrue(record(unknownContext));
|
||||
|
||||
assertPackageDexUsage(null, unknownContext);
|
||||
writeAndReadBack();
|
||||
assertPackageDexUsage(null, unknownContext);
|
||||
|
||||
// Now update the secondary dex record with a class loader context. This simulates the
|
||||
// version 2 to version 3 upgrade.
|
||||
|
||||
assertTrue(record(mFooSecondary1User0));
|
||||
|
||||
assertPackageDexUsage(null, mFooSecondary1User0);
|
||||
writeAndReadBack();
|
||||
assertPackageDexUsage(null, mFooSecondary1User0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDexUsageClassLoaderContext() {
|
||||
final boolean isUsedByOtherApps = false;
|
||||
final int userId = 0;
|
||||
PackageDexUsage.DexUseInfo validContext = new DexUseInfo(isUsedByOtherApps, userId,
|
||||
"valid_context", "arm");
|
||||
assertFalse(validContext.isUnknownClassLoaderContext());
|
||||
assertFalse(validContext.isUnsupportedClassLoaderContext());
|
||||
assertFalse(validContext.isVariableClassLoaderContext());
|
||||
|
||||
PackageDexUsage.DexUseInfo variableContext = new DexUseInfo(isUsedByOtherApps, userId,
|
||||
PackageDexUsage.VARIABLE_CLASS_LOADER_CONTEXT, "arm");
|
||||
assertFalse(variableContext.isUnknownClassLoaderContext());
|
||||
assertFalse(variableContext.isUnsupportedClassLoaderContext());
|
||||
assertTrue(variableContext.isVariableClassLoaderContext());
|
||||
|
||||
PackageDexUsage.DexUseInfo unknownContext = new DexUseInfo(isUsedByOtherApps, userId,
|
||||
PackageDexUsage.UNKNOWN_CLASS_LOADER_CONTEXT, "arm");
|
||||
assertTrue(unknownContext.isUnknownClassLoaderContext());
|
||||
assertFalse(unknownContext.isVariableClassLoaderContext());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -482,80 +456,6 @@ public class PackageDexUsageTests {
|
||||
assertPackageDexUsage(mBarBaseUser0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadVersion1() {
|
||||
String isa = VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]);
|
||||
// Equivalent to
|
||||
// record(mFooSplit2UsedByOtherApps0);
|
||||
// record(mFooSecondary1User0);
|
||||
// record(mFooSecondary2UsedByOtherApps0);
|
||||
// record(mBarBaseUser0);
|
||||
// record(mBarSecondary1User0);
|
||||
String content = "PACKAGE_MANAGER__PACKAGE_DEX_USAGE__1\n"
|
||||
+ "com.google.foo,1\n"
|
||||
+ "#/data/user/0/com.google.foo/sec-1.dex\n"
|
||||
+ "0,0," + isa + "\n"
|
||||
+ "#/data/user/0/com.google.foo/sec-2.dex\n"
|
||||
+ "0,1," + isa + "\n"
|
||||
+ "com.google.bar,0\n"
|
||||
+ "#/data/user/0/com.google.bar/sec-1.dex\n"
|
||||
+ "0,0," + isa + "\n";
|
||||
|
||||
PackageDexUsage packageDexUsage = new PackageDexUsage();
|
||||
try {
|
||||
packageDexUsage.read(new StringReader(content));
|
||||
} catch (IOException e) {
|
||||
fail();
|
||||
}
|
||||
|
||||
// After the read we must sync the data to fill the missing information on the code paths.
|
||||
Map<String, Set<Integer>> packageToUsersMap = new HashMap<>();
|
||||
Map<String, Set<String>> packageToCodePaths = new HashMap<>();
|
||||
|
||||
// Handle foo package.
|
||||
packageToUsersMap.put(mFooSplit2UsedByOtherApps0.mPackageName,
|
||||
new HashSet<>(Arrays.asList(mFooSplit2UsedByOtherApps0.mOwnerUserId)));
|
||||
packageToCodePaths.put(mFooSplit2UsedByOtherApps0.mPackageName,
|
||||
new HashSet<>(Arrays.asList(mFooSplit2UsedByOtherApps0.mDexFile,
|
||||
mFooSplit1User0.mDexFile, mFooBaseUser0.mDexFile)));
|
||||
// Handle bar package.
|
||||
packageToUsersMap.put(mBarBaseUser0.mPackageName,
|
||||
new HashSet<>(Arrays.asList(mBarBaseUser0.mOwnerUserId)));
|
||||
packageToCodePaths.put(mBarBaseUser0.mPackageName,
|
||||
new HashSet<>(Arrays.asList(mBarBaseUser0.mDexFile)));
|
||||
|
||||
// Sync the data.
|
||||
packageDexUsage.syncData(packageToUsersMap, packageToCodePaths);
|
||||
|
||||
// Update the class loaders to unknown before asserting if needed. Before version 2 we
|
||||
// didn't have any.
|
||||
String unknown = PackageDexUsage.UNKNOWN_CLASS_LOADER_CONTEXT;
|
||||
TestData fooBaseUser0 = mFooBaseUser0.updateClassLoaderContext(unknown);
|
||||
TestData fooSplit1User0 = mFooSplit1User0.updateClassLoaderContext(unknown);
|
||||
TestData fooSplit2UsedByOtherApps0 =
|
||||
mFooSplit2UsedByOtherApps0.updateClassLoaderContext(unknown);
|
||||
TestData fooSecondary1User0 = mFooSecondary1User0.updateClassLoaderContext(unknown);
|
||||
TestData fooSecondary2UsedByOtherApps0 =
|
||||
mFooSecondary2UsedByOtherApps0.updateClassLoaderContext(unknown);
|
||||
TestData barBaseUser0 = mBarBaseUser0.updateClassLoaderContext(unknown);
|
||||
TestData barSecondary1User0 = mBarSecondary1User0.updateClassLoaderContext(unknown);
|
||||
|
||||
// Assert foo code paths. Note that we ignore the users during upgrade.
|
||||
final Set<String> ignoredUsers = null;
|
||||
assertPackageDexUsage(packageDexUsage, ignoredUsers,
|
||||
fooSplit2UsedByOtherApps0, fooSecondary1User0, fooSecondary2UsedByOtherApps0);
|
||||
// Because fooSplit2UsedByOtherApps0 is used by others, all the other code paths must
|
||||
// share the same data.
|
||||
assertPackageDexUsage(packageDexUsage, ignoredUsers,
|
||||
fooSplit1User0.updateUseByOthers(true),
|
||||
fooSecondary1User0, fooSecondary2UsedByOtherApps0);
|
||||
assertPackageDexUsage(packageDexUsage, ignoredUsers, fooBaseUser0.updateUseByOthers(true),
|
||||
fooSecondary1User0, fooSecondary2UsedByOtherApps0);
|
||||
|
||||
// Assert bar code paths. Note that we ignore the users during upgrade.
|
||||
assertPackageDexUsage(packageDexUsage, ignoredUsers, barBaseUser0, barSecondary1User0);
|
||||
}
|
||||
|
||||
private void assertPackageDexUsage(TestData primary, TestData... secondaries) {
|
||||
assertPackageDexUsage(mPackageDexUsage, null, primary, secondaries);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user