linux源码版本-->3.4
一.总体分析
1.
-
root@MLTE4:/ # ps
-
USER PID PPID VSIZE RSS WCHAN PC NAME
-
root 1 0 1612 428 ffffffff 0001d82c S /init
-
root 2 0 0 0 c0048904 00000000 S kthreadd
-
root 3 2 0 0 c002ee84 00000000 S ksoftirqd/0
-
root 4 2 0 0 c00438bc 00000000 S kworker/0:0
-
root 6 2 0 0 c0089278 00000000 S migration/0
- root 7 2 0 0 c009dacc 00000000 S watchdog/0
二.init进程的启动
三.init进程分析
3.0 在sytem/core/init/init.c中
-
int main(int argc, char **argv)
-
{
-
int fd_count = 0;
-
struct pollfd ufds[4];
-
char *tmpdev;
-
char* debuggable;
-
char tmp[32];
-
int property_set_fd_init = 0;
-
int signal_fd_init = 0;
-
int keychord_fd_init = 0;
-
bool is_charger = false;
-
-
char* args_swapon[2];
-
args_swapon[0] = "swapon_all";;
-
args_swapon[1] = "/fstab.sun8i";;
-
-
char* args_write[3];
-
args_write[0] = "write";
-
args_write[1] = "/proc/sys/vm/page-cluster";
-
args_write[2] = "0";
- //init与ueventd与watchdogd共享一份代码,通过argv[0]来区分到底是调用的哪一个
-
if (!strcmp(basename(argv[0]), "ueventd"))
-
return ueventd_main(argc, argv);
-
-
if (!strcmp(basename(argv[0]), "watchdogd"))
-
return watchdogd_main(argc, argv);
-
-
/* clear the umask */
-
ERROR("init proc start\n");
-
umask(0);
-
-
//创建dev proc sys目录并分别挂载
-
mkdir("/dev", 0755);
-
mkdir("/proc", 0755);
-
mkdir("/sys", 0755);
-
-
mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "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);
-
- close(open("/dev/.booting", O_WRONLY | O_CREAT, 0000)); //这个不知道谁会用到
-
//因为现在/dev/刚刚挂载,/dev/下面没有任何文件
-
//创建设备结点/dev/__null__,其实就是/dev/null,将标准输入输出与错误都重定向到/dev/__null__上面
- open_devnull_stdio();
- //创建设备结点/dev/__kmsg__,其实就是/dev/kmsg,临时先借用内核的打印函数来输出调试信息
- klog_init();
-
property_init(); //初始化android的属性系统
-
//打开/proc/cpuinfo,读取文件中全部数据到buf中,查到buf中的Hardware与revision字段,将其值保存在hardware与revision下
-
get_hardware_name(hardware, &revision);
-
//打开/proc/cmdline,读取文件中全部数据到buf中,查到buf中的Hardware与revision字段,将其值保存在hardware与revision下
-
process_kernel_cmdline();
-
-
#if ASYNC_INIT_SELINUX
-
int err = 0;
-
int selinux_tid = 0;
-
INFO("Selinux async initialize...\n");
-
err = pthread_create(&selinux_tid, NULL, selinux_init_thread, NULL);
-
if (err != 0)
-
{
-
ERROR("create selinux init thread failed: %s\n", strerror(err));
-
return -1;
-
}
-
#else
-
INFO("Selinux sync initialize...\n");
-
union selinux_callback cb;
-
cb.func_log = klog_write;
-
selinux_set_callback(SELINUX_CB_LOG, cb);
-
-
cb.func_audit = audit_callback;
-
selinux_set_callback(SELINUX_CB_AUDIT, cb);
-
-
selinux_initialize();
-
/* These directories were necessarily created before initial policy load
-
* and therefore need their security context restored to the proper value.
-
* This must happen before /dev is populated by ueventd.
-
*/
-
#endif
-
if (!selinux_is_disabled()) {
-
restorecon("/dev");
-
restorecon("/dev/socket");
-
restorecon("/dev/__properties__");
-
restorecon_recursive("/sys");
-
}
-
-
is_charger = !strcmp(bootmode, "charger");
- if (!is_charger)
- property_load_boot_defaults();
- //打开/proc/cmdline,读取文件中全部数据到buf中,查到buf中的partitions=,在/dev/block/by-name中创建软连接
-
get_kernel_cmdline_partitions();
-
//打开/proc/cmdline,读取文件中全部数据到buf中,这儿没啥用处
-
get_kernel_cmdline_signature();
- //不仅仅解析init.rc还解析import的其它*.rc文件,这会构造多条list
- init_parse_config_file("/init.rc");
-
//把early-init与init中的命令都插入到队尾,因为队列是先进先出,所以early-init是最先执行的命令
-
action_for_each_trigger("early-init", action_add_queue_tail);
- action_for_each_trigger("init", action_add_queue_tail);
-
-
/* skip mounting filesystems in charger mode */
-
if (!is_charger) {
-
action_for_each_trigger("early-fs", action_add_queue_tail);
-
queue_builtin_action(wait_for_coldboot_done_action, "wait_for_coldboot_done");
-
queue_builtin_action(console_init_action, "console_init");
-
action_for_each_trigger("fs", action_add_queue_tail);
-
action_for_each_trigger("post-fs", action_add_queue_tail);
-
action_for_each_trigger("post-fs-data", action_add_queue_tail);
-
//SWAP TO ZRAM if low mem devices
-
if (!(get_dram_size() > 512)) {
-
char trigger[] = {"early-fs"};
-
ERROR("***************************LOW MEM DEVICE DETECT");
-
add_command(trigger, 2, args_swapon);
-
char trigger2[] = {"post-fs-data"};
-
add_command(trigger2, 3, args_write);
-
}
-
}
- queue_builtin_action(property_service_init_action, "property_service_init");
-
queue_builtin_action(init_set_disp_policy, "init_set_disp_policy");
-
queue_builtin_action(signal_init_action, "signal_init");
-
queue_builtin_action(check_startup_action, "check_startup");
-
-
if (is_charger) {
-
action_for_each_trigger("charger", action_add_queue_tail);
-
} else {
-
action_for_each_trigger("early-boot", action_add_queue_tail);
-
action_for_each_trigger("boot", action_add_queue_tail);
-
}
-
-
-
/* run all property triggers based on current state of the properties */
-
queue_builtin_action(queue_property_triggers_action, "queue_property_triggers");
-
-
-
#if BOOTCHART
-
queue_builtin_action(bootchart_init_action, "bootchart_init");
-
#endif
-
-
queue_builtin_action(init_sn, "init_sn");
-
for(;;) {
-
int nr, i, timeout = -1;
-
-
execute_one_command();
-
restart_processes();
-
-
if (!property_set_fd_init && get_property_set_fd() > 0) {
-
ufds[fd_count].fd = get_property_set_fd();
-
ufds[fd_count].events = POLLIN;
-
ufds[fd_count].revents = 0;
-
fd_count++;
-
property_set_fd_init = 1;
-
}
-
if (!signal_fd_init && get_signal_fd() > 0) {
-
ufds[fd_count].fd = get_signal_fd();
-
ufds[fd_count].events = POLLIN;
-
ufds[fd_count].revents = 0;
-
fd_count++;
-
signal_fd_init = 1;
-
}
-
if (!keychord_fd_init && get_keychord_fd() > 0) {
-
ufds[fd_count].fd = get_keychord_fd();
-
ufds[fd_count].events = POLLIN;
-
ufds[fd_count].revents = 0;
-
fd_count++;
-
keychord_fd_init = 1;
-
}
-
-
if (process_needs_restart) {
-
timeout = (process_needs_restart - gettime()) * 1000;
-
if (timeout < 0)
-
timeout = 0;
-
}
-
-
if (!action_queue_empty() || cur_action)
-
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, fd_count, timeout);
-
if (nr <= 0)
-
continue;
-
-
for (i = 0; i < fd_count; i++) {
-
if (ufds[i].revents == POLLIN) {
-
if (ufds[i].fd == get_property_set_fd())
-
handle_property_set_fd();
-
else if (ufds[i].fd == get_keychord_fd())
-
handle_keychord();
-
else if (ufds[i].fd == get_signal_fd())
-
handle_signal();
-
}
-
}
-
}
-
-
return 0;
- }
3.1 脚本解析的过程
-
int init_parse_config_file(const char *fn) //这里的fn="/init.rc"
-
{
-
char *data;
-
data = read_file(fn, 0); //将"/init.rc"的内容全部读取到以data为首指针的buffer中,函数会调用malloc
-
if (!data) return -1; //并在文件最后添加结束标志\n\0
-
-
parse_config(fn, data);
-
DUMP();
-
return 0;
- }
附录1:
/proc/cpuinfo
-
root@MLTE4:/ # cat /proc/cpuinfo
-
Processor : ARMv7 Processor rev 5 (v7l)
-
processor : 0
-
BogoMIPS : 4800.00
-
-
processor : 1
-
BogoMIPS : 4800.00
-
-
processor : 2
-
BogoMIPS : 4800.00
-
-
processor : 3
-
BogoMIPS : 4800.00
-
-
Features : swp half thumb fastmult vfp edsp thumbee neon vfpv3 tls vfpv4 idiva idivt
-
CPU implementer : 0x41
-
CPU architecture: 7
-
CPU variant : 0x0
-
CPU part : 0xc07
-
CPU revision : 5
-
-
Hardware : sun8i
-
Revision : 0000
- Serial : 54005035c4180838058e
-
root@MLTE4:/ # cat /proc/cmdline
- console=ttyS0,115200 root=/dev/block/mmcblk0p7 init=/init loglevel=15 vmalloc=384M partitions=bootloader@mmcblk0p2:env@mmcblk0p5:boot@mmcblk0p6:system@mmcblk0p7:misc@mmcblk0p8:recovery@mmcblk0p9:sysrecovery@mmcblk0p10:private@mmcblk0p11:Reserve0@mmcblk0p12:klog@mmcblk0p13:Reserve1@mmcblk0p14:Reserve2@mmcblk0p15:cache@mmcblk0p16:UDISK@mmcblk0p1 mac_addr= wifi_mac= bt_mac= specialstr= serialno= boot_type=2 disp_para=0 init_disp=20b0404 tv_vdid=0 fb_base=0x46400000 config_size=49152
附录2:对cmdline的处理
-
static void process_kernel_cmdline(void)
-
{
-
/* don't expose the raw commandline to nonpriv processes */
-
chmod("/proc/cmdline", 0440);
-
-
import_kernel_cmdline(0, import_kernel_nv);
-
if (qemu[0])
-
import_kernel_cmdline(1, import_kernel_nv);
- //会设置 ro.boot.serialno, ro.boot.mode, ro.boot.baseband,
-
// ro.boot.bootloader, ro.boot.console, ro.bootmode, ro.boot.hardware
-
// 这几个参数
- export_kernel_boot_props();
- }
-
void import_kernel_cmdline(int in_qemu,
-
void (*import_kernel_nv)(char *name, int in_qemu))
-
{
-
char cmdline[1024];
-
char *ptr;
-
int fd;
-
//将文件/proc/cmdline的内容读取到buf中
-
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;
-
}
-
//查找buf中的空格,以空格为分隔符划分出一个个的字符串,每一个字符串就是一个设置,调用回调函数import_kernel_nv
-
ptr = cmdline;
-
while (ptr && *ptr) {
-
char *x = strchr(ptr, ' ');
-
if (x != 0) *x++ = 0; //查找到空格,将空格替换为\0,字符串结束
-
import_kernel_nv(ptr, in_qemu); //如果是实体机in_qemu=0
-
ptr = x;
-
}
- }
如果是实体机for_emulator=0,
-
static void import_kernel_nv(char *name, int for_emulator)
-
{
-
char *value = strchr(name, '=');
-
int name_len = strlen(name);
-
-
if (value == 0) return;
-
*value++ = 0;
-
if (name_len == 0) return;
-
-
if (for_emulator) { //for_emulator=0
-
/* in the emulator, export any kernel option with the
-
* ro.kernel. prefix */
-
char buff[PROP_NAME_MAX];
-
int len = snprintf( buff, sizeof(buff), "ro.kernel.%s", name );
-
-
if (len < (int)sizeof(buff))
-
property_set( buff, value );
-
return;
-
}
-
-
if (!strcmp(name,"qemu")) { //检查cmdline中是否有qemu字段,这儿没有
-
strlcpy(qemu, value, sizeof(qemu));
-
} else if (!strncmp(name, "androidboot.", 12) && name_len > 12) { //检查cmdline中是否有androidboot.字段,这儿没有
-
const char *boot_prop_name = name + 12;
-
char prop[PROP_NAME_MAX];
-
int cnt;
-
-
cnt = snprintf(prop, sizeof(prop), "ro.boot.%s", boot_prop_name);
-
if (cnt < PROP_NAME_MAX)
-
property_set(prop, value);
-
}
- }