普通应用加载流程
Instant Run应用加载流程
会在编译过程中修改AndroidManifest。加入Application和Appserver的代码。
最后的apk中会有classes.dex和classes2.dex两个dex文件,原来的代码会如instant-run.zip文件
classes.dex反编译后
classes2.dex反编译后
instant-run.zip中的内容,为我们自己的代码
AndroidManifest中application被替换为BootstrapApplication
BootstrapApplication的attachBaseContext
createResources → setupClassLoaders → createRealApplication → 调用realApplication的attachBaseContext
createResources:
检查resource有没有改变
setupClassLoaders、
设置IncrementalClassLoader到loader链条中
Application的OnCreate
monkeyPatchApplication → monkeyPatchExistingResources → Server启动 → 调用realApplication的onCreate方法
monkeyPatchApplication
1.替换ActivityThread的mInitialApplication为realApplication
2.替换mAllApplications 中所有的Application为realApplication
3.替换ActivityThread的mPackages,mResourcePackages中的mLoaderApk中的application为realApplication。
monkeyPatchExistingResources
如果resource.ap_文件有改变,那么新建一个AssetManager对象newAssetManager,然后用newAssetManager对象替换所有当前Resource、Resource.Theme的mAssets成员变量。 2.如果当前的已经有Activity启动了,还需要替换所有Activity中mAssets成员变量
热部署
Server启动后会监听socket,当命令为1,且patch路径为classes.dex.3,则是HotSwapPatch
先将patch的dex文件写入到临时目录,然后使用DexClassLoader(父classloader为PathClassloader)去加载dex。然后反射调用AppPatchesLoaderImpl类的load方法,需要说明的是,AppPatchesLoaderImpl继承自抽象类AbstractPatchesLoaderImpl,并实现了抽象方法:getPatchedClasses
在第一次构建apk时,在每一个类中注入了一个$change的成员变量,它实现了IncrementalChange接口,并在每一个方法中,插入了一段类似的逻辑。
IncrementalChange localIncrementalChange = $change;
if (localIncrementalChange != null) {
localIncrementalChange.access$dispatch(
"onCreate.(Landroid/os/Bundle;)V", new Object[] { this,
... });
return;
}
增量编译时,会把修改类的名称会从AppPathcesLoaderImpl的getPatchedClasses方法中返回,并生成修改类的名称+$overide
的类并实现IncrementalChange 接口,把修改的方法放在里面。load方法会加载$overide类,放入原来修改类的$change变量中。
冷部署
patch路径以dex结尾时
把dex文件写到私有目录,等待整个app重启,重启之后,使用前面提到的IncrementalClassLoader加载dex即可。
IncrementalClassLoader的作用为从私有目录中加载class文件