Android JankTracker 原理解析

1.数据说明

JankTracker中定义了5中jank类型

static const char* JANK_TYPE_NAMES[] = {
    "Missed Vsync", //错过vsync
    "High input latency", //高输入延迟
    "Slow UI thread", //UI线程耗时
    "Slow bitmap uploads", //图片上传耗时
    "Slow issue draw commands", //执行渲染命令耗时
};

上述指标的计算方法是根据以下时间区间:

static const Comparison COMPARISONS[] = {
    {FrameInfoIndex::IntendedVsync, FrameInfoIndex::Vsync},
    {FrameInfoIndex::OldestInputEvent, FrameInfoIndex::Vsync},
    {FrameInfoIndex::Vsync, FrameInfoIndex::SyncStart},
    {FrameInfoIndex::SyncStart, FrameInfoIndex::IssueDrawCommandsStart},
    {FrameInfoIndex::IssueDrawCommandsStart, FrameInfoIndex::FrameCompleted},
};

* 其中时间点参数说明如下:*
- FrameInfoIndex::IntendedVsync 期望的vsync时间点
- FrameInfoIndex::Vsync 距离真正执行时最近的vsync时间点
- FrameInfoIndex::OldestInputEvent 这一帧之前的输入时间时间点
- FrameInfoIndex::SyncStart 主线程和RenderThread线程资源同步的时间点
- FrameInfoIndex::IssueDrawCommandsStart 执行渲染命令的时间点
- FrameInfoIndex::FrameCompleted 渲染结束的时间点

其他的还有:
- FrameInfoIndex::SwapBuffers swapbuffer开始的时间点
- FrameInfoIndex::PerformTraversalsStart preformTraversals开始的时间点
- FrameInfoIndex::SyncQueued syncAndDrawFrame任务入队的时间点
- FrameInfoIndex::NewestInputEvent 上一帧的最新的Input事件时间点

除了之前的5中jank类型,这些数据还可以反映其他的问题:
- {FrameInfoIndex::SyncQueued, FrameInfoIndex::SyncStart} sync任务从入队到执行的时间
- {FrameInfoIndex::SwapBuffers, FrameInfoIndex::FrameCompleted} swapbuffer的耗时

设置时间点的代码段落:

1、FrameInfoIndex::Vsync & FrameInfoIndex::IntendedVsync

//Choreographer.java
void doFrame(long frameTimeNanos, int frame) {

    *** ***
    mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos);
    *** ***
    try {
        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#doFrame");

        mFrameInfo.markInputHandlingStart(); //FrameInfoIndex::HandleInputStart
        doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);

        mFrameInfo.markAnimationsStart(); //FrameInfoIndex::AnimationStart
        doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);

        mFrameInfo.markPerformTraversalsStart(); //FrameInfoIndex::PerformTraversalsStart
        doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);

        doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
    } finally {
        Trace.traceEnd(Trace.TRACE_TAG_VIEW);
    }
}

//FrameInfo.java
public void setVsync(long intendedVsync, long usedVsync) {
    mFrameInfo[INTENDED_VSYNC] = intendedVsync;
    mFrameInfo[VSYNC] = usedVsync;
    mFrameInfo[OLDEST_INPUT_EVENT] = Long.MAX_VALUE;
    mFrameInfo[NEWEST_INPUT_EVENT] = 0;
    mFrameInfo[FLAGS] = 0;
}

3、FrameInfoIndex::OldestInputEvent & FrameInfoIndex::NewestInputEvent

//ViewRootImpl.java
void doProcessInputEvents() {
    *** ***
    mChoreographer.mFrameInfo.updateInputEventTime(eventTime, oldestEventTime);
    *** ***
}

//FrameInfo.java
public void updateInputEventTime(long inputEventTime, long inputEventOldestTime) {
    if (inputEventOldestTime < mFrameInfo[OLDEST_INPUT_EVENT]) {
        mFrameInfo[OLDEST_INPUT_EVENT] = inputEventOldestTime;
    }
    if (inputEventTime > mFrameInfo[NEWEST_INPUT_EVENT]) {
        mFrameInfo[NEWEST_INPUT_EVENT] = inputEventTime;
    }
}

4、FrameInfoIndex::SyncStart

bool DrawFrameTask::syncFrameState(TreeInfo& info) {
    ATRACE_CALL();
    int64_t vsync = mFrameInfo[static_cast<int>(FrameInfoIndex::Vsync)];
    mRenderThread->timeLord().vsyncReceived(vsync); //here
}

5、FrameInfoIndex::IssueDrawCommandsStart & FrameInfoIndex::SwapBuffers & FrameInfoIndex::FrameCompleted

void CanvasContext::draw() {
    mCurrentFrameInfo->markIssueDrawCommandsStart();

    mCurrentFrameInfo->markSwapBuffers();

    mCurrentFrameInfo->markFrameCompleted();
}

6、FrameInfoIndex::SyncQueued

int DrawFrameTask::drawFrame(TreeObserver* observer) {
    mSyncResult = SyncResult::OK;
    mSyncQueued = systemTime(CLOCK_MONOTONIC); //here
    mObserver = observer;
    postAndWait();
    return mSyncResult;
}

FrameInfo信息java层到c++层数据传递

//ThreadedRenderer.java
void draw(View view, AttachInfo attachInfo, HardwareDrawCallbacks callbacks) {
final long[] frameInfo = choreographer.mFrameInfo.mFrameInfo;
    int syncResult = nSyncAndDrawFrame(mNativeProxy, frameInfo, frameInfo.length);
}

static int android_view_ThreadedRenderer_syncAndDrawFrame(JNIEnv* env, jobject clazz,
        jlong proxyPtr, jlongArray frameInfo, jint frameInfoSize) {
    LOG_ALWAYS_FATAL_IF(frameInfoSize != UI_THREAD_FRAME_INFO_SIZE,
            "Mismatched size expectations, given %d expected %d",
            frameInfoSize, UI_THREAD_FRAME_INFO_SIZE);
    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
    ScopedRemovedRenderNodeObserver observer(env);
    env->GetLongArrayRegion(frameInfo, 0, frameInfoSize, proxy->frameInfo());
    return proxy->syncAndDrawFrame(&observer);
}

2.数据在systrace上对应的位置:

未完待续….

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值