Merge pie-platform-release to aosp-master - DO NOT MERGE
Change-Id: I45c04d3a035af1cfa2b379cb9025b5c52eb1302f
diff --git a/Android.mk b/Android.mk
index 817bb53..8f07553 100644
--- a/Android.mk
+++ b/Android.mk
@@ -26,30 +26,31 @@
LOCAL_JAVA_RESOURCE_DIRS := resources
LOCAL_STATIC_JAVA_LIBRARIES := \
- caliper-host \
- caliper-gson-host \
+ caliper \
+ caliper-gson \
guavalib \
- junit-host \
+ junit \
vogar-jsr305 \
vogar-kxml-libcore-20110123
LOCAL_ADDITIONAL_DEPENDENCIES := \
$(HOST_OUT_EXECUTABLES)/dx \
$(HOST_OUT_EXECUTABLES)/d8-compat-dx \
- $(HOST_OUT_EXECUTABLES)/adb \
$(HOST_OUT_JAVA_LIBRARIES)/desugar.jar
# Vogar uses android.jar.
-LOCAL_CLASSPATH := prebuilts/sdk/9/android.jar
+LOCAL_CLASSPATH := $(call resolve-prebuilt-sdk-jar-path,current)
LOCAL_JAVA_LANGUAGE_VERSION := 1.7
include $(BUILD_HOST_JAVA_LIBRARY)
# build vogar tests jar
# ============================================================
-# Run the tests using the following command:
-# java -cp ${ANDROID_BUILD_TOP}/out/host/linux-x86/framework/vogar-tests.jar \
- org.junit.runner.JUnitCore vogar.AllTests
+# Run the tests using using the following target.
+.PHONY: run-vogar-tests
+run-vogar-tests: vogar-tests
+ java -cp ./out/host/linux-x86/framework/vogar-tests.jar \
+ org.junit.runner.JUnitCore vogar.AllTests
include $(CLEAR_VARS)
@@ -59,9 +60,9 @@
LOCAL_SRC_FILES := $(call all-java-files-under, test/)
LOCAL_STATIC_JAVA_LIBRARIES := \
- junit-host \
- mockito-host \
- objenesis-host \
+ junit \
+ mockito \
+ objenesis \
vogar
LOCAL_JAVA_LANGUAGE_VERSION := 1.7
diff --git a/src/vogar/Driver.java b/src/vogar/Driver.java
index cbb7365..53fcf2a 100644
--- a/src/vogar/Driver.java
+++ b/src/vogar/Driver.java
@@ -89,7 +89,8 @@
Outcome outcome = outcomes.get(action.getName());
if (outcome != null) {
addEarlyResult(outcome);
- } else if (run.expectationStore.get(action.getName()).getResult() == Result.UNSUPPORTED) {
+ } else if (run.expectationStore.get(action.getName()).getResult()
+ == Result.UNSUPPORTED) {
addEarlyResult(new Outcome(action.getName(), Result.UNSUPPORTED,
"Unsupported according to expectations file"));
} else {
diff --git a/src/vogar/FileCache.java b/src/vogar/FileCache.java
index b25a63a..c54a1dd 100644
--- a/src/vogar/FileCache.java
+++ b/src/vogar/FileCache.java
@@ -24,7 +24,7 @@
public interface FileCache {
boolean existsInCache(String key);
-
+
void copyToCache(File source, String key);
void copyFromCache(String key, File destination);
diff --git a/src/vogar/ModeId.java b/src/vogar/ModeId.java
index 54b3ce0..7a79ce1 100644
--- a/src/vogar/ModeId.java
+++ b/src/vogar/ModeId.java
@@ -42,7 +42,7 @@
"telephony-common",
"voip-common",
"ims-common",
- "org.apache.http.legacy.boot",
+ "org.apache.http.legacy.impl",
"android.hidl.base-V1.0-java",
"android.hidl.manager-V1.0-java"
// TODO: get this list programatically
@@ -54,6 +54,7 @@
private static final String[] DEVICE_JARS = new String[] {
"core-oj",
"core-libart",
+ "core-simple",
"conscrypt",
"okhttp",
"bouncycastle",
@@ -67,6 +68,7 @@
private static final String[] HOST_JARS = new String[] {
"core-oj-hostdex",
"core-libart-hostdex",
+ "core-simple-hostdex",
"conscrypt-hostdex",
"okhttp-hostdex",
"bouncycastle-hostdex",
@@ -104,6 +106,12 @@
|| ((this == HOST || this == DEVICE) && (variant == Variant.X64));
}
+ /** Does this mode support chroot-based execution? */
+ public boolean supportsChroot() {
+ // We only support execution from a chroot directory in device mode for now.
+ return this == ModeId.DEVICE;
+ }
+
public boolean supportsToolchain(Toolchain toolchain) {
return (this == JVM && toolchain == Toolchain.JAVAC)
|| (this != JVM && toolchain != Toolchain.JAVAC);
diff --git a/src/vogar/Run.java b/src/vogar/Run.java
index cbfab20..4a61a76 100644
--- a/src/vogar/Run.java
+++ b/src/vogar/Run.java
@@ -106,8 +106,8 @@
public final boolean checkJni;
public final boolean debugging;
- public Run(Vogar vogar, Toolchain toolchain, Console console, Mkdir mkdir, AndroidSdk androidSdk,
- Rm rm, Target target, File runnerDir)
+ public Run(Vogar vogar, Toolchain toolchain, Console console, Mkdir mkdir,
+ AndroidSdk androidSdk, Rm rm, Target target, File runnerDir)
throws IOException {
this.console = console;
diff --git a/src/vogar/Target.java b/src/vogar/Target.java
index 8ce93a9..30d88a5 100644
--- a/src/vogar/Target.java
+++ b/src/vogar/Target.java
@@ -30,7 +30,48 @@
* A target runtime environment such as a remote device or the local host
*/
public abstract class Target {
+
+ /**
+ * Return the process prefix for this target.
+ * <p>
+ * A process prefix is a list of tokens added in front of a script (VM command) to be run on
+ * this target.
+ *
+ * @see AdbTarget#targetProcessPrefix()
+ * @see AdbChrootTarget#targetProcessPrefix()
+ * @see SshTarget#targetProcessPrefix()
+ *
+ * @see Target#targetProcessWrapper()
+ * @see ScriptBuilder#commandLine()
+ */
+
protected abstract ImmutableList<String> targetProcessPrefix();
+
+ /**
+ * Return the process wrapper for this target if there is one, or {@code null} otherwise.
+ * <p>
+ * A process wrapper is a command that is used to execute a script (VM command) to be run on
+ * this target. The script, preceded by the process prefix, is surrounded with double quotes
+ * and passed as an argument to the process wrapper:
+ * <ul>
+ * <li>{@code <process-wrapper> "<process-prefix> <script>"}
+ * </ul>
+ * A {@code null} process wrapper means that the script will be executed as-is (but still
+ * preceded by the process prefix):
+ * <ul>
+ * <li>{@code <process-prefix> <script>}
+ * </ul>
+ *
+ * @see AdbChrootTarget#targetProcessWrapper()
+ *
+ * @see Target#targetProcessPrefix()
+ * @see ScriptBuilder#commandLine()
+ */
+ protected String targetProcessWrapper() {
+ // By default, targets don't have a process wrapper.
+ return null;
+ };
+
public abstract String getDeviceUserName();
public abstract List<File> ls(File directory) throws FileNotFoundException;
@@ -63,7 +104,7 @@
* Create a {@link ScriptBuilder} appropriate for this target.
*/
public ScriptBuilder newScriptBuilder() {
- return new ScriptBuilder(targetProcessPrefix());
+ return new ScriptBuilder(targetProcessPrefix(), targetProcessWrapper());
}
/**
@@ -108,13 +149,20 @@
private final ImmutableList<String> commandLinePrefix;
/**
+ * An optional wrapper of the command line. This can be used e.g. to wrap 'COMMAND' into
+ * 'sh -c "COMMAND"' before execution.
+ */
+ private final String commandLineWrapper;
+
+ /**
* The list of tokens making up the script, they were escaped where necessary before they
* were added to the list.
*/
private final List<String> escapedTokens;
- private ScriptBuilder(ImmutableList<String> commandLinePrefix) {
+ private ScriptBuilder(ImmutableList<String> commandLinePrefix, String commandLineWrapper) {
this.commandLinePrefix = commandLinePrefix;
+ this.commandLineWrapper = commandLineWrapper;
escapedTokens = new ArrayList<>();
}
@@ -175,6 +223,10 @@
// adb or ssh shells as they both concatenate all their arguments into one single
// string before parsing.
String grouped = SCRIPT_JOINER.join(escapedTokens);
+ // Honor a wrapper if there is one.
+ if (commandLineWrapper != null) {
+ grouped = commandLineWrapper + " \"" + grouped + "\"";
+ }
return new ImmutableList.Builder<String>()
.addAll(commandLinePrefix)
.add(grouped)
diff --git a/src/vogar/Vogar.java b/src/vogar/Vogar.java
index 86d0d52..88277d3 100644
--- a/src/vogar/Vogar.java
+++ b/src/vogar/Vogar.java
@@ -27,6 +27,7 @@
import java.util.Set;
import java.util.LinkedHashSet;
+import vogar.android.AdbChrootTarget;
import vogar.android.AdbTarget;
import vogar.android.AndroidSdk;
import vogar.android.DeviceFileCache;
@@ -69,6 +70,9 @@
@Option(names = { "--ssh" })
private String sshHost;
+ @Option(names = { "--chroot" })
+ private String chrootDir;
+
@Option(names = { "--timeout" })
int timeoutSeconds = 60; // default is one minute;
@@ -240,6 +244,9 @@
System.out.println();
System.out.println(" --ssh <host:port>: target a remote machine via SSH.");
System.out.println();
+ System.out.println(" --chroot <dir>: target a chroot dir on device");
+ System.out.println(" Only works with --mode device.");
+ System.out.println();
System.out.println(" --clean: synonym for --clean-before and --clean-after (default).");
System.out.println(" Disable with --no-clean if you want no files removed.");
System.out.println();
@@ -452,6 +459,11 @@
return false;
}
+ if (chrootDir != null && !modeId.supportsChroot()) {
+ System.out.println("Chroot-based execution not supported for mode " + modeId);
+ return false;
+ }
+
if (xmlReportsDirectory != null && !xmlReportsDirectory.isDirectory()) {
System.out.println("Invalid XML reports directory: " + xmlReportsDirectory);
return false;
@@ -543,6 +555,7 @@
*/
private enum TargetType {
ADB(AdbTarget.defaultDeviceDir()),
+ ADB_CHROOT(AdbChrootTarget.defaultDeviceDir()),
LOCAL(LocalTarget.defaultDeviceDir()),
SSH(SshTarget.defaultDeviceDir());
@@ -580,6 +593,8 @@
targetType = TargetType.SSH;
} else if (modeId.isLocal()) {
targetType = TargetType.LOCAL;
+ } else if (chrootDir != null) {
+ targetType = TargetType.ADB_CHROOT;
} else {
targetType = TargetType.ADB;
}
@@ -591,12 +606,27 @@
// Create the target.
Target target;
switch (targetType) {
- case ADB:
- DeviceFilesystem deviceFilesystem =
- new DeviceFilesystem(console, ImmutableList.of("adb", "shell"));
- DeviceFileCache deviceFileCache =
- new DeviceFileCache(console, runnerDir, deviceFilesystem);
- target = new AdbTarget(console, deviceFilesystem, deviceFileCache);
+ case ADB: {
+ ImmutableList<String> targetProcessPrefix = ImmutableList.of("adb", "shell");
+ DeviceFilesystem deviceFilesystem =
+ new DeviceFilesystem(console, targetProcessPrefix);
+ DeviceFileCache deviceFileCache =
+ new DeviceFileCache(console, runnerDir, deviceFilesystem);
+ target = new AdbTarget(console, deviceFilesystem, deviceFileCache);
+ }
+ break;
+ case ADB_CHROOT: {
+ ImmutableList<String> targetProcessPrefix = ImmutableList.of("adb", "shell");
+ DeviceFilesystem deviceFilesystem =
+ new DeviceFilesystem(console, targetProcessPrefix);
+ // Directory `runnerDir` is relative to the chroot; `runnerDirInRoot` is its
+ // counterpart relative to the device's filesystem "absolute" root.
+ File runnerDirInRoot = new File(chrootDir + "/" + runnerDir.getPath());
+ DeviceFileCache deviceFileCache =
+ new DeviceFileCache(console, runnerDirInRoot, deviceFilesystem);
+ target =
+ new AdbChrootTarget(console, deviceFilesystem, deviceFileCache, chrootDir);
+ }
break;
case SSH:
target = new SshTarget(console, sshHost);
diff --git a/src/vogar/android/AdbChrootTarget.java b/src/vogar/android/AdbChrootTarget.java
new file mode 100644
index 0000000..42ed491
--- /dev/null
+++ b/src/vogar/android/AdbChrootTarget.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2018 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.collect.ImmutableList;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.List;
+import java.util.ListIterator;
+import vogar.Log;
+import vogar.android.AdbTarget;
+import vogar.commands.Command;
+
+/**
+ * A class similar to AdbTarget, but working relatively to a chroot
+ * directory (instead of the whole system under the root directory on
+ * the device).
+ *
+ * All "remote" pathnames (as java.io.File objects) passed as
+ * arguments to methods below and/or returned by them are relative to
+ * the chroot directory, except when they represent "local" (host)
+ * files.
+ *
+ * @see AdbTarget
+ */
+public final class AdbChrootTarget extends AdbTarget {
+
+ private final String chrootDir;
+
+ private final ImmutableList<String> targetProcessPrefixList;
+
+ private static String TARGET_PROCESS_WRAPPER = "sh -c";
+
+ public AdbChrootTarget(Log log, DeviceFilesystem deviceFilesystem,
+ DeviceFileCache deviceFileCache, String chrootDir) {
+ super(log, deviceFilesystem, deviceFileCache);
+ this.chrootDir = chrootDir;
+ this.targetProcessPrefixList = ImmutableList.of("adb", "shell", "chroot", chrootDir);
+ }
+
+ @Override
+ public void await(File directory) {
+ super.await(chrootToRoot(directory));
+ }
+
+ @Override
+ public List<File> ls(File directory) throws FileNotFoundException {
+ // Add chroot prefix to searched directory.
+ List<File> files = super.ls(chrootToRoot(directory));
+ // Remove chroot prefix from files found in directory.
+ ListIterator<File> iterator = files.listIterator();
+ while (iterator.hasNext()){
+ File file = iterator.next();
+ try {
+ iterator.set(rootToChroot(file));
+ } catch (PathnameNotUnderChrootException e) {
+ // This should never happen, as `file` is derived from a chroot-based pathname.
+ throw new Error(e);
+ }
+ }
+ return files;
+ }
+
+ @Override
+ public void rm(File file) {
+ super.rm(chrootToRoot(file));
+ }
+
+ @Override
+ public void mkdirs(File file) {
+ super.mkdirs(chrootToRoot(file));
+ }
+
+ @Override
+ public void push(File local, File remote) {
+ super.push(local, chrootToRoot(remote));
+ }
+
+ @Override
+ public void pull(File remote, File local) {
+ super.pull(chrootToRoot(remote), local);
+ }
+
+ @Override
+ protected ImmutableList<String> targetProcessPrefix() {
+ return targetProcessPrefixList;
+ }
+
+ @Override
+ protected String targetProcessWrapper() {
+ return TARGET_PROCESS_WRAPPER;
+ }
+
+ /**
+ * Convert a file relative to the chroot dir to a file relative to
+ * the device's filesystem "absolute" root.
+ */
+ private File chrootToRoot(File file) {
+ return new File(chrootDir + "/" + file.getPath());
+ }
+
+ /**
+ * Convert a file relative to the device's filesystem "absolute"
+ * root to a file relative to the chroot dir .
+ */
+ private File rootToChroot(File file) throws PathnameNotUnderChrootException {
+ String pathname = file.getPath();
+ if (!pathname.startsWith(chrootDir)) {
+ throw new PathnameNotUnderChrootException(pathname, chrootDir);
+ }
+ return new File(pathname.substring(chrootDir.length()));
+ }
+
+ /**
+ * Exception thrown when a pathname does not represent a file
+ * under the chroot directory.
+ */
+ private class PathnameNotUnderChrootException extends Exception {
+
+ public PathnameNotUnderChrootException(String pathname, String chrootDir) {
+ super("Pathname " + pathname + " does not represent a file under chroot directory "
+ + chrootDir);
+ }
+ }
+
+}
diff --git a/src/vogar/android/AdbTarget.java b/src/vogar/android/AdbTarget.java
index 48473fd..44bf868 100644
--- a/src/vogar/android/AdbTarget.java
+++ b/src/vogar/android/AdbTarget.java
@@ -29,12 +29,12 @@
import vogar.Target;
import vogar.commands.Command;
-public final class AdbTarget extends Target {
+public class AdbTarget extends Target {
private static final ImmutableList<String> TARGET_PROCESS_PREFIX =
ImmutableList.of("adb", "shell");
- private final Log log;
+ protected final Log log;
private final DeviceFilesystem deviceFilesystem;
diff --git a/src/vogar/android/AndroidSdk.java b/src/vogar/android/AndroidSdk.java
index 01c4e07..b19f404 100644
--- a/src/vogar/android/AndroidSdk.java
+++ b/src/vogar/android/AndroidSdk.java
@@ -132,10 +132,10 @@
}
} else if ("bin".equals(buildToolDirString)) {
log.verbose("Using android source build mode to find dependencies.");
- String tmpJarPath = "prebuilts/sdk/current/android.jar";
+ String tmpJarPath = "prebuilts/sdk/current/public/android.jar";
String androidBuildTop = System.getenv("ANDROID_BUILD_TOP");
if (!com.google.common.base.Strings.isNullOrEmpty(androidBuildTop)) {
- tmpJarPath = androidBuildTop + "/prebuilts/sdk/current/android.jar";
+ tmpJarPath = androidBuildTop + "/prebuilts/sdk/current/public/android.jar";
} else {
log.warn("Assuming current directory is android build tree root.");
}
diff --git a/src/vogar/android/DeviceFileCache.java b/src/vogar/android/DeviceFileCache.java
index 5d4a131..4625e93 100644
--- a/src/vogar/android/DeviceFileCache.java
+++ b/src/vogar/android/DeviceFileCache.java
@@ -38,6 +38,7 @@
this.deviceFilesystem = deviceFilesystem;
}
+ @Override
public boolean existsInCache(String key) {
if (cachedFiles == null) {
try {
@@ -53,11 +54,13 @@
return cachedFiles.contains(cachedFile);
}
+ @Override
public void copyFromCache(String key, File destination) {
File cachedFile = new File(cacheRoot, key);
cp(cachedFile, destination);
}
+ @Override
public void copyToCache(File source, String key) {
File cachedFile = new File(cacheRoot, key);
deviceFilesystem.mkdirs(cacheRoot);
diff --git a/src/vogar/android/DeviceFilesystem.java b/src/vogar/android/DeviceFilesystem.java
index 4dad4ca..65c1cbd 100644
--- a/src/vogar/android/DeviceFilesystem.java
+++ b/src/vogar/android/DeviceFilesystem.java
@@ -93,7 +93,10 @@
.execute();
List<File> files = new ArrayList<File>();
for (String fileString : rawResult) {
- if (fileString.equals(dir.getPath() + ": No such file or directory")) {
+ // Try to match outputs like:
+ //
+ // ls: <path>: No such file or directory
+ if (fileString.contains(dir.getPath() + ": No such file or directory")) {
throw new FileNotFoundException(dir + " not found.");
}
if (fileString.equals(dir.getPath())) {
diff --git a/src/vogar/tasks/RetrieveFilesTask.java b/src/vogar/tasks/RetrieveFilesTask.java
index de71266..aaf93e6 100644
--- a/src/vogar/tasks/RetrieveFilesTask.java
+++ b/src/vogar/tasks/RetrieveFilesTask.java
@@ -38,7 +38,7 @@
}
/**
- * Scans {@code dir} for files to grab.
+ * Scans directory {@code source} for files to grab.
*/
private void retrieveFiles(File destination, File source, FileFilter filenameFilter)
throws FileNotFoundException {
diff --git a/test/vogar/android/HostRuntimeLocalTargetTest.java b/test/vogar/android/HostRuntimeLocalTargetTest.java
index 995acda..8330c6f 100644
--- a/test/vogar/android/HostRuntimeLocalTargetTest.java
+++ b/test/vogar/android/HostRuntimeLocalTargetTest.java
@@ -82,6 +82,7 @@
+ " -Xbootclasspath"
+ ":${ANDROID_BUILD_TOP}/out/host/linux-x86/framework/core-oj-hostdex.jar"
+ ":${ANDROID_BUILD_TOP}/out/host/linux-x86/framework/core-libart-hostdex.jar"
+ + ":${ANDROID_BUILD_TOP}/out/host/linux-x86/framework/core-simple-hostdex.jar"
+ ":${ANDROID_BUILD_TOP}/out/host/linux-x86/framework/conscrypt-hostdex.jar"
+ ":${ANDROID_BUILD_TOP}/out/host/linux-x86/framework/okhttp-hostdex.jar"
+ ":${ANDROID_BUILD_TOP}/out/host/linux-x86/framework/bouncycastle-hostdex.jar"
@@ -137,6 +138,7 @@
+ " -Xbootclasspath"
+ ":${ANDROID_BUILD_TOP}/out/host/linux-x86/framework/core-oj-hostdex.jar"
+ ":${ANDROID_BUILD_TOP}/out/host/linux-x86/framework/core-libart-hostdex.jar"
+ + ":${ANDROID_BUILD_TOP}/out/host/linux-x86/framework/core-simple-hostdex.jar"
+ ":${ANDROID_BUILD_TOP}/out/host/linux-x86/framework/conscrypt-hostdex.jar"
+ ":${ANDROID_BUILD_TOP}/out/host/linux-x86/framework/okhttp-hostdex.jar"
+ ":${ANDROID_BUILD_TOP}/out/host/linux-x86/framework/bouncycastle-hostdex.jar"