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/cdefs.h> 24 #include <sys/stat.h> 25 #include <sys/types.h> 26 #include <sys/wait.h> 27 #include <unistd.h> 28 29 #include <memory> 30 #include <string> 31 32 #include <android-base/file.h> 33 #include <gtest/gtest.h> 34 #include <log/log.h> 35 #include <log/log_event_list.h> 36 37 #ifndef logcat_popen 38 #define logcat_define(context) 39 #define logcat_popen(context, command) popen((command), "r") 40 #define logcat_pclose(context, fp) pclose(fp) 41 #define logcat_system(command) system(command) 42 #endif 43 #ifndef logcat_executable 44 #define USING_LOGCAT_EXECUTABLE_DEFAULT 45 #define logcat_executable "logcat" 46 #endif 47 48 #define BIG_BUFFER (5 * 1024) 49 50 // enhanced version of LOG_FAILURE_RETRY to add support for EAGAIN and 51 // non-syscall libs. Since we are only using this in the emergency of 52 // a signal to stuff a terminating code into the logs, we will spin rather 53 // than try a usleep. 54 #define LOG_FAILURE_RETRY(exp) \ 55 ({ \ 56 typeof(exp) _rc; \ 57 do { \ 58 _rc = (exp); \ 59 } while (((_rc == -1) && ((errno == EINTR) || (errno == EAGAIN))) || \ 60 (_rc == -EINTR) || (_rc == -EAGAIN)); \ 61 _rc; \ 62 }) 63 64 static const char begin[] = "--------- beginning of "; 65 66 TEST(logcat, buckets) { 67 FILE* fp; 68 logcat_define(ctx); 69 70 #undef LOG_TAG 71 #define LOG_TAG "inject" 72 RLOGE(logcat_executable ".buckets"); 73 sleep(1); 74 75 ASSERT_TRUE(NULL != 76 (fp = logcat_popen( 77 ctx, logcat_executable 78 " -b radio -b events -b system -b main -d 2>/dev/null"))); 79 80 char buffer[BIG_BUFFER]; 81 82 int ids = 0; 83 int count = 0; 84 85 while (fgets(buffer, sizeof(buffer), fp)) { 86 if (!strncmp(begin, buffer, sizeof(begin) - 1)) { 87 while (char* cp = strrchr(buffer, '\n')) { 88 *cp = '\0'; 89 } 90 log_id_t id = android_name_to_log_id(buffer + sizeof(begin) - 1); 91 ids |= 1 << id; 92 ++count; 93 } 94 } 95 96 logcat_pclose(ctx, fp); 97 98 EXPECT_EQ(15, ids); 99 100 EXPECT_EQ(4, count); 101 } 102 103 TEST(logcat, event_tag_filter) { 104 FILE* fp; 105 logcat_define(ctx); 106 107 ASSERT_TRUE(NULL != 108 (fp = logcat_popen(ctx, logcat_executable 109 " -b events -d -s auditd " 110 "am_proc_start am_pss am_proc_bound " 111 "dvm_lock_sample am_wtf 2>/dev/null"))); 112 113 char buffer[BIG_BUFFER]; 114 115 int count = 0; 116 117 while (fgets(buffer, sizeof(buffer), fp)) { 118 ++count; 119 } 120 121 logcat_pclose(ctx, fp); 122 123 EXPECT_LT(4, count); 124 } 125 126 // If there is not enough background noise in the logs, then spam the logs to 127 // permit tail checking so that the tests can progress. 128 static size_t inject(ssize_t count) { 129 if (count <= 0) return 0; 130 131 static const size_t retry = 4; 132 size_t errors = retry; 133 size_t num = 0; 134 for (;;) { 135 log_time ts(CLOCK_MONOTONIC); 136 if (__android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)) >= 0) { 137 if (++num >= (size_t)count) { 138 // let data settle end-to-end 139 sleep(3); 140 return num; 141 } 142 errors = retry; 143 usleep(100); // ~32 per timer tick, we are a spammer regardless 144 } else if (--errors <= 0) { 145 return num; 146 } 147 } 148 // NOTREACH 149 return num; 150 } 151 152 TEST(logcat, year) { 153 if (android_log_clockid() == CLOCK_MONOTONIC) { 154 fprintf(stderr, "Skipping test, logd is monotonic time\n"); 155 return; 156 } 157 158 int count; 159 int tries = 3; // in case run too soon after system start or buffer clear 160 161 do { 162 FILE* fp; 163 logcat_define(ctx); 164 165 char needle[32]; 166 time_t now; 167 time(&now); 168 struct tm* ptm; 169 #if !defined(_WIN32) 170 struct tm tmBuf; 171 ptm = localtime_r(&now, &tmBuf); 172 #else 173 ptm = localtime(&&now); 174 #endif 175 strftime(needle, sizeof(needle), "[ %Y-", ptm); 176 177 ASSERT_TRUE(NULL != (fp = logcat_popen( 178 ctx, logcat_executable 179 " -v long -v year -b all -t 3 2>/dev/null"))); 180 181 char buffer[BIG_BUFFER]; 182 183 count = 0; 184 185 while (fgets(buffer, sizeof(buffer), fp)) { 186 if (!strncmp(buffer, needle, strlen(needle))) { 187 ++count; 188 } 189 } 190 logcat_pclose(ctx, fp); 191 192 } while ((count < 3) && --tries && inject(3 - count)); 193 194 ASSERT_EQ(3, count); 195 } 196 197 // Return a pointer to each null terminated -v long time field. 198 static char* fgetLongTime(char* buffer, size_t buflen, FILE* fp) { 199 while (fgets(buffer, buflen, fp)) { 200 char* cp = buffer; 201 if (*cp != '[') { 202 continue; 203 } 204 while (*++cp == ' ') { 205 ; 206 } 207 char* ep = cp; 208 while (isdigit(*ep)) { 209 ++ep; 210 } 211 if ((*ep != '-') && (*ep != '.')) { 212 continue; 213 } 214 // Find PID field. Look for ': ' or ':[0-9][0-9][0-9]' 215 while (((ep = strchr(ep, ':'))) && (*++ep != ' ')) { 216 if (isdigit(ep[0]) && isdigit(ep[1]) && isdigit(ep[2])) break; 217 } 218 if (!ep) { 219 continue; 220 } 221 static const size_t pid_field_width = 7; 222 ep -= pid_field_width; 223 *ep = '\0'; 224 return cp; 225 } 226 return NULL; 227 } 228 229 TEST(logcat, tz) { 230 if (android_log_clockid() == CLOCK_MONOTONIC) { 231 fprintf(stderr, "Skipping test, logd is monotonic time\n"); 232 return; 233 } 234 235 int tries = 4; // in case run too soon after system start or buffer clear 236 int count; 237 238 do { 239 FILE* fp; 240 logcat_define(ctx); 241 242 ASSERT_TRUE(NULL != 243 (fp = logcat_popen(ctx, logcat_executable 244 " -v long -v America/Los_Angeles " 245 "-b all -t 3 2>/dev/null"))); 246 247 char buffer[BIG_BUFFER]; 248 249 count = 0; 250 251 while (fgetLongTime(buffer, sizeof(buffer), fp)) { 252 if (strstr(buffer, " -0700") || strstr(buffer, " -0800")) { 253 ++count; 254 } else { 255 fprintf(stderr, "ts=\"%s\"\n", buffer + 2); 256 } 257 } 258 259 logcat_pclose(ctx, fp); 260 261 } while ((count < 3) && --tries && inject(3 - count)); 262 263 ASSERT_EQ(3, count); 264 } 265 266 TEST(logcat, ntz) { 267 FILE* fp; 268 logcat_define(ctx); 269 270 ASSERT_TRUE(NULL != (fp = logcat_popen(ctx, logcat_executable 271 " -v long -v America/Los_Angeles -v " 272 "zone -b all -t 3 2>/dev/null"))); 273 274 char buffer[BIG_BUFFER]; 275 276 int count = 0; 277 278 while (fgetLongTime(buffer, sizeof(buffer), fp)) { 279 if (strstr(buffer, " -0700") || strstr(buffer, " -0800")) { 280 ++count; 281 } 282 } 283 284 logcat_pclose(ctx, fp); 285 286 ASSERT_EQ(0, count); 287 } 288 289 static void do_tail(int num) { 290 int tries = 4; // in case run too soon after system start or buffer clear 291 int count; 292 293 if (num > 10) ++tries; 294 if (num > 100) ++tries; 295 do { 296 char buffer[BIG_BUFFER]; 297 298 snprintf(buffer, sizeof(buffer), 299 "ANDROID_PRINTF_LOG=long logcat -b all -t %d 2>/dev/null", num); 300 301 FILE* fp; 302 logcat_define(ctx); 303 ASSERT_TRUE(NULL != (fp = logcat_popen(ctx, buffer))); 304 305 count = 0; 306 307 while (fgetLongTime(buffer, sizeof(buffer), fp)) { 308 ++count; 309 } 310 311 logcat_pclose(ctx, fp); 312 313 } while ((count < num) && --tries && inject(num - count)); 314 315 ASSERT_EQ(num, count); 316 } 317 318 TEST(logcat, tail_3) { 319 do_tail(3); 320 } 321 322 TEST(logcat, tail_10) { 323 do_tail(10); 324 } 325 326 TEST(logcat, tail_100) { 327 do_tail(100); 328 } 329 330 TEST(logcat, tail_1000) { 331 do_tail(1000); 332 } 333 334 static void do_tail_time(const char* cmd) { 335 FILE* fp; 336 int count; 337 char buffer[BIG_BUFFER]; 338 char* last_timestamp = NULL; 339 // Hard to predict 100% if first (overlap) or second line will match. 340 // -v nsec will in a substantial majority be the second line. 341 char* first_timestamp = NULL; 342 char* second_timestamp = NULL; 343 char* input; 344 345 int tries = 4; // in case run too soon after system start or buffer clear 346 347 do { 348 snprintf(buffer, sizeof(buffer), "%s -t 10 2>&1", cmd); 349 logcat_define(ctx); 350 ASSERT_TRUE(NULL != (fp = logcat_popen(ctx, buffer))); 351 count = 0; 352 353 while ((input = fgetLongTime(buffer, sizeof(buffer), fp))) { 354 ++count; 355 if (!first_timestamp) { 356 first_timestamp = strdup(input); 357 } else if (!second_timestamp) { 358 second_timestamp = strdup(input); 359 } 360 free(last_timestamp); 361 last_timestamp = strdup(input); 362 } 363 logcat_pclose(ctx, fp); 364 365 } while ((count < 10) && --tries && inject(10 - count)); 366 367 EXPECT_EQ(10, count); // We want _some_ history, too small, falses below 368 EXPECT_TRUE(last_timestamp != NULL); 369 EXPECT_TRUE(first_timestamp != NULL); 370 EXPECT_TRUE(second_timestamp != NULL); 371 372 snprintf(buffer, sizeof(buffer), "%s -t '%s' 2>&1", cmd, first_timestamp); 373 logcat_define(ctx); 374 ASSERT_TRUE(NULL != (fp = logcat_popen(ctx, buffer))); 375 376 int second_count = 0; 377 int last_timestamp_count = -1; 378 379 --count; // One less unless we match the first_timestamp 380 bool found = false; 381 while ((input = fgetLongTime(buffer, sizeof(buffer), fp))) { 382 ++second_count; 383 // We want to highlight if we skip to the next entry. 384 // WAI, if the time in logd is *exactly* 385 // XX-XX XX:XX:XX.XXXXXX000 (usec) or XX-XX XX:XX:XX.XXX000000 386 // this can happen, but it should not happen with nsec. 387 // We can make this WAI behavior happen 1000 times less 388 // frequently if the caller does not use the -v usec flag, 389 // but always the second (always skip) if they use the 390 // (undocumented) -v nsec flag. 391 if (first_timestamp) { 392 found = !strcmp(input, first_timestamp); 393 if (found) { 394 ++count; 395 GTEST_LOG_(INFO) 396 << "input = first(" << first_timestamp << ")\n"; 397 } 398 free(first_timestamp); 399 first_timestamp = NULL; 400 } 401 if (second_timestamp) { 402 found = found || !strcmp(input, second_timestamp); 403 if (!found) { 404 GTEST_LOG_(INFO) << "input(" << input << ") != second(" 405 << second_timestamp << ")\n"; 406 } 407 free(second_timestamp); 408 second_timestamp = NULL; 409 } 410 if (!strcmp(input, last_timestamp)) { 411 last_timestamp_count = second_count; 412 } 413 } 414 logcat_pclose(ctx, fp); 415 416 EXPECT_TRUE(found); 417 if (!found) { 418 if (first_timestamp) { 419 GTEST_LOG_(INFO) << "first = " << first_timestamp << "\n"; 420 } 421 if (second_timestamp) { 422 GTEST_LOG_(INFO) << "second = " << second_timestamp << "\n"; 423 } 424 if (last_timestamp) { 425 GTEST_LOG_(INFO) << "last = " << last_timestamp << "\n"; 426 } 427 } 428 free(last_timestamp); 429 last_timestamp = NULL; 430 free(first_timestamp); 431 free(second_timestamp); 432 433 EXPECT_TRUE(first_timestamp == NULL); 434 EXPECT_TRUE(second_timestamp == NULL); 435 EXPECT_LE(count, second_count); 436 EXPECT_LE(count, last_timestamp_count); 437 } 438 439 TEST(logcat, tail_time) { 440 do_tail_time(logcat_executable " -v long -v nsec -b all"); 441 } 442 443 TEST(logcat, tail_time_epoch) { 444 do_tail_time(logcat_executable " -v long -v nsec -v epoch -b all"); 445 } 446 447 TEST(logcat, End_to_End) { 448 pid_t pid = getpid(); 449 450 log_time ts(CLOCK_MONOTONIC); 451 452 ASSERT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts))); 453 454 FILE* fp; 455 logcat_define(ctx); 456 ASSERT_TRUE(NULL != 457 (fp = logcat_popen(ctx, logcat_executable 458 " -v brief -b events -t 100 2>/dev/null"))); 459 460 char buffer[BIG_BUFFER]; 461 462 int count = 0; 463 464 while (fgets(buffer, sizeof(buffer), fp)) { 465 int p; 466 unsigned long long t; 467 468 if ((2 != sscanf(buffer, "I/[0] ( %d): %llu", &p, &t)) || 469 (p != pid)) { 470 continue; 471 } 472 473 log_time tx((const char*)&t); 474 if (ts == tx) { 475 ++count; 476 } 477 } 478 479 logcat_pclose(ctx, fp); 480 481 ASSERT_EQ(1, count); 482 } 483 484 TEST(logcat, End_to_End_multitude) { 485 pid_t pid = getpid(); 486 487 log_time ts(CLOCK_MONOTONIC); 488 489 ASSERT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts))); 490 491 FILE* fp[256]; // does this count as a multitude! 492 memset(fp, 0, sizeof(fp)); 493 logcat_define(ctx[sizeof(fp) / sizeof(fp[0])]); 494 size_t num = 0; 495 do { 496 EXPECT_TRUE(NULL != 497 (fp[num] = logcat_popen(ctx[num], logcat_executable 498 " -v brief -b events -t 100"))); 499 if (!fp[num]) { 500 fprintf(stderr, 501 "WARNING: limiting to %zu simultaneous logcat operations\n", 502 num); 503 break; 504 } 505 } while (++num < sizeof(fp) / sizeof(fp[0])); 506 507 char buffer[BIG_BUFFER]; 508 509 size_t count = 0; 510 511 for (size_t idx = 0; idx < sizeof(fp) / sizeof(fp[0]); ++idx) { 512 if (!fp[idx]) break; 513 while (fgets(buffer, sizeof(buffer), fp[idx])) { 514 int p; 515 unsigned long long t; 516 517 if ((2 != sscanf(buffer, "I/[0] ( %d): %llu", &p, &t)) || 518 (p != pid)) { 519 continue; 520 } 521 522 log_time tx((const char*)&t); 523 if (ts == tx) { 524 ++count; 525 } 526 } 527 528 logcat_pclose(ctx[idx], fp[idx]); 529 } 530 531 ASSERT_EQ(num, count); 532 } 533 534 static int get_groups(const char* cmd) { 535 FILE* fp; 536 logcat_define(ctx); 537 538 // NB: crash log only available in user space 539 EXPECT_TRUE(NULL != (fp = logcat_popen(ctx, cmd))); 540 541 if (fp == NULL) { 542 return 0; 543 } 544 545 char buffer[BIG_BUFFER]; 546 547 int count = 0; 548 549 while (fgets(buffer, sizeof(buffer), fp)) { 550 int size, consumed, max, payload; 551 char size_mult[3], consumed_mult[3]; 552 long full_size, full_consumed; 553 554 size = consumed = max = payload = 0; 555 // NB: crash log can be very small, not hit a Kb of consumed space 556 // doubly lucky we are not including it. 557 if (6 != sscanf(buffer, 558 "%*s ring buffer is %d%2s (%d%2s consumed)," 559 " max entry is %db, max payload is %db", 560 &size, size_mult, &consumed, consumed_mult, &max, 561 &payload)) { 562 fprintf(stderr, "WARNING: Parse error: %s", buffer); 563 continue; 564 } 565 full_size = size; 566 switch (size_mult[0]) { 567 case 'G': 568 full_size *= 1024; 569 /* FALLTHRU */ 570 case 'M': 571 full_size *= 1024; 572 /* FALLTHRU */ 573 case 'K': 574 full_size *= 1024; 575 /* FALLTHRU */ 576 case 'b': 577 break; 578 } 579 full_consumed = consumed; 580 switch (consumed_mult[0]) { 581 case 'G': 582 full_consumed *= 1024; 583 /* FALLTHRU */ 584 case 'M': 585 full_consumed *= 1024; 586 /* FALLTHRU */ 587 case 'K': 588 full_consumed *= 1024; 589 /* FALLTHRU */ 590 case 'b': 591 break; 592 } 593 EXPECT_GT((full_size * 9) / 4, full_consumed); 594 EXPECT_GT(full_size, max); 595 EXPECT_GT(max, payload); 596 597 if ((((full_size * 9) / 4) >= full_consumed) && (full_size > max) && 598 (max > payload)) { 599 ++count; 600 } 601 } 602 603 logcat_pclose(ctx, fp); 604 605 return count; 606 } 607 608 TEST(logcat, get_size) { 609 ASSERT_EQ(4, get_groups(logcat_executable 610 " -v brief -b radio -b events -b system -b " 611 "main -g 2>/dev/null")); 612 } 613 614 // duplicate test for get_size, but use comma-separated list of buffers 615 TEST(logcat, multiple_buffer) { 616 ASSERT_EQ( 617 4, get_groups(logcat_executable 618 " -v brief -b radio,events,system,main -g 2>/dev/null")); 619 } 620 621 TEST(logcat, bad_buffer) { 622 ASSERT_EQ(0, 623 get_groups( 624 logcat_executable 625 " -v brief -b radio,events,bogo,system,main -g 2>/dev/null")); 626 } 627 628 #ifndef logcat 629 static void caught_blocking(int signum) { 630 unsigned long long v = 0xDEADBEEFA55A0000ULL; 631 632 v += getpid() & 0xFFFF; 633 if (signum == 0) ++v; 634 635 LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v))); 636 } 637 638 TEST(logcat, blocking) { 639 FILE* fp; 640 unsigned long long v = 0xDEADBEEFA55F0000ULL; 641 642 pid_t pid = getpid(); 643 644 v += pid & 0xFFFF; 645 646 LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v))); 647 648 v &= 0xFFFFFFFFFFFAFFFFULL; 649 650 ASSERT_TRUE( 651 NULL != 652 (fp = popen("( trap exit HUP QUIT INT PIPE KILL ; sleep 6; echo DONE )&" 653 " logcat -v brief -b events 2>&1", 654 "r"))); 655 656 char buffer[BIG_BUFFER]; 657 658 int count = 0; 659 660 int signals = 0; 661 662 signal(SIGALRM, caught_blocking); 663 alarm(2); 664 while (fgets(buffer, sizeof(buffer), fp)) { 665 if (!strncmp(buffer, "DONE", 4)) { 666 break; 667 } 668 669 ++count; 670 671 int p; 672 unsigned long long l; 673 674 if ((2 != sscanf(buffer, "I/[0] ( %u): %lld", &p, &l)) || (p != pid)) { 675 continue; 676 } 677 678 if (l == v) { 679 ++signals; 680 break; 681 } 682 } 683 alarm(0); 684 signal(SIGALRM, SIG_DFL); 685 686 // Generate SIGPIPE 687 fclose(fp); 688 caught_blocking(0); 689 690 pclose(fp); 691 692 EXPECT_LE(2, count); 693 694 EXPECT_EQ(1, signals); 695 } 696 697 static void caught_blocking_tail(int signum) { 698 unsigned long long v = 0xA55ADEADBEEF0000ULL; 699 700 v += getpid() & 0xFFFF; 701 if (signum == 0) ++v; 702 703 LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v))); 704 } 705 706 TEST(logcat, blocking_tail) { 707 FILE* fp; 708 unsigned long long v = 0xA55FDEADBEEF0000ULL; 709 710 pid_t pid = getpid(); 711 712 v += pid & 0xFFFF; 713 714 LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v))); 715 716 v &= 0xFFFAFFFFFFFFFFFFULL; 717 718 ASSERT_TRUE( 719 NULL != 720 (fp = popen("( trap exit HUP QUIT INT PIPE KILL ; sleep 6; echo DONE )&" 721 " logcat -v brief -b events -T 5 2>&1", 722 "r"))); 723 724 char buffer[BIG_BUFFER]; 725 726 int count = 0; 727 728 int signals = 0; 729 730 signal(SIGALRM, caught_blocking_tail); 731 alarm(2); 732 while (fgets(buffer, sizeof(buffer), fp)) { 733 if (!strncmp(buffer, "DONE", 4)) { 734 break; 735 } 736 737 ++count; 738 739 int p; 740 unsigned long long l; 741 742 if ((2 != sscanf(buffer, "I/[0] ( %u): %lld", &p, &l)) || (p != pid)) { 743 continue; 744 } 745 746 if (l == v) { 747 if (count >= 5) { 748 ++signals; 749 } 750 break; 751 } 752 } 753 alarm(0); 754 signal(SIGALRM, SIG_DFL); 755 756 // Generate SIGPIPE 757 fclose(fp); 758 caught_blocking_tail(0); 759 760 pclose(fp); 761 762 EXPECT_LE(2, count); 763 764 EXPECT_EQ(1, signals); 765 } 766 #endif 767 768 // meant to be handed to ASSERT_FALSE / EXPECT_FALSE to expand the message 769 static testing::AssertionResult IsFalse(int ret, const char* command) { 770 return ret ? (testing::AssertionSuccess() 771 << "ret=" << ret << " command=\"" << command << "\"") 772 : testing::AssertionFailure(); 773 } 774 775 TEST(logcat, logrotate) { 776 static const char form[] = "/data/local/tmp/logcat.logrotate.XXXXXX"; 777 char buf[sizeof(form)]; 778 ASSERT_TRUE(NULL != mkdtemp(strcpy(buf, form))); 779 780 static const char comm[] = logcat_executable 781 " -b radio -b events -b system -b main" 782 " -d -f %s/log.txt -n 7 -r 1"; 783 char command[sizeof(buf) + sizeof(comm)]; 784 snprintf(command, sizeof(command), comm, buf); 785 786 int ret; 787 EXPECT_FALSE(IsFalse(ret = logcat_system(command), command)); 788 if (!ret) { 789 snprintf(command, sizeof(command), "ls -s %s 2>/dev/null", buf); 790 791 FILE* fp; 792 EXPECT_TRUE(NULL != (fp = popen(command, "r"))); 793 if (fp) { 794 char buffer[BIG_BUFFER]; 795 int count = 0; 796 797 while (fgets(buffer, sizeof(buffer), fp)) { 798 static const char total[] = "total "; 799 int num; 800 char c; 801 802 if ((2 == sscanf(buffer, "%d log.tx%c", &num, &c)) && 803 (num <= 40)) { 804 ++count; 805 } else if (strncmp(buffer, total, sizeof(total) - 1)) { 806 fprintf(stderr, "WARNING: Parse error: %s", buffer); 807 } 808 } 809 pclose(fp); 810 if ((count != 7) && (count != 8)) { 811 fprintf(stderr, "count=%d\n", count); 812 } 813 EXPECT_TRUE(count == 7 || count == 8); 814 } 815 } 816 snprintf(command, sizeof(command), "rm -rf %s", buf); 817 EXPECT_FALSE(IsFalse(system(command), command)); 818 } 819 820 TEST(logcat, logrotate_suffix) { 821 static const char tmp_out_dir_form[] = 822 "/data/local/tmp/logcat.logrotate.XXXXXX"; 823 char tmp_out_dir[sizeof(tmp_out_dir_form)]; 824 ASSERT_TRUE(NULL != mkdtemp(strcpy(tmp_out_dir, tmp_out_dir_form))); 825 826 static const char logcat_cmd[] = logcat_executable 827 " -b radio -b events -b system -b main" 828 " -d -f %s/log.txt -n 10 -r 1"; 829 char command[sizeof(tmp_out_dir) + sizeof(logcat_cmd)]; 830 snprintf(command, sizeof(command), logcat_cmd, tmp_out_dir); 831 832 int ret; 833 EXPECT_FALSE(IsFalse(ret = logcat_system(command), command)); 834 if (!ret) { 835 snprintf(command, sizeof(command), "ls %s 2>/dev/null", tmp_out_dir); 836 837 FILE* fp; 838 EXPECT_TRUE(NULL != (fp = popen(command, "r"))); 839 char buffer[BIG_BUFFER]; 840 int log_file_count = 0; 841 842 while (fgets(buffer, sizeof(buffer), fp)) { 843 static const char rotated_log_filename_prefix[] = "log.txt."; 844 static const size_t rotated_log_filename_prefix_len = 845 strlen(rotated_log_filename_prefix); 846 static const char log_filename[] = "log.txt"; 847 848 if (!strncmp(buffer, rotated_log_filename_prefix, 849 rotated_log_filename_prefix_len)) { 850 // Rotated file should have form log.txt.## 851 char* rotated_log_filename_suffix = 852 buffer + rotated_log_filename_prefix_len; 853 char* endptr; 854 const long int suffix_value = 855 strtol(rotated_log_filename_suffix, &endptr, 10); 856 EXPECT_EQ(rotated_log_filename_suffix + 2, endptr); 857 EXPECT_LE(suffix_value, 10); 858 EXPECT_GT(suffix_value, 0); 859 ++log_file_count; 860 continue; 861 } 862 863 if (!strncmp(buffer, log_filename, strlen(log_filename))) { 864 ++log_file_count; 865 continue; 866 } 867 868 fprintf(stderr, "ERROR: Unexpected file: %s", buffer); 869 ADD_FAILURE(); 870 } 871 pclose(fp); 872 EXPECT_EQ(11, log_file_count); 873 } 874 snprintf(command, sizeof(command), "rm -rf %s", tmp_out_dir); 875 EXPECT_FALSE(IsFalse(system(command), command)); 876 } 877 878 TEST(logcat, logrotate_continue) { 879 static const char tmp_out_dir_form[] = 880 "/data/local/tmp/logcat.logrotate.XXXXXX"; 881 char tmp_out_dir[sizeof(tmp_out_dir_form)]; 882 ASSERT_TRUE(NULL != mkdtemp(strcpy(tmp_out_dir, tmp_out_dir_form))); 883 884 static const char log_filename[] = "log.txt"; 885 static const char logcat_cmd[] = 886 logcat_executable " -b all -v nsec -d -f %s/%s -n 256 -r 1024"; 887 static const char cleanup_cmd[] = "rm -rf %s"; 888 char command[sizeof(tmp_out_dir) + sizeof(logcat_cmd) + sizeof(log_filename)]; 889 snprintf(command, sizeof(command), logcat_cmd, tmp_out_dir, log_filename); 890 891 int ret; 892 EXPECT_FALSE(IsFalse(ret = logcat_system(command), command)); 893 if (ret) { 894 snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir); 895 EXPECT_FALSE(IsFalse(system(command), command)); 896 return; 897 } 898 FILE* fp; 899 snprintf(command, sizeof(command), "%s/%s", tmp_out_dir, log_filename); 900 EXPECT_TRUE(NULL != ((fp = fopen(command, "r")))); 901 if (!fp) { 902 snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir); 903 EXPECT_FALSE(IsFalse(system(command), command)); 904 return; 905 } 906 char* line = NULL; 907 char* last_line = 908 NULL; // this line is allowed to stutter, one-line overlap 909 char* second_last_line = NULL; // should never stutter 910 char* first_line = NULL; // help diagnose failure? 911 size_t len = 0; 912 while (getline(&line, &len, fp) != -1) { 913 if (!first_line) { 914 first_line = line; 915 line = NULL; 916 continue; 917 } 918 free(second_last_line); 919 second_last_line = last_line; 920 last_line = line; 921 line = NULL; 922 } 923 fclose(fp); 924 free(line); 925 if (second_last_line == NULL) { 926 fprintf(stderr, "No second to last line, using last, test may fail\n"); 927 second_last_line = last_line; 928 last_line = NULL; 929 } 930 free(last_line); 931 EXPECT_TRUE(NULL != second_last_line); 932 if (!second_last_line) { 933 snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir); 934 EXPECT_FALSE(IsFalse(system(command), command)); 935 free(first_line); 936 return; 937 } 938 // re-run the command, it should only add a few lines more content if it 939 // continues where it left off. 940 snprintf(command, sizeof(command), logcat_cmd, tmp_out_dir, log_filename); 941 EXPECT_FALSE(IsFalse(ret = logcat_system(command), command)); 942 if (ret) { 943 snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir); 944 EXPECT_FALSE(IsFalse(system(command), command)); 945 free(second_last_line); 946 free(first_line); 947 return; 948 } 949 std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(tmp_out_dir), 950 closedir); 951 EXPECT_NE(nullptr, dir); 952 if (!dir) { 953 snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir); 954 EXPECT_FALSE(IsFalse(system(command), command)); 955 free(second_last_line); 956 free(first_line); 957 return; 958 } 959 struct dirent* entry; 960 unsigned count = 0; 961 while ((entry = readdir(dir.get()))) { 962 if (strncmp(entry->d_name, log_filename, sizeof(log_filename) - 1)) { 963 continue; 964 } 965 snprintf(command, sizeof(command), "%s/%s", tmp_out_dir, entry->d_name); 966 EXPECT_TRUE(NULL != ((fp = fopen(command, "r")))); 967 if (!fp) { 968 fprintf(stderr, "%s ?\n", command); 969 continue; 970 } 971 line = NULL; 972 size_t number = 0; 973 while (getline(&line, &len, fp) != -1) { 974 ++number; 975 if (!strcmp(line, second_last_line)) { 976 EXPECT_TRUE(++count <= 1); 977 fprintf(stderr, "%s(%zu):\n", entry->d_name, number); 978 } 979 } 980 fclose(fp); 981 free(line); 982 unlink(command); 983 } 984 if (count > 1) { 985 char* brk = strpbrk(second_last_line, "\r\n"); 986 if (!brk) brk = second_last_line + strlen(second_last_line); 987 fprintf(stderr, "\"%.*s\" occurred %u times\n", 988 (int)(brk - second_last_line), second_last_line, count); 989 if (first_line) { 990 brk = strpbrk(first_line, "\r\n"); 991 if (!brk) brk = first_line + strlen(first_line); 992 fprintf(stderr, "\"%.*s\" was first line, fault?\n", 993 (int)(brk - first_line), first_line); 994 } 995 } 996 free(second_last_line); 997 free(first_line); 998 999 snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir); 1000 EXPECT_FALSE(IsFalse(system(command), command)); 1001 } 1002 1003 TEST(logcat, logrotate_clear) { 1004 static const char tmp_out_dir_form[] = 1005 "/data/local/tmp/logcat.logrotate.XXXXXX"; 1006 char tmp_out_dir[sizeof(tmp_out_dir_form)]; 1007 ASSERT_TRUE(NULL != mkdtemp(strcpy(tmp_out_dir, tmp_out_dir_form))); 1008 1009 static const char log_filename[] = "log.txt"; 1010 static const unsigned num_val = 32; 1011 static const char logcat_cmd[] = 1012 logcat_executable " -b all -d -f %s/%s -n %d -r 1"; 1013 static const char clear_cmd[] = " -c"; 1014 static const char cleanup_cmd[] = "rm -rf %s"; 1015 char command[sizeof(tmp_out_dir) + sizeof(logcat_cmd) + 1016 sizeof(log_filename) + sizeof(clear_cmd) + 32]; 1017 1018 // Run command with all data 1019 { 1020 snprintf(command, sizeof(command) - sizeof(clear_cmd), logcat_cmd, 1021 tmp_out_dir, log_filename, num_val); 1022 1023 int ret; 1024 EXPECT_FALSE(IsFalse(ret = logcat_system(command), command)); 1025 if (ret) { 1026 snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir); 1027 EXPECT_FALSE(IsFalse(system(command), command)); 1028 return; 1029 } 1030 std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(tmp_out_dir), 1031 closedir); 1032 EXPECT_NE(nullptr, dir); 1033 if (!dir) { 1034 snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir); 1035 EXPECT_FALSE(IsFalse(system(command), command)); 1036 return; 1037 } 1038 struct dirent* entry; 1039 unsigned count = 0; 1040 while ((entry = readdir(dir.get()))) { 1041 if (strncmp(entry->d_name, log_filename, sizeof(log_filename) - 1)) { 1042 continue; 1043 } 1044 ++count; 1045 } 1046 EXPECT_EQ(count, num_val + 1); 1047 } 1048 1049 { 1050 // Now with -c option tacked onto the end 1051 strcat(command, clear_cmd); 1052 1053 int ret; 1054 EXPECT_FALSE(IsFalse(ret = logcat_system(command), command)); 1055 if (ret) { 1056 snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir); 1057 EXPECT_FALSE(system(command)); 1058 EXPECT_FALSE(IsFalse(system(command), command)); 1059 return; 1060 } 1061 std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(tmp_out_dir), 1062 closedir); 1063 EXPECT_NE(nullptr, dir); 1064 if (!dir) { 1065 snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir); 1066 EXPECT_FALSE(IsFalse(system(command), command)); 1067 return; 1068 } 1069 struct dirent* entry; 1070 unsigned count = 0; 1071 while ((entry = readdir(dir.get()))) { 1072 if (strncmp(entry->d_name, log_filename, sizeof(log_filename) - 1)) { 1073 continue; 1074 } 1075 fprintf(stderr, "Found %s/%s!!!\n", tmp_out_dir, entry->d_name); 1076 ++count; 1077 } 1078 EXPECT_EQ(count, 0U); 1079 } 1080 1081 snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir); 1082 EXPECT_FALSE(IsFalse(system(command), command)); 1083 } 1084 1085 static int logrotate_count_id(const char* logcat_cmd, const char* tmp_out_dir) { 1086 static const char log_filename[] = "log.txt"; 1087 char command[strlen(tmp_out_dir) + strlen(logcat_cmd) + 1088 strlen(log_filename) + 32]; 1089 1090 snprintf(command, sizeof(command), logcat_cmd, tmp_out_dir, log_filename); 1091 1092 int ret = logcat_system(command); 1093 if (ret) { 1094 fprintf(stderr, "system(\"%s\")=%d", command, ret); 1095 return -1; 1096 } 1097 std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(tmp_out_dir), 1098 closedir); 1099 if (!dir) { 1100 fprintf(stderr, "opendir(\"%s\") failed", tmp_out_dir); 1101 return -1; 1102 } 1103 struct dirent* entry; 1104 int count = 0; 1105 while ((entry = readdir(dir.get()))) { 1106 if (strncmp(entry->d_name, log_filename, sizeof(log_filename) - 1)) { 1107 continue; 1108 } 1109 ++count; 1110 } 1111 return count; 1112 } 1113 1114 TEST(logcat, logrotate_id) { 1115 static const char logcat_cmd[] = 1116 logcat_executable " -b all -d -f %s/%s -n 32 -r 1 --id=test"; 1117 static const char logcat_short_cmd[] = 1118 logcat_executable " -b all -t 10 -f %s/%s -n 32 -r 1 --id=test"; 1119 static const char tmp_out_dir_form[] = 1120 "/data/local/tmp/logcat.logrotate.XXXXXX"; 1121 static const char log_filename[] = "log.txt"; 1122 char tmp_out_dir[strlen(tmp_out_dir_form) + 1]; 1123 ASSERT_TRUE(NULL != mkdtemp(strcpy(tmp_out_dir, tmp_out_dir_form))); 1124 1125 EXPECT_EQ(34, logrotate_count_id(logcat_cmd, tmp_out_dir)); 1126 EXPECT_EQ(34, logrotate_count_id(logcat_short_cmd, tmp_out_dir)); 1127 1128 char id_file[strlen(tmp_out_dir_form) + strlen(log_filename) + 5]; 1129 snprintf(id_file, sizeof(id_file), "%s/%s.id", tmp_out_dir, log_filename); 1130 if (getuid() != 0) { 1131 chmod(id_file, 0); 1132 EXPECT_EQ(34, logrotate_count_id(logcat_short_cmd, tmp_out_dir)); 1133 } 1134 unlink(id_file); 1135 EXPECT_EQ(34, logrotate_count_id(logcat_short_cmd, tmp_out_dir)); 1136 1137 FILE* fp = fopen(id_file, "w"); 1138 if (fp) { 1139 fprintf(fp, "not_a_test"); 1140 fclose(fp); 1141 } 1142 if (getuid() != 0) { 1143 chmod(id_file, 1144 0); // API to preserve content even with signature change 1145 ASSERT_EQ(34, logrotate_count_id(logcat_short_cmd, tmp_out_dir)); 1146 chmod(id_file, 0600); 1147 } 1148 1149 int new_signature; 1150 EXPECT_LE( 1151 2, (new_signature = logrotate_count_id(logcat_short_cmd, tmp_out_dir))); 1152 EXPECT_GT(34, new_signature); 1153 1154 static const char cleanup_cmd[] = "rm -rf %s"; 1155 char command[strlen(cleanup_cmd) + strlen(tmp_out_dir_form)]; 1156 snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir); 1157 EXPECT_FALSE(IsFalse(system(command), command)); 1158 } 1159 1160 TEST(logcat, logrotate_nodir) { 1161 // expect logcat to error out on writing content and not exit(0) for nodir 1162 static const char command[] = logcat_executable 1163 " -b all -d" 1164 " -f /das/nein/gerfingerpoken/logcat/log.txt" 1165 " -n 256 -r 1024"; 1166 EXPECT_FALSE(IsFalse(0 == logcat_system(command), command)); 1167 } 1168 1169 #ifndef logcat 1170 static void caught_blocking_clear(int signum) { 1171 unsigned long long v = 0xDEADBEEFA55C0000ULL; 1172 1173 v += getpid() & 0xFFFF; 1174 if (signum == 0) ++v; 1175 1176 LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v))); 1177 } 1178 1179 TEST(logcat, blocking_clear) { 1180 FILE* fp; 1181 unsigned long long v = 0xDEADBEEFA55C0000ULL; 1182 1183 pid_t pid = getpid(); 1184 1185 v += pid & 0xFFFF; 1186 1187 // This test is racey; an event occurs between clear and dump. 1188 // We accept that we will get a false positive, but never a false negative. 1189 ASSERT_TRUE( 1190 NULL != 1191 (fp = popen("( trap exit HUP QUIT INT PIPE KILL ; sleep 6; echo DONE )&" 1192 " logcat -b events -c 2>&1 ;" 1193 " logcat -b events -g 2>&1 ;" 1194 " logcat -v brief -b events 2>&1", 1195 "r"))); 1196 1197 char buffer[BIG_BUFFER]; 1198 1199 int count = 0; 1200 int minus_g = 0; 1201 1202 int signals = 0; 1203 1204 signal(SIGALRM, caught_blocking_clear); 1205 alarm(2); 1206 while (fgets(buffer, sizeof(buffer), fp)) { 1207 if (!strncmp(buffer, "clearLog: ", 10)) { 1208 fprintf(stderr, "WARNING: Test lacks permission to run :-(\n"); 1209 count = signals = 1; 1210 break; 1211 } 1212 1213 if (!strncmp(buffer, "DONE", 4)) { 1214 break; 1215 } 1216 1217 int size, consumed, max, payload; 1218 char size_mult[3], consumed_mult[3]; 1219 size = consumed = max = payload = 0; 1220 if (6 == sscanf(buffer, 1221 "events: ring buffer is %d%2s (%d%2s consumed)," 1222 " max entry is %db, max payload is %db", 1223 &size, size_mult, &consumed, consumed_mult, &max, 1224 &payload)) { 1225 long full_size = size, full_consumed = consumed; 1226 1227 switch (size_mult[0]) { 1228 case 'G': 1229 full_size *= 1024; 1230 /* FALLTHRU */ 1231 case 'M': 1232 full_size *= 1024; 1233 /* FALLTHRU */ 1234 case 'K': 1235 full_size *= 1024; 1236 /* FALLTHRU */ 1237 case 'b': 1238 break; 1239 } 1240 switch (consumed_mult[0]) { 1241 case 'G': 1242 full_consumed *= 1024; 1243 /* FALLTHRU */ 1244 case 'M': 1245 full_consumed *= 1024; 1246 /* FALLTHRU */ 1247 case 'K': 1248 full_consumed *= 1024; 1249 /* FALLTHRU */ 1250 case 'b': 1251 break; 1252 } 1253 EXPECT_GT(full_size, full_consumed); 1254 EXPECT_GT(full_size, max); 1255 EXPECT_GT(max, payload); 1256 EXPECT_GT(max, full_consumed); 1257 1258 ++minus_g; 1259 continue; 1260 } 1261 1262 ++count; 1263 1264 int p; 1265 unsigned long long l; 1266 1267 if ((2 != sscanf(buffer, "I/[0] ( %u): %lld", &p, &l)) || (p != pid)) { 1268 continue; 1269 } 1270 1271 if (l == v) { 1272 if (count > 1) { 1273 fprintf(stderr, "WARNING: Possible false positive\n"); 1274 } 1275 ++signals; 1276 break; 1277 } 1278 } 1279 alarm(0); 1280 signal(SIGALRM, SIG_DFL); 1281 1282 // Generate SIGPIPE 1283 fclose(fp); 1284 caught_blocking_clear(0); 1285 1286 pclose(fp); 1287 1288 EXPECT_LE(1, count); 1289 EXPECT_EQ(1, minus_g); 1290 1291 EXPECT_EQ(1, signals); 1292 } 1293 #endif 1294 1295 static bool get_white_black(char** list) { 1296 FILE* fp; 1297 logcat_define(ctx); 1298 1299 fp = logcat_popen(ctx, logcat_executable " -p 2>/dev/null"); 1300 if (fp == NULL) { 1301 fprintf(stderr, "ERROR: logcat -p 2>/dev/null\n"); 1302 return false; 1303 } 1304 1305 char buffer[BIG_BUFFER]; 1306 1307 while (fgets(buffer, sizeof(buffer), fp)) { 1308 char* hold = *list; 1309 char* buf = buffer; 1310 while (isspace(*buf)) { 1311 ++buf; 1312 } 1313 char* end = buf + strlen(buf); 1314 while (isspace(*--end) && (end >= buf)) { 1315 *end = '\0'; 1316 } 1317 if (end < buf) { 1318 continue; 1319 } 1320 if (hold) { 1321 asprintf(list, "%s %s", hold, buf); 1322 free(hold); 1323 } else { 1324 asprintf(list, "%s", buf); 1325 } 1326 } 1327 logcat_pclose(ctx, fp); 1328 return *list != NULL; 1329 } 1330 1331 static bool set_white_black(const char* list) { 1332 FILE* fp; 1333 logcat_define(ctx); 1334 1335 char buffer[BIG_BUFFER]; 1336 1337 snprintf(buffer, sizeof(buffer), logcat_executable " -P '%s' 2>&1", 1338 list ? list : ""); 1339 fp = logcat_popen(ctx, buffer); 1340 if (fp == NULL) { 1341 fprintf(stderr, "ERROR: %s\n", buffer); 1342 return false; 1343 } 1344 1345 while (fgets(buffer, sizeof(buffer), fp)) { 1346 char* buf = buffer; 1347 while (isspace(*buf)) { 1348 ++buf; 1349 } 1350 char* end = buf + strlen(buf); 1351 while ((end > buf) && isspace(*--end)) { 1352 *end = '\0'; 1353 } 1354 if (end <= buf) { 1355 continue; 1356 } 1357 fprintf(stderr, "%s\n", buf); 1358 logcat_pclose(ctx, fp); 1359 return false; 1360 } 1361 return logcat_pclose(ctx, fp) == 0; 1362 } 1363 1364 TEST(logcat, white_black_adjust) { 1365 char* list = NULL; 1366 char* adjust = NULL; 1367 1368 get_white_black(&list); 1369 1370 static const char adjustment[] = "~! 300/20 300/25 2000 ~1000/5 ~1000/30"; 1371 ASSERT_EQ(true, set_white_black(adjustment)); 1372 ASSERT_EQ(true, get_white_black(&adjust)); 1373 EXPECT_STREQ(adjustment, adjust); 1374 free(adjust); 1375 adjust = NULL; 1376 1377 static const char adjustment2[] = "300/20 300/21 2000 ~1000"; 1378 ASSERT_EQ(true, set_white_black(adjustment2)); 1379 ASSERT_EQ(true, get_white_black(&adjust)); 1380 EXPECT_STREQ(adjustment2, adjust); 1381 free(adjust); 1382 adjust = NULL; 1383 1384 ASSERT_EQ(true, set_white_black(list)); 1385 get_white_black(&adjust); 1386 EXPECT_STREQ(list ? list : "", adjust ? adjust : ""); 1387 free(adjust); 1388 adjust = NULL; 1389 1390 free(list); 1391 list = NULL; 1392 } 1393 1394 TEST(logcat, regex) { 1395 FILE* fp; 1396 logcat_define(ctx); 1397 int count = 0; 1398 1399 char buffer[BIG_BUFFER]; 1400 #define logcat_regex_prefix ___STRING(logcat) "_test" 1401 1402 snprintf(buffer, sizeof(buffer), 1403 logcat_executable " --pid %d -d -e " logcat_regex_prefix "_a+b", 1404 getpid()); 1405 1406 LOG_FAILURE_RETRY(__android_log_print(ANDROID_LOG_WARN, logcat_regex_prefix, 1407 logcat_regex_prefix "_ab")); 1408 LOG_FAILURE_RETRY(__android_log_print(ANDROID_LOG_WARN, logcat_regex_prefix, 1409 logcat_regex_prefix "_b")); 1410 LOG_FAILURE_RETRY(__android_log_print(ANDROID_LOG_WARN, logcat_regex_prefix, 1411 logcat_regex_prefix "_aaaab")); 1412 LOG_FAILURE_RETRY(__android_log_print(ANDROID_LOG_WARN, logcat_regex_prefix, 1413 logcat_regex_prefix "_aaaa")); 1414 // Let the logs settle 1415 sleep(1); 1416 1417 ASSERT_TRUE(NULL != (fp = logcat_popen(ctx, buffer))); 1418 1419 while (fgets(buffer, sizeof(buffer), fp)) { 1420 if (!strncmp(begin, buffer, sizeof(begin) - 1)) { 1421 continue; 1422 } 1423 1424 EXPECT_TRUE(strstr(buffer, logcat_regex_prefix "_") != NULL); 1425 1426 count++; 1427 } 1428 1429 logcat_pclose(ctx, fp); 1430 1431 ASSERT_EQ(2, count); 1432 } 1433 1434 TEST(logcat, maxcount) { 1435 FILE* fp; 1436 logcat_define(ctx); 1437 int count = 0; 1438 1439 char buffer[BIG_BUFFER]; 1440 1441 snprintf(buffer, sizeof(buffer), 1442 logcat_executable " --pid %d -d --max-count 3", getpid()); 1443 1444 LOG_FAILURE_RETRY( 1445 __android_log_print(ANDROID_LOG_WARN, "logcat_test", "logcat_test")); 1446 LOG_FAILURE_RETRY( 1447 __android_log_print(ANDROID_LOG_WARN, "logcat_test", "logcat_test")); 1448 LOG_FAILURE_RETRY( 1449 __android_log_print(ANDROID_LOG_WARN, "logcat_test", "logcat_test")); 1450 LOG_FAILURE_RETRY( 1451 __android_log_print(ANDROID_LOG_WARN, "logcat_test", "logcat_test")); 1452 1453 // Let the logs settle 1454 sleep(1); 1455 1456 ASSERT_TRUE(NULL != (fp = logcat_popen(ctx, buffer))); 1457 1458 while (fgets(buffer, sizeof(buffer), fp)) { 1459 if (!strncmp(begin, buffer, sizeof(begin) - 1)) { 1460 continue; 1461 } 1462 1463 count++; 1464 } 1465 1466 logcat_pclose(ctx, fp); 1467 1468 ASSERT_EQ(3, count); 1469 } 1470 1471 static bool End_to_End(const char* tag, const char* fmt, ...) 1472 #if defined(__GNUC__) 1473 __attribute__((__format__(printf, 2, 3))) 1474 #endif 1475 ; 1476 1477 static bool End_to_End(const char* tag, const char* fmt, ...) { 1478 logcat_define(ctx); 1479 FILE* fp = logcat_popen(ctx, 1480 "logcat" 1481 " -v brief" 1482 " -b events" 1483 " -v descriptive" 1484 " -t 100" 1485 " 2>/dev/null"); 1486 if (!fp) { 1487 fprintf(stderr, "End_to_End: popen failed"); 1488 return false; 1489 } 1490 1491 char buffer[BIG_BUFFER]; 1492 va_list ap; 1493 1494 va_start(ap, fmt); 1495 vsnprintf(buffer, sizeof(buffer), fmt, ap); 1496 va_end(ap); 1497 1498 char* str = NULL; 1499 asprintf(&str, "I/%s ( %%d):%%c%s%%c", tag, buffer); 1500 std::string expect(str); 1501 free(str); 1502 1503 int count = 0; 1504 pid_t pid = getpid(); 1505 std::string lastMatch; 1506 int maxMatch = 1; 1507 while (fgets(buffer, sizeof(buffer), fp)) { 1508 char space; 1509 char newline; 1510 int p; 1511 int ret = sscanf(buffer, expect.c_str(), &p, &space, &newline); 1512 if ((ret == 3) && (p == pid) && (space == ' ') && (newline == '\n')) { 1513 ++count; 1514 } else if ((ret >= maxMatch) && (p == pid) && (count == 0)) { 1515 lastMatch = buffer; 1516 maxMatch = ret; 1517 } 1518 } 1519 1520 logcat_pclose(ctx, fp); 1521 1522 if ((count == 0) && (lastMatch.length() > 0)) { 1523 // Help us pinpoint where things went wrong ... 1524 fprintf(stderr, "Closest match for\n %s\n is\n %s", 1525 expect.c_str(), lastMatch.c_str()); 1526 } else if (count > 2) { 1527 fprintf(stderr, "Too many matches (%d) for %s\n", count, expect.c_str()); 1528 } 1529 1530 // Expect one the first time around as either liblogcat.descriptive or 1531 // logcat.descriptive. Expect two the second time as the other. 1532 return count == 1 || count == 2; 1533 } 1534 1535 TEST(logcat, descriptive) { 1536 struct tag { 1537 uint32_t tagNo; 1538 const char* tagStr; 1539 }; 1540 1541 { 1542 static const struct tag hhgtg = { 42, "answer" }; 1543 android_log_event_list ctx(hhgtg.tagNo); 1544 static const char theAnswer[] = "what is five by seven"; 1545 ctx << theAnswer; 1546 ctx.write(); 1547 EXPECT_TRUE( 1548 End_to_End(hhgtg.tagStr, "to life the universe etc=%s", theAnswer)); 1549 } 1550 1551 { 1552 static const struct tag sync = { 2720, "sync" }; 1553 static const char id[] = "logcat.decriptive"; 1554 { 1555 android_log_event_list ctx(sync.tagNo); 1556 ctx << id << (int32_t)42 << (int32_t)-1 << (int32_t)0; 1557 ctx.write(); 1558 EXPECT_TRUE(End_to_End(sync.tagStr, 1559 "[id=%s,event=42,source=-1,account=0]", id)); 1560 } 1561 1562 // Partial match to description 1563 { 1564 android_log_event_list ctx(sync.tagNo); 1565 ctx << id << (int32_t)43 << (int64_t)-1 << (int32_t)0; 1566 ctx.write(); 1567 EXPECT_TRUE(End_to_End(sync.tagStr, "[id=%s,event=43,-1,0]", id)); 1568 } 1569 1570 // Negative Test of End_to_End, ensure it is working 1571 { 1572 android_log_event_list ctx(sync.tagNo); 1573 ctx << id << (int32_t)44 << (int32_t)-1 << (int64_t)0; 1574 ctx.write(); 1575 fprintf(stderr, "Expect a \"Closest match\" message\n"); 1576 EXPECT_FALSE(End_to_End( 1577 sync.tagStr, "[id=%s,event=44,source=-1,account=0]", id)); 1578 } 1579 } 1580 1581 { 1582 static const struct tag sync = { 2747, "contacts_aggregation" }; 1583 { 1584 android_log_event_list ctx(sync.tagNo); 1585 ctx << (uint64_t)30 << (int32_t)2; 1586 ctx.write(); 1587 EXPECT_TRUE( 1588 End_to_End(sync.tagStr, "[aggregation time=30ms,count=2]")); 1589 } 1590 1591 { 1592 android_log_event_list ctx(sync.tagNo); 1593 ctx << (uint64_t)31570 << (int32_t)911; 1594 ctx.write(); 1595 EXPECT_TRUE( 1596 End_to_End(sync.tagStr, "[aggregation time=31.57s,count=911]")); 1597 } 1598 } 1599 1600 { 1601 static const struct tag sync = { 75000, "sqlite_mem_alarm_current" }; 1602 { 1603 android_log_event_list ctx(sync.tagNo); 1604 ctx << (uint32_t)512; 1605 ctx.write(); 1606 EXPECT_TRUE(End_to_End(sync.tagStr, "current=512B")); 1607 } 1608 1609 { 1610 android_log_event_list ctx(sync.tagNo); 1611 ctx << (uint32_t)3072; 1612 ctx.write(); 1613 EXPECT_TRUE(End_to_End(sync.tagStr, "current=3KB")); 1614 } 1615 1616 { 1617 android_log_event_list ctx(sync.tagNo); 1618 ctx << (uint32_t)2097152; 1619 ctx.write(); 1620 EXPECT_TRUE(End_to_End(sync.tagStr, "current=2MB")); 1621 } 1622 1623 { 1624 android_log_event_list ctx(sync.tagNo); 1625 ctx << (uint32_t)2097153; 1626 ctx.write(); 1627 EXPECT_TRUE(End_to_End(sync.tagStr, "current=2097153B")); 1628 } 1629 1630 { 1631 android_log_event_list ctx(sync.tagNo); 1632 ctx << (uint32_t)1073741824; 1633 ctx.write(); 1634 EXPECT_TRUE(End_to_End(sync.tagStr, "current=1GB")); 1635 } 1636 1637 { 1638 android_log_event_list ctx(sync.tagNo); 1639 ctx << (uint32_t)3221225472; // 3MB, but on purpose overflowed 1640 ctx.write(); 1641 EXPECT_TRUE(End_to_End(sync.tagStr, "current=-1GB")); 1642 } 1643 } 1644 1645 { 1646 static const struct tag sync = { 27501, "notification_panel_hidden" }; 1647 android_log_event_list ctx(sync.tagNo); 1648 ctx.write(); 1649 EXPECT_TRUE(End_to_End(sync.tagStr, "")); 1650 } 1651 } 1652 1653 static bool reportedSecurity(const char* command) { 1654 logcat_define(ctx); 1655 FILE* fp = logcat_popen(ctx, command); 1656 if (!fp) return true; 1657 1658 std::string ret; 1659 bool val = android::base::ReadFdToString(fileno(fp), &ret); 1660 logcat_pclose(ctx, fp); 1661 1662 if (!val) return true; 1663 return std::string::npos != ret.find("'security'"); 1664 } 1665 1666 TEST(logcat, security) { 1667 EXPECT_FALSE(reportedSecurity(logcat_executable " -b all -g 2>&1")); 1668 EXPECT_TRUE(reportedSecurity(logcat_executable " -b security -g 2>&1")); 1669 EXPECT_TRUE(reportedSecurity(logcat_executable " -b security -c 2>&1")); 1670 EXPECT_TRUE( 1671 reportedSecurity(logcat_executable " -b security -G 256K 2>&1")); 1672 } 1673 1674 static size_t commandOutputSize(const char* command) { 1675 logcat_define(ctx); 1676 FILE* fp = logcat_popen(ctx, command); 1677 if (!fp) return 0; 1678 1679 std::string ret; 1680 if (!android::base::ReadFdToString(fileno(fp), &ret)) return 0; 1681 if (logcat_pclose(ctx, fp) != 0) return 0; 1682 1683 return ret.size(); 1684 } 1685 1686 TEST(logcat, help) { 1687 size_t logcatHelpTextSize = commandOutputSize(logcat_executable " -h 2>&1"); 1688 EXPECT_LT(4096UL, logcatHelpTextSize); 1689 size_t logcatLastHelpTextSize = 1690 commandOutputSize(logcat_executable " -L -h 2>&1"); 1691 #ifdef USING_LOGCAT_EXECUTABLE_DEFAULT // logcat and liblogcat 1692 EXPECT_EQ(logcatHelpTextSize, logcatLastHelpTextSize); 1693 #else 1694 // logcatd -L -h prints the help twice, as designed. 1695 EXPECT_EQ(logcatHelpTextSize * 2, logcatLastHelpTextSize); 1696 #endif 1697 } 1698