Matrix---FrameTracer源码分析

    技术2024-10-27  20

    参考 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初始化二、TracePlugin初始化2.1 TracePlugin.init 三、FrameTracer初始化3.1 new FrameTrace3.2 TracePlugin.start3.3 UIThreadMonitor.init初始化3.4 LooperMonitor初始化3.5 LooperPrinter监听Message事件的开始与结束 四、UIThreadMonitor 启动4.1 UIThreadMonitor.onStart4.2 UIThreadMonitor.addFrameCallback4.3 事件分发与UIThreadMonitor.run的流程 五、帧率FPS检测5.1 LooperMonitor.dispatch事件分发5.2 关于frameIntervalNanos与事件分发5.3 UIThreadMonitor.dispatchBegin Message事件分发开始5.4 FrameTracer.dispatchBegin5.5 UIThreadMonitor.run5.5.1 UIThreadMonitor.doFrameBegin5.5.2 UIThreadMonitor.doQueueBegin5.5.3 UIThreadMonitor.doQueueEnd 5.6 UIThreadMonitor.dispatchEnd Message事件分发结束 六、Frame帧刷新事件处理6.1 FrameTracer.doFrame6.2 FrameTracer.notifyListener6.3 FPSCollector.doFrameAsync6.4 FrameCollectItem.collect6.5 FrameCollectItem.report 上报数据

    一、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中添加的Plugin2.这里主要分析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初始化: 监控ANR2、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信号给应用层, 应用层收到该信号之后, 才开始进行measure、layout、draw绘制操作, 上层回调的入口是 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; } }
    Processed: 0.013, SQL: 9