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