Matrix---FrameTracer源码分析

参考
View、Window、WindowManager—vsync信号
View、Window、WindowManager—Choreographer源码阅读

Matrix提供了fps检测的功能, 该功能由 FrameTracer 完成, 这里围绕FrameTracer分析

/**
 * 何时被回调?
 * visibleScene: 当前Activity名
 * taskCost: 整个任务耗时
 * frameCostMs: 该帧耗时
 * droppedFrames: 消耗帧数
 * isContainsFrame: 是否属于帧刷新
 */
public void doFrameAsync(String visibleScene, 
                         long taskCost, 
                         long frameCostMs, 
                         int droppedFrames, 
                         boolean isContainsFrame);

涉及到的主要method:

1. new Matrix: Matric初始化
   -> 1 Plugin.init: 插件初始化 
2. Plugin.init: 插件初始化
   -> 1. new AnrTracer
   -> 2. new FrameTracer
   -> 3. new EvilMethodTracer
   -> 4. new StartupTracer
3. TracePlugin.start: 启动TracePlugin插件
   -> 1. UIThreadMonitor.getMonitor().init: UIThreadMonitor初始化
   -> 2. UIThreadMonitor.getMonitor().onStart()
   -> 3. frameTracer.onStartTrace()
4. UIThreadMonitor.init: UIThreadMonitor初始化
   -> 1. LooperMonitor初始化
   -> 2. 获取Choreographer实例
   -> 3. 反射获取Choreographer.mLock
   -> 4. 返回获取Choreographer.mCallbackQueues
   -> 5. 反射获取addInputQueue = Choreographer.callbackQueues[0]
   -> 6. 反射获取addAnimationQueue = Choreographer.callbackQueues[1]
   -> 7. 反射获取addTraversalQueue = Choreographer.callbackQueues[2]
   -> 8. 返回获取Choreographer.mFrameIntervalNanos
   -> 9. LooperMonitor.register注册Message事件分发的监听
5. LooperMonitor初始化
   -> 1. LooperMonitor.resetPrinter: hook Looper中的Printer
   -> 2. LooperMonitor.dispatch: Message事件分发
   -> 3. UIThreadMonitor.dispatchBegin: Message事件开始分发
   -> 4. UIThreadMonitor.dispatchEnd: Message事件结束分发
6. UIThreadMonitor.onStart
   -> 1. callbackExist = new boolean[CALLBACK_LAST + 1]
   -> 2. queueStatus = new int[CALLBACK_LAST + 1]
   -> 3. queueCost = new long[CALLBACK_LAST + 1]
   -> 4. UIThreadMonitor.addFrameCallback
   -> 5. UIThreadMonitor.run
   -> 6. UIThreadMonitor.doFrameBegin
   -> 7. UIThreadMonitor.doQueueBegin
   -> 8. UIThreadMonitor.doQueueEnd
7. frameTracer.onStartTrace
   -> 1. onAlive -> UIThreadMonitor.getMonitor().addObserver(this);
8. 帧刷新回调, Message事件回调
   -> 1. FrameTracer.dispatchBegin
   -> 2. FrameTracer.doFrame
   -> 3. FrameTracer.dispatchEnd
9. FrameTracer.doFrame
   -> 1. FrameTracer.notifyListener
   -> 2. FPSCollector.doFrameAsync

接下来围绕这些方法进行分析

一、Matrix初始化

private Matrix(Application app, PluginListener listener, HashSet<Plugin> plugins) {
    this.application = app;
    this.pluginListener = listener;
    this.plugins = plugins;
    AppActiveMatrixDelegate.INSTANCE.init(application);
    for (Plugin plugin : plugins) {
        // 各自插件的初始化, 这里主要分析TracePlugin.init的初始化
        plugin.init(application, pluginListener);
        pluginListener.onInit(plugin);
    }
}
  • 1.Matrix构造函数会对所有插件Plugin进行初始化, 这些插件就是MAtrix-demo在Application.onCreate中添加的Plugin
  • 2.这里主要分析FrameTracer, 而FrameTracer又与TracePlugin相关, 所以这里只分析TracePlugin.init方法

