View绘制流程2-安卓如何执行measure/draw 全球最新

发布时间:   来源:CSDN  

前言:

vsync信号其实主要有两种,APP和SF两种。


(资料图)

两种类似的信号分别具有以下的作用:

1.APP类型,我们常说的Vsync信号其实指的就是这种类型。

2.SF类型,我感觉有可能是SurfaceFlinger的缩写,这个同步信号主要是通知进行数据buffer的合成。

本文主要探讨的主APP类型的Vsync信号,SF类型的会在另外一篇文章,View绘制流程中讲解。

一.整体流程简介

我把app-VSync的整个流程分为四大块:

第一块,APP侧发出请求信号,通知到SurfaceFlinger;

第二块,SurfaceFlinger收到通知后,作为消费者侧去缓存池中查询是否存在VSYNC,如果有,则通知APP侧。

第三块,SurfaceFlinger中的生产者逻辑,生产下一次的Vsync信号。

第四块,APP侧收到Vsync信号后进行处理,最终完成绘制流程。

整体的流程图如下图所示,后续文章也会按照这四大块流程去细讲。

二.客户端发出信号

2.1 java端流转

我们把代码的开始点设置为ViewRootImpl中的scheduleTraversals方法,如果想了解这个方法之前的流程,可以参看我的另外一篇文章:

View绘制流程2-安卓是如何执行measure/layout/draw三个绘制流程_失落夏天的博客-CSDN博客

scheduleTraversals是负责渲染流程的,界面上任何布局上的改动,最终都会执行这个方法进行刷新操作。scheduleTraversals会通过Choreographer的postCallback方法去请求Vsync信号并且设置回调方法。

mChoreographer.postCallback(                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);

Choreographer中的最终实现是postCallbackDelayedInternal方法:

private void postCallbackDelayedInternal(int callbackType,            Object action, Object token, long delayMillis) {        ...        synchronized (mLock) {            final long now = SystemClock.uptimeMillis();            final long dueTime = now + delayMillis;            mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);            if (dueTime <= now) {                scheduleFrameLocked(now);            }            ...        }    }

这个方法会把回调加入到mCallbackQueues中,然后通过scheduleFrameLocked方法开始请求Vsync信号。

scheduleFrameLocked中又会进行层层传递,最终调用到native方法。传递关系如下:

scheduleFrameLocked(Choreographer.java)->scheduleVsyncLocked(Choreographer.java)->scheduleVsync(DisplayEventReceiver.java)->nativeScheduleVsync(DisplayEventReceiver.java)

2.2 native方法中的逻辑流转

nativeScheduleVsync在native层的注册是DisplayEventReceiver.cpp中的nativeScheduleVsync方法,方法中通过NativeDisplayEventReceiver的scheduleVsync来完成请求:

static void nativeScheduleVsync(JNIEnv* env, jclass clazz, jlong receiverPtr) {    spreceiver =            reinterpret_cast(receiverPtr);    status_t status = receiver->scheduleVsync();   ...}

NativeDisplayEventReceiver是DisplayEventDispatcher的子类,scheduleVsync方法会执行到DisplayEventDispatcher中的scheduleVsync方法,调用DisplayEventReceiver的requestNextVsync继续请求流程。

status_t DisplayEventDispatcher::scheduleVsync() {    if (!mWaitingForVsync) {        ...        status_t status = mReceiver.requestNextVsync();        ...        mWaitingForVsync = true;        ...    }    return OK;}

这里有一个本地变量mWaitingForVsync,如果请求了一次sync,就会改为true,接下来的Vsync请求,都不会传输到SurfaceFlinger一层了,避免重复无意义请求。只有等到收到Vsync信号的时候,才会改为false。

DisplayEventReceiver中,会交给mEventConnection处理:

status_t DisplayEventReceiver::requestNextVsync() {    if (mEventConnection != nullptr) {        mEventConnection->requestNextVsync();        return NO_ERROR;    }    return NO_INIT;}

mEventConnection其实是一个binder客户端,是在创建DisplayEventReceiver的时候通过binder方法创建的,其binder服务端实现在SurfaceFlinger进程侧的EventThread.cpp。

