开篇
第二篇文章中,我们分析了 TracePlugin
中的 LooperAnrTrace
类。今天这篇文章接着分析 TracePlugin
中的 FrameTrace
类源码。
一、FrameTrace的触发时机
1.1 TracePlugin. start() 方法
注意看,在 TracePlugin
类的start()
方法中,调用了所有 Trace
类的 onStartTrace()
方法:
@Override
public void start() {
// ... 省略
Runnable runnable = new Runnable() {
@Override
public void run() {
// ... 省略
// 1, 通过反射得到addInputQueue method对象,加入inputCallback事件
UIThreadMonitor.getMonitor().onStart();
if (traceConfig.isAnrTraceEnable()) {
looperAnrTracer.onStartTrace();
}
if (traceConfig.isIdleHandlerEnable()) {
idleHandlerLagTracer = new IdleHandlerLagTracer(traceConfig);
idleHandlerLagTracer.onStartTrace();
}
if (traceConfig.isSignalAnrTraceEnable()) {
if (!SignalAnrTracer.hasInstance) {
signalAnrTracer = new SignalAnrTracer(traceConfig);
signalAnrTracer.onStartTrace();
}
}
if (traceConfig.isMainThreadPriorityTraceEnable()) {
threadPriorityTracer = new ThreadPriorityTracer();
threadPriorityTracer.onStartTrace();
}
// 2,这里调用,如果isFPSEnable为true 则启用fps监听
if (traceConfig.isFPSEnable()) {
frameTracer.onStartTrace();
}
if (traceConfig.isEvilMethodTraceEnable()) {
evilMethodTracer.onStartTrace();
}
if (traceConfig.isStartupEnable()) {
startupTracer.onStartTrace();
}
}
};
// ... 省略
}
- 说明:
由于在第一篇启动分析已经详细分析过,因此就省略了部分不相关的代码。我们主要看其中的两点:
- UIThreadMonitor.getMonitor().onStart();
- frameTracer.onStartTrace();
我们先看第一点到底做了什么工作。
1.1.1 UIThreadMonitor.onStart()
@Override
public synchronized void onStart() {
if (!isInit) {
MatrixLog.e(TAG, "[onStart] is never init.");
return;
}
if (!isAlive) {
this.isAlive = true;
synchronized (this) {
MatrixLog.i(TAG, "[onStart] callbackExist:%s %s", Arrays.toString(callbackExist), Utils.getStack());
callbackExist = new boolean[CALLBACK_LAST + 1];
}
//1,这个int[]数组用来保存UI渲染一帧中的三个阶段(input、animation、traversal)的开始和结束状态。
queueStatus = new int[CALLBACK_LAST + 1];
//2,这个long[]数组则是保存每一帧的三个阶段每个阶段对应的执行耗时
queueCost = new long[CALLBACK_LAST + 1];
//3,往input类型的链表中加入一个input阶段的callback。
addFrameCallback(CALLBACK_INPUT, this, true);
}
}
- 说明:
1,2 两点比较好理解,见注释。第三点需要详细分析下,先看 addFrameCallback 的源码:
private synchronized void addFrameCallback(int type, Runnable callback, boolean isAddHeader) {
//省略...
try {
//1, 还记得,第一篇文章中启动分析里面,通过反射拿到的choreographer中锁对象。
synchronized (callbackQueueLock) {
Method method = null;
switch (type) {
case CALLBACK_INPUT:
method = addInputQueue;
break;
case CALLBACK_ANIMATION:
method = addAnimationQueue;
break;
case CALLBACK_TRAVERSAL:
method = addTraversalQueue;
break;
}
// 2,最终method就是 CallbackQueue的 addCallbackLocked 方法, 反射调用callback加入type对应的链表结构中
if (null != method) {
method.invoke(callbackQueues[type], !isAddHeader ? SystemClock.uptimeMillis() : -1, callback, null);
callbackExist[type] = true;
}
}
} catch (Exception e) {
MatrixLog.e(TAG, e.toString());
}
}
总结:
外部需要监听每一帧的不同阶段,那么就通过反射的方法对象,注册不同类型的 callback
进去即可。
可以看到,我们在 onStart()
方法中就注册了一个input类型的callback。后面肯定会走run方法。因此我们接着看下 callback 的run
方法:
@Override
public void run() {
final long start = System.nanoTime();
try {
doFrameBegin(token);
doQueueBegin(CALLBACK_INPUT);
addFrameCallback(CALLBACK_ANIMATION, new Runnable() {
@Override
public void run() {
doQueueEnd(CALLBACK_INPUT);
doQueueBegin(CALLBACK_ANIMATION);
}
}, true);
addFrameCallback(CALLBACK_TRAVERSAL, new Runnable() {
@Override
public void run() {
doQueueEnd(CALLBACK_ANIMATION);
doQueueBegin(CALLBACK_TRAVERSAL);
}
}, true);
} finally {
if (config.isDevEnv()) {
MatrixLog.d(TAG, "[UIThreadMonitor#run] inner cost:%sns", System.nanoTime() - start);
}
}
}
private void doQueueBegin(int type) {
queueStatus[type] = DO_QUEUE_BEGIN;
queueCost[type] = System.nanoTime();
}
private void doQueueEnd(int type) {
queueStatus[type] = DO_QUEUE_END;
// 计算耗时
queueCost[type] = System.nanoTime() - queueCost[type];
synchronized (this) {
callbackExist[type] = false;
}
}
- 说明:
逻辑很清晰,我们按顺序分别在input、animation、traversal三个阶段的开始和结束打点,然后统计每个阶段的耗时,存起来用作后面的上报。
好了,我们在接着看第二点: frameTracer.onStartTrace();