Android 启动流程及 init 进程解析
一、Android 启动流程概括
按下电源键触发开机,从 ROM 加载引导程序 BootLoader 到 RAM 中,BootLoader 执行启动 Linux kernel,然后启动第一个用户进程 init,init 进程的工作包括挂载文件、创建文件目录、设置 selinux 安全策略,解析 init.rc 脚本等。随后 init 进程会启动 Zygote 进程,Zygote 进程做一些资源预加载的工作,并启动 SystemServer 进程。SystemServer 进程作为 Socket 服务端,启动包括 AMS、WMS、PMS 等 90 多个服务在内的系统服务。在众多服务启动完毕后,AMS 会打开 Launcher 应用的 Home Activity,进入手机桌面。
附:kernel 的初始化流程(详细代码自行下载 linux kernel 源码)
传统的加载器包含两个文件
init.s:初始化堆栈,调用 main.c 的 main() 函数
main.c:初始化硬件(主板、闹钟等),创建 linux 标签
当内核完成系统设置后,会在系统文件中寻找 init 文件。
Dir:kernel/common/init/main.c
(1)执行 kernel_init() 函数
(2)启动 /bin/init 文件:try_to_run_init_process("/bin/init");
(3)try_to_run_init_process() ---> run_init_process()--->kernel_execve()
init/android.bp 中指明了 init 的入口函数:init/main.cpp,随后会执行 main.cpp 中的 main 方法
二、init 进程的启动流程
Dir:system/core/init/main.cpp ---> main() 方法
FirstStageMain() ---- SetupSelinux() ---- SecondStageMain()
第一阶段
FirstStageMain()
1、mount()--挂载文件、mkdir()--创建文件目录
2、SetStdioToDevNull()--重定向标准输入输出
3、InitKernelLogging()--初始化内核日志
4、启动 setupSelinux
SetupSelinux()
配置安全策略 -- 对应安卓的权限策略
第二阶段
SecondStageMain()
1、初始化属性系统
PropertyInit()
2、监听子进程的终止信号,释放资源,防止僵尸进程
InstallSignalFdHandler(&epoll);
InstallInitNotifier(&epoll);
StartPropertyService(&property_fd);
3、匹配 linux 命令和实际执行函数之间的关系
GetBuiltinFunctionMap()
4、解析 init.rc
LoadBootScripts(am, sm)-->CreateParser() //创建解析器-->//添加 rc 文件的解析组件 service、on、importparser.AddSectionParser("service", std::make_unique<ServiceParser>(&service_list, GetSubcontext(), std::nullopt));parser.AddSectionParser("on", std::make_unique<ActionParser>(&action_manager, GetSubcontext()));parser.AddSectionParser("import", std::make_unique<ImportParser>(&parser));-->//解析 rc 文件parser.ParseConfig("/system/etc/init/hw/init.rc");-->ParserConfigDir-->ParserConfigFile-->ParserConfigFile-->ParserData
5、While(true) 循环监听
auto pending_functions = epoll.Wait(epoll_timeout);
总结:init 进程处理的事情:
1、 挂载文件
2、设置 selinux -- 安全策略
3、开启属性服务,注册到 epoll 中
4、解析 init.rc
5、循环处理脚本,包括启动 zygote
6、循环等待
启动 Service 的过程
/system/core/rootdir/init.rc-->on nonencryptedclass_start main --> do_class_start(const BuiltinArguments& args)class_start late_start/system/core/init/builtins.cpp-->do_class_start(const BuiltinArguments& args)-->StartIfNotDisabled()/system/core/init/service.cpp-->StartIfNotDisabled()-->Start()
三、Zygote 启动流程
1、触发 Zygote
Dir:/system/core/rootdir/init.rc
(1)init.rc 中引入的 zygote.rc 脚本
import /system/etc/init/hw/init.${ro.zygote}.rc
不同的 rc 配置文件对应不同的启动策略
根据不同厂商共有四个属性:
init.zygote32.rc -- 执行 app_process
init.zygote64.rc --执行 app_process64
init.zygote32_64.rc -- 启动两个 zygote 进程,名为 zygote 和 zygote_secondary,分别执行 app_process32、app_process64
init.zygote64_32.rc -- -- 启动两个 zygote 进程,名为 zygote 和 zygote_secondary,分别执行 app_process64、app_process32
(2)zygote 触发时机
on late-init-->trigger zygote-starton zygote-start-->start zygoteDir:/system/core/init/init.cpp
if (bootmode == "charger") {am.QueueEventTrigger("charger");
} else {am.QueueEventTrigger("late-init");
}
附:app_process 位于手机系统的 bin 目录下,在 AS File Explorer 中可以看到,app_process 会
读取到 /frameworks/base/cmds/app_process/Android.bp 文件,然后执行 app_main.cpp,
/frameworks/base/cmds/app_process/app_main.cpp 的 main 方法解析的参数,则来源于 init.zygote.rc
2、Zygote 初始化
Dir:/frameworks/base/cmds/app_process/app_main.cpp
(1)main() 进行参数解析【--zygote --start-system-server】
if (strcmp(arg, "--zygote") == 0) {zygote = true;niceName = ZYGOTE_NICE_NAME;
}
if (zygote) {runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
}
(2)创建虚拟机及注册 JNI
Dir:frameworks/base/core/jni/AndroidRuntime.cpp
startVm() -- 创建虚拟机
startReg() -- 注册 JNI--> register_jni_procs(gRegJNI, NELEM(gRegJNI), env) //gRegJNI 是一个 jni 数组对象env->CallStaticVoidMethod(startClass, startMeth, strArray); //startClass 即传入的ZygoteInit//接下来就会执行 ZygoteInit.java 的 main 方法,从 native 层进入 java 层//JVM :虚拟机,其实就是一块代码,负责实现内存管理,因为是 zygote 通过 fork 创建的进程,所以每个进程都拥有一个独立的 JVM
3、Zygote 的 java 启动
(1)预加载,加快 app 进程的启动
Dir:frameworks/base/core/java/com/android/internal/os/ZygoteInit.java -- main()
preload(bootTimingsTraceLog);
(1)bootTimingsTraceLog.traceBegin("PreloadClasses");
//preloadClassess 将framework.jar里的preloaded-classes 定义的所有class load到内存里,preloaded-classes 编译Android后可以在framework/base下找到。
//会加载手机 system/etc/preloaded-classes 文件中记录好的类文件
(2)preloadResources();
//preloadResources 将系统的Resource(不是在用户apk里定义的resource)load到内存。资源preload到Zygoted的进程地址空间,所有fork的子进程将共享这份空间而无需重新load, 这大大减少了应用程序的启动时间,但反过来增加了系统的启动时间。通过对preload 类和资源数目进行调整可以加快系统启动。Preload也是Android启动最耗时的部分之一
(2)通知 VM 进行垃圾回收
//gc()必须在fork之前完成(接下来的StartSystemServer就会有fork操作),这样将来被复制出来的子进程才能有尽可能少的垃圾内存没有释放
gcAndFinalize();
(3)创建 zygote 服务端,本质上是一个 socket
//frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
zygoteServer = new ZygoteServer(isPrimaryZygote);-->//frameworks/base/core/java/com/android/internal/os/ZygoteServer.javamZygoteSocket = Zygote.createManagedSocketFromInitSocket(Zygote.PRIMARY_SOCKET_NAME);-->//frameworks/base/core/java/com/android/internal/os/Zygote.javareturn new LocalServerSocket(fd);
(4)创建 SystemServer 进程
Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);ZygoteInit.java--forkSystemServer()-->Zygote.java--nativeForkSystemServer()-->com_android_internal_os_Zygote_nativeForkSystemServer.cpp【通过 JNI 的映射】-->pid_t pid = zygote::ForkCommon(env, true,fds_to_close,fds_to_ignore,true);-->pid_t pid = fork(); //最终调用 linux 的 fork()
(5)循环等待
caller = zygoteServer.runSelectLoop(abiList);
四、SystemServer 启动流程
1、参数处理
//ZygoteInit.java
//在 handleSystemServerProcess() 中进行 server 的初始化工作if (pid == 0) {if (hasSecondZygote(abiList)) {waitForSecondaryZygote(socketName);}zygoteServer.closeServerSocket();return handleSystemServerProcess(parsedArgs);
}//(1) prepareSystemServerProfile(systemServerClasspath);
//(2) 判断fork args 中是否有 invokWith 参数,如果有则进行WrapperInit.execApplicationif (parsedArgs.mInvokeWith != null) {String[] args = parsedArgs.mRemainingArgs;// If we have a non-null system server class path, we'll have to duplicate the// existing arguments and append the classpath to it. ART will handle the classpath// correctly when we exec a new process.if (systemServerClasspath != null) {String[] amendedArgs = new String[args.length + 2];amendedArgs[0] = "-cp";amendedArgs[1] = systemServerClasspath;System.arraycopy(args, 0, amendedArgs, 2, args.length);args = amendedArgs;}WrapperInit.execApplication(parsedArgs.mInvokeWith,parsedArgs.mNiceName, parsedArgs.mTargetSdkVersion,VMRuntime.getCurrentInstructionSet(), null, args);throw new IllegalStateException("Unexpected return from WrapperInit.execApplication");} else {ClassLoader cl = getOrCreateSystemServerClassLoader();if (cl != null) {Thread.currentThread().setContextClassLoader(cl);}/** Pass the remaining arguments to SystemServer.*/return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,parsedArgs.mDisabledCompatChanges,parsedArgs.mRemainingArgs, cl);
}
2、初始化
(1) ZygoteInit
//ZygoteInit.javaZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,parsedArgs.mDisabledCompatChanges,parsedArgs.mRemainingArgs, cl);-->ZygoteInit.nativeZygoteInit();--> //JNIcom_android_internal_os_ZygoteInit_nativeZygoteInit-->//AndroidRuntime.cppgCurRuntime->onZygoteInit();-->//app_main.cppvirtual void onZygoteInit(){sp<ProcessState> proc = ProcessState::self();ALOGV("App process: starting thread pool.\n");//启动一个 Binder 线程池,用于 SystemServer 和其他线程的通信proc->startThreadPool();}
(2)applicationInit
//ZygoteInit.javareturn RuntimeInit.applicationInit(targetSdkVersion, disabledCompatChanges, argv,classLoader);-->//RuntimeInit.javareturn findStaticMain(args.startClass, args.startArgs, classLoader);-->//RuntimeInit.java; 通过反射找到SystemServer 的 main 方法m = cl.getMethod("main", new Class[] { String[].class });return new MethodAndArgsCaller(m, argv);//耗时操作通过线程完成,MethodAndArgsCaller 的 run 方法中执行 mMethod.invoke(null, new Object[] {null, new Object[]{ mArgs });-->//SystemServer 的 main 方法执行:public static void main(String[] args) {new SystemServer().run();}
五、SystemServer 执行流程
1、初始化
(1)一些属性的设置
(2)初始化上下文
// Initialize the system context.
createSystemContext();private void createSystemContext() {ActivityThread activityThread = ActivityThread.systemMain();mSystemContext = activityThread.getSystemContext();mSystemContext.setTheme(DEFAULT_SYSTEM_THEME);final Context systemUiContext = activityThread.getSystemUiContext();systemUiContext.setTheme(DEFAULT_SYSTEM_THEME);
}
2、创建 SystemServiceManager
//初始化SystemServiceManager,用来管理启动service,SystemServiceManager中封装了启动Service的startService方法启动系统必要的Service
mSystemServiceManager = new SystemServiceManager(mSystemContext);
3、启动一系列系统服务
try {t.traceBegin("StartServices");startBootstrapServices(t);startCoreServices(t);startOtherServices(t);startApexServices(t);
} catch (Throwable ex) {Slog.e("System", "******************************************");Slog.e("System", "************ Failure starting system services", ex);throw ex;
} finally {t.traceEnd(); // StartServices
}
相关文章:
Android 启动流程及 init 进程解析
一、Android 启动流程概括 按下电源键触发开机,从 ROM 加载引导程序 BootLoader 到 RAM 中,BootLoader 执行启动 Linux kernel,然后启动第一个用户进程 init,init 进程的工作包括挂载文件、创建文件目录、设置 selinux 安全策略&…...
Java设计模式:核心概述(一)
在软件开发中,设计模式是一种被广泛认可的解决方案,用于解决在软件设计中经常遇到的一些特定问题。Java作为一种面向对象的编程语言,特别适合于应用各种设计模式。本文将带您深入了解Java中的设计模式,包括它们的定义、出现的原因…...

