插件化&热修复
- 系统类加载器
- BootClassLoader
- java实现,包访问修饰符
- PathClassLoader
- PathClassLoader来加载系统类和应用程序类
- PathClassLoader通常用来加载已经安装的apk的dex文件(安装的apk的dex文件在/data/dalvik-cache)
- PathClassLoader来加载系统类和应用程序类
- DexClassLoader
- DexClassLoader可以加载dex文件和包含dex文件的压缩文件(比如jar和apk文件),不管加载那种文件,最终都是加载dex文件
- dexPath:dex相关文件的路径集合,多个文件用路径分割符分割,默认的文件分割符为 “:”
- optimizedDirectory:解压的dex文件储存的路径,这个路径必须是一个内部储存路径,一般情况下使用当钱应用程序的私有路径/data/data/Package Name/…
- librarySearchPath:包含C++库的路径集合,多个路径用文件分割符分割,可以为null
- parent:父加载器
- DexClassLoader可以加载dex文件和包含dex文件的压缩文件(比如jar和apk文件),不管加载那种文件,最终都是加载dex文件
- BootClassLoader
- 自定义加载器
- 新建DexPathList对象pathList
- 调用pathList.findClass
- 新建dexElements
- 遍历dexElements,调用element.findClass方法
- 获取DexFile对象dexFile,调用dexFile.findClass方法
- 底层替换方案
- System.load:可以加载自定义路径下的so
- System.loadLibaray:用来加载已经安装APK中的so
- 类加载方案
- 在element.findClass时加载bugfix的包
- 给每个类中的方法插入一个public static的ChangeQuickRedirect对象对所有方法使用Javassist插入代码:当该方法的changeQuickRedirect不为空时,直接将参数直接传入PatchProxy的accessDispatchVoid/accessDispatch方法并返回, 这样做跳过了原方法后面的代码
- Instant Run方案
- 创建新的AssetManager,并通过反射调用addAssetPath方法加载外部资源,这样新建的AssetManager就包含了外部资源
- 将AssetManager类型的mAsset字段的引用全部替换为新创建的AssetManager,主要是Resources中
- Hook技术
- 用来启动指定组件,一般hook点为Instrumentation中的execStartActivity
- 通过静态代理ProxyInstrumentation获取到Instrumentation对象
- 通过反射执行execStartActivity的方法
- 通过反射将Activity中的Instrumentation对象替换为ProxyInstrumentation
- 插件的类加载
- 获取插件apk地址
- 传入插件apk地址新建插件类加载DexClassLoader对象
- 通过反射dexElements获取插件中的类
- 通过反射dexElements获取当前应用中的类
- 创建新的dexElements数组合并两个中的类
- 用新的数组替换应用dexElements中的数组
- 插件的资源加载
- 通过addAssetPath加载外部资源,再构建新的Resource替换Application中的Resource
- 启动插件Activity
- 使用占坑的Activity通过AMS中对AndroidManifest.xml的验证
- hook execStartActivity时将intent替换为跳转到占坑Activity的intent,其中原始跳转intent存储在占坑intent中
- hook ActivityThread中的mH,读取占坑intent中的原始intent,通过setCompnent加载原始intent
- 使用占坑的Activity通过AMS中对AndroidManifest.xml的验证
- 打包资源文件 资源文件(res文件夹下的文件)通过 AAPT(Android Asset Packaging Tool)打包生成R.java类(资源索引表)以及.arsc资源文件。 经过aapt生成的R文件占4个字节
public static final int design_appbar_state_list_animator=0x7f020000;
- 第一位字节0x7f表示packageID,用来限定资源的来源。系统资源包是ox01,SharedLibrary类型资源包是0x00,普通App包则是0x7f;
- 次一位字节02表示typeID,用来表示资源类型,如drawable、layouts、anims、color、menu等;
- 后2字节0000表示EvtryID,指的是每一个资源在对应的TypID中出现的顺序。
- aapt生成的.arsc资源文件对应我们将apk解压(apk本质是一个zip压缩包)得到的Resources.arsc,它实际上就是App的资源索引表。简单来说,通过R.java文件与Resources.arsc就可以定位到资源的内存地址
- 处理 aidl files 如果有aidl文件,会通过aidl工具(源碼位于system/tools/aidl)打包成java接口类
- 编译(Compilers) R.java+工程源码+aidl.java通过javac生成.class文件
- dex(生成dex文件) 源码.class文件和第三方jar或者library通过dx工具打包成dex文件。AndroidStudio有提供 proguard、D8、R8等工具来处理这一流程。Android 还会针对 Dalvik 虚拟机和 Art 虚拟机对dex进行优化
- apkbuilder(生成未签名apk) apkbuilder工具会将所有没有编译的资源、.arsc资源、.dex文件打包到一个完成apk文件中
- Jarsigner(签名) jarsigner工具会对未签名的apk验证签名。得到一个签名后的apk(signed.apk)
- zipalign(对齐) zipAlign工具对6中的signed.apk进行对齐处理,所谓对齐,主要过程是将APK包中所有的资源文件距离文件起始偏移为4字节整数倍,这样通过内存映射访问apk文件时的速度会更快。对齐的作用主要是为了减少运行时内存的使用