Matrix源码分析
卡顿监控原理
替换主线程Looper的Printer,从而监控dispatchMessage的执行时间,源码可以查看com/tencent/matrix/trace/core/LooperMonitor.java
具体可以查看公众号里面微信团队的解析
通过监控dispatchMessage的执行时间有三个缺点
IdleHandler的耗时无法被监控到
Matrix的解决方案是反射替换了IdleHandler,源码可以查看com/tencent/matrix/trace/tracer/IdleHandlerLagTracer.java
Touch的卡顿无法监控到
Matrix的方案是send和recv方法来监控Touch事件啊,源码可以查看com/tencent/matrix/trace/tracer/TouchEventLagTracer.java
有一个低成本的方案
class TouchCostWindowCallback(private val windowCallback: Window.Callback) :
Window.Callback by windowCallback {
override fun dispatchTouchEvent(event: MotionEvent?): Boolean {
val start = System.currentTimeMillis()
val rst = windowCallback.dispatchTouchEvent(event)
val cost = System.currentTimeMillis() - start
// 监控
return rst
}
}
使用方案如下
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks {
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
val originalCallback = activity.window.callback
val wrappedCallback = TouchCostWindowCallback(originalCallback)
activity.window.callback = wrappedCallback
}
override fun onActivityStarted(activity: Activity) {}
override fun onActivityResumed(activity: Activity) {}
override fun onActivityPaused(activity: Activity) {}
override fun onActivityStopped(activity: Activity) {}
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {}
override fun onActivityDestroyed(activity: Activity) {}
})
}
}
SyncBarrier泄露
这里直接复制公众号里面的内容:目前我们的方案是不断轮询主线程Looper的MessageQueue的mMessage(也就是主线程当前正在处理的Message)。而SyncBarrier本身也是一种特殊的Message,其特殊在它的target是null。如果我们通过反射mMessage,发现当前的Message的target为null,并且通过这个Message的when发现其已经存在很久了,这个时候我们合理怀疑产生了SyncBarrier的泄漏(但还不能完全确定,因为如果当时因为其他原因导致主线程卡死,也可能会导致这种现象),然后再发送一个同步消息和一个异步消息,如果异步消息被处理了,但是同步消息一直无法被处理,这时候就说明产生了SyncBarrier的泄漏。如果激进一些,这个时候我们甚至可以反射调用MessageQueue的removeSyncBarrier方法,手动把这个SyncBarrier移除掉,从而从错误状态中恢复。下面代码展示了大概的原理:
MessageQueue mainQueue = Looper.getMainLooper().getQueue();
Field field = mainQueue.getClass().getDeclaredField("mMessages");
field.setAccessible(true);
Message mMessage = (Message) field.get(mainQueue); //通过反射得到当前正在等待执行的Message
if (mMessage != null) {
currentMessageToString = mMessage.toString();
long when = mMessage.getWhen() - SystemClock.uptimeMillis();
if (when < -3000 && mMessage.getTarget() == null) { //target == null则为sync barrier
int token = mMessage.arg1;
startCheckLeaking(token);
}
}
private static void startCheckLeaking(int token) {
int checkCount = 0;
barrierCount = 0;
while (checkCount < CHECK_STRICTLY_MAX_COUNT) {
checkCount++;
int latestToken = getSyncBarrierToken();
if (token != latestToken) { //token变了,不是同一个barrier,return
break;
}
if (DetectSyncBarrierOnce()) {
//发生了sync barrier泄漏
removeSyncBarrier(token); //手动remove泄漏的sync barrier
break;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private static void removeSyncBarrier(int token) {
MessageQueue mainQueue = Looper.getMainLooper().getQueue();
Method method = mainQueue.getClass().getDeclaredMethod("removeSyncBarrier", int.class);
method.setAccessible(true);
method.invoke(mainQueue, token);
}
private static boolean DetectSyncBarrierOnce() {
Handler mainHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.arg1 == 0) {
barrierCount ++; //收到了异步消息,count++
} else if (msg.arg1 == 1) {
barrierCount = 0; //收到了同步消息,说明同步屏障不在, count设置为0
}
}
};
Message asyncMessage = Message.obtain();
asyncMessage.setAsynchronous(true);
asyncMessage.setTarget(mainHandler);
asyncMessage.arg1 = 0;
Message syncNormalMessage = Message.obtain();
syncNormalMessage.arg1 = 1;
mainHandler.sendMessage(asyncMessage); //发送一个异步消息
mainHandler.sendMessage(syncNormalMessage); //发送一个同步消息
if(barrierCount > 3){
return true;
}
return false;
}
简单版本的Matrix
class LagException(s: String) : Exception(s)
class AnrException(s: String) : Exception(s)
class IdleLagException(s: String) : Exception(s)
object MsgMonitor {
private const val DEFAULT_ANR = 5 * 1000L
private const val DEFAULT_NORMAL_LAG = 2 * 1000L
private const val DEFAULT_IDLE_HANDLER_LAG = DEFAULT_NORMAL_LAG
private val msgMonitorHandler by lazy {
val thread = HandlerThread("MsgMonitor")
thread.start()
Handler(thread.looper)
}
private val idleMsgHandler by lazy {
val thread = HandlerThread("idleMsgMonitor")
thread.start()
Handler(thread.looper)
}
private val lagReportTask: Runnable by lazy {
Runnable {
val stackTrace = getMainThreadStackTrace()
val lagException = LagException("卡顿异常")
lagException.stackTrace = stackTrace
Log.i("MsgMonitor", Log.getStackTraceString(lagException))
}
}
private val anrReportTask: Runnable by lazy {
Runnable {
val stackTrace = getMainThreadStackTrace()
val anrException = AnrException("ANR异常")
anrException.stackTrace = stackTrace
Log.i("MsgMonitor", Log.getStackTraceString(anrException))
}
}
private val idleReportTask: Runnable by lazy {
Runnable {
val stackTrace = getMainThreadStackTrace()
val idleLagException = IdleLagException("IdleLag卡顿")
idleLagException.stackTrace = stackTrace
Log.i("MsgMonitor", Log.getStackTraceString(idleLagException))
}
}
private val touchReportTask: Runnable by lazy {
Runnable {
val stackTrace = getMainThreadStackTrace()
val idleLagException = TouchLagException("touch卡顿")
idleLagException.stackTrace = stackTrace
Log.i("MsgMonitor", Log.getStackTraceString(idleLagException))
}
}
fun init() {
hookLooper()
hookIdleHandler()
}
fun injectTouch(window: Window) {
val originalCallback = window.callback
val wrappedCallback = TouchCostWindowCallback(originalCallback)
window.callback = wrappedCallback
}
private fun hookLooper() {
Looper.getMainLooper().setMessageLogging { x ->
val isValid = x[0] == '>' || x[0] == '<'
if (isValid) {
dispatch(x[0] == '>', x)
}
}
}
private fun hookIdleHandler() {
try {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
return
}
val mainQueue = Looper.getMainLooper().queue
val field = MessageQueue::class.java.getDeclaredField("mIdleHandlers")
field.isAccessible = true
val myIdleHandlerArrayList = IdleArrayList()
field[mainQueue] = myIdleHandlerArrayList
} catch (t: Throwable) {
Log.i("MsgMonitor", "hook fail")
}
}
private fun dispatch(isBegin: Boolean, log: String) {
if (isBegin) {
msgMonitorHandler.postDelayed(lagReportTask, DEFAULT_NORMAL_LAG)
msgMonitorHandler.postDelayed(anrReportTask, DEFAULT_ANR)
} else {
msgMonitorHandler.removeCallbacks(lagReportTask)
msgMonitorHandler.removeCallbacks(anrReportTask)
}
}
private fun getMainThreadStackTrace(): Array<out StackTraceElement> {
val mainThread = Looper.getMainLooper().thread
return mainThread.stackTrace
}
private class IdleHandlerProxy(val idleHandler: MessageQueue.IdleHandler) :
MessageQueue.IdleHandler {
override fun queueIdle(): Boolean {
idleMsgHandler.postDelayed(idleReportTask, DEFAULT_IDLE_HANDLER_LAG)
val ret = idleHandler.queueIdle()
idleMsgHandler.removeCallbacks(idleReportTask)
return ret
}
override fun toString(): String {
return idleHandler.toString()
}
}
class IdleArrayList : ArrayList<Any>() {
private var map: MutableMap<IdleHandler, IdleHandlerProxy> =
HashMap()
override fun add(element: Any): Boolean {
if (element is IdleHandler) {
val myIdleHandler = IdleHandlerProxy(element)
map[element] = myIdleHandler
return super.add(myIdleHandler)
}
return super.add(element)
}
override fun remove(element: Any): Boolean {
return if (element is IdleHandlerProxy) {
val idleHandler: IdleHandler = element.idleHandler
map.remove(idleHandler)
super.remove(element)
} else {
val myIdleHandler: IdleHandlerProxy? = map.remove(element)
if (myIdleHandler != null) {
super.remove(myIdleHandler)
} else super.remove(element)
}
}
}
internal class TouchCostWindowCallback(private val windowCallback: Window.Callback) :
Window.Callback by windowCallback {
override fun dispatchTouchEvent(event: MotionEvent?): Boolean {
val start = System.currentTimeMillis()
msgMonitorHandler.postDelayed(touchReportTask, DEFAULT_NORMAL_LAG)
val rst = windowCallback.dispatchTouchEvent(event)
msgMonitorHandler.removeCallbacks(touchReportTask)
val cost = System.currentTimeMillis() - start
return rst
}
}
}
其实在ANR的时候,我们也可以检查一下当前的消息,封装如下
object MsgUtils {
fun dumpMsgQueue() {
try {
// 获取主线程的Looper
val looper = Looper.getMainLooper()
// 获取MessageQueue
val messageQueue = looper.queue
// 反射获取MessageQueue中的mMessages字段
val messagesField = MessageQueue::class.java.getDeclaredField("mMessages")
messagesField.isAccessible = true
// 反射获取MessageQueue中的next()方法
val nextMethod = MessageQueue::class.java.getDeclaredMethod("next")
nextMethod.isAccessible = true
// 获取mMessages字段的首个Message
var message = messagesField[messageQueue]
// 遍历Message链表
while (message != null) {
// 打印Message信息
Log.d("MsgMonitor", message.toString())
// 通过反射获取下一个Message
val nextField = message.javaClass.getDeclaredField("next")
nextField.isAccessible = true
message = nextField[message]
}
} catch (e: Exception) {
e.printStackTrace()
}
}
fun dumpMsgQueue2(): String {
val printer = DumpPrinter()
Looper.getMainLooper().dump(printer, "")
val pendingMsgStr = printer.stringBuilder.toString()
Log.d("MsgMonitor", pendingMsgStr)
return pendingMsgStr
}
class DumpPrinter : Printer {
val stringBuilder = StringBuilder()
override fun println(x: String) {
stringBuilder.append(x).append("\n")
}
}
fun dumpPendingMsg() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
return
}
try {
// 获取主线程的Looper
val looper = Looper.getMainLooper()
// 获取MessageQueue
val messageQueue = looper.queue
// 反射获取MessageQueue中的mIdleHandlers字段
val idleHandlersField: Field =
MessageQueue::class.java.getDeclaredField("mIdleHandlers")
idleHandlersField.setAccessible(true)
val idleHandlers = idleHandlersField.get(messageQueue) as? ArrayList<*>
val array = idleHandlers?.toArray()
// 打印所有的IdleHandlers
if (array != null) {
for (idleHandler in array) {
Log.d("MsgMonitor", idleHandler.toString())
}
}
} catch (e: java.lang.Exception) {
e.printStackTrace()
}
}
}