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,

            vsyncPhaseOffsetNs, true);


 수직동기화의 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 클래스]

http://elecs.tistory.com/138


 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


300x250

PHLASHNT.SYS 드라이버를 로드할 수 없습니다. 오류 코드: 1275

공대생의 팁 2015. 9. 7. 23:36

 현재 제가 데스크톱으로 활용하고 있는 리퍼비시 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 설치 프로그램을 실행하시면 아래와 같이 정상적으로 설치되는 것을 확인하실 수 있습니다.


 


300x250

안드로이드 프레임워크 프로그래밍(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


300x250