二、TracePlugin初始化

2.1 TracePlugin.init
@Override
public void init(Application app, PluginListener listener) {
    super.init(app, listener);
    // 1.获取AnrTracer
    anrTracer = new AnrTracer(traceConfig);
    // 2.获取FrameTracer
    frameTracer = new FrameTracer(traceConfig);
    // 3.获取EvilMethodTracer
    evilMethodTracer = new EvilMethodTracer(traceConfig);
    // 4.获取StartupTracer
    startupTracer = new StartupTracer(traceConfig);
}
  • 这里主要做了以下四件事:
  • 1、AnrTracer初始化: 监控ANR
  • 2、FrameTracer初始化: 监控帧率
  • 3、EvilMethodTracer初始化: 方法打点, 记录方法时长
  • 4、StartupTracer初始化

三、FrameTracer初始化

3.1 new FrameTrace
public FrameTracer(TraceConfig config) {
    this.config = config;
    // 1.一帧的耗时16ms
    this.frameIntervalMs = TimeUnit.MILLISECONDS.convert(UIThreadMonitor.getMonitor().getFrameIntervalNanos(), TimeUnit.NANOSECONDS) + 1;
    // 2.fps上报时间阈值
    this.timeSliceMs = config.getTimeSliceMs();
    // 3.fps监控是否打开
    this.isFPSEnable = config.isFPSEnable();
    // 4.一秒钟掉帧数量: 42帧为FROZEN
    this.frozenThreshold = config.getFrozenThreshold();
    // 5.一秒钟掉帧数量: 24帧为HIGH
    this.highThreshold = config.getHighThreshold();
    // 6.一秒钟掉帧数量: 3帧为NORMAL
    this.normalThreshold = config.getNormalThreshold();
    // 7.一秒钟掉帧数量: 9帧为MIDDLE
    this.middleThreshold = config.getMiddleThreshold();
    MatrixLog.i(TAG, "[init] frameIntervalMs:%s isFPSEnable:%s", frameIntervalMs, isFPSEnable);
    if (isFPSEnable) {
        // 添加FPS收集器
        addListener(new FPSCollector());
    }
}
  • 根据Matrix-demo提供的流程, 在Application.onCreate中对TracePlugin进行初始化(TracePlugin初始化时会初始化FrameTracer), 之后通过TracePlugin.start开始帧率的检测
