📄 fake_log_device.c
字号:
/* * Copyright (C) 2008 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *//* * Intercepts log messages intended for the Android log device. * When running in the context of the simulator, the messages are * passed on to the underlying (fake) log device. When not in the * simulator, messages are printed to stderr. */#include "cutils/logd.h"#include <stdlib.h>#include <string.h>#include <ctype.h>#include <errno.h>#include <fcntl.h>#ifdef HAVE_PTHREADS#include <pthread.h>#endif#define kMaxTagLen 16 /* from the long-dead utils/Log.cpp */#define kTagSetSize 16 /* arbitrary */#if 0#define TRACE(...) printf("fake_log_device: " __VA_ARGS__)#else#define TRACE(...) ((void)0)#endif/* from the long-dead utils/Log.cpp */typedef enum { FORMAT_OFF = 0, FORMAT_BRIEF, FORMAT_PROCESS, FORMAT_TAG, FORMAT_THREAD, FORMAT_RAW, FORMAT_TIME, FORMAT_THREADTIME, FORMAT_LONG} LogFormat;/* * Log driver state. */typedef struct LogState { /* the fake fd that's seen by the user */ int fakeFd; /* a printable name for this fake device */ char *debugName; /* nonzero if this is a binary log */ int isBinary; /* global minimum priority */ int globalMinPriority; /* output format */ LogFormat outputFormat; /* tags and priorities */ struct { char tag[kMaxTagLen]; int minPriority; } tagSet[kTagSetSize];} LogState;#ifdef HAVE_PTHREADS/* * Locking. Since we're emulating a device, we need to be prepared * to have multiple callers at the same time. This lock is used * to both protect the fd list and to prevent LogStates from being * freed out from under a user. */static pthread_mutex_t fakeLogDeviceLock = PTHREAD_MUTEX_INITIALIZER;static void lock(){ pthread_mutex_lock(&fakeLogDeviceLock);}static void unlock(){ pthread_mutex_unlock(&fakeLogDeviceLock);}#else // !HAVE_PTHREADS#define lock() ((void)0)#define unlock() ((void)0)#endif // !HAVE_PTHREADS/* * File descriptor management. */#define FAKE_FD_BASE 10000#define MAX_OPEN_LOGS 16static LogState *openLogTable[MAX_OPEN_LOGS];/* * Allocate an fd and associate a new LogState with it. * The fd is available via the fakeFd field of the return value. */static LogState *createLogState(){ size_t i; for (i = 0; i < sizeof(openLogTable); i++) { if (openLogTable[i] == NULL) { openLogTable[i] = calloc(1, sizeof(LogState)); openLogTable[i]->fakeFd = FAKE_FD_BASE + i; return openLogTable[i]; } } return NULL;}/* * Translate an fd to a LogState. */static LogState *fdToLogState(int fd){ if (fd >= FAKE_FD_BASE && fd < FAKE_FD_BASE + MAX_OPEN_LOGS) { return openLogTable[fd - FAKE_FD_BASE]; } return NULL;}/* * Unregister the fake fd and free the memory it pointed to. */static void deleteFakeFd(int fd){ LogState *ls; lock(); ls = fdToLogState(fd); if (ls != NULL) { openLogTable[fd - FAKE_FD_BASE] = NULL; free(ls->debugName); free(ls); } unlock();}/* * Configure logging based on ANDROID_LOG_TAGS environment variable. We * need to parse a string that looks like * * *:v jdwp:d dalvikvm:d dalvikvm-gc:i dalvikvmi:i * * The tag (or '*' for the global level) comes first, followed by a colon * and a letter indicating the minimum priority level we're expected to log. * This can be used to reveal or conceal logs with specific tags. * * We also want to check ANDROID_PRINTF_LOG to determine how the output * will look. */static void configureInitialState(const char* pathName, LogState* logState){ static const int kDevLogLen = sizeof("/dev/log/") - 1; logState->debugName = strdup(pathName); /* identify binary logs */ if (strcmp(pathName + kDevLogLen, "events") == 0) { logState->isBinary = 1; } /* global min priority defaults to "info" level */ logState->globalMinPriority = ANDROID_LOG_INFO; /* * This is based on the the long-dead utils/Log.cpp code. */ const char* tags = getenv("ANDROID_LOG_TAGS"); TRACE("Found ANDROID_LOG_TAGS='%s'\n", tags); if (tags != NULL) { int entry = 0; while (*tags != '\0') { char tagName[kMaxTagLen]; int i, minPrio; while (isspace(*tags)) tags++; i = 0; while (*tags != '\0' && !isspace(*tags) && *tags != ':' && i < kMaxTagLen) { tagName[i++] = *tags++; } if (i == kMaxTagLen) { TRACE("ERROR: env tag too long (%d chars max)\n", kMaxTagLen-1); return; } tagName[i] = '\0'; /* default priority, if there's no ":" part; also zero out '*' */ minPrio = ANDROID_LOG_VERBOSE; if (tagName[0] == '*' && tagName[1] == '\0') { minPrio = ANDROID_LOG_DEBUG; tagName[0] = '\0'; } if (*tags == ':') { tags++; if (*tags >= '0' && *tags <= '9') { if (*tags >= ('0' + ANDROID_LOG_SILENT)) minPrio = ANDROID_LOG_VERBOSE; else minPrio = *tags - '\0'; } else { switch (*tags) { case 'v': minPrio = ANDROID_LOG_VERBOSE; break; case 'd': minPrio = ANDROID_LOG_DEBUG; break; case 'i': minPrio = ANDROID_LOG_INFO; break; case 'w': minPrio = ANDROID_LOG_WARN; break; case 'e': minPrio = ANDROID_LOG_ERROR; break; case 'f': minPrio = ANDROID_LOG_FATAL; break; case 's': minPrio = ANDROID_LOG_SILENT; break; default: minPrio = ANDROID_LOG_DEFAULT; break; } } tags++; if (*tags != '\0' && !isspace(*tags)) { TRACE("ERROR: garbage in tag env; expected whitespace\n"); TRACE(" env='%s'\n", tags); return; } } if (tagName[0] == 0) { logState->globalMinPriority = minPrio; TRACE("+++ global min prio %d\n", logState->globalMinPriority); } else { logState->tagSet[entry].minPriority = minPrio; strcpy(logState->tagSet[entry].tag, tagName); TRACE("+++ entry %d: %s:%d\n", entry, logState->tagSet[entry].tag, logState->tagSet[entry].minPriority); entry++; } } } /* * Taken from the long-dead utils/Log.cpp */ const char* fstr = getenv("ANDROID_PRINTF_LOG"); LogFormat format; if (fstr == NULL) { format = FORMAT_BRIEF; } else { if (strcmp(fstr, "brief") == 0) format = FORMAT_BRIEF; else if (strcmp(fstr, "process") == 0) format = FORMAT_PROCESS; else if (strcmp(fstr, "tag") == 0) format = FORMAT_PROCESS; else if (strcmp(fstr, "thread") == 0) format = FORMAT_PROCESS; else if (strcmp(fstr, "raw") == 0) format = FORMAT_PROCESS; else if (strcmp(fstr, "time") == 0) format = FORMAT_PROCESS; else if (strcmp(fstr, "long") == 0) format = FORMAT_PROCESS; else format = (LogFormat) atoi(fstr); // really?! } logState->outputFormat = format;}/* * Return a human-readable string for the priority level. Always returns * a valid string. */static const char* getPriorityString(int priority){ /* the first character of each string should be unique */ static const char* priorityStrings[] = { "Verbose", "Debug", "Info", "Warn", "Error", "Assert" }; int idx; idx = (int) priority - (int) ANDROID_LOG_VERBOSE; if (idx < 0 || idx >= (int) (sizeof(priorityStrings) / sizeof(priorityStrings[0]))) return "?unknown?"; return priorityStrings[idx];}#ifndef HAVE_WRITEV/* * Some platforms like WIN32 do not have writev(). * Make up something to replace it. */static ssize_t fake_writev(int fd, const struct iovec *iov, int iovcnt) { int result = 0; struct iovec* end = iov + iovcnt; for (; iov < end; iov++) { int w = write(fd, iov->iov_base, iov->iov_len); if (w != iov->iov_len) { if (w < 0) return w; return result + w; } result += w; } return result;}#define writev fake_writev#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -