Android架構分析之LOG模塊

Android的LOG模塊分為內核驅動部分和用戶空間接口部分。

 

一、內核LOG模塊分析

 

我們先來看內核驅動部分,其代碼位於drivers/staging/android/logger.c文件中。按照分析Linux內核驅動程序的慣例,我們從模塊初始化函數開始分析:

[cpp]  588static int __init logger_init(void) 
589{                                                              
590    int ret; 
591 
592    ret =init_log(&log_main); 
593    if (unlikely(ret)) 
594        goto out; 
595 
596    ret =init_log(&log_events); 
597    if (unlikely(ret)) 
598        goto out; 
599 
600    ret =init_log(&log_radio); 
601    if (unlikely(ret)) 
602        goto out; 
603 
604out: 
605    return ret; 
606} 
607device_initcall(logger_init); 

588static int __init logger_init(void)
589{                                                            
590    int ret;
591
592    ret =init_log(&log_main);
593    if (unlikely(ret))
594        goto out;
595
596    ret =init_log(&log_events);
597    if (unlikely(ret))
598        goto out;
599
600    ret =init_log(&log_radio);
601    if (unlikely(ret))
602        goto out;
603
604out:
605    return ret;
606}
607device_initcall(logger_init);
logger_init函數即是LOG模塊初始化函數,其調用瞭3次init_log函數,註冊瞭log_main,log_events,log_radio三個LOG設備,init_log函數定義如下:

[cpp]  571static int __init init_log(struct logger_log *log) 
572{ 
573    int ret; 
574 
575    ret =misc_register(&log->misc); 
576    if (unlikely(ret)) { 
577        printk(KERN_ERR"logger: failed to register misc " 
578               "device forlog '%s'!\n", log->misc.name); 
579        return ret; 
580    } 
581 
582    printk(KERN_INFO"logger: created %luK log '%s'\n", 
583           (unsigned long)log->size >> 10, log->misc.name); 
584 
585    return 0; 
586} 

571static int __init init_log(struct logger_log *log)
572{
573    int ret;
574
575    ret =misc_register(&log->misc);
576    if (unlikely(ret)) {
577        printk(KERN_ERR"logger: failed to register misc "
578               "device forlog '%s'!\n", log->misc.name);
579        return ret;
580    }
581
582    printk(KERN_INFO"logger: created %luK log '%s'\n",
583           (unsigned long)log->size >> 10, log->misc.name);
584
585    return 0;
586}
575行,調用misc_register函數,註冊misc設備。

init_log函數的參數是logger_log結構體類型,該類型代表一個LOG設備,其定義如下:

[cpp]  30/*
31 * struct logger_log -represents a specific log, such as 'main' or 'radio'
32 *
33 * This structure lives frommodule insertion until module removal, so it does
34 * not need additionalreference counting. The structure is protected by the
35 * mutex 'mutex'.
36 */ 
37struct logger_log { 
38    unsigned char *     buffer; /* the ring buffer itself */ 
39    struct miscdevice   misc;  /* misc device representing the log */ 
40    wait_queue_head_t   wq; /* wait queue for readers */ 
41    struct list_head    readers; /* this log's readers */ 
42    struct mutex        mutex; /* mutex protecting buffer */ 
43    size_t          w_off;  /* current write head offset */ 
44    size_t          head;   /* new readers start here */ 
45    size_t          size;   /* size of the log */ 
46}; 

 30/*
 31 * struct logger_log -represents a specific log, such as 'main' or 'radio'
 32 *
 33 * This structure lives frommodule insertion until module removal, so it does
 34 * not need additionalreference counting. The structure is protected by the
 35 * mutex 'mutex'.
 36 */
 37struct logger_log {
 38    unsigned char *     buffer; /* the ring buffer itself */
 39    struct miscdevice   misc;  /* misc device representing the log */
 40    wait_queue_head_t   wq; /* wait queue for readers */
 41    struct list_head    readers; /* this log's readers */
 42    struct mutex        mutex; /* mutex protecting buffer */
 43    size_t          w_off;  /* current write head offset */
 44    size_t          head;   /* new readers start here */
 45    size_t          size;   /* size of the log */
 46};
log_main,log_events,log_radio三個LOG設備都是logger_log結構體類型的變量,其定義如下:

[cpp]  533/*
534 * Defines a log structure with name 'NAME' and a size of 'SIZE'bytes, which
535 * must be a power of two, greater than LOGGER_ENTRY_MAX_LEN, andless than
536 * LONG_MAX minus LOGGER_ENTRY_MAX_LEN.
537 */ 
538#define DEFINE_LOGGER_DEVICE(VAR, NAME, SIZE) \ 
539static unsigned char _buf_ ## VAR[SIZE]; \ 
540static struct logger_log VAR = { \ 
541    .buffer = _buf_ ## VAR, \ 
542    .misc = { \ 
543        .minor =MISC_DYNAMIC_MINOR, \ 
544        .name = NAME, \ 
545        .fops =&logger_fops, \ 
546        .parent = NULL, \ 
547    }, \ 
548    .wq =__WAIT_QUEUE_HEAD_INITIALIZER(VAR .wq), \ 
549    .readers = LIST_HEAD_INIT(VAR.readers), \ 
550    .mutex =__MUTEX_INITIALIZER(VAR .mutex), \ 
551    .w_off = 0, \ 
552    .head = 0, \ 
553    .size = SIZE, \ 
554}; 
555 
556DEFINE_LOGGER_DEVICE(log_main, LOGGER_LOG_MAIN, 64*1024) 
557DEFINE_LOGGER_DEVICE(log_events, LOGGER_LOG_EVENTS, 256*1024) 
558DEFINE_LOGGER_DEVICE(log_radio, LOGGER_LOG_RADIO, 64*1024) 

533/*
534 * Defines a log structure with name 'NAME' and a size of 'SIZE'bytes, which
535 * must be a power of two, greater than LOGGER_ENTRY_MAX_LEN, andless than
536 * LONG_MAX minus LOGGER_ENTRY_MAX_LEN.
537 */
538#define DEFINE_LOGGER_DEVICE(VAR, NAME, SIZE) \
539static unsigned char _buf_ ## VAR[SIZE]; \
540static struct logger_log VAR = { \
541    .buffer = _buf_ ## VAR, \
542    .misc = { \
543        .minor =MISC_DYNAMIC_MINOR, \
544        .name = NAME, \
545        .fops =&logger_fops, \
546        .parent = NULL, \
547    }, \
548    .wq =__WAIT_QUEUE_HEAD_INITIALIZER(VAR .wq), \
549    .readers = LIST_HEAD_INIT(VAR.readers), \
550    .mutex =__MUTEX_INITIALIZER(VAR .mutex), \
551    .w_off = 0, \
552    .head = 0, \
553    .size = SIZE, \
554};
555
556DEFINE_LOGGER_DEVICE(log_main, LOGGER_LOG_MAIN, 64*1024)
557DEFINE_LOGGER_DEVICE(log_events, LOGGER_LOG_EVENTS, 256*1024)
558DEFINE_LOGGER_DEVICE(log_radio, LOGGER_LOG_RADIO, 64*1024)
在drivers/staging/android/logger.h文件中,有如下定義:

[cpp]  33#define LOGGER_LOG_RADIO   "log_radio" /* radio-related messages */ 
34#define LOGGER_LOG_EVENTS  "log_events"    /*system/hardware events */ 
35#define LOGGER_LOG_MAIN    "log_main"  /*everything else */ 

33#define LOGGER_LOG_RADIO   "log_radio" /* radio-related messages */
34#define LOGGER_LOG_EVENTS  "log_events"    /*system/hardware events */
35#define LOGGER_LOG_MAIN    "log_main"  /*everything else */
由上面代碼的註釋,可以理解log_main,log_events,log_radio三種LOG設備的作用。

綜合以上分析,可知在LOG模塊初始化函數logger_init中,以misc設備類型註冊瞭3個LOG設備log_main,log_events和log_radio,分別對應/dev/log/main,/dev/log/events,/dev/log/radio,應用空間程序就可以通過對這三個設備進行讀寫操作與LOG內核驅動模塊交互。

 

由DEFINE_LOGGER_DEVICE 宏定義可知,LOG設備的操作函數集被設置為logger_fops,其定義如下:

[cpp]  522static struct file_operations logger_fops = { 
523    .owner = THIS_MODULE, 
524    .read = logger_read, 
525    .aio_write =logger_aio_write, 
526    .poll = logger_poll, 
527    .unlocked_ioctl =logger_ioctl, 
528    .compat_ioctl =logger_ioctl, 
529    .open = logger_open, 
530    .release = logger_release, 
531}; 

522static struct file_operations logger_fops = {
523    .owner = THIS_MODULE,
524    .read = logger_read,
525    .aio_write =logger_aio_write,
526    .poll = logger_poll,
527    .unlocked_ioctl =logger_ioctl,
528    .compat_ioctl =logger_ioctl,
529    .open = logger_open,
530    .release = logger_release,
531};
我們先來看open函數:

