第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號(hào)安全,請(qǐng)及時(shí)綁定郵箱和手機(jī)立即綁定

補(bǔ)丁生成之DexDiff原理簡(jiǎn)析

標(biāo)簽:
Android

前言

微信的热修复框架Tinker已经在国庆节之前开源了,成为了github.com/Tecent下第一个项目,刷爆了各位开发者的朋友圈。作为一个超级APP的HotFix库,Tinker不仅值得我们compile,更值得我们read

原理

Tinker和以往的HotFix库思路不太一样,它更像是APP的增量更新,在服务器端通过差异性算法,计算出新旧dex之间的差异包,推送到客户端,进行合成。传统的差异性算法有BsDiff,而Tinker的牛逼之处就在于它自己基于Dex的文件格式,研发出了DexDiff算法。

补丁生成之DexDiff

补丁生成是在编译阶段进行的,当我们在build.gradle中配置好tinkerOldApkPath后,调用tinkerPatchDebug,补丁就开始生成了。

调用链为:

TinkerPatchSchemaTask.tinkerPatch()
->Runner.gradleRun()
->Runner.run()
->Runner.tinkerPatch()
->ApkDecoder.patch()
……
->DexPatchGenerator.executeAndSaveTo()

executeAndSaveTo()方法是DexDiff算法的真正入口,DexDiff算法的特点在于它深入分析了Dex文件格式,深度利用Dex的格式来减少差异大小。

在了解DexDiff之前,我们需要对Dex文件有个初步了解,Dex的文件格式如下表。参考自这里:Dalvik可执行格式(dex)上

5bab92de0001fc9e07230836.jpg

了解了Dex的格式后,让我们来看一下DexDiff的基本步骤。想要深入了解Dex文件格式的可以看Google官方文档:https://source.android.com/devices/tech/dalvik/dex-format.html,《Android软件安全与逆向分析》这本书里关于Dex文件也有很详细的讲解。

DexDiff的主要步骤如下:

Step1:计算出new dex中每项Section的大小,比如string_ids在dex文件中所占大小。

int patchedStringIdsSize = newDex.getTableOfContents().stringIds.size * SizeOf.STRING_ID_ITEM;

step2:根据表中前一项的偏移地址和大小,计算出每项Section的偏移地址。

this.patchedStringIdsOffset = patchedHeaderOffset + patchedheaderSize;

step3:调用DexSectionDiffAlgorithm.execute(),将new dex与old dex中的每项section进行对比,对于每项Section,遍历其每一项Item,进行新旧对比,记录ADD,DEL标识,存放于patchOperationList中。接着遍历patchOperationList,添加REPLACE标识,最后将ADD,DEL,REPLACE操作分别记录到各自的List中。

这里面的新旧对比的算法很有趣,它是直接将oldItem.compareTo(newItem),结果小于0记为DEL,大于0记为ADD。为什么可以直接这样比较呢?别忘啦,从上面Dex文件格式表中可知,Dex文件中的Section都是经过排序的。

上图中,old dex中下标为2的item “c” 被DEL,c后面的元素前移,new dex中下标5处ADD一个item “f”,而在下标8处又ADD一个item “j”。

下标5的”f”在这里被记为ADD,但是它其实是REPLACE了”g”。在之后遍历patchOperationList时,算法会判断operation前一个opearation(prevPatchOperation)的类型,若prevPatchOperation为DEL,而自己刚好为ADD,那么就将自己的类型改为REPLACE。

Iterator<PatchOperation<T>> patchOperationIt = this.patchOperationList.iterator();
PatchOperation<T> prevPatchOperation = null;
while (patchOperationIt.hasNext()) {
   PatchOperation<T> patchOperation = patchOperationIt.next();
   if (prevPatchOperation != null
       && prevPatchOperation.op == PatchOperation.OP_DEL
       && patchOperation.op == PatchOperation.OP_ADD
      ) {
          if (prevPatchOperation.index == patchOperation.index) {
              prevPatchOperation.op = PatchOperation.OP_REPLACE;
              prevPatchOperation.newItem = patchOperation.newItem;
              patchOperationIt.remove();
              prevPatchOperation = null;
            } else {
              prevPatchOperation = patchOperation;
            }
        } else {
            prevPatchOperation = patchOperation;
        }
 }

step4:调用DexPatchGenerator.writePatchOperations(),将记录写入补丁。
对于DEL:
开辟一块DelOpIndexList大小的区域(DelOpIndexList中记录了每块要删除部分的索引),遍历记录DelOpIndexList,对于每一个DEL索引,计算出其相对于前一个DEL索引的偏移,记录偏移量。

buffer.writeUleb128(delOpIndexList.size());
    int lastIndex = 0;
    for (Integer index : delOpIndexList) {
        buffer.writeSleb128(index - lastIndex);
        lastIndex = index;
    }

对于ADD和REPLACE,也会进行和DEL一样的操作。

buffer.writeUleb128(addOpIndexList.size());
    lastIndex = 0;
    for (Integer index : addOpIndexList) {
        buffer.writeSleb128(index - lastIndex);
        lastIndex = index;
    }

buffer.writeUleb128(replaceOpIndexList.size());
    lastIndex = 0;
    for (Integer index : replaceOpIndexList) {
        buffer.writeSleb128(index - lastIndex);
        lastIndex = index;
    }

不同的一点是,ADD和REPALACE还会接着写入新增和替换的item。

 for (T newItem : newItemList) {
        if (newItem instanceof StringData) {
            buffer.writeStringData((StringData) newItem);
        } else
        if (newItem instanceof Integer) {
            // TypeId item.
            buffer.writeInt((Integer) newItem);
        } else
        if (newItem instanceof TypeList) {
            buffer.writeTypeList((TypeList) newItem);
        }
        ......
}

总结

这里只是简单的介绍了DexDiff的简要过程,中间其实省去了很多细节,而这些细节与Dex文件格式联系非常紧密,想要彻底的了解DexDiff原理,还需好好研究Dex文件。

原文链接:http://www.apkbus.com/blog-705730-62593.html

點(diǎn)擊查看更多內(nèi)容
TA 點(diǎn)贊

若覺(jué)得本文不錯(cuò),就分享一下吧!

評(píng)論

作者其他優(yōu)質(zhì)文章

正在加載中
  • 推薦
  • 評(píng)論
  • 收藏
  • 共同學(xué)習(xí),寫下你的評(píng)論
感謝您的支持,我會(huì)繼續(xù)努力的~
掃碼打賞,你說(shuō)多少就多少
贊賞金額會(huì)直接到老師賬戶
支付方式
打開(kāi)微信掃一掃,即可進(jìn)行掃碼打賞哦
今天注冊(cè)有機(jī)會(huì)得

100積分直接送

付費(fèi)專欄免費(fèi)學(xué)

大額優(yōu)惠券免費(fèi)領(lǐng)

立即參與 放棄機(jī)會(huì)
微信客服

購(gòu)課補(bǔ)貼
聯(lián)系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動(dòng)學(xué)習(xí)伙伴

公眾號(hào)

掃描二維碼
關(guān)注慕課網(wǎng)微信公眾號(hào)

舉報(bào)

0/150
提交
取消