Android boot 流程

本文深入探讨了Android设备从按下电源按钮到系统完全启动的全过程,包括Bootloader、引导加载程序、内核启动、初始化进程(init)、zygote服务和系统服务器的启动等关键步骤。介绍了各阶段的具体任务、执行流程以及相互之间的关系,旨在为开发者提供全面的理解和指导。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转载请标明出处:

http://blog.youkuaiyun.com/a991192001/article/details/34102491


1.Question

Whathappened when I press power on button in my Android device ?
bootloader ?
Zygote?
init.rc ?
SystemServer ?

2.Bootloader

BootLoader是在操作系统内核运行之前运行。为最终调用操作系统内核准备好正确的环境。
Basichardware initialization
导入binoperatingsystem kernel
程序解压(可能)
程序运行

注:It’s not part of Android Operating System.
 bootloader is the place where OEMs and Carriers put there locks and restrictions.
BootLoader是严重地依赖于硬件而实现的,特别是在嵌入式世界。
因此,在嵌入式世界里建立一个通用的BootLoader几乎是不可能的。


3.Bootloaders on X86


  注:BIOS是英文"Basic Input Output System"的缩略语,直译过来后中文名称就是"基本输入输出系统"。其实,它是一组固化到计算机内主板上一个ROM芯片上的程序,它保存着计算机最重要的基本输入输出的程序、系统设置信息、开机后自检程序和系统自启动程序。


4.Booting on embedded CPU

TheCPU has an integrated boot code in ROM
Thisboot code is able to load a first stagebootloader fromastorage device into an internal SRAM (DRAM not initialized yet)
Thisfirst stage bootloadermust initialize DRAM andotherhardware devices and load a second stagebootloader into RAM

注:

Storage device can typically be: MMC, NAND,SPI fash,UART, etc.

Limited in size due to hardware constraints(SRAM size)

Provided either by the CPU vendor or throughcommunity Projects

第一阶段:

1,初始化基本硬件;

2,把bootloader自动搬运到内存中;

3,设置堆栈指针并将bss段清零。为后续执行代码做准备;

第二阶段:

1,初始化本阶段要用到的硬件;

2,读取环境变量;

3,启动:(a)自启动模式,从Flash或通过网络加载内核并执行;

(b) 下载模式,接收到用户的命令后执行;


5.Bootingon ARM TI OMAP3

注:

Linux Kernel启动后,bootloader不会再存在


6.加载linux kernel:第一个linux进程

Idle进程
     –名字:process 0/ idle process/swapperprocess
由函数startup_32()  setup第一个linux进程idle进程)的执行环境
     –android\kernel\arch\arm\kernel head.S
面我们会看到:原始进程(pid=0)创建init进程(pid=1),然后演化成idle进程(pid=0)init进程为每个从处理器(运行队列)创建出一个   idle进程(pid=0)
     –cpu_idle()

注:

idle是一个进程,其pid号为0。其前身是系统创建的第一个进程,也是唯一一个没有通过fork()产生的进程。

注:这时候bootloader已经把kernel image导入了RAM,因而代码在android\kernel\arch\arm\kernel

当执行完汇编代码head.s后会直接跳到:start_kernel( )function

在此之前都是executed by jumping to their initial physical addresses


7.加载linux kernelstart_kernel( )

代码路径:

android/bootable/bootloader/lk/app/aboot/aboot.c

………………..

  void(*entry)(unsigned, unsigned, unsigned*) = (entry_func_ptr*)(PA((addr_t)kernel))

       uint32_ttags_phys = PA((addr_t)tags);

       entry(0,machtype, (unsigned*)tags_phys);

…………………

entry(0, machtype,(unsigned*)tags_phys);//根据Kernel的地址走至Kernel\init\main.cstart_kernel() 


8.Kernel启动

Kernel先进行相关setup
setupcache,
protectedmemory,
scheduling,
loadsdrivers.
在进行一系列与内核相关的初始化后,调用第一个用户进程-init进程并等待用户进程的执行,这样整个Linux内核便启动完毕


9.Kernel启动:init进程

Init进程
1.bootloader调用到fork
2.fork 产生进程跑init内核线程。执行execve(即执行了用户空间的init程序),此时,进程1就拥有了自己的地址空间等属性,成为一个普通进程。

注:

idle进程开始执行start_kernel()

