这篇博客分析的是logcat是如何获取logd中的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的。

更多相关文章

  1. 第十三篇 Android(安卓)系统电话管理机制与架构二
  2. android获取网络图片的用法 BitmapFactory.decodeByteArray 返回
  3. Android(安卓)自定义adapter的getView中的ViewGroup parent的宽
  4. 浅析Android下的Android.mk文件(三)
  5. web app 第三方登录-微博登录(二)
  6. (一)、Android底层开发实战之基础知识
  7. android根目录获取
  8. Android(安卓)NDK开发 Cmake环境调用 so文件
  9. Android——Fragment的静态注册和动态注册(含源码下载)

随机推荐

  1. android客户端和php服务简单交互
  2. Fragment和ViewPager的介绍和使用
  3. android 服务概述 本地服务示例
  4. Android简单修改原有应用和添加应用的方
  5. 【Android】界面布局之 LinearLayout(线
  6. 谷歌官方Android应用架构库(Android Archi
  7. 如何自学Android编程——Android自学资料
  8. Android原生开发、H5、React-Native之间
  9. 光学识别信用卡阅读器Card.io终于发布And
  10. Android netd和Framework以及netd和kerne