• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 Google Inc.
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 package com.google.caliper.platform.dalvik;
18 
19 import static com.google.common.base.Preconditions.checkState;
20 
21 import com.google.caliper.platform.Platform;
22 import com.google.common.base.Preconditions;
23 import com.google.common.base.Predicate;
24 import com.google.common.base.Predicates;
25 import com.google.common.collect.ImmutableList;
26 import com.google.common.collect.ImmutableSet;
27 import com.google.common.base.Joiner;
28 
29 import java.io.File;
30 import java.util.Collection;
31 import java.util.Collections;
32 import java.util.Map;
33 
34 /**
35  * An abstraction of the Dalvik (aka Android) platform.
36  *
37  * <p>Although this talks about dalvik it actually works with ART too.
38  */
39 public final class DalvikPlatform extends Platform {
40 
41   // By default, use dalvikvm.
42   // However with --vm (by calling customVmHomeDir) we can change this.
43   private String vmExecutable = "dalvikvm";
44   private String vmAndroidRoot = System.getenv("ANDROID_ROOT");
45 
DalvikPlatform()46   public DalvikPlatform() {
47     super(Type.DALVIK);
48 
49     if (vmAndroidRoot == null) {
50       // Shouldn't happen unless running it on the host and someone forgot to set it.
51       // On an actual device, ANDROID_ROOT is always set.
52       vmAndroidRoot = "/system";
53     }
54   }
55 
56   @Override
vmExecutable(File vmHome)57   public File vmExecutable(File vmHome) {
58     File bin = new File(vmHome, "bin");
59     Preconditions.checkState(bin.exists() && bin.isDirectory(),
60         "Could not find %s under android root %s", bin, vmHome);
61     String executableName = vmExecutable;
62     File dalvikvm = new File(bin, executableName);
63     if (!dalvikvm.exists() || dalvikvm.isDirectory()) {
64       throw new IllegalStateException(
65           String.format("Cannot find %s binary in %s", executableName, bin));
66     }
67 
68     return dalvikvm;
69   }
70 
71   @Override
commonInstrumentVmArgs()72   public ImmutableSet<String> commonInstrumentVmArgs() {
73     return ImmutableSet.of();
74   }
75 
76   @Override
workerProcessArgs()77   public ImmutableSet<String> workerProcessArgs() {
78     if (vmExecutable.equals("app_process")) {
79       // app_process expects a parent_dir argument before the main class name, e.g.
80       // app_process -cp /path/to/dex/file /system/bin foo.bar.Main
81       return ImmutableSet.of(vmAndroidRoot + "/bin");
82     }
83     return ImmutableSet.of();
84   }
85 
86   @Override
workerClassPath()87   protected String workerClassPath() {
88     // TODO(user): Find a way to get the class path programmatically from the class loader.
89     return System.getProperty("java.class.path");
90   }
91 
92   /**
93    * Construct the set of arguments that specify the classpath which
94    * is passed to the worker.
95    *
96    * <p>
97    * Use {@code -Djava.class.path=$classpath} for dalvik because it is supported
98    * by dalvikvm and also by app_process (which doesn't recognize "-cp args").
99    * </p>
100    */
101   @Override
workerClassPathArgs()102   public ImmutableList<String> workerClassPathArgs() {
103     String classPathArgs = String.format("-Djava.class.path=%s", workerClassPath());
104     return ImmutableList.of(classPathArgs);
105   }
106 
107   @Override
inputArguments()108   public Collection<String> inputArguments() {
109     return Collections.emptyList();
110   }
111 
112   @Override
vmPropertiesToRetain()113   public Predicate<String> vmPropertiesToRetain() {
114     return Predicates.alwaysFalse();
115   }
116 
117   @Override
checkVmProperties(Map<String, String> options)118   public void checkVmProperties(Map<String, String> options) {
119     checkState(options.isEmpty());
120   }
121 
122   @Override
customVmHomeDir(Map<String, String> vmGroupMap, String vmConfigName)123   public File customVmHomeDir(Map<String, String> vmGroupMap, String vmConfigName) {
124     // Support a handful of specific commands:
125     switch (vmConfigName) {
126       case "app_process":   // run with Android framework code already initialized.
127       case "dalvikvm":      // same as not using --vm (selects 64-bit on 64-bit, 32-bit on 32-bit)
128       case "dalvikvm32":    // 32-bit specific dalvikvm (e.g. if running on 64-bit device)
129       case "dalvikvm64":    // 64-bit specific dalvikvm (which is already default on 64-bit)
130       case "art":           // similar to dalvikvm but goes through a script with better settings.
131       {
132         // Usually passed as vmHome to vmExecutable, but we don't get that passed here.
133         String vmHome = vmAndroidRoot;
134 
135         // Do not return the binary here. We return the new vmHome used by #vmExecutable.
136         // Remember that the home directory was changed, and accordingly update the executable name.
137         vmExecutable = vmConfigName;
138 
139         File androidRootFile = new File(vmHome);
140 
141         if (!androidRootFile.exists()) {
142           throw new IllegalStateException(String.format("%s does not exist", androidRootFile));
143         } else if (!androidRootFile.isDirectory()) {
144           throw new IllegalStateException(String.format("%s is not a directory", androidRootFile));
145         }
146 
147         return androidRootFile;
148       }
149     }
150 
151     // Unknown vm, throw an exception.
152 
153     Joiner.MapJoiner mapJoiner = Joiner.on(',').withKeyValueSeparator("=");
154     String mapString = (vmGroupMap == null) ? "<null>" : mapJoiner.join(vmGroupMap);
155 
156     if (vmConfigName == null) {
157       vmConfigName = "<null>";
158     }
159 
160     throw new UnsupportedOperationException(
161             "Running with a custom Dalvik VM is not currently supported (group map = '" + mapString
162             + "', vmConfigName = '" + vmConfigName + "')");
163   }
164 }
165