注意:idle进程是kernel thread,不会进入用户态,init进程才是第一个用户进程

Kernel threads run only in Kernel Mode, while regularprocesses run alternatively in Kernel Mode and in User Mode


10.创建内核线程


注:

Bootloader:android/bootable/bootloader/lk/app/aboot/aboot.c

Kernel入口代码路径 :android\kernel\init\main.c

Process.c :android\kernel\arch\arm\kernel

Fork.c :android\kernel


2.entry(0,machtype,(unsigned*)tags_phys);

 //根据Kernel的地址走至Kernel\init\main.cstart_kernel()

3.大量形如XXX_init()的函数

4.Rest_init()是最后执行的


11.Kernel thread to Process


kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);

pid_tkernel_thread(int(*fn)(void *), void *arg, unsigned long flags)

内核创建的内核线程运行函数:kernel_init 位于main.c

init是个普通的用户态进程,它是Unix系统内核初始化与用户态初始化的接合点,它是所有process的祖宗。在运行kernel_init以前是内核态初始化


12.create Init process


这里的run_init_process就是通过execve()来运行init程序。从这里我们看到了init长大成人的整个过程。

http://blog.youkuaiyun.com/longshan_2009/article/details/8693672

这里在执行execve之前,进程1还是共享着内核线程0资源属性的内核线程。执行execve(即执行了用户空间的init程序),此时,进程1就拥有了自己的地址空间等属性,成为一个普通进程。

而如果是在这些目录中扔未找到init文件,内核就会终止执行init进程,并引发kernel Panic.

panic("No init found.  Try passing init= option to kernel. “

"See Linux Documentation/init.txt forguidance.");


13.android启动

init进程working
zygote服务启动
systemserver服务启动

15.Init process

init是一个进程,确切的说,是linux系统用户空间的第一个进程,android是基于linux的,所以init也是android用户空间的第一个进程.
它都干了些什么呢?
mountdirectories like /sys, /dev, /proc
run init.rc script.
    •Thisis very important

16.Init.rc

Android initlanguage
语法主要包含了以下内容:
Commands:命令
Actions: 动作
Triggers:触发条件
Services:服务
Options:选项
Propertise:属性
Init进程会解释init.rc里面的内容,并且把要执行的命令动作等添加到queue里面,然后顺序执行。

注:

” on  post-fs-data“开始的这样一个section里的所有命令加入到一个执行队列,在未来的某个时候会顺序执行队列里的命令,所以调用action_for_each_trigger()的先后决定了命令执行的先后。


17.What is in Init.rc

详细见android源代码,这里略过。


18.Init.rcmajor events and services


注:安卓的内存管理机制:系统会根据“oom_adj”来判断需要结束哪些进程,一般来说,“oom_adj”的值越大,该进程被系统选中终止的可能就越高

存储器技术设备(英语:Memory Technology Device,缩写为 MTD),是Linux系统中设备文件系统的一个类型,主要用于闪存的应用,是一种闪存转换层(Flash Translation Layer,FTL)。创造MTD子系统的主要目的是提供一个介于闪存硬件驱动程序与高级应用程序之间的抽象层。

 在init.rc中完成了一系列的重要操作:文件系统权限及挂载,启动zygote,启动系统服务,播放开机动画。当然如何解析对应的代码,并完成对应的操作,如启动zygote、播放开机动画,可以参考相关资料或查看源码


19.解析init.rc并执行action


20.Dalvik

Dalvik是虚拟机,运行androidapp
C/C++写的,好的移植性,轻量级,很适合在嵌入式运行
By default, 系统会分配给每个app一个独一无二的Linuxuser IDset permission
By default, 每个app都运行在自己的进程里面,每个app都有自己的虚拟机,app互不影响
每个app都有用自己的Dalvik VM实例?岂不是很耗费memorytime


21.Zygote

Zygote是在boot的时候init启动的
在地址空间内初始化虚拟机
将所有的Java核心库都加载起来
启动System Server
等待UNIX socket连接(产生新进程)
启动新app
通过Socket申请启动新application
ZygoteForkCOW
子进程运行

Zygote进程创建 一个Android应用程序进程通过复制自身来实现,也就是通过fork系统调用来实现。
这些被fork出来的Android应用程序进程
一方面是复制了Zygote进程中的虚拟机实例
另一方面是与Zygote进程共享了同一套Java核心库
这样不仅Android应用程序进程的创建过程很快(time),而且由于所有的Android应用程序进程都共享同一套Java核心库而节省了内存空间(memroy)。

