diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp index 4da503038384986dff9d620e0522890c6164964d..813493699135758608a54a5cdc00a96028942687 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); + // if not in emulator, exit quietly + if (false == android::base::GetBoolProperty(QEMU_PROPERTY, false)) { + context->retval = EXIT_SUCCESS; + goto exit; + } + + std::string cmdline = android::base::GetProperty(QEMU_CMDLINE, ""); + if (cmdline.empty()) { + android::base::ReadFileToString("/proc/cmdline", &cmdline); + } - const char* logcat = strstr(cmdline.c_str(), KERNEL_OPTION); + const char* logcatFilter = strstr(cmdline.c_str(), LOGCAT_FILTER); // if nothing found or invalid filters, exit quietly - if (!logcat) { + if (!logcatFilter) { context->retval = EXIT_SUCCESS; goto exit; } - const char* p = logcat + strlen(KERNEL_OPTION); + 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);