深入研究源码:DispSync详解(1)

std::make_unique(&mPrimaryDispSync, SurfaceFlinger::vsyncPhaseOffsetNs,
true, “app”);
mEventThread = std::make_uniqueimpl::EventThread(mEventThreadSource.get(),
this { resyncWithRateLimit(); },
impl::EventThread::InterceptVSyncsCallback(),
“appEventThread”);
mSfEventThreadSource =
std::make_unique(&mPrimaryDispSync,
SurfaceFlinger::sfVsyncPhaseOffsetNs, true, “sf”);

mSFEventThread =
std::make_uniqueimpl::EventThread(mSfEventThreadSource.get(),
this { resyncWithRateLimit(); },
[this](nsecs_t timestamp) {
mInterceptor->saveVSyncEvent(timestamp);
},
“sfEventThread”);

前面提到,DispSyncSource 是 DispSyncThread 和 EventThread 的中间人,先来看一下 DispSyncSource 的构造函数:

class DispSyncSource final : public VSyncSource, private DispSync::Callback {
public:
DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync,
const char* name) :
mName(name),
mValue(0),
mTraceVsync(traceVsync),
mVsyncOnLabel(String8::format(“VsyncOn-%s”, name)),
mVsyncEventLabel(String8::format(“VSYNC-%s”, name)),
mDispSync(dispSync),
mCallbackMutex(),
mVsyncMutex(),
mPhaseOffset(phaseOffset),
mEnabled(false) {}

请注意这里有一个非常重要的点,就是 mVsyncEventLabel(String8::format("VSYNC-%s", name))。SurfaceFlinger 的 DispSyncSource 传进来的 name 是 “sf”,app 的 DispSyncSource 传进来的 name 是 “app”,所以连起来就是 “VSYNC-sf” 和 “VSYNC-app”。为什么说重要呢?来看一段 systrace:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这里面的 VSYNC-app 和 VSYNC-sf 就是说的 DispSyncSource,至于它的意义,后面会提到。

然后 DispSyncSource 作为参数传给 EventThread 的构造函数:

EventThread::EventThread(VSyncSource* src, ResyncWithRateLimitCallback resyncWithRateLimitCallback,
InterceptVSyncsCallback interceptVSyncsCallback, const char* threadName)
: mVSyncSource(src),
mResyncWithRateLimitCallback(resyncWithRateLimitCallback),
mInterceptVSyncsCallback(interceptVSyncsCallback) {
for (auto& event : mVSyncEvent) {
event.header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
event.header.id = 0;
event.header.timestamp = 0;
event.vsync.count = 0;
}

mThread = std::thread(&EventThread::threadMain, this);

pthread_setname_np(mThread.native_handle(), threadName);

pid_t tid = pthread_gettid_np(mThread.native_handle());

// Use SCHED_FIFO to minimize jitter
constexpr int EVENT_THREAD_PRIORITY = 2;
struct sched_param param = {0};
param.sched_priority = EVENT_THREAD_PRIORITY;
if (pthread_setschedparam(mThread.native_handle(), SCHED_FIFO, &param) != 0) {
ALOGE(“Couldn’t set SCHED_FIFO for EventThread”);
}

set_sched_policy(tid, SP_FOREGROUND);
}

构造函数的最主要功能就是把 EventThread 的线程主体 threadMain 运行起来并且设置其优先级为 SCHED_FIFO,接下来看 threadMain:

