Android / Dalvik VM Cannot Find Native Framework Methods

82 views Asked by At

I am trying something a little unconventional so I am not surprised that I am encountering difficulties.

I want to use an Ubuntu chroot on an Android tablet as a UNIX CLI IDE for various kinds of software development. Since I am working on an Android device, I was curious if I could build Android code against the SDK, dx (Dalvik eXchange compiler) the compiled bytecode, copy out to the sdcard, and execute with dalvikvm.

A 'hello world' test (with no Android API) worked fine but the handful of Android API calls I've tried failed with java.lang.UnsatisfiedLinkError. The calls into the API that I have tried seem to call down to (presumably JNI) native methods that Dalvik cannot find at runtime:

java.lang.UnsatisfiedLinkError: No implementation found for boolean android.os.SystemProperties.native_get_boolean(java.lang.String, boolean) (tried Java_android_os_SystemProperties_native_1get_1boolean and Java_android_os_SystemProperties_native_1get_1boolean__Ljava_lang_String_2Z)
        at android.os.SystemProperties.native_get_boolean(Native Method)
        at android.os.SystemProperties.getBoolean(SystemProperties.java:114)
        at android.text.TextUtils.<clinit>(TextUtils.java:1919)
        at android.media.AudioAttributes$Builder.build(AudioAttributes.java:337)
        at android.media.AudioRecord.<init>(AudioRecord.java:233)
        at AltTest.main(alttest.java:34)

For a concrete example, I tried the following code as, say, test.java:

import android.media.AudioRecord;

class APITest {

 public static void main(String[] args) {
  System.out.println("Hello, world!");

  // compiles, 'dx'ifies, and runs up this this point
  int apiMinimumBufferSize = AudioRecord.getMinBufferSize(44100,16,2);

  System.out.println("Your audio sample buffer must be at least " + apiMinimumBufferSize + " bytes.");
 }

}

Compiled to APITest.class with the following:

root@localhost:~/projects/test# CLASSPATH=/root/android-sdk-linux/platforms/android-21/android.jar javac test.java

dxified:

root@localhost:~/projects/test# /root/android-sdk-linux/build-tools/25.0.0/dx --dex --output=test.dex APITest.class

Note that we would not expect APITest.class to execute in the chroot java environment due to the android.jar dependency:

root@localhost:~/projects/test# java -cp ".:/root/android-sdk-linux/platforms/android-21/android.jar" APITest
Hello, world!
Exception in thread "main" java.lang.RuntimeException: Stub!
        at android.media.AudioRecord.getMinBufferSize(AudioRecord.java:21)
        at APITest.main(test.java:9)

But, if we place a copy of the dxified build where we can see it from the non-chrooted android environment:

root@localhost:~/projects/test# cp test.dex /mnt/android_root/sdcard

Then we can attempt to execute the code in dalvikvm on a running Android machine:

[non-root-user]@[product_ID]:/ # su
root@[product_ID]:/ # cd sdcard
root@[product_ID]:/sdcard # dalvikvm -cp test.dex APITest
Hello, world!
java.lang.UnsatisfiedLinkError: No implementation found for int android.media.AudioRecord.native_get_min_buff_size(int, int, int) (tried Java_android_media_AudioRecord_native_1get_1min_1buff_1size and Java_android_media_AudioRecord_native_1get_1min_1buff_1size__III)
        at android.media.AudioRecord.native_get_min_buff_size(Native Method)
        at android.media.AudioRecord.getMinBufferSize(AudioRecord.java:592)
        at APITest.main(test.java:9)

I have scanned all the lib*.so files in the native android filesystem (e.g. '/system/lib' and '/vendor/lib') for dynamic symbols that look like the method names that dalvikvm was looking for and other possible "DLL entry points" based on my vague knowledge of JNI. I don't know exactly what I am looking for. So far, I have only found a random scattering of potentially related methods.

I have tried running dalvikvm under strace (which I carefully liberated from my chroot so I could run it against shell commands in the native Android environment). My read of the system-call traffic was that, other than reading many of the libs in /system/vendor, dalvikvm gave little hint regarding where it would have expected those native implementations to be.

One idea I had was to figure out how to make dalvikvm tell me where it found a native implementation. Using Ruboto IRB, one may call Android API methods and many of these call through to native implementations. If there were available introspection in Dalvik and I knew how to call on it, or if I knew how to attach debugging equipment to a running process that has been activated by the Android GUI, or if I knew how to invoke Android GUI apps from the CLI presented by the Terminal Emulator app, I could imagine trying something like that.

I have also imagined disassembling a working app to study the interrelationships between the parts and attempt to back-out build or run-time requirements for practical Dalvik code in the Android ecosystem.

Most of my ideas are a bit "blue sky", heading off into an open research question from a position of ignorance. I'm sure I would learn a lot but it might take me a long time to find a way to move forward.

And, so, I'm hoping that someone with relevant experience might have the grace to tell me what they know about the mistakes I am making and how to fix them.


So, to get some Android code running from the terminal:

What am I missing from the ad-hoc build process detailed above?

Or, what am I missing from the execution context at run-time?


Thanks!

0

There are 0 answers