Vsync与app、surfaceFlinger关系(2)

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信号的返回大致说完。接下来应用的绘制后续再看。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值