3.2 TracePlugin.start
@Override
public void start() {
    super.start();
    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            if (!UIThreadMonitor.getMonitor().isInit()) {
                // 1.初始化UIThreadMonitor
                UIThreadMonitor.getMonitor().init(traceConfig);
            } 
            AppMethodBeat.getInstance().onStart();
            // 2.启动UIThreadMonitor
            UIThreadMonitor.getMonitor().onStart();
            anrTracer.onStartTrace();
            // 3.启动FrameTracer
            frameTracer.onStartTrace();
            evilMethodTracer.onStartTrace();
            startupTracer.onStartTrace();
        }
    };
    if (Thread.currentThread() == Looper.getMainLooper().getThread()) {
        runnable.run();
    } else {
        MatrixHandlerThread.getDefaultMainHandler().post(runnable);
    }
}
3.3 UIThreadMonitor.init初始化
public void init(TraceConfig config) {
    if (Thread.currentThread() != Looper.getMainLooper().getThread()) {
        throw new AssertionError("must be init in main thread!");
    }
    this.config = config;
    // 1.获取主线程的Choreographer
    choreographer = Choreographer.getInstance();
    // 2.反射获取Choreographer mLock变量
    callbackQueueLock = reflectObject(choreographer, "mLock");
    // 3.反射获取Choreographer mCallbackQueues变量
    callbackQueues = reflectObject(choreographer, "mCallbackQueues");
    // 4.反射获取处理input事件的CallbackQueue的addCallbackLocked方法
    addInputQueue = reflectChoreographerMethod(callbackQueues[CALLBACK_INPUT], ADD_CALLBACK, long.class, Object.class, Object.class);
    // 5.反射获取处理animation的CallbackQueue的addCallbackLocked方法
    addAnimationQueue = reflectChoreographerMethod(callbackQueues[CALLBACK_ANIMATION], ADD_CALLBACK, long.class, Object.class, Object.class);
    // 6.反射获取处理UI刷新的CallbackQueue的addCallbackLocked方法
    addTraversalQueue = reflectChoreographerMethod(callbackQueues[CALLBACK_TRAVERSAL], ADD_CALLBACK, long.class, Object.class, Object.class);
    // 7.反射获取frameIntervalNanos变量
    frameIntervalNanos = reflectObject(choreographer, "mFrameIntervalNanos");
    // 8.注册监听Message事件分发的回调
    LooperMonitor.register(new LooperMonitor.LooperDispatchListener() {
        @Override
        public boolean isValid() {
            return isAlive;
        }
        @Override
        public void dispatchStart() {
            super.dispatchStart();
            UIThreadMonitor.this.dispatchBegin();
        }
        @Override
        public void dispatchEnd() {
            super.dispatchEnd();
            UIThreadMonitor.this.dispatchEnd();
        }
    });
    this.isInit = true;
}
  • 1、在 Choreographer源码分析 时, mFrameIntervalNanos为vsync信号回调时的时间戳
3.4 LooperMonitor初始化
public LooperMonitor(Looper looper) {
    // 1.主线程的Looper
    this.looper = looper;
    // 2.向Looper中注入LooperPrinter, 获取事件执行的开始与结束的监听
    resetPrinter();
    // 3.添加IdleHandler
    addIdleHandler(looper);
}
3.5 LooperPrinter监听Message事件的开始与结束
public void println(String x) {
    if (null != origin) {
        origin.println(x);
    }
    if (!isHasChecked) {
        isValid = x.charAt(0) == '>' || x.charAt(0) == '<';
        isHasChecked = true;
        if (!isValid) {
            MatrixLog.e(TAG, "[println] Printer is inValid! x:%s", x);
        }
    }
    if (isValid) {
        // 利用Looper.loop方法中日志的打印, >开头表示事件开始进行, <开头表示结束
        dispatch(x.charAt(0) == '>', x);
    }
}

public class Looper {
    public static void loop() {
        if (logging != null) {
            logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
        }
        ...
        if (logging != null) {
            logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
        }
    }
}

当Message事件开始和结束时会分别回调Printer.println方法, 并带上开始/结束的标识, 这里最终会调用到LooperMonitor.dispatch方法

四、UIThreadMonitor 启动

