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