Android开机服务启动流程

2023-11-09

在Android系统启动时候,会解析init.rc文件,然后根据里面的定义,启动各种服务,如netd、zygote、servier_manager等等,但这些服务之间其实是有依赖关系的,而且当其中的某个服务启动失败时,有时候会影响后续的服务启动。这篇文章就具体的分析一下开机服务的启动顺序

 

服务的分类 

init.rc中对服务做了分类,在service section里面有一个’class’标签,指明了该服务所属的类。如: 

service surfaceflinger /system/bin/surfaceflinger
    class core  //所属类为‘core’
    user system
    group graphics drmrpc
    onrestart restart zygote

service media /system/bin/mediaserver
    class main  //所属类为‘main’
    user media
    group audio camera inet net_bt net_bt_admin net_bw_acct drmrpc mediadrm system
    ioprio rt 4

init.rc中总共有三个分类:core、main和late_start,下面整理了各分类下属的服务:

core:

ueventd、logd、healthd、adbd(disabled)、lmkd(LowMemoryKiller)、servicemanager、vold、debuggerd、surfaceflinger、bootanim(disabled)等

core分类中的服务都是一些核心服务,它们不启动,后续的服务或系统启动就可能出问题。比如servicemanager,binder通信大管家,它的启动很靠前,因为,其他服务启动时候需要向servicemanager注册binder服务。vold,负责存储类设备的挂载;还有surfaceflinger,图形显示的核心服务等 

main:

debuggerd64、drm、media、ril-daemon、installd、flash_recovery、racoon(disabled)、mtpd(disabled)、keystore、dumpstate(disabled)、mdnsd(disabled)、pre-recovery(disabled)、cmd_services(disabled)、phasecheckserver、zygote等 

main分类中的服务是一些系统的基本服务,有了这些服务android系统、Java世界才能正常运行 

 

late_start

字面意思是晚些启动。/device/中一些硬件厂商的.rc文件中会将一些服务设置为该类

上面服务后面加”(disabled)”,代表init进程在初始化阶段不会启动该服务。该服务的启动是由其他的因素触发而启动的,比如:

on property:persist.sys.cmdservice.enable=enable
    start cmd_services

表示当属性persist.sys.cmdservice.enable的值设置为enable时,会触发该action,执行下面的命令。由于命令是start,所以init进程会启动cmd_services

除了“disabled”的服务,上面的顺序基本上就是服务的开机启动顺序,即先启动core服务,然后启动main服务,最后启动late_start类别的服务。注意,相同类别的服务,基本上是同时启动,相互之间的延时很小

 

服务的启动

首先看一下,init.c–>main()源码:

int main(int argc, char **argv)
{
    ...
    action_for_each_trigger("early-init", action_add_queue_tail);
    ...
    action_for_each_trigger("init", action_add_queue_tail);
    ...
    action_for_each_trigger("late-init", action_add_queue_tail);
    ...
    for(;;) {
        ...
        execute_one_command();
        ...
    }
}

可以看到,依次将early-init、init、late-init三个section对应的命令插入到操作队列中。 
然后在后面的for循环中,调用execute_one_command依次执行操作队列中的命令。 
那early-init、init、late-init都定义了哪些操作呢?我们看一下init.rc中的定义。这里,我们只关注服务的启动,其他的操作屏蔽掉

on early-init
    ...
    start ueventd  //ueventd是init启动的第一个进程
    ...

on init
    ... // 创建各种路径,并写入一些参数

on late-init
    //trigger 会调用action_for_each_trigger("xxx", action_add_queue_tail);
    //从而将xxx section里的操作加入操作队列

    // mount文件系统相关的操作
    trigger early-fs 
    trigger fs 
    trigger post-fs
    trigger post-fs-data

    trigger load_all_props_action  //加载属性
    trigger firmware_mounts_complete

    trigger early-boot //将‘early-boot’中的操作加入执行队列
    trigger boot  //将‘boot’中的操作加入执行队列

on early-boot
    ... // kernel trace相关

on boot
    ...
    class_start core // 启动core类别的服务

