blob: 1920772af69aa1337baa771f034ada70fd94f019 [file] [log] [blame]
/*
* 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 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.AdbTarget;
import vogar.android.AndroidSdk;
import vogar.android.DeviceFileCache;
import vogar.android.DeviceRuntime;
import vogar.android.HostRuntime;
import vogar.commands.CommandFailedException;
import vogar.commands.Jack;
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>();
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 boolean profile;
public final boolean profileBinary;
public final int profileDepth;
public final int profileInterval;
public final boolean profileThreadGroup;
public final File profileFile;
public final File javaHome;
public final Integer debugPort;
public final List<String> javacArgs;
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 boolean testOnly;
public final boolean useJack;
public final boolean checkJni;
public Run(Vogar vogar) throws IOException {
this.console = vogar.stream
? new Console.StreamingConsole()
: new Console.MultiplexingConsole();
console.setUseColor(
vogar.color, vogar.passColor, vogar.skipColor, vogar.failColor, vogar.warnColor);
console.setAnsi(vogar.ansi);
console.setIndent(vogar.indent);
console.setVerbose(vogar.verbose);
this.localTemp = new File("/tmp/vogar/" + UUID.randomUUID());
this.log = console;
if (vogar.sshHost != null) {
this.target = new SshTarget(vogar.sshHost, log);
} else if (vogar.modeId.isLocal()) {
this.target = new LocalTarget(this);
} else {
this.target = new AdbTarget(this);
}
this.useJack = vogar.toolchain.toLowerCase().equals("jack");
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 = vogar.deviceDir != null
? new File(vogar.deviceDir, "run")
: new File(target.defaultDeviceDir(), "run");
this.deviceUserHome = new File(runnerDir, "user.home");
this.mkdir = new Mkdir(console);
this.rm = new Rm(console);
this.firstMonitorPort = vogar.firstMonitorPort;
this.invokeWith = vogar.invokeWith;
this.javacArgs = vogar.javacArgs;
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.profile = vogar.profile;
this.profileBinary = vogar.profileBinary;
this.profileFile = vogar.profileFile;
this.profileDepth = vogar.profileDepth;
this.profileInterval = vogar.profileInterval;
this.profileThreadGroup = vogar.profileThreadGroup;
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);
// When we are running in jack mode, extra jack files are needed to compile our sources
// as jack takes libraries in it's own .jack format, and these need to be in the classpath.
// We add the jack libraries for compiling although the jar libraries are still needed at
// runtime, so they are added too.
if (useJack) {
// We try to convert the vogar jar file with required testing frameworks into a jack
// library so we can use it while building sources.
try {
String vogarJarPath = vogarJar().getAbsolutePath();
String vogarJackPath = Jack.convertJarToJackLib(log, vogarJarPath);
this.classpath.addAll(new File(vogarJackPath), new File(vogarJarPath));
} catch (IllegalArgumentException | CommandFailedException e) {
System.out.println("There was an error finding required jack libraries. Details: "
+ e.getMessage());
throw new IllegalStateException("Jack was requested but could not be found.");
}
} else {
this.classpath.addAll(vogarJar());
}
this.testOnly = vogar.testOnly;
if (vogar.modeId.requiresAndroidSdk()) {
androidSdk = new AndroidSdk(log, mkdir, vogar.modeId, this.useJack);
androidSdk.setCaches(new HostFileCache(log, mkdir),
new DeviceFileCache(log, runnerDir, androidSdk));
} else {
androidSdk = null;
}
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 (vogar.modeId.requiresAndroidSdk()) {
buildClasspath.addAll(androidSdk.getCompilationClasspath());
}
this.classFileIndex = new ClassFileIndex(log, mkdir, vogar.jarSearchDirs);
if (vogar.suggestClasspaths) {
classFileIndex.createIndex();
}
this.retrievedFiles = new RetrievedFilesFilter(profile, profileFile);
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;
}
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);
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));
}
private File vogarJar() {
URL jarUrl = Vogar.class.getResource("/vogar/Vogar.class");
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("!");
String JAR_URI_PREFIX = "jar:file:";
if (url.startsWith(JAR_URI_PREFIX) && bang != -1) {
return new File(url.substring(JAR_URI_PREFIX.length(), bang));
} 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 an environment variable assignment to configure where the VM will
* store its dexopt files. This must be set on production devices and is
* optional for development devices.
*/
public String getAndroidData() {
// The VM wants the parent directory of a directory named "dalvik-cache"
return "ANDROID_DATA=" + dalvikCache().getParentFile();
}
/**
* 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);
}
}