Merge "Add missing liblog dependency"
diff --git a/adb/adb_utils.cpp b/adb/adb_utils.cpp
index 474d1b4..8a16e51 100644
--- a/adb/adb_utils.cpp
+++ b/adb/adb_utils.cpp
@@ -134,7 +134,7 @@
   return result;
 }
 
-// Given a relative or absolute filepath, create the parent directory hierarchy
+// Given a relative or absolute filepath, create the directory hierarchy
 // as needed. Returns true if the hierarchy is/was setup.
 bool mkdirs(const std::string& path) {
   // TODO: all the callers do unlink && mkdirs && adb_creat ---
@@ -157,12 +157,12 @@
     return true;
   }
 
+  const std::string parent(adb_dirname(path));
+
   // If dirname returned the same path as what we passed in, don't go recursive.
   // This can happen on Windows when walking up the directory hierarchy and not
   // finding anything that already exists (unlike POSIX that will eventually
   // find . or /).
-  const std::string parent(adb_dirname(path));
-
   if (parent == path) {
     errno = ENOENT;
     return false;
@@ -174,14 +174,14 @@
   }
 
   // Now that the parent directory hierarchy of 'path' has been ensured,
-  // create parent itself.
+  // create path itself.
   if (adb_mkdir(path, 0775) == -1) {
-    // Can't just check for errno == EEXIST because it might be a file that
-    // exists.
     const int saved_errno = errno;
-    if (directory_exists(parent)) {
+    // If someone else created the directory, that is ok.
+    if (directory_exists(path)) {
       return true;
     }
+    // There might be a pre-existing file at 'path', or there might have been some other error.
     errno = saved_errno;
     return false;
   }
diff --git a/adb/adb_utils_test.cpp b/adb/adb_utils_test.cpp
index dfe6f20..f1ebaa1 100644
--- a/adb/adb_utils_test.cpp
+++ b/adb/adb_utils_test.cpp
@@ -112,20 +112,26 @@
 }
 
 void test_mkdirs(const std::string basepath) {
-  EXPECT_TRUE(mkdirs(adb_dirname(basepath)));
-  EXPECT_NE(-1, adb_creat(basepath.c_str(), 0600));
-  EXPECT_FALSE(mkdirs(basepath + "/subdir/"));
+  // Test creating a directory hierarchy.
+  EXPECT_TRUE(mkdirs(basepath));
+  // Test finding an existing directory hierarchy.
+  EXPECT_TRUE(mkdirs(basepath));
+  const std::string filepath = basepath + "/file";
+  // Verify that the hierarchy was created by trying to create a file in it.
+  EXPECT_NE(-1, adb_creat(filepath.c_str(), 0600));
+  // If a file exists where we want a directory, the operation should fail.
+  EXPECT_FALSE(mkdirs(filepath));
 }
 
 TEST(adb_utils, mkdirs) {
   TemporaryDir td;
 
   // Absolute paths.
-  test_mkdirs(std::string(td.path) + "/dir/subdir/file");
+  test_mkdirs(std::string(td.path) + "/dir/subdir");
 
   // Relative paths.
   ASSERT_EQ(0, chdir(td.path)) << strerror(errno);
-  test_mkdirs(std::string("relative/subrel/file"));
+  test_mkdirs(std::string("relative/subrel"));
 }
 
 #if !defined(_WIN32)
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index 85ab4d1..8e76168 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -482,7 +482,7 @@
 // Loops to read from stdin and push the data to the given FD.
 // The argument should be a pointer to a StdinReadArgs object. This function
 // will take ownership of the object and delete it when finished.
-static void* stdin_read_thread_loop(void* x) {
+static void stdin_read_thread_loop(void* x) {
     std::unique_ptr<StdinReadArgs> args(reinterpret_cast<StdinReadArgs*>(x));
 
 #if !defined(_WIN32)
@@ -586,8 +586,6 @@
             }
         }
     }
-
-    return nullptr;
 }
 
 // Returns a shell service string with the indicated arguments and command.
diff --git a/adb/services.cpp b/adb/services.cpp
index 9cbf787..75cbe5d 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -57,13 +57,11 @@
     void *cookie;
 };
 
