KSCrash 源碼解析

在業(yè)界,用很多有名的 Crash 監(jiān)聽工具,如閉源的 Firebase(Crashlytics)、Bugly 等,也有開源 PLCrashReporter、KSCrash 等。KSCrash 就是其中享有盛名的一個開源庫。KSCrash 有對準(zhǔn)抓取準(zhǔn)確、接口設(shè)計(jì)優(yōu)秀、Crash 文件易于二次分析的優(yōu)點(diǎn)。也因此網(wǎng)上有很多分析 KSCrash 的文章。但這些文章往往太過于追求邏輯細(xì)節(jié),而沒有對整體架構(gòu)的梳理,使得讀者還是難以自己真正理解 KSCrash 。

為了讓大家對 KSCrash 有個整體的理解,我將會使用 UML 圖來分析 KSCrash,不熟悉的讀者建議先自行了解。

本文是Crash 系列的第三篇,這個系列的目錄如下:

一 KSCrash 的主要模塊

1. KSCrash 的核心

KSCrash 的核心在于KSCrashC.c,這個文件包括了KSCrash 系統(tǒng)的所有重要入口。KSCrash.m是對KSCrashC.c的封裝。

KSCrashC.c的主要部分如下:

  • Installation

    kscrash_install()負(fù)責(zé)初始化 KSCrash 系統(tǒng)以監(jiān)聽 Crash。你可以通過kscrash_setMonitoring文件里面的函數(shù)來配置 KSCrash

  • Configuration

    所有的主要設(shè)置項(xiàng)都要可以通過類似kscrash_setXYZ的方法設(shè)置

  • App State

    KSCrash hook 了大量的app 狀態(tài)變更的通知,這些 hook 方法的命名為kscrash_notifyXYZ。

  • Crash Entry Point

    onCrash函數(shù)是處理 Crash 的主要方法,它負(fù)責(zé)獲取 app 狀態(tài),寫 crash 文件(JSON),分析 crash 等。

  • Report Management

    這個文件包括一些底層的 C 方法用來處理 crash 文件,如:kscrash_getReportCount()、kscrash_getReportIDs()、kscrash_readReport()kscrash_deleteReportWithID()等。

  • Enabling / Disabling KSCrash

    你可以用kscrash_setMonitoring方法設(shè)置啟用某些 crash 監(jiān)聽,如:Mach 監(jiān)聽、Signal 監(jiān)聽等

2. KSCrash 的主要架構(gòu)

下圖是我整理的 KSCrash 核心邏輯。通過下圖可以對KSCrash 有個整體的認(rèn)知:

KSCrash

限于篇幅,上圖只整理了核心的 Crash 監(jiān)聽相關(guān)的邏輯。在上圖我們會看到類似繼承/抽象類的概念。可能有讀者會疑惑,KSCrash 是用 C 語言寫的,哪來的類哪來的繼承呢。

實(shí)際上, 當(dāng)我們細(xì)細(xì)去理解 KSCrash 的代碼,我們會發(fā)現(xiàn)每一個 C 語言的文件的行為其實(shí)類似于一個類,并且每個方法可以理解為類的方法。只是在 C 語言的語法下,很多方法都會有一個參數(shù)表示類實(shí)例。

當(dāng)然一下子看一個整體的類圖,我們也會比較茫然。所以我將會在下面對每個主功能模塊做講解。

二 KSCrash 的主要功能模塊和運(yùn)行邏輯

1. Installation

首先要講的是 KSCrash 的初始化部分,我們可以從這里粗略了解到 KSCrash 是如何設(shè)計(jì)分離各種 Crash 監(jiān)聽模型。

Install

KSCrashMonitorType

這個枚舉定義了所有的 Crash 監(jiān)聽類型,比如 Mach 監(jiān)聽、Signal 監(jiān)聽等。這個枚舉是 Options 類型的,也就是它的值是按位偏移的。這也意味著一個 Type 的值實(shí)際代表的是一個類型集合,比如 KSCrashMonitorTypeAll 代表的是所有監(jiān)聽類型,KSCrashMonitorTypeDebuggerUnsafe代表的是 Xcode 聯(lián)調(diào)的時(shí)候不宜打開的監(jiān)聽類型等。

