通过更改 libcore 的 Runtime.class 来公开新的 ART 功能

Expose new ART functionality by changing the Runtime.class of libcore

我在 Android 运行时 (ART) 中插入了一些新功能,现在我想通过接口将其公开给外界。由于它是本机代码,我将使用 JNI 接口来调用此新功能,其方式与垃圾收集器功能类似:Runtime.getInstance().gc().

但是,我不关心构建可供 IDE 使用的新 SDK,因为我将手动将字节码注入将进行调用的 .dex 文件。

我在 libcore/luni 中编辑了 Runtime.java,在 art 中编辑了 java_lang_Runtime.cc,方法与 gc() 功能类似。我正在生成新的 libart.socore-libart.jar 并将它们闪存到设备上。 但是,当我尝试重启设备时,我收到消息:

Failed to register native method java.lang.Runtime.myMethod()V in /system/framework/core-libart.jar
...
----- class 'Ljava/lang/Runtime;' cl=0x0 -----
vtable (24 entries, 11 in super):
// 24 entries are listed here. My entry is missing.
...

Runtime.java 中,我注册了本机方法并使用 @hide 在完整构建中抑制了一些警告。例如,

/** @hide */
public native void myMethod();

java_lang_Runtime.cc 中,我定义了函数(将调用 ART 内部的东西)并使用宏将其注册到 gMethods[] 数组。例如,

static void Runtime_myMethod(JNIEnv*, jclass) {  
// body
}

NATIVE_METHOD(Runtime, myMethod, "()V")

设备处于引导循环中。还有其他我应该编辑的文件吗?我应该构建额外的模块,还是在设备上发送任何其他文件?

顺便说一句,我不想​​构建一个新的 SDK 至于调用 myMethod 我会将 Dalvik bytecode 注入到一个 APK 文件中。基本上我会获取Runtime实例,然后调用方法。

问题:

Android 出厂图像与框架组件进行了预优化。 文件 boot.oat 包含预先优化的代码(或 odex 代码),可以通过读取 boot.art 文件中包含的指针来访问这些代码。

这两个文件仅包含 boot classpath 的代码。 框架的其余部分和系统应用程序的其余部分(在 apppriv-app 中)文件夹具有独立的 odex 文件。

在这个预优化阶段,dex代码被取出的框架模块(jar,或apk),使用dex2oat编译,生成的代码位于我刚才提到的文件中。

我试过的一些东西:

仅运送 libart.socore-libart.jar 不起作用,即使后者包含 dex 代码。这是因为 运行time 仍在尝试从 boot.oat.

中读取该信息

通过修改设备配置做预优化,aosp build system可以生成boot.oat|art和其余的odex文件(更多here)。我预计闪烁所有这些应该工作,但它没有。 (至少对于 marshmallow-release 分支,在 nexus6 上)

我试过刷新整个 aosp 生成的构建,但它没有用,即使我构建的自定义内核禁用了安全功能 (verity)。

我确信其中一些应该有效,但在构建 OS.

期间必须考虑其他一些事情

解法:

最后的手段是 deodexing,谢天谢地,它奏效了。 我写了一个小的 script 用于 Marshmallow 上的 Nexus 6。

脚本,在第一阶段,它从相关位置取出所有 oat/odex 代码,并将其取消优化为 dex 代码,感谢 oat2dex and smali 项目. 在第二阶段,它将 dex 代码打包回框架模块 (jars/apks).

将全新的 core-libart.jar 发送到设备仍然无法正常工作(不知道为什么),但是在将 dex 文件打包到模块之前修改它们就可以了! :))

libart.so 现在可以找到 Runtime.myMethod(),它可以被应用程序调用(smali 再次修补)到 运行 我在 ART.[=36 中的代码=]