Android 9.0 ART编译分析(三)-虚拟机触发dex2oat编译流程
原创内容,转载请注明出处,多谢配合。
这部分是针对动态加载插件的编译,主要是由ClassLoader来触发的,下面简单总结下。
一、Android 的ClassLoder介绍
1.1 ClassLoder类
ClassLoader
抽象父类 。
BootClassLoader
加载Android 系统编译文件。
BaseDexClassLoader
PathClassLoader和DexClassLoader的父类,主要功能执行者。
PathClassLoader
加载已被安装的应用路径中.dex 文件。
DexClassLoader
加载指定路径中的.dex 文件。
1.2 初始化
getClassloader实际上就是选择对应classLoader并保证初始化的过程,常用的是Context去获取的。
/frameworks/base/core/java/android/app/ContextImpl.java@Overridepublic ClassLoader getClassLoader() { return mClassLoader != null ? mClassLoader : (mPackageInfo != null ? mPackageInfo.getClassLoader() : ClassLoader.getSystemClassLoader());}
不管是LoadedApk. getClassLoader 还是ClassLoader.getSystemClassLoader(),针对系统级别的类加载都是PathClassLoader。
1.3 DexClassLoader与PathClassLoader构造方法说明
DexClassLoader与PathClassLoader均继承BaseDexClassLoader,内部只包含构造方法,真正的功能实现都在BaseDexClassLoader。
两者构造方法解析:
public DexClassLoader(String dexPath, String optimizedDirectory, String librarySearchPath, ClassLoader parent) { / /热修复使用这个 super((String)null, (File)null, (String)null, (ClassLoader)null); throw new RuntimeException("Stub!"); }参数:dexPath:dex 文件路径列表,多个路径使用”:”分隔optimizedDirectory:经过优化的 dex 文件(odex)文件输出目录librarySearchPath:动态库路径(将被添加到 app 动态库搜索路径列表中)parent:这是一个 ClassLoader,这个参数的主要作用是保留 java 中 ClassLoader 的委托机制。
public PathClassLoader(String dexPath, String librarySearchPath, ClassLoader parent) { super((String)null, (File)null, (String)null, (ClassLoader)null); throw new RuntimeException("Stub!"); }参数:dexPath:文件或者目录的列表librarySearchPath:包含 lib 库的目录列表parent:父类加载器
二、ClassLoader相关流程
先上流程图
动态加载插件直接触发dex2oat编译流程
注:这里loadClass线路点到为止,因为它并不是本篇文章的重点。
两条路线解析:
先走dex编译,再走loadClass类加载。
1)6-17是makeDexElements 保存dexElements 并触发dex编译过程
DexPathList有一个Element[] dexElements; 是用来保存dex/resource(class path) 的集合,由makeDexElements来收集。makeDexElements 方法会遍历所有dex path,并将它们一个个封装为Element,保存到Element[]中,长度不够通过copyOf翻倍扩容。另外会通过loadDexFile开始走编译路线。
编译的核心方法在oat_file_manager.cc中的OpenDexFilesFromOat,这里通过oat_file_assistant.cc 执行isUpToDate判断dex文件是否需要编译,如果需要走它的MakeUpToDate方法,执行编译。
MakeUpToDate中如果需要执行编译会走GenerateOatFileNoChecks,最终调用其Dex2Oat方法,调整好参数传给dex2oat这个执行文件去Exec。
2)1-5是loadClass类加载过程
在ClassLoader中执行classLoader:这里遵循双亲委派机制,先判断当前ClassLoader是否加载过,如果没有就让父类去加载,父类都不加载,再轮到子类去加载。
BaseDexClassLoader执行findClass,实际是通过DexPathList去执行findClass。
因为之前makeDexElements给Element[] dexElements赋值了,这里DexPathList执行的findClass实际上是遍历所有dexElements,每一个element都执行findClass
而最终是交给DexFile去做的类加载:其具体流程不赘述,跟java ClassLoader差不多:
顺序经历如下流程:
- Loading:类的信息从文件中获取并加载到JVM内存中。
- Verifying:检查读入的结构是否符合JVM规范。
- Preparing:验证完正确,会分配一个结构来存储类信息。
- Resolving: 把这个类的常量池中的所有符号引用转变为直接引用。
- Initializing:执行静态初始化程序,把静态变量初始化成指定的值。
最终就是将dex字节码文件loader到内存,按虚拟机内存划分区域去存放对应的数据。
更多相关文章
- android 点击重新加载界面设计
- Android加载SD卡目录,文件夹遍历,图片设置,设置文件对应打开方式等
- 我的android 第9天 - 文件存储
- Android加载字体包及封装
- Android下拉刷新上拉加载控件,对所有View通用!
- Android之怎么操作文件(读写以及保存到sdcard)
- Android中strings.xml文件
- 三种方式实现自定义圆形页面加载中效果的进度条
- Android Studio导入.so库文件方法