天天看点

android log机制

1、linux内核的log输出

   在标准的linux内核开发过程中,使用 printk ,这是一个与printf输出打印齐名的函数,同样提供格式化输出功能,只是其有

   打印级别且将信息保存到 /proc/kmsg 日志中,使用cat命令查看其信息[cat  /proc/kmsg]

[cpp]  view plain  copy

  1. <span style="font-size:14px;color:#003333;">#define KERN_EMERG  "<0>"         
  2. #define KERN_ALERT  "<1>"         
  3. #define KERN_CRIT   "<2>"         
  4. #deinfe KERN_ERR    "<3>"         
  5. #deinfe KERN_WARNING    "<4>"         
  6. #deinfe KERN_NOTICE "<5>"         
  7. #deinfe KERN_INFO   "<6>"         
  8. #deinfe KERN_DEBUG  "<7>"       </span>  

2、android中log输出

Android系统在用户空间中提供了轻量级的logger日志系统,它是在内核中实现的一种设备驱动,与用户空间的logcat工具配合使用能够方便地跟踪调试程序。

Android系统中的C/C++日志接口是通过宏来使用的。在system/core/include/android/log.h定义了日志的级别:

typedef enum android_LogPriority {

   ANDROID_LOG_UNKNOWN = 0,

   ANDROID_LOG_DEFAULT,    

   ANDROID_LOG_VERBOSE,

   ANDROID_LOG_DEBUG,

   ANDROID_LOG_INFO,

   ANDROID_LOG_WARN,

   ANDROID_LOG_ERROR,

   ANDROID_LOG_FATAL,

   ANDROID_LOG_SILENT,    

} android_LogPriority;

为了使用方便,在system/core/include/cutils/log.h定义了相对应的宏:

#define LOGV(...) ((void)LOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__))

#define LOGD(...) ((void)LOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__))

#define LOGI(...) ((void)LOG(LOG_INFO, LOG_TAG, __VA_ARGS__))

#define LOGW(...) ((void)LOG(LOG_WARN, LOG_TAG, __VA_ARGS__))

#define LOGE(...) ((void)LOG(LOG_ERROR, LOG_TAG, __VA_ARGS__))

因为如果需要使用log输出,包含其头文件:#include <cutils/log.h> 并link其动态库:liblog.so 即可

#define LOG_TAG "XX_LOG_TAG" // 这里可以定义其输出的TAG

    #include <cutils/log.h>

   JAVA层打印:

   import android.util.Log;

   private static final String TAG = "XX_LOG_TAG";

   Log.e(TAG, "This is the error log printed by Log.i in android user space.");

内核代码路径:

kernel/drivers/staging/android/logger.h

kernel/drivers/staging/android/logger.c

1、Logger驱动程序的相关数据结构

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

[cpp]  view plain  copy

  1. #ifndef _LINUX_LOGGER_H  
  2. #define _LINUX_LOGGER_H  
  3. #include <linux/types.h>  
  4. #include <linux/ioctl.h>  
  5. struct logger_entry {  
  6.     __u16       len;      
  7.     __u16       __pad;    
  8.     __s32       pid;      
  9.     __s32       tid;      
  10.     __s32       sec;      
  11.     __s32       nsec;     
  12.     char        msg[0];   
  13. };  
  14. #define LOGGER_LOG_RADIO    "log_radio"   
  15. #define LOGGER_LOG_EVENTS   "log_events"      
  16. #define LOGGER_LOG_SYSTEM   "log_system"      
  17. #define LOGGER_LOG_MAIN     "log_main"    
  18. #define LOGGER_ENTRY_MAX_LEN        (4*1024)  
  19. #define LOGGER_ENTRY_MAX_PAYLOAD    \  
  20.     (LOGGER_ENTRY_MAX_LEN - sizeof(struct logger_entry))  
  21. #define __LOGGERIO  0xAE  
  22. #define LOGGER_GET_LOG_BUF_SIZE     _IO(__LOGGERIO, 1)   
  23. #define LOGGER_GET_LOG_LEN      _IO(__LOGGERIO, 2)   
  24. #define LOGGER_GET_NEXT_ENTRY_LEN   _IO(__LOGGERIO, 3)   
  25. #define LOGGER_FLUSH_LOG        _IO(__LOGGERIO, 4)   
  26. #endif   

struct logger_entry是一个用于描述一条Log记录的结构体。

其中len成员变量记录了这条记录的有效负载的长度,有效负载指定的日志记录本身的长度,但是不包括用于描述这个记录的struct logger_entry结构体。

从struct logger_entry中也可以看出:优先级别Priority、Tag字符串以及Msg字符串,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.c实现文件:

[cpp]  view plain  copy

  1. struct logger_log {  
  2.     unsigned char       *buffer;  
  3.     struct miscdevice   misc;     
  4.     wait_queue_head_t   wq;   
  5.     struct list_head    readers;   
  6.     struct mutex        mutex;    
  7.     size_t          w_off;    
  8.     size_t          head;     
  9.     size_t          size;     
  10. };  

  结构体struct logger_log就是真正用来保存日志的地方了。buffer成员变量变是用保存日志信息的内存缓冲区,它的大小由size成员变量确定。

 buffer是一个循环使用的环形缓冲区,缓冲区中保存的内容是以struct logger_entry为单位的,其组成方式是:

struct logger_entry | priority | tag | msg

  • truct logger_reader {  
  • struct logger_log   *log;     
  • struct list_head    list;     
  • size_t          r_off;    
  • ;