计算机网络:IP
引言: IP协议是互联网协议族中的核心协议之一,负责为数据包在网络中传输提供路由寻址。它定义了数据包如何在互联网上从源地址传输到目的地址的规则和流程。IP协议使得各种不同类型的网络设备能够相互通信,实现了全球范围内的信息交换。 目录…...
CSS中使用变量的两个函数var和calc
CSS/CSS3 变量var()函数和calc()函数计算的使用 var()变量 var变量的定义语法 : --变量名 (两个短横线加上变量名) calc() 函数计算 calc使用的时候有几个地方需要注意: 1. 运算符前后都需要保留一个空格 2. 任何长度值都可以使用calc()函数进行计算; 3. 支持 - …...

了解docker与k8s
随着 k8s 作为容器编排解决方案变得越来越流行,有些人开始拿 Docker 和 k8s 进行对比,不禁问道:Docker 不香吗? k8s 是 kubernetes 的缩写,8 代表中间的八个字符。 其实 Docker 和 k8s 并非直接的竞争对手两者相互依存…...
服务器防火墙的应用技术有哪些
服务器防火墙的应用技术有哪些 1.数据包过滤技术 数据包过滤是最基本的服务器防火墙技术之一,它根据一系列预定义规则过滤进出网络的数据包。数据包过滤器通常基于IP地址、端口号和协议类型等信息来判断数据包是否合法,如果不符合规则,则将被…...

