1 /* 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 17 import java.io.File; 18 import java.lang.ref.WeakReference; 19 import java.lang.reflect.Constructor; 20 import java.lang.reflect.Method; 21 import java.lang.reflect.InvocationTargetException; 22 23 public class Main { 24 private static final int TEST_LENGTH = 100; 25 makeArray(int i)26 private static boolean makeArray(int i) { 27 return i % 10 == 0; 28 } 29 fillArray(Object global[], Object local[], int i)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 allocInDifferentLoader()38 private static Object allocInDifferentLoader() throws Exception { 39 final String DEX_FILE = System.getenv("DEX_LOCATION") + "/130-hprof-ex.jar"; 40 Class pathClassLoader = Class.forName("dalvik.system.PathClassLoader"); 41 if (pathClassLoader == null) { 42 throw new AssertionError("Couldn't find path class loader class"); 43 } 44 Constructor constructor = 45 pathClassLoader.getDeclaredConstructor(String.class, ClassLoader.class); 46 ClassLoader loader = (ClassLoader)constructor.newInstance( 47 DEX_FILE, ClassLoader.getSystemClassLoader()); 48 Class allocator = loader.loadClass("Allocator"); 49 return allocator.getDeclaredMethod("allocObject", null).invoke(null); 50 } 51 createDumpAndConv()52 private static void createDumpAndConv() throws RuntimeException { 53 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 main(String[] args)89 public static void main(String[] args) throws Exception { 90 // Create some data. 91 Object data[] = new Object[TEST_LENGTH]; 92 for (int i = 0; i < data.length; i++) { 93 if (makeArray(i)) { 94 data[i] = new Object[TEST_LENGTH]; 95 } else { 96 data[i] = String.valueOf(i); 97 } 98 } 99 for (int i = 0; i < data.length; i++) { 100 if (makeArray(i)) { 101 Object data2[] = (Object[]) data[i]; 102 fillArray(data, data2, i); 103 } 104 } 105 System.out.println("Generated data."); 106 107 createDumpAndConv(); 108 Class klass = Class.forName("org.apache.harmony.dalvik.ddmc.DdmVmInternal"); 109 if (klass == null) { 110 throw new AssertionError("Couldn't find path class loader class"); 111 } 112 Method enableMethod = klass.getDeclaredMethod("enableRecentAllocations", 113 Boolean.TYPE); 114 if (enableMethod == null) { 115 throw new AssertionError("Couldn't find path class loader class"); 116 } 117 enableMethod.invoke(null, true); 118 Object o = allocInDifferentLoader(); 119 // Run GC to cause class unloading. 120 Runtime.getRuntime().gc(); 121 createDumpAndConv(); 122 // TODO: Somehow check contents of hprof file. 123 enableMethod.invoke(null, false); 124 } 125 getHprofConf()126 private static File getHprofConf() { 127 // Use the java.library.path. It points to the lib directory. 128 File libDir = new File(System.getProperty("java.library.path")); 129 return new File(new File(libDir.getParentFile(), "bin"), "hprof-conv"); 130 } 131 createDump()132 private static File createDump() { 133 java.lang.reflect.Method dumpHprofDataMethod = getDumpHprofDataMethod(); 134 if (dumpHprofDataMethod != null) { 135 File f = getDumpFile(); 136 try { 137 dumpHprofDataMethod.invoke(null, f.getAbsoluteFile().toString()); 138 return f; 139 } catch (Exception exc) { 140 exc.printStackTrace(System.out); 141 } 142 } else { 143 System.out.println("Could not find dump method!"); 144 } 145 return null; 146 } 147 148 /** 149 * Finds VMDebug.dumpHprofData() through reflection. In the reference 150 * implementation this will not be available. 151 * 152 * @return the reflection object, or null if the method can't be found 153 */ getDumpHprofDataMethod()154 private static Method getDumpHprofDataMethod() { 155 ClassLoader myLoader = Main.class.getClassLoader(); 156 Class vmdClass; 157 try { 158 vmdClass = myLoader.loadClass("dalvik.system.VMDebug"); 159 } catch (ClassNotFoundException cnfe) { 160 return null; 161 } 162 163 Method meth; 164 try { 165 meth = vmdClass.getMethod("dumpHprofData", 166 new Class[] { String.class }); 167 } catch (NoSuchMethodException nsme) { 168 System.err.println("Found VMDebug but not dumpHprofData method"); 169 return null; 170 } 171 172 return meth; 173 } 174 getDumpFile()175 private static File getDumpFile() { 176 try { 177 return File.createTempFile("test-130-hprof", "dump"); 178 } catch (Exception exc) { 179 return null; 180 } 181 } 182 getConvFile()183 private static File getConvFile() { 184 try { 185 return File.createTempFile("test-130-hprof", "conv"); 186 } catch (Exception exc) { 187 return null; 188 } 189 } 190 } 191