검색결과 리스트
글
안드로이드 프레임워크 프로그래밍(24) [BitTube 클래스]
안드로이드 Native Framework에 대한 분석을 계속 진행을 하다보니 어느덧 linux 기반의 시스템프로그래밍에 대한 지식이 많이 필요하더군요. 종종 튀어나오는 unix 명령어들을 보면 반가우면서도 한편으로는 동작 원리를 다시 살펴보는 제 모습을 보게 됩니다.
이번 포스팅에서는 Native Framework 단계에서 프로세스간 통신 기능을 보조해주는 BitTube에 대해 알아보도록 하겠습니다.
/frameworks/native/services/surfaceflinger/EventThread.cpp
1 2 3 4 5 | EventThread::Connection::Connection( const sp<EventThread>& eventThread) : count(-1), mEventThread(eventThread), mChannel(new BitTube()) { } | cs |
위 소스코드를 보시면 BitTube라는 이름의 클래스가 새로 만들어지고 있는 것을 보실 수 있습니다. BitTube는 안드로이드 상에서 unix 소켓 프로그래밍을 쓰기 쉽게 만들어진 클래스 입니다. BitTube 클래스의 내부를 살펴보신다면 이전에 시스템 프로그래밍에 대해 공부하신 분들이라면 익숙한 함수들을 만나보실 수 있을 것입니다.
/frameworks/native/include/gui/BitTube.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 | class Parcel; class BitTube : public RefBase { public: // creates a BitTube with a default (4KB) send buffer BitTube(); // creates a BitTube with a a specified send and receive buffer size explicit BitTube(size_t bufsize); explicit BitTube(const Parcel& data); virtual ~BitTube(); // check state after construction status_t initCheck() const; // get receive file-descriptor int getFd() const; // send objects (sized blobs). All objects are guaranteed to be written or the call fails. template <typename T> static ssize_t sendObjects(const sp<BitTube>& tube, T const* events, size_t count) { return sendObjects(tube, events, count, sizeof(T)); } // receive objects (sized blobs). If the receiving buffer isn't large enough, // excess messages are silently discarded. template <typename T> static ssize_t recvObjects(const sp<BitTube>& tube, T* events, size_t count) { return recvObjects(tube, events, count, sizeof(T)); } // parcels this BitTube status_t writeToParcel(Parcel* reply) const; private: void init(size_t rcvbuf, size_t sndbuf); // send a message. The write is guaranteed to send the whole message or fail. ssize_t write(void const* vaddr, size_t size); // receive a message. the passed buffer must be at least as large as the // write call used to send the message, excess data is silently discarded. ssize_t read(void* vaddr, size_t size); int mSendFd; mutable int mReceiveFd; static ssize_t sendObjects(const sp<BitTube>& tube, void const* events, size_t count, size_t objSize); static ssize_t recvObjects(const sp<BitTube>& tube, void* events, size_t count, size_t objSize); }; | cs |
BitTube의 기능을 전반적으로 보여드리기 위해 BitTube의 헤더파일을 모두 살펴보았습니다. 위 소스코드를 살펴보신다면 BitTube 클래스가 어떠한 동작으로 움직이는 어느 정도 감이 오실 것입니다. 여기서 BitTube의 생성자를 보도록 합시다.
/frameworks/native/libs/gui/BitTube.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 | // Socket buffer size. The default is typically about 128KB, which is much larger than // we really need. So we make it smaller. static const size_t DEFAULT_SOCKET_BUFFER_SIZE = 4 * 1024; BitTube::BitTube() : mSendFd(-1), mReceiveFd(-1) { init(DEFAULT_SOCKET_BUFFER_SIZE, DEFAULT_SOCKET_BUFFER_SIZE); } .... void BitTube::init(size_t rcvbuf, size_t sndbuf) { int sockets[2]; if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets) == 0) { size_t size = DEFAULT_SOCKET_BUFFER_SIZE; setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf)); setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf)); // sine we don't use the "return channel", we keep it small... setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)); setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)); fcntl(sockets[0], F_SETFL, O_NONBLOCK); fcntl(sockets[1], F_SETFL, O_NONBLOCK); mReceiveFd = sockets[0]; mSendFd = sockets[1]; } else { mReceiveFd = -errno; ALOGE("BitTube: pipe creation failed (%s)", strerror(-mReceiveFd)); } } | cs |
BitTube 클래스가 생성되면 BitTube를 생성한 해당 프로세스의 File Discriptor가 만들어집니다. 이후 해당 FD를 BitTube 클래스가 관리해주며 프로세스는 BitTube를 통해 다른 프로세서로부터 값을 받아오거나 보낼 수 있게 됩니다. 위의 함수들은 unix 표준 함수이므로 관련 자료를 쉽게 구하실 수 있을 것입니다.
/frameworks/native/libs/gui/BitTube.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 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | status_t BitTube::initCheck() const { if (mReceiveFd < 0) { return status_t(mReceiveFd); } return NO_ERROR; } int BitTube::getFd() const { return mReceiveFd; } ssize_t BitTube::write(void const* vaddr, size_t size) { ssize_t err, len; do { len = ::send(mSendFd, vaddr, size, MSG_DONTWAIT | MSG_NOSIGNAL); // cannot return less than size, since we're using SOCK_SEQPACKET err = len < 0 ? errno : 0; } while (err == EINTR); return err == 0 ? len : -err; } ssize_t BitTube::read(void* vaddr, size_t size) { ssize_t err, len; do { len = ::recv(mReceiveFd, vaddr, size, MSG_DONTWAIT); err = len < 0 ? errno : 0; } while (err == EINTR); if (err == EAGAIN || err == EWOULDBLOCK) { // EAGAIN means that we have non-blocking I/O but there was // no data to be read. Nothing the client should care about. return 0; } return err == 0 ? len : -err; } status_t BitTube::writeToParcel(Parcel* reply) const { if (mReceiveFd < 0) return -EINVAL; status_t result = reply->writeDupFileDescriptor(mReceiveFd); close(mReceiveFd); mReceiveFd = -1; return result; } ssize_t BitTube::sendObjects(const sp<BitTube>& tube, void const* events, size_t count, size_t objSize) { const char* vaddr = reinterpret_cast<const char*>(events); ssize_t size = tube->write(vaddr, count*objSize); // should never happen because of SOCK_SEQPACKET LOG_ALWAYS_FATAL_IF((size >= 0) && (size % objSize), "BitTube::sendObjects(count=%d, size=%d), res=%d (partial events were sent!)", count, objSize, size); //ALOGE_IF(size<0, "error %d sending %d events", size, count); return size < 0 ? size : size / objSize; } ssize_t BitTube::recvObjects(const sp<BitTube>& tube, void* events, size_t count, size_t objSize) { char* vaddr = reinterpret_cast<char*>(events); ssize_t size = tube->read(vaddr, count*objSize); // should never happen because of SOCK_SEQPACKET LOG_ALWAYS_FATAL_IF((size >= 0) && (size % objSize), "BitTube::recvObjects(count=%d, size=%d), res=%d (partial events were received!)", count, objSize, size); //ALOGE_IF(size<0, "error %d receiving %d events", size, count); return size < 0 ? size : size / objSize; } | cs |
'안드로이드 > 프레임워크' 카테고리의 다른 글
SurfaceFlinger의 초기화 과정 흐름도 (0) | 2015.09.09 |
---|---|
SurfaceFlinger에서 EventThread의 초기화 과정 (1) | 2015.09.08 |
안드로이드 프레임워크 프로그래밍(23) [onFirstRef() 함수 호출시기] (0) | 2015.09.03 |
Android에서 VSync 동작 원리 및 초기화 과정(4) (5) | 2015.09.02 |
Android에서 VSync 동작 원리 및 초기화 과정(3) (0) | 2015.08.31 |
설정
트랙백
댓글
글
안드로이드 프레임워크 프로그래밍(23) [onFirstRef() 함수 호출시기]
안드로이드 Native 단계에서의 Framework를 분석해 보던 도중 의문이 들었던 함수가 하나 있었습니다.
/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
1 2 3 4 | void SurfaceFlinger::onFirstRef() { mEventQueue.init(this); } | cs |
표면적으로 보았을 때 onFirstRef() 함수를 바로 호출하는 부분을 해당 부분을 실행하는 소스코드 내에서 바로 찾아내기는 어렵습니다. 그렇다면 위 함수 onFirstRef()가 어느 시점에서 호출이 되는지 살펴보도록 하겠습니다.
먼저 SurfaceFlinger가 처음 생성되는 부분에서부터 추적해 나가도록 해보겠습니다.
/frameworks/native/services/surfaceflinger/main_surfaceflinger.cpp
1 2 3 4 5 6 7 8 9 10 | int main(int argc, char** argv) { .... // instantiate surfaceflinger sp<SurfaceFlinger> flinger = new SurfaceFlinger(); .... } | cs |
위 함수 onFirstRef()의 호출 시점을 파악하기 위해 Strong Pointer를 분석해 볼 필요가 있습니다. Strong Pointer에 대해 분석한 이전 포스팅에 대한 내용은 아래 링크를 참조해 주시기 바랍니다.
여기서 바로 StrongPointer에 SurfaceFlinger가 적용되는 코드를 보도록 하겠습니다.
/system/core/include/utils/StrongPointer.h
1 2 3 4 5 6 7 8 9 10 11 12 13 | template<typename T> sp<T>::sp(T* other) : m_ptr(other) { if (other) other->incStrong(this); } template<typename T> sp<T>::sp(const sp<T>& other) : m_ptr(other.m_ptr) { if (m_ptr) m_ptr->incStrong(this); } | cs |
Strong Pointer가 생성될 때 해당 포인터를 받게 되면 해당 포인터의 incStrong() 함수를 실행하게 됩니다. 여기서 incStrong() 함수를 찾아보도록 하겠습니다.
/frameworks/native/services/surfaceflinger/main_surfaceflinger.h
1 2 3 4 5 6 7 8 | class SurfaceFlinger : public BnSurfaceComposer, private IBinder::DeathRecipient, private HWComposer::EventHandler { .... }; | cs |
/frameworks/native/include/gui/ISurfaceComposer.h
1 2 3 4 5 6 | class BnSurfaceComposer: public BnInterface<ISurfaceComposer> { public: .... }; | cs |
/frameworks/native/include/binder/IInterface.h
1 2 3 4 5 6 7 8 9 10 | template<typename INTERFACE> class BnInterface : public INTERFACE, public BBinder { public: virtual sp<IInterface> queryLocalInterface(const String16& _descriptor); virtual const String16& getInterfaceDescriptor() const; protected: virtual IBinder* onAsBinder(); }; | cs |
/frameworks/native/include/binder/Binder.h
1 2 3 4 5 6 | class BBinder : public IBinder { .... }; | cs |
/frameworks/native/include/binder/IBinder.h
1 2 3 4 5 6 | class IBinder : public virtual RefBase { .... }; | cs |
/system/core/include/utils/RefBase.h
1 2 3 4 5 6 7 8 | class RefBase { public: void incStrong(const void* id) const; .... } | cs |
안드로이드 Native 클래스들의 토대라 할 수 있는 RefBase 클래스 내에 incStrong()함수가 존재하는 것을 확인하였습니다. 이제 해당 함수의 소스코드를 살펴보도록 합시다.
/system/core/libutils/RefBase.cpp
1 2 3 4 | RefBase::RefBase() : mRefs(new weakref_impl(this)) { } | cs |
/system/core/libutils/RefBase.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 | class RefBase::weakref_impl : public RefBase::weakref_type { public: volatile int32_t mStrong; volatile int32_t mWeak; RefBase* const mBase; volatile int32_t mFlags; .... weakref_impl(RefBase* base) : mStrong(INITIAL_STRONG_VALUE) , mWeak(0) , mBase(base) , mFlags(0) , mStrongRefs(NULL) , mWeakRefs(NULL) , mTrackEnabled(!!DEBUG_REFS_ENABLED_BY_DEFAULT) , mRetain(false) { } .... } | cs |
/system/core/libutils/RefBase.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | #include <utils/RefBase.h> ... void RefBase::incStrong(const void* id) const { weakref_impl* const refs = mRefs; refs->incWeak(id); refs->addStrongRef(id); const int32_t c = android_atomic_inc(&refs->mStrong); ALOG_ASSERT(c > 0, "incStrong() called on %p after last strong ref", refs); #if PRINT_REFS ALOGD("incStrong of %p from %p: cnt=%d\n", this, id, c); #endif if (c != INITIAL_STRONG_VALUE) { return; } android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong); refs->mBase->onFirstRef(); } | cs |
위의 RefBase 단계에서의 incStrong() 함수가 호출될 때 onFirstRef()함수가 호출되는 것을 확인하실 수 있습니다.
'안드로이드 > 프레임워크' 카테고리의 다른 글
SurfaceFlinger에서 EventThread의 초기화 과정 (1) | 2015.09.08 |
---|---|
안드로이드 프레임워크 프로그래밍(24) [BitTube 클래스] (2) | 2015.09.06 |
Android에서 VSync 동작 원리 및 초기화 과정(4) (5) | 2015.09.02 |
Android에서 VSync 동작 원리 및 초기화 과정(3) (0) | 2015.08.31 |
Android에서 VSync 동작 원리 및 초기화 과정(2) (0) | 2015.08.30 |
설정
트랙백
댓글
글
Android에서 VSync 동작 원리 및 초기화 과정(4)
이번 포스팅에서는 Java Framework 단계에서 초기화 되는 과정에서 VSync 관련 동작이 Native 단계와 연결되는 과정을 살펴보도록 하겠습니다.
Java 단계에서 안드로이드 기반 디바이스의 화면을 관리하는 클래스로 Choreographer가 있습니다. 이 클래스는 화면의 변화나 입력등을 통해 그려지는 타이밍을 관리합니다. Choreographer는 디스플레이의 부속시스템으로부터 전달되는 VSync(Vertical Synchronization)와 같은 신호를 수신하고, 다음 디스플레이 프레임을 렌더링 하기 위해 작업을 스케줄링 합니다.
그렇다면 이제 Choreographer가 초기화 되는 과정을 살펴보도록 하겠습니다.
/frameworks/base/core/java/android/view/Choreographer.java
1 2 3 4 5 6 7 8 9 10 11 12 | // Thread local storage for the choreographer. private static final ThreadLocal<Choreographer> sThreadInstance = new ThreadLocal<Choreographer>() { @Override protected Choreographer initialValue() { Looper looper = Looper.myLooper(); if (looper == null) { throw new IllegalStateException("The current thread must have a looper!"); } return new Choreographer(looper); } }; | cs |
ThreadLocal을 통하여 Choreographer 값을 thread에 저장합니다. static으로 선언되어 있으므로 sThreadInstance의 값이 초기화 되면서 return 값인 new Choreographer()가 실행됩니다.
/frameworks/base/core/java/android/view/Choreographer.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | // Enable/disable vsync for animations and drawing. private static final boolean USE_VSYNC = SystemProperties.getBoolean( "debug.choreographer.vsync", true); .... private Choreographer(Looper looper) { mLooper = looper; mHandler = new FrameHandler(looper); mDisplayEventReceiver = USE_VSYNC ? new FrameDisplayEventReceiver(looper) : null; mLastFrameTimeNanos = Long.MIN_VALUE; mFrameIntervalNanos = (long)(1000000000 / getRefreshRate()); mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1]; for (int i = 0; i <= CALLBACK_LAST; i++) { mCallbackQueues[i] = new CallbackQueue(); } } | cs |
Choreographer의 Constructor가 생성되고 있습니다. VSync를 사용하고 있으므로 FrameDisplayEventReceiver()의 Constructor가 새로 생성됨을 확인하실 수 있습니다.
/frameworks/base/core/java/android/view/Choreographer.java
1 2 3 4 5 6 7 8 9 10 11 12 13 | private final class FrameDisplayEventReceiver extends DisplayEventReceiver implements Runnable { private boolean mHavePendingVsync; private long mTimestampNanos; private int mFrame; public FrameDisplayEventReceiver(Looper looper) { super(looper); } .... } | cs |
/frameworks/base/core/java/android/view/DisplayEventReceiver.java
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 | /** * Provides a low-level mechanism for an application to receive display events * such as vertical sync. * * The display event receive is NOT thread safe. Moreover, its methods must only * be called on the Looper thread to which it is attached. * * @hide */ public abstract class DisplayEventReceiver { private static final String TAG = "DisplayEventReceiver"; private final CloseGuard mCloseGuard = CloseGuard.get(); private int mReceiverPtr; // We keep a reference message queue object here so that it is not // GC'd while the native peer of the receiver is using them. private MessageQueue mMessageQueue; private static native int nativeInit(DisplayEventReceiver receiver, MessageQueue messageQueue); private static native void nativeDispose(int receiverPtr); private static native void nativeScheduleVsync(int receiverPtr); /** * Creates a display event receiver. * * @param looper The looper to use when invoking callbacks. */ public DisplayEventReceiver(Looper looper) { if (looper == null) { throw new IllegalArgumentException("looper must not be null"); } mMessageQueue = looper.getQueue(); mReceiverPtr = nativeInit(this, mMessageQueue); mCloseGuard.open("dispose"); } .... } | cs |
위 소스코드를 통해 DisplayEventReceiver 클래스에서 nativeInit를 통해 JNI로 연결되는 것을 보실 수 있습니다.
/frameworks/base/core/jni/android_view_DisplayEventReceiver.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | static jint nativeInit(JNIEnv* env, jclass clazz, jobject receiverObj, jobject messageQueueObj) { sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj); if (messageQueue == NULL) { jniThrowRuntimeException(env, "MessageQueue is not initialized."); return 0; } sp<NativeDisplayEventReceiver> receiver = new NativeDisplayEventReceiver(env, receiverObj, messageQueue); status_t status = receiver->initialize(); if (status) { String8 message; message.appendFormat("Failed to initialize display event receiver. status=%d", status); jniThrowRuntimeException(env, message.string()); return 0; } receiver->incStrong(gDisplayEventReceiverClassInfo.clazz); // retain a reference for the object return reinterpret_cast<jint>(receiver.get()); } | cs |
NativeDisplayEventReceiver클래스의 Constructor가 생성된 후 initialize() 함수가 호출되고 있는 모습입니다.
/frameworks/base/core/jni/android_view_DisplayEventReceiver.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 | class NativeDisplayEventReceiver : public LooperCallback { public: NativeDisplayEventReceiver(JNIEnv* env, jobject receiverObj, const sp<MessageQueue>& messageQueue); status_t initialize(); void dispose(); status_t scheduleVsync(); protected: virtual ~NativeDisplayEventReceiver(); private: jobject mReceiverObjGlobal; sp<MessageQueue> mMessageQueue; DisplayEventReceiver mReceiver; bool mWaitingForVsync; virtual int handleEvent(int receiveFd, int events, void* data); bool processPendingEvents(nsecs_t* outTimestamp, int32_t* id, uint32_t* outCount); void dispatchVsync(nsecs_t timestamp, int32_t id, uint32_t count); void dispatchHotplug(nsecs_t timestamp, int32_t id, bool connected); }; NativeDisplayEventReceiver::NativeDisplayEventReceiver(JNIEnv* env, jobject receiverObj, const sp<MessageQueue>& messageQueue) : mReceiverObjGlobal(env->NewGlobalRef(receiverObj)), mMessageQueue(messageQueue), mWaitingForVsync(false) { ALOGV("receiver %p ~ Initializing input event receiver.", this); } NativeDisplayEventReceiver::~NativeDisplayEventReceiver() { JNIEnv* env = AndroidRuntime::getJNIEnv(); env->DeleteGlobalRef(mReceiverObjGlobal); } status_t NativeDisplayEventReceiver::initialize() { status_t result = mReceiver.initCheck(); if (result) { ALOGW("Failed to initialize display event receiver, status=%d", result); return result; } int rc = mMessageQueue->getLooper()->addFd(mReceiver.getFd(), 0, ALOOPER_EVENT_INPUT, this, NULL); if (rc < 0) { return UNKNOWN_ERROR; } return OK; } | cs |
위의 과정을 보았을 때 MessageQueue 내에 들어있는 Looper를 얻어낸 후 addFd() 함수를 통해 DisplayEventReceiver의 File Description이 등록됩니다. NativeDisplayEventReceiver 내에 있는 mReceiver는 DisplayEventReceiver의 클래스 변스로 해당 클래스의 소스코드를 살펴보도록 하겠습니다.
/frameworks/native/include/gui/DisplayEventReceiver.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 91 92 93 | class DisplayEventReceiver { public: enum { DISPLAY_EVENT_VSYNC = 'vsyn', DISPLAY_EVENT_HOTPLUG = 'plug' }; struct Event { struct Header { uint32_t type; uint32_t id; nsecs_t timestamp; }; struct VSync { uint32_t count; }; struct Hotplug { bool connected; }; Header header; union { VSync vsync; Hotplug hotplug; }; }; public: /* * DisplayEventReceiver creates and registers an event connection with * SurfaceFlinger. VSync events are disabled by default. Call setVSyncRate * or requestNextVsync to receive them. * Other events start being delivered immediately. */ DisplayEventReceiver(); /* * ~DisplayEventReceiver severs the connection with SurfaceFlinger, new events * stop being delivered immediately. Note that the queue could have * some events pending. These will be delivered. */ ~DisplayEventReceiver(); /* * initCheck returns the state of DisplayEventReceiver after construction. */ status_t initCheck() const; /* * getFd returns the file descriptor to use to receive events. * OWNERSHIP IS RETAINED by DisplayEventReceiver. DO NOT CLOSE this * file-descriptor. */ int getFd() const; /* * getEvents reads events from the queue and returns how many events were * read. Returns 0 if there are no more events or a negative error code. * If NOT_ENOUGH_DATA is returned, the object has become invalid forever, it * should be destroyed and getEvents() shouldn't be called again. */ ssize_t getEvents(Event* events, size_t count); static ssize_t getEvents(const sp<BitTube>& dataChannel, Event* events, size_t count); /* * sendEvents write events to the queue and returns how many events were * written. */ static ssize_t sendEvents(const sp<BitTube>& dataChannel, Event const* events, size_t count); /* * setVsyncRate() sets the Event::VSync delivery rate. A value of * 1 returns every Event::VSync. A value of 2 returns every other event, * etc... a value of 0 returns no event unless requestNextVsync() has * been called. */ status_t setVsyncRate(uint32_t count); /* * requestNextVsync() schedules the next Event::VSync. It has no effect * if the vsync rate is > 0. */ status_t requestNextVsync(); private: sp<IDisplayEventConnection> mEventConnection; sp<BitTube> mDataChannel; }; | cs |
/frameworks/native/libs/gui/DisplayEventReceiver.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 | DisplayEventReceiver::DisplayEventReceiver() { sp<ISurfaceComposer> sf(ComposerService::getComposerService()); if (sf != NULL) { mEventConnection = sf->createDisplayEventConnection(); if (mEventConnection != NULL) { mDataChannel = mEventConnection->getDataChannel(); } } } DisplayEventReceiver::~DisplayEventReceiver() { } status_t DisplayEventReceiver::initCheck() const { if (mDataChannel != NULL) return NO_ERROR; return NO_INIT; } int DisplayEventReceiver::getFd() const { if (mDataChannel == NULL) return NO_INIT; return mDataChannel->getFd(); } | cs |
DisplayEventReceiver의 소스코드를 하나씩 살펴보도록 하겠습니다.
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
SurfaceFlinger로부터 ComposerService의 Binder Proxy를 얻어옵니다.
/frameworks/native/libs/gui/SurfaceComposerClient.cpp
1 2 3 4 5 6 7 8 9 10 | /*static*/ sp<ISurfaceComposer> ComposerService::getComposerService() { ComposerService& instance = ComposerService::getInstance(); Mutex::Autolock _l(instance.mLock); if (instance.mComposerService == NULL) { ComposerService::getInstance().connectLocked(); assert(instance.mComposerService != NULL); ALOGD("ComposerService reconnected"); } return instance.mComposerService; } | cs |
/frameworks/native/include/private/gui/ComposerService.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | // This holds our connection to the composer service (i.e. SurfaceFlinger). // If the remote side goes away, we will re-establish the connection. // Users of this class should not retain the value from // getComposerService() for an extended period. // // (It's not clear that using Singleton is useful here anymore.) class ComposerService : public Singleton<ComposerService> { sp<ISurfaceComposer> mComposerService; sp<IBinder::DeathRecipient> mDeathObserver; Mutex mLock; ComposerService(); void connectLocked(); void composerServiceDied(); friend class Singleton<ComposerService>; public: // Get a connection to the Composer Service. This will block until // a connection is established. static sp<ISurfaceComposer> getComposerService(); }; | cs |
mEventConnection = sf->createDisplayEventConnection();
SurfaceFlinger로 부터 디스플레이와 관련된 이벤트를 수신할 수 있는 EventConnection 클래스를 받습니다.
/frameworks/native/libs/gui/ISurfaceComposer.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 | class BpSurfaceComposer : public BpInterface<ISurfaceComposer> { public: BpSurfaceComposer(const sp<IBinder>& impl) : BpInterface<ISurfaceComposer>(impl) { } .... virtual sp<IDisplayEventConnection> createDisplayEventConnection() { Parcel data, reply; sp<IDisplayEventConnection> result; int err = data.writeInterfaceToken( ISurfaceComposer::getInterfaceDescriptor()); if (err != NO_ERROR) { return result; } err = remote()->transact( BnSurfaceComposer::CREATE_DISPLAY_EVENT_CONNECTION, data, &reply); if (err != NO_ERROR) { ALOGE("ISurfaceComposer::createDisplayEventConnection: error performing " "transaction: %s (%d)", strerror(-err), -err); return result; } result = interface_cast<IDisplayEventConnection>(reply.readStrongBinder()); return result; } .... } status_t BnSurfaceComposer::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { switch(code) { .... case CREATE_DISPLAY_EVENT_CONNECTION: { CHECK_INTERFACE(ISurfaceComposer, data, reply); sp<IDisplayEventConnection> connection(createDisplayEventConnection()); reply->writeStrongBinder(connection->asBinder()); return NO_ERROR; } .... } | 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 | void SurfaceFlinger::init() { .... // 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); .... } .... sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection() { return mEventThread->createEventConnection(); } | cs |
EventThread를 통해 createEventConnection() 함수를 실행하게 됩니다. EventThread가 SurfaceFlinger에 적용되는 과정에 대해 알고 싶으신 분은 이전 포스팅의 내용을 참조해 주시기 바랍니다.
SurfaceFlinger에서 EventThread의 초기화 과정
http://elecs.tistory.com/140
/frameworks/native/services/surfaceflinger/EventThread.cpp
1 2 3 4 5 6 7 8 9 10 11 | sp<EventThread::Connection> EventThread::createEventConnection() const { return new Connection(const_cast<EventThread*>(this)); } .... EventThread::Connection::Connection( const sp<EventThread>& eventThread) : count(-1), mEventThread(eventThread), mChannel(new BitTube()) { } | cs |
mDataChannel = mEventConnection->getDataChannel();
위 Connection 클래스를 생성하면서 만들어진 FD인 BitTube 클래스를 mDataChannel에 저장합니다.
/frameworks/native/services/surfaceflinger/EventThread.cpp
1 2 3 | sp<BitTube> EventThread::Connection::getDataChannel() const { return mChannel; } | cs |
이후 등록된 FD가 호출될 경우 VSync 관련 이벤트가 발생하게 됩니다.
/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 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | 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; } .... int Looper::pollInner(int timeoutMillis) { .... // 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 == 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 |
'안드로이드 > 프레임워크' 카테고리의 다른 글
안드로이드 프레임워크 프로그래밍(24) [BitTube 클래스] (2) | 2015.09.06 |
---|---|
안드로이드 프레임워크 프로그래밍(23) [onFirstRef() 함수 호출시기] (0) | 2015.09.03 |
Android에서 VSync 동작 원리 및 초기화 과정(3) (0) | 2015.08.31 |
Android에서 VSync 동작 원리 및 초기화 과정(2) (0) | 2015.08.30 |
Android에서 VSync 동작 원리 및 초기화 과정(1) (0) | 2015.08.29 |