今天來分析下 Matrix 框架的 matrix-trace-canary 部分,相關文檔可查看《 Matrix Android TraceCanary 》,這份文檔是閱讀源碼的關鍵,強烈建議先看文檔再讀源碼。java
TraceCanary 是檢測應用卡頓的模塊,在該模塊下又細分了以下幾個模塊:android
在這些模塊當中,又是依賴 MethodBeat 的提早插樁來達到檢測的效果,因此,咱們在分析這幾個模塊以前,得先分析 MethodBeat 幹了些什麼,他是如何輔助以上幾個模塊來進行檢測的。git
爲了避免使文章變得枯燥無味,上面的四個模塊會另起新的文章標題進行講解,那麼本文將會對 matrix-gradle-plugin 的插樁部分先進行一個大概的講解,細節部分可能不會去分析,由於牽扯起來東西太多了。github
來看下文檔中對編譯插樁部分的描述:app
經過代理編譯期間的任務 transformClassesWithDexTask,將全局 class 文件做爲輸入,利用 ASM 工具,高效地對全部 class 文件進行掃描及插樁。框架
插樁過程有幾個關鍵點: 一、選擇在該編譯任務執行時插樁,是由於 proguard 操做是在該任務以前就完成的,意味着插樁時的 class 文件已經被混淆過的。而選擇 proguard 以後去插樁,是由於若是提早插樁會形成部分方法不符合內聯規則,無法在 proguard 時進行優化,最終致使程序方法數沒法減小,從而引起方法數過大問題。函數
二、爲了減小插樁量及性能損耗,經過遍歷 class 方法指令集,判斷掃描的函數是否只含有 PUT/READ FIELD 等簡單的指令,來過濾一些默認或匿名構造函數,以及 get/set 等簡單不耗時函數。工具
三、針對界面啓動耗時,由於要統計從 Activity#onCreate 到 Activity#onWindowFocusChange 間的耗時,因此在插樁過程當中須要收集應用內全部 Activity 的實現類,並覆蓋 onWindowFocusChange 函數進行打點。post
四、爲了方便及高效記錄函數執行過程,咱們爲每一個插樁的函數分配一個獨立 ID,在插樁過程當中,記錄插樁的函數簽名及分配的 ID,在插樁完成後輸出一份 mapping,做爲數據上報後的解析支持性能
apply plugin: 'om.tencent.matrix-plugin' 對應的是 matrix-gradle-plugin 中的MatrixPlugin 類:
implementation-class=com.tencent.matrix.plugin.MatrixPlugin
MatrixPlugin.java
該插件作了以下操做:
一、關聯 apply MatrixPlugin 設置的 extensions 參數,該參數能夠查看 sample 的 app build.gradle
二、插入 transfrom task,該 task 就如文檔所描述的 transformClassesWithDexTask
三、移除未使用的資源文件
咱們進入 MatrixTraceTransform.inject 看看:
配置的部分我省略掉了,因爲 sample app build.gradle 中未設置 customDexTransformName 的,因此,hardTask 會返回 transformClassesWithDexBuilderForDebug 和 transformClassesWithDexForDebug,在運行 sample 項目時,複製了全部的 build 過程的日誌信息,在查找的過程當中,只有 transformClassesWithDexBuilderForDebug 參與了活動,而且,也打印瞭如上的MatrixTraceTransform.java
successfully inject task:transformClassesWithDexBuilderForDebug
日誌信息。
origTransform.transform(transformInvocation);
這個 origTransform 就是系統的 transformClassesWithDexBuilderForDebug
這時候,咱們能夠直接來看 MatrixTraceTransform task 了, doTransfrom 是最重要的方法,這個部分我大概去講解一下,由於涉及跳轉太多,篇幅就會很是有影響,好在 Matrix 的開發者留給了咱們三個 step 註釋,咱們就按照這三個步驟去解釋:
一、step1:
這個地方須要關注幾個 executor.submit 的執行,第一個 ParseMappingTask,這個 task 從名稱上就能看出是一個解析 Mapping 的任務,這個任務作了以下的操做:
接着看 CollectDirectoryInputTask 和 CollectJarInputTask 任務,這兩個任務主要收集 class 原文件和 traceClassOut 文件,class 原文件咱們都知道,就是掃描到的 class 文件,那 traceClassOut 文件是什麼呢?在默認的配置中,會設置一份 traceClassOut 路徑,這個配置路徑指向的是 output/traceClassOut 路徑,咱們能夠打開 sample 下面的這個路徑:
collectedClassExtendMap 集合中的數據是須要作插樁的類,該集合中的數據保存在 output/mapping/methodMapping 下面:
三、step3
拿到混淆類集合和還原的類集合,而後拿到在 step1 中收集到的原文件和 traceOut 文件,一併參與 trace 操做。所作的內容有:
補充部分:
整體的分析差很少了,但細節部分仍是須要去細扣,本人能力有限,不對之處還望指正。