参考
Choreographer原理
View、Window、WindowManager---VSYNC信号
运行Matrix demo时, 进入到TestTraceMainActivity界面以后会展示当前的fps相关新, fps展示View是通过FrameDecorator来完成, 所以在阅读Matrix-FrameTracer模块的代码时, 围绕着FrameDecorator来进行.
FrameDecorator相关信息
// 展示fps信息
private FloatFrameView view;
/**
* 何时被回调?
* 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.1 Plugin.init: 插件初始化
1.1 Plugin.init: 插件初始化
-> 1.1.1 new AnrTracer
-> 1.1.2 new FrameTracer
-> 1.1.3 new EvilMethodTracer
-> 1.1.4 new StartupTracer
2. TracePlugin.start: 启动TracePlugin插件
-> 2.1 UIThreadMonitor.getMonitor().init: UIThreadMonitor初始化
-> 2.2 UIThreadMonitor.getMonitor().onStart()
-> 2.3 frameTracer.onStartTrace()
2.1 UIThreadMonitor.init: UIThreadMonitor初始化
-> 2.1.1 LooperMonitor初始化
-> (1) 获取Choreographer实例
-> (2) 反射获取Choreographer.mLock
-> (3) 返回获取Choreographer.mCallbackQueues
-> (4) 反射获取addInputQueue = Choreographer.callbackQueues[0]
-> (5) 反射获取addAnimationQueue = Choreographer.callbackQueues[1]
-> (6) 反射获取addTraversalQueue = Choreographer.callbackQueues[2]
-> (7) 返回获取Choreographer.mFrameIntervalNanos
-> 2.1.2 LooperMonitor.register注册Message事件分发的监听
2.1.1 LooperMonitor初始化
-> 2.1.1.1 LooperMonitor.resetPrinter: hook Looper中的Printer
-> 2.1.1.2 LooperMonitor.dispatch: Message事件分发
-> 2.1.2.3 UIThreadMonitor.dispatchBegin: Message事件开始分发
-> 2.1.3.4 UIThreadMonitor.dispatchEnd: Message事件结束分发
2.2 UIThreadMonitor.onStart
-> (1) callbackExist = new boolean[CALLBACK_LAST + 1]
-> (2) queueStatus = new int[CALLBACK_LAST + 1]
-> (3) queueCost = new long[CALLBACK_LAST + 1]
-> 2.2.1 UIThreadMonitor.addFrameCallback
-> 2.2.2 UIThreadMonitor.run
-> 2.2.3 UIThreadMonitor.doFrameBegin
-> 2.2.4 UIThreadMonitor.doQueueBegin
-> 2.2.5 UIThreadMonitor.doQueueEnd
2.3 frameTracer.onStartTrace
-> 2.3.1 onAlive -> UIThreadMonitor.getMonitor().addObserver(this);
3. 帧刷新回调, Message事件回调
-> 3.1 FrameTracer.dispatchBegin
-> 3.2 FrameTracer.doFrame
-> 3.3 FrameTracer.dispatchEnd
3.3 FrameTracer.doFrame
-> 3.3.1 FrameTracer.notifyListener
-> 3.3.2 FPSCollector.doFrameAsync
接下来围绕这些方法进行分析
1. Matrix初始化
private Matrix(Application app, PluginListener listener, HashSet 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方法
1.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.1.2 FrameTracer初始化
public FrameTracer(TraceConfig config) {
this.config = config;
// 一帧的耗时16ms
this.frameIntervalMs = TimeUnit.MILLISECONDS.convert(UIThreadMonitor.getMonitor().getFrameIntervalNanos(), TimeUnit.NANOSECONDS) + 1;
// fps上报时间阈值
this.timeSliceMs = config.getTimeSliceMs();
// fps监控是否打开
this.isFPSEnable = config.isFPSEnable();
// 一秒钟掉帧数量: 42帧为FROZEN
this.frozenThreshold = config.getFrozenThreshold();
// 一秒钟掉帧数量: 24帧为HIGH
this.highThreshold = config.getHighThreshold();
// 一秒钟掉帧数量: 3帧为NORMAL
this.normalThreshold = config.getNormalThreshold();
// 一秒钟掉帧数量: 9帧为MIDDLE
this.middleThreshold = config.getMiddleThreshold();
MatrixLog.i(TAG, "[init] frameIntervalMs:%s isFPSEnable:%s", frameIntervalMs, isFPSEnable);
if (isFPSEnable) {
// 添加FPS收集器
addListener(new FPSCollector());
}
}
TracePlugin与FrameTracer初始化完成之后, 接下来执行Application.onCreate调用的tracePlugin.start方法
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);
}
}
2.1 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;
}
UIThreadMonitor初始化时会对其持有的静态变量LooperMonitor进行初始化.
2.1.1 LooperMonitor初始化
public LooperMonitor(Looper looper) {
// 1.主线程的Looper
this.looper = looper;
// 2.向Looper中注入LooperPrinter, 获取事件执行的开始与结束的监听
resetPrinter();
// 3.添加IdleHandler
addIdleHandler(looper);
}
2.1.1.1 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方法
2.1.1.2 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();
}
}
}
当Message事件开始执行时, 会回调到LooperMonitor.dispatch方法, 这里的listener指向的就是在UIThreadMonitor.init中通过LooperMonitor.register注册的回调, 因此这里最终是会触发到UIThreadMonitor的dispatchBegin
和dispatchEnd
方法
2.1.1.3 UIThreadMonitor.dispatchBegin Message事件分发开始
private void dispatchBegin() {
// 1.从开机到现在的毫秒数
token = dispatchTimeMs[0] = SystemClock.uptimeMillis();
// 2.当前线程运行的毫秒数
dispatchTimeMs[2] = SystemClock.currentThreadTimeMillis();
AppMethodBeat.i(AppMethodBeat.METHOD_ID_DISPATCH);
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.
- 3.这里回调到FrameTracer.dispatchBegin暂不作分析.
2.1.1.4 UIThreadMonitor.dispatchEnd Message事件分发结束
private void dispatchEnd() {
// 1.帧开始刷新
if (isBelongFrame) {
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消耗的时间
*/
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();
AppMethodBeat.o(AppMethodBeat.METHOD_ID_DISPATCH);
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执行结束时当前线程消耗的时间
2.2 UIThreadMonitor.onStart 启动UIThreadMonitor
@Override
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];
addFrameCallback(CALLBACK_INPUT, this, true);
}
}
- 1.这里分别定义三个参数, 应该是对应了input(输入事件)、animation(动画)、TRAVERSAL(窗口刷新)三个回调事件
2.2.1 UIThreadMonitor.addFrameCallback
private synchronized void addFrameCallback(int type, Runnable callback, boolean isAddHeader) {
if (!isAlive && type == CALLBACK_INPUT) {
return;
}
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.这里涉及到的Choreographer, 关于Choreographer的篇幅比较大, 这里暂时只引用一点关于Choreographer的概念:
- 2.当vsync信号由SurfaceFlinger中创建HWC触发, 唤醒DispSyncThread线程, 再到EventThread线程, 然后再通过BitTube直接传递到目标进程所对应的目标线程, 执行handleEvent方法
- 3.经过一系列的调用, 最后会调用到CallbackRecord.run方法
- 4.结合Matrix-FrameTracer模块的代码, 这里的CallbackRecord指向的是UIThreadMonitor, 因此当有vsync信号时, UITHreadMonitor.run方法会被触发
2.2.2 UIThreadMonitor.run
@Override
public void run() {
final long start = System.nanoTime();
// 1.帧刷新开始, isBelongFrame被置为true
doFrameBegin(token);
// 2.设置事件开始的状态
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);
}
2.2.3 UIThreadMonitor.doFrameBegin
private void doFrameBegin(long token) {
// 所以这里是一个标志位, 表示帧开始刷新
this.isBelongFrame = true;
}
2.2.4 UIThreadMonitor.doQueueBegin
private void doQueueBegin(int type) {
// 1.设置事件type(input, animation, traversal)的状态
queueStatus[type] = DO_QUEUE_BEGIN;
// 2.设置事件开始时的时间
queueCost[type] = System.nanoTime();
}
2.2.5 UIThreadMonitor.doQueueEnd
private void doQueueEnd(int type) {
// 1.记录事件结束的状态
queueStatus[type] = DO_QUEUE_END;
// 2.记录Message事件结束时花费的时间
queueCost[type] = System.nanoTime() - queueCost[type];
synchronized (this) {
// 3.当前事件被移除
callbackExist[type] = false;
}
}
- doQueueEnd执行完之后, 会将callbackExist[type]置为false, 这个是因为
回收callbacks,加入对象池mCallbackPool,就是说callback一旦执行完成,则会被回收。
2.3 FrameTracer.onStartTrace FrameTracer启动
@Override
final synchronized public void onStartTrace() {
if (!isAlive) {
this.isAlive = true;
onAlive();
}
}
@Override
public void onAlive() {
super.onAlive();
// 添加监听, UIThreadMonitor.dispatchBegin、doFrame、dispatchEnd分别触发
// FrameTracer: dispatchBegin、doFrame、dispatchEnd三个方法
UIThreadMonitor.getMonitor().addObserver(this);
}
3. 事件回调
3.1 FrameTracer.dispatchBegin
public void dispatchBegin(long beginMs, long cpuBeginMs, long token) {
// Message事件开始
isDispatchBegin = true;
}
3.2 FrameTracer.dispatchEnd
public void dispatchEnd(long beginMs, long cpuBeginMs, long endMs, long cpuEndMs, long token, boolean isBelongFrame) {
// Message事件结束
isDispatchBegin = false;
}
3.3 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);
}
}
3.3.1 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花费的时间越多, 掉帧也就越多.
3.3.2 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();
}
}
3.3.3 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);
}
}
3.3.4 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;
}
}