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

          Line data    Source code
       1             : /*
       2             :  * Copyright (C) 2008 The Android Open Source Project
       3             :  *
       4             :  * Licensed under the Apache License, Version 2.0 (the "License");
       5             :  * you may not use this file except in compliance with the License.
       6             :  * You may obtain a copy of the License at
       7             :  *
       8             :  *      http://www.apache.org/licenses/LICENSE-2.0
       9             :  *
      10             :  * Unless required by applicable law or agreed to in writing, software
      11             :  * distributed under the License is distributed on an "AS IS" BASIS,
      12             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      13             :  * See the License for the specific language governing permissions and
      14             :  * limitations under the License.
      15             :  */
      16             : /*
      17             :  * Intercepts log messages intended for the Android log device.
      18             :  * When running in the context of the simulator, the messages are
      19             :  * passed on to the underlying (fake) log device.  When not in the
      20             :  * simulator, messages are printed to stderr.
      21             :  */
      22             : #include <log/logd.h>
      23             : 
      24             : #include <stdlib.h>
      25             : #include <string.h>
      26             : #include <ctype.h>
      27             : #include <errno.h>
      28             : #include <fcntl.h>
      29             : 
      30             : #ifdef HAVE_PTHREADS
      31             : #include <pthread.h>
      32             : #endif
      33             : 
      34             : #ifdef _MSC_VER
      35             : #include <io.h>
      36             : #include <process.h>
      37             : #if _MSC_VER < 1900
      38             : #include <nspr/prprf.h>
      39             : #define snprintf PR_snprintf
      40             : #endif
      41             : 
      42             : /* We don't want to indent large blocks because it causes unnecessary merge
      43             :  * conflicts */
      44             : #define UNINDENTED_BLOCK_START {
      45             : #define UNINDENTED_BLOCK_END }
      46             : #else
      47             : #define UNINDENTED_BLOCK_START
      48             : #define UNINDENTED_BLOCK_END
      49             : #endif
      50             : 
      51             : #ifdef _MSC_VER
      52             : #include <io.h>
      53             : #include <process.h>
      54             : 
      55             : /* We don't want to indent large blocks because it causes unnecessary merge
      56             :  * conflicts */
      57             : #define UNINDENTED_BLOCK_START {
      58             : #define UNINDENTED_BLOCK_END }
      59             : #else
      60             : #define UNINDENTED_BLOCK_START
      61             : #define UNINDENTED_BLOCK_END
      62             : #endif
      63             : 
      64             : #define kMaxTagLen  16      /* from the long-dead utils/Log.cpp */
      65             : 
      66             : #define kTagSetSize 16      /* arbitrary */
      67             : 
      68             : #if 0
      69             : #define TRACE(...) printf("fake_log_device: " __VA_ARGS__)
      70             : #else
      71             : #define TRACE(...) ((void)0)
      72             : #endif
      73             : 
      74             : /* from the long-dead utils/Log.cpp */
      75             : typedef enum {
      76             :     FORMAT_OFF = 0,
      77             :     FORMAT_BRIEF,
      78             :     FORMAT_PROCESS,
      79             :     FORMAT_TAG,
      80             :     FORMAT_THREAD,
      81             :     FORMAT_RAW,
      82             :     FORMAT_TIME,
      83             :     FORMAT_THREADTIME,
      84             :     FORMAT_LONG
      85             : } LogFormat;
      86             : 
      87             : 
      88             : /*
      89             :  * Log driver state.
      90             :  */
      91             : typedef struct LogState {
      92             :     /* the fake fd that's seen by the user */
      93             :     int     fakeFd;
      94             : 
      95             :     /* a printable name for this fake device */
      96             :     char   *debugName;
      97             : 
      98             :     /* nonzero if this is a binary log */
      99             :     int     isBinary;
     100             : 
     101             :     /* global minimum priority */
     102             :     int     globalMinPriority;
     103             : 
     104             :     /* output format */
     105             :     LogFormat outputFormat;
     106             : 
     107             :     /* tags and priorities */
     108             :     struct {
     109             :         char    tag[kMaxTagLen];
     110             :         int     minPriority;
     111             :     } tagSet[kTagSetSize];
     112             : } LogState;
     113             : 
     114             : 
     115             : #ifdef HAVE_PTHREADS
     116             : /*
     117             :  * Locking.  Since we're emulating a device, we need to be prepared
     118             :  * to have multiple callers at the same time.  This lock is used
     119             :  * to both protect the fd list and to prevent LogStates from being
     120             :  * freed out from under a user.
     121             :  */
     122             : static pthread_mutex_t fakeLogDeviceLock = PTHREAD_MUTEX_INITIALIZER;
     123             : 
     124             : static void lock()
     125             : {
     126             :     pthread_mutex_lock(&fakeLogDeviceLock);
     127             : }
     128             : 
     129             : static void unlock()
     130             : {
     131             :     pthread_mutex_unlock(&fakeLogDeviceLock);
     132             : }
     133             : #else   // !HAVE_PTHREADS
     134             : #define lock() ((void)0)
     135             : #define unlock() ((void)0)
     136             : #endif  // !HAVE_PTHREADS
     137             : 
     138             : 
     139             : /*
     140             :  * File descriptor management.
     141             :  */
     142             : #define FAKE_FD_BASE 10000
     143             : #define MAX_OPEN_LOGS 16
     144             : static LogState *openLogTable[MAX_OPEN_LOGS];
     145             : 
     146             : /*
     147             :  * Allocate an fd and associate a new LogState with it.
     148             :  * The fd is available via the fakeFd field of the return value.
     149             :  */
     150           0 : static LogState *createLogState()
     151             : {
     152             :     size_t i;
     153             : 
     154           0 :     for (i = 0; i < sizeof(openLogTable); i++) {
     155           0 :         if (openLogTable[i] == NULL) {
     156           0 :             openLogTable[i] = calloc(1, sizeof(LogState));
     157           0 :             openLogTable[i]->fakeFd = FAKE_FD_BASE + i;
     158           0 :             return openLogTable[i];
     159             :         }
     160             :     }
     161           0 :     return NULL;
     162             : }
     163             : 
     164             : /*
     165             :  * Translate an fd to a LogState.
     166             :  */
     167           0 : static LogState *fdToLogState(int fd)
     168             : {
     169           0 :     if (fd >= FAKE_FD_BASE && fd < FAKE_FD_BASE + MAX_OPEN_LOGS) {
     170           0 :         return openLogTable[fd - FAKE_FD_BASE];
     171             :     }
     172           0 :     return NULL;
     173             : }
     174             : 
     175             : /*
     176             :  * Unregister the fake fd and free the memory it pointed to.
     177             :  */
     178           0 : static void deleteFakeFd(int fd)
     179             : {
     180             :     LogState *ls;
     181             : 
     182             :     lock();
     183             : 
     184           0 :     ls = fdToLogState(fd);
     185           0 :     if (ls != NULL) {
     186           0 :         openLogTable[fd - FAKE_FD_BASE] = NULL;
     187           0 :         free(ls->debugName);
     188           0 :         free(ls);
     189             :     }
     190             : 
     191             :     unlock();
     192           0 : }
     193             : 
     194             : /*
     195             :  * Configure logging based on ANDROID_LOG_TAGS environment variable.  We
     196             :  * need to parse a string that looks like
     197             :  *
     198             :  *   *:v jdwp:d dalvikvm:d dalvikvm-gc:i dalvikvmi:i
     199             :  *
     200             :  * The tag (or '*' for the global level) comes first, followed by a colon
     201             :  * and a letter indicating the minimum priority level we're expected to log.
     202             :  * This can be used to reveal or conceal logs with specific tags.
     203             :  *
     204             :  * We also want to check ANDROID_PRINTF_LOG to determine how the output
     205             :  * will look.
     206             :  */
     207           0 : static void configureInitialState(const char* pathName, LogState* logState)
     208             : {
     209             :     static const int kDevLogLen = sizeof("/dev/log/") - 1;
     210             : 
     211           0 :     logState->debugName = strdup(pathName);
     212             : 
     213             :     /* identify binary logs */
     214           0 :     if (strcmp(pathName + kDevLogLen, "events") == 0) {
     215           0 :         logState->isBinary = 1;
     216             :     }
     217             : 
     218             :     /* global min priority defaults to "info" level */
     219           0 :     logState->globalMinPriority = ANDROID_LOG_INFO;
     220             : 
     221             :     /*
     222             :      * This is based on the the long-dead utils/Log.cpp code.
     223             :      */
     224             :     UNINDENTED_BLOCK_START
     225           0 :     const char* tags = getenv("ANDROID_LOG_TAGS");
     226             :     TRACE("Found ANDROID_LOG_TAGS='%s'\n", tags);
     227           0 :     if (tags != NULL) {
     228           0 :         int entry = 0;
     229             : 
     230           0 :         while (*tags != '\0') {
     231             :             char tagName[kMaxTagLen];
     232             :             int i, minPrio;
     233             : 
     234           0 :             while (isspace(*tags))
     235           0 :                 tags++;
     236             : 
     237           0 :             i = 0;
     238           0 :             while (*tags != '\0' && !isspace(*tags) && *tags != ':' &&
     239             :                 i < kMaxTagLen)
     240             :             {
     241           0 :                 tagName[i++] = *tags++;
     242             :             }
     243           0 :             if (i == kMaxTagLen) {
     244             :                 TRACE("ERROR: env tag too long (%d chars max)\n", kMaxTagLen-1);
     245           0 :                 return;
     246             :             }
     247           0 :             tagName[i] = '\0';
     248             : 
     249             :             /* default priority, if there's no ":" part; also zero out '*' */
     250           0 :             minPrio = ANDROID_LOG_VERBOSE;
     251           0 :             if (tagName[0] == '*' && tagName[1] == '\0') {
     252           0 :                 minPrio = ANDROID_LOG_DEBUG;
     253           0 :                 tagName[0] = '\0';
     254             :             }
     255             : 
     256           0 :             if (*tags == ':') {
     257           0 :                 tags++;
     258           0 :                 if (*tags >= '0' && *tags <= '9') {
     259           0 :                     if (*tags >= ('0' + ANDROID_LOG_SILENT))
     260           0 :                         minPrio = ANDROID_LOG_VERBOSE;
     261             :                     else
     262           0 :                         minPrio = *tags - '\0';
     263             :                 } else {
     264           0 :                     switch (*tags) {
     265           0 :                     case 'v':   minPrio = ANDROID_LOG_VERBOSE;  break;
     266           0 :                     case 'd':   minPrio = ANDROID_LOG_DEBUG;    break;
     267           0 :                     case 'i':   minPrio = ANDROID_LOG_INFO;     break;
     268           0 :                     case 'w':   minPrio = ANDROID_LOG_WARN;     break;
     269           0 :                     case 'e':   minPrio = ANDROID_LOG_ERROR;    break;
     270           0 :                     case 'f':   minPrio = ANDROID_LOG_FATAL;    break;
     271           0 :                     case 's':   minPrio = ANDROID_LOG_SILENT;   break;
     272           0 :                     default:    minPrio = ANDROID_LOG_DEFAULT;  break;
     273             :                     }
     274             :                 }
     275             : 
     276           0 :                 tags++;
     277           0 :                 if (*tags != '\0' && !isspace(*tags)) {
     278             :                     TRACE("ERROR: garbage in tag env; expected whitespace\n");
     279             :                     TRACE("       env='%s'\n", tags);
     280           0 :                     return;
     281             :                 }
     282             :             }
     283             : 
     284           0 :             if (tagName[0] == 0) {
     285           0 :                 logState->globalMinPriority = minPrio;
     286             :                 TRACE("+++ global min prio %d\n", logState->globalMinPriority);
     287             :             } else {
     288           0 :                 logState->tagSet[entry].minPriority = minPrio;
     289           0 :                 strcpy(logState->tagSet[entry].tag, tagName);
     290             :                 TRACE("+++ entry %d: %s:%d\n",
     291             :                     entry,
     292             :                     logState->tagSet[entry].tag,
     293             :                     logState->tagSet[entry].minPriority);
     294           0 :                 entry++;
     295             :             }
     296             :         }
     297             :     }
     298             :     UNINDENTED_BLOCK_END
     299             : 
     300             :     /*
     301             :      * Taken from the long-dead utils/Log.cpp
     302             :      */
     303             :     UNINDENTED_BLOCK_START
     304           0 :     const char* fstr = getenv("ANDROID_PRINTF_LOG");
     305             :     LogFormat format;
     306           0 :     if (fstr == NULL) {
     307           0 :         format = FORMAT_BRIEF;
     308             :     } else {
     309           0 :         if (strcmp(fstr, "brief") == 0)
     310           0 :             format = FORMAT_BRIEF;
     311           0 :         else if (strcmp(fstr, "process") == 0)
     312           0 :             format = FORMAT_PROCESS;
     313           0 :         else if (strcmp(fstr, "tag") == 0)
     314           0 :             format = FORMAT_PROCESS;
     315           0 :         else if (strcmp(fstr, "thread") == 0)
     316           0 :             format = FORMAT_PROCESS;
     317           0 :         else if (strcmp(fstr, "raw") == 0)
     318           0 :             format = FORMAT_PROCESS;
     319           0 :         else if (strcmp(fstr, "time") == 0)
     320           0 :             format = FORMAT_PROCESS;
     321           0 :         else if (strcmp(fstr, "long") == 0)
     322           0 :             format = FORMAT_PROCESS;
     323             :         else
     324           0 :             format = (LogFormat) atoi(fstr);        // really?!
     325             :     }
     326             : 
     327           0 :     logState->outputFormat = format;
     328             :     UNINDENTED_BLOCK_END
     329             : }
     330             : 
     331             : /*
     332             :  * Return a human-readable string for the priority level.  Always returns
     333             :  * a valid string.
     334             :  */
     335           0 : static const char* getPriorityString(int priority)
     336             : {
     337             :     /* the first character of each string should be unique */
     338             :     static const char* priorityStrings[] = {
     339             :         "Verbose", "Debug", "Info", "Warn", "Error", "Assert"
     340             :     };
     341             :     int idx;
     342             : 
     343           0 :     idx = (int) priority - (int) ANDROID_LOG_VERBOSE;
     344           0 :     if (idx < 0 ||
     345             :         idx >= (int) (sizeof(priorityStrings) / sizeof(priorityStrings[0])))
     346           0 :         return "?unknown?";
     347           0 :     return priorityStrings[idx];
     348             : }
     349             : 
     350             : #ifndef HAVE_WRITEV
     351             : /*
     352             :  * Some platforms like WIN32 do not have writev().
     353             :  * Make up something to replace it.
     354             :  */
     355           0 : static ssize_t fake_writev(int fd, const struct iovec *iov, int iovcnt) {
     356           0 :     int result = 0;
     357           0 :     const struct iovec* end = iov + iovcnt;
     358           0 :     for (; iov < end; iov++) {
     359           0 :         int w = write(fd, iov->iov_base, iov->iov_len);
     360           0 :         if (w != iov->iov_len) {
     361           0 :             if (w < 0)
     362           0 :                 return w;
     363           0 :             return result + w;
     364             :         }
     365           0 :         result += w;
     366             :     }
     367           0 :     return result;
     368             : }
     369             : 
     370             : #define writev fake_writev
     371             : #endif
     372             : 
     373             : 
     374             : /*
     375             :  * Write a filtered log message to stderr.
     376             :  *
     377             :  * Log format parsing taken from the long-dead utils/Log.cpp.
     378             :  */
     379           0 : static void showLog(LogState *state,
     380             :         int logPrio, const char* tag, const char* msg)
     381             : {
     382             : #if defined(HAVE_LOCALTIME_R)
     383             :     struct tm tmBuf;
     384             : #endif
     385             :     struct tm* ptm;
     386             :     char timeBuf[32];
     387             :     char prefixBuf[128], suffixBuf[128];
     388             :     char priChar;
     389             :     time_t when;
     390             : #ifdef _MSC_VER
     391             :     int pid, tid;
     392             : #else
     393             :     pid_t pid, tid;
     394             : #endif
     395             : 
     396             :     TRACE("LOG %d: %s %s", logPrio, tag, msg);
     397             : 
     398           0 :     priChar = getPriorityString(logPrio)[0];
     399           0 :     when = time(NULL);
     400           0 :     pid = tid = getpid();       // find gettid()?
     401             : 
     402             :     /*
     403             :      * Get the current date/time in pretty form
     404             :      *
     405             :      * It's often useful when examining a log with "less" to jump to
     406             :      * a specific point in the file by searching for the date/time stamp.
     407             :      * For this reason it's very annoying to have regexp meta characters
     408             :      * in the time stamp.  Don't use forward slashes, parenthesis,
     409             :      * brackets, asterisks, or other special chars here.
     410             :      */
     411             : #if defined(HAVE_LOCALTIME_R)
     412           0 :     ptm = localtime_r(&when, &tmBuf);
     413             : #else
     414             :     ptm = localtime(&when);
     415             : #endif
     416             :     //strftime(timeBuf, sizeof(timeBuf), "%Y-%m-%d %H:%M:%S", ptm);
     417           0 :     strftime(timeBuf, sizeof(timeBuf), "%m-%d %H:%M:%S", ptm);
     418             : 
     419             :     /*
     420             :      * Construct a buffer containing the log header and log message.
     421             :      */
     422             :     UNINDENTED_BLOCK_START
     423             :     size_t prefixLen, suffixLen;
     424             : 
     425           0 :     switch (state->outputFormat) {
     426             :     case FORMAT_TAG:
     427           0 :         prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
     428             :             "%c/%-8s: ", priChar, tag);
     429           0 :         strcpy(suffixBuf, "\n"); suffixLen = 1;
     430           0 :         break;
     431             :     case FORMAT_PROCESS:
     432           0 :         prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
     433             :             "%c(%5d) ", priChar, pid);
     434           0 :         suffixLen = snprintf(suffixBuf, sizeof(suffixBuf),
     435             :             "  (%s)\n", tag);
     436           0 :         break;
     437             :     case FORMAT_THREAD:
     438           0 :         prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
     439             :             "%c(%5d:%5d) ", priChar, pid, tid);
     440           0 :         strcpy(suffixBuf, "\n"); suffixLen = 1;
     441           0 :         break;
     442             :     case FORMAT_RAW:
     443           0 :         prefixBuf[0] = 0; prefixLen = 0;
     444           0 :         strcpy(suffixBuf, "\n"); suffixLen = 1;
     445           0 :         break;
     446             :     case FORMAT_TIME:
     447           0 :         prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
     448             :             "%s %-8s\n\t", timeBuf, tag);
     449           0 :         strcpy(suffixBuf, "\n"); suffixLen = 1;
     450           0 :         break;
     451             :     case FORMAT_THREADTIME:
     452           0 :         prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
     453             :             "%s %5d %5d %c %-8s \n\t", timeBuf, pid, tid, priChar, tag);
     454           0 :         strcpy(suffixBuf, "\n"); suffixLen = 1;
     455           0 :         break;
     456             :     case FORMAT_LONG:
     457           0 :         prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
     458             :             "[ %s %5d:%5d %c/%-8s ]\n",
     459             :             timeBuf, pid, tid, priChar, tag);
     460           0 :         strcpy(suffixBuf, "\n\n"); suffixLen = 2;
     461           0 :         break;
     462             :     default:
     463           0 :         prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
     464             :             "%c/%-8s(%5d): ", priChar, tag, pid);
     465           0 :         strcpy(suffixBuf, "\n"); suffixLen = 1;
     466           0 :         break;
     467             :      }
     468             : 
     469             :     /*
     470             :      * Figure out how many lines there will be.
     471             :      */
     472             :     UNINDENTED_BLOCK_START
     473           0 :     const char* end = msg + strlen(msg);
     474           0 :     size_t numLines = 0;
     475           0 :     const char* p = msg;
     476           0 :     while (p < end) {
     477           0 :         if (*p++ == '\n') numLines++;
     478             :     }
     479           0 :     if (p > msg && *(p-1) != '\n') numLines++;
     480             : 
     481             :     /*
     482             :      * Create an array of iovecs large enough to write all of
     483             :      * the lines with a prefix and a suffix.
     484             :      */
     485             :     UNINDENTED_BLOCK_START
     486             :     #define INLINE_VECS 6
     487           0 :     const size_t MAX_LINES   = ((size_t)~0)/(3*sizeof(struct iovec*));
     488             :     struct iovec stackVec[INLINE_VECS];
     489           0 :     struct iovec* vec = stackVec;
     490             :     size_t numVecs;
     491             : 
     492           0 :     if (numLines > MAX_LINES)
     493           0 :         numLines = MAX_LINES;
     494             : 
     495           0 :     numVecs = numLines*3;  // 3 iovecs per line.
     496           0 :     if (numVecs > INLINE_VECS) {
     497           0 :         vec = (struct iovec*)malloc(sizeof(struct iovec)*numVecs);
     498           0 :         if (vec == NULL) {
     499           0 :             msg = "LOG: write failed, no memory";
     500           0 :             numVecs = 3;
     501           0 :             numLines = 1;
     502           0 :             vec = stackVec;
     503             :         }
     504             :     }
     505             : 
     506             :     /*
     507             :      * Fill in the iovec pointers.
     508             :      */
     509           0 :     p = msg;
     510             :     UNINDENTED_BLOCK_START
     511           0 :     struct iovec* v = vec;
     512           0 :     int totalLen = 0;
     513           0 :     while (numLines > 0 && p < end) {
     514           0 :         if (prefixLen > 0) {
     515           0 :             v->iov_base = prefixBuf;
     516           0 :             v->iov_len = prefixLen;
     517           0 :             totalLen += prefixLen;
     518           0 :             v++;
     519             :         }
     520             :         UNINDENTED_BLOCK_START
     521           0 :         const char* start = p;
     522           0 :         while (p < end && *p != '\n') p++;
     523           0 :         if ((p-start) > 0) {
     524           0 :             v->iov_base = (void*)start;
     525           0 :             v->iov_len = p-start;
     526           0 :             totalLen += p-start;
     527           0 :             v++;
     528             :         }
     529           0 :         if (*p == '\n') p++;
     530           0 :         if (suffixLen > 0) {
     531           0 :             v->iov_base = suffixBuf;
     532           0 :             v->iov_len = suffixLen;
     533           0 :             totalLen += suffixLen;
     534           0 :             v++;
     535             :         }
     536           0 :         numLines -= 1;
     537             :         UNINDENTED_BLOCK_END
     538             :     }
     539             :     
     540             :     /*
     541             :      * Write the entire message to the log file with a single writev() call.
     542             :      * We need to use this rather than a collection of printf()s on a FILE*
     543             :      * because of multi-threading and multi-process issues.
     544             :      *
     545             :      * If the file was not opened with O_APPEND, this will produce interleaved
     546             :      * output when called on the same file from multiple processes.
     547             :      *
     548             :      * If the file descriptor is actually a network socket, the writev()
     549             :      * call may return with a partial write.  Putting the writev() call in
     550             :      * a loop can result in interleaved data.  This can be alleviated
     551             :      * somewhat by wrapping the writev call in the Mutex.
     552             :      */
     553             : 
     554           0 :     for(;;) {
     555           0 :         int cc = writev(fileno(stderr), vec, v-vec);
     556             : 
     557           0 :         if (cc == totalLen) break;
     558             :         
     559           0 :         if (cc < 0) {
     560           0 :             if(errno == EINTR) continue;
     561             :             
     562             :                 /* can't really log the failure; for now, throw out a stderr */
     563           0 :             fprintf(stderr, "+++ LOG: write failed (errno=%d)\n", errno);
     564           0 :             break;
     565             :         } else {
     566             :                 /* shouldn't happen when writing to file or tty */
     567           0 :             fprintf(stderr, "+++ LOG: write partial (%d of %d)\n", cc, totalLen);
     568           0 :             break;
     569             :         }
     570             :     }
     571             : 
     572             :     /* if we allocated storage for the iovecs, free it */
     573           0 :     if (vec != stackVec)
     574           0 :         free(vec);
     575             :     UNINDENTED_BLOCK_END
     576             :     UNINDENTED_BLOCK_END
     577             :     UNINDENTED_BLOCK_END
     578             :     UNINDENTED_BLOCK_END
     579           0 : }
     580             : 
     581             : 
     582             : /*
     583             :  * Receive a log message.  We happen to know that "vector" has three parts:
     584             :  *
     585             :  *  priority (1 byte)
     586             :  *  tag (N bytes -- null-terminated ASCII string)
     587             :  *  message (N bytes -- null-terminated ASCII string)
     588             :  */
     589           0 : static ssize_t logWritev(int fd, const struct iovec* vector, int count)
     590             : {
     591             :     LogState* state;
     592             : 
     593             :     /* Make sure that no-one frees the LogState while we're using it.
     594             :      * Also guarantees that only one thread is in showLog() at a given
     595             :      * time (if it matters).
     596             :      */
     597             :     lock();
     598             : 
     599           0 :     state = fdToLogState(fd);
     600           0 :     if (state == NULL) {
     601           0 :         errno = EBADF;
     602           0 :         goto error;
     603             :     }
     604             : 
     605           0 :     if (state->isBinary) {
     606             :         TRACE("%s: ignoring binary log\n", state->debugName);
     607           0 :         goto bail;
     608             :     }
     609             : 
     610           0 :     if (count != 3) {
     611             :         TRACE("%s: writevLog with count=%d not expected\n",
     612             :             state->debugName, count);
     613           0 :         goto error;
     614             :     }
     615             : 
     616             :     /* pull out the three fields */
     617             :     UNINDENTED_BLOCK_START
     618           0 :     int logPrio = *(const char*)vector[0].iov_base;
     619           0 :     const char* tag = (const char*) vector[1].iov_base;
     620           0 :     const char* msg = (const char*) vector[2].iov_base;
     621             : 
     622             :     /* see if this log tag is configured */
     623             :     int i;
     624           0 :     int minPrio = state->globalMinPriority;
     625           0 :     for (i = 0; i < kTagSetSize; i++) {
     626           0 :         if (state->tagSet[i].minPriority == ANDROID_LOG_UNKNOWN)
     627           0 :             break;      /* reached end of configured values */
     628             : 
     629           0 :         if (strcmp(state->tagSet[i].tag, tag) == 0) {
     630             :             //TRACE("MATCH tag '%s'\n", tag);
     631           0 :             minPrio = state->tagSet[i].minPriority;
     632           0 :             break;
     633             :         }
     634             :     }
     635             : 
     636           0 :     if (logPrio >= minPrio) {
     637           0 :         showLog(state, logPrio, tag, msg);
     638             :     } else {
     639             :         //TRACE("+++ NOLOG(%d): %s %s", logPrio, tag, msg);
     640             :     }
     641             :     UNINDENTED_BLOCK_END
     642             : 
     643             : bail:
     644             :     unlock();
     645           0 :     return vector[0].iov_len + vector[1].iov_len + vector[2].iov_len;
     646             : error:
     647             :     unlock();
     648           0 :     return -1;
     649             : }
     650             : 
     651             : /*
     652             :  * Free up our state and close the fake descriptor.
     653             :  */
     654           0 : static int logClose(int fd)
     655             : {
     656           0 :     deleteFakeFd(fd);
     657           0 :     return 0;
     658             : }
     659             : 
     660             : /*
     661             :  * Open a log output device and return a fake fd.
     662             :  */
     663           0 : static int logOpen(const char* pathName, int flags)
     664             : {
     665             :     LogState *logState;
     666           0 :     int fd = -1;
     667             : 
     668             :     lock();
     669             : 
     670           0 :     logState = createLogState();
     671           0 :     if (logState != NULL) {
     672           0 :         configureInitialState(pathName, logState);
     673           0 :         fd = logState->fakeFd;
     674             :     } else  {
     675           0 :         errno = ENFILE;
     676             :     }
     677             : 
     678             :     unlock();
     679             : 
     680           0 :     return fd;
     681             : }
     682             : 
     683             : 
     684             : /*
     685             :  * Runtime redirection.  If this binary is running in the simulator,
     686             :  * just pass log messages to the emulated device.  If it's running
     687             :  * outside of the simulator, write the log messages to stderr.
     688             :  */
     689             : 
     690             : static int (*redirectOpen)(const char *pathName, int flags) = NULL;
     691             : static int (*redirectClose)(int fd) = NULL;
     692             : static ssize_t (*redirectWritev)(int fd, const struct iovec* vector, int count)
     693             :         = NULL;
     694             : 
     695           0 : static void setRedirects()
     696             : {
     697             :     const char *ws;
     698             : 
     699             :     /* Wrapsim sets this environment variable on children that it's
     700             :      * created using its LD_PRELOAD wrapper.
     701             :      */
     702           0 :     ws = getenv("ANDROID_WRAPSIM");
     703           0 :     if (ws != NULL && strcmp(ws, "1") == 0) {
     704             :         /* We're running inside wrapsim, so we can just write to the device. */
     705           0 :         redirectOpen = (int (*)(const char *pathName, int flags))open;
     706           0 :         redirectClose = close;
     707           0 :         redirectWritev = writev;
     708             :     } else {
     709             :         /* There's no device to delegate to; handle the logging ourselves. */
     710           0 :         redirectOpen = logOpen;
     711           0 :         redirectClose = logClose;
     712           0 :         redirectWritev = logWritev;
     713             :     }
     714           0 : }
     715             : 
     716           0 : int fakeLogOpen(const char *pathName, int flags)
     717             : {
     718           0 :     if (redirectOpen == NULL) {
     719           0 :         setRedirects();
     720             :     }
     721           0 :     return redirectOpen(pathName, flags);
     722             : }
     723             : 
     724           0 : int fakeLogClose(int fd)
     725             : {
     726             :     /* Assume that open() was called first. */
     727           0 :     return redirectClose(fd);
     728             : }
     729             : 
     730           0 : ssize_t fakeLogWritev(int fd, const struct iovec* vector, int count)
     731             : {
     732             :     /* Assume that open() was called first. */
     733           0 :     return redirectWritev(fd, vector, count);
     734             : }
     735             : 
     736             : #undef UNINDENTED_BLOCK_START
     737             : #undef UNINDENTED_BLOCK_END

Generated by: LCOV version 1.13