content: /*
   * Copyright (C) 2009 The Android Open Source Project
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  import java.io.File;
  import java.lang.ref.WeakReference;
  import java.lang.reflect.Constructor;
  import java.lang.reflect.Method;
  import java.lang.reflect.InvocationTargetException;
  
  public class Main {
      private static final int TEST_LENGTH = 100;
  
      private static boolean makeArray(int i) {
          return i % 10 == 0;
      }
  
      private static void fillArray(Object global[], Object local[], int i) {
          // Very stupid linking.
          local[0] = global;
          for (int j = 1; j < local.length; j++) {
              local[j] = global[j];
          }
      }
  
      private static Object allocInDifferentLoader() throws Exception {
          final String DEX_FILE = System.getenv("DEX_LOCATION") + "/130-hprof-ex.jar";
          Class pathClassLoader = Class.forName("dalvik.system.PathClassLoader");
          if (pathClassLoader == null) {
              throw new AssertionError("Couldn't find path class loader class");
          }
          Constructor constructor =
              pathClassLoader.getDeclaredConstructor(String.class, ClassLoader.class);
          ClassLoader loader = (ClassLoader)constructor.newInstance(
                  DEX_FILE, ClassLoader.getSystemClassLoader());
          Class allocator = loader.loadClass("Allocator");
          return allocator.getDeclaredMethod("allocObject", null).invoke(null);
      }
  
      private static void createDumpAndConv() throws RuntimeException {
          File dumpFile = null;
          File convFile = null;
  
          try {
              // Now dump the heap.
              dumpFile = createDump();
  
              // Run hprof-conv on it.
              convFile = getConvFile();
  
              File hprof_conv = getHprofConf();
              try {
                  ProcessBuilder pb = new ProcessBuilder(
                          hprof_conv.getAbsoluteFile().toString(),
                          dumpFile.getAbsoluteFile().toString(),
                          convFile.getAbsoluteFile().toString());
                  pb.redirectErrorStream(true);
                  Process process = pb.start();
                  int ret = process.waitFor();
                  if (ret != 0) {
                      throw new RuntimeException("Exited abnormally with " + ret);
                  }
              } catch (Exception exc) {
                  throw new RuntimeException(exc);
              }
          } finally {
              // Delete the files.
              if (dumpFile != null) {
                  dumpFile.delete();
              }
              if (convFile != null) {
                  convFile.delete();
              }
          }
      }
  
      public static void main(String[] args) throws Exception {
          // Create some data.
          Object data[] = new Object[TEST_LENGTH];
          for (int i = 0; i < data.length; i++) {
              if (makeArray(i)) {
                  data[i] = new Object[TEST_LENGTH];
              } else {
                  data[i] = String.valueOf(i);
              }
          }
          for (int i = 0; i < data.length; i++) {
              if (makeArray(i)) {
                  Object data2[] = (Object[]) data[i];
                  fillArray(data, data2, i);
              }
          }
          System.out.println("Generated data.");
  
          createDumpAndConv();
          Class klass = Class.forName("org.apache.harmony.dalvik.ddmc.DdmVmInternal");
          if (klass == null) {
              throw new AssertionError("Couldn't find path class loader class");
          }
          Method enableMethod = klass.getDeclaredMethod("enableRecentAllocations",
                  Boolean.TYPE);
          if (enableMethod == null) {
              throw new AssertionError("Couldn't find path class loader class");
          }
          enableMethod.invoke(null, true);
          Object o = allocInDifferentLoader();
          // Run GC to cause class unloading.
          Runtime.getRuntime().gc();
          createDumpAndConv();
          // TODO: Somehow check contents of hprof file.
          enableMethod.invoke(null, false);
      }
  
      private static File getHprofConf() {
          // Use the java.library.path. It points to the lib directory.
          File libDir = new File(System.getProperty("java.library.path"));
          return new File(new File(libDir.getParentFile(), "bin"), "hprof-conv");
      }
  
      private static File createDump() {
          java.lang.reflect.Method dumpHprofDataMethod = getDumpHprofDataMethod();
          if (dumpHprofDataMethod != null) {
              File f = getDumpFile();
              try {
                  dumpHprofDataMethod.invoke(null, f.getAbsoluteFile().toString());
                  return f;
              } catch (Exception exc) {
                  exc.printStackTrace(System.out);
              }
          } else {
              System.out.println("Could not find dump method!");
          }
          return null;
      }
  
      /**
       * Finds VMDebug.dumpHprofData() through reflection.  In the reference
       * implementation this will not be available.
       *
       * @return the reflection object, or null if the method can't be found
       */
      private static Method getDumpHprofDataMethod() {
          ClassLoader myLoader = Main.class.getClassLoader();
          Class vmdClass;
          try {
              vmdClass = myLoader.loadClass("dalvik.system.VMDebug");
          } catch (ClassNotFoundException cnfe) {
              return null;
          }
  
          Method meth;
          try {
              meth = vmdClass.getMethod("dumpHprofData",
                      new Class[] { String.class });
          } catch (NoSuchMethodException nsme) {
              System.err.println("Found VMDebug but not dumpHprofData method");
              return null;
          }
  
          return meth;
      }
  
      private static File getDumpFile() {
          try {
              return File.createTempFile("test-130-hprof", "dump");
          } catch (Exception exc) {
              return null;
          }
      }
  
      private static File getConvFile() {
          try {
              return File.createTempFile("test-130-hprof", "conv");
          } catch (Exception exc) {
              return null;
          }
      }
  }
  