4.1 UIThreadMonitor.onStart
public synchronized void onStart() {
    if (!isAlive) {
        this.isAlive = true;
        synchronized (this) {
            callbackExist = new boolean[CALLBACK_LAST + 1];
        }
        // 1.定义与事件相对应的数组, 记录每个事件的开始/结束
        queueStatus = new int[CALLBACK_LAST + 1];
        // 2.定义与事件相对应的数组, 记录每个type对应的执行时间
        queueCost = new long[CALLBACK_LAST + 1];
        // 3.首先回调input事件
        addFrameCallback(CALLBACK_INPUT, this, true);
    }
}
4.2 UIThreadMonitor.addFrameCallback
private synchronized void addFrameCallback(int type, Runnable callback, boolean isAddHeader) {
	// 1.记录事件是否存在, 默认为false
	if (callbackExist[type]) {
		MatrixLog.w(TAG, "[addFrameCallback] this type %s callback has exist! isAddHeader:%s", type, isAddHeader);
		return;
	}
	// 2.
	if (!isAlive && type == CALLBACK_INPUT) {
		MatrixLog.w(TAG, "[addFrameCallback] UIThreadMonitor is not alive!");
		return;
	}
	// 3.
	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;
		}
		if (null != method) {
			/**
			 * 1.method对应CallbackQueue.addCallbackLocked方法
             * 2.将callback(->UIThreadMonitor)添加到CallbackRecord队列中
             */
			method.invoke(callbackQueues[type], !isAddHeader ? SystemClock.uptimeMillis() : -1, callback, null);
			callbackExist[type] = true;
		}
	}
}
  • 1、将UIThreadMonitor添加到Choreographer.mCallbackQueues对应的CallbackQueue中
  • 2、底层回调vsync信号会触发FrameDisplayEventReceiver.onVsync的执行, 最终调用CallbackRecord.run方法的执行, 将UIThreadMonitor添加到CallbackRecord, 绘制之前触发UIThreadMonitor.run的执行
4.3 事件分发与UIThreadMonitor.run的流程
UIThreadMonitor.onStart() //这个方法在稍后模块会分析
-> CallbackRecord.enqueue(UIThreadMonitor)

FrameDisplayEventReceiver.onVsync() -> FrameHandler.sendMessageAtTime() 
									-> Printer.println(">>>>> Dispatching to...")
									-> FrameDisplayEventReceiver.run() 
	  								-> Choreographer.doFrame() 
	  								-> CallbackRecord.doCallbacks()
		 							-> CallbackRecord.run() 
		 							-> UIThreadMonitor.run()
									-> mTraversalRunnable.run() 
			   						-> ViewRootImpl.performTraversal()
			   						-> Printer.println("<<<<< Finished to...")

五、帧率FPS检测

5.1 LooperMonitor.dispatch事件分发
// isBegin: true: 事件开始, false: 事件结束
private void dispatch(boolean isBegin, String log) {
    for (LooperDispatchListener listener : listeners) {
        if (listener.isValid()) {
            if (isBegin) {
                if (!listener.isHasDispatchStart) {
                    // 分发开始
                    listener.onDispatchStart(log);
                }
            } else {
                if (listener.isHasDispatchStart) {
                    // 分发结束
                    listener.onDispatchEnd(log);
                }
            }
        } else if (!isBegin && listener.isHasDispatchStart) {
            listener.dispatchEnd();
        }
    }
}
  • 1、Message事件分发开始时回调listener.onDispatchStart方法
  • 2、Message事件分发结束时回调listener.onDispatchEnd方法
  • 3、LooperDispatchListener只考虑UIThreadMonitor.init中通过LooperMoniter.register注册的回调
  • 4、所以listener.onDispatchStart、listener.onDispatchEnd会分别回调UIThreadMonitor.dispatchBegin与UIThreadMonitor.dispatchEnd方法.
5.2 关于frameIntervalNanos与事件分发
  • FrameTracer为何通过这种方式进行hook检测帧率(FPS)
public void onVsync(long timestampNanos, long physicalDisplayId, int frame) {
	long now = System.nanoTime();
	if (timestampNanos > now) {
		timestampNanos = now;
	}
	mTimestampNanos = timestampNanos;
	mFrame = frame;
	Message msg = Message.obtain(mHandler, this);
	msg.setAsynchronous(true);
	mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
}
  • 1、在进行UI绘制之前, 先向natice层发送vsync信号, 然后native层收到该信号之后会回调vsync信号给应用层, 应用层收到该信号之后, 才开始进行measurelayoutdraw绘制操作, 上层回调的入口是 FrameDisplayEventReceiver.onVsync, 在onVsync通过Handler.sendMessageAtTime向Looper发送事件, 然后调用FrameDisplayEventReceiver.run方法
  • 2、FrameTracer基于这一点对Printer进行hook, 完成对FPS的检测
