LogReader.cpp revision 2ee4371cb73cd23a8615593956de2e4f0cea4a98
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 <utils/Errors.h> 20 21#include <time.h> 22#include <unistd.h> 23 24using namespace android; 25using namespace std; 26 27namespace android { 28namespace os { 29namespace statsd { 30 31#define SNOOZE_INITIAL_MS 100 32#define SNOOZE_MAX_MS (10 * 60 * 1000) // Ten minutes 33 34LogReader::LogReader(const sp<LogListener>& listener) : mListener(listener) { 35} 36 37LogReader::~LogReader() { 38} 39 40void LogReader::Run() { 41 int nextSnoozeMs = SNOOZE_INITIAL_MS; 42 43 // In an ideal world, this outer loop will only ever run one iteration, but it 44 // exists to handle crashes in logd. The inner loop inside connect_and_read() 45 // reads from logd forever, but if that read fails, we fall out to the outer 46 // loop, do the backoff (resetting the backoff timeout if we successfully read 47 // something), and then try again. 48 while (true) { 49 // Connect and read 50 int lineCount = connect_and_read(); 51 52 // Figure out how long to sleep. 53 if (lineCount > 0) { 54 // If we managed to read at least one line, reset the backoff 55 nextSnoozeMs = SNOOZE_INITIAL_MS; 56 } else { 57 // Otherwise, expontial backoff 58 nextSnoozeMs *= 1.5f; 59 if (nextSnoozeMs > 10 * 60 * 1000) { 60 // Don't wait for toooo long. 61 nextSnoozeMs = SNOOZE_MAX_MS; 62 } 63 } 64 65 // Sleep 66 timespec ts; 67 timespec rem; 68 ts.tv_sec = nextSnoozeMs / 1000; 69 ts.tv_nsec = (nextSnoozeMs % 1000) * 1000000L; 70 while (nanosleep(&ts, &rem) == -1) { 71 if (errno == EINTR) { 72 ts = rem; 73 } 74 // other errors are basically impossible 75 } 76 } 77} 78 79int LogReader::connect_and_read() { 80 int lineCount = 0; 81 status_t err; 82 logger_list* loggers; 83 logger* eventLogger; 84 85 // Prepare the logging context 86 loggers = android_logger_list_alloc(ANDROID_LOG_RDONLY, 87 /* don't stop after N lines */ 0, 88 /* no pid restriction */ 0); 89 90 // Open the buffer(s) 91 eventLogger = android_logger_open(loggers, LOG_ID_STATS); 92 93 // Read forever 94 if (eventLogger) { 95 96 while (true) { 97 log_msg msg; 98 99 // Read a message 100 err = android_logger_list_read(loggers, &msg); 101 // err = 0 - no content, unexpected connection drop or EOF. 102 // err = +ive number - size of retrieved data from logger 103 // err = -ive number, OS supplied error _except_ for -EAGAIN 104 if (err <= 0) { 105 fprintf(stderr, "logcat read failure: %s\n", strerror(err)); 106 break; 107 } 108 109 // Record that we read one (used above to know how to snooze). 110 lineCount++; 111 112 // Wrap it in a LogEvent object 113 LogEvent event(msg); 114 115 // Call the listener 116 mListener->OnLogEvent(&event); 117 } 118 } 119 120 // Free the logger list and close the individual loggers 121 android_logger_list_free(loggers); 122 123 return lineCount; 124} 125 126} // namespace statsd 127} // namespace os 128} // namespace android 129