Android Native crash處理案例分享

{"type":"doc","content":[{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"一 背景"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"目前 "},{"type":"link","attrs":{"href":"https://www.aliyun.com/product/mpaas","title":null},"content":[{"type":"text","text":"mPaas"}]},{"type":"text","text":" Android是使用的是Crash SDK對閃退進行的處理,CrashSDK 是 Android 平臺上一款功能強大的崩潰日誌收集 SDK,有着極高的崩潰收集率和完整、全面的崩潰日誌信息,生成的日誌內容非常利於問題的跟進和解決。在我們的日常運維中,經常遇到一些閃退,無法直接從閃退堆棧看到原因,尤其是一些非Java的Native的閃退,這裏分享下在mPaas框架下怎麼使用Crash SDK對閃退進行分析。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"二 閃退報文分析工具介紹"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"對於mPaas的用戶,從MAS上閃退分析平臺導出的一般是原始的閃退信息,閃退信息比較多,如果直接閱讀會比較困難,使用者可以通過下載Chrome的插件"},{"type":"link","attrs":{"href":"https://chrome.google.com/webstore/detail/loganalyzer/foigdjdmacffmdeneaohncefpaiiobjk","title":null},"content":[{"type":"text","text":"LogAnalyzer"}]},{"type":"text","text":",LogAnalyzer會將Crash SDK生成的日誌文本內容轉化成可視效果較強的 HTML 頁面展現,功能還是很強大的,主要包含:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"1. 高亮顯示日誌中重點信息,並使用不同顏色區分;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"2. 支持日誌內容整體結構預覽,快速定位重點內容;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"3. 常見崩潰原因提醒;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"安裝好chrome插件後,還需要做以下配置"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"1. 修改閃退文件後綴爲 .txt"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"由於MAS上默認下載的文件後綴是.dat,需要改爲.txt,否則 LogAnalyzer 會不識別"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"2. 修改插件配置"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"由於 Chrome 默認權限限制,任何 Chrome 插件默認都不能訪問文件網址,需要在 Chrome 插件中進行如下操作。"}]},{"type":"numberedlist","attrs":{"start":"1","normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"打開 Chrome 插件管理頁面 chrome://extensions/"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"找到 LogAnalyzer 插件,點擊 “詳細信息\" 進入設置:"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/d7/d7bd2637be4c5dfe507d821b7b4bc54b.png","alt":"image.png","title":"image.png","style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":"4","normalizeStart":"4"},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":4,"align":null,"origin":null},"content":[{"type":"text","text":"找到允許訪問文件網址選項,並勾選:"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":5,"align":null,"origin":null},"content":[{"type":"text","text":"打開或者刷新日誌頁面,LogAnalyzer 就生效了。"}]}]}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"3. 生效效果"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"把日誌文件直接拖到chrome後,可以看到右邊插件生效後,可以通過不同顏色顯示閃退信息的各個字段"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"首次打開後的使用說明如下:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/7b/7b7d3461d2f8c17a75c0412d1a4fa452.png","alt":"image.png","title":"image.png","style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"正常查看閃退截圖如下:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/13/13806202e6345303995bc9d5246df914.png","alt":"image.png","title":"image.png","style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"三 閃退分析舉例"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們經常在日常運維中遇到一些非Java的Native模塊閃退,比如UC。這種時候很多時候只能去聯繫UC團隊進行支撐,其實很多場景下,閃退的根因並不是UC,只是最後的閃退點在UC。以我最近日常運維中比較常遇到的UC內核的閃退爲例,對一些案例的處理分享如下。"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"1. java空指針導致UC閃退"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們在閃退點上可以看到以下閃退(已經隱藏客戶apk相關信息),如果只是從這看我們暫時沒有任何線索,我們繼續往下看日誌"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/f1/f14b953ad06012b48d03ccc4f73f619a.png","alt":"image.png","title":"image.png","style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當看到logcat節點信息的時候,我們發現了線索,首先我們看到關鍵字:begin to generate native report, 表示當前是閃退日誌上報的日誌,我們在往前看,logcat節點裏打印了異常堆棧信息,從堆棧信息可以看到,是由於precreate操作觸發了底層的空指針,從而導致初始化異常,最後觸發了閃退。解決方案就是臨時關閉預創建,從而規避了閃退。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/28/28d40a08c1b22e86262873e4f717813b.png","alt":"image.png","title":"image.png","style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"從上面的案例我們可以看出,"}]},{"type":"numberedlist","attrs":{"start":"1","normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"Native的閃退不一定是Native模塊的原因導致的,有可能是由於java導致的異常,從而導致Native閃退"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"begin to generate native report 附近可以看閃退相關的logcat信息,協助定位閃退的一些上下文日誌。"}]}]}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"2. 上層OOM導致UC閃退"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"首先我們看上報的閃退點的日誌如下圖所示,閃退在了RenderThread裏,也是毫無頭緒。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/65/652a0ce707e99741086683d146c34d18.png","alt":"image.png","title":"image.png","style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們繼續硬着頭皮往下看,在logcat節點裏查找begin to generate native report上報節點,我們看到了大量的底層OOM的異常日誌,基本大概率確定是OOM的原因了。剩下的就是查找OOM是哪裏觸發的。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/66/66e8fb1ab573bbebb4f93f515f9b90c7.png","alt":"image.png","title":"image.png","style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"點擊閃退裏的內存節點,基本原因就比較清晰了,當前手機的vmsize基本已經到最大了,我們知道對於 32 位的進程,APP 可使用的 VmSize 最大爲 3GB,不過當運行在 64 位 CPU 上時,VmSize 最大可超過 3GB,接近 4GB。但是由於內核需要佔據一部分,以及不同的ROM版本的差別,我們發現有以下規律:android  8.1.0 及之後的系統,大部分 native oom crash 發生時 vmSize 分佈在 3.5 - 3.9 G 的位置,相對較爲集中。所以下面的案例的解決思路就變成了怎麼解決OOM了。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/f0/f0ceec1544c789fd5f604f19cf1ce230.png","alt":"image.png","title":"image.png","style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"3. FD誤關導致UC閃退"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"上報的日誌如下圖所示,我們大概只能看出SIGILL有可能是主動崩潰,崩潰ILL_ILLOPC表示非法操作。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/4e/4e10e94237630b987152ac0cbaf238fb.png","alt":"image.png","title":"image.png","style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"然後我們繼續看logcat節點的begin to generate native report, 基本確認原因是因爲uc使用的FD對象被其他程序關閉。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/1e/1e14d01dad29cd0683f6e5f8ab19f363.png","alt":"image.png","title":"image.png","style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"隨後UC提供了帶FDscan的工具包,通過我們復現後發現,是由於UC調用shouldIntercept回調的輸入流對象被其他模塊close掉了,導致UC使用的時候發現FD對象已經被關閉,從而做了崩潰處理。最後的處理方案就變成了用戶解決其他模塊的誤關FD的問題。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/7a/7a50efbd7d1f67ea45e055b17d9d4444.png","alt":"image.png","title":"image.png","style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"四 總結"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"綜合以上的case分析,在遇到Native模塊閃退的時候,一般如果從直接的閃退堆棧看不出原因的時候,不要心急,可以搜索begin to generate native report 找到崩潰上下文,多看看logcat閃退上下文的日誌,會有一些收穫,同時對於oom類型的問題,可以結合當前內存統計來看。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章