Matrix 之 TraceCanary 源碼分析

今天來分析下 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

image.png

該插件作了以下操做:
一、關聯 apply MatrixPlugin 設置的 extensions 參數,該參數能夠查看 sample 的 app build.gradle
二、插入 transfrom task,該 task 就如文檔所描述的 transformClassesWithDexTask
三、移除未使用的資源文件

咱們進入 MatrixTraceTransform.inject 看看:

MatrixTraceTransform.java

image.png
配置的部分我省略掉了,因爲 sample app build.gradle 中未設置 customDexTransformName 的,因此,hardTask 會返回  transformClassesWithDexBuilderForDebug 和 transformClassesWithDexForDebug,在運行 sample 項目時,複製了全部的 build 過程的日誌信息,在查找的過程當中,只有 transformClassesWithDexBuilderForDebug 參與了活動,而且,也打印瞭如上的 successfully inject task:transformClassesWithDexBuilderForDebug  日誌信息。
最後會 hook 掉 transformClassesWithDexBuilderForDebug 的 task,替換成本身的 MatrixTraceTransform,MatrixTraceTransform 的構造方法傳入了 transformClassesWithDexBuilderForDebug task,在 MatrixTraceTransform 使用完成後,是須要傳遞給下一個 transfrom 繼續運行的,因此,在 MatrixTraceTransform 的 transfrom 方法中,會看到:

origTransform.transform(transformInvocation);

這個 origTransform 就是系統的 transformClassesWithDexBuilderForDebug

這時候,咱們能夠直接來看 MatrixTraceTransform task 了, doTransfrom 是最重要的方法,這個部分我大概去講解一下,由於涉及跳轉太多,篇幅就會很是有影響,好在 Matrix 的開發者留給了咱們三個 step 註釋,咱們就按照這三個步驟去解釋:

image.png

一、step1:
這個地方須要關注幾個 executor.submit 的執行,第一個 ParseMappingTask,這個 task 從名稱上就能看出是一個解析 Mapping 的任務,這個任務作了以下的操做:

  1. 讀取 output 下面的 mapping.txt 文件,還原混淆前的類和方法,存放在 MappingCollector 類中 mObfuscatedClassMethodMap 和 mOriginalClassMethodMap 集合中
  2. 讀取自定義的 baseMethodMapFile 配置,直接生成 TraceMethod 存放到 collectedMethodMap 中,在 sample 中,baseMethodMapFile 未設置配置文件

接着看 CollectDirectoryInputTask 和 CollectJarInputTask 任務,這兩個任務主要收集 class 原文件和 traceClassOut 文件,class 原文件咱們都知道,就是掃描到的 class 文件,那 traceClassOut 文件是什麼呢?在默認的配置中,會設置一份 traceClassOut 路徑,這個配置路徑指向的是 output/traceClassOut 路徑,咱們能夠打開 sample 下面的這個路徑:

image.png


二、step2
主要看 collect 方法,該方法作了以下的幾個操做:

  1. 將 DirectoryInput 收集的 class 原文件和 CollectJarInputTask 收集的原文件進行遍歷,利用 TraceClassAdapter 來收集須要插入字節碼(collectedClassExtendMap)和類和須要忽略掉的類(collectedIgnoreMethodMap)
  2. 分類保存上面收集到的兩個集合,在寫入文件時,會根據原 class 混淆文件 revert 還原 class,而後一併寫入到文件中,這樣,咱們在查看混淆與對應文件時會很是的方便:

collectedClassExtendMap 集合中的數據是須要作插樁的類,該集合中的數據保存在 output/mapping/methodMapping 下面:

image.png

collectedIgnoreMethodMap 集合中的數據是須要忽略掉的類,該集合中的數據保存在 output/mapping/ignoreMethodMapping 下面 : 

image.png

三、step3
拿到混淆類集合和還原的類集合,而後拿到在 step1 中收集到的原文件和 traceOut 文件,一併參與 trace 操做。所作的內容有:

  1. 遍歷原 class 文件,並建立 traceOut 路徑文件
  2. 對原 class 文件進行插樁操做,插樁的內容有:
  3. Activity 的 onWindowFocusChanged 方法插入 AppMethodBeat.getInstance().at 方法
  4. 知足類的方法在開頭和結尾插入 i/o 方法
  5. 對插樁後的 class 文件 copy 一份到 traceOut 路徑文件

總結

補充部分:

  1. matrix-gradle-plugin 是能夠設置黑名單的,在 sample app build.gradle 下能夠看到設置的 balckMethodList,對於設置了黑名單的 package 或是 class,是不會被插樁操做
  2. 若是想看插樁以後的代碼效果,能夠直接查看 output/mapping/traceClassOut 路徑下的效果類,確實很方便,建議作插樁效果的插件都能像 matrix 這樣去作,在看實現效果時,不再用去看 transfrom 下面各類各類的 jar 或是反編譯 apk 才能看到本身是否真正被插入成功
  3. 對於未被插樁的函數,能夠直接查看 output/mapping/ignoreMethodMapping.txt 文件
  4. 每一個插樁函數都有對應的 methodId,若是想看對應關係的話,能夠直接查看 output/mapping/methodMapping.txt 文件

整體的分析差很少了,但細節部分仍是須要去細扣,本人能力有限,不對之處還望指正。

相關文章
相關標籤/搜索