美文网首页
Tinker_imitator 原理篇

Tinker_imitator 原理篇

作者: 轻微 | 来源:发表于2016-07-20 11:17 被阅读2347次

    dim.red

    参考资料:微信Android热补丁实践演进之路

    简单来说,在编译时通过新旧两个Dex生成差异patch.dex。在运行时,将差异patch.dex重新跟原始安装包的旧Dex还原为新的Dex。这个过程可能比较耗费时间与内存,所以我们是单独放在一个后台进程:patch中。为了补丁包尽量的小,微信自研了DexDiff算法,它深度利用Dex的格式来减少差异的大小。它的粒度是Dex格式的每一项,可以充分利用原本Dex的信息,而BsDiff的粒度是文件,AndFix/Qzone的粒度为class。
    —来自<微信Android热补丁实践演进之路>

    项目的Github地址:

    Tinker_imitator

    梳理一下过程:
    我们通过gradle打包app的时候记录下生成的dex,当线上版本出现问题以后.使用gradle插件打出相对应的dex,并且与之前生成的dex做差分生成patch.dex,将patch.dex push到手机上,在手机端上将patch和旧的dex合成成新的dex.,并且将这个dex放置在classloder的最前面。

    主要技术点

    1. 差分算法
    2. 为了使patch包足够的小就应该保证新旧dex包内的内容足够的相近

    第一个难点:

    差分算法我们使用google开源的Bsdiff。
    通过编译成so文件.实现了在手机端合成算法。

    第二个难点:

    我们会gradle打包的时候。记录每个dex的class列表。在打patch的时候会根据这个列表。
    并且检查这个列表中的文件是不是有改动. 将改动所在的dex.打出新的dex. 使用差分算法生成patch。
    怎么记录class列表?
    我们都知道gradle是通过dx命令生成dex。
    我们查看dx源码发现源码位于:
    /dalvik/dx/src/com/android/dx/command/dexer/Main
    dx源码中有一个verbose参数,会在处理所有的文件(eg class )的时候会有一个输出"processing xxx .class...,但是比较可惜的是现有的代码只能获取都处理class信息,不能获取分dex的信息。这里的做法是,自己编译dx.jar。

    在dx源码中加入下面代码。

    dx

    然后在gradle中指定我们编译的dx.jar。
    gradle怎么使用dx的呢?
    源码地址com.android.builder.core.DexProcessBuilder.build

    DexProcessBuilder.build

    我们看出这里指定了dx地址。我们直接hook了AndroidBuilder类,
    然后直接生成自定义的DexProcessBuilder将dx地址指向了我们自己的编译的dx。
    同时hook了一个BaseProcessOutputHandler对dx的输出信息进行分析。
    这样下来就能获取dex的class列表。
    比较有意思的是在不开启Instant Run的情况下会把所有的java代码合成一个combined的jar,dx其实是操作是这个combined的jar。Instant Run情况就不一样了。

    手机端sdk

    sdk就比较简单了。将过来的patch和手机上旧的dex使用bsdiff进行合成新的dex并且放置在classloder的最前面。
    比较有意思的是在当打完patch后app进入后台以后会kill当前进程。并发起一个NoneService服。然后app会被重新启动,而activiy栈也会被保存起来。重新构建起来。

    尾巴

    最近阿宅开了个QQ实践群(568863373),欢迎大家进来玩耍,也可以关注我们的公众号:魔都三帅

    Paste_Image.png

    相关文章

      网友评论

          本文标题:Tinker_imitator 原理篇

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