前面说了core类别的服务有很多,那这些服务的启动顺序怎么定义的呢?init进程在解析init.rc(init.rc中还import了其他的rc文件,解析完init.rc后,依次解析其他的rc文件)文件时,是从上到下依次解析,并存放在一个全局链表中的。服务的启动顺序就是该服务在全局链表中的位置。所以在rc文件中定义靠前的服务也会在全局链表的靠前位置,也就会先执行。 
core类别的服务启动完了,那main类别的服务什么时候启动呢? 
init.rc中对启动main类别服务的定义如下:

on nonencrypted
      class_start main
      class_start late_start

on property:vold.decrypt=trigger_restart_min_framework
      class_start main

on property:vold.decrypt=trigger_restart_framework
     class_start main
     class_start late_start

可见,有以上三种方式,会触发启动main类别的服务。通过名字可以看出,都和系统是否加密有关。 
这里,我们分析一下nonencrypted。前面提到,在“late-init”section中会触发“fs”section

on late-init
    ...
    trigger fs 
    ...

//这个section一般在init.${ro.hardware}.rc中定义
on fs 
    ...
    mount_all fstab
    ...

在“fs”section中会执行mount_all fstab命令。fstab是Android下比较重要的配置文件,它包含了系统在启动时挂载文件系统和存储设备的详细信息。对应的处理函数为:

int do_mount_all(int nargs, char **args)
{
    ...

    pid = fork();
    if (pid > 0) {
        // 父进程,等待子进程的处理返回结果
        int wp_ret = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0));

        if (WIFEXITED(status)) {
            ret = WEXITSTATUS(status);
        } else {
            ret = -1;
        }
    } else if (pid == 0) {
        // 子进程,进一步调用fs_mgr_mount_all()
        fstab = fs_mgr_read_fstab(args[1]);
        child_ret = fs_mgr_mount_all(fstab);
        ...
        _exit(child_ret);
    } else {
        ...
    }

    if (ret == FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION) {
        ...
    } else if (ret == FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED) {
        ...
    } else if (ret == FS_MGR_MNTALL_DEV_NOT_ENCRYPTED) {
        ...
        // 这里就将"nonencrypted"中的操作加入到操作队列中
        action_for_each_trigger("nonencrypted", action_add_queue_tail);
    } else if (ret == FS_MGR_MNTALL_DEV_NEEDS_RECOVERY) {
        ...
    }
    ...
}

这里注意:如果调用fs_mgr_mount_all()返回结果不是FS_MGR_MNTALL_DEV_NOT_ENCRYPTED,就不会执行action_for_each_trigger(“nonencrypted”, action_add_queue_tail);这样main类别的服务就不会执行,系统就会无法正常启动

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android开机服务启动流程 的相关文章

