diff options
Diffstat (limited to 'tools/runner')
-rw-r--r-- | tools/runner/Android.mk | 28 | ||||
-rw-r--r-- | tools/runner/java/dalvik/runner/Dx.java | 13 | ||||
-rw-r--r-- | tools/runner/java/dalvik/runner/Md5Cache.java | 115 |
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(); + } +} |