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 <signal.h>
     19 #include <stdio.h>
     20 #include <stdlib.h>
     21 #include <string.h>
     22 
     23 #include <gtest/gtest.h>
     24 #include <log/log.h>
     25 #include <log/logger.h>
     26 #include <log/log_read.h>
     27 
     28 // enhanced version of LOG_FAILURE_RETRY to add support for EAGAIN and
     29 // non-syscall libs. Since we are only using this in the emergency of
     30 // a signal to stuff a terminating code into the logs, we will spin rather
     31 // than try a usleep.
     32 #define LOG_FAILURE_RETRY(exp) ({  \
     33     typeof (exp) _rc;              \
     34     do {                           \
     35         _rc = (exp);               \
     36     } while (((_rc == -1)          \
     37            && ((errno == EINTR)    \
     38             || (errno == EAGAIN))) \
     39           || (_rc == -EINTR)       \
     40           || (_rc == -EAGAIN));    \
     41     _rc; })
     42 
     43 static const char begin[] = "--------- beginning of ";
     44 
     45 TEST(logcat, buckets) {
     46     FILE *fp;
     47 
     48     ASSERT_TRUE(NULL != (fp = popen(
     49       "logcat -b radio -b events -b system -b main -d 2>/dev/null",
     50       "r")));
     51 
     52     char buffer[5120];
     53 
     54     int ids = 0;
     55     int count = 0;
     56 
     57     while (fgets(buffer, sizeof(buffer), fp)) {
     58         if (!strncmp(begin, buffer, sizeof(begin) - 1)) {
     59             while (char *cp = strrchr(buffer, '\n')) {
     60                 *cp = '\0';
     61             }
     62             log_id_t id = android_name_to_log_id(buffer + sizeof(begin) - 1);
     63             ids |= 1 << id;
     64             ++count;
     65         }
     66     }
     67 
     68     pclose(fp);
     69 
     70     EXPECT_EQ(15, ids);
     71 
     72     EXPECT_EQ(4, count);
     73 }
     74 
     75 TEST(logcat, tail_3) {
     76     FILE *fp;
     77 
     78     ASSERT_TRUE(NULL != (fp = popen(
     79       "logcat -v long -b radio -b events -b system -b main -t 3 2>/dev/null",
     80       "r")));
     81 
     82     char buffer[5120];
     83 
     84     int count = 0;
     85 
     86     while (fgets(buffer, sizeof(buffer), fp)) {
     87         if ((buffer[0] == '[') && (buffer[1] == ' ')
     88          && isdigit(buffer[2]) && isdigit(buffer[3])
     89          && (buffer[4] == '-')) {
     90             ++count;
     91         }
     92     }
     93 
     94     pclose(fp);
     95 
     96     ASSERT_EQ(3, count);
     97 }
     98 
     99 TEST(logcat, tail_10) {
    100     FILE *fp;
    101 
    102     ASSERT_TRUE(NULL != (fp = popen(
    103       "logcat -v long -b radio -b events -b system -b main -t 10 2>/dev/null",
    104       "r")));
    105 
    106     char buffer[5120];
    107 
    108     int count = 0;
    109 
    110     while (fgets(buffer, sizeof(buffer), fp)) {
    111         if ((buffer[0] == '[') && (buffer[1] == ' ')
    112          && isdigit(buffer[2]) && isdigit(buffer[3])
    113          && (buffer[4] == '-')) {
    114             ++count;
    115         }
    116     }
    117 
    118     pclose(fp);
    119 
    120     ASSERT_EQ(10, count);
    121 }
    122 
    123 TEST(logcat, tail_100) {
    124     FILE *fp;
    125 
    126     ASSERT_TRUE(NULL != (fp = popen(
    127       "logcat -v long -b radio -b events -b system -b main -t 100 2>/dev/null",
    128       "r")));
    129 
    130     char buffer[5120];
    131 
    132     int count = 0;
    133 
    134     while (fgets(buffer, sizeof(buffer), fp)) {
    135         if ((buffer[0] == '[') && (buffer[1] == ' ')
    136          && isdigit(buffer[2]) && isdigit(buffer[3])
    137          && (buffer[4] == '-')) {
    138             ++count;
    139         }
    140     }
    141 
    142     pclose(fp);
    143 
    144     ASSERT_EQ(100, count);
    145 }
    146 
    147 TEST(logcat, tail_1000) {
    148     FILE *fp;
    149 
    150     ASSERT_TRUE(NULL != (fp = popen(
    151       "logcat -v long -b radio -b events -b system -b main -t 1000 2>/dev/null",
    152       "r")));
    153 
    154     char buffer[5120];
    155 
    156     int count = 0;
    157 
    158     while (fgets(buffer, sizeof(buffer), fp)) {
    159         if ((buffer[0] == '[') && (buffer[1] == ' ')
    160          && isdigit(buffer[2]) && isdigit(buffer[3])
    161          && (buffer[4] == '-')) {
    162             ++count;
    163         }
    164     }
    165 
    166     pclose(fp);
    167 
    168     ASSERT_EQ(1000, count);
    169 }
    170 
    171 TEST(logcat, tail_time) {
    172     FILE *fp;
    173 
    174     ASSERT_TRUE(NULL != (fp = popen("logcat -v long -b all -t 10 2>&1", "r")));
    175 
    176     char buffer[5120];
    177     char *last_timestamp = NULL;
    178     char *first_timestamp = NULL;
    179     int count = 0;
    180     const unsigned int time_length = 18;
    181     const unsigned int time_offset = 2;
    182 
    183     while (fgets(buffer, sizeof(buffer), fp)) {
    184         if ((buffer[0] == '[') && (buffer[1] == ' ')
    185          && isdigit(buffer[time_offset]) && isdigit(buffer[time_offset + 1])
    186          && (buffer[time_offset + 2] == '-')) {
    187             ++count;
    188             buffer[time_length + time_offset] = '\0';
    189             if (!first_timestamp) {
    190                 first_timestamp = strdup(buffer + time_offset);
    191             }
    192             free(last_timestamp);
    193             last_timestamp = strdup(buffer + time_offset);
    194         }
    195     }
    196     pclose(fp);
    197 
    198     EXPECT_EQ(10, count);
    199     EXPECT_TRUE(last_timestamp != NULL);
    200     EXPECT_TRUE(first_timestamp != NULL);
    201 
    202     snprintf(buffer, sizeof(buffer), "logcat -v long -b all -t '%s' 2>&1",
    203              first_timestamp);
    204     ASSERT_TRUE(NULL != (fp = popen(buffer, "r")));
    205 
    206     int second_count = 0;
    207     int last_timestamp_count = -1;
    208 
    209     while (fgets(buffer, sizeof(buffer), fp)) {
    210         if ((buffer[0] == '[') && (buffer[1] == ' ')
    211          && isdigit(buffer[time_offset]) && isdigit(buffer[time_offset + 1])
    212          && (buffer[time_offset + 2] == '-')) {
    213             ++second_count;
    214             buffer[time_length + time_offset] = '\0';
    215             if (first_timestamp) {
    216                 // we can get a transitory *extremely* rare failure if hidden
    217                 // underneath the time is *exactly* XX-XX XX:XX:XX.XXX000000
    218                 EXPECT_STREQ(buffer + time_offset, first_timestamp);
    219                 free(first_timestamp);
    220                 first_timestamp = NULL;
    221             }
    222             if (!strcmp(buffer + time_offset, last_timestamp)) {
    223                 last_timestamp_count = second_count;
    224             }
    225         }
    226     }
    227     pclose(fp);
    228 
    229     free(last_timestamp);
    230     last_timestamp = NULL;
    231 
    232     EXPECT_TRUE(first_timestamp == NULL);
    233     EXPECT_LE(count, second_count);
    234     EXPECT_LE(count, last_timestamp_count);
    235 }
    236 
    237 TEST(logcat, End_to_End) {
    238     pid_t pid = getpid();
    239 
    240     log_time ts(CLOCK_MONOTONIC);
    241 
    242     ASSERT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)));
    243 
    244     FILE *fp;
    245     ASSERT_TRUE(NULL != (fp = popen(
    246       "logcat -b events -t 100 2>/dev/null",
    247       "r")));
    248 
    249     char buffer[5120];
    250 
    251     int count = 0;
    252 
    253     while (fgets(buffer, sizeof(buffer), fp)) {
    254         int p;
    255         unsigned long long t;
    256 
    257         if ((2 != sscanf(buffer, "I/[0]     ( %d): %llu", &p, &t))
    258          || (p != pid)) {
    259             continue;
    260         }
    261 
    262         log_time tx((const char *) &t);
    263         if (ts == tx) {
    264             ++count;
    265         }
    266     }
    267 
    268     pclose(fp);
    269 
    270     ASSERT_EQ(1, count);
    271 }
    272 
    273 TEST(logcat, get_size) {
    274     FILE *fp;
    275 
    276     // NB: crash log only available in user space
    277     ASSERT_TRUE(NULL != (fp = popen(
    278       "logcat -b radio -b events -b system -b main -g 2>/dev/null",
    279       "r")));
    280 
    281     char buffer[5120];
    282 
    283     int count = 0;
    284 
    285     while (fgets(buffer, sizeof(buffer), fp)) {
    286         int size, consumed, max, payload;
    287         char size_mult[2], consumed_mult[2];
    288         long full_size, full_consumed;
    289 
    290         size = consumed = max = payload = 0;
    291         // NB: crash log can be very small, not hit a Kb of consumed space
    292         //     doubly lucky we are not including it.
    293         if (6 != sscanf(buffer, "%*s ring buffer is %d%2s (%d%2s consumed),"
    294                                 " max entry is %db, max payload is %db",
    295                                 &size, size_mult, &consumed, consumed_mult,
    296                                 &max, &payload)) {
    297             fprintf(stderr, "WARNING: Parse error: %s", buffer);
    298             continue;
    299         }
    300         full_size = size;
    301         switch(size_mult[0]) {
    302         case 'G':
    303             full_size *= 1024;
    304             /* FALLTHRU */
    305         case 'M':
    306             full_size *= 1024;
    307             /* FALLTHRU */
    308         case 'K':
    309             full_size *= 1024;
    310             /* FALLTHRU */
    311         case 'b':
    312             break;
    313         }
    314         full_consumed = consumed;
    315         switch(consumed_mult[0]) {
    316         case 'G':
    317             full_consumed *= 1024;
    318             /* FALLTHRU */
    319         case 'M':
    320             full_consumed *= 1024;
    321             /* FALLTHRU */
    322         case 'K':
    323             full_consumed *= 1024;
    324             /* FALLTHRU */
    325         case 'b':
    326             break;
    327         }
    328         EXPECT_GT((full_size * 9) / 4, full_consumed);
    329         EXPECT_GT(full_size, max);
    330         EXPECT_GT(max, payload);
    331 
    332         if ((((full_size * 9) / 4) >= full_consumed)
    333          && (full_size > max)
    334          && (max > payload)) {
    335             ++count;
    336         }
    337     }
    338 
    339     pclose(fp);
    340 
    341     ASSERT_EQ(4, count);
    342 }
    343 
    344 static void caught_blocking(int /*signum*/)
    345 {
    346     unsigned long long v = 0xDEADBEEFA55A0000ULL;
    347 
    348     v += getpid() & 0xFFFF;
    349 
    350     LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v)));
    351 }
    352 
    353 TEST(logcat, blocking) {
    354     FILE *fp;
    355     unsigned long long v = 0xDEADBEEFA55F0000ULL;
    356 
    357     pid_t pid = getpid();
    358 
    359     v += pid & 0xFFFF;
    360 
    361     LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v)));
    362 
    363     v &= 0xFFFFFFFFFFFAFFFFULL;
    364 
    365     ASSERT_TRUE(NULL != (fp = popen(
    366       "( trap exit HUP QUIT INT PIPE KILL ; sleep 6; echo DONE )&"
    367       " logcat -b events 2>&1",
    368       "r")));
    369 
    370     char buffer[5120];
    371 
    372     int count = 0;
    373 
    374     int signals = 0;
    375 
    376     signal(SIGALRM, caught_blocking);
    377     alarm(2);
    378     while (fgets(buffer, sizeof(buffer), fp)) {
    379 
    380         if (!strncmp(buffer, "DONE", 4)) {
    381             break;
    382         }
    383 
    384         ++count;
    385 
    386         int p;
    387         unsigned long long l;
    388 
    389         if ((2 != sscanf(buffer, "I/[0] ( %u): %lld", &p, &l))
    390          || (p != pid)) {
    391             continue;
    392         }
    393 
    394         if (l == v) {
    395             ++signals;
    396             break;
    397         }
    398     }
    399     alarm(0);
    400     signal(SIGALRM, SIG_DFL);
    401 
    402     // Generate SIGPIPE
    403     fclose(fp);
    404     caught_blocking(0);
    405 
    406     pclose(fp);
    407 
    408     EXPECT_LE(2, count);
    409 
    410     EXPECT_EQ(1, signals);
    411 }
    412 
    413 static void caught_blocking_tail(int /*signum*/)
    414 {
    415     unsigned long long v = 0xA55ADEADBEEF0000ULL;
    416 
    417     v += getpid() & 0xFFFF;
    418 
    419     LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v)));
    420 }
    421 
    422 TEST(logcat, blocking_tail) {
    423     FILE *fp;
    424     unsigned long long v = 0xA55FDEADBEEF0000ULL;
    425 
    426     pid_t pid = getpid();
    427 
    428     v += pid & 0xFFFF;
    429 
    430     LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v)));
    431 
    432     v &= 0xFFFAFFFFFFFFFFFFULL;
    433 
    434     ASSERT_TRUE(NULL != (fp = popen(
    435       "( trap exit HUP QUIT INT PIPE KILL ; sleep 6; echo DONE )&"
    436       " logcat -b events -T 5 2>&1",
    437       "r")));
    438 
    439     char buffer[5120];
    440 
    441     int count = 0;
    442 
    443     int signals = 0;
    444 
    445     signal(SIGALRM, caught_blocking_tail);
    446     alarm(2);
    447     while (fgets(buffer, sizeof(buffer), fp)) {
    448 
    449         if (!strncmp(buffer, "DONE", 4)) {
    450             break;
    451         }
    452 
    453         ++count;
    454 
    455         int p;
    456         unsigned long long l;
    457 
    458         if ((2 != sscanf(buffer, "I/[0] ( %u): %lld", &p, &l))
    459          || (p != pid)) {
    460             continue;
    461         }
    462 
    463         if (l == v) {
    464             if (count >= 5) {
    465                 ++signals;
    466             }
    467             break;
    468         }
    469     }
    470     alarm(0);
    471     signal(SIGALRM, SIG_DFL);
    472 
    473     // Generate SIGPIPE
    474     fclose(fp);
    475     caught_blocking_tail(0);
    476 
    477     pclose(fp);
    478 
    479     EXPECT_LE(2, count);
    480 
    481     EXPECT_EQ(1, signals);
    482 }
    483 
    484 TEST(logcat, logrotate) {
    485     static const char form[] = "/data/local/tmp/logcat.logrotate.XXXXXX";
    486     char buf[sizeof(form)];
    487     ASSERT_TRUE(NULL != mkdtemp(strcpy(buf, form)));
    488 
    489     static const char comm[] = "logcat -b radio -b events -b system -b main"
    490                                      " -d -f %s/log.txt -n 7 -r 1";
    491     char command[sizeof(buf) + sizeof(comm)];
    492     sprintf(command, comm, buf);
    493 
    494     int ret;
    495     EXPECT_FALSE((ret = system(command)));
    496     if (!ret) {
    497         sprintf(command, "ls -s %s 2>/dev/null", buf);
    498 
    499         FILE *fp;
    500         EXPECT_TRUE(NULL != (fp = popen(command, "r")));
    501         if (fp) {
    502             char buffer[5120];
    503             int count = 0;
    504 
    505             while (fgets(buffer, sizeof(buffer), fp)) {
    506                 static const char match[] = "4 log.txt";
    507                 static const char total[] = "total ";
    508 
    509                 if (!strncmp(buffer, match, sizeof(match) - 1)) {
    510                     ++count;
    511                 } else if (strncmp(buffer, total, sizeof(total) - 1)) {
    512                     fprintf(stderr, "WARNING: Parse error: %s", buffer);
    513                 }
    514             }
    515             pclose(fp);
    516             EXPECT_TRUE(count == 7 || count == 8);
    517         }
    518     }
    519     sprintf(command, "rm -rf %s", buf);
    520     EXPECT_FALSE(system(command));
    521 }
    522 
    523 static void caught_blocking_clear(int /*signum*/)
    524 {
    525     unsigned long long v = 0xDEADBEEFA55C0000ULL;
    526 
    527     v += getpid() & 0xFFFF;
    528 
    529     LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v)));
    530 }
    531 
    532 TEST(logcat, blocking_clear) {
    533     FILE *fp;
    534     unsigned long long v = 0xDEADBEEFA55C0000ULL;
    535 
    536     pid_t pid = getpid();
    537 
    538     v += pid & 0xFFFF;
    539 
    540     // This test is racey; an event occurs between clear and dump.
    541     // We accept that we will get a false positive, but never a false negative.
    542     ASSERT_TRUE(NULL != (fp = popen(
    543       "( trap exit HUP QUIT INT PIPE KILL ; sleep 6; echo DONE )&"
    544       " logcat -b events -c 2>&1 ;"
    545       " logcat -b events 2>&1",
    546       "r")));
    547 
    548     char buffer[5120];
    549 
    550     int count = 0;
    551 
    552     int signals = 0;
    553 
    554     signal(SIGALRM, caught_blocking_clear);
    555     alarm(2);
    556     while (fgets(buffer, sizeof(buffer), fp)) {
    557 
    558         if (!strncmp(buffer, "clearLog: ", 10)) {
    559             fprintf(stderr, "WARNING: Test lacks permission to run :-(\n");
    560             count = signals = 1;
    561             break;
    562         }
    563 
    564         if (!strncmp(buffer, "DONE", 4)) {
    565             break;
    566         }
    567 
    568         ++count;
    569 
    570         int p;
    571         unsigned long long l;
    572 
    573         if ((2 != sscanf(buffer, "I/[0] ( %u): %lld", &p, &l))
    574          || (p != pid)) {
    575             continue;
    576         }
    577 
    578         if (l == v) {
    579             if (count > 1) {
    580                 fprintf(stderr, "WARNING: Possible false positive\n");
    581             }
    582             ++signals;
    583             break;
    584         }
    585     }
    586     alarm(0);
    587     signal(SIGALRM, SIG_DFL);
    588 
    589     // Generate SIGPIPE
    590     fclose(fp);
    591     caught_blocking_clear(0);
    592 
    593     pclose(fp);
    594 
    595     EXPECT_LE(1, count);
    596 
    597     EXPECT_EQ(1, signals);
    598 }
    599 
    600 static bool get_white_black(char **list) {
    601     FILE *fp;
    602 
    603     fp = popen("logcat -p 2>/dev/null", "r");
    604     if (fp == NULL) {
    605         fprintf(stderr, "ERROR: logcat -p 2>/dev/null\n");
    606         return false;
    607     }
    608 
    609     char buffer[5120];
    610 
    611     while (fgets(buffer, sizeof(buffer), fp)) {
    612         char *hold = *list;
    613         char *buf = buffer;
    614 	while (isspace(*buf)) {
    615             ++buf;
    616         }
    617         char *end = buf + strlen(buf);
    618         while (isspace(*--end) && (end >= buf)) {
    619             *end = '\0';
    620         }
    621         if (end < buf) {
    622             continue;
    623         }
    624         if (hold) {
    625             asprintf(list, "%s %s", hold, buf);
    626             free(hold);
    627         } else {
    628             asprintf(list, "%s", buf);
    629         }
    630     }
    631     pclose(fp);
    632     return *list != NULL;
    633 }
    634 
    635 static bool set_white_black(const char *list) {
    636     FILE *fp;
    637 
    638     char buffer[5120];
    639 
    640     snprintf(buffer, sizeof(buffer), "logcat -P '%s' 2>&1", list ? list : "");
    641     fp = popen(buffer, "r");
    642     if (fp == NULL) {
    643         fprintf(stderr, "ERROR: %s\n", buffer);
    644         return false;
    645     }
    646 
    647     while (fgets(buffer, sizeof(buffer), fp)) {
    648         char *buf = buffer;
    649 	while (isspace(*buf)) {
    650             ++buf;
    651         }
    652         char *end = buf + strlen(buf);
    653         while ((end > buf) && isspace(*--end)) {
    654             *end = '\0';
    655         }
    656         if (end <= buf) {
    657             continue;
    658         }
    659         fprintf(stderr, "%s\n", buf);
    660         pclose(fp);
    661         return false;
    662     }
    663     return pclose(fp) == 0;
    664 }
    665 
    666 TEST(logcat, white_black_adjust) {
    667     char *list = NULL;
    668     char *adjust = NULL;
    669 
    670     get_white_black(&list);
    671 
    672     static const char adjustment[] = "~! 300/20 300/25 2000 ~1000/5 ~1000/30";
    673     ASSERT_EQ(true, set_white_black(adjustment));
    674     ASSERT_EQ(true, get_white_black(&adjust));
    675     EXPECT_STREQ(adjustment, adjust);
    676     free(adjust);
    677     adjust = NULL;
    678 
    679     static const char adjustment2[] = "300/20 300/21 2000 ~1000";
    680     ASSERT_EQ(true, set_white_black(adjustment2));
    681     ASSERT_EQ(true, get_white_black(&adjust));
    682     EXPECT_STREQ(adjustment2, adjust);
    683     free(adjust);
    684     adjust = NULL;
    685 
    686     ASSERT_EQ(true, set_white_black(list));
    687     get_white_black(&adjust);
    688     EXPECT_STREQ(list ? list : "", adjust ? adjust : "");
    689     free(adjust);
    690     adjust = NULL;
    691 
    692     free(list);
    693     list = NULL;
    694 }
    695