天天看點

argus-apm-main中的task(1) —— FpsTaskargus-apm-main中的task(1) —— FpsTask

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清空。