diff --git a/include/gui/BitTube.h b/include/gui/BitTube.h index 76389a037..3022d05f0 100644 --- a/include/gui/BitTube.h +++ b/include/gui/BitTube.h @@ -22,6 +22,7 @@ #include #include +#include namespace android { @@ -43,9 +44,27 @@ public: status_t writeToParcel(Parcel* reply) const; + template + static ssize_t sendObjects(const sp& tube, + T const* events, size_t count) { + return sendObjects(tube, events, count, sizeof(T)); + } + + template + static ssize_t recvObjects(const sp& tube, + T* events, size_t count) { + return recvObjects(tube, events, count, sizeof(T)); + } + private: int mSendFd; mutable int mReceiveFd; + + static ssize_t sendObjects(const sp& tube, + void const* events, size_t count, size_t objSize); + + static ssize_t recvObjects(const sp& tube, + void* events, size_t count, size_t objSize); }; // ---------------------------------------------------------------------------- diff --git a/include/gui/DisplayEventReceiver.h b/include/gui/DisplayEventReceiver.h index 7bca8d6ea..e631cca33 100644 --- a/include/gui/DisplayEventReceiver.h +++ b/include/gui/DisplayEventReceiver.h @@ -89,7 +89,7 @@ public: int getFd() const; /* - * getEvents reads event from the queue and returns how many events were + * 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. @@ -98,6 +98,13 @@ public: static ssize_t getEvents(const sp& 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& 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, diff --git a/include/gui/SensorEventQueue.h b/include/gui/SensorEventQueue.h index ef7c6e369..759b5cb94 100644 --- a/include/gui/SensorEventQueue.h +++ b/include/gui/SensorEventQueue.h @@ -54,7 +54,10 @@ public: virtual void onFirstRef(); int getFd() const; - ssize_t write(ASensorEvent const* events, size_t numEvents); + + static ssize_t write(const sp& tube, + ASensorEvent const* events, size_t numEvents); + ssize_t read(ASensorEvent* events, size_t numEvents); status_t waitForEvent() const; diff --git a/libs/gui/BitTube.cpp b/libs/gui/BitTube.cpp index 55f417842..355a319c5 100644 --- a/libs/gui/BitTube.cpp +++ b/libs/gui/BitTube.cpp @@ -16,9 +16,9 @@ #include #include +#include #include -#include #include #include @@ -30,17 +30,25 @@ namespace android { // ---------------------------------------------------------------------------- +// 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 SOCKET_BUFFER_SIZE = 4 * 1024; + + BitTube::BitTube() : mSendFd(-1), mReceiveFd(-1) { - int fds[2]; - if (pipe(fds) == 0) { - mReceiveFd = fds[0]; - mSendFd = fds[1]; - fcntl(mReceiveFd, F_SETFL, O_NONBLOCK); - fcntl(mSendFd, F_SETFL, O_NONBLOCK); - // ignore SIGPIPE, we handle write errors through EPIPE instead - signal(SIGPIPE, SIG_IGN); + int sockets[2]; + if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets) == 0) { + int size = SOCKET_BUFFER_SIZE; + setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)); + setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)); + setsockopt(sockets[1], 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)); @@ -52,6 +60,9 @@ BitTube::BitTube(const Parcel& data) { mReceiveFd = dup(data.readFileDescriptor()); if (mReceiveFd >= 0) { + int size = SOCKET_BUFFER_SIZE; + setsockopt(mReceiveFd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)); + setsockopt(mReceiveFd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)); fcntl(mReceiveFd, F_SETFL, O_NONBLOCK); } else { mReceiveFd = -errno; @@ -86,7 +97,7 @@ ssize_t BitTube::write(void const* vaddr, size_t size) { ssize_t err, len; do { - len = ::write(mSendFd, vaddr, size); + len = ::send(mSendFd, vaddr, size, MSG_DONTWAIT | MSG_NOSIGNAL); err = len < 0 ? errno : 0; } while (err == EINTR); return err == 0 ? len : -err; @@ -97,7 +108,7 @@ ssize_t BitTube::read(void* vaddr, size_t size) { ssize_t err, len; do { - len = ::read(mReceiveFd, vaddr, size); + len = ::recv(mReceiveFd, vaddr, size, MSG_DONTWAIT); err = len < 0 ? errno : 0; } while (err == EINTR); if (err == EAGAIN || err == EWOULDBLOCK) { @@ -119,5 +130,46 @@ status_t BitTube::writeToParcel(Parcel* reply) const return result; } + +ssize_t BitTube::sendObjects(const sp& tube, + void const* events, size_t count, size_t objSize) +{ + ssize_t numObjects = 0; + for (size_t i=0 ; i(events) + objSize * i; + ssize_t size = tube->write(vaddr, objSize); + if (size < 0) { + // error occurred + numObjects = -size; + break; + } else if (size == 0) { + // no more space + break; + } + numObjects++; + } + return numObjects; +} + +ssize_t BitTube::recvObjects(const sp& tube, + void* events, size_t count, size_t objSize) +{ + ssize_t numObjects = 0; + for (size_t i=0 ; i(events) + objSize * i; + ssize_t size = tube->read(vaddr, objSize); + if (size < 0) { + // error occurred + numObjects = -size; + break; + } else if (size == 0) { + // no more messages + break; + } + numObjects++; + } + return numObjects; +} + // ---------------------------------------------------------------------------- }; // namespace android diff --git a/libs/gui/DisplayEventReceiver.cpp b/libs/gui/DisplayEventReceiver.cpp index a6790ad07..9973e8dae 100644 --- a/libs/gui/DisplayEventReceiver.cpp +++ b/libs/gui/DisplayEventReceiver.cpp @@ -85,22 +85,13 @@ ssize_t DisplayEventReceiver::getEvents(DisplayEventReceiver::Event* events, ssize_t DisplayEventReceiver::getEvents(const sp& dataChannel, Event* events, size_t count) { - ssize_t size = dataChannel->read(events, sizeof(events[0])*count); - ALOGE_IF(size<0, - "DisplayEventReceiver::getEvents error (%s)", - strerror(-size)); - if (size >= 0) { - // Note: if (size % sizeof(events[0])) != 0, we've got a - // partial read. This can happen if the queue filed up (ie: if we - // didn't pull from it fast enough). - // We discard the partial event and rely on the sender to - // re-send the event if appropriate (some events, like VSYNC - // can be lost forever). + return BitTube::recvObjects(dataChannel, events, count); +} - // returns number of events read - size /= sizeof(events[0]); - } - return size; +ssize_t DisplayEventReceiver::sendEvents(const sp& dataChannel, + Event const* events, size_t count) +{ + return BitTube::sendObjects(dataChannel, events, count); } // --------------------------------------------------------------------------- diff --git a/libs/gui/SensorEventQueue.cpp b/libs/gui/SensorEventQueue.cpp index b95dd9023..04ba6404a 100644 --- a/libs/gui/SensorEventQueue.cpp +++ b/libs/gui/SensorEventQueue.cpp @@ -53,36 +53,15 @@ int SensorEventQueue::getFd() const return mSensorChannel->getFd(); } -ssize_t SensorEventQueue::write(ASensorEvent const* events, size_t numEvents) -{ - ssize_t size = mSensorChannel->write(events, numEvents * sizeof(events[0])); - if (size >= 0) { - if (size % sizeof(events[0])) { - // partial write!!! should never happen. - return -EINVAL; - } - // returns number of events written - size /= sizeof(events[0]); - } - return size; + +ssize_t SensorEventQueue::write(const sp& tube, + ASensorEvent const* events, size_t numEvents) { + return BitTube::sendObjects(tube, events, numEvents); } ssize_t SensorEventQueue::read(ASensorEvent* events, size_t numEvents) { - ssize_t size = mSensorChannel->read(events, numEvents*sizeof(events[0])); - ALOGE_IF(size<0 && size!=-EAGAIN, - "SensorChannel::read error (%s)", strerror(-size)); - if (size >= 0) { - if (size % sizeof(events[0])) { - // partial read!!! should never happen. - ALOGE("SensorEventQueue partial read (event-size=%u, read=%d)", - sizeof(events[0]), int(size)); - return -EINVAL; - } - // returns number of events read - size /= sizeof(events[0]); - } - return size; + return BitTube::recvObjects(mSensorChannel, events, numEvents); } sp SensorEventQueue::getLooper() const diff --git a/services/surfaceflinger/DisplayEventConnection.cpp b/services/surfaceflinger/DisplayEventConnection.cpp index 77ecbd280..67381ef05 100644 --- a/services/surfaceflinger/DisplayEventConnection.cpp +++ b/services/surfaceflinger/DisplayEventConnection.cpp @@ -60,9 +60,9 @@ void DisplayEventConnection::requestNextVsync() { mEventThread->requestNextVsync(this); } -status_t DisplayEventConnection::postEvent(const DisplayEventReceiver::Event& event) -{ - ssize_t size = mChannel->write(&event, sizeof(DisplayEventReceiver::Event)); +status_t DisplayEventConnection::postEvent( + const DisplayEventReceiver::Event& event) { + ssize_t size = DisplayEventReceiver::sendEvents(mChannel, &event, 1); return size < 0 ? status_t(size) : status_t(NO_ERROR); }