Android系统启动流程分析
当按下Android系统的开机电源按键时候,硬件会触发引导芯片,执行预定义的代码,然后加载引导程序(BootLoader)到RAM,Bootloader是Android系统起来前第一个程序,主要用来拉起Android系统程序,Android系统被拉起首先肯定会启动Linux内核。
备注: 我们再刷机时候,经常看到工具软件会让我们切换bootloader/loader模式,其实就是重新激活bootloader程序,然后再拷贝新的镜像文件重新刷机,就是通过这个程序重新初始化硬件设备,建立内存空间映射。
我们也知道一个系统肯定会存在一些重要服务和进程来支持整个系统正常运作。 那么Android系统中肯定也存在这种重要进程,如下:
| 序号 | 进程名称 | 概述 |
| 1 | init进程 | Linux系统中用户空间第一个进程 |
| 2 | zygote进程 | 所有App进程的父进程,Zygote Init |
| 3 | system_server进程 | 各大系统服务的载体,forkSystemServer / SystemServer |
| 4 | servicemanager进程 | binder服务的大管家,守护进程循环运行在binder_loop |
内核启动首先会第一个创建init进程,进程号是1,是所有用户空间的鼻祖,init进程又会启动servicemanager(binder服务管家) 和zygote进程(Java进程鼻祖),zygote进程会创建system_server进程以及各种app进程,大致启动关系如下:

