1 /*
2  * Copyright (C) 2010 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.android;
18 
19 import com.google.common.collect.Iterables;
20 
21 import java.io.File;
22 import java.util.ArrayList;
23 import java.util.Collections;
24 import java.util.HashSet;
25 import java.util.List;
26 import java.util.Set;
27 
28 import vogar.Action;
29 import vogar.Classpath;
30 import vogar.Mode;
31 import vogar.ModeId;
32 import vogar.Run;
33 import vogar.Toolchain;
34 import vogar.Variant;
35 import vogar.commands.VmCommandBuilder;
36 import vogar.tasks.MkdirTask;
37 import vogar.tasks.RunActionTask;
38 import vogar.tasks.Task;
39 
40 /**
41  * Executes actions on a Dalvik or ART runtime on a Linux desktop.
42  */
43 public final class HostRuntime implements Mode {
44     private final Run run;
45     private final ModeId modeId;
46     private final Variant variant;
47 
HostRuntime(Run run, ModeId modeId, Variant variant)48     public HostRuntime(Run run, ModeId modeId, Variant variant) {
49         if (!modeId.isHost() || !modeId.supportsVariant(variant)) {
50             throw new IllegalArgumentException("Unsupported mode:" + modeId +
51                     " or variant: " + variant);
52         }
53         this.run = run;
54         this.modeId = modeId;
55         this.variant = variant;
56     }
57 
executeActionTask(Action action, boolean useLargeTimeout)58     @Override public Task executeActionTask(Action action, boolean useLargeTimeout) {
59         return new RunActionTask(run, action, useLargeTimeout);
60     }
61 
dalvikCache()62     private File dalvikCache() {
63         return run.localFile("android-data", run.dalvikCache);
64     }
65 
installTasks()66     @Override public Set<Task> installTasks() {
67         Set<Task> result = new HashSet<Task>();
68         for (File classpathElement : run.classpath.getElements()) {
69             // Libraries need to be dex'ed and put in the temporary directory.
70             String name = run.basenameOfJar(classpathElement);
71             File localDex = run.localDexFile(name);
72             File localTempDir = run.localDir(name);
73             result.add(createCreateDexJarTask(run.classpath, classpathElement, name,
74                     null /* action */, localDex, localTempDir));
75         }
76         result.add(new MkdirTask(run.mkdir, dalvikCache()));
77         return result;
78     }
79 
cleanupTasks(Action action)80     @Override public Set<Task> cleanupTasks(Action action) {
81         return Collections.emptySet();
82     }
83 
installActionTasks(Action action, File jar)84     @Override public Set<Task> installActionTasks(Action action, File jar) {
85         File localDexFile = run.localDexFile(action.getName());
86         File localTempDir = run.localDir(action.getName());
87         Task createDexJarTask = createCreateDexJarTask(Classpath.of(jar), jar, action.getName(),
88                 action, localDexFile, localTempDir);
89         return Collections.singleton(createDexJarTask);
90     }
91 
newVmCommandBuilder(Action action, File workingDirectory)92     @Override public VmCommandBuilder newVmCommandBuilder(Action action, File workingDirectory) {
93         String hostOut = System.getenv("ANDROID_HOST_OUT");
94         if (hostOut == null || hostOut.length() == 0) {
95           hostOut = System.getenv("ANDROID_BUILD_TOP");
96           if (hostOut == null) {
97             hostOut = "";
98           } else {
99             hostOut += "/";
100           }
101           hostOut += "out/host/linux-x86";
102         }
103 
104         List<File> jars = new ArrayList<File>();
105         for (String jar : modeId.getJarNames()) {
106             jars.add(new File(hostOut, "framework/" + jar + ".jar"));
107         }
108         Classpath bootClasspath = Classpath.of(jars);
109 
110         String libDir = hostOut;
111         if (variant == Variant.X32) {
112             libDir += "/lib";
113         } else if (variant == Variant.DEFAULT || variant == Variant.X64) {
114             libDir += "/lib64";
115         } else {
116             throw new AssertionError("Unsupported variant:" + variant);
117         }
118 
119         List<String> vmCommand = new ArrayList<String>();
120         Iterables.addAll(vmCommand, run.invokeWith());
121         vmCommand.add(hostOut + "/bin/" + run.vmCommand);
122 
123         // If you edit this, see also DeviceRuntime...
124         VmCommandBuilder builder = new VmCommandBuilder(run.log)
125                 .env("ANDROID_PRINTF_LOG", "tag")
126                 .env("ANDROID_LOG_TAGS", "*:i")
127                 .env("ANDROID_DATA", dalvikCache().getParent())
128                 .env("ANDROID_ROOT", hostOut)
129                 .env("ANDROID_RUNTIME_ROOT", hostOut + "/com.android.runtime")
130                 .env("ANDROID_TZDATA_ROOT", hostOut + "/com.android.tzdata")
131                 .env("LD_LIBRARY_PATH", libDir)
132                 .env("DYLD_LIBRARY_PATH", libDir)
133                 // This is needed on the host so that the linker loads core.oat at the necessary
134                 // address.
135                 .env("LD_USE_LOAD_BIAS", "1")
136                 .vmCommand(vmCommand)
137                 .vmArgs("-Xbootclasspath:" + bootClasspath.toString())
138                 .vmArgs("-Duser.language=en")
139                 .vmArgs("-Duser.region=US");
140         if (run.debugPort != null) {
141             builder.vmArgs(
142                     "-Xcompiler-option", "--debuggable", "-Xplugin:libopenjdkjvmti.so",
143                     "-agentpath:libjdwp.so=transport=dt_socket,address=" + run.debugPort
144                             + ",server=y,suspend=y");
145         }
146         if (!run.benchmark && run.checkJni) {
147             builder.vmArgs("-Xcheck:jni");
148         }
149         // dalvikvm defaults to no limit, but the framework sets the limit at 2000.
150         builder.vmArgs("-Xjnigreflimit:2000");
151         return builder;
152     }
153 
getRuntimeClasspath(Action action)154     @Override public Classpath getRuntimeClasspath(Action action) {
155         Classpath result = new Classpath();
156         result.addAll(run.localDexFile(action.getName()));
157         for (File classpathElement : run.classpath.getElements()) {
158             result.addAll(run.localDexFile(run.basenameOfJar(classpathElement)));
159         }
160         result.addAll(run.resourceClasspath);
161         return result;
162     }
163 
createCreateDexJarTask(Classpath classpath, File classpathElement, String name, Action action, File localDex, File localTempDir)164     private Task createCreateDexJarTask(Classpath classpath, File classpathElement, String name,
165             Action action, File localDex, File localTempDir) {
166         return new DexTask(run.toolchain.getDexer(), run.androidSdk, classpath, run.benchmark, name,
167                 classpathElement, action, localDex, localTempDir, run.multidex);
168     }
169 }
170