??最后以介紹 Matrix 對于卡頓是如何監(jiān)控來結(jié)束卡頓這部分。
1.函數(shù)插樁
??Matrix 在 matrix-gradle-plugin 模塊中用 ASM 實(shí)現(xiàn)了對函數(shù)的插樁,記錄了需要插樁和不需要插樁的名單,并且可以配置其白名單和黑名單,可以配置插樁時(shí)的函數(shù)名映射文件,最終效果如下
//一般函數(shù) 在函數(shù)的開始和結(jié)尾插入了如 AppMethodBeat.i(34); 和 AppMethodBeat.o(34); 的函數(shù),可以得到函數(shù)的調(diào)用順序,數(shù)字的參數(shù)是收集需要插樁的函數(shù)從0開始遞增的
//去除了空函數(shù)、GetSet函數(shù)、單例函數(shù)、白名單過濾函數(shù)及一些系統(tǒng)函數(shù)
protected void onResume() {
AppMethodBeat.i(34);
super.onResume();
IssuesMap.clear();
AppMethodBeat.o(34);
}
//對于 Activity 的 onWindowFocusChanged 特殊處理,如果 activity 中沒有 onWindowFocusChanged 函數(shù) ,那就變下面這樣,可以統(tǒng)計(jì) app 啟動的結(jié)束點(diǎn)
public void onWindowFocusChanged(boolean var1) {
super.onWindowFocusChanged(var1);
AppMethodBeat.at(this, var1);
}
2.hook ActivityThread 中的 mH,實(shí)現(xiàn)代理主線程 handler 的 msg 分發(fā)處理
在第一次執(zhí)行到 AppMethodBeat.i(xxx); 的時(shí)候檢測有沒有代理主線程的 handler ,沒有的話就通過反射將原來的拿出來并將自己的設(shè)置進(jìn) ActivityThread 中去,對于主線程分發(fā)事件時(shí)調(diào)用 AppMethodBeat.o(0xFFFFF - 1);
可以額外記錄調(diào)用該函數(shù)的時(shí)間。
3.壞方法的監(jiān)控
通過反射拿出之前的 Printer 接口實(shí)現(xiàn)后放進(jìn)自己的 Printer 類中,將自己的 Printer 類設(shè)置為 looper 的 log 類,之后就是通過觀察主線程執(zhí)行方法時(shí)打印的 “>>>>>”和“<<<<<” 來計(jì)算方法執(zhí)行的耗時(shí),大于 700 為壞函數(shù)。
4.fps計(jì)算
類似與之前提到的,可查看之前的文章
5.anr監(jiān)控
在主線程開始執(zhí)行方法前,向子線程的 handler 里面放一個(gè)延時(shí)的 task,當(dāng)主線程方法執(zhí)行完之后延時(shí) atsk 沒有被執(zhí)行就移除掉,當(dāng)主線程方法執(zhí)行超時(shí)就執(zhí)行 Task 來收集現(xiàn)場信息,包含了進(jìn)程優(yōu)先級,nice值,從 AppMethodBeat 中拿到函數(shù)的調(diào)用順序及主線程函數(shù)掉用時(shí)間差,java 已使用內(nèi)存,native 可用內(nèi)存,vm大小,線程信息,主線程堆棧及其他信息等等