fake_log_device.c
来自「Android 一些工具」· C语言 代码 · 共 678 行 · 第 1/2 页
C
678 行
/* * Write a filtered log message to stderr. * * Log format parsing taken from the long-dead utils/Log.cpp. */static void showLog(LogState *state, int logPrio, const char* tag, const char* msg){#if defined(HAVE_LOCALTIME_R) struct tm tmBuf;#endif struct tm* ptm; char timeBuf[32]; char prefixBuf[128], suffixBuf[128]; char priChar; time_t when; pid_t pid, tid; TRACE("LOG %d: %s %s", logPrio, tag, msg); priChar = getPriorityString(logPrio)[0]; when = time(NULL); pid = tid = getpid(); // find gettid()? /* * Get the current date/time in pretty form * * It's often useful when examining a log with "less" to jump to * a specific point in the file by searching for the date/time stamp. * For this reason it's very annoying to have regexp meta characters * in the time stamp. Don't use forward slashes, parenthesis, * brackets, asterisks, or other special chars here. */#if defined(HAVE_LOCALTIME_R) ptm = localtime_r(&when, &tmBuf);#else ptm = localtime(&when);#endif //strftime(timeBuf, sizeof(timeBuf), "%Y-%m-%d %H:%M:%S", ptm); strftime(timeBuf, sizeof(timeBuf), "%m-%d %H:%M:%S", ptm); /* * Construct a buffer containing the log header and log message. */ size_t prefixLen, suffixLen; switch (state->outputFormat) { case FORMAT_TAG: prefixLen = snprintf(prefixBuf, sizeof(prefixBuf), "%c/%-8s: ", priChar, tag); strcpy(suffixBuf, "\n"); suffixLen = 1; break; case FORMAT_PROCESS: prefixLen = snprintf(prefixBuf, sizeof(prefixBuf), "%c(%5d) ", priChar, pid); suffixLen = snprintf(suffixBuf, sizeof(suffixBuf), " (%s)\n", tag); break; case FORMAT_THREAD: prefixLen = snprintf(prefixBuf, sizeof(prefixBuf), "%c(%5d:%p) ", priChar, pid, (void*)tid); strcpy(suffixBuf, "\n"); suffixLen = 1; break; case FORMAT_RAW: prefixBuf[0] = 0; prefixLen = 0; strcpy(suffixBuf, "\n"); suffixLen = 1; break; case FORMAT_TIME: prefixLen = snprintf(prefixBuf, sizeof(prefixBuf), "%s %-8s\n\t", timeBuf, tag); strcpy(suffixBuf, "\n"); suffixLen = 1; break; case FORMAT_THREADTIME: prefixLen = snprintf(prefixBuf, sizeof(prefixBuf), "%s %5d %5d %c %-8s \n\t", timeBuf, pid, tid, priChar, tag); strcpy(suffixBuf, "\n"); suffixLen = 1; break; case FORMAT_LONG: prefixLen = snprintf(prefixBuf, sizeof(prefixBuf), "[ %s %5d:%p %c/%-8s ]\n", timeBuf, pid, (void*)tid, priChar, tag); strcpy(suffixBuf, "\n\n"); suffixLen = 2; break; default: prefixLen = snprintf(prefixBuf, sizeof(prefixBuf), "%c/%-8s(%5d): ", priChar, tag, pid); strcpy(suffixBuf, "\n"); suffixLen = 1; break; } /* * Figure out how many lines there will be. */ const char* end = msg + strlen(msg); size_t numLines = 0; const char* p = msg; while (p < end) { if (*p++ == '\n') numLines++; } if (p > msg && *(p-1) != '\n') numLines++; /* * Create an array of iovecs large enough to write all of * the lines with a prefix and a suffix. */ const size_t INLINE_VECS = 6; struct iovec stackVec[INLINE_VECS]; struct iovec* vec = stackVec; numLines *= 3; // 3 iovecs per line. if (numLines > INLINE_VECS) { vec = (struct iovec*)malloc(sizeof(struct iovec)*numLines); if (vec == NULL) { msg = "LOG: write failed, no memory"; numLines = 3; } } /* * Fill in the iovec pointers. */ p = msg; struct iovec* v = vec; int totalLen = 0; while (p < end) { if (prefixLen > 0) { v->iov_base = prefixBuf; v->iov_len = prefixLen; totalLen += prefixLen; v++; } const char* start = p; while (p < end && *p != '\n') p++; if ((p-start) > 0) { v->iov_base = (void*)start; v->iov_len = p-start; totalLen += p-start; v++; } if (*p == '\n') p++; if (suffixLen > 0) { v->iov_base = suffixBuf; v->iov_len = suffixLen; totalLen += suffixLen; v++; } } /* * Write the entire message to the log file with a single writev() call. * We need to use this rather than a collection of printf()s on a FILE* * because of multi-threading and multi-process issues. * * If the file was not opened with O_APPEND, this will produce interleaved * output when called on the same file from multiple processes. * * If the file descriptor is actually a network socket, the writev() * call may return with a partial write. Putting the writev() call in * a loop can result in interleaved data. This can be alleviated * somewhat by wrapping the writev call in the Mutex. */ for(;;) { int cc = writev(fileno(stderr), vec, v-vec); if (cc == totalLen) break; if (cc < 0) { if(errno == EINTR) continue; /* can't really log the failure; for now, throw out a stderr */ fprintf(stderr, "+++ LOG: write failed (errno=%d)\n", errno); break; } else { /* shouldn't happen when writing to file or tty */ fprintf(stderr, "+++ LOG: write partial (%d of %d)\n", cc, totalLen); break; } } /* if we allocated storage for the iovecs, free it */ if (vec != stackVec) free(vec);}/* * Receive a log message. We happen to know that "vector" has three parts: * * priority (1 byte) * tag (N bytes -- null-terminated ASCII string) * message (N bytes -- null-terminated ASCII string) */static ssize_t logWritev(int fd, const struct iovec* vector, int count){ LogState* state; /* Make sure that no-one frees the LogState while we're using it. * Also guarantees that only one thread is in showLog() at a given * time (if it matters). */ lock(); state = fdToLogState(fd); if (state == NULL) { errno = EBADF; goto error; } if (state->isBinary) { TRACE("%s: ignoring binary log\n", state->debugName); goto bail; } if (count != 3) { TRACE("%s: writevLog with count=%d not expected\n", state->debugName, count); goto error; } /* pull out the three fields */ int logPrio = *(const char*)vector[0].iov_base; const char* tag = (const char*) vector[1].iov_base; const char* msg = (const char*) vector[2].iov_base; /* see if this log tag is configured */ int i; int minPrio = state->globalMinPriority; for (i = 0; i < kTagSetSize; i++) { if (state->tagSet[i].minPriority == ANDROID_LOG_UNKNOWN) break; /* reached end of configured values */ if (strcmp(state->tagSet[i].tag, tag) == 0) { //TRACE("MATCH tag '%s'\n", tag); minPrio = state->tagSet[i].minPriority; break; } } if (logPrio >= minPrio) { showLog(state, logPrio, tag, msg); } else { //TRACE("+++ NOLOG(%d): %s %s", logPrio, tag, msg); }bail: unlock(); return vector[0].iov_len + vector[1].iov_len + vector[2].iov_len;error: unlock(); return -1;}/* * Free up our state and close the fake descriptor. */static int logClose(int fd){ deleteFakeFd(fd); return 0;}/* * Open a log output device and return a fake fd. */static int logOpen(const char* pathName, int flags){ LogState *logState; int fd = -1; lock(); logState = createLogState(); if (logState != NULL) { configureInitialState(pathName, logState); fd = logState->fakeFd; } else { errno = ENFILE; } unlock(); return fd;}/* * Runtime redirection. If this binary is running in the simulator, * just pass log messages to the emulated device. If it's running * outside of the simulator, write the log messages to stderr. */static int (*redirectOpen)(const char *pathName, int flags) = NULL;static int (*redirectClose)(int fd) = NULL;static ssize_t (*redirectWritev)(int fd, const struct iovec* vector, int count) = NULL;static void setRedirects(){ const char *ws; /* Wrapsim sets this environment variable on children that it's * created using its LD_PRELOAD wrapper. */ ws = getenv("ANDROID_WRAPSIM"); if (ws != NULL && strcmp(ws, "1") == 0) { /* We're running inside wrapsim, so we can just write to the device. */ redirectOpen = (int (*)(const char *pathName, int flags))open; redirectClose = close; redirectWritev = writev; } else { /* There's no device to delegate to; handle the logging ourselves. */ redirectOpen = logOpen; redirectClose = logClose; redirectWritev = logWritev; }}int fakeLogOpen(const char *pathName, int flags){ if (redirectOpen == NULL) { setRedirects(); } return redirectOpen(pathName, flags);}int fakeLogClose(int fd){ /* Assume that open() was called first. */ return redirectClose(fd);}ssize_t fakeLogWritev(int fd, const struct iovec* vector, int count){ /* Assume that open() was called first. */ return redirectWritev(fd, vector, count);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?