• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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