KSCrashMonitor 和 Monitor

Monitor 是對各種監(jiān)聽的一種抽象,KSCrashMonitor 持有一個 Monitor 類型的數(shù)組,并管理 Type 和 Monitor 的對應(yīng)關(guān)系。在初始化的時(shí)候,KSCrashMonitor 會根據(jù)運(yùn)行環(huán)境,以及傳入?yún)?shù),來決定需要初始化哪些 Crash 監(jiān)聽。并且會循環(huán)執(zhí)行各種監(jiān)聽的初始化工作: setEnabled初始化監(jiān)聽,isEnabled 初始化是否成功。

Monitor

下圖是Monitor抽象結(jié)構(gòu)和各種 KSCrashMonitor的關(guān)系。其中setEnabledisEnabled、addContextualInfoToEvent是抽象接口,也就是說各種底下的KSCrashMonitor都有這些方法。

Monitor

當(dāng)然實(shí)際上這種抽象的實(shí)現(xiàn)是依賴于結(jié)構(gòu)體Monitor,他的結(jié)構(gòu)如下:

typedef struct
{
    KSCrashMonitorType monitorType;
    KSCrashMonitorAPI* (*getAPI)(void);
} Monitor;

typedef struct
{
    void (*setEnabled)(bool isEnabled);
    bool (*isEnabled)(void);
    void (*addContextualInfoToEvent)(struct KSCrash_MonitorContext* eventContext);
} KSCrashMonitorAPI;

在各種Monitor中,會有類似的getAPI方法,其實(shí)就是返回抽象接口對應(yīng)的具體實(shí)現(xiàn)的函數(shù)指針。比如在KSCrashMonitor_MachException中:

KSCrashMonitorAPI* kscm_machexception_getAPI()
{
    static KSCrashMonitorAPI api =
    {
#if KSCRASH_HAS_MACH
        .setEnabled = setEnabled,
        .isEnabled = isEnabled,
        .addContextualInfoToEvent = addContextualInfoToEvent
#endif
    };
    return &api;
}

各種監(jiān)聽的初始化流程

KSCrash 的初始化監(jiān)聽的大致調(diào)用流程如上圖所示,需要注意的是setMonitorEnabled后面部分是一個循環(huán)過程,KSCrashMointor_XXX代表各種類型的 Monitor。

2. Crash 信息的存儲結(jié)構(gòu)

在KSCrash中主要依靠KSCrash_MonitorContext、KSMachineContext來記錄 Crash 發(fā)生時(shí)的上下文信息,比如線程信息、寄存器信息、Crash 類型以及特征等。這塊的結(jié)構(gòu)如下:

KSCrash_MonitorContext

記錄 Crash 中的 crash 類型、crash 原因等,詳見 KSCrash 的源碼或者上圖

KSMachineContext

記錄 Crash 發(fā)生在哪個線程,以及 Crash 時(shí)的所有線程列表還有寄存器信息(machineContext)。如上圖所示,KSMachineContext有兩個初始化方法。分別靠ThreadSignal來初始化。

KSStackCursor

可以理解為是一個游標(biāo),指向當(dāng)前正在分析的函數(shù)堆棧位置。這里有個核心的方法advanceCursor,這個方法的作用是函數(shù)堆棧向下溯源。從前面兩篇文章,我們知道不同情況下函數(shù)溯源的方式不同,比如 Mach 異常和 Signal 異??康氖?FP/LR 寄存器信息,NSThread 異常則是靠指針數(shù)組溯源。

上圖是列舉的幾種實(shí)現(xiàn)特殊的 Cursor。比如MachineContext用于需要使用 FP/LR 寄存器溯源的情況,Backtrace用于使用堆棧指針數(shù)組的情況。

上圖是簡單的異常處理類溯源方式的一種對應(yīng)關(guān)系。

3. Crash 的處理過程(KSCrashReport)

首先我們看一下 Crash 處理時(shí)相關(guān)的類:

KSCrashReport

