CLI на DalvikVM терпит неудачу в JNI lib

Мне нужно запустить версию java-приложения для командной строки на Android (да, я знаю, что это не тривиально).

Я пытаюсь запустить его с помощью Dalvikvm, он начинается, но где-то позже мой код выходит из строя, потому что он начинает использовать android.util.log и выдает это исключение.

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)

Я попытался установить переменные среды, я установил переменные LD_LIBRARY_PATH и BOOTCLASSPATH. Я даже пытался предварительно загрузить liblog с LD_PRELOAD, но ничего не исправил. Кажется, что что-то неправильно/отличается тем, как dalvikvm устанавливает среду.

Ответ 1

Хороший вопрос! Мне пришлось немного разобраться, чтобы понять это.

В libandroid_runtime.so есть множество методов JNI, которые не связаны по умолчанию, когда вы используете команду dalvikvm. К сожалению, вы не можете просто сделать System.loadLibrary( "android_runtime" ), потому что это фактически не связывает все собственные методы.

Однако после некоторого копания выясняется, что существует внутренний, непубличный, не гарантированный класс класса com.android.internal.util.WithFramework, целью которого является загрузка libandroid_runtime.so и привязка всех его JNI.

Чтобы использовать его, просто бросьте com.android.internal.util.WithFramework перед именем вашего класса в команде dalvikvm, например:

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

(Примечание. Это работает только на устройствах pre-M из-за того, что класс WithFramework

Ответ 2

Для android M, я нашел, что этот метод работает.
Создайте helloworld.sh script, чтобы сопровождать ваш файл jar\zip:

#!/system/bin/sh
# Copied by example from am command
base=/system
export CLASSPATH=/path/to/your/jar/HelloWorld.jar
exec app_process $base/bin HelloWorldMainClass "[email protected]"

app_process, похоже, запускает ваш код Java со всеми классами Java и загруженными общими библиотеками, поэтому вы можете использовать оба класса SDK, такие как android. util.log.Log И "секретные" родные классы, например ActivityManagerNative, которые используются в других командах оболочки adb и не присутствуют в SDK.

BTW, для команды java shell, которую я создал, мне пришлось прибегнуть к использованию отражения для вышеуказанных классов, потому что мне кажется, что нет возможности правильно компилировать без клонирования и построения всего AOSP...
Если кто-то знает более простой способ, например, используйте ActivityManagerNative в Java-коде без отражения, я был бы признателен за помощь.