5.3 UIThreadMonitor.dispatchBegin Message事件分发开始
private void dispatchBegin() {
    // 1.从开机到现在的毫秒数
    token = dispatchTimeMs[0] = SystemClock.uptimeMillis();
    // 2.当前线程运行的毫秒数
    dispatchTimeMs[2] = SystemClock.currentThreadTimeMillis();
    synchronized (observers) {
        for (LooperObserver observer : observers) {
            if (!observer.isDispatchBegin()) {
                // 这里的observer指向的就是在FrameTracer.onStartTrace中通过addObserver
                // 注册回调事件
                observer.dispatchBegin(dispatchTimeMs[0], dispatchTimeMs[2], token);
            }
        }
    }
}
  • 1.Message执行之前, 记录了从开机到现在的毫秒数, 当前线程运行的毫秒数, 并将该参数通过observer.dispatchBegin回调时传入
  • 2.通过UIThreadMonitor.addObserver添加LooperObserver, 方法调用链可知FrameTracer.onStart时会向UITHreadMonitor注册一个LooperObserver.
5.4 FrameTracer.dispatchBegin
public void dispatchBegin(long beginMs, long cpuBeginMs, long token) {
	// 设置标识位isDispatchBegin true
    isDispatchBegin = true;
}
  • 结合 4.3事件分发与hook的流程 事件分发开始时将标识位置为true, 并且输出日志, 当View绘制结束之后, 输出日志, 并调用事件分发结束的接口dispatchEnd
5.5 UIThreadMonitor.run

结合流程 4.3 如果当前事件(Message)对应的是vsync信号的事件, 既从FrameDisplayEventReceiver.onVsync()发出来的消息, 则在UIThreadMonitor.dispatchEnd调用之前会先执行UIThreadMonitor.run

public void run() {
    final long start = System.nanoTime();
    // 1.当前事件为帧刷新事件, 将标识位isBelongFrame置为true
    doFrameBegin(token);
    // 2.进行View绘制时, 会依次调用input、animation、traversal事件run方法
    doQueueBegin(CALLBACK_INPUT);
    // 3.CallbackRecord(input)结束run之前hook一个animation的回调
    addFrameCallback(CALLBACK_ANIMATION, new Runnable() {
        @Override
        public void run() {
        	// 4.CallbackRecord(animation).run执行时触发这里的回调
            doQueueEnd(CALLBACK_INPUT);
            doQueueBegin(CALLBACK_ANIMATION);
        }
    }, true);
    // 4.CallbackRecord(input)结束run之前hook一个traversal的回调
    addFrameCallback(CALLBACK_TRAVERSAL, new Runnable() {
        @Override
        public void run() {
        	// 5.CallbackRecord(traversal).run执行时触发这里的回调
            doQueueEnd(CALLBACK_ANIMATION);
            doQueueBegin(CALLBACK_TRAVERSAL);
        }
    }, true);
}
5.5.1 UIThreadMonitor.doFrameBegin
private void doFrameBegin(long token) {
    // 置为true, 表示当前事件为帧刷新事件
    this.isBelongFrame = true;
}
5.5.2 UIThreadMonitor.doQueueBegin
 private void doQueueBegin(int type) {
    // 1.记录事件type(input, animation, traversal)的状态
    queueStatus[type] = DO_QUEUE_BEGIN;
    // 2.记录事件开始时的时间
    queueCost[type] = System.nanoTime();
 }
5.5.3 UIThreadMonitor.doQueueEnd
private void doQueueEnd(int type) {
    // 1.记录事件结束的状态
    queueStatus[type] = DO_QUEUE_END;
    // 2.记录事件(input、animation、traversal)结束时花费的时间
    queueCost[type] = System.nanoTime() - queueCost[type];
    synchronized (this) {
        // 3.当前事件被移除
        callbackExist[type] = false;
    }
}