[cpp]  384/*
385 * logger_open – the log's open() file operation
386 *
387 * Note how near a no-op this is in the write-only case. Keep it thatway!
388 */ 
389static int logger_open(struct inode *inode, struct file *file) 
390{ 
391    struct logger_log *log; 
392    int ret; 
393 
394    ret =nonseekable_open(inode, file); 
395    if (ret) 
396        return ret; 
397 
398    log =get_log_from_minor(MINOR(inode->i_rdev)); 
399    if (!log) 
400        return -ENODEV; 
401 
402    if (file->f_mode &FMODE_READ) { 
403        struct logger_reader*reader; 
404 
405        reader =kmalloc(sizeof(struct logger_reader), GFP_KERNEL); 
406        if (!reader) 
407            return -ENOMEM; 
408 
409        reader->log = log; 
410       INIT_LIST_HEAD(&reader->list); 
411 
412       mutex_lock(&log->mutex); 
413        reader->r_off =log->head; 
414       list_add_tail(&reader->list, &log->readers); 
415       mutex_unlock(&log->mutex); 
416 
417        file->private_data =reader; 
418    } else 
419        file->private_data =log; 
420 
421    return 0; 
422} 
423 

384/*
385 * logger_open – the log's open() file operation
386 *
387 * Note how near a no-op this is in the write-only case. Keep it thatway!
388 */
389static int logger_open(struct inode *inode, struct file *file)
390{
391    struct logger_log *log;
392    int ret;
393
394    ret =nonseekable_open(inode, file);
395    if (ret)
396        return ret;
397
398    log =get_log_from_minor(MINOR(inode->i_rdev));
399    if (!log)
400        return -ENODEV;
401
402    if (file->f_mode &FMODE_READ) {
403        struct logger_reader*reader;
404
405        reader =kmalloc(sizeof(struct logger_reader), GFP_KERNEL);
406        if (!reader)
407            return -ENOMEM;
408
409        reader->log = log;
410       INIT_LIST_HEAD(&reader->list);
411
412       mutex_lock(&log->mutex);
413        reader->r_off =log->head;
414       list_add_tail(&reader->list, &log->readers);
415       mutex_unlock(&log->mutex);
416
417        file->private_data =reader;
418    } else
419        file->private_data =log;
420
421    return 0;
422}
423
398行,調用get_log_from_minor函數,通過次設備號來取得對應的logger_log結構體變量。該函數定義如下:

[cpp]  560static struct logger_log * get_log_from_minor(int minor) 
561{ 
562    if (log_main.misc.minor ==minor) 
563        return &log_main; 
564    if (log_events.misc.minor== minor) 
565        return &log_events; 
566    if (log_radio.misc.minor ==minor) 
567        return &log_radio; 
568    return NULL; 
569} 

560static struct logger_log * get_log_from_minor(int minor)
561{
562    if (log_main.misc.minor ==minor)
563        return &log_main;
564    if (log_events.misc.minor== minor)
565        return &log_events;
566    if (log_radio.misc.minor ==minor)
567        return &log_radio;
568    return NULL;
569}
回到logger_open函數,402-418行,如果打開的LOG設備是可讀的,創建一個logger_reader結構體變量,並初始化。logger_reader結構體代表被打開進行讀操作的LOG設備,其定義如下:

[cpp]  48/*
49 * struct logger_reader – alogging device open for reading
50 *
51 * This object lives from opento release, so we don't need additional
52 * reference counting. Thestructure is protected by log->mutex.
53 */ 
54struct logger_reader { 
55    struct logger_log * log;    /* associated log */ 
56    struct list_head    list;  /* entry in logger_log's list */ 
57    size_t          r_off;  /* current read head offset */ 
58}; 

 48/*
 49 * struct logger_reader – alogging device open for reading
 50 *
 51 * This object lives from opento release, so we don't need additional
 52 * reference counting. Thestructure is protected by log->mutex.
 53 */
 54struct logger_reader {
 55    struct logger_log * log;    /* associated log */
 56    struct list_head    list;  /* entry in logger_log's list */
 57    size_t          r_off;  /* current read head offset */
 58};
下面我們來看read函數:

[cpp] 143/*
144 * logger_read – our log's read() method
145 *
146 * Behavior:
147 *
148 *  – O_NONBLOCK works
149 *  – If there are no logentries to read, blocks until log is written to
150 *  – Atomically reads exactlyone log entry
151 *
152 * Optimal read size is LOGGER_ENTRY_MAX_LEN. Will set errno toEINVAL if read
153 * buffer is insufficient to hold next entry.
154 */ 
155static ssize_t logger_read(struct file *file, char __user *buf, 
156               size_t count,loff_t *pos) 
157{ 
158    struct logger_reader*reader = file->private_data; 
159    struct logger_log *log =reader->log; 
160    ssize_t ret; 
161    DEFINE_WAIT(wait); 
162 
163start: 
164    while (1) { 
165       prepare_to_wait(&log->wq, &wait, TASK_INTERRUPTIBLE); 
166 
167        mutex_lock(&log->mutex); 
168        ret = (log->w_off ==reader->r_off); 
169       mutex_unlock(&log->mutex); 
170        if (!ret) 
171            break; 
172 
173        if (file->f_flags& O_NONBLOCK) { 
174            ret = -EAGAIN; 
175            break; 
176        } 
177 
178        if(signal_pending(current)) { 
179            ret = -EINTR; 
180            break; 
181        } 
182 
183        schedule(); 
184    } 
185 
186   finish_wait(&log->wq, &wait); 
187    if (ret) 
188        return ret; 
189 
190   mutex_lock(&log->mutex); 
191 
192    /* is there still somethingto read or did we race? */ 
193    if (unlikely(log->w_off== reader->r_off)) { 
194       mutex_unlock(&log->mutex); 
195        goto start; 
196    } 
197 
198    /* get the size of the nextentry */ 
199    ret = get_entry_len(log,reader->r_off); 
200    if (count < ret) { 
201        ret = -EINVAL; 
202        goto out; 
203    } 
204 
205    /* get exactly one entryfrom the log */ 
206    ret =do_read_log_to_user(log, reader, buf, ret); 
207 
208out: 
209   mutex_unlock(&log->mutex); 
210 
211    return ret; 
212} 

143/*
144 * logger_read – our log's read() method
145 *
146 * Behavior:
147 *
148 *  – O_NONBLOCK works
149 *  – If there are no logentries to read, blocks until log is written to
150 *  – Atomically reads exactlyone log entry
151 *
152 * Optimal read size is LOGGER_ENTRY_MAX_LEN. Will set errno toEINVAL if read
153 * buffer is insufficient to hold next entry.
154 */
155static ssize_t logger_read(struct file *file, char __user *buf,
156               size_t count,loff_t *pos)
157{
158    struct logger_reader*reader = file->private_data;
159    struct logger_log *log =reader->log;
160    ssize_t ret;
161    DEFINE_WAIT(wait);
162
163start:
164    while (1) {
165       prepare_to_wait(&log->wq, &wait, TASK_INTERRUPTIBLE);
166
167        mutex_lock(&log->mutex);
168        ret = (log->w_off ==reader->r_off);
169       mutex_unlock(&log->mutex);
170        if (!ret)
171            break;
172
173        if (file->f_flags& O_NONBLOCK) {
174            ret = -EAGAIN;
175            break;
176        }
177
178        if(signal_pending(current)) {
179            ret = -EINTR;
180            break;
181        }
182
183        schedule();
184    }
185
186   finish_wait(&log->wq, &wait);
187    if (ret)
188        return ret;
189
190   mutex_lock(&log->mutex);
191
192    /* is there still somethingto read or did we race? */
193    if (unlikely(log->w_off== reader->r_off)) {
194       mutex_unlock(&log->mutex);
195        goto start;
196    }
197
198    /* get the size of the nextentry */
199    ret = get_entry_len(log,reader->r_off);
200    if (count < ret) {
201        ret = -EINVAL;
202        goto out;
203    }
204
205    /* get exactly one entryfrom the log */
206    ret =do_read_log_to_user(log, reader, buf, ret);
207
208out:
209   mutex_unlock(&log->mutex);
210
211    return ret;
212}
164-184行,這個while循環是用來處理如果沒有LOG可讀,則進入休眠等待。但是如果文件打開時被設置為非阻塞模式O_NONBLOCK或者有信號需要處理signal_pending(current),則不休眠等待,直接返回。

LOG內容保存在一個循環緩沖區中,代碼中通過log->w_off == reader->r_off判斷是否有LOG可讀。

198-203行,如果有LOG可讀,則調用get_entry_len函數取得下一條LOG的長度(LOG的長度包括loger_entry結構體的大小和有效負載payload的長度),該函數定義如下:

[cpp]  86/*
 87 * get_entry_len – Grabs thelength of the payload of the next entry starting
 88 * from 'off'.
 89 *
 90 * Caller needs to holdlog->mutex.
 91 */ 
 92static __u32get_entry_len(struct logger_log *log, size_t off) 
 93{ 
 94    __u16 val; 
 95 
 96    switch (log->size – off) { 
 97    case 1: 
 98        memcpy(&val, log->buffer + off,1); 
 99        memcpy(((char *) &val) + 1,log->buffer, 1); 
100        break; 
101    default: 
102        memcpy(&val,log->buffer + off, 2); 
103    } 
104 
105    return sizeof(structlogger_entry) + val; 
106} 

