热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

andriod/linux开机启动流程

本文目录:(一)整体概述(二)BootLoader(三)Kernel初始化

本文目录:

(一)整体概述

(二)BootLoader

(三)Kernel初始化

(四)Init初始化介绍

(a)Init.rc

(b)boottanim启动

(c)Surfaceflinger启动

(五)Zygote启动介绍

(a)app_process

(b)AppRuntime

(c)ZygoteInit

(六)SystemServer启动介绍

(a)AMS启动

(b)PackageMS启动

(七)Launcher启动介绍

(a)SystemUI启动

(b)Launcher启动

(八)Log抓取与分析方法

(九)总结及参考

概述:Loader  > Kernel > Native >  Framework > Application

细分:BootRom > Bootloader > Kernel > Init > Zygote > SystemServer > Launcher

Ø  Loader层主要包括Boot RomBoot Loader;

Ø  Kernel层主要是Android内核层,启动0号和1号进程;

Ø  Native层主要是包括init进程以及其fork出来的用户空间的守护进程、HAL层、开机动画等;

Ø  Framework层主要是AMSPMSService的初始化;

Ø  Application层主要指SystemUILauncher的启动;

(二)BootLoader

Bootloader 就是在操作系统内核运行之前运行的一段小程序。通过这段小程序,我们可以初始化硬件设备、建立内存空间的映射图,从而将系统的软硬件环境带到一个合适的状态,以便为最终调用操作系统内核准备好正确的环境。

调用流程:
crt0.S > kmain > arch_init > target_init > apps_init > aboot_init

详细步骤如下:

Ø  crt0.s中:

n  主要完成CPU初始化,禁用mmu,禁用cache,初始化异常向量表等操作,最后直接跳转到kmain中;

n  MTK平台:alps/vendor/mediatek/proprietary/bootable/bootloader/lk/arch/{paltform}/crt0.S

Ø  kmain方法中

n  MTK平台:alps/vendor/mediatek/proprietary/bootable/bootloader/lk/kernel/main.c

n  初始化线程系统 > 初始化mmu,设置异常向量基地址 > 初始化硬件时钟、主板等 > 初始化uart端口 > 内核堆栈初始化(用于kmalloc等函数的内存分配) > 初始化定时器 > 初始化内核定时器 > 判断是否定义ENABLE_NANDWRITE:如果是运行bootstrap2线程;如果不是则在timer_init之后执行bootstrap_nandwrite

Ø  Bootstrap2中执行arch_init > target_init > apps_init:

n  arch_init:打印信息;

n  target_init:

u  从共享内存中读写xbl提供的pmic信息;

u  初始化spmi总线,用于cpupmic通信;

u  初始化aprpm通信通道;

u  初始化按键;

u  判断内核是否签名,当使用的是签名的内核时,需要初始化加密解密引擎;

u  判断是从usf还是emmc启动;

u  获取分区表信息;

u  判断电池电压是否过低,过低则进入预充电和tz通信;

u  初始化emmc或ufs中的rpmb用户加解密认证分区;

u  运行keymaster。

n  app_init:功能的初始化,并调用aboot_init

Ø  aboot_init:在about.c

n  根据target_is_emmc_boot()判断是否是从emmc存储设备上启动,然后分别获取对应存储设备的页大小和页掩码;

n  取得设备的device_info信息,保存到device变量中;

n  初始化lcd驱动,显示手机开机后的第一幅图片;

n  获取emmc或者flash芯片的产品序列号,最后在启动kernel时通过cmdline中的androidboot.serialno参数传给内核;

n  检查按键判断是进入recovery还是fastboot;

n  检查重启模式;

n  跳转到kernel。

(三)kernel初始化

概述:Loader  > Kernel > Native >  Framework > Application

细分:BootRom > Bootloader > Kernel > Init > Zygote > SystemServer > Launcher

 

分为三部分:zImage解压缩、kernel的汇编启动阶段、kernelC启动阶段。

内核启动引导地址由bootp.lds决定,内核启动执行的第一条代码在head.S文件中,主要功能是实现压缩内核的解压跳转内核vmlinux内核的入口

 

kernelC启动阶段可以理解为真正的启动阶段,从head.S中可知,最终调用的是kernel/init/main.cstart_kernel()函数。

start_kernel()函数中执行了大量的初始化操作,如:

Ø  setup_arch():板级初始化等。

Ø  sched_init():初始化处理器的可运行队列,设置系统初始化进程,即0号进程;

