android 6.0 logcat机制(二)logcat从logd中获取log保存到文件中
2016-04-06 18:45
1006 查看
这篇博客分析的是logcat是如何获取logd中的log,然后写入文件。
/system/bin/logcat -r 5120 -v threadtime -v usec -v printable -n 5 -f /data/local/log/logcat.log
/system/bin/logcat -r 5120 -v threadtime -v usec -v printable -n 5 -b radio -f /data/local/log/logcat-radio.log
/system/bin/logcat -r 5120 -v threadtime -v usec -v printable -n 5 -b events -f /data/local/log/logcat-events.log
我们先看下logcat的如何对这个命令的实现的,在其main函数中,对f命令的实现如下:
把文件名保存在g_outputFileName了,然后在main函数后面会调用setupOutput函数,我们来看下这个函数:
在这个函数中把文件的fd获取到了,是g_outFD。
最后我们可以在printBinary函数中往这个文件中写值。
也可以通过processBuffer来往文件写log。我们最后应该是通过processBuffer来写log的。
也就是上面的命令最终会把log保存在/data/local/log/logcat-radio.log文件下,当然这只是radio的log。
打印的话就是通过之前传进来的文件,写log到该文件的fd。
android_logger_list_read函数就是通过socket连接logd获取log。
int android_logger_list_read(struct logger_list *logger_list,
struct log_msg *log_msg)
{
int ret, e;
struct logger *logger;
struct sigaction ignore;
struct sigaction old_sigaction;
unsigned int old_alarm = 0;
if (!logger_list) {
return -EINVAL;
}
if (logger_list->mode & ANDROID_LOG_PSTORE) {
return android_logger_list_read_pstore(logger_list, log_msg);
}
if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
memset(&ignore, 0, sizeof(ignore));
ignore.sa_handler = caught_signal;
sigemptyset(&ignore.sa_mask);
}
if (logger_list->sock < 0) {
char buffer[256], *cp, c;
int sock = socket_local_client("logdr",
ANDROID_SOCKET_NAMESPACE_RESERVED,
SOCK_SEQPACKET);
if (sock < 0) {
if ((sock == -1) && errno) {
return -errno;
}
return sock;
}上面logdr就是logcat到logd的socket。
/system/bin/logcat -r 5120 -v threadtime -v usec -v printable -n 5 -f /data/local/log/logcat.log
/system/bin/logcat -r 5120 -v threadtime -v usec -v printable -n 5 -b radio -f /data/local/log/logcat-radio.log
/system/bin/logcat -r 5120 -v threadtime -v usec -v printable -n 5 -b events -f /data/local/log/logcat-events.log
是通过节点来实现,而不是通过socket到logd实现的
节点:
dev/log/main
dev/log/radio
dev/log/system
dev/log/events
下篇博客我们主要说下logd是如何处理logcat的请求读log的。
一、设置保存log文件的路径
在手机刚开机的时候,会有类似如下命令执行/system/bin/logcat -r 5120 -v threadtime -v usec -v printable -n 5 -f /data/local/log/logcat.log
/system/bin/logcat -r 5120 -v threadtime -v usec -v printable -n 5 -b radio -f /data/local/log/logcat-radio.log
/system/bin/logcat -r 5120 -v threadtime -v usec -v printable -n 5 -b events -f /data/local/log/logcat-events.log
我们先看下logcat的如何对这个命令的实现的,在其main函数中,对f命令的实现如下:
case 'f': if ((tail_time == log_time::EPOCH) && (tail_lines != 0)) { tail_time = lastLogTime(optarg); } // redirect output to a file g_outputFileName = optarg;
把文件名保存在g_outputFileName了,然后在main函数后面会调用setupOutput函数,我们来看下这个函数:
static void setupOutput() { if (g_outputFileName == NULL) { g_outFD = STDOUT_FILENO; } else { if (set_sched_policy(0, SP_BACKGROUND) < 0) { fprintf(stderr, "failed to set background scheduling policy\n"); } struct sched_param param; memset(¶m, 0, sizeof(param)); if (sched_setscheduler((pid_t) 0, SCHED_BATCH, ¶m) < 0) { fprintf(stderr, "failed to set to batch scheduler\n"); } if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND) < 0) { fprintf(stderr, "failed set to priority\n"); } g_outFD = openLogFile (g_outputFileName);//得到了fd if (g_outFD < 0) { logcat_panic(false, "couldn't open output file"); } struct stat statbuf; if (fstat(g_outFD, &statbuf) == -1) { close(g_outFD); logcat_panic(false, "couldn't get output file stat\n"); } if ((size_t) statbuf.st_size > SIZE_MAX || statbuf.st_size < 0) { close(g_outFD); logcat_panic(false, "invalid output file stat\n"); } g_outByteCount = statbuf.st_size; } }
在这个函数中把文件的fd获取到了,是g_outFD。
最后我们可以在printBinary函数中往这个文件中写值。
void printBinary(struct log_msg *buf) { size_t size = buf->len(); TEMP_FAILURE_RETRY(write(g_outFD, buf, size)); }
也可以通过processBuffer来往文件写log。我们最后应该是通过processBuffer来写log的。
也就是上面的命令最终会把log保存在/data/local/log/logcat-radio.log文件下,当然这只是radio的log。
二、logcat获取logd中的log
而我们再看logcat的main最后是一个死循环,一直调用android_logger_list_read来从logd中获取log,然后再打印。while (1) { struct log_msg log_msg; log_device_t* d; int ret = android_logger_list_read(logger_list, &log_msg);//调用android_logger_list_read获取log if (ret == 0) { logcat_panic(false, "read: unexpected EOF!\n"); } if (ret < 0) { if (ret == -EAGAIN) { break; } if (ret == -EIO) { logcat_panic(false, "read: unexpected EOF!\n"); } if (ret == -EINVAL) { logcat_panic(false, "read: unexpected length.\n"); } logcat_panic(false, "logcat read failure"); } for(d = devices; d; d = d->next) { if (android_name_to_log_id(d->device) == log_msg.id()) { break; } } if (!d) { g_devCount = 2; // set to Multiple d = &unexpected; d->binary = log_msg.id() == LOG_ID_EVENTS; } if (dev != d) { dev = d; maybePrintStart(dev, printDividers); } if (g_printBinary) { printBinary(&log_msg); } else { processBuffer(dev, &log_msg); } } android_logger_list_free(logger_list); return EXIT_SUCCESS;
打印的话就是通过之前传进来的文件,写log到该文件的fd。
android_logger_list_read函数就是通过socket连接logd获取log。
int android_logger_list_read(struct logger_list *logger_list,
struct log_msg *log_msg)
{
int ret, e;
struct logger *logger;
struct sigaction ignore;
struct sigaction old_sigaction;
unsigned int old_alarm = 0;
if (!logger_list) {
return -EINVAL;
}
if (logger_list->mode & ANDROID_LOG_PSTORE) {
return android_logger_list_read_pstore(logger_list, log_msg);
}
if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
memset(&ignore, 0, sizeof(ignore));
ignore.sa_handler = caught_signal;
sigemptyset(&ignore.sa_mask);
}
if (logger_list->sock < 0) {
char buffer[256], *cp, c;
int sock = socket_local_client("logdr",
ANDROID_SOCKET_NAMESPACE_RESERVED,
SOCK_SEQPACKET);
if (sock < 0) {
if ((sock == -1) && errno) {
return -errno;
}
return sock;
}上面logdr就是logcat到logd的socket。
三、总结
3.1 开3个进程保存不同log
我们手机上会开3个logcat进程来保存log,这3个进程会一直开着就是上面的死循环来不断保存log。/system/bin/logcat -r 5120 -v threadtime -v usec -v printable -n 5 -f /data/local/log/logcat.log
/system/bin/logcat -r 5120 -v threadtime -v usec -v printable -n 5 -b radio -f /data/local/log/logcat-radio.log
/system/bin/logcat -r 5120 -v threadtime -v usec -v printable -n 5 -b events -f /data/local/log/logcat-events.log
3.2 kernel相关log
另外kernel的log是通过log_read_kern.c中的函数来实现的,而写的话通过logd_write_kern.c来实现的。是通过节点来实现,而不是通过socket到logd实现的
节点:
dev/log/main
dev/log/radio
dev/log/system
dev/log/events
下篇博客我们主要说下logd是如何处理logcat的请求读log的。
相关文章推荐
- android 6.0 logcat机制(一)java层写log,logd接受log
- 使用logcat命令增加logd白名单 黑名单
- 基于Android N的Log机制浅析 下篇
- 基于Android N的Log机制浅析 上篇
- android 6.0 logcat机制(三)logd处理请求log
- 学习笔记:Android里JSON解析的几种方法
- Android 四大组件之ContentProvider工作原理
- Android Studio Unable to start the daemo process,Gradle报错
- android中的@{} @+id ?/attr
- android 热修补之andfix实践
- android 热修补之andfix实践
- android 热修补之andfix实践
- LayoutInflater.inflate()方法的ViewGroup参数问题
- Android热补丁动态修复技术(二):实战!CLASS_ISPREVERIFIED问题!
- android crash log 分析[精确地址查询]
- Android-耗电量测试
- Android初试--Android中的BroadcastReceiver(2)
- android popupWindow使用
- Android应用层View绘制流程与源码分析,性能优化
- textview、edittext下划线边框,以及圆弧边框的添加