blob: 9ae95f99608e3d9728de4321324fa0d1b0758b30 [file] [log] [blame]
Mark Salyzynae4d9282014-10-15 08:49:39 -07001/*
2 * Copyright (C) 2014 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 <ctype.h>
18#include <errno.h>
19#include <inttypes.h>
20#include <limits.h>
21#include <stdarg.h>
22#include <stdlib.h>
Mark Salyzyn317bfb92016-02-23 08:55:43 -080023#include <string.h>
Mark Salyzynae4d9282014-10-15 08:49:39 -070024#include <sys/prctl.h>
25#include <sys/uio.h>
26#include <syslog.h>
27
Mark Salyzyn83b24782016-08-11 16:07:10 -070028#include <private/android_filesystem_config.h>
Mark Salyzyn501c3732017-03-10 14:31:54 -080029#include <private/android_logger.h>
Mark Salyzynae4d9282014-10-15 08:49:39 -070030
Mark Salyzyn317bfb92016-02-23 08:55:43 -080031#include "LogBuffer.h"
Mark Salyzynae4d9282014-10-15 08:49:39 -070032#include "LogKlog.h"
Mark Salyzyn317bfb92016-02-23 08:55:43 -080033#include "LogReader.h"
Mark Salyzynae4d9282014-10-15 08:49:39 -070034
Mark Salyzyn501c3732017-03-10 14:31:54 -080035#define KMSG_PRIORITY(PRI) \
36 '<', '0' + (LOG_SYSLOG | (PRI)) / 10, '0' + (LOG_SYSLOG | (PRI)) % 10, '>'
Mark Salyzynae4d9282014-10-15 08:49:39 -070037
38static const char priority_message[] = { KMSG_PRIORITY(LOG_INFO), '\0' };
39
Mark Salyzyn2c3b3002015-05-22 15:23:44 -070040// Parsing is hard
41
42// called if we see a '<', s is the next character, returns pointer after '>'
Mark Salyzyn501c3732017-03-10 14:31:54 -080043static char* is_prio(char* s, size_t len) {
Mark Salyzynea1a2412015-09-02 07:39:53 -070044 if (!len || !isdigit(*s++)) {
Mark Salyzyn2c3b3002015-05-22 15:23:44 -070045 return NULL;
46 }
Mark Salyzynea1a2412015-09-02 07:39:53 -070047 --len;
48 static const size_t max_prio_len = (len < 4) ? len : 4;
49 size_t priolen = 0;
Mark Salyzyn2c3b3002015-05-22 15:23:44 -070050 char c;
Mark Salyzynea1a2412015-09-02 07:39:53 -070051 while (((c = *s++)) && (++priolen <= max_prio_len)) {
Mark Salyzynee49c6a2015-06-12 14:59:42 -070052 if (!isdigit(c)) {
Mark Salyzyn46d159d2015-08-26 09:30:00 -070053 return ((c == '>') && (*s == '[')) ? s : NULL;
Mark Salyzyn2c3b3002015-05-22 15:23:44 -070054 }
55 }
56 return NULL;
57}
58
59// called if we see a '[', s is the next character, returns pointer after ']'
Mark Salyzyn501c3732017-03-10 14:31:54 -080060static char* is_timestamp(char* s, size_t len) {
Mark Salyzynea1a2412015-09-02 07:39:53 -070061 while (len && (*s == ' ')) {
Mark Salyzyn2c3b3002015-05-22 15:23:44 -070062 ++s;
Mark Salyzynea1a2412015-09-02 07:39:53 -070063 --len;
Mark Salyzyn2c3b3002015-05-22 15:23:44 -070064 }
Mark Salyzynea1a2412015-09-02 07:39:53 -070065 if (!len || !isdigit(*s++)) {
Mark Salyzyn2c3b3002015-05-22 15:23:44 -070066 return NULL;
67 }
Mark Salyzynea1a2412015-09-02 07:39:53 -070068 --len;
Mark Salyzyn2c3b3002015-05-22 15:23:44 -070069 bool first_period = true;
70 char c;
Mark Salyzynea1a2412015-09-02 07:39:53 -070071 while (len && ((c = *s++))) {
72 --len;
Mark Salyzyn2c3b3002015-05-22 15:23:44 -070073 if ((c == '.') && first_period) {
74 first_period = false;
Mark Salyzynee49c6a2015-06-12 14:59:42 -070075 } else if (!isdigit(c)) {
76 return ((c == ']') && !first_period && (*s == ' ')) ? s : NULL;
Mark Salyzyn2c3b3002015-05-22 15:23:44 -070077 }
78 }
79 return NULL;
80}
81
82// Like strtok_r with "\r\n" except that we look for log signatures (regex)
Mark Salyzyn501c3732017-03-10 14:31:54 -080083// \(\(<[0-9]\{1,4\}>\)\([[] *[0-9]+[.][0-9]+[]] \)\{0,1\}\|[[]
84// *[0-9]+[.][0-9]+[]] \)
Mark Salyzyn2c3b3002015-05-22 15:23:44 -070085// and split if we see a second one without a newline.
Mark Salyzyn151beac2015-09-04 11:37:42 -070086// We allow nuls in content, monitoring the overall length and sub-length of
87// the discovered tokens.
Mark Salyzyn2c3b3002015-05-22 15:23:44 -070088
Mark Salyzyn501c3732017-03-10 14:31:54 -080089#define SIGNATURE_MASK 0xF0
Mark Salyzyn2c3b3002015-05-22 15:23:44 -070090// <digit> following ('0' to '9' masked with ~SIGNATURE_MASK) added to signature
Mark Salyzyn501c3732017-03-10 14:31:54 -080091#define LESS_THAN_SIG SIGNATURE_MASK
92#define OPEN_BRACKET_SIG ((SIGNATURE_MASK << 1) & SIGNATURE_MASK)
Mark Salyzyn2c3b3002015-05-22 15:23:44 -070093// space is one more than <digit> of 9
Mark Salyzyn3e21de22015-06-08 14:51:30 -070094#define OPEN_BRACKET_SPACE ((char)(OPEN_BRACKET_SIG | 10))
Mark Salyzyn2c3b3002015-05-22 15:23:44 -070095
Mark Salyzyn501c3732017-03-10 14:31:54 -080096char* log_strntok_r(char* s, size_t* len, char** last, size_t* sublen) {
Mark Salyzynea1a2412015-09-02 07:39:53 -070097 *sublen = 0;
98 if (!*len) {
99 return NULL;
100 }
Mark Salyzyn2c3b3002015-05-22 15:23:44 -0700101 if (!s) {
102 if (!(s = *last)) {
103 return NULL;
104 }
105 // fixup for log signature split <,
106 // LESS_THAN_SIG + <digit>
107 if ((*s & SIGNATURE_MASK) == LESS_THAN_SIG) {
108 *s = (*s & ~SIGNATURE_MASK) + '0';
109 *--s = '<';
Mark Salyzynea1a2412015-09-02 07:39:53 -0700110 ++*len;
Mark Salyzyn2c3b3002015-05-22 15:23:44 -0700111 }
112 // fixup for log signature split [,
113 // OPEN_BRACKET_SPACE is space, OPEN_BRACKET_SIG + <digit>
114 if ((*s & SIGNATURE_MASK) == OPEN_BRACKET_SIG) {
115 if (*s == OPEN_BRACKET_SPACE) {
116 *s = ' ';
117 } else {
118 *s = (*s & ~SIGNATURE_MASK) + '0';
119 }
120 *--s = '[';
Mark Salyzynea1a2412015-09-02 07:39:53 -0700121 ++*len;
Mark Salyzyn2c3b3002015-05-22 15:23:44 -0700122 }
123 }
124
Mark Salyzynea1a2412015-09-02 07:39:53 -0700125 while (*len && ((*s == '\r') || (*s == '\n'))) {
126 ++s;
127 --*len;
128 }
Mark Salyzyn2c3b3002015-05-22 15:23:44 -0700129
Mark Salyzynea1a2412015-09-02 07:39:53 -0700130 if (!*len) {
Mark Salyzyn2c3b3002015-05-22 15:23:44 -0700131 *last = NULL;
132 return NULL;
133 }
134 char *peek, *tok = s;
135
136 for (;;) {
Mark Salyzynea1a2412015-09-02 07:39:53 -0700137 if (*len == 0) {
Mark Salyzyn2c3b3002015-05-22 15:23:44 -0700138 *last = NULL;
139 return tok;
Mark Salyzynea1a2412015-09-02 07:39:53 -0700140 }
141 char c = *s++;
142 --*len;
143 size_t adjust;
144 switch (c) {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800145 case '\r':
146 case '\n':
Mark Salyzyn2c3b3002015-05-22 15:23:44 -0700147 s[-1] = '\0';
Mark Salyzyn2c3b3002015-05-22 15:23:44 -0700148 *last = s;
149 return tok;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800150
151 case '<':
152 peek = is_prio(s, *len);
153 if (!peek) {
154 break;
155 }
156 if (s != (tok + 1)) { // not first?
157 s[-1] = '\0';
158 *s &= ~SIGNATURE_MASK;
159 *s |= LESS_THAN_SIG; // signature for '<'
160 *last = s;
161 return tok;
162 }
Mark Salyzynea1a2412015-09-02 07:39:53 -0700163 adjust = peek - s;
164 if (adjust > *len) {
165 adjust = *len;
166 }
167 *sublen += adjust;
168 *len -= adjust;
Mark Salyzyn2c3b3002015-05-22 15:23:44 -0700169 s = peek;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800170 if ((*s == '[') && ((peek = is_timestamp(s + 1, *len - 1)))) {
171 adjust = peek - s;
172 if (adjust > *len) {
173 adjust = *len;
174 }
175 *sublen += adjust;
176 *len -= adjust;
177 s = peek;
Mark Salyzyn2c3b3002015-05-22 15:23:44 -0700178 }
Mark Salyzyn501c3732017-03-10 14:31:54 -0800179 break;
180
181 case '[':
182 peek = is_timestamp(s, *len);
183 if (!peek) {
184 break;
185 }
186 if (s != (tok + 1)) { // not first?
187 s[-1] = '\0';
188 if (*s == ' ') {
189 *s = OPEN_BRACKET_SPACE;
190 } else {
191 *s &= ~SIGNATURE_MASK;
192 *s |= OPEN_BRACKET_SIG; // signature for '['
193 }
194 *last = s;
195 return tok;
196 }
197 adjust = peek - s;
198 if (adjust > *len) {
199 adjust = *len;
200 }
201 *sublen += adjust;
202 *len -= adjust;
203 s = peek;
204 break;
Mark Salyzyn2c3b3002015-05-22 15:23:44 -0700205 }
Mark Salyzynea1a2412015-09-02 07:39:53 -0700206 ++*sublen;
Mark Salyzyn2c3b3002015-05-22 15:23:44 -0700207 }
Mark Salyzyn618d0de2015-07-13 10:19:34 -0700208 // NOTREACHED
Mark Salyzyn2c3b3002015-05-22 15:23:44 -0700209}
210
Mark Salyzyn10b82b62015-12-28 15:33:01 -0800211log_time LogKlog::correction =
212 (log_time(CLOCK_REALTIME) < log_time(CLOCK_MONOTONIC))
213 ? log_time::EPOCH
214 : (log_time(CLOCK_REALTIME) - log_time(CLOCK_MONOTONIC));
Mark Salyzynae4d9282014-10-15 08:49:39 -0700215
Mark Salyzyn501c3732017-03-10 14:31:54 -0800216LogKlog::LogKlog(LogBuffer* buf, LogReader* reader, int fdWrite, int fdRead,
217 bool auditd)
218 : SocketListener(fdRead, false),
219 logbuf(buf),
220 reader(reader),
221 signature(CLOCK_MONOTONIC),
222 initialized(false),
223 enableLogging(true),
224 auditd(auditd) {
Mark Salyzynae4d9282014-10-15 08:49:39 -0700225 static const char klogd_message[] = "%slogd.klogd: %" PRIu64 "\n";
226 char buffer[sizeof(priority_message) + sizeof(klogd_message) + 20 - 4];
227 snprintf(buffer, sizeof(buffer), klogd_message, priority_message,
Mark Salyzyn501c3732017-03-10 14:31:54 -0800228 signature.nsec());
Mark Salyzynae4d9282014-10-15 08:49:39 -0700229 write(fdWrite, buffer, strlen(buffer));
230}
231
Mark Salyzyn501c3732017-03-10 14:31:54 -0800232bool LogKlog::onDataAvailable(SocketClient* cli) {
Mark Salyzynae4d9282014-10-15 08:49:39 -0700233 if (!initialized) {
234 prctl(PR_SET_NAME, "logd.klogd");
235 initialized = true;
236 enableLogging = false;
237 }
238
239 char buffer[LOGGER_ENTRY_MAX_PAYLOAD];
240 size_t len = 0;
241
Mark Salyzyn501c3732017-03-10 14:31:54 -0800242 for (;;) {
Mark Salyzynae4d9282014-10-15 08:49:39 -0700243 ssize_t retval = 0;
244 if ((sizeof(buffer) - 1 - len) > 0) {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800245 retval =
246 read(cli->getSocket(), buffer + len, sizeof(buffer) - 1 - len);
Mark Salyzynae4d9282014-10-15 08:49:39 -0700247 }
248 if ((retval == 0) && (len == 0)) {
249 break;
250 }
251 if (retval < 0) {
252 return false;
253 }
254 len += retval;
255 bool full = len == (sizeof(buffer) - 1);
Mark Salyzyn501c3732017-03-10 14:31:54 -0800256 char* ep = buffer + len;
Mark Salyzynae4d9282014-10-15 08:49:39 -0700257 *ep = '\0';
Mark Salyzynea1a2412015-09-02 07:39:53 -0700258 size_t sublen;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800259 for (char *ptr = NULL, *tok = buffer;
260 ((tok = log_strntok_r(tok, &len, &ptr, &sublen))); tok = NULL) {
Mark Salyzynea1a2412015-09-02 07:39:53 -0700261 if (((tok + sublen) >= ep) && (retval != 0) && full) {
262 memmove(buffer, tok, sublen);
263 len = sublen;
Mark Salyzynae4d9282014-10-15 08:49:39 -0700264 break;
265 }
266 if (*tok) {
Mark Salyzyn151beac2015-09-04 11:37:42 -0700267 log(tok, sublen);
Mark Salyzynae4d9282014-10-15 08:49:39 -0700268 }
269 }
270 }
271
272 return true;
273}
274
Mark Salyzyn501c3732017-03-10 14:31:54 -0800275void LogKlog::calculateCorrection(const log_time& monotonic,
276 const char* real_string, size_t len) {
Mark Salyzynae4d9282014-10-15 08:49:39 -0700277 log_time real;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800278 const char* ep = real.strptime(real_string, "%Y-%m-%d %H:%M:%S.%09q UTC");
Mark Salyzyn10b82b62015-12-28 15:33:01 -0800279 if (!ep || (ep > &real_string[len]) || (real > log_time(CLOCK_REALTIME))) {
Mark Salyzynae4d9282014-10-15 08:49:39 -0700280 return;
281 }
282 // kernel report UTC, log_time::strptime is localtime from calendar.
283 // Bionic and liblog strptime does not support %z or %Z to pick up
284 // timezone so we are calculating our own correction.
285 time_t now = real.tv_sec;
286 struct tm tm;
287 memset(&tm, 0, sizeof(tm));
288 tm.tm_isdst = -1;
289 localtime_r(&now, &tm);
Mark Salyzynff8b8e82015-12-30 13:46:07 -0800290 if ((tm.tm_gmtoff < 0) && ((-tm.tm_gmtoff) > (long)real.tv_sec)) {
Mark Salyzyn10b82b62015-12-28 15:33:01 -0800291 real = log_time::EPOCH;
292 } else {
293 real.tv_sec += tm.tm_gmtoff;
294 }
295 if (monotonic > real) {
296 correction = log_time::EPOCH;
297 } else {
298 correction = real - monotonic;
299 }
Mark Salyzynae4d9282014-10-15 08:49:39 -0700300}
301
Mark Salyzyn2d159bf2015-09-01 13:09:23 -0700302static const char suspendStr[] = "PM: suspend entry ";
303static const char resumeStr[] = "PM: suspend exit ";
304static const char suspendedStr[] = "Suspended for ";
305
Mark Salyzyna2c02222016-12-13 10:31:29 -0800306const char* android::strnstr(const char* s, size_t len, const char* needle) {
Mark Salyzyn151beac2015-09-04 11:37:42 -0700307 char c;
308
Mark Salyzyna2c02222016-12-13 10:31:29 -0800309 if (!len) return NULL;
Mark Salyzyn151beac2015-09-04 11:37:42 -0700310 if ((c = *needle++) != 0) {
311 size_t needleLen = strlen(needle);
312 do {
313 do {
Mark Salyzyna2c02222016-12-13 10:31:29 -0800314 if (len <= needleLen) return NULL;
Mark Salyzyn151beac2015-09-04 11:37:42 -0700315 --len;
316 } while (*s++ != c);
Mark Salyzyn0eeb06b2016-12-02 10:08:48 -0800317 } while (fastcmp<memcmp>(s, needle, needleLen));
Mark Salyzyn151beac2015-09-04 11:37:42 -0700318 s--;
319 }
320 return s;
321}
322
Mark Salyzyn501c3732017-03-10 14:31:54 -0800323void LogKlog::sniffTime(log_time& now, const char** buf, size_t len,
Mark Salyzyn151beac2015-09-04 11:37:42 -0700324 bool reverse) {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800325 const char* cp = now.strptime(*buf, "[ %s.%q]");
Mark Salyzyn151beac2015-09-04 11:37:42 -0700326 if (cp && (cp >= &(*buf)[len])) {
327 cp = NULL;
328 }
Mark Salyzyn151beac2015-09-04 11:37:42 -0700329 if (cp) {
Mark Salyzyn2d159bf2015-09-01 13:09:23 -0700330 static const char healthd[] = "healthd";
331 static const char battery[] = ": battery ";
Mark Salyzynae4d9282014-10-15 08:49:39 -0700332
Mark Salyzyn10b82b62015-12-28 15:33:01 -0800333 len -= cp - *buf;
Mark Salyzyn151beac2015-09-04 11:37:42 -0700334 if (len && isspace(*cp)) {
Mark Salyzynae4d9282014-10-15 08:49:39 -0700335 ++cp;
Mark Salyzyn151beac2015-09-04 11:37:42 -0700336 --len;
Mark Salyzynae4d9282014-10-15 08:49:39 -0700337 }
Mark Salyzyn2d159bf2015-09-01 13:09:23 -0700338 *buf = cp;
339
Mark Salyzynb6bee332015-09-08 08:56:32 -0700340 if (isMonotonic()) {
341 return;
342 }
343
Mark Salyzyna2c02222016-12-13 10:31:29 -0800344 const char* b;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800345 if (((b = android::strnstr(cp, len, suspendStr))) &&
346 ((size_t)((b += sizeof(suspendStr) - 1) - cp) < len)) {
Mark Salyzyn151beac2015-09-04 11:37:42 -0700347 len -= b - cp;
348 calculateCorrection(now, b, len);
Mark Salyzyn501c3732017-03-10 14:31:54 -0800349 } else if (((b = android::strnstr(cp, len, resumeStr))) &&
350 ((size_t)((b += sizeof(resumeStr) - 1) - cp) < len)) {
Mark Salyzyn151beac2015-09-04 11:37:42 -0700351 len -= b - cp;
352 calculateCorrection(now, b, len);
Mark Salyzyn501c3732017-03-10 14:31:54 -0800353 } else if (((b = android::strnstr(cp, len, healthd))) &&
354 ((size_t)((b += sizeof(healthd) - 1) - cp) < len) &&
355 ((b = android::strnstr(b, len -= b - cp, battery))) &&
356 ((size_t)((b += sizeof(battery) - 1) - cp) < len)) {
Mark Salyzyn10b82b62015-12-28 15:33:01 -0800357 // NB: healthd is roughly 150us late, so we use it instead to
358 // trigger a check for ntp-induced or hardware clock drift.
359 log_time real(CLOCK_REALTIME);
360 log_time mono(CLOCK_MONOTONIC);
361 correction = (real < mono) ? log_time::EPOCH : (real - mono);
Mark Salyzyn501c3732017-03-10 14:31:54 -0800362 } else if (((b = android::strnstr(cp, len, suspendedStr))) &&
363 ((size_t)((b += sizeof(suspendStr) - 1) - cp) < len)) {
Mark Salyzyn151beac2015-09-04 11:37:42 -0700364 len -= b - cp;
Mark Salyzynae4d9282014-10-15 08:49:39 -0700365 log_time real;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800366 char* endp;
Mark Salyzyn151beac2015-09-04 11:37:42 -0700367 real.tv_sec = strtol(b, &endp, 10);
368 if ((*endp == '.') && ((size_t)(endp - b) < len)) {
Mark Salyzyn2d159bf2015-09-01 13:09:23 -0700369 unsigned long multiplier = NS_PER_SEC;
370 real.tv_nsec = 0;
Mark Salyzyn151beac2015-09-04 11:37:42 -0700371 len -= endp - b;
372 while (--len && isdigit(*++endp) && (multiplier /= 10)) {
Mark Salyzyn2d159bf2015-09-01 13:09:23 -0700373 real.tv_nsec += (*endp - '0') * multiplier;
374 }
Mark Salyzynae4d9282014-10-15 08:49:39 -0700375 if (reverse) {
Mark Salyzyn10b82b62015-12-28 15:33:01 -0800376 if (real > correction) {
377 correction = log_time::EPOCH;
378 } else {
379 correction -= real;
380 }
Mark Salyzynae4d9282014-10-15 08:49:39 -0700381 } else {
382 correction += real;
383 }
384 }
385 }
386
387 convertMonotonicToReal(now);
Mark Salyzynae4d9282014-10-15 08:49:39 -0700388 } else {
Mark Salyzynb6bee332015-09-08 08:56:32 -0700389 if (isMonotonic()) {
390 now = log_time(CLOCK_MONOTONIC);
391 } else {
392 now = log_time(CLOCK_REALTIME);
393 }
Mark Salyzynae4d9282014-10-15 08:49:39 -0700394 }
395}
396
Mark Salyzyn501c3732017-03-10 14:31:54 -0800397pid_t LogKlog::sniffPid(const char** buf, size_t len) {
398 const char* cp = *buf;
Mark Salyzyn0b4a63d2016-07-15 08:54:03 -0700399 // HTC kernels with modified printk "c0 1648 "
Mark Salyzyn501c3732017-03-10 14:31:54 -0800400 if ((len > 9) && (cp[0] == 'c') && isdigit(cp[1]) &&
401 (isdigit(cp[2]) || (cp[2] == ' ')) && (cp[3] == ' ')) {
Mark Salyzyn0b4a63d2016-07-15 08:54:03 -0700402 bool gotDigit = false;
403 int i;
404 for (i = 4; i < 9; ++i) {
405 if (isdigit(cp[i])) {
406 gotDigit = true;
407 } else if (gotDigit || (cp[i] != ' ')) {
408 break;
409 }
410 }
411 if ((i == 9) && (cp[i] == ' ')) {
412 int pid = 0;
413 char dummy;
414 if (sscanf(cp + 4, "%d%c", &pid, &dummy) == 2) {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800415 *buf = cp + 10; // skip-it-all
Mark Salyzyn0b4a63d2016-07-15 08:54:03 -0700416 return pid;
417 }
418 }
419 }
Mark Salyzyn151beac2015-09-04 11:37:42 -0700420 while (len) {
Mark Salyzyn46d159d2015-08-26 09:30:00 -0700421 // Mediatek kernels with modified printk
422 if (*cp == '[') {
423 int pid = 0;
424 char dummy;
425 if (sscanf(cp, "[%d:%*[a-z_./0-9:A-Z]]%c", &pid, &dummy) == 2) {
426 return pid;
427 }
Mark Salyzyn501c3732017-03-10 14:31:54 -0800428 break; // Only the first one
Mark Salyzyn46d159d2015-08-26 09:30:00 -0700429 }
430 ++cp;
Mark Salyzyn151beac2015-09-04 11:37:42 -0700431 --len;
Mark Salyzyn46d159d2015-08-26 09:30:00 -0700432 }
433 return 0;
434}
435
Mark Salyzynae4d9282014-10-15 08:49:39 -0700436// kernel log prefix, convert to a kernel log priority number
Mark Salyzyn501c3732017-03-10 14:31:54 -0800437static int parseKernelPrio(const char** buf, size_t len) {
Mark Salyzynae4d9282014-10-15 08:49:39 -0700438 int pri = LOG_USER | LOG_INFO;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800439 const char* cp = *buf;
Mark Salyzyn151beac2015-09-04 11:37:42 -0700440 if (len && (*cp == '<')) {
Mark Salyzynae4d9282014-10-15 08:49:39 -0700441 pri = 0;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800442 while (--len && isdigit(*++cp)) {
Mark Salyzynae4d9282014-10-15 08:49:39 -0700443 pri = (pri * 10) + *cp - '0';
444 }
Mark Salyzyn151beac2015-09-04 11:37:42 -0700445 if (len && (*cp == '>')) {
Mark Salyzynae4d9282014-10-15 08:49:39 -0700446 ++cp;
447 } else {
448 cp = *buf;
449 pri = LOG_USER | LOG_INFO;
450 }
451 *buf = cp;
452 }
453 return pri;
454}
455
Mark Salyzyn2d159bf2015-09-01 13:09:23 -0700456// Passed the entire SYSLOG_ACTION_READ_ALL buffer and interpret a
457// compensated start time.
Mark Salyzyna2c02222016-12-13 10:31:29 -0800458void LogKlog::synchronize(const char* buf, size_t len) {
459 const char* cp = android::strnstr(buf, len, suspendStr);
Mark Salyzyn2d159bf2015-09-01 13:09:23 -0700460 if (!cp) {
Mark Salyzyna2c02222016-12-13 10:31:29 -0800461 cp = android::strnstr(buf, len, resumeStr);
462 if (!cp) return;
Mark Salyzyn2d159bf2015-09-01 13:09:23 -0700463 } else {
Mark Salyzyna2c02222016-12-13 10:31:29 -0800464 const char* rp = android::strnstr(buf, len, resumeStr);
465 if (rp && (rp < cp)) cp = rp;
Mark Salyzyn2d159bf2015-09-01 13:09:23 -0700466 }
467
468 do {
469 --cp;
470 } while ((cp > buf) && (*cp != '\n'));
471 if (*cp == '\n') {
472 ++cp;
473 }
Mark Salyzyn151beac2015-09-04 11:37:42 -0700474 parseKernelPrio(&cp, len - (cp - buf));
Mark Salyzyn2d159bf2015-09-01 13:09:23 -0700475
476 log_time now;
Mark Salyzyn151beac2015-09-04 11:37:42 -0700477 sniffTime(now, &cp, len - (cp - buf), true);
Mark Salyzyn2d159bf2015-09-01 13:09:23 -0700478
Mark Salyzyna2c02222016-12-13 10:31:29 -0800479 const char* suspended = android::strnstr(buf, len, suspendedStr);
Mark Salyzyn2d159bf2015-09-01 13:09:23 -0700480 if (!suspended || (suspended > cp)) {
481 return;
482 }
483 cp = suspended;
484
485 do {
486 --cp;
487 } while ((cp > buf) && (*cp != '\n'));
488 if (*cp == '\n') {
489 ++cp;
490 }
Mark Salyzyn151beac2015-09-04 11:37:42 -0700491 parseKernelPrio(&cp, len - (cp - buf));
Mark Salyzyn2d159bf2015-09-01 13:09:23 -0700492
Mark Salyzyn151beac2015-09-04 11:37:42 -0700493 sniffTime(now, &cp, len - (cp - buf), true);
Mark Salyzyn2d159bf2015-09-01 13:09:23 -0700494}
495
Mark Salyzynae4d9282014-10-15 08:49:39 -0700496// Convert kernel log priority number into an Android Logger priority number
497static int convertKernelPrioToAndroidPrio(int pri) {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800498 switch (pri & LOG_PRIMASK) {
499 case LOG_EMERG:
Mark Salyzynae4d9282014-10-15 08:49:39 -0700500 // FALLTHRU
Mark Salyzyn501c3732017-03-10 14:31:54 -0800501 case LOG_ALERT:
Mark Salyzynae4d9282014-10-15 08:49:39 -0700502 // FALLTHRU
Mark Salyzyn501c3732017-03-10 14:31:54 -0800503 case LOG_CRIT:
504 return ANDROID_LOG_FATAL;
Mark Salyzynae4d9282014-10-15 08:49:39 -0700505
Mark Salyzyn501c3732017-03-10 14:31:54 -0800506 case LOG_ERR:
507 return ANDROID_LOG_ERROR;
Mark Salyzynae4d9282014-10-15 08:49:39 -0700508
Mark Salyzyn501c3732017-03-10 14:31:54 -0800509 case LOG_WARNING:
510 return ANDROID_LOG_WARN;
Mark Salyzynae4d9282014-10-15 08:49:39 -0700511
Mark Salyzyn501c3732017-03-10 14:31:54 -0800512 default:
Mark Salyzynae4d9282014-10-15 08:49:39 -0700513 // FALLTHRU
Mark Salyzyn501c3732017-03-10 14:31:54 -0800514 case LOG_NOTICE:
Mark Salyzynae4d9282014-10-15 08:49:39 -0700515 // FALLTHRU
Mark Salyzyn501c3732017-03-10 14:31:54 -0800516 case LOG_INFO:
517 break;
Mark Salyzynae4d9282014-10-15 08:49:39 -0700518
Mark Salyzyn501c3732017-03-10 14:31:54 -0800519 case LOG_DEBUG:
520 return ANDROID_LOG_DEBUG;
Mark Salyzynae4d9282014-10-15 08:49:39 -0700521 }
522
523 return ANDROID_LOG_INFO;
524}
525
Mark Salyzyn501c3732017-03-10 14:31:54 -0800526static const char* strnrchr(const char* s, size_t len, char c) {
527 const char* save = NULL;
528 for (; len; ++s, len--) {
529 if (*s == c) {
530 save = s;
531 }
Mark Salyzyn47dba712015-08-26 09:30:00 -0700532 }
Mark Salyzyn501c3732017-03-10 14:31:54 -0800533 return save;
Mark Salyzyn47dba712015-08-26 09:30:00 -0700534}
535
Mark Salyzynae4d9282014-10-15 08:49:39 -0700536//
537// log a message into the kernel log buffer
538//
539// Filter rules to parse <PRI> <TIME> <tag> and <message> in order for
540// them to appear correct in the logcat output:
541//
542// LOG_KERN (0):
543// <PRI>[<TIME>] <tag> ":" <message>
544// <PRI>[<TIME>] <tag> <tag> ":" <message>
545// <PRI>[<TIME>] <tag> <tag>_work ":" <message>
546// <PRI>[<TIME>] <tag> '<tag>.<num>' ":" <message>
547// <PRI>[<TIME>] <tag> '<tag><num>' ":" <message>
548// <PRI>[<TIME>] <tag>_host '<tag>.<num>' ":" <message>
549// (unimplemented) <PRI>[<TIME>] <tag> '<num>.<tag>' ":" <message>
550// <PRI>[<TIME>] "[INFO]"<tag> : <message>
551// <PRI>[<TIME>] "------------[ cut here ]------------" (?)
552// <PRI>[<TIME>] "---[ end trace 3225a3070ca3e4ac ]---" (?)
553// LOG_USER, LOG_MAIL, LOG_DAEMON, LOG_AUTH, LOG_SYSLOG, LOG_LPR, LOG_NEWS
554// LOG_UUCP, LOG_CRON, LOG_AUTHPRIV, LOG_FTP:
555// <PRI+TAG>[<TIME>] (see sys/syslog.h)
556// Observe:
557// Minimum tag length = 3 NB: drops things like r5:c00bbadf, but allow PM:
558// Maximum tag words = 2
559// Maximum tag length = 16 NB: we are thinking of how ugly logcat can get.
560// Not a Tag if there is no message content.
561// leading additional spaces means no tag, inherit last tag.
562// Not a Tag if <tag>: is "ERROR:", "WARNING:", "INFO:" or "CPU:"
563// Drop:
564// empty messages
565// messages with ' audit(' in them if auditd is running
566// logd.klogd:
567// return -1 if message logd.klogd: <signature>
568//
Mark Salyzyna2c02222016-12-13 10:31:29 -0800569int LogKlog::log(const char* buf, size_t len) {
570 if (auditd && android::strnstr(buf, len, " audit(")) {
Mark Salyzynae4d9282014-10-15 08:49:39 -0700571 return 0;
572 }
573
Mark Salyzyna2c02222016-12-13 10:31:29 -0800574 const char* p = buf;
Mark Salyzyn151beac2015-09-04 11:37:42 -0700575 int pri = parseKernelPrio(&p, len);
Mark Salyzynae4d9282014-10-15 08:49:39 -0700576
577 log_time now;
Mark Salyzyn151beac2015-09-04 11:37:42 -0700578 sniffTime(now, &p, len - (p - buf), false);
Mark Salyzynae4d9282014-10-15 08:49:39 -0700579
580 // sniff for start marker
581 const char klogd_message[] = "logd.klogd: ";
Mark Salyzyna2c02222016-12-13 10:31:29 -0800582 const char* start = android::strnstr(p, len - (p - buf), klogd_message);
Mark Salyzyn46d159d2015-08-26 09:30:00 -0700583 if (start) {
584 uint64_t sig = strtoll(start + sizeof(klogd_message) - 1, NULL, 10);
Mark Salyzynae4d9282014-10-15 08:49:39 -0700585 if (sig == signature.nsec()) {
586 if (initialized) {
587 enableLogging = true;
588 } else {
589 enableLogging = false;
590 }
591 return -1;
592 }
593 return 0;
594 }
595
596 if (!enableLogging) {
597 return 0;
598 }
599
Mark Salyzyn46d159d2015-08-26 09:30:00 -0700600 // Parse pid, tid and uid
Mark Salyzyn0b4a63d2016-07-15 08:54:03 -0700601 const pid_t pid = sniffPid(&p, len - (p - buf));
Mark Salyzyn46d159d2015-08-26 09:30:00 -0700602 const pid_t tid = pid;
Mark Salyzyn83b24782016-08-11 16:07:10 -0700603 uid_t uid = AID_ROOT;
604 if (pid) {
605 logbuf->lock();
606 uid = logbuf->pidToUid(pid);
607 logbuf->unlock();
608 }
Mark Salyzynae4d9282014-10-15 08:49:39 -0700609
610 // Parse (rules at top) to pull out a tag from the incoming kernel message.
611 // Some may view the following as an ugly heuristic, the desire is to
612 // beautify the kernel logs into an Android Logging format; the goal is
613 // admirable but costly.
Mark Salyzyneb298082015-11-10 15:56:41 -0800614 while ((p < &buf[len]) && (isspace(*p) || !*p)) {
Mark Salyzyn151beac2015-09-04 11:37:42 -0700615 ++p;
Mark Salyzynae4d9282014-10-15 08:49:39 -0700616 }
Mark Salyzyn501c3732017-03-10 14:31:54 -0800617 if (p >= &buf[len]) { // timestamp, no content
Mark Salyzynae4d9282014-10-15 08:49:39 -0700618 return 0;
619 }
Mark Salyzyn151beac2015-09-04 11:37:42 -0700620 start = p;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800621 const char* tag = "";
622 const char* etag = tag;
Mark Salyzyn151beac2015-09-04 11:37:42 -0700623 size_t taglen = len - (p - buf);
Mark Salyzyn501c3732017-03-10 14:31:54 -0800624 const char* bt = p;
Mark Salyzynae4d9282014-10-15 08:49:39 -0700625
Mark Salyzyna146a772016-08-05 08:16:37 -0700626 static const char infoBrace[] = "[INFO]";
627 static const size_t infoBraceLen = strlen(infoBrace);
Mark Salyzyn501c3732017-03-10 14:31:54 -0800628 if ((taglen >= infoBraceLen) &&
629 !fastcmp<strncmp>(p, infoBrace, infoBraceLen)) {
Mark Salyzyna146a772016-08-05 08:16:37 -0700630 // <PRI>[<TIME>] "[INFO]"<tag> ":" message
631 bt = p + infoBraceLen;
632 taglen -= infoBraceLen;
633 }
Mark Salyzynae4d9282014-10-15 08:49:39 -0700634
Mark Salyzyn501c3732017-03-10 14:31:54 -0800635 const char* et;
636 for (et = bt; taglen && *et && (*et != ':') && !isspace(*et);
637 ++et, --taglen) {
638 // skip ':' within [ ... ]
639 if (*et == '[') {
640 while (taglen && *et && *et != ']') {
641 ++et;
642 --taglen;
643 }
644 if (!taglen) {
645 break;
646 }
647 }
Mark Salyzyna146a772016-08-05 08:16:37 -0700648 }
Mark Salyzyn501c3732017-03-10 14:31:54 -0800649 const char* cp;
650 for (cp = et; taglen && isspace(*cp); ++cp, --taglen) {
651 }
Mark Salyzyna146a772016-08-05 08:16:37 -0700652
653 // Validate tag
654 size_t size = et - bt;
655 if (taglen && size) {
Mark Salyzynae4d9282014-10-15 08:49:39 -0700656 if (*cp == ':') {
Mark Salyzyna146a772016-08-05 08:16:37 -0700657 // ToDo: handle case insensitive colon separated logging stutter:
658 // <tag> : <tag>: ...
659
Mark Salyzynae4d9282014-10-15 08:49:39 -0700660 // One Word
661 tag = bt;
662 etag = et;
Mark Salyzyn151beac2015-09-04 11:37:42 -0700663 p = cp + 1;
Mark Salyzyna146a772016-08-05 08:16:37 -0700664 } else if ((taglen > size) && (tolower(*bt) == tolower(*cp))) {
665 // clean up any tag stutter
Mark Salyzyn501c3732017-03-10 14:31:54 -0800666 if (!fastcmp<strncasecmp>(bt + 1, cp + 1, size - 1)) { // no match
Mark Salyzyna146a772016-08-05 08:16:37 -0700667 // <PRI>[<TIME>] <tag> <tag> : message
668 // <PRI>[<TIME>] <tag> <tag>: message
669 // <PRI>[<TIME>] <tag> '<tag>.<num>' : message
670 // <PRI>[<TIME>] <tag> '<tag><num>' : message
671 // <PRI>[<TIME>] <tag> '<tag><stuff>' : message
Mark Salyzyn501c3732017-03-10 14:31:54 -0800672 const char* b = cp;
Mark Salyzyna146a772016-08-05 08:16:37 -0700673 cp += size;
674 taglen -= size;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800675 while (--taglen && !isspace(*++cp) && (*cp != ':')) {
676 }
677 const char* e;
678 for (e = cp; taglen && isspace(*cp); ++cp, --taglen) {
679 }
Mark Salyzyna146a772016-08-05 08:16:37 -0700680 if (taglen && (*cp == ':')) {
681 tag = b;
682 etag = e;
683 p = cp + 1;
684 }
685 } else {
686 // what about <PRI>[<TIME>] <tag>_host '<tag><stuff>' : message
687 static const char host[] = "_host";
688 static const size_t hostlen = strlen(host);
689 if ((size > hostlen) &&
Mark Salyzyn501c3732017-03-10 14:31:54 -0800690 !fastcmp<strncmp>(bt + size - hostlen, host, hostlen) &&
691 !fastcmp<strncmp>(bt + 1, cp + 1, size - hostlen - 1)) {
692 const char* b = cp;
Mark Salyzyna146a772016-08-05 08:16:37 -0700693 cp += size - hostlen;
694 taglen -= size - hostlen;
Mark Salyzynae4d9282014-10-15 08:49:39 -0700695 if (*cp == '.') {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800696 while (--taglen && !isspace(*++cp) && (*cp != ':')) {
697 }
698 const char* e;
699 for (e = cp; taglen && isspace(*cp); ++cp, --taglen) {
700 }
Mark Salyzyna146a772016-08-05 08:16:37 -0700701 if (taglen && (*cp == ':')) {
Mark Salyzynae4d9282014-10-15 08:49:39 -0700702 tag = b;
703 etag = e;
Mark Salyzyn151beac2015-09-04 11:37:42 -0700704 p = cp + 1;
Mark Salyzynae4d9282014-10-15 08:49:39 -0700705 }
706 }
707 } else {
Mark Salyzyna146a772016-08-05 08:16:37 -0700708 goto twoWord;
Mark Salyzynae4d9282014-10-15 08:49:39 -0700709 }
710 }
Mark Salyzyna146a772016-08-05 08:16:37 -0700711 } else {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800712 // <PRI>[<TIME>] <tag> <stuff>' : message
713 twoWord:
714 while (--taglen && !isspace(*++cp) && (*cp != ':')) {
715 }
716 const char* e;
717 for (e = cp; taglen && isspace(*cp); ++cp, --taglen) {
718 }
Mark Salyzyna146a772016-08-05 08:16:37 -0700719 // Two words
720 if (taglen && (*cp == ':')) {
721 tag = bt;
722 etag = e;
723 p = cp + 1;
724 }
Mark Salyzynae4d9282014-10-15 08:49:39 -0700725 }
Mark Salyzyn501c3732017-03-10 14:31:54 -0800726 } // else no tag
Mark Salyzyna146a772016-08-05 08:16:37 -0700727
728 static const char cpu[] = "CPU";
729 static const size_t cpuLen = strlen(cpu);
730 static const char warning[] = "WARNING";
731 static const size_t warningLen = strlen(warning);
732 static const char error[] = "ERROR";
733 static const size_t errorLen = strlen(error);
734 static const char info[] = "INFO";
735 static const size_t infoLen = strlen(info);
736
737 size = etag - tag;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800738 if ((size <= 1) ||
Mark Salyzyna146a772016-08-05 08:16:37 -0700739 // register names like x9
Mark Salyzyn501c3732017-03-10 14:31:54 -0800740 ((size == 2) && (isdigit(tag[0]) || isdigit(tag[1]))) ||
Mark Salyzyna146a772016-08-05 08:16:37 -0700741 // register names like x18 but not driver names like en0
Mark Salyzyn501c3732017-03-10 14:31:54 -0800742 ((size == 3) && (isdigit(tag[1]) && isdigit(tag[2]))) ||
Mark Salyzyna146a772016-08-05 08:16:37 -0700743 // blacklist
Mark Salyzyn501c3732017-03-10 14:31:54 -0800744 ((size == cpuLen) && !fastcmp<strncmp>(tag, cpu, cpuLen)) ||
745 ((size == warningLen) &&
746 !fastcmp<strncasecmp>(tag, warning, warningLen)) ||
747 ((size == errorLen) && !fastcmp<strncasecmp>(tag, error, errorLen)) ||
748 ((size == infoLen) && !fastcmp<strncasecmp>(tag, info, infoLen))) {
Mark Salyzyna146a772016-08-05 08:16:37 -0700749 p = start;
750 etag = tag = "";
Mark Salyzynae4d9282014-10-15 08:49:39 -0700751 }
Mark Salyzyna146a772016-08-05 08:16:37 -0700752
Mark Salyzyn46d159d2015-08-26 09:30:00 -0700753 // Suppress additional stutter in tag:
754 // eg: [143:healthd]healthd -> [143:healthd]
Mark Salyzyn151beac2015-09-04 11:37:42 -0700755 taglen = etag - tag;
Mark Salyzyn46d159d2015-08-26 09:30:00 -0700756 // Mediatek-special printk induced stutter
Mark Salyzyn501c3732017-03-10 14:31:54 -0800757 const char* mp = strnrchr(tag, ']', taglen);
Mark Salyzyn47dba712015-08-26 09:30:00 -0700758 if (mp && (++mp < etag)) {
759 size_t s = etag - mp;
Mark Salyzyn0eeb06b2016-12-02 10:08:48 -0800760 if (((s + s) < taglen) && !fastcmp<memcmp>(mp, mp - 1 - s, s)) {
Mark Salyzyn47dba712015-08-26 09:30:00 -0700761 taglen = mp - tag;
Mark Salyzyn46d159d2015-08-26 09:30:00 -0700762 }
763 }
Mark Salyzyneb298082015-11-10 15:56:41 -0800764 // Deal with sloppy and simplistic harmless p = cp + 1 etc above.
765 if (len < (size_t)(p - buf)) {
766 p = &buf[len];
767 }
Mark Salyzynee49c6a2015-06-12 14:59:42 -0700768 // skip leading space
Mark Salyzyneb298082015-11-10 15:56:41 -0800769 while ((p < &buf[len]) && (isspace(*p) || !*p)) {
Mark Salyzyn151beac2015-09-04 11:37:42 -0700770 ++p;
Mark Salyzynae4d9282014-10-15 08:49:39 -0700771 }
Mark Salyzyn151beac2015-09-04 11:37:42 -0700772 // truncate trailing space or nuls
773 size_t b = len - (p - buf);
Mark Salyzyn501c3732017-03-10 14:31:54 -0800774 while (b && (isspace(p[b - 1]) || !p[b - 1])) {
Mark Salyzynee49c6a2015-06-12 14:59:42 -0700775 --b;
776 }
777 // trick ... allow tag with empty content to be logged. log() drops empty
Mark Salyzyn46d159d2015-08-26 09:30:00 -0700778 if (!b && taglen) {
Mark Salyzyn151beac2015-09-04 11:37:42 -0700779 p = " ";
Mark Salyzynee49c6a2015-06-12 14:59:42 -0700780 b = 1;
781 }
Mark Salyzyneb298082015-11-10 15:56:41 -0800782 // paranoid sanity check, can not happen ...
Mark Salyzynddda2122015-10-02 09:22:52 -0700783 if (b > LOGGER_ENTRY_MAX_PAYLOAD) {
784 b = LOGGER_ENTRY_MAX_PAYLOAD;
785 }
Mark Salyzyneb298082015-11-10 15:56:41 -0800786 if (taglen > LOGGER_ENTRY_MAX_PAYLOAD) {
787 taglen = LOGGER_ENTRY_MAX_PAYLOAD;
788 }
789 // calculate buffer copy requirements
Mark Salyzyn46d159d2015-08-26 09:30:00 -0700790 size_t n = 1 + taglen + 1 + b + 1;
Mark Salyzyneb298082015-11-10 15:56:41 -0800791 // paranoid sanity check, first two just can not happen ...
792 if ((taglen > n) || (b > n) || (n > USHRT_MAX)) {
793 return -EINVAL;
Mark Salyzyn47dba712015-08-26 09:30:00 -0700794 }
Mark Salyzynae4d9282014-10-15 08:49:39 -0700795
Mark Salyzyneb298082015-11-10 15:56:41 -0800796 // Careful.
797 // We are using the stack to house the log buffer for speed reasons.
798 // If we malloc'd this buffer, we could get away without n's USHRT_MAX
799 // test above, but we would then required a max(n, USHRT_MAX) as
800 // truncating length argument to logbuf->log() below. Gain is protection
801 // of stack sanity and speedup, loss is truncated long-line content.
Mark Salyzynddda2122015-10-02 09:22:52 -0700802 char newstr[n];
Mark Salyzyn501c3732017-03-10 14:31:54 -0800803 char* np = newstr;
Mark Salyzynae4d9282014-10-15 08:49:39 -0700804
805 // Convert priority into single-byte Android logger priority
806 *np = convertKernelPrioToAndroidPrio(pri);
807 ++np;
808
809 // Copy parsed tag following priority
Mark Salyzyn151beac2015-09-04 11:37:42 -0700810 memcpy(np, tag, taglen);
Mark Salyzyn46d159d2015-08-26 09:30:00 -0700811 np += taglen;
Mark Salyzynae4d9282014-10-15 08:49:39 -0700812 *np = '\0';
813 ++np;
814
815 // Copy main message to the remainder
Mark Salyzyn151beac2015-09-04 11:37:42 -0700816 memcpy(np, p, b);
Mark Salyzynee49c6a2015-06-12 14:59:42 -0700817 np[b] = '\0';
Mark Salyzynae4d9282014-10-15 08:49:39 -0700818
Mark Salyzynb06247d2015-12-04 09:32:27 -0800819 if (!isMonotonic()) {
820 // Watch out for singular race conditions with timezone causing near
821 // integer quarter-hour jumps in the time and compensate accordingly.
822 // Entries will be temporal within near_seconds * 2. b/21868540
823 static uint32_t vote_time[3];
824 vote_time[2] = vote_time[1];
825 vote_time[1] = vote_time[0];
826 vote_time[0] = now.tv_sec;
827
828 if (vote_time[1] && vote_time[2]) {
829 static const unsigned near_seconds = 10;
830 static const unsigned timezones_seconds = 900;
831 int diff0 = (vote_time[0] - vote_time[1]) / near_seconds;
832 unsigned abs0 = (diff0 < 0) ? -diff0 : diff0;
833 int diff1 = (vote_time[1] - vote_time[2]) / near_seconds;
834 unsigned abs1 = (diff1 < 0) ? -diff1 : diff1;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800835 if ((abs1 <= 1) && // last two were in agreement on timezone
836 ((abs0 + 1) % (timezones_seconds / near_seconds)) <= 2) {
Mark Salyzynb06247d2015-12-04 09:32:27 -0800837 abs0 = (abs0 + 1) / (timezones_seconds / near_seconds) *
Mark Salyzyn501c3732017-03-10 14:31:54 -0800838 timezones_seconds;
Mark Salyzynb06247d2015-12-04 09:32:27 -0800839 now.tv_sec -= (diff0 < 0) ? -abs0 : abs0;
840 }
841 }
842 }
843
Mark Salyzynae4d9282014-10-15 08:49:39 -0700844 // Log message
Mark Salyzyneb298082015-11-10 15:56:41 -0800845 int rc = logbuf->log(LOG_ID_KERNEL, now, uid, pid, tid, newstr,
Mark Salyzyn501c3732017-03-10 14:31:54 -0800846 (unsigned short)n);
Mark Salyzynae4d9282014-10-15 08:49:39 -0700847
848 // notify readers
849 if (!rc) {
850 reader->notifyNewLog();
851 }
852
853 return rc;
854}