在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 main和core,其中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_class的func(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的設備目錄和節點就創建完成了。