void EventThread::threadMain() NO_THREAD_SAFETY_ANALYSIS {
std::unique_lockstd::mutex lock(mMutex);
while (mKeepRunning) {
DisplayEventReceiver::Event event;
Vector<spEventThread::Connection > signalConnections;
signalConnections = waitForEventLocked(&lock, &event);

// dispatch events to listeners…
const size_t count = signalConnections.size();
for (size_t i = 0; i < count; i++) {
const sp& conn(signalConnections[i]);
// now see if we still need to report this event
status_t err = conn->postEvent(event);

}
}

threadMain 的主要工作是调用 waitForEventLocked 等待一个 Event,然后在一个个地通知 signalConnections。至于这个 EventsignalConnections 分别是什么,后面会具体描述。现在先来看一下 waitForEventLocked 的逻辑:

// This will return when (1) a vsync event has been received, and (2) there was
// at least one connection interested in receiving it when we started waiting.
Vector<spEventThread::Connection > EventThread::waitForEventLocked(
std::unique_lockstd::mutex* lock, DisplayEventReceiver::Event* event) {
Vector<spEventThread::Connection > signalConnections;

while (signalConnections.isEmpty() && mKeepRunning) {
bool eventPending = false;
bool waitForVSync = false;

size_t vsyncCount = 0;
nsecs_t timestamp = 0;
// 在前面 EventThread 的构造函数里面已经把 mVSyncEvent 数组内的所有 timestamp 都置为 0
// 因此在第一次初始化的时候,这个循环会直接退出
for (int32_t i = 0; i < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES; i++) {

}

// 第一次初始化的时候 mDisplayEventConnections 的数组也为空,count 为 0
size_t count = mDisplayEventConnections.size();
if (!timestamp && count) {

}

// 第一次初始化不执行这个循环
for (size_t i = 0; i < count;) {

}

// timestamp 为 0, waitForVSync 为 false
if (timestamp && !waitForVSync) {

} else if (!timestamp && waitForVSync) {

}

// eventPending 为 false,符合条件
if (!timestamp && !eventPending) {
if (waitForVSync) {

// waitForVSync 为 false,进入 else
} else {
// 最终,在第一次初始化的时候,EventThread 就阻塞在这里了
mCondition.wait(*lock);
}
}
}


}

好,到这里,SurfaceFlinger 创建的两个 EventThread 都会阻塞在上面代码提到的地方,SurfaceFlinger 的初始化继续执行。

补充:SurfaceFlinger 的启动

首先说明一下 mEventQueue 是在哪里被初始化的。是在 SurfaceFlinger 的另一个方法:

提到这里就需要 SurfaceFlinger 是怎么启动和初始化的。SurfaceFlinger 作为系统最基本最核心的服务之一,是通过 init.rc 的方式进行启动的(内容在 frameworks/native/services/surfaceflinger/surfaceflinger.rc):

service surfaceflinger /system/bin/surfaceflinger
class core animation
user system
group graphics drmrpc readproc input
onrestart restart zygote

然后就需要提到 SurfaceFlinger 的组成部分,init.rc 里面提到的 /system/bin/surfaceflinger 这个二进制文件,由 main_surfaceflinger.cpp 这个文件编译得到;而上面提到 DispSync,EventThread 等,都被编译到了 libsurfaceflinger.so 这个库。这也给了我们一个启示:当我们在自己调试 SurfaceFlinger 的时候,大部分时间都只需要重新编译 libsurfaceflinger.so 这个文件即可

回来简单看一下 SurfaceFlinger 是如何启动的,来看看 main_surfaceflinger.cpp

int main(int, char **) {

sp flinger = DisplayUtils::getInstance()->getSFInstance();

flinger->init();

这里的重点就是这个 sp<SurfaceFlinger>,当被 sp 指针引用的时候,会触发 onFirstRef() 函数:

void SurfaceFlinger::onFirstRef()
{
mEventQueue->init(this);
}

这样,就走到了 MessageQueue 部分了:

MessageQueue

接着 EventThread,然后就执行到这里:

void SurfaceFlinger::init() {

mEventQueue->setEventThread(mSFEventThread.get());

mEventQueue 在前面的 SurfaceFlinger::onFirstRef() 中完成了初始化:

void MessageQueue::init(const sp& flinger) {
mFlinger = flinger;
mLooper = new Looper(true);
mHandler = new Handler(*this);
}

接着来看一下很重要的 setEventThread()

void MessageQueue::setEventThread(android::EventThread* eventThread) {
if (mEventThread == eventThread) {
return;
}

if (mEventTube.getFd() >= 0) {
mLooper->removeFd(mEventTube.getFd());
}

mEventThread = eventThread;
mEvents = eventThread->createEventConnection();
mEvents->stealReceiveChannel(&mEventTube);
mLooper->addFd(mEventTube.getFd(), 0, Looper::EVENT_INPUT, MessageQueue::cb_eventReceiver,
this);
}

重点来了,前面创建的 SurfaceFlinger 的 EventThread 被作为参数传给了 setEventThread,并且执行了 EventThread 的 createEventConnection()。(注意,需要时时刻刻地记住,现在处理的 SurfaceFlinger 的 EventThread

(后面为了方便,将使用 sfEventThread 指代 SurfaceFlinger 的 EventThread;使用 appEventThread 指代 app 的 EventThread)

EventThread::Connection

sp EventThread::createEventConnection() const {
return new Connection(const_cast<EventThread*>(this));
}

在这里,sfEventThread 迎来了第一个(同时也是唯一的) Connection:

EventThread::Connection::Connection(EventThread* eventThread)
count(-1), mEventThread(eventThread), mChannel(gui::BitTube::DefaultSize) {}

void EventThread::Connection::onFirstRef() {
// NOTE: mEventThread doesn’t hold a strong reference on us
mEventThread->registerDisplayEventConnection(this);
}

status_t EventThread::registerDisplayEventConnection(
const spEventThread::Connection& connection) {
std::lock_guardstd::mutex lock(mMutex);
mDisplayEventConnections.add(connection);
mCondition.notify_all();
return NO_ERROR;
}

MessageQueue 调用 sfEventThread 的 createEventConnection 创建一个 Connection。由于 sp 指针的作用,将会调用 Connection::onFirstRef,最终这个 Connection 会被添加到 mDisplayEventConnections 并且唤醒在 EventThread - 01 中阻塞的线程。

EventThread-02

在前面把 EventThread 唤醒后,由于 signalConnections 为空,继续循环。然后由于新加入的 Connection count 为 -1,所以这个 EventThread 会继续阻塞,不过此时 mDisplayEventConnections 里面已经有一个 Connection 了。接着看下去。

EventControlThread-01

SurfaceFlinger::init() 接着运行到这里:

void SurfaceFlinger::init() {

mEventControlThread = std::make_uniqueimpl::EventControlThread(
[this](bool enabled) { setVsyncEnabled(HWC_DISPLAY_PRIMARY, enabled); });

主要提一下的是,这个传进来的参数是一个 Lambda 表达式,具体的语法不讲。稍微解释一下这里传进来的 Lambda 表达式的意义就是,捕获列表为 SurfaceFlinger 本身,接受一个布尔参数,当这个 Lamda 表达式被调用的时候,会调用 SurfaceFlinger::setVsyncEnabled() 这个函数,这个函数后面会提到,也是一个很重要的函数。

EventControlThread 的构造函数的主要内容也是启动一个线程:

EventControlThread::EventControlThread(EventControlThread::SetVSyncEnabledFunction function)
mSetVSyncEnabled(function) {
pthread_setname_np(mThread.native_handle(), “EventControlThread”);

pid_t tid = pthread_gettid_np(mThread.native_handle());
setpriority(PRIO_PROCESS, tid, ANDROID_PRIORITY_URGENT_DISPLAY);
set_sched_policy(tid, SP_FOREGROUND);
}

void EventControlThread::threadMain() NO_THREAD_SAFETY_ANALYSIS {
auto keepRunning = true;
auto currentVsyncEnabled = false;

while (keepRunning) {
mSetVSyncEnabled(currentVsyncEnabled);

std::unique_lockstd::mutex lock(mMutex);
// keepRunning 为 true,currentVsyncEnabled 为 false,mVsyncEnabled 默认值为 false,mKeepRunning 默认值为 true,因此 Lambda 表达式为 false,线程阻塞
mCondition.wait(lock, this, currentVsyncEnabled, keepRunning NO_THREAD_SAFETY_ANALYSIS {
return currentVsyncEnabled != mVsyncEnabled || keepRunning != mKeepRunning;
});
currentVsyncEnabled = mVsyncEnabled;
keepRunning = mKeepRunning;
}
}

此时,EventControlThread 也会陷入阻塞之中。而 SurfaceFlinger 也将迎来初始化中最为复杂的一步。

唤醒所有线程

至此,SurfaceFlinger 总共起了四个线程 —— DispSyncThread,两个 EvenThread 和 EventControlThread,并且这四个线程全都处于阻塞状态。导致这些线程处于阻塞状态的原因是:

  • DispSyncThread: mPeriod 为 0
  • EventThread: Connection->count 为 -1
  • EventControlThread: mVsyncEnabled 为 false

然后让我们一个个将其唤醒。

EventThread-03

接下来的 SurfaceFlinger 会进行非常复杂的初始化操作,EventThread 唤醒相关的调用流程如下(这里借用了这位大佬《Android SurfaceFlinger SW Vsync模型》的内容,写得非常棒,在学习的过程中能够得到了很大的启发):

initializeDisplays();
flinger->onInitializeDisplays();
setTransactionState(state, displays, 0);
setTransactionFlags(transactionFlags);
signalTransaction();
mEventQueue->invalidate();
mEvents->requestNextVsync() //mEvents是Connection实例
EventThread->requestNextVsync(this);

void EventThread::requestNextVsync(const spEventThread::Connection& connection) {

if (connection->count < 0) {
connection->count = 0;
mCondition.notify_all();
}
}

在这里把前面创建的那个 Connection 的 count 置为 0,并且唤醒阻塞的 EventThread,这个时候,mDisplayEventConnections 不为空并且 count 不为 -1,可以正常地运行了,EventThread::waitForEventLocked() 走到了这里:

} else if (!timestamp && waitForVSync) {
// we have at least one client, so we want vsync enabled
// (TODO: this function is called right after we finish
// notifying clients of a vsync, so this call will be made
// at the vsync rate, e.g. 60fps. If we can accurately
// track the current state we could avoid making this call
// so often.)
enableVSyncLocked();
}

void EventThread::enableVSyncLocked() {
// 一般都为 false
if (!mUseSoftwareVSync) {
// never enable h/w VSYNC when screen is off
if (!mVsyncEnabled) {
mVsyncEnabled = true;
mVSyncSource->setCallback(this);
mVSyncSource->setVSyncEnabled(true);
}
}
mDebugVsyncEnabled = true;
}

调用了 DispSyncSource::setCallback()将 EventThread 和 DispSyncSource 联系在了一起

void setCallback(VSyncSource::Callback* callback) override{
Mutex::Autolock lock(mCallbackMutex);
mCallback = callback;
}

接着调用 DispSyncSource::setVSyncEnabled

void setVSyncEnabled(bool enable) override {
Mutex::Autolock lock(mVsyncMutex);
// true
if (enable) {
status_t err = mDispSync->addEventListener(mName, mPhaseOffset,
static_castDispSync::Callback*(this));

}

最终调用了 DispSync::addEventListener

status_t addEventListener(const char* name, nsecs_t phase, DispSync::Callback* callback) {
if (kTraceDetailedInfo) ATRACE_CALL();
Mutex::Autolock lock(mMutex);

// 保证了 mEventListeners 的唯一性
for (size_t i = 0; i < mEventListeners.size(); i++) {
if (mEventListeners[i].mCallback == callback) {
return BAD_VALUE;
}
}

EventListener listener;
listener.mName = name;
listener.mPhase = phase;
listener.mCallback = callback;

listener.mLastEventTime = systemTime() - mPeriod / 2 + mPhase - mWakeupLatency;

mEventListeners.push(listener);

// 唤醒 DispSyncThread
mCond.signal();

return NO_ERROR;
}

把 DispSyncSource 加到 mEventListeners,将 DispSync 和 DispSyncSource 联系在了一起,并且把前面阻塞的 DispSyncThread 唤醒,但是由于 mPeriod 还是为 0,因此 DispSyncThread 还是会继续阻塞。

不过此时从调用关系已经初步可以看到前面我说的那句 DispSyncSource 是 DispSync 和 EventThread 的中间人 是正确的了。

接着来看 DispSyncThread。

DispSync 和 DispSyncThread-02

设置 mPeriod 的流程如下(依旧引用了这位大佬的《Android SurfaceFlinger SW Vsync模型》的内容,再次感谢):

initializeDisplays();
flinger->onInitializeDisplays();
setPowerModeInternal()
resyncToHardwareVsync(true);
repaintEverything();

这里把 SurfaceFlinger::resyncToHardwareVsync() 分为两部分,先看上部分:

void SurfaceFlinger::resyncToHardwareVsync(bool makeAvailable) {
Mutex::Autolock _l(mHWVsyncLock);

if (makeAvailable) {
mHWVsyncAvailable = true;
} else if (!mHWVsyncAvailable) {
// Hardware vsync is not currently available, so abort the resync
// attempt for now
return;
}

const auto& activeConfig = getBE().mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
const nsecs_t period = activeConfig->getVsyncPeriod();

mPrimaryDispSync.reset();
// 设置 mPeriod
mPrimaryDispSync.setPeriod(period);

// 默认为 false
if (!mPrimaryHWVsyncEnabled) {
mPrimaryDispSync.beginResync();
// 上部分结束

DispSync::setPeriod() 里面给 mPeriod 赋值,并且把 DispSyncThread 唤醒:

void DispSync::setPeriod(nsecs_t period) {
Mutex::Autolock lock(mMutex);
mPeriod = period;
mPhase = 0;
mReferenceTime = 0;
mThread->updateModel(mPeriod, mPhase, mReferenceTime);
}

void updateModel(nsecs_t period, nsecs_t phase, nsecs_t referenceTime) {
if (kTraceDetailedInfo) ATRACE_CALL();
Mutex::Autolock lock(mMutex);
mPeriod = period;
mPhase = phase;
mReferenceTime = referenceTime;
ALOGV(“[%s] updateModel: mPeriod = %” PRId64 “, mPhase = %” PRId64
" mReferenceTime = %" PRId64,
mName, ns2us(mPeriod), ns2us(mPhase), ns2us(mReferenceTime));
// 这里把 DispSyncThread 唤醒
mCond.signal();
}

至此,DispSyncThread 也开始运转。

EventControlThread-02

接着看 SurfaceFlinger::resyncToHardwareVsync() 的下半部分:


mEventControlThread->setVsyncEnabled(true);
mPrimaryHWVsyncEnabled = true;
}
}

void EventControlThread::setVsyncEnabled(bool enabled) {
std::lock_guardstd::mutex lock(mMutex);
mVsyncEnabled = enabled;
// 把 EventControlThread 唤醒
mCondition.notify_all();
}

把 EventControlThread 唤醒以后,会重新把 SurfaceFlinger 传进来的那个被 Lambda 表达式包裹的 SurfaceFlinger::setVsyncEnabled() 重新执行一下:

void SurfaceFlinger::setVsyncEnabled(int disp, int enabled) {
ATRACE_CALL();
Mutex::Autolock lock(mStateLock);
getHwComposer().setVsyncEnabled(disp,
enabled ? HWC2::Vsync::Enable : HWC2::Vsync::Disable);
}

void HWComposer::setVsyncEnabled(int32_t displayId, HWC2::Vsync enabled) {
if (displayId < 0 || displayId >= HWC_DISPLAY_VIRTUAL) {
ALOGD(“setVsyncEnabled: Ignoring for virtual display %d”, displayId);
return;
}

RETURN_IF_INVALID_DISPLAY(displayId);

// NOTE: we use our own internal lock here because we have to call
// into the HWC with the lock held, and we want to make sure
// that even if HWC blocks (which it shouldn’t), it won’t
// affect other threads.
Mutex::Autolock _l(mVsyncLock);
auto& displayData = mDisplayData[displayId];
if (enabled != displayData.vsyncEnabled) {
ATRACE_CALL();
auto error = displayData.hwcDisplay->setVsyncEnabled(enabled);
RETURN_IF_HWC_ERROR(error, displayId);

displayData.vsyncEnabled = enabled;

char tag[16];
snprintf(tag, sizeof(tag), “HW_VSYNC_ON_%1u”, displayId);
// 在 systrace 看到的就是在这里
ATRACE_INT(tag, enabled == HWC2::Vsync::Enable ? 1 : 0);
}
}

在这里,真正地去开启 HW-VSync。然后由于 SurfaceFlinger 接收了 HW-VSync,然后辗转发给 DispSync,DispSync 接收,校正 SW-VSYNC。而整个 DispSync SurfaceFlinger 部分的初始化的流程也最终完成。

注意,上面说的是 SurfaceFlinger 部分。前面提到,总共有两个 EventThread,而上面分析的都是 sfEventThread,下面简单地描述一下 appEventThread 的流程,其实 EventThread 到 DispSync 这部分都是一致的,只是 EventThread 的 Connection 的注册流程不一样。sfEventThread 是 MessageQueue 去注册 Connection,而 appEventThread 则是另一种方法。

appEventThread

SurfaceFlinger 接收 VSYNC 是为了合成,因此 sfEventThread 的 Connection 只有一个,就是 SurfaceFlinger 本身;而 app 接收 VSYNC 是为了画帧,appEventThread 会有很多很多个 Connection。

app 本身是如何在 appEventThread 注册一个 Connection 的,与这篇文章的主体有点偏移,这个可以另开一篇文章来详细说明,流程也是非常复杂,这里只简单地描述:核心就是 libgui 下面的 DisplayEventReceiver,它在初始化的时候会调用 SurfaceFlinger::createEventConnection

sp SurfaceFlinger::createDisplayEventConnection(
ISurfaceComposer::VsyncSource vsyncSource) {
if (vsyncSource == eVsyncSourceSurfaceFlinger) {
return mSFEventThread->createEventConnection();
} else {
return mEventThread->createEventConnection();
}
}

然后后面的流程就跟前面的一致了。

小结

通过上面的描述,依据各个类的依赖关系,其实可以总结出这么一个图:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

请注意箭头方向。

运作流程

前面提到,引入 DispSync 的目的是为了通过 SF-VSYNC 来模拟 HW-VSYNC 的行为并且通过加入 offset 来让通知时机变得灵活。因此理解整个 DispSync 的流程就可以归结为下面几个部分:SF-VSYNC 通知周期 mPeriod 的计算;SF-VSYNC 的模拟方式以及 SF-VSYNC 传递流程,分别来看。

mPeriod 计算逻辑

前面提到,DispSync 通过接收 HW-VSYNC 并且更新计算出 SW-VSYNC 间隔—— mPeriod,首先看一下 DispSync 是如何收到 HW-VSYNC。

先看一下 SurfaceFlinger 这个类:

class SurfaceFlinger : public BnSurfaceComposer,
public PriorityDumper,
private IBinder::DeathRecipient,
private HWC2::ComposerCallback

SurfaceFlinger 实现了 HW2::ComposerCallback 的接口,然后当 HW-VSYNC 到来的时候,HWC 会将 HW-VSYNC 发生的时间戳发给 SurfaceFlinger,然后 SurfaceFlinger 会转发给 DispSync:

class ComposerCallbackBridge : public Hwc2::IComposerCallback {
public:

Return onVsync(Hwc2::Display display, int64_t timestamp) override
{
mCallback->onVsyncReceived(mSequenceId, display, timestamp);
return Void();
}

};

void SurfaceFlinger::onVsyncReceived(int32_t sequenceId,
hwc2_display_t displayId, int64_t timestamp) {

{ // Scope for the lock
Mutex::Autolock _l(mHWVsyncLock);
if (type == DisplayDevice::DISPLAY_PRIMARY && mPrimaryHWVsyncEnabled) {
needsHwVsync = mPrimaryDispSync.addResyncSample(timestamp);
}
}

// 这个很重要,后面会提到
if (needsHwVsync) {
enableHardwareVsync();
} else {
disableHardwareVsync(false);
}
}

重点看 DispSync 怎么处理这些 HW-VSYNC,是在 addResyncSample() 这个函数:

bool DispSync::addResyncSample(nsecs_t timestamp) {
Mutex::Autolock lock(mMutex);

size_t idx = (mFirstResyncSample + mNumResyncSamples) % MAX_RESYNC_SAMPLES;
mResyncSamples[idx] = timestamp;
if (mNumResyncSamples == 0) {
mPhase = 0;
mReferenceTime = timestamp;
mThread->updateModel(mPeriod, mPhase, mReferenceTime);
}

if (mNumResyncSamples < MAX_RESYNC_SAMPLES) {
mNumResyncSamples++;
} else {
mFirstResyncSample = (mFirstResyncSample + 1) % MAX_RESYNC_SAMPLES;
}

updateModelLocked();

if (mNumResyncSamplesSincePresent++ > MAX_RESYNC_SAMPLES_WITHOUT_PRESENT) {
resetErrorLocked();
}

bool modelLocked = mModelUpdated && mError < (kErrorThreshold / 2);
return !modelLocked;
}

这里需要重点说明这里面几个变量的意义(在 DispSync.h 这个头文件里面有说明):

  • mPeriod 这个就是 DispSync 根据 HW-VSYNC,计算出来的 SW-VSYNC 的时间间隔,单位是纳秒。 这里有人可能会有疑问,这个值的意义在哪?硬件是以一个固定的时间间隔去发 HW-VSYNC,为什么还需要去计算一个新的时间间隔?直接跟 HW-VSYNC 的时间间隔一致不行吗? 这个当做作业留给大家思考。
  • mPhase 这个说实话我看了好久一直都看不懂这个值的意义
  • mReferenceTime 这个是第一次收到 HW-VSYNC 的时间戳,用来当做 DispSync 的参考标准
  • mWakeupLatency
  • mResyncSample 长度 32,用来记录收到硬件 VSYNC 的时间戳的数组,不过被解释为一个 ring buffer,新的会覆盖旧的
  • mFirstResyncSample 记录了 mResyncSample 这个 ring buffer 的开头
  • mNumResyncSamples 接收到硬件 VSYNC 的个数

DispSync 将从 SurfaceFlinger 发来的 HW-VSYNC 的时间戳都给记录到一个 ring buffer,当有了足够多的 HW-VSYNC 了以后(目前是 6 个即以上),就可以开始来拟合 SF-VSYNC 的间隔 mPeriod 了,是在 DispSync::updateModelLocked() 里面计算的,核心算法就在这里了。分为两部分,一部分是 mPeriod 的计算:

void DispSync::updateModelLocked() {
if (mNumResyncSamples >= MIN_RESYNC_SAMPLES_FOR_UPDATE) {
nsecs_t durationSum = 0;
nsecs_t minDuration = INT64_MAX;
nsecs_t maxDuration = 0;
for (size_t i = 1; i < mNumResyncSamples; i++) {
size_t idx = (mFirstResyncSample + i) % MAX_RESYNC_SAMPLES;
size_t prev = (idx + MAX_RESYNC_SAMPLES - 1) % MAX_RESYNC_SAMPLES;
nsecs_t duration = mResyncSamples[idx] - mResyncSamples[prev];
durationSum += duration;
minDuration = min(minDuration, duration);
maxDuration = max(maxDuration, duration);
}

durationSum -= minDuration + maxDuration;
mPeriod = durationSum / (mNumResyncSamples - 3);

mPeriod 的计算十分简单,把所有的 HW-VSYNC 前后相减算出 HW-VSYNC 的时间间隔,然后去掉一个最小值和最大值,然后所有 HW-VSYNC 的时间戳之和除以总个数就是 mPeriod 了。这里有一个问题就是为什么在最后除的时候是除数是 3?其实很简单,因为前面的 for 循环是从 1 开始算起的,所以循环结束一下 durationSum 其实是 mNumResyncSamples - 1 个 HW-VSYNC 的总和,然后再去掉一个最大和最小,所以总数是 mNumResyncSamples - 3。

另一部分是 mPhase 的计算,这一块看上去好像挺复杂的,甚至还有三角函数:


double sampleAvgX = 0;
double sampleAvgY = 0;

写在最后

由于本文罗列的知识点是根据我自身总结出来的,并且由于本人水平有限,无法全部提及,欢迎大神们能补充~

将来我会对上面的知识点一个一个深入学习,也希望有童鞋跟我一起学习,一起进阶。

提升架构认知不是一蹴而就的,它离不开刻意学习和思考。

**这里,笔者分享一份从架构哲学的层面来剖析的视频及资料分享给大家,**梳理了多年的架构经验,筹备近1个月最新录制的,相信这份视频能给你带来不一样的启发、收获。

最近还在整理并复习一些Android基础知识点,有问题希望大家够指出,谢谢。

希望读到这的您能转发分享和关注一下我,以后还会更新技术干货,谢谢您的支持!

转发+点赞+关注,第一时间获取最新知识点

Android架构师之路很漫长,一起共勉吧!
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!
Sum 其实是 mNumResyncSamples - 1 个 HW-VSYNC 的总和,然后再去掉一个最大和最小,所以总数是 mNumResyncSamples - 3。

另一部分是 mPhase 的计算,这一块看上去好像挺复杂的,甚至还有三角函数:


double sampleAvgX = 0;
double sampleAvgY = 0;

写在最后

由于本文罗列的知识点是根据我自身总结出来的,并且由于本人水平有限,无法全部提及,欢迎大神们能补充~

将来我会对上面的知识点一个一个深入学习,也希望有童鞋跟我一起学习,一起进阶。

提升架构认知不是一蹴而就的,它离不开刻意学习和思考。

**这里,笔者分享一份从架构哲学的层面来剖析的视频及资料分享给大家,**梳理了多年的架构经验,筹备近1个月最新录制的,相信这份视频能给你带来不一样的启发、收获。

[外链图片转存中…(img-ZpeiFMMA-1715337890620)]

[外链图片转存中…(img-Jc1ECqjV-1715337890620)]

最近还在整理并复习一些Android基础知识点,有问题希望大家够指出,谢谢。

希望读到这的您能转发分享和关注一下我,以后还会更新技术干货,谢谢您的支持!

转发+点赞+关注,第一时间获取最新知识点

Android架构师之路很漫长,一起共勉吧!
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值