当前位置: 首页 > news >正文

Android系统启动流程--zygote进程的启动流程

在上一篇init进程启动流程中已经提到,在init中会解析一个init.rc文件,解析后会执行其中的命令来启动zygote进程、serviceManager进程等,下面我们来看一下:

//文件路径:system/core/init/init.cppstatic void LoadBootScripts(ActionManager& action_manager, ServiceList& service_list) {//创建解析器Parser parser = CreateParser(action_manager, service_list);std::string bootscript = GetProperty("ro.boot.init_rc", "");if (bootscript.empty()) {//解析init.rc ,这个是手机设备上的路径,和源码中system/core/rootdir/init.rc是一个文件parser.ParseConfig("/system/etc/init/hw/init.rc");if (!parser.ParseConfig("/system/etc/init")) {late_import_paths.emplace_back("/system/etc/init");}// late_import is available only in Q and earlier release. As we don't// have system_ext in those versions, skip late_import for system_ext.parser.ParseConfig("/system_ext/etc/init");if (!parser.ParseConfig("/product/etc/init")) {late_import_paths.emplace_back("/product/etc/init");}if (!parser.ParseConfig("/odm/etc/init")) {late_import_paths.emplace_back("/odm/etc/init");}if (!parser.ParseConfig("/vendor/etc/init")) {late_import_paths.emplace_back("/vendor/etc/init");}} else {parser.ParseConfig(bootscript);}
}

我们来看一下这个init.rc中和zygote相关的部分:

#文件路径:system/core/rootdir/init.rc   或设备上 /system/etc/init/hw/init.rc#引入子rc文件,${ro.zygote}是一个变量,取值范围zygote32、zygote64、zygote32_64、zygote64_32,会根据实际设备是32位还是64位进行选择
import /system/etc/init/hw/init.${ro.zygote}.rc# Mount filesystems and start core system services.
on late-init# Now we can start zygote for devices with file based encryption#在init启动后的一个时机,触发启动zygote进程trigger zygote-starton zygote-start && property:ro.crypto.state=unencrypted# A/B update verifier that marks a successful boot.exec_start update_verifier_nonencryptedstart statsdstart netdstart zygote  #启动zygote进程,那么这个zygote是什么呢?start zygote_secondary#还记得文件开头处的import 引入的子rc文件吗?我们以init.zygote64.rc为例:
#文件路径: system/core/rootdir/init.zygote64.rc#service zygote 服务名为zygote
#对应的可执行程序路径:/system/bin/app_process64  (设备上的路径)
#-Xzygote /system/bin --zygote --start-system-server  执行app_process64时传入的参数
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-serverclass mainpriority -20user root  #用户角色group root readproc reserved_disksocket zygote stream 660 root systemsocket usap_pool_primary stream 660 root system#如果意外挂掉需要重启的服务onrestart exec_background - system system -- /system/bin/vdc volume abort_fuseonrestart write /sys/power/state ononrestart restart audioserveronrestart restart cameraserveronrestart restart mediaonrestart restart netdonrestart restart wificondwritepid /dev/cpuset/foreground/tasks

和上一篇中的init一样,zygote进程也具化到了设备中的执行程序,即app_process,我们来看下他是由那个文件编译出来的。

//文件路径 frameworks/base/cmds/app_process/Android.bpcc_binary {name: "app_process",srcs: ["app_main.cpp"], //是同目录的app_main.cpp...
}

至于怎么去找这么文件的路径目前没有发现太好的办法,只能是多熟悉每一层的bp编译脚本+关键字搜索。

打开app_main.cpp文件:

