AChoreographer到vsync
1、本文的基本作用引导阅读源码但更重要的是要自己去理解2、本文的最大价值久之皆已遗忘顾之皆已忆起。一、使用示例AChoreographer的AChoreographer_getInstance需要ALooper因此如果调用线程没有ALooper需自己创建。if (vlc_clone(helper-choreographer_thread, choreographer_thread, cl, 0)) { msg_Err(cl, create choreographer_thread error ); return VLC_EGENERIC; }static void *choreographer_thread(void *p_data) { input_clock_t *cl (input_clock_t *)p_data; release_helper *helper cl-p_videoframereleasehelper; ALooper* looper achoreographer.ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS); achoreographer.ALooper_acquire(looper); helper-p_achoreographer achoreographer.AChoreographer_getInstance(); if (!helper-p_achoreographer ) { msg_Err(cl, cant get achoreographer instance); return NULL; } msg_Dbg(cl, start registerRefreshRateCallback); achoreographer.AChoreographer_registerRefreshRateCallback(helper-p_achoreographer, release_helper_refresh_rate_cb, (void*)cl); if (achoreographer.use_post64) { msg_Dbg(cl, start postFrameCallback64); achoreographer.AChoreographer_postFrameCallback64(helper-p_achoreographer, release_helper_post_frame_cb64, (void*)cl); } else { msg_Dbg(cl, start postFrameCallback); achoreographer.AChoreographer_postFrameCallback(helper-p_achoreographer, release_helper_post_frame_cb, (void*)cl); } helper-is_running true; helper-p_looper looper; while (helper-is_running) { int ret achoreographer.ALooper_pollAll(100, NULL, NULL, NULL); if (ret ALOOPER_POLL_ERROR) { msg_Err(cl, choreographer_thread loop error); break; } } msg_Info(cl, choreographer_thread exit loop); achoreographer.ALooper_release(looper); return NULL; }二、AChoreographer.cppAChoreographer.cpp它只是个包装实际实现都在Choreographer.cpp中源码位于frameworks/native/libs/gui/Choreographer.cpp中。AChoreographer* AChoreographer_getInstance() { return Choreographer_to_AChoreographer(Choreographer::getForThread().get()); } void AChoreographer_postFrameCallback(AChoreographer* choreographer, AChoreographer_frameCallback callback, void* data) { AChoreographer_to_Choreographer(choreographer) -postFrameCallbackDelayed(callback, nullptr, nullptr, data, 0, CALLBACK_ANIMATION); }spChoreographer Choreographer::getForThread() { if (gChoreographer nullptr) { spLooper looper Looper::getForThread(); if (!looper.get()) { ALOGW(No looper prepared for thread); return nullptr; } gChoreographer spChoreographer::make(looper); status_t result gChoreographer-initialize(); if (result ! OK) { ALOGW(Failed to initialize); return nullptr; } } return gChoreographer; }三、Choreographer.cppChoreographer类需要Looper去构造并且继承了类DisplayEventDispatcher。class Choreographer : public DisplayEventDispatcher, public MessageHandler { public: struct Context { std::mutex lock; std::vectorChoreographer* ptrs GUARDED_BY(lock); std::mapAVsyncId, int64_t startTimes GUARDED_BY(lock); bool registeredToDisplayManager GUARDED_BY(lock) false; std::atomicnsecs_t mLastKnownVsync -1; }; static Context gChoreographers; explicit Choreographer(const spLooper looper, const spIBinder layerHandle nullptr) EXCLUDES(gChoreographers.lock); }四、DisplayEventDispatcher.cpp源码位于frameworks/native/libs/gui/DisplayEventDispatcher.cpp它主要负责消息的分发。class DisplayEventDispatcher : public LooperCallback { public: status_t initialize(); void dispose(); status_t scheduleVsync(); void injectEvent(const DisplayEventReceiver::Event event); int getFd() const; virtual int handleEvent(int receiveFd, int events, void* data); status_t getLatestVsyncEventData(ParcelableVsyncEventData* outVsyncEventData) const; protected: explicit DisplayEventDispatcher(const spLooper looper, gui::ISurfaceComposer::VsyncSource vsyncSource gui::ISurfaceComposer::VsyncSource::eVsyncSourceApp, EventRegistrationFlags eventRegistration {}, const spIBinder layerHandle nullptr); friend class spDisplayEventDispatcher; virtual ~DisplayEventDispatcher() default; private: spLooper mLooper; DisplayEventReceiver mReceiver; }1、将mReceiver的fd加入到looper的pool监听中status_t DisplayEventDispatcher::initialize() { status_t result mReceiver.initCheck(); if (result) { ALOGW(Failed to initialize display event receiver, status%d, result); return result; } if (mLooper ! nullptr) { int rc mLooper-addFd(mReceiver.getFd(), 0, Looper::EVENT_INPUT, this, NULL); if (rc 0) { return UNKNOWN_ERROR; } } return OK; }2、mReceiver中有刷新率变化、vsync消息就会往fd中写入消息int DisplayEventReceiver::getFd() const { if (mDataChannel nullptr) return mInitError.has_value() ? mInitError.value() : NO_INIT; return mDataChannel-getFd(); }ssize_t DisplayEventReceiver::sendEvents(Event const* events, size_t count) { return DisplayEventReceiver::sendEvents(mDataChannel.get(), events, count); } ssize_t DisplayEventReceiver::sendEvents(gui::BitTube* dataChannel, Event const* events, size_t count) { return gui::BitTube::sendObjects(dataChannel, events, count); }3、looper的pool监听到fd变化后会调用LooperCallback实现的handleEventint Looper::pollAll(int timeoutMillis, int* outFd, int* outEvents, void** outData) { if (timeoutMillis 0) { int result; do { result pollOnce(timeoutMillis, outFd, outEvents, outData); } while (result POLL_CALLBACK); return result; } else { nsecs_t endTime systemTime(SYSTEM_TIME_MONOTONIC) milliseconds_to_nanoseconds(timeoutMillis); for (;;) { int result pollOnce(timeoutMillis, outFd, outEvents, outData); if (result ! POLL_CALLBACK) { return result; } nsecs_t now systemTime(SYSTEM_TIME_MONOTONIC); timeoutMillis toMillisecondTimeoutDelay(now, endTime); if (timeoutMillis 0) { return POLL_TIMEOUT; } } } }int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) { int result 0; for (;;) { while (mResponseIndex mResponses.size()) { const Response response mResponses.itemAt(mResponseIndex); int ident response.request.ident; if (ident 0) { int fd response.request.fd; int events response.events; void* data response.request.data; #if DEBUG_POLL_AND_WAKE ALOGD(%p ~ pollOnce - returning signalled identifier %d: fd%d, events0x%x, data%p, this, ident, fd, events, data); #endif if (outFd ! nullptr) *outFd fd; if (outEvents ! nullptr) *outEvents events; if (outData ! nullptr) *outData data; return ident; } } if (result ! 0) { #if DEBUG_POLL_AND_WAKE ALOGD(%p ~ pollOnce - returning result %d, this, result); #endif if (outFd ! nullptr) *outFd 0; if (outEvents ! nullptr) *outEvents 0; if (outData ! nullptr) *outData nullptr; return result; } result pollInner(timeoutMillis); } }int Looper::pollInner(int timeoutMillis) { // Invoke all response callbacks. for (size_t i 0; i mResponses.size(); i) { Response response mResponses.editItemAt(i); if (response.request.ident POLL_CALLBACK) { int fd response.request.fd; int events response.events; void* data response.request.data; #if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS ALOGD(%p ~ pollOnce - invoking fd event callback %p: fd%d, events0x%x, data%p, this, response.request.callback.get(), fd, events, data); #endif // Invoke the callback. Note that the file descriptor may be closed by // the callback (and potentially even reused) before the function returns so // we need to be a little careful when removing the file descriptor afterwards. int callbackResult response.request.callback-handleEvent(fd, events, data); if (callbackResult 0) { AutoMutex _l(mLock); removeSequenceNumberLocked(response.seq); } // Clear the callback reference in the response structure promptly because we // will not clear the response vector itself until the next poll. response.request.callback.clear(); result POLL_CALLBACK; } } return result; }int DisplayEventDispatcher::handleEvent(int, int events, void*) { if (events (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) { ALOGE(Display event receiver pipe was closed or an error occurred. events0x%x, events); return 0; // remove the callback } if (!(events Looper::EVENT_INPUT)) { ALOGW(Received spurious callback for unhandled poll event. events0x%x, events); return 1; // keep the callback } // Drain all pending events, keep the last vsync. nsecs_t vsyncTimestamp; PhysicalDisplayId vsyncDisplayId; uint32_t vsyncCount; VsyncEventData vsyncEventData; if (processPendingEvents(vsyncTimestamp, vsyncDisplayId, vsyncCount, vsyncEventData)) { ALOGV(dispatcher %p ~ Vsync pulse: timestamp% PRId64 , displayId%s, count%d, vsyncId% PRId64, this, ns2ms(vsyncTimestamp), to_string(vsyncDisplayId).c_str(), vsyncCount, vsyncEventData.preferredVsyncId()); mWaitingForVsync false; mLastVsyncCount vsyncCount; dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount, vsyncEventData); } if (mWaitingForVsync) { const nsecs_t currentTime systemTime(SYSTEM_TIME_MONOTONIC); const nsecs_t vsyncScheduleDelay currentTime - mLastScheduleVsyncTime; if (vsyncScheduleDelay WAITING_FOR_VSYNC_TIMEOUT) { ALOGW(Vsync time out! vsyncScheduleDelay% PRId64 ms, ns2ms(vsyncScheduleDelay)); mWaitingForVsync false; dispatchVsync(currentTime, vsyncDisplayId /* displayId is not used */, mLastVsyncCount, vsyncEventData /* empty data */); } } return 1; // keep the callback }4、Choreographer实现了虚函数dispatchVsync()最终将vsync回调给AChoreographer的使用者oid Choreographer::dispatchVsync(nsecs_t timestamp, PhysicalDisplayId, uint32_t, VsyncEventData vsyncEventData) { std::vectorFrameCallback animationCallbacks{}; std::vectorFrameCallback inputCallbacks{}; { std::lock_guardstd::mutex _l{mLock}; nsecs_t now systemTime(SYSTEM_TIME_MONOTONIC); while (!mFrameCallbacks.empty() mFrameCallbacks.top().dueTime now) { if (mFrameCallbacks.top().callbackType CALLBACK_INPUT) { inputCallbacks.push_back(mFrameCallbacks.top()); } else { animationCallbacks.push_back(mFrameCallbacks.top()); } mFrameCallbacks.pop(); } } mLastVsyncEventData vsyncEventData; // Callbacks with type CALLBACK_INPUT should always run first { ATRACE_FORMAT(CALLBACK_INPUT); dispatchCallbacks(inputCallbacks, vsyncEventData, timestamp); } { ATRACE_FORMAT(CALLBACK_ANIMATION); dispatchCallbacks(animationCallbacks, vsyncEventData, timestamp); } }void Choreographer::dispatchCallbacks(const std::vectorFrameCallback callbacks, VsyncEventData vsyncEventData, nsecs_t timestamp) { for (const auto cb : callbacks) { if (cb.vsyncCallback ! nullptr) { ATRACE_FORMAT(AChoreographer_vsyncCallback % PRId64, vsyncEventData.preferredVsyncId()); const ChoreographerFrameCallbackDataImpl frameCallbackData createFrameCallbackData(timestamp); registerStartTime(); mInCallback true; cb.vsyncCallback(reinterpret_castconst AChoreographerFrameCallbackData*( frameCallbackData), cb.data); mInCallback false; } else if (cb.callback64 ! nullptr) { ATRACE_FORMAT(AChoreographer_frameCallback64); cb.callback64(timestamp, cb.data); } else if (cb.callback ! nullptr) { ATRACE_FORMAT(AChoreographer_frameCallback); cb.callback(timestamp, cb.data); } } }五、DisplayEventReceiver.cpp源码位于frameworks/native/libs/gui/DisplayEventReceiver.cpp它负责接收底层变化的消息。具体怎么送给receiver的没有跟, 可以大概看一下下面的图是逻辑不是真实的验证过的代码:六、Looper.cpp源码位于system/core/libutils/Looper.cpp它负责监听fd的变化并调用回调int Looper::pollAll(int timeoutMillis, int* outFd, int* outEvents, void** outData) { if (timeoutMillis 0) { int result; do { result pollOnce(timeoutMillis, outFd, outEvents, outData); } while (result POLL_CALLBACK); return result; } else { nsecs_t endTime systemTime(SYSTEM_TIME_MONOTONIC) milliseconds_to_nanoseconds(timeoutMillis); for (;;) { int result pollOnce(timeoutMillis, outFd, outEvents, outData); if (result ! POLL_CALLBACK) { return result; } nsecs_t now systemTime(SYSTEM_TIME_MONOTONIC); timeoutMillis toMillisecondTimeoutDelay(now, endTime); if (timeoutMillis 0) { return POLL_TIMEOUT; } } } } void Looper::wake() { #if DEBUG_POLL_AND_WAKE ALOGD(%p ~ wake, this); #endif uint64_t inc 1; ssize_t nWrite TEMP_FAILURE_RETRY(write(mWakeEventFd.get(), inc, sizeof(uint64_t))); if (nWrite ! sizeof(uint64_t)) { if (errno ! EAGAIN) { LOG_ALWAYS_FATAL(Could not write wake signal to fd %d (returned %zd): %s, mWakeEventFd.get(), nWrite, strerror(errno)); } } }int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) { int result 0; for (;;) { while (mResponseIndex mResponses.size()) { const Response response mResponses.itemAt(mResponseIndex); int ident response.request.ident; if (ident 0) { int fd response.request.fd; int events response.events; void* data response.request.data; #if DEBUG_POLL_AND_WAKE ALOGD(%p ~ pollOnce - returning signalled identifier %d: fd%d, events0x%x, data%p, this, ident, fd, events, data); #endif if (outFd ! nullptr) *outFd fd; if (outEvents ! nullptr) *outEvents events; if (outData ! nullptr) *outData data; return ident; } } if (result ! 0) { #if DEBUG_POLL_AND_WAKE ALOGD(%p ~ pollOnce - returning result %d, this, result); #endif if (outFd ! nullptr) *outFd 0; if (outEvents ! nullptr) *outEvents 0; if (outData ! nullptr) *outData nullptr; return result; } result pollInner(timeoutMillis); } }int Looper::pollInner(int timeoutMillis) { #if DEBUG_POLL_AND_WAKE ALOGD(%p ~ pollOnce - waiting: timeoutMillis%d, this, timeoutMillis); #endif // Adjust the timeout based on when the next message is due. if (timeoutMillis ! 0 mNextMessageUptime ! LLONG_MAX) { nsecs_t now systemTime(SYSTEM_TIME_MONOTONIC); int messageTimeoutMillis toMillisecondTimeoutDelay(now, mNextMessageUptime); if (messageTimeoutMillis 0 (timeoutMillis 0 || messageTimeoutMillis timeoutMillis)) { timeoutMillis messageTimeoutMillis; } #if DEBUG_POLL_AND_WAKE ALOGD(%p ~ pollOnce - next message in % PRId64 ns, adjusted timeout: timeoutMillis%d, this, mNextMessageUptime - now, timeoutMillis); #endif } // Poll. int result POLL_WAKE; mResponses.clear(); mResponseIndex 0; // We are about to idle. mPolling true; struct epoll_event eventItems[EPOLL_MAX_EVENTS]; int eventCount epoll_wait(mEpollFd.get(), eventItems, EPOLL_MAX_EVENTS, timeoutMillis); // No longer idling. mPolling false; // Acquire lock. mLock.lock(); // Rebuild epoll set if needed. if (mEpollRebuildRequired) { mEpollRebuildRequired false; rebuildEpollLocked(); goto Done; } // Check for poll error. if (eventCount 0) { if (errno EINTR) { goto Done; } ALOGW(Poll failed with an unexpected error: %s, strerror(errno)); result POLL_ERROR; goto Done; } // Check for poll timeout. if (eventCount 0) { #if DEBUG_POLL_AND_WAKE ALOGD(%p ~ pollOnce - timeout, this); #endif result POLL_TIMEOUT; goto Done; } // Handle all events. #if DEBUG_POLL_AND_WAKE ALOGD(%p ~ pollOnce - handling events from %d fds, this, eventCount); #endif for (int i 0; i eventCount; i) { const SequenceNumber seq eventItems[i].data.u64; uint32_t epollEvents eventItems[i].events; if (seq WAKE_EVENT_FD_SEQ) { if (epollEvents EPOLLIN) { awoken(); } else { ALOGW(Ignoring unexpected epoll events 0x%x on wake event fd., epollEvents); } } else { const auto request_it mRequests.find(seq); if (request_it ! mRequests.end()) { const auto request request_it-second; int events 0; if (epollEvents EPOLLIN) events | EVENT_INPUT; if (epollEvents EPOLLOUT) events | EVENT_OUTPUT; if (epollEvents EPOLLERR) events | EVENT_ERROR; if (epollEvents EPOLLHUP) events | EVENT_HANGUP; mResponses.push({.seq seq, .events events, .request request}); } else { ALOGW(Ignoring unexpected epoll events 0x%x for sequence number % PRIu64 that is no longer registered., epollEvents, seq); } } } Done: ; // Invoke pending message callbacks. mNextMessageUptime LLONG_MAX; while (mMessageEnvelopes.size() ! 0) { nsecs_t now systemTime(SYSTEM_TIME_MONOTONIC); const MessageEnvelope messageEnvelope mMessageEnvelopes.itemAt(0); if (messageEnvelope.uptime now) { // Remove the envelope from the list. // We keep a strong reference to the handler until the call to handleMessage // finishes. Then we drop it so that the handler can be deleted *before* // we reacquire our lock. { // obtain handler spMessageHandler handler messageEnvelope.handler; Message message messageEnvelope.message; mMessageEnvelopes.removeAt(0); mSendingMessage true; mLock.unlock(); #if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS ALOGD(%p ~ pollOnce - sending message: handler%p, what%d, this, handler.get(), message.what); #endif handler-handleMessage(message); } // release handler mLock.lock(); mSendingMessage false; result POLL_CALLBACK; } else { // The last message left at the head of the queue determines the next wakeup time. mNextMessageUptime messageEnvelope.uptime; break; } } // Release lock. mLock.unlock(); // Invoke all response callbacks. for (size_t i 0; i mResponses.size(); i) { Response response mResponses.editItemAt(i); if (response.request.ident POLL_CALLBACK) { int fd response.request.fd; int events response.events; void* data response.request.data; #if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS ALOGD(%p ~ pollOnce - invoking fd event callback %p: fd%d, events0x%x, data%p, this, response.request.callback.get(), fd, events, data); #endif // Invoke the callback. Note that the file descriptor may be closed by // the callback (and potentially even reused) before the function returns so // we need to be a little careful when removing the file descriptor afterwards. int callbackResult response.request.callback-handleEvent(fd, events, data); if (callbackResult 0) { AutoMutex _l(mLock); removeSequenceNumberLocked(response.seq); } // Clear the callback reference in the response structure promptly because we // will not clear the response vector itself until the next poll. response.request.callback.clear(); result POLL_CALLBACK; } } return result; }