blob: a8597f13915debc51fac98e68cc99be8d1d73c98 [file] [log] [blame]
Andreas Gampe3a913092015-01-10 00:26:17 -08001/*
2 * Copyright (C) 2009 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.lang.ref.WeakReference;
Mathieu Chartier8a7ef102016-02-22 16:56:54 -080019import java.lang.reflect.Constructor;
Andreas Gampe3a913092015-01-10 00:26:17 -080020import java.lang.reflect.Method;
21import java.lang.reflect.InvocationTargetException;
22
23public class Main {
24 private static final int TEST_LENGTH = 100;
25
26 private static boolean makeArray(int i) {
27 return i % 10 == 0;
28 }
29
30 private static void fillArray(Object global[], Object local[], int i) {
31 // Very stupid linking.
32 local[0] = global;
33 for (int j = 1; j < local.length; j++) {
34 local[j] = global[j];
35 }
36 }
37
Mathieu Chartier8a7ef102016-02-22 16:56:54 -080038 private static Object allocInDifferentLoader() throws Exception {
39 final String DEX_FILE = System.getenv("DEX_LOCATION") + "/130-hprof-ex.jar";
Andreas Gampe166aaee2016-07-18 08:27:23 -070040 Class<?> pathClassLoader = Class.forName("dalvik.system.PathClassLoader");
Mathieu Chartier8a7ef102016-02-22 16:56:54 -080041 if (pathClassLoader == null) {
42 throw new AssertionError("Couldn't find path class loader class");
Andreas Gampe3a913092015-01-10 00:26:17 -080043 }
Andreas Gampe166aaee2016-07-18 08:27:23 -070044 Constructor<?> constructor =
Mathieu Chartier8a7ef102016-02-22 16:56:54 -080045 pathClassLoader.getDeclaredConstructor(String.class, ClassLoader.class);
46 ClassLoader loader = (ClassLoader)constructor.newInstance(
47 DEX_FILE, ClassLoader.getSystemClassLoader());
Andreas Gampe166aaee2016-07-18 08:27:23 -070048 Class<?> allocator = loader.loadClass("Allocator");
Mathieu Chartier8a7ef102016-02-22 16:56:54 -080049 return allocator.getDeclaredMethod("allocObject", null).invoke(null);
50 }
Andreas Gampe3a913092015-01-10 00:26:17 -080051
Mathieu Chartier8a7ef102016-02-22 16:56:54 -080052 private static void createDumpAndConv() throws RuntimeException {
Andreas Gampe3a913092015-01-10 00:26:17 -080053 File dumpFile = null;
54 File convFile = null;
55
56 try {
57 // Now dump the heap.
58 dumpFile = createDump();
59
60 // Run hprof-conv on it.
61 convFile = getConvFile();
62
63 File hprof_conv = getHprofConf();
64 try {
65 ProcessBuilder pb = new ProcessBuilder(
66 hprof_conv.getAbsoluteFile().toString(),
67 dumpFile.getAbsoluteFile().toString(),
68 convFile.getAbsoluteFile().toString());
69 pb.redirectErrorStream(true);
70 Process process = pb.start();
71 int ret = process.waitFor();
72 if (ret != 0) {
73 throw new RuntimeException("Exited abnormally with " + ret);
74 }
75 } catch (Exception exc) {
76 throw new RuntimeException(exc);
77 }
78 } finally {
79 // Delete the files.
80 if (dumpFile != null) {
81 dumpFile.delete();
82 }
83 if (convFile != null) {
84 convFile.delete();
85 }
86 }
87 }
88
Mathieu Chartier8a7ef102016-02-22 16:56:54 -080089 public static void main(String[] args) throws Exception {
Hiroshi Yamauchia34efac2016-10-13 15:14:45 -070090 testBasicDump();
91 testAllocationTrackingAndClassUnloading();
92 testGcAndDump();
93 }
94
95 private static void testBasicDump() throws Exception {
Mathieu Chartier8a7ef102016-02-22 16:56:54 -080096 // Create some data.
97 Object data[] = new Object[TEST_LENGTH];
98 for (int i = 0; i < data.length; i++) {
99 if (makeArray(i)) {
100 data[i] = new Object[TEST_LENGTH];
101 } else {
102 data[i] = String.valueOf(i);
103 }
104 }
105 for (int i = 0; i < data.length; i++) {
106 if (makeArray(i)) {
107 Object data2[] = (Object[]) data[i];
108 fillArray(data, data2, i);
109 }
110 }
111 System.out.println("Generated data.");
Mathieu Chartier8a7ef102016-02-22 16:56:54 -0800112 createDumpAndConv();
Hiroshi Yamauchia34efac2016-10-13 15:14:45 -0700113 }
114
115 private static void testAllocationTrackingAndClassUnloading() throws Exception {
Andreas Gampe166aaee2016-07-18 08:27:23 -0700116 Class<?> klass = Class.forName("org.apache.harmony.dalvik.ddmc.DdmVmInternal");
Mathieu Chartier8a7ef102016-02-22 16:56:54 -0800117 if (klass == null) {
118 throw new AssertionError("Couldn't find path class loader class");
119 }
120 Method enableMethod = klass.getDeclaredMethod("enableRecentAllocations",
121 Boolean.TYPE);
122 if (enableMethod == null) {
123 throw new AssertionError("Couldn't find path class loader class");
124 }
125 enableMethod.invoke(null, true);
126 Object o = allocInDifferentLoader();
127 // Run GC to cause class unloading.
128 Runtime.getRuntime().gc();
129 createDumpAndConv();
130 // TODO: Somehow check contents of hprof file.
131 enableMethod.invoke(null, false);
132 }
133
Hiroshi Yamauchia34efac2016-10-13 15:14:45 -0700134 private static void testGcAndDump() throws Exception {
135 Allocator allocator = new Allocator();
136 Dumper dumper = new Dumper(allocator);
137 allocator.start();
138 dumper.start();
139 try {
140 allocator.join();
141 dumper.join();
142 } catch (InterruptedException e) {
Kevin Brodskyf6c66c32015-12-17 14:13:00 +0000143 System.out.println("join interrupted");
Hiroshi Yamauchia34efac2016-10-13 15:14:45 -0700144 }
145 }
146
147 private static class Allocator extends Thread {
148 private static int ARRAY_SIZE = 1024;
149 public volatile boolean running = true;
150 public void run() {
151 Object[] array = new Object[ARRAY_SIZE];
152 int i = 0;
153 while (running) {
154 array[i] = new byte[1024];
155 if (i % ARRAY_SIZE == 0) {
156 Main.sleep(100L);
157 }
158 i = (i + 1) % ARRAY_SIZE;
159 }
160 }
161 }
162
163 private static class Dumper extends Thread {
164 Dumper(Allocator allocator) {
165 this.allocator = allocator;
166 }
167 Allocator allocator;
168 public void run() {
Hiroshi Yamauchif8f830c2016-10-21 13:07:18 -0700169 for (int i = 0; i < 5; ++i) {
Hiroshi Yamauchia34efac2016-10-13 15:14:45 -0700170 Main.sleep(1000L);
171 createDumpAndConv();
172 }
173 allocator.running = false;
174 }
175 }
176
177 public static void sleep(long ms) {
178 try {
179 Thread.sleep(ms);
180 } catch (InterruptedException e) {
Kevin Brodskyf6c66c32015-12-17 14:13:00 +0000181 System.out.println("sleep interrupted");
Hiroshi Yamauchia34efac2016-10-13 15:14:45 -0700182 }
183 }
184
Andreas Gampe3a913092015-01-10 00:26:17 -0800185 private static File getHprofConf() {
186 // Use the java.library.path. It points to the lib directory.
Colin Crossafd3c9e2016-09-16 13:47:21 -0700187 File libDir = new File(System.getProperty("java.library.path").split(":")[0]);
Andreas Gampe3a913092015-01-10 00:26:17 -0800188 return new File(new File(libDir.getParentFile(), "bin"), "hprof-conv");
189 }
190
191 private static File createDump() {
192 java.lang.reflect.Method dumpHprofDataMethod = getDumpHprofDataMethod();
193 if (dumpHprofDataMethod != null) {
194 File f = getDumpFile();
195 try {
196 dumpHprofDataMethod.invoke(null, f.getAbsoluteFile().toString());
197 return f;
198 } catch (Exception exc) {
199 exc.printStackTrace(System.out);
200 }
201 } else {
202 System.out.println("Could not find dump method!");
203 }
204 return null;
205 }
206
207 /**
208 * Finds VMDebug.dumpHprofData() through reflection. In the reference
209 * implementation this will not be available.
210 *
211 * @return the reflection object, or null if the method can't be found
212 */
213 private static Method getDumpHprofDataMethod() {
214 ClassLoader myLoader = Main.class.getClassLoader();
Andreas Gampe166aaee2016-07-18 08:27:23 -0700215 Class<?> vmdClass;
Andreas Gampe3a913092015-01-10 00:26:17 -0800216 try {
217 vmdClass = myLoader.loadClass("dalvik.system.VMDebug");
218 } catch (ClassNotFoundException cnfe) {
219 return null;
220 }
221
222 Method meth;
223 try {
Andreas Gampe166aaee2016-07-18 08:27:23 -0700224 meth = vmdClass.getMethod("dumpHprofData", String.class);
Andreas Gampe3a913092015-01-10 00:26:17 -0800225 } catch (NoSuchMethodException nsme) {
Kevin Brodskyf6c66c32015-12-17 14:13:00 +0000226 System.out.println("Found VMDebug but not dumpHprofData method");
Andreas Gampe3a913092015-01-10 00:26:17 -0800227 return null;
228 }
229
230 return meth;
231 }
232
233 private static File getDumpFile() {
234 try {
235 return File.createTempFile("test-130-hprof", "dump");
236 } catch (Exception exc) {
237 return null;
238 }
239 }
240
241 private static File getConvFile() {
242 try {
243 return File.createTempFile("test-130-hprof", "conv");
244 } catch (Exception exc) {
245 return null;
246 }
247 }
248}