| /* |
| * Copyright (C) 2011 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. |
| */ |
| |
| package vogar; |
| |
| import com.google.common.base.Splitter; |
| |
| import com.google.common.base.Supplier; |
| import java.io.File; |
| import java.io.IOException; |
| import java.net.URL; |
| import java.util.Collections; |
| import java.util.Date; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Set; |
| import java.util.UUID; |
| |
| import vogar.android.ActivityMode; |
| import vogar.android.AndroidSdk; |
| import vogar.android.DeviceRuntime; |
| import vogar.android.HostRuntime; |
| import vogar.commands.Mkdir; |
| import vogar.commands.Rm; |
| import vogar.tasks.TaskQueue; |
| import vogar.util.Strings; |
| |
| public final class Run { |
| /** |
| * A list of generic names that we avoid when naming generated files. |
| */ |
| private static final Set<String> BANNED_NAMES = new HashSet<String>(); |
| |
| private static final String JAR_URI_PREFIX = "jar:file:"; |
| |
| private static final String FILE_URL_PREFIX = "file:"; |
| |
| private static final String VOGAR_CLASS_RESOURCE_PATH = "/vogar/Vogar.class"; |
| |
| static { |
| BANNED_NAMES.add("classes"); |
| BANNED_NAMES.add("javalib"); |
| } |
| |
| public final File xmlReportsDirectory; |
| public final File resultsDir; |
| public final boolean recordResults; |
| public final ExpectationStore expectationStore; |
| public final Date date; |
| public final String invokeWith; |
| public final File keystore; |
| public final Log log; |
| public final Classpath classpath; |
| public final Classpath buildClasspath; |
| public final Classpath resourceClasspath; |
| public final List<File> sourcepath; |
| public final Mkdir mkdir; |
| public final Rm rm; |
| public final int firstMonitorPort; |
| public final int timeoutSeconds; |
| public final File javaHome; |
| public final Integer debugPort; |
| public final Language language; |
| public final List<String> javacArgs; |
| public final boolean multidex; |
| public final boolean benchmark; |
| public final File runnerDir; |
| public final boolean cleanBefore; |
| public final boolean cleanAfter; |
| public final File localTemp; |
| public final int maxConcurrentActions; |
| public final File deviceUserHome; |
| public final Console console; |
| public final int smallTimeoutSeconds; |
| public final String vmCommand; |
| public final String dalvikCache; |
| public final List<String> additionalVmArgs; |
| public final List<String> targetArgs; |
| public final boolean useBootClasspath; |
| public final int largeTimeoutSeconds; |
| public final RetrievedFilesFilter retrievedFiles; |
| public final Driver driver; |
| public final Mode mode; |
| public final Target target; |
| public final AndroidSdk androidSdk; |
| public final XmlReportPrinter reportPrinter; |
| public final JarSuggestions jarSuggestions; |
| public final ClassFileIndex classFileIndex; |
| public final OutcomeStore outcomeStore; |
| public final TaskQueue taskQueue; |
| public final RunnerType runnerType; |
| public final Toolchain toolchain; |
| public final boolean checkJni; |
| public final boolean debugging; |
| |
| public Run(Vogar vogar, Toolchain toolchain, Console console, Mkdir mkdir, AndroidSdk androidSdk, |
| Rm rm, Target target, File runnerDir) |
| throws IOException { |
| this.console = console; |
| |
| this.localTemp = new File("/tmp/vogar/" + UUID.randomUUID()); |
| this.log = console; |
| |
| this.target = target; |
| |
| this.toolchain = toolchain; |
| this.vmCommand = vogar.vmCommand; |
| this.dalvikCache = vogar.dalvikCache; |
| this.additionalVmArgs = vogar.vmArgs; |
| this.benchmark = vogar.benchmark; |
| this.cleanBefore = vogar.cleanBefore; |
| this.cleanAfter = vogar.cleanAfter; |
| this.date = new Date(); |
| this.debugPort = vogar.debugPort; |
| this.runnerDir = runnerDir; |
| this.deviceUserHome = new File(runnerDir, "user.home"); |
| this.mkdir = mkdir; |
| this.rm = rm; |
| this.firstMonitorPort = vogar.firstMonitorPort; |
| this.invokeWith = vogar.invokeWith; |
| this.language = vogar.language; |
| this.javacArgs = vogar.javacArgs; |
| this.multidex = vogar.multidex; |
| this.javaHome = vogar.javaHome; |
| this.largeTimeoutSeconds = vogar.timeoutSeconds * Vogar.LARGE_TIMEOUT_MULTIPLIER; |
| this.maxConcurrentActions = (vogar.stream || vogar.modeId == ModeId.ACTIVITY) |
| ? 1 |
| : Vogar.NUM_PROCESSORS; |
| this.timeoutSeconds = vogar.timeoutSeconds; |
| this.smallTimeoutSeconds = vogar.timeoutSeconds; |
| this.sourcepath = vogar.sourcepath; |
| this.resourceClasspath = Classpath.of(vogar.resourceClasspath); |
| this.useBootClasspath = vogar.useBootClasspath; |
| this.targetArgs = vogar.targetArgs; |
| this.xmlReportsDirectory = vogar.xmlReportsDirectory; |
| this.recordResults = vogar.recordResults; |
| this.resultsDir = vogar.resultsDir == null |
| ? new File(vogar.vogarDir, "results") |
| : vogar.resultsDir; |
| this.keystore = localFile("activity", "vogar.keystore"); |
| this.classpath = Classpath.of(vogar.classpath); |
| this.classpath.addAll(vogarJar()); |
| this.runnerType = vogar.runnerType; |
| |
| this.androidSdk = androidSdk; |
| |
| expectationStore = ExpectationStore.parse( |
| console, vogar.expectationFiles, vogar.modeId, vogar.variant); |
| if (vogar.openBugsCommand != null) { |
| expectationStore.loadBugStatuses(new CommandBugDatabase(log, vogar.openBugsCommand)); |
| } |
| |
| this.mode = createMode(vogar.modeId, vogar.variant); |
| |
| this.buildClasspath = Classpath.of(vogar.buildClasspath); |
| if (androidSdk != null) { |
| buildClasspath.addAll(androidSdk.getCompilationClasspath()); |
| } |
| |
| this.classFileIndex = new ClassFileIndex(log, mkdir, vogar.jarSearchDirs); |
| if (vogar.suggestClasspaths) { |
| classFileIndex.createIndex(); |
| } |
| |
| this.retrievedFiles = new RetrievedFilesFilter(); |
| this.reportPrinter = new XmlReportPrinter(xmlReportsDirectory, expectationStore, date); |
| this.jarSuggestions = new JarSuggestions(); |
| this.outcomeStore = new OutcomeStore(log, mkdir, rm, resultsDir, recordResults, |
| expectationStore, date); |
| this.driver = new Driver(this); |
| this.taskQueue = new TaskQueue(console, maxConcurrentActions); |
| this.checkJni = vogar.checkJni; |
| this.debugging = (vogar.debugPort != null) || vogar.debugApp; |
| } |
| |
| private Mode createMode(ModeId modeId, Variant variant) { |
| switch (modeId) { |
| case JVM: |
| return new JavaVm(this); |
| case HOST: |
| return new HostRuntime(this, modeId, variant); |
| case DEVICE: |
| case APP_PROCESS: |
| return new DeviceRuntime(this, modeId, variant, new Supplier<String>() { |
| @Override |
| public String get() { |
| return target.getDeviceUserName(); |
| } |
| }); |
| case ACTIVITY: |
| return new ActivityMode(this); |
| default: |
| throw new IllegalArgumentException("Unsupported mode: " + modeId); |
| } |
| } |
| |
| public final File localFile(Object... path) { |
| return new File(localTemp + "/" + Strings.join("/", path)); |
| } |
| |
| public final File localDir(Object... path) { |
| String joinedPath = localTemp + "/" + Strings.join("/", path); |
| File f = new File(joinedPath); |
| f.mkdirs(); |
| if (!f.exists()) { |
| throw new AssertionError("Failed to mkdirs: " + joinedPath); |
| } |
| return f; |
| } |
| |
| private File vogarJar() { |
| URL jarUrl = Vogar.class.getResource(VOGAR_CLASS_RESOURCE_PATH); |
| if (jarUrl == null) { |
| // should we add an option for IDE users, to use a user-specified vogar.jar? |
| throw new IllegalStateException("Vogar cannot find its own .jar"); |
| } |
| |
| /* |
| * Parse a URI like jar:file:/Users/jessewilson/vogar/vogar.jar!/vogar/Vogar.class |
| * to yield a .jar file like /Users/jessewilson/vogar/vogar.jar. |
| */ |
| String url = jarUrl.toString(); |
| int bang = url.indexOf("!"); |
| if (url.startsWith(JAR_URI_PREFIX) && bang != -1) { |
| return new File(url.substring(JAR_URI_PREFIX.length(), bang)); |
| } else if (url.startsWith(FILE_URL_PREFIX) && url.endsWith(VOGAR_CLASS_RESOURCE_PATH)) { |
| // Vogar is being run from a classes directory. |
| return new File(url.substring(FILE_URL_PREFIX.length(), |
| url.length() - VOGAR_CLASS_RESOURCE_PATH.length())); |
| } else { |
| throw new IllegalStateException("Vogar cannot find the .jar file in " + jarUrl); |
| } |
| } |
| |
| public final File hostJar(Object nameOrAction) { |
| return localFile(nameOrAction, nameOrAction + ".jar"); |
| } |
| |
| /** |
| * Returns a path for a Java tool such as java, javac, jar where |
| * the Java home is used if present, otherwise assumes it will |
| * come from the path. |
| */ |
| public String javaPath(String tool) { |
| return (javaHome == null) |
| ? tool |
| : new File(new File(javaHome, "bin"), tool).getPath(); |
| } |
| |
| public File targetDexFile(String name) { |
| return new File(runnerDir, name + ".dex.jar"); |
| } |
| |
| public File localDexFile(String name) { |
| return localFile(name, name + ".dex.jar"); |
| } |
| |
| /** |
| * Returns a recognizable readable name for the given generated .jar file, |
| * appropriate for use in naming derived files. |
| * |
| * @param file a product of the android build system, such as |
| * "out/core-libart_intermediates/javalib.jar". |
| * @return a recognizable base name like "core-libart_intermediates". |
| */ |
| public String basenameOfJar(File file) { |
| String name = file.getName().replaceAll("(\\.jar)$", ""); |
| while (BANNED_NAMES.contains(name)) { |
| file = file.getParentFile(); |
| name = file.getName(); |
| } |
| return name; |
| } |
| |
| public File vogarTemp() { |
| return new File(runnerDir, "tmp"); |
| } |
| |
| public File dalvikCache() { |
| return new File(runnerDir.getParentFile(), dalvikCache); |
| } |
| |
| /** |
| * Returns the directory where the VM stores its dexopt files. |
| */ |
| public String getAndroidDataPath() { |
| // The VM wants the parent directory of a directory named "dalvik-cache" |
| return dalvikCache().getParentFile().getPath(); |
| } |
| |
| /** |
| * Returns a parsed list of the --invoke-with command and its |
| * arguments, or an empty list if no --invoke-with was provided. |
| */ |
| public Iterable<String> invokeWith() { |
| if (invokeWith == null) { |
| return Collections.emptyList(); |
| } |
| return Splitter.onPattern("\\s+").omitEmptyStrings().split(invokeWith); |
| } |
| } |