DisplayEventReceiver::DisplayEventReceiver(        ISurfaceComposer::VsyncSource vsyncSource,        ISurfaceComposer::EventRegistrationFlags eventRegistration) {    spsf(ComposerService::getComposerService());    if (sf != nullptr) {        mEventConnection = sf->createDisplayEventConnection(vsyncSource, eventRegistration);        ...    }}

三.SurfaceFlinger端Vsync信号消费者

首先,SurfaceFlinger的总体结构图如下,SurfaceFlinger中存在一个Scheduler,Scheduler中存在多个VsyncDispatch。其中VSYNC-app负责所有APP的VSYNC信号的处理,本文主要讲的也是这个流程中的。

其次,下图是主流程图中的一部分,也是本章要讲的内容。

3.1 EventThread收到通知后,转发EventThread的工作线程

是接收方法如下,转发到mEventThread的requestNextVsync方法中。

binder::Status EventThreadConnection::requestNextVsync() {    ATRACE_CALL();    mEventThread->requestNextVsync(this);    return binder::Status::ok();}

我们接着看一下EventThread中的requestNextVsync方法:

void EventThread::requestNextVsync(const sp& connection) {    ...    if (connection->vsyncRequest == VSyncRequest::None) {        connection->vsyncRequest = VSyncRequest::Single;        mCondition.notify_all();    } else if (connection->vsyncRequest == VSyncRequest::SingleSuppressCallback) {        connection->vsyncRequest = VSyncRequest::Single;    }}

这里的逻辑很简单,如果当前的VSYNC状态是None的话,释放锁mCondition。

这里既然notify_all,那么一定有地方wait等待锁,而等待的地方就是threadMain方法。

3.2 threadMain方法

这个方法算是整个Vsync流程的核心,它是一个无限循环的模式,其作用是不断的从mPendingEvents中获取Vsync信号,然后转交给APP端。并且在一次Vsync流程结束后,又通过VsyncSource请求下一次的Vsync信号。

threadMain方法是EventThread类初始化的时候创建的线程去执行的方法:

mThread = std::thread([this]() NO_THREAD_SAFETY_ANALYSIS {        std::unique_locklock(mMutex);        threadMain(lock);    });

我们看一下精简后的threadMain方法:

