1 /* 2 * Copyright (C) 2011 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 package vogar; 18 19 import com.google.common.base.Splitter; 20 21 import com.google.common.base.Supplier; 22 import java.io.File; 23 import java.io.IOException; 24 import java.net.URL; 25 import java.util.Collections; 26 import java.util.Date; 27 import java.util.HashSet; 28 import java.util.List; 29 import java.util.Set; 30 import java.util.UUID; 31 32 import vogar.android.ActivityMode; 33 import vogar.android.AndroidSdk; 34 import vogar.android.DeviceRuntime; 35 import vogar.android.HostRuntime; 36 import vogar.commands.Mkdir; 37 import vogar.commands.Rm; 38 import vogar.tasks.TaskQueue; 39 import vogar.util.Strings; 40 41 public final class Run { 42 /** 43 * A list of generic names that we avoid when naming generated files. 44 */ 45 private static final Set<String> BANNED_NAMES = new HashSet<String>(); 46 47 private static final String JAR_URI_PREFIX = "jar:file:"; 48 49 private static final String FILE_URL_PREFIX = "file:"; 50 51 private static final String VOGAR_CLASS_RESOURCE_PATH = "/vogar/Vogar.class"; 52 53 static { 54 BANNED_NAMES.add("classes"); 55 BANNED_NAMES.add("javalib"); 56 } 57 58 public final File xmlReportsDirectory; 59 public final File resultsDir; 60 public final boolean recordResults; 61 public final ExpectationStore expectationStore; 62 public final Date date; 63 public final String invokeWith; 64 public final File keystore; 65 public final Log log; 66 public final Classpath classpath; 67 public final Classpath buildClasspath; 68 public final Classpath resourceClasspath; 69 public final List<File> sourcepath; 70 public final Mkdir mkdir; 71 public final Rm rm; 72 public final int firstMonitorPort; 73 public final int timeoutSeconds; 74 public final File javaHome; 75 public final Integer debugPort; 76 public final Language language; 77 public final List<String> javacArgs; 78 public final boolean multidex; 79 public final boolean benchmark; 80 public final File runnerDir; 81 public final boolean cleanBefore; 82 public final boolean cleanAfter; 83 public final File localTemp; 84 public final int maxConcurrentActions; 85 public final File deviceUserHome; 86 public final Console console; 87 public final int smallTimeoutSeconds; 88 public final String vmCommand; 89 public final String dalvikCache; 90 public final List<String> additionalVmArgs; 91 public final List<String> targetArgs; 92 public final boolean useBootClasspath; 93 public final int largeTimeoutSeconds; 94 public final RetrievedFilesFilter retrievedFiles; 95 public final Driver driver; 96 public final Mode mode; 97 public final Target target; 98 public final AndroidSdk androidSdk; 99 public final XmlReportPrinter reportPrinter; 100 public final JarSuggestions jarSuggestions; 101 public final ClassFileIndex classFileIndex; 102 public final OutcomeStore outcomeStore; 103 public final TaskQueue taskQueue; 104 public final RunnerType runnerType; 105 public final Toolchain toolchain; 106 public final boolean checkJni; 107 public final boolean debugging; 108 public final Integer sdkVersion; 109 public final boolean serialDexing; 110 public final boolean verboseDexStats; 111 Run(Vogar vogar, Toolchain toolchain, Console console, Mkdir mkdir, AndroidSdk androidSdk, Rm rm, Target target, File runnerDir)112 public Run(Vogar vogar, Toolchain toolchain, Console console, Mkdir mkdir, 113 AndroidSdk androidSdk, Rm rm, Target target, File runnerDir) 114 throws IOException { 115 this.console = console; 116 117 this.localTemp = new File("/tmp/vogar/" + UUID.randomUUID()); 118 this.log = console; 119 120 this.target = target; 121 122 this.toolchain = toolchain; 123 this.vmCommand = vogar.vmCommand; 124 this.dalvikCache = vogar.dalvikCache; 125 this.additionalVmArgs = vogar.vmArgs; 126 this.benchmark = vogar.benchmark; 127 this.cleanBefore = vogar.cleanBefore; 128 this.cleanAfter = vogar.cleanAfter; 129 this.date = new Date(); 130 this.debugPort = vogar.debugPort; 131 this.runnerDir = runnerDir; 132 this.deviceUserHome = new File(runnerDir, "user.home"); 133 this.mkdir = mkdir; 134 this.rm = rm; 135 this.firstMonitorPort = vogar.firstMonitorPort; 136 this.invokeWith = vogar.invokeWith; 137 this.language = vogar.language; 138 this.javacArgs = vogar.javacArgs; 139 this.multidex = vogar.multidex; 140 this.javaHome = vogar.javaHome; 141 this.largeTimeoutSeconds = vogar.timeoutSeconds * Vogar.LARGE_TIMEOUT_MULTIPLIER; 142 this.maxConcurrentActions = (vogar.stream || vogar.modeId == ModeId.ACTIVITY) 143 ? 1 144 : Vogar.NUM_PROCESSORS; 145 this.timeoutSeconds = vogar.timeoutSeconds; 146 this.smallTimeoutSeconds = vogar.timeoutSeconds; 147 this.sourcepath = vogar.sourcepath; 148 this.resourceClasspath = Classpath.of(vogar.resourceClasspath); 149 this.useBootClasspath = vogar.useBootClasspath; 150 this.targetArgs = vogar.targetArgs; 151 this.xmlReportsDirectory = vogar.xmlReportsDirectory; 152 this.recordResults = vogar.recordResults; 153 this.resultsDir = vogar.resultsDir == null 154 ? new File(vogar.vogarDir, "results") 155 : vogar.resultsDir; 156 this.keystore = localFile("activity", "vogar.keystore"); 157 this.classpath = Classpath.of(vogar.classpath); 158 this.classpath.addAll(vogarJar()); 159 this.runnerType = vogar.runnerType; 160 161 this.androidSdk = androidSdk; 162 163 expectationStore = ExpectationStore.parse( 164 console, vogar.expectationFiles, vogar.modeId, vogar.variant); 165 if (vogar.openBugsCommand != null) { 166 expectationStore.loadBugStatuses(new CommandBugDatabase(log, vogar.openBugsCommand)); 167 } 168 169 this.mode = createMode(vogar.modeId, vogar.variant); 170 171 this.buildClasspath = Classpath.of(vogar.buildClasspath); 172 if (androidSdk != null) { 173 buildClasspath.addAll(androidSdk.getCompilationClasspath()); 174 } 175 176 this.classFileIndex = new ClassFileIndex(log, mkdir, vogar.jarSearchDirs); 177 if (vogar.suggestClasspaths) { 178 classFileIndex.createIndex(); 179 } 180 181 this.retrievedFiles = new RetrievedFilesFilter(); 182 this.reportPrinter = new XmlReportPrinter(xmlReportsDirectory, expectationStore, date); 183 this.jarSuggestions = new JarSuggestions(); 184 this.outcomeStore = new OutcomeStore(log, mkdir, rm, resultsDir, recordResults, 185 expectationStore, date); 186 this.driver = new Driver(this); 187 this.taskQueue = new TaskQueue(console, maxConcurrentActions); 188 this.checkJni = vogar.checkJni; 189 this.debugging = (vogar.debugPort != null) || vogar.debugApp; 190 this.sdkVersion = vogar.sdkVersion; 191 this.serialDexing = vogar.serialDexing; 192 this.verboseDexStats = vogar.verboseDexStats; 193 } 194 createMode(ModeId modeId, Variant variant)195 private Mode createMode(ModeId modeId, Variant variant) { 196 switch (modeId) { 197 case JVM: 198 return new JavaVm(this); 199 case HOST: 200 return new HostRuntime(this, modeId, variant); 201 case DEVICE: 202 case APP_PROCESS: 203 return new DeviceRuntime(this, modeId, variant, new Supplier<String>() { 204 @Override 205 public String get() { 206 return target.getDeviceUserName(); 207 } 208 }); 209 case ACTIVITY: 210 return new ActivityMode(this); 211 default: 212 throw new IllegalArgumentException("Unsupported mode: " + modeId); 213 } 214 } 215 216 public final File localFile(Object... path) { 217 return new File(localTemp + "/" + Strings.join("/", path)); 218 } 219 220 public final File localDir(Object... path) { 221 String joinedPath = localTemp + "/" + Strings.join("/", path); 222 File f = new File(joinedPath); 223 f.mkdirs(); 224 if (!f.exists()) { 225 throw new AssertionError("Failed to mkdirs: " + joinedPath); 226 } 227 return f; 228 } 229 230 private File vogarJar() { 231 URL jarUrl = Vogar.class.getResource(VOGAR_CLASS_RESOURCE_PATH); 232 if (jarUrl == null) { 233 // should we add an option for IDE users, to use a user-specified vogar.jar? 234 throw new IllegalStateException("Vogar cannot find its own .jar"); 235 } 236 237 /* 238 * Parse a URI like jar:file:/Users/jessewilson/vogar/vogar.jar!/vogar/Vogar.class 239 * to yield a .jar file like /Users/jessewilson/vogar/vogar.jar. 240 */ 241 String url = jarUrl.toString(); 242 int bang = url.indexOf("!"); 243 if (url.startsWith(JAR_URI_PREFIX) && bang != -1) { 244 return new File(url.substring(JAR_URI_PREFIX.length(), bang)); 245 } else if (url.startsWith(FILE_URL_PREFIX) && url.endsWith(VOGAR_CLASS_RESOURCE_PATH)) { 246 // Vogar is being run from a classes directory. 247 return new File(url.substring(FILE_URL_PREFIX.length(), 248 url.length() - VOGAR_CLASS_RESOURCE_PATH.length())); 249 } else { 250 throw new IllegalStateException("Vogar cannot find the .jar file in " + jarUrl); 251 } 252 } 253 254 public final File hostJar(Object nameOrAction) { 255 return localFile(nameOrAction, nameOrAction + ".jar"); 256 } 257 258 /** 259 * Returns a path for a Java tool such as java, javac, jar where 260 * the Java home is used if present, otherwise assumes it will 261 * come from the path. 262 */ 263 public String javaPath(String tool) { 264 return (javaHome == null) 265 ? tool 266 : new File(new File(javaHome, "bin"), tool).getPath(); 267 } 268 269 public File targetDexFile(String name) { 270 return new File(runnerDir, name + ".dex.jar"); 271 } 272 273 public File localDexFile(String name) { 274 return localFile(name, name + ".dex.jar"); 275 } 276 277 /** 278 * Returns a recognizable readable name for the given generated .jar file, 279 * appropriate for use in naming derived files. 280 * 281 * @param file a product of the android build system, such as 282 * "out/core-libart_intermediates/javalib.jar". 283 * @return a recognizable base name like "core-libart_intermediates". 284 */ 285 public String basenameOfJar(File file) { 286 String name = file.getName().replaceAll("(\\.jar)$", ""); 287 while (BANNED_NAMES.contains(name)) { 288 file = file.getParentFile(); 289 name = file.getName(); 290 } 291 return name; 292 } 293 294 public File vogarTemp() { 295 return new File(runnerDir, "tmp"); 296 } 297 298 public File dalvikCache() { 299 return new File(runnerDir.getParentFile(), dalvikCache); 300 } 301 302 /** 303 * Returns the directory where the VM stores its dexopt files. 304 */ 305 public String getAndroidDataPath() { 306 // The VM wants the parent directory of a directory named "dalvik-cache" 307 return dalvikCache().getParentFile().getPath(); 308 } 309 310 /** 311 * Returns a parsed list of the --invoke-with command and its 312 * arguments, or an empty list if no --invoke-with was provided. 313 */ 314 public Iterable<String> invokeWith() { 315 if (invokeWith == null) { 316 return Collections.emptyList(); 317 } 318 return Splitter.onPattern("\\s+").omitEmptyStrings().split(invokeWith); 319 } 320 } 321