Merge "dalvik: Accept custom --vm to a degree" am: 9809f45fa7
am: 003056143e

Change-Id: I77c7b3496a94460d7bb1ee621e0411df62a1d75b
diff --git a/caliper/src/main/java/com/google/caliper/platform/dalvik/DalvikPlatform.java b/caliper/src/main/java/com/google/caliper/platform/dalvik/DalvikPlatform.java
index 9a971d3..3f3e56c 100644
--- a/caliper/src/main/java/com/google/caliper/platform/dalvik/DalvikPlatform.java
+++ b/caliper/src/main/java/com/google/caliper/platform/dalvik/DalvikPlatform.java
@@ -23,6 +23,7 @@
 import com.google.common.base.Predicate;
 import com.google.common.base.Predicates;
 import com.google.common.collect.ImmutableSet;
+import com.google.common.base.Joiner;
 
 import java.io.File;
 import java.util.Collection;
@@ -36,18 +37,27 @@
  */
 public final class DalvikPlatform extends Platform {
 
+  // By default, use dalvikvm.
+  // However with --vm (by calling customVmHomeDir) we can change this.
+  private String vmExecutable = "dalvikvm";
+  private String vmAndroidRoot = System.getenv("ANDROID_ROOT");
+
   public DalvikPlatform() {
     super(Type.DALVIK);
+
+    if (vmAndroidRoot == null) {
+      // Shouldn't happen unless running it on the host and someone forgot to set it.
+      // On an actual device, ANDROID_ROOT is always set.
+      vmAndroidRoot = "/system";
+    }
   }
 
   @Override
   public File vmExecutable(File vmHome) {
-    // TODO(user): Allow the 32/64 version of dalvik to be selected rather than the default
-    // standard configurations of Android systems and windows.
     File bin = new File(vmHome, "bin");
     Preconditions.checkState(bin.exists() && bin.isDirectory(),
         "Could not find %s under android root %s", bin, vmHome);
-    String executableName = "dalvikvm";
+    String executableName = vmExecutable;
     File dalvikvm = new File(bin, executableName);
     if (!dalvikvm.exists() || dalvikvm.isDirectory()) {
       throw new IllegalStateException(
@@ -64,6 +74,11 @@
 
   @Override
   public ImmutableSet<String> workerProcessArgs() {
+    if (vmExecutable.equals("app_process")) {
+      // app_process expects a parent_dir argument before the main class name, e.g.
+      // app_process -cp /path/to/dex/file /system/bin foo.bar.Main
+      return ImmutableSet.of(vmAndroidRoot + "/bin");
+    }
     return ImmutableSet.of();
   }
 
@@ -90,9 +105,44 @@
 
   @Override
   public File customVmHomeDir(Map<String, String> vmGroupMap, String vmConfigName) {
-    // TODO(user): Should probably use this to support specifying dalvikvm32/dalvikvm64
-    // and maybe even app_process.
+    // Support a handful of specific commands:
+    switch (vmConfigName) {
+      case "app_process":   // run with Android framework code already initialized.
+      case "dalvikvm":      // same as not using --vm (selects 64-bit on 64-bit, 32-bit on 32-bit)
+      case "dalvikvm32":    // 32-bit specific dalvikvm (e.g. if running on 64-bit device)
+      case "dalvikvm64":    // 64-bit specific dalvikvm (which is already default on 64-bit)
+      case "art":           // similar to dalvikvm but goes through a script with better settings.
+      {
+        // Usually passed as vmHome to vmExecutable, but we don't get that passed here.
+        String vmHome = vmAndroidRoot;
+
+        // Do not return the binary here. We return the new vmHome used by #vmExecutable.
+        // Remember that the home directory was changed, and accordingly update the executable name.
+        vmExecutable = vmConfigName;
+
+        File androidRootFile = new File(vmHome);
+
+        if (!androidRootFile.exists()) {
+          throw new IllegalStateException(String.format("%s does not exist", androidRootFile));
+        } else if (!androidRootFile.isDirectory()) {
+          throw new IllegalStateException(String.format("%s is not a directory", androidRootFile));
+        }
+
+        return androidRootFile;
+      }
+    }
+
+    // Unknown vm, throw an exception.
+
+    Joiner.MapJoiner mapJoiner = Joiner.on(',').withKeyValueSeparator("=");
+    String mapString = (vmGroupMap == null) ? "<null>" : mapJoiner.join(vmGroupMap);
+
+    if (vmConfigName == null) {
+      vmConfigName = "<null>";
+    }
+
     throw new UnsupportedOperationException(
-            "Running with a custom Dalvik VM is not currently supported");
+            "Running with a custom Dalvik VM is not currently supported (group map = '" + mapString
+            + "', vmConfigName = '" + vmConfigName + "')");
   }
 }