三、 Logger初始化过程分析。
kernel/drivers/staging/Android/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(l og_radio LOGGER_LOG_RADIO , 64*1024)  
DEFINE_LOGGER_DEVICE(log_system, LOGGER_LOG_SYSTEM, 64*1024
      上面的代码创建了 log_main log_events,log_system log_radio 这4个logger_log结构体,名称分别 LOGGER_LOG_MAIN LOGGER_LOG_EVENTS,LOGGER_LOG_SYSTEM LOGGER_LOG_RADIO ,它们的次设备号为MISC_DYNAMIC_MINOR,即为在注册时动态分配。在 logger.h 文件中,这三个宏的定义如下:
        #define LOGGER_LOG_RADIO "log_radio" /* radio-related messages */
       #define LOGGER_LOG_EVENTS "log_events" /* system/hardware events */
       #define LOGGER_LOG_SYSTEM "log_system" /* system/framework  message*/
       #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;  
    ret = init_log(&log_system);  
    if (unlikely(ret))  
        goto out;  
out:  
    return ret;  
}  
device_initcall( logger_init );  

logger_init 函数通过调用 init_log 函数来初始化了上述提到的4个日志设备.
关于 static int  __init  logger_init(void)  __init的意义请参照《 linux代码中的__init和__exit宏
关于 device_initcall( logger_init );  请参考《 Linux内核中的xx_initcall
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;  
}  
   init_log 函数主要调用了 misc_register 函数来注册misc设备, misc_register 函数定义在 kernel/common/drivers/char/misc.c 文件中:
/** 
 *      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;  
}  
注册完成后,通过device_create创建设备文件节点。
这样将创建 /sys/class/misc/log_radion , /sys/class/misc/log_events , /sys/class/misc/log_system , /sys/class/misc/log_main 四个设备节点文件。
我们一般是通过读写这四个文件的映射文件来进行交互。映射文件分别为 /dev/log/radio , /dev/log/events , /dev/log/system , /dev/log/main
应用init层之后init进程
在system/core/init/devices.c中device_init()->coldboot()->do_coldboot()->handle_device_fd()->handle_device_event()
static void handle_device_event(struct uevent *uevent)
{
     char devpath[96];
     char *base, *name;
    i nt block;

         /* if it's not a /dev device, nothing to do */
     if((uevent->major < 0) || (uevent->minor < 0))
         return;

         /* do we have a name? */
    name = strrchr(uevent->path, '/');
     if(!name)
         return;
    name++;

         /* too-long names would overrun our buffer */
     if(strlen(name) > 64)
        return;

         /* are we block or char? where should we live? */
     if(!strncmp(uevent->path, "/block", 6)) {
        block = 1;
        base = "/dev/block/";
        mkdir(base, 0755);
    }  else {
        block = 0;
             /* this should probably be configurable somehow */
         if(!strncmp(uevent->path, "/class/graphics/", 16)) {
            base = "/dev/graphics/";
            mkdir(base, 0755);
        }  else if (!strncmp(uevent->path, "/class/oncrpc/", 14)) {
            base = "/dev/oncrpc/";
            mkdir(base, 0755);
        }  else if (!strncmp(uevent->path, "/class/adsp/", 12)) {
            base = "/dev/adsp/";
            mkdir(base, 0755);
      }  else if(!strncmp(uevent->path, "/class/input/", 13)) {
            base = "/dev/input/";
            mkdir(base, 0755);
        }  else if(!strncmp(uevent->path, "/class/mtd/", 11)) {
            base = "/dev/mtd/";
            mkdir(base, 0755);
        }  else if(!strncmp(uevent->path,  "/class/misc/", 12) &&
                    !strncmp(name, " log_", 4)) {
            base = " /dev/log/";
             mkdir(base, 0755);
            name += 4;
        } else
            base = "/dev/";
    }

     snprintf(devpath, sizeof(devpath), "%s%s", base, name);

     if(!strcmp(uevent->action, "add")) {
         make_device(devpath, block, uevent->major, uevent->minor);
         return;
    }

     if(!strcmp(uevent->action, "remove")) {
        unlink(devpath);
         return;
    }
}
这样将日志的四个设备节点文件映射为以下4个文件/dev/log/radio,/dev/log/events,/dev/log/system,/dev/log/main.
Logo

更多推荐