美文网首页
Android Instant-Run 最新原理剖析

Android Instant-Run 最新原理剖析

作者: 雁过留声_泪落无痕 | 来源:发表于2017-08-16 17:07 被阅读0次

一、背景

1.参考:深度理解Android InstantRun原理以及源码分析

2.时间:2017.08.16

3.AS版本:2.3.3

4.TAG:InstantRun(开启此 TAG 可以看到 instant-run 的相关输出,帮助理解)

二、最新原理

上面那篇文章其实已经分析得比较到位了,但是随着 google 对 instant-run 的升级,文章里的一些东西已经发生了变化,比如不再使用 IncrementalClassLoader,也不再使用 BootstrapApplication 进行代理了。

1.运作流程

a.程序如何运行起来的?

在设置里勾选使能 instant-run 的情况下,运行程序,程序会在手机上正常跑起来,同时在 app/build/outputs/apk/ 目录下会生成一个名为 app-debug.apk 的文件。我们现在把 app 卸载掉,单独以 adb install -r app-debug.apk 的方式安装 app 到手机,点击桌面图标启动 app,会发现报 class not found 的错误!

我们解压 app-debug.apk 可以看到只有两个 dex,使用 d2j-dex2jar.sh 转换成 jar 文件再用 JD-GUI 查看,可以看到,这里只有 instant-run 相关的宿主代码,根本没有我们的业务代码。这也是驱动我去看 instant-run 代码的最原始的动力,奇了怪了,没有业务代码你是怎么跑起来的呢?

上面的参考文章里说了业务代码在 instant-run.zip 中,但是我们解压 app-debug.apk 也没有发现这个 zip 包啊!经过一番折腾,最后才发现,AS 使用了如下的安装命令:

adb install-multiple -r -p com.xxx.example.titan /xxx/Titan/app/build/intermediates/split-apk/debug/slices/slice_1.apk /xxx/Titan/app/build/outputs/apk/app-debug.apk

我勒个乖乖,难怪呢,原来使用了 install-multiple 命令同时安装了两个 apk,此时找到 slice_1.apk,解压确实看到了我们的业务代码。一样的,业务代码的每个方法前都插入了代码,参考上面给出的文章。

同时,root 过的手机,进入 /data/app/com.xxx.example.titan/ 目录下,也是可以发现我们的业务代码的,说明业务代码确实是安装到了手机上的。

b.程序和 as 如何通信的?

这里,建议看官们下载 google 官方的源码阅读,大致有如图所示的代码:

instant-run 源码目录

主要通信的类是 InstantRunService 和 Server 两个类,现从 app-debug.apk 中解压出来的类来看,InstantRunService 已经不用了,改成了 InstantRunContentProvider,如图:

app-debug.apk 解压出来的 dex 代码

/**
* Service which starts the Instant Run server; started by the IDE via
* adb shell am startservice pkg/service
*/
public classInstantRunServiceextendsService {
...
}

从官方的注释可以看出,通过 as 先启动 service(现在是 content provider),然后在 provider 中,创建了 Server 实例,并启动了 server,开启了 socket 等待 as 的连接。

然后就是协商协议版本,读取消息头,决定后续处理步骤等工作了。

2.源码之 Server#handleHotSwapPatch() 

a.客户端(AS 端)

当改动了我们的业务代码时,比如 MainActivity.java 的 onCreate() 方法,然后点击 AS 上的闪电一样的符号,表示开始进行热部署,此时 AS 会生成一个 dex 文件,包含两个类,一个名为 MainActivty$override;另外一个叫 AppPatchesLoaderImpl,这个类继承 AbstractPatchesLoaderImpl,主要是要靠 AS 实现一个虚方法:

public abstract String[] getPatchedClasses();

另外还有一个由 AbstractPatchesLoaderImpl 实现了的方法:

public boolean load() {
...
}

b.服务端(app 端)

AS 通过 socket 告诉 app,我有代码改动了,需要进行部署。此时,app 通过 socket 得到这个消息,然后进入 handleHotSwapPatch() 方法进行处理。

