android logd 原理及实现

摘要:
它用于在Android运行期间保存日志。1) 当日志进程启动并且系统启动init函数时,init.rc文件将被解析。上层应用程序(Android层)通过调用log/log/Rlog中的v/d方法打印日志。1.Android层将日志写入日志。Android层调用Log/Log/Rlog中的v/d方法来打印日志。

一、logd介绍

logd 是Android L版本提出来的概念,其作用是保存Android运行期间的log(日志)。在Android L之前,log由kernel的ring buffer 保存,在Android L之后,log保存在用户空间。

1)  logd进程启动

系统启动到init函数时会解析init.rc文件,启动logd进程和logd-reinit(重新初始化logd) 进程,init.rc文件中的相关内容如下:

onload_persist_props_action

     load_persist_props

     start logd             

     start logd-reinit

在system/core/logd中的logd.rc文件中,启动logdservice和logd-reinit service,具体内容如下:

service logd /system/bin/logd                  

    socket logd stream 0666logd logd

    socket logdr seqpacket0666 logd logd

    socket logdw dgram 0222logd logd

    group root system readproc

    writepid/dev/cpuset/system-background/tasks

service logd-reinit /system/bin/logd --reinit

    oneshot

    disabled

    writepid/dev/cpuset/system-background/tasks

注:logd-reinit只会执行一次,logd和logd-reinit都会调用system/core/logd/main.cpp中的main函数,但logd-reinit通过netlink给logd进程发送reinit命令后就会退出。

2)  logd 实现log管理

主要原理是:上层应用(Android层)通过调用Log/Slog/Rlog中的v/d方法打印log,最终log会通过netlink传递给logd,logd会将log保存在内存中(由C++中的list容器管理,后续会介绍),logcat等log获取工具同样通过netlink方式从logd获取log。

二、logd实现流程

本文主要介绍load侧的实现,对于Androidlog如何传递给logd,只做简要介绍。

1.      Android层往logd写log

Android层调用Log/Slog/Rlog中的v/d方法打印log,最终会调用到

system/core/liblog/logger_write.c 中的__android_log_buf_write函数,调用流程如下:

__android_log_buf_write

->write_to_log

           ->__write_to_log_init

                    ->__write_to_log_initialize

                             ->logdOpen

                    ->__write_to_log_daemon

                             ->logdWrite

文件最终写到 “/dev/socket/logdw”中,此时logd中的LogListener会监测到有log需写入,待log保存后,会通知LogReader将新保存的log传递给logcat等。

2.      Logd log保存机制

在system/core/lodgd/main.cpp文件的main函数中,创建了LogBuffer,LogReader,LogListener和CommandListener四个对象,

LogBuffer用于管理log;

LogReader用于将log传递给logcat;

LogListener用于监听是否有log写入logd;

CommandListener用于监听是否有命令发送给logd。

接下来介绍log的保存流程:

1)  创建LogBuffer对象,在classLogBuffer类中,定义了一个list容器,保存了指向LogBufferElement对象的指针,创建LogBuffer对象时在其构造函数中会调用LogBuffer::init()函数初始化各log域(如main/system/kernel/crash等)的大小。

2)  创建LogListener对象并开始监听

    LogListener *swl = newLogListener(logBuf, reader);

   // Backlog and /proc/sys/net/unix/max_dgram_qlen set to large value

    if(swl->startListener(600)) {
        exit(1);

          }

3)  在startListener函数中创建线程,线程注册函数为SocketListener::threadStart;

4)  执行runListener函数,如果socket监听到数据,则执行onDataAvailable函数进行处理;

5)  调用logbuf->log(LogBuffer::log),这个函数很重要,新建一个LogBufferElement对象(用于保存log),调用mLogElements.insert将LogBufferElement加入list容器,实现log的保存。

3.       

三、Logd-reinit 进程

Logd-reinit 进程在启动时,会给logd进程发送reinit命令,logd在收到命令后,会重新初始化LogBuffer。

