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設備中瞭。