有buffer但不latch
frameIsEarly - buffer生成后不立即latch

正常情况下latchBuffers时会对每个有buffer的layer进行latchBuffer

但7707397 没有latchBuffer操作

latchBuffers
bool SurfaceFlinger::latchBuffers() {
ATRACE_CALL();
//...
if (layer->hasReadyFrame()) {
frameQueued = true;
if (layer->shouldPresentNow(expectedPresentTime)) {
// 准备好的layer会在下面进行latchBuffer操作
mLayersWithQueuedFrames.emplace(layer);
} else {
ATRACE_NAME("!layer->shouldPresentNow()");
layer->useEmptyDamage();
}
} else {
layer->useEmptyDamage();
}
});
// ...
if (!mLayersWithQueuedFrames.empty()) {
// mStateLock is needed for latchBuffer as LayerRejecter::reject()
// writes to Layer current state. See also b/119481871
Mutex::Autolock lock(mStateLock);
for (const auto& layer : mLayersWithQueuedFrames) {
// 对每个layer的latchBuffer操作
if (layer->latchBuffer(visibleRegions, latchTime, expectedPresentTime)) {
mLayersPendingRefresh.push_back(layer);
newDataLatched = true;
}
layer->useSurfaceDamage();
}
}
//...hasReadyFrame
bool BufferLayer::hasReadyFrame() const {
return hasFrameUpdate() || getSidebandStreamChanged() || getAutoRefresh();
}正常有buffer情况第一个hasFrameUpdate()为true,其他为false
hasFrameUpdate
bool BufferStateLayer::hasFrameUpdate() const {
const State& c(getDrawingState());
return (mDrawingStateModified || mDrawingState.modified) && (c.buffer != nullptr || c.bgColorLayer != nullptr);
}c.buffer在 BufferStateLayer::setBuffer 中设置
没有进行setBuffer
导致上面的hasFrameUpdate 的 c.buffer = nullptr


acquireNextBuffer侧
acquireNextBufferLocked中有frame=且没有releaseBuffer的trace说明调用了t→setBuffer


既然acquire时buffer != null所以SurfaceComposerClient::Transaction::setBuffer也会将
s→what |= layer_state_t::eBufferChanged;
那就可能是SurfaceFlinger处的setBuffer前面的栈没有调用上
flushTransactionQueues

其调用栈上会调用transactionIsReadyToBeApplied

有如下关键trace


frameIsEarly

frameIsEarly
bool SurfaceFlinger::frameIsEarly(nsecs_t expectedPresentTime, int64_t vsyncId) const {
// The amount of time SF can delay a frame if it is considered early based
// on the VsyncModulator::VsyncConfig::appWorkDuration
constexpr static std::chrono::nanoseconds kEarlyLatchMaxThreshold = 100ms;
// vsync周期时间
const auto currentVsyncPeriod = mScheduler->getDisplayStatInfo(systemTime()).vsyncPeriod;
const auto earlyLatchVsyncThreshold = currentVsyncPeriod / 2;
// 这里vsyncid对应app token
const auto prediction = mFrameTimeline->getTokenManager()->getPredictionsForToken(vsyncId);
if (!prediction.has_value()) {
return false;
}
if (std::abs(prediction->presentTime - expectedPresentTime) >=
kEarlyLatchMaxThreshold.count()) {
return false;
}
// True则isEarly,不setBuffer
return prediction->presentTime >= expectedPresentTime &&
prediction->presentTime - expectedPresentTime >= earlyLatchVsyncThreshold;
}expectedPresentTime 是由 SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expectedVsyncTime) 传入的 expectedVsyncTime 这个是计算出来的真实vsync时间,系统根据这个计算的sf.vsyncTime和app.vsyncTime
-
expectedPresentTime
可以理解为上显的vsyncTime
- expectedPresentTime = real.vsyncTime = sf.prediction.startTime + sfwork
-
prediction
→
presentTime
对应app的预测上显时间
- prediction→presentTime = app.persent = app.prediction.endTime + sfWork

