liblog: add private android_log_write_list_buffer()

Allows us to compose an event message for our own in-memory purposes.
Will be used to compose an event message in logd and directly write
it to just the pmsg buffer.  Provide an internal enhanced C++ wrapper
for event handling.

Test: gTest liblog-unit-tests --gtest_filter=liblog.android_log_write_list_buffer
Bug: 31456426
Change-Id: I98246898ba580f9e506baba8af2fd1b26a2a8aae
diff --git a/include/log/log_event_list.h b/include/log/log_event_list.h
index 04c1cd6..31d49b2 100644
--- a/include/log/log_event_list.h
+++ b/include/log/log_event_list.h
@@ -116,6 +116,7 @@
 /* android_log_list C++ helpers */
 extern "C++" {
 class android_log_event_list {
+friend class __android_log_event_list;
 
 private:
     android_log_context ctx;
diff --git a/include/private/android_logger.h b/include/private/android_logger.h
index f3c6cf7..9f81b1f 100644
--- a/include/private/android_logger.h
+++ b/include/private/android_logger.h
@@ -25,6 +25,13 @@
 #include <stdint.h>
 #include <sys/types.h>
 
+#if (defined(__cplusplus) && defined(_USING_LIBCXX))
+extern "C++" {
+#include <string>
+}
+#endif
+
+#include <log/log_event_list.h>
 #include <log/log.h>
 
 #define LOGGER_MAGIC 'l'
@@ -146,6 +153,40 @@
 unsigned long __android_logger_get_buffer_size(log_id_t logId);
 bool __android_logger_valid_buffer_size(unsigned long value);
 
+/* Retrieve the composed event buffer */
+int android_log_write_list_buffer(android_log_context ctx, const char** msg);
+
+#ifdef __cplusplus
+#ifdef __class_android_log_event_list_defined
+#ifndef __class_android_log_event_list_private_defined
+#define __class_android_log_event_list_private_defined
+/* android_log_context C++ helpers */
+extern "C++" {
+class __android_log_event_list : public android_log_event_list {
+    __android_log_event_list(const android_log_event_list&) = delete;
+    void operator =(const __android_log_event_list&) = delete;
+
+public:
+    explicit __android_log_event_list(int tag) : android_log_event_list(tag) { }
+    explicit __android_log_event_list(log_msg& log_msg) : android_log_event_list(log_msg) { }
+
+#if defined(_USING_LIBCXX)
+    operator std::string() {
+        if (ret) return std::string("");
+        const char* cp = NULL;
+        ssize_t len = android_log_write_list_buffer(ctx, &cp);
+        if (len < 0) ret = len;
+        if (!cp || (len <= 0)) return std::string("");
+        return std::string(cp, len);
+    }
+#endif
+
+};
+}
+#endif
+#endif
+#endif
+
 #if defined(__cplusplus)
 }
 #endif
diff --git a/liblog/log_event_list.c b/liblog/log_event_list.c
index 8303b63..9ac1d30 100644
--- a/liblog/log_event_list.c
+++ b/liblog/log_event_list.c
@@ -320,7 +320,7 @@
     context->storage[1] = context->count[0];
     len = context->len = context->pos;
     msg = (const char *)context->storage;
-    /* it'snot a list */
+    /* it's not a list */
     if (context->count[0] <= 1) {
         len -= sizeof(uint8_t) + sizeof(uint8_t);
         if (len < 0) {
@@ -333,6 +333,38 @@
         __android_log_security_bwrite(context->tag, msg, len);
 }
 
+LIBLOG_ABI_PRIVATE int android_log_write_list_buffer(android_log_context ctx,
+                                                     const char **buffer) {
+    android_log_context_internal *context;
+    const char *msg;
+    ssize_t len;
+
+    context = (android_log_context_internal *)ctx;
+    if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
+        return -EBADF;
+    }
+    if (context->list_nest_depth) {
+        return -EIO;
+    }
+    if (buffer == NULL) {
+        return -EFAULT;
+    }
+    /* NB: if there was overflow, then log is truncated. Nothing reported */
+    context->storage[1] = context->count[0];
+    len = context->len = context->pos;
+    msg = (const char *)context->storage;
+    /* it's not a list */
+    if (context->count[0] <= 1) {
+        len -= sizeof(uint8_t) + sizeof(uint8_t);
+        if (len < 0) {
+            len = 0;
+        }
+        msg += sizeof(uint8_t) + sizeof(uint8_t);
+    }
+    *buffer = msg;
+    return len;
+}
+
 /*
  * Extract a 4-byte value from a byte stream.
  */
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index 9c418c1..02a572d 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -2651,6 +2651,19 @@
     ASSERT_TRUE(NULL == ctx);
 }
 
+TEST(liblog, android_log_write_list_buffer) {
+    __android_log_event_list ctx(1005);
+    ctx << 1005 << "tag_def" << "(tag|1),(name|3),(format|3)";
+    std::string buffer(ctx);
+    ctx.close();
+
+    char msgBuf[1024];
+    memset(msgBuf, 0, sizeof(msgBuf));
+    EXPECT_EQ(android_log_buffer_to_string(buffer.data(), buffer.length(),
+                                           msgBuf, sizeof(msgBuf)), 0);
+    EXPECT_STREQ(msgBuf, "[1005,tag_def,(tag|1),(name|3),(format|3)]");
+}
+
 static const char __pmsg_file[] =
         "/data/william-shakespeare/MuchAdoAboutNothing.txt";