随机推荐

  • Python 贝叶斯在文本分类的应用案例

    关注微信公共号 小程在线 关注CSDN博客 程志伟的博客 1 1 文本编码技术简介 1 1 1 单词计数向量 在开始分类之前 我们必须先将文本编码成数字 一种常用的方法是单词计数向量 在这种技术中 一个样本可以包 含一段话或一篇文章 这个样
  • 10种排序算法总结(Python 版)

    文章目录 1 冒泡排序 O n 2 2 快速排序 O nlogn 3 简单插入排序 O n 2 4 希尔排序 O n log n 5 简单选择排序 O n 2 6 堆排序 O n log n 7 归并排序 O n log n 8 计数排序
  • 解决keil5编译报错 undefined symbol

    在编译keil5 工程时出现报错 xxx axf Error L6218E Undefined symbol xxx referred from xxxo 正常情况下遇到Undefined symbol问题根据经验有以下几种原因 1 c文件
  • pinia实现持久化存储

    pinia的作用是什么 Pinia 是 Vue 的存储库 它允许您跨组件 页面共享状态 如果您熟悉 Composition API 您可能会认为您已经可以通过一个简单的 export const state reactive 这对于单页应用
  • 论文笔记--Attention is all you need

    Attention is all you need transformer模型 摘要 当前的序列转录模型基于encoder和decoder的循环或卷积神经网络 较好的做法是在encoder和decoder中间加入一个注意力机制 我们提出了一
  • 使用Spyder,导入tensorflow以及相关库出现kernel died等问题的解决方法

    自从使用了Spyder之后 感觉腰不算了 腿不疼了 走路都带风了 呵呵 好吧 那是之前 使用Spyder给我的感觉就好像一台快报废的电脑重新装了系统一样 刚开始顺风顺水 可是后来就发现毕竟是老年机 容易出现个什么白内障 风湿病什么的 做一些
  • 离散数学:数学语言与证明方法(练习题)

    练习1 1 判断下列命题是真是假 1 x x 答 假 x 并不是 x 元素 2 x x 答 真 x 是 x 子集 3 x x 答 真 x 是 x 元素 4 x x 答 假 x 不是 x 子集 5 x 答 真 是 x 元素但不是任何集合元素
  • SpringBoot:构建一个SpringBoot项目

    文章目录 一 创建项目 1 点击 File gt Project 2 选择 Spring Initializr 3 填写项目基本信息 5 目录结果 6 pom xml 依赖 7 主函数入口 二 项目启动 测试 三 项目源码 SpringBo
  • MongoDB常见问题

    问题一 还原报错 root mongodb bin mongorestore h 127 0 0 1 27017 d runoob directoryperdb data db runoob 2022 12 19T19 47 23 909
  • [LeetCode-21]-Merge Two Sorted Lists(有序列表合并)

    文章目录 题目相关 Solution 不带头结点 增加头结点 使用递归 题目相关 题目解读 合并两个有序列表 并返回新列表 原题描述 原题链接 Merge two sorted linked lists and return it as a
  • 合并两个有序表到新的有序表

    系列目录 左右移动 旋转 数组元素 查找两个升序数组的中间数 判断数组的某一个元素的数量是否超过了整个数组数量的一半 文图介绍 将有序数组A和有序数组B合并得有序数组C A 1 2 3 4 5 B 2 3 4 5 6 C 1 2 2 3 3
  • java什么时候用异常_深入理解Java异常的使用场景

    最近在项目代码中 遇见异常滥用的情形 分析下会带来哪些后果 1 代码可读性变差 业务逻辑难以理解 异常流与业务状态流混在一起 无法从接口协议层面理解业务代码 只能深入到方法 Method 内部才能准确理解返回值的行为 可看一下代码 publ
  • 如何计算留存率(Hive Sql or Spark sql)

    在互联网行业中 用户在某段时间内开始使用应用 经过一段时间后 仍然继续使用该应用的用户 被认作是留存用户 这部分用户占当时新增用户的比例即是留存率 会按照每隔1单位时间 例日 周 月 来进行统计 顾名思义 留存指的就是 有多少用户留下来了
  • unistd.h文件

    转载地址 http baike baidu com link url nEyMMFYevs4yoHgQUs2bcfd5WApHUKx0b1ervi7ulR09YhtqC4txmvL1Ce3FS8xTKtWQuvmEBHC9xezMGpvGH
  • valgrind 在开发板上运行以及使用

    前言 bedug无处不在 今天花落我家 现象 一个月出现一次异常 难易复现排查 借助神器valgrind排查 1 下载及编译准备 下载地址 https www valgrind org tar jxvf valgrind 3 16 1 ta
  • java实用类之正则工具类

    正则工具类 public class PatternUtil 匹配邮箱正则 private static final Pattern VALID EMAIL ADDRESS REGEX Pattern compile A Z0 9 A Z0
  • EL文件上传

    一 通过时间修改与文件上传 weixin 43985399的博客 CSDN博客查询并添加相应的文件 二 编辑前端页面
  • [操作系统]3.内存管理

    和前面两篇是差不多的思路 仅为快速复习操作i系统基础知识点 例题暂无 考试不要参考 知识点来自王道操作系统 1 内存管理的基本要求和设定 内存管理主要完成的功能有 内存空间的分配和回收 地址转换 把逻辑地址转化为内存物理地址 内存空间的扩充
  • LUT学习了解

    知乎 LUT Lookup Table 颜色查找表 通过LUT可以将一组RGB值输出为另一组RGB值 从而改变画面的曝光与色彩 如果我们规定 当原始R值为0时 输出R值为5 当原始R值为1时 输出R值为6 当原始R值为2时 输出R值为8 当
  • Android开机服务启动流程

    在Android系统启动时候 会解析init rc文件 然后根据里面的定义 启动各种服务 如netd zygote servier manager等等 但这些服务之间其实是有依赖关系的 而且当其中的某个服务启动失败时 有时候会影响后续的服务