📄 init.c
字号:
char name[16]; int number;} mtd_part_map[MAX_MTD_PARTITIONS];static int mtd_part_count = -1;static void find_mtd_partitions(void){ int fd; char buf[1024]; char *pmtdbufp; ssize_t pmtdsize; int r; fd = open("/proc/mtd", O_RDONLY); if (fd < 0) return; buf[sizeof(buf) - 1] = '\0'; pmtdsize = read(fd, buf, sizeof(buf) - 1); pmtdbufp = buf; while (pmtdsize > 0) { int mtdnum, mtdsize, mtderasesize; char mtdname[16]; mtdname[0] = '\0'; mtdnum = -1; r = sscanf(pmtdbufp, "mtd%d: %x %x %15s", &mtdnum, &mtdsize, &mtderasesize, mtdname); if ((r == 4) && (mtdname[0] == '"')) { char *x = strchr(mtdname + 1, '"'); if (x) { *x = 0; } INFO("mtd partition %d, %s\n", mtdnum, mtdname + 1); if (mtd_part_count < MAX_MTD_PARTITIONS) { strcpy(mtd_part_map[mtd_part_count].name, mtdname + 1); mtd_part_map[mtd_part_count].number = mtdnum; mtd_part_count++; } else { ERROR("too many mtd partitions\n"); } } while (pmtdsize > 0 && *pmtdbufp != '\n') { pmtdbufp++; pmtdsize--; } if (pmtdsize > 0) { pmtdbufp++; pmtdsize--; } } close(fd);}int mtd_name_to_number(const char *name) { int n; if (mtd_part_count < 0) { mtd_part_count = 0; find_mtd_partitions(); } for (n = 0; n < mtd_part_count; n++) { if (!strcmp(name, mtd_part_map[n].name)) { return mtd_part_map[n].number; } } return -1;}static void import_kernel_nv(char *name, int in_qemu){ char *value = strchr(name, '='); if (value == 0) return; *value++ = 0; if (*name == 0) return; if (!in_qemu) { /* on a real device, white-list the kernel options */ if (!strcmp(name,"qemu")) { strlcpy(qemu, value, sizeof(qemu)); } else if (!strcmp(name,"androidboot.console")) { strlcpy(console, value, sizeof(console)); } else if (!strcmp(name,"androidboot.mode")) { strlcpy(bootmode, value, sizeof(bootmode)); } else if (!strcmp(name,"androidboot.serialno")) { strlcpy(serialno, value, sizeof(serialno)); } else if (!strcmp(name,"androidboot.baseband")) { strlcpy(baseband, value, sizeof(baseband)); } else if (!strcmp(name,"androidboot.carrier")) { strlcpy(carrier, value, sizeof(carrier)); } else if (!strcmp(name,"androidboot.bootloader")) { strlcpy(bootloader, value, sizeof(bootloader)); } else if (!strcmp(name,"androidboot.hardware")) { strlcpy(hardware, value, sizeof(hardware)); } else { qemu_cmdline(name, value); } } else { /* in the emulator, export any kernel option with the * ro.kernel. prefix */ char buff[32]; int len = snprintf( buff, sizeof(buff), "ro.kernel.%s", name ); if (len < (int)sizeof(buff)) { property_set( buff, value ); } }}static void import_kernel_cmdline(int in_qemu){ char cmdline[1024]; char *ptr; int fd; fd = open("/proc/cmdline", O_RDONLY); if (fd >= 0) { int n = read(fd, cmdline, 1023); if (n < 0) n = 0; /* get rid of trailing newline, it happens */ if (n > 0 && cmdline[n-1] == '\n') n--; cmdline[n] = 0; close(fd); } else { cmdline[0] = 0; } ptr = cmdline; while (ptr && *ptr) { char *x = strchr(ptr, ' '); if (x != 0) *x++ = 0; import_kernel_nv(ptr, in_qemu); ptr = x; } /* don't expose the raw commandline to nonpriv processes */ chmod("/proc/cmdline", 0440);}static void get_hardware_name(void){ char data[1024]; int fd, n; char *x, *hw, *rev; /* Hardware string was provided on kernel command line */ if (hardware[0]) return; fd = open("/proc/cpuinfo", O_RDONLY); if (fd < 0) return; n = read(fd, data, 1023); close(fd); if (n < 0) return; data[n] = 0; hw = strstr(data, "\nHardware"); rev = strstr(data, "\nRevision"); if (hw) { x = strstr(hw, ": "); if (x) { x += 2; n = 0; while (*x && !isspace(*x)) { hardware[n++] = tolower(*x); x++; if (n == 31) break; } hardware[n] = 0; } } if (rev) { x = strstr(rev, ": "); if (x) { revision = strtoul(x + 2, 0, 16); } }}static void drain_action_queue(void){ struct listnode *node; struct command *cmd; struct action *act; int ret; while ((act = action_remove_queue_head())) { INFO("processing action %p (%s)\n", act, act->name); list_for_each(node, &act->commands) { cmd = node_to_item(node, struct command, clist); ret = cmd->func(cmd->nargs, cmd->args); INFO("command '%s' r=%d\n", cmd->args[0], ret); } }}void open_devnull_stdio(void){ int fd; static const char *name = "/dev/__null__"; if (mknod(name, S_IFCHR | 0600, (1 << 8) | 3) == 0) { fd = open(name, O_RDWR); unlink(name); if (fd >= 0) { dup2(fd, 0); dup2(fd, 1); dup2(fd, 2); if (fd > 2) { close(fd); } return; } } exit(1);}int main(int argc, char **argv){ int device_fd = -1; int property_set_fd = -1; int signal_recv_fd = -1; int s[2]; int fd; struct sigaction act; char tmp[PROP_VALUE_MAX]; struct pollfd ufds[4]; char *tmpdev; act.sa_handler = sigchld_handler; act.sa_flags = SA_NOCLDSTOP; act.sa_mask = 0; act.sa_restorer = NULL; sigaction(SIGCHLD, &act, 0); /* clear the umask */ umask(0); /* Get the basic filesystem setup we need put * together in the initramdisk on / and then we'll * let the rc file figure out the rest. */ mkdir("/dev", 0755); mkdir("/proc", 0755); mkdir("/sys", 0755); mount("tmpfs", "/dev", "tmpfs", 0, "mode=0755"); mkdir("/dev/pts", 0755); mkdir("/dev/socket", 0755); mount("devpts", "/dev/pts", "devpts", 0, NULL); mount("proc", "/proc", "proc", 0, NULL); mount("sysfs", "/sys", "sysfs", 0, NULL); /* We must have some place other than / to create the * device nodes for kmsg and null, otherwise we won't * be able to remount / read-only later on. * Now that tmpfs is mounted on /dev, we can actually * talk to the outside world. */ open_devnull_stdio(); log_init(); INFO("reading config file\n"); parse_config_file("/init.rc"); /* pull the kernel commandline and ramdisk properties file in */ qemu_init(); import_kernel_cmdline(0); get_hardware_name(); snprintf(tmp, sizeof(tmp), "/init.%s.rc", hardware); parse_config_file(tmp); action_for_each_trigger("early-init", action_add_queue_tail); drain_action_queue(); INFO("device init\n"); device_fd = device_init(); property_init(); if (console[0]) { snprintf(tmp, sizeof(tmp), "/dev/%s", console); console_name = strdup(tmp); } fd = open(console_name, O_RDWR); if (fd >= 0) have_console = 1; close(fd); if( load_565rle_image(INIT_IMAGE_FILE) ) { fd = open("/dev/tty0", O_WRONLY); if (fd >= 0) { const char *msg; msg = "\n" "\n" "\n" "\n" "\n" "\n" "\n" // console is 40 cols x 30 lines "\n" "\n" "\n" "\n" "\n" "\n" "\n" " A N D R O I D "; write(fd, msg, strlen(msg)); close(fd); } } if (qemu[0]) import_kernel_cmdline(1); if (!strcmp(bootmode,"factory")) property_set("ro.factorytest", "1"); else if (!strcmp(bootmode,"factory2")) property_set("ro.factorytest", "2"); else property_set("ro.factorytest", "0"); property_set("ro.serialno", serialno[0] ? serialno : ""); property_set("ro.bootmode", bootmode[0] ? bootmode : "unknown"); property_set("ro.baseband", baseband[0] ? baseband : "unknown"); property_set("ro.carrier", carrier[0] ? carrier : "unknown"); property_set("ro.bootloader", bootloader[0] ? bootloader : "unknown"); property_set("ro.hardware", hardware); snprintf(tmp, PROP_VALUE_MAX, "%d", revision); property_set("ro.revision", tmp); /* execute all the boot actions to get us started */ action_for_each_trigger("init", action_add_queue_tail); drain_action_queue(); /* read any property files on system or data and * fire up the property service. This must happen * after the ro.foo properties are set above so * that /data/local.prop cannot interfere with them. */ property_set_fd = start_property_service(); /* create a signalling mechanism for the sigchld handler */ if (socketpair(AF_UNIX, SOCK_STREAM, 0, s) == 0) { signal_fd = s[0]; signal_recv_fd = s[1]; fcntl(s[0], F_SETFD, FD_CLOEXEC); fcntl(s[0], F_SETFL, O_NONBLOCK); fcntl(s[1], F_SETFD, FD_CLOEXEC); fcntl(s[1], F_SETFL, O_NONBLOCK); } /* make sure we actually have all the pieces we need */ if ((device_fd < 0) || (property_set_fd < 0) || (signal_recv_fd < 0)) { ERROR("init startup failure\n"); return 1; } /* execute all the boot actions to get us started */ action_for_each_trigger("early-boot", action_add_queue_tail); action_for_each_trigger("boot", action_add_queue_tail); drain_action_queue(); /* run all property triggers based on current state of the properties */ queue_all_property_triggers(); drain_action_queue(); /* enable property triggers */ property_triggers_enabled = 1; ufds[0].fd = device_fd; ufds[0].events = POLLIN; ufds[1].fd = property_set_fd; ufds[1].events = POLLIN; ufds[2].fd = signal_recv_fd; ufds[2].events = POLLIN;#if BOOTCHART if (bootchart_init() < 0) ERROR("bootcharting init failure\n"); else { NOTICE("bootcharting started\n"); bootchart_count = BOOTCHART_MAX_COUNT; }#endif for(;;) { int nr, timeout = -1; ufds[0].revents = 0; ufds[1].revents = 0; ufds[2].revents = 0; drain_action_queue(); restart_processes(); if (process_needs_restart) { timeout = (process_needs_restart - gettime()) * 1000; if (timeout < 0) timeout = 0; }#if BOOTCHART if (bootchart_count > 0) { if (timeout < 0 || timeout > BOOTCHART_POLLING_MS) timeout = BOOTCHART_POLLING_MS; if (bootchart_step() < 0 || --bootchart_count == 0) { bootchart_finish(); bootchart_count = 0; } }#endif nr = poll(ufds, 3, timeout); if (nr <= 0) continue; if (ufds[2].revents == POLLIN) { /* we got a SIGCHLD - reap and restart as needed */ read(signal_recv_fd, tmp, sizeof(tmp)); while (!wait_for_one_process(0)) ; continue; } if (ufds[0].revents == POLLIN) handle_device_fd(device_fd); if (ufds[1].revents == POLLIN) handle_property_set_fd(property_set_fd); } return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -