type
status
date
slug
summary
tags
category
icon
password
基于Android 10 源码分析
之前已经大致分析了一下Android系统启动的过程,这里回顾一下:
  1. 上电,从Boot ROM中执行一段烧录好的代码加载bootloader
  1. bootloader执行,引导加载并启动linux kernel
  1. linux kernel启动,并创建第一个用户态的进程init
  1. init进程解析init.rc并启动各种服务,包括通过app_process程序创建并启动Zygote进程和system server进程,这个阶段已经启动了虚拟机,进入了Java世界
  1. system server进程会启动各种服务,包括AMS,WMS等
  1. 启动完成之后,发送广播通知
这里来分析一下init进程的一些主要逻辑:
强调一点,init就是一个普通的命令行程序,程序位置在/system/core/init

入口:system/core/init/main.cpp

main(int argc, char** argv) ,其中argc是命令行参数的个数,默认为1,argv是传入的参数,argv[0]是程序的全路径名,arg[1]才是实际意义上的第一个参数.
strcmp(s1,s2)则是用来比较字符串的,如果s1 == s2,则返回0
basename(path),返回的是文件名,比如 “/system/bin/ueventd”,返回uevened
ueventd其实就是init进程的一个软连接,在system/bin中也可以看到,通过ls -l可以看到:
这个地方根据程序不同的执行方式,有三种入口:
  • 默认启动,执行FirstStageMain(argc, argv)
  • 启动ueventd程序,执行ueventd_main(argc, argv)
  • 带参启动init,执行SubcontextMain(argc, argv, &function_map);SetupSelinux(argv)SecondStageMain(argc, argv)中的一个
目前很多文章都说watchdogd进程也是init进程的软连接,但是在新版本的Android中,比如Android 10,watchdogd是一个独立的进程了,并不是init进程.
先来看下 FirstStageMain

第一阶段: FirstStageMain

源码在:system/core/init/first_stage_init.cpp
setenv():设置环境变量
mount():挂载文件系统:
mknod():Linux中创建字符设备文件或者块设备文件
tmpfs:一个基于内存的文件系统,断电后数据丢失
0755:用户具有读/写/执行权限,组用户和其它用户具有读写权限
可以看到这个阶段主要是挂载一些文件系统.并启动SELinux.

启动SELinux

这个过程中会执行:
然后进入到init进程的第二个阶段

第二阶段:SecondStageMain

在第一阶段的源码中有一饿SecondStageMain的方法调用,这个时候会进入第二个执行阶段:
可以看到第二个阶段依次做了这些事:
  • 加载init.rc配置文件
    • 这里会根据init.rc中的item类型创建对应的parser:
    • ActionParser
    • ServiceParser
    • ImportParser
    • 在加载完init.rc文件之后,会加载/{system,vendor,odm}/etc/init/ 下(Android设备中的目录)的所有rc配置文件:
    • /system/etc/init/ : 核心系统,比如SurfaceFlinger,MediaService,logd
      • /vendor/etc/init/ : SOC需要的核心功能和守护程序
        • /odm/etc/init/ : 设备制造商使用,比如传感器和其他外设功能或者守护程序
        • 在触发early_int 之前,配置cgroup,kptr_restrict,perf等限制资源使用的工具
          • Cgroup 抽象层
        • 触发early init,创建一些文件目录,挂载一些文件系统等,并启动ueventd
          • 触发init,修改权限并挂载binderfs,启动logd.lmkd,servicemanager,hwservicemanager,vndservicemanager等
            • 低内存终止守护进程 (lmkd)
            • 挂载binderfs
              • Android的IPC机制是通过/dev节点从用户空间访问的.一般会分配三个节点:
              • /dev/binder : 框架/应用进程之间的 IPC,使用 AIDL 接口
              • /dev/hwbinder : 框架/供应商进程之间的 IPC,使用 HIDL 接口 供应商进程之间的 IPC,使用 HIDL 接口
              • /dev/vndbinder : 供应商/供应商进程之间的 IPC,使用 AIDL 接口
            • 启动logd,即Android的日志进程
            • 启动servicemanager,hwservicemanager,vndservicemanager
              • Android O之前,Binder服务通过servicemanager注册,Android O开始binder节点分成了三种,因此对应的servicemanager也分成了三种.
            • 判断启动模式,如果是充电模式,在调用charger程序
            • 正常模式下启动,则挂载文件系统,并启动核心系统服务
              • 核心服务,即那些标记 class core的服务,比如init程序入口的ueventd:
                还有就是surfaceFlinger等:
            • 启动zygote相关进程
              • late-init中会触发:
                zygote_secondary是针对同时支持64位,32位架构的配置:

          总结

          • init入口中包含5个分支:
            • ueventd : 实际上就是init程序的软连接,在init.rc的early-init阶段启动
            • selinux_setup : FirstStageMain 中通过 /system/bin/init selinux_setup 启动
            • subcontext : SecondStageMain 中启动
              • second_stage : 在selinux_setp启动完之后执行
              • fisrt_stage : 默认首先执行
            • 第二个阶段,首先加载int.rc配置,然后再依次在Android设备中查找以下三种配置,并加载:
              • /system/etc/init/
              • /vendor/etc/init/
              • /odm/etc/init/
            • init.rc各个过程中会挂载文件系统,包括binderfs,创建各种文件目录,并分配权限
            • 启动servce manager,Android O开始分成三种,对应三种binder节点,给不同的层使用
            Android通知的简单用法Android快捷方式的简单使用
            Loading...