86/*
 87 * get_entry_len – Grabs thelength of the payload of the next entry starting
 88 * from 'off'.
 89 *
 90 * Caller needs to holdlog->mutex.
 91 */
 92static __u32get_entry_len(struct logger_log *log, size_t off)
 93{
 94    __u16 val;
 95
 96    switch (log->size – off) {
 97    case 1:
 98        memcpy(&val, log->buffer + off,1);
 99        memcpy(((char *) &val) + 1,log->buffer, 1);
100        break;
101    default:
102        memcpy(&val,log->buffer + off, 2);
103    }
104
105    return sizeof(structlogger_entry) + val;
106}
LOG緩沖區中的每一條LOG由兩部分組成,一是用於描述LOG信息的logger_entry結構體,二是LOG本身,又稱為payload。在drivers/staging/android/logger.h文件中,logger_entry結構體定義如下:

[cpp] 23struct logger_entry { 
24    __u16       len;   /* length of the payload */ 
25    __u16       __pad; /* no matter what, we get 2 bytes of padding */ 
26    __s32       pid;   /* generating process's pid */ 
27    __s32       tid;   /* generating process's tid */ 
28    __s32       sec;   /* seconds since Epoch */ 
29    __s32       nsec;  /* nanoseconds */ 
30    char        msg[0]; /* the entry's payload */ 
31}; 

23struct logger_entry {
24    __u16       len;   /* length of the payload */
25    __u16       __pad; /* no matter what, we get 2 bytes of padding */
26    __s32       pid;   /* generating process's pid */
27    __s32       tid;   /* generating process's tid */
28    __s32       sec;   /* seconds since Epoch */
29    __s32       nsec;  /* nanoseconds */
30    char        msg[0]; /* the entry's payload */
31};
get_entry_len函數用於取得整個LOG的長度,包括logger_entry結構體大小和payload的長度,logger_entry的大小是固定的,關鍵是怎樣取得payload的長度。

payload的長度記錄在logger_entry第一個成員len中,16位,占2個字節。因為LOG緩沖區是一個循環緩沖區,所以這2個字節存放的位置有一種特殊情況是,第一個字節在最後一個位置,第二個字節在第一個位置。所以在get_entry_len函數的實現中,分兩種情況處理,case 1就是分別拷貝第一個字節和第二個字節到val變量中,其它的情況都是直接將2個節的內容拷貝到val變量中。

最後,註意get_entry_len函數的105行,返回值是sizeof(struct logger_entry) + val,即我們前面所說的,返回logger_entry結構體的大小加上payload的長度。

 

回到logger_read函數,206行,調用do_read_log_to_user函數,該函數真正將LOG信息讀到用戶空間,定義如下:

[cpp] 08/*
109 * do_read_log_to_user – reads exactly 'count' bytes from 'log' intothe
110 * user-space buffer 'buf'. Returns 'count' on success.
111 *
112 * Caller must hold log->mutex.
113 */ 
114static ssize_t do_read_log_to_user(struct logger_log *log, 
115                   structlogger_reader *reader, 
116                   char __user*buf, 
117                   size_tcount) 
118{ 
119    size_t len; 
120 
121    /*
122     * We read from the log intwo disjoint operations. First, we read from
123     * the current read headoffset up to 'count' bytes or to the end of
124     * the log, whichever comesfirst.
125     */ 
126    len = min(count, log->size- reader->r_off); 
127    if (copy_to_user(buf,log->buffer + reader->r_off, len)) 
128        return -EFAULT; 
129 
130    /*
131     * Second, we read anyremaining bytes, starting back at the head of
132     * the log.
133     */ 
134    if (count != len) 
135        if (copy_to_user(buf +len, log->buffer, count – len)) 
136            return -EFAULT; 
137 
138    reader->r_off =logger_offset(reader->r_off + count); 
139 
140    return count; 
141} 

108/*
109 * do_read_log_to_user – reads exactly 'count' bytes from 'log' intothe
110 * user-space buffer 'buf'. Returns 'count' on success.
111 *
112 * Caller must hold log->mutex.
113 */
114static ssize_t do_read_log_to_user(struct logger_log *log,
115                   structlogger_reader *reader,
116                   char __user*buf,
117                   size_tcount)
118{
119    size_t len;
120
121    /*
122     * We read from the log intwo disjoint operations. First, we read from
123     * the current read headoffset up to 'count' bytes or to the end of
124     * the log, whichever comesfirst.
125     */
126    len = min(count, log->size- reader->r_off);
127    if (copy_to_user(buf,log->buffer + reader->r_off, len))
128        return -EFAULT;
129
130    /*
131     * Second, we read anyremaining bytes, starting back at the head of
132     * the log.
133     */
134    if (count != len)
135        if (copy_to_user(buf +len, log->buffer, count – len))
136            return -EFAULT;
137
138    reader->r_off =logger_offset(reader->r_off + count);
139
140    return count;
141}
因為LOG保存在循環緩沖區中,所以do_read_log_to_user函數考慮到這種情況,分兩步通過copy_to_user函數拷貝LOG到用戶空間。

最後註意138行,通過logger_offset宏設置下一次的讀取位置。該宏定義如下:

[cpp]  60/* logger_offset- returns index 'n' into the log via (optimized) modulus */ 
61#define logger_offset(n)    ((n) & (log->size – 1)) 

 60/* logger_offset- returns index 'n' into the log via (optimized) modulus */
 61#define logger_offset(n)    ((n) & (log->size – 1))
下面我們來看LOG模塊的write函數:

[cpp]  317/*
318 * logger_aio_write – our write method, implementing support forwrite(),
319 * writev(), and aio_write(). Writes are our fast path, and we try tooptimize
320 * them above all else.
321 */ 
322ssize_t logger_aio_write(struct kiocb *iocb, const struct iovec *iov, 
323             unsigned longnr_segs, loff_t ppos) 
324{ 
325    struct logger_log *log =file_get_log(iocb->ki_filp); 
326    size_t orig =log->w_off; 
327    struct logger_entry header; 
328    struct timespec now; 
329    ssize_t ret = 0; 
330 
331    now =current_kernel_time(); 
332 
333    header.pid =current->tgid; 
334    header.tid =current->pid; 
335    header.sec = now.tv_sec; 
336    header.nsec = now.tv_nsec; 
337    header.len = min_t(size_t,iocb->ki_left, LOGGER_ENTRY_MAX_PAYLOAD); 
338 
339    /* null writes succeed,return zero */ 
340    if (unlikely(!header.len)) 
341        return 0; 
342 
343   mutex_lock(&log->mutex); 
344 
345    /*
346     * Fix up any readers,pulling them forward to the first readable
347     * entry after (what willbe) the new write offset. We do this now
348     * because if we partiallyfail, we can end up with clobbered log
349     * entries that encroach onreadable buffer.
350     */ 
351    fix_up_readers(log,sizeof(struct logger_entry) + header.len); 
352 
353    do_write_log(log,&header, sizeof(struct logger_entry)); 
354 
355    while (nr_segs– > 0) { 
356        size_t len; 
357        ssize_t nr; 
358 
359        /* figure out how muchof this vector we can keep */ 
360        len = min_t(size_t,iov->iov_len, header.len – ret); 
361 
362        /* write out thissegment's payload */ 
363        nr =do_write_log_from_user(log, iov->iov_base, len); 
364        if (unlikely(nr <0)) { 
365            log->w_off = orig; 
366           mutex_unlock(&log->mutex); 
367            return nr; 
368        } 
369 
370        iov++; 
371        ret += nr; 
372    } 
373 
374   mutex_unlock(&log->mutex); 
375 
376    /* wake up any blockedreaders */ 
377   wake_up_interruptible(&log->wq); 
378 
379    return ret; 
380} 

317/*
318 * logger_aio_write – our write method, implementing support forwrite(),
319 * writev(), and aio_write(). Writes are our fast path, and we try tooptimize
320 * them above all else.
321 */
322ssize_t logger_aio_write(struct kiocb *iocb, const struct iovec *iov,
323             unsigned longnr_segs, loff_t ppos)
324{
325    struct logger_log *log =file_get_log(iocb->ki_filp);
326    size_t orig =log->w_off;
327    struct logger_entry header;
328    struct timespec now;
329    ssize_t ret = 0;
330
331    now =current_kernel_time();
332
333    header.pid =current->tgid;
334    header.tid =current->pid;
335    header.sec = now.tv_sec;
336    header.nsec = now.tv_nsec;
337    header.len = min_t(size_t,iocb->ki_left, LOGGER_ENTRY_MAX_PAYLOAD);
338
339    /* null writes succeed,return zero */
340    if (unlikely(!header.len))
341        return 0;
342
343   mutex_lock(&log->mutex);
344
345    /*
346     * Fix up any readers,pulling them forward to the first readable
347     * entry after (what willbe) the new write offset. We do this now
348     * because if we partiallyfail, we can end up with clobbered log
349     * entries that encroach onreadable buffer.
350     */
351    fix_up_readers(log,sizeof(struct logger_entry) + header.len);
352
353    do_write_log(log,&header, sizeof(struct logger_entry));
354
355    while (nr_segs– > 0) {
356        size_t len;
357        ssize_t nr;
358
359        /* figure out how muchof this vector we can keep */
360        len = min_t(size_t,iov->iov_len, header.len – ret);
361
362        /* write out thissegment's payload */
363        nr =do_write_log_from_user(log, iov->iov_base, len);
364        if (unlikely(nr <0)) {
365            log->w_off = orig;
366           mutex_unlock(&log->mutex);
367            return nr;
368        }
369
370        iov++;
371        ret += nr;
372    }
373
374   mutex_unlock(&log->mutex);
375
376    /* wake up any blockedreaders */
377   wake_up_interruptible(&log->wq);
378
379    return ret;
380}
325行,調用file_get_log函數取得要讀取的LOG設備:

