blob: ed7a625e750b0a304833b8c81e6e946e6def9a7c [file] [log] [blame]
Calin Juravlec90bc922016-02-24 10:13:09 +00001/*
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
17import java.io.File;
18import java.io.FileInputStream;
19import java.io.FileOutputStream;
20import java.io.IOException;
21import java.lang.reflect.Method;
22import java.lang.reflect.Constructor;
23import java.util.HashMap;
24
25public 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
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.
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.
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
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
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
113 private static void loadDexFile(String dexFile) throws Exception {
Andreas Gampe166aaee2016-07-18 08:27:23 -0700114 Class<?> pathClassLoader = Class.forName("dalvik.system.PathClassLoader");
Calin Juravlec90bc922016-02-24 10:13:09 +0000115 if (pathClassLoader == null) {
116 throw new RuntimeException("Couldn't find path class loader class");
117 }
Andreas Gampe166aaee2016-07-18 08:27:23 -0700118 Constructor<?> constructor =
Calin Juravlec90bc922016-02-24 10:13:09 +0000119 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 {
Andreas Gampe166aaee2016-07-18 08:27:23 -0700128 Class<?> c = Class.forName("dalvik.system.VMRuntime");
Calin Juravlec90bc922016-02-24 10:13:09 +0000129 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
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
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
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}