我在Android运行时(ART)中插入了一些新功能,现在我想通过界面将它暴露给外界。由于它是本机代码,我将使用JNI
接口来调用此新功能,与垃圾收集器功能类似:Runtime.getInstance().gc()
。
但是,我并不关心构建可供IDE使用的新SDK,因为我将手动将字节码注入将进行调用的.dex文件。
我已使用Runtime.java
函数以类似的方式编辑libcore/luni
中的java_lang_Runtime.cc
和art
中的gc()
。我正在生成新的libart.so
和core-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")
该设备位于bootloop上。我应该编辑其他文件吗?我应该在设备上构建额外的模块,还是发送任何其他文件?
顺便说一句,我不想为调用SDK
构建新的myMethod
我会将Dalvik bytecode
注入到APK文件中。基本上我将获取Runtime实例,然后调用该方法。
答案 0 :(得分:0)
问题:
Android通过预先优化的框架组件发布工厂映像。
文件boot.oat
包含预优化的代码(或odex代码),可以通过读取boot.art
文件中包含的指针来访问它。
这两个文件仅包含boot classpath
的代码。
框架的其余部分以及其他系统应用程序(在app
和priv-app
)文件夹中都有独立的odex
文件。
在此预优化阶段,dex代码取出框架模块(jar或apk),使用dex2oat
进行编译,结果代码驻留在我刚提到的文件中。
我尝试过的一些事情:
仅发送libart.so
和core-libart.jar
不起作用,即使后者包含dex代码。这是因为运行时仍在尝试从boot.oat
读取该信息。
通过修改设备配置以进行预优化,aosp build system
可以生成boot.oat|art
和其余odex
个文件(更多here)。我希望闪存所有这些都应该有效,但事实并非如此。
(至少对于marshmallow-release
分支,在nexus6上)
我已经尝试过闪存整个aosp生成的构建版本,但它无法正常工作,即使我使用已禁用安全功能(verity
)构建的自定义内核也是如此。
我确信其中一些应该有效,但在构建操作系统时必须考虑其他一些事项。
<强>解决方案:强>
最后的手段是deodexing
,幸好它有效。
我为Marshmallow的Nexus 6写了一个小script。
该脚本在第一阶段从相关位置取出所有oat/odex
代码,并将其取消优化为dex
代码,这要归功于oat2dex和{{ 3}}项目。
在第二阶段,它将dex
代码打包回框架模块(jars / apks)。
将全新的core-libart.jar
发送到设备仍然无法正常工作(不确定原因),但在将dex文件打包到模块之前修改它们就可以了!的:))强>
libart.so
现在可以找到Runtime.myMethod()
,可以由应用程序调用(再次修改)以在ART
内运行我的代码。