微信團隊披露:微信介面卡死超級bug“15。。。。”的來龍去脈
1、微信超級Bug
大家好,給大家介紹一下,這是Bug:
應該有很多Android的使用者熟悉上面這圖。
(本文同步釋出於:http://www.52im.net/thread-1099-1-1.html)
2、事件背景
國慶前幾天,微信Android大量使用者反饋接收或傳送類似“15。。。。。。。。。。。。。。。”資訊會導致微信聊天介面卡死,程式崩潰。這對微信來說是很嚴重的事情啊,一時半會反饋也鋪天蓋地的過來,我們得知這個問題後,第一時間對這個問題進行了緊急修復並在兩天內覆蓋了全網大部分使用者,最終這個問題得到了解決。追根溯源,毫無疑問這鍋開發小弟來背,這次不能冤枉了產品MM哈哈。
與此同時,很多熱心的網友也開始分析原因,25號當日就有行內大神通過ANR日誌和反編譯debug,一步步推敲出此次ANR的根源,給出了卡死的原因。請受小弟一拜,實在佩服佩服!
詳情可參考連結:http://androidwing.net/index.php/243
下圖是網友分析結果圖:
根據該網友的推敲,此次卡死的真正原因在於:“這個wwk是始終等於0的,也就是不滿足while內部的dVar2的置空條件,也就造成了while死迴圈”。這裡具體怎麼做到動態反編譯的?
這個知乎的回答很詳細:https://www.zhihu.com/question/65828771
3、真正原因揭曉
真正的原因確實如網友分析的,主要是卡在了這個while迴圈裡面,這個迴圈的主要作用是將當前文字內容按具體的規則進行斷句排版,見下圖。
因為dVar2且dVar2.getText一直不為空,一直滿足這個條件,所以造成死迴圈。
而dVar2這個值為null的條件取決於下面這個函式:
“i4”變數實際是斷句演算法返回截斷的實際位置,dvar2.getLength()實際是當前行的文字長度,這裡因為斷句演算法的bug,造成了”i4”這個變數一直返回0,而當前行文字長度dvar2.getLength()是>0的,所以這個dVar2永遠不會被賦值為空。
繼續追根問底:是什麼原因造成斷句演算法一直返回0呢,實際上斷句演算法是呼叫了以下這個函式:
該函式返回了一個物件a其包含兩個引數,一個是斷句的位置(a.wwk),及斷句後的文字長度(a.width),主要是因為在判斷換行的時候,因為考慮到標點符號不應該位於行首這條規則,需要將當前行最後一個非標點符號截斷到下一行,而截斷受另外一條規則限制,截斷不可以為英文或者數字,這導致“15。。。。。。。。。。。。。。。”最後返回截斷的位置為0,並將結果返回,所以才產生了死迴圈,造成這個bug。
4、那麼問題來了
很多網友也開始討論,為什麼要自己排版,放著好端端的系統TextView不用?到底好在哪裡?效果是怎麼樣的?
不著急,諸多問題的來龍去脈得容小弟一一道來。
5、為什麼有這個需求?
實際上,世界上大部分需求都源於使用者。這需求還得得益於之前有幾個使用者會反饋說“微信Android的聊天氣泡好像沒有iOS的美觀,比較死板”。這個問題也引起了我們的關注。
那事實是否如此呢?我們對iOS和Android進行了對比,如下圖:
從效果圖看,iOS確實比Android好看了些,至少最右邊並不會有多餘的padding這麼明顯,簡單來說多餘的padding產生的原因是氣泡寬度受螢幕大小的限制,所以這裡TextView即是氣泡有了最大的寬度限制,當剩下的空間不足以容下一個字元時,系統排版會選擇自動換行,導致了這個問題的產生。
6、又一個問題
那麼,iOS的排版是否就是完美的呢,其實仔細觀察並非這樣,從上圖可以看出,除了Android,iOS也會有這種問題,那就是氣泡中的文字左右參差不齊。
一開始我們懷疑,會不會是微信應用本身使用該元件不當的原因造成,而非系統元件的問題。於是乎,在手機上,我們隨便找了一些熱門app,仔細對比,同樣的問題依然存在。
知乎:
掘金:
支付寶:
等等。。。
而且除了移動端,pc端同樣也有諸類問題。結合上面這些對比,確實市面上大部分應用都存在這個問題。通過這次反饋,我們也開始在思考能不能在移動客戶端的文字排版上做得更人性化一些,體驗上更好?。就這個問題,我們找了設計的同學一起探討,認為確實有這個必要。於是就開始有了下一步。
7、排版要怎麼排?
對於文字排版,這容易讓人想起,“我的(word)哥”,微軟對於這款應用,有沒有一些文字左右對齊的手段或者方案可以參考呢?
下圖為word的左對齊效果,也就是Android的TextView預設對其方式:
下圖為word的居中‘硬’對齊效果:
下圖為word的居中‘軟’對齊效果:
從這種效果上看,“軟對齊方式”更美觀,體驗最好。於是我們能想到的就是動態調整字間距的方式來實現這種效果(word也是這麼實現的)。
那既然要動態調整字型間距,是不是可以一味的這麼做就可以?答案當然不是,如果這麼做就像‘硬對齊方式’一樣,顯得過於生硬了。
我們就這個問題跟設計組的同事進行討論,通過他們的調研及嘗試,得出了一個合理的方案,那就是最多允許有一個英文字元寬度的調整範圍,將調整的寬度平均分配到當前行每個字元中去,對使用者來說影響是最小的,同時也保持了一定的美觀。
8、實踐自定義排版
對於Android來說,實現這條規則並不難,要麼是改造系統TextView,要麼自己寫個自定義view實現文字排版及渲染,最後我們採用了後者這個方案。
原因在於:
系統TextView真正排版及繪製的邏輯不在其本身,而是交給三個繼承了Layout的子類負責,分別為StaticLayout、DynamicLayout、BoringLayout,我們更常用的是StaticLayout,它只負責靜態的文書處理,關於各自Layout的區別,這裡了就不展開講了。系統TextView並沒有暴露介面去代理它們。當然沒有介面不意味著做不到,我們完全可以通過反射等手段代理它,但其實這麼做的話,代價是比較大的。
原因有三:
1)其一:從Android 2.3到Android 8.0,TextView的程式碼雖說變化不會很大,但從Layout來看,實現的邏輯或者介面也好都有所變更,如果通過這個方式,代理的相容性會是一個問題;
2)其二:TextView堪稱Android最複雜的一個元件之一,幾個Layout邏輯程式碼的複雜程度很高,自己實現所有的Layout介面,本身就是一件複雜且工作量很大的工作;
3)其三:實際上自己實現一個Layout,基本上就實現了一個顯示元件,排版和渲染都是要處理的,所以這樣實現的意義不大,甚至反而不靈活。
迴歸正題,我們對系統TextView的規則進行對比,最後我們確定了以下幾條規則:
1、最多允許有一個字母字元寬度的來調整字間距;
2、對於標點符號儘量規避不出現在行首;
3、對於英文單詞或數字不截斷排版。
於是我們開始進行簡單的demo實現。效果如下圖:
對比優化前的效果,確實這麼做效果是明顯的。但仔細觀察,還是會發現,對於一些特殊的中文全形符號(如,《》()【】等)因為有多餘的padding存在,放在行首和行末也會導致參差不齊的效果。
於是我們多增加了一條規則:
對一些常見的有多餘padding的全形符號位於行首或行末時,預設減去多餘的padding來達到更好的對齊效果。
最後的優化效果,如圖:
最後一張是應用了4條規則的效果圖,整體文字的對齊效果比系統預設的排版改善了不少。
9、問題又來了
那既然效果是不錯的,是否存在其他問題?確實如此。
9.1 小語種處理問題
因為微信對小語種是支援的,對於一些特殊的小語種,如泰語,阿拉伯語等,泰語的排版方式並非簡單的橫排,字元與字元之間是有上下關係的,而對於阿拉伯語,是從右往左排列的。如果只是按上面所講的幾個規則,那麼排版後的效果肯定是不合理的。
考慮到小語種存在多樣性,排版規則不統一,而且使用小語種使用者比例小,但也不能讓其排版錯誤不管,所以對於這種情況,我們通過一個簡單的正規表示式去匹配是否屬於能處理的字串範圍內,這就是為什麼有網友分析”15。。。。。。。。”這個事件時,一開始會懷疑是正則匹配耗時造成的。
下圖為該網友的分析:
而實際上,這個簡單的正規表示式,如該網友測試的一樣,處理起來很快,基本都在1ms內,對效能的影響可忽略。通過正則去判斷後,如果是可處理的字串則應用上面的規則進行排版,如果是特殊的字串,則用系統的TextView代理顯示。
9.2 適配率問題
既然小語種的問題可以解決,但這裡又產生一個問題,現網上的使用者, 使用特殊字元的頻率多高?這問題直接關係到我們這個排版元件的適配率,也就是對使用者體驗改善多少?在我們看來,一般人並不會發些奇奇怪怪的符號在微信裡面,所以能應用上這個排版規則的應該佔大多數。當然這裡只是猜想,如果這樣確定可行性也太草率了。
於是我們針對這個問題,進行了一輪灰度,灰度的結果如下:
通過這次灰度,現網使用者能應用上該元件適配的情況達到了預期的結果。
9.3 效能問題
如果該元件的效能跟系統相差太多,甚至嚴重影響幀率,造成使用者卡頓,這當然也是不可取的。我們針對這個問題,進行了本地的自動化幀率測試及與系統TextView進行函式間的對比。
下圖是實驗資料:
得出結論:
從微觀上:通過函式進行對比,CellTextView對比系統TextView效能稍差2倍,主要差距在於繪製文字時需要單字調整間距;
從巨集觀上:CellTextView對實際幀率的影響較小,使用者無明顯感知效能變差。
通過以上的嘗試及灰度結果來看,做這個事情其實是很有意義的,那麼最後也敲定下了這個優化方案。
10、事件結尾
整個需求的來龍去脈就是這樣子的,其實梳理這個過程的來龍去脈來,一來可以讓自己不斷反思該過程存在的一些問題,二來呢,因為本次bug確實對大家造成了不好的影響(真的是深感歉意啊!),可以讓大家清楚這個事情是怎麼發生的,至少大家不會卡得不明不白的。
寫程式碼萬萬要小心謹慎,考慮周全啊。這次痛定思痛,吃一塹,長一智吧。願天下的程式統統沒有bug。對,統統沒有!
最後貼上一張優化後的效果圖:
文章寫得不好的地方,望見諒,大神莫噴莫噴。小弟我要背鍋去面壁了。
(原文連結:點此進入)
附錄:更多微信、QQ技術文章彙總
[1] 有關QQ、微信的技術文章:
《微信團隊披露:微信介面卡死超級bug“15。。。。”的來龍去脈》
《月活8.89億的超級IM微信是如何進行Android端相容測試的》
《微信客戶端團隊負責人技術訪談:如何著手客戶端效能監控和優化》
《微信團隊原創分享:Android版微信的臃腫之困與模組化實踐之路》
《微信團隊原創分享:微信客戶端SQLite資料庫損壞修復實踐》
《騰訊原創分享(一):如何大幅提升行動網路下手機QQ的圖片傳輸速度和成功率》
《騰訊原創分享(二):如何大幅壓縮行動網路下APP的流量消耗(下篇)》
《騰訊原創分享(二):如何大幅壓縮行動網路下APP的流量消耗(上篇)》
《如約而至:微信自用的移動端IM網路層跨平臺元件庫Mars已正式開源》
《開源libco庫:單機千萬連線、支撐微信8億使用者的後臺框架基石 [原始碼下載]》
《微信新一代通訊安全解決方案:基於TLS1.3的MMTLS詳解》
《微信團隊原創分享:Android版微信後臺保活實戰分享(程式保活篇)》
《微信團隊原創分享:Android版微信後臺保活實戰分享(網路保活篇)》
《Android版微信從300KB到30MB的技術演進(PPT講稿) [附件下載]》
《微信團隊原創分享:Android版微信從300KB到30MB的技術演進》
《微信技術總監談架構:微信之道——大道至簡(PPT講稿) [附件下載]》
《微信海量使用者背後的後臺系統儲存架構(視訊+PPT) [附件下載]》
《微信非同步化改造實踐:8億月活、單機千萬連線背後的後臺解決方案》
《架構之道:3個程式設計師成就微信朋友圈日均10億釋出量[有視訊]》
《微信團隊原創分享:Android記憶體洩漏監控和優化技巧總結》
《微信團隊原創Android資源混淆工具:AndResGuard [有原始碼]》
《移動端IM實踐:Android版微信如何大幅提升互動效能(一)》
《移動端IM實踐:Android版微信如何大幅提升互動效能(二)》
《移動端IM實踐:WhatsApp、Line、微信的心跳策略分析》
《移動端IM實踐:谷歌訊息推送服務(GCM)研究(來自微信)》
[2] 有關QQ、微信的技術故事:
《技術往事:創業初期的騰訊——16年前的冬天,誰動了馬化騰的程式碼》
《技術往事:史上最全QQ圖示變遷過程,追尋IM巨人的演進歷史》
《開發往事:深度講述2010到2015,微信一路風雨的背後》
(本文同步釋出於:http://www.52im.net/thread-1099-1-1.html)
相關文章
- 雲端計算風險的來龍去脈
- 關於View中mParent的來龍去脈View
- AI晶片行業發展的來龍去脈AI晶片行業
- Alink漫談(四) : 模型的來龍去脈模型
- 『MySQL』深入理解事務的來龍去脈MySql
- 牛人寫的facebook優化php來龍去脈優化PHP
- 可複用程式碼:元件的來龍去脈元件
- Android效能最佳化來龍去脈Android
- 一文搞清楚 DNS 的來龍去脈DNS
- Linux 程式編譯過程的來龍去脈Linux編譯
- 【Javascript】淺析JS中閉包的來龍去脈JavaScriptJS
- Android效能優化來龍去脈總結Android優化
- 【來龍去脈系列】什麼是區塊鏈?區塊鏈
- 敲開遊戲引擎的大門,聊聊引擎的來龍去脈遊戲引擎
- [原始碼解析]Oozie來龍去脈之提交任務原始碼
- HMM隱馬爾可夫模型來龍去脈(二)HMM隱馬爾可夫模型
- jmeter學習指南之分散式測試的來龍去脈JMeter分散式
- 微信支付團隊釋出“微信青蛙pro” 支援刷臉支付功能
- [原始碼解析]Oozie來龍去脈之內部執行原始碼
- 一文講透CabloyJS全棧框架的來龍去脈JS全棧框架
- WinXP盜版來龍去脈及微軟承認的完美盜版(轉)微軟
- 藉助 AIDL 理解 Android Binder 機制——Binder 來龍去脈AIAndroid
- 微信支付介面升級(微信開通免充值產品功能的前戲)
- 今天你被騷擾了嗎?起底AI電話的來龍去脈AI
- 【Android 效能優化】—— 詳解記憶體優化的來龍去脈Android優化記憶體
- 微信團隊分享:微信移動端的全文檢索多音字問題解決方案
- 談談網站架構設計開發的一些來龍去脈網站架構
- 資料分析:18張圖表講透奢侈品“價差”的來龍去脈
- 微信小程式swiper輪播圖卡死來回瘋狂輪播微信小程式
- 類微信介面
- 微信團隊原創分享:iOS版微信的記憶體監控系統技術實踐iOS記憶體
- 微信後團隊分享:微信後臺基於Ray的分散式AI計算技術實踐分散式AI
- [廣州] 從微信離職的創業團隊找創業夥伴創業團隊
- 微信團隊分享:微信後臺在海量併發請求下是如何做到不崩潰的
- 整個微信設計團隊被支付寶“挖走”了?
- 馬雲“以德服人”阿里團隊指出微信“高危漏洞”助騰訊修改阿里
- Facebook、微信團隊、Twitter、微軟開源軟體列表一覽微軟
- 微信API介面大全API