Ø  softirq_init():内核软中断机制初始化函数;

Ø  console_init():初始化系统的控制台结构;

Ø  rest_init():调用kernel_thread()创建1号内核线程,调用schedule()函数切换当前进程,在调用该函数之前,Linux系统中只有两个进程,即0号进程init_task1号进程kernel_init,其中kernel_init进程也是刚创建的。调用该函数后,1号进程将会执行。

 

Kernel进程:

Linux下有3个特殊的进程:

Ø  idle(swapper)进程,由系统自动创建,运行在内核态:

pid = 0,前身是系统创建的第一个进程,也是唯一一个没有通过fork或者kernel_thread产生的进程。完成加载系统后,演变为进程调度、交换,常被称为交换进程。

Ø  init进程,由idle通过 kernel_thread创建,在内核空间完成初始化后,加载init程序,并最终转变为用户空间的init进程:

 0 进程创建,完成系统的初始化,是系统中所有其他用户进程的祖先进程。Linux中的所有进程都是由init进程创建并运行的,首先Linux内核启动,然后在用户空间中启动init进程,再启动其他系统进程,在系统启动完成后,init将变为守护进程监视系统其他进程。

Ø  kthreadd进程,由idle通过kernel_thread创建,并始终运行在内核空间,负责所有内核线程的调度和管理:

该进程任务就是管理和调度其他内核线程kernel_thread,会循环执行一个kthreadd的函数,该函数的作用就是运行kthread_create_list全局链表中维护的kthread,当我们调用kernel_thread创建的内核线程会被加入到此链表中,故所有的内核线程都是直接或间接地以kthreadd为父进程。

 

(四)Init初始化介绍

概述:Loader  > Kernel > Native >  Framework > Application

细分:BootRom > Bootloader > Kernel > Init > Zygote > SystemServer > Launcher

 

Init进程是Linux内核启动后创建的第一个用户空间的进程,init在初始化工程中会启动很多重要的守护进程

代码位于:alps/system/core/init/init.cpp

此外,该文件的main函数入口也是ueventdwatchdog守护进程的入口,通过参数控制。

默认情况下,一个进程创建出来的文件和文件夹属性都是022,使用umask()函数能设置文件属性的掩码,参数为时表示进程创建的文件属性是0777。接着创建一些基本的目录包括dev, proc, sys,等,同时把分区mount到对应的目录。

Init进程会调用property_init创建一个共享区域来存储属性值,初始化完后,获取kernel传过来的cmdline去设置一些属性,然后初始化SELinux和安全上下文,接着会通过property_load_boot_defaults去加载default.prop等文件初始化系统属性。

初始化属性和SELinux后,接着解析init.rc的文件内容,通过init.rc相关语法配置和启动进程以及启动的顺序。

Main()函数最后会进入一个死循环,每次循环都会去调用ExecuteOneCommand执行命令列表中的一条命令,如果服务挂了还会调用restart_processes重启服务。

Init进程初始化系统后,会化身为守护进程来处理子进程的死亡信号,修改属性的请求和组合键事件。

 

l  Init.rc

该文件位于: alps/system/core/rootdir/init.rc

init.cpp中,启动init.rc各个阶段的顺序是early-init > init > late_init, late_init中又会去触发其他阶段的启动,所以各个阶段在init中启动的顺序如下:

early_init > init > late_init > early-fs > post-fs > late_fs > post-fs-data > zygote-start > boot > on property

各阶段的作用分别是:

Ø  on early-init:设置init进程以及它创建的子进程的优先级,设置init进程的安全环境;

Ø  on init:设置全局环境,为cpu accounting创建cgroup(资源控制)挂载点;

Ø  on fs:挂载mtd分区;

Ø  on post-fs:改变系统目录的访问权限

Ø  on post-fs-data:改变/data目录以及它的子目录的访问权限

Ø  on boot:基本网络的初始化,内存管理等等

Ø  service servicemanager:启动系统管理器管理所有的本地服务,比如位置、音频、Shared preference

Ø  service zygote:启动zygote作为应用进程

 

boot阶段会启动classhalcore的服务。

Init.rc中支持的命令实现在builtins.cpp中,具体语法可参考文件:alps/system/core/init/READMe.md

l  bootanim启动】:bootanim意思是boot animation翻译为“开机动画”

Bootanim.rc中定义了bootanim属于core服务,但是设置了disable说明bootanim不是自启动的服务,需要别的服务进行唤醒。

