1 /* 2 * Copyright (C) 2009 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.base.Supplier; 20 import com.google.common.collect.Iterables; 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 import vogar.Action; 28 import vogar.Toolchain; 29 import vogar.Variant; 30 import vogar.Classpath; 31 import vogar.Mode; 32 import vogar.ModeId; 33 import vogar.Run; 34 import vogar.commands.VmCommandBuilder; 35 import vogar.tasks.RunActionTask; 36 import vogar.tasks.Task; 37 38 /** 39 * Execute actions on an Android device or emulator using "app_process" or the runtime directly. 40 */ 41 public final class DeviceRuntime implements Mode { 42 private final Run run; 43 private final ModeId modeId; 44 private final Supplier<String> deviceUserNameSupplier; 45 46 public DeviceRuntime(Run run, ModeId modeId, Variant variant, 47 Supplier<String> deviceUserNameSupplier) { 48 this.deviceUserNameSupplier = deviceUserNameSupplier; 49 if (!modeId.isDevice() || !modeId.supportsVariant(variant)) { 50 throw new IllegalArgumentException("Unsupported mode:" + modeId + 51 " or variant: " + variant); 52 } 53 this.run = run; 54 this.modeId = modeId; 55 } 56 57 @Override public Set<Task> installTasks() { 58 Set<Task> result = new HashSet<Task>(); 59 // dex everything on the classpath and push it to the device. 60 for (File classpathElement : run.classpath.getElements()) { 61 addCreateDexJarAndPushTasks(result, run.basenameOfJar(classpathElement), 62 classpathElement, null); 63 } 64 return result; 65 } 66 67 @Override public Set<Task> installActionTasks(Action action, File jar) { 68 Set<Task> result = new HashSet<Task>(); 69 addCreateDexJarAndPushTasks(result, action.getName(), jar, action); 70 return result; 71 } 72 73 @Override public Task executeActionTask(Action action, boolean useLargeTimeout) { 74 return new RunActionTask(run, action, useLargeTimeout); 75 } 76 77 @Override public VmCommandBuilder newVmCommandBuilder(Action action, File workingDirectory) { 78 List<String> vmCommand = new ArrayList<String>(); 79 Iterables.addAll(vmCommand, run.invokeWith()); 80 vmCommand.add(run.vmCommand); 81 82 // If you edit this, see also HostRuntime... 83 VmCommandBuilder vmCommandBuilder = new VmCommandBuilder(run.log) 84 .env("ANDROID_DATA", run.getAndroidDataPath()) 85 .workingDirectory(workingDirectory) 86 .vmCommand(vmCommand) 87 .vmArgs("-Duser.home=" + run.deviceUserHome) 88 // Use the same command line limit (4096) as adb (see 89 // _adb_connect in system/core/adb/adb_client.cpp). 90 .maxLength(4096); 91 if (run.debugPort != null) { 92 vmCommandBuilder.vmArgs( 93 "-Xcompiler-option", "--debuggable", "-Xplugin:libopenjdkjvmti.so", 94 "-agentpath:libjdwp.so=transport=dt_socket,address=" + run.debugPort 95 + ",server=y,suspend=y"); 96 } 97 98 if (modeId == ModeId.APP_PROCESS) { 99 return vmCommandBuilder 100 .vmArgs(action.getUserDir().getPath()) 101 .classpathViaProperty(true); 102 } 103 104 vmCommandBuilder 105 .vmArgs("-Duser.name=" + deviceUserNameSupplier.get()) 106 .vmArgs("-Duser.language=en") 107 .vmArgs("-Duser.region=US"); 108 109 if (!run.benchmark && run.checkJni) { 110 vmCommandBuilder.vmArgs("-Xcheck:jni"); 111 } 112 // dalvikvm defaults to no limit, but the framework sets the limit at 2000. 113 vmCommandBuilder.vmArgs("-Xjnigreflimit:2000"); 114 return vmCommandBuilder; 115 } 116 117 @Override public Set<Task> cleanupTasks(Action action) { 118 return Collections.singleton(run.target.rmTask(action.getUserDir())); 119 } 120 121 @Override public Classpath getRuntimeClasspath(Action action) { 122 Classpath result = new Classpath(); 123 result.addAll(run.targetDexFile(action.getName())); 124 if (!run.benchmark) { 125 for (File classpathElement : run.classpath.getElements()) { 126 result.addAll(run.targetDexFile(run.basenameOfJar(classpathElement))); 127 } 128 } 129 // Note we intentionally do not add run.resourceClasspath on 130 // the device since it contains host path names. 131 return result; 132 } 133 134 private void addCreateDexJarAndPushTasks( 135 Set<Task> tasks, String name, File jar, Action action) { 136 File localDex = run.localDexFile(name); 137 File localTempDir = run.localDir(name); 138 File deviceDex = run.targetDexFile(name); 139 Task createDexJarTask = newCreateDexJarTask(run.classpath, jar, name, action, localDex, 140 localTempDir); 141 tasks.add(createDexJarTask); 142 tasks.add(run.target.pushTask(localDex, deviceDex).afterSuccess(createDexJarTask)); 143 } 144 145 private Task newCreateDexJarTask(Classpath classpath, File classpathElement, String name, 146 Action action, File localDex, File localTempDir) { 147 return new DexTask(run.toolchain.getDexer(), run.androidSdk, classpath, run.benchmark, 148 name, classpathElement, action, localDex, localTempDir, run.multidex); 149 } 150 } 151