启动图解如下:
linux内核启动完成后,执行的第一个程序中/etc/preinit。此时环境变量PREINIT为空,所以马上执行/sbin/init /sbin/init是由procd/init.c编译而来。主要过程如下:
- /sbin/kmodloader 加载内核模块
- 执行一些early cmdline等
- 执行preinit()函数,设置PREINIT=1, 再次fork了/etc/preinit。
/etc/preinit执行完成后,进程消失后,调用了回调函数spawn_procd spawn_procd则execp(“procd”),至此0号进程/sbin/init被1号进程/sbin/procd替换,成为真正的用户空间的父进程 主要过程如下:
- 安装hostplug_preinit.json()
- 打开watchdog
- 开始hotplug
- udevtrigger
- 再去执行/etc/init.d/*文件,启动各个服务。
第二次执行 /etc/preinit的过程:
preinit功能由几个脚本组成,主脚本是/etc/preinit,它会读取其它的脚本【其中hook_XX函数库在/lib/functions/preinit.sh。 其它功能性的脚本在/lib/preinit/*】。它定义了一些函数挂到hook上.当运行时,这些hook们会启动函数按函数加入的顺序。
hook点如下:
- preinit_essential
- preinit_main
- failsafe
- initramfs
- preinit_mount_root
这些hook点说白了就是一个保存一些函数名+空格的字符串。如preinit_essentail的hook就是变量:preinit_essentail_hook 使用boot_hook_add把一些函数名的字符串加入相关变量中。示例:
boot_hook_add preinit_main define_default_set_state ## export -n preinit_main_hook=define_default_set_state
使用 boot_run_hook时,把从hook的变量中取出函数来并一一执行。 示例代码:
boot_run_hook preinit_main ## export -n PI_RAN_define_default_set_state=1 export -n PI_RAN_define_default_set_state=1
procd启动各服务
- procd: - early - //初始化看门狗。
- procd: - watchdog -
- procd: - ubus -
- procd: - init -
如上日志表示了procd的初始化过程。 procd有几个state。state_enter函数为状态机处理入口。
STATE_NONE –>STATE_EARLY –>STATE_UBUS–>STATE_INIT–>STATE_RUNNING
- STATE_NONE :什么也不干。
- STATE_EARLY :初始化看门狗等。
- STATE_UBUS:与ubusd建立socket.
- STATE_INIT:读取/etc/initab中的条目,为每一个条目建议一个action(其中有cb处理函数)。再依次执行respawn,askconsole,askfirst,sysinit的action.
执行完成sysinit后则进程了STAT_RUNNING状态。