APM框架Matrix源码分析(三)IdleHandlerLagTracer卡顿监控

171 阅读2分钟

Looper日志检测卡顿检测是无法监控IdleHandler的queueIdle回调方法的,这个方法会在主线程空闲的时候被调用,主线程MessageQueue的queueIdle默认也在在主线程中执行,这里的耗时操作会阻塞在MessageQueue的next方法中,也会引起卡顿和ANR的。

//looper轮询消息
Message msg = me.mQueue.next(); // might block
//MessageQueue
Message next() {
for (;;) {
   nativePollOnce(ptr, nextPollTimeoutMillis);
   //...
   // Run the idle handlers.
   // We only ever reach this code block during the first iteration.
   for (int i = 0; i < pendingIdleHandlerCount; i++) {
     final IdleHandler idler = mPendingIdleHandlers[i];
     mPendingIdleHandlers[i] = null// release the reference to the handler

     boolean keep = false;
     try {
       //IdleHandler的queueIdle
       keep = idler.queueIdle();
     } catch (Throwable t) {
       Log.wtf(TAG, "IdleHandler threw exception", t);
     }

     if (!keep) {
       synchronized (this) {
         mIdleHandlers.remove(idler);
       }
     }
   }
 }
}

TracePlugin的IdleHandlerLagTracer就是解决这个问题的。TracePlugin启动时开启了IdleHandlerLagTracer

if (traceConfig.isIdleHandlerTraceEnable()) {
  idleHandlerLagTracer = new IdleHandlerLagTracer(traceConfig);
  idleHandlerLagTracer.onStartTrace();
}
@Override
public void onAlive() {
 super.onAlive();
 if (traceConfig.isIdleHandlerTraceEnable()) {
   //创建自己的HandlerThread
   idleHandlerLagHandlerThread = new HandlerThread("IdleHandlerLagThread");
   //创建上报任务
   idleHandlerLagRunnable = new IdleHandlerLagRunable();
   //监控IdleHandler
   detectIdleHandler();
 }
}

@Override
public void onDead() {
 super.onDead();
 if (traceConfig.isIdleHandlerTraceEnable()) {
   //onDead时移除消息
   idleHandlerLagHandler.removeCallbacksAndMessages(null);
 }
}

接着看下detectIdleHandler方法:

private static void detectIdleHandler() {
   try {
       if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.M) {
           return;
       }
      //拿到主线程消息队列MessageQueue
       MessageQueue mainQueue = Looper.getMainLooper().getQueue();
      //通过反射拿到MessageQueue的mIdleHandlers,我们使用addIdleHandler的IdleHandler会存放在ArrayList<IdleHandler> mIdleHandlers
       Field field = MessageQueue.class.getDeclaredField("mIdleHandlers");
       field.setAccessible(true);
      //创建自己的myIdleHandlerArrayList
       MyArrayList<MessageQueue.IdleHandler> myIdleHandlerArrayList = new MyArrayList<>();
     //将MessageQueue的mIdleHandlers替换成自己的myIdleHandlerArrayList,用来接管空闲消息
       field.set(mainQueue, myIdleHandlerArrayList);
       idleHandlerLagHandlerThread.start();
       idleHandlerLagHandler = new Handler(idleHandlerLagHandlerThread.getLooper());
   } catch (Throwable t) {
       MatrixLog.e(TAG, "reflect idle handler error = " + t.getMessage());
   }
}

通过反射拿到消息队列MessageQueue的空闲消息ArrayList,替换成自己的MyArrayList,然后在自己的MyArrayList的add和remove增加自己的逻辑来接管空闲消息。

static class MyArrayList<T> extends ArrayList {
 Map<MessageQueue.IdleHandler, MyIdleHandler> map = new HashMap<>();

 @Override
 public boolean add(Object o) {
   if (o instanceof MessageQueue.IdleHandler) {
     //包装一层MyIdleHandler
     MyIdleHandler myIdleHandler = new MyIdleHandler((MessageQueue.IdleHandler) o);
     map.put((MessageQueue.IdleHandler) o, myIdleHandler);
     return super.add(myIdleHandler);
   }
   return super.add(o);
}

 @Override
 public boolean remove(@Nullable Object o) {
   if (o instanceof MyIdleHandler) {
     MessageQueue.IdleHandler idleHandler = ((MyIdleHandler) o).idleHandler;
     map.remove(idleHandler);
     return super.remove(o);
   } else {
     MyIdleHandler myIdleHandler = map.remove(o);
     if (myIdleHandler != null) {
       return super.remove(myIdleHandler);
    }
     return super.remove(o);
   }
 }
}

包装一层MyIdleHandler,添加自己的逻辑且不改变原有逻辑。

static class MyIdleHandler implements MessageQueue.IdleHandler {
  private final MessageQueue.IdleHandler idleHandler;

  MyIdleHandler(MessageQueue.IdleHandler idleHandler) {
    this.idleHandler = idleHandler;
  }

  @Override
  public boolean queueIdle() {
    //发送一个延迟2秒的消息
    idleHandlerLagHandler.postDelayed(idleHandlerLagRunnable, traceConfig.idleHandlerLagThreshold);
    //queueIdle的执行
    boolean ret = this.idleHandler.queueIdle();
    //如果不能在2秒后清空任务,说明queueIdle太慢了,则会执行上报。
    idleHandlerLagHandler.removeCallbacks(idleHandlerLagRunnable);
    return ret;
  }
}

至此,IdleHandlerLagTracer卡顿监控分析完毕。