探索APP进程的启动流程(二)完结篇

2023-11-17

首先回顾下冷启动的流程图:
冷启动
共有四个步骤:
1.launcher进程通过binder请求ams启动Activity,AMS进程查询内存中是否存在该进程。
2.内存中无相应进程,ams通过socket发送创建进程命令和相关资料到zygote进程。
3.zygote进程收到socket信息后,fork子进程,创建出ActivityThread的进程(目的进程)
4.ActivityThread通过binder把新建的进程信息与AMS进行相关联。
在上一篇博客中探索APP进程的启动流程(一),介绍了从用户点开app到发送指令给zygote进程的过程(步骤1,步骤2)。

再往下就去到Zygote进程(步骤3,步骤4),Zygote接收到初始化进程指令,fork子进程。
(剧透:如果没时间看源码,可以直接去到本文末尾,有 zygote进程等待socket消息和处理的简单模型 图)
frameworks\base\core\java\com\android\internal\os\ZygoteInit.java

public static void main(String argv[]) {
		//ZygoteServer处理有关socket服务端的业务
        ZygoteServer zygoteServer = new ZygoteServer();
        ...
        ///注册Zygote的Socket服务端
        zygoteServer.registerServerSocketFromEnv(socketName);
        ...
          if (startSystemServer) {
                //开启SystemServer
                startSystemServer(abiList, socketName, zygoteServer);
            }
            Log.i(TAG, "Accepting command socket connections");
            //等待客户端请求,
            //在runSelectLoop()里面是while(true),线程堵塞等到客户端的socket发送信息
            zygoteServer.runSelectLoop(abiList);
            //关闭Socket服务端
            zygoteServer.closeServerSocket();
          ...
}

zygoteServer. runSelectLoop(), 进行接收socket客户端信息

\frameworks\base\core\java\com\android\internal\os\ZygoteServer.java

Runnable runSelectLoop(String abiList) {
...
 		ZygoteConnection connection = peers.get(i);
 		//接收到socket客户端信息,processOneCommand进行处理
        final Runnable command = connection.processOneCommand(this);
...
}

\frameworks\base\core\java\com\android\internal\os\ZygoteConnection.java
继续看看processOneCommand()如何处理socket信息

Runnable processOneCommand(ZygoteServer zygoteServer) {
        String args[];
        Arguments parsedArgs = null;
        FileDescriptor[] descriptors;

        try {
            //readArgumentList函数来获取启动应用程序进程的命令参数
            args = readArgumentList();
            ...
            //将readArgumentList函数返回的字符串args封装到Arguments对象parsedArgs中
        	parsedArgs = new Arguments(args);
            ...
            //调用Zygote的forkAndSpecialize函数来创建应用程序进程,
        	//参数为parsedArgs中存储的应用进程启动参数,返回值为pid
       		//forkAndSpecialize函数主要是通过fork当前进程来创建一个子进程(native完成)
	        pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
	                parsedArgs.runtimeFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
	                parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.startChildZygote,
	                parsedArgs.instructionSet, parsedArgs.appDataDir);
            ...
            if (pid == 0) {
                // 如果pid等于0,则说明是现在在新创建的子进程中执行
                // in child
                zygoteServer.setForkChild();

                zygoteServer.closeServerSocket();
                IoUtils.closeQuietly(serverPipeFd);
                serverPipeFd = null;
,
                //调用 handleChildProc 函数来启动这个子进程也就是应用程序进程
                return handleChildProc(parsedArgs, descriptors, childPipeFd,
                        parsedArgs.startChildZygote);
             }
            ...
 }

\frameworks\base\core\java\com\android\internal\os\ZygoteConnection.java
进去handleChildProc()看看

  private Runnable handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors,
            FileDescriptor pipeFd, boolean isZygote) {
          ...
          //zygoteInit() 来初始化进程
		 return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs,
                        null /* classLoader */);
         ...
	}
            

frameworks\base\core\java\com\android\internal\os\ZygoteInit.java

public static final Runnable zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) {
     ...
     // 新创建的应用程序进程中创建Binder线程池
        ZygoteInit.nativeZygoteInit();
        //初始化进程入口类ActivityThread
        return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
    }

