Android init进程启动过程

时间:2021-02-07 04:34:48


init源码在:android/system/core/init/,编译出来的init二进制可执行文件在:android/out/target/product/s900_vr/root/,系统运行起来后,这个root/目录里面的内容都是在根目录下的,也就是说,要想实现从kernel到android的跳转,就需要有地方启动这个完整路径是 "/init"的init进程。

1,机器上电

2,bootloader启动过程
一般做法是到地址为0x00000000处执行bootloader的第一阶段的汇编代码(意思就是bootloader就放到0x00000000的地址处),初始化硬件设备,比如内存等,拷贝bootloader的第二阶段C代码到内存,然后执行第二阶段C代码,第二阶段代码会拷贝kernel到RAM并跳转到kernel的入口处执行;(我们公司的bootloader采用的是u-boot,分为5个阶段,firsMBR/secMBRC/APP/BL31/B32,上电先跑brom代码,brom是固化在CPU内部的0xffff0000处的代码,一般arm启动地址是0x00000000或0xffff0000,我们公司选用的是0xffff0000,然后brom从flash(sd、emmc或nand)加载1stMbrc启动代码到shareRam,shareRam是CPU内部的ram空间,然后运行secMBRC,APP/BL31/B32都是在DDR上跑)

3,u-boot中有指定kernel的入口函数start_kernel():
u-boot/arch/arm/lib/bootm.c
72 static void announce_and_cleanup(int fake)
73 {
74     printf("\nStarting kernel ...%s\n\n", fake ?
75         "(fake run for tracing)" : "");
76     bootstage_mark_name(BOOTSTAGE_ID_BOOTM_HANDOFF, "start_kernel");
77 #ifdef CONFIG_BOOTSTAGE_FDT
78     bootstage_fdt_add_report();
79 #endif
80 #ifdef CONFIG_BOOTSTAGE_REPORT
81     bootstage_report();
82 #endif
84 #ifdef CONFIG_USB_DEVICE
85     udc_disconnect();
86 #endif
87     cleanup_before_linux();
88 }

4,kernel的start_kernel()里面的每个函数都是重量级的,这里不讨论,我们关注的是大的流程:
kernel/init/main.c
472 asmlinkage void __init start_kernel(void)
473 {
474     char * command_line;
475     extern const struct kernel_param __start___param[], __stop___param[];
481     lockdep_init();
482     smp_setup_processor_id();
483     debug_objects_early_init();
484     //此处省略一万行
647     rest_init();
648 }

4.1,直接看rest_init(),这里新开了一个thread执行kernel_init:
366 static noinline void __init_refok rest_init(void)
367 {
368     int pid;
370     rcu_scheduler_starting();
376     kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);
377     numa_default_policy();
378     pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);
379     rcu_read_lock();
380     kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns);
381     rcu_read_unlock();
382     complete(&kthreadd_done);
388     init_idle_bootup_task(current);
389     schedule_preempt_disabled();
391     cpu_startup_entry(CPUHP_ONLINE);
392 }

4.2,kernel执行到kernel_init函数后,整个kernel该干的活差不多都已经完成,剩下的就是要启动用户空间的第一个进程init:
819 static int __ref kernel_init(void *unused)
820 {
821     kernel_init_freeable();
823     async_synchronize_full();
824     free_initmem();
825     mark_rodata_ro();
826     system_state = SYSTEM_RUNNING;
827     numa_default_policy();
828
829     flush_delayed_fput();
830
831     if (ramdisk_execute_command) {
832         if (!run_init_process(ramdisk_execute_command))
833             return 0;
834         pr_err("Failed to execute %s\n", ramdisk_execute_command);
835     }
836
843     if (execute_command) {
844         if (!run_init_process(execute_command))
845             return 0;
846         pr_err("Failed to execute %s.  Attempting defaults...\n",
847             execute_command);
848     }
849     if (!run_init_process("/sbin/init") ||
850         !run_init_process("/etc/init") ||
851         !run_init_process("/bin/init") ||
852         !run_init_process("/bin/sh"))
853         return 0;
854
855     panic("No init found.  Try passing init= option to kernel. "
856           "See Linux Documentation/init.txt for guidance.");
857 }

859 static noinline void __init kernel_init_freeable(void)
860 {
900     //此处省略n行代码
901     if (!ramdisk_execute_command)
902         ramdisk_execute_command = "/init";
903     //此处省略n行代码
904 }

上面821行的kernel_init_freeable函数给ramdisk_execute_command赋值为init的完整路径名称,然后832行就正式启动init进程了。