发布日期:2022-08-07 21:46 点击次数:189
为了加速应用冷启动过程且不过度涉及业务改动,本文从虚拟机加载类的过程中找到优化项,且与业界的方案作了对比,并实现了半自动化的分析功能。类在使用或实例化之前需要被加载到虚拟机中并进行初始化。整个过程如下图所示:主要由LoadingClass和InitializingClass两部分组合。
LoadingClass旨在把Class从Dex加载到虚拟机中,但不涉及类的使用或执行流程。InitializingClass旨在保证使用类前已经经过了初始化流程,此流程嵌入类的使用或执行过程中。
加载类DefineClass主要通过SetupClass、InsertClass以及LoadClass将一个类加载到虚拟机中,最后返回mirror:Class对象指针。
SetupClass:设置类的访问标志以及ClassLoader。 InsertClass:将类插入到对应ClassLoader的ClassTable中,以便查找。 LoadClass:将类的属性及方法加载到类中。 类初始化类的属性或方法在使用前必须经过类的初始化。
InitializeClass:核验类、初始化父类、接口方法以及静态属性。 VerifyClass:核验类的合法性,在下一节详细分析。 核验类VerifyClass使用VerifyClassUsingOatFile或PerformClassVerification方法之一去核查Class。其中PerformClassVerification就包含了Systrace中耗时VerifyClass的Tag,如下图所示:
从上面的分析可以看出,应该尽可能让核查走VerifyClassUsingOatFile流程,即通过Oat文件状态位核查成功。Oat文件中类的状态位是什么以及为什么状态位不等于kStatusVerified是问题的突破点。
通过oatdump命令去dump相应的odex文件,可以查看类的状态位,操作方式如下:
VLOG默认是不会被打印的,需要动态开启,开启的方式可以通过:art::gLogVerbosity.class_linker = true而打开,因为本项目需要看到dex2oat和其他进程的打印情况,本人是在系统源码中进行编译生成的so,然后,通过ptrace注入so到Zygote的,此方法需要root设备,如果只需要查看本进程, yahoo邮箱应不需要这么麻烦,具体方法还未探索,但思路应该是一致的。举例如下,本人碰到的问题是AppCompat包中的类不能被核验通过。
将Runtime对象中的verify_设置成verifier::VerifyMode::kNone。
需要通过Runtime对象首地址遍历查找verify_属性,魔改厂商可能带来兼容性问题。 缺少VerifyClass过程,可能会后置发现非法指令问题。 对zygote中值verify_进行修改将造成cow内存消耗。 将多出EnsureSkipAccessChecksMethods一步处理逻辑,将类中每个函数flag进行修改,此处逻辑没有对单个类进行处理,所以,每个类的每个函数的flag都将被无谓修改,如下图所示:为了降低方案实施难度,现已将方案平台化,只要将apk拖入网页中即可看到类核验不通过的原因。
作者:大力智能技术
链接:https://juejin.cn/post/6951225539990388750
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。