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

Android 应用进程启动

跨进程协作过程:

详细步骤解析

第一步:发起 Fork 请求(从 System Server 到 Zygote)
  1. 起点: 当系统需要启动一个应用组件(如 Activity)而该应用进程不存在时,ActivityManagerService (AMS) 会决定要启动一个新进程
  2. 准备参数: AMS 会收集所有启动新进程所需的信息,例如:
    ○ 应用包名: 用于识别应用身份
    ○ 进程名: 通常是包名或带有特定后缀(如 :background
    ○ UID/GID: 应用的用户和组 ID,用于沙盒隔离
    ○ 目标 SDK 版本: 用于兼容性控制
    ○ 入口类名: 即 android.app.ActivityThread
    ○ 其他标志位: 用于控制运行行为(如是否为调试应用)
  3. 跨进程通信: AMS(运行在 system_server 进程)通过 Unix Domain Socket 向 Zygote 进程发送一个 fork 新进程的请求。这是通过 ZygoteProcess 类(其内部是 ZygoteState)建立 Socket 连接并发送参数实现的
第二步:Zygote Fork 新进程
  1. 接收请求: Zygote 进程通过 ZygoteServer 一直在其 Socket 上监听来自 AMS 的请求
  2. 解析参数: Zygote 收到请求后,会解析参数,准备好 fork 操作
  3. Fork 系统调用: Zygote 调用 fork() 系统调用。这是最关键的一步
    ○ Zygote 的优化: 得益于 Copy-on-Write (COW) 机制,Zygote 在启动时已预加载了大量的 Android 框架类和资源(如 ActivityThreadContextImpl, 通用资源等)。新 fork 出的进程几乎零成本地继承了所有这些预加载的类和信息,这极大地加快了应用启动速度并节省了内存
  4. 子进程(新应用进程)初始化:
    ○ 处理 Socket: 子进程会关闭从 Zygote 继承下来的、用于监听 fork 请求的 Socket,因为它不需要这个
    ○ 清理状态: 清理从 Zygote 继承的、不需要的线程和内存状态
  5. 执行入口方法: 在子进程中,会调用 ZygoteInit.zygoteInit() 方法,该方法主要做三件事:
    ○ 启动 Binder 线程池: 调用 ZygoteInit.nativeZygoteInit() -> AppRuntime.onZygoteInit() -> ProcessState.startThreadPool()。这启动了 Binder 机制,使得新进程具备了 IPC 能力,可以与其他系统服务(如 AMS)进行通信
    ○ 关闭 Log 流: 关闭从 Zygote 继承的日志流
    ○ 进入主入口: 最终,通过反射调用 AMS 请求中指定的入口类的 main() 方法,即 android.app.ActivityThread.main(String[] args)
第三步:ActivityThread 接管和应用初始化
  1. ActivityThread.main(): 这是应用进程的“主函数”和入口点
    ○ 主线程初始化: 它运行在应用的主线程(UI 线程)上
    ○ 创建 ActivityThread 实例: ActivityThread 对象被创建,它是应用进程中的核心管理器,负责调度和管理四大组件
    ○ 创建 Looper: 调用 Looper.prepareMainLooper() 和 Looper.loop(),为主线程建立消息队列(MessageQueue),开始处理消息(如 UI 事件、生命周期回调等)
  2. attach 到系统服务: ActivityThread.main() 方法会调用 thread.attach(false)(其中 thread 是 ActivityThread 实例)
    ○ 这个方法会通过 Binder 调用 IActivityManager.attachApplication(),最终通知到 AMS,告诉它:“我这个新进程已经启动完毕,并且准备好了”
  3. AMS 完成后续启动: AMS 收到 attachApplication() 回调后,会知道新进程已就绪。然后它会:
    ○ 通过 Binder IPC 回调到应用进程的 ApplicationThread(一个实现了 IApplicationThread 接口的 Binder 对象,是 ActivityThread 的内部类)
    ○ 发送 BIND_APPLICATION 等消息到应用进程的消息队列
  4. 加载应用 APK 和创建 Application:
    ○ 主线程的 H(Handler)会处理 BIND_APPLICATION 消息
    ○ 这会触发 ActivityThread.handleBindApplication() 方法
    ○ 在该方法中,会:
    ◎ 创建 ContextImpl(Context 的真正实现)
    ◎ 使用 LoadedApk 类的信息,通过 ClassLoader 加载应用的 APK
    ◎ 实例化应用的 Application 对象(根据 AndroidManifest.xml 中 <application> 的 android:name 属性,默认为 android.app.Application
    ◎ 调用 Application.onCreate() 生命周期方法。这是应用开发者可以接受到的第一个自定义回调

总结与关键点

  • Zygote 的作用: 预加载通用框架资源和类,通过 fork 快速创建新进程,节省内存和启动时间
  • 进程分工:
    ○ system_server (AMS): 决策者。决定何时、为何启动新进程,并收集启动参数
    ○ Zygote 孵化器。负责执行 fork(),创建进程实例
    ○ 应用进程: 执行者。运行 ActivityThread 和应用代码
  • 两次 IPC:
    ① 
    AMS -> Zygote (via Socket):请求 fork
    ② 应用进程 -> AMS (via Binder):通知 attach,完成后续启动流程
  • 主线程消息循环: ActivityThread.main() 的核心是启动 Looper,使得主线程成为一个事件驱动的工作模式,所有来自系统的回调(如生命周期、界面绘制)都通过消息队列来调度
http://www.xdnf.cn/news/1462645.html

相关文章:

  • 趣味学RUST基础篇(构建一个命令行程序2重构)
  • 基于FPGA实现数字QAM调制系统
  • AiPPT生成的PPT内容质量怎么样?会不会出现逻辑混乱或数据错误?
  • 一键生成PPT的AI工具排名:2025年能读懂你思路的AI演示工具
  • 深度学习——迁移学习
  • 鸿蒙:获取UIContext实例的方法
  • Spring Boot+Nacos+MySQL微服务问题排查指南
  • 国产化PDF处理控件Spire.PDF教程:如何在 Java 中通过模板生成 PDF
  • 抓虫:sw架构防火墙服务启动失败 Unable to initialize Netlink socket: 不支持的协议
  • 还有人没搞懂住宅代理IP的属性优势吗?
  • java解析网络大端、小端解析方法
  • 信息安全基础知识
  • 云原生部署_Docker入门
  • 将 Android 设备的所有系统日志(包括内核日志、系统服务日志等)完整拷贝到 Windows 本地
  • android View详解—动画
  • Kali搭建sqli-labs靶场
  • modbus_tcp和modbus_rtu对比移植AT-socket,modbus_tcp杂记
  • 《sklearn机器学习——聚类性能指数》同质性,完整性和 V-measure
  • 从 Prompt 到 Context:LLM OS 时代的核心工程范式演进
  • [特殊字符] AI时代依然不可或缺:精通后端开发的10个GitHub宝藏仓库
  • Xilinx系列FPGA实现DP1.4视频收发,支持4K60帧分辨率,提供2套工程源码和技术支持
  • 【Arxiv 2025 预发行论文】重磅突破!STAR-DSSA 模块横空出世:显著性+拓扑双重加持,小目标、大场景统统拿下!
  • K8S的Pod为什么可以解析访问集群之外的域名地址
  • LeetCode刷题-top100( 矩阵置零)
  • android 四大组件—BroadcastReceiver
  • 《深入理解双向链表:增删改查及销毁操作》
  • 贪吃蛇鱼小游戏抖音快手微信小程序看广告流量主开源
  • 架构性能优化三板斧:从10秒响应到毫秒级的演进之路
  • VSCode+MobaXterm+X11可视化界面本地显示
  • pydantic定义llm response数据模型