【个人笔记一】ART系统类的编译解析加载探究

在ART上用YAHFA、Legend以及一个java层实现的Andix:ART深度探索开篇:从Method Hook谈起对系统中不同的类进行hook,发现除了framework层的类(如telephonymanager)和应用中的类有效外,对于java核心库的类(如IOBridge和Class等)的hook都无效,所以我就以telephonymanager和IOBridge这两个类为例,试图从编译解析加载等角度分析这两者的区别以及造成hook结果不同的原因,如果有大牛能指点一二的话,不胜感激。。。


首先对于应用层的类,由于是标准的从apk经过dex2oat生成OAT文件(虽然后缀还是dex),然后加载到系统中进行类解析和方法链接等流程,这种流程在老罗博客和上述三种常见的ART hook上进行了详细分析,而上述三种hook方法正是针对这种流程设计的,所以毫无疑问有效,此处不再赘述。


接下来正式开始,首先看下源码路径

telephonymanager等框架层类位于android源码目录\framework\base路径下,经编译后生成的jar包位于android系统的/system/framework/framework.jar

IOBridge等java核心类位于android源码目录\libcore路径下,经编译后生成的jar包位于android系统的/system/framework/core.jar或者/system/framework/core-libart.jar


从这个角度看两者也没太大区别,都是从源码生成了jar包,位于了同一个路径下的不同jar包,但是这个jar包是怎么被加载到内存中去的呢?由于ART系统上执行APK时都被从DEX编译转换成了OAT文件,然后进行加载,所以不禁会问系统的JAR包被如何处理成OAT的呢?


这里就要引出boot.art和boot.oat这两个文件了,这两个文件都位于手机系统的/data/dalvik-cache/arm目录下。boot.art是一个img文件,而boot.oat文件可以将其理解为ART虚拟机的启动类,这两个文件是dex2oat命令将Android系统必须的的jar包编译生成的,这两个文件相互联系,缺一不可,boot.art这个img文件直接被映射到ART虚拟机的堆空间中,包含了boot.oat中的某些对象实例以及函数地址。老罗的文章中也讲了,我们后边再介绍,先看看这两个文件的来历。

这两个文件是从什么地方生成的呢?删除了这两个boot文件,那么在下次android启动的时候,系统就会重新生成这两个文件,通过查找手机log中的dex2oat关键字就可以查看到这两个文件的生成命令。注意删除了这两个文件后,重新启动也会重新解析apk,所以会花较长时间。

08-09 16:10:47.463: I/art(324): GenerateImage: /system/bin/dex2oat --image=/data/dalvik-cache/arm/system@framework@boot.art --dex-file=/system/framework/core-libart.jar --dex-file=/system/framework/conscrypt.jar --dex-file=/system/framework/okhttp.jar --dex-file=/system/framework/core-junit.jar --dex-file=/system/framework/bouncycastle.jar --dex-file=/system/framework/ext.jar --dex-file=/system/framework/framework.jar --dex-file=/system/framework/telephony-common.jar --dex-file=/system/framework/voip-common.jar --dex-file=/system/framework/ims-common.jar --dex-file=/system/framework/apache-xml.jar --dex-file=/system/framework/org.apache.http.legacy.boot.jar --oat-file=/data/dalvik-cache/arm/system@framework@boot.oat --instruction-set=arm --instruction-set-features=smp,div,atomic_ldrd_strd --base=0x6fc33000 --runtime-arg -Xms64m --runtime-arg -Xmx64m --image-classes=/system/etc/preloaded-classes --instruction-set-variant=krait --instruction-set-features=default
08-09 16:10:47.632: I/dex2oat(627): /system/bin/dex2oat --image=/data/dalvik-cache/arm/system@framework@boot.art --dex-file=/system/framework/core-libart.jar --dex-file=/system/framework/conscrypt.jar --dex-file=/system/framework/okhttp.jar --dex-file=/system/framework/core-junit.jar --dex-file=/system/framework/bouncycastle.jar --dex-file=/system/framework/ext.jar --dex-file=/system/framework/framework.jar --dex-file=/system/framework/telephony-common.jar --dex-file=/system/framework/voip-common.jar --dex-file=/system/framework/ims-common.jar --dex-file=/system/framework/apache-xml.jar --dex-file=/system/framework/org.apache.http.legacy.boot.jar --oat-file=/data/dalvik-cache/arm/system@framework@boot.oat --instruction-set=arm --instruction-set-features=smp,div,atomic_ldrd_strd --base=0x6fc33000 --runtime-arg -Xms64m --runtime-arg -Xmx64m --image-classes=/system/etc/preloaded-classes --instruction-set-variant=krait --instruction-set-features=default
08-09 16:10:47.639: I/dex2oat(627): setting boot class path to /system/framework/core-libart.jar:/system/framework/conscrypt.jar:/system/framework/okhttp.jar:/system/framework/core-junit.jar:/system/framework/bouncycastle.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/telephony-common.jar:/system/framework/voip-common.jar:/system/framework/ims-common.jar:/system/framework/apache-xml.jar:/system/framework/org.apache.http.legacy.boot.jar

