Home | History | Annotate | Download | only in liblog
      1 /* //device/libs/cutils/logprint.c
      2 **
      3 ** Copyright 2006, The Android Open Source Project
      4 **
      5 ** Licensed under the Apache License, Version 2.0 (the "License");
      6 ** you may not use this file except in compliance with the License.
      7 ** You may obtain a copy of the License at
      8 **
      9 **     http://www.apache.org/licenses/LICENSE-2.0
     10 **
     11 ** Unless required by applicable law or agreed to in writing, software
     12 ** distributed under the License is distributed on an "AS IS" BASIS,
     13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14 ** See the License for the specific language governing permissions and
     15 ** limitations under the License.
     16 */
     17 
     18 #define _GNU_SOURCE /* for asprintf */
     19 
     20 #include <ctype.h>
     21 #include <stdio.h>
     22 #include <errno.h>
     23 #include <stdlib.h>
     24 #include <stdint.h>
     25 #include <string.h>
     26 #include <assert.h>
     27 #include <arpa/inet.h>
     28 
     29 #include <cutils/logd.h>
     30 #include <cutils/logprint.h>
     31 
     32 typedef struct FilterInfo_t {
     33     char *mTag;
     34     android_LogPriority mPri;
     35     struct FilterInfo_t *p_next;
     36 } FilterInfo;
     37 
     38 struct AndroidLogFormat_t {
     39     android_LogPriority global_pri;
     40     FilterInfo *filters;
     41     AndroidLogPrintFormat format;
     42 };
     43 
     44 static FilterInfo * filterinfo_new(const char * tag, android_LogPriority pri)
     45 {
     46     FilterInfo *p_ret;
     47 
     48     p_ret = (FilterInfo *)calloc(1, sizeof(FilterInfo));
     49     p_ret->mTag = strdup(tag);
     50     p_ret->mPri = pri;
     51 
     52     return p_ret;
     53 }
     54 
     55 static void filterinfo_free(FilterInfo *p_info)
     56 {
     57     if (p_info == NULL) {
     58         return;
     59     }
     60 
     61     free(p_info->mTag);
     62     p_info->mTag = NULL;
     63 }
     64 
     65 /*
     66  * Note: also accepts 0-9 priorities
     67  * returns ANDROID_LOG_UNKNOWN if the character is unrecognized
     68  */
     69 static android_LogPriority filterCharToPri (char c)
     70 {
     71     android_LogPriority pri;
     72 
     73     c = tolower(c);
     74 
     75     if (c >= '0' && c <= '9') {
     76         if (c >= ('0'+ANDROID_LOG_SILENT)) {
     77             pri = ANDROID_LOG_VERBOSE;
     78         } else {
     79             pri = (android_LogPriority)(c - '0');
     80         }
     81     } else if (c == 'v') {
     82         pri = ANDROID_LOG_VERBOSE;
     83     } else if (c == 'd') {
     84         pri = ANDROID_LOG_DEBUG;
     85     } else if (c == 'i') {
     86         pri = ANDROID_LOG_INFO;
     87     } else if (c == 'w') {
     88         pri = ANDROID_LOG_WARN;
     89     } else if (c == 'e') {
     90         pri = ANDROID_LOG_ERROR;
     91     } else if (c == 'f') {
     92         pri = ANDROID_LOG_FATAL;
     93     } else if (c == 's') {
     94         pri = ANDROID_LOG_SILENT;
     95     } else if (c == '*') {
     96         pri = ANDROID_LOG_DEFAULT;
     97     } else {
     98         pri = ANDROID_LOG_UNKNOWN;
     99     }
    100 
    101     return pri;
    102 }
    103 
    104 static char filterPriToChar (android_LogPriority pri)
    105 {
    106     switch (pri) {
    107         case ANDROID_LOG_VERBOSE:       return 'V';
    108         case ANDROID_LOG_DEBUG:         return 'D';
    109         case ANDROID_LOG_INFO:          return 'I';
    110         case ANDROID_LOG_WARN:          return 'W';
    111         case ANDROID_LOG_ERROR:         return 'E';
    112         case ANDROID_LOG_FATAL:         return 'F';
    113         case ANDROID_LOG_SILENT:        return 'S';
    114 
    115         case ANDROID_LOG_DEFAULT:
    116         case ANDROID_LOG_UNKNOWN:
    117         default:                        return '?';
    118     }
    119 }
    120 
    121 static android_LogPriority filterPriForTag(
    122         AndroidLogFormat *p_format, const char *tag)
    123 {
    124     FilterInfo *p_curFilter;
    125 
    126     for (p_curFilter = p_format->filters
    127             ; p_curFilter != NULL
    128             ; p_curFilter = p_curFilter->p_next
    129     ) {
    130         if (0 == strcmp(tag, p_curFilter->mTag)) {
    131             if (p_curFilter->mPri == ANDROID_LOG_DEFAULT) {
    132                 return p_format->global_pri;
    133             } else {
    134                 return p_curFilter->mPri;
    135             }
    136         }
    137     }
    138 
    139     return p_format->global_pri;
    140 }
    141 
    142 /** for debugging */
    143 static void dumpFilters(AndroidLogFormat *p_format)
    144 {
    145     FilterInfo *p_fi;
    146 
    147     for (p_fi = p_format->filters ; p_fi != NULL ; p_fi = p_fi->p_next) {
    148         char cPri = filterPriToChar(p_fi->mPri);
    149         if (p_fi->mPri == ANDROID_LOG_DEFAULT) {
    150             cPri = filterPriToChar(p_format->global_pri);
    151         }
    152         fprintf(stderr,"%s:%c\n", p_fi->mTag, cPri);
    153     }
    154 
    155     fprintf(stderr,"*:%c\n", filterPriToChar(p_format->global_pri));
    156 
    157 }
    158 
    159 /**
    160  * returns 1 if this log line should be printed based on its priority
    161  * and tag, and 0 if it should not
    162  */
    163 int android_log_shouldPrintLine (
    164         AndroidLogFormat *p_format, const char *tag, android_LogPriority pri)
    165 {
    166     return pri >= filterPriForTag(p_format, tag);
    167 }
    168 
    169 AndroidLogFormat *android_log_format_new()
    170 {
    171     AndroidLogFormat *p_ret;
    172 
    173     p_ret = calloc(1, sizeof(AndroidLogFormat));
    174 
    175     p_ret->global_pri = ANDROID_LOG_VERBOSE;
    176     p_ret->format = FORMAT_BRIEF;
    177 
    178     return p_ret;
    179 }
    180 
    181 void android_log_format_free(AndroidLogFormat *p_format)
    182 {
    183     FilterInfo *p_info, *p_info_old;
    184 
    185     p_info = p_format->filters;
    186 
    187     while (p_info != NULL) {
    188         p_info_old = p_info;
    189         p_info = p_info->p_next;
    190 
    191         free(p_info_old);
    192     }
    193 
    194     free(p_format);
    195 }
    196 
    197 
    198 
    199 void android_log_setPrintFormat(AndroidLogFormat *p_format,
    200         AndroidLogPrintFormat format)
    201 {
    202     p_format->format=format;
    203 }
    204 
    205 /**
    206  * Returns FORMAT_OFF on invalid string
    207  */
    208 AndroidLogPrintFormat android_log_formatFromString(const char * formatString)
    209 {
    210     static AndroidLogPrintFormat format;
    211 
    212     if (strcmp(formatString, "brief") == 0) format = FORMAT_BRIEF;
    213     else if (strcmp(formatString, "process") == 0) format = FORMAT_PROCESS;
    214     else if (strcmp(formatString, "tag") == 0) format = FORMAT_TAG;
    215     else if (strcmp(formatString, "thread") == 0) format = FORMAT_THREAD;
    216     else if (strcmp(formatString, "raw") == 0) format = FORMAT_RAW;
    217     else if (strcmp(formatString, "time") == 0) format = FORMAT_TIME;
    218     else if (strcmp(formatString, "threadtime") == 0) format = FORMAT_THREADTIME;
    219     else if (strcmp(formatString, "long") == 0) format = FORMAT_LONG;
    220     else format = FORMAT_OFF;
    221 
    222     return format;
    223 }
    224 
    225 /**
    226  * filterExpression: a single filter expression
    227  * eg "AT:d"
    228  *
    229  * returns 0 on success and -1 on invalid expression
    230  *
    231  * Assumes single threaded execution
    232  */
    233 
    234 int android_log_addFilterRule(AndroidLogFormat *p_format,
    235         const char *filterExpression)
    236 {
    237     size_t i=0;
    238     size_t tagNameLength;
    239     android_LogPriority pri = ANDROID_LOG_DEFAULT;
    240 
    241     tagNameLength = strcspn(filterExpression, ":");
    242 
    243     if (tagNameLength == 0) {
    244         goto error;
    245     }
    246 
    247     if(filterExpression[tagNameLength] == ':') {
    248         pri = filterCharToPri(filterExpression[tagNameLength+1]);
    249 
    250         if (pri == ANDROID_LOG_UNKNOWN) {
    251             goto error;
    252         }
    253     }
    254 
    255     if(0 == strncmp("*", filterExpression, tagNameLength)) {
    256         // This filter expression refers to the global filter
    257         // The default level for this is DEBUG if the priority
    258         // is unspecified
    259         if (pri == ANDROID_LOG_DEFAULT) {
    260             pri = ANDROID_LOG_DEBUG;
    261         }
    262 
    263         p_format->global_pri = pri;
    264     } else {
    265         // for filter expressions that don't refer to the global
    266         // filter, the default is verbose if the priority is unspecified
    267         if (pri == ANDROID_LOG_DEFAULT) {
    268             pri = ANDROID_LOG_VERBOSE;
    269         }
    270 
    271         char *tagName;
    272 
    273 // Presently HAVE_STRNDUP is never defined, so the second case is always taken
    274 // Darwin doesn't have strnup, everything else does
    275 #ifdef HAVE_STRNDUP
    276         tagName = strndup(filterExpression, tagNameLength);
    277 #else
    278         //a few extra bytes copied...
    279         tagName = strdup(filterExpression);
    280         tagName[tagNameLength] = '\0';
    281 #endif /*HAVE_STRNDUP*/
    282 
    283         FilterInfo *p_fi = filterinfo_new(tagName, pri);
    284         free(tagName);
    285 
    286         p_fi->p_next = p_format->filters;
    287         p_format->filters = p_fi;
    288     }
    289 
    290     return 0;
    291 error:
    292     return -1;
    293 }
    294 
    295 
    296 /**
    297  * filterString: a comma/whitespace-separated set of filter expressions
    298  *
    299  * eg "AT:d *:i"
    300  *
    301  * returns 0 on success and -1 on invalid expression
    302  *
    303  * Assumes single threaded execution
    304  *
    305  */
    306 
    307 int android_log_addFilterString(AndroidLogFormat *p_format,
    308         const char *filterString)
    309 {
    310     char *filterStringCopy = strdup (filterString);
    311     char *p_cur = filterStringCopy;
    312     char *p_ret;
    313     int err;
    314 
    315     // Yes, I'm using strsep
    316     while (NULL != (p_ret = strsep(&p_cur, " \t,"))) {
    317         // ignore whitespace-only entries
    318         if(p_ret[0] != '\0') {
    319             err = android_log_addFilterRule(p_format, p_ret);
    320 
    321             if (err < 0) {
    322                 goto error;
    323             }
    324         }
    325     }
    326 
    327     free (filterStringCopy);
    328     return 0;
    329 error:
    330     free (filterStringCopy);
    331     return -1;
    332 }
    333 
    334 static inline char * strip_end(char *str)
    335 {
    336     char *end = str + strlen(str) - 1;
    337 
    338     while (end >= str && isspace(*end))
    339         *end-- = '\0';
    340     return str;
    341 }
    342 
    343 /**
    344  * Splits a wire-format buffer into an AndroidLogEntry
    345  * entry allocated by caller. Pointers will point directly into buf
    346  *
    347  * Returns 0 on success and -1 on invalid wire format (entry will be
    348  * in unspecified state)
    349  */
    350 int android_log_processLogBuffer(struct logger_entry *buf,
    351                                  AndroidLogEntry *entry)
    352 {
    353     size_t tag_len;
    354 
    355     entry->tv_sec = buf->sec;
    356     entry->tv_nsec = buf->nsec;
    357     entry->priority = buf->msg[0];
    358     entry->pid = buf->pid;
    359     entry->tid = buf->tid;
    360     entry->tag = buf->msg + 1;
    361     tag_len = strlen(entry->tag);
    362     entry->messageLen = buf->len - tag_len - 3;
    363     entry->message = entry->tag + tag_len + 1;
    364 
    365     return 0;
    366 }
    367 
    368 /*
    369  * Extract a 4-byte value from a byte stream.
    370  */
    371 static inline uint32_t get4LE(const uint8_t* src)
    372 {
    373     return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
    374 }
    375 
    376 /*
    377  * Extract an 8-byte value from a byte stream.
    378  */
    379 static inline uint64_t get8LE(const uint8_t* src)
    380 {
    381     uint32_t low, high;
    382 
    383     low = src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
    384     high = src[4] | (src[5] << 8) | (src[6] << 16) | (src[7] << 24);
    385     return ((long long) high << 32) | (long long) low;
    386 }
    387 
    388 
    389 /*
    390  * Recursively convert binary log data to printable form.
    391  *
    392  * This needs to be recursive because you can have lists of lists.
    393  *
    394  * If we run out of room, we stop processing immediately.  It's important
    395  * for us to check for space on every output element to avoid producing
    396  * garbled output.
    397  *
    398  * Returns 0 on success, 1 on buffer full, -1 on failure.
    399  */
    400 static int android_log_printBinaryEvent(const unsigned char** pEventData,
    401     size_t* pEventDataLen, char** pOutBuf, size_t* pOutBufLen)
    402 {
    403     const unsigned char* eventData = *pEventData;
    404     size_t eventDataLen = *pEventDataLen;
    405     char* outBuf = *pOutBuf;
    406     size_t outBufLen = *pOutBufLen;
    407     unsigned char type;
    408     size_t outCount;
    409     int result = 0;
    410 
    411     if (eventDataLen < 1)
    412         return -1;
    413     type = *eventData++;
    414     eventDataLen--;
    415 
    416     //fprintf(stderr, "--- type=%d (rem len=%d)\n", type, eventDataLen);
    417 
    418     switch (type) {
    419     case EVENT_TYPE_INT:
    420         /* 32-bit signed int */
    421         {
    422             int ival;
    423 
    424             if (eventDataLen < 4)
    425                 return -1;
    426             ival = get4LE(eventData);
    427             eventData += 4;
    428             eventDataLen -= 4;
    429 
    430             outCount = snprintf(outBuf, outBufLen, "%d", ival);
    431             if (outCount < outBufLen) {
    432                 outBuf += outCount;
    433                 outBufLen -= outCount;
    434             } else {
    435                 /* halt output */
    436                 goto no_room;
    437             }
    438         }
    439         break;
    440     case EVENT_TYPE_LONG:
    441         /* 64-bit signed long */
    442         {
    443             long long lval;
    444 
    445             if (eventDataLen < 8)
    446                 return -1;
    447             lval = get8LE(eventData);
    448             eventData += 8;
    449             eventDataLen -= 8;
    450 
    451             outCount = snprintf(outBuf, outBufLen, "%lld", lval);
    452             if (outCount < outBufLen) {
    453                 outBuf += outCount;
    454                 outBufLen -= outCount;
    455             } else {
    456                 /* halt output */
    457                 goto no_room;
    458             }
    459         }
    460         break;
    461     case EVENT_TYPE_STRING:
    462         /* UTF-8 chars, not NULL-terminated */
    463         {
    464             unsigned int strLen;
    465 
    466             if (eventDataLen < 4)
    467                 return -1;
    468             strLen = get4LE(eventData);
    469             eventData += 4;
    470             eventDataLen -= 4;
    471 
    472             if (eventDataLen < strLen)
    473                 return -1;
    474 
    475             if (strLen < outBufLen) {
    476                 memcpy(outBuf, eventData, strLen);
    477                 outBuf += strLen;
    478                 outBufLen -= strLen;
    479             } else if (outBufLen > 0) {
    480                 /* copy what we can */
    481                 memcpy(outBuf, eventData, outBufLen);
    482                 outBuf += outBufLen;
    483                 outBufLen -= outBufLen;
    484                 goto no_room;
    485             }
    486             eventData += strLen;
    487             eventDataLen -= strLen;
    488             break;
    489         }
    490     case EVENT_TYPE_LIST:
    491         /* N items, all different types */
    492         {
    493             unsigned char count;
    494             int i;
    495 
    496             if (eventDataLen < 1)
    497                 return -1;
    498 
    499             count = *eventData++;
    500             eventDataLen--;
    501 
    502             if (outBufLen > 0) {
    503                 *outBuf++ = '[';
    504                 outBufLen--;
    505             } else {
    506                 goto no_room;
    507             }
    508 
    509             for (i = 0; i < count; i++) {
    510                 result = android_log_printBinaryEvent(&eventData, &eventDataLen,
    511                         &outBuf, &outBufLen);
    512                 if (result != 0)
    513                     goto bail;
    514 
    515                 if (i < count-1) {
    516                     if (outBufLen > 0) {
    517                         *outBuf++ = ',';
    518                         outBufLen--;
    519                     } else {
    520                         goto no_room;
    521                     }
    522                 }
    523             }
    524 
    525             if (outBufLen > 0) {
    526                 *outBuf++ = ']';
    527                 outBufLen--;
    528             } else {
    529                 goto no_room;
    530             }
    531         }
    532         break;
    533     default:
    534         fprintf(stderr, "Unknown binary event type %d\n", type);
    535         return -1;
    536     }
    537 
    538 bail:
    539     *pEventData = eventData;
    540     *pEventDataLen = eventDataLen;
    541     *pOutBuf = outBuf;
    542     *pOutBufLen = outBufLen;
    543     return result;
    544 
    545 no_room:
    546     result = 1;
    547     goto bail;
    548 }
    549 
    550 /**
    551  * Convert a binary log entry to ASCII form.
    552  *
    553  * For convenience we mimic the processLogBuffer API.  There is no
    554  * pre-defined output length for the binary data, since we're free to format
    555  * it however we choose, which means we can't really use a fixed-size buffer
    556  * here.
    557  */
    558 int android_log_processBinaryLogBuffer(struct logger_entry *buf,
    559     AndroidLogEntry *entry, const EventTagMap* map, char* messageBuf,
    560     int messageBufLen)
    561 {
    562     size_t inCount;
    563     unsigned int tagIndex;
    564     const unsigned char* eventData;
    565 
    566     entry->tv_sec = buf->sec;
    567     entry->tv_nsec = buf->nsec;
    568     entry->priority = ANDROID_LOG_INFO;
    569     entry->pid = buf->pid;
    570     entry->tid = buf->tid;
    571 
    572     /*
    573      * Pull the tag out.
    574      */
    575     eventData = (const unsigned char*) buf->msg;
    576     inCount = buf->len;
    577     if (inCount < 4)
    578         return -1;
    579     tagIndex = get4LE(eventData);
    580     eventData += 4;
    581     inCount -= 4;
    582 
    583     if (map != NULL) {
    584         entry->tag = android_lookupEventTag(map, tagIndex);
    585     } else {
    586         entry->tag = NULL;
    587     }
    588 
    589     /*
    590      * If we don't have a map, or didn't find the tag number in the map,
    591      * stuff a generated tag value into the start of the output buffer and
    592      * shift the buffer pointers down.
    593      */
    594     if (entry->tag == NULL) {
    595         int tagLen;
    596 
    597         tagLen = snprintf(messageBuf, messageBufLen, "[%d]", tagIndex);
    598         entry->tag = messageBuf;
    599         messageBuf += tagLen+1;
    600         messageBufLen -= tagLen+1;
    601     }
    602 
    603     /*
    604      * Format the event log data into the buffer.
    605      */
    606     char* outBuf = messageBuf;
    607     size_t outRemaining = messageBufLen-1;      /* leave one for nul byte */
    608     int result;
    609     result = android_log_printBinaryEvent(&eventData, &inCount, &outBuf,
    610                 &outRemaining);
    611     if (result < 0) {
    612         fprintf(stderr, "Binary log entry conversion failed\n");
    613         return -1;
    614     } else if (result == 1) {
    615         if (outBuf > messageBuf) {
    616             /* leave an indicator */
    617             *(outBuf-1) = '!';
    618         } else {
    619             /* no room to output anything at all */
    620             *outBuf++ = '!';
    621             outRemaining--;
    622         }
    623         /* pretend we ate all the data */
    624         inCount = 0;
    625     }
    626 
    627     /* eat the silly terminating '\n' */
    628     if (inCount == 1 && *eventData == '\n') {
    629         eventData++;
    630         inCount--;
    631     }
    632 
    633     if (inCount != 0) {
    634         fprintf(stderr,
    635             "Warning: leftover binary log data (%d bytes)\n", inCount);
    636     }
    637 
    638     /*
    639      * Terminate the buffer.  The NUL byte does not count as part of
    640      * entry->messageLen.
    641      */
    642     *outBuf = '\0';
    643     entry->messageLen = outBuf - messageBuf;
    644     assert(entry->messageLen == (messageBufLen-1) - outRemaining);
    645 
    646     entry->message = messageBuf;
    647 
    648     return 0;
    649 }
    650 
    651 /**
    652  * Formats a log message into a buffer
    653  *
    654  * Uses defaultBuffer if it can, otherwise malloc()'s a new buffer
    655  * If return value != defaultBuffer, caller must call free()
    656  * Returns NULL on malloc error
    657  */
    658 
    659 char *android_log_formatLogLine (
    660     AndroidLogFormat *p_format,
    661     char *defaultBuffer,
    662     size_t defaultBufferSize,
    663     const AndroidLogEntry *entry,
    664     size_t *p_outLength)
    665 {
    666 #if defined(HAVE_LOCALTIME_R)
    667     struct tm tmBuf;
    668 #endif
    669     struct tm* ptm;
    670     char timeBuf[32];
    671     char headerBuf[128];
    672     char prefixBuf[128], suffixBuf[128];
    673     char priChar;
    674     int prefixSuffixIsHeaderFooter = 0;
    675     char * ret = NULL;
    676 
    677     priChar = filterPriToChar(entry->priority);
    678 
    679     /*
    680      * Get the current date/time in pretty form
    681      *
    682      * It's often useful when examining a log with "less" to jump to
    683      * a specific point in the file by searching for the date/time stamp.
    684      * For this reason it's very annoying to have regexp meta characters
    685      * in the time stamp.  Don't use forward slashes, parenthesis,
    686      * brackets, asterisks, or other special chars here.
    687      */
    688 #if defined(HAVE_LOCALTIME_R)
    689     ptm = localtime_r(&(entry->tv_sec), &tmBuf);
    690 #else
    691     ptm = localtime(&(entry->tv_sec));
    692 #endif
    693     //strftime(timeBuf, sizeof(timeBuf), "%Y-%m-%d %H:%M:%S", ptm);
    694     strftime(timeBuf, sizeof(timeBuf), "%m-%d %H:%M:%S", ptm);
    695 
    696     /*
    697      * Construct a buffer containing the log header and log message.
    698      */
    699     size_t prefixLen, suffixLen;
    700 
    701     switch (p_format->format) {
    702         case FORMAT_TAG:
    703             prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
    704                 "%c/%-8s: ", priChar, entry->tag);
    705             strcpy(suffixBuf, "\n"); suffixLen = 1;
    706             break;
    707         case FORMAT_PROCESS:
    708             prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
    709                 "%c(%5d) ", priChar, entry->pid);
    710             suffixLen = snprintf(suffixBuf, sizeof(suffixBuf),
    711                 "  (%s)\n", entry->tag);
    712             break;
    713         case FORMAT_THREAD:
    714             prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
    715                 "%c(%5d:%p) ", priChar, entry->pid, (void*)entry->tid);
    716             strcpy(suffixBuf, "\n");
    717             suffixLen = 1;
    718             break;
    719         case FORMAT_RAW:
    720             prefixBuf[0] = 0;
    721             prefixLen = 0;
    722             strcpy(suffixBuf, "\n");
    723             suffixLen = 1;
    724             break;
    725         case FORMAT_TIME:
    726             prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
    727                 "%s.%03ld %c/%-8s(%5d): ", timeBuf, entry->tv_nsec / 1000000,
    728                 priChar, entry->tag, entry->pid);
    729             strcpy(suffixBuf, "\n");
    730             suffixLen = 1;
    731             break;
    732         case FORMAT_THREADTIME:
    733             prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
    734                 "%s.%03ld %5d %5d %c %-8s: ", timeBuf, entry->tv_nsec / 1000000,
    735                 (int)entry->pid, (int)entry->tid, priChar, entry->tag);
    736             strcpy(suffixBuf, "\n");
    737             suffixLen = 1;
    738             break;
    739         case FORMAT_LONG:
    740             prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
    741                 "[ %s.%03ld %5d:%p %c/%-8s ]\n",
    742                 timeBuf, entry->tv_nsec / 1000000, entry->pid,
    743                 (void*)entry->tid, priChar, entry->tag);
    744             strcpy(suffixBuf, "\n\n");
    745             suffixLen = 2;
    746             prefixSuffixIsHeaderFooter = 1;
    747             break;
    748         case FORMAT_BRIEF:
    749         default:
    750             prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
    751                 "%c/%-8s(%5d): ", priChar, entry->tag, entry->pid);
    752             strcpy(suffixBuf, "\n");
    753             suffixLen = 1;
    754             break;
    755     }
    756     /* snprintf has a weird return value.   It returns what would have been
    757      * written given a large enough buffer.  In the case that the prefix is
    758      * longer then our buffer(128), it messes up the calculations below
    759      * possibly causing heap corruption.  To avoid this we double check and
    760      * set the length at the maximum (size minus null byte)
    761      */
    762     if(prefixLen >= sizeof(prefixBuf))
    763         prefixLen = sizeof(prefixBuf) - 1;
    764     if(suffixLen >= sizeof(suffixBuf))
    765         suffixLen = sizeof(suffixBuf) - 1;
    766 
    767     /* the following code is tragically unreadable */
    768 
    769     size_t numLines;
    770     size_t i;
    771     char *p;
    772     size_t bufferSize;
    773     const char *pm;
    774 
    775     if (prefixSuffixIsHeaderFooter) {
    776         // we're just wrapping message with a header/footer
    777         numLines = 1;
    778     } else {
    779         pm = entry->message;
    780         numLines = 0;
    781 
    782         // The line-end finding here must match the line-end finding
    783         // in for ( ... numLines...) loop below
    784         while (pm < (entry->message + entry->messageLen)) {
    785             if (*pm++ == '\n') numLines++;
    786         }
    787         // plus one line for anything not newline-terminated at the end
    788         if (pm > entry->message && *(pm-1) != '\n') numLines++;
    789     }
    790 
    791     // this is an upper bound--newlines in message may be counted
    792     // extraneously
    793     bufferSize = (numLines * (prefixLen + suffixLen)) + entry->messageLen + 1;
    794 
    795     if (defaultBufferSize >= bufferSize) {
    796         ret = defaultBuffer;
    797     } else {
    798         ret = (char *)malloc(bufferSize);
    799 
    800         if (ret == NULL) {
    801             return ret;
    802         }
    803     }
    804 
    805     ret[0] = '\0';       /* to start strcat off */
    806 
    807     p = ret;
    808     pm = entry->message;
    809 
    810     if (prefixSuffixIsHeaderFooter) {
    811         strcat(p, prefixBuf);
    812         p += prefixLen;
    813         strncat(p, entry->message, entry->messageLen);
    814         p += entry->messageLen;
    815         strcat(p, suffixBuf);
    816         p += suffixLen;
    817     } else {
    818         while(pm < (entry->message + entry->messageLen)) {
    819             const char *lineStart;
    820             size_t lineLen;
    821 
    822             lineStart = pm;
    823 
    824             // Find the next end-of-line in message
    825             while (pm < (entry->message + entry->messageLen)
    826                     && *pm != '\n') pm++;
    827             lineLen = pm - lineStart;
    828 
    829             strcat(p, prefixBuf);
    830             p += prefixLen;
    831             strncat(p, lineStart, lineLen);
    832             p += lineLen;
    833             strcat(p, suffixBuf);
    834             p += suffixLen;
    835 
    836             if (*pm == '\n') pm++;
    837         }
    838     }
    839 
    840     if (p_outLength != NULL) {
    841         *p_outLength = p - ret;
    842     }
    843 
    844     return ret;
    845 }
    846 
    847 /**
    848  * Either print or do not print log line, based on filter
    849  *
    850  * Returns count bytes written
    851  */
    852 
    853 int android_log_printLogLine(
    854     AndroidLogFormat *p_format,
    855     int fd,
    856     const AndroidLogEntry *entry)
    857 {
    858     int ret;
    859     char defaultBuffer[512];
    860     char *outBuffer = NULL;
    861     size_t totalLen;
    862 
    863     outBuffer = android_log_formatLogLine(p_format, defaultBuffer,
    864             sizeof(defaultBuffer), entry, &totalLen);
    865 
    866     if (!outBuffer)
    867         return -1;
    868 
    869     do {
    870         ret = write(fd, outBuffer, totalLen);
    871     } while (ret < 0 && errno == EINTR);
    872 
    873     if (ret < 0) {
    874         fprintf(stderr, "+++ LOG: write failed (errno=%d)\n", errno);
    875         ret = 0;
    876         goto done;
    877     }
    878 
    879     if (((size_t)ret) < totalLen) {
    880         fprintf(stderr, "+++ LOG: write partial (%d of %d)\n", ret,
    881                 (int)totalLen);
    882         goto done;
    883     }
    884 
    885 done:
    886     if (outBuffer != defaultBuffer) {
    887         free(outBuffer);
    888     }
    889 
    890     return ret;
    891 }
    892 
    893 
    894 
    895 void logprint_run_tests()
    896 {
    897 #if 0
    898 
    899     fprintf(stderr, "tests disabled\n");
    900 
    901 #else
    902 
    903     int err;
    904     const char *tag;
    905     AndroidLogFormat *p_format;
    906 
    907     p_format = android_log_format_new();
    908 
    909     fprintf(stderr, "running tests\n");
    910 
    911     tag = "random";
    912 
    913     android_log_addFilterRule(p_format,"*:i");
    914 
    915     assert (ANDROID_LOG_INFO == filterPriForTag(p_format, "random"));
    916     assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) == 0);
    917     android_log_addFilterRule(p_format, "*");
    918     assert (ANDROID_LOG_DEBUG == filterPriForTag(p_format, "random"));
    919     assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
    920     android_log_addFilterRule(p_format, "*:v");
    921     assert (ANDROID_LOG_VERBOSE == filterPriForTag(p_format, "random"));
    922     assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
    923     android_log_addFilterRule(p_format, "*:i");
    924     assert (ANDROID_LOG_INFO == filterPriForTag(p_format, "random"));
    925     assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) == 0);
    926 
    927     android_log_addFilterRule(p_format, "random");
    928     assert (ANDROID_LOG_VERBOSE == filterPriForTag(p_format, "random"));
    929     assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
    930     android_log_addFilterRule(p_format, "random:v");
    931     assert (ANDROID_LOG_VERBOSE == filterPriForTag(p_format, "random"));
    932     assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
    933     android_log_addFilterRule(p_format, "random:d");
    934     assert (ANDROID_LOG_DEBUG == filterPriForTag(p_format, "random"));
    935     assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
    936     android_log_addFilterRule(p_format, "random:w");
    937     assert (ANDROID_LOG_WARN == filterPriForTag(p_format, "random"));
    938     assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) == 0);
    939 
    940     android_log_addFilterRule(p_format, "crap:*");
    941     assert (ANDROID_LOG_VERBOSE== filterPriForTag(p_format, "crap"));
    942     assert(android_log_shouldPrintLine(p_format, "crap", ANDROID_LOG_VERBOSE) > 0);
    943 
    944     // invalid expression
    945     err = android_log_addFilterRule(p_format, "random:z");
    946     assert (err < 0);
    947     assert (ANDROID_LOG_WARN == filterPriForTag(p_format, "random"));
    948     assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) == 0);
    949 
    950     // Issue #550946
    951     err = android_log_addFilterString(p_format, " ");
    952     assert(err == 0);
    953     assert(ANDROID_LOG_WARN == filterPriForTag(p_format, "random"));
    954 
    955     // note trailing space
    956     err = android_log_addFilterString(p_format, "*:s random:d ");
    957     assert(err == 0);
    958     assert(ANDROID_LOG_DEBUG == filterPriForTag(p_format, "random"));
    959 
    960     err = android_log_addFilterString(p_format, "*:s random:z");
    961     assert(err < 0);
    962 
    963 
    964 #if 0
    965     char *ret;
    966     char defaultBuffer[512];
    967 
    968     ret = android_log_formatLogLine(p_format,
    969         defaultBuffer, sizeof(defaultBuffer), 0, ANDROID_LOG_ERROR, 123,
    970         123, 123, "random", "nofile", strlen("Hello"), "Hello", NULL);
    971 #endif
    972 
    973 
    974     fprintf(stderr, "tests complete\n");
    975 #endif
    976 }
    977