Search code examples
androidandroid-ndkjava-native-interfacedalvik

CLI on DalvikVM fails on JNI lib


I need to run a command line version of java application on Android(Yeah I know it's not trivial).

I'm trying to start it using Dalvikvm, it actually starts but somewhere later my code fails because it starts using android.util.log and throws this exception.

java.lang.UnsatisfiedLinkError: println_native
    at android.util.Log.println_native(Native Method)
    at android.util.Log.i(Log.java:159)
    at org.slf4j.impl.AndroidLogger.info(AndroidLogger.java:151)
    at org.gihon.client.TunnelingClient.<init>(TunnelingClient.java:62)
    at org.gihon.client.CLI.main(CLI.java:95)
    at dalvik.system.NativeStart.main(Native Method)

I tried setting the environment variables, I set the LD_LIBRARY_PATH and the BOOTCLASSPATH variables. I even tried preloading liblog with LD_PRELOAD but nothing fixed that. It seems that something is wrong/different with the way dalvikvm sets the environment.


Solution

  • Good question! I had to dig a bit to figure this out.

    There are a slew of JNI methods in libandroid_runtime.so that don't get bound by default, when you're using the dalvikvm command. Unfortunately, you can't just do a System.loadLibrary("android_runtime"), because this doesn't actually bind all the native methods.

    However, after some digging, it turns out there is an internal, non-public, not guaranteed to be there class called com.android.internal.util.WithFramework, whose purpose is to load libandroid_runtime.so and bind all its JNI methods.

    To use it, just throw com.android.internal.util.WithFramework in front of your class name, on the dalvikvm command, like so:

    dalvikvm -cp /some/path/classes.dex com.android.internal.util.WithFramework my.example.cls "This is an argument"
    

    (Note: This only works on pre-M devices, due to the WithFramework class being removed in M - thanks for the heads up @JaredRummler)