Emulator: enhance logcat -Q to handle qemu pipe device

Upon opening, qemu pipe (a.k.a. goldfish pipe) requires a purpose
string so that emulator can route the content to the right channel
on the host.

This CL will ask emulator to send the content to pipe based 'logcat'
service on the host.

Change-Id:  Icc71f81d5b95b64ea315fe10da82ff704416e449
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index 4da5030..8134936 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -41,6 +41,7 @@
 #include <vector>
 
 #include <android-base/file.h>
+#include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <cutils/sched_policy.h>
@@ -1195,39 +1196,71 @@
             } break;
 
             case 'Q':
-#define KERNEL_OPTION "androidboot.logcat="
+#define LOGCAT_FILTER "androidboot.logcat="
+#define CONSOLE_PIPE_OPTION "androidboot.consolepipe="
 #define CONSOLE_OPTION "androidboot.console="
+#define QEMU_PROPERTY "ro.kernel.qemu"
+#define QEMU_CMDLINE "qemu.cmdline"
                 // This is a *hidden* option used to start a version of logcat
                 // in an emulated device only.  It basically looks for
                 // androidboot.logcat= on the kernel command line.  If
                 // something is found, it extracts a log filter and uses it to
-                // run the program.  If nothing is found, the program should
-                // quit immediately.
+                // run the program. The logcat output will go to consolepipe if
+                // androiboot.consolepipe (e.g. qemu_pipe) is given, otherwise,
+                // it goes to androidboot.console (e.g. tty)
                 {
-                    std::string cmdline;
-                    android::base::ReadFileToString("/proc/cmdline", &cmdline);
-
-                    const char* logcat = strstr(cmdline.c_str(), KERNEL_OPTION);
-                    // if nothing found or invalid filters, exit quietly
-                    if (!logcat) {
+                    // if not in emulator, exit quietly
+                    if (false == android::base::GetBoolProperty(QEMU_PROPERTY, false)) {
                         context->retval = EXIT_SUCCESS;
                         goto exit;
                     }
 
-                    const char* p = logcat + strlen(KERNEL_OPTION);
+                    std::string cmdline = android::base::GetProperty(QEMU_CMDLINE, "");
+                    if (cmdline.empty()) {
+                        android::base::ReadFileToString("/proc/cmdline", &cmdline);
+                    }
+
+                    const char* logcatFilter = strstr(cmdline.c_str(), LOGCAT_FILTER);
+                    // if nothing found or invalid filters, exit quietly
+                    if (!logcatFilter) {
+                        context->retval = EXIT_SUCCESS;
+                        goto exit;
+                    }
+
+                    const char* p = logcatFilter + strlen(LOGCAT_FILTER);
                     const char* q = strpbrk(p, " \t\n\r");
                     if (!q) q = p + strlen(p);
                     forceFilters = std::string(p, q);
 
-                    // redirect our output to the emulator console
+                    // redirect our output to the emulator console pipe or console
+                    const char* consolePipe =
+                        strstr(cmdline.c_str(), CONSOLE_PIPE_OPTION);
                     const char* console =
                         strstr(cmdline.c_str(), CONSOLE_OPTION);
-                    if (!console) break;
 
-                    p = console + strlen(CONSOLE_OPTION);
+                    if (consolePipe) {
+                        p = consolePipe + strlen(CONSOLE_PIPE_OPTION);
+                    } else if (console) {
+                        p = console + strlen(CONSOLE_OPTION);
+                    } else {
+                        context->retval = EXIT_FAILURE;
+                        goto exit;
+                    }
+
                     q = strpbrk(p, " \t\n\r");
                     int len = q ? q - p : strlen(p);
                     std::string devname = "/dev/" + std::string(p, len);
+                    std::string pipePurpose("pipe:logcat");
+                    if (consolePipe) {
+                        // example: "qemu_pipe,pipe:logcat"
+                        // upon opening of /dev/qemu_pipe, the "pipe:logcat"
+                        // string with trailing '\0' should be written to the fd
+                        size_t pos = devname.find(",");
+                        if (pos != std::string::npos) {
+                            pipePurpose = devname.substr(pos + 1);
+                            devname = devname.substr(0, pos);
+                        }
+                    }
                     cmdline.erase();
 
                     if (context->error) {
@@ -1239,6 +1272,16 @@
                     devname.erase();
                     if (!fp) break;
 
+                    if (consolePipe) {
+                        // need the trailing '\0'
+                        if(!android::base::WriteFully(fileno(fp), pipePurpose.c_str(),
+                                    pipePurpose.size() + 1)) {
+                            fclose(fp);
+                            context->retval = EXIT_FAILURE;
+                            goto exit;
+                        }
+                    }
+
                     // close output and error channels, replace with console
                     android::close_output(context);
                     android::close_error(context);