//文件路径:framesworks/base/cmds/app_process/app_main.cpp//argv :-Xzygote /system/bin --zygote --start-system-server
int main(int argc, char* const argv[])
{//创建了android运行时环境AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));//根据传入的参数设置变量值bool zygote = false;bool startSystemServer = false;bool application = false;String8 niceName;String8 className;while (i < argc) {const char* arg = argv[i++];if (strcmp(arg, "--zygote") == 0) { //传入参数中有--zygote,所以zygote = truezygote = true;niceName = ZYGOTE_NICE_NAME;} else if (strcmp(arg, "--start-system-server") == 0) { //同理startSystemServer = truestartSystemServer = true;} else if (strcmp(arg, "--application") == 0) {application = true;} else if (strncmp(arg, "--nice-name=", 12) == 0) {niceName.setTo(arg + 12);} else if (strncmp(arg, "--", 2) != 0) {className.setTo(arg);break;} else {--i;break;}}Vector<String8> args;if (!className.isEmpty()) {...}else {// We're in zygote mode.maybeCreateDalvikCache();if (startSystemServer) { //上面已经赋值为true// args中又添加了这个参数args.add(String8("start-system-server"));}...// In zygote mode, pass all remaining arguments to the zygote// main() method.for (; i < argc; ++i) {args.add(String8(argv[i]));}}...if (zygote) {//启动运行时环境,这里就是有native转到到java层的入口,这也是为什么说zygote是java层进程的鼻祖runtime.start("com.android.internal.os.ZygoteInit", args, zygote);} else if (className) { //而这个分支是启动app相关的流程,可以先有个印象后续分析到应用的启动流程可能还会看到这里// 将上面的args参数数组传入runtime.start("com.android.internal.os.RuntimeInit", args, zygote);} else {fprintf(stderr, "Error: no class name or --zygote supplied.\n");app_usage();LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");}
}

继续跟踪runtime.start()方法,runtime是AppRuntime类型,但AppRuntime并没有start(),因为是定义在AppRuntime的父类中,找到此方法看下具体操作:

//文件路径: frameworks/base/core/jni/AndroidRuntime.cpp
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{bool primary_zygote = false;/** 'startSystemServer == true' means runtime is obsolete and not run from* init.rc anymore, so we print out the boot start event here.*///根据options参数判断是否是第一次启动zygotefor (size_t i = 0; i < options.size(); ++i) {if (options[i] == startSystemServer) {primary_zygote = true;/* track our progress through the boot sequence */const int LOG_BOOT_PROGRESS_START = 3000;LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START,  ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));}}//设置android root目录环境变量const char* rootDir = getenv("ANDROID_ROOT");if (rootDir == NULL) {rootDir = "/system";if (!hasDir("/system")) {LOG_FATAL("No root directory specified, and /system does not exist.");return;}setenv("ANDROID_ROOT", rootDir, 1);}JNIEnv* env;if (startVm(&mJavaVM, &env, zygote, primary_zygote) != 0) {  //启动虚拟机,设置虚拟机的参数默认值return;}if (startReg(env) < 0) {  //注册JNI方法,系统api中涉及的jni方法都是在这里注册的ALOGE("Unable to register all android natives\n");return;}char* slashClassName = toSlashClassName(className != NULL ? className : "");jclass startClass = env->FindClass(slashClassName);if (startClass == NULL) {}else {jmethodID startMeth = env->GetStaticMethodID(startClass, "main","([Ljava/lang/String;)V");if (startMeth == NULL) {ALOGE("JavaVM unable to find main() in '%s'\n", className);/* keep going */} else {//jni 执行ZygoteInit.java 的main()方法,由此过渡到java层env->CallStaticVoidMethod(startClass, startMeth, strArray);}}
}

这里放一张图用于表示进程与虚拟机的关系,即每个进程都有独立的虚拟机,而虚拟机就是一块大的内存区域,这块大内存又划分为堆、线程栈、方法区、程序计数器、本地方法栈等等更小的内存块。

 继续上面的流程,进入java层的com.android.internal.os.ZygoteInit的main()函数:

