1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.cts.useslibrary;
18 
19 import android.content.pm.PackageManager;
20 import android.os.Environment;
21 import android.support.test.uiautomator.UiDevice;
22 import android.support.test.uiautomator.UiObject;
23 import android.support.test.uiautomator.UiSelector;
24 import android.test.InstrumentationTestCase;
25 
26 import dalvik.system.BaseDexClassLoader;
27 import dalvik.system.DexFile;
28 import dalvik.system.PathClassLoader;
29 
30 import java.io.File;
31 import java.lang.reflect.Field;
32 import java.lang.reflect.Method;
33 
34 public class UsesLibraryTest extends InstrumentationTestCase {
35     private static final String TAG = "UsesLibraryTest";
36 
testUsesLibrary()37     public void testUsesLibrary() throws Exception {
38         ClassLoader loader = getClass().getClassLoader();
39         if (loader instanceof BaseDexClassLoader) {
40             Object[] dexElements = getDexElementsFromClassLoader((BaseDexClassLoader) loader);
41             for (Object dexElement : dexElements) {
42                 DexFile dexFile = getDexFileFromDexElement(dexElement);
43                 assertTrue(isDexFileBackedByOatFile(dexFile));
44             }
45         }
46     }
47 
testMissingLibrary()48     public void testMissingLibrary() throws Exception {
49         ClassLoader loader = getClass().getClassLoader();
50         if (loader instanceof BaseDexClassLoader) {
51             Object[] dexElements = getDexElementsFromClassLoader((BaseDexClassLoader) loader);
52             assertTrue(dexElements != null && dexElements.length > 1);
53 
54             DexFile dexFile = getDexFileFromDexElement(dexElements[1]);
55             String testApkPath = dexFile.getName();
56             PathClassLoader testLoader = new PathClassLoader(testApkPath, null);
57             Object[] testDexElements = getDexElementsFromClassLoader(testLoader);
58             assertTrue(testDexElements != null && testDexElements.length == 1);
59 
60             DexFile testDexFile = getDexFileFromDexElement(testDexElements[0]);
61             assertTrue(isDexFileBackedByOatFile(testDexFile));
62         }
63     }
64 
testDuplicateLibrary()65     public void testDuplicateLibrary() throws Exception {
66         ClassLoader loader = getClass().getClassLoader();
67         if (loader instanceof BaseDexClassLoader) {
68             Object[] dexElements = getDexElementsFromClassLoader((BaseDexClassLoader) loader);
69             assertTrue(dexElements != null && dexElements.length > 1);
70 
71             DexFile libDexFile = getDexFileFromDexElement(dexElements[0]);
72             String libPath = libDexFile.getName();
73             DexFile apkDexFile = getDexFileFromDexElement(dexElements[1]);
74             String apkPath = apkDexFile.getName();
75             String testPath = libPath + File.pathSeparator + apkPath + File.pathSeparator + apkPath;
76             PathClassLoader testLoader = new PathClassLoader(testPath, null);
77             Object[] testDexElements = getDexElementsFromClassLoader(testLoader);
78             assertTrue(testDexElements != null && testDexElements.length == 3);
79 
80             DexFile testDexFile = getDexFileFromDexElement(testDexElements[2]);
81             assertFalse(isDexFileBackedByOatFile(testDexFile));
82         }
83     }
84 
getDexElementsFromClassLoader(BaseDexClassLoader loader)85     private Object[] getDexElementsFromClassLoader(BaseDexClassLoader loader) throws Exception {
86         Field pathListField = BaseDexClassLoader.class.getDeclaredField("pathList");
87         pathListField.setAccessible(true);
88         // This is a DexPathList, but that class is package private.
89         Object pathList = pathListField.get(loader);
90         Field dexElementsField = pathList.getClass().getDeclaredField("dexElements");
91         dexElementsField.setAccessible(true);
92         // The objects in this array are Elements, but that class is package private.
93         return (Object[]) dexElementsField.get(pathList);
94     }
95 
96     // The argument must be a DexPathList.Element.
getDexFileFromDexElement(Object dexElement)97     private DexFile getDexFileFromDexElement(Object dexElement) throws Exception {
98         Field dexFileField = dexElement.getClass().getDeclaredField("dexFile");
99         dexFileField.setAccessible(true);
100         return (DexFile) dexFileField.get(dexElement);
101     }
102 
isDexFileBackedByOatFile(DexFile dexFile)103     private boolean isDexFileBackedByOatFile(DexFile dexFile) throws Exception {
104         Method isBackedByOatFileMethod = DexFile.class.getDeclaredMethod("isBackedByOatFile");
105         isBackedByOatFileMethod.setAccessible(true);
106         return (boolean) isBackedByOatFileMethod.invoke(dexFile);
107     }
108 }
109