LCOV - code coverage report
Current view: top level - media/libstagefright/system/core/liblog - logprint.c (source / functions) Hit Total Coverage
Test: output.info Lines: 0 426 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 21 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13