注: 当前执行到这里, 只记录了input、animation事件的结束状态, 并没有记录traversal结束的状态, traversal结束的状态在dispatchEnd的doFrameEnd中执行

5.6 UIThreadMonitor.dispatchEnd Message事件分发结束

当前Message事件执行完成, 回调dispatchEnd方法

private void dispatchEnd() {
    // 1.当前事件是否属于帧刷新, true: 属于帧刷新Message
    if (isBelongFrame) {
    	// 2.重置isBelongFrame, 记录CALLBACK_TRAVERSAL事件结束时的相关状态
        doFrameEnd(token);
    }
    // 2.start: 开机到Message开始执行之前的时间(毫秒数)
    long start = token;
    // 3.end: 从开机到Message执行结束的时间(毫秒数)
    long end = SystemClock.uptimeMillis();
    synchronized (observers) {
        for (LooperObserver observer : observers) {
            if (observer.isDispatchBegin()) {
                /**
                 * 4.具体到LooperMonitor.doFrame先不作分析, 这里只记录每个参数的含义:
                 * (1)token: 在dispatchBegin中被赋值, 记录的是开机到Message开始执行时的时间
                 * (2)SystemClock.uptimeMillis: 开机到Message执行结束的时间(毫秒数)
                 * (3)isBelongFrame: 这里只是一个标志位的作用
                 * (4)end-start: 对应一次Message消耗的时间
                 * (5)queueCost[INPUT]: input事件消耗的时间
                 * (6)queueCost[ANIMATION]: animation事件消耗的时间
                 * (7)queueCost[TRAVERSAL]: traversal事件消耗的时间
                 */
                observer.doFrame(AppMethodBeat.getVisibleScene(), token, SystemClock.uptimeMillis(), isBelongFrame ? end - start : 0, queueCost[CALLBACK_INPUT], queueCost[CALLBACK_ANIMATION], queueCost[CALLBACK_TRAVERSAL]);
            }
        }
    }
    // 5.当前线程执行的时间 
    dispatchTimeMs[3] = SystemClock.currentThreadTimeMillis();
    // 6.从开机到当前Message执行完毕的时间
    dispatchTimeMs[1] = SystemClock.uptimeMillis();
    synchronized (observers) {
        for (LooperObserver observer : observers) {
            if (observer.isDispatchBegin()) {
                observer.dispatchEnd(dispatchTimeMs[0], dispatchTimeMs[2], dispatchTimeMs[1], dispatchTimeMs[3], token, isBelongFrame);
            }
        }
    }
}

dispatchTimeMs[0]: 从开机到Message执行开始的时间
dispatchTimeMs[1]: 从开机到Message执行完毕的时间
dispatchTimeMs[2]: Message执行开始时当前线程消耗的时间
dispatchTimeMs[3]: Message执行结束时当前线程消耗的时间

  • 有一个地方没看明白, 如果isBelongFrame = true, 则会进入到doFrameEnd中将isBelongFrame置为false, 如果为false, 则跳过doFrameEnd, 因此observer.doFrame(isBelongFrame? end - start : 0)这个参数一定只能是0, 那这样的意义何在呢? 这个问题留待手撸Matrix-FrameTracer代码之后再确定是否自己理解有误

六、Frame帧刷新事件处理

6.1 FrameTracer.doFrame
/**
 * focusedActivityName: 当前Activity
 * start: 从开机到Message开始执行时的时间(毫秒数)
 * end: 从开机到Message执行结束的时间(毫秒数)
 * frameCostMs: end - start: 一帧消耗的时间
 * inputCostNs: 一帧input事件消耗的时间
 * animationCostNs: 一帧animation消耗的时间
 * traversalCostNs: 一帧traversal消耗的时间
 */
