검색결과 리스트
글
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 |
설정
트랙백
댓글
글
SurfaceFlinger에서 EventThread의 초기화 과정
SurfaceFlinger가 수직동기화(VSync)를 수행하기 위해 이를 담당하는 별도의 Thread를 만들어 줄 필요가 있습니다. EventThread 클래스가 바로 그러한 역할을 담당하고 있다고 보면 되겠습니다. 이번 포스팅에서 EventThread의 초기화 과정을 살펴보도록 하겠습니다.
/frameworks/native/services/surfaceflinger/EventThread.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 | 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; }; class EventThread : public Thread, private VSyncSource::Callback { class Connection : public BnDisplayEventConnection { public: Connection(const sp<EventThread>& eventThread); status_t postEvent(const DisplayEventReceiver::Event& event); // count >= 1 : continuous event. count is the vsync rate // count == 0 : one-shot event that has not fired // count ==-1 : one-shot event that fired this round / disabled int32_t count; private: virtual ~Connection(); virtual void onFirstRef(); virtual sp<BitTube> getDataChannel() const; virtual void setVsyncRate(uint32_t count); virtual void requestNextVsync(); // asynchronous sp<EventThread> const mEventThread; sp<BitTube> const mChannel; }; public: EventThread(const sp<VSyncSource>& src); sp<Connection> createEventConnection() const; status_t registerDisplayEventConnection(const sp<Connection>& connection); void setVsyncRate(uint32_t count, const sp<Connection>& connection); void requestNextVsync(const sp<Connection>& connection); // called before the screen is turned off from main thread void onScreenReleased(); // called after the screen is turned on from main thread void onScreenAcquired(); // called when receiving a hotplug event void onHotplugReceived(int type, bool connected); Vector< sp<EventThread::Connection> > waitForEvent( DisplayEventReceiver::Event* event); void dump(String8& result) const; private: virtual bool threadLoop(); virtual void onFirstRef(); virtual void onVSyncEvent(nsecs_t timestamp); void removeDisplayEventConnection(const wp<Connection>& connection); void enableVSyncLocked(); void disableVSyncLocked(); // constants sp<VSyncSource> mVSyncSource; PowerHAL mPowerHAL; mutable Mutex mLock; mutable Condition mCondition; // protected by mLock SortedVector< wp<Connection> > mDisplayEventConnections; Vector< DisplayEventReceiver::Event > mPendingEvents; DisplayEventReceiver::Event mVSyncEvent[DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES]; bool mUseSoftwareVSync; bool mVsyncEnabled; // for debugging bool mDebugVsyncEnabled; }; | cs |
/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 | 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; }; }; .... } | cs |
전체적인 맥락을 파악하기 위해 EventThread의 전체 헤더 소스코드를 보았습니다. 이번에는 EventThread가 초기화 되는 과정을 살펴보도록 하겠습니다.
/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 | 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); .... } | cs |
SurfaceFlinger에서 EventThread가 초기화 되는 부분입니다. 여기서 mEventThread 클래스 변수가 초기화 되는 과정을 살펴보도록 하겠습니다.
sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync,
수직동기화의 Source를 설정하는 부분입니다. 해당 부분은 다음과 같이 구성되어 있습니다.
/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 | 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() {} .... private: .... int mValue; const nsecs_t mPhaseOffset; const bool mTraceVsync; DispSync* mDispSync; sp<VSyncSource::Callback> mCallback; Mutex mMutex; }; | cs |
mEventThread = new EventThread(vsyncSrc);
이전 줄에서 설정하였던 수직동기화 정보를 기반으로 EventThread 생성자를 실행합니다.
/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 45 46 47 48 | EventThread::EventThread(const sp<VSyncSource>& src) : mVSyncSource(src), mUseSoftwareVSync(false), mVsyncEnabled(false), mDebugVsyncEnabled(false) { for (int32_t i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) { mVSyncEvent[i].header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC; mVSyncEvent[i].header.id = 0; mVSyncEvent[i].header.timestamp = 0; mVSyncEvent[i].vsync.count = 0; } } void EventThread::onFirstRef() { run("EventThread", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE); } .... bool EventThread::threadLoop() { DisplayEventReceiver::Event event; Vector< sp<EventThread::Connection> > signalConnections; signalConnections = waitForEvent(&event); // dispatch events to listeners... const size_t count = signalConnections.size(); for (size_t i=0 ; i<count ; i++) { const sp<Connection>& conn(signalConnections[i]); // now see if we still need to report this event status_t err = conn->postEvent(event); if (err == -EAGAIN || err == -EWOULDBLOCK) { // The destination doesn't accept events anymore, it's probably // full. For now, we just drop the events on the floor. // FIXME: Note that some events cannot be dropped and would have // to be re-sent later. // Right-now we don't have the ability to do this. ALOGW("EventThread: dropping event (%08x) for connection %p", event.header.type, conn.get()); } else if (err < 0) { // handle any other error on the pipe as fatal. the only // reasonable thing to do is to clean-up this connection. // The most common error we'll get here is -EPIPE. removeDisplayEventConnection(signalConnections[i]); } } return true; } | cs |
위의 소스코드에서 waitForEvent() 소스코드를 통해 EventThread의 연결과정이 드러나고 있습니다. 해당 부분을 살펴보면 다음과 같습니다.
/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 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 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | // 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 { bool eventPending = false; bool waitForVSync = false; size_t vsyncCount = 0; nsecs_t timestamp = 0; for (int32_t i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) { timestamp = mVSyncEvent[i].header.timestamp; if (timestamp) { // we have a vsync event to dispatch *event = mVSyncEvent[i]; mVSyncEvent[i].header.timestamp = 0; vsyncCount = mVSyncEvent[i].vsync.count; break; } } if (!timestamp) { // no vsync event, see if there are some other event eventPending = !mPendingEvents.isEmpty(); if (eventPending) { // we have some other event to dispatch *event = mPendingEvents[0]; mPendingEvents.removeAt(0); } } // find out connections waiting for events size_t count = mDisplayEventConnections.size(); for (size_t i=0 ; i<count ; i++) { sp<Connection> connection(mDisplayEventConnections[i].promote()); if (connection != NULL) { bool added = false; if (connection->count >= 0) { // we need vsync events because at least // one connection is waiting for it waitForVSync = true; if (timestamp) { // we consume the event only if it's time // (ie: we received a vsync event) if (connection->count == 0) { // fired this time around connection->count = -1; signalConnections.add(connection); added = true; } else if (connection->count == 1 || (vsyncCount % connection->count) == 0) { // continuous event, and time to report it signalConnections.add(connection); added = true; } } } if (eventPending && !timestamp && !added) { // we don't have a vsync event to process // (timestamp==0), but we have some pending // messages. signalConnections.add(connection); } } else { // we couldn't promote this reference, the connection has // died, so clean-up! mDisplayEventConnections.removeAt(i); --i; --count; } } // 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(); } // note: !timestamp implies signalConnections.isEmpty(), because we // don't populate signalConnections if there's no vsync pending if (!timestamp && !eventPending) { // wait for something to happen if (waitForVSync) { // This is where we spend most of our time, waiting // for vsync events and new client registrations. // // If the screen is off, we can't use h/w vsync, so we // use a 16ms timeout instead. It doesn't need to be // precise, we just need to keep feeding our clients. // // We don't want to stall if there's a driver bug, so we // use a (long) timeout when waiting for h/w vsync, and // generate fake events when necessary. bool softwareSync = mUseSoftwareVSync; nsecs_t timeout = softwareSync ? ms2ns(16) : ms2ns(1000); if (mCondition.waitRelative(mLock, timeout) == TIMED_OUT) { if (!softwareSync) { ALOGW("Timed out waiting for hw vsync; faking it"); } // FIXME: how do we decide which display id the fake // vsync came from ? mVSyncEvent[0].header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC; mVSyncEvent[0].header.id = DisplayDevice::DISPLAY_PRIMARY; mVSyncEvent[0].header.timestamp = systemTime(SYSTEM_TIME_MONOTONIC); mVSyncEvent[0].vsync.count++; } } else { // Nobody is interested in vsync, so we just want to sleep. // h/w vsync should be disabled, so this will wait until we // get a new connection, or an existing connection becomes // interested in receiving vsync again. mCondition.wait(mLock); } } } while (signalConnections.isEmpty()); // here we're guaranteed to have a timestamp and some connections to signal // (The connections might have dropped out of mDisplayEventConnections // while we were asleep, but we'll still have strong references to them.) return signalConnections; } | cs |
위의 waitForEvent() 함수의 실행이 종료되면 이후에 Connection 클래스가 생성됩니다.
/frameworks/native/services/surfaceflinger/EventThread.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | EventThread::Connection::Connection( const sp<EventThread>& eventThread) : count(-1), mEventThread(eventThread), mChannel(new BitTube()) { } EventThread::Connection::~Connection() { // do nothing here -- clean-up will happen automatically // when the main thread wakes up } void EventThread::Connection::onFirstRef() { // NOTE: mEventThread doesn't hold a strong reference on us mEventThread->registerDisplayEventConnection(this); } | cs |
위의 Connection 클래스가 생성되면서 mChannel을 통해 File Descriptor을 통해 프로세스간 통신을 수행하는 BitTube 클래스가 새로 생성됩니다. BitTube에 대한 자세한 내용은 이전의 포스팅을 참조해주시기 바랍니다.
안드로이드 프레임워크 프로그래밍(24) [BitTube 클래스]
Connection 클래스의 onFirstRef()함수에 의해 EventThread 클래스의 registerDisplayEventConnection()함수가 호출됩니다.
/frameworks/native/services/surfaceflinger/EventThread.cpp
1 2 3 4 5 6 7 8 | status_t EventThread::registerDisplayEventConnection( const sp<EventThread::Connection>& connection) { Mutex::Autolock _l(mLock); mDisplayEventConnections.add(connection); mCondition.broadcast(); return NO_ERROR; } | cs |
EventThread에 EventThread의 Connection 클래스를 벡터에 등록한 후 멈추어 있던 Thread들을 모두 깨웁니다. 위의 과정을 통해 생성된 Connection 클래스는 이후 postEvent() 함수를 수행하게 됩니다.
/frameworks/native/services/surfaceflinger/EventThread.cpp
1 2 3 4 5 | status_t EventThread::Connection::postEvent( const DisplayEventReceiver::Event& event) { ssize_t size = DisplayEventReceiver::sendEvents(mChannel, &event, 1); return size < 0 ? status_t(size) : status_t(NO_ERROR); } | cs |
/frameworks/native/libs/gui/DisplayEventReceiver.cpp
1 2 3 4 5 | ssize_t DisplayEventReceiver::sendEvents(const sp<BitTube>& dataChannel, Event const* events, size_t count) { return BitTube::sendObjects(dataChannel, events, count); } | cs |
'안드로이드 > 프레임워크' 카테고리의 다른 글
| SurfaceFlinger에서 DispSyncSource의 초기화 과정 (0) | 2015.09.12 |
|---|---|
| SurfaceFlinger의 초기화 과정 흐름도 (0) | 2015.09.09 |
| 안드로이드 프레임워크 프로그래밍(24) [BitTube 클래스] (2) | 2015.09.06 |
| 안드로이드 프레임워크 프로그래밍(23) [onFirstRef() 함수 호출시기] (0) | 2015.09.03 |
| Android에서 VSync 동작 원리 및 초기화 과정(4) (5) | 2015.09.02 |
설정
트랙백
댓글
글
PHLASHNT.SYS 드라이버를 로드할 수 없습니다. 오류 코드: 1275
현재 제가 데스크톱으로 활용하고 있는 리퍼비시 PC인 Smasung 매직스테이션 DB-Z70을 사용하다가 최신 BIOS로 업그레이드를 해 보고자 삼성전자 홈페이지에서 해당 데스크톱의 최신 BIOS 버전을 다운로드 받은 후 실행해 보았습니다. 그러자 아래와 같은 경고문이 뜨면서 저를 반기더군요.
"PHLASHNT.SYS 드라이버를 로드할 수 없습니다. 계정을 확인하십시오. 관리자 권한이 없는 경우에는 다시 로그인하십시오! 이 드라이버가 차단되었기 때문에 로드할 수 없습니다. 오류 코드: 1275"
위 화면은 Windows 10 64-bit 버전에서 해당 프로그램을 실행하였을 때 위와 같은 현상이 발생합니다. 위와 같은 문제가 발생하는 원인은 아래 중 하나에 해당될 것입니다.
- 현재 자신이 사용하는 운영체제의 버전이 Windows 7 이상(8, 8.1, 10)인 경우
- 자신이 사용하는 운영체제가 64비트 기반일 경우
구글링을 통해 다른 분들의 사례들을 분석해 본 결과, 해당 BIOS의 버전이 설치되지 않는 이유는 Windows 7에서 부터 실행권한이 Root와 User가 분리되면서 발생하는 것으로 추정됩니다. 현재 해외의 사례에서 가장 좋은 해결 방법은 32비트 기반의 Windows XP 운영체제를 통해 설치하는 것을 권장하고 있습니다. 위 프로그램을 설치하기 위해서는 아래의 방법 중 하나를 선택해 주시면 될 것으로 보입니다.
- 자신의 하드디스크에 임시로 파티션을 분리하여 Windows XP를 설치한 후 BIOS 설치 프로그램을 실행합니다.
- Windows XP가 설치되어 있는 하드디스크 혹은 USB를 통해 Windows XP를 부팅한 후 BIOS 설치 프로그램을 실행합니다.
위에서 제시한 방법들 중 하나를 선택하여 BIOS 설치 프로그램을 실행하시면 아래와 같이 정상적으로 설치되는 것을 확인하실 수 있습니다.
'공대생의 팁' 카테고리의 다른 글
| [컴퓨터비전]이미지 변환시 DoF(Degrees of Freedom)에 대한 고찰 (0) | 2015.10.13 |
|---|---|
| IP v4 주소 0.0.0.0의 의미 (0) | 2015.09.27 |
| Intel Management Engine BIOS Extention 설정시 암호 변경이 안될 때 해결방법 (1) | 2015.08.19 |
| Ubuntu에서 특정 Unicode가 안보일 때 (0) | 2015.07.22 |
| GFDM(Generalized Frequency Domain Multiplexing) (0) | 2015.06.06 |