// 文件路径:frameworks\base\core\java\com\android\internal\os\ZygoteInit.javapublic static void main(String argv[]) {ZygoteServer zygoteServer = null;//根据传入的参数设置变量for (int i = 1; i < argv.length; i++) {if ("start-system-server".equals(argv[i])) { //由层传入,所以startSystemServer = truestartSystemServer = true;} else if ("--enable-lazy-preload".equals(argv[i])) {enableLazyPreload = true;} else if (argv[i].startsWith(ABI_LIST_ARG)) {abiList = argv[i].substring(ABI_LIST_ARG.length());} else if (argv[i].startsWith(SOCKET_NAME_ARG)) {zygoteSocketName = argv[i].substring(SOCKET_NAME_ARG.length());} else {throw new RuntimeException("Unknown command line argument: " + argv[i]);}}if (!enableLazyPreload) {bootTimingsTraceLog.traceBegin("ZygotePreload");EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,SystemClock.uptimeMillis());//预加载系统资源文件,应用进程都是zygote进程fork出来的,在此进行预加载就不用在应用进程中再去重复加载资源文件,提升应用启动速度preload(bootTimingsTraceLog);EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,SystemClock.uptimeMillis());bootTimingsTraceLog.traceEnd(); // ZygotePreload}...zygoteServer = new ZygoteServer(isPrimaryZygote);if (startSystemServer) {//启动SystemServer进程,有zygote fork而来Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);// {@code r == null} in the parent (zygote) process, and {@code r != null} in the// child (system_server) process.if (r != null) {r.run();return;}}Log.i(TAG, "Accepting command socket connections");// The select loop returns early in the child process after a fork and// loops forever in the zygote.//死循环,等待Ams发出的创建应用进程的消息caller = zygoteServer.runSelectLoop(abiList);
}

zygote进程重要事项总结

c++层:

  1. 创建Android runtime
  2. 启动虚拟机
  3. 注册JNI方法
  4. 通过JNI调用ZygoteInit.java的main(),转入到java层

java层:

  1. 预加载一些系统资源,如一些java类,resources文件,Graphics驱动、hal层的资源、动态库相关的操作等等
  2. 创建zygoteServer 服务端socket,等待AMS发出的创建应用进程的消息。
  3. fork 出systemServer进程

相关文章:

Android系统启动流程--zygote进程的启动流程

在上一篇init进程启动流程中已经提到&#xff0c;在init中会解析一个init.rc文件&#xff0c;解析后会执行其中的命令来启动zygote进程、serviceManager进程等&#xff0c;下面我们来看一下&#xff1a; //文件路径&#xff1a;system/core/init/init.cppstatic void LoadBoot…...

C++程序设计——异常

一、C异常概念 异常处理是一种处理错误的方式&#xff0c;当一个函数发现自己无法处理的错误时&#xff0c;就可以抛出异常&#xff0c;让函数的直接或间接的调用者处理这个错误。 &#xff08;1&#xff09;throw&#xff1a;当问题出现时&#xff0c;程序会通过throw关键字抛…...

2022年第十三届蓝桥杯web开发—东奥大抽奖【题目、附官方解答】

冬奥大抽奖 介绍 蓝桥云课庆冬奥需要举行一次抽奖活动&#xff0c;我们一起做一个页面提供给云课冬奥抽奖活动使用。 准备 开始答题前&#xff0c;需要先打开本题的项目代码文件夹&#xff0c;目录结构如下&#xff1a; ├── css │ └── style.css ├── effect.g…...

一份两年前一个月的工作经历没写在简历上,背调前主动坦白,却被背调公司亮了红灯,到手的offer没了!...

只因为简历上漏写了一份一个月的工作&#xff0c;就被亮了背调红灯&#xff0c;这公平吗&#xff1f;一位网友就被狠狠坑了一把&#xff0c;来看下他的遭遇&#xff1a;他有一份两年前、时长一个月的工作经历没写在简历上&#xff0c;背调前主动和背调公司还有招聘方hr都说了这…...

C++游戏分析与破解方法介绍

1、C游戏简介 目前手机游戏直接用C开发的已经不多&#xff0c;使用C开发的多是早期的基于cocos2dx的游戏&#xff0c;因此我们这里就以cocos2d-x为例讲解C游戏的分析与破解方法。 Cocos2d-x是一个移动端游戏开发框架&#xff0c;可以使用C或者lua进行开发&#xff0c;也可以混…...

食堂总是拥挤不堪?解决用餐拥挤,教你一招

