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