android9启动进程,MSM8909+Android5.1.1启动流程(9) ---start_kernel()到init进程

MSM8909+Android5.1.1启动流程(9) ---start_kernel()到init进程

上一篇:MSM8909+Android5.1.1启动流程(8)---boot_linux()和kernel入口

由上面可知kernel的入口是arch/arm/kernel/head.S中stext, head.S包含同目录文件head-common.S,其调用kernel\init\main.c函数start_kernel()。

从start_kernel函数开始,内核即进入了C语言部分,它完成了内核的大部分初始化工作。实际上,可以将start_kernel函数看做内核的main函数,调用大量的init函数来对内核环境进行初始化;包括CPU初始化、内存管理初始化、进程管理初始化、文件系统初始化、中断、同步互斥等

调用流程:

start_kernel()--->rest_init()--->kernel_init()

rest_init()来初始化0号进程和1号用户态的进程。

static noinline void __init_refokrest_init(void)

{

intpid;

conststruct sched_param param = { .sched_priority = 1 };

rcu_scheduler_starting();

/*

* We need to spawn init first so that itobtains pid 1, however

* the init task will end up wanting to createkthreads, which, if

* we schedule it before we create kthreadd,will OOPS.

*/

kernel_thread(kernel_init,NULL, CLONE_FS | CLONE_SIGHAND);

numa_default_policy();

pid= kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);

rcu_read_lock();

kthreadd_task= find_task_by_pid_ns(pid, &init_pid_ns);

rcu_read_unlock();

sched_setscheduler_nocheck(kthreadd_task,SCHED_FIFO, ¶m);

complete(&kthreadd_done);

/*

* The boot idle thread must execute schedule()

* at least once to get things moving:

*/

init_idle_bootup_task(current);

schedule_preempt_disabled();

/*Call into cpu_idle with preempt disabled */

cpu_startup_entry(CPUHP_ONLINE);

}

kernel_thread函数调用do_fork创建了2号内核线程kthreadd、1号内核线程init,他们的父进程是内核0号进程,2号内核线程kthreadd作用是管理调度其他内核线程,而init内核线程通过调用init可执行程序转变成init进程,进程号还是1。

kernel_thread函数第一个参数就是kernel_init函数,kernel\init\main.c文件

static int __ref kernel_init(void *unused)

{

kernel_init_freeable();

/*need to finish all async __init code before freeing the memory */

async_synchronize_full();

free_initmem();

mark_rodata_ro();

system_state= SYSTEM_RUNNING;

numa_default_policy();

flush_delayed_fput();

/*一开始,ramdisk_execute_command为空,被初始化为”/init”,默认init进程的路径在根目录下,ramdisk_execute_command已经被赋值为”/init”不为空,调用run_init_process处理init可执行程序,run_init_process函数中的do_execve就是系统调用execve的具体实现,作用是运行可执行程序。*/

if(ramdisk_execute_command) {

if(!run_init_process(ramdisk_execute_command))

return0;

pr_err("Failedto execute %s\n", ramdisk_execute_command);

}

/*

* We try each of these until one succeeds.

*

* The Bourne shell can be used instead of initif we are

* trying to recover a really broken machine.

*/

/*如果根目录下没有init可执行程序,就会在”/sbin”、”/etc”、”/bin”下查找,直到找到后执行,如果都没有找到,系统尝试建立一个交互的shell命令可执行程序,让管理员尝试修复。如果sh也没有,此时Android系统启动失败,调用panic把错误提示保存到磁盘中,待重启后显示。*/

if(execute_command) {

if(!run_init_process(execute_command))

return0;

pr_err("Failedto execute %s. Attemptingdefaults...\n",

execute_command);

}

if(!run_init_process("/sbin/init") ||

!run_init_process("/etc/init") ||

!run_init_process("/bin/init") ||

!run_init_process("/bin/sh"))

return0;

panic("Noinit found. Try passing init= option tokernel. "

"See Linux Documentation/init.txtfor guidance.");

}

内核启动init可执行程序,内核把控制权交到了用户空间,开始真正的Android之旅!init进程源码所在路径:system\core\init, Android.mk文件,相关内容:

// 编译后生成的模块的名字,具体是什么模块,看include关键字编译成什么

LOCAL_MODULE:= init

LOCAL_FORCE_STATIC_EXECUTABLE := true

LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)

include $(BUILD_EXECUTABLE) //编译成可执行程序

生成的可执行程序init在out/target/product/msm8909/root目录下,此路径由\build\core\envsetup.mk定义

# the target build type defaults to release

ifneq ($(TARGET_BUILD_TYPE),debug)

TARGET_BUILD_TYPE := release

endif

# ---------------------------------------------------------------

# figure out the output directories

ifeq (,$(strip $(OUT_DIR)))

ifeq (,$(strip $(OUT_DIR_COMMON_BASE)))

OUT_DIR := $(TOPDIR)out

else

OUT_DIR := $(OUT_DIR_COMMON_BASE)/$(notdir$(PWD))

endif

endif

DEBUG_OUT_DIR := $(OUT_DIR)/debug

# Move the host or target under the debug/directory

# if necessary.

TARGET_OUT_ROOT_release :=$(OUT_DIR)/target

TARGET_OUT_ROOT_debug :=$(DEBUG_OUT_DIR)/target

TARGET_OUT_ROOT :=$(TARGET_OUT_ROOT_$(TARGET_BUILD_TYPE))

TARGET_PRODUCT_OUT_ROOT :=$(TARGET_OUT_ROOT)/product

PRODUCT_OUT :=$(TARGET_PRODUCT_OUT_ROOT)/$(TARGET_DEVICE)

TARGET_COPY_OUT_ROOT := root

TARGET_ROOT_OUT :=$(PRODUCT_OUT)/$(TARGET_COPY_OUT_ROOT)

init进程主要代码是init.c,标准c语言写的程序,其main函数是入口,main()函数下部分再学习。

参考链接:

arm linux kernel 从入口到start_kernel 的代码分析

Android系统开机启动流程及init进程浅析

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值