首先,把 AS 生成的那个 dex 文件存入 /data/data/files/instant-run/ 目录下,然后构造一个 DexClassLoader,把这个 dex 作为寻找路径。

然后反射创造 AppPatchesLoaderImpl 实例,调用其 getPatchedClasses() 方法,获取到一个列表,这个列表表明了哪些代码发生了改变,即需要“修复”的类列表,比如这里,列表中只有一个数据,就是 MainActivity。

跟着,就进入了 AbstractPatchesLoaderImpl#load() 方法了,通过一个循环,读取所有列表,比如读到 MainActivity 时:

1.先通过反射创建一个 MainActivity$override 实例;

2.再用 ClassLoader 把 MainActivity load 进来,由于在最开始 gradle 编译 app-debug.apk 时,就使用 asm 等字节码操作工具给每个类都生成了一个 $change 静态成员,同时在每个方法的开头都插入了逻辑,判断 $change 是否为空,为空则走正常逻辑,否则走修复后的逻辑;这里通过反射直接把 MainActivity$override 实例赋值给了 $change 成员;同时,如果以前已经热部署过了一次或者多次,会把 $change 成员的 $change 字段置为 true,表明之前的过期了。

3.源码之 Server#restart()

由于修改了 MainActivity 的代码,所以会走到:

if(updateMode ==UPDATE_MODE_WARM_SWAP) {
...
Restarter.restartActivityOnUiThread(activity);
}

进而会辗转走到:

Restarter#restartActivity

至此,MainActivity 得以重新加载,当运行到 onCreate() 的时候,此时 $change 成员已经不为空,且指向了 MainActivity$override 类的实例,也就是说 MainActivity#onCreate() 原有的逻辑已经执行不到了,而是执行了修改过后的逻辑,也就是 MainActivity$override#onCreate() 中的逻辑了。

三、最后

其中还涉及到资源相关的处理,这里就不罗列了。

Instant-Run 的好处就是只会把有修改的地方打成 dex 传到手机进行部署,主要是节约了开发时间;

这里强烈推荐一下阿里的 freeline,也是非常不错的一个及时部署得工具,有个缺陷就是会侵入我们的业务代码,比如需要在 Application 中进行初始化,不过这都好办,比如通过判断是否是 debug 包来初始化;同时通过增加 Property 来判断是否需要在 build.gradle 中应用插件。

相关文章

  • Android Instant-Run 最新原理剖析

    一、背景 1.参考:深度理解Android InstantRun原理以及源码分析 2.时间:2017.08.16 ...

  • 对Binder的实现原理的理解

    写给 Android 应用工程师的 Binder 原理剖析简单理解Binder机制的原理 aidl Android...

  • 热修复笔记

    Android热修复技术原理详解(最新最全版本) Android 热修复 -- 实现原理 (QQ空间)安卓App热...

  • Android inflate原理剖析

    1.inflate方法的调用存在于两个类中 使用View中的静态方法View.inflate()方法: 使用Lay...

  • Android Binder原理剖析

    本文来自网络,也可能略有改动,如有任何不妥可以联系删除,原文地址 https://www.jianshu.com/...

  • iOS IP 直连原理剖析

    iOS IP 直连原理剖析 iOS IP 直连原理剖析

  • [Android 学习笔记] instant-run 源码学习

    instant-run 源码地址仔细过一遍 README, 对 instant-run 就会有一个大体的了解;in...

  • Android 架构学习目录

    【转】剖析Android开发中常用开源库的基础知识,架构设计和核心原理,目前规划剖析的开源框架有:1)日志框架:l...

  • 线程优化

    1Android线程调度原理剖析 线程调度原理 任意时刻,只有一个线程占用CPU,处于运行状态。多线程并发:轮流获...

  • 五. Android 线程优化

    1. Android线程调度原理剖析 线程调度原理:任一时刻,只有一个线程占用CPU,处于运行状态 多线程并发:轮...

网友评论

      本文标题:Android Instant-Run 最新原理剖析

      本文链接:https://www.haomeiwen.com/subject/rvvirxtx.html