APM框架Matrix源码分析(二)LooperAnrTracer卡顿ANR监控

199 阅读3分钟

Looper日志检测卡顿:利用Handler消息机制,给Looper设置一个Printer,计算dispatchMessage的执行时间,是否超过阈值来判断是否卡顿。

Message msg = me.mQueue.next(); // might block
// This must be in a local variable, in case a UI event sets the logger
final Printer logging = me.mLogging;
if (logging != null) {
 logging.println(">>>>> Dispatching to " + msg.target + " "
                 + msg.callback + ": " + msg.what);
}
//...
msg.target.dispatchMessage(msg);
//...
if (logging != null) {
   logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}

卡顿ANR监控是在TracePluginLooperAnrTracer

public class TracePlugin extends Plugin {
 
 private LooperAnrTracer looperAnrTracer;
 
 @Override
 public void init(Application app, PluginListener listener) {
   super.init(app, listener);
   looperAnrTracer = new LooperAnrTracer(traceConfig);
 }
 
 @Override
 public void start() {
   super.start();
   Runnable runnable = new Runnable() {
     @Override
     public void run() {
       if (sdkInt < Build.VERSION_CODES.N && willUiThreadMonitorRunning(traceConfig)){
         if (!UIThreadMonitor.getMonitor().isInit()) {
           try {
             //初始化UIThreadMonitor
             UIThreadMonitor.getMonitor().init(traceConfig);
          } catch (java.lang.RuntimeException e) {
             MatrixLog.e(TAG, "[start] RuntimeException:%s", e);
             return;
          }
        }
      }
       //UIThreadMonitord的isAlive置为true
       UIThreadMonitor.getMonitor().onStart();
       //start根据配置开关开启追踪
       if (traceConfig.isAnrTraceEnable()) {
         //onStartTrace最终调到了自身的onAlive
         looperAnrTracer.onStartTrace();
      }
    }
  };
   //主线程执行
   if (Thread.currentThread() == Looper.getMainLooper().getThread()) {
     runnable.run();
   } else {
     MatrixHandlerThread.getDefaultMainHandler().post(runnable);
   }
 }   
}

初始化TracePlugin时会初始化LooperAnrTracer,start时会初始化UIThreadMonitor(UI 线程的监视器)并start,监视器和追踪器等需要在主线程进行工作。接着看下UIThreadMonitor的init:

UIThreadMonitor
public void init(TraceConfig config) {
 //Looper 监听
 LooperMonitor.register(new LooperMonitor.LooperDispatchListener(historyMsgRecorder,denseMsgTracer) {
       //如果LooperMonitor处于Alive状态,才会回调dispatchStart和dispatchEnd
       @Override
       public boolean isValid() {
           return isAlive;
      }
       //日志>>>>>回调   x.charAt(0) == '>' 表示事件开始
       @Override
       public void dispatchStart() {
           super.dispatchStart();
           UIThreadMonitor.this.dispatchBegin();
      }
       //日志<<<<<回调 表示事件结束
       @Override
       public void dispatchEnd() {
           super.dispatchEnd();
           UIThreadMonitor.this.dispatchEnd();
      }
      
    });
}
LooperMonitor

LooperMonitor就是给Looper设置一个Printer

//主线程Looper监控
private static final LooperMonitor sMainMonitor = LooperMonitor.of(Looper.getMainLooper());
//维护一个map支持多个looper监控
public static LooperMonitor of(@NonNull Looper looper) {
    LooperMonitor looperMonitor = sLooperMonitorMap.get(looper);
    if (looperMonitor == null) {
      looperMonitor = new LooperMonitor(looper);
      sLooperMonitorMap.put(looper, looperMonitor);
    }
    return looperMonitor;
}
//注册监控回调
@Deprecated
static void register(LooperDispatchListener listener) {
    sMainMonitor.addListener(listener);
}
//创建LooperMonitor
private LooperMonitor(Looper looper) {
    Objects.requireNonNull(looper);
    this.looper = looper;
    //利用反射设置Printer
    resetPrinter();
    //空闲时Handler每分钟设置一次,避免失效
    addIdleHandler(looper);
}

private synchronized void resetPrinter() {
    Printer originPrinter = null;
    try {
      if (!isReflectLoggingError) {
         originPrinter = ReflectUtils.get(looper.getClass(), "mLogging", looper);
         //已经设置过了,不再设置
         //LooperPrinter被不同的ClassLoader加载处理
      }
    } catch (Exception e) {
       isReflectLoggingError = true;
    }
    //装饰者模式,不影响原 Printer 打印日志的逻辑,又可以获取到日志
    looper.setMessageLogging(printer = new LooperPrinter(originPrinter));
}

利用反射获取mLogging对象,然后使用装饰者模式不影响原 Printer 打印日志的逻辑,又可以获取到日志。根据dispatch(x.charAt(0) == '>', x); ,即>>>>>回调dispatchStart和<<<<<回调dispatchEnd。

接着我们回头看LooperAnrTracer

LooperAnrTracer
public class LooperAnrTracer extends Tracer implements ILooperListener {
     //anr上报
     private final AnrHandleTask anrTask = new AnrHandleTask();
     //卡顿上报
     private final LagHandleTask lagTask = new LagHandleTask();

     @Override
     public void onAlive() {
       super.onAlive();
       if (isAnrTraceEnable) {
         //注册LooperMonitor 
         LooperMonitor.register(this);
         //用于发送延时消息来判断是否anr的Handler
         this.anrHandler = new Handler(MatrixHandlerThread.getDefaultHandler().getLooper());
         this.lagHandler = new Handler(MatrixHandlerThread.getDefaultHandler().getLooper());
       }
     }
 
     @Override
     public void onDead() {
       super.onDead();
       if (isAnrTraceEnable) {
         //解注册LooperMonitor
         LooperMonitor.unregister(this);
         //移除消息
         anrHandler.removeCallbacksAndMessages(null);
         lagHandler.removeCallbacksAndMessages(null);
       }
     }
 
     @Override
     public boolean isValid() {
       return true;
     }

     @Override
     public void onDispatchBegin(String log) {
       //发送延时5秒消息
       anrHandler.postDelayed(anrTask, Constants.DEFAULT_ANR);
       //发送延迟2秒消息
       lagHandler.postDelayed(lagTask, Constants.DEFAULT_NORMAL_LAG);
     }

     @Override
     public void onDispatchEnd(String log, long beginNs, long endNs) {
       if (traceConfig.isDevEnv()) {
         long cost = (endNs - beginNs) / Constants.TIME_MILLIS_TO_NANO;
         MatrixLog.v(TAG, "[dispatchEnd] beginNs:%s endNs:%s cost:%sms", beginNs, endNs, cost);
       }
       //移除消息
       anrHandler.removeCallbacks(anrTask);
       lagHandler.removeCallbacks(lagTask);
     }
}

上述anr和卡顿处理方式一样 ,在消息开始的时候通过Handler发送一个延迟上报任务Runable,结束的时候移除任务,执行时间超过阈值执行Runable

至此,LooperAnrTracer卡顿ANR监控分析完毕

但是,有些情况的卡顿上述方案无法监控到(might block):

1.主线程空闲时,也会阻塞在MessageQueue的next方法中,无法区分卡顿还是主线程空闲。

2.View的TouchEvent中的卡顿,Touch事件大部分是从nativePollOnce直接到InputEventReceiver,然后到然后到ViewRootImpl进行分发。

3.IdeaHandler的queueIdle回调方法也无法被监控到

4.同步屏障

后续再分析。。。