diff options
author | Hugo Hudson <hugohudson@google.com> | 2011-11-30 12:12:51 +0000 |
---|---|---|
committer | Hugo Hudson <hugohudson@google.com> | 2011-12-16 01:38:42 +0000 |
commit | 7adb0bfc638ba2f6ce896975ee49c889e73bad44 (patch) | |
tree | 63f03346df0eb5935cbe27ba7e348d7a8bdc6bf2 /dx | |
parent | 69c475676546a97f872df9e19125c0154b40ae0b (diff) | |
download | android_dalvik-7adb0bfc638ba2f6ce896975ee49c889e73bad44.tar.gz android_dalvik-7adb0bfc638ba2f6ce896975ee49c889e73bad44.tar.bz2 android_dalvik-7adb0bfc638ba2f6ce896975ee49c889e73bad44.zip |
DexGenerator: allow specifying dex cache dir.
- Switches DexGenerator to not use extended opcodes. This allows us to
write suitable files for earlier versions of Android.
- Allows caller to specify optimised dex directory. This allows us to
get around /data/dalvik-cache not being world-writeable.
- Allows caller to specify optimised dex files cache dir. This allows
us to skip the requirement of being able to write to /sdcard.
Change-Id: I2cae2e187ccf5b20b98763cb7eb791383a7d5a59
Diffstat (limited to 'dx')
-rw-r--r-- | dx/junit-tests/HelloWorldMaker.java | 6 | ||||
-rw-r--r-- | dx/junit-tests/com/android/dx/gen/DexGeneratorTest.java | 17 | ||||
-rw-r--r-- | dx/src/com/android/dx/gen/DexGenerator.java | 38 |
3 files changed, 49 insertions, 12 deletions
diff --git a/dx/junit-tests/HelloWorldMaker.java b/dx/junit-tests/HelloWorldMaker.java index 001f31a90..038701c77 100644 --- a/dx/junit-tests/HelloWorldMaker.java +++ b/dx/junit-tests/HelloWorldMaker.java @@ -22,6 +22,8 @@ import com.android.dx.gen.Local; import com.android.dx.gen.MethodId; import com.android.dx.gen.Type; import com.android.dx.rop.code.AccessFlags; + +import java.io.File; import java.io.PrintStream; public class HelloWorldMaker { @@ -79,7 +81,9 @@ public class HelloWorldMaker { generator.declare(helloWorld, "Generated.java", AccessFlags.ACC_PUBLIC, Type.OBJECT); // load the dex - ClassLoader loader = generator.load(HelloWorldMaker.class.getClassLoader()); + File outputDir = new File("."); + ClassLoader loader = generator.load(HelloWorldMaker.class.getClassLoader(), + outputDir, outputDir); Class<?> helloWorldClass = loader.loadClass("HelloWorld"); helloWorldClass.getMethod("hello").invoke(null); } diff --git a/dx/junit-tests/com/android/dx/gen/DexGeneratorTest.java b/dx/junit-tests/com/android/dx/gen/DexGeneratorTest.java index 8b23805d7..8dc6c8db5 100644 --- a/dx/junit-tests/com/android/dx/gen/DexGeneratorTest.java +++ b/dx/junit-tests/com/android/dx/gen/DexGeneratorTest.java @@ -22,6 +22,10 @@ import static com.android.dx.rop.code.AccessFlags.ACC_PRIVATE; import static com.android.dx.rop.code.AccessFlags.ACC_PROTECTED; import static com.android.dx.rop.code.AccessFlags.ACC_PUBLIC; import static com.android.dx.rop.code.AccessFlags.ACC_STATIC; + +import junit.framework.TestCase; + +import java.io.File; import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; @@ -29,7 +33,6 @@ import java.lang.reflect.Method; import java.util.Arrays; import java.util.List; import java.util.concurrent.Callable; -import junit.framework.TestCase; /** * This generates a class named 'Generated' with one or more generated methods @@ -1660,7 +1663,15 @@ public final class DexGeneratorTest extends TestCase { throw new IllegalStateException("no call() method"); } - private Class<?> loadAndGenerate() throws IOException, ClassNotFoundException { - return generator.load(DexGeneratorTest.class.getClassLoader()).loadClass("Generated"); + public static File getDataDirectory() throws Exception { + Class<?> environmentClass = Class.forName("android.os.Environment"); + Method method = environmentClass.getMethod("getDataDirectory"); + Object dataDirectory = method.invoke(null); + return (File) dataDirectory; + } + + private Class<?> loadAndGenerate() throws Exception { + return generator.load(getClass().getClassLoader(), + getDataDirectory(), getDataDirectory()).loadClass("Generated"); } } diff --git a/dx/src/com/android/dx/gen/DexGenerator.java b/dx/src/com/android/dx/gen/DexGenerator.java index 7cde9a93f..56c516b0c 100644 --- a/dx/src/com/android/dx/gen/DexGenerator.java +++ b/dx/src/com/android/dx/gen/DexGenerator.java @@ -16,6 +16,10 @@ package com.android.dx.gen; +import static com.android.dx.rop.code.AccessFlags.ACC_CONSTRUCTOR; +import static com.android.dx.rop.code.AccessFlags.ACC_PRIVATE; +import static com.android.dx.rop.code.AccessFlags.ACC_STATIC; + import com.android.dx.dex.DexFormat; import com.android.dx.dex.DexOptions; import com.android.dx.dex.code.DalvCode; @@ -26,12 +30,12 @@ import com.android.dx.dex.file.DexFile; import com.android.dx.dex.file.EncodedField; import com.android.dx.dex.file.EncodedMethod; import com.android.dx.rop.code.AccessFlags; -import static com.android.dx.rop.code.AccessFlags.*; import com.android.dx.rop.code.LocalVariableInfo; import com.android.dx.rop.code.RopMethod; import com.android.dx.rop.cst.CstString; import com.android.dx.rop.cst.CstType; import com.android.dx.rop.type.StdTypeList; + import java.io.File; import java.io.FileOutputStream; import java.io.IOException; @@ -102,7 +106,9 @@ public final class DexGenerator { * Returns a .dex formatted file. */ public byte[] generate() { - DexFile outputDex = new DexFile(new DexOptions()); + DexOptions options = new DexOptions(); + options.targetApiLevel = DexFormat.API_NO_EXTENDED_OPCODES; + DexFile outputDex = new DexFile(options); for (TypeDeclaration typeDeclaration : types.values()) { outputDex.add(typeDeclaration.toClassDefItem()); @@ -116,9 +122,25 @@ public final class DexGenerator { } /** - * Loads the generated types into the current dalvikvm process. + * Loads the generated types into the current process. + * + * <p>All parameters are optional, you may pass {@code null} and suitable + * defaults will be used. + * + * <p>If you opt to provide your own output directories, take care to + * ensure that they are not world-readable, otherwise a malicious app will + * be able to inject code to run. A suitable parameter for these output + * directories would be something like this: + * {@code getApplicationContext().getDir("dx", Context.MODE_PRIVATE); } + * + * @param parent the parent ClassLoader to be used when loading + * our generated types + * @param dexOutputDir the destination directory wherein we will write + * emitted .dex files before they end up in the cache directory + * @param dexOptCacheDir where optimized .dex files are to be written */ - public ClassLoader load(ClassLoader parent) throws IOException { + public ClassLoader load(ClassLoader parent, File dexOutputDir, File dexOptCacheDir) + throws IOException { byte[] dex = generate(); /* @@ -128,7 +150,7 @@ public final class DexGenerator { * * TODO: load the dex from memory where supported. */ - File result = File.createTempFile("Generated", ".jar"); + File result = File.createTempFile("Generated", ".jar", dexOutputDir); result.deleteOnExit(); JarOutputStream jarOut = new JarOutputStream(new FileOutputStream(result)); jarOut.putNextEntry(new JarEntry(DexFormat.DEX_IN_JAR_NAME)); @@ -136,9 +158,9 @@ public final class DexGenerator { jarOut.closeEntry(); jarOut.close(); try { - Class<?> pathClassLoader = Class.forName("dalvik.system.PathClassLoader"); - return (ClassLoader) pathClassLoader.getConstructor(String.class, ClassLoader.class) - .newInstance(result.getPath(), parent); + return (ClassLoader) Class.forName("dalvik.system.DexClassLoader") + .getConstructor(String.class, String.class, String.class, ClassLoader.class) + .newInstance(result.getPath(), dexOptCacheDir.getAbsolutePath(), null, parent); } catch (ClassNotFoundException e) { throw new UnsupportedOperationException("load() requires a Dalvik VM", e); } catch (InvocationTargetException e) { |