[cpp] 77static inlinestruct logger_log * file_get_log(struct file *file) 
78{ 
79    if (file->f_mode & FMODE_READ) { 
80        struct logger_reader *reader =file->private_data; 
81        return reader->log; 
82    } else 
83        return file->private_data; 
84} 

 77static inlinestruct logger_log * file_get_log(struct file *file)
 78{
 79    if (file->f_mode & FMODE_READ) {
 80        struct logger_reader *reader =file->private_data;
 81        return reader->log;
 82    } else
 83        return file->private_data;
 84}
327行,定義瞭一個logger_entry結構體變量header,logger_entry結構體用於描述一個LOG的信息,定義在drivers/staging/android/logger.h文件中:

[cpp]  23struct logger_entry { 
24    __u16       len;   /* length of the payload */ 
25    __u16       __pad; /* no matter what, we get 2 bytes of padding */ 
26    __s32       pid;   /* generating process's pid */ 
27    __s32       tid;   /* generating process's tid */ 
28    __s32       sec;   /* seconds since Epoch */ 
29    __s32       nsec;  /* nanoseconds */ 
30    char        msg[0]; /* the entry's payload */ 
31}; 

23struct logger_entry {
24    __u16       len;   /* length of the payload */
25    __u16       __pad; /* no matter what, we get 2 bytes of padding */
26    __s32       pid;   /* generating process's pid */
27    __s32       tid;   /* generating process's tid */
28    __s32       sec;   /* seconds since Epoch */
29    __s32       nsec;  /* nanoseconds */
30    char        msg[0]; /* the entry's payload */
31};
333-337行,對logger_entry結構體變量header進行初始化。

351行,調用fix_up_readers函數,修正某些logger_read的讀取位置指針。因為LOG緩沖區是循環使用的,當進行寫操作後,可能會覆蓋一些末讀取的內容,因此,需要修正某些logger_read的讀取位置指針。

[cpp] 250/*
251 * fix_up_readers – walk the list of all readers and "fixup" any who were
252 * lapped by the writer; also do the same for the default "starthead".
253 * We do this by "pulling forward" the readers and starthead to the first
254 * entry after the new write head.
255 *
256 * The caller needs to hold log->mutex.
257 */ 
258static void fix_up_readers(struct logger_log *log, size_t len) 
259{ 
260    size_t old = log->w_off; 
261    size_t new =logger_offset(old + len); 
262    struct logger_reader*reader; 
263 
264    if (clock_interval(old,new, log->head)) 
265        log->head =get_next_entry(log, log->head, len); 
266 
267    list_for_each_entry(reader,&log->readers, list) 
268        if (clock_interval(old,new, reader->r_off)) 
269            reader->r_off =get_next_entry(log, reader->r_off, len); 
270} 

250/*
251 * fix_up_readers – walk the list of all readers and "fixup" any who were
252 * lapped by the writer; also do the same for the default "starthead".
253 * We do this by "pulling forward" the readers and starthead to the first
254 * entry after the new write head.
255 *
256 * The caller needs to hold log->mutex.
257 */
258static void fix_up_readers(struct logger_log *log, size_t len)
259{
260    size_t old = log->w_off;
261    size_t new =logger_offset(old + len);
262    struct logger_reader*reader;
263
264    if (clock_interval(old,new, log->head))
265        log->head =get_next_entry(log, log->head, len);
266
267    list_for_each_entry(reader,&log->readers, list)
268        if (clock_interval(old,new, reader->r_off))
269            reader->r_off =get_next_entry(log, reader->r_off, len);
270}
264行,調用clock_interval(old, new, log->head)函數,判斷第三個參數log->head是否在第一個和第二個參數范圍之內,即判斷第三個參數log->head指定的位置是否會被本次write操作覆蓋。clock_interval函數定義如下:

[cpp]  233/*
234 * clock_interval – is a < c < b in mod-space? Put another way,does the line
235 * from a to b cross c?
236 */ 
237static inline int clock_interval(size_t a, size_t b, size_t c) 
238{ 
239    if (b < a) {      // 轉到循環緩沖區前面  
240        if (a < c || b >=c) 
241            return 1; 
242    } else { 
243        if (a < c &&b >= c) 
244            return 1; 
245    } 
246 
247    return 0; 
248} 

233/*
234 * clock_interval – is a < c < b in mod-space? Put another way,does the line
235 * from a to b cross c?
236 */
237static inline int clock_interval(size_t a, size_t b, size_t c)
238{
239    if (b < a) {      // 轉到循環緩沖區前面
240        if (a < c || b >=c)
241            return 1;
242    } else {
243        if (a < c &&b >= c)
244            return 1;
245    }
246
247    return 0;
248}
回到fix_up_readers 函數,265行,如果log->head指定的位置會被本次write操作覆蓋,則調用get_next_entry獲得下一條LOG記錄的起始位置,並賦值給log->head。get_next_entry函數定義如下:

[cpp] 14/*
215 * get_next_entry – return the offset of the first valid entry atleast 'len'
216 * bytes after 'off'.
217 *
218 * Caller must hold log->mutex.
219 */ 
220static size_t get_next_entry(struct logger_log *log, size_t off,size_t len) 
221{ 
222    size_t count = 0; 
223 
224    do { 
225        size_t nr =get_entry_len(log, off);  // 取得一下條記錄的長度  
226        off = logger_offset(off+ nr);     // off指向一條記錄  
227        count += nr; 
228    } while (count < len); 
229 
230    return off; 
231} 

214/*
215 * get_next_entry – return the offset of the first valid entry atleast 'len'
216 * bytes after 'off'.
217 *
218 * Caller must hold log->mutex.
219 */
220static size_t get_next_entry(struct logger_log *log, size_t off,size_t len)
221{
222    size_t count = 0;
223
224    do {
225        size_t nr =get_entry_len(log, off);  // 取得一下條記錄的長度
226        off = logger_offset(off+ nr);     // off指向一條記錄
227        count += nr;
228    } while (count < len);
229
230    return off;
231}
回到fix_up_readers 函數,267-269行,遍歷log->readers列表。對於每個logger_reader,如果logger_reader.r_off被覆蓋,則向後做偏移。

回到logger_aio_write函數,353行,調用do_write_log函數,將logger_entry寫入LOG緩沖區。do_write_log函數定義如下:

[cpp]  272/*
273 * do_write_log – writes 'len' bytes from 'buf' to 'log'
274 *
275 * The caller needs to hold log->mutex.
276 */ 
277static void do_write_log(struct logger_log *log, const void *buf,size_t count) 
278{ 
279    size_t len; 
280 
281    len = min(count,log->size – log->w_off); // 處理後半部分  
282    memcpy(log->buffer +log->w_off, buf, len); 
283 
284    if (count != len) // 如果有需要,處理前半部分  
285        memcpy(log->buffer,buf + len, count – len); 
286 
287    log->w_off =logger_offset(log->w_off + count); 
288 
289} 

272/*
273 * do_write_log – writes 'len' bytes from 'buf' to 'log'
274 *
275 * The caller needs to hold log->mutex.
276 */
277static void do_write_log(struct logger_log *log, const void *buf,size_t count)
278{
279    size_t len;
280
281    len = min(count,log->size – log->w_off); // 處理後半部分
282    memcpy(log->buffer +log->w_off, buf, len);
283
284    if (count != len) // 如果有需要,處理前半部分
285        memcpy(log->buffer,buf + len, count – len);
286
287    log->w_off =logger_offset(log->w_off + count);
288
289}
回到logger_aio_write函數,355-372行,通過這個while循環將用戶空間提供的LOG內容寫入LOG設備中。真正的寫操作是通過do_write_log_from_user函數完成的,該函數定義如下:

[cpp]  291/*
292 * do_write_log_user – writes 'len' bytes from the user-space buffer'buf' to
293 * the log 'log'
294 *
295 * The caller needs to hold log->mutex.
296 *
297 * Returns 'count' on success, negative error code on failure.
298 */ 
299static ssize_t do_write_log_from_user(struct logger_log *log, 
300                      constvoid __user *buf, size_t count) 
301{ 
302    size_t len; 
303 
304    len = min(count,log->size – log->w_off); 
305    if (len &©_from_user(log->buffer + log->w_off, buf, len)) 
306        return -EFAULT; 
307 
308    if (count != len) 
309        if(copy_from_user(log->buffer, buf + len, count – len)) 
310            return -EFAULT; 
311 
312    log->w_off =logger_offset(log->w_off + count); 
313 
314    return count; 
315} 

291/*
292 * do_write_log_user – writes 'len' bytes from the user-space buffer'buf' to
293 * the log 'log'
294 *
295 * The caller needs to hold log->mutex.
296 *
297 * Returns 'count' on success, negative error code on failure.
298 */
299static ssize_t do_write_log_from_user(struct logger_log *log,
300                      constvoid __user *buf, size_t count)
301{
302    size_t len;
303
304    len = min(count,log->size – log->w_off);
305    if (len &©_from_user(log->buffer + log->w_off, buf, len))
306        return -EFAULT;
307
308    if (count != len)
309        if(copy_from_user(log->buffer, buf + len, count – len))
310            return -EFAULT;
311
312    log->w_off =logger_offset(log->w_off + count);
313
314    return count;
315}
回到logger_aio_write函數,377行,調用wake_up_interruptible函數喚醒在log->wq上等待的logger_reader。

