• 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.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