注:Copy On Write (COW). What this means is that during the fork process, no memory is actually copy to another space. It is shared and marked as copy-on-write. Which means that when a process attempt to modify that memory, the kernel will intercept the call and do the copy of that piece of memory.

22.Zygote启动


创建一个名为“zygote”的进程,这个zygote进程要执行的程序是/system/bin/app_process
创建一个一个Socket “zygote”
由于Zygote进程在脚本文件init.rc中以服务的形式来启动,因此,会调用函数Service_start来启动。

Zygote进程以服务形式进行。

关键字service告诉init进程创建一个名为“zygote”的进程,这个zygote进程要执行的程序是/system/bin/app_process,后面四项是要传给app_process的参数。

最后的一系列onrestart关键字表示这个zygote进程重启时需要执行的命令。

ActivityManagerService就是通这个socket来和zygote进程通信请求fork一个应用程序进程的(先创建一个连接到Zygote进程的clientSocket

23.Init fork Zygote


\android\system\core\init

Fork函数返回两次,第一次在当前进程init中,第二次在新创建的进程中返回。

Pid == 0代表在新创建的进程


24.Zygote进程启动的过程

第一步:


BionicAndroidLinux内核库)

对于fork():
1、子进程复制父进程的所有进程内存到其内存地址空间中。父、子进程的
 “数据段”,“堆栈段”和“代码段”完全相同,即子进程中的每一个字节都 
  和父进程一样。
2、子进程的当前工作目录、umask掩码值和父进程相同,fork()之前父进程
  打开的文件描述符,在子进程中同样打开,并且都指向相同的文件表项。
3、子进程拥有自己的进程ID。对于父进程,fork函数返回了子程序的进程号,

而对于子程序,fork函数则返回零

对于exec():
1、进程调用exec()后,将在同一块进程内存里用一个新程序来代替调用
 
exec()的那个进程,新程序代替当前进程映像,当前进程的“数据段”,
 “堆栈段”和“代码段”背新程序改写。
2、新程序会保持调用exec()进程的ID不变。
3、调用exec()之前打开打开的描述字继续打开(好像有什么参数可以令打开
  的描述字在新程序中关闭)

第二步:


Zygote进程要执行的程序便是system/bin/app_process,它的源代码位于frameworks/base/cmds/app_process/app_main.cpp文件中,入口函数是main

App_process执行的时候会把自己名字重命名:niceName = "zygote";

2.runtime.start("com.android.internal.os.ZygoteInit",startSystemServer ? "start-system-server" :"");

frameworks/base/core/jni/AndroidRuntime.cpp

3:startVm()创建虚拟机实例

4.在虚拟机实例中注册一系列JNI方法

5. env->CallStaticVoidMethod(startClassstartMethstrArray);  调用ZygoteInit.main

 ZygoteInit.java ---main()----- >java世界准备已经完成,欢迎来到java世界

frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

registerZygoteSocket();创建server端的socket

startSystemServer(); 启动system进程

runSelectLoopMode();等待ActivityManagerService请求Zygote创建新进程。


25.ZygoteInit

调用registerZygoteSocket函数创建了一个socket接口,用来和ActivityManagerService通讯
调用 startSystemServer函数来启动SystemServer组件
调用runSelectLoopMode函数进入一个无限循环在前面创 建的socket接口上等待ActivityManagerService请求创建新的应用程序进程。

26.System进程的启动过程

第一步:

6.由于由Zygote进程创建的子进程会继承Zygote进程在前面Step 4中创建的Socket文件描述符,而这里的子进程又不会用到它,因此,这里就调用closeServerSocket函数来关闭它。

7.调用RuntimeInit类的静态函数zygoteInit来进一步启动System进程



第二步:

2.System 进程时区等

3.System进程中启动一个Binder线程池

4.invokeStaticMain()

6.Init native services(C++语言开发的系统服务)

7.将系统中的关键服务启动起来,注册到Service Manager中,最后通过函数loop(), 使当前线程进入一个消息循环中。

  KKKK以前的os不一样,KK是在SystemServerMain Thread上面跑initLoop

  KK以前是start一个新的threadServerThread



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值