void EventThread::threadMain(std::unique_lock& lock) {    DisplayEventConsumers consumers;    //只要没有退出,就一直循环    while (mState != State::Quit) {        执行以下1-7的操作           }}

总体来说,分为以下四大步骤:

1.作为消费者尝试从mPendingEvents中获取Vsync信号,如果获取成功,则赋值给event。

std::optionalevent;        //查看mPendingEvents中是否存在Vsync信号        if (!mPendingEvents.empty()) {            event = mPendingEvents.front();            mPendingEvents.pop_front();            ...        }

2.计算vsyncRequested的状态,只要客户端消费者的Connection保持连接,则vsyncRequested=true,并且上面步骤一获取到event的话,则把消费者的connection加入到consumers集合中。

bool vsyncRequested = false;       //获取当前的状态,并且判断是否有客户端的消费者在请求,如果有则加入到consumers集合中        auto it = mDisplayEventConnections.begin();        while (it != mDisplayEventConnections.end()) {            if (const auto connection = it->promote()) {                //客户端还是处于请求的状态                vsyncRequested |= connection->vsyncRequest != VSyncRequest::None;                if (event && shouldConsumeEvent(*event, connection)) {                    consumers.push_back(connection);                }                ++it;            } else {                it = mDisplayEventConnections.erase(it);            }        }

3.如果consumers集合不为空,则进行消费。把Vsync信号分发给消费者。(具体步骤我们下一小节中讲)

//如果消费者不为空,则通过dispatchEvent方法最终通知到APP一侧        if (!consumers.empty()) {            dispatchEvent(*event, consumers);            consumers.clear();        }

4.获取下一个状态

//mVSyncState不会为空,则主要是根据vsyncRequested来判断的。vsyncRequested上面计算的        State nextState;        if (mVSyncState && vsyncRequested) {            nextState = mVSyncState->synthetic ? State::SyntheticVSync : State::VSync;        } else {            ALOGW_IF(!mVSyncState, "Ignoring VSYNC request while display is disconnected");            nextState = State::Idle;        }

5.进行判断,确定是否需要请求VSYNC信号。这一块挺有意思的,简单理解如下:

如果当前是VSYNC状态,下一个状态也是VSYNC状态,那么说明信号还没来,所以没必要重复发送。

如果当前是Idle状态,下一个状态是VSYNC状态,那么则要进行VSYNC信号请求。

如果当前是VSYNC状态,下一个状态也是Idle状态,那么说明信号已经来了,下一次的客户端请求还没来,所以不要进行VSYNC信号请求,则会进行取消操作。

if (mState != nextState) {            if (mState == State::VSync) {                mVSyncSource->setVSyncEnabled(false);            } else if (nextState == State::VSync) {                //如果下一个状态还是VSync,则继续去请求VSYNC信号                mVSyncSource->setVSyncEnabled(true);            }            mState = nextState;        }

如何开始和结束去进行VSYNC信号获取的获取操作,我们第四章中讲,这个主要就是消费者逻辑了。

6.如果event为空,说明mPendingEvents中已经取光了,则进入休眠操作。

反之event不为空,说明mPendingEvents中也许还存在未消费的VSYNC信号,则contine继续消费。

//如果处理了event,那么说明此次已经拿到了Vsync信号,说明后面有可能还有,则继续拿        if (event) {            continue;        }

7.进入休眠或者超时之后主动模拟信号加入到mPendingEvents中。

//说明Vsync信号已经消费完了,则进入休眠模式,等到APP侧的下一次通知进行唤醒        // Wait for event or client registration/request.        if (mState == State::Idle) {            mCondition.wait(lock);        } else {            // Generate a fake VSYNC after a long timeout in case the driver stalls. When the            // display is off, keep feeding clients at 60 Hz.            const std::chrono::nanoseconds timeout =                    mState == State::SyntheticVSync ? 16ms : 1000ms;            if (mCondition.wait_for(lock, timeout) == std::cv_status::timeout) {                if (mState == State::VSync) {                    ALOGW("Faking VSYNC due to driver stall for thread %s", mThreadName);                    std::string debugInfo = "VsyncSource debug info:\n";                    mVSyncSource->dump(debugInfo);                    // Log the debug info line-by-line to avoid logcat overflow                    auto pos = debugInfo.find("\n");                    while (pos != std::string::npos) {                        ALOGW("%s", debugInfo.substr(0, pos).c_str());                        debugInfo = debugInfo.substr(pos + 1);                        pos = debugInfo.find("\n");                    }                }                LOG_FATAL_IF(!mVSyncState);                const auto now = systemTime(SYSTEM_TIME_MONOTONIC);                const auto deadlineTimestamp = now + timeout.count();                const auto expectedVSyncTime = deadlineTimestamp + timeout.count();                mPendingEvents.push_back(makeVSync(mVSyncState->displayId, now,                                                   ++mVSyncState->count, expectedVSyncTime,                                                   deadlineTimestamp));            }        }

3.3  dispatchEvent方法把Vsync信号分发给消费者

首先遍历消费者,调用postEvent进行通知

void EventThread::dispatchEvent(const DisplayEventReceiver::Event& event,                                const DisplayEventConsumers& consumers) {     for (const auto& consumer : consumers) {            ...            switch (consumer->postEvent(copy)) {            }     }}

然后postEvent方法中,调用sendEvent进行信号的发送

status_t EventThreadConnection::postEvent(const DisplayEventReceiver::Event& event) {   ...        auto size = DisplayEventReceiver::sendEvents(&mChannel, mPendingEvents.data(),                                                     mPendingEvents.size());    ...}

最终通过Socket的方法进行信号的发送,接受者就是APP侧了。

ssize_t DisplayEventReceiver::sendEvents(gui::BitTube* dataChannel,        Event const* events, size_t count){    return gui::BitTube::sendObjects(dataChannel, events, count);}

四.SurfaceFlinger端生产者

上面讲到通过setVSyncEnabled方法去开始或者结束获取Vsync信号的操作。

4.1 获取VSYNC信号

setVSyncEnabled方法如下:

void DispSyncSource::setVSyncEnabled(bool enable) {    std::lock_guard lock(mVsyncMutex);    if (enable) {        mCallbackRepeater->start(mWorkDuration, mReadyDuration);    } else {        mCallbackRepeater->stop();    }    mEnabled = enable;}

对应的其实就是mCallbackRepeater的start和stop方法,其实现类是DispSyncSource.cpp中的CallbackRepeater。

我们这里看到一个成员变量mWorkDuration,这个值其实就是控制Vscyn触发时间的。这个我们后续小节再讲,这里只是知道有这个值就好了。

4.2 把时间设置给Timer定时触发

start方法中,记录一下传入的workDuration时间,然后传递给mRegistration处理。

void start(std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration) {        std::lock_guard lock(mMutex);        mStarted = true;        mWorkDuration = workDuration;        mReadyDuration = readyDuration;        auto const scheduleResult =                mRegistration.schedule({.workDuration = mWorkDuration.count(),                                        .readyDuration = mReadyDuration.count(),                                        .earliestVsync = mLastCallTime.count()});           }

mRegistration的实现类是VSyncCallbackRegistration,其中schedule方法也是交给VSyncDispatchTimerQueue来处理:

ScheduleResult VSyncCallbackRegistration::schedule(VSyncDispatch::ScheduleTiming scheduleTiming) {    if (!mValidToken) {        return std::nullopt;    }    return mDispatch.get().schedule(mToken, scheduleTiming);}

schedule方法中,进行一系列的合法判断,最终会交给 rearmTimerSkippingUpdateFor方法处理。

然后我们就可以看到rearmTimerSkippingUpdateFor中去调用setTimer方法去设置定时触发。

rearmTimerSkippingUpdateFor方法略,

setTimer方法如下:

void VSyncDispatchTimerQueue::setTimer(nsecs_t targetTime, nsecs_t /*now*/) {    mIntendedWakeupTime = targetTime;    mTimeKeeper->alarmAt(std::bind(&VSyncDispatchTimerQueue::timerCallback, this),                         mIntendedWakeupTime);    mLastTimerSchedule = mTimeKeeper->now();}

则到了targetTime之后,就会执行timerCallBack方法。

4.3 生成Vsync信号加入mPendingEvents

timerCallback方法如下:

void VSyncDispatchTimerQueue::timerCallback() {    struct Invocation {        std::shared_ptrcallback;        nsecs_t vsyncTimestamp;        nsecs_t wakeupTimestamp;        nsecs_t deadlineTimestamp;    };    std::vectorinvocations;    {        std::lock_guard lock(mMutex);        auto const now = mTimeKeeper->now();        mLastTimerCallback = now;        for (auto it = mCallbacks.begin(); it != mCallbacks.end(); it++) {            auto& callback = it->second;            auto const wakeupTime = callback->wakeupTime();            if (!wakeupTime) {                continue;            }            auto const readyTime = callback->readyTime();            auto const lagAllowance = std::max(now - mIntendedWakeupTime, static_cast(0));            if (*wakeupTime < mIntendedWakeupTime + mTimerSlack + lagAllowance) {                callback->executing();                invocations.emplace_back(Invocation{callback, *callback->lastExecutedVsyncTarget(),                                                    *wakeupTime, *readyTime});            }        }        mIntendedWakeupTime = kInvalidTime;        rearmTimer(mTimeKeeper->now());    }    for (auto const& invocation : invocations) {        invocation.callback->callback(invocation.vsyncTimestamp, invocation.wakeupTimestamp,                                      invocation.deadlineTimestamp);    }

这里的核心逻辑其实就是遍历mCallbacks,然后分别回调。

那么mCallbacks是怎么添加的呢? CallbackRepeater创建的时候,回去注册 mRegistration,同时会传入CallbackRepeater::callback方法作为回调,所以mCallbacks其实就是CallbackRepeater::callback。

void callback(nsecs_t vsyncTime, nsecs_t wakeupTime, nsecs_t readyTime) {       ...        mCallback(vsyncTime, wakeupTime, readyTime);        ...    }

很明显直接交给mCallback处理,所以我们又得看一下这个mCallback从何而来。

这个mCallback是CallbackRepeater创建时传入的DispSyncSource::onVsyncCallback方法:

mCallbackRepeater =            std::make_unique(vSyncDispatch,                                               std::bind(&DispSyncSource::onVsyncCallback, this,                                                         std::placeholders::_1,                                                         std::placeholders::_2,                                                         std::placeholders::_3),                                               name, workDuration, readyDuration,                                               std::chrono::steady_clock::now().time_since_epoch());

所以,最终会调用到DispSyncSource::onVsyncCallback方法:

void DispSyncSource::onVsyncCallback(nsecs_t vsyncTime, nsecs_t targetWakeupTime,                                     nsecs_t readyTime) {    VSyncSource::Callback* callback;    {        std::lock_guard lock(mCallbackMutex);        callback = mCallback;    }    ...    if (callback != nullptr) {        callback->onVSyncEvent(targetWakeupTime, {vsyncTime, readyTime});    }}

又是回调,这里很绕。这里的callback其实就是EventThread,仍然是在创建EventThread的时候设置的:

EventThread::EventThread(std::unique_ptrvsyncSource,                         android::frametimeline::TokenManager* tokenManager,                         InterceptVSyncsCallback interceptVSyncsCallback,                         ThrottleVsyncCallback throttleVsyncCallback,                         GetVsyncPeriodFunction getVsyncPeriodFunction)      : mVSyncSource(std::move(vsyncSource)),        mTokenManager(tokenManager),        mInterceptVSyncsCallback(std::move(interceptVSyncsCallback)),        mThrottleVsyncCallback(std::move(throttleVsyncCallback)),        mGetVsyncPeriodFunction(std::move(getVsyncPeriodFunction)),        mThreadName(mVSyncSource->getName()) {    LOG_ALWAYS_FATAL_IF(getVsyncPeriodFunction == nullptr,            "getVsyncPeriodFunction must not be null");    mVSyncSource->setCallback(this);    ...}

所以,终于可以看到尽头了。最终其实就是调用到EventThread的onVSyncEvent方法:

void EventThread::onVSyncEvent(nsecs_t timestamp, VSyncSource::VSyncData vsyncData) {    std::lock_guardlock(mMutex);    LOG_FATAL_IF(!mVSyncState);    mPendingEvents.push_back(makeVSync(mVSyncState->displayId, timestamp, ++mVSyncState->count,                                       vsyncData.expectedPresentationTime,                                       vsyncData.deadlineTimestamp));    mCondition.notify_all();}

这里我们看到,会生成一个VSync信号,加入到mPendingEvents集合中,并且发出通知,让threadMain去获取,从而完成了VSync信号的生产者流程。

画了如下的surfaceFlinger结构图,方便理解(非完整版):

五.APP层收到信号进行刷新

本章讲的主要流程如下图红圈所示:

5.1 APP端接受流程

3.3小节中讲到,SurfaceFlinger会通过BitTube的方式传递给APP侧Vsync信号。发送vscyn信号的方法在DisplayEventReceiver.cpp中,而接收方法也在这个类当中。而具体调用方则是DisplayEventDispatcher.cpp中的dispatchVsync方法。流程如下图所示:

5.2 dispathVsync分发流程

上面在handleEvent中,processPendingEvents获取到了Vsync信号VsyncEventData后,交给dispatchVsync方法负责处理。

dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount, vsyncEventData);

dispatchVsync方法的实现者是android_view_DisplayEventReceiver.cpp,如下:

void NativeDisplayEventReceiver::dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId,                                               uint32_t count, VsyncEventData vsyncEventData) {    JNIEnv* env = AndroidRuntime::getJNIEnv();    ...    jobject javaVsyncEventData = createJavaVsyncEventData(env, vsyncEventData);    env->CallVoidMethod(receiverObj.get(), gDisplayEventReceiverClassInfo.dispatchVsync,                            timestamp, displayId.value, count, javaVsyncEventData);    ...}

我们可以看到,先是把VsyncEventData转换为java可以接受的jobject对象,然后通过CallVoidMethod方法通知到java层中DisplayEventReceiver.java中的dispatchVsync方法。

5.3 java中流程流转

首先DisplayEventReceiver中dispatchVsync方法被调用:

// Called from native code.    @SuppressWarnings("unused")    private void dispatchVsync(long timestampNanos, long physicalDisplayId, int frame,            VsyncEventData vsyncEventData) {        onVsync(timestampNanos, physicalDisplayId, frame, vsyncEventData);    }

该方法中直接调用onVsync方法,调用到Choreographer.java中FrameDisplayEventReceiver下的onVsync方法:

@Override        public void onVsync(long timestampNanos, long physicalDisplayId, int frame,                VsyncEventData vsyncEventData) {            try {                ...                if (timestampNanos > now) {                    timestampNanos = now;                }                if (mHavePendingVsync) {                } else {                    mHavePendingVsync = true;                }                mTimestampNanos = timestampNanos;                mFrame = frame;                mLastVsyncEventData = vsyncEventData;                Message msg = Message.obtain(mHandler, this);                msg.setAsynchronous(true);                mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);            } finally {                Trace.traceEnd(Trace.TRACE_TAG_VIEW);            }        }

onVsync方法中,主要判断时间。如果timestampNanos>now,则是用当前时间。所以还是以方法的调用时间为准。然后通过handle转发到主线程中执行。

Message.obj=this,本身FrameDisplayEventReceiver又实现了Runnable接口,所以自然会执行FrameDisplayEventReceiver下的run方法:

@Override        public void run() {            mHavePendingVsync = false;            doFrame(mTimestampNanos, mFrame, mLastVsyncEventData);        }

这时候我们就看到,执行到了doFrame方法,而这个方法也是就是渲染流程的执行者。

5.4 如何触发handleEvent流程?

讲到这里,你或许有个疑问,上面流程中,如何执行到5.1中的handleEvent方法的呢?

主要是下图所示的流程:

如果你断点调试的时候,会发现下面所示的这个方法,竟然是主线程调用的:

DisplayEventReceiver.java // Called from native code.    @SuppressWarnings("unused")    private void dispatchVsync(long timestampNanos, long physicalDisplayId, int frame,            long frameTimelineVsyncId, long frameDeadline, long frameInterval) {        onVsync(timestampNanos, physicalDisplayId, frame,                new VsyncEventData(frameTimelineVsyncId, frameDeadline, frameInterval));    }

为什么用竟然呢?因为一般来看,应该是子线程等待接受SurfaceFlinger的信号,收到了信号后交给主线程处理,如果是主线程去等待,岂不是主线程阻塞了?

这里使用looper.addFd()方法,在该方法中,用到了一个epoll_ctl的机制,即对FD文件进行监听,当FD改变时触发主线程的回调。如果处理完回调任务,则会进入epoll_wait的阻塞,继续监听。

六.扩展问题

问:高频次请求vsync信号,会突破60FPS的限制吗?

答:不会。

首先ViewRootImpl中做了一层处理,哪怕16ms改变了很多View的布局,最终执行到了scheduleTraversals方法时,因为有如下的判断,所以都只会执行一次vsync信号的请求和注册一次回调,直至收到VSYNC信号。

void scheduleTraversals() {        if (!mTraversalScheduled) {            mTraversalScheduled = true;            mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();            mChoreographer.postCallback(                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);        }    }

取消限制:

void doTraversal() {        if (mTraversalScheduled) {            mTraversalScheduled = false;}

其次,2.2小节中讲到,native请求VSYNC信号时也有一次限制,等到VSYNC信号时是不会再次发送请求的。

status_t DisplayEventDispatcher::scheduleVsync() {    if (!mWaitingForVsync) {        ...        status_t status = mReceiver.requestNextVsync();        ...        mWaitingForVsync = true;        ...    }    return OK;}

七.参考资料

https://www.jianshu.com/p/6083c590521b

https://www.jianshu.com/p/386bbb5fa29a //努比亚技术团队文章

八.声明

1.本文是原创,根据网上资料和阅读ASOP的源码之后得出的结论,如有问题,欢迎指出。

2.图中涉及到的流程图如果想要高清大图或者pos格式的原图,可以私信我。

相关文章Related

返回栏目>>