Java程序  |  315行  |  11.22 KB

/*
 * 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);
    }
}