美文网首页android_display
Vsync与app、surfaceFlinger关系(2)

Vsync与app、surfaceFlinger关系(2)

作者: 欣兄 | 来源:发表于2021-03-23 20:37 被阅读0次

    App 的Vsync 信号已经进行了注册,那什么时候和怎么返回这个信号到 Choreographer.java的onVsync呢,DispSync对象在创建的时候会启动一个DispSyncThread线程,该线程用于模拟Vsync信号,主要是在DispSync.cpp文件中。

    流程图如下: 20.png

    堆栈信息如下:

    2021-03-23 14:21:53.423 968-1128/? D/zx1: #00 pc 000000000009090c  /system/lib64/libgui.so (android::DisplayEventReceiver::sendEvents(android::gui::BitTube*, android::DisplayEventReceiver::Event const*, unsigned long)+72)
    2021-03-23 14:21:53.423 968-1128/? D/zx1: #01 pc 00000000000f5d78  /system/lib64/libsurfaceflinger.so (android::EventThreadConnection::postEvent(android::DisplayEventReceiver::Event const&)+84)
    2021-03-23 14:21:53.423 968-1128/? D/zx1: #02 pc 00000000000f796c  /system/lib64/libsurfaceflinger.so (void* std::__1::__thread_proxy<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct> >, android::impl::EventThread::EventThread(std::__1::unique_ptr<android::VSyncSource, std::__1::default_delete<android::VSyncSource> >, std::__1::function<void (long)>)::$_0> >(void*)+1504)
    2021-03-23 14:21:53.423 968-1128/? D/zx1: #03 pc 00000000000b0654  /apex/com.android.runtime/lib64/bionic/libc.so (__pthread_start(void*)+392)
    2021-03-23 14:21:53.423 968-1128/? D/zx1: #04 pc 0000000000050888  /apex/com.android.runtime/lib64/bionic/libc.so (__start_thread+64)
    
    /frameworks/native/services/surfaceflinger/scheduler/DispSync.cpp
    DispSync::DispSync(const char* name, bool hasSyncFramework)
          : mName(name), mIgnorePresentFences(!hasSyncFramework) {
        // This flag offers the ability to turn on systrace logging from the shell.
        char value[PROPERTY_VALUE_MAX];
        property_get("debug.sf.dispsync_trace_detailed_info", value, "0");
        mTraceDetailedInfo = atoi(value);
    
        mThread = new DispSyncThread(name, mTraceDetailedInfo);
        mThread->run("DispSync", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);   @1
    
        // set DispSync to SCHED_FIFO to minimize jitter
        struct sched_param param = {0};
        param.sched_priority = 2;
        if (sched_setscheduler(mThread->getTid(), SCHED_FIFO, &param) != 0) {
            ALOGE("Couldn't set SCHED_FIFO for DispSyncThread");
        }
    
        beginResync();
    
        if (mTraceDetailedInfo && kEnableZeroPhaseTracer) {
            mZeroPhaseTracer = std::make_unique<ZeroPhaseTracer>();
            addEventListener("ZeroPhaseTracer", 0, mZeroPhaseTracer.get(), 0);
        }
    }
    
    class DispSyncThread : public Thread {
    ......
    }
    

    在@1处创建了DispSyncThread 并执行了run方法,由于DispSyncThread继承Thread, run方法执行后会执行DispSyncThread的 threadLoop方法,

    /frameworks/native/services/surfaceflinger/scheduler/DispsSync.cpp
        virtual bool threadLoop() {
     nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
    
            while (true) {
                std::vector<CallbackInvocation> callbackInvocations;
    ......
      callbackInvocations = gatherCallbackInvocationsLocked(now, computeNextRefreshLocked(0, now));  @1
    
     if (callbackInvocations.size() > 0) {
                    fireCallbackInvocations(callbackInvocations);  @2
                }
    }
    ......
    

    省略了若干代码,此处是一个死循环,用于制造模拟信号。最终会到代码末尾@1 @2处,@1处是收集注册的listener信息,@2处就是进行回调。

     nsecs_t computeNextRefreshLocked(int periodOffset, nsecs_t now) const {
            nsecs_t phase = mReferenceTime + mPhase;
            if (mPeriod == 0) {
                return 0;
            }
            return (((now - phase) / mPeriod) + periodOffset + 1) * mPeriod + phase;
        }
    

    有一定的计算,最终返回一个时间,从命名上面看,意思是计算下一个刷新时间。

    再看gatherCallbackInvocationsLocked,第一个参数是从开机开始算,第二个参数就是computeNextRefreshLocked算出来的那个。

    std::vector<CallbackInvocation> gatherCallbackInvocationsLocked(nsecs_t now,
                                                                        nsecs_t expectedVSyncTime) {
            if (mTraceDetailedInfo) ATRACE_CALL();
            ALOGV("[%s] gatherCallbackInvocationsLocked @ %" PRId64, mName, ns2us(now));
    
            std::vector<CallbackInvocation> callbackInvocations;
            nsecs_t onePeriodAgo = now - mPeriod;
    
            for (auto& eventListener : mEventListeners) { @1
                nsecs_t t = computeListenerNextEventTimeLocked(eventListener, onePeriodAgo);
    
                if (t < now) {
                    if (isCloseToPeriod(now - eventListener.mLastCallbackTime)) {
                        eventListener.mLastEventTime = t;
                        ALOGV("[%s] [%s] Skipping event due to model error", mName,
                              eventListener.mName);
                        continue;
                    }
    
                    CallbackInvocation ci;
                    ci.mCallback = eventListener.mCallback;
                    ci.mEventTime = t;
                    ci.mExpectedVSyncTime = expectedVSyncTime;
                    if (eventListener.mPhase < 0) {
                        ci.mExpectedVSyncTime += mPeriod;
                    }
                    ALOGV("[%s] [%s] Preparing to fire, latency: %" PRId64, mName, eventListener.mName,
                          t - eventListener.mLastEventTime);
                    callbackInvocations.push_back(ci);
                    eventListener.mLastEventTime = t;
                    eventListener.mLastCallbackTime = now;
                }
            }
    
            return callbackInvocations;
        }
    

    @1 处是一个for循环,遍历mEventListeners。之前注册的listener全部被mEventListeners.push_back存起来( 回忆addEventListener方法)。mEventListeners经过一系列的操作存入到了callbackInvocations中。主要就是把EventListener对象值 赋给callbackInvocation对象。
    它两个的结构体

     struct EventListener {
            const char* mName;
            nsecs_t mPhase;
            nsecs_t mLastEventTime;
            nsecs_t mLastCallbackTime;
            DispSync::Callback* mCallback;
        };
    
        struct CallbackInvocation {
            DispSync::Callback* mCallback;
            nsecs_t mEventTime;
            nsecs_t mExpectedVSyncTime;
        };
    

    接下来会执行fireCallbakcInvocations方法。

        void fireCallbackInvocations(const std::vector<CallbackInvocation>& callbacks) {
            if (mTraceDetailedInfo) ATRACE_CALL();
            for (size_t i = 0; i < callbacks.size(); i++) {
                callbacks[i].mCallback->onDispSyncEvent(callbacks[i].mEventTime,                                                    callbacks[i].mExpectedVSyncTime);
            }
        }
    

    很明显 要把vsync分发下去,且有两个参数。

     /frameworks/native/services/surfaceflinger/Scheduler/DispSyncSource.cpp
    void DispSyncSource::onDispSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp) {
        VSyncSource::Callback* callback;
        {
            std::lock_guard lock(mCallbackMutex);
            callback = mCallback;
        }
    
        if (mTraceVsync) {
            mValue = (mValue + 1) % 2;
        }
    
        if (callback != nullptr) {
            callback->onVSyncEvent(when, expectedVSyncTimestamp);
        }
    }
    
    void DispSyncSource::setCallback(VSyncSource::Callback* callback) {
        std::lock_guard lock(mCallbackMutex);
        mCallback = callback;
    }
    

    callback是谁呢,发现是在EventThread的构造方法中调用了DispSyncSource的setCallback方法

    /frameworks/native/services/surfaceflinger/Scheduler/EventThread.cpp
    EventThread::EventThread(std::unique_ptr<VSyncSource> vsyncSource,
                             InterceptVSyncsCallback interceptVSyncsCallback)
          : mVSyncSource(std::move(vsyncSource)),
            mInterceptVSyncsCallback(std::move(interceptVSyncsCallback)),
            mThreadName(mVSyncSource->getName()) {
        mVSyncSource->setCallback(this);
    

    所以这个callback就是eventthread的对象,所以就会调用到EventThread的onVsyncEvent方法

    /frameworks/native/services/surfaceflinger/Scheduler/EventThread.cpp
    void EventThread::onVSyncEvent(nsecs_t timestamp, nsecs_t expectedVSyncTimestamp) {
        std::lock_guard<std::mutex> lock(mMutex);
    
        LOG_FATAL_IF(!mVSyncState);
        mPendingEvents.push_back(makeVSync(mVSyncState->displayId, timestamp, ++mVSyncState->count,
                                           expectedVSyncTimestamp));
        mCondition.notify_all();
    }
    

    重要的一句mCondition.notify_all,唤醒 threadMain中wait的地方,进行下一个循环,会执行如下语句

    void EventThread::threadMain(std::unique_lock<std::mutex>& lock) {
    ......
            if (!consumers.empty()) {
                dispatchEvent(*event, consumers);
                consumers.clear();
            }
    ......
    }
    

    这个consumer是什么,它是eventThreadConnection,consumer会在threadMain中的循环,根据mDisplayEventConnections的数据来填充,注册过当然不为空,下一句consumer.clear,
    都分发出去了,当然要清空了,否则下次多发了vsync,不就出问题了。

    void EventThread::dispatchEvent(const DisplayEventReceiver::Event& event,
                                    const DisplayEventConsumers& consumers) {
        for (const auto& consumer : consumers) {
            switch (consumer->postEvent(event)) {  @1
                case NO_ERROR:
                    break;
    
                case -EAGAIN:
                    // TODO: Try again if pipe is full.
                    ALOGW("Failed dispatching %s for %s", toString(event).c_str(),
                          toString(*consumer).c_str());
                    break;
    
                default:
                    // Treat EPIPE and other errors as fatal.
                    removeDisplayEventConnectionLocked(consumer);  @2;
            }
        }
    }
    

    @1处执行EventThreadConnection的postEvent方法,@2处移除掉此监听。就验证了咱们的请求一次vsync,返回一次vsync。

    status_t EventThreadConnection::postEvent(const DisplayEventReceiver::Event& event) {
        ssize_t size = DisplayEventReceiver::sendEvents(&mChannel, &event, 1);
        return size < 0 ? status_t(size) : status_t(NO_ERROR);
    }
    
    /frameworks/native/libs/gui/DisplayEventReceiver.cpp
    ssize_t DisplayEventReceiver::sendEvents(gui::BitTube* dataChannel,
            Event const* events, size_t count)
    {
        return gui::BitTube::sendObjects(dataChannel, events, count);
    }
    

    这块就发出去了,跨进程?之后就能到Choreograhper.java 的onVsync。
    打印了一下Choreographer onVsync堆栈

    2021-03-23 14:21:53.449 1686-2293/system_process D/zx1 Choreographer: java.lang.Throwable
            at android.view.Choreographer$FrameDisplayEventReceiver.onVsync(Choreographer.java:1015)
            at android.view.DisplayEventReceiver.dispatchVsync(DisplayEventReceiver.java:203)
            at android.os.MessageQueue.nativePollOnce(Native Method)
            at android.os.MessageQueue.next(MessageQueue.java:335)
            at android.os.Looper.loop(Looper.java:195)
            at android.os.HandlerThread.run(HandlerThread.java:67)
            at com.android.server.ServiceThread.run(ServiceThread.java:44)
    

    可以知道这条vsync从何而来。但中间怎么通过BitTube 跨进程的,目前还咩有看出来,问题暂存。
    看一下Choreographer.java 的FrameDisplayEventReceive 的onVsync

    /frameworks/base/core/java/android/view/Choreographer.java
    private final class FrameDisplayEventReceiver extends DisplayEventReceiver
                implements Runnable {
            private boolean mHavePendingVsync;
            private long mTimestampNanos;
            private int mFrame;
    
            public FrameDisplayEventReceiver(Looper looper, int vsyncSource) {
                super(looper, vsyncSource, CONFIG_CHANGED_EVENT_SUPPRESS);
            }
    
            // TODO(b/116025192): physicalDisplayId is ignored because SF only emits VSYNC events for
            // the internal display and DisplayEventReceiver#scheduleVsync only allows requesting VSYNC
            // for the internal display implicitly.
            @Override
            public void onVsync(long timestampNanos, long physicalDisplayId, int frame) {
                // Post the vsync event to the Handler.
                // The idea is to prevent incoming vsync events from completely starving
                // the message queue.  If there are no messages in the queue with timestamps
                // earlier than the frame time, then the vsync event will be processed immediately.
                // Otherwise, messages that predate the vsync event will be handled first.
                long now = System.nanoTime();
                if (timestampNanos > now) {
                    Log.w(TAG, "Frame time is " + ((timestampNanos - now) * 0.000001f)
                            + " ms in the future!  Check that graphics HAL is generating vsync "
                            + "timestamps using the correct timebase.");
                    timestampNanos = now;
                }
    
                if (mHavePendingVsync) {
                    Log.w(TAG, "Already have a pending vsync event.  There should only be "
                            + "one at a time.");
                } else {
                    mHavePendingVsync = true;
                }
    
                mTimestampNanos = timestampNanos;
                mFrame = frame;
                Message msg = Message.obtain(mHandler, this);  @1
                msg.setAsynchronous(true);  @2
                mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
            }
    
            @Override
            public void run() {  @3
                mHavePendingVsync = false;
                doFrame(mTimestampNanos, mFrame);
            }
        }
    

    在@2处设置了此message为异步消息,还记得当时在ViewRootImpl的scheduleTraversals方法吗?

      @UnsupportedAppUsage
        void scheduleTraversals() {
    ......
                mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
                mChoreographer.postCallback(
                        Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
    ......       
     }
       }
    

    对在申请Vsync之前mHandler.getLooper().getQueue().postSyncBarrier(); 设置了同步栅栏,也就是所申请的vsync信号到来后,优先执行异步消息。而在@2处设置了此消息为异步消息,此消息就会优先执行,所以一般view的更新消息是优先执行的。执行完了异步消息后就会通过removeSyncBarrier该方法将同步屏障移除。(方法在 MessageQueue.java 中)

    在@1 处注意看一下obtain第二个参数是this,FrameDisplayEventReceiver implements Runnable,所以this为当前runnable, Message中的callback也就不为null了

    /frameworks/base/core/java/android/os/Message.java
        public static Message obtain(Handler h, Runnable callback) {
            Message m = obtain();
            m.target = h;
            m.callback = callback;
    
            return m;
        }
    

    而我们都知道Handle的handleMessage在执行之前会执行dispatchMessage

    /frameworks/base/core/java/android/os/Handler.java
        /**
         * Handle system messages here.
         */
        public void dispatchMessage(@NonNull Message msg) {
            if (msg.callback != null) {  @4
                handleCallback(msg); 
            } else {
                if (mCallback != null) {
                    if (mCallback.handleMessage(msg)) {
                        return;
                    }
                }
                handleMessage(msg);
            }
        }
    

    在@3处 很明显msg.callback不为空,执行handleCallback

    /frameworks/base/core/java/android/os/Handler.java
    private static void handleCallback(Message message) {
            message.callback.run();
        }
    

    这个run方法又让回到了Choreographer中的 FrameDisplayEventReceiver中的run方法也就会@3处,会执行我们熟悉的doFrame,两个参数第一个应该是vsync信号的时间,第二个参数根据前面是1,

    @UnsupportedAppUsage
    void doFrame(long frameTimeNanos, int frame) {

    }

    23.png

    App申请Vsync信号和Vsync信号的返回大致说完。接下来应用的绘制后续再看。

    相关文章

      网友评论

        本文标题:Vsync与app、surfaceFlinger关系(2)

        本文链接:https://www.haomeiwen.com/subject/mvcqhltx.html