public void doFrame(String focusedActivityName, long start, long end, long frameCostMs, long inputCostNs, long animationCostNs, long traversalCostNs) {
    if (isForeground()) {
        notifyListener(focusedActivityName, end - start, frameCostMs, frameCostMs >= 0);
    }
}
6.2 FrameTracer.notifyListener
/**
 * 1.taskCostMs: 一次Message事件消耗的时间
 * 2.frameCostMs: 一帧消耗的时间
 * 3.是否为帧刷新: 结合UIThreadMonitor.doFrame可知, 如果是帧刷新, frameCostMs > 0,
 *               即isContainsFrame = true
 */
private void notifyListener(final String visibleScene, final long taskCostMs, final long frameCostMs, final boolean isContainsFrame) {
    long start = System.currentTimeMillis();
    synchronized (listeners) {
        for (final IDoFrameListener listener : listeners) {
            if (config.isDevEnv()) {
                listener.time = SystemClock.uptimeMillis();
            }
            // 1.一次Message消耗的时间, 理论上一帧需要的时间16ms, 因此这里的dropFrame是指
            //   一次Message事件消耗的帧数.
            final int dropFrame = (int) (taskCostMs / frameIntervalMs);
            listener.doFrameSync(visibleScene, taskCostMs, frameCostMs, dropFrame, isContainsFrame);
            if (null != listener.getExecutor()) {
                listener.getExecutor().execute(new Runnable() {
                    @Override
                    public void run() {
                        // 2.这里只分析FPSCollector.doFrameAsync
                        listener.doFrameAsync(visibleScene, taskCostMs, frameCostMs, dropFrame, isContainsFrame);
                    }
                });
            }
        }
    }
}

dropFrame: 理论上一次Message需要的时间与一帧的时间相同为16ms, 因此dropFrame理论上取值应该为1, 因此dropFrame的值越大, 表明Message花费的时间越多, 掉帧也就越多.

6.3 FPSCollector.doFrameAsync
/**
 * droppedFrames: 一次Message事件消耗的帧数
 */
public void doFrameAsync(String visibleScene, long taskCost, long frameCostMs, int droppedFrames, boolean isContainsFrame) {
    super.doFrameAsync(visibleScene, taskCost, frameCostMs, droppedFrames, isContainsFrame);
    FrameCollectItem item = map.get(visibleScene);
    if (null == item) {
        item = new FrameCollectItem(visibleScene);
        map.put(visibleScene, item);
    }
    // 1.收集当前Activity消耗的时间
    item.collect(droppedFrames, isContainsFrame);
    if (item.sumFrameCost >= timeSliceMs) { // report
        // 2.上报之前通过remove对FrameCollectionItem进行重置
        map.remove(visibleScene);
        // 3.上报数据
        item.report();
    }
}
6.4 FrameCollectItem.collect
void collect(int droppedFrames, boolean isContainsFrame) {
    // 1.一帧需要的时间16.7ms
    long frameIntervalCost = UIThreadMonitor.getMonitor().getFrameIntervalNanos();
    // 2.总消耗时间
    sumFrameCost += (droppedFrames + 1) * frameIntervalCost / Constants.TIME_MILLIS_TO_NANO;
    // 3.总丢帧率
    sumDroppedFrames += droppedFrames;
    // 4.doFrameAsync回调次数, 回调一次表示一帧刷新结束
    sumFrame++;
    if (!isContainsFrame) {
        // 除过刷新帧事件外, 其他事件数
        sumTaskFrame++;
    }
    if (droppedFrames >= frozenThreshold) {
        dropLevel[DropStatus.DROPPED_FROZEN.index]++;
        dropSum[DropStatus.DROPPED_FROZEN.index] += droppedFrames;
    } else if (droppedFrames >= highThreshold) {
        dropLevel[DropStatus.DROPPED_HIGH.index]++;
        dropSum[DropStatus.DROPPED_HIGH.index] += droppedFrames;
    } else if (droppedFrames >= middleThreshold) {
        dropLevel[DropStatus.DROPPED_MIDDLE.index]++;
        dropSum[DropStatus.DROPPED_MIDDLE.index] += droppedFrames;
    } else if (droppedFrames >= normalThreshold) {
        dropLevel[DropStatus.DROPPED_NORMAL.index]++;
        dropSum[DropStatus.DROPPED_NORMAL.index] += droppedFrames;
    } else {
        dropLevel[DropStatus.DROPPED_BEST.index]++;
        dropSum[DropStatus.DROPPED_BEST.index] += (droppedFrames < 0 ? 0 : droppedFrames);
    }
}
6.5 FrameCollectItem.report 上报数据