-
prediction
→
presentTime
>=
expectedPresentTime
- app. prediction.endTime + sfWork >= sf. prediction.startTime + sfwork
- app. prediction.endTime >= sf. prediction.startTime
-
prediction
→
presentTime
-
expectedPresentTime
>=
earlyLatchVsyncThreshold
- app. prediction.endTime >= sf. prediction.startTime + vsyncdur/2
7707391的prediction.endTime

当前app-vsync期望的sf合成时间在app-vsync+appwork,7707391并非期望的sf合成时间,则判定为来早了,
(这个时间段应该合成上一帧的buffer,而上一帧由于之前sf合成慢的原因,app-vsync晚了而没有触发绘制)
作用
- frameIsEarly对下面这种场景特别重要,app隔一帧绘制,一般出现在非全屏播放视频的场景,系统fps和视频fps不一致的情况下
- 正常情况下,app-1 → sf-1;app-3 → sf-3;app-5 → sf-5,对应vsync的合成
- 如果没有frameIsEarly,app第1帧被sf-0提前latch了,而第二帧如果慢了一点没赶上sf-2,而是在sf-3latch,这种情况下就会出现两次帧更新间隔不一致的情况,而此时app并未发生掉帧。

- 另一种还可以防止有多个layer时,此layer提前更新的问题,(同一个app-vsync下所有layer的buffer能够给到sf同时合成)
app不绘制
导致上述原因的问题主要是TimerDispatch 的 vsyncCallback 来了或没有触发app-vsync,既没有触发app绘制

参考了下这篇文章:https://wiki.n.miui.com/display/~xuyingfeng/Timer.cpp
TimerDispatch 采用 Epoll+Timerfd 的方式触发,设置的唤醒时间如下
void VSyncDispatchTimerQueue::setTimer(nsecs_t targetTime, nsecs_t /*now*/) {
mIntendedWakeupTime = targetTime;
mTimeKeeper->alarmAt(std::bind(&VSyncDispatchTimerQueue::timerCallback, this),
mIntendedWakeupTime);
mLastTimerSchedule = mTimeKeeper->now();
}
void Timer::alarmAt(std::function<void()> callback, nsecs_t time) {
// ..
if (timerfd_settime(mTimerFd, TFD_TIMER_ABSTIME, &new_timer, &old_timer)) {
ALOGW("Failed to set timerfd %s (%i)", strerror(errno), errno);
}
}
// setTimer位置
void VSyncDispatchTimerQueue::rearmTimerSkippingUpdateFor(
nsecs_t now, CallbackMap::iterator const& skipUpdateIt) {
//... now是当前时间:systemTime(SYSTEM_TIME_MONOTONIC);
auto const wakeupTime = *callback->wakeupTime();
if (!min || *min > wakeupTime) {
nextWakeupName = callback->name();
// 设置下次唤醒时间
min = wakeupTime;
targetVsync = callback->targetVsync();
}
}
if (min && min < mIntendedWakeupTime) {
#ifdef MI_FEATURE_ENABLE
if (MiSurfaceFlingerStub::isSceneExist(VSYNC_OPTIMIZE_SCENE)) {
if (*min < now + mTimerSlack)
min = now + mTimerSlack;
}
#endif
if (ATRACE_ENABLED() && nextWakeupName && targetVsync) {
ftl::Concat trace(ftl::truncated<5>(*nextWakeupName), " alarm in ", ns2us(*min - now),
"us; VSYNC in ", ns2us(*targetVsync - now), "us");
ATRACE_NAME(trace.c_str());
}
setTimer(*min, now); //*
} else {
// 当前没有此trace,所有setTimer正常设置
ATRACE_NAME("cancel timer");
cancelTimer();
}
}从未下app-vsync的前一个rearmTimerSkippingUpdateFor来看,有alarm in的trace,所以这里设置了setTimer

alarm in 看设置到下次唤醒时间距离当前now:2.78ms

但是2.78ms后并没有唤醒

其他地方并不会在调用setTimer,那说明可能被cancelTimer了
但周期内并未发生cancel timer事件

只有这两个地方发生了timerfd_settime,似乎只剩下Epoll+Timerfd出问题的可能…