LogReader.cpp revision 9fc9edf95a308f5884bf541cac81ce1f41aba0ba
1/* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "logd/LogReader.h" 18 19#include <log/log_read.h> 20 21#include <utils/Errors.h> 22 23#include <time.h> 24#include <unistd.h> 25 26using namespace android; 27using namespace std; 28 29namespace android { 30namespace os { 31namespace statsd { 32 33#define SNOOZE_INITIAL_MS 100 34#define SNOOZE_MAX_MS (10 * 60 * 1000) // Ten minutes 35 36LogReader::LogReader(const sp<LogListener>& listener) : mListener(listener) { 37} 38 39LogReader::~LogReader() { 40} 41 42void LogReader::Run() { 43 int nextSnoozeMs = SNOOZE_INITIAL_MS; 44 45 // In an ideal world, this outer loop will only ever run one iteration, but it 46 // exists to handle crashes in logd. The inner loop inside connect_and_read() 47 // reads from logd forever, but if that read fails, we fall out to the outer 48 // loop, do the backoff (resetting the backoff timeout if we successfully read 49 // something), and then try again. 50 while (true) { 51 // Connect and read 52 int lineCount = connect_and_read(); 53 54 // Figure out how long to sleep. 55 if (lineCount > 0) { 56 // If we managed to read at least one line, reset the backoff 57 nextSnoozeMs = SNOOZE_INITIAL_MS; 58 } else { 59 // Otherwise, expontial backoff 60 nextSnoozeMs *= 1.5f; 61 if (nextSnoozeMs > 10 * 60 * 1000) { 62 // Don't wait for toooo long. 63 nextSnoozeMs = SNOOZE_MAX_MS; 64 } 65 } 66 67 // Sleep 68 timespec ts; 69 timespec rem; 70 ts.tv_sec = nextSnoozeMs / 1000; 71 ts.tv_nsec = (nextSnoozeMs % 1000) * 1000000L; 72 while (nanosleep(&ts, &rem) == -1) { 73 if (errno == EINTR) { 74 ts = rem; 75 } 76 // other errors are basically impossible 77 } 78 } 79} 80 81int LogReader::connect_and_read() { 82 int lineCount = 0; 83 status_t err; 84 logger_list* loggers; 85 logger* eventLogger; 86 87 // Prepare the logging context 88 loggers = android_logger_list_alloc(ANDROID_LOG_RDONLY, 89 /* don't stop after N lines */ 0, 90 /* no pid restriction */ 0); 91 92 // Open the buffer(s) 93 eventLogger = android_logger_open(loggers, LOG_ID_STATS); 94 95 // Read forever 96 if (eventLogger) { 97 while (true) { 98 log_msg msg; 99 100 // Read a message 101 err = android_logger_list_read(loggers, &msg); 102 if (err < 0) { 103 fprintf(stderr, "logcat read failure: %s\n", strerror(err)); 104 break; 105 } 106 107 // Record that we read one (used above to know how to snooze). 108 lineCount++; 109 110 // Call the listener 111 mListener->OnLogEvent(msg); 112 } 113 } 114 115 // Free the logger list and close the individual loggers 116 android_logger_list_free(loggers); 117 118 return lineCount; 119} 120 121} // namespace statsd 122} // namespace os 123} // namespace android 124