use a socketpair instead of a pipe in BitTube

Bug: 6252830
Change-Id: Ia7a7b08409517214136261c05569dc5959a597ab
diff --git a/libs/gui/BitTube.cpp b/libs/gui/BitTube.cpp
index 55f4178..355a319 100644
--- a/libs/gui/BitTube.cpp
+++ b/libs/gui/BitTube.cpp
@@ -16,9 +16,9 @@
 
 #include <stdint.h>
 #include <sys/types.h>
+#include <sys/socket.h>
 
 #include <fcntl.h>
-#include <signal.h>
 #include <unistd.h>
 
 #include <utils/Errors.h>
@@ -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 @@
 {
     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 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 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 @@
     return result;
 }
 
+
+ssize_t BitTube::sendObjects(const sp<BitTube>& tube,
+        void const* events, size_t count, size_t objSize)
+{
+    ssize_t numObjects = 0;
+    for (size_t i=0 ; i<count ; i++) {
+        const char* vaddr = reinterpret_cast<const char*>(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<BitTube>& tube,
+        void* events, size_t count, size_t objSize)
+{
+    ssize_t numObjects = 0;
+    for (size_t i=0 ; i<count ; i++) {
+        char* vaddr = reinterpret_cast<char*>(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 a6790ad..9973e8d 100644
--- a/libs/gui/DisplayEventReceiver.cpp
+++ b/libs/gui/DisplayEventReceiver.cpp
@@ -85,22 +85,13 @@
 ssize_t DisplayEventReceiver::getEvents(const sp<BitTube>& 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<BitTube>& 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 b95dd90..04ba640 100644
--- a/libs/gui/SensorEventQueue.cpp
+++ b/libs/gui/SensorEventQueue.cpp
@@ -53,36 +53,15 @@
     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<BitTube>& 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<Looper> SensorEventQueue::getLooper() const