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, "can't 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.cpp
AChoreographer.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); }sp<Choreographer> Choreographer::getForThread() { if (gChoreographer == nullptr) { sp<Looper> looper = Looper::getForThread(); if (!looper.get()) { ALOGW("No looper prepared for thread"); return nullptr; } gChoreographer = sp<Choreographer>::make(looper); status_t result = gChoreographer->initialize(); if (result != OK) { ALOGW("Failed to initialize"); return nullptr; } } return gChoreographer; }三、Choreographer.cpp
Choreographer类需要Looper去构造,并且继承了类DisplayEventDispatcher。
class Choreographer : public DisplayEventDispatcher, public MessageHandler { public: struct Context { std::mutex lock; std::vector<Choreographer*> ptrs GUARDED_BY(lock); std::map<AVsyncId, int64_t> startTimes GUARDED_BY(lock); bool registeredToDisplayManager GUARDED_BY(lock) = false; std::atomic<nsecs_t> mLastKnownVsync = -1; }; static Context gChoreographers; explicit Choreographer(const sp<Looper>& looper, const sp<IBinder>& 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 sp<Looper>& looper, gui::ISurfaceComposer::VsyncSource vsyncSource = gui::ISurfaceComposer::VsyncSource::eVsyncSourceApp, EventRegistrationFlags eventRegistration = {}, const sp<IBinder>& layerHandle = nullptr); friend class sp<DisplayEventDispatcher>; virtual ~DisplayEventDispatcher() = default; private: sp<Looper> 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实现的handleEvent
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; } } } }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, events=0x%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, events=0x%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. " "events=0x%x", events); return 0; // remove the callback } if (!(events & Looper::EVENT_INPUT)) { ALOGW("Received spurious callback for unhandled poll event. " "events=0x%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::vector<FrameCallback> animationCallbacks{}; std::vector<FrameCallback> inputCallbacks{}; { std::lock_guard<std::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::vector<FrameCallback>& 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_cast<const 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, events=0x%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 sp<MessageHandler> 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, events=0x%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; }