logcat_test.cpp revision 7545b471a223a4a222a24b8b1693cc4a69ee3833
1/* 2 * Copyright (C) 2013-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 <dirent.h> 19#include <signal.h> 20#include <stdio.h> 21#include <stdlib.h> 22#include <string.h> 23#include <sys/types.h> 24#include <sys/wait.h> 25 26#include <gtest/gtest.h> 27#include <log/log.h> 28#include <log/logger.h> 29#include <log/log_read.h> 30 31#define BIG_BUFFER (5 * 1024) 32 33// enhanced version of LOG_FAILURE_RETRY to add support for EAGAIN and 34// non-syscall libs. Since we are only using this in the emergency of 35// a signal to stuff a terminating code into the logs, we will spin rather 36// than try a usleep. 37#define LOG_FAILURE_RETRY(exp) ({ \ 38 typeof (exp) _rc; \ 39 do { \ 40 _rc = (exp); \ 41 } while (((_rc == -1) \ 42 && ((errno == EINTR) \ 43 || (errno == EAGAIN))) \ 44 || (_rc == -EINTR) \ 45 || (_rc == -EAGAIN)); \ 46 _rc; }) 47 48static const char begin[] = "--------- beginning of "; 49 50TEST(logcat, buckets) { 51 FILE *fp; 52 53 ASSERT_TRUE(NULL != (fp = popen( 54 "logcat -b radio -b events -b system -b main -d 2>/dev/null", 55 "r"))); 56 57 char buffer[BIG_BUFFER]; 58 59 int ids = 0; 60 int count = 0; 61 62 while (fgets(buffer, sizeof(buffer), fp)) { 63 if (!strncmp(begin, buffer, sizeof(begin) - 1)) { 64 while (char *cp = strrchr(buffer, '\n')) { 65 *cp = '\0'; 66 } 67 log_id_t id = android_name_to_log_id(buffer + sizeof(begin) - 1); 68 ids |= 1 << id; 69 ++count; 70 } 71 } 72 73 pclose(fp); 74 75 EXPECT_EQ(15, ids); 76 77 EXPECT_EQ(4, count); 78} 79 80TEST(logcat, year) { 81 82 if (android_log_clockid() == CLOCK_MONOTONIC) { 83 fprintf(stderr, "Skipping test, logd is monotonic time\n"); 84 return; 85 } 86 87 FILE *fp; 88 89 char needle[32]; 90 time_t now; 91 time(&now); 92 struct tm *ptm; 93#if !defined(_WIN32) 94 struct tm tmBuf; 95 ptm = localtime_r(&now, &tmBuf); 96#else 97 ptm = localtime(&&now); 98#endif 99 strftime(needle, sizeof(needle), "[ %Y-", ptm); 100 101 ASSERT_TRUE(NULL != (fp = popen( 102 "logcat -v long -v year -b all -t 3 2>/dev/null", 103 "r"))); 104 105 char buffer[BIG_BUFFER]; 106 107 int count = 0; 108 109 while (fgets(buffer, sizeof(buffer), fp)) { 110 if (!strncmp(buffer, needle, strlen(needle))) { 111 ++count; 112 } 113 } 114 115 pclose(fp); 116 117 ASSERT_EQ(3, count); 118} 119 120// Return a pointer to each null terminated -v long time field. 121char *fgetLongTime(char *buffer, size_t buflen, FILE *fp) { 122 while (fgets(buffer, buflen, fp)) { 123 char *cp = buffer; 124 if (*cp != '[') { 125 continue; 126 } 127 while (*++cp == ' ') { 128 ; 129 } 130 char *ep = cp; 131 while (isdigit(*ep)) { 132 ++ep; 133 } 134 if ((*ep != '-') && (*ep != '.')) { 135 continue; 136 } 137 // Find PID field 138 while (((ep = strchr(ep, ':'))) && (*++ep != ' ')) { 139 ; 140 } 141 if (!ep) { 142 continue; 143 } 144 ep -= 7; 145 *ep = '\0'; 146 return cp; 147 } 148 return NULL; 149} 150 151TEST(logcat, tz) { 152 153 if (android_log_clockid() == CLOCK_MONOTONIC) { 154 fprintf(stderr, "Skipping test, logd is monotonic time\n"); 155 return; 156 } 157 158 int tries = 3; // in case run too soon after system start or buffer clear 159 int count; 160 161 do { 162 FILE *fp; 163 164 ASSERT_TRUE(NULL != (fp = popen( 165 "logcat -v long -v America/Los_Angeles -b all -t 3 2>/dev/null", 166 "r"))); 167 168 char buffer[BIG_BUFFER]; 169 170 count = 0; 171 172 while (fgetLongTime(buffer, sizeof(buffer), fp)) { 173 if (strstr(buffer, " -0700") || strstr(buffer, " -0800")) { 174 ++count; 175 } 176 } 177 178 pclose(fp); 179 180 } while ((count < 3) && --tries && (sleep(1), true)); 181 182 ASSERT_EQ(3, count); 183} 184 185TEST(logcat, ntz) { 186 FILE *fp; 187 188 ASSERT_TRUE(NULL != (fp = popen( 189 "logcat -v long -v America/Los_Angeles -v zone -b all -t 3 2>/dev/null", 190 "r"))); 191 192 char buffer[BIG_BUFFER]; 193 194 int count = 0; 195 196 while (fgetLongTime(buffer, sizeof(buffer), fp)) { 197 if (strstr(buffer, " -0700") || strstr(buffer, " -0800")) { 198 ++count; 199 } 200 } 201 202 pclose(fp); 203 204 ASSERT_EQ(0, count); 205} 206 207void do_tail(int num) { 208 int tries = 3; // in case run too soon after system start or buffer clear 209 int count; 210 211 do { 212 char buffer[BIG_BUFFER]; 213 214 snprintf(buffer, sizeof(buffer), 215 "logcat -v long -b radio -b events -b system -b main -t %d 2>/dev/null", 216 num); 217 218 FILE *fp; 219 ASSERT_TRUE(NULL != (fp = popen(buffer, "r"))); 220 221 count = 0; 222 223 while (fgetLongTime(buffer, sizeof(buffer), fp)) { 224 ++count; 225 } 226 227 pclose(fp); 228 229 } while ((count < num) && --tries && (sleep(1), true)); 230 231 ASSERT_EQ(num, count); 232} 233 234TEST(logcat, tail_3) { 235 do_tail(3); 236} 237 238TEST(logcat, tail_10) { 239 do_tail(10); 240} 241 242TEST(logcat, tail_100) { 243 do_tail(100); 244} 245 246TEST(logcat, tail_1000) { 247 do_tail(1000); 248} 249 250TEST(logcat, tail_time) { 251 FILE *fp; 252 253 ASSERT_TRUE(NULL != (fp = popen("logcat -v long -b all -t 10 2>&1", "r"))); 254 255 char buffer[BIG_BUFFER]; 256 char *last_timestamp = NULL; 257 char *first_timestamp = NULL; 258 int count = 0; 259 260 char *cp; 261 while ((cp = fgetLongTime(buffer, sizeof(buffer), fp))) { 262 ++count; 263 if (!first_timestamp) { 264 first_timestamp = strdup(cp); 265 } 266 free(last_timestamp); 267 last_timestamp = strdup(cp); 268 } 269 pclose(fp); 270 271 EXPECT_EQ(10, count); 272 EXPECT_TRUE(last_timestamp != NULL); 273 EXPECT_TRUE(first_timestamp != NULL); 274 275 snprintf(buffer, sizeof(buffer), "logcat -v long -b all -t '%s' 2>&1", 276 first_timestamp); 277 ASSERT_TRUE(NULL != (fp = popen(buffer, "r"))); 278 279 int second_count = 0; 280 int last_timestamp_count = -1; 281 282 while ((cp = fgetLongTime(buffer, sizeof(buffer), fp))) { 283 ++second_count; 284 if (first_timestamp) { 285 // we can get a transitory *extremely* rare failure if hidden 286 // underneath the time is *exactly* XX-XX XX:XX:XX.XXX000000 287 EXPECT_STREQ(cp, first_timestamp); 288 free(first_timestamp); 289 first_timestamp = NULL; 290 } 291 if (!strcmp(cp, last_timestamp)) { 292 last_timestamp_count = second_count; 293 } 294 } 295 pclose(fp); 296 297 free(last_timestamp); 298 last_timestamp = NULL; 299 free(first_timestamp); 300 301 EXPECT_TRUE(first_timestamp == NULL); 302 EXPECT_LE(count, second_count); 303 EXPECT_LE(count, last_timestamp_count); 304} 305 306TEST(logcat, End_to_End) { 307 pid_t pid = getpid(); 308 309 log_time ts(CLOCK_MONOTONIC); 310 311 ASSERT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts))); 312 313 FILE *fp; 314 ASSERT_TRUE(NULL != (fp = popen( 315 "logcat -v brief -b events -t 100 2>/dev/null", 316 "r"))); 317 318 char buffer[BIG_BUFFER]; 319 320 int count = 0; 321 322 while (fgets(buffer, sizeof(buffer), fp)) { 323 int p; 324 unsigned long long t; 325 326 if ((2 != sscanf(buffer, "I/[0] ( %d): %llu", &p, &t)) 327 || (p != pid)) { 328 continue; 329 } 330 331 log_time tx((const char *) &t); 332 if (ts == tx) { 333 ++count; 334 } 335 } 336 337 pclose(fp); 338 339 ASSERT_EQ(1, count); 340} 341 342int get_groups(const char *cmd) { 343 FILE *fp; 344 345 // NB: crash log only available in user space 346 EXPECT_TRUE(NULL != (fp = popen(cmd, "r"))); 347 348 if (fp == NULL) { 349 return 0; 350 } 351 352 char buffer[BIG_BUFFER]; 353 354 int count = 0; 355 356 while (fgets(buffer, sizeof(buffer), fp)) { 357 int size, consumed, max, payload; 358 char size_mult[3], consumed_mult[3]; 359 long full_size, full_consumed; 360 361 size = consumed = max = payload = 0; 362 // NB: crash log can be very small, not hit a Kb of consumed space 363 // doubly lucky we are not including it. 364 if (6 != sscanf(buffer, "%*s ring buffer is %d%2s (%d%2s consumed)," 365 " max entry is %db, max payload is %db", 366 &size, size_mult, &consumed, consumed_mult, 367 &max, &payload)) { 368 fprintf(stderr, "WARNING: Parse error: %s", buffer); 369 continue; 370 } 371 full_size = size; 372 switch(size_mult[0]) { 373 case 'G': 374 full_size *= 1024; 375 /* FALLTHRU */ 376 case 'M': 377 full_size *= 1024; 378 /* FALLTHRU */ 379 case 'K': 380 full_size *= 1024; 381 /* FALLTHRU */ 382 case 'b': 383 break; 384 } 385 full_consumed = consumed; 386 switch(consumed_mult[0]) { 387 case 'G': 388 full_consumed *= 1024; 389 /* FALLTHRU */ 390 case 'M': 391 full_consumed *= 1024; 392 /* FALLTHRU */ 393 case 'K': 394 full_consumed *= 1024; 395 /* FALLTHRU */ 396 case 'b': 397 break; 398 } 399 EXPECT_GT((full_size * 9) / 4, full_consumed); 400 EXPECT_GT(full_size, max); 401 EXPECT_GT(max, payload); 402 403 if ((((full_size * 9) / 4) >= full_consumed) 404 && (full_size > max) 405 && (max > payload)) { 406 ++count; 407 } 408 } 409 410 pclose(fp); 411 412 return count; 413} 414 415TEST(logcat, get_size) { 416 ASSERT_EQ(4, get_groups( 417 "logcat -v brief -b radio -b events -b system -b main -g 2>/dev/null")); 418} 419 420// duplicate test for get_size, but use comma-separated list of buffers 421TEST(logcat, multiple_buffer) { 422 ASSERT_EQ(4, get_groups( 423 "logcat -v brief -b radio,events,system,main -g 2>/dev/null")); 424} 425 426TEST(logcat, bad_buffer) { 427 ASSERT_EQ(0, get_groups( 428 "logcat -v brief -b radio,events,bogo,system,main -g 2>/dev/null")); 429} 430 431static void caught_blocking(int /*signum*/) 432{ 433 unsigned long long v = 0xDEADBEEFA55A0000ULL; 434 435 v += getpid() & 0xFFFF; 436 437 LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v))); 438} 439 440TEST(logcat, blocking) { 441 FILE *fp; 442 unsigned long long v = 0xDEADBEEFA55F0000ULL; 443 444 pid_t pid = getpid(); 445 446 v += pid & 0xFFFF; 447 448 LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v))); 449 450 v &= 0xFFFFFFFFFFFAFFFFULL; 451 452 ASSERT_TRUE(NULL != (fp = popen( 453 "( trap exit HUP QUIT INT PIPE KILL ; sleep 6; echo DONE )&" 454 " logcat -v brief -b events 2>&1", 455 "r"))); 456 457 char buffer[BIG_BUFFER]; 458 459 int count = 0; 460 461 int signals = 0; 462 463 signal(SIGALRM, caught_blocking); 464 alarm(2); 465 while (fgets(buffer, sizeof(buffer), fp)) { 466 467 if (!strncmp(buffer, "DONE", 4)) { 468 break; 469 } 470 471 ++count; 472 473 int p; 474 unsigned long long l; 475 476 if ((2 != sscanf(buffer, "I/[0] ( %u): %lld", &p, &l)) 477 || (p != pid)) { 478 continue; 479 } 480 481 if (l == v) { 482 ++signals; 483 break; 484 } 485 } 486 alarm(0); 487 signal(SIGALRM, SIG_DFL); 488 489 // Generate SIGPIPE 490 fclose(fp); 491 caught_blocking(0); 492 493 pclose(fp); 494 495 EXPECT_LE(2, count); 496 497 EXPECT_EQ(1, signals); 498} 499 500static void caught_blocking_tail(int /*signum*/) 501{ 502 unsigned long long v = 0xA55ADEADBEEF0000ULL; 503 504 v += getpid() & 0xFFFF; 505 506 LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v))); 507} 508 509TEST(logcat, blocking_tail) { 510 FILE *fp; 511 unsigned long long v = 0xA55FDEADBEEF0000ULL; 512 513 pid_t pid = getpid(); 514 515 v += pid & 0xFFFF; 516 517 LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v))); 518 519 v &= 0xFFFAFFFFFFFFFFFFULL; 520 521 ASSERT_TRUE(NULL != (fp = popen( 522 "( trap exit HUP QUIT INT PIPE KILL ; sleep 6; echo DONE )&" 523 " logcat -v brief -b events -T 5 2>&1", 524 "r"))); 525 526 char buffer[BIG_BUFFER]; 527 528 int count = 0; 529 530 int signals = 0; 531 532 signal(SIGALRM, caught_blocking_tail); 533 alarm(2); 534 while (fgets(buffer, sizeof(buffer), fp)) { 535 536 if (!strncmp(buffer, "DONE", 4)) { 537 break; 538 } 539 540 ++count; 541 542 int p; 543 unsigned long long l; 544 545 if ((2 != sscanf(buffer, "I/[0] ( %u): %lld", &p, &l)) 546 || (p != pid)) { 547 continue; 548 } 549 550 if (l == v) { 551 if (count >= 5) { 552 ++signals; 553 } 554 break; 555 } 556 } 557 alarm(0); 558 signal(SIGALRM, SIG_DFL); 559 560 // Generate SIGPIPE 561 fclose(fp); 562 caught_blocking_tail(0); 563 564 pclose(fp); 565 566 EXPECT_LE(2, count); 567 568 EXPECT_EQ(1, signals); 569} 570 571TEST(logcat, logrotate) { 572 static const char form[] = "/data/local/tmp/logcat.logrotate.XXXXXX"; 573 char buf[sizeof(form)]; 574 ASSERT_TRUE(NULL != mkdtemp(strcpy(buf, form))); 575 576 static const char comm[] = "logcat -b radio -b events -b system -b main" 577 " -d -f %s/log.txt -n 7 -r 1"; 578 char command[sizeof(buf) + sizeof(comm)]; 579 snprintf(command, sizeof(command), comm, buf); 580 581 int ret; 582 EXPECT_FALSE((ret = system(command))); 583 if (!ret) { 584 snprintf(command, sizeof(command), "ls -s %s 2>/dev/null", buf); 585 586 FILE *fp; 587 EXPECT_TRUE(NULL != (fp = popen(command, "r"))); 588 if (fp) { 589 char buffer[BIG_BUFFER]; 590 int count = 0; 591 592 while (fgets(buffer, sizeof(buffer), fp)) { 593 static const char total[] = "total "; 594 int num; 595 char c; 596 597 if ((2 == sscanf(buffer, "%d log.tx%c", &num, &c)) && 598 (num <= 40)) { 599 ++count; 600 } else if (strncmp(buffer, total, sizeof(total) - 1)) { 601 fprintf(stderr, "WARNING: Parse error: %s", buffer); 602 } 603 } 604 pclose(fp); 605 if ((count != 7) && (count != 8)) { 606 fprintf(stderr, "count=%d\n", count); 607 } 608 EXPECT_TRUE(count == 7 || count == 8); 609 } 610 } 611 snprintf(command, sizeof(command), "rm -rf %s", buf); 612 EXPECT_FALSE(system(command)); 613} 614 615TEST(logcat, logrotate_suffix) { 616 static const char tmp_out_dir_form[] = "/data/local/tmp/logcat.logrotate.XXXXXX"; 617 char tmp_out_dir[sizeof(tmp_out_dir_form)]; 618 ASSERT_TRUE(NULL != mkdtemp(strcpy(tmp_out_dir, tmp_out_dir_form))); 619 620 static const char logcat_cmd[] = "logcat -b radio -b events -b system -b main" 621 " -d -f %s/log.txt -n 10 -r 1"; 622 char command[sizeof(tmp_out_dir) + sizeof(logcat_cmd)]; 623 snprintf(command, sizeof(command), logcat_cmd, tmp_out_dir); 624 625 int ret; 626 EXPECT_FALSE((ret = system(command))); 627 if (!ret) { 628 snprintf(command, sizeof(command), "ls %s 2>/dev/null", tmp_out_dir); 629 630 FILE *fp; 631 EXPECT_TRUE(NULL != (fp = popen(command, "r"))); 632 char buffer[BIG_BUFFER]; 633 int log_file_count = 0; 634 635 while (fgets(buffer, sizeof(buffer), fp)) { 636 static const char rotated_log_filename_prefix[] = "log.txt."; 637 static const size_t rotated_log_filename_prefix_len = 638 strlen(rotated_log_filename_prefix); 639 static const char log_filename[] = "log.txt"; 640 641 if (!strncmp(buffer, rotated_log_filename_prefix, rotated_log_filename_prefix_len)) { 642 // Rotated file should have form log.txt.## 643 char* rotated_log_filename_suffix = buffer + rotated_log_filename_prefix_len; 644 char* endptr; 645 const long int suffix_value = strtol(rotated_log_filename_suffix, &endptr, 10); 646 EXPECT_EQ(rotated_log_filename_suffix + 2, endptr); 647 EXPECT_LE(suffix_value, 10); 648 EXPECT_GT(suffix_value, 0); 649 ++log_file_count; 650 continue; 651 } 652 653 if (!strncmp(buffer, log_filename, strlen(log_filename))) { 654 ++log_file_count; 655 continue; 656 } 657 658 fprintf(stderr, "ERROR: Unexpected file: %s", buffer); 659 ADD_FAILURE(); 660 } 661 pclose(fp); 662 EXPECT_EQ(11, log_file_count); 663 } 664 snprintf(command, sizeof(command), "rm -rf %s", tmp_out_dir); 665 EXPECT_FALSE(system(command)); 666} 667 668TEST(logcat, logrotate_continue) { 669 static const char tmp_out_dir_form[] = "/data/local/tmp/logcat.logrotate.XXXXXX"; 670 char tmp_out_dir[sizeof(tmp_out_dir_form)]; 671 ASSERT_TRUE(NULL != mkdtemp(strcpy(tmp_out_dir, tmp_out_dir_form))); 672 673 static const char log_filename[] = "log.txt"; 674 static const char logcat_cmd[] = "logcat -b all -d -f %s/%s -n 256 -r 1024"; 675 static const char cleanup_cmd[] = "rm -rf %s"; 676 char command[sizeof(tmp_out_dir) + sizeof(logcat_cmd) + sizeof(log_filename)]; 677 snprintf(command, sizeof(command), logcat_cmd, tmp_out_dir, log_filename); 678 679 int ret; 680 EXPECT_FALSE((ret = system(command))); 681 if (ret) { 682 snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir); 683 EXPECT_FALSE(system(command)); 684 return; 685 } 686 FILE *fp; 687 snprintf(command, sizeof(command), "%s/%s", tmp_out_dir, log_filename); 688 EXPECT_TRUE(NULL != ((fp = fopen(command, "r")))); 689 if (!fp) { 690 snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir); 691 EXPECT_FALSE(system(command)); 692 return; 693 } 694 char *line = NULL; 695 char *last_line = NULL; // this line is allowed to stutter, one-line overlap 696 char *second_last_line = NULL; 697 size_t len = 0; 698 while (getline(&line, &len, fp) != -1) { 699 free(second_last_line); 700 second_last_line = last_line; 701 last_line = line; 702 line = NULL; 703 } 704 fclose(fp); 705 free(line); 706 if (second_last_line == NULL) { 707 fprintf(stderr, "No second to last line, using last, test may fail\n"); 708 second_last_line = last_line; 709 last_line = NULL; 710 } 711 free(last_line); 712 EXPECT_TRUE(NULL != second_last_line); 713 if (!second_last_line) { 714 snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir); 715 EXPECT_FALSE(system(command)); 716 return; 717 } 718 // re-run the command, it should only add a few lines more content if it 719 // continues where it left off. 720 snprintf(command, sizeof(command), logcat_cmd, tmp_out_dir, log_filename); 721 EXPECT_FALSE((ret = system(command))); 722 if (ret) { 723 snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir); 724 EXPECT_FALSE(system(command)); 725 return; 726 } 727 DIR *dir; 728 EXPECT_TRUE(NULL != (dir = opendir(tmp_out_dir))); 729 if (!dir) { 730 snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir); 731 EXPECT_FALSE(system(command)); 732 return; 733 } 734 struct dirent *entry; 735 unsigned count = 0; 736 while ((entry = readdir(dir))) { 737 if (strncmp(entry->d_name, log_filename, sizeof(log_filename) - 1)) { 738 continue; 739 } 740 snprintf(command, sizeof(command), "%s/%s", tmp_out_dir, entry->d_name); 741 EXPECT_TRUE(NULL != ((fp = fopen(command, "r")))); 742 if (!fp) { 743 fprintf(stderr, "%s ?\n", command); 744 continue; 745 } 746 line = NULL; 747 size_t number = 0; 748 while (getline(&line, &len, fp) != -1) { 749 ++number; 750 if (!strcmp(line, second_last_line)) { 751 EXPECT_TRUE(++count <= 1); 752 fprintf(stderr, "%s(%zu):\n", entry->d_name, number); 753 } 754 } 755 fclose(fp); 756 free(line); 757 unlink(command); 758 } 759 closedir(dir); 760 if (count > 1) { 761 char *brk = strpbrk(second_last_line, "\r\n"); 762 if (!brk) { 763 brk = second_last_line + strlen(second_last_line); 764 } 765 fprintf(stderr, "\"%.*s\" occured %u times\n", 766 (int)(brk - second_last_line), second_last_line, count); 767 } 768 free(second_last_line); 769 770 snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir); 771 EXPECT_FALSE(system(command)); 772} 773 774TEST(logcat, logrotate_clear) { 775 static const char tmp_out_dir_form[] = "/data/local/tmp/logcat.logrotate.XXXXXX"; 776 char tmp_out_dir[sizeof(tmp_out_dir_form)]; 777 ASSERT_TRUE(NULL != mkdtemp(strcpy(tmp_out_dir, tmp_out_dir_form))); 778 779 static const char log_filename[] = "log.txt"; 780 static const unsigned num_val = 32; 781 static const char logcat_cmd[] = "logcat -b all -d -f %s/%s -n %d -r 1"; 782 static const char clear_cmd[] = " -c"; 783 static const char cleanup_cmd[] = "rm -rf %s"; 784 char command[sizeof(tmp_out_dir) + sizeof(logcat_cmd) + sizeof(log_filename) + sizeof(clear_cmd) + 32]; 785 786 // Run command with all data 787 { 788 snprintf(command, sizeof(command) - sizeof(clear_cmd), 789 logcat_cmd, tmp_out_dir, log_filename, num_val); 790 791 int ret; 792 EXPECT_FALSE((ret = system(command))); 793 if (ret) { 794 snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir); 795 EXPECT_FALSE(system(command)); 796 return; 797 } 798 std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(tmp_out_dir), closedir); 799 EXPECT_NE(nullptr, dir); 800 if (!dir) { 801 snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir); 802 EXPECT_FALSE(system(command)); 803 return; 804 } 805 struct dirent *entry; 806 unsigned count = 0; 807 while ((entry = readdir(dir.get()))) { 808 if (strncmp(entry->d_name, log_filename, sizeof(log_filename) - 1)) { 809 continue; 810 } 811 ++count; 812 } 813 EXPECT_EQ(count, num_val + 1); 814 } 815 816 { 817 // Now with -c option tacked onto the end 818 strcat(command, clear_cmd); 819 820 int ret; 821 EXPECT_FALSE((ret = system(command))); 822 if (ret) { 823 snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir); 824 EXPECT_FALSE(system(command)); 825 return; 826 } 827 std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(tmp_out_dir), closedir); 828 EXPECT_NE(nullptr, dir); 829 if (!dir) { 830 snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir); 831 EXPECT_FALSE(system(command)); 832 return; 833 } 834 struct dirent *entry; 835 unsigned count = 0; 836 while ((entry = readdir(dir.get()))) { 837 if (strncmp(entry->d_name, log_filename, sizeof(log_filename) - 1)) { 838 continue; 839 } 840 fprintf(stderr, "Found %s/%s!!!\n", tmp_out_dir, entry->d_name); 841 ++count; 842 } 843 EXPECT_EQ(count, 0U); 844 } 845 846 snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir); 847 EXPECT_FALSE(system(command)); 848} 849 850TEST(logcat, logrotate_nodir) { 851 // expect logcat to error out on writing content and exit(1) for nodir 852 EXPECT_EQ(W_EXITCODE(1, 0), 853 system("logcat -b all -d" 854 " -f /das/nein/gerfingerpoken/logcat/log.txt" 855 " -n 256 -r 1024")); 856} 857 858static void caught_blocking_clear(int /*signum*/) { 859 unsigned long long v = 0xDEADBEEFA55C0000ULL; 860 861 v += getpid() & 0xFFFF; 862 863 LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v))); 864} 865 866TEST(logcat, blocking_clear) { 867 FILE *fp; 868 unsigned long long v = 0xDEADBEEFA55C0000ULL; 869 870 pid_t pid = getpid(); 871 872 v += pid & 0xFFFF; 873 874 // This test is racey; an event occurs between clear and dump. 875 // We accept that we will get a false positive, but never a false negative. 876 ASSERT_TRUE(NULL != (fp = popen( 877 "( trap exit HUP QUIT INT PIPE KILL ; sleep 6; echo DONE )&" 878 " logcat -b events -c 2>&1 ;" 879 " logcat -v brief -b events 2>&1", 880 "r"))); 881 882 char buffer[BIG_BUFFER]; 883 884 int count = 0; 885 886 int signals = 0; 887 888 signal(SIGALRM, caught_blocking_clear); 889 alarm(2); 890 while (fgets(buffer, sizeof(buffer), fp)) { 891 892 if (!strncmp(buffer, "clearLog: ", 10)) { 893 fprintf(stderr, "WARNING: Test lacks permission to run :-(\n"); 894 count = signals = 1; 895 break; 896 } 897 898 if (!strncmp(buffer, "DONE", 4)) { 899 break; 900 } 901 902 ++count; 903 904 int p; 905 unsigned long long l; 906 907 if ((2 != sscanf(buffer, "I/[0] ( %u): %lld", &p, &l)) 908 || (p != pid)) { 909 continue; 910 } 911 912 if (l == v) { 913 if (count > 1) { 914 fprintf(stderr, "WARNING: Possible false positive\n"); 915 } 916 ++signals; 917 break; 918 } 919 } 920 alarm(0); 921 signal(SIGALRM, SIG_DFL); 922 923 // Generate SIGPIPE 924 fclose(fp); 925 caught_blocking_clear(0); 926 927 pclose(fp); 928 929 EXPECT_LE(1, count); 930 931 EXPECT_EQ(1, signals); 932} 933 934static bool get_white_black(char **list) { 935 FILE *fp; 936 937 fp = popen("logcat -p 2>/dev/null", "r"); 938 if (fp == NULL) { 939 fprintf(stderr, "ERROR: logcat -p 2>/dev/null\n"); 940 return false; 941 } 942 943 char buffer[BIG_BUFFER]; 944 945 while (fgets(buffer, sizeof(buffer), fp)) { 946 char *hold = *list; 947 char *buf = buffer; 948 while (isspace(*buf)) { 949 ++buf; 950 } 951 char *end = buf + strlen(buf); 952 while (isspace(*--end) && (end >= buf)) { 953 *end = '\0'; 954 } 955 if (end < buf) { 956 continue; 957 } 958 if (hold) { 959 asprintf(list, "%s %s", hold, buf); 960 free(hold); 961 } else { 962 asprintf(list, "%s", buf); 963 } 964 } 965 pclose(fp); 966 return *list != NULL; 967} 968 969static bool set_white_black(const char *list) { 970 FILE *fp; 971 972 char buffer[BIG_BUFFER]; 973 974 snprintf(buffer, sizeof(buffer), "logcat -P '%s' 2>&1", list ? list : ""); 975 fp = popen(buffer, "r"); 976 if (fp == NULL) { 977 fprintf(stderr, "ERROR: %s\n", buffer); 978 return false; 979 } 980 981 while (fgets(buffer, sizeof(buffer), fp)) { 982 char *buf = buffer; 983 while (isspace(*buf)) { 984 ++buf; 985 } 986 char *end = buf + strlen(buf); 987 while ((end > buf) && isspace(*--end)) { 988 *end = '\0'; 989 } 990 if (end <= buf) { 991 continue; 992 } 993 fprintf(stderr, "%s\n", buf); 994 pclose(fp); 995 return false; 996 } 997 return pclose(fp) == 0; 998} 999 1000TEST(logcat, white_black_adjust) { 1001 char *list = NULL; 1002 char *adjust = NULL; 1003 1004 get_white_black(&list); 1005 1006 static const char adjustment[] = "~! 300/20 300/25 2000 ~1000/5 ~1000/30"; 1007 ASSERT_EQ(true, set_white_black(adjustment)); 1008 ASSERT_EQ(true, get_white_black(&adjust)); 1009 EXPECT_STREQ(adjustment, adjust); 1010 free(adjust); 1011 adjust = NULL; 1012 1013 static const char adjustment2[] = "300/20 300/21 2000 ~1000"; 1014 ASSERT_EQ(true, set_white_black(adjustment2)); 1015 ASSERT_EQ(true, get_white_black(&adjust)); 1016 EXPECT_STREQ(adjustment2, adjust); 1017 free(adjust); 1018 adjust = NULL; 1019 1020 ASSERT_EQ(true, set_white_black(list)); 1021 get_white_black(&adjust); 1022 EXPECT_STREQ(list ? list : "", adjust ? adjust : ""); 1023 free(adjust); 1024 adjust = NULL; 1025 1026 free(list); 1027 list = NULL; 1028} 1029 1030TEST(logcat, regex) { 1031 FILE *fp; 1032 int count = 0; 1033 1034 char buffer[BIG_BUFFER]; 1035 1036 snprintf(buffer, sizeof(buffer), "logcat --pid %d -d -e logcat_test_a+b", getpid()); 1037 1038 LOG_FAILURE_RETRY(__android_log_print(ANDROID_LOG_WARN, "logcat_test", "logcat_test_ab")); 1039 LOG_FAILURE_RETRY(__android_log_print(ANDROID_LOG_WARN, "logcat_test", "logcat_test_b")); 1040 LOG_FAILURE_RETRY(__android_log_print(ANDROID_LOG_WARN, "logcat_test", "logcat_test_aaaab")); 1041 LOG_FAILURE_RETRY(__android_log_print(ANDROID_LOG_WARN, "logcat_test", "logcat_test_aaaa")); 1042 1043 // Let the logs settle 1044 sleep(1); 1045 1046 ASSERT_TRUE(NULL != (fp = popen(buffer, "r"))); 1047 1048 while (fgets(buffer, sizeof(buffer), fp)) { 1049 if (!strncmp(begin, buffer, sizeof(begin) - 1)) { 1050 continue; 1051 } 1052 1053 EXPECT_TRUE(strstr(buffer, "logcat_test_") != NULL); 1054 1055 count++; 1056 } 1057 1058 pclose(fp); 1059 1060 ASSERT_EQ(2, count); 1061} 1062 1063TEST(logcat, maxcount) { 1064 FILE *fp; 1065 int count = 0; 1066 1067 char buffer[BIG_BUFFER]; 1068 1069 snprintf(buffer, sizeof(buffer), "logcat --pid %d -d --max-count 3", getpid()); 1070 1071 LOG_FAILURE_RETRY(__android_log_print(ANDROID_LOG_WARN, "logcat_test", "logcat_test")); 1072 LOG_FAILURE_RETRY(__android_log_print(ANDROID_LOG_WARN, "logcat_test", "logcat_test")); 1073 LOG_FAILURE_RETRY(__android_log_print(ANDROID_LOG_WARN, "logcat_test", "logcat_test")); 1074 LOG_FAILURE_RETRY(__android_log_print(ANDROID_LOG_WARN, "logcat_test", "logcat_test")); 1075 1076 // Let the logs settle 1077 sleep(1); 1078 1079 ASSERT_TRUE(NULL != (fp = popen(buffer, "r"))); 1080 1081 while (fgets(buffer, sizeof(buffer), fp)) { 1082 if (!strncmp(begin, buffer, sizeof(begin) - 1)) { 1083 continue; 1084 } 1085 1086 count++; 1087 } 1088 1089 pclose(fp); 1090 1091 ASSERT_EQ(3, count); 1092} 1093