blob: 21b286e68adfc76a7fe910f4f12764b5feaab3ec [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package com.android.server.pm.dex;
import static org.junit.Assert.assertEquals;
import android.content.pm.ApplicationInfo;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.util.SparseArray;
import dalvik.system.DelegateLastClassLoader;
import dalvik.system.PathClassLoader;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class DexoptUtilsTest {
private static final String PATH_CLASS_LOADER_NAME = PathClassLoader.class.getName();
private static final String DELEGATE_LAST_CLASS_LOADER_NAME =
DelegateLastClassLoader.class.getName();
private ApplicationInfo createMockApplicationInfo(String baseClassLoader, boolean addSplits,
boolean addSplitDependencies) {
ApplicationInfo ai = new ApplicationInfo();
String codeDir = "/data/app/mock.android.com";
ai.setBaseCodePath(codeDir + "/base.dex");
ai.privateFlags = ai.privateFlags | ApplicationInfo.PRIVATE_FLAG_ISOLATED_SPLIT_LOADING;
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"});
if (addSplitDependencies) {
ai.splitDependencies = new SparseArray<>(6 + 1);
ai.splitDependencies.put(0, new int[] {-1}); // base has no dependency
ai.splitDependencies.put(1, new int[] {2}); // split 1 depends on 2
ai.splitDependencies.put(2, new int[] {4}); // split 2 depends on 4
ai.splitDependencies.put(3, new int[] {4}); // split 3 depends on 4
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
}
}
return ai;
}
@Test
public void testSplitChain() {
ApplicationInfo ai = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, true, true);
String[] sharedLibrary = new String[] {"a.dex", "b.dex"};
String[] contexts = DexoptUtils.getClassLoaderContexts(ai, sharedLibrary);
assertEquals(7, contexts.length);
assertEquals("PCL[a.dex:b.dex]", contexts[0]);
assertEquals("PCL[];PCL[base-2.dex];PCL[base-4.dex];PCL[a.dex:b.dex:base.dex]",
contexts[1]);
assertEquals("PCL[];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]);
}
@Test
public void testSplitChainNoSplitDependencies() {
ApplicationInfo ai = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, true, false);
String[] sharedLibrary = new String[] {"a.dex", "b.dex"};
String[] contexts = DexoptUtils.getClassLoaderContexts(ai, sharedLibrary);
assertEquals(7, 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]);
assertEquals("PCL[a.dex:b.dex:base.dex:base-1.dex:base-2.dex]", contexts[3]);
assertEquals("PCL[a.dex:b.dex:base.dex:base-1.dex:base-2.dex:base-3.dex]", contexts[4]);
assertEquals(
"PCL[a.dex:b.dex:base.dex:base-1.dex:base-2.dex:base-3.dex:base-4.dex]",
contexts[5]);
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]);
}
@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);
assertEquals(7, contexts.length);
assertEquals("PCL[]", contexts[0]);
assertEquals("PCL[base.dex]", contexts[1]);
assertEquals("PCL[base.dex:base-1.dex]", contexts[2]);
assertEquals("PCL[base.dex:base-1.dex:base-2.dex]", contexts[3]);
assertEquals("PCL[base.dex:base-1.dex:base-2.dex:base-3.dex]", contexts[4]);
assertEquals("PCL[base.dex:base-1.dex:base-2.dex:base-3.dex:base-4.dex]", contexts[5]);
assertEquals(
"PCL[base.dex:base-1.dex:base-2.dex:base-3.dex:base-4.dex:base-5.dex]",
contexts[6]);
}
@Test
public void testSplitChainNoSharedLibraries() {
ApplicationInfo ai = createMockApplicationInfo(
DELEGATE_LAST_CLASS_LOADER_NAME, true, true);
String[] contexts = DexoptUtils.getClassLoaderContexts(ai, null);
assertEquals(7, contexts.length);
assertEquals("PCL[]", contexts[0]);
assertEquals("PCL[];PCL[base-2.dex];PCL[base-4.dex];PCL[base.dex]", contexts[1]);
assertEquals("PCL[];PCL[base-4.dex];PCL[base.dex]", contexts[2]);
assertEquals("PCL[];PCL[base-4.dex];PCL[base.dex]", contexts[3]);
assertEquals("PCL[];PCL[base.dex]", contexts[4]);
assertEquals("PCL[];PCL[base.dex]", contexts[5]);
assertEquals("PCL[];PCL[base-5.dex];PCL[base.dex]", contexts[6]);
}
@Test
public void testSplitChainWithNullPrimaryClassLoader() {
// A null classLoaderName should mean PathClassLoader.
ApplicationInfo ai = createMockApplicationInfo(null, true, true);
String[] sharedLibrary = new String[] {"a.dex", "b.dex"};
String[] contexts = DexoptUtils.getClassLoaderContexts(ai, sharedLibrary);
assertEquals(7, contexts.length);
assertEquals("PCL[a.dex:b.dex]", contexts[0]);
assertEquals("PCL[];PCL[base-2.dex];PCL[base-4.dex];PCL[a.dex:b.dex:base.dex]", contexts[1]);
assertEquals("PCL[];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]);
}
@Test
public void tesNoSplits() {
ApplicationInfo ai = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, false, false);
String[] sharedLibrary = new String[] {"a.dex", "b.dex"};
String[] contexts = DexoptUtils.getClassLoaderContexts(ai, sharedLibrary);
assertEquals(1, contexts.length);
assertEquals("PCL[a.dex:b.dex]", contexts[0]);
}
@Test
public void tesNoSplitsNullClassLoaderName() {
ApplicationInfo ai = createMockApplicationInfo(null, false, false);
String[] sharedLibrary = new String[] {"a.dex", "b.dex"};
String[] contexts = DexoptUtils.getClassLoaderContexts(ai, sharedLibrary);
assertEquals(1, contexts.length);
assertEquals("PCL[a.dex:b.dex]", contexts[0]);
}
@Test
public void tesNoSplitDelegateLast() {
ApplicationInfo ai = createMockApplicationInfo(
DELEGATE_LAST_CLASS_LOADER_NAME, false, false);
String[] sharedLibrary = new String[] {"a.dex", "b.dex"};
String[] contexts = DexoptUtils.getClassLoaderContexts(ai, sharedLibrary);
assertEquals(1, contexts.length);
assertEquals("PCL[a.dex:b.dex]", contexts[0]);
}
@Test
public void tesNoSplitsNoSharedLibraries() {
ApplicationInfo ai = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, false, false);
String[] contexts = DexoptUtils.getClassLoaderContexts(ai, null);
assertEquals(1, contexts.length);
assertEquals("PCL[]", contexts[0]);
}
@Test
public void tesNoSplitDelegateLastNoSharedLibraries() {
ApplicationInfo ai = createMockApplicationInfo(
DELEGATE_LAST_CLASS_LOADER_NAME, false, false);
String[] contexts = DexoptUtils.getClassLoaderContexts(ai, null);
assertEquals(1, contexts.length);
assertEquals("PCL[]", contexts[0]);
}
}