http://blog.youkuaiyun.com/luoshengyang/article/details/6595744
logger.h
1 /* include/linux/logger.h
2 *
3 * Copyright (C) 2007-2008 Google, Inc.
4 * Author: Robert Love <rlove@android.com>
5 *
6 * This software is licensed under the terms of the GNU General Public
7 * License version 2, as published by the Free Software Foundation, and
8 * may be copied, distributed, and modified under those terms.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 */
16
17 #ifndef _LINUX_LOGGER_H
18 #define _LINUX_LOGGER_H
19
20 #include <linux/types.h>
21 #include <linux/ioctl.h>
22
23 struct 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 };
32
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 */
36
37 #define LOGGER_ENTRY_MAX_LEN (4*1024)
38 #define LOGGER_ENTRY_MAX_PAYLOAD \
39 (LOGGER_ENTRY_MAX_LEN - sizeof(struct logger_entry))
40
41 #define __LOGGERIO 0xAE
42
43 #define LOGGER_GET_LOG_BUF_SIZE _IO(__LOGGERIO, 1) /* size of log */
44 #define LOGGER_GET_LOG_LEN _IO(__LOGGERIO, 2) /* used log len */
45 #define LOGGER_GET_NEXT_ENTRY_LEN _IO(__LOGGERIO, 3) /* next entry len */
46 #define LOGGER_FLUSH_LOG _IO(__LOGGERIO, 4) /* flush log */
47
48 #endif /* _LINUX_LOGGER_H */
49
1 /*
2 * drivers/misc/logger.c
3 *
4 * A Logging Subsystem
5 *
6 * Copyright (C) 2007-2008 Google, Inc.
7 *
8 * Robert Love <rlove@google.com>
9 *
10 * This software is licensed under the terms of the GNU General Public
11 * License version 2, as published by the Free Software Foundation, and
12 * may be copied, distributed, and modified under those terms.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 */
19
20 #include <linux/module.h>
21 #include <linux/fs.h>
22 #include <linux/miscdevice.h>
23 #include <linux/uaccess.h>
24 #include <linux/poll.h>
25 #include <linux/time.h>
26 #include "logger.h"
27
28 #include <asm/ioctls.h>
29
30 /*
31 * struct logger_log - represents a specific log, such as 'main' or 'radio'
32 *
33 * This structure lives from module insertion until module removal, so it does
34 * not need additional reference counting. The structure is protected by the
35 * mutex 'mutex'.
36 */
37 struct 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 };
47
48 /*
49 * struct logger_reader - a logging device open for reading
50 *
51 * This object lives from open to release, so we don't need additional
52 * reference counting. The structure is protected by log->mutex.
53 */
54 struct 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 };
59
60 /* logger_offset - returns index 'n' into the log via (optimized) modulus */
61 #define logger_offset(n) ((n) & (log->size - 1))
62
63 /*
64 * file_get_log - Given a file structure, return the associated log
65 *
66 * This isn't aesthetic. We have several goals:
67 *
68 * 1) Need to quickly obtain the associated log during an I/O operation
69 * 2) Readers need to maintain state (logger_reader)
70 * 3) Writers need to be very fast (open() should be a near no-op)
71 *
72 * In the reader case, we can trivially go file->logger_reader->logger_log.
73 * For a writer, we don't want to maintain a logger_reader, so we just go
74 * file->logger_log. Thus what file->private_data points at depends on whether
75 * or not the file was opened for reading. This function hides that dirtiness.
76 */
77 static inline struct 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 }
85
86 /*
87 * get_entry_len - Grabs the length of the payload of the next entry starting
88 * from 'off'.
89 *
90 * Caller needs to hold log->mutex.
91 */
92 static __u32 get_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(struct logger_entry) + val;
106 }
107
108 /*
109 * do_read_log_to_user - reads exactly 'count' bytes from 'log' into the
110 * user-space buffer 'buf'. Returns 'count' on success.
111 *
112 * Caller must hold log->mutex.
113 */
114 static ssize_t do_read_log_to_user(struct logger_log *log,
115 struct logger_reader *reader,
116 char __user *buf,
117 size_t count)
118 {
119 size_t len;
120
121 /*
122 * We read from the log in two disjoint operations. First, we read from
123 * the current read head offset up to 'count' bytes or to the end of
124 * the log, whichever comes first.
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 any remaining 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 }
142
143 /*
144 * logger_read - our log's read() method
145 *
146 * Behavior:
147 *
148 * - O_NONBLOCK works
149 * - If there are no log entries to read, blocks until log is written to
150 * - Atomically reads exactly one log entry
151 *
152 * Optimal read size is LOGGER_ENTRY_MAX_LEN. Will set errno to EINVAL if read
153 * buffer is insufficient to hold next entry.
154 */
155 static 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
163 start:
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 something to 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 next entry */
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 entry from the log */
206 ret = do_read_log_to_user(log, reader, buf, ret);
207
208 out:
209 mutex_unlock(&log->mutex);
210
211 return ret;
212 }
213
214 /*
215 * get_next_entry - return the offset of the first valid entry at least 'len'
216 * bytes after 'off'.
217 *
218 * Caller must hold log->mutex.
219 */
220 static 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);
227 count += nr;
228 } while (count < len);
229
230 return off;
231 }
232
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 */
237 static 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 }
249
250 /*
251 * fix_up_readers - walk the list of all readers and "fix up" any who were
252 * lapped by the writer; also do the same for the default "start head".
253 * We do this by "pulling forward" the readers and start head to the first
254 * entry after the new write head.
255 *
256 * The caller needs to hold log->mutex.
257 */
258 static 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 }
271
272 /*
273 * do_write_log - writes 'len' bytes from 'buf' to 'log'
274 *
275 * The caller needs to hold log->mutex.
276 */
277 static 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 }
290
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 */
299 static ssize_t do_write_log_from_user(struct logger_log *log,
300 const void __user *buf, size_t count)
301 {
302 size_t len;
303
304 len = min(count, log->size - log->w_off);
305 if (len && copy_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 }
316
317 /*
318 * logger_aio_write - our write method, implementing support for write(),
319 * writev(), and aio_write(). Writes are our fast path, and we try to optimize
320 * them above all else.
321 */
322 ssize_t logger_aio_write(struct kiocb *iocb, const struct iovec *iov,
323 unsigned long nr_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 will be) the new write offset. We do this now
348 * because if we partially fail, we can end up with clobbered log
349 * entries that encroach on readable 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 much of this vector we can keep */
360 len = min_t(size_t, iov->iov_len, header.len - ret);
361
362 /* write out this segment'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 blocked readers */
377 wake_up_interruptible(&log->wq);
378
379 return ret;
380 }
381
382 static struct logger_log *get_log_from_minor(int);
383
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 that way!
388 */
389 static 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
424 /*
425 * logger_release - the log's release file operation
426 *
427 * Note this is a total no-op in the write-only case. Keep it that way!
428 */
429 static int logger_release(struct inode *ignored, struct file *file)
430 {
431 if (file->f_mode & FMODE_READ) {
432 struct logger_reader *reader = file->private_data;
433 list_del(&reader->list);
434 kfree(reader);
435 }
436
437 return 0;
438 }
439
440 /*
441 * logger_poll - the log's poll file operation, for poll/select/epoll
442 *
443 * Note we always return POLLOUT, because you can always write() to the log.
444 * Note also that, strictly speaking, a return value of POLLIN does not
445 * guarantee that the log is readable without blocking, as there is a small
446 * chance that the writer can lap the reader in the interim between poll()
447 * returning and the read() request.
448 */
449 static unsigned int logger_poll(struct file *file, poll_table *wait)
450 {
451 struct logger_reader *reader;
452 struct logger_log *log;
453 unsigned int ret = POLLOUT | POLLWRNORM;
454
455 if (!(file->f_mode & FMODE_READ))
456 return ret;
457
458 reader = file->private_data;
459 log = reader->log;
460
461 poll_wait(file, &log->wq, wait);
462
463 mutex_lock(&log->mutex);
464 if (log->w_off != reader->r_off)
465 ret |= POLLIN | POLLRDNORM;
466 mutex_unlock(&log->mutex);
467
468 return ret;
469 }
470
471 static long logger_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
472 {
473 struct logger_log *log = file_get_log(file);
474 struct logger_reader *reader;
475 long ret = -ENOTTY;
476
477 mutex_lock(&log->mutex);
478
479 switch (cmd) {
480 case LOGGER_GET_LOG_BUF_SIZE:
481 ret = log->size;
482 break;
483 case LOGGER_GET_LOG_LEN:
484 if (!(file->f_mode & FMODE_READ)) {
485 ret = -EBADF;
486 break;
487 }
488 reader = file->private_data;
489 if (log->w_off >= reader->r_off)
490 ret = log->w_off - reader->r_off;
491 else
492 ret = (log->size - reader->r_off) + log->w_off;
493 break;
494 case LOGGER_GET_NEXT_ENTRY_LEN:
495 if (!(file->f_mode & FMODE_READ)) {
496 ret = -EBADF;
497 break;
498 }
499 reader = file->private_data;
500 if (log->w_off != reader->r_off)
501 ret = get_entry_len(log, reader->r_off);
502 else
503 ret = 0;
504 break;
505 case LOGGER_FLUSH_LOG:
506 if (!(file->f_mode & FMODE_WRITE)) {
507 ret = -EBADF;
508 break;
509 }
510 list_for_each_entry(reader, &log->readers, list)
511 reader->r_off = log->w_off;
512 log->head = log->w_off;
513 ret = 0;
514 break;
515 }
516
517 mutex_unlock(&log->mutex);
518
519 return ret;
520 }
521
522 static const 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 };
532
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, and less than
536 * LONG_MAX minus LOGGER_ENTRY_MAX_LEN.
537 */
538 #define DEFINE_LOGGER_DEVICE(VAR, NAME, SIZE) \
539 static unsigned char _buf_ ## VAR[SIZE]; \
540 static 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
556 DEFINE_LOGGER_DEVICE(log_main, LOGGER_LOG_MAIN, 64*1024)
557 DEFINE_LOGGER_DEVICE(log_events, LOGGER_LOG_EVENTS, 256*1024)
558 DEFINE_LOGGER_DEVICE(log_radio, LOGGER_LOG_RADIO, 64*1024)
559
560 static 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 }
570
571 static 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 for log '%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 }
587
588 static 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
604 out:
605 return ret;
606 }
607 device_initcall(logger_init);
608
我们知道,在Android系统中,提供了一个轻量级的日志系统,这个日志系统是以驱动程序的形式实现在内核空间的,而在用户空间分别提供了Java接口和C/C++接口来使用这个日志系统,取决于你编写的是Android应用程序还是系统组件。在前面的文章浅谈Android系统开发中LOG的使用中,已经简要地介绍了在Android应用程序开发中Log的使用方法,在这一篇文章中,我们将更进一步地分析Logger驱动程序的源代码,使得我们对Android日志系统有一个深刻的认识。
既然Android 日志系统是以驱动程序的形式实现在内核空间的,我们就需要获取Android内核源代码来分析了,请参照前面在Ubuntu上下载、编译和安装Android最新源代码和在Ubuntu上下载、编译和安装Android最新内核源代码(Linux Kernel)两篇文章,下载好Android源代码工程。Logger驱动程序主要由两个文件构成,分别是:
kernel/common/drivers/staging/android/logger.h
kernel/common/drivers/staging/android/logger.c
接下来,我们将分别介绍Logger驱动程序的相关数据结构,然后对Logger驱动程序源代码进行情景分析,分别日志系统初始化情景、日志读取情景和日志写入情景。
一. Logger驱动程序的相关数据结构。
我们首先来看logger.h头文件的内容:
- #ifndef _LINUX_LOGGER_H
- #define _LINUX_LOGGER_H
- #include <linux/types.h>
- #include <linux/ioctl.h>
- struct logger_entry {
- __u16 len; /* length of the payload */
- __u16 __pad; /* no matter what, we get 2 bytes of padding */
- __s32 pid; /* generating process's pid */
- __s32 tid; /* generating process's tid */
- __s32 sec; /* seconds since Epoch */
- __s32 nsec; /* nanoseconds */
- char msg[0]; /* the entry's payload */
- };
- #define LOGGER_LOG_RADIO "log_radio" /* radio-related messages */
- #define LOGGER_LOG_EVENTS "log_events" /* system/hardware events */
- #define LOGGER_LOG_MAIN "log_main" /* everything else */
- #define LOGGER_ENTRY_MAX_LEN (4*1024)
- #define LOGGER_ENTRY_MAX_PAYLOAD \
- (LOGGER_ENTRY_MAX_LEN - sizeof(struct logger_entry))
- #define __LOGGERIO 0xAE
- #define LOGGER_GET_LOG_BUF_SIZE _IO(__LOGGERIO, 1) /* size of log */
- #define LOGGER_GET_LOG_LEN _IO(__LOGGERIO, 2) /* used log len */
- #define LOGGER_GET_NEXT_ENTRY_LEN _IO(__LOGGERIO, 3) /* next entry len */
- #define LOGGER_FLUSH_LOG _IO(__LOGGERIO, 4) /* flush log */
- #endif /* _LINUX_LOGGER_H */
接着定义两个宏:
#define LOGGER_ENTRY_MAX_LEN (4*1024)
#define LOGGER_ENTRY_MAX_PAYLOAD \
(LOGGER_ENTRY_MAX_LEN - sizeof(struct logger_entry))
从这两个宏可以看出,每条日志记录的有效负载长度加上结构体logger_entry的长度不能超过4K个字节。
logger.h文件中还定义了其它宏,读者可以自己分析,在下面的分析中,碰到时,我们也会详细解释。
再来看logger.c文件中,其它相关数据结构的定义:
- /*
- * struct logger_log - represents a specific log, such as 'main' or 'radio'
- *
- * This structure lives from module insertion until module removal, so it does
- * not need additional reference counting. The structure is protected by the
- * mutex 'mutex'.
- */
- struct logger_log {
- unsigned char * buffer; /* the ring buffer itself */
- struct miscdevice misc; /* misc device representing the log */
- wait_queue_head_t wq; /* wait queue for readers */
- struct list_head readers; /* this log's readers */
- struct mutex mutex; /* mutex protecting buffer */
- size_t w_off; /* current write head offset */
- size_t head; /* new readers start here */
- size_t size; /* size of the log */
- };
- /*
- * struct logger_reader - a logging device open for reading
- *
- * This object lives from open to release, so we don't need additional
- * reference counting. The structure is protected by log->mutex.
- */
- struct logger_reader {
- struct logger_log * log; /* associated log */
- struct list_head list; /* entry in logger_log's list */
- size_t r_off; /* current read head offset */
- };
- /* logger_offset - returns index 'n' into the log via (optimized) modulus */
- #define logger_offset(n) ((n) & (log->size - 1))
结构体struct logger_reader用来表示一个读取日志的进程,log成员变量指向要读取的日志缓冲区。list成员变量用来连接其它读者进程。r_off成员变量表示当前要读取的日志在缓冲区中的位置。
struct logger_log结构体中用于保存日志信息的内存缓冲区buffer是一个循环使用的环形缓冲区,缓冲区中保存的内容是以struct logger_entry为单位的,每个单位的组成为:
struct logger_entry | priority | tag | msg
由于是内存缓冲区buffer是一个循环使用的环形缓冲区,给定一个偏移值,它在buffer中的位置由下logger_offset来确定:
#define logger_offset(n) ((n) & (log->size - 1))
二. Logger驱动程序模块的初始化过程分析。
继续看logger.c文件,定义了三个日志设备:
- /*
- * Defines a log structure with name 'NAME' and a size of 'SIZE' bytes, which
- * must be a power of two, greater than LOGGER_ENTRY_MAX_LEN, and less than
- * LONG_MAX minus LOGGER_ENTRY_MAX_LEN.
- */
- #define DEFINE_LOGGER_DEVICE(VAR, NAME, SIZE) \
- static unsigned char _buf_ ## VAR[SIZE]; \
- static struct logger_log VAR = { \
- .buffer = _buf_ ## VAR, \
- .misc = { \
- .minor = MISC_DYNAMIC_MINOR, \
- .name = NAME, \
- .fops = &logger_fops, \
- .parent = NULL, \
- }, \
- .wq = __WAIT_QUEUE_HEAD_INITIALIZER(VAR .wq), \
- .readers = LIST_HEAD_INIT(VAR .readers), \
- .mutex = __MUTEX_INITIALIZER(VAR .mutex), \
- .w_off = 0, \
- .head = 0, \
- .size = SIZE, \
- };
- DEFINE_LOGGER_DEVICE(log_main, LOGGER_LOG_MAIN, 64*1024)
- DEFINE_LOGGER_DEVICE(log_events, LOGGER_LOG_EVENTS, 256*1024)
- DEFINE_LOGGER_DEVICE(log_radio, LOGGER_LOG_RADIO, 64*1024)
#define LOGGER_LOG_RADIO "log_radio"/* radio-related messages */
#define LOGGER_LOG_EVENTS "log_events"/* system/hardware events */
#define LOGGER_LOG_MAIN "log_main"/* everything else */
注释说明了这三个日志设备的用途。注册的日志设备文件操作方法为logger_fops:
- static struct file_operations logger_fops = {
- .owner = THIS_MODULE,
- .read = logger_read,
- .aio_write = logger_aio_write,
- .poll = logger_poll,
- .unlocked_ioctl = logger_ioctl,
- .compat_ioctl = logger_ioctl,
- .open = logger_open,
- .release = logger_release,
- };
日志驱动程序模块的初始化函数为logger_init:
- static int __init logger_init(void)
- {
- int ret;
- ret = init_log(&log_main);
- if (unlikely(ret))
- goto out;
- ret = init_log(&log_events);
- if (unlikely(ret))
- goto out;
- ret = init_log(&log_radio);
- if (unlikely(ret))
- goto out;
- out:
- return ret;
- }
- device_initcall(logger_init);
- static int __init init_log(struct logger_log *log)
- {
- int ret;
- ret = misc_register(&log->misc);
- if (unlikely(ret)) {
- printk(KERN_ERR "logger: failed to register misc "
- "device for log '%s'!\n", log->misc.name);
- return ret;
- }
- printk(KERN_INFO "logger: created %luK log '%s'\n",
- (unsigned long) log->size >> 10, log->misc.name);
- return 0;
- }
- /**
- * misc_register - register a miscellaneous device
- * @misc: device structure
- *
- * Register a miscellaneous device with the kernel. If the minor
- * number is set to %MISC_DYNAMIC_MINOR a minor number is assigned
- * and placed in the minor field of the structure. For other cases
- * the minor number requested is used.
- *
- * The structure passed is linked into the kernel and may not be
- * destroyed until it has been unregistered.
- *
- * A zero is returned on success and a negative errno code for
- * failure.
- */
- int misc_register(struct miscdevice * misc)
- {
- struct miscdevice *c;
- dev_t dev;
- int err = 0;
- INIT_LIST_HEAD(&misc->list);
- mutex_lock(&misc_mtx);
- list_for_each_entry(c, &misc_list, list) {
- if (c->minor == misc->minor) {
- mutex_unlock(&misc_mtx);
- return -EBUSY;
- }
- }
- if (misc->minor == MISC_DYNAMIC_MINOR) {
- int i = DYNAMIC_MINORS;
- while (--i >= 0)
- if ( (misc_minors[i>>3] & (1 << (i&7))) == 0)
- break;
- if (i<0) {
- mutex_unlock(&misc_mtx);
- return -EBUSY;
- }
- misc->minor = i;
- }
- if (misc->minor < DYNAMIC_MINORS)
- misc_minors[misc->minor >> 3] |= 1 << (misc->minor & 7);
- dev = MKDEV(MISC_MAJOR, misc->minor);
- misc->this_device = device_create(misc_class, misc->parent, dev, NULL,
- "%s", misc->name);
- if (IS_ERR(misc->this_device)) {
- err = PTR_ERR(misc->this_device);
- goto out;
- }
- /*
- * Add it to the front, so that later devices can "override"
- * earlier defaults
- */
- list_add(&misc->list, &misc_list);
- out:
- mutex_unlock(&misc_mtx);
- return err;
- }
三. Logger驱动程序的日志记录读取过程分析。
继续看logger.c 文件,注册的读取日志设备文件的方法为logger_read:
- /*
- * logger_read - our log's read() method
- *
- * Behavior:
- *
- * - O_NONBLOCK works
- * - If there are no log entries to read, blocks until log is written to
- * - Atomically reads exactly one log entry
- *
- * Optimal read size is LOGGER_ENTRY_MAX_LEN. Will set errno to EINVAL if read
- * buffer is insufficient to hold next entry.
- */
- static ssize_t logger_read(struct file *file, char __user *buf,
- size_t count, loff_t *pos)
- {
- struct logger_reader *reader = file->private_data;
- struct logger_log *log = reader->log;
- ssize_t ret;
- DEFINE_WAIT(wait);
- start:
- while (1) {
- prepare_to_wait(&log->wq, &wait, TASK_INTERRUPTIBLE);
- mutex_lock(&log->mutex);
- ret = (log->w_off == reader->r_off);
- mutex_unlock(&log->mutex);
- if (!ret)
- break;
- if (file->f_flags & O_NONBLOCK) {
- ret = -EAGAIN;
- break;
- }
- if (signal_pending(current)) {
- ret = -EINTR;
- break;
- }
- schedule();
- }
- finish_wait(&log->wq, &wait);
- if (ret)
- return ret;
- mutex_lock(&log->mutex);
- /* is there still something to read or did we race? */
- if (unlikely(log->w_off == reader->r_off)) {
- mutex_unlock(&log->mutex);
- goto start;
- }
- /* get the size of the next entry */
- ret = get_entry_len(log, reader->r_off);
- if (count < ret) {
- ret = -EINVAL;
- goto out;
- }
- /* get exactly one entry from the log */
- ret = do_read_log_to_user(log, reader, buf, ret);
- out:
- mutex_unlock(&log->mutex);
- return ret;
- }
疑问:logger_reader保存在file->private_data里面,这样在logger_read()函数里面就能取出来。那比如“log_main”在同时被多个reader读取的情况下(每个reader->r_off都是不同的)在logger_read()函数里面如何区别这些不同的reader哪??对应某个文件来说inode是唯一的,file可以有很多个,每打开一次文件就会有一个file,所以实际上不同file结构的private_data是不同的。我猜想有kernel来保证每次调用file_operations的函数,都会传入正确的file* ,这样就就说的通了。
- /*
- * logger_open - the log's open() file operation
- *
- * Note how near a no-op this is in the write-only case. Keep it that way!
- */
- static int logger_open(struct inode *inode, struct file *file)
- {
- struct logger_log *log;
- int ret;
- ret = nonseekable_open(inode, file);
- if (ret)
- return ret;
- log = get_log_from_minor(MINOR(inode->i_rdev));
- if (!log)
- return -ENODEV;
- if (file->f_mode & FMODE_READ) {
- struct logger_reader *reader;
- reader = kmalloc(sizeof(struct logger_reader), GFP_KERNEL);
- if (!reader)
- return -ENOMEM;
- reader->log = log;
- INIT_LIST_HEAD(&reader->list);
- mutex_lock(&log->mutex);
- reader->r_off = log->head;
- list_add_tail(&reader->list, &log->readers);
- mutex_unlock(&log->mutex);
- file->private_data = reader;
- } else
- file->private_data = log;
- return 0;
- }
疑问:驱动程序中全局static数据的生命周期?logger.c中定义了logger_log log_main, log_events, log_radio, 在logger_open函数获取logger_log的时候用get_log_from_minor根据minor来返回log_main/log_events/log_radio的一个,这样确保每次新建的logger_reader都放入对应logger_log->readers里面,这样说来驱动中的全局static数据从“驱动设备”打开(open)到移除(release)都一直存在的??
新打开日志设备文件时,是从log->head位置开始读取日志的,保存在struct logger_reader的成员变量r_off中。
start标号处的while循环是在等待日志可读,如果已经没有新的日志可读了,那么就要读进程就要进入休眠状态,等待新的日志写入后再唤醒,这是通过prepare_wait和schedule两个调用来实现的。如果没有新的日志可读,并且设备文件不是以非阻塞O_NONBLOCK的方式打开或者这时有信号要处理(signal_pending(current)),那么就直接返回,不再等待新的日志写入。判断当前是否有新的日志可读的方法是:
ret = (log->w_off == reader->r_off);
即判断当前缓冲区的写入位置和当前读进程的读取位置是否相等,如果不相等,则说明有新的日志可读。
继续向下看,如果有新的日志可读,那么就,首先通过get_entry_len来获取下一条可读的日志记录的长度,从这里可以看出,日志读取进程是以日志记录为单位进行读取的,一次只读取一条记录。get_entry_len的函数实现如下:
- /*
- * get_entry_len - Grabs the length of the payload of the next entry starting
- * from 'off'.
- *
- * Caller needs to hold log->mutex.
- */
- static __u32 get_entry_len(struct logger_log *log, size_t off)
- {
- __u16 val;
- switch (log->size - off) {
- case 1:
- memcpy(&val, log->buffer + off, 1);
- memcpy(((char *) &val) + 1, log->buffer, 1);
- break;
- default:
- memcpy(&val, log->buffer + off, 2);
- }
- return sizeof(struct logger_entry) + val;
- }
接着往下看,得到了要读取的记录的长度,就调用do_read_log_to_user函数来执行真正的读取动作:
- static ssize_t do_read_log_to_user(struct logger_log *log,
- struct logger_reader *reader,
- char __user *buf,
- size_t count)
- {
- size_t len;
- /*
- * We read from the log in two disjoint operations. First, we read from
- * the current read head offset up to 'count' bytes or to the end of
- * the log, whichever comes first.
- */
- len = min(count, log->size - reader->r_off);
- if (copy_to_user(buf, log->buffer + reader->r_off, len))
- return -EFAULT;
- /*
- * Second, we read any remaining bytes, starting back at the head of
- * the log.
- */
- if (count != len)
- if (copy_to_user(buf + len, log->buffer, count - len))
- return -EFAULT;
- reader->r_off = logger_offset(reader->r_off + count);
- return count;
- }
四. Logger驱动程序的日志记录写入过程分析。
继续看logger.c 文件,注册的写入日志设备文件的方法为logger_aio_write:
- /*
- * logger_aio_write - our write method, implementing support for write(),
- * writev(), and aio_write(). Writes are our fast path, and we try to optimize
- * them above all else.
- */
- ssize_t logger_aio_write(struct kiocb *iocb, const struct iovec *iov,
- unsigned long nr_segs, loff_t ppos)
- {
- struct logger_log *log = file_get_log(iocb->ki_filp);
- size_t orig = log->w_off;
- struct logger_entry header;
- struct timespec now;
- ssize_t ret = 0;
- now = current_kernel_time();
- header.pid = current->tgid;
- header.tid = current->pid;
- header.sec = now.tv_sec;
- header.nsec = now.tv_nsec;
- header.len = min_t(size_t, iocb->ki_left, LOGGER_ENTRY_MAX_PAYLOAD);
- /* null writes succeed, return zero */
- if (unlikely(!header.len))
- return 0;
- mutex_lock(&log->mutex);
- /*
- * Fix up any readers, pulling them forward to the first readable
- * entry after (what will be) the new write offset. We do this now
- * because if we partially fail, we can end up with clobbered log
- * entries that encroach on readable buffer.
- */
- fix_up_readers(log, sizeof(struct logger_entry) + header.len);
- do_write_log(log, &header, sizeof(struct logger_entry));
- while (nr_segs-- > 0) {
- size_t len;
- ssize_t nr;
- /* figure out how much of this vector we can keep */
- len = min_t(size_t, iov->iov_len, header.len - ret);
- /* write out this segment's payload */
- nr = do_write_log_from_user(log, iov->iov_base, len);
- if (unlikely(nr < 0)) {
- log->w_off = orig;
- mutex_unlock(&log->mutex);
- return nr;
- }
- iov++;
- ret += nr;
- }
- mutex_unlock(&log->mutex);
- /* wake up any blocked readers */
- wake_up_interruptible(&log->wq);
- return ret;
- }
struct logger_entry | priority | tag | msg
其中, priority、tag和msg这三个段的内容是由iov参数从用户空间传递下来的,分别对应iov里面的三个元素。而logger_entry是由内核空间来构造的:
struct logger_entry header;
struct timespec now;
now = current_kernel_time();
header.pid = current->tgid;
header.tid = current->pid;
header.sec = now.tv_sec;
header.nsec = now.tv_nsec;
header.len = min_t(size_t, iocb->ki_left, LOGGER_ENTRY_MAX_PAYLOAD);
然后调用do_write_log首先把logger_entry结构体写入到日志缓冲区中:
- /*
- * do_write_log - writes 'len' bytes from 'buf' to 'log'
- *
- * The caller needs to hold log->mutex.
- */
- static void do_write_log(struct logger_log *log, const void *buf, size_t count)
- {
- size_t len;
- len = min(count, log->size - log->w_off);
- memcpy(log->buffer + log->w_off, buf, len);
- if (count != len)
- memcpy(log->buffer, buf + len, count - len);
- log->w_off = logger_offset(log->w_off + count);
- }
接着,通过一个while循环把iov的内容写入到日志缓冲区中,也就是日志的优先级别priority、日志Tag和日志主体Msg:
- while (nr_segs-- > 0) {
- size_t len;
- ssize_t nr;
- /* figure out how much of this vector we can keep */
- len = min_t(size_t, iov->iov_len, header.len - ret);
- /* write out this segment's payload */
- nr = do_write_log_from_user(log, iov->iov_base, len);
- if (unlikely(nr < 0)) {
- log->w_off = orig;
- mutex_unlock(&log->mutex);
- return nr;
- }
- iov++;
- ret += nr;
- }
- static ssize_t do_write_log_from_user(struct logger_log *log,
- const void __user *buf, size_t count)
- {
- size_t len;
- len = min(count, log->size - log->w_off);
- if (len && copy_from_user(log->buffer + log->w_off, buf, len))
- return -EFAULT;
- if (count != len)
- if (copy_from_user(log->buffer, buf + len, count - len))
- return -EFAULT;
- log->w_off = logger_offset(log->w_off + count);
- return count;
- }
- /*
- * Fix up any readers, pulling them forward to the first readable
- * entry after (what will be) the new write offset. We do this now
- * because if we partially fail, we can end up with clobbered log
- * entries that encroach on readable buffer.
- */
- fix_up_readers(log, sizeof(struct logger_entry) + header.len);
- /*
- * fix_up_readers - walk the list of all readers and "fix up" any who were
- * lapped by the writer; also do the same for the default "start head".
- * We do this by "pulling forward" the readers and start head to the first
- * entry after the new write head.
- *
- * The caller needs to hold log->mutex.
- */
- static void fix_up_readers(struct logger_log *log, size_t len)
- {
- size_t old = log->w_off;
- size_t new = logger_offset(old + len);
- struct logger_reader *reader;
- if (clock_interval(old, new, log->head))
- log->head = get_next_entry(log, log->head, len);
- list_for_each_entry(reader, &log->readers, list)
- if (clock_interval(old, new, reader->r_off))
- reader->r_off = get_next_entry(log, reader->r_off, len);
- }
- /*
- * get_next_entry - return the offset of the first valid entry at least 'len'
- * bytes after 'off'.
- *
- * Caller must hold log->mutex.
- */
- static size_t get_next_entry(struct logger_log *log, size_t off, size_t len)
- {
- size_t count = 0;
- do {
- size_t nr = get_entry_len(log, off);
- off = logger_offset(off + nr);
- count += nr;
- } while (count < len);
- return off;
- }
- /*
- * clock_interval - is a < c < b in mod-space? Put another way, does the line
- * from a to b cross c?
- */
- static inline int clock_interval(size_t a, size_t b, size_t c)
- {
- if (b < a) {
- if (a < c || b >= c)
- return 1;
- } else {
- if (a < c && b >= c)
- return 1;
- }
- return 0;
- }
/* wake up any blocked readers */
wake_up_interruptible(&log->wq);
至此, Logger驱动程序的主要逻辑就分析完成了,还有其它的一些接口,如logger_poll、 logger_ioctl和logger_release函数,比较简单,读取可以自行分析。这里还需要提到的一点是,由于Logger驱动程序模块在退出系统时,是不会卸载的,所以这个模块没有module_exit函数,而对于模块里面定义的对象,也没有用对引用计数技术。
这篇文章着重介绍了Android日志系统在内核空间的实现,在下一篇文章中,我们将接着介绍在用户空间中,提供给Android应用程序使用的Java和C/C++ LOG调用接口的实现过程,敬请关注。