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服务器和客户端,让你可以随时随地享受存储在家中的电影、照片、音乐,并且可以实现观看记录无缝衔接,手机…...

基于有效集MPC控制算法的直线同步电机simulink建模与仿真,MPC使用S函数实现
目录 1.课题概述 2.系统仿真结果 3.核心程序 4.系统仿真参数 5.系统原理简介 6.参考文献 7.完整工程文件 1.课题概述 有效集算法通过迭代地选择一组 "有效" 约束,将约束优化问题转化为一系列无约束或等式约束优化问题。直线同步电机 (Linear Synch…...
c# List<string>.Add(s) 报错:UnsupportedOperationException
在使用c#读取目录下指定格式文件目录后,使用List<string>.Add 来保存文件名时,出现UnsupportedOperationException错误,找了好久不知道问题出在哪里。 以下是错误代码: using (var fbd new FolderBrowserDialog{Descripti…...
嵌入式学习笔记- freeRTOS 带FromISR后缀的函数
FreeRTOS中带FromISR后缀的函数 是用于中断的函数,它有两个特点 一个是无等待延时, 一个是无立刻触发任务切换, 那么 一 为什么中断中不能等待(阻塞)? 因为中断中等待的,一般都是任务给予的…...
如何快速找出某表的重复记录 - 数据库专家面试指南
如何快速找出某表的重复记录 - 数据库专家面试指南 一、理解问题本质 在数据库操作中,重复记录通常指表中存在两条或多条记录在特定字段组合上具有相同值的情况。识别重复记录是数据清洗、ETL流程和数据库维护的重要任务。 关键概念:重复记录的定义取决于业务场景,可能是基…...
[论文阅读] 软件工程 | 如何挖掘可解释性需求?三种方法的深度对比研究
如何挖掘可解释性需求?三种方法的深度对比研究 研究背景:当软件变复杂,我们需要“说明书” 想象你买了一台智能家电,却发现它的运行逻辑完全看不懂,按钮按下后毫无反应,故障时也不提示原因——这就是现代…...

双空间知识蒸馏用于大语言模型
Dual-Space Knowledge Distillation for Large Language Models 发表:EMNLP 2024 机构:Beijing Key Lab of Traffic Data Analysis and Mining 连接:https://aclanthology.org/2024.emnlp-main.1010.pdf 代码:GitHub - songmz…...
深入解析C++五大常用设计模式:原理、实现与应用场景
设计模式是解决特定软件设计问题的经典方案,掌握它们能显著提升代码的可维护性和扩展性。本文详细解析C中五种最常用的设计模式,附带完整代码示例和实战技巧。 一、设计模式概述 设计模式是面向对象编程中可复用的解决方案,它们源于工程师们…...
Linux网络——socket网络通信udp
文章目录 UDP通信基础UDP的特点 Linux下UDP通信核心步骤创建UDP套接字绑定本地地址(可选)发送数据函数:sendto()函数原型参数详解典型使用示例 接收数据函数:recvfrom()函数原型参数详解返回值典型使用示例 关键设计原因无连接特性…...
面试题:SQL 中如何将 多行合并为一行(合并行数据为列)?
✅ 面试题:SQL 中如何将 多行合并为一行(合并行数据为列)? 这是面试和实战中非常常见的场景,属于“行列转换”问题之一,常用于报表聚合、分类汇总、透视表生成等。 go专栏:https://duoke360.co…...
nginx 服务启动失败问题记录
背景和问题 systemctl status nginx.service 查看报错信息,显示如下: nginx: [emerg] socket() [::]:80 failed (97: Address family not supported by protocol) nginx: configuration file /etc/nginx/nginx.conf test failed问题分析 这个错误通常…...