• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 import java.io.File;
18 import java.io.FileInputStream;
19 import java.io.FileOutputStream;
20 import java.io.IOException;
21 import java.lang.reflect.Method;
22 import java.lang.reflect.Constructor;
23 import java.util.HashMap;
24 
25 public class Main {
26 
27   private static final String PROFILE_NAME = "primary.prof";
28   private static final String APP_DIR_PREFIX = "app_dir_";
29   private static final String FOREIGN_DEX_PROFILE_DIR = "foreign-dex";
30   private static final String TEMP_FILE_NAME_PREFIX = "dummy";
31   private static final String TEMP_FILE_NAME_SUFFIX = "-file";
32 
main(String[] args)33   public static void main(String[] args) throws Exception {
34     File tmpFile = null;
35     File appDir = null;
36     File profileFile = null;
37     File foreignDexProfileDir = null;
38 
39     try {
40       // Create the necessary files layout.
41       tmpFile = createTempFile();
42       appDir = new File(tmpFile.getParent(), APP_DIR_PREFIX + tmpFile.getName());
43       appDir.mkdir();
44       foreignDexProfileDir = new File(tmpFile.getParent(), FOREIGN_DEX_PROFILE_DIR);
45       foreignDexProfileDir.mkdir();
46       profileFile = createTempFile();
47 
48       String codePath = System.getenv("DEX_LOCATION") + "/577-profile-foreign-dex.jar";
49 
50       // Register the app with the runtime
51       VMRuntime.registerAppInfo(profileFile.getPath(), appDir.getPath(),
52              new String[] { codePath }, foreignDexProfileDir.getPath());
53 
54       testMarkerForForeignDex(foreignDexProfileDir);
55       testMarkerForCodePath(foreignDexProfileDir);
56       testMarkerForApplicationDexFile(foreignDexProfileDir, appDir);
57     } finally {
58       if (tmpFile != null) {
59         tmpFile.delete();
60       }
61       if (profileFile != null) {
62         profileFile.delete();
63       }
64       if (foreignDexProfileDir != null) {
65         foreignDexProfileDir.delete();
66       }
67       if (appDir != null) {
68         appDir.delete();
69       }
70     }
71   }
72 
73   // Verify we actually create a marker on disk for foreign dex files.
testMarkerForForeignDex(File foreignDexProfileDir)74   private static void testMarkerForForeignDex(File foreignDexProfileDir) throws Exception {
75     String foreignDex = System.getenv("DEX_LOCATION") + "/577-profile-foreign-dex-ex.jar";
76     loadDexFile(foreignDex);
77     checkMarker(foreignDexProfileDir, foreignDex, /* exists */ true);
78   }
79 
80   // Verify we do not create a marker on disk for dex files path of the code path.
testMarkerForCodePath(File foreignDexProfileDir)81   private static void testMarkerForCodePath(File foreignDexProfileDir) throws Exception {
82     String codePath = System.getenv("DEX_LOCATION") + "/577-profile-foreign-dex.jar";
83     loadDexFile(codePath);
84     checkMarker(foreignDexProfileDir, codePath, /* exists */ false);
85   }
86 
testMarkerForApplicationDexFile(File foreignDexProfileDir, File appDir)87   private static void testMarkerForApplicationDexFile(File foreignDexProfileDir, File appDir)
88       throws Exception {
89     // Copy the -ex jar to the application directory and load it from there.
90     // This will record duplicate class conflicts but we don't care for this use case.
91     File foreignDex = new File(System.getenv("DEX_LOCATION") + "/577-profile-foreign-dex-ex.jar");
92     File appDex = new File(appDir, "appDex.jar");
93     try {
94       copyFile(foreignDex, appDex);
95 
96       loadDexFile(appDex.getAbsolutePath());
97       checkMarker(foreignDexProfileDir, appDex.getAbsolutePath(), /* exists */ false);
98     } finally {
99       if (appDex != null) {
100         appDex.delete();
101       }
102     }
103   }
104 
checkMarker(File foreignDexProfileDir, String dexFile, boolean exists)105   private static void checkMarker(File foreignDexProfileDir, String dexFile, boolean exists) {
106     File marker = new File(foreignDexProfileDir, dexFile.replace('/', '@'));
107     boolean result_ok = exists ? marker.exists() : !marker.exists();
108     if (!result_ok) {
109       throw new RuntimeException("Marker test failed for:" + marker.getPath());
110     }
111   }
112 
loadDexFile(String dexFile)113   private static void loadDexFile(String dexFile) throws Exception {
114     Class pathClassLoader = Class.forName("dalvik.system.PathClassLoader");
115     if (pathClassLoader == null) {
116         throw new RuntimeException("Couldn't find path class loader class");
117     }
118     Constructor constructor =
119         pathClassLoader.getDeclaredConstructor(String.class, ClassLoader.class);
120     constructor.newInstance(
121             dexFile, ClassLoader.getSystemClassLoader());
122   }
123 
124   private static class VMRuntime {
125     private static final Method registerAppInfoMethod;
126     static {
127       try {
128         Class c = Class.forName("dalvik.system.VMRuntime");
129         registerAppInfoMethod = c.getDeclaredMethod("registerAppInfo",
130             String.class, String.class, String[].class, String.class);
131       } catch (Exception e) {
132         throw new RuntimeException(e);
133       }
134     }
135 
registerAppInfo(String pkgName, String appDir, String[] codePath, String foreignDexProfileDir)136     public static void registerAppInfo(String pkgName, String appDir,
137         String[] codePath, String foreignDexProfileDir) throws Exception {
138       registerAppInfoMethod.invoke(null, pkgName, appDir, codePath, foreignDexProfileDir);
139     }
140   }
141 
copyFile(File fromFile, File toFile)142   private static void copyFile(File fromFile, File toFile) throws Exception {
143     FileInputStream in = new FileInputStream(fromFile);
144     FileOutputStream out = new FileOutputStream(toFile);
145     try {
146       byte[] buffer = new byte[4096];
147       int bytesRead;
148       while ((bytesRead = in.read(buffer)) >= 0) {
149           out.write(buffer, 0, bytesRead);
150       }
151     } finally {
152       out.flush();
153       try {
154           out.getFD().sync();
155       } catch (IOException e) {
156       }
157       out.close();
158       in.close();
159     }
160   }
161 
createTempFile()162   private static File createTempFile() throws Exception {
163     try {
164       return File.createTempFile(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX);
165     } catch (IOException e) {
166       System.setProperty("java.io.tmpdir", "/data/local/tmp");
167       try {
168         return File.createTempFile(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX);
169       } catch (IOException e2) {
170         System.setProperty("java.io.tmpdir", "/sdcard");
171         return File.createTempFile(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX);
172       }
173     }
174   }
175 }
176