简析 Android 四大组件

367 阅读5分钟

解析 Android 四大组件(Activity、Service、ContentProvider、BroadcastReceiver)与进程启动的底层关联,结合 Android 6.0 源码,阐述组件如何触发进程创建及进程与系统服务的交互机制。以下是通俗且详尽的解读:

一、四大组件与进程的关系:组件运行的载体

1. 进程是组件的 “容器”

  • 每个组件(如 Activity)必须运行在某个进程中。若组件配置的进程不存在,系统会自动创建新进程。

  • 进程创建触发场景

    • 首次启动 Activity、Service。
    • 首次访问 ContentProvider。
    • 静态广播 Receiver 首次接收广播(需启动所在进程)。

2. 组件与进程创建的映射

组件触发进程创建的核心方法场景说明
ActivityActivityStackSupervisor.startSpecificActivityLocked启动 Activity 时,所属进程未运行
ServiceActiveServices.bringUpServiceLocked启动 Service 时,所属进程未运行
ContentProviderAMS.getContentProviderImpl首次调用query/insert等方法时
BroadcastReceiverBroadcastQueue.processNextBroadcast静态广播首次接收时,所属进程未运行

示例
当应用首次点击按钮启动 Activity 时,若该 Activity 所属进程未运行,系统会先创建进程,再启动 Activity。

二、进程创建核心流程:从组件到 Zygote 的协作

1. 核心方法:AMS.startProcessLocked

  • 作用:由系统服务 AMS 发起,负责创建新进程或唤醒已存在进程。

  • 重载方法

    • startProcessLocked(String processName, ...):根据进程名和应用信息创建进程(四大组件常用)。

    • startProcessLocked(ProcessRecord app, ...):基于已有进程记录启动进程。

关键逻辑

  1. 检查进程是否存在:通过mPidsSelfLocked查找已存在的进程记录(ProcessRecord)。
  2. 创建新进程记录:若进程不存在,创建ProcessRecord并配置参数(如 UID、GID、权限等)。
  3. 请求 Zygote 创建进程:通过Process.start向 Zygote 发送创建请求,Zygote 通过 fork 复制自身生成新进程。

2. Zygote 的角色:进程的 “孵化器”

  • 功能:作为系统首个 Java 进程,预加载系统资源,通过 fork 快速创建新进程,避免重复初始化开销。

  • 流程

    1. AMS 通过 Socket 向 Zygote 发送创建进程的请求(含进程名、参数等)。
    2. Zygote 执行 fork,生成新进程(子进程继承 Zygote 的资源和状态)。
    3. 子进程加载应用代码,调用ActivityThread.main初始化主线程。

3. 新进程初始化:从 Zygote 到主线程

  • 子进程启动

    • 调用ActivityThread.main,创建主线程 Looper、消息队列,并初始化ActivityThread对象。
    • 通过attach方法与 AMS 建立 Binder 连接,通知系统进程已启动。
  • Binder 通信建立

    • 子进程通过ActivityManagerProxy(AMP)向 AMS 发送ATTACH_APPLICATION请求,注册进程信息。
    • AMS 通过ApplicationThreadProxy(ATP)回调子进程的bindApplication,完成应用初始化(如创建 Application 实例、注册组件)。

三、四大组件的进程创建细节

1. Activity:界面组件的进程触发

  • 流程

    1. 用户点击启动 Activity,调用startActivity
    2. AMS 检查 Activity 所属进程是否存在,不存在则调用startProcessLocked创建。
    3. 新进程启动后,通过attachApplication回调初始化 Activity 组件。

2. Service:后台组件的进程管理

  • 特点

    • 若 Service 配置为独立进程(android:process),首次启动时创建新进程。
    • 进程创建逻辑通过ActiveServices.bringUpServiceLocked触发,与 Activity 类似,但无需处理 UI 线程。

3. ContentProvider:数据组件的延迟加载

  • 触发时机

    • 首次调用ContentResolver.query等方法时,AMS 检查 Provider 所属进程,不存在则创建。
    • 通过AMS.getContentProviderImpl触发进程创建,确保 Provider 在首次使用时初始化。

4. BroadcastReceiver:广播驱动的进程唤醒

  • 静态广播的特殊性

    • 静态注册的 Receiver 在接收到广播时,若所属进程未运行,系统创建进程并触发onReceive
    • 通过BroadcastQueue.processNextBroadcast检测进程状态,缺失则调用startProcessLocked

四、多进程应用与进程配置

1. android:process属性解析

  • 单进程应用:默认所有组件运行在应用主进程(包名同名进程)。

  • 多进程应用

    • 私有进程:属性值以 “:” 开头(如:remote),仅当前应用可访问。

    • 全局进程:属性值为完整名称(如com.example.remote),需包含 “.”,其他应用可通过该进程名启动组件。

示例

xml

<service android:name=".RemoteService" android:process=":remote" /> <!-- 私有进程 -->
<provider android:name=".RemoteProvider" android:process="com.example.remote" /> <!-- 全局进程 -->

2. 进程名合法性

  • 全局进程名必须包含 “.”(如com.example.process),私有进程名可不含(如:worker)。
  • 系统通过PackageParser校验进程名格式,非法名会导致组件启动失败。

五、进程与系统服务的通信:Binder 的双向交互

1. 双向 Binder 通道

  • 客户端(进程)→ AMS
    通过ActivityManagerProxy(AMP)调用 AMS 接口(如attachApplication)。
  • AMS → 客户端(进程)
    通过ApplicationThreadProxy(ATP)回调进程内的ApplicationThread(如bindApplication)。

2. 关键通信步骤

  1. 进程启动后
    子进程通过ActivityThread.attach向 AMS 发送ATTACH_APPLICATION请求,携带ApplicationThread(Binder 服务端)。
  2. AMS 初始化
    AMS 通过attachApplicationLocked保存进程记录,并通过 ATP 调用子进程的bindApplication,初始化应用环境(如创建 Application、注册 Provider)。
  3. 组件生命周期回调
    AMS 通过 ATP 触发组件生命周期(如 Activity 的onCreate),子进程通过 Handler 在主线程执行回调。

六、总结:进程创建的全景图

  1. 触发链
    组件启动 → AMS 检测进程存在性 → 调用startProcessLocked → Zygote fork 新进程 → 新进程通过 Binder 注册到 AMS → 初始化组件。

  2. 核心目标

    • 确保组件在独立或共享进程中正确运行。
    • 通过 Zygote 和 Binder 机制优化进程创建效率,减少资源消耗。
  3. 开发者视角

    • 合理配置android:process避免不必要的进程创建。

    • 注意多进程场景下的内存隔离和通信问题(如使用AIDLLocalBroadcastManager)。

通过理解四大组件与进程启动的深层关联,开发者可更精准地优化应用启动性能,处理多进程通信问题,并深入分析系统级异常(如 ANR、进程崩溃)。