l  surfaceflinger启动】flinger翻译为“护圈”

代码里搜索bootanim,可以看到surfaceflinger服务将bootanim启动,surfaceflinger属于core服务,自启动服务,在init进程的on boot阶段会启动surfaceflinger,surfaceflinger最后会启动startPropertySetThread从而启动bootanim

surfaceFlinger服务的main函数入口在main_surfaceflinger,主要操作有:

Ø  启动Hidl服务,主要是DisplayService

Ø  启动线程池;

Ø  初始化surfaceflingerGpuService注册到serviceManager;

Ø  启动surfaceFlinger线程。

启动函数在开机过程中只会执行一次。

(五)Zygote启动介绍

概述:Loader  > Kernel > Native >  Framework > Application

细分:BootRom > Bootloader > Kernel > Init > Zygote > SystemServer > Launcher

init执行过程中,在on late-init阶段,会trigger[引发] zygote-start(如下图示) , on zygote-start会根据当前的加密状态选择启动服务。

(六)SystemServer启动介绍

SystemServer主要从zygoteInit.java文件的 forkSystemServer()函数开始分析,主要是设置参数,然后调用zygote的forkSystemServer方法,再判断是否有SecondaryZygote启动,有则等待其启动,无则返回。

Zygote的forkSystemServer方法主要是调用了native方法nativeForkSystemServer,在native层进行fork动作,并设置pid, gid, seLinux安全上下文等,最后启动com.android.server.SystemServer。

SystemServer是一个Java类,从main函数入口分析,主要调用run方法,工作是:

Ø  调整时间,如果系统时间比1970要早,调整到1970;

Ø  设置语言;

Ø  调整虚拟机堆内存大小和内存利用率;

Ø  初始化Looper为mainLooper;

Ø  装载库libandroid_server.so;

Ø  初始化系统Context;

Ø  创建SystemServiceManager负责系统Service启动;

Ø  创建和启动Java服务,包含AMS,WMS,PMS,IMS等,主要分在三个函数中进行的;

n  启动引导程序服务startBootstrapServices():

u  会初始化一个watchdog实例,并启动watchdog子线程;

u  读取系统配置,初始化线程池,最大32个;

u  平台兼容性设置platformCompat;

u  启动Installer,为了有权限能创建重要的一些目录,如/data/user等;

u  为了获取设备id,启动DeviceIdentifiersPolicyService;

u  UriGrantsManagerService;

u  AMS;

u  在PMS之前要启动DataLoaderManagerService,IncrementalService;

u  启动pMS,powerManagerService;

u  启动ThermalManagerService;

u  初始化powerManagerService;

u  启动RecoverySystemService;

u  到此为止,OS启动和运行的基本要素基本集齐,注册一个healthObserver,为的是如果陷入runtime restart loop时,可以有一个救援队(rescue party)来救援,watchdog有监控;

u  启动ledService;

u  启动助手服务SidekickService;

u  启动DisplayManagerService;

u  启动PMS, packageManagerService,有watchdog监控;

u  PMS启动后,注册二进制文件报告器,该报告器会捕捉所有由系统加载的二进制文件,这些二进制文件会被BackgroundDexOptService优化;

u  至此,完成PMS启动;

u  再启动UserManagerService,至此,以上所有服务都是由systemServiceManager调用startService()方法启动;

u  接下来,将ActivityManagerService设置为系统进程,并启动。

u  初始化watchdog,并用ActivityManager实例启动,并开始监听reboot

n  启动核心服务startCoreServices()

u  启动系统配置服务systemConfigService;

u  启动电池服务batteryService,如果跟踪电池电量,需要LightService;

u  启动跟踪应用使用状态服务UsageService;

u  启动webViewUpdateService, CacheDeviceStateService跟踪和缓存设备状态, BinderCallsStateService跟踪CPU在binder 调用的时间, LooperStatesService跟踪在handlers中的传递消息的时间, RollbackManagerService管理apk的回滚,bugreportorMS捕捉bugreport的服务, GPUService 是GPU和GPU驱动的服务。

n  启动其他服务OtherServices(),下面列出主要的几项:

u  DropBoxManagerService,主要记录errors和log;

u  闹钟alarmManagerService, IMS (InputManagerService), WMS (WindowManagerService)……

u  在所有的与显示相关的服务都启动完之后,make display ready;

u  接下来启动一些生物识别相关的服务;