-void *service_bootstrap_func(void *x)
-{
+static void service_bootstrap_func(void* x) {
     stinfo* sti = reinterpret_cast<stinfo*>(x);
     adb_thread_setname(android::base::StringPrintf("service %d", sti->fd));
     sti->func(sti->fd, sti->cookie);
     free(sti);
-    return 0;
 }
 
 #if !ADB_HOST
diff --git a/adb/shell_service.cpp b/adb/shell_service.cpp
index d080e09..f84447f 100644
--- a/adb/shell_service.cpp
+++ b/adb/shell_service.cpp
@@ -198,7 +198,7 @@
     // Opens the file at |pts_name|.
     int OpenPtyChildFd(const char* pts_name, ScopedFd* error_sfd);
 
-    static void* ThreadHandler(void* userdata);
+    static void ThreadHandler(void* userdata);
     void PassDataStreams();
     void WaitForExit();
 
@@ -465,7 +465,7 @@
     return child_fd;
 }
 
-void* Subprocess::ThreadHandler(void* userdata) {
+void Subprocess::ThreadHandler(void* userdata) {
     Subprocess* subprocess = reinterpret_cast<Subprocess*>(userdata);
 
     adb_thread_setname(android::base::StringPrintf(
@@ -475,8 +475,6 @@
 
     D("deleting Subprocess for PID %d", subprocess->pid());
     delete subprocess;
-
-    return nullptr;
 }
 
 void Subprocess::PassDataStreams() {
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index 761a4c7..3bae09e 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -115,25 +115,26 @@
     LeaveCriticalSection( lock );
 }
 
-typedef void* (*adb_thread_func_t)(void* arg);
+typedef void (*adb_thread_func_t)(void* arg);
 typedef HANDLE adb_thread_t;
 
-struct win_thread_args {
+struct adb_winthread_args {
     adb_thread_func_t func;
     void* arg;
 };
 
-static unsigned __stdcall win_thread_wrapper(void* args) {
-    win_thread_args thread_args = *static_cast<win_thread_args*>(args);
-    delete static_cast<win_thread_args*>(args);
-    void* result = thread_args.func(thread_args.arg);
-    return reinterpret_cast<unsigned>(result);
+static unsigned __stdcall adb_winthread_wrapper(void* heap_args) {
+    // Move the arguments from the heap onto the thread's stack.
+    adb_winthread_args thread_args = *static_cast<adb_winthread_args*>(heap_args);
+    delete static_cast<adb_winthread_args*>(heap_args);
+    thread_args.func(thread_args.arg);
+    return 0;
 }
 
 static __inline__ bool adb_thread_create(adb_thread_func_t func, void* arg,
                                          adb_thread_t* thread = nullptr) {
-    win_thread_args* args = new win_thread_args{.func = func, .arg = arg};
-    uintptr_t handle = _beginthreadex(nullptr, 0, win_thread_wrapper, args, 0, nullptr);
+    adb_winthread_args* args = new adb_winthread_args{.func = func, .arg = arg};
+    uintptr_t handle = _beginthreadex(nullptr, 0, adb_winthread_wrapper, args, 0, nullptr);
     if (handle != static_cast<uintptr_t>(0)) {
         if (thread) {
             *thread = reinterpret_cast<HANDLE>(handle);
@@ -168,6 +169,10 @@
     return true;
 }
 
+static __inline__ void __attribute__((noreturn)) adb_thread_exit() {
+    _endthreadex(0);
+}
+
 static __inline__ int adb_thread_setname(const std::string& name) {
     // TODO: See https://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx for how to set
     // the thread name in Windows. Unfortunately, it only works during debugging, but
@@ -701,17 +706,32 @@
 #define  unix_write  adb_write
 #define  unix_close  adb_close
 
-typedef void*  (*adb_thread_func_t)( void*  arg );
-
+// Win32 is limited to DWORDs for thread return values; limit the POSIX systems to this as well to
+// ensure compatibility.
+typedef void (*adb_thread_func_t)(void* arg);
 typedef pthread_t adb_thread_t;
 
+struct adb_pthread_args {
+    adb_thread_func_t func;
+    void* arg;
+};
+
+static void* adb_pthread_wrapper(void* heap_args) {
+    // Move the arguments from the heap onto the thread's stack.
+    adb_pthread_args thread_args = *reinterpret_cast<adb_pthread_args*>(heap_args);
+    delete static_cast<adb_pthread_args*>(heap_args);
+    thread_args.func(thread_args.arg);
+    return nullptr;
+}
+
 static __inline__ bool adb_thread_create(adb_thread_func_t start, void* arg,
                                          adb_thread_t* thread = nullptr) {
     pthread_t temp;
     pthread_attr_t attr;
     pthread_attr_init(&attr);
     pthread_attr_setdetachstate(&attr, thread ? PTHREAD_CREATE_JOINABLE : PTHREAD_CREATE_DETACHED);
-    errno = pthread_create(&temp, &attr, start, arg);
+    auto* pthread_args = new adb_pthread_args{.func = start, .arg = arg};
+    errno = pthread_create(&temp, &attr, adb_pthread_wrapper, pthread_args);
     if (errno == 0) {
         if (thread) {
             *thread = temp;
@@ -731,6 +751,10 @@
     return errno == 0;
 }
 
+static __inline__ void __attribute__((noreturn)) adb_thread_exit() {
+    pthread_exit(nullptr);
+}
+
 static __inline__ int adb_thread_setname(const std::string& name) {
 #ifdef __APPLE__
     return pthread_setname_np(name.c_str());
diff --git a/adb/sysdeps_test.cpp b/adb/sysdeps_test.cpp
index 24a0d6f..360eaa7 100644
--- a/adb/sysdeps_test.cpp
+++ b/adb/sysdeps_test.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2065 The Android Open Source Project
+ * Copyright (C) 2016 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -20,10 +20,9 @@
 
 #include "sysdeps.h"
 
-static void* increment_atomic_int(void* c) {
+static void increment_atomic_int(void* c) {
     sleep(1);
     reinterpret_cast<std::atomic<int>*>(c)->fetch_add(1);
-    return nullptr;
 }
 
 TEST(sysdeps_thread, smoke) {
@@ -57,3 +56,14 @@
 
     ASSERT_EQ(500, counter.load());
 }
+
+TEST(sysdeps_thread, exit) {
+    adb_thread_t thread;
+    ASSERT_TRUE(adb_thread_create(
+        [](void*) {
+            adb_thread_exit();
+            for (;;) continue;
+        },
+        nullptr, &thread));
+    ASSERT_TRUE(adb_thread_join(thread));
+}
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 6020ad5..d9180bc 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -190,8 +190,7 @@
 //
 // read_transport thread reads data from a transport (representing a usb/tcp connection),
 // and makes the main thread call handle_packet().
-static void *read_transport_thread(void *_t)
-{
+static void read_transport_thread(void* _t) {
     atransport *t = reinterpret_cast<atransport*>(_t);
     apacket *p;
 
@@ -244,13 +243,11 @@
     D("%s: read_transport thread is exiting", t->serial);
     kick_transport(t);
     transport_unref(t);
-    return 0;
 }
 
 // write_transport thread gets packets sent by the main thread (through send_packet()),
 // and writes to a transport (representing a usb/tcp connection).
-static void *write_transport_thread(void *_t)
-{
+static void write_transport_thread(void* _t) {
     atransport *t = reinterpret_cast<atransport*>(_t);
     apacket *p;
     int active = 0;
@@ -295,7 +292,6 @@
     D("%s: write_transport thread is exiting, fd %d", t->serial, t->fd);
     kick_transport(t);
     transport_unref(t);
-    return 0;
 }
 
 static void kick_transport_locked(atransport* t) {
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index d2a375a..e6e699b 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -121,8 +121,7 @@
 }
 
 #if ADB_HOST
-static void *client_socket_thread(void *x)
-{
+static void client_socket_thread(void* x) {
     adb_thread_setname("client_socket_thread");
     D("transport: client_socket_thread() starting");
     while (true) {
@@ -135,13 +134,11 @@
         }
         sleep(1);
     }
-    return 0;
 }
 
 #else // ADB_HOST
 
-static void *server_socket_thread(void * arg)
-{
+static void server_socket_thread(void* arg) {
     int serverfd, fd;
     sockaddr_storage ss;
     sockaddr *addrp = reinterpret_cast<sockaddr*>(&ss);
@@ -174,7 +171,6 @@
         }
     }
     D("transport: server_socket_thread() exiting");
-    return 0;
 }
 
 /* This is relevant only for ADB daemon running inside the emulator. */
@@ -220,14 +216,13 @@
  *   the transport registration is completed. That's why we need to send the
  *   'start' request after the transport is registered.
  */
-static void *qemu_socket_thread(void * arg)
-{
-/* 'accept' request to the adb QEMUD service. */
-static const char _accept_req[] = "accept";
-/* 'start' request to the adb QEMUD service. */
-static const char _start_req[]  = "start";
-/* 'ok' reply from the adb QEMUD service. */
-static const char _ok_resp[]    = "ok";
+static void qemu_socket_thread(void* arg) {
+    /* 'accept' request to the adb QEMUD service. */
+    static const char _accept_req[] = "accept";
+    /* 'start' request to the adb QEMUD service. */
+    static const char _start_req[] = "start";
+    /* 'ok' reply from the adb QEMUD service. */
+    static const char _ok_resp[] = "ok";
 
     const int port = (int) (uintptr_t) arg;
     int res, fd;
@@ -247,7 +242,7 @@
          * implement adb QEMUD service. Fall back to the old TCP way. */
         D("adb service is not available. Falling back to TCP socket.");
         adb_thread_create(server_socket_thread, arg);
-        return 0;
+        return;
     }
 
     for(;;) {
@@ -275,21 +270,21 @@
             fd = qemu_pipe_open(con_name);
             if (fd < 0) {
                 D("adb service become unavailable.");
-                return 0;
+                return;
             }
         } else {
             D("Unable to send the '%s' request to ADB service.", _accept_req);
-            return 0;
+            return;
         }
     }
     D("transport: qemu_socket_thread() exiting");
-    return 0;
+    return;
 }
 #endif  // !ADB_HOST
 
 void local_init(int port)
 {
-    void* (*func)(void *);
+    adb_thread_func_t func;
     const char* debug_name = "";
 
 #if ADB_HOST
diff --git a/adb/usb_linux.cpp b/adb/usb_linux.cpp
index ed5d2d6..500898a 100644
--- a/adb/usb_linux.cpp
+++ b/adb/usb_linux.cpp
@@ -571,7 +571,7 @@
     register_usb_transport(done_usb, serial.c_str(), dev_path, done_usb->writeable);
 }
 
-static void* device_poll_thread(void* unused) {
+static void device_poll_thread(void*) {
     adb_thread_setname("device poll");
     D("Created device thread");
     while (true) {
@@ -580,7 +580,6 @@
         kick_disconnected_devices();
         sleep(1);
     }
-    return nullptr;
 }
 
 void usb_init() {
diff --git a/adb/usb_linux_client.cpp b/adb/usb_linux_client.cpp
index a4f1a70..c863ed2 100644
--- a/adb/usb_linux_client.cpp
+++ b/adb/usb_linux_client.cpp
@@ -232,10 +232,7 @@
     },
 };
 
-
-
-static void *usb_adb_open_thread(void *x)
-{
+static void usb_adb_open_thread(void* x) {
     struct usb_handle *usb = (struct usb_handle *)x;
     int fd;
 
@@ -270,7 +267,7 @@
     }
 
     // never gets here
-    return 0;
+    abort();
 }
 
 static int usb_adb_write(usb_handle *h, const void *data, int len)
@@ -434,8 +431,7 @@
     return;
 }
 
-static void *usb_ffs_open_thread(void *x)
-{
+static void usb_ffs_open_thread(void* x) {
     struct usb_handle *usb = (struct usb_handle *)x;
 
     adb_thread_setname("usb ffs open");
@@ -462,7 +458,7 @@
     }
 
     // never gets here
-    return 0;
+    abort();
 }
 
 static int usb_ffs_write(usb_handle* h, const void* data, int len) {
diff --git a/adb/usb_osx.cpp b/adb/usb_osx.cpp
index 148be1d..54d4c6c 100644
--- a/adb/usb_osx.cpp
+++ b/adb/usb_osx.cpp
@@ -400,9 +400,7 @@
     return NULL;
 }
 
-
-void* RunLoopThread(void* unused)
-{
+static void RunLoopThread(void* unused) {
     adb_thread_setname("RunLoop");
     InitUSB();
 
@@ -420,7 +418,6 @@
     IONotificationPortDestroy(notificationPort);
 
     LOG(DEBUG) << "RunLoopThread done";
-    return NULL;
 }
 
 static void usb_cleanup() {
diff --git a/adb/usb_windows.cpp b/adb/usb_windows.cpp
index e79008f..8ecca37 100644
--- a/adb/usb_windows.cpp
+++ b/adb/usb_windows.cpp
@@ -97,7 +97,7 @@
 
 /// Entry point for thread that polls (every second) for new usb interfaces.
 /// This routine calls find_devices in infinite loop.
-void* device_poll_thread(void* unused);
+static void device_poll_thread(void*);
 
 /// Initializes this module
 void usb_init();
@@ -172,7 +172,7 @@
   return 1;
 }
 
-void* device_poll_thread(void* unused) {
+void device_poll_thread(void*) {
   adb_thread_setname("Device Poll");
   D("Created device thread");
 
@@ -180,8 +180,6 @@
     find_devices();
     adb_sleep_ms(1000);
   }
-
-  return NULL;
 }
 
 static LRESULT CALLBACK _power_window_proc(HWND hwnd, UINT uMsg, WPARAM wParam,
@@ -203,7 +201,7 @@
   return DefWindowProcW(hwnd, uMsg, wParam, lParam);
 }
 
-static void* _power_notification_thread(void* unused) {
+static void _power_notification_thread(void*) {
   // This uses a thread with its own window message pump to get power
   // notifications. If adb runs from a non-interactive service account, this
   // might not work (not sure). If that happens to not work, we could use
@@ -255,8 +253,6 @@
   // shutting down. Not a big deal since the whole process will be going away
   // soon anyway.
   D("Power notification thread exiting");
-
-  return NULL;
 }
 
 void usb_init() {
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index 8d9c5a3..f8d4c4c 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -173,7 +173,7 @@
     return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
 }
 
-TEST(liblog, __android_log_bswrite) {
+static void bswrite_test(const char *message) {
     struct logger_list *logger_list;
 
     pid_t pid = getpid();
@@ -181,10 +181,30 @@
     ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
         LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
 
-    static const char buffer[] = "Hello World";
     log_time ts(android_log_clockid());
 
-    ASSERT_LT(0, __android_log_bswrite(0, buffer));
+    ASSERT_LT(0, __android_log_bswrite(0, message));
+    size_t num_lines = 1, size = 0, length = 0, total = 0;
+    const char *cp = message;
+    while (*cp) {
+        if (*cp == '\n') {
+            if (cp[1]) {
+                ++num_lines;
+            }
+        } else {
+            ++size;
+        }
+        ++cp;
+        ++total;
+        ++length;
+        if ((LOGGER_ENTRY_MAX_PAYLOAD - 4 - 1 - 4) <= length) {
+            break;
+        }
+    }
+    while (*cp) {
+        ++cp;
+        ++total;
+    }
     usleep(1000000);
 
     int count = 0;
@@ -199,7 +219,7 @@
 
         if ((log_msg.entry.sec < (ts.tv_sec - 1))
          || ((ts.tv_sec + 1) < log_msg.entry.sec)
-         || (log_msg.entry.len != (4 + 1 + 4 + sizeof(buffer) - 1))
+         || ((size_t)log_msg.entry.len != (4 + 1 + 4 + length))
          || (log_msg.id() != LOG_ID_EVENTS)) {
             continue;
         }
@@ -210,22 +230,22 @@
             continue;
         }
 
-        int len = get4LE(eventData + 4 + 1);
-        if (len == (sizeof(buffer) - 1)) {
+        size_t len = get4LE(eventData + 4 + 1);
+        if (len == total) {
             ++count;
 
             AndroidLogFormat *logformat = android_log_format_new();
             EXPECT_TRUE(NULL != logformat);
             AndroidLogEntry entry;
             char msgBuf[1024];
-            EXPECT_EQ(0, android_log_processBinaryLogBuffer(&log_msg.entry_v1,
-                                                            &entry,
-                                                            NULL,
-                                                            msgBuf,
-                                                            sizeof(msgBuf)));
-            fflush(stderr);
-            EXPECT_EQ((int)(19 + sizeof(buffer)),
-                      android_log_printLogLine(logformat, fileno(stderr), &entry));
+            int processBinaryLogBuffer = android_log_processBinaryLogBuffer(
+                &log_msg.entry_v1, &entry, NULL, msgBuf, sizeof(msgBuf));
+            EXPECT_EQ((length == total) ? 0 : -1, processBinaryLogBuffer);
+            if (processBinaryLogBuffer == 0) {
+                fflush(stderr);
+                EXPECT_EQ((int)((20 * num_lines) + size),
+                    android_log_printLogLine(logformat, fileno(stderr), &entry));
+            }
             android_log_format_free(logformat);
         }
     }
@@ -235,131 +255,27 @@
     android_logger_list_close(logger_list);
 }
 
-TEST(liblog, __android_log_bswrite__empty_string) {
-    struct logger_list *logger_list;
-
-    pid_t pid = getpid();
-
-    ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
-        LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
-
-    static const char buffer[] = "";
-    log_time ts(android_log_clockid());
-
-    ASSERT_LT(0, __android_log_bswrite(0, buffer));
-    usleep(1000000);
-
-    int count = 0;
-
-    for (;;) {
-        log_msg log_msg;
-        if (android_logger_list_read(logger_list, &log_msg) <= 0) {
-            break;
-        }
-
-        ASSERT_EQ(log_msg.entry.pid, pid);
-
-        if ((log_msg.entry.sec < (ts.tv_sec - 1))
-         || ((ts.tv_sec + 1) < log_msg.entry.sec)
-         || (log_msg.entry.len != (4 + 1 + 4))
-         || (log_msg.id() != LOG_ID_EVENTS)) {
-            continue;
-        }
-
-        char *eventData = log_msg.msg();
-
-        if (eventData[4] != EVENT_TYPE_STRING) {
-            continue;
-        }
-
-        int len = get4LE(eventData + 4 + 1);
-        if (len == (sizeof(buffer) - 1)) {
-            ++count;
-
-            AndroidLogFormat *logformat = android_log_format_new();
-            EXPECT_TRUE(NULL != logformat);
-            AndroidLogEntry entry;
-            char msgBuf[1024];
-            EXPECT_EQ(0, android_log_processBinaryLogBuffer(&log_msg.entry_v1,
-                                                            &entry,
-                                                            NULL,
-                                                            msgBuf,
-                                                            sizeof(msgBuf)));
-            fflush(stderr);
-            EXPECT_EQ((int)(19 + sizeof(buffer)),
-                      android_log_printLogLine(logformat, fileno(stderr), &entry));
-            android_log_format_free(logformat);
-        }
-    }
-
-    EXPECT_EQ(1, count);
-
-    android_logger_list_close(logger_list);
+TEST(liblog, __android_log_bswrite_and_print) {
+    bswrite_test("Hello World");
 }
 
-TEST(liblog, __android_log_bswrite__newline_prefix) {
-    struct logger_list *logger_list;
-
-    pid_t pid = getpid();
-
-    ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
-        LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
-
-    static const char buffer[] = "\nHello World\n";
-    log_time ts(android_log_clockid());
-
-    ASSERT_LT(0, __android_log_bswrite(0, buffer));
-    usleep(1000000);
-
-    int count = 0;
-
-    for (;;) {
-        log_msg log_msg;
-        if (android_logger_list_read(logger_list, &log_msg) <= 0) {
-            break;
-        }
-
-        ASSERT_EQ(log_msg.entry.pid, pid);
-
-        if ((log_msg.entry.sec < (ts.tv_sec - 1))
-         || ((ts.tv_sec + 1) < log_msg.entry.sec)
-         || (log_msg.entry.len != (4 + 1 + 4 + sizeof(buffer) - 1))
-         || (log_msg.id() != LOG_ID_EVENTS)) {
-            continue;
-        }
-
-        char *eventData = log_msg.msg();
-
-        if (eventData[4] != EVENT_TYPE_STRING) {
-            continue;
-        }
-
-        int len = get4LE(eventData + 4 + 1);
-        if (len == (sizeof(buffer) - 1)) {
-            ++count;
-
-            AndroidLogFormat *logformat = android_log_format_new();
-            EXPECT_TRUE(NULL != logformat);
-            AndroidLogEntry entry;
-            char msgBuf[1024];
-            EXPECT_EQ(0, android_log_processBinaryLogBuffer(&log_msg.entry_v1,
-                                                            &entry,
-                                                            NULL,
-                                                            msgBuf,
-                                                            sizeof(msgBuf)));
-            fflush(stderr);
-            EXPECT_EQ((int)(19 + 19 - 1 + sizeof(buffer)),
-                      android_log_printLogLine(logformat, fileno(stderr), &entry));
-            android_log_format_free(logformat);
-        }
-    }
-
-    EXPECT_EQ(1, count);
-
-    android_logger_list_close(logger_list);
+TEST(liblog, __android_log_bswrite_and_print__empty_string) {
+    bswrite_test("");
 }
 
-TEST(liblog, __android_log_buf_write__newline_prefix) {
+TEST(liblog, __android_log_bswrite_and_print__newline_prefix) {
+    bswrite_test("\nHello World\n");
+}
+
+TEST(liblog, __android_log_bswrite_and_print__newline_space_prefix) {
+    bswrite_test("\n Hello World \n");
+}
+
+TEST(liblog, __android_log_bswrite_and_print__multiple_newline) {
+    bswrite_test("one\ntwo\nthree\nfour\nfive\nsix\nseven\neight\nnine\nten");
+}
+
+static void buf_write_test(const char *message) {
     struct logger_list *logger_list;
 
     pid_t pid = getpid();
@@ -368,11 +284,26 @@
         LOG_ID_MAIN, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
 
     static const char tag[] = "TEST__android_log_buf_write";
-    static const char buffer[] = "\nHello World\n";
     log_time ts(android_log_clockid());
 
     EXPECT_LT(0, __android_log_buf_write(LOG_ID_MAIN, ANDROID_LOG_INFO,
-                                         tag, buffer));
+                                         tag, message));
+    size_t num_lines = 1, size = 0, length = 0;
+    const char *cp = message;
+    while (*cp) {
+        if (*cp == '\n') {
+            if (cp[1]) {
+                ++num_lines;
+            }
+        } else {
+            ++size;
+        }
+        ++length;
+        if ((LOGGER_ENTRY_MAX_PAYLOAD - 2 - sizeof(tag)) <= length) {
+            break;
+        }
+        ++cp;
+    }
     usleep(1000000);
 
     int count = 0;
@@ -387,7 +318,7 @@
 
         if ((log_msg.entry.sec < (ts.tv_sec - 1))
          || ((ts.tv_sec + 1) < log_msg.entry.sec)
-         || (log_msg.entry.len != (sizeof(tag) + sizeof(buffer) + 1))
+         || ((size_t)log_msg.entry.len != (sizeof(tag) + length + 2))
          || (log_msg.id() != LOG_ID_MAIN)) {
             continue;
         }
@@ -397,11 +328,14 @@
         AndroidLogFormat *logformat = android_log_format_new();
         EXPECT_TRUE(NULL != logformat);
         AndroidLogEntry entry;
-        EXPECT_EQ(0, android_log_processLogBuffer(&log_msg.entry_v1,
-                                                  &entry));
-        fflush(stderr);
-        EXPECT_EQ((int)(11 + 11 + sizeof(tag) + sizeof(tag) + sizeof(buffer) - 3),
-                  android_log_printLogLine(logformat, fileno(stderr), &entry));
+        int processLogBuffer = android_log_processLogBuffer(&log_msg.entry_v1,
+                                                            &entry);
+        EXPECT_EQ(0, processLogBuffer);
+        if (processLogBuffer == 0) {
+            fflush(stderr);
+            EXPECT_EQ((int)(((11 + sizeof(tag)) * num_lines) + size),
+                android_log_printLogLine(logformat, fileno(stderr), &entry));
+        }
         android_log_format_free(logformat);
     }
 
@@ -410,6 +344,18 @@
     android_logger_list_close(logger_list);
 }
 
+TEST(liblog, __android_log_buf_write_and_print__empty) {
+    buf_write_test("");
+}
+
+TEST(liblog, __android_log_buf_write_and_print__newline_prefix) {
+    buf_write_test("\nHello World\n");
+}
+
+TEST(liblog, __android_log_buf_write_and_print__newline_space_prefix) {
+    buf_write_test("\n Hello World \n");
+}
+
 TEST(liblog, __security) {
     static const char persist_key[] = "persist.logd.security";
     static const char readonly_key[] = "ro.device_owner";
@@ -1691,6 +1637,14 @@
     android_logger_list_close(logger_list);
 }
 
+TEST(liblog, __android_log_bswrite_and_print___max) {
+    bswrite_test(max_payload_buf);
+}
+
+TEST(liblog, __android_log_buf_write_and_print__max) {
+    buf_write_test(max_payload_buf);
+}
+
 TEST(liblog, android_errorWriteLog__android_logger_list_read__success) {
     const int TAG = 123456785;
     const char SUBTAG[] = "test-subtag";