打开 Camera app 出图,前几帧图像偏暗、偏色该怎样去避免?
1、问题背景 使用的安卓平台,客户的应用是要尽可能快的获取到1帧图像效果正常的图片。 但当打开 camera 启动出流后,前3-5帧图像是偏暗、偏色的,如下图所示,是抓取出流的前25帧图像, 前3帧颜色是偏蓝的,…...

SD-WAN技术:优化国内外服务器访问的关键
在全球化的商业环境中,企业经常需要在国内访问国外的服务器。然而,由于地理位置和网络架构的限制,这种跨国访问往往会遇到速度慢、延迟高等问题。SD-WAN(软件定义广域网)技术的兴起,为企业提供了一种新的解…...

【MySQL】学习和总结标量子查询
🌈个人主页: Aileen_0v0 🔥热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 💫个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-kLo6jykc7AcEVEQk {font-family:"trebuchet ms",verdana,arial,sans-serif;font-siz…...

vue3第三节(v-model 执行原理)
特殊说明: 以下vue3语法是基于 3.4之前版本进行使用的,3.4之后的版本 引入了 defineModel 宏,后续会介绍defineModel 1、vue3 与vue2 中v-model区别 vue3 中v-model绑定的不再是value,而是modelValue,接收的方法也不再…...

RunnerGo UI自动化测试脚本如何配置
RunnerGo提供从API管理到API性能再到可视化的API自动化、UI自动化测试功能模块,覆盖了整个产品测试周期。 RunnerGo UI自动化基于Selenium浏览器自动化方案构建,内嵌高度可复用的测试脚本,测试团队无需复杂的代码编写即可开展低代码的自动化…...
Android 指南针校准进度计算实现
关于Android中指南针的实现,我们可以使用传感器来获取设备的方向信息,从而实现指南针功能。 Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);sensorManager (SensorManager) getSystemService(Conte…...
c++学习:Lambda练习和数组练习
练习一 进行加减乘除 普通方法 #include <iostream> using namespace std; int add(int a,int b) {return ab; } int min(int a,int b) {return a-b; } int mul(int a,int b) {return a*b; } float divRet(int a,int b) {return (float)a/b; } int main() {int a;int …...
数据仓库和数据湖的区别
数据仓库和数据湖是两种不同的数据存储和管理架构,它们有以下区别: 1.数据结构:数据仓库采用结构化的数据模型,通常是规范化的关系型数据库,其中数据以表格形式组织,使用预定义的模式和架构。而数据湖则是…...

tkinterFrame框架+标签框架LabelFrame+Toplevel窗口的使用
1.在tkinter中,Frame是一个容器小部件用于组织和管理其他小部件。它可以作为一个独立的可见区域,也可以作为其他小部件的父容器。 import tkinter as tk import tkinter.ttk as ttk import tkinter.messagebox as mbm tk.Tk() m.title("tkinter L…...
C 语言中的 char 关键字详解
1. char类型 char类型用于存储单个字符,占用1个字节的内存空间。在C语言中,char类型可以用于存储ASCII码表中的任意字符,包括大小写字母、数字、标点符号等。例如: char ch A;在这个例子中,变量ch存储了字符A的ASCI…...
信息安全管理与评估赛题解析-应急响应(含环境)
服务器应急响应 文章目录 服务器应急响应题目:答案:192.168.1.7答案:Linux x86_64答案:shodan答案:DIRSEARCH答案:24/Apr/2022:15:26:42答案:2022答案:/var/www/html/footer.php答案:./prism答案:/root/.mal/prism答案:后门行为相关资源...

微服务-微服务Spring Security OAuth 2实战
1. Spring Authorization Server 是什么 Spring Authorization Server 是一个框架,它提供了 OAuth 2.1 和 OpenID Connect 1.0 规范以及其他相关规范的实现。它建立在 Spring Security 之上,为构建 OpenID Connect 1.0 身份提供者和 OAuth2 授权服务器产品提供了一个安全、轻…...

二次供水物联网:HiWoo Cloud助力城市水务管理升级
随着城市化的快速推进,二次供水系统作为城市基础设施的重要组成部分,其稳定运行和高效管理显得至关重要。然而,传统的二次供水管理方式在应对复杂多变的城市供水需求时,显得力不从心。为了破解这一难题,HiWoo Cloud平台…...
P1015 [NOIP1999 普及组] 回文数
题目传送门 题目描述 若一个数(首位不为零)从左向右读与从右向左读都一样,我们就将其称之为回文数。 例如:给定一个十进制数 56,将 56 加 65(即把 56 从右向左读),得到 121 是一个…...
云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?
大家好,欢迎来到《云原生核心技术》系列的第七篇! 在上一篇,我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在,我们就像一个拥有了一块崭新数字土地的农场主,是时…...
反向工程与模型迁移:打造未来商品详情API的可持续创新体系
在电商行业蓬勃发展的当下,商品详情API作为连接电商平台与开发者、商家及用户的关键纽带,其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息(如名称、价格、库存等)的获取与展示,已难以满足市场对个性化、智能…...

AI Agent与Agentic AI:原理、应用、挑战与未来展望
文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例:使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例:使用OpenAI GPT-3进…...

基于Docker Compose部署Java微服务项目
一. 创建根项目 根项目(父项目)主要用于依赖管理 一些需要注意的点: 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件,否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...
Caliper 配置文件解析:fisco-bcos.json
config.yaml 文件 config.yaml 是 Caliper 的主配置文件,通常包含以下内容: test:name: fisco-bcos-test # 测试名称description: Performance test of FISCO-BCOS # 测试描述workers:type: local # 工作进程类型number: 5 # 工作进程数量monitor:type: - docker- pro…...

破解路内监管盲区:免布线低位视频桩重塑停车管理新标准
城市路内停车管理常因行道树遮挡、高位设备盲区等问题,导致车牌识别率低、逃费率高,传统模式在复杂路段束手无策。免布线低位视频桩凭借超低视角部署与智能算法,正成为破局关键。该设备安装于车位侧方0.5-0.7米高度,直接规避树枝遮…...
Oracle11g安装包
Oracle 11g安装包 适用于windows系统,64位 下载路径 oracle 11g 安装包...
小木的算法日记-多叉树的递归/层序遍历
🌲 从二叉树到森林:一文彻底搞懂多叉树遍历的艺术 🚀 引言 你好,未来的算法大神! 在数据结构的世界里,“树”无疑是最核心、最迷人的概念之一。我们中的大多数人都是从 二叉树 开始入门的,它…...
云原生周刊:k0s 成为 CNCF 沙箱项目
开源项目推荐 HAMi HAMi(原名 k8s‑vGPU‑scheduler)是一款 CNCF Sandbox 级别的开源 K8s 中间件,通过虚拟化 GPU/NPU 等异构设备并支持内存、计算核心时间片隔离及共享调度,为容器提供统一接口,实现细粒度资源配额…...
[特殊字符] 手撸 Redis 互斥锁那些坑
📖 手撸 Redis 互斥锁那些坑 最近搞业务遇到高并发下同一个 key 的互斥操作,想实现分布式环境下的互斥锁。于是私下顺手手撸了个基于 Redis 的简单互斥锁,也顺便跟 Redisson 的 RLock 机制对比了下,记录一波,别踩我踩过…...