從字面意義上看,KSCrashReport是將 Crash 信息變成文件的處理類。但實(shí)際上他還是 Crash 信息的進(jìn)一步組織整理者。KSCrashReport會將收到的 Crash 信息分析出來,并分析函數(shù)調(diào)用棧、線程等相關(guān)信息,然后將其整理成一個 json 文件。在后續(xù),開發(fā)者可以根據(jù)自己的需要將這個 json 文件變成標(biāo)準(zhǔn)的蘋果 crash 文件或者其他格式的文件

Crash 的處理流程

從抽象角度上講,一個 Crash 的處理流程實(shí)際上就是:

  1. Monitor 監(jiān)聽到 Crash 發(fā)生
  2. Mointor 分析 Crash 堆棧信息,錯誤原因等,并生成一個KSCrash_MonitorContext實(shí)例
  3. Monitor 調(diào)用KSCrashMonitorhandleException方法,將第2步生成的 context 實(shí)例傳入。
  4. handleException調(diào)用KSCrashonCrash方法處理 crash
  5. onCrash調(diào)用KSCrashReport將 Crash 信息轉(zhuǎn)換為標(biāo)準(zhǔn)文件(wrtieStandReport),期間會循環(huán)訪問 Cursor 的advanceCursor方法

以下以 MachException 為例,展示一個 crash 分析堆棧的處理過程。

需要注意的是,writeAllThreads方法里面有一個特殊的處理邏輯,在循環(huán)處理所有線程時(shí),它會判斷正在處理的線程是不是 Crash 發(fā)生時(shí)的線程,如果是則writeThread將會使用KSCrash_MonitorContextoffendingMachineContext來處理線程的回溯。如果是看過我前兩篇分析 crash 的文章,就會知道 Crash 線程的回溯在不同的情況下各有不同,不能和其他線程采用同樣的處理方式。

三 總結(jié)

到這里,這篇文章就結(jié)束。我沒有像其他分析 KSCrash 的文章一樣去詳細(xì)分析 Mach 異常、Signal 異常等是怎么處理的,因?yàn)槿绾畏治鲞@些異常在前兩篇文章我早已講過。在這篇文章我采用大量的類圖來講解 KSCrash 的結(jié)構(gòu),是希望幫助像我一樣缺少 C 語言開發(fā)經(jīng)驗(yàn)的人可以輕松理解 KSCrash 的架構(gòu),減少理解 KSCrash 的成本。如果有讀者在看完我三篇文章后,還是不能理解 KSCrash 是如何分析 Crash 的,可以結(jié)合本文參考一下網(wǎng)上其他分析 KSCrash 的文章,如iOS Crash 收集框架 KSCrash 源碼解析等。

本文寫于2022牛年的最后一天,提前祝大家新年快樂!如果我的文章幫助到你,請輕輕的點(diǎn)個贊喔~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • AFNetWorkingAFNetWorking一款輕量級網(wǎng)絡(luò)請求開源框架,基于iOS和mac os 網(wǎng)絡(luò)進(jìn)行擴(kuò)展...
    陽明AI閱讀 33,331評論 6 100
  • 原創(chuàng):知識點(diǎn)總結(jié)性文章創(chuàng)作不易,請珍惜,之后會持續(xù)更新,不斷完善個人比較喜歡做筆記和寫總結(jié),畢竟好記性不如爛筆頭哈...
    時(shí)光啊混蛋_97boy閱讀 902評論 0 5
  • 本文對BlockCanary源碼進(jìn)行了分析。 《行宮》寥落古行宮,宮花寂寞紅。白頭宮女在,閑坐說玄宗?!?,元稹 ...
    于衛(wèi)國閱讀 437評論 0 1
  • 源碼分析一共分為三個部分: 介紹 AFNetworking 發(fā)起網(wǎng)絡(luò)請求的主流程; 介紹 AFNetworking...
    Hpwu閱讀 492評論 0 0
  • 0x01 安裝過程 1.1 拋磚引玉1.2 Mach kernel exceptions1.3 Fatal sig...
    Adam大魔王閱讀 2,395評論 0 8

友情鏈接更多精彩內(nèi)容