《Linux设备节点创建》用户空间ueventd创建设备节点规则

说明:本文基于Android2.3和Linux2.6,其余版本仅供参考。

Android2.3及Linux2.6.29内核模拟器版本编译与调试

一、devfs、udev和sysfs是什么关系?

linux2.6之前使用devfs设备文件系统,它存在与内核空间;

linux2.6之后使用udev设备文件系统,它存在与用户空间、但严重依赖与sysfs文件系统。

二、Android(使用linux2.6以后的设备节点创建策略)设备节点的创建

  在Android中,没有独立的类似于udev或者mdev的用户程序,这个功能集成到了init中做了。代码见:system/core/init/init.c文件,如下:

if (ufds[0].revents == POLLIN)
  handle_device_fd(device_fd);

其中handle_device_fd(device_fd)函数在system/core/init/devices.c中实现,参数device_fd 由函数device_init()->open_uevent_socket()->socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT)函数调用返回。

函数handle_device_fd(device_fd)中,根据传进来的device_fd参数,调用recv(fd, msg, UEVENT_MSG_LEN, 0)函数,将内核探测到的设备并通过NETLINK机制传过来的socket描述符转化成消息。接着调用parse_event(msg, &uevent);函数将消息翻译成uevent事件,并将改事件传递给handle_device_event(&uevent)函数。

handle_device_event(&uevent)函数中,依据参数uevent->subsystem类型创建dev下的相应目录,如:/dev/graphics。紧接着根据uevent->action是"add"还是"remove"来实现设备节点的创建与删除。如果uevent->action是"add",则调用make_device(devpath, block, uevent->major, uevent->minor)函数生成设备节点。如果uevent->action是"remove",则调用unlink(devpath)对设备节点进行删除。

三、下边看看Android的ueventd进程

说明:其配置文件uevent.rc不起实际作用,只是对创建的设备节点文件属性做设置。

1.system/core/init/ueventd.c

int ueventd_main(int argc, char **argv){
  device_init();
  /*
  system/core/init/device.c
  void device_init(void){
    device_fd = uevent_open_socket(64*1024, true);
    coldboot("/sys/class");
    coldboot("/sys/block");
    coldboot("/sys/devices");
  }
  */
  ufd.events = POLLIN;
  ufd.fd = get_device_fd();
  while(1) {
    ufd.revents = 0;
    nr = poll(&ufd, 1, -1);
    if (nr <= 0)
      continue;
    if (ufd.revents == POLLIN)
      handle_device_fd();
  }     
}

2.system/core/init/device.c

注意:只有主次设备号的事件才会创建设备节点

void handle_device_fd(){
  while ((n = uevent_kernel_multicast_recv(device_fd, msg, UEVENT_MSG_LEN)) > 0) {
    handle_device_event(&uevent);
  }
}
static void handle_device_event(struct uevent *uevent){
  if (!strcmp(uevent->action,"add"))
    fixup_sys_perms(uevent->path);

  /* if it's not a /dev device, nothing else to do */
  if((uevent->major < 0) || (uevent->minor < 0)){//只有主次设备号的事件才会创建设备节点
    //ERROR("TK------------>>>>device.c>>>>>>handle_device_event>>>>>>uevent->major and minor < 0\n");//add by tankai
    return;
  }
  if(!strncmp(uevent->subsystem, "block", 5)) {
    block = 1;
    base = "/dev/block/";
    mkdir(base, 0755);
    if (!strncmp(uevent->path, "/devices/platform/", 18))
      links = parse_platform_block_device(uevent);
  } else {
    block = 0;
    /* this should probably be configurable somehow */
    if (!strncmp(uevent->subsystem, "usb", 3)) {
      if (!strcmp(uevent->subsystem, "usb")) {
        /* This imitates the file system that would be created
        * if we were using devfs instead.
        * Minors are broken up into groups of 128, starting at "001"
        */
        int bus_id = uevent->minor / 128 + 1;
        int device_id = uevent->minor % 128 + 1;
        /* build directories */
        mkdir("/dev/bus", 0755);
        mkdir("/dev/bus/usb", 0755);
        snprintf(devpath, sizeof(devpath), "/dev/bus/usb/%03d", bus_id);
        mkdir(devpath, 0755);
        snprintf(devpath, sizeof(devpath), "/dev/bus/usb/%03d/%03d", bus_id, device_id);
        devpath_ready = 1;
      } else {
        /* ignore other USB events */
        return;
      }
    } else if (!strncmp(uevent->subsystem, "graphics", 8)) {
      base = "/dev/graphics/";
      mkdir(base, 0755);
    } else if (!strncmp(uevent->subsystem, "oncrpc", 6)) {
      base = "/dev/oncrpc/";
      mkdir(base, 0755);
    } else if (!strncmp(uevent->subsystem, "adsp", 4)) {
      base = "/dev/adsp/";
      mkdir(base, 0755);
    } else if (!strncmp(uevent->subsystem, "msm_camera", 10)) {
      base = "/dev/msm_camera/";
      mkdir(base, 0755);
    } else if(!strncmp(uevent->subsystem, "input", 5)) {
      base = "/dev/input/";
      mkdir(base, 0755);
    } else if(!strncmp(uevent->subsystem, "mtd", 3)) {
      base = "/dev/mtd/";
      mkdir(base, 0755);
    } else if(!strncmp(uevent->subsystem, "sound", 5)) {
      base = "/dev/snd/";
      mkdir(base, 0755);
    } else if(!strncmp(uevent->subsystem, "misc", 4) &&
                    !strncmp(name, "log_", 4)) {
      base = "/dev/log/";
      mkdir(base, 0755);
      name += 4;
    } else
      base = "/dev/";
  }

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

  if(!strcmp(uevent->action, "add")) {
    //ERROR("TK------_>>>>>>>>>make_devices\n");//add by tankai
    make_device(devpath, uevent->path, block, uevent->major, uevent->minor);
    if (links) {
      for (i = 0; links[i]; i++)
        make_link(devpath, links[i]);
    }
  }
}
static void make_device(const char *path,
                        const char *upath,
                        int block, int major, int minor)
{
  mode = get_device_perm(path, &uid, &gid) | (block ? S_IFBLK : S_IFCHR);
  setegid(gid);
  mknod(path, mode, dev);
  chown(path, uid, -1);
  setegid(AID_ROOT);
}


你可能感兴趣的:(《Linux设备节点创建》用户空间ueventd创建设备节点规则)