至此,內核空間的LOG模塊我們就分析完瞭。

 

二、用戶空間LOG模塊分析

Android應用程序是通過應用程序框架層的JAVA接口android.util.Log來使用LOG系統的,該接口定義在frameworks/base/core/java/android/util/Log.java文件中:

[cpp] 52public finalclass Log { 
 53 
 54    /**
 55     * Priority constant for the printlnmethod; use Log.v.
 56     */ 
 57    public static final int VERBOSE = 2; 
 58 
 59    /**
 60     * Priority constant for the printlnmethod; use Log.d.
 61     */ 
 62    public static final int DEBUG = 3; 
 63 
 64    /**
 65     * Priority constant for the printlnmethod; use Log.i.
 66     */ 
 67    public static final int INFO = 4; 
 68 
 69    /**
 70     * Priority constant for the printlnmethod; use Log.w.
 71     */ 
 72    public static final int WARN = 5; 
 73 
 74    /**
 75     * Priority constant for the printlnmethod; use Log.e.
 76     */ 
 77    public static final int ERROR = 6; 
 78 
 79    /**
 80     * Priority constant for the printlnmethod.
 81     */ 
 82    public static final int ASSERT = 7; 
 83 
 84    /**
 85     * Exception class used to capture a stacktrace in {@link #wtf()}.
 86     */ 
 87    private static class TerribleFailureextends Exception { 
 88        TerribleFailure(String msg, Throwablecause) { super(msg, cause); } 
 89    } 
 90 
 91    /**
 92     * Interface to handle terrible failuresfrom {@link #wtf()}.
 93     *
 94     * @hide
 95     */ 
 96    public interface TerribleFailureHandler { 
97        void onTerribleFailure(String tag, TerribleFailurewhat); 
 98    } 
 99 
100    private staticTerribleFailureHandler sWtfHandler = new TerribleFailureHandler() { 
101            public voidonTerribleFailure(String tag, TerribleFailure what) { 
102               RuntimeInit.wtf(tag, what); 
103            } 
104        }; 
105 
106    private Log() { 
107    } 
108 
109    /**
110     * Send a {@link #VERBOSE}log message.
111     * @param tag Used toidentify the source of a log message.  Itusually identifies
112     *        the class or activity where the logcall occurs.
113     * @param msg The messageyou would like logged.
114     */ 
115    public static int v(Stringtag, String msg) { 
116        returnprintln_native(LOG_ID_MAIN, VERBOSE, tag, msg); 
117    } 
118 
119    /**
120     * Send a {@link #VERBOSE}log message and log the exception.
121     * @param tag Used toidentify the source of a log message.  Itusually identifies
122     *        the class or activity where the logcall occurs.
123     * @param msg The messageyou would like logged.
124     * @param tr An exceptionto log
125     */ 
126    public static int v(Stringtag, String msg, Throwable tr) { 
127        returnprintln_native(LOG_ID_MAIN, VERBOSE, tag, msg + '\n' + getStackTraceString(tr)); 
128    } 
129 
130    /**
131     * Send a {@link #DEBUG}log message.
132     * @param tag Used toidentify the source of a log message.  Itusually identifies
133     *        the class or activity where the logcall occurs.
134     * @param msg The messageyou would like logged.
135     */ 
136    public static int d(Stringtag, String msg) { 
137        returnprintln_native(LOG_ID_MAIN, DEBUG, tag, msg); 
138    } 
139 
140    /**
141     * Send a {@link #DEBUG}log message and log the exception.
142     * @param tag Used toidentify the source of a log message.  Itusually identifies
143     *        the class or activity where the logcall occurs.
144     * @param msg The messageyou would like logged.
145     * @param tr An exceptionto log
146     */ 
147    public static int d(Stringtag, String msg, Throwable tr) { 
148        returnprintln_native(LOG_ID_MAIN, DEBUG, tag, msg + '\n' + getStackTraceString(tr)); 
149    } 
150 
151    /**
152     * Send an {@link #INFO}log message.
153     * @param tag Used toidentify the source of a log message.  Itusually identifies
154     *        the class or activity where the logcall occurs.
155     * @param msg The messageyou would like logged.
156     */ 
157    public static int i(Stringtag, String msg) { 
158        returnprintln_native(LOG_ID_MAIN, INFO, tag, msg); 
159    } 
160 
161    /**
162     * Send a {@link #INFO} logmessage and log the exception.
163     * @param tag Used toidentify the source of a log message.  Itusually identifies
164     *        the class or activity where the logcall occurs.
165     * @param msg The messageyou would like logged.
166     * @param tr An exceptionto log
167     */ 
168    public static int i(Stringtag, String msg, Throwable tr) { 
169        returnprintln_native(LOG_ID_MAIN, INFO, tag, msg + '\n' + getStackTraceString(tr)); 
170    } 
171 
172    /**
173     * Send a {@link #WARN} logmessage.
174     * @param tag Used toidentify the source of a log message.  Itusually identifies
175     *        the class or activity where the logcall occurs.
176     * @param msg The messageyou would like logged.
177     */ 
178    public static int w(Stringtag, String msg) { 
179        returnprintln_native(LOG_ID_MAIN, WARN, tag, msg); 
180    } 
181 
182    /**
183     * Send a {@link #WARN} logmessage and log the exception.
184     * @param tag Used toidentify the source of a log message.  Itusually identifies
185     *        the class or activity where the log calloccurs.
186     * @param msg The messageyou would like logged.
187     * @param tr An exceptionto log
188     */ 
189    public static int w(Stringtag, String msg, Throwable tr) { 
190        return println_native(LOG_ID_MAIN,WARN, tag, msg + '\n' + getStackTraceString(tr)); 
191    } 
192 
193    /**
194     * Checks to see whether ornot a log for the specified tag is loggable at the specified level.
195     *
196     *  The default level of any tag is set to INFO.This means that any level above and including
197     *  INFO will be logged. Before you make anycalls to a logging method you should check to see
198     *  if your tag should be logged. You can changethe default level by setting a system property:
199     *      'setprop log.tag.<YOUR_LOG_TAG><LEVEL>'
200     *  Where level is either VERBOSE, DEBUG, INFO,WARN, ERROR, ASSERT, or SUPPRESS. SUPPRESS will
201     *  turn off all logging for your tag. You canalso create a local.prop file that with the
202     *  following in it:
203     *     'log.tag.<YOUR_LOG_TAG>=<LEVEL>'
204     *  and place that in /data/local.prop.
205     *
206     * @param tag The tag tocheck.
207     * @param level The levelto check.
208     * @return Whether or notthat this is allowed to be logged.
209     * @throwsIllegalArgumentException is thrown if the tag.length() > 23.
210     */ 
211    public static nativeboolean isLoggable(String tag, int level); 
212 
213    /*
214     * Send a {@link #WARN} logmessage and log the exception.
215     * @param tag Used toidentify the source of a log message.  Itusually identifies
216     *        the class or activity where the logcall occurs.
217     * @param tr An exceptionto log
218     */ 
219    public static int w(Stringtag, Throwable tr) { 
220        returnprintln_native(LOG_ID_MAIN, WARN, tag, getStackTraceString(tr)); 
221    } 
222 
223    /**
224     * Send an {@link #ERROR}log message.
225     * @param tag Used toidentify the source of a log message.  Itusually identifies
226     *        the class or activity where the logcall occurs.
227     * @param msg The messageyou would like logged.
228     */ 
229    public static int e(Stringtag, String msg) { 
230        returnprintln_native(LOG_ID_MAIN, ERROR, tag, msg); 
231    } 
232 
233    /**
234     * Send a {@link #ERROR}log message and log the exception.
235     * @param tag Used toidentify the source of a log message.  Itusually identifies
236     *        the class or activity where the logcall occurs.
237     * @param msg The messageyou would like logged.
238     * @param tr An exceptionto log
239     */ 
240    public static int e(Stringtag, String msg, Throwable tr) { 
241        return println_native(LOG_ID_MAIN, ERROR,tag, msg + '\n' + getStackTraceString(tr)); 
242    } 
243 
244    /**
245     * What a Terrible Failure:Report a condition that should never happen.
246     * The error will always belogged at level ASSERT with the call stack.
247     * Depending on systemconfiguration, a report may be added to the
248     * {@linkandroid.os.DropBoxManager} and/or the process may be terminated
249     * immediately with anerror dialog.
250     * @param tag Used toidentify the source of a log message.
251     * @param msg The messageyou would like logged.
252     */ 
253    public static intwtf(String tag, String msg) { 
254        return wtf(tag, msg,null); 
255    } 
256 
257    /**
258     * What a Terrible Failure:Report an exception that should never happen.
259     * Similar to {@link#wtf(String, String)}, with an exception to log.
260     * @param tag Used toidentify the source of a log message.
261     * @param tr An exceptionto log.
262     */ 
263    public static intwtf(String tag, Throwable tr) { 
264        return wtf(tag,tr.getMessage(), tr); 
265    } 
266 
267    /**
268     * What a Terrible Failure:Report an exception that should never happen.
269     * Similar to {@link #wtf(String,Throwable)}, with a message as well.
270     * @param tag Used toidentify the source of a log message.
271     * @param msg The messageyou would like logged.
272     * @param tr An exceptionto log.  May be null.
273     */ 
274    public static intwtf(String tag, String msg, Throwable tr) { 
275        TerribleFailure what =new TerribleFailure(msg, tr); 
276        int bytes =println_native(LOG_ID_MAIN, ASSERT, tag, getStackTraceString(tr)); 
277       sWtfHandler.onTerribleFailure(tag, what); 
278        return bytes; 
279    } 
280 
281    /**
282     * Sets the terriblefailure handler, for testing.
283     *
284     * @return the old handler
285     *
286     * @hide
287     */ 
288    public staticTerribleFailureHandler setWtfHandler(TerribleFailureHandler handler) { 
289        if (handler == null) { 
290            throw newNullPointerException("handler == null"); 
291        } 
292        TerribleFailureHandleroldHandler = sWtfHandler; 
293        sWtfHandler = handler; 
294        return oldHandler; 
295    } 
296 
297    /**
298     * Handy function to get aloggable stack trace from a Throwable
299     * @param tr An exceptionto log
300     */ 
301    public static StringgetStackTraceString(Throwable tr) { 
302        if (tr == null) { 
303            return""; 
304        } 
305        StringWriter sw = newStringWriter(); 
306        PrintWriter pw = newPrintWriter(sw); 
307        tr.printStackTrace(pw); 
308        return sw.toString(); 
309    } 
310 
311    /**
312     * Low-level logging call.
313     * @param priority Thepriority/type of this log message
314     * @param tag Used toidentify the source of a log message.  Itusually identifies
315     *        the class or activity where the log calloccurs.
316     * @param msg The messageyou would like logged.
317     * @return The number ofbytes written.
318     */ 
319    public static intprintln(int priority, String tag, String msg) { 
320        returnprintln_native(LOG_ID_MAIN, priority, tag, msg); 
321    } 
322 
323    /** @hide */ public staticfinal int LOG_ID_MAIN = 0; 
324    /** @hide */ public staticfinal int LOG_ID_RADIO = 1; 
325    /** @hide */ public staticfinal int LOG_ID_EVENTS = 2; 
326    /** @hide */ public staticfinal int LOG_ID_SYSTEM = 3; 
327 
328    /** @hide */ public staticnative int println_native(int bufID, 
329            int priority,String tag, String msg); 
330} 

