part 2:怎麼載入新的apk
tinker:全量替換,無須插樁
傳統的熱修復需要插樁實現,插樁的原因和操作:
原因:
1. 通過將補丁dex檔案插入到類載入器的dexelement列表最前面,完成熱修復
2. 呼叫bug類的時候就會先搜尋到補丁dex裡的類,從而fix bug
3. bug類和它引用的類都在乙個dex中,這個類就被打上了class_ispreverified標識,如果這個類呼叫了插在dexelement佇列前面的補丁dex檔案中的同名方法,就會報錯,所以需要阻止bug類打上該標識
4. 通過「插樁」的方法避免需要被fix的class打上class_ispreverified標識
如何插樁:
使可能會產生bug的class引用另外乙個dex中的class,從而避免該class被打上class_ispreverified標識(groovy語言位元組碼織入)。
tinker使用的是apk全量替換的方法,使用差量包補丁包和原來的apk合成新的apk,使用全新apk,從而不會出現引用其他dex的class的情況,避免了插樁。
apk diff包括:dexdiff,resdiff,manifestdiff和sodiff
用來檢測新的manifest是否傳送過改變,tinker不支援manifest修改。原因應該是apk在執行install操作的時候會向系統註冊manifest資訊,tinker熱修復不會經歷這個過程。
bsdiff演算法,求新版本和舊版本的二進位制差異。原理來自這篇博士******* differences of executable code
基本步驟:
a.對old檔案中所有子字串形成乙個字典;
b.對比old檔案和new檔案,產生diffstring和extra string;
c.將diffstring 和extra string 以及相應的控制字用zip壓縮成乙個patch包。
優點:通用性強,適用於所有檔案的補丁包生成
缺點:沒有針對特定的格式做優化,導致補丁包可能過大
dex檔案頭部,記錄整個dex檔案的相關屬性,如都包含哪些部分(如string,field,method,class等),每部分的大小和偏移量。
存放每種型別資料的位址列表,如在string table中,連續存放若干個string的位址,根據每個位址,可以在data段找到改位址儲存的字串。
存放具體的資料,由table段不同型別的位址進行索引。
以string資料為例,首先讀取dex header部分string ids offset和string ids size的內容,如0x70和0x14,代表string資料在table段的偏移量是0x70,共20個。在table段讀取這20個資料,每個資料4個位元組,根據這4個位元組代表的位址,去datasection找這個位址儲存的內容,解析成string資料。
接下來計算新舊dex的string資料的diff資料。採用最小序列生成演算法,生成由舊string列表生成新列表的操作,用刪除,新增,修改三種操作表示。
演算法描述如下,摘抄自這篇帖子:
首先我們需要將新舊內容排序,這需要針對排序的陣列進行操作dex載入:將合成的新的dex加入到pathclassloader的dexelements列表中新舊兩個指標,在內容一樣的時候 old、new 指標同時加1,在 old 內容小於 new >內容的時候 old 指標加1,標記當前 old 項為刪除
在 old 內容大於 new 內容 new 指標加1, 標記當前 new 項為新增
------old-----
11 foo2
12 foo5
13 hello dodola
14 hello dodola1
------new-----
11 foo3
12 foo5
13 hello dodola1
14 hello dodola3
對比的old cursor 和 new cursor 指標的改變以及操作判定,判定過程如下
old_11 new_11 cmp <0 del
old_12 new_11 cmp >0 add
old_12 new_12 cmp =0 no
old_13 new_13 cmp <0 del
old_14 new_13 cmp =0 no
break;
old_11 del
new_11 add
old_13 del
new_14 add
到這一步我們需要找出替換的內容,很明顯替換的內容就是從old中del的並且在 >new 中 add 的並且 index 相同的i tem,所以這就簡單了
old_11 replace
old_13 del
new_14 add
這樣就生成了兩個dex的string部分的變化。
pathclassloader classloader =
(pathclassloader) tinkerdexloader.
class
.getclassloader()
;field pathlistfield = sharereflectutil.
findfield
(loader,
"pathlist");
object dexpathlist = pathlistfield.
get(loader)
;arraylist
suppressedexceptions =
newarraylist
();sharereflectutil.
expandfieldarray
(dexpathlist,
"dexelements"
,makepathelements
(dexpathlist,
newarraylist
(additionalclasspathentries)
, optimizeddirectory, suppressedexceptions)
);
res載入
訪問應用程式資源的函式有兩個:getresources和getassets。getresources返回resources物件,resources物件通過資源的id訪問編譯後的資源。getassets返回assetmanager物件,assetmanager物件通過資源的檔名訪問編譯後或未經編譯的資源檔案。實際上,resources訪問資源是先通過資源id獲取檔名,然後通過assetmanager根據檔名訪問資源檔案。
為了使這兩個方法載入新的資源檔案,執行以下操作:
a. 新建乙個assetmanager物件newassetmanager,通過反射呼叫其addassetpath方法,傳入新生成的apk檔案路徑
b. 新建resources物件,通過反射設定其massets屬性的值為newassetmanager
通過這種方式實現新的資源檔案的載入。
addassetpathmethod.
invoke
(newassetmanager, externalresourcefile)
assetsfiled.
set(resources, newassetmanager)
;
js時間轉化格式及UCC HIBC條碼解析
就記錄下,條形碼解析寫的很糟糕,好多地方可以封裝函式的,所以有點亂,直接複製過去還能用的,ucc條碼只能解析包裝 通過包裝 獲取型號是調後台介面,然後上面是自己寫的各種時間格式轉yy mm dd的函式,寫的low但能用。import from api distributionsheet 時間轉化函式...
DNS報文格式及抓包解析
dns的報文結構如下,其中黃色為基礎部分,綠色為問題部分,藍色為資源記錄部分。資源記錄部分只在響應包 現。1.事務id 16bit,dns報文的標識,請求報文和對應的響應報文的事務id應該相同。2.標誌 16bit,分為8個字段 字段長度 bit 作用qr 1查詢報文為0,響應報文為1 opcode...
Linux軟體源書寫格式解析及本地yum源製作
配置檔案 etc apt sources.list 例子 deb kali rolling main contrib non free 說明 1.格式 協議 映象站 發行版 發行版版本代號 軟體集合 2.格式 deb deb格式的包 deb src 原始碼包 3.協議 http http協議 ftp...