aboutsummaryrefslogtreecommitdiff
path: root/src/vogar/android/DeviceRuntime.java
blob: 2b5f01fe2c28059b489f0a01d6e6e55640b7ca52 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
/*
 * Copyright (C) 2009 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.android;

import com.google.common.base.Supplier;
import com.google.common.collect.Iterables;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import vogar.Action;
import vogar.Variant;
import vogar.Classpath;
import vogar.Mode;
import vogar.ModeId;
import vogar.Run;
import vogar.commands.VmCommandBuilder;
import vogar.tasks.RunActionTask;
import vogar.tasks.Task;

/**
 * Execute actions on an Android device or emulator using "app_process" or the runtime directly.
 */
public final class DeviceRuntime implements Mode {
    private final Run run;
    private final ModeId modeId;
    private final Supplier<String> deviceUserNameSupplier;

    public DeviceRuntime(Run run, ModeId modeId, Variant variant,
                         Supplier<String> deviceUserNameSupplier) {
        this.deviceUserNameSupplier = deviceUserNameSupplier;
        if (!modeId.isDevice() || !modeId.supportsVariant(variant)) {
            throw new IllegalArgumentException("Unsupported mode:" + modeId +
                    " or variant: " + variant);
        }
        this.run = run;
        this.modeId = modeId;
    }

    @Override public Set<Task> installTasks() {
        Set<Task> result = new HashSet<Task>();
        Task lastDexTask = null;
        // dex everything on the classpath and push it to the device.
        for (File classpathElement : run.classpath.getElements()) {
            Task currentDexTask = addCreateDexJarAndPushTasks(result, run.basenameOfJar(classpathElement),
                    classpathElement, null);
            // If {@code serialDexing} is enabled, make each subsequent dex task
            // depend on previous so any moment of time only one dexer (d8) instance is run
            // simultaneously.
            if (lastDexTask != null && run.serialDexing) {
                currentDexTask.afterSuccess(lastDexTask);
            }
            lastDexTask = currentDexTask;
        }
        return result;
    }

    @Override public Set<Task> installActionTasks(Action action, File jar) {
        Set<Task> result = new HashSet<Task>();
        addCreateDexJarAndPushTasks(result, action.getName(), jar, action);
        return result;
    }

    @Override public Task executeActionTask(Action action, boolean useLargeTimeout) {
        return new RunActionTask(run, action, useLargeTimeout);
    }

    @Override public VmCommandBuilder newVmCommandBuilder(Action action, File workingDirectory) {
        List<String> vmCommand = new ArrayList<String>();
        Iterables.addAll(vmCommand, run.invokeWith());
        vmCommand.add(run.vmCommand);

        // If you edit this, see also HostRuntime...
        VmCommandBuilder vmCommandBuilder = new VmCommandBuilder(run.log)
                .env("ANDROID_DATA", run.getAndroidDataPath())
                .workingDirectory(workingDirectory)
                .vmCommand(vmCommand)
                .vmArgs("-Duser.home=" + run.deviceUserHome)
                // Use the same command line limit (4096) as adb (see
                // _adb_connect in system/core/adb/adb_client.cpp).
                .maxLength(4096);
        if (run.debugPort != null) {
            vmCommandBuilder.vmArgs(
                    "-Xcompiler-option", "--debuggable", "-Xplugin:libopenjdkjvmti.so",
                    "-agentpath:libjdwp.so=transport=dt_socket,address=" + run.debugPort
                            + ",server=y,suspend=y");
        }

        if (modeId == ModeId.APP_PROCESS) {
            return vmCommandBuilder
                .vmArgs(action.getUserDir().getPath())
                .classpathViaProperty(true);
        }

        vmCommandBuilder
                .vmArgs("-Duser.name=" + deviceUserNameSupplier.get())
                .vmArgs("-Duser.language=en")
                .vmArgs("-Duser.region=US");

        if (!run.benchmark && run.checkJni) {
            vmCommandBuilder.vmArgs("-Xcheck:jni");
        }
        // dalvikvm defaults to no limit, but the framework sets the limit at 2000.
        vmCommandBuilder.vmArgs("-Xjnigreflimit:2000");
        return vmCommandBuilder;
    }

    @Override public Set<Task> cleanupTasks(Action action) {
        return Collections.singleton(run.target.rmTask(action.getUserDir()));
    }

    @Override public Classpath getRuntimeClasspath(Action action) {
        Classpath result = new Classpath();
        result.addAll(run.targetDexFile(action.getName()));
        if (!run.benchmark) {
            for (File classpathElement : run.classpath.getElements()) {
                result.addAll(run.targetDexFile(run.basenameOfJar(classpathElement)));
            }
        }
        // Note we intentionally do not add run.resourceClasspath on
        // the device since it contains host path names.
        return result;
    }

    private Task addCreateDexJarAndPushTasks(
            Set<Task> tasks, String name, File jar, Action action) {
        File localDex = run.localDexFile(name);
        File localTempDir = run.localDir(name);
        File deviceDex = run.targetDexFile(name);
        Task createDexJarTask = newCreateDexJarTask(run.classpath, jar, name, action, localDex,
                localTempDir);
        tasks.add(createDexJarTask);
        tasks.add(run.target.pushTask(localDex, deviceDex).afterSuccess(createDexJarTask));
        return createDexJarTask;
    }

    private Task newCreateDexJarTask(Classpath classpath, File classpathElement, String name,
            Action action, File localDex, File localTempDir) {
        return new DexTask(run.toolchain.getDexer(), run.androidSdk, classpath, run.benchmark,
                name, classpathElement, action, localDex, localTempDir, run.multidex);
    }
}