在system/core/lodgd/main.cpp文件的main函数中会创建一个线程用于监测是否有reinit请求

if (pthread_create(&thread, &attr,reinit_thread_start, NULL))

在reinit_thread_start函数中,会重新初始化各个log区的大小,以及其他参数的初始化,但不会重新生成LogBuffer对象。相关代码如下:

//Anything that reads persist.<property>

if(logBuf) {
    logBuf->init();                     

    logBuf->initPrune(NULL);

}

四、Logd log 获取

可通过logcat工具获取logd log,logcat 相关代码所在路径:system/core/logcat

执行adb logcat 即可查看log

注:通过logcat获取的log,并不完全是按照log分类来打印的,如在KERNEL log中可能存在MAIN log。


logcat实现的大部分函数都在logcat/logcat.cpp文件中,其中__logcat函数是最重要的函数,其负责logcat 输入参数的解析以及log的处理。

logcat 最终读取log通过liblog/logd_reader.c 中的logdRead函数实现。此函数负责打开/dev/logdr,并通过socket获取log。


最近在使用logcat 获取log时,存在log丢失的情况,不知大家是否有遇到过。

调查发现,当同时启动6个线程分别获取main/kernel/system/crash/events等log时,由于启动的线程太多(即多个socket 与server 连接),导致有log丢失。


原文链接:https://blog.csdn.net/yinjian1013/article/details/78261527

免责声明:文章转载自《android logd 原理及实现》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇什么是零拷贝shell for循环 多个变量下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

记录IDEA回退,远程库未回退问题

在使用IDEA的reset时,会出现本地代码虽然回退了,但是远程代码库并未回退到对应的版本。简单说,本地回退了,远程库未回退。这时候我们就需要使用命令行操作方式了。 1、在log上找到要恢复的版本号 使用git log查看需要恢复到的版本号。拿到git log version版本号。 git log git log 2、在客户端执行如下命令(执行...

CentOS7进程管理systemd详解

  概述: 系统启动过程中,当内核启动完成,后加载根文件系统,后就绪的一些用户空间的服务的管理工作,就交由init进行启动和管理,在CentOS6之前的init的管理方式都类似,相关的内容我们在之前的文章中也做出过介绍。在CentOS7上,init变成了systemd,其管理方式也发生了重大的变化,本章就跟大家欧一起探讨一些关于CentOS7上的sys...

SourceTree使用教程详解(连接远程仓库,克隆,拉取,提交,推送,新建/切换/合并分支,冲突解决)

前言:   俗话说的好工欲善其事必先利其器,Git分布式版本控制系统是我们日常开发中不可或缺的。目前市面上比较流行的Git可视化管理工具有SourceTree、Github Desktop、TortoiseGit,综合网上的一些文章分析和自己的日常开发实践心得个人比较推荐开发者使用SourceTree,因为SourceTree同时支持Windows和Mac...

删除或重命名文件夹和文件的方法

删除或重命名文件夹和文件的办法 一、Linux、CentOS下重命名文件和文件夹mv:move 用移动文件命令就可以了,因为linux系统没有专门的重命名命令。基本格式:移动文件:mv 文件名 移动目的地文件名重命名文件:mv 文件名 修改后的文件名示例:mv oldfilename newfilename (oldfilename为旧文件名,newfil...

Android——bootchart

bootchart:android原生自带的开机性能查看机制。通过收集android开机过程中的各种log数据,终于能够图表的形式展现各个进程在开机过程中的性能。(博客不能断…) 撰写不易,转载需注明出处:http://blog.csdn.net/jscese/article/details/45933943本文来自 【jscese】的博客。 编译boo...

三、文件的操作、函数、类和对象

一、文件 文件的打开与关闭 在python,使用open函数,可以打开一个已经存在的文件,或者创建一个新文件 open(文件名,访问模式) 示例如下: f = open('test.txt', 'w') 说明: 访问模式 说明 r 以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。 w 打开一个文件只用于写入。如果该文件已存...