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 是一个…...
iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘
美国西海岸的夏天,再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至,这不仅是开发者的盛宴,更是全球数亿苹果用户翘首以盼的科技春晚。今年,苹果依旧为我们带来了全家桶式的系统更新,包括 iOS 26、iPadOS 26…...
【OSG学习笔记】Day 18: 碰撞检测与物理交互
物理引擎(Physics Engine) 物理引擎 是一种通过计算机模拟物理规律(如力学、碰撞、重力、流体动力学等)的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互,广泛应用于 游戏开发、动画制作、虚…...
STM32+rt-thread判断是否联网
一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...
AtCoder 第409场初级竞赛 A~E题解
A Conflict 【题目链接】 原题链接:A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串,只有在同时为 o 时输出 Yes 并结束程序,否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...
C# 类和继承(抽象类)
抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...
相机Camera日志分析之三十一:高通Camx HAL十种流程基础分析关键字汇总(后续持续更新中)
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:有对最普通的场景进行各个日志注释讲解,但相机场景太多,日志差异也巨大。后面将展示各种场景下的日志。 通过notepad++打开场景下的日志,通过下列分类关键字搜索,即可清晰的分析不同场景的相机运行流程差异…...
前端开发面试题总结-JavaScript篇(一)
文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包(Closure)?闭包有什么应用场景和潜在问题?2.解释 JavaScript 的作用域链(Scope Chain) 二、原型与继承3.原型链是什么?如何实现继承&a…...
高防服务器能够抵御哪些网络攻击呢?
高防服务器作为一种有着高度防御能力的服务器,可以帮助网站应对分布式拒绝服务攻击,有效识别和清理一些恶意的网络流量,为用户提供安全且稳定的网络环境,那么,高防服务器一般都可以抵御哪些网络攻击呢?下面…...
浅谈不同二分算法的查找情况
二分算法原理比较简单,但是实际的算法模板却有很多,这一切都源于二分查找问题中的复杂情况和二分算法的边界处理,以下是博主对一些二分算法查找的情况分析。 需要说明的是,以下二分算法都是基于有序序列为升序有序的情况…...
【开发技术】.Net使用FFmpeg视频特定帧上绘制内容
目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法,当前调用一个医疗行业的AI识别算法后返回…...
