1*795d594fSAndroid Build Coastguard Worker /* 2*795d594fSAndroid Build Coastguard Worker * Copyright (C) 2009 The Android Open Source Project 3*795d594fSAndroid Build Coastguard Worker * 4*795d594fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 5*795d594fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 6*795d594fSAndroid Build Coastguard Worker * You may obtain a copy of the License at 7*795d594fSAndroid Build Coastguard Worker * 8*795d594fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 9*795d594fSAndroid Build Coastguard Worker * 10*795d594fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 11*795d594fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 12*795d594fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*795d594fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 14*795d594fSAndroid Build Coastguard Worker * limitations under the License. 15*795d594fSAndroid Build Coastguard Worker */ 16*795d594fSAndroid Build Coastguard Worker 17*795d594fSAndroid Build Coastguard Worker import java.io.File; 18*795d594fSAndroid Build Coastguard Worker import java.lang.ref.WeakReference; 19*795d594fSAndroid Build Coastguard Worker import java.lang.reflect.Constructor; 20*795d594fSAndroid Build Coastguard Worker import java.lang.reflect.Method; 21*795d594fSAndroid Build Coastguard Worker import java.lang.reflect.InvocationTargetException; 22*795d594fSAndroid Build Coastguard Worker 23*795d594fSAndroid Build Coastguard Worker public class Main { 24*795d594fSAndroid Build Coastguard Worker private static final int TEST_LENGTH = 100; 25*795d594fSAndroid Build Coastguard Worker makeArray(int i)26*795d594fSAndroid Build Coastguard Worker private static boolean makeArray(int i) { 27*795d594fSAndroid Build Coastguard Worker return i % 10 == 0; 28*795d594fSAndroid Build Coastguard Worker } 29*795d594fSAndroid Build Coastguard Worker fillArray(Object global[], Object local[], int i)30*795d594fSAndroid Build Coastguard Worker private static void fillArray(Object global[], Object local[], int i) { 31*795d594fSAndroid Build Coastguard Worker // Very stupid linking. 32*795d594fSAndroid Build Coastguard Worker local[0] = global; 33*795d594fSAndroid Build Coastguard Worker for (int j = 1; j < local.length; j++) { 34*795d594fSAndroid Build Coastguard Worker local[j] = global[j]; 35*795d594fSAndroid Build Coastguard Worker } 36*795d594fSAndroid Build Coastguard Worker } 37*795d594fSAndroid Build Coastguard Worker allocInDifferentLoader()38*795d594fSAndroid Build Coastguard Worker private static Object allocInDifferentLoader() throws Exception { 39*795d594fSAndroid Build Coastguard Worker final String DEX_FILE = System.getenv("DEX_LOCATION") + "/130-hprof-ex.jar"; 40*795d594fSAndroid Build Coastguard Worker Class<?> pathClassLoader = Class.forName("dalvik.system.PathClassLoader"); 41*795d594fSAndroid Build Coastguard Worker if (pathClassLoader == null) { 42*795d594fSAndroid Build Coastguard Worker throw new AssertionError("Couldn't find path class loader class"); 43*795d594fSAndroid Build Coastguard Worker } 44*795d594fSAndroid Build Coastguard Worker Constructor<?> constructor = 45*795d594fSAndroid Build Coastguard Worker pathClassLoader.getDeclaredConstructor(String.class, ClassLoader.class); 46*795d594fSAndroid Build Coastguard Worker ClassLoader loader = (ClassLoader)constructor.newInstance( 47*795d594fSAndroid Build Coastguard Worker DEX_FILE, ClassLoader.getSystemClassLoader()); 48*795d594fSAndroid Build Coastguard Worker Class<?> allocator = loader.loadClass("Allocator"); 49*795d594fSAndroid Build Coastguard Worker return allocator.getDeclaredMethod("allocObject", null).invoke(null); 50*795d594fSAndroid Build Coastguard Worker } 51*795d594fSAndroid Build Coastguard Worker createDumpAndConv()52*795d594fSAndroid Build Coastguard Worker private static void createDumpAndConv() throws RuntimeException { 53*795d594fSAndroid Build Coastguard Worker File dumpFile = null; 54*795d594fSAndroid Build Coastguard Worker File convFile = null; 55*795d594fSAndroid Build Coastguard Worker 56*795d594fSAndroid Build Coastguard Worker try { 57*795d594fSAndroid Build Coastguard Worker // Now dump the heap. 58*795d594fSAndroid Build Coastguard Worker dumpFile = createDump(); 59*795d594fSAndroid Build Coastguard Worker 60*795d594fSAndroid Build Coastguard Worker // Run hprof-conv on it. 61*795d594fSAndroid Build Coastguard Worker convFile = getConvFile(); 62*795d594fSAndroid Build Coastguard Worker 63*795d594fSAndroid Build Coastguard Worker File hprof_conv = getHprofConf(); 64*795d594fSAndroid Build Coastguard Worker try { 65*795d594fSAndroid Build Coastguard Worker ProcessBuilder pb = new ProcessBuilder( 66*795d594fSAndroid Build Coastguard Worker hprof_conv.getAbsoluteFile().toString(), 67*795d594fSAndroid Build Coastguard Worker dumpFile.getAbsoluteFile().toString(), 68*795d594fSAndroid Build Coastguard Worker convFile.getAbsoluteFile().toString()); 69*795d594fSAndroid Build Coastguard Worker pb.redirectErrorStream(true); 70*795d594fSAndroid Build Coastguard Worker Process process = pb.start(); 71*795d594fSAndroid Build Coastguard Worker int ret = process.waitFor(); 72*795d594fSAndroid Build Coastguard Worker if (ret != 0) { 73*795d594fSAndroid Build Coastguard Worker throw new RuntimeException("Exited abnormally with " + ret); 74*795d594fSAndroid Build Coastguard Worker } 75*795d594fSAndroid Build Coastguard Worker } catch (Exception exc) { 76*795d594fSAndroid Build Coastguard Worker throw new RuntimeException(exc); 77*795d594fSAndroid Build Coastguard Worker } 78*795d594fSAndroid Build Coastguard Worker } finally { 79*795d594fSAndroid Build Coastguard Worker // Delete the files. 80*795d594fSAndroid Build Coastguard Worker if (dumpFile != null) { 81*795d594fSAndroid Build Coastguard Worker dumpFile.delete(); 82*795d594fSAndroid Build Coastguard Worker } 83*795d594fSAndroid Build Coastguard Worker if (convFile != null) { 84*795d594fSAndroid Build Coastguard Worker convFile.delete(); 85*795d594fSAndroid Build Coastguard Worker } 86*795d594fSAndroid Build Coastguard Worker } 87*795d594fSAndroid Build Coastguard Worker } 88*795d594fSAndroid Build Coastguard Worker main(String[] args)89*795d594fSAndroid Build Coastguard Worker public static void main(String[] args) throws Exception { 90*795d594fSAndroid Build Coastguard Worker testBasicDump(); 91*795d594fSAndroid Build Coastguard Worker testAllocationTrackingAndClassUnloading(); 92*795d594fSAndroid Build Coastguard Worker testGcAndDump(); 93*795d594fSAndroid Build Coastguard Worker } 94*795d594fSAndroid Build Coastguard Worker testBasicDump()95*795d594fSAndroid Build Coastguard Worker private static void testBasicDump() throws Exception { 96*795d594fSAndroid Build Coastguard Worker // Create some data. 97*795d594fSAndroid Build Coastguard Worker Object data[] = new Object[TEST_LENGTH]; 98*795d594fSAndroid Build Coastguard Worker for (int i = 0; i < data.length; i++) { 99*795d594fSAndroid Build Coastguard Worker if (makeArray(i)) { 100*795d594fSAndroid Build Coastguard Worker data[i] = new Object[TEST_LENGTH]; 101*795d594fSAndroid Build Coastguard Worker } else { 102*795d594fSAndroid Build Coastguard Worker data[i] = String.valueOf(i); 103*795d594fSAndroid Build Coastguard Worker } 104*795d594fSAndroid Build Coastguard Worker } 105*795d594fSAndroid Build Coastguard Worker for (int i = 0; i < data.length; i++) { 106*795d594fSAndroid Build Coastguard Worker if (makeArray(i)) { 107*795d594fSAndroid Build Coastguard Worker Object data2[] = (Object[]) data[i]; 108*795d594fSAndroid Build Coastguard Worker fillArray(data, data2, i); 109*795d594fSAndroid Build Coastguard Worker } 110*795d594fSAndroid Build Coastguard Worker } 111*795d594fSAndroid Build Coastguard Worker System.out.println("Generated data."); 112*795d594fSAndroid Build Coastguard Worker createDumpAndConv(); 113*795d594fSAndroid Build Coastguard Worker } 114*795d594fSAndroid Build Coastguard Worker testAllocationTrackingAndClassUnloading()115*795d594fSAndroid Build Coastguard Worker private static void testAllocationTrackingAndClassUnloading() throws Exception { 116*795d594fSAndroid Build Coastguard Worker Class<?> klass = Class.forName("org.apache.harmony.dalvik.ddmc.DdmVmInternal"); 117*795d594fSAndroid Build Coastguard Worker if (klass == null) { 118*795d594fSAndroid Build Coastguard Worker throw new AssertionError("Couldn't find path class loader class"); 119*795d594fSAndroid Build Coastguard Worker } 120*795d594fSAndroid Build Coastguard Worker Method enableMethod = klass.getDeclaredMethod("setRecentAllocationsTrackingEnabled", 121*795d594fSAndroid Build Coastguard Worker boolean.class); 122*795d594fSAndroid Build Coastguard Worker if (enableMethod == null) { 123*795d594fSAndroid Build Coastguard Worker throw new AssertionError("Couldn't find setRecentAllocationsTrackingEnabled method"); 124*795d594fSAndroid Build Coastguard Worker } 125*795d594fSAndroid Build Coastguard Worker enableMethod.invoke(null, true); 126*795d594fSAndroid Build Coastguard Worker Object o = allocInDifferentLoader(); 127*795d594fSAndroid Build Coastguard Worker // Run GC to cause class unloading. 128*795d594fSAndroid Build Coastguard Worker Runtime.getRuntime().gc(); 129*795d594fSAndroid Build Coastguard Worker createDumpAndConv(); 130*795d594fSAndroid Build Coastguard Worker // TODO: Somehow check contents of hprof file. 131*795d594fSAndroid Build Coastguard Worker enableMethod.invoke(null, false); 132*795d594fSAndroid Build Coastguard Worker } 133*795d594fSAndroid Build Coastguard Worker testGcAndDump()134*795d594fSAndroid Build Coastguard Worker private static void testGcAndDump() throws Exception { 135*795d594fSAndroid Build Coastguard Worker Allocator allocator = new Allocator(); 136*795d594fSAndroid Build Coastguard Worker Dumper dumper = new Dumper(allocator); 137*795d594fSAndroid Build Coastguard Worker allocator.start(); 138*795d594fSAndroid Build Coastguard Worker dumper.start(); 139*795d594fSAndroid Build Coastguard Worker try { 140*795d594fSAndroid Build Coastguard Worker allocator.join(); 141*795d594fSAndroid Build Coastguard Worker dumper.join(); 142*795d594fSAndroid Build Coastguard Worker } catch (InterruptedException e) { 143*795d594fSAndroid Build Coastguard Worker System.out.println("join interrupted"); 144*795d594fSAndroid Build Coastguard Worker } 145*795d594fSAndroid Build Coastguard Worker } 146*795d594fSAndroid Build Coastguard Worker 147*795d594fSAndroid Build Coastguard Worker private static class Allocator extends Thread { 148*795d594fSAndroid Build Coastguard Worker private static int ARRAY_SIZE = 1024; 149*795d594fSAndroid Build Coastguard Worker public volatile boolean running = true; run()150*795d594fSAndroid Build Coastguard Worker public void run() { 151*795d594fSAndroid Build Coastguard Worker Object[] array = new Object[ARRAY_SIZE]; 152*795d594fSAndroid Build Coastguard Worker int i = 0; 153*795d594fSAndroid Build Coastguard Worker while (running) { 154*795d594fSAndroid Build Coastguard Worker array[i] = new byte[1024]; 155*795d594fSAndroid Build Coastguard Worker if (i % ARRAY_SIZE == 0) { 156*795d594fSAndroid Build Coastguard Worker Main.sleep(100L); 157*795d594fSAndroid Build Coastguard Worker } 158*795d594fSAndroid Build Coastguard Worker i = (i + 1) % ARRAY_SIZE; 159*795d594fSAndroid Build Coastguard Worker } 160*795d594fSAndroid Build Coastguard Worker } 161*795d594fSAndroid Build Coastguard Worker } 162*795d594fSAndroid Build Coastguard Worker 163*795d594fSAndroid Build Coastguard Worker private static class Dumper extends Thread { Dumper(Allocator allocator)164*795d594fSAndroid Build Coastguard Worker Dumper(Allocator allocator) { 165*795d594fSAndroid Build Coastguard Worker this.allocator = allocator; 166*795d594fSAndroid Build Coastguard Worker } 167*795d594fSAndroid Build Coastguard Worker Allocator allocator; run()168*795d594fSAndroid Build Coastguard Worker public void run() { 169*795d594fSAndroid Build Coastguard Worker for (int i = 0; i < 5; ++i) { 170*795d594fSAndroid Build Coastguard Worker Main.sleep(1000L); 171*795d594fSAndroid Build Coastguard Worker createDumpAndConv(); 172*795d594fSAndroid Build Coastguard Worker } 173*795d594fSAndroid Build Coastguard Worker allocator.running = false; 174*795d594fSAndroid Build Coastguard Worker } 175*795d594fSAndroid Build Coastguard Worker } 176*795d594fSAndroid Build Coastguard Worker sleep(long ms)177*795d594fSAndroid Build Coastguard Worker public static void sleep(long ms) { 178*795d594fSAndroid Build Coastguard Worker try { 179*795d594fSAndroid Build Coastguard Worker Thread.sleep(ms); 180*795d594fSAndroid Build Coastguard Worker } catch (InterruptedException e) { 181*795d594fSAndroid Build Coastguard Worker System.out.println("sleep interrupted"); 182*795d594fSAndroid Build Coastguard Worker } 183*795d594fSAndroid Build Coastguard Worker } 184*795d594fSAndroid Build Coastguard Worker getHprofConf()185*795d594fSAndroid Build Coastguard Worker private static File getHprofConf() { 186*795d594fSAndroid Build Coastguard Worker // Use the java.library.path. It points to the lib directory. 187*795d594fSAndroid Build Coastguard Worker File libDir = new File(System.getProperty("java.library.path").split(":")[0]); 188*795d594fSAndroid Build Coastguard Worker return new File(new File(libDir.getParentFile(), "bin"), "hprof-conv"); 189*795d594fSAndroid Build Coastguard Worker } 190*795d594fSAndroid Build Coastguard Worker createDump()191*795d594fSAndroid Build Coastguard Worker private static File createDump() { 192*795d594fSAndroid Build Coastguard Worker java.lang.reflect.Method dumpHprofDataMethod = getDumpHprofDataMethod(); 193*795d594fSAndroid Build Coastguard Worker if (dumpHprofDataMethod != null) { 194*795d594fSAndroid Build Coastguard Worker File f = getDumpFile(); 195*795d594fSAndroid Build Coastguard Worker try { 196*795d594fSAndroid Build Coastguard Worker dumpHprofDataMethod.invoke(null, f.getAbsoluteFile().toString()); 197*795d594fSAndroid Build Coastguard Worker return f; 198*795d594fSAndroid Build Coastguard Worker } catch (Exception exc) { 199*795d594fSAndroid Build Coastguard Worker exc.printStackTrace(System.out); 200*795d594fSAndroid Build Coastguard Worker } 201*795d594fSAndroid Build Coastguard Worker } else { 202*795d594fSAndroid Build Coastguard Worker System.out.println("Could not find dump method!"); 203*795d594fSAndroid Build Coastguard Worker } 204*795d594fSAndroid Build Coastguard Worker return null; 205*795d594fSAndroid Build Coastguard Worker } 206*795d594fSAndroid Build Coastguard Worker 207*795d594fSAndroid Build Coastguard Worker /** 208*795d594fSAndroid Build Coastguard Worker * Finds VMDebug.dumpHprofData() through reflection. In the reference 209*795d594fSAndroid Build Coastguard Worker * implementation this will not be available. 210*795d594fSAndroid Build Coastguard Worker * 211*795d594fSAndroid Build Coastguard Worker * @return the reflection object, or null if the method can't be found 212*795d594fSAndroid Build Coastguard Worker */ getDumpHprofDataMethod()213*795d594fSAndroid Build Coastguard Worker private static Method getDumpHprofDataMethod() { 214*795d594fSAndroid Build Coastguard Worker ClassLoader myLoader = Main.class.getClassLoader(); 215*795d594fSAndroid Build Coastguard Worker Class<?> vmdClass; 216*795d594fSAndroid Build Coastguard Worker try { 217*795d594fSAndroid Build Coastguard Worker vmdClass = myLoader.loadClass("dalvik.system.VMDebug"); 218*795d594fSAndroid Build Coastguard Worker } catch (ClassNotFoundException cnfe) { 219*795d594fSAndroid Build Coastguard Worker return null; 220*795d594fSAndroid Build Coastguard Worker } 221*795d594fSAndroid Build Coastguard Worker 222*795d594fSAndroid Build Coastguard Worker Method meth; 223*795d594fSAndroid Build Coastguard Worker try { 224*795d594fSAndroid Build Coastguard Worker meth = vmdClass.getMethod("dumpHprofData", String.class); 225*795d594fSAndroid Build Coastguard Worker } catch (NoSuchMethodException nsme) { 226*795d594fSAndroid Build Coastguard Worker System.out.println("Found VMDebug but not dumpHprofData method"); 227*795d594fSAndroid Build Coastguard Worker return null; 228*795d594fSAndroid Build Coastguard Worker } 229*795d594fSAndroid Build Coastguard Worker 230*795d594fSAndroid Build Coastguard Worker return meth; 231*795d594fSAndroid Build Coastguard Worker } 232*795d594fSAndroid Build Coastguard Worker getDumpFile()233*795d594fSAndroid Build Coastguard Worker private static File getDumpFile() { 234*795d594fSAndroid Build Coastguard Worker try { 235*795d594fSAndroid Build Coastguard Worker return File.createTempFile("test-130-hprof", "dump"); 236*795d594fSAndroid Build Coastguard Worker } catch (Exception exc) { 237*795d594fSAndroid Build Coastguard Worker return null; 238*795d594fSAndroid Build Coastguard Worker } 239*795d594fSAndroid Build Coastguard Worker } 240*795d594fSAndroid Build Coastguard Worker getConvFile()241*795d594fSAndroid Build Coastguard Worker private static File getConvFile() { 242*795d594fSAndroid Build Coastguard Worker try { 243*795d594fSAndroid Build Coastguard Worker return File.createTempFile("test-130-hprof", "conv"); 244*795d594fSAndroid Build Coastguard Worker } catch (Exception exc) { 245*795d594fSAndroid Build Coastguard Worker return null; 246*795d594fSAndroid Build Coastguard Worker } 247*795d594fSAndroid Build Coastguard Worker } 248*795d594fSAndroid Build Coastguard Worker } 249