Android设备目录和节点的创建

    在编写linux设备驱动程序的时候,很多时候都是利用mknod命令来手动创建设备节点的,带上名字和主次设备号就可以在/dev目录下生成设备节点。同样Android沿用了linux内核,很多设备驱动的节点是又是什么时候创建的呢? 

    在kernel自解压模块加载完成之后,会去运行android第一个应用程序init。在init.c的main函数中。


System/core/init/init.c 
int main(int argc, char **argv) 
{ 
	…… 
	action_for_each_trigger("boot", action_add_queue_tail); 
	…… 
}

    在init进程解析init.rc脚本完成后,在onboot的最后两句是classstart maincore,其中class

    Start是命令,在keyword.h中定义了class_start对应的function实际就是do_class_start

System/core/init/builtins.c
int do_class_start(int nargs, char **args)
{
	service_for_each_class(args[1], service_start_if_not_disabled);
	return 0;
}

System/core/init/init_parser.c
void service_for_each_class(const char *classname, void (*func)(struct service *svc))
{
	……
	list_for_each(node, &service_list) 
	{
		svc = node_to_item(node, struct service, slist);
		if (!strcmp(svc->classname, classname)) 
		{
			func(svc);
		}   
	}
}

    在之前解析init.rc脚本的时候,service会被放在service_list的链表里。接下来就是要执行service_for_each_classfunc(svc),也就是service_start_if_not_disabled

System/core/init/builtins.c
static void service_start_if_not_disabled(struct service *svc)
{
	if (!(svc->flags & SVC_DISABLED)) 
	{
		service_start(svc, NULL);
	}   
}

    Android的service大都是编译成可执行文件以命令的格式,我们注意到在init.rc中又这么个service值得关注下。

service ueventd /sbin/ueventd
	class core
	critical

    Android的服务不是选项不是disabled并且带core和main的选项的服务都是需要开机自动加载的服务。而ueventd是由system/core/init/ueventd.c编译而成的。

System/core/init/ueventd.c
int ueventd_main(int argc, char **argv)
{
	……
	ueventd_parse_config_file("/ueventd.rc");
	……
	snprintf(tmp, sizeof(tmp), "/ueventd.%s.rc", hardware);
	ueventd_parse_config_file(tmp);
	……
	device_init();
	……
	while(1) {
		ufd.revents = 0;
		nr = poll(&ufd, 1, -1);
		if (nr <= 0)
			continue;
		if (ufd.revents == POLLIN)
			handle_device_fd();
	}
}

    Ueventd的main函数做的事情比较多,首先是要解析根文件系统下的ueventd.rc以及ueventd.${hardware}.rc。

System/core/init/devices.c
void handle_device_fd()
{
……
	char msg[UEVENT_MSG_LEN+2];
	int  n; 
	while ((n = uevent_kernel_multicast_recv(device_fd, msg, UEVENT_MSG_LEN)) > 0) {
		if(n >= UEVENT_MSG_LEN)   /* overflow -- discard */
			continue;

		msg[n] = '\0';
		msg[n+1] = '\0';

		struct uevent uevent;
		parse_event(msg, &uevent);

		handle_device_event(&uevent);
		handle_firmware_event(&uevent);
	}       
}   

    接收的uevent的小心不能超过1024个字节,如果超出就算溢出将不会处理。如果接收的uevent有效,解析这个uevent会根据设备的类型来解析。之后handle_device_event会处理设备的event。而handle_firmware_event则是和某些设备需要firmware回去处理firmware的加载。

System/core/init/devices.c
static void handle_device_event(struct uevent *uevent)
{
	if (!strcmp(uevent->action,"add"))
		fixup_sys_perms(uevent->path);

	if (!strncmp(uevent->subsystem, "block", 5)) {
		handle_block_device_event(uevent);
	} else if (!strncmp(uevent->subsystem, "platform", 8)) {
		handle_platform_device_event(uevent);
	} else {
		handle_generic_device_event(uevent);
	}
}
   

    首先得到设备的名字,然后是创建一些设备的子目录,如果uevent->subsystem是usb,就需要创建一个/dev/bus/usb的目录。如果是uevent->subsystem是graphic的话,就需要创建一个/dev/graphics的目录,按照这样依次比较下去,创建设备类所需要的子目录。

System/core/init/devices.c
static void handle_device(const char *action, const char *devpath, const char *path, int block, int major, int minor, char **links)
{
	……
	if(!strcmp(action, "add")) {
		make_device(devpath, path, block, major, minor);
	……
}

    如果uevent的action是设备添加,就会调用make_device来创建设备节点。

System/core/init/devices.c
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);
	dev = makedev(major, minor);
	setegid(gid);
	mknod(path, mode, dev);
	chown(path, uid, -1);
	setegid(AID_ROOT);
}

    通过get_device_perm得到设备的访问权限,makedev根据主设备号和次设备号得到dev。设置临时setegid,然后又mknod就在设备相应的目录下面创建了设备节点。最后将设备的egid设备为AID_ROOT。到这里整个android的设备目录和节点就创建完成了。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章