zoukankan      html  css  js  c++  java
  • android logd 原理及实现

    一、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

  • 相关阅读:
    Java线程九:线程的调度-让步
    Java线程八:线程的调度-优先级
    Java线程七:线程的调度-休眠
    Java线程六:线程的交互
    丸の内の霊 5
    丸の内の霊 4
    丸の内の例 3
    丸の内の例 2
    幽霊物件 1
    質問力 D
  • 原文地址:https://www.cnblogs.com/aspirs/p/14697676.html
Copyright © 2011-2022 走看看