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 + -
显示快捷键?