Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android remote code loading

I am developing a library for Android that requires frequent updates from a central server. I was thinking how nice it would be if my library could update itself -- or if I could just release a bootstrap library that downloads the target library when the app is installed.

I see this class in 1.5 called "DexClassLoader" but there seems to be precious little on the web besides the API docs. Has anyone used this successfully for the scenario which I described?

Also, do the terms of the Android Market permit such a thing?

like image 839
sehugg Avatar asked Jun 16 '09 14:06

sehugg


3 Answers

I've successfully used DexClassLoader. It's important to provide a dexOutputDir that is actually writeable by your app, so not /data/dalvik-cache. Otherwise the log will show one or two lines about failing to write there, followed by ClassNotFoundException.

cl = new DexClassLoader("/full/path/com.example.apk",
                        getFilesDir().getAbsolutePath(),// /data/data/foo/files
                        null,  // native lib path, I haven't used this
                        MyClass.class.getClassLoader());
// This doesn't make Class.forName() work, instead I do this:
Class<?> foo = cl.loadClass("com.example.foo");

To make Class.forName() work, you could try Thread.setContextClassLoader() (I haven't).

like image 192
Chris Boyle Avatar answered Nov 10 '22 06:11

Chris Boyle


Indeed what you want is supported and works. DexClassLoader is not working as expected for me, but the following code works fine.

DexFile df = new DexFile(new File("/data/app/my_downloaded_lib.apk"));
ClassLoader cl = getClassLoader();
Class clazz = df.loadClass("com/my/lib/MyClass", cl);

About the market question, i don't see any issue with this, but you have to read the EULA to be sure.

like image 43
Lucas S. Avatar answered Nov 10 '22 05:11

Lucas S.


DexClassLoader is the right answer. Applications should never use DexFile directly (it's meant to be used by class loaders).

You could use external storage (/sdcard), or the app's private data area, for the dexOutputDir parameter. External storage is usually larger, but if the card is ejected your app will be killed, and due to the lack of file permission enforcement it's easy for a third party to replace your code. This can allow malicious apps to cause your app to perform arbitrary actions. (If you want to do it anyway, get the path via Environment.getExternalStorageDirectory(); requires the WRITE_EXTERNAL_STORAGE permission.)

The app-private data area (get the path from Context.getFilesDir()) is more secure, and also has the advantage of being cleaned up automatically if the app is uninstalled. This is the recommended approach.

like image 45
fadden Avatar answered Nov 10 '22 06:11

fadden