源码分析:基于 android10
inity源码分析
/system/core/init/main.cpp
int main(int argc, char** argv) {#if __has_feature(address_sanitizer)__asan_set_error_report_callback(AsanReportCallback);#endifif (!strcmp(basename(argv[0]), "ueventd")) {return ueventd_main(argc, argv);}if (argc > 1) {if (!strcmp(argv[1], "subcontext")) {android::base::InitLogging(argv, &android::base::KernelLogger);const BuiltinFunctionMap function_map;return SubcontextMain(argc, argv, &function_map);}if (!strcmp(argv[1], "selinux_setup")) {return SetupSelinux(argv);}if (!strcmp(argv[1], "second_stage")) {return SecondStageMain(argc, argv);}}return FirstStageMain(argc, argv);}
main函数有四个参数入口:
1.参数有ueventd进入 uevent_main
2. 参数中有subcontext,进入InitLogging和 SubcontextMain
3. 参数中有selinux_setup,进入SetupSelinux
4. 参数中有second_state,进入SecondStageMain
执行顺序如下: 首先会进入FirstStateMain ,主要执行是初始化环境变量,挂载和创建基本的文件系统,并设置访问权限,挂载system、cache、data等系统分区 。 之后进入 SetupSelinxu 根据源码我们可以看到FirstStateMain最后传送了参数selinux_setup
int FirstStageMain(int argc, char** argv) {....... const char* path = "/system/bin/init";const char* args[] = {path, "selinux_setup", nullptr};execv(path, const_cast<char**>(args));// execv() only returns if an error happened, in which case we// panic and never fall through this conditional.PLOG(FATAL) << "execv(\"" << path << "\") failed";return 1;}
SetupSelinux主要工作谁设置SELinux安全策略,之后进入SecondStageMain 。
int SecondStageMain(int argc, char** argv) {..... // oom_scroe_adj 为-1000时候相当与关闭OOM机制。 范围 -1000 - 1000 if (auto result = WriteFile("/proc/1/oom_score_adj", "-1000"); !result) {LOG(ERROR) << "Unable to write -1000 to /proc/1/oom_score_adj: " << result.error();}// 启用全局Seccomp GlobalSeccomp();// 设置所有进程都可以访问的会话密钥环keyctl_get_keyring_ID(KEY_SPEC_SESSION_KEYRING, 1);// 标记booting中 close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000));//初始化属性服务,指定文件读取属性property_init();....... // 为第二阶段设置 SELinux。SelinuxSetupKernelLogging();SelabelInitialize();SelinuxRestoreContext();// android封装好的Epoll开始初始化 Epoll epoll;if (auto result = epoll.Open(); !result) {PLOG(FATAL) << result.error();}// 注册singelfd信号,为创建handler处理子进程终止信号 InstallSignalFdHandler(&epoll);..... // 注册property_set_fd, 设置其他系统属性并开启系统属性服务 StartPropertyService(&epoll);MountHandler mount_handler(&epoll);....... ActionManager& am = ActionManager::GetInstance();ServiceList& sm = ServiceList::GetInstance();//解析init.rc 等文件,建立rc文件的action,service,启动其他进程。 LoadBootScripts(am, sm);..... am.QueueBuiltinAction(SetupCgroupsAction, "SetupCgroups");//rc文件中触发器为 on earyly-init 语句 am.QueueEventTrigger("early-init");// 等待冷插拔设备初始化完成 am.QueueBuiltinAction(wait_for_coldboot_done_action,"wait_for_coldboot_done");// so that we can start queuing up actions that require stuff from /dev.am.QueueBuiltinAction(MixHwrngIntoLinuxRngAction, "MixHwrngIntoLinuxRng");am.QueueBuiltinAction(SetMmapRndBitsAction, "SetMmapRndBits");am.QueueBuiltinAction(SetKptrRestrictAction, "SetKptrRestrict");// 设备组合键初始化操作 Keychords keychords;am.QueueBuiltinAction([&epoll, &keychords](const BuiltinArguments& args) -> Result<Success> {for (const auto& svc : ServiceList::GetInstance()) {keychords.Register(svc->keycodes());}keychords.Start(&epoll, HandleKeychord);return Success();},"KeychordInit");am.QueueBuiltinAction(console_init_action, "console_init");// 开始触发rc文件中为 on init 的语句 am.QueueEventTrigger("init");// Starting the BoringSSL self test, for NIAP certification compliance.am.QueueBuiltinAction(StartBoringSslSelfTest, "StartBoringSslSelfTest");// Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random// wasn't ready immediately after wait_for_coldboot_doneam.QueueBuiltinAction(MixHwrngIntoLinuxRngAction, "MixHwrngIntoLinuxRng");// Initialize binder before bringing up other system servicesam.QueueBuiltinAction(InitBinder, "InitBinder");//不要在充电器模式下挂载文件系统或启动核心系统服务。.std::string bootmode = GetProperty("ro.bootmode", "");if (bootmode == "charger") {am.QueueEventTrigger("charger");} else {am.QueueEventTrigger("late-init");} // 根据属性的当前状态运行所有属性触发器。.am.QueueBuiltinAction(queue_property_triggers_action, "queue_property_triggers");while (true) {//进入死循环s.auto epoll_timeout = std::optional<std::chrono::milliseconds>{};if (do_shutdown && !shutting_down) {do_shutdown = false;if (HandlePowerctlMessage(shutdown_command)) {shutting_down = true;}}if (!(waiting_for_prop || Service::is_exec_service_running())) {am.ExecuteOneCommand();}if (!(waiting_for_prop || Service::is_exec_service_running())) {if (!shutting_down) {auto next_process_action_time = HandleProcessActions();// 如果有一个进程需要重新启动,请及时唤醒。if (next_process_action_time) {epoll_timeout = std::chrono::ceil<std::chrono::milliseconds>(*next_process_action_time - boot_clock::now());if (*epoll_timeout < 0ms) epoll_timeout = 0ms;}}// 如果还有更多工作要做,请立即醒来。if (am.HasMoreCommands()) epoll_timeout = 0ms;}// 这里一直等待循环事件 过来if (auto result = epoll.Wait(epoll_timeout); !result) {LOG(ERROR) << result.error();}}return 0;}
其中最关键就是解析init.rc 文件,并且按照rc文件定义去启动服务,然后开启死循环,用于接受epoll事件
init.rc文件
init.rc文件在 /system/core/rootdir/init.rc
import /init.environ.rcimport /init.usb.rcimport /init.${ro.hardware}.rcimport /vendor/etc/init/hw/init.${ro.hardware}.rcimport /init.usb.configfs.rcimport /init.${ro.zygote}.rc
zygote服务启动
Zygote是由init进程通过解析init.zygote.rc文件而创建
我们可以看到/system/core/rootdir/下有4个init.zygote.rc文件,通过ro.zygote配置得值去读取对应配置文件,这里以init.zygote64.rc 为例子
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-serverclass mainpriority -20user rootgroup root readproc reserved_disksocket zygote stream 660 root systemsocket usap_pool_primary stream 660 root systemonrestart write /sys/android_power/request_state wakeonrestart write /sys/power/state ononrestart restart audioserveronrestart restart cameraserveronrestart restart mediaonrestart restart netdonrestart restart wificondwritepid /dev/cpuset/foreground/tasks
对应的可执行程序是app_process64 , 对应的源文件是/frameworks/base/cmds/app_process/app_main.cpp
zygote启动过程如下:
1.创建了AppRuntime,并且调用了start方法。
2. AndroidRuntime调用了startVm创建了虚拟机,调用startReg注册JNI函数。
3.通过JNI调用ZygoteInit.main 进入Java 。
4. 建立socket通道,zygote作为通讯服务端,用于响应客户端请求。
5. 预加载通用类,drawable,color资源,共享库等,用于提高app启动效率。
6. forksytem_server进程,上层java framework的运行载体。
参考文章:Android系统启动-zygote篇 - Gityuan博客 | 袁辉辉的技术博客袁辉辉, Gityuan, Android博客, Android源码, Flutter博客,Flutter源码http://gityuan.com/2016/02/13/android-zygote/
相关文章:
Android系统启动流程分析
当按下Android系统的开机电源按键时候,硬件会触发引导芯片,执行预定义的代码,然后加载引导程序(BootLoader)到RAM,Bootloader是Android系统起来前第一个程序,主要用来拉起Android系统程序,Android系统被拉起…...
如何在Ubuntu上安装OpenneBula
OpenNebula是一个开源云计算平台,允许我们在完全虚拟化云中组合和管理VMware和KVM虚拟机 第1步:安装MariaDB数据库服务器 OpenNebula还需要一个数据库服务器来存储其内容。 安装MariaDB: 1 2 sudo apt update sudo apt install mariadb-s…...
解决MySQL中分页查询时多页有重复数据,实际只有一条数据的问题
0 前言 有一个离奇的BUG,在查询时,第一页跟第二页有一个共同的数据。有的数据却不显示。 后来发现是在SQL排序时没用主键排序。 解决:使用主键排序 以下是我准备的举例,可以自己试试。 1 数据准备 SET NAMES utf8mb4; SET FORE…...
【数据结构】时间复杂度---OJ练习题
目录 🌴时间复杂度练习 📌面试题--->消失的数字 题目描述 题目链接:面试题 17.04. 消失的数字 🌴解题思路 📌思路1: malloc函数用法 📌思路2: 📌思路3&…...
京东自动化功能之商品信息监控是否有库存
这里有两个参数,分别是area和skuids area是地区编码,我这里统计了全国各个区县的area编码,用户可以根据实际地址进行构造skuids是商品的信息ID填写好这两个商品之后,会显示两种状态,判断有货或者无货状态,详情如下图所示 简单编写下python代码,比如我们的地址是北京市…...
【SwitchyOmega】SwitchyOmega 安装及使用
文章目录 安装教程使用教程 安装教程 SwitchyOmega 谷歌商店下载链接:https://chrome.google.com/webstore/detail/proxy-switchyomega/padekgcemlokbadohgkifijomclgjgif?hlen-US 在谷歌商店搜索 SwitchyOmega, 选择 Proxy SwitchyOmega 点击 Add t…...
CentOS5678 repo源 地址 阿里云开源镜像站
CentOS5678 repo 地址 阿里云开源镜像站 https://mirrors.aliyun.com/repo/ CentOS-5.repo https://mirrors.aliyun.com/repo/Centos-5.repo [base] nameCentOS-$releasever - Base - mirrors.aliyun.com failovermethodpriority baseurlhttp://mirrors.aliyun.com/centos/$r…...
【LLM】Langchain使用[二](模型链)
文章目录 1. SimpleSequentialChain2. SequentialChain3. 路由链 Router Chain Reference 1. SimpleSequentialChain 场景:一个输入和一个输出 from langchain.chat_models import ChatOpenAI #导入OpenAI模型 from langchain.prompts import ChatPromptTempla…...
简单机器学习工程化过程
1、确认需求(构建问题) 我们需要做什么? 比如根据一些输入数据,预测某个值? 比如输入一些特征,判断这个是个什么动物? 这里我们要可以尝试分析一下,我们要处理的是个什么问题&…...
【MongoDB】SpringBoot整合MongoDB
【MongoDB】SpringBoot整合MongoDB 文章目录 【MongoDB】SpringBoot整合MongoDB0. 准备工作1. 集合操作1.1 创建集合1.2 删除集合 2. 相关注解3. 文档操作3.1 添加文档3.2 批量添加文档3.3 查询文档3.3.1 查询所有文档3.3.2 根据id查询3.3.3 等值查询3.3.4 范围查询3.3.5 and查…...
关于游戏引擎(godot)对齐音乐bpm的技术
引擎默认底层 1. _process(): 每秒钟调用60次(无限的) 数学 1. bpm1分钟节拍数量60s节拍数量 bpm120 60s120拍 2. 每拍子时间 60/bpm 3. 每个拍子触发周期所需要的帧数 每拍子时间*60(帧率) 这个是从帧数级别上对齐拍子的时间&#x…...
【Go】实现一个代理Kerberos环境部分组件控制台的Web服务
实现一个代理Kerberos环境部分组件控制台的Web服务 背景安全措施引入的问题SSO单点登录 过程整体设计路由反向代理登录会话组件代理YarnHbase 结果 背景 首先要说明下我们目前有部分集群的环境使用的是HDP-3.1.5.0的大数据集群,除了集成了一些自定义的服务以外&…...
Spring Security 6.x 系列【63】扩展篇之匿名认证
有道无术,术尚可求,有术无道,止于术。 本系列Spring Boot 版本 3.1.0 本系列Spring Security 版本 6.1.0 本系列Spring Authorization Server 版本 1.1.0 源码地址:https://gitee.com/pearl-organization/study-spring-security-demo 文章目录 1. 概述2. 配置3. Anonymo…...
供应链管理系统有哪些?
1万字干货分享,国内外 20款 供应链管理软件都给你讲的明明白白。如果你还不知道怎么选择,一定要翻到第三大段,这里我将会通过8年的软件产品选型经验告诉你,怎么样才能快速选到适合自己的软件工具。 (为防后续找不到&a…...
如何在PADS Logic中查找器件
PADS Logic提供类似于Windows的查找功能,可以进行器件的查找。 (1)在Logic设计界面中,将菜单显示中的“选择工具栏”进行打开,如图1所示,会弹出对应的“选择工具栏”的分栏菜单选项,如图2所示。…...
Android 生成pdf文件
Android 生成pdf文件 1.使用官方的方式 使用官方的方式也就是PdfDocument类的使用 1.1 基本使用 /**** 将tv内容写入到pdf文件*/RequiresApi(api Build.VERSION_CODES.KITKAT)private void newPdf() {// 创建一个PDF文本对象PdfDocument document new PdfDocument();//创建…...
Kafka 入门到起飞 - 生产者发送消息流程解析
生产者通过send()方法发送消息消息会经过拦截器->序列化器->分区器 进行加工然后将消息存在缓冲区当缓冲区中消息达到条件会按批次发送到broker对应分区上broker将接收到的消息进行刷盘持久化消息处理broker会返回给producer响应落盘成功返回元数据…...
基于单片机智能台灯坐姿矫正器视力保护器的设计与实现
功能介绍 以51单片机作为主控系统;LCD1602液晶显示当前当前光线强度、台灯灯光强度、当前时间、坐姿距离等;按键设置当前时间,闹钟、提醒时间、坐姿最小距离;通过超声波检测坐姿,当坐姿不正容易对眼睛和身体腰部等造成…...
欧姆龙以太网模块如何设置ip连接 Kepware opc步骤
在数字化和自动化的今天,PLC在工业控制领域的作用日益重要。然而,PLC通讯口的有限资源成为了困扰工程师们的问题。为了解决这一问题,捷米特推出了JM-ETH-CP转以太网模块,让即插即用的以太网通讯成为可能,不仅有效利用了…...
PLEX如何搭建个人局域网的视频网站
Plex是一款功能非常强大的影音媒体管理系统,最大的优势是多平台支持和界面优美,几乎可以在所有的平台上安装plex服务器和客户端,让你可以随时随地享受存储在家中的电影、照片、音乐,并且可以实现观看记录无缝衔接,手机…...
2.Vue编写一个app
1.src中重要的组成 1.1main.ts // 引入createApp用于创建应用 import { createApp } from "vue"; // 引用App根组件 import App from ./App.vue;createApp(App).mount(#app)1.2 App.vue 其中要写三种标签 <template> <!--html--> </template>…...
k8s业务程序联调工具-KtConnect
概述 原理 工具作用是建立了一个从本地到集群的单向VPN,根据VPN原理,打通两个内网必然需要借助一个公共中继节点,ktconnect工具巧妙的利用k8s原生的portforward能力,简化了建立连接的过程,apiserver间接起到了中继节…...
Typeerror: cannot read properties of undefined (reading ‘XXX‘)
最近需要在离线机器上运行软件,所以得把软件用docker打包起来,大部分功能都没问题,出了一个奇怪的事情。同样的代码,在本机上用vscode可以运行起来,但是打包之后在docker里出现了问题。使用的是dialog组件,…...
【LeetCode】3309. 连接二进制表示可形成的最大数值(递归|回溯|位运算)
LeetCode 3309. 连接二进制表示可形成的最大数值(中等) 题目描述解题思路Java代码 题目描述 题目链接:LeetCode 3309. 连接二进制表示可形成的最大数值(中等) 给你一个长度为 3 的整数数组 nums。 现以某种顺序 连接…...
通过 Ansible 在 Windows 2022 上安装 IIS Web 服务器
拓扑结构 这是一个用于通过 Ansible 部署 IIS Web 服务器的实验室拓扑。 前提条件: 在被管理的节点上安装WinRm 准备一张自签名的证书 开放防火墙入站tcp 5985 5986端口 准备自签名证书 PS C:\Users\azureuser> $cert New-SelfSignedCertificate -DnsName &…...
Ubuntu系统复制(U盘-电脑硬盘)
所需环境 电脑自带硬盘:1块 (1T) U盘1:Ubuntu系统引导盘(用于“U盘2”复制到“电脑自带硬盘”) U盘2:Ubuntu系统盘(1T,用于被复制) !!!建议“电脑…...
ubuntu22.04有线网络无法连接,图标也没了
今天突然无法有线网络无法连接任何设备,并且图标都没了 错误案例 往上一顿搜索,试了很多博客都不行,比如 Ubuntu22.04右上角网络图标消失 最后解决的办法 下载网卡驱动,重新安装 操作步骤 查看自己网卡的型号 lspci | gre…...
《Offer来了:Java面试核心知识点精讲》大纲
文章目录 一、《Offer来了:Java面试核心知识点精讲》的典型大纲框架Java基础并发编程JVM原理数据库与缓存分布式架构系统设计二、《Offer来了:Java面试核心知识点精讲(原理篇)》技术文章大纲核心主题:Java基础原理与面试高频考点Java虚拟机(JVM)原理Java并发编程原理Jav…...
游戏开发中常见的战斗数值英文缩写对照表
游戏开发中常见的战斗数值英文缩写对照表 基础属性(Basic Attributes) 缩写英文全称中文释义常见使用场景HPHit Points / Health Points生命值角色生存状态MPMana Points / Magic Points魔法值技能释放资源SPStamina Points体力值动作消耗资源APAction…...
32位寻址与64位寻址
32位寻址与64位寻址 32位寻址是什么? 32位寻址是指计算机的CPU、内存或总线系统使用32位二进制数来标识和访问内存中的存储单元(地址),其核心含义与能力如下: 1. 核心定义 地址位宽:CPU或内存控制器用32位…...
