編輯:關於android開發
最近半年以來,Android熱補丁技術熱潮繼續爆發,各大公司相繼推出自己的開源框架。Tinker在最近也順利完成了公司的審核,並非常榮幸的成為github.com/Tencent上第一個正式公開的項目。
回顧這半年多的歷程,這是一條跪著走完,坑坑不息之路。或許只有自己真正經歷過,深入研究過, 才會真正的明白
熱補丁不是請客吃飯
對熱補丁技術本身,還是對使用者來說都是如此。它並不簡單,也有著自己的局限性,在使用之前我們需要對它有所了解。我希望通過分享微信在這歷程中的思考與經驗,能幫助大家更容易的決定是否在自己的項目中使用熱補丁技術,以及選擇什麼樣方案。
熱補丁是什麼以及它的應用場景介紹,大家可以參考文章微信Android熱補丁實踐演進之路。
在筆者看來Android熱補丁技術應該分為以下兩個流派:
Native流派與Java流派都有著自己的優缺點,它們具體差異大家可參考上文。事實上從來都沒有最好的方案,只有最適合自己的。
對於微信來說,我們希望得到一個“高可用”的補丁框架,它應該滿足以下幾個條件:
在“高可用”這個大前提下,微信對當時存在的兩個方案做了大量的研究:
在2016年3月,微信為了追尋“高可用”這個目標,決定嘗試搭建自己的補丁框架——Tinker。Tinker框架的演繹並不是一蹴而就,它大致分為三個階段,每一階段需要解決的核心問題並不相同。而Tinker v1.0的核心問題是實現符合性能要求的Dex補丁框架。
為了穩定性與兼容性,微信選擇了Java流派。當前最大難點在於如何突破Qzone方案的性能問題,這時通過研究Instant Run的冷插拔與buck的exopackage給了我們靈感。它們的思想都是全量替換新的Dex。
簡單來說,我們通過完全使用了新的Dex,那樣既不出現Art地址錯亂的問題,在Dalvik也無須插樁。當然考慮到補丁包的體積,我們不能直接將新的Dex放在裡面。但我們可以將新舊兩個Dex的差異放到補丁包中,這裡我們可以調研的方法有以下幾個:
如何選擇?在“高可用”的核心訴求下,性能問題也尤為重要。非常慶幸微信在當時那個節點堅決的選擇了自研DexDiff算法,這過程雖然有苦有淚,但也正是有它,才有現在的Tinker。
在不斷的深入研究Dex格式後,我們發現自己跳進了一個深坑,主要難點有以下三個:
這不僅要求我們需要研究透Dex的格式,也要把dex2opt與dex2oat的代碼全部研究透。現在回想起來,這的確是一條跪著走完的路。與研究Dalvik與Art執行一致,這是經歷一次次翻看源碼,一次次編Rom查看日志,一次次dump內存結構換來的結果。
下面以最簡單的Index區域舉例:
要想將從左邊序列更改成右邊序列,Diff算法的核心在於如何生成最小操作序列,同時修正Index與Offset,實現增刪改的功能。
對於Offset區,由於每個Section可能有非常多的元素,這裡會更加復雜。最後我們得到最終的操作隊列,為什麼DexDiff可以做到內存非常少?這是因為DexDiff算法是每一個操作的處理,它無需一次性讀入所有的數據。DexDiff的各項數據如下:
通過DexDiff算法的實現,我們既解決了Dalvik平台的性能損耗問題,又解決了Art平台補丁包過大的問題。但這套方案的缺點在於占Rom體積比較大,微信考慮到移動設備的存儲空間提升比較快,增加幾十M的Rom空間這個代價可以接受。
信心滿滿上線後,卻很快收到華為反饋的一個Crash:
而且這個Crash只在Android N上出現,在當時對我們震動非常大,難道Android N不支持Java方式熱補丁了?難道這兩個月的辛苦都白費了嗎?一切想象都蒼白無力,只有繼續去源碼裡面找原因。
在之前的基礎上,這一塊的研究並沒有花太多的時間,主要是Android N的混合編譯模式導致。更多的詳細分析可參考文章Android N混合編譯與對熱補丁影響解析。
剛剛解決完Android N的問題,還在沉醉在自己的勝利的愉悅中。前線很快又傳來噩耗,小米反饋開發版的一些用戶在微信啟動時黑屏,甚至ANR.
當時第一反應是不可能,所有的DexOpt操作都是放到單獨的進程,為什麼只在Art平台出現?為什麼小米開發版用戶反饋比較多?經過分析,我們發現優化後odex文件存在有效性的檢查:
這就非常好理解了,因為OTA之後系統image改變了,odex文件用到image的偏移地址很可能已經錯誤。對於ClassN.dex文件,在OTA升級系統已完成重新dex2oat,而補丁是動態加載的,只能在第一次執行時同步執行。
這個耗時可能高達十幾秒,黑屏甚至ANR也是非常好理解。那為什麼只有小米用戶反饋比較多呢?這也是因為小米開發版每周都會推送系統升級的原因。
在當時那個節點上,我們重新的審視了全量合成這一思路,再次對方案原理本身產生懷疑,它在Art平台上面帶來了以下幾個代價:
回想起來,Qzone方案它只把需要的類打包成補丁推送,在Art平台上可能導致補丁很大,但它肯定比全量合成10M的Dex少很多很多。在此我們提出分平台合成的想法,即在Dalvik平台合成全量Dex,在Art平台合成需要的Dex
DexDiff算法已經非常復雜,事實上要實現分平台合成並不容易。
主要難點有以下幾個方面:
慶幸的是,面對困難我們並沒有畏懼,最後實現了這一套方案,這也是其他全量合成方案所不能做到的:
事實上,DexDiff算法變的如此復雜,怎麼樣保證它的正確性呢?微信為此做了以下三件事情:
每一次DexDiff算法的更新,都需要經過以上三個Test才可以提交,這樣DexDiff的這套算法已完成了整個閉環。
在實現過程,我們還發現其他的一些問題:
通過Tinker v1,0的努力,我們解決了Qzone方案的性能問題,得到一個符合“高可用”性能要求的補丁框架。
也許有人會質疑微信成功率為什麼這麼低,其他方案都是99%以上。事實上,我們的成功率計算方式是:
應用成功率= 補丁版本轉化人數/基准版本安裝人數
即三天後,94.1%的基礎版本都成功升級到補丁版本,由於基礎版本人數也是持續增長,同時可能存在基准或補丁版本用戶安裝了其他版本,所以本統計結果應略為偏低,但它能現實的反應補丁的線上總體覆蓋情況。
事實上,采用Qzone方案,3天的成功率大約為96.3%,這裡還是有很多的優化空間。
在v1.0階段,大部分的異常都是通過廠商反饋而來,Tinker並沒有解決“高可用”下最核心的穩定性與兼容性問題。我們需要建立完整的監控與補丁回退機制,監控每一個階段的異常情況。這也是Tinker v2.0的核心任務,由於邊幅問題這部分內容將放在下一篇文章。
關注Tinker,來Github給我們star吧
https://github.com/Tencent/tinker
對圖片進行各種樣式裁對圖片進行各種樣式裁剪:圓形、星形、心形、花瓣形等剪:圓形、星形、心形、花瓣形等--第三方開源--CustomShapeImageView, Cust
Android 面試題--Service,android--service1、Service 是否在 main thread 中執行, service 裡面是否能執行耗時
了解Activity 依照郭霖老師的《第一行代碼Android》,今天我要來學習Activity,首先來初步了解Activity,基本上就是照葫蘆畫瓢的模式,有點回到當初
圖文詳解Andorid中用Shape定義GradientDrawable Android中提供了各種類型的Drawable,也可以用XML定義各種Drawable。本文