Add android/utils/eintr_wrapper.h

Add a new Android-specific header that defines two macros to
handle EINTR in a consistent way, as well as allow detecting
when a system call loops too many times and exit with a fatal
error message when that happens.

+ Unit tests.

+ Update existing code under android/ which uses to deal directly
  with EINTR to use the new HANDLE_EINTR() and IGNORE_EINTR()

+ Remove EINTR checks for functions that call socket_xxx() functions
  which already loop around EINTR.

Change-Id: I1d2ee64d9743a2edc506f616465ea091878db620
diff --git a/android/protocol/ui-commands-impl.c b/android/protocol/ui-commands-impl.c
index 2ceeca1..307e7c7 100644
--- a/android/protocol/ui-commands-impl.c
+++ b/android/protocol/ui-commands-impl.c
@@ -22,6 +22,7 @@
 #include "android/sync-utils.h"
 #include "android/utils/system.h"
 #include "android/utils/debug.h"
+#include "android/utils/eintr_wrapper.h"
 #include "android/utils/panic.h"
 #include "android/protocol/core-connection.h"
 #include "android/protocol/ui-commands-impl.h"
@@ -124,23 +125,23 @@
     // Read requests while they are immediately available.
     for (;;) {
         // Read next chunk of data.
-        status = socket_recv(uicmd->sock,
-                             uicmd->reader_buffer + uicmd->reader_offset,
-                             uicmd->reader_bytes - uicmd->reader_offset);
-        if (status == 0) {
-            /* Disconnection, meaning that the core process got terminated. */
-            fprintf(stderr, "core-ui-control service got disconnected\n");
-            uiCmdImpl_destroy();
+        status = HANDLE_EINTR(
+                socket_recv(uicmd->sock,
+                            uicmd->reader_buffer + uicmd->reader_offset,
+                            uicmd->reader_bytes - uicmd->reader_offset));
+        if (status < 0 && (errno == EWOULDBLOCK || errno == EGAIN) {
+            // Chunk is not avalable at this point. Come back later.
             return;
         }
-        if (status < 0) {
-            if (errno == EINTR) {
-                /* loop on EINTR */
-                continue;
-            } else if (errno == EWOULDBLOCK || errno == EAGAIN) {
-                // Chunk is not avalable at this point. Come back later.
-                return;
-            }
+        if (status <= 0) {
+            /* Disconnection, meaning that the core process got terminated. */
+            fprintf(stderr,
+                    "core-ui-control service got disconnected: %s\n",
+                    status < 0 ?
+                        strerror(errno) :
+                        "unexpected disconnection");
+            uiCmdImpl_destroy();
+            return;
         }
 
         uicmd->reader_offset += status;