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