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