52public finalclass Log {
 53
 54    /**
 55     * Priority constant for the printlnmethod; use Log.v.
 56     */
 57    public static final int VERBOSE = 2;
 58
 59    /**
 60     * Priority constant for the printlnmethod; use Log.d.
 61     */
 62    public static final int DEBUG = 3;
 63
 64    /**
 65     * Priority constant for the printlnmethod; use Log.i.
 66     */
 67    public static final int INFO = 4;
 68
 69    /**
 70     * Priority constant for the printlnmethod; use Log.w.
 71     */
 72    public static final int WARN = 5;
 73
 74    /**
 75     * Priority constant for the printlnmethod; use Log.e.
 76     */
 77    public static final int ERROR = 6;
 78
 79    /**
 80     * Priority constant for the printlnmethod.
 81     */
 82    public static final int ASSERT = 7;
 83
 84    /**
 85     * Exception class used to capture a stacktrace in {@link #wtf()}.
 86     */
 87    private static class TerribleFailureextends Exception {
 88        TerribleFailure(String msg, Throwablecause) { super(msg, cause); }
 89    }
 90
 91    /**
 92     * Interface to handle terrible failuresfrom {@link #wtf()}.
 93     *
 94     * @hide
 95     */
 96    public interface TerribleFailureHandler {
97        void onTerribleFailure(String tag, TerribleFailurewhat);
 98    }
 99
100    private staticTerribleFailureHandler sWtfHandler = new TerribleFailureHandler() {
101            public voidonTerribleFailure(String tag, TerribleFailure what) {
102               RuntimeInit.wtf(tag, what);
103            }
104        };
105
106    private Log() {
107    }
108
109    /**
110     * Send a {@link #VERBOSE}log message.
111     * @param tag Used toidentify the source of a log message.  Itusually identifies
112     *        the class or activity where the logcall occurs.
113     * @param msg The messageyou would like logged.
114     */
115    public static int v(Stringtag, String msg) {
116        returnprintln_native(LOG_ID_MAIN, VERBOSE, tag, msg);
117    }
118
119    /**
120     * Send a {@link #VERBOSE}log message and log the exception.
121     * @param tag Used toidentify the source of a log message.  Itusually identifies
122     *        the class or activity where the logcall occurs.
123     * @param msg The messageyou would like logged.
124     * @param tr An exceptionto log
125     */
126    public static int v(Stringtag, String msg, Throwable tr) {
127        returnprintln_native(LOG_ID_MAIN, VERBOSE, tag, msg + '\n' + getStackTraceString(tr));
128    }
129
130    /**
131     * Send a {@link #DEBUG}log message.
132     * @param tag Used toidentify the source of a log message.  Itusually identifies
133     *        the class or activity where the logcall occurs.
134     * @param msg The messageyou would like logged.
135     */
136    public static int d(Stringtag, String msg) {
137        returnprintln_native(LOG_ID_MAIN, DEBUG, tag, msg);
138    }
139
140    /**
141     * Send a {@link #DEBUG}log message and log the exception.
142     * @param tag Used toidentify the source of a log message.  Itusually identifies
143     *        the class or activity where the logcall occurs.
144     * @param msg The messageyou would like logged.
145     * @param tr An exceptionto log
146     */
147    public static int d(Stringtag, String msg, Throwable tr) {
148        returnprintln_native(LOG_ID_MAIN, DEBUG, tag, msg + '\n' + getStackTraceString(tr));
149    }
150
151    /**
152     * Send an {@link #INFO}log message.
153     * @param tag Used toidentify the source of a log message.  Itusually identifies
154     *        the class or activity where the logcall occurs.
155     * @param msg The messageyou would like logged.
156     */
157    public static int i(Stringtag, String msg) {
158        returnprintln_native(LOG_ID_MAIN, INFO, tag, msg);
159    }
160
161    /**
162     * Send a {@link #INFO} logmessage and log the exception.
163     * @param tag Used toidentify the source of a log message.  Itusually identifies
164     *        the class or activity where the logcall occurs.
165     * @param msg The messageyou would like logged.
166     * @param tr An exceptionto log
167     */
168    public static int i(Stringtag, String msg, Throwable tr) {
169        returnprintln_native(LOG_ID_MAIN, INFO, tag, msg + '\n' + getStackTraceString(tr));
170    }
171
172    /**
173     * Send a {@link #WARN} logmessage.
174     * @param tag Used toidentify the source of a log message.  Itusually identifies
175     *        the class or activity where the logcall occurs.
176     * @param msg The messageyou would like logged.
177     */
178    public static int w(Stringtag, String msg) {
179        returnprintln_native(LOG_ID_MAIN, WARN, tag, msg);
180    }
181
182    /**
183     * Send a {@link #WARN} logmessage and log the exception.
184     * @param tag Used toidentify the source of a log message.  Itusually identifies
185     *        the class or activity where the log calloccurs.
186     * @param msg The messageyou would like logged.
187     * @param tr An exceptionto log
188     */
189    public static int w(Stringtag, String msg, Throwable tr) {
190        return println_native(LOG_ID_MAIN,WARN, tag, msg + '\n' + getStackTraceString(tr));
191    }
192
193    /**
194     * Checks to see whether ornot a log for the specified tag is loggable at the specified level.
195     *
196     *  The default level of any tag is set to INFO.This means that any level above and including
197     *  INFO will be logged. Before you make anycalls to a logging method you should check to see
198     *  if your tag should be logged. You can changethe default level by setting a system property:
199     *      'setprop log.tag.<YOUR_LOG_TAG><LEVEL>'
200     *  Where level is either VERBOSE, DEBUG, INFO,WARN, ERROR, ASSERT, or SUPPRESS. SUPPRESS will
201     *  turn off all logging for your tag. You canalso create a local.prop file that with the
202     *  following in it:
203     *     'log.tag.<YOUR_LOG_TAG>=<LEVEL>'
204     *  and place that in /data/local.prop.
205     *
206     * @param tag The tag tocheck.
207     * @param level The levelto check.
208     * @return Whether or notthat this is allowed to be logged.
209     * @throwsIllegalArgumentException is thrown if the tag.length() > 23.
210     */
211    public static nativeboolean isLoggable(String tag, int level);
212
213    /*
214     * Send a {@link #WARN} logmessage and log the exception.
215     * @param tag Used toidentify the source of a log message.  Itusually identifies
216     *        the class or activity where the logcall occurs.
217     * @param tr An exceptionto log
218     */
219    public static int w(Stringtag, Throwable tr) {
220        returnprintln_native(LOG_ID_MAIN, WARN, tag, getStackTraceString(tr));
221    }
222
223    /**
224     * Send an {@link #ERROR}log message.
225     * @param tag Used toidentify the source of a log message.  Itusually identifies
226     *        the class or activity where the logcall occurs.
227     * @param msg The messageyou would like logged.
228     */
229    public static int e(Stringtag, String msg) {
230        returnprintln_native(LOG_ID_MAIN, ERROR, tag, msg);
231    }
232
233    /**
234     * Send a {@link #ERROR}log message and log the exception.
235     * @param tag Used toidentify the source of a log message.  Itusually identifies
236     *        the class or activity where the logcall occurs.
237     * @param msg The messageyou would like logged.
238     * @param tr An exceptionto log
239     */
240    public static int e(Stringtag, String msg, Throwable tr) {
241        return println_native(LOG_ID_MAIN, ERROR,tag, msg + '\n' + getStackTraceString(tr));
242    }
243
244    /**
245     * What a Terrible Failure:Report a condition that should never happen.
246     * The error will always belogged at level ASSERT with the call stack.
247     * Depending on systemconfiguration, a report may be added to the
248     * {@linkandroid.os.DropBoxManager} and/or the process may be terminated
249     * immediately with anerror dialog.
250     * @param tag Used toidentify the source of a log message.
251     * @param msg The messageyou would like logged.
252     */
253    public static intwtf(String tag, String msg) {
254        return wtf(tag, msg,null);
255    }
256
257    /**
258     * What a Terrible Failure:Report an exception that should never happen.
259     * Similar to {@link#wtf(String, String)}, with an exception to log.
260     * @param tag Used toidentify the source of a log message.
261     * @param tr An exceptionto log.
262     */
263    public static intwtf(String tag, Throwable tr) {
264        return wtf(tag,tr.getMessage(), tr);
265    }
266
267    /**
268     * What a Terrible Failure:Report an exception that should never happen.
269     * Similar to {@link #wtf(String,Throwable)}, with a message as well.
270     * @param tag Used toidentify the source of a log message.
271     * @param msg The messageyou would like logged.
272     * @param tr An exceptionto log.  May be null.
273     */
274    public static intwtf(String tag, String msg, Throwable tr) {
275        TerribleFailure what =new TerribleFailure(msg, tr);
276        int bytes =println_native(LOG_ID_MAIN, ASSERT, tag, getStackTraceString(tr));
277       sWtfHandler.onTerribleFailure(tag, what);
278        return bytes;
279    }
280
281    /**
282     * Sets the terriblefailure handler, for testing.
283     *
284     * @return the old handler
285     *
286     * @hide
287     */
288    public staticTerribleFailureHandler setWtfHandler(TerribleFailureHandler handler) {
289        if (handler == null) {
290            throw newNullPointerException("handler == null");
291        }
292        TerribleFailureHandleroldHandler = sWtfHandler;
293        sWtfHandler = handler;
294        return oldHandler;
295    }
296
297    /**
298     * Handy function to get aloggable stack trace from a Throwable
299     * @param tr An exceptionto log
300     */
301    public static StringgetStackTraceString(Throwable tr) {
302        if (tr == null) {
303            return"";
304        }
305        StringWriter sw = newStringWriter();
306        PrintWriter pw = newPrintWriter(sw);
307        tr.printStackTrace(pw);
308        return sw.toString();
309    }
310
311    /**
312     * Low-level logging call.
313     * @param priority Thepriority/type of this log message
314     * @param tag Used toidentify the source of a log message.  Itusually identifies
315     *        the class or activity where the log calloccurs.
316     * @param msg The messageyou would like logged.
317     * @return The number ofbytes written.
318     */
319    public static intprintln(int priority, String tag, String msg) {
320        returnprintln_native(LOG_ID_MAIN, priority, tag, msg);
321    }
322
323    /** @hide */ public staticfinal int LOG_ID_MAIN = 0;
324    /** @hide */ public staticfinal int LOG_ID_RADIO = 1;
325    /** @hide */ public staticfinal int LOG_ID_EVENTS = 2;
326    /** @hide */ public staticfinal int LOG_ID_SYSTEM = 3;
327
328    /** @hide */ public staticnative int println_native(int bufID,
329            int priority,String tag, String msg);
330}
57-82行,定義瞭2-7共6個LOG優先級。

