本文基于Android 12介绍Linux Kernel层和init进程的启动过程。

一、Android启动过程概述

Android正常模式启动过程如下图所示:

  • 启动电源:当按下电源键时,引用芯片从预定义的地方开始执行,加载引导程序BootLoader到RAM,开始执行。
  • BootLoader:它是在操作系统内核运行之前运行的一段小程序,初始化硬件设备、建立内存空间映射图,从而将OS拉起来。
  • Linux Kernel:它启动后,设置缓存、计划列表、加载驱动,启动init进程。
  • init:初始化和启动PropertyService,启动zygote和servicemanager进程。
  • zygote:c++层:启动VM并为VM注册JNI方法,调用ZygoteInit进入Java层;Java层:预加载类、库等各种资源,创建服务器端Socket,启动systemserver进程。
  • Launcher:在SystemServer.startOtherService()中的AMS.systemReady()中启动Launcher。

android中kernel日志 kernel android_android

二、Linux Kernel启动过程

Android 12源码中没有相关Kernel的代码,以下是参考《Android的设计与实现 卷I》和项目上kernel代码总结。

Kernel启动分为两个阶段:

(1)内核引导阶段。通常使用汇编语言,代码路径为:kernel/msm-4.19/arch/arm/kernel/head.S和
kernel/msm-4.19/arch/arm/kernel/head-common.S。

(2)内核启动阶段。引导阶段调用start_kernel()进入启动阶段,代码路径在:/kernel/msm-4.19/init/main.c。Kernel启动init过程如下:

android中kernel日志 kernel android_加载_02

三、init进程启动过程

init进程是Linux Kernel用户空间的第一个进程,Pid=1。代码路径为: /system/core/init/,他的入口为main.cpp,它的main()方法会多次进入,源码参考地址为:main.cpp - OpenGrok cross reference for /system/core/init/main.cpp

1. init进程启动的FirstStageMain阶段

android中kernel日志 kernel android_初始化_03

在FirstStageMain阶段,主要的工作如下:

  • umask(0):清除系统默认权限,保证新建目录的访问权限由mkdir设置。
  • 使用mkdir/mount/chmod指令来创建基本文件系统目录并挂载相关的文件系统。Android系统挂载了tmpfs、devpts、proc、sysfs这四类文件系统。其中,/dev是设备目录,所有外部设备和虚拟设备都在该目录下;/proc是存储当前系统内核运行信息的文件目录,/sys存储了硬件设备在内核上的映射。
  • SetStdioToDevNull():关闭/stdin/stdout/stderr的fd,重定向到/dev/null。
  • InitKernelLogging():初始化kernel日志,输出到/dev/kmsg。
  • load内核各模块。
  • 第一阶段做完后,再次调用main()进入SetupSelinux阶段。

2. init进程启动的SetupSelinux阶段

android中kernel日志 kernel android_初始化_04

 Selinux启动完后会再次携带参数调用main()进入SecondStageMain阶段。

3. init进程启动的SecondStageMain阶段

android中kernel日志 kernel android_android_05

在FirstStageMain阶段,主要的工作如下:

  • SetStdioToDevNull():关闭/stdin/stdout/stderr的fd,重定向到/dev/null。
  • InitKernelLogging():初始化kernel日志,输出到/dev/kmsg。
  • 创建会话秘钥。
  • 设置init进程和其fork()的子进程的oom_adj。oom_adj主要用在lowmemorykiller机制中,每一类别的进程会有其oom_adj的范围,oom_adj值越大表示进程越不重要,当lowmemory时,会优先kill oom_adj高的进程。
  • PropertyInit(),初始化属性服务。

初始化属性服务的逻辑:

1. mkdir "/dev/__properties"目录;
2. createSerializedPropertyInfo()读取context信息并将内容序列化写入 /dev/__properties__/ property_info;
3. ProcessKernelDt()读取设备树DT;
4. ProcessKernelCmdline()加载proc/cmdline,把"androidboot."开头的替换成ro.boot并设置新值。
5.ProcessBootconfig()加载/proc/bootconfig,把"androidboot."开头的替换成ro.boot并设置新值。
6. ExportKernelBootProps()将kernel变量传播到init可用的变量和其当前可用的属性。
7. PropertyLoadBootDefaults()加载开机默认的属性
  • StartPropertyService:启动属性服务。
  •  InitializeSubcontext:初始化SubContext。
  • 获取ActionManager实例和ServiceList实例
  • LoadBootScrpts:加载和解析init.rc文件。
  • 把Action和Trigger添加到ActionManager的相应队列中。
  • 无限循环执行init.rc中的command。

 init.rc中可以看到在触发“init”,会启动logd、servicemanager、hwservicemanager等。

on init
    sysclktz 0 //将时区设置为0
    ...
    # Start logd before any other services run to ensure we capture all of their logs.
    start logd
    # Start essential services.
    start servicemanager
    start hwservicemanager
    start vndservicemanager

触发 late-init,会启动各种fs,Zygote、early-boot、boot等。

# Mount filesystems and start core system services.
on late-ini
    trigger early-fs
    trigger fs
    trigger post-fs.
    trigger late-fs
    trigger post-fs-data
    trigger load_persist_props_action
    trigger load_bpf_programs
    #触发启动zygote
    trigger zygote-start
    trigger firmware_mounts_complete
    trigger early-boot
    trigger boot


on early-fs
    # Once metadata has been mounted, we'll need vold to deal with userdata checkpointing
    start vold

on post-fs
    exec - system system -- /system/bin/vdc checkpoint markBootAttempt
    mount rootfs rootfs / remount bind ro nodev

    # Mount default storage into root namespace
    mount none /mnt/user/0 /storage bind rec
    mount none none /storage slave rec

    chown system cache /cache
    chmod 0770 /cache
    restorecon_recursive /cache
    mkdir /cache/recovery 0770 system cache

    chown root system /proc/kmsg
    chmod 0440 /proc/kmsg

# It is recommended to put unnecessary data/ initialization from post-fs-data
# to start-zygote in device's init.rc to unblock zygote start.
on zygote-start && property:ro.crypto.state=unencrypted
    wait_for_prop odsign.verification.done 1
    # A/B update verifier that marks a successful boot.
    exec_start update_verifier_nonencrypted
    start statsd
    start netd
    start zygote
    start zygote_secondary

所以servicemanager进程比zygote启动更早。