Merge "Improve liblog's fatal logging."
diff --git a/liblog/log_read.c b/liblog/log_read.c
index 0ff94bf..11fe848 100644
--- a/liblog/log_read.c
+++ b/liblog/log_read.c
@@ -17,6 +17,7 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <inttypes.h>
+#include <poll.h>
 #include <signal.h>
 #include <stddef.h>
 #define NOMINMAX /* for windows to suppress definition of min in stdlib.h */
@@ -273,6 +274,8 @@
                             const char *msg, char *buf, size_t buf_size)
 {
     ssize_t ret;
+    size_t len;
+    char *cp;
     int errno_save = 0;
     int sock = socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_RESERVED,
                                    SOCK_STREAM);
@@ -284,12 +287,44 @@
         snprintf(buf, buf_size, msg, logger ? logger->id : (unsigned) -1);
     }
 
-    ret = write(sock, buf, strlen(buf) + 1);
+    len = strlen(buf) + 1;
+    ret = TEMP_FAILURE_RETRY(write(sock, buf, len));
     if (ret <= 0) {
         goto done;
     }
 
-    ret = read(sock, buf, buf_size);
+    len = buf_size;
+    cp = buf;
+    while ((ret = TEMP_FAILURE_RETRY(read(sock, cp, len))) > 0) {
+        struct pollfd p;
+
+        if (((size_t)ret == len) || (buf_size < PAGE_SIZE)) {
+            break;
+        }
+
+        len -= ret;
+        cp += ret;
+
+        memset(&p, 0, sizeof(p));
+        p.fd = sock;
+        p.events = POLLIN;
+
+        /* Give other side 20ms to refill pipe */
+        ret = TEMP_FAILURE_RETRY(poll(&p, 1, 20));
+
+        if (ret <= 0) {
+            break;
+        }
+
+        if (!(p.revents & POLLIN)) {
+            ret = 0;
+            break;
+        }
+    }
+
+    if (ret >= 0) {
+        ret += buf_size - len;
+    }
 
 done:
     if ((ret == -1) && errno) {
diff --git a/logd/tests/logd_test.cpp b/logd/tests/logd_test.cpp
index 9ad8973..23e6146 100644
--- a/logd/tests/logd_test.cpp
+++ b/logd/tests/logd_test.cpp
@@ -15,6 +15,7 @@
  */
 
 #include <fcntl.h>
+#include <poll.h>
 #include <signal.h>
 #include <stdio.h>
 #include <string.h>
@@ -37,7 +38,25 @@
                                    SOCK_STREAM);
     if (sock >= 0) {
         if (write(sock, buf, strlen(buf) + 1) > 0) {
-            read(sock, buf, len);
+            ssize_t ret;
+            while ((ret = read(sock, buf, len)) > 0) {
+                if ((size_t)ret == len) {
+                    break;
+                }
+                len -= ret;
+                buf += ret;
+
+                struct pollfd p = {
+                    .fd = sock,
+                    .events = POLLIN,
+                    .revents = 0
+                };
+
+                ret = poll(&p, 1, 20);
+                if ((ret <= 0) || !(p.revents & POLLIN)) {
+                    break;
+                }
+            }
         }
         close(sock);
     }