贵阳市聚信天下网络科技有限公司
首页 | 联系方式 | 加入收藏 | 设为首页 | 手机站

产品目录

联系方式

联系人:业务部
电话: 00130-882723
邮箱:service@szshijibodd.com

当前位置:首页 >> 产品展示 >> 默认分类 >> 正文

Logcat源码分析(五)

详细信息:

四、输出日志设备文件的内容
从前面的分析中看出,最终日志设备文件内容的输出是通过logcat.cpp文件的printNextEntry函数进行的:
static void printNextEntry(log_device_t* dev) {
maybePrintStart(dev);
if (g_printBinary) {
printBinary(&dev->queue->entry);
} else {
processBuffer(dev, &dev->queue->entry);
}
skipNextEntry(dev);
}
g_printBinary为true时,以二进制方式输出日志内容到指定的文件中:
void printBinary(struct logger_entry *buf)
{
size_t size = sizeof(logger_entry) + buf->len;
int ret;
do {
ret = write(g_outFD, buf, size);
} while (ret < 0 && errno == EINTR);
}
g_printBinary为false的情况,调用processBuffer进一步处理
static void processBuffer(log_device_t* dev, struct logger_entry *buf)
{
int bytesWritten = 0;
int err;
AndroidLogEntry entry;
char binaryMsgBuf[1024];
if (dev->binary) {
err = Android_log_processBinaryLogBuffer(buf, &entry, g_eventTagMap,
binaryMsgBuf, sizeof(binaryMsgBuf));
//printf(">>> pri=%d len=%d msg='%s'\n",
// entry.priority, entry.messageLen, entry.message);
} else {
err = Android_log_processLogBuffer(buf, &entry);
}
if (err < 0) {
goto error;
}
if (Android_log_shouldPrintLine(g_logformat, entry.tag, entry.priority)) {
if (false && g_devCount > 1) {
binaryMsgBuf[0] = dev->label;
binaryMsgBuf[1] = ' ';
bytesWritten = write(g_outFD, binaryMsgBuf, 2);
if (bytesWritten < 0) {
perror("output error");
exit(-1);
}
}
bytesWritten = Android_log_printLogLine(g_logformat, g_outFD, &entry);
if (bytesWritten < 0) {
perror("output error");
exit(-1);
}
}
g_outByteCount += bytesWritten;
if (g_logRotateSizeKBytes > 0
&& (g_outByteCount / 1024) >= g_logRotateSizeKBytes
) {
rotateLogs();
}
error:
//fprintf (stderr, "Error processing record\n");
return;
}
当dev->binary为true,日志记录项是二进制形式,不同于我们在《Logger详解》文中提到的常规格式:
logger_entry + priority + tag + msg
这里我们不关注这种情况,有兴趣的读者可以自已分析,Android_log_processBinaryLogBuffer函数定义在system/core/liblog/logprint.c文件中,它的作用是将一条二进制形式的日志记录转换为ASCII形式,并保存在entry参数中,它的原型为
/**
* Convert a binary log entry to ASCII form.
*
* For convenience we mimic the processLogBuffer API. There is no
* pre-defined output length for the binary data, since we're free to format
* it however we choose, which means we can't really use a fixed-size buffer
* here.
*/
int Android_log_processBinaryLogBuffer(struct logger_entry *buf,
AndroidLogEntry *entry, const EventTagMap* map, char* messageBuf,
int messageBufLen);
通常情况下,dev->binary为false,调用Android_log_processLogBuffer函数将日志记录由logger_entry格式转换为AndroidLogEntry格式。logger_entry格式在在 《Logger详解》一文中已经有详细描述,这里不述。
AndroidLogEntry结构体定义在system/core/include/cutils/logprint.h中:
typedef struct AndroidLogEntry_t {
time_t tv_sec;
long tv_nsec;
Android_LogPriority priority;
pid_t pid;
pthread_t tid;
const char * tag;
size_t messageLen;
const char * message;
} AndroidLogEntry;
Android_LogPriority是一个枚举类型,定义在system/core/include/android/log.h文件中:
/*
* Android log priority values, in ascending priority order.
*/
typedef enum Android_LogPriority {
Android_LOG_UNKNOWN = 0,
Android_LOG_DEFAULT, /* only for SetMinPriority() */
Android_LOG_VERBOSE,
Android_LOG_DEBUG,
Android_LOG_INFO,
Android_LOG_WARN,
Android_LOG_ERROR,
Android_LOG_FATAL,
Android_LOG_SILENT, /* only for SetMinPriority(); must be last */
} Android_LogPriority;
Android_log_processLogBuffer定义在system/core/liblog/logprint.c文件中:
/**
* Splits a wire-format buffer into an AndroidLogEntry
* entry allocated by caller. Pointers will point directly into buf
*
* Returns 0 on success and -1 on invalid wire format (entry will be
* in unspecified state)
*/
int Android_log_processLogBuffer(struct logger_entry *buf,
AndroidLogEntry *entry)
{
size_t tag_len;
entry->tv_sec = buf->sec;
entry->tv_nsec = buf->nsec;
entry->priority = buf->msg[0];
entry->pid = buf->pid;
entry->tid = buf->tid;
entry->tag = buf->msg + 1;
tag_len = strlen(entry->tag);
entry->messageLen = buf->len - tag_len - 3;
entry->message = entry->tag + tag_len + 1;
return 0;
}
结合logger_entry结构体中日志项的格式定义(logger_entry + priority + tag + msg),这个函数很直观,不再累述。
调用完Android_log_processLogBuffer函数后,日志记录的具体信息就保存在本地变量entry中了,接着调用android_log_shouldPrintLine函数来判断这条日志记录是否应该输出。
在分析Android_log_shouldPrintLine函数之前,我们先了解数据结构AndroidLogFormat,这个结构体定义在system/core/liblog/logprint.c文件中:
struct AndroidLogFormat_t {
Android_LogPriority global_pri;
FilterInfo *filters;
AndroidLogPrintFormat format;
};
AndroidLogPrintFormat和FilterInfo_t也是定义在system/core/liblog/logprint.c文件中:
/**
* Returns FORMAT_OFF on invalid string
*/
AndroidLogPrintFormat android_log_formatFromString(const char * formatString)
{
static AndroidLogPrintFormat format;

if (strcmp(formatString, "brief") == 0) format = FORMAT_BRIEF;
else if (strcmp(formatString, "process") == 0) format = FORMAT_PROCESS;
else if (strcmp(formatString, "tag") == 0) format = FORMAT_TAG;
else if (strcmp(formatString, "thread") == 0) format = FORMAT_THREAD;
else if (strcmp(formatString, "raw") == 0) format = FORMAT_RAW;
else if (strcmp(formatString, "time") == 0) format = FORMAT_TIME;
else if (strcmp(formatString, "threadtime") == 0) format = FORMAT_THREADTIME;
else if (strcmp(formatString, "long") == 0) format = FORMAT_LONG;
else format = FORMAT_OFF;

return format;
}
typedef struct FilterInfo_t {
char *mTag;
Android_LogPriority mPri;
struct FilterInfo_t *p_next;
} FilterInfo;
因此,可以看出,AndroidLogFormat结构体定义了日志过滤规范。在logcat.c文件中,定义了变量
static AndroidLogFormat * g_logformat;
这个变量是在main函数里面进行分配的:
g_logformat = Android_log_format_new();
在main函数里面,在分析logcat命令行参数时,会将g_logformat进行初始化,有兴趣的读者可以自行分析。
回到Android_log_shouldPrintLine函数中,它定义在system/core