u  启动完成后,开始启动app进程,并且systemServiceManager.startBootPhase()各种服务,各种服务ready;

u  Ready之后,启动各个服务的第三方代码,让各个服务running:

Ø  调用Looper.loop(),进入处理消息的循环。

SystemServer主要从zygoteInit.java文件的 forkSystemServer()函数开始分析,主要是设置参数,然后调用zygote的forkSystemServer方法,再判断是否有SecondaryZygote启动,有则等待其启动,无则返回。

Zygote的forkSystemServer方法主要是调用了native方法nativeForkSystemServer,在native层进行fork动作,并设置pid, gid, seLinux安全上下文等,最后启动com.android.server.SystemServer。

SystemServer是一个Java类,从main函数入口分析,主要调用run方法,工作是:

Ø  调整时间,如果系统时间比1970要早,调整到1970;

Ø  设置语言;

Ø  调整虚拟机堆内存大小和内存利用率;

Ø  初始化Looper为mainLooper;

Ø  装载库libandroid_server.so;

Ø  初始化系统Context;

Ø  创建SystemServiceManager负责系统Service启动;

Ø  创建和启动Java服务,包含AMS,WMS,PMS,IMS等,主要分在三个函数中进行的;

n  启动引导程序服务startBootstrapServices():

u  会初始化一个watchdog实例,并启动watchdog子线程;

u  读取系统配置,初始化线程池,最大32个;

u  平台兼容性设置platformCompat;

u  启动Installer,为了有权限能创建重要的一些目录,如/data/user等;

u  为了获取设备id,启动DeviceIdentifiersPolicyService;

u  UriGrantsManagerService;

u  AMS;

u  在PMS之前要启动DataLoaderManagerService,IncrementalService;

u  启动pMS,powerManagerService;

u  启动ThermalManagerService;

u  初始化powerManagerService;

u  启动RecoverySystemService;

u  到此为止,OS启动和运行的基本要素基本集齐,注册一个healthObserver,为的是如果陷入runtime restart loop时,可以有一个救援队(rescue party)来救援,watchdog有监控;

u  启动ledService;

u  启动助手服务SidekickService;

u  启动DisplayManagerService;

u  启动PMS, packageManagerService,有watchdog监控;

u  PMS启动后,注册二进制文件报告器,该报告器会捕捉所有由系统加载的二进制文件,这些二进制文件会被BackgroundDexOptService优化;

u  至此,完成PMS启动;

u  再启动UserManagerService,至此,以上所有服务都是由systemServiceManager调用startService()方法启动;

u  接下来,将ActivityManagerService设置为系统进程,并启动。

u  初始化watchdog,并用ActivityManager实例启动,并开始监听reboot

n  启动核心服务startCoreServices()

u  启动系统配置服务systemConfigService;

u  启动电池服务batteryService,如果跟踪电池电量,需要LightService;

u  启动跟踪应用使用状态服务UsageService;

u  启动webViewUpdateService, CacheDeviceStateService跟踪和缓存设备状态, BinderCallsStateService跟踪CPU在binder 调用的时间, LooperStatesService跟踪在handlers中的传递消息的时间, RollbackManagerService管理apk的回滚,bugreportorMS捕捉bugreport的服务, GPUService 是GPU和GPU驱动的服务。

n  启动其他服务OtherServices(),下面列出主要的几项:

u  DropBoxManagerService,主要记录errors和log;

u  闹钟alarmManagerService, IMS (InputManagerService), WMS (WindowManagerService)……

u  在所有的与显示相关的服务都启动完之后,make display ready;

u  接下来启动一些生物识别相关的服务;

u  启动完成后,开始启动app进程,并且systemServiceManager.startBootPhase()各种服务,各种服务ready;

u  Ready之后,启动各个服务的第三方代码,让各个服务running:

Ø  调用Looper.loop(),进入处理消息的循环。                                                            

(七)Launcher启动介绍

                                                    后续持续更新中,尽情期待


