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(proxyPtr);
ScopedRemovedRenderNodeObserver observer(env);
env->GetLongArrayRegion(frameInfo, 0, frameInfoSize, proxy->frameInfo());
return proxy->syncAndDrawFrame(&observer);
}
未完待续….