From 94aab86d57ebd8ff6d9b542080538252e9581cf1 Mon Sep 17 00:00:00 2001 From: bohu Date: Tue, 21 Feb 2017 14:31:19 -0800 Subject: [PATCH] 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 --- logcat/logcat.cpp | 69 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 56 insertions(+), 13 deletions(-) diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp index 4da503038..813493699 100644 --- a/logcat/logcat.cpp +++ b/logcat/logcat.cpp @@ -41,6 +41,7 @@ #include #include +#include #include #include #include @@ -1195,39 +1196,71 @@ static int __logcat(android_logcat_context_internal* context) { } 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 @@ static int __logcat(android_logcat_context_internal* context) { 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);