解析 Android 四大组件(Activity、Service、ContentProvider、BroadcastReceiver)与进程启动的底层关联,结合 Android 6.0 源码,阐述组件如何触发进程创建及进程与系统服务的交互机制。以下是通俗且详尽的解读:
一、四大组件与进程的关系:组件运行的载体
1. 进程是组件的 “容器”
-
每个组件(如 Activity)必须运行在某个进程中。若组件配置的进程不存在,系统会自动创建新进程。
-
进程创建触发场景:
- 首次启动 Activity、Service。
- 首次访问 ContentProvider。
- 静态广播 Receiver 首次接收广播(需启动所在进程)。
2. 组件与进程创建的映射
| 组件 | 触发进程创建的核心方法 | 场景说明 |
|---|---|---|
| Activity | ActivityStackSupervisor.startSpecificActivityLocked | 启动 Activity 时,所属进程未运行 |
| Service | ActiveServices.bringUpServiceLocked | 启动 Service 时,所属进程未运行 |
| ContentProvider | AMS.getContentProviderImpl | 首次调用query/insert等方法时 |
| BroadcastReceiver | BroadcastQueue.processNextBroadcast | 静态广播首次接收时,所属进程未运行 |
示例:
当应用首次点击按钮启动 Activity 时,若该 Activity 所属进程未运行,系统会先创建进程,再启动 Activity。
二、进程创建核心流程:从组件到 Zygote 的协作
1. 核心方法:AMS.startProcessLocked
-
作用:由系统服务 AMS 发起,负责创建新进程或唤醒已存在进程。
-
重载方法:
-
startProcessLocked(String processName, ...):根据进程名和应用信息创建进程(四大组件常用)。 -
startProcessLocked(ProcessRecord app, ...):基于已有进程记录启动进程。
-
关键逻辑:
- 检查进程是否存在:通过
mPidsSelfLocked查找已存在的进程记录(ProcessRecord)。 - 创建新进程记录:若进程不存在,创建
ProcessRecord并配置参数(如 UID、GID、权限等)。 - 请求 Zygote 创建进程:通过
Process.start向 Zygote 发送创建请求,Zygote 通过 fork 复制自身生成新进程。
2. Zygote 的角色:进程的 “孵化器”
-
功能:作为系统首个 Java 进程,预加载系统资源,通过 fork 快速创建新进程,避免重复初始化开销。
-
流程:
- AMS 通过 Socket 向 Zygote 发送创建进程的请求(含进程名、参数等)。
- Zygote 执行 fork,生成新进程(子进程继承 Zygote 的资源和状态)。
- 子进程加载应用代码,调用
ActivityThread.main初始化主线程。
3. 新进程初始化:从 Zygote 到主线程
-
子进程启动:
- 调用
ActivityThread.main,创建主线程 Looper、消息队列,并初始化ActivityThread对象。 - 通过
attach方法与 AMS 建立 Binder 连接,通知系统进程已启动。
- 调用
-
Binder 通信建立:
- 子进程通过
ActivityManagerProxy(AMP)向 AMS 发送ATTACH_APPLICATION请求,注册进程信息。 - AMS 通过
ApplicationThreadProxy(ATP)回调子进程的bindApplication,完成应用初始化(如创建 Application 实例、注册组件)。
- 子进程通过
三、四大组件的进程创建细节
1. Activity:界面组件的进程触发
-
流程:
- 用户点击启动 Activity,调用
startActivity。 - AMS 检查 Activity 所属进程是否存在,不存在则调用
startProcessLocked创建。 - 新进程启动后,通过
attachApplication回调初始化 Activity 组件。
- 用户点击启动 Activity,调用
2. Service:后台组件的进程管理
-
特点:
- 若 Service 配置为独立进程(
android:process),首次启动时创建新进程。 - 进程创建逻辑通过
ActiveServices.bringUpServiceLocked触发,与 Activity 类似,但无需处理 UI 线程。
- 若 Service 配置为独立进程(
3. ContentProvider:数据组件的延迟加载
-
触发时机:
- 首次调用
ContentResolver.query等方法时,AMS 检查 Provider 所属进程,不存在则创建。 - 通过
AMS.getContentProviderImpl触发进程创建,确保 Provider 在首次使用时初始化。
- 首次调用
4. BroadcastReceiver:广播驱动的进程唤醒
-
静态广播的特殊性:
- 静态注册的 Receiver 在接收到广播时,若所属进程未运行,系统创建进程并触发
onReceive。 - 通过
BroadcastQueue.processNextBroadcast检测进程状态,缺失则调用startProcessLocked。
- 静态注册的 Receiver 在接收到广播时,若所属进程未运行,系统创建进程并触发
四、多进程应用与进程配置
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. 关键通信步骤
- 进程启动后:
子进程通过ActivityThread.attach向 AMS 发送ATTACH_APPLICATION请求,携带ApplicationThread(Binder 服务端)。 - AMS 初始化:
AMS 通过attachApplicationLocked保存进程记录,并通过 ATP 调用子进程的bindApplication,初始化应用环境(如创建 Application、注册 Provider)。 - 组件生命周期回调:
AMS 通过 ATP 触发组件生命周期(如 Activity 的onCreate),子进程通过 Handler 在主线程执行回调。
六、总结:进程创建的全景图
-
触发链:
组件启动 → AMS 检测进程存在性 → 调用startProcessLocked→ Zygote fork 新进程 → 新进程通过 Binder 注册到 AMS → 初始化组件。 -
核心目标:
- 确保组件在独立或共享进程中正确运行。
- 通过 Zygote 和 Binder 机制优化进程创建效率,减少资源消耗。
-
开发者视角:
-
合理配置
android:process避免不必要的进程创建。 -
注意多进程场景下的内存隔离和通信问题(如使用
AIDL或LocalBroadcastManager)。
-
通过理解四大组件与进程启动的深层关联,开发者可更精准地优化应用启动性能,处理多进程通信问题,并深入分析系统级异常(如 ANR、进程崩溃)。