8

我需要在 Android 上运行 java 应用程序的命令行版本(是的,我知道这不是微不足道的)。

我正在尝试使用 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 变量。我什至尝试使用 LD_PRELOAD 预加载 liblog,但没有解决这个问题。dalvikvm 设置环境的方式似乎有问题/不同。

4

2 回答 2

13

好问题!我不得不挖掘一下才能弄清楚这一点。

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"

(注意:这仅适用于 M 之前的设备,因为在 M 中删除了 WithFramework 类- 感谢@JaredRummler 的提醒)

于 2012-10-21T19:45:19.583 回答
6

对于 android M,我发现这种方法可行。
创建一个 helloworld.sh 脚本来伴随您的 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 "$@"

app_process似乎在加载所有 java 类和共享库的情况下启动您的 java 代码,因此您可以使用 android.util.log.Log 等 SDK 类和其他 adb shell 命令中使用的“秘密”本机类,例如 ActivityManagerNative,并且不存在于 SDK 中。

顺便说一句,对于我创建的 java shell 命令,我不得不对上述类使用反射,因为在我看来,如果不克隆和构建整个 AOSP 就无法正确编译...
如果有人知道更简单的方法例如在没有反射的Java代码中使用ActivityManagerNative,我会很感激帮助。

于 2015-12-10T15:20:34.900 回答