Merge "Handle configuration splits when creating the class loader context" into oc-mr1-dev
am: ed54b41e3c
Change-Id: I34d37f77255226ec46bb833b64d8196b746f413e
This commit is contained in:
@@ -718,6 +718,10 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
|
||||
* Cycles do not exist because they are illegal and screened for during installation.
|
||||
*
|
||||
* May be null if no splits are installed, or if no dependencies exist between them.
|
||||
*
|
||||
* NOTE: Any change to the way split dependencies are stored must update the logic that
|
||||
* creates the class loader context for dexopt (DexoptUtils#getClassLoaderContexts).
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public SparseArray<int[]> splitDependencies;
|
||||
|
||||
@@ -147,8 +147,13 @@ public class PackageDexOptimizer {
|
||||
// Get the class loader context dependencies.
|
||||
// For each code path in the package, this array contains the class loader context that
|
||||
// needs to be passed to dexopt in order to ensure correct optimizations.
|
||||
boolean[] pathsWithCode = new boolean[paths.size()];
|
||||
pathsWithCode[0] = (pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0;
|
||||
for (int i = 1; i < paths.size(); i++) {
|
||||
pathsWithCode[i] = (pkg.splitFlags[i - 1] & ApplicationInfo.FLAG_HAS_CODE) != 0;
|
||||
}
|
||||
String[] classLoaderContexts = DexoptUtils.getClassLoaderContexts(
|
||||
pkg.applicationInfo, sharedLibraries);
|
||||
pkg.applicationInfo, sharedLibraries, pathsWithCode);
|
||||
|
||||
// Sanity check that we do not call dexopt with inconsistent data.
|
||||
if (paths.size() != classLoaderContexts.length) {
|
||||
@@ -164,10 +169,15 @@ public class PackageDexOptimizer {
|
||||
int result = DEX_OPT_SKIPPED;
|
||||
for (int i = 0; i < paths.size(); i++) {
|
||||
// Skip paths that have no code.
|
||||
if ((i == 0 && (pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) == 0) ||
|
||||
(i != 0 && (pkg.splitFlags[i - 1] & ApplicationInfo.FLAG_HAS_CODE) == 0)) {
|
||||
if (!pathsWithCode[i]) {
|
||||
continue;
|
||||
}
|
||||
if (classLoaderContexts[i] == null) {
|
||||
throw new IllegalStateException("Inconsistent information in the "
|
||||
+ "package structure. A split is marked to contain code "
|
||||
+ "but has no dependency listed. Index=" + i + " path=" + paths.get(i));
|
||||
}
|
||||
|
||||
// Append shared libraries with split dependencies for this split.
|
||||
String path = paths.get(i);
|
||||
if (options.getSplitName() != null) {
|
||||
|
||||
@@ -35,7 +35,9 @@ public final class DexoptUtils {
|
||||
/**
|
||||
* Creates the class loader context dependencies for each of the application code paths.
|
||||
* The returned array contains the class loader contexts that needs to be passed to dexopt in
|
||||
* order to ensure correct optimizations.
|
||||
* order to ensure correct optimizations. "Code" paths with no actual code, as specified by
|
||||
* {@param pathsWithCode}, are ignored and will have null as their context in the returned array
|
||||
* (configuration splits are an example of paths without code).
|
||||
*
|
||||
* A class loader context describes how the class loader chain should be built by dex2oat
|
||||
* in order to ensure that classes are resolved during compilation as they would be resolved
|
||||
@@ -60,7 +62,8 @@ public final class DexoptUtils {
|
||||
* {@link android.app.LoadedApk#makePaths(
|
||||
* android.app.ActivityThread, boolean, ApplicationInfo, List, List)}.
|
||||
*/
|
||||
public static String[] getClassLoaderContexts(ApplicationInfo info, String[] sharedLibraries) {
|
||||
public static String[] getClassLoaderContexts(ApplicationInfo info,
|
||||
String[] sharedLibraries, boolean[] pathsWithCode) {
|
||||
// The base class loader context contains only the shared library.
|
||||
String sharedLibrariesClassPath = encodeClasspath(sharedLibraries);
|
||||
String baseApkContextClassLoader = encodeClassLoader(
|
||||
@@ -86,7 +89,7 @@ public final class DexoptUtils {
|
||||
// Index 0 is the class loaded context for the base apk.
|
||||
// Index `i` is the class loader context encoding for split `i`.
|
||||
String[] classLoaderContexts = new String[/*base apk*/ 1 + splitRelativeCodePaths.length];
|
||||
classLoaderContexts[0] = baseApkContextClassLoader;
|
||||
classLoaderContexts[0] = pathsWithCode[0] ? baseApkContextClassLoader : null;
|
||||
|
||||
if (!info.requestsIsolatedSplitLoading() || info.splitDependencies == null) {
|
||||
// If the app didn't request for the splits to be loaded in isolation or if it does not
|
||||
@@ -94,7 +97,15 @@ public final class DexoptUtils {
|
||||
// apk class loader (in the order of their definition).
|
||||
String classpath = sharedLibrariesAndBaseClassPath;
|
||||
for (int i = 1; i < classLoaderContexts.length; i++) {
|
||||
classLoaderContexts[i] = encodeClassLoader(classpath, info.classLoaderName);
|
||||
classLoaderContexts[i] = pathsWithCode[i]
|
||||
? encodeClassLoader(classpath, info.classLoaderName) : null;
|
||||
// Note that the splits with no code are not removed from the classpath computation.
|
||||
// i.e. split_n might get the split_n-1 in its classpath dependency even
|
||||
// if split_n-1 has no code.
|
||||
// The splits with no code do not matter for the runtime which ignores
|
||||
// apks without code when doing the classpath checks. As such we could actually
|
||||
// filter them but we don't do it in order to keep consistency with how the apps
|
||||
// are loaded.
|
||||
classpath = encodeClasspath(classpath, splitRelativeCodePaths[i - 1]);
|
||||
}
|
||||
} else {
|
||||
@@ -116,9 +127,17 @@ public final class DexoptUtils {
|
||||
String splitDependencyOnBase = encodeClassLoader(
|
||||
sharedLibrariesAndBaseClassPath, info.classLoaderName);
|
||||
SparseArray<int[]> splitDependencies = info.splitDependencies;
|
||||
|
||||
// Note that not all splits have dependencies (e.g. configuration splits)
|
||||
// The splits without dependencies will have classLoaderContexts[config_split_index]
|
||||
// set to null after this step.
|
||||
for (int i = 1; i < splitDependencies.size(); i++) {
|
||||
getParentDependencies(splitDependencies.keyAt(i), splitClassLoaderEncodingCache,
|
||||
splitDependencies, classLoaderContexts, splitDependencyOnBase);
|
||||
int splitIndex = splitDependencies.keyAt(i);
|
||||
if (pathsWithCode[splitIndex]) {
|
||||
// Compute the class loader context only for the splits with code.
|
||||
getParentDependencies(splitIndex, splitClassLoaderEncodingCache,
|
||||
splitDependencies, classLoaderContexts, splitDependencyOnBase);
|
||||
}
|
||||
}
|
||||
|
||||
// At this point classLoaderContexts contains only the parent dependencies.
|
||||
@@ -126,8 +145,17 @@ public final class DexoptUtils {
|
||||
// come first in the context.
|
||||
for (int i = 1; i < classLoaderContexts.length; i++) {
|
||||
String splitClassLoader = encodeClassLoader("", info.splitClassLoaderNames[i - 1]);
|
||||
classLoaderContexts[i] = encodeClassLoaderChain(
|
||||
splitClassLoader, classLoaderContexts[i]);
|
||||
if (pathsWithCode[i]) {
|
||||
// If classLoaderContexts[i] is null it means that the split does not have
|
||||
// any dependency. In this case its context equals its declared class loader.
|
||||
classLoaderContexts[i] = classLoaderContexts[i] == null
|
||||
? splitClassLoader
|
||||
: encodeClassLoaderChain(splitClassLoader, classLoaderContexts[i]);
|
||||
} else {
|
||||
// This is a split without code, it has no dependency and it is not compiled.
|
||||
// Its context will be null.
|
||||
classLoaderContexts[i] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -46,22 +46,35 @@ public class DexoptUtilsTest {
|
||||
private static final String DELEGATE_LAST_CLASS_LOADER_NAME =
|
||||
DelegateLastClassLoader.class.getName();
|
||||
|
||||
private ApplicationInfo createMockApplicationInfo(String baseClassLoader, boolean addSplits,
|
||||
private static class TestData {
|
||||
ApplicationInfo info;
|
||||
boolean[] pathsWithCode;
|
||||
}
|
||||
|
||||
private TestData createMockApplicationInfo(String baseClassLoader, boolean addSplits,
|
||||
boolean addSplitDependencies) {
|
||||
ApplicationInfo ai = new ApplicationInfo();
|
||||
String codeDir = "/data/app/mock.android.com";
|
||||
ai.setBaseCodePath(codeDir + "/base.dex");
|
||||
ai.classLoaderName = baseClassLoader;
|
||||
ai.privateFlags = ai.privateFlags | ApplicationInfo.PRIVATE_FLAG_ISOLATED_SPLIT_LOADING;
|
||||
boolean[] pathsWithCode;
|
||||
if (!addSplits) {
|
||||
pathsWithCode = new boolean[] {true};
|
||||
} else {
|
||||
pathsWithCode = new boolean[9];
|
||||
Arrays.fill(pathsWithCode, true);
|
||||
pathsWithCode[7] = false; // config split
|
||||
|
||||
if (addSplits) {
|
||||
ai.setSplitCodePaths(new String[]{
|
||||
codeDir + "/base-1.dex",
|
||||
codeDir + "/base-2.dex",
|
||||
codeDir + "/base-3.dex",
|
||||
codeDir + "/base-4.dex",
|
||||
codeDir + "/base-5.dex",
|
||||
codeDir + "/base-6.dex"});
|
||||
codeDir + "/base-6.dex",
|
||||
codeDir + "/config-split-7.dex",
|
||||
codeDir + "/feature-no-deps.dex"});
|
||||
|
||||
ai.splitClassLoaderNames = new String[]{
|
||||
DELEGATE_LAST_CLASS_LOADER_NAME,
|
||||
@@ -69,7 +82,9 @@ public class DexoptUtilsTest {
|
||||
PATH_CLASS_LOADER_NAME,
|
||||
DEX_CLASS_LOADER_NAME,
|
||||
PATH_CLASS_LOADER_NAME,
|
||||
null}; // A null class loader name should default to PathClassLoader.
|
||||
null, // A null class loader name should default to PathClassLoader.
|
||||
null, // The config split gets a null class loader.
|
||||
null}; // The feature split with no dependency and no specified class loader.
|
||||
if (addSplitDependencies) {
|
||||
ai.splitDependencies = new SparseArray<>(ai.splitClassLoaderNames.length + 1);
|
||||
ai.splitDependencies.put(0, new int[] {-1}); // base has no dependency
|
||||
@@ -79,18 +94,24 @@ public class DexoptUtilsTest {
|
||||
ai.splitDependencies.put(4, new int[] {0}); // split 4 depends on base
|
||||
ai.splitDependencies.put(5, new int[] {0}); // split 5 depends on base
|
||||
ai.splitDependencies.put(6, new int[] {5}); // split 6 depends on 5
|
||||
// Do not add the config split to the dependency list.
|
||||
// Do not add the feature split with no dependency to the dependency list.
|
||||
}
|
||||
}
|
||||
return ai;
|
||||
TestData data = new TestData();
|
||||
data.info = ai;
|
||||
data.pathsWithCode = pathsWithCode;
|
||||
return data;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSplitChain() {
|
||||
ApplicationInfo ai = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, true, true);
|
||||
TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, true, true);
|
||||
String[] sharedLibrary = new String[] {"a.dex", "b.dex"};
|
||||
String[] contexts = DexoptUtils.getClassLoaderContexts(ai, sharedLibrary);
|
||||
String[] contexts = DexoptUtils.getClassLoaderContexts(
|
||||
data.info, sharedLibrary, data.pathsWithCode);
|
||||
|
||||
assertEquals(7, contexts.length);
|
||||
assertEquals(9, contexts.length);
|
||||
assertEquals("PCL[a.dex:b.dex]", contexts[0]);
|
||||
assertEquals("DLC[];DLC[base-2.dex];PCL[base-4.dex];PCL[a.dex:b.dex:base.dex]",
|
||||
contexts[1]);
|
||||
@@ -99,15 +120,18 @@ public class DexoptUtilsTest {
|
||||
assertEquals("PCL[];PCL[a.dex:b.dex:base.dex]", contexts[4]);
|
||||
assertEquals("PCL[];PCL[a.dex:b.dex:base.dex]", contexts[5]);
|
||||
assertEquals("PCL[];PCL[base-5.dex];PCL[a.dex:b.dex:base.dex]", contexts[6]);
|
||||
assertEquals(null, contexts[7]); // config split
|
||||
assertEquals("PCL[]", contexts[8]); // feature split with no dependency
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSplitChainNoSplitDependencies() {
|
||||
ApplicationInfo ai = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, true, false);
|
||||
TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, true, false);
|
||||
String[] sharedLibrary = new String[] {"a.dex", "b.dex"};
|
||||
String[] contexts = DexoptUtils.getClassLoaderContexts(ai, sharedLibrary);
|
||||
String[] contexts = DexoptUtils.getClassLoaderContexts(
|
||||
data.info, sharedLibrary, data.pathsWithCode);
|
||||
|
||||
assertEquals(7, contexts.length);
|
||||
assertEquals(9, contexts.length);
|
||||
assertEquals("PCL[a.dex:b.dex]", contexts[0]);
|
||||
assertEquals("PCL[a.dex:b.dex:base.dex]", contexts[1]);
|
||||
assertEquals("PCL[a.dex:b.dex:base.dex:base-1.dex]", contexts[2]);
|
||||
@@ -119,15 +143,21 @@ public class DexoptUtilsTest {
|
||||
assertEquals(
|
||||
"PCL[a.dex:b.dex:base.dex:base-1.dex:base-2.dex:base-3.dex:base-4.dex:base-5.dex]",
|
||||
contexts[6]);
|
||||
assertEquals(null, contexts[7]); // config split
|
||||
assertEquals(
|
||||
"PCL[a.dex:b.dex:base.dex:base-1.dex:base-2.dex:base-3.dex:base-4.dex:base-5.dex:base-6.dex:config-split-7.dex]",
|
||||
contexts[8]); // feature split with no dependency
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSplitChainNoIsolationNoSharedLibrary() {
|
||||
ApplicationInfo ai = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, true, true);
|
||||
ai.privateFlags = ai.privateFlags & (~ApplicationInfo.PRIVATE_FLAG_ISOLATED_SPLIT_LOADING);
|
||||
String[] contexts = DexoptUtils.getClassLoaderContexts(ai, null);
|
||||
TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, true, true);
|
||||
data.info.privateFlags = data.info.privateFlags
|
||||
& (~ApplicationInfo.PRIVATE_FLAG_ISOLATED_SPLIT_LOADING);
|
||||
String[] contexts = DexoptUtils.getClassLoaderContexts(
|
||||
data.info, null, data.pathsWithCode);
|
||||
|
||||
assertEquals(7, contexts.length);
|
||||
assertEquals(9, contexts.length);
|
||||
assertEquals("PCL[]", contexts[0]);
|
||||
assertEquals("PCL[base.dex]", contexts[1]);
|
||||
assertEquals("PCL[base.dex:base-1.dex]", contexts[2]);
|
||||
@@ -137,14 +167,20 @@ public class DexoptUtilsTest {
|
||||
assertEquals(
|
||||
"PCL[base.dex:base-1.dex:base-2.dex:base-3.dex:base-4.dex:base-5.dex]",
|
||||
contexts[6]);
|
||||
assertEquals(null, contexts[7]); // config split
|
||||
assertEquals(
|
||||
"PCL[base.dex:base-1.dex:base-2.dex:base-3.dex:base-4.dex:base-5.dex:base-6.dex:config-split-7.dex]",
|
||||
contexts[8]); // feature split with no dependency
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSplitChainNoSharedLibraries() {
|
||||
ApplicationInfo ai = createMockApplicationInfo(
|
||||
TestData data = createMockApplicationInfo(
|
||||
DELEGATE_LAST_CLASS_LOADER_NAME, true, true);
|
||||
String[] contexts = DexoptUtils.getClassLoaderContexts(ai, null);
|
||||
String[] contexts = DexoptUtils.getClassLoaderContexts(
|
||||
data.info, null, data.pathsWithCode);
|
||||
|
||||
assertEquals(7, contexts.length);
|
||||
assertEquals(9, contexts.length);
|
||||
assertEquals("DLC[]", contexts[0]);
|
||||
assertEquals("DLC[];DLC[base-2.dex];PCL[base-4.dex];DLC[base.dex]", contexts[1]);
|
||||
assertEquals("DLC[];PCL[base-4.dex];DLC[base.dex]", contexts[2]);
|
||||
@@ -152,16 +188,19 @@ public class DexoptUtilsTest {
|
||||
assertEquals("PCL[];DLC[base.dex]", contexts[4]);
|
||||
assertEquals("PCL[];DLC[base.dex]", contexts[5]);
|
||||
assertEquals("PCL[];PCL[base-5.dex];DLC[base.dex]", contexts[6]);
|
||||
assertEquals(null, contexts[7]); // config split
|
||||
assertEquals("PCL[]", contexts[8]); // feature split with no dependency
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSplitChainWithNullPrimaryClassLoader() {
|
||||
// A null classLoaderName should mean PathClassLoader.
|
||||
ApplicationInfo ai = createMockApplicationInfo(null, true, true);
|
||||
TestData data = createMockApplicationInfo(null, true, true);
|
||||
String[] sharedLibrary = new String[] {"a.dex", "b.dex"};
|
||||
String[] contexts = DexoptUtils.getClassLoaderContexts(ai, sharedLibrary);
|
||||
String[] contexts = DexoptUtils.getClassLoaderContexts(
|
||||
data.info, sharedLibrary, data.pathsWithCode);
|
||||
|
||||
assertEquals(7, contexts.length);
|
||||
assertEquals(9, contexts.length);
|
||||
assertEquals("PCL[a.dex:b.dex]", contexts[0]);
|
||||
assertEquals("DLC[];DLC[base-2.dex];PCL[base-4.dex];PCL[a.dex:b.dex:base.dex]", contexts[1]);
|
||||
assertEquals("DLC[];PCL[base-4.dex];PCL[a.dex:b.dex:base.dex]", contexts[2]);
|
||||
@@ -169,13 +208,16 @@ public class DexoptUtilsTest {
|
||||
assertEquals("PCL[];PCL[a.dex:b.dex:base.dex]", contexts[4]);
|
||||
assertEquals("PCL[];PCL[a.dex:b.dex:base.dex]", contexts[5]);
|
||||
assertEquals("PCL[];PCL[base-5.dex];PCL[a.dex:b.dex:base.dex]", contexts[6]);
|
||||
assertEquals(null, contexts[7]); // config split
|
||||
assertEquals("PCL[]", contexts[8]); // feature split with no dependency
|
||||
}
|
||||
|
||||
@Test
|
||||
public void tesNoSplits() {
|
||||
ApplicationInfo ai = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, false, false);
|
||||
TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, false, false);
|
||||
String[] sharedLibrary = new String[] {"a.dex", "b.dex"};
|
||||
String[] contexts = DexoptUtils.getClassLoaderContexts(ai, sharedLibrary);
|
||||
String[] contexts = DexoptUtils.getClassLoaderContexts(
|
||||
data.info, sharedLibrary, data.pathsWithCode);
|
||||
|
||||
assertEquals(1, contexts.length);
|
||||
assertEquals("PCL[a.dex:b.dex]", contexts[0]);
|
||||
@@ -183,9 +225,10 @@ public class DexoptUtilsTest {
|
||||
|
||||
@Test
|
||||
public void tesNoSplitsNullClassLoaderName() {
|
||||
ApplicationInfo ai = createMockApplicationInfo(null, false, false);
|
||||
TestData data = createMockApplicationInfo(null, false, false);
|
||||
String[] sharedLibrary = new String[] {"a.dex", "b.dex"};
|
||||
String[] contexts = DexoptUtils.getClassLoaderContexts(ai, sharedLibrary);
|
||||
String[] contexts = DexoptUtils.getClassLoaderContexts(
|
||||
data.info, sharedLibrary, data.pathsWithCode);
|
||||
|
||||
assertEquals(1, contexts.length);
|
||||
assertEquals("PCL[a.dex:b.dex]", contexts[0]);
|
||||
@@ -193,10 +236,11 @@ public class DexoptUtilsTest {
|
||||
|
||||
@Test
|
||||
public void tesNoSplitDelegateLast() {
|
||||
ApplicationInfo ai = createMockApplicationInfo(
|
||||
TestData data = createMockApplicationInfo(
|
||||
DELEGATE_LAST_CLASS_LOADER_NAME, false, false);
|
||||
String[] sharedLibrary = new String[] {"a.dex", "b.dex"};
|
||||
String[] contexts = DexoptUtils.getClassLoaderContexts(ai, sharedLibrary);
|
||||
String[] contexts = DexoptUtils.getClassLoaderContexts(
|
||||
data.info, sharedLibrary, data.pathsWithCode);
|
||||
|
||||
assertEquals(1, contexts.length);
|
||||
assertEquals("DLC[a.dex:b.dex]", contexts[0]);
|
||||
@@ -204,8 +248,9 @@ public class DexoptUtilsTest {
|
||||
|
||||
@Test
|
||||
public void tesNoSplitsNoSharedLibraries() {
|
||||
ApplicationInfo ai = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, false, false);
|
||||
String[] contexts = DexoptUtils.getClassLoaderContexts(ai, null);
|
||||
TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, false, false);
|
||||
String[] contexts = DexoptUtils.getClassLoaderContexts(
|
||||
data.info, null, data.pathsWithCode);
|
||||
|
||||
assertEquals(1, contexts.length);
|
||||
assertEquals("PCL[]", contexts[0]);
|
||||
@@ -213,14 +258,54 @@ public class DexoptUtilsTest {
|
||||
|
||||
@Test
|
||||
public void tesNoSplitDelegateLastNoSharedLibraries() {
|
||||
ApplicationInfo ai = createMockApplicationInfo(
|
||||
TestData data = createMockApplicationInfo(
|
||||
DELEGATE_LAST_CLASS_LOADER_NAME, false, false);
|
||||
String[] contexts = DexoptUtils.getClassLoaderContexts(ai, null);
|
||||
String[] contexts = DexoptUtils.getClassLoaderContexts(
|
||||
data.info, null, data.pathsWithCode);
|
||||
|
||||
assertEquals(1, contexts.length);
|
||||
assertEquals("DLC[]", contexts[0]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testContextWithNoCode() {
|
||||
TestData data = createMockApplicationInfo(null, true, false);
|
||||
Arrays.fill(data.pathsWithCode, false);
|
||||
|
||||
String[] sharedLibrary = new String[] {"a.dex", "b.dex"};
|
||||
String[] contexts = DexoptUtils.getClassLoaderContexts(
|
||||
data.info, sharedLibrary, data.pathsWithCode);
|
||||
|
||||
assertEquals(9, contexts.length);
|
||||
assertEquals(null, contexts[0]);
|
||||
assertEquals(null, contexts[1]);
|
||||
assertEquals(null, contexts[2]);
|
||||
assertEquals(null, contexts[3]);
|
||||
assertEquals(null, contexts[4]);
|
||||
assertEquals(null, contexts[5]);
|
||||
assertEquals(null, contexts[6]);
|
||||
assertEquals(null, contexts[7]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testContextBaseNoCode() {
|
||||
TestData data = createMockApplicationInfo(null, true, true);
|
||||
data.pathsWithCode[0] = false;
|
||||
String[] sharedLibrary = new String[] {"a.dex", "b.dex"};
|
||||
String[] contexts = DexoptUtils.getClassLoaderContexts(
|
||||
data.info, sharedLibrary, data.pathsWithCode);
|
||||
|
||||
assertEquals(9, contexts.length);
|
||||
assertEquals(null, contexts[0]);
|
||||
assertEquals("DLC[];DLC[base-2.dex];PCL[base-4.dex];PCL[a.dex:b.dex:base.dex]", contexts[1]);
|
||||
assertEquals("DLC[];PCL[base-4.dex];PCL[a.dex:b.dex:base.dex]", contexts[2]);
|
||||
assertEquals("PCL[];PCL[base-4.dex];PCL[a.dex:b.dex:base.dex]", contexts[3]);
|
||||
assertEquals("PCL[];PCL[a.dex:b.dex:base.dex]", contexts[4]);
|
||||
assertEquals("PCL[];PCL[a.dex:b.dex:base.dex]", contexts[5]);
|
||||
assertEquals("PCL[];PCL[base-5.dex];PCL[a.dex:b.dex:base.dex]", contexts[6]);
|
||||
assertEquals(null, contexts[7]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProcessContextForDexLoad() {
|
||||
List<String> classLoaders = Arrays.asList(
|
||||
|
||||
Reference in New Issue
Block a user