summaryrefslogtreecommitdiffstats
path: root/tools/runner
diff options
context:
space:
mode:
Diffstat (limited to 'tools/runner')
-rw-r--r--tools/runner/Android.mk28
-rw-r--r--tools/runner/java/dalvik/runner/Dx.java13
-rw-r--r--tools/runner/java/dalvik/runner/Md5Cache.java115
3 files changed, 147 insertions, 9 deletions
diff --git a/tools/runner/Android.mk b/tools/runner/Android.mk
index bc7c5b7..2fb3591 100644
--- a/tools/runner/Android.mk
+++ b/tools/runner/Android.mk
@@ -2,15 +2,7 @@ LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
-ext_dirs := \
- ../../../../external/jsr305/ri/src/main/java \
- ../../../../external/guava/src \
- ../../../../external/caliper/src
-
-ext_src_files := $(call all-java-files-under,$(ext_dirs))
-
LOCAL_SRC_FILES := \
- $(ext_src_files) \
java/dalvik/runner/Aapt.java \
java/dalvik/runner/Adb.java \
java/dalvik/runner/ActivityMode.java \
@@ -36,6 +28,7 @@ LOCAL_SRC_FILES := \
java/dalvik/runner/JtregRunner.java \
java/dalvik/runner/MainFinder.java \
java/dalvik/runner/MainRunner.java \
+ java/dalvik/runner/Md5Cache.java \
java/dalvik/runner/Mkdir.java \
java/dalvik/runner/Mode.java \
java/dalvik/runner/NamingPatternCodeFinder.java \
@@ -53,7 +46,7 @@ LOCAL_SRC_FILES := \
java/dalvik/runner/XmlReportPrinter.java \
LOCAL_MODULE:= dalvik_runner
-LOCAL_STATIC_JAVA_LIBRARIES := javatest jh jtreg kxml2-2.3.0
+LOCAL_STATIC_JAVA_LIBRARIES := jsr305 guava caliper javatest jh jtreg kxml2-2.3.0
# TODO this only works when junit is already built...
LOCAL_JAVA_LIBRARIES := junit
@@ -64,6 +57,23 @@ include $(BUILD_HOST_JAVA_LIBRARY)
include $(call all-subdir-makefiles)
+# prebuilt jsr305.jar
+# TODO: do we need this any more? caliper.jar has a jarjar'ed copy.
+include $(CLEAR_VARS)
+LOCAL_PREBUILT_JAVA_LIBRARIES := jsr305:lib/jsr305.jar
+include $(BUILD_HOST_PREBUILT)
+
+# prebuilt guava.jar
+# TODO: do we need this any more? caliper.jar has a jarjar'ed copy.
+include $(CLEAR_VARS)
+LOCAL_PREBUILT_JAVA_LIBRARIES := guava:lib/guava.jar
+include $(BUILD_HOST_PREBUILT)
+
+# prebuilt caliper.jar
+include $(CLEAR_VARS)
+LOCAL_PREBUILT_JAVA_LIBRARIES := caliper:lib/caliper.jar
+include $(BUILD_HOST_PREBUILT)
+
# prebuilt javatest.jar
include $(CLEAR_VARS)
LOCAL_PREBUILT_JAVA_LIBRARIES := javatest:lib/javatest.jar
diff --git a/tools/runner/java/dalvik/runner/Dx.java b/tools/runner/java/dalvik/runner/Dx.java
index 1190bce..393b70d 100644
--- a/tools/runner/java/dalvik/runner/Dx.java
+++ b/tools/runner/java/dalvik/runner/Dx.java
@@ -17,13 +17,25 @@
package dalvik.runner;
import java.io.File;
+import java.util.logging.Logger;
/**
* A dx command.
*/
final class Dx {
+ private static final Logger logger = Logger.getLogger(Dx.class.getName());
+ private static final Md5Cache DEX_CACHE = new Md5Cache("dex");
+ /**
+ * Converts all the .class files on 'classpath' into a dex file written to 'output'.
+ */
public void dex(File output, Classpath classpath) {
+ File key = DEX_CACHE.makeKey(classpath);
+ if (key != null && key.exists()) {
+ logger.fine("dex cache hit for " + classpath);
+ new Command.Builder().args("cp", key, output).execute();
+ return;
+ }
/*
* We pass --core-library so that we can write tests in the
* same package they're testing, even when that's a core
@@ -44,5 +56,6 @@ final class Dx {
.args("--core-library")
.args(Strings.objectsToStrings(classpath.getElements()))
.execute();
+ DEX_CACHE.insert(key, output);
}
}
diff --git a/tools/runner/java/dalvik/runner/Md5Cache.java b/tools/runner/java/dalvik/runner/Md5Cache.java
new file mode 100644
index 0000000..f6ba85d
--- /dev/null
+++ b/tools/runner/java/dalvik/runner/Md5Cache.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2010 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 dalvik.runner;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.security.MessageDigest;
+import java.util.logging.Logger;
+
+/**
+ * Caches content by MD5.
+ */
+public final class Md5Cache {
+ private static final Logger logger = Logger.getLogger(Md5Cache.class.getName());
+ private static final File CACHE_ROOT = new File("/tmp/vogar-md5-cache/");
+
+ private final String keyPrefix;
+
+ /**
+ * Creates a new cache accessor. There's only one directory on disk, so 'keyPrefix' is really
+ * just a convenience for humans inspecting the cache.
+ */
+ public Md5Cache(String keyPrefix) {
+ this.keyPrefix = keyPrefix;
+ }
+
+ /**
+ * Returns an ASCII hex representation of the MD5 of the content of 'file'.
+ */
+ private static String md5(File file) {
+ byte[] digest = null;
+ try {
+ MessageDigest digester = MessageDigest.getInstance("MD5");
+ byte[] bytes = new byte[8192];
+ FileInputStream in = new FileInputStream(file);
+ try {
+ int byteCount;
+ while ((byteCount = in.read(bytes)) > 0) {
+ digester.update(bytes, 0, byteCount);
+ }
+ digest = digester.digest();
+ } finally {
+ in.close();
+ }
+ } catch (Exception cause) {
+ throw new RuntimeException("Unable to compute MD5 of \"" + file + "\"", cause);
+ }
+ return (digest == null) ? null : byteArrayToHexString(digest);
+ }
+
+ private static String byteArrayToHexString(byte[] bytes) {
+ StringBuilder result = new StringBuilder();
+ for (byte b : bytes) {
+ result.append(Integer.toHexString((b >> 4) & 0xf));
+ result.append(Integer.toHexString(b & 0xf));
+ }
+ return result.toString();
+ }
+
+ /**
+ * Returns the appropriate key for a dex file corresponding to the contents of 'classpath'.
+ * Returns null if we don't think it's possible to cache the given classpath.
+ */
+ public File makeKey(Classpath classpath) {
+ // Do we have it in cache?
+ String key = keyPrefix;
+ for (File element : classpath.getElements()) {
+ // We only cache dexed .jar files, not directories.
+ if (!element.toString().endsWith(".jar")) {
+ return null;
+ }
+ key += "-" + md5(element);
+ }
+ return new File(CACHE_ROOT, key);
+ }
+
+ /**
+ * Copy the file 'content' into the cache with the given 'key'.
+ * This method assumes you're using the appropriate key for the content (and has no way to
+ * check because the key is a function of the inputs that made the content, not the content
+ * itself).
+ * We accept a null so the caller doesn't have to pay attention to whether we think we can
+ * cache the content or not.
+ */
+ public void insert(File key, File content) {
+ if (key == null) {
+ return;
+ }
+ logger.fine("inserting " + key);
+ if (!key.toString().startsWith(CACHE_ROOT.toString())) {
+ throw new IllegalArgumentException("key '" + key + "' not a valid cache key");
+ }
+ // Make sure the cache exists first.
+ new Mkdir().mkdirs(CACHE_ROOT);
+ // Copy it onto the same file system first, then atomically move it into place.
+ // That way, if we fail, we don't leave anything dangerous lying around.
+ File temporary = new File(key + ".tmp");
+ new Command.Builder().args("cp", content, temporary).execute();
+ new Command.Builder().args("mv", temporary, key).execute();
+ }
+}