argus-apm-main中的task(1) —— FpsTask
argus-apm-main中定義和實作了各個具體的監控task,包括Activity,網絡,fps等等。這裡我們先從fps作為例子入手分析。
FpsTask類
FpsTask類定義了fps監控的task,相當于是fps task的入口。先來看一下這個類的代碼。
public class FpsTask extends BaseTask implements Choreographer.FrameCallback {
private final String SUB_TAG = ApmTask.TASK_FPS;
private long mLastFrameTimeNanos = 0; //最後一次時間
private long mFrameTimeNanos = 0; //本次的目前時間
private int mCurrentCount = 0; //目前采集條數
private int mFpsCount = 0;
private FpsInfo fpsInfo = new FpsInfo();
private JSONObject paramsJson = new JSONObject();
//定時任務
private Runnable runnable = new Runnable() {
@Override
public void run() {
if (!isCanWork()) {
mCurrentCount = 0;
return;
}
calculateFPS();
mCurrentCount++;
//實作分段采集
if (mCurrentCount < ArgusApmConfigManager.getInstance().getArgusApmConfigData().onceMaxCount) {
AsyncThreadTask.executeDelayed(runnable, TaskConfig.FPS_INTERVAL);
} else {
AsyncThreadTask.executeDelayed(runnable, ArgusApmConfigManager.getInstance().getArgusApmConfigData().pauseInterval > TaskConfig.FPS_INTERVAL ? ArgusApmConfigManager.getInstance().getArgusApmConfigData().pauseInterval : TaskConfig.FPS_INTERVAL);
mCurrentCount = 0;
}
}
};
private void calculateFPS() {
if (mLastFrameTimeNanos == 0) {
mLastFrameTimeNanos = mFrameTimeNanos;
return;
}
float costTime = (float) (mFrameTimeNanos - mLastFrameTimeNanos) / 1000000.0F;
if (mFpsCount <= 0 && costTime <= 0.0F) {
return;
}
int fpsResult = (int) (mFpsCount * 1000 / costTime);
if (fpsResult < 0) {
return;
}
if (fpsResult <= TaskConfig.DEFAULT_FPS_MIN_COUNT) {
fpsInfo.setFps(fpsResult);
try {
paramsJson.put(FpsInfo.KEY_STACK, CommonUtils.getStack());
} catch (JSONException e) {
e.printStackTrace();
}
fpsInfo.setParams(paramsJson.toString());
fpsInfo.setProcessName(ProcessUtils.getCurrentProcessName());
save(fpsInfo);
}
if (AnalyzeManager.getInstance().isDebugMode()) {
if (fpsResult > TaskConfig.DEFAULT_FPS_MIN_COUNT) {
fpsInfo.setFps(fpsResult);
}
AnalyzeManager.getInstance().getParseTask(ApmTask.TASK_FPS).parse(fpsInfo);
}
mLastFrameTimeNanos = mFrameTimeNanos;
mFpsCount = 0;
}
@Override
protected IStorage getStorage() {
return new FpsStorage();
}
@Override
public void start() {
super.start();
AsyncThreadTask.executeDelayed(runnable, (int) (Math.round(Math.random() * TaskConfig.TASK_DELAY_RANDOM_INTERVAL)));
Choreographer.getInstance().postFrameCallback(this);
}
@Override
public void stop() {
super.stop();
}
@Override
public String getTaskName() {
return ApmTask.TASK_FPS;
}
@Override
public void doFrame(long frameTimeNanos) {
mFpsCount++;
mFrameTimeNanos = frameTimeNanos;
if (isCanWork()) {
//注冊下一幀回調
Choreographer.getInstance().postFrameCallback(this);
} else {
mCurrentCount = 0;
}
}
}
fps task從start方法啟動。至于任務如何被啟動,我們在“開始”一篇裡已經分析過,這裡不重複了。start方法首先調用超類的start方法。所有task類的超類是BaseTask類,其實這個類裡的start方法,隻是記了一行log。回到FpsTask的start方法,這裡啟動類内定義的runnable(稍後分析)。AsyncThreadTask建立并維護了一個線程池。executeDelayed的第二個參數,要求任務延時指定的毫秒數執行。啟動任務之後,向下一幀post一個frame callback,call就是FpsTask本身,這個類實作了Choreographer.FrameCallback接口。
我們先看一下要啟動執行的runnable。run方法首先要判斷任務是不是可以執行,如果不能執行,就把目前采集條數設定為0,并且傳回。如果可以執行fps任務,調用calculateFPS計算fps,并且把calculateFPS加1。如果目前采集的條數小于設定的最大值,那麼,TaskConfig.FPS_INTERVALms之後,繼續執行這個runnable;如果采集條數已經達到最大值,就取pauseInterval和TaskConfig.FPS_INTERVAL之間的大值,在這個間隔之後,再次執行runnable,并且要把mCurrentCount清空。這樣做的目的是實作fps的分段采集。
calculateFPS函數計算幀率。如果mLastFrameTimeNanos等于0,說明之前沒有記錄frame資訊,那麼就把mFrameTimeNanos的值賦給mLastFrameTimeNanos,直接傳回。如果mLastFrameTimeNanos不等于0,mFrameTimeNanos減去mLastFrameTimeNanos,再除以1000000(換算成豪秒),作為costTime。如果mFpsCount小于等于0,或者costTime小于等于0,函數直接傳回。mFpsCount乘以1000再除以costTime,作為fpsResult。mFpsCount的值在doFrame回調方法中累加,稍後分析這個函數。乘以1000是因為costTime的機關是毫秒,計算fps要換算成秒。如果這裡計算出的fpsResult小于0,直接傳回,因為幀率不可能小于0。如果fpsResult小于TaskConfig.DEFAULT_FPS_MIN_COUNT的值,設定fpsInfo中的各個字段:包括fps,就是上面計算出的fpsResult;調用棧,通過CommonUtils.getStack()擷取;processName,通過ProcessUtils.getCurrentProcessName()擷取目前程序的名稱。save(fpsInfo)儲存fpsInfo中資訊到資料庫。
save方法會調用mStorage中的save,在FpsTask中,getStorage方法會傳回一個新的FpsStorage執行個體,不過它并沒有重載save方法,是以這裡的save實際上就是TableStorage中的save。
最後看一下重載的Choreographer.FrameCallback的回調方法doFrame。代碼比較簡單,首先實作mFpsCount的自增。然後把參數frameTimeNanos的值指派給mFrameTimeNanos。如果現在的canWork标記還是true,繼續注冊下一幀的回調;否則的話,就把mCurrentCount清空。