推荐阅读
  • Android系统源码分析Zygote和SystemServer启动过程详解
    本文详细解析了Android系统源码中Zygote和SystemServer的启动过程。首先介绍了系统framework层启动的内容,帮助理解四大组件的启动和管理过程。接着介绍了AMS、PMS等系统服务的作用和调用方式。然后详细分析了Zygote的启动过程,解释了Zygote在Android启动过程中的决定作用。最后通过时序图展示了整个过程。 ... [详细]
  • 本文介绍了解决Netty拆包粘包问题的一种方法——使用特殊结束符。在通讯过程中,客户端和服务器协商定义一个特殊的分隔符号,只要没有发送分隔符号,就代表一条数据没有结束。文章还提供了服务端的示例代码。 ... [详细]
  • Android源码深入理解JNI技术的概述和应用
    本文介绍了Android源码中的JNI技术,包括概述和应用。JNI是Java Native Interface的缩写,是一种技术,可以实现Java程序调用Native语言写的函数,以及Native程序调用Java层的函数。在Android平台上,JNI充当了连接Java世界和Native世界的桥梁。本文通过分析Android源码中的相关文件和位置,深入探讨了JNI技术在Android开发中的重要性和应用场景。 ... [详细]
  • Java在运行已编译完成的类时,是通过java虚拟机来装载和执行的,java虚拟机通过操作系统命令JAVA_HOMEbinjava–option来启 ... [详细]
  • Spring学习(4):Spring管理对象之间的关联关系
    本文是关于Spring学习的第四篇文章,讲述了Spring框架中管理对象之间的关联关系。文章介绍了MessageService类和MessagePrinter类的实现,并解释了它们之间的关联关系。通过学习本文,读者可以了解Spring框架中对象之间的关联关系的概念和实现方式。 ... [详细]
  • 本文介绍了MVP架构模式及其在国庆技术博客中的应用。MVP架构模式是一种演变自MVC架构的新模式,其中View和Model之间的通信通过Presenter进行。相比MVC架构,MVP架构将交互逻辑放在Presenter内部,而View直接从Model中读取数据而不是通过Controller。本文还探讨了MVP架构在国庆技术博客中的具体应用。 ... [详细]
  • Mono为何能跨平台
    概念JIT编译(JITcompilation),运行时需要代码时,将Microsoft中间语言(MSIL)转换为机器码的编译。CLR(CommonLa ... [详细]
  • Question该提问来源于开源项目:react-native-device-info/react-native-device-info ... [详细]
  • Annotation的大材小用
    为什么80%的码农都做不了架构师?最近在开发一些通用的excel数据导入的功能,由于涉及到导入的模块很多,所以开发了一个比较通用的e ... [详细]
  • CentOS 7部署KVM虚拟化环境之一架构介绍
    本文介绍了CentOS 7部署KVM虚拟化环境的架构,详细解释了虚拟化技术的概念和原理,包括全虚拟化和半虚拟化。同时介绍了虚拟机的概念和虚拟化软件的作用。 ... [详细]
  • 数组的排序:数组本身有Arrays类中的sort()方法,这里写几种常见的排序方法。(1)冒泡排序法publicstaticvoidmain(String[]args ... [详细]
  • 面向对象之3:封装的总结及实现方法
    本文总结了面向对象中封装的概念和好处,以及在Java中如何实现封装。封装是将过程和数据用一个外壳隐藏起来,只能通过提供的接口进行访问。适当的封装可以提高程序的理解性和维护性,增强程序的安全性。在Java中,封装可以通过将属性私有化并使用权限修饰符来实现,同时可以通过方法来访问属性并加入限制条件。 ... [详细]
  • (三)多表代码生成的实现方法
    本文介绍了一种实现多表代码生成的方法,使用了java代码和org.jeecg框架中的相关类和接口。通过设置主表配置,可以生成父子表的数据模型。 ... [详细]
  • 从Oracle安全移植到国产达梦数据库的DBA实践与攻略
    随着我国对信息安全和自主可控技术的重视,国产数据库在党政机关、军队和大型央企等行业中得到了快速应用。本文介绍了如何降低从Oracle到国产达梦数据库的技术门槛,保障用户现有业务系统投资。具体包括分析待移植系统、确定移植对象、数据迁移、PL/SQL移植、校验移植结果以及应用系统的测试和优化等步骤。同时提供了移植攻略,包括待移植系统分析和准备移植环境的方法。通过本文的实践与攻略,DBA可以更好地完成Oracle安全移植到国产达梦数据库的工作。 ... [详细]
  • 使用eclipse创建一个Java项目的步骤
    本文介绍了使用eclipse创建一个Java项目的步骤,包括启动eclipse、选择New Project命令、在对话框中输入项目名称等。同时还介绍了Java Settings对话框中的一些选项,以及如何修改Java程序的输出目录。 ... [详细]
author-avatar
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有