Android日志系统驱动程序Logger源代码分析


我们知道,在Android系统中,提供了一个轻量级的日志系统,这个日志系统是以驱动程序的形式实现在内核空间的,而在用户空间分别提供了Java接口和C/C++接口来使用这个日志系统,取决于你编写的是Android应用程序还是系统组件。在前面的文章浅谈Android系统开发中LOG的使用中,已经简要地介绍了在Android应用程序开发中Log的使用方法,在这一篇文章中,我们将更进一步地分析Logger驱动程序的源代码,使得我们对Android日志系统有一个深刻的认识。

既然Android 日志系统是以驱动程序的形式实现在内核空间的,我们就需要获取Android内核源代码来分析了,请参照前面在Ubuntu上下载、编译和安装Android最新源代码和在Ubuntu上下载、编译和安装Android最新内核源代码(Linux Kernel)两篇文章,下载好Android源代码工程。Logger驱动程序主要由两个文件构成,分别是:

       kernel/common/drivers/staging/android/logger.h

       kernel/common/drivers/staging/android/logger.c

       接下来,我们将分别介绍Logger驱动程序的相关数据结构,然后对Logger驱动程序源代码进行情景分析,分别日志系统初始化情景、日志读取情景和日志写入情景。

       一. Logger驱动程序的相关数据结构。

      我们首先来看logger.h头文件的内容:

  1. #ifndef _LINUX_LOGGER_H   
  2. #define _LINUX_LOGGER_H   
  3.   
  4. #include <linux/types.h>   
  5. #include <linux/ioctl.h>   
  6.   
  7. struct logger_entry {  
  8.     __u16       len;    /* length of the payload */  
  9.     __u16       __pad;  /* no matter what, we get 2 bytes of padding */  
  10.     __s32       pid;    /* generating process's pid */  
  11.     __s32       tid;    /* generating process's tid */  
  12.     __s32       sec;    /* seconds since Epoch */  
  13.     __s32       nsec;   /* nanoseconds */  
  14.     char        msg[0]; /* the entry's payload */  
  15. };  
  16.   
  17. #define LOGGER_LOG_RADIO    "log_radio" /* radio-related messages */   
  18. #define LOGGER_LOG_EVENTS   "log_events"    /* system/hardware events */   
  19. #define LOGGER_LOG_MAIN     "log_main"  /* everything else */   
  20.   
  21. #define LOGGER_ENTRY_MAX_LEN        (4*1024)   
  22. #define LOGGER_ENTRY_MAX_PAYLOAD    \   
  23.     (LOGGER_ENTRY_MAX_LEN - sizeof(struct logger_entry))  
  24.   
  25. #define __LOGGERIO  0xAE   
  26.   
  27. #define LOGGER_GET_LOG_BUF_SIZE     _IO(__LOGGERIO, 1) /* size of log */   
  28. #define LOGGER_GET_LOG_LEN      _IO(__LOGGERIO, 2) /* used log len */   
  29. #define LOGGER_GET_NEXT_ENTRY_LEN   _IO(__LOGGERIO, 3) /* next entry len */   
  30. #define LOGGER_FLUSH_LOG        _IO(__LOGGERIO, 4) /* flush log */   
  31.   
  32. #endif /* _LINUX_LOGGER_H */  
        struct logger_entry是一个用于描述一条Log记录的结构体。len成员变量记录了这条记录的有效负载的长度,有效负载指定的日志记录本身的长度,但是不包括用于描述这个记录的struct logger_entry结构体。回忆一下我们调用android.util.Log接口来使用日志系统时,会指定日志的优先级别Priority、Tag字符串以及Msg字符串,Priority + Tag + Msg三者内容的长度加起来就是记录的有效负载长度了。__pad成员变量是用来对齐结构体的。pid和tid成员变量分别用来记录是哪条进程写入了这条记录。sec和nsec成员变量记录日志写的时间。msg成员变量记录的就有效负载的内容了,它的大小由len成员变量来确定。

       接着定义两个宏:

       #define LOGGER_ENTRY_MAX_LEN             (4*1024)

       #define LOGGER_ENTRY_MAX_PAYLOAD   \

                         (LOGGER_ENTRY_MAX_LEN - sizeof(struct logger_entry))

      从这两个宏可以看出,每条日志记录的有效负载长度加上结构体logger_entry的长度不能超过4K个字节。

      logger.h文件中还定义了其它宏,读者可以自己分析,在下面的分析中,碰到时,我们也会详细解释。

      再来看logger.c文件中,其它相关数据结构的定义:

  1. /* 
  2.  * struct logger_log - represents a specific log, such as 'main' or 'radio' 
  3.  * 
  4.  * This structure lives from module insertion until module removal, so it does 
  5.  * not need additional reference counting. The structure is protected by the 
  6.  * mutex 'mutex'. 
  7.  */  
  8. struct logger_log {  
  9.     unsigned char *     buffer; /* the ring buffer itself */  
  10.     struct miscdevice   misc;   /* misc device representing the log */  
  11.     wait_queue_head_t   wq; /* wait queue for readers */  
  12.     struct list_head    readers; /* this log's readers */  
  13.     struct mutex        mutex;  /* mutex protecting buffer */  
  14.     size_t          w_off;  /* current write head offset */  
  15.     size_t          head;   /* new readers start here */  
  16.     size_t          size;   /* size of the log */  
  17. };  
  18.   
  19. /* 
  20.  * struct logger_reader - a logging device open for reading 
  21.  * 
  22.  * This object lives from open to release, so we don't need additional 
  23.  * reference counting. The structure is protected by log->mutex. 
  24.  */  
  25. struct logger_reader {  
  26.     struct logger_log * log;    /* associated log */  
  27.     struct list_head    list;   /* entry in logger_log's list */  
  28.     size_t          r_off;  /* current read head offset */  
  29. };  
  30.   
  31. /* logger_offset - returns index 'n' into the log via (optimized) modulus */  
  32. #define logger_offset(n)    ((n) & (log->size - 1))  
        结构体struct logger_log就是真正用来保存日志的地方了。buffer成员变量变是用保存日志信息的内存缓冲区,它的大小由size成员变量确定。从misc成员变量可以看出,logger驱动程序使用的设备属于misc类型的设备,通过在Android模拟器上执行cat /proc/devices命令(可参考 在Ubuntu上下载、编译和安装Android最新内核源代码(Linux Kernel) 一文),可以看出,misc类型设备的主设备号是10。关于主设备号的相关知识,可以参考Android学习启动篇一文中提到的Linux Driver Development一书。wq成员变量是一个等待队列,用于保存正在等待读取日志的进程。readers成员变量用来保存当前正在读取日志的进程,正在读取日志的进程由结构体logger_reader来描述。mutex成员变量是一个互斥量,用来保护log的并发访问。可以看出,这里的日志系统的读写问题,其实是一个生产者-消费者的问题,因此,需要互斥量来保护log的并发访问。 w_off成员变量用来记录下一条日志应该从哪里开始写。head成员变量用来表示打开日志文件中,应该从哪一个位置开始读取日志。

       结构体struct logger_reader用来表示一个读取日志的进程,log成员变量指向要读取的日志缓冲区。list成员变量用来连接其它读者进程。r_off成员变量表示当前要读取的日志在缓冲区中的位置。

       struct logger_log结构体中用于保存日志信息的内存缓冲区buffer是一个循环使用的环形缓冲区,缓冲区中保存的内容是以struct logger_entry为单位的,每个单位的组成为:

       struct logger_entry | priority | tag | msg

       由于是内存缓冲区buffer是一个循环使用的环形缓冲区,给定一个偏移值,它在buffer中的位置由下logger_offset来确定:

       #define logger_offset(n)          ((n) & (log->size - 1))

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 下一页

相关内容