每个页面监控的总时间超过预设阈值就进行上报

void report() {
    // 1.1秒内帧数
    float fps = Math.min(60.f, 1000.f * sumFrame / sumFrameCost);
    MatrixLog.i(TAG, "[report] FPS:%s %s", fps, toString());
    try {
        TracePlugin plugin = Matrix.with().getPluginByClass(TracePlugin.class);
        if (null == plugin) {
            return;
        }
        // 2.记录卡顿级别以及出现的次数
        JSONObject dropLevelObject = new JSONObject();
        dropLevelObject.put(DropStatus.DROPPED_FROZEN.name(), dropLevel[DropStatus.DROPPED_FROZEN.index]);
        dropLevelObject.put(DropStatus.DROPPED_HIGH.name(), dropLevel[DropStatus.DROPPED_HIGH.index]);
        dropLevelObject.put(DropStatus.DROPPED_MIDDLE.name(), dropLevel[DropStatus.DROPPED_MIDDLE.index]);
        dropLevelObject.put(DropStatus.DROPPED_NORMAL.name(), dropLevel[DropStatus.DROPPED_NORMAL.index]);
        dropLevelObject.put(DropStatus.DROPPED_BEST.name(), dropLevel[DropStatus.DROPPED_BEST.index]);
        // 3.记录卡顿级别及掉帧总次数
        JSONObject dropSumObject = new JSONObject();
        dropSumObject.put(DropStatus.DROPPED_FROZEN.name(), dropSum[DropStatus.DROPPED_FROZEN.index]);
        dropSumObject.put(DropStatus.DROPPED_HIGH.name(), dropSum[DropStatus.DROPPED_HIGH.index]);
        dropSumObject.put(DropStatus.DROPPED_MIDDLE.name(), dropSum[DropStatus.DROPPED_MIDDLE.index]);
        dropSumObject.put(DropStatus.DROPPED_NORMAL.name(), dropSum[DropStatus.DROPPED_NORMAL.index]);
        dropSumObject.put(DropStatus.DROPPED_BEST.name(), dropSum[DropStatus.DROPPED_BEST.index]);

        JSONObject resultObject = new JSONObject();
        resultObject = DeviceUtil.getDeviceInfo(resultObject, plugin.getApplication());

        resultObject.put(SharePluginInfo.ISSUE_SCENE, visibleScene);
        resultObject.put(SharePluginInfo.ISSUE_DROP_LEVEL, dropLevelObject);
        resultObject.put(SharePluginInfo.ISSUE_DROP_SUM, dropSumObject);
        resultObject.put(SharePluginInfo.ISSUE_FPS, fps);
        resultObject.put(SharePluginInfo.ISSUE_SUM_TASK_FRAME, sumTaskFrame);

        Issue issue = new Issue();
        issue.setTag(SharePluginInfo.TAG_PLUGIN_FPS);
        issue.setContent(resultObject);
        plugin.onDetectIssue(issue);

    } catch (JSONException e) {
        MatrixLog.e(TAG, "json error", e);
    } finally {
        sumFrame = 0;
        sumDroppedFrames = 0;
        sumFrameCost = 0;
        sumTaskFrame = 0;
    }
}

你可能感兴趣的:(Android源码阅读)