鴻蒙HarmonyOS NEXT應用崩潰分析及修復
如何保證應用的健壯性,其中一個指標就是看崩潰率,如何降低崩潰率,就需要知道存在哪些崩潰,然后對癥下藥,解決崩潰。那么鴻蒙應用中存在哪些崩潰類型呢?又改如何解決呢?
故障類型
目前鴻蒙中存在的崩潰主要分為CPP_CRASH、JS_ERROR、OOM、PROCESS_KILL、APP_FREEZE、RESOURCE_LEAK6大類型。
CPP_CRASH類型
主要是進程崩潰指C/C++運行時崩潰,主要體現在so相關的sdk上。
1.空指針解引用 NULL pointer dereference
形如SIGSEGV(SEGV_MAPERR)@0x00000000或r0 r1等傳參寄存器的值為0時應首先考慮調用時是否傳入了空指針
2.結構體/類未初始化指針
形如SIGSEGV(SEGV_MAPERR)@0x0000000c或 r1等傳參寄存器的值為一個很小的值時應考慮調用入參的結構體成員是否包含空指針
3.程序主動終止SIGABRT
一般為用戶/框架/C庫主動觸發,大部分場景下跳過C庫/abort發起的框架庫的第一幀即為崩潰原因
這里主要檢測的是資源使用類的問題,如線程創建,文件描述符使用,接口調用時序等
4.棧溢出
如遞歸調用,析構函數相互調用,特殊的棧(信號棧)中使用大塊棧內存
5.多線程操作集合
std的集合為非線程安全,如果多線程添加刪除,容易出現SIGSEGV, 如果使用addr2line后的代碼行與集合相關,可以考慮這個原因
6.不匹配的對象生命周期
如使用裸指針保存sptr類型以及shared_ptr類型
7.返回臨時變量、野指針
如返回棧變量的引用,釋放后未置空繼續訪問
具體可參考官方
https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/fault-analysis
JS_ERROR類型
當未處理的JS異常導致應用意外退出時,應用會在拋出未處理的異常時崩潰并且會生成對應的JS Crash崩潰日志文件。
JS Crash異常根據不同的異常場景,在 Reason 字段進行了分類,分為Error、TypeError、SyntaxError、RangeError等錯誤類型。
自定義 Error 類:Error 是最基本的錯誤類型,其他的錯誤類型都繼承自該類型。Error 對象主要有兩個重要屬性 message 和 name 分別表示錯誤信息和錯誤名稱。程序運行過程中拋出的異常一般都有具體的類型,Error 類型一般都是開發人員自己拋出的異常。
TypeError(類型錯誤)類:運行時最常見的異常,表示變量或參數不是預期類型。
SyntaxError(語法錯誤)類:語法錯誤也稱為解析錯誤。語法錯誤在任何編程語言中都是最常見的錯誤類型,表示不符合編程語言的語法規范。
RangeError(邊界錯誤)類:表示超出有效范圍時發生的異常,主要的有以下幾種情況:
數組長度為負數或超長。
數字類型的方法參數超出預定義范圍。
函數堆棧調用超過最大值。
ReferenceError - 引用錯誤:引用一個不存在的變量時發生的錯誤。每當我們創建一個變量時,變量名稱都會寫入一個變量存儲中心中。這個變量存儲中心就像鍵值存儲一樣,每當我們引用變量時,它都去存儲中找到 key并提取并返回 value。如果我們要找的變量不在存儲中,就會拋出 ReferenceError。
URI Error - URL錯誤:在調用 URI 相關的方法中 URL 無效時拋出的異常,主要包括 encodeURI()、decodeURI()、encodeURIComponent()、decodeURIComponent()、escape() 和 unescape() 幾個函數 。
其中這一類型的bug是最容易修復的,因為這些往往就是業務側的一些不嚴謹代碼導致的,異常也暴漏在業務層代碼。
PROCESS_KILL類型
SWAP_FULL: 系統交換分區空間不足,系統清理;
LowMemoryKill:系統整機可用內存較低,系統清理;
CAMERA_QUICK_Kll:相機場景內存需求較大,需要查殺應用清理內存;
這個不是異常,如果想規避可以通過降低自身內存占用,降低被清理的優先級。
APP_FREEZE類型
主要對應Appfreeze事件:
THREAD_BLOCK_6S 應用主線程卡死超時。
APP_INPUT_BLOCK 用戶輸入響應超時。
LIFECYCLE_TIMEOUT Ability生命周期切換超時。
主線程Watchdog(3S/6S)
用戶輸入事件超時5S
生命周期切換超時分為Ability生命周期切換超時和PageAbility生命周期切換超時。
該故障出現在生命周期切換的過程中,影響當前應用內Ability的切換或者不同PageAbility之間的切換。
OOM類型
內存溢出(Out Of Memory,簡稱OOM)是指應用系統中存在無法回收的內存或使用的內存過多,最終使得程序運行要用到的內存大于能提供的最大內存。此時程序就運行不了,系統會提示內存溢出。
RESOURCE_LEAK
資源泄漏是指句柄/線程/內存等資源超過系統設定上限,部分資源甚至失去了管控能力,此時系統可能出現卡死/重啟等異常情況。LeakDetector模塊提供資源泄漏檢測、判決、維測日志抓取、日志上報的能力,為開發者提供詳細的維測日志以輔助故障定位。
故障恢復
代碼定位
TypeError類問題在實際應用開發調試運行過程中是最常見的JS Crash類型,其表示為變量不是預期類型,在代碼層面則為對變量的使用未進行事先的校驗,在錯誤日志中報錯多表現為如下:
Error name:TypeError
Error message:Cannot read property xxx of undefined
通過Error message很清除可以明白報錯原因。
JS調用棧可直接通過超鏈接跳轉到對應錯誤代碼行,棧頂即為問題第一現場,如下樣例所示。
Device info:xxx
Build info:xxx-xxx x.x.x.xxx(xxxx)
Fingerprint:ed1811f3f5ae13c7262b51aab73ddd01df95b2c64466a204e0d70e6461cf1697
Module name:com.xxx.xxx
Version:1.0.0
VersionCode:1000000
PreInstalled:No
Foreground:Yes
Pid:31255
Uid:20020145
Reason:Error
Error name:Error
Error message:JSERROR
Sourcecode:throw new ErrOr("JSERROR");^
Stacktrace:at anonymous (entry/src/main/ets/pages/Index.ets:13:19)
異常代碼調用棧包含 SourceMap is not initialized yet ,表示因SourceMap轉換非常耗時,改為通過異步線程去進行初始化,導致會出現SourceMap沒初始化完成就有異常產生的情況。針對這種情況增加這行日志來提示開發者。eTS棧對應編譯后產物中代碼行號,可通過超鏈接跳轉到對應錯誤代碼行。
Generated by HiviewDFX@HarmonyOS
================================================================
Device info:xxxx
Build info:xxxx
Fingerprint:9851196f9fed7fd818170303296ae7a5767c9ab11f38fd8b0072f0e32c42ea39
Module name:com.xxx.xxx
Version:1.0.0.29
VersionCode:10000029
PreInstalled:Yes
Foreground:No
Pid:2780
Uid:20020018
Reason:TypeError
Error name:TypeError
Error message:Cannot read property needRenderTranslate of undefined
Stacktrace:
Cannot get SourceMap info, dump raw stack:at updateGestureValue (phone/src/main/ets/SceneBoard/recent/scenepanel/recentpanel/RecentGesture.ts:51:51)at onRecentGestureActionBegin (phone/src/main/ets/SceneBoard/scenemanager/SCBScenePanel.ts:5609:5609)at anonymous (phone/src/main/ets/SceneBoard/scenemanager/SCBScenePanel.ts:555:555)at anonymous (phone/src/main/ets/SceneBoard/recent/RecentEventView.ts:183:183)
Cannot get SourceMap info, dump raw stack 信息表示該應用為release包安裝,JS棧轉換eTS行列號失敗,可考慮使用應用堆棧解析來解析行號。
應用堆棧解析
將報錯信息直接使用ide查看,選擇DevEco Studio底部log選擇AnalyzeStackTrace,選擇Source map、So、Name cache,點擊start,右側就會把ts對應的ets代碼映射關系出來。
或者使用三方網站 https://www.murzwin.com/base64vlq.html,將BaseEncode的報錯,decode解析出來,效果是這樣的,把ts的行列信息映射到ets中。
sourceMaps和nameCache分別在下面的勾對號和紅框里面的,文件是一樣的,可能是針對不同使用方使用的。所以在打APP包產物的時候要備份sourceMaps和nameCache文件,就是為了轉換報錯信息使用的。sourceMaps是解決行列信息,nameCache主要是為了解混淆文件使用的。
總結
通過上面我們很清楚的知道鴻蒙中故障分類和產生的原因、以及產生故障的代碼應用層位置,我們就可以很容易去解決以上問題,從而降低線上的崩潰率。