从log中我们可以看到,生成boot.art和boot.oat文件主要依赖了core-libart.jar和framework.jar这两个文件,所以可以理解为telephonymanager和IOBridge所在的jar包经dex2oat打包到了boot.art和boot.oat文件中,所以下一步就可以直接分析boot.art和boot.oat文件是如何被加载到内存了。


由于这两个boot文件是由多个jar包生成的,而不是像apk那样通过一个classes.dex生成,所以情况可能会特殊,所以接下来的分析可能会回退到虚拟机启动流程分析入手,有兴趣可以看下老罗的几篇关于ART虚拟机的文章。

老罗的文章:Android运行时ART加载OAT文件的过程分析前半部分和网上其他一位大牛的文章:ART虚拟机启动之image空间都讲了boot镜像加载的流程,强烈推荐自己看下第二篇文章的讲解,比较简洁易懂。下面开始分析:


首先转载下大牛的流程图:



上述流程牵涉的代码位于以下三个文件中:

framework/base/cmds/app_process/app_main.cpp
frameworks/base/core/jni/AndroidRuntime.cpp
art/runtime/jni_internal.cc

首先AndroidRuntime::start函数中会进行jni的初始化,实际上就是加载虚拟机的so库,并从中导出三个函数,其中JNI_CreateJavaVM用来启动虚拟机。Android 5.0之后默认加载的就是libart.so。

JNI_CreateJavaVM主要负责创建ART虚拟机实例,并且启动ART虚拟机,然后给app_process返回JNIEnv和JavaVM。有了JNIEnv,app_process中才能使用JNI中的FindClass等函数。
创建虚拟机实例中,最主要的是Runtime::init函数,负责创建虚拟机堆空间,绑定Thread,创建和初始化classLinker。
利用gc::Heap创建堆空间时,主要有两件事情,加载boot.ar和boot.oat初始化imgae空间,另外就是与垃圾回收机制相关的东东(垃圾回收太复杂了,暂时略过,后面详谈)。


上述过程详前半部分细解析请查看我整理精简过的老罗的博客:Android ART运行时无缝替换Dalvik虚拟机的过程分析,为了省事我不再复制粘贴过来了,请自行跳转查看,然后再回来继续。


然后我们继续分析,从AndroidRuntime::startVm调用了JNI_CreateJavaVM,跳转到libart.so中执行的JNI_CreateJavaVM函数,函数JNI_CreateJavaVM的实现如下所示:

extern "C" jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
  ATRACE_BEGIN(__FUNCTION__);
  const JavaVMInitArgs* args = static_cast<JavaVMInitArgs*>(vm_args);
  if (IsBadJniVersion(args->version)) {
    LOG(ERROR) << "Bad JNI version passed to CreateJavaVM: " << args->version;
    ATRACE_END();
    return JNI_EVERSION;
  }
  RuntimeOptions options;
  for (int i = 0; i < args->nOptions; ++i) {
    JavaVMOption* option = &args->options[i];
    options.push_back(std::make_pair(std::string(option->optionString), option->extraInfo));
  }
  bool ignore_unrecognized = args->ignoreUnrecognized;
  if (!Runtime::Create(options, ignore_unrecognized)) {
    ATRACE_END();
    return JNI_ERR;
  }
  Runtime* runtime = Runtime::Current();
  bool started = runtime->Start();
  if (!started) {
    delete Thread::Current()->GetJniEnv();
    delete runtime->GetJavaVM();
    LOG(WARNING) << "CreateJavaVM failed";
    ATRACE_END();
    return JNI_ERR;
  }
  *p_env = Thread::Current()->GetJniEnv();
  *p_vm = runtime->GetJavaVM();
  ATRACE_END();
  retu
  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值