android日志系统中定义了设备驱动的实现代码位于kernel/common/drivers/staging/android/logger.hkernel/common/drivers/staging/android/logger.c中。

首先,我们阅读logger.h文件代码。

struct logger_entry {__u16len;/* length of the payload */__u16__pad;/* no matter what, we get 2 bytes of padding */__s32pid;/* generating process's pid */__s32tid;/* generating process's tid */__s32sec;/* seconds since Epoch */__s32nsec;/* nanoseconds */charmsg[0];/* the entry's payload */};/*结构体logger_entry定义了日志系统数据的头部信息,其中len定义了负载的长度,__pad主要是用作数据域的对齐,提高数据结构访问的效率。pid是输出日志信息的进程的pid, tid是输出日志信息的进程的tid。sec和nsec构成了日志输出时的时间。msg代表负载的开始处。负载就是我们要输出的一些字符串信息,它们的大小本身是不会影响logger_entry结构体本身的大小。事实上,logger_entry结构体可视为一个可变大小的结构体定义的范例。*/#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 __LOGGERIO0xAE//定义ioctl命令码的设备类型为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 */

再来阅读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 miscdevicemisc;/* misc device representing the log */wait_queue_head_twq;/* wait queue for readers */struct list_headreaders; /* this log's readers */struct mutexmutex;/* mutex protecting buffer */size_tw_off;/* current write head offset */size_thead;/* new readers start here */size_tsize;/* 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_headlist;/* entry in logger_log's list */size_tr_off;/* current read head offset */};/*该数据结构定义了一个设备结构体,用于读日志信息*//* logger_offset - returns index 'n' into the log via (optimized) modulus */#define logger_offset(n)((n) & (log->size - 1))/*通过模运算返回索引号n在log中对应的offset。*//* * file_get_log - Given a file structure, return the associated log * * This isn't aesthetic. We have several goals: * * 1) Need to quickly obtain the associated log during an I/O operation * 2) Readers need to maintain state (logger_reader) * 3) Writers need to be very fast (open() should be a near no-op) * * In the reader case, we can trivially go file->logger_reader->logger_log. * For a writer, we don't want to maintain a logger_reader, so we just go * file->logger_log. Thus what file->private_data points at depends on whether * or not the file was opened for reading. This function hides that dirtiness. */static inline struct logger_log * file_get_log(struct file *file){   /*当在读模式下时*/if (file->f_mode & FMODE_READ) {struct logger_reader *reader = file->private_data;return reader->log;} elsereturn file->private_data;}/*返回与file相关联的logger_log结构体。*//* * 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;   //log->buffer的开始处是头,而头的前两个字节记录了负载的长度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;}/*返回位于下一个位于off处的日志项负载的大小,注意该大小包括日志项结构体本身的大小*//* * do_read_log_to_user - reads exactly 'count' bytes from 'log' into the * user-space buffer 'buf'. Returns 'count' on success. * * Caller must hold log->mutex. */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;      /*因为缓冲区是环形的,所以当从offset开始到缓冲区的最后一位之间的大小小于count时,就要分两步读,第一次读到缓冲区末尾,第二次从缓冲区开始处读取剩余的字节大小的数据*//* * 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. */   /*当count == len时,表明缓冲区从当前位置到结尾处的大小大于count*/if (count != len)if (copy_to_user(buf + len, log->buffer, count - len))return -EFAULT;   //重新计算当前的offsetreader->r_off = logger_offset(reader->r_off + count);return count;}/*返回log中的数据到用户空间的缓冲区*//* * 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);   //定义一个等待队列项,它将在等待队列log->wq上休眠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) //只要log->w_off != reader->r_off即可读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;}/* * 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;   //找到第一个超过当off至少len长的第一个合法的日志项的offset。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;}/* * 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;      //修正log->head, 将其后移lenif (clock_interval(old, new, log->head))log->head = get_next_entry(log, log->head, len);   //修正所有当前的reader->r_off与log->w_off的距离小于len的日志项,将reader->r_off后移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);}/* * 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;   //写入count个字节的数据,len = min(count, log->size - log->w_off);memcpy(log->buffer + log->w_off, buf, len);   //当count-len大于零时,将剩余的数据从开头处开始写入if (count != len)memcpy(log->buffer, buf + len, count - len);log->w_off = logger_offset(log->w_off + count);}/* * do_write_log_user - writes 'len' bytes from the user-space buffer 'buf' to * the log 'log' * * The caller needs to hold log->mutex. * * Returns 'count' on success, negative error code on failure. */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;}/* * 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;}static struct logger_log * get_log_from_minor(int);/* * 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当前的读位置reader->r_off = log->head;list_add_tail(&reader->list, &log->readers);mutex_unlock(&log->mutex);file->private_data = reader;} elsefile->private_data = log;return 0;}/* * logger_release - the log's release file operation * * Note this is a total no-op in the write-only case. Keep it that way! */static int logger_release(struct inode *ignored, struct file *file){   //只有在读模式下才会去释放分配的内存空间if (file->f_mode & FMODE_READ) {struct logger_reader *reader = file->private_data;list_del(&reader->list);kfree(reader);}return 0;}/* * logger_poll - the log's poll file operation, for poll/select/epoll * * Note we always return POLLOUT, because you can always write() to the log. * Note also that, strictly speaking, a return value of POLLIN does not * guarantee that the log is readable without blocking, as there is a small * chance that the writer can lap the reader in the interim between poll() * returning and the read() request. */static unsigned int logger_poll(struct file *file, poll_table *wait){struct logger_reader *reader;struct logger_log *log;unsigned int ret = POLLOUT | POLLWRNORM;   //总是可写的if (!(file->f_mode & FMODE_READ))return ret;reader = file->private_data;log = reader->log;   //将当前进行添加到wait指定的等待列表(轮询表)中poll_wait(file, &log->wq, wait);mutex_lock(&log->mutex);if (log->w_off != reader->r_off)ret |= POLLIN | POLLRDNORM;mutex_unlock(&log->mutex);return ret;}//ioctl实现函数static long logger_ioctl(struct file *file, unsigned int cmd, unsigned long arg){struct logger_log *log = file_get_log(file);struct logger_reader *reader;long ret = -ENOTTY;mutex_lock(&log->mutex);switch (cmd) {case LOGGER_GET_LOG_BUF_SIZE:ret = log->size;break;case LOGGER_GET_LOG_LEN:if (!(file->f_mode & FMODE_READ)) {ret = -EBADF;break;}reader = file->private_data;if (log->w_off >= reader->r_off)ret = log->w_off - reader->r_off;elseret = (log->size - reader->r_off) + log->w_off;break;case LOGGER_GET_NEXT_ENTRY_LEN:if (!(file->f_mode & FMODE_READ)) {ret = -EBADF;break;}reader = file->private_data;if (log->w_off != reader->r_off)ret = get_entry_len(log, reader->r_off);elseret = 0;break;case LOGGER_FLUSH_LOG:if (!(file->f_mode & FMODE_WRITE)) {ret = -EBADF;break;}list_for_each_entry(reader, &log->readers, list)reader->r_off = log->w_off;log->head = log->w_off;ret = 0;break;}mutex_unlock(&log->mutex);return ret;}//定义字符设备操作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,};/* * 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)//根据次设备号返回相应的设备static struct logger_log * get_log_from_minor(int minor){if (log_main.misc.minor == minor)return &log_main;if (log_events.misc.minor == minor)return &log_events;if (log_radio.misc.minor == minor)return &log_radio;return NULL;}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;}//字符设备初始化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);


更多相关文章

  1. 【整理】Android中EditText中的InputType类型含义与如何定义
  2. Android高德地图自定义放大缩小控件
  3. 自定义Android应用程序标题条
  4. Android日志系统分析之日志设备驱动程序代码阅读
  5. android 自带的主题 theme 的使用
  6. 关于GridView控件中设置大小的问题
  7. 自定义RadioButton 文字在下,图片在上
  8. android 自定义加减按钮
  9. android AlertDialog 弹窗自定义布局 点击外部不关闭弹窗

随机推荐

  1. Android学习札记26:深入理解Android中的消
  2. Android学习之期末复习重点整理
  3. Android中转义字符
  4. Android(安卓)Building System 总结
  5. Android报表解决方案 使用开源组件iChart
  6. 丢失Android系统库或者Conversion to Dal
  7. 致Android初学者:如何学习Android开发
  8. android应用开发总论
  9. Android(安卓)中判断网络连接和GPS是否可
  10. [转]Android笔记:Eclipse嵌入Unity3D开发