33

I'm wondering if and how one can load dex or class files dynamically in dalvik, some quick'n'dirty test function I wrote was this:

    public void testLoader() { 
            InputStream in; 
            int len; 
            byte[] data = new byte[2048]; 
            try { 
                    in = context.getAssets().open("f.dex"); 
                    len = in.read(data); 
                    in.close(); 
                    DexFile d; 
                    Class c = defineClass("net.webvm.FooImpl", data, 0, len); 
                    Foo foo = (Foo)c.newInstance(); 
            } catch (IOException e1) { 
                    // TODO Auto-generated catch block 
                    e1.printStackTrace(); 
            } catch (IllegalAccessException e) { 
                    // TODO Auto-generated catch block 
                    e.printStackTrace(); 
            } catch (InstantiationException e) { 
                    // TODO Auto-generated catch block 
                    e.printStackTrace(); 
            } 
    } 

whereas the Foo interface is this

    public interface Foo { 
            int get42(); 
    } 

and f.dex contains some dx'ed implementation of that interface:

    public class FooImpl implements Foo { 
            public int get42() { 
                    return 42; 
            } 
    } 

The above test driver throws at defineClass() and it doesn't work and I investigated the dalvik code and found this:

http://www.google.com/codesearch/p?hl=en#atE6BTe41-M/vm/Jni.c&q=Jni.c...

So I'm wondering if anyone can enlighten me if this is possible in some other way or not supposed to be possible. If it is not possible, can anyone provide reasons why this is not possible?

anselm
  • 792
  • 1
  • 8
  • 21
  • 1
    You have `DexFile d`, then never assign or use it. AFAIK, `DexClassLoader` is the correct approach, though I haven't used it personally. – CommonsWare Jun 11 '10 at 12:51
  • That's true, the DexFile is some remainder of another dirty hack I tried, I'll look into DexClassLoader now. – anselm Jun 11 '10 at 13:24
  • I tried using DexClassLoader, but that doesn't work either. I created a derived class and called the superconstructor with super("/sdcard/f.jar", "/sdcard", null, getSystemClassLoader()); But no success. Wether defineClass nor findClass return any class that is attached dynamically. My suspect is that android does not support this at all, otherwise normal defineClass should work already. Probably because of some security issues. But I'd definately like to hear reasons, I also started a thread on android-developers Google group. – anselm Jun 11 '10 at 13:56
  • DexClassLoader works, as illustrated by dalvik/tests/068-classloader in the source tree. It's used by apps that want a "plugin" architecture. Bear in mind that the class is only visible by going through the custom class loader. – fadden Jun 11 '10 at 23:36
  • Maybe PathClassLoader is better: http://stackoverflow.com/questions/2903260/android-using-dexclassloader-to-load-apk-file – diyism Mar 21 '12 at 09:53
  • Look at: http://stackoverflow.com/questions/5104823/dexclassloader-on-android-honeycomb – diyism Mar 21 '12 at 10:01
  • Could you plese replace http://www.google.com/codesearch/p?hl=en#atE6BTe41-M/vm/Jni.c&q=Jni.c as it is broken ? – Mr_and_Mrs_D Nov 28 '13 at 17:14

1 Answers1

53

There's an example of DexClassLoader in the Dalvik test suite. It accesses the classloader reflectively, but if you're building against the Android SDK you can just do this:

String jarFile = "path/to/jarfile.jar";
DexClassLoader classLoader = new DexClassLoader(
    jarFile, "/tmp", null, getClass().getClassLoader());
Class<?> myClass = classLoader.loadClass("MyClass");

For this to work, the jar file should contain an entry named classes.dex. You can create such a jar with the dx tool that ships with your SDK.

JFL
  • 1,502
  • 14
  • 18
Jesse Wilson
  • 39,078
  • 8
  • 121
  • 128
  • 2
    Replace "/tmp" with something else on the device. – fadden Jun 11 '10 at 23:32
  • 3
    dx.bat --dex --output=E:\classes.dex E:\test_app.jar – diyism Mar 21 '12 at 09:24
  • 1
    That's a lot better than the `build.xml` tweaks in http://android-developers.blogspot.com/2011/07/custom-class-loading-in-dalvik.html - but is there a way to have Eclipse do the dx step on every build? – Jon Shemitz Jun 06 '13 at 23:50
  • 1
    I have a question: How do you unload what you've loaded? – android developer Feb 19 '14 at 12:03
  • @androiddeveloper there is no way to unload a class in java. – Snicolas Jul 17 '14 at 03:56
  • @Snicolas you can only load new classes? what if (as an alternative) I try to load from a file that already has the same package and class name, and have an empty implementation inside the class? is it possible? will it minimize the memory being used as I don't need the real loaded class anymore? – android developer Jul 17 '14 at 11:02
  • @androiddeveloper, I don'T think it can work, but please try. Maybe you could also have a look at ActivityTestCase source code, there is a scrubClass method that may help. http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.4.2_r1/android/test/ActivityTestCase.java/ – Snicolas Jul 20 '14 at 16:13
  • 1
    @Snicolas Interesting. Sadly I can't do it right now, as I have an army-draft (I'm from Israel), so I hope to remember to get back to this some time in the future. thank you. – android developer Jul 28 '14 at 13:49