随着近几年科技的快速发展&#xff0c;行业里出现了很多新的名词&#xff0c;比如智慧社区、智慧旅游、智慧建筑&#xff0c;那么智慧食堂是什么呢&#xff1f;它又是如何实现全自助、全智能消费&#xff1f; 在先进的智能技术以及市场需求带动下&#xff0c;智慧食堂经历了由传…...

ubuntu系统安装时 MBR和GPT的区别

主引导记录&#xff08;Master Boot Record &#xff0c; MBR&#xff09;是指一个存储设备的开头 512 字节。它包含操作系统的引导器和存储设备的分区表。   全局唯一标识分区表&#xff08;GUID Partition Table&#xff0c;缩写&#xff1a;GPT&#xff09;是一个实体硬盘…...

我在windows10下,使用msys64 mingw64终端

系列文章目录 文章目录系列文章目录前言一、MSYS2是什么&#xff1f;前言 msys2官网 MSYS2 &#xff08;Minimal SYStem 2&#xff09; 是一个MSYS的独立改写版本&#xff0c;主要用于 shell 命令行开发环境。 同时它也是一个在Cygwin &#xff08;POSIX 兼容性层&#xff09…...

个人2023FALL CS申请总结(PhD/MPhil/保研夏令营)

个人2023FALL CS申请总结&#xff08;PhD/MPhil/保研夏令营&#xff09;写在最前个人BG及申请情况个人BG申请情况MPhilPhD收获一句话总结&#xff1a;心态爆炸没用&#xff0c;脸皮够厚够勇就行 写在最前 真是一场恶战。有几天&#xff0c;我每天早上都海投几封套瓷邮件&…...

【优化算法】使用遗传算法优化MLP神经网络参数(TensorFlow2)

文章目录任务查看当前的准确率情况使用遗传算法进行优化完整代码任务 使用启发式优化算法遗传算法对多层感知机中中间层神经个数进行优化&#xff0c;以提高模型的准确率。 待优化的模型&#xff1a; 基于TensorFlow2实现的Mnist手写数字识别多层感知机MLP # MLP手写数字识别…...

CAM类激活映射 |神经网络可视化 | 热力图

文章目录前言&#xff1a;安装库&#xff1a;分类案例--ResNet50分割案例AttributeError: ‘tuple‘ object has no attribute ‘cpu‘RuntimeError: grad can be implicitly created only for scalar outputsTypeError: cant convert cuda:0 device type tensor to numpy. Use…...

RecyclerView+BaseRecyclerViewAdapterHelper显示不全只显示第一行item的解决问题

RecyclerViewBaseRecyclerViewAdapterHelper显示不全只显示第一行item&#xff0c;我懵了…&#xff0c;我不说多&#xff0c;直接说吧 先看一下适配器代码中的convert()方法&#xff1a; class MineRadioAdapter(layoutResId: Int R.layout.item_my_live) :BaseQuickAdapte…...

解决后端无法对前端的ajax请求重定向

本章目录&#xff1a; 问题描述 AJAX请求后端直接重定向失败解决方案 后端拦截请为响应头添加重定向标志后端拦截器为响应头添加重定向路径前端响应拦截器获取响应头数据&#xff0c;并通过location.href url 完成页面跳转一、问题描述 本来想在拦截器里设置未登录用户访问指…...

【Python】1分钟就能制作精美的框架图?太棒啦

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录前言一、准备二、基本使用与例子1.初始化与导出2.节点类型3.集群块4.自定义线的颜色与属性总结前言 Diagrams 是一个基于Python绘制云系统架构的模块&#xff0c;它能…...

淘宝必备的补单技巧及注意事项!

补单&#xff0c;是优化善后的s单。单只是模拟用户的购物习惯&#xff0c;而补单同时还要模拟整个店铺的综合数据&#xff0c;包括点击率、转化率等等&#xff0c;补到略高于同行、竞品的平均数据时&#xff0c;淘宝会判断为买家比较喜欢你的商品&#xff0c;从而给你更多推荐机…...

【实用篇】SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud分布式

