log_read.c revision 6c1b07fbbd0ccce0e4fdf79abd38494cc622d67e
1/* 2** Copyright 2013, 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#define _GNU_SOURCE /* asprintf for x86 host */ 18#include <errno.h> 19#include <fcntl.h> 20#include <poll.h> 21#include <string.h> 22#include <stdio.h> 23#include <stdlib.h> 24#include <cutils/list.h> 25#include <log/log.h> 26#include <log/logger.h> 27 28typedef char bool; 29#define false (const bool)0 30#define true (const bool)1 31 32#define LOG_FILE_DIR "/dev/log/" 33 34#define LOG_TIMEOUT_MS 5 35 36#define logger_for_each(logger, logger_list) \ 37 for (logger = node_to_item((logger_list)->node.next, struct logger, node); \ 38 logger != node_to_item(&(logger_list)->node, struct logger, node); \ 39 logger = node_to_item((logger)->node.next, struct logger, node)) 40 41/* In the future, we would like to make this list extensible */ 42static const char *LOG_NAME[LOG_ID_MAX] = { 43 [LOG_ID_MAIN] = "main", 44 [LOG_ID_RADIO] = "radio", 45 [LOG_ID_EVENTS] = "events", 46 [LOG_ID_SYSTEM] = "system" 47}; 48 49const char *android_log_id_to_name(log_id_t log_id) { 50 if (log_id >= LOG_ID_MAX) { 51 log_id = LOG_ID_MAIN; 52 } 53 return LOG_NAME[log_id]; 54} 55 56static int accessmode(int mode) 57{ 58 if ((mode & O_ACCMODE) == O_WRONLY) { 59 return W_OK; 60 } 61 if ((mode & O_ACCMODE) == O_RDWR) { 62 return R_OK | W_OK; 63 } 64 return R_OK; 65} 66 67/* repeated fragment */ 68static int check_allocate_accessible(char **n, const char *b, int mode) 69{ 70 *n = NULL; 71 72 if (!b) { 73 return -EINVAL; 74 } 75 76 asprintf(n, LOG_FILE_DIR "%s", b); 77 if (!*n) { 78 return -1; 79 } 80 81 return access(*n, accessmode(mode)); 82} 83 84log_id_t android_name_to_log_id(const char *logName) { 85 const char *b; 86 char *n; 87 int ret; 88 89 if (!logName) { 90 return -1; /* NB: log_id_t is unsigned */ 91 } 92 b = strrchr(logName, '/'); 93 if (!b) { 94 b = logName; 95 } else { 96 ++b; 97 } 98 99 ret = check_allocate_accessible(&n, b, O_RDONLY); 100 free(n); 101 if (ret) { 102 return ret; 103 } 104 105 for(ret = LOG_ID_MIN; ret < LOG_ID_MAX; ++ret) { 106 const char *l = LOG_NAME[ret]; 107 if (l && !strcmp(b, l)) { 108 return ret; 109 } 110 } 111 return -1; /* should never happen */ 112} 113 114struct logger_list { 115 struct listnode node; 116 int mode; 117 unsigned int tail; 118 pid_t pid; 119 unsigned int queued_lines; 120 int timeout_ms; 121 int error; 122 bool flush; 123 bool valid_entry; /* valiant(?) effort to deal with memory starvation */ 124 struct log_msg entry; 125}; 126 127struct log_list { 128 struct listnode node; 129 struct log_msg entry; /* Truncated to event->len() + 1 to save space */ 130}; 131 132struct logger { 133 struct listnode node; 134 struct logger_list *top; 135 int fd; 136 log_id_t id; 137 short *revents; 138 struct listnode log_list; 139}; 140 141/* android_logger_alloc unimplemented, no use case */ 142/* android_logger_free not exported */ 143static void android_logger_free(struct logger *logger) 144{ 145 if (!logger) { 146 return; 147 } 148 149 while (!list_empty(&logger->log_list)) { 150 struct log_list *entry = node_to_item( 151 list_head(&logger->log_list), struct log_list, node); 152 list_remove(&entry->node); 153 free(entry); 154 if (logger->top->queued_lines) { 155 logger->top->queued_lines--; 156 } 157 } 158 159 if (logger->fd >= 0) { 160 close(logger->fd); 161 } 162 163 list_remove(&logger->node); 164 165 free(logger); 166} 167 168log_id_t android_logger_get_id(struct logger *logger) 169{ 170 return logger->id; 171} 172 173/* worker for sending the command to the logger */ 174static int logger_ioctl(struct logger *logger, int cmd, int mode) 175{ 176 char *n; 177 int f, ret; 178 179 if (!logger || !logger->top) { 180 return -EFAULT; 181 } 182 183 if (((mode & O_ACCMODE) == O_RDWR) 184 || (((mode ^ logger->top->mode) & O_ACCMODE) == 0)) { 185 return ioctl(logger->fd, cmd); 186 } 187 188 /* We go here if android_logger_list_open got mode wrong for this ioctl */ 189 ret = check_allocate_accessible(&n, android_log_id_to_name(logger->id), mode); 190 if (ret) { 191 free(n); 192 return ret; 193 } 194 195 f = open(n, mode); 196 free(n); 197 if (f < 0) { 198 return f; 199 } 200 201 ret = ioctl(f, cmd); 202 close (f); 203 204 return ret; 205} 206 207int android_logger_clear(struct logger *logger) 208{ 209 return logger_ioctl(logger, LOGGER_FLUSH_LOG, O_WRONLY); 210} 211 212/* returns the total size of the log's ring buffer */ 213int android_logger_get_log_size(struct logger *logger) 214{ 215 return logger_ioctl(logger, LOGGER_GET_LOG_BUF_SIZE, O_RDWR); 216} 217 218/* 219 * returns the readable size of the log's ring buffer (that is, amount of the 220 * log consumed) 221 */ 222int android_logger_get_log_readable_size(struct logger *logger) 223{ 224 return logger_ioctl(logger, LOGGER_GET_LOG_LEN, O_RDONLY); 225} 226 227/* 228 * returns the logger version 229 */ 230int android_logger_get_log_version(struct logger *logger) 231{ 232 int ret = logger_ioctl(logger, LOGGER_GET_VERSION, O_RDWR); 233 return (ret < 0) ? 1 : ret; 234} 235 236struct logger_list *android_logger_list_alloc(int mode, 237 unsigned int tail, 238 pid_t pid) 239{ 240 struct logger_list *logger_list; 241 242 logger_list = calloc(1, sizeof(*logger_list)); 243 if (!logger_list) { 244 return NULL; 245 } 246 list_init(&logger_list->node); 247 logger_list->mode = mode; 248 logger_list->tail = tail; 249 logger_list->pid = pid; 250 return logger_list; 251} 252 253/* android_logger_list_register unimplemented, no use case */ 254/* android_logger_list_unregister unimplemented, no use case */ 255 256/* Open the named log and add it to the logger list */ 257struct logger *android_logger_open(struct logger_list *logger_list, 258 log_id_t id) 259{ 260 struct listnode *node; 261 struct logger *logger; 262 char *n; 263 264 if (!logger_list || (id >= LOG_ID_MAX)) { 265 goto err; 266 } 267 268 logger_for_each(logger, logger_list) { 269 if (logger->id == id) { 270 goto ok; 271 } 272 } 273 274 logger = calloc(1, sizeof(*logger)); 275 if (!logger) { 276 goto err; 277 } 278 279 if (check_allocate_accessible(&n, android_log_id_to_name(id), 280 logger_list->mode)) { 281 goto err_name; 282 } 283 284 logger->fd = open(n, logger_list->mode); 285 if (logger->fd < 0) { 286 goto err_name; 287 } 288 289 free(n); 290 logger->id = id; 291 list_init(&logger->log_list); 292 list_add_tail(&logger_list->node, &logger->node); 293 logger->top = logger_list; 294 logger_list->timeout_ms = LOG_TIMEOUT_MS; 295 goto ok; 296 297err_name: 298 free(n); 299err_logger: 300 free(logger); 301err: 302 logger = NULL; 303ok: 304 return logger; 305} 306 307/* Open the single named log and make it part of a new logger list */ 308struct logger_list *android_logger_list_open(log_id_t id, 309 int mode, 310 unsigned int tail, 311 pid_t pid) 312{ 313 struct logger_list *logger_list = android_logger_list_alloc(mode, tail, pid); 314 if (!logger_list) { 315 return NULL; 316 } 317 318 if (!android_logger_open(logger_list, id)) { 319 android_logger_list_free(logger_list); 320 return NULL; 321 } 322 323 return logger_list; 324} 325 326/* prevent memory starvation when backfilling */ 327static unsigned int queue_threshold(struct logger_list *logger_list) 328{ 329 return (logger_list->tail < 64) ? 64 : logger_list->tail; 330} 331 332static bool low_queue(struct listnode *node) 333{ 334 /* low is considered less than 2 */ 335 return list_head(node) == list_tail(node); 336} 337 338/* Flush queues in sequential order, one at a time */ 339static int android_logger_list_flush(struct logger_list *logger_list, 340 struct log_msg *log_msg) 341{ 342 int ret = 0; 343 struct log_list *firstentry = NULL; 344 345 while ((ret == 0) 346 && (logger_list->flush 347 || (logger_list->queued_lines > logger_list->tail))) { 348 struct logger *logger; 349 350 /* Merge sort */ 351 bool at_least_one_is_low = false; 352 struct logger *firstlogger = NULL; 353 firstentry = NULL; 354 355 logger_for_each(logger, logger_list) { 356 struct listnode *node; 357 struct log_list *oldest = NULL; 358 359 /* kernel logger channels not necessarily time-sort order */ 360 list_for_each(node, &logger->log_list) { 361 struct log_list *entry = node_to_item(node, 362 struct log_list, node); 363 if (!oldest 364 || (entry->entry.entry.sec < oldest->entry.entry.sec) 365 || ((entry->entry.entry.sec == oldest->entry.entry.sec) 366 && (entry->entry.entry.nsec < oldest->entry.entry.nsec))) { 367 oldest = entry; 368 } 369 } 370 371 if (!oldest) { 372 at_least_one_is_low = true; 373 continue; 374 } else if (low_queue(&logger->log_list)) { 375 at_least_one_is_low = true; 376 } 377 378 if (!firstentry 379 || (oldest->entry.entry.sec < firstentry->entry.entry.sec) 380 || ((oldest->entry.entry.sec == firstentry->entry.entry.sec) 381 && (oldest->entry.entry.nsec < firstentry->entry.entry.nsec))) { 382 firstentry = oldest; 383 firstlogger = logger; 384 } 385 } 386 387 if (!firstentry) { 388 break; 389 } 390 391 /* when trimming list, tries to keep one entry behind in each bucket */ 392 if (!logger_list->flush 393 && at_least_one_is_low 394 && (logger_list->queued_lines < queue_threshold(logger_list))) { 395 break; 396 } 397 398 /* within tail?, send! */ 399 if ((logger_list->tail == 0) 400 || (logger_list->queued_lines <= logger_list->tail)) { 401 ret = firstentry->entry.entry.hdr_size; 402 if (!ret) { 403 ret = sizeof(firstentry->entry.entry_v1); 404 } 405 ret += firstentry->entry.entry.len; 406 407 memcpy(log_msg->buf, firstentry->entry.buf, ret + 1); 408 log_msg->extra.id = firstlogger->id; 409 } 410 411 /* next entry */ 412 list_remove(&firstentry->node); 413 free(firstentry); 414 if (logger_list->queued_lines) { 415 logger_list->queued_lines--; 416 } 417 } 418 419 /* Flushed the list, no longer in tail mode for continuing content */ 420 if (logger_list->flush && !firstentry) { 421 logger_list->tail = 0; 422 } 423 return ret; 424} 425 426/* Read from the selected logs */ 427int android_logger_list_read(struct logger_list *logger_list, 428 struct log_msg *log_msg) 429{ 430 struct logger *logger; 431 nfds_t nfds; 432 struct pollfd *p, *pollfds = NULL; 433 int error = 0, ret = 0; 434 435 memset(log_msg, 0, sizeof(struct log_msg)); 436 437 if (!logger_list) { 438 return -ENODEV; 439 } 440 441 if (!(accessmode(logger_list->mode) & R_OK)) { 442 logger_list->error = EPERM; 443 goto done; 444 } 445 446 nfds = 0; 447 logger_for_each(logger, logger_list) { 448 ++nfds; 449 } 450 if (nfds <= 0) { 451 error = ENODEV; 452 goto done; 453 } 454 455 /* Do we have anything to offer from the buffer or state? */ 456 if (logger_list->valid_entry) { /* implies we are also in a flush state */ 457 goto flush; 458 } 459 460 ret = android_logger_list_flush(logger_list, log_msg); 461 if (ret) { 462 goto done; 463 } 464 465 if (logger_list->error) { /* implies we are also in a flush state */ 466 goto done; 467 } 468 469 /* Lets start grinding on metal */ 470 pollfds = calloc(nfds, sizeof(struct pollfd)); 471 if (!pollfds) { 472 error = ENOMEM; 473 goto flush; 474 } 475 476 p = pollfds; 477 logger_for_each(logger, logger_list) { 478 p->fd = logger->fd; 479 p->events = POLLIN; 480 logger->revents = &p->revents; 481 ++p; 482 } 483 484 while (!ret && !error) { 485 int result; 486 487 /* If we oversleep it's ok, i.e. ignore EINTR. */ 488 result = TEMP_FAILURE_RETRY( 489 poll(pollfds, nfds, logger_list->timeout_ms)); 490 491 if (result <= 0) { 492 if (result) { 493 error = errno; 494 } else if (logger_list->mode & O_NDELAY) { 495 error = EAGAIN; 496 } else { 497 logger_list->timeout_ms = 0; 498 } 499 500 logger_list->flush = true; 501 goto try_flush; 502 } 503 504 logger_list->timeout_ms = LOG_TIMEOUT_MS; 505 506 /* Anti starvation */ 507 if (!logger_list->flush 508 && (logger_list->queued_lines > (queue_threshold(logger_list) / 2))) { 509 /* Any queues with input pending that is low? */ 510 bool starving = false; 511 logger_for_each(logger, logger_list) { 512 if ((*(logger->revents) & POLLIN) 513 && low_queue(&logger->log_list)) { 514 starving = true; 515 break; 516 } 517 } 518 519 /* pushback on any queues that are not low */ 520 if (starving) { 521 logger_for_each(logger, logger_list) { 522 if ((*(logger->revents) & POLLIN) 523 && !low_queue(&logger->log_list)) { 524 *(logger->revents) &= ~POLLIN; 525 } 526 } 527 } 528 } 529 530 logger_for_each(logger, logger_list) { 531 unsigned int hdr_size; 532 struct log_list *entry; 533 534 if (!(*(logger->revents) & POLLIN)) { 535 continue; 536 } 537 538 memset(logger_list->entry.buf, 0, sizeof(struct log_msg)); 539 /* NOTE: driver guarantees we read exactly one full entry */ 540 result = read(logger->fd, logger_list->entry.buf, 541 LOGGER_ENTRY_MAX_LEN); 542 if (result <= 0) { 543 if (!result) { 544 error = EIO; 545 } else if (errno != EINTR) { 546 error = errno; 547 } 548 continue; 549 } 550 551 if (logger_list->pid 552 && (logger_list->pid != logger_list->entry.entry.pid)) { 553 continue; 554 } 555 556 hdr_size = logger_list->entry.entry.hdr_size; 557 if (!hdr_size) { 558 hdr_size = sizeof(logger_list->entry.entry_v1); 559 } 560 561 if ((hdr_size > sizeof(struct log_msg)) 562 || (logger_list->entry.entry.len 563 > sizeof(logger_list->entry.buf) - hdr_size) 564 || (logger_list->entry.entry.len != result - hdr_size)) { 565 error = EINVAL; 566 continue; 567 } 568 569 logger_list->entry.extra.id = logger->id; 570 571 /* speedup: If not tail, and only one list, send directly */ 572 if (!logger_list->tail 573 && (list_head(&logger_list->node) 574 == list_tail(&logger_list->node))) { 575 ret = result; 576 memcpy(log_msg->buf, logger_list->entry.buf, result + 1); 577 log_msg->extra.id = logger->id; 578 break; 579 } 580 581 entry = malloc(sizeof(*entry) - sizeof(entry->entry) + result + 1); 582 583 if (!entry) { 584 logger_list->valid_entry = true; 585 error = ENOMEM; 586 break; 587 } 588 589 logger_list->queued_lines++; 590 591 memcpy(entry->entry.buf, logger_list->entry.buf, result); 592 entry->entry.buf[result] = '\0'; 593 list_add_tail(&logger->log_list, &entry->node); 594 } 595 596 if (ret <= 0) { 597try_flush: 598 ret = android_logger_list_flush(logger_list, log_msg); 599 } 600 } 601 602 free(pollfds); 603 604flush: 605 if (error) { 606 logger_list->flush = true; 607 } 608 609 if (ret <= 0) { 610 ret = android_logger_list_flush(logger_list, log_msg); 611 612 if (!ret && logger_list->valid_entry) { 613 ret = logger_list->entry.entry.hdr_size; 614 if (!ret) { 615 ret = sizeof(logger_list->entry.entry_v1); 616 } 617 ret += logger_list->entry.entry.len; 618 619 memcpy(log_msg->buf, logger_list->entry.buf, 620 sizeof(struct log_msg)); 621 logger_list->valid_entry = false; 622 } 623 } 624 625done: 626 if (logger_list->error) { 627 error = logger_list->error; 628 } 629 if (error) { 630 logger_list->error = error; 631 if (!ret) { 632 ret = -error; 633 } 634 } 635 return ret; 636} 637 638/* Close all the logs */ 639void android_logger_list_free(struct logger_list *logger_list) 640{ 641 if (logger_list == NULL) { 642 return; 643 } 644 645 while (!list_empty(&logger_list->node)) { 646 struct listnode *node = list_head(&logger_list->node); 647 struct logger *logger = node_to_item(node, struct logger, node); 648 android_logger_free(logger); 649 } 650 651 free(logger_list); 652} 653