Android的Logger日志系統是基於內核中的Logger日志驅動程序實現的。
日志保存在內核空間中
緩沖區保存日志
分類方法:日志的類型 + 日志的輸出量
日志類型: main sysytem radio events
以上四種日志分別通過以下四個設備文件來訪問:
/dev/log/main
/dev/log/system
.../radio
.../events
Android系統在應用中提供了三個 Java接口,往Logger日志驅動程序中寫入日志,分別對應main, system, event:
android.util.Log
android.util.Slog
android.util.EventLog
Logger日志驅動程序
基礎數據結構
Logger主要用到了logger_entry logger_log logger_reader三個結構體。
struct logger_entry {
__u16 len; /* length of the payload */
__u16 hdr_size; /* sizeof(struct logger_entry_v2) */
__s32 pid; /* generating process's pid */
__s32 tid; /* generating process's tid */
__s32 sec; /* seconds since Epoch */
__s32 nsec; /* nanoseconds */
uid_t euid; /* effective UID of logger */
char msg[0]; /* the entry's payload */
};
------------------------------------------------------------------
struct logger_log {
unsigned char *buffer; /* the ring buffer itself 保存內容*/
struct miscdevice misc; /* misc device representing the log 日志設備*/
wait_queue_head_t wq; /* wait queue for readers */
struct list_head readers; /* this log's readers */
struct mutex mutex; /* mutex protecting buffer */
size_t w_off; /* current write head offset */
size_t head; /* new readers start here */
size_t size; /* size of the log */
}
-------------------------------------------------------------------------------------------------------
struct logger_reader {
struct logger_log *log; /* associated log */
struct list_head list; /* entry in logger_log's list */
size_t r_off; /* current read head offset */
bool r_all; /* reader can read all entries */
int r_ver; /* reader ABI version */
};
日志設備的初始化過程
日志設備的初始化:
入口函數:logger_init
日志設備的打開,讀取, 寫入, 分別對應:logger_open, logger_read, logger_aio_write.
初始化過程:
注冊日志設備 kernel/goldfish/drivers/staging/android/logger.c init_log
將日志設備注冊到系統中: init_log中調用misc_register函數
在misc_register中調用device_create函數注冊到系統中
在設備的/dev目錄下看到/dev/log/main, .../events, .../radio
日志設備文件的打開過程
日志驅動程序的讀寫之前,都需要先打開日志設備文件。日志設備文件的打開函數為looger_open:
kernel/goldfish/drivers/statging/android/logger.c logger_open()
get_log_from_minor根據從設備號獲取日志緩沖區
日志記錄的讀取過程
進程調用read函數,從日志設備中讀取日志記錄
logger_read被調用:
do_read_log_to_user:
/*
* First, copy the header to userspace, using the version of
* the header requested
*/
/*
* We read from the msg in two disjoint operations. First, we read from
* the current msg head offset up to 'count' bytes or to the end of
* the log, whichever comes first.
*/
/*
* Second, we read any remaining bytes, starting back at the head of
* the log.
*/
運行時庫層日志

write_to_log
函數指針write_to_log第一次被調用的時候,便執行函數__write_to_log_init來初始化日志庫liblog。
- 日志初始化過程(__write_to_log_init函數):
- 如果 write_to_log 指向__write_to_log_init
執行打開日志設備文件/log/main,.../radio, .../events, .../system到相應的log-fds數組中。
write_to_log指向__write_to_log_kernel
- 如果main, radio, events日志設備文件其中一個沒有打開成功
關閉日志文件/log/main,.../radio, .../event,並將write_to_log指向__write_to_log_null
- 如果system日志設備文件沒有打開
將system和main的日志記錄全都寫入到日志設備文件/dev/log/main中
- __write_to_log_kernel函數
根據參數log_id在全局數組log_fds中找到對應的日志設備文件描述符,
把日志記錄寫入到Logger日志驅動程序中
__write_to_log_null
該函數什么也不做
__android_log_write
默認情況下,日志記錄類型為main。如果參數日志標簽以“RIL”開頭或HTC_RIL、AT、GSM、STK、CDMA、PHONE、SMS,日志類型則為radio。
__android_log_buf_write
該函數的實現和__android_log_write類似,不過可以指定寫入日志記錄的類型。
__android_log_vprint __android_log_print __android_log_assert
這三個函數都是調用__android_log_write日志驅動程序寫入日志記錄的。
__android_log_bWrite __android_log_btwrite
這兩個函數寫入的日志記錄的類型為events。其中,函數__android_log_bwrite寫入的日志記錄的內容尅有由多個值組成,而后者只能寫入一個值。
C/C++日志寫入接口
logv logd logi logw loge用來寫入類型為main的日志記錄
slogv slogd slogi slogw sloge用來寫入類型為system的日志記錄
log_event_int log_event_long long_event_string用來寫入類型為events的日志記錄
Java日志寫入接口
...