frameworks\base\core\java\com\android\internal\os\RuntimeInit.java

 protected static Runnable applicationInit(int targetSdkVersion, String[] argv,
            ClassLoader classLoader) {
...
        // args.startClass 为 从AMS的startProcessLocked()传入的参数
	 return findStaticMain(args.startClass, args.startArgs, classLoader);
...
}

再跟进findStaticMain():
frameworks\base\core\java\com\android\internal\os\RuntimeInit.java

 protected static Runnable findStaticMain(String className, String[] argv,
            ClassLoader classLoader) {
        Class<?> cl;
   		 ...
        //根据类加载器,获得Android.app.ActivityThread类
        cl = Class.forName(className, true, classLoader);
        ...
         Method m;
         ...
         //获得ActivityThread.java main()
         m = cl.getMethod("main", new Class[] { String[].class });
         ...
         //把调用ActivityThread. main()的runnable实例返回
        return new MethodAndArgsCaller(m, argv);
}

new MethodAndArgsCaller(m, argv)返回的runnable实例到ZygoteInit类的caller对象。 在ZygoteInit.main()方法中执行caller.run()
frameworks\base\core\java\com\android\internal\os\ZygoteInit.java

public static void main(String argv[]) {
        ZygoteServer zygoteServer = new ZygoteServer();
		...
		// We're in the child process and have exited the select loop. Proceed to execute the
        // command.
        //子进程会离开socket服务端等待信息的循环
        if (caller != null) {
            caller.run();
        }

MethodAndArgsCaller.run()执行了,ActivityThread.main()。
在代码,有:

static class MethodAndArgsCaller implements Runnable {
....
	public void run() {
            try {
            //mMethod为ActivityThread.main()方法。这里调用ActivityThread的main()
                mMethod.invoke(null, new Object[] { mArgs });
            } catch (IllegalAccessException ex) {
                throw new RuntimeException(ex);
            } catch (InvocationTargetException ex) {
                Throwable cause = ex.getCause();
                if (cause instanceof RuntimeException) {
                    throw (RuntimeException) cause;
                } else if (cause instanceof Error) {
                    throw (Error) cause;
                }
                throw new RuntimeException(ex);
            }
        }
....
}

初始化ActivityThread类(进程的入口类)
\frameworks\base\core\java\android\app\ActivityThread.java

//ApplicationThread 为 ActivityThread内部类,是binder服务的服务端
 final ApplicationThread mAppThread = new ApplicationThread();
 
public static void main(String[] args) {
	...
	//初始化进程的主线程 Looper
	Looper.prepareMainLooper();
	...
	//实例化 ActivityThread 对象
	ActivityThread thread = new ActivityThread();
	//在attach()方法里进行请求ams绑定当前新建的进程
    thread.attach(false, startSeq);
	...
	//loop启动
	 Looper.loop();
	...
}

继续跟进attach()
\frameworks\base\core\java\android\app\ActivityThread.java

    private void attach(boolean system, long startSeq) {
    ...
    //获得ActivityManagerService服务
    final IActivityManager mgr = ActivityManager.getService();
    //调用ActivityManagerService.attachApplication(),并传入mAppThread。请求关联进程
    mgr.attachApplication(mAppThread, startSeq);
    ...
    }

zygote进程等待socket消息和处理的简单模型

将上述的代码分析,转成流程图形式:
< zygote进程等待socket消息和处理的简单模型>
在这里插入图片描述

在这两篇文章里,只对进程的创建做分析。对于APP的启动流程,这里先不做细节分析,后续文章再继续简述APP的启动流程。

来到这里,从 新建一个进程 到 把进程与AMS关联的关键步骤已大概分析介绍。如果有其他疑问或有错误地方可以给我留言哦。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

探索APP进程的启动流程(二)完结篇 的相关文章

  • linux漏洞处理(更新中)

    1 Diffie Hellman Key Agreement Protocol 资源管理错误漏洞 CVE 2002 20001 vim etc ssh sshd config 在文件中加入下方配置 KexAlgorithms diffie
  • 【C++入门到精通】C++入门 —— 内存管理(new函数的讲解)

    目录 一 C C 内存分布 1 栈 Stack 2 堆 Heap 3 全局区 静态区 Global Area Static Area 4 常量区 Constant Area 5 代码区 Code Area 二 C语言中动态内存管理方式 1
  • 在Ubuntu上基于wayland/weston源码构建weston桌面

    Ubuntu构建weston桌面 简介 下载工具 库 安装ninja 设置环境变量 构建wayland 构建wayland protocols 构建weston 运行weston weston的一些测试程序 简介 wayland官网 htt
  • mybatis choose when 多条件_Mybatis—动态SQL详解

    前言 今天我们来聊聊Mybatis的动态SQL的使用 动态SQL可以说是mybatis的核心 可以对SQL语句进行灵活操作 通过表达式进行判断 对SQL进行灵活拼接 组装 在实际项目开发中 我们还可以将在业务层处理的逻辑转移到SQL中进行处
  • ubuntu下开启端口

    查看端口启动情况 sudo ufw status 开启端口号命令 sudo ufw allow lt 端口号 gt v6的意思就是 ipv6 开启防火墙 sudo ufw enable
  • 小米9开源linux内核,小米开源 Redmi Note 8 Pro 和 Note 9 Pro 系列的内核源码

    小米开源了基于 Android Q 的 Redmi Note 8 Pro 代号 begonia 以及 Redmi Note 9 Pro Note 9 Pro Max 代号 curtana 的内核源码 按照 XDA 的说法 GPLv2 要求所
  • 初学者的卡尔曼滤波——扩展卡尔曼滤波

    简介 转自 http www cnblogs com ymxiansen p 5368547 html 已经历经了半个世纪的卡尔曼滤波至今仍然是研究的热点 相关的文章不断被发表 其中许多文章是关于卡尔曼滤波器的新应用 但也不乏改善和扩展滤波
  • vue中监听元素尺寸变化

    data中 widthPlay 0 元素宽 heightPlay 0 元素高 observer null mounted中监听 let ResizeObserver window ResizeObserver window WebKitRe
  • 极光笔记

    PART 01 前 言 随着网络技术的发展 从粗犷型到精细化运营型 再到现在的数字化运营 数据变得越来越细分和重要 不仅可以进行策略调整 还可以实现自动化的精细化运营 而数据价值的起点就是埋点 只有合理地埋点 规范地上报 数据才会产生价值
  • SpringBoot 使用 log4j2

    一 新建工程 选择一些基础依赖 填写工程名称和项目路径 二 工程配置 修改文件编码格式 设置Java Compiler 修改maven配置文件路径 三 pom xml的web依赖中排除掉logging依赖 并且引入log4j2依赖
  • Apikit 自学日记:API 异常监控-监控报告

    在 api 管理中 查看 api 异常监控的监控报告 在 apikit 中也是常用的功能 通常你可以在流程综合报告页中看到当前流程在选定时间段内的整体监控情况 在 APIkit 中监控报告有这几种类别 单接口监控报告 流程监控报告 项目监控

随机推荐

  • 【C#学习笔记】读文件

    using System using System IO namespace ConsoleApplication class Program static void Main string args FileStream file new
  • 解决Win11休眠一段时间后自动关机的问题

    1 Win11系统有以下工作状态 S0 工作状态 系统完全可用 S0 睡眠 现代待机 低功耗空闲 网络可用 S1 睡眠 CPU停止工作 S2 睡眠 CPU关闭 S3 睡眠 仅保留内存工作 S1 S3 S4 混合睡眠 睡眠和休眠状态的组合 S
  • 最小生成树和最短路径算法

    图的概念 图表明了一种多对多的关系 图由两个元素组成 节点 vertex 和边 edge 有向图 如果给每条边规定一个方向 那么就是一个有向图 入度出度 对于有向图而言 指向一个顶点的边数称为一个点的入度 从一个顶点指出的边的个数就是出度
  • 【深度探索STL】空间配置器(二) 第一级配置器

    了解内存配置后的对象构造行为和内存释放前的对象析构行为后 参见博文 http blog csdn net wenqian1991 article details 19545049 空间配置器 构造与析构 我们再来学习内存的配置与释放 定义在
  • Keil5/MDK结构体无法自动指示成员变量

    方法总结 1 点击魔术棒法 1条消息 MDK5的结构体变量成员不提示问题的解决办法 weixin 45722312的博客 CSDN博客 keil5结构体加点后没有提示成员https blog csdn net weixin 45722312
  • elasticsearch基础5——文档处理解析、数据入盘流程、文档分片存储

    文章目录 一 同步和异步 阻塞和非阻塞 1 1 四种组合 二 客户端 2 1 高级客户端文档解析 2 2 文档索引 2 3 构建JSON文档 2 4 文档处理过程解析 2 5 数据入盘流程 2 6 与MongoDB比较 三 文档分片存储 3
  • java 生成uuid 16位_java生成16位随机UUID数

    public void testUid for int i 0 i UUID uuid UUID randomUUID System out println uuid toString 9e0db051 5ca9 46f4 958f ebd
  • STM32CubeMX学习六 之ADC配置

    文章目录 前言 一 本地环境 二 开始 1 定时器配置 2 引脚配置 在这里插入图片描述 https img blog csdnimg cn e5b6f155a1b8468cb15046a0a9d031cd png 3 内部时钟配置 4 A
  • redis必杀命令:列表(List)

    题记 Redis列表是简单的字符串列表 按照插入顺序排序 你可以添加一个元素导列表的头部 左边 或者尾部 右边 一个列表最多可以包含 232 1 个元素 4294967295 每个列表超过40亿个元素 例如 wd wd usr local
  • idea+springboot启动报错 ERROR org.apache.catalina.core.ContainerBase

    用idea导入了一个spring boot的项目 结果启动报错 ERROR org apache catalina core ContainerBase A child container failed during start tomca
  • 【JavaScript高级】Proxy和Reflect

    文章目录 存储属性描述符监听对象 Proxy 基本使用 set和get捕获器 Proxy的其他捕获器 construct和apply捕获器 Reflect 作用 方法 举个例子 Reflect的construct Receiver 参考 存
  • React 开发一个移动端项目(1)

    技术栈 项目搭建 React 官方脚手架 create react app react hooks 状态管理 redux redux thunk UI 组件库 antd mobile ajax请求库 axios 路由 react route
  • 1)数据库系统概述

    文章目录 一 数据库概念 二 常见的数据模型 三 关系型数据库 1 关系术语 2 关系的特点 3 常见存在的关系问题 4 关系运算 四 数据库设计 1 设计步骤 2 设计实例 一 数据库概念 长期存放在计算机上有组织的可共享的数据集合 二
  • secure boot 是什么

    一 secure boot 是什么 secure boot 中文叫安全启动 是电脑行业成员共同开发的一种安全机制 用于确保电脑只能启动原装系统 如果电脑重装了其他系统 那么这个系统是启动不了的 说白了 就是垄断 所以安装完其他系统 必须关闭
  • flex伸缩布局看着一篇就够啦

    flex伸缩布局 flex弹性概念 弹性盒子是一种按行或者按列布局元素的一种布局方式 它是需要父子盒子嵌套使用的 作用在父盒子 容器 上的属性有 flex direction 改变轴方向 flex wrap 换行 flex flow 前两项
  • 项目重点问题

    面试大保健 https blog csdn net Mrerlou article details 114295888 ops request misc 257B 2522request 255Fid 2522 253A 252216786
  • Java Swing图书管理系统,界面漂亮功能全,完整源码、下载直接使用 -417

    今天为利用晚上的一小段时间为大家分享一个写的不错的窗体程序 图书管理系统 417 系统功能已经比较全面 而且界面非常漂亮 有较强的参考和使用价值 项目系统有完整源码 下载后即可以运行 希望大家可以喜欢 喜欢的帮忙点赞和关注 一起编程 一起进
  • Shell脚本运行中的停止方法

    Linux系统Shell中提交了一个脚本 但是需要停止这个进程 如何处理 方式1 killall file flume kafka 说明 killall是一个命令 不是kill all file flume kafka是脚本名 此方法简单粗
  • MyBatis-Plus 的基础增删改查

    目录 1 简介 2 准备工作 3 MyBatis Plus 实现增删改查 1 MyBatis Plus 简介 MyBatis Plus 简称 MP 是 MyBatis 的增强工具 在 MyBatis 的基础上只做增强不做改变 为简化开发 提
  • 探索APP进程的启动流程(二)完结篇

    首先回顾下冷启动的流程图 共有四个步骤 1 launcher进程通过binder请求ams启动Activity AMS进程查询内存中是否存在该进程 2 内存中无相应进程 ams通过socket发送创建进程命令和相关资料到zygote进程 3