文章目录一、服务拆分1.1 服务拆分Demo1.2 微服务远程调用二、Eureka2.1 Eureka原理2.2 Eureka-server服务搭建2.3 eureka-client服务注册2.4 eureka-client服务复制2.5 eureka服务发现三、Ribbon负载均衡3.1 负载均衡原理3.2 负载均衡策略3.3 自定义负载均衡策略3.4 饥饿加载与…...

私人飞机、公务机包机会成为富豪圈的主流出行方式吗?

从炫耀性消费到按需使用&#xff0c;私人飞机的消费群体正在被拓宽&#xff0c;但离“成为主流”还有一段距离。“时间就是金钱”为有钱人消费私人飞机提供合理动机&#xff0c;而这群高净值人群的数量增长则成为撑起市场基本面。据相关数据显示&#xff0c;2018年全球超级富豪…...

Oracle组织架构

组织架构 &#xff08;一&#xff09;业务组&#xff08;BG&#xff09; &#xff08;二&#xff09;法律实体&#xff08;LE&#xff09; &#xff08;三&#xff09;业务实体&#xff08;OU&#xff09; &#xff08;四&#xff09;库存组织&#xff08;INV&#xff09; …...

最小公倍数

目录 最小公倍数 程序设计 程序分析 最小公倍数 【问题描述】给定两个正整数,计算这两个数的最小公倍数。 【输入形式】输入包含多组测试数据,每组只有一行,包括两个不大于1000的正整数. 【输出形式】 对于每个测试用例,给出这两个数的最小公倍数,每个实例输出一行。…...

二叉树的后序遍历(力扣145)

目录 题目描述&#xff1a; 解法一&#xff1a;递归法 解法二&#xff1a;迭代法 解法三&#xff1a;Morris遍历 二叉树的后序遍历 题目描述&#xff1a; 给你一棵二叉树的根节点 root &#xff0c;返回其节点值的 后序遍历 。 示例 1&#xff1a; 输入&#xff1a;root …...

《Effective C++》读书纪实 -- 诸君同享

文章目录《Effective C》是一本经典的C编程指南&#xff0c;共包含50条C编程的最佳实践。 确定你的构造函数的行为 在构造函数中&#xff0c;应该尽可能地避免调用虚函数、非静态成员函数和虚基类的函数。 尽量使用const、enum、inline替换#define 使用const、enum、inline可以…...

【云原生】K8S-ConfigMap 实现应用和配置分离

文章目录前言ConfigMap 背景ConfigMap 创建方式ConfigMap 的使用使用 ConfigMap 的注意事项总结前言 Kubernetes 是目前最流行的容器编排系统之一&#xff0c;它提供了丰富的功能来支持容器化应用程序的管理和部署。 ConfigMap 是 Kubernetes 中重要的资源对象&#xff0c;用…...

java -测距工具(经纬度)

代码 /*** 测距工具* author qb*/ public class DistanceUtils {/*** 赤道半径*/private static final double EARTH_RADIUS 6378.137;private static double rad(double d) {return d * Math.PI / 180.0;}/*** Description : 通过经纬度获取距离(单位&#xff1a;米)* Group…...

postgres分区表的创建-基于继承

参考文档&#xff1a; http://postgres.cn/docs/12/ddl-partitioning.html 创建基于继承的分区表的步骤 1 创建父表 2 创建子表&#xff0c;从父表继承过来 3 创建函数及触发器&#xff0c;使插入的数据根据规则&#xff0c;插入到对应的子表中 -- 创建父表 CREATE TABLE a…...

Docker应用部署

文章目录Docker 应用部署一、部署MySQL二、部署Tomcat三、部署Nginx四、部署RedisDocker 应用部署 一、部署MySQL 搜索mysql镜像 docker search mysql拉取mysql镜像 docker pull mysql:5.6创建容器&#xff0c;设置端口映射、目录映射 # 在/root目录下创建mysql目录用于存…...

使用golang实现日志收集系统的logagent

整体架构 参考 七米老师的日志收集项目 主要用go实现logagent的部分&#xff0c;logagent的作用主要是实时监控日志追加的变化&#xff0c;并将变化发送到kafka中。 之前我们已经实现了 用go连接kafka并向其中发送数据&#xff0c;也实现了使用tail库监控日志追加操作。 我们…...

小红书点赞不显示怎么回事?小红书笔记评论被吞怎么办

小红书作为一个互联网产品&#xff0c;是一个软件。既然是软件就会有一定的程序漏洞&#xff0c;这是无法避免的。但是很多时候其实并不一定是漏洞的问题。今天就来和大家谈谈小红书点赞不显示怎么回事&#xff0c;小红书评论被吞又是怎么一回事&#xff0c;这些难道都是程序性…...

地址变换和缺页置换习题

1.设某进程页面的访问序列为4,3,2,1,4,3,5,4,3&#xff0c;2,1,5&#xff0c;当分配给该进程的内存页框数分别为3和4时&#xff0c;对于先进先出&#xff0c;最近最少使用&#xff0c;最佳页面置换算法&#xff0c;分别发生多少次缺页中断&#xff1f; 答&#xff1a; 分配的…...

PAT 乙级 1010 一元多项式求导(解题思路+AC代码)

题目&#xff1a; 设计函数求一元多项式的导数。&#xff08;注&#xff1a;xn&#xff08;n为整数&#xff09;的一阶导数为nxn−1。&#xff09; 输入格式: 以指数递降方式输入多项式非零项系数和指数&#xff08;绝对值均为不超过 1000 的整数&#xff09;。数字间以空格分…...

一维河流污染持续排放模拟(水污染扩散)

一、处理河道转换为geojson数据 以淮河为例处理示例数据&#xff1a; {"type": "FeatureCollection","features": [{"geometry": {"coordinates": [[[115.5803,34.4982],[115.5922,34.498],[115.6061,34.4994],[115.6203,…...

中企动力邮箱登陆首页/成都优化官网公司

上周&#xff0c;Mike和我们分享了他在数据库设计方面的部分经验和SQL的一些注意点。 一、数据库设计 1&#xff0e;树形结构数据 &#xff1a;分为邻接模型和 物化路径模型 1.1树形数据&#xff0c;需要解决的问题是&#xff1a; 如何将数据高效地以树形的形式展现给用户&…...

wordpress 付费下载/长沙百度快照优化排名

找1-3三个你所做的创新的关键词 分别在IEEE&#xff0c;sci-hub&#xff0c;知网上按以上关键词查找会议&#xff0c;期刊...

做的网站怎样适配手机/广告联盟官网

知行软件已于 15~17 年成功助力星宇车灯对接 BMW、上汽大众、PLASTIC OMNIUM、广汽丰田及 VDL 等。2018 年知行与星宇再次合作&#xff0c;成功对接 BBA EDI 系统。 - EDI 需求概览 - - EDI 解决方案 - OFTP2.0 on Internet 支持 OFTP2.0 传输协议且通过 ODETTE 认证的 EDI 系…...

wordpress程序版本/怎么推广游戏代理赚钱

文章目录0 效果1 实现1.1 创建名称和位置1.2 关联信号和槽函数1.3 编写事件0 效果 开始&#xff1a; 中间步骤 结束&#xff1a; 1 实现 1.1 创建名称和位置 在ui设计界面新建需要的菜单名称 1.2 关联信号和槽函数 找到对象的名称 在类的构造函数中编写函数&#x…...

wordpress 个人博客 主题/成都seo学徒

一维数组定义 定义形式&#xff1a;类型名 数组名 [数组长度]; ——数组长度是一个整型常量表达式。 例如&#xff1a; int a [10];char c [200]; 2.引用形式&#xff1a; 数组名 [ 下标 ] ——C语言规定只能引用单个的数组元素。 a[0…...

石景山区城乡建设委员会网站/百度网站是什么

好消息&#xff1a; 近日&#xff0c;拉勾招聘数据研究院对程序员群体开展深度调研后&#xff0c;发布了一份《2022程序员群体职场洞察报告》&#xff08;以下简称报告&#xff09;&#xff0c;对当下程序员群体职场生存状态、薪资水平和职场选择等方面给出了数据参考。 近8成…...