검색결과 리스트
글
안드로이드 프레임워크 프로그래밍(25) [Native 단계에서 Looper의 동작 원리]
SurfaceFlinger의 동작 원리에 대해 좀 더 정확히 이해하기 위해서는 Native 단계에서 Looper의 동작 방식을 파악할 필요가 있습니다. 비록 Looper는 안드로이드의 System Library에 있지만 Native 단계에서의 Framework에서 상당히 중요하므로 간단하게 짚고 넘어가도록 하겠습니다.
Looper란 폴링이 이루어지고 있는 루프(loop)로서 File Discriptor 이벤트를 관찰하는 역할을 하고, 등록된 Callback 함수를 호출하는 역할을 수행하기도 합니다. 실제로 Native 단계에서의 Looper는 UNIX 명령어 집합 epoll() 함수를 사용합니다.
/system/core/libutils/Looper.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | Looper::Looper(bool allowNonCallbacks) : mAllowNonCallbacks(allowNonCallbacks), mSendingMessage(false), mResponseIndex(0), mNextMessageUptime(LLONG_MAX) { int wakeFds[2]; int result = pipe(wakeFds); LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe. errno=%d", errno); mWakeReadPipeFd = wakeFds[0]; mWakeWritePipeFd = wakeFds[1]; result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK); LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake read pipe non-blocking. errno=%d", errno); result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK); LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking. errno=%d", errno); mIdling = false; // Allocate the epoll instance and register the wake pipe. mEpollFd = epoll_create(EPOLL_SIZE_HINT); LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance. errno=%d", errno); struct epoll_event eventItem; memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union eventItem.events = EPOLLIN; eventItem.data.fd = mWakeReadPipeFd; result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, & eventItem); LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake read pipe to epoll instance. errno=%d", errno); } | cs |
Looper 클래스의 생성자 소스코드를 살펴보시면 IPC 함수들이 눈에 띄는 것을 보실 수 있습니다. Looper의 Pipe File Descriptor를 Non-block로 설정되고 있는 모습 또한 확인하실 수 있습니다.
mEpollFd = epoll_create(EPOLL_SIZE_HINT);
Looper에 등록된 File Descriptor를 관리할 epoll 인스턴스를 생성합니다. 인자로 인스턴스의 크기를 설정하며 return 값으로 해당 인스턴스의 FD를 돌려받습니다.
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, & eventItem);
epoll 인스턴스인 mEpollFd에 제어하고자 하는 File Descriptor인 mWakeReadPipeFd를 등록합니다.
위의 과정을 거쳐 등록된 Looper는 이후 외부 이벤트를 통해 File Descriptor를 제어하게 됩니다. Looper가 생성된 이후 부터는 addFd()함수를 통해 File Descriptor가 등록됩니다.
/system/core/include/utils/Looper.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | /** * A looper callback. */ class LooperCallback : public virtual RefBase { protected: virtual ~LooperCallback() { } public: /** * Handles a poll event for the given file descriptor. * It is given the file descriptor it is associated with, * a bitmask of the poll events that were triggered (typically ALOOPER_EVENT_INPUT), * and the data pointer that was originally supplied. * * Implementations should return 1 to continue receiving callbacks, or 0 * to have this file descriptor and callback unregistered from the looper. */ virtual int handleEvent(int fd, int events, void* data) = 0; }; .... /** * A polling loop that supports monitoring file descriptor events, optionally * using callbacks. The implementation uses epoll() internally. * * A looper can be associated with a thread although there is no requirement that it must be. */ class Looper : public ALooper, public RefBase { protected: virtual ~Looper(); .... private: struct Request { int fd; int ident; sp<LooperCallback> callback; void* data; }; struct Response { int events; Request request; }; struct MessageEnvelope { MessageEnvelope() : uptime(0) { } MessageEnvelope(nsecs_t uptime, const sp<MessageHandler> handler, const Message& message) : uptime(uptime), handler(handler), message(message) { } nsecs_t uptime; sp<MessageHandler> handler; Message message; }; const bool mAllowNonCallbacks; // immutable int mWakeReadPipeFd; // immutable int mWakeWritePipeFd; // immutable Mutex mLock; Vector<MessageEnvelope> mMessageEnvelopes; // guarded by mLock bool mSendingMessage; // guarded by mLock // Whether we are currently waiting for work. Not protected by a lock, // any use of it is racy anyway. volatile bool mIdling; int mEpollFd; // immutable // Locked list of file descriptor monitoring requests. KeyedVector<int, Request> mRequests; // guarded by mLock // This state is only used privately by pollOnce and does not require a lock since // it runs on a single thread. Vector<Response> mResponses; size_t mResponseIndex; nsecs_t mNextMessageUptime; // set to LLONG_MAX when none int pollInner(int timeoutMillis); void awoken(); void pushResponse(int events, const Request& request); static void initTLSKey(); static void threadDestructor(void *st); }; | cs |
/system/core/libutils/Looper.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | int Looper::addFd(int fd, int ident, int events, ALooper_callbackFunc callback, void* data) { return addFd(fd, ident, events, callback ? new SimpleLooperCallback(callback) : NULL, data); } int Looper::addFd(int fd, int ident, int events, const sp<LooperCallback>& callback, void* data) { #if DEBUG_CALLBACKS ALOGD("%p ~ addFd - fd=%d, ident=%d, events=0x%x, callback=%p, data=%p", this, fd, ident, events, callback.get(), data); #endif if (!callback.get()) { if (! mAllowNonCallbacks) { ALOGE("Invalid attempt to set NULL callback but not allowed for this looper."); return -1; } if (ident < 0) { ALOGE("Invalid attempt to set NULL callback with ident < 0."); return -1; } } else { ident = ALOOPER_POLL_CALLBACK; } int epollEvents = 0; if (events & ALOOPER_EVENT_INPUT) epollEvents |= EPOLLIN; if (events & ALOOPER_EVENT_OUTPUT) epollEvents |= EPOLLOUT; { // acquire lock AutoMutex _l(mLock); Request request; request.fd = fd; request.ident = ident; request.callback = callback; request.data = data; struct epoll_event eventItem; memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union eventItem.events = epollEvents; eventItem.data.fd = fd; ssize_t requestIndex = mRequests.indexOfKey(fd); if (requestIndex < 0) { int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, & eventItem); if (epollResult < 0) { ALOGE("Error adding epoll events for fd %d, errno=%d", fd, errno); return -1; } mRequests.add(fd, request); } else { int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_MOD, fd, & eventItem); if (epollResult < 0) { ALOGE("Error modifying epoll events for fd %d, errno=%d", fd, errno); return -1; } mRequests.replaceValueAt(requestIndex, request); } } // release lock return 1; } | cs |
Looper 이외의 클래스로부터 File Descriptor를 등록받게 되변 epoll을 통해 해당 File Descriptor를 등록하게 되고 해당 File Descriptor가 epoll에 의해 실행이 요청되었을 때, callback 함수가 동작할 수 있도록 Vector 변수인 mRequests에 등록됩니다.
/system/core/libutils/Looper.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | int Looper::pollInner(int timeoutMillis) { .... struct epoll_event eventItems[EPOLL_MAX_EVENTS]; int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis); // No longer idling. mIdling = false; // Acquire lock. mLock.lock(); // Check for poll error. if (eventCount < 0) { if (errno == EINTR) { goto Done; } ALOGW("Poll failed with an unexpected error, errno=%d", errno); result = ALOOPER_POLL_ERROR; goto Done; } // Check for poll timeout. if (eventCount == 0) { #if DEBUG_POLL_AND_WAKE ALOGD("%p ~ pollOnce - timeout", this); #endif result = ALOOPER_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++) { int fd = eventItems[i].data.fd; uint32_t epollEvents = eventItems[i].events; if (fd == mWakeReadPipeFd) { if (epollEvents & EPOLLIN) { awoken(); } else { ALOGW("Ignoring unexpected epoll events 0x%x on wake read pipe.", epollEvents); } } else { ssize_t requestIndex = mRequests.indexOfKey(fd); if (requestIndex >= 0) { int events = 0; if (epollEvents & EPOLLIN) events |= ALOOPER_EVENT_INPUT; if (epollEvents & EPOLLOUT) events |= ALOOPER_EVENT_OUTPUT; if (epollEvents & EPOLLERR) events |= ALOOPER_EVENT_ERROR; if (epollEvents & EPOLLHUP) events |= ALOOPER_EVENT_HANGUP; pushResponse(events, mRequests.valueAt(requestIndex)); } else { ALOGW("Ignoring unexpected epoll events 0x%x on fd %d that is " "no longer registered.", epollEvents, fd); } } } Done: ; .... } | cs |
Looper에서 pollInner()함수가 호출되면 epoll을 통해 등록되었던 File Descriptor를 통해 이벤트가 들어왔는지 확인한 후 이를 처리하도록 합니다.
int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
epoll에 등록된 File Descriptor 중 파일 읽기가 준비된 FD의 갯수를 return 합니다. 이후 준비된 이벤트를 처리하는 과정을 거치게 됩니다.
awoken();
만약 준비된 File Descriptor가 Looper의 것일 경우 위 함수를 실행합니다.
/system/core/libutils/Looper.cpp
1 2 3 4 5 6 7 8 9 10 11 | void Looper::awoken() { #if DEBUG_POLL_AND_WAKE ALOGD("%p ~ awoken", this); #endif char buffer[16]; ssize_t nRead; do { nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer)); } while ((nRead == -1 && errno == EINTR) || nRead == sizeof(buffer)); } | cs |
pushResponse(events, mRequests.valueAt(requestIndex));
만약 준비된 File Descriptor가 addFd에 의해 등록된 것의 경우 위 함수를 실행합니다.
/system/core/libutils/Looper.cpp
1 2 3 4 5 6 | void Looper::pushResponse(int events, const Request& request) { Response response; response.events = events; response.request = request; mResponses.push(response); } | cs |
위에서 보시는 바와 같이 mResponses에 이벤트가 등록되는 것을 확인하였습니다. 이제 해당 이벤트의 Callback이 호출되는 과정을 살펴보도록 하겠습니다.
/system/core/libutils/Looper.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 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 == ALOOPER_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 int callbackResult = response.request.callback->handleEvent(fd, events, data); if (callbackResult == 0) { removeFd(fd); } // 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 = ALOOPER_POLL_CALLBACK; } } return result; } | cs |
위 함수를 통해 Looper에 등록된 Callback 함수가 실행됨을 확인할 수 있습니다.
'안드로이드 > 프레임워크' 카테고리의 다른 글
안드로이드 프레임워크 프로그래밍(26) [System Service에서 Activity 함수 호출하기] (0) | 2015.10.27 |
---|---|
Android에서 VSync 동작 원리 및 초기화 과정(5) (0) | 2015.09.20 |
SurfaceFlinger에서 DispSyncSource의 초기화 과정 (0) | 2015.09.12 |
SurfaceFlinger의 초기화 과정 흐름도 (0) | 2015.09.09 |
SurfaceFlinger에서 EventThread의 초기화 과정 (1) | 2015.09.08 |
설정
트랙백
댓글
글
SurfaceFlinger에서 DispSyncSource의 초기화 과정
DisplaySyncSource 클래스는 SurfaceFlinger.cpp 내에 소스코드가 존재합니다. 이는 이후 안드로이드의 VSync(수직동기화)를 수행하기 위해 따로 만들어지는 EventThread에서 적합하게 사용될 수 있도록 설계되어 있습니다. 전반적인 소스코드를 분석해 보도록 하겠습니다.
/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
1 2 3 4 5 6 7 8 9 10 11 | // start the EventThread sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync, vsyncPhaseOffsetNs, true); mEventThread = new EventThread(vsyncSrc); sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync, sfVsyncPhaseOffsetNs, false); mSFEventThread = new EventThread(sfVsyncSrc); mEventQueue.setEventThread(mSFEventThread); mEventControlThread = new EventControlThread(this); mEventControlThread->run("EventControl", PRIORITY_URGENT_DISPLAY); | cs |
위의 DispSyncSource 생성자 내의 mPrimaryDispSync 변수는 DispSync 클래스의 변수입니다. DispSync 클래스에 대해 자세히 알고 싶으신 분은 아래 포스팅을 참조해 주시기 바랍니다.
Android에서 VSync 동작 원리 및 초기화 과정(3)
위의 소스코드를 통해 DisySyncSource 클래스가 VSync를 수행하기 위한 Thread를 위해 실행되고 있는 것을 알 수 있습니다. 위에서 생성되고 있는 DispSyncSource 클래스를 살펴보도록 하겠습니다.
1 2 3 4 5 6 7 8 9 10 11 12 | class VSyncSource : public virtual RefBase { public: class Callback: public virtual RefBase { public: virtual ~Callback() {} virtual void onVSyncEvent(nsecs_t when) = 0; }; virtual ~VSyncSource() {} virtual void setVSyncEnabled(bool enable) = 0; virtual void setCallback(const sp<Callback>& callback) = 0; }; | cs |
/frameworks/native/services/surfaceflinger/DispSync.h
1 2 3 4 5 6 7 8 9 10 11 12 13 | class DispSync { public: class Callback: public virtual RefBase { public: virtual ~Callback() {}; virtual void onDispSyncEvent(nsecs_t when) = 0; }; .... } | cs |
/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | class DispSyncSource : public VSyncSource, private DispSync::Callback { public: DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync) : mValue(0), mPhaseOffset(phaseOffset), mTraceVsync(traceVsync), mDispSync(dispSync) {} virtual ~DispSyncSource() {} virtual void setVSyncEnabled(bool enable) { // Do NOT lock the mutex here so as to avoid any mutex ordering issues // with locking it in the onDispSyncEvent callback. if (enable) { status_t err = mDispSync->addEventListener(mPhaseOffset, static_cast<DispSync::Callback*>(this)); if (err != NO_ERROR) { ALOGE("error registering vsync callback: %s (%d)", strerror(-err), err); } ATRACE_INT("VsyncOn", 1); } else { status_t err = mDispSync->removeEventListener( static_cast<DispSync::Callback*>(this)); if (err != NO_ERROR) { ALOGE("error unregistering vsync callback: %s (%d)", strerror(-err), err); } ATRACE_INT("VsyncOn", 0); } } virtual void setCallback(const sp<VSyncSource::Callback>& callback) { Mutex::Autolock lock(mMutex); mCallback = callback; } private: virtual void onDispSyncEvent(nsecs_t when) { sp<VSyncSource::Callback> callback; { Mutex::Autolock lock(mMutex); callback = mCallback; if (mTraceVsync) { mValue = (mValue + 1) % 2; ATRACE_INT("VSYNC", mValue); } } if (callback != NULL) { callback->onVSyncEvent(when); } } int mValue; const nsecs_t mPhaseOffset; const bool mTraceVsync; DispSync* mDispSync; sp<VSyncSource::Callback> mCallback; Mutex mMutex; }; | cs |
위 과정을 거쳐 이후 EventThread를 통해 해당 내용들이 등록되게 됩니다. EventThread에 대한 자세한 사항은 아래 포스팅을 참조해 주시기 바랍니다.
SurfaceFlinger에서 EventThread의 초기화 과정
이후 EventThread가 초기화가 이루어진 후 waitForEvent() 함수가 호출됩니다. 이 때, 해당 함수 내에 있는 enableVSyncLocked() 함수가 실행되면 DispSyncSource에 Callback이 등록됩니다.
/frameworks/native/services/surfaceflinger/EventThread.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | // This will return when (1) a vsync event has been received, and (2) there was // at least one connection interested in receiving it when we started waiting. Vector< sp<EventThread::Connection> > EventThread::waitForEvent( DisplayEventReceiver::Event* event) { Mutex::Autolock _l(mLock); Vector< sp<EventThread::Connection> > signalConnections; do { .... // Here we figure out if we need to enable or disable vsyncs if (timestamp && !waitForVSync) { // we received a VSYNC but we have no clients // don't report it, and disable VSYNC events disableVSyncLocked(); } else if (!timestamp && waitForVSync) { // we have at least one client, so we want vsync enabled // (TODO: this function is called right after we finish // notifying clients of a vsync, so this call will be made // at the vsync rate, e.g. 60fps. If we can accurately // track the current state we could avoid making this call // so often.) enableVSyncLocked(); .... } .... void EventThread::enableVSyncLocked() { if (!mUseSoftwareVSync) { // never enable h/w VSYNC when screen is off if (!mVsyncEnabled) { mVsyncEnabled = true; mVSyncSource->setCallback(static_cast<VSyncSource::Callback*>(this)); mVSyncSource->setVSyncEnabled(true); mPowerHAL.vsyncHint(true); } } mDebugVsyncEnabled = true; } | cs |
/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
1 2 3 4 | virtual void setCallback(const sp<VSyncSource::Callback>& callback) { Mutex::Autolock lock(mMutex); mCallback = callback; } | cs |
위 과정을 통하여 VSyncSource에 callback 함수가 등록됩니다. 해당 callback 함수는 아래와 같습니다.
/frameworks/native/services/surfaceflinger/EventThread.h
1 2 3 4 5 6 7 8 9 10 11 12 | class VSyncSource : public virtual RefBase { public: class Callback: public virtual RefBase { public: virtual ~Callback() {} virtual void onVSyncEvent(nsecs_t when) = 0; }; virtual ~VSyncSource() {} virtual void setVSyncEnabled(bool enable) = 0; virtual void setCallback(const sp<Callback>& callback) = 0; }; | cs |
/frameworks/native/services/surfaceflinger/EventThread.cpp
1 2 3 4 5 6 7 8 | void EventThread::onVSyncEvent(nsecs_t timestamp) { Mutex::Autolock _l(mLock); mVSyncEvent[0].header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC; mVSyncEvent[0].header.id = 0; mVSyncEvent[0].header.timestamp = timestamp; mVSyncEvent[0].vsync.count++; mCondition.broadcast(); } | cs |
Callback이 등록된 후 setVSyncEnable() 함수를 통해 DispSync Thread에 Listener를 등록합니다.
/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | virtual void setVSyncEnabled(bool enable) { // Do NOT lock the mutex here so as to avoid any mutex ordering issues // with locking it in the onDispSyncEvent callback. if (enable) { status_t err = mDispSync->addEventListener(mPhaseOffset, static_cast<DispSync::Callback*>(this)); if (err != NO_ERROR) { ALOGE("error registering vsync callback: %s (%d)", strerror(-err), err); } ATRACE_INT("VsyncOn", 1); } else { status_t err = mDispSync->removeEventListener( static_cast<DispSync::Callback*>(this)); if (err != NO_ERROR) { ALOGE("error unregistering vsync callback: %s (%d)", strerror(-err), err); } ATRACE_INT("VsyncOn", 0); } } | cs |
위의 과정을 통해 DisySync 클래스의 addEventListener()함수를 통해 DisySync의 callback 함수가 등록되는 것을 보실 수 있습니다. 소스코드는 다음과 같습니다.
/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | virtual void onDispSyncEvent(nsecs_t when) { sp<VSyncSource::Callback> callback; { Mutex::Autolock lock(mMutex); callback = mCallback; if (mTraceVsync) { mValue = (mValue + 1) % 2; ATRACE_INT("VSYNC", mValue); } } if (callback != NULL) { callback->onVSyncEvent(when); } } | cs |
1 2 3 4 5 6 | status_t DispSync::addEventListener(nsecs_t phase, const sp<Callback>& callback) { Mutex::Autolock lock(mMutex); return mThread->addEventListener(phase, callback); } | cs |
위의 소스코드를 통해 DispSyncThread에 Event가 등록되는 것을 확인하실 수 있습니다.
/frameworks/native/services/surfaceflinger/DispSync.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | class DispSyncThread: public Thread { .... status_t addEventListener(nsecs_t phase, const sp<DispSync::Callback>& callback) { Mutex::Autolock lock(mMutex); for (size_t i = 0; i < mEventListeners.size(); i++) { if (mEventListeners[i].mCallback == callback) { return BAD_VALUE; } } EventListener listener; listener.mPhase = phase; listener.mCallback = callback; // We want to allow the firstmost future event to fire without // allowing any past events to fire. Because // computeListenerNextEventTimeLocked filters out events within a half // a period of the last event time, we need to initialize the last // event time to a half a period in the past. listener.mLastEventTime = systemTime(SYSTEM_TIME_MONOTONIC) - mPeriod / 2; mEventListeners.push(listener); mCond.signal(); return NO_ERROR; } .... } | cs |
DispSync에 등록된 이벤트들은 이후 DispSyncThread에서 VSync 이벤트 Callback 발생시 실행됩니다.
/frameworks/native/services/surfaceflinger/DispSync.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | class DispSyncThread: public Thread { .... Vector<CallbackInvocation> gatherCallbackInvocationsLocked(nsecs_t now) { Vector<CallbackInvocation> callbackInvocations; nsecs_t ref = now - mPeriod; for (size_t i = 0; i < mEventListeners.size(); i++) { nsecs_t t = computeListenerNextEventTimeLocked(mEventListeners[i], ref); if (t < now) { CallbackInvocation ci; ci.mCallback = mEventListeners[i].mCallback; ci.mEventTime = t; callbackInvocations.push(ci); mEventListeners.editItemAt(i).mLastEventTime = t; } } return callbackInvocations; } .... void fireCallbackInvocations(const Vector<CallbackInvocation>& callbacks) { for (size_t i = 0; i < callbacks.size(); i++) { callbacks[i].mCallback->onDispSyncEvent(callbacks[i].mEventTime); } } .... } | cs |
위의 과정을 거쳐 EventThread의 Callback 함수를 수행하게 되면 broadcast()함수에 의해 EventThread 내의 Thread들이 모두 깨어나게 됩니다. 이는 이후 postEvent() 함수를 호출하게 됩니다.
'안드로이드 > 프레임워크' 카테고리의 다른 글
Android에서 VSync 동작 원리 및 초기화 과정(5) (0) | 2015.09.20 |
---|---|
안드로이드 프레임워크 프로그래밍(25) [Native 단계에서 Looper의 동작 원리] (0) | 2015.09.16 |
SurfaceFlinger의 초기화 과정 흐름도 (0) | 2015.09.09 |
SurfaceFlinger에서 EventThread의 초기화 과정 (1) | 2015.09.08 |
안드로이드 프레임워크 프로그래밍(24) [BitTube 클래스] (2) | 2015.09.06 |
설정
트랙백
댓글
글
SurfaceFlinger의 초기화 과정 흐름도
※이 흐름도는 Android 4.4.4 r2 kitkat을 기준으로 만들어진 흐름도입니다.
'안드로이드 > 프레임워크' 카테고리의 다른 글
안드로이드 프레임워크 프로그래밍(25) [Native 단계에서 Looper의 동작 원리] (0) | 2015.09.16 |
---|---|
SurfaceFlinger에서 DispSyncSource의 초기화 과정 (0) | 2015.09.12 |
SurfaceFlinger에서 EventThread의 초기화 과정 (1) | 2015.09.08 |
안드로이드 프레임워크 프로그래밍(24) [BitTube 클래스] (2) | 2015.09.06 |
안드로이드 프레임워크 프로그래밍(23) [onFirstRef() 함수 호출시기] (0) | 2015.09.03 |