115-117行,定義瞭Log.v函數,可以看到,該函數是通過調用本地函數println_native來實現的。

LOG類的其它函數很多都是類似的實現,我們不再詳細分析,下面我們來看println_native函數是怎麼實現的。該函數定義在frameworks/base/core/jni/android_util_Log.cpp文件中。

[cpp]  142/*
143 * JNI registration.
144 */ 
145static JNINativeMethod gMethods[] = { 
146    /* name, signature, funcPtr*/ 
147    {"isLoggable",     "(Ljava/lang/String;I)Z", (void*) android_util_Log_isLoggable}, 
148    {"println_native", "(IILjava/lang/String;Ljava/lang/String;)I", (void*)android_util_Log_println_native }, 
149}; 

142/*
143 * JNI registration.
144 */
145static JNINativeMethod gMethods[] = {
146    /* name, signature, funcPtr*/
147    {"isLoggable",     "(Ljava/lang/String;I)Z", (void*) android_util_Log_isLoggable},
148    {"println_native", "(IILjava/lang/String;Ljava/lang/String;)I", (void*)android_util_Log_println_native },
149};
由這段代碼可以看出,JAVA層調用的本地函數println_native,在這裡是指向android_util_Log_println_native函數,該函數定義如下:

[cpp] 99/*
100 * In class android.util.Log:
101 *  public static native intprintln_native(int buffer, int priority, String tag, String msg)
102 */ 
103static jint android_util_Log_println_native(JNIEnv* env, jobjectclazz, 
104        jint bufID, jintpriority, jstring tagObj, jstring msgObj) 
105{ 
106    const char* tag = NULL; 
107    const char* msg = NULL; 
108 
109    if (msgObj == NULL) { 
110        jclass npeClazz; 
111 
112        npeClazz =env->FindClass("java/lang/NullPointerException"); 
113        assert(npeClazz !=NULL); 
114 
115       env->ThrowNew(npeClazz, "println needs a message"); 
116        return -1; 
117    } 
118 
119    if (bufID < 0 || bufID>= LOG_ID_MAX) { 
120        jclass npeClazz; 
121 
122        npeClazz =env->FindClass("java/lang/NullPointerException"); 
123        assert(npeClazz !=NULL); 
124 
125       env->ThrowNew(npeClazz, "bad bufID"); 
126        return -1; 
127    } 
128 
129    if (tagObj != NULL) 
130        tag =env->GetStringUTFChars(tagObj, NULL); 
131    msg =env->GetStringUTFChars(msgObj, NULL); 
132 
133    int res =__android_log_buf_write(bufID, (android_LogPriority)priority, tag, msg); 
134 
135    if (tag != NULL) 
136       env->ReleaseStringUTFChars(tagObj, tag); 
137   env->ReleaseStringUTFChars(msgObj, msg); 
138 
139    return res; 
140} 

99/*
100 * In class android.util.Log:
101 *  public static native intprintln_native(int buffer, int priority, String tag, String msg)
102 */
103static jint android_util_Log_println_native(JNIEnv* env, jobjectclazz,
104        jint bufID, jintpriority, jstring tagObj, jstring msgObj)
105{
106    const char* tag = NULL;
107    const char* msg = NULL;
108
109    if (msgObj == NULL) {
110        jclass npeClazz;
111
112        npeClazz =env->FindClass("java/lang/NullPointerException");
113        assert(npeClazz !=NULL);
114
115       env->ThrowNew(npeClazz, "println needs a message");
116        return -1;
117    }
118
119    if (bufID < 0 || bufID>= LOG_ID_MAX) {
120        jclass npeClazz;
121
122        npeClazz =env->FindClass("java/lang/NullPointerException");
123        assert(npeClazz !=NULL);
124
125       env->ThrowNew(npeClazz, "bad bufID");
126        return -1;
127    }
128
129    if (tagObj != NULL)
130        tag =env->GetStringUTFChars(tagObj, NULL);
131    msg =env->GetStringUTFChars(msgObj, NULL);
132
133    int res =__android_log_buf_write(bufID, (android_LogPriority)priority, tag, msg);
134
135    if (tag != NULL)
136       env->ReleaseStringUTFChars(tagObj, tag);
137   env->ReleaseStringUTFChars(msgObj, msg);
138
139    return res;
140}
開始是進行一些參數的檢查,133行,調用運行時庫函數__android_log_buf_write執行寫操作,該函數定義在system/core/liblog/logd_write.c文件中:

[cpp]  162int __android_log_buf_write(int bufID, int prio, const char *tag,const char *msg) 
163{ 
164    struct iovec vec[3]; 
165 
166    if (!tag) 
167        tag = ""; 
168 
169    /* XXX: This needs to go!*/ 
170    if (!strcmp(tag,"HTC_RIL") || 
171        !strncmp(tag,"RIL", 3) || /* Any log tag with "RIL" as the prefix */ 
172        !strcmp(tag,"AT") || 
173        !strcmp(tag,"GSM") || 
174        !strcmp(tag,"STK") || 
175        !strcmp(tag,"CDMA") || 
176        !strcmp(tag,"PHONE") || 
177        !strcmp(tag,"SMS")) 
178            bufID =LOG_ID_RADIO; 
179 
180    vec[0].iov_base   = (unsigned char *) &prio; 
181    vec[0].iov_len    = 1; 
182    vec[1].iov_base   = (void *) tag; 
183    vec[1].iov_len    = strlen(tag) + 1; 
184    vec[2].iov_base   = (void *) msg; 
185    vec[2].iov_len    = strlen(msg) + 1; 
186 
187    return write_to_log(bufID,vec, 3); 
188} 

162int __android_log_buf_write(int bufID, int prio, const char *tag,const char *msg)
163{
164    struct iovec vec[3];
165
166    if (!tag)
167        tag = "";
168
169    /* XXX: This needs to go!*/
170    if (!strcmp(tag,"HTC_RIL") ||
171        !strncmp(tag,"RIL", 3) || /* Any log tag with "RIL" as the prefix */
172        !strcmp(tag,"AT") ||
173        !strcmp(tag,"GSM") ||
174        !strcmp(tag,"STK") ||
175        !strcmp(tag,"CDMA") ||
176        !strcmp(tag,"PHONE") ||
177        !strcmp(tag,"SMS"))
178            bufID =LOG_ID_RADIO;
179
180    vec[0].iov_base   = (unsigned char *) &prio;
181    vec[0].iov_len    = 1;
182    vec[1].iov_base   = (void *) tag;
183    vec[1].iov_len    = strlen(tag) + 1;
184    vec[2].iov_base   = (void *) msg;
185    vec[2].iov_len    = strlen(msg) + 1;
186
187    return write_to_log(bufID,vec, 3);
188}
170-178行,如果出現“HTC_RIL”等字符,將bufID設置為LOG_ID_RADIO。

180-185行,將prio,tag,msg保存在數組vec中。

187行,調用write_to_log函數,該函數定義如下:

[cpp]  45static int __write_to_log_init(log_id_t, struct iovec *vec, size_tnr); 
46static int (*write_to_log)(log_id_t, struct iovec *vec, size_t nr) =__write_to_log_init; 

45static int __write_to_log_init(log_id_t, struct iovec *vec, size_tnr);
46static int (*write_to_log)(log_id_t, struct iovec *vec, size_t nr) =__write_to_log_init;
__write_to_log_init函數定義如下:

[cpp]  96static int__write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr) 
 97{ 
 98#ifdef HAVE_PTHREADS 
 99    pthread_mutex_lock(&log_init_lock); 
100#endif 
101 
102    if (write_to_log ==__write_to_log_init) { 
103        log_fds[LOG_ID_MAIN] =log_open("/dev/"LOGGER_LOG_MAIN, O_WRONLY); 
104        log_fds[LOG_ID_RADIO] =log_open("/dev/"LOGGER_LOG_RADIO, O_WRONLY); 
105        log_fds[LOG_ID_EVENTS]= log_open("/dev/"LOGGER_LOG_EVENTS, O_WRONLY); 
106        log_fds[LOG_ID_SYSTEM]= log_open("/dev/"LOGGER_LOG_SYSTEM, O_WRONLY); 
107 
108        write_to_log =__write_to_log_kernel; 
109 
110        if(log_fds[LOG_ID_MAIN] < 0 || log_fds[LOG_ID_RADIO] < 0 || 
111               log_fds[LOG_ID_EVENTS] < 0) { 
112           log_close(log_fds[LOG_ID_MAIN]); 
113           log_close(log_fds[LOG_ID_RADIO]); 
114           log_close(log_fds[LOG_ID_EVENTS]); 
115           log_fds[LOG_ID_MAIN] = -1; 
116           log_fds[LOG_ID_RADIO] = -1; 
117           log_fds[LOG_ID_EVENTS] = -1; 
118            write_to_log =__write_to_log_null; 
119        } 
120 
121        if(log_fds[LOG_ID_SYSTEM] < 0) { 
122           log_fds[LOG_ID_SYSTEM] = log_fds[LOG_ID_MAIN]; 
123        } 
124    } 
125 
126#ifdef HAVE_PTHREADS 
127   pthread_mutex_unlock(&log_init_lock); 
128#endif 
129 
130    return write_to_log(log_id,vec, nr); 
131} 

 96static int__write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr)
 97{
 98#ifdef HAVE_PTHREADS
 99    pthread_mutex_lock(&log_init_lock);
100#endif
101
102    if (write_to_log ==__write_to_log_init) {
103        log_fds[LOG_ID_MAIN] =log_open("/dev/"LOGGER_LOG_MAIN, O_WRONLY);
104        log_fds[LOG_ID_RADIO] =log_open("/dev/"LOGGER_LOG_RADIO, O_WRONLY);
105        log_fds[LOG_ID_EVENTS]= log_open("/dev/"LOGGER_LOG_EVENTS, O_WRONLY);
106        log_fds[LOG_ID_SYSTEM]= log_open("/dev/"LOGGER_LOG_SYSTEM, O_WRONLY);
107
108        write_to_log =__write_to_log_kernel;
109
110        if(log_fds[LOG_ID_MAIN] < 0 || log_fds[LOG_ID_RADIO] < 0 ||
111               log_fds[LOG_ID_EVENTS] < 0) {
112           log_close(log_fds[LOG_ID_MAIN]);
113           log_close(log_fds[LOG_ID_RADIO]);
114           log_close(log_fds[LOG_ID_EVENTS]);
115           log_fds[LOG_ID_MAIN] = -1;
116           log_fds[LOG_ID_RADIO] = -1;
117           log_fds[LOG_ID_EVENTS] = -1;
118            write_to_log =__write_to_log_null;
119        }
120
121        if(log_fds[LOG_ID_SYSTEM] < 0) {
122           log_fds[LOG_ID_SYSTEM] = log_fds[LOG_ID_MAIN];
123        }
124    }
125
126#ifdef HAVE_PTHREADS
127   pthread_mutex_unlock(&log_init_lock);
128#endif
129
130    return write_to_log(log_id,vec, nr);
131}
如果write_to_log等於__write_to_log_init,即第一次調用write_to_log,則調用log_open打開4個LOG設備,並將write_to_log設置為__write_to_log_kernel,所以130行再調用write_to_log,即是調用__write_to_log_kernel函數。

[cpp]  78static int__write_to_log_kernel(log_id_t log_id, struct iovec *vec, size_t nr) 
79{ 
80    ssize_t ret; 
81    int log_fd; 
82 
83    if (/*(int)log_id >= 0 &&*/(int)log_id < (int)LOG_ID_MAX) { 
84        log_fd = log_fds[(int)log_id]; 
85    } else { 
86        return EBADF; 
87    } 
88 
89    do { 
90        ret = log_writev(log_fd, vec, nr); 
91    } while (ret < 0 && errno ==EINTR); 
92 
93    return ret; 
94} 

 78static int__write_to_log_kernel(log_id_t log_id, struct iovec *vec, size_t nr)
 79{
 80    ssize_t ret;
 81    int log_fd;
 82
 83    if (/*(int)log_id >= 0 &&*/(int)log_id < (int)LOG_ID_MAX) {
 84        log_fd = log_fds[(int)log_id];
 85    } else {
 86        return EBADF;
 87    }
 88
 89    do {
 90        ret = log_writev(log_fd, vec, nr);
 91    } while (ret < 0 && errno ==EINTR);
 92
 93    return ret;
 94}
核心函數是第90行調用的log_writev,該函數實現瞭寫入操作。

[cpp] 40#definelog_open(pathname, flags) open(pathname, flags) 
41#define log_writev(filedes,vector, count) writev(filedes, vector, count) 
42#define log_close(filedes)close(filedes) 

 40#definelog_open(pathname, flags) open(pathname, flags)
 41#define log_writev(filedes,vector, count) writev(filedes, vector, count)
 42#define log_close(filedes)close(filedes)

log_writev是一個宏,對應writev函數,定義在system/core/libcutils/uio.c文件中:

[cpp]  49int  writev( int  fd, const struct iovec*  vecs, int count ) 
50{ 
51    int   total = 0; 
52 
53    for ( ; count > 0;count–, vecs++ ) { 
54        const char*  buf = (const char*)vecs->iov_base; 
55        int          len = (int)vecs->iov_len; 
56 
57        while (len > 0) { 
58            int  ret = write( fd, buf, len ); 
59            if (ret < 0) { 
60                if (total == 0) 
61                    total = -1; 
62                goto Exit; 
63            } 
64            if (ret == 0) 
65                goto Exit; 
66 
67            total += ret; 
68            buf   += ret; 
69            len   -= ret; 
70        } 
71    } 
72Exit: 
73    return total; 
74} 

49int  writev( int  fd, const struct iovec*  vecs, int count )
50{
51    int   total = 0;
52
53    for ( ; count > 0;count–, vecs++ ) {
54        const char*  buf = (const char*)vecs->iov_base;
55        int          len = (int)vecs->iov_len;
56
57        while (len > 0) {
58            int  ret = write( fd, buf, len );
59            if (ret < 0) {
60                if (total == 0)
61                    total = -1;
62                goto Exit;
63            }
64            if (ret == 0)
65                goto Exit;
66
67            total += ret;
68            buf   += ret;
69            len   -= ret;
70        }
71    }
72Exit:
73    return total;
74}
該函數完成將字符串數組成員依次寫到指定的設備中。

分析到這裡,我們就清楚瞭應用程序怎樣把LOG信息寫到LOG設備中瞭。

 

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *