
该文实际上是上一篇文章的下半部分。
如果说上一文是讲解 Context
是什么的话,那么本文,就是讲解 Context
干了什么,以及怎么干的。
如果你深入阅读过 Android 的源码,那么本文,可以巩固你的现有知识。
如果还没有深入阅读,只了解过 Context
相关的知识,那么在你不久的将来阅读源码时,耳边应该总能回想起本文涉及到的知识面。
为了方便文章的阐述和讲解(主要是太长了,不想写),我列出了该文用到的专有名词,后续行文将使用缩写,而非全拼。
IPC(Inter-Process Communication):进程间通信
RPC(Remote Procedure Call):远程过程调用
ActivityTaskManagerService(ATMS):任务与窗口管理服务
ActivityManagerService(AMS):进程与组件管理服务
PackageManagerService(PMS):应用包管理服务
Application Programming Interface(API):应用程序编程接口
WindowManagerService(WMS):管理窗口显示、布局、层级和输入事件的核心系统服务
USAP(Unspecialized App Process):未特化应用进程
UID(User ID):用户 ID
GID(Grouup ID):组 ID
AIDL(Android Interface Definition Language):Android 接口定义语言
好戏,开场了!
Android 架构的核心,是一个强大的抽象层------Context
,它架起了应用程序与系统之间的桥梁。
正是它,支撑起了 Android 基于组件的架构体系。
本文通过 Context
这一关键纽带,深入剖析进程模型、组件生命周期及 Activity
切换机制。
Context:Android 的连接组织

Context
是应用组件与 Android 系统之间的接口,提供以下核心功能:
- 系统身份与通信:为所有系统交互建立应用身份标识;
- 资源访问:提供资源、资产、文件及偏好设置的访问能力;
- 组件导航:支持启动
Activity
、Service
和广播; - 系统服务访问:作为访问所有系统服务的入口;
- 权限验证:实现权限检查与强制实施。
Android 中每个主要组件(Activity
、Service
、BroadcastReceiver
、ContentProvider
)都会获得专属的 Context
实例,这些实例都有区别于其他组件的特定需求和生命周期。
通信骨干:RPC 与 Binder
Context
促成的大部分交互(尤其是与系统服务或其他进程中的组件通信时),都依赖于 Android 的核心 IPC 机制:Binder 框架。
Binder 是 Android 针对 RPC 的一种专有实现。
RPC 是一个通用计算概念,指一个程序无需管理底层通信细节,就能请求另一个程序(可能位于不同进程,甚至不同机器)提供的服务。
这类似于发起一次"远程函数调用"------程序 A 请求程序 B 执行特定功能(可能传递数据),而程序 B 执行后可能返回结果(大家都写过 AIDL 对吧,那个就是函数调用)。
Android 的 Binder 框架针对移动设备的资源限制和安全要求进行了高度优化。它为应用组件(通过 Context
表示)提供了一种高效且安全的方式,使其能够跨越进程边界,与底层 Android 系统甚至其他应用进行交互。理解 Binder 作为 Android 基础 RPC 机制的本质,对掌握 Context
如何实现这些关键系统交互至关重要。
我知道,聪明的你可能会问这样一个问题!
为什么即使是在应用内部执行操作时,我们也需要依赖 IPC 的这种机制?(或者通俗点说,我为什么不能直接 new Activity
?)
当你通过 Context.startActivity()
从第一个 Activity
(ActivityA
)启动第二个 Activity
(ActivityB
)时(即便这两个 Activity
属于同一个应用进程):
-
你的应用是无法直接创建或管理
ActivityB
生命周期的。Android 将此控制权保留给操作系统,以确保系统稳定性与资源的合理分配。 -
当
ActivityA
调用startActivity()
时,其持有的Context
会向系统组件ActivityTaskManagerService
(ATMS )发送请求------该组件如今负责统一协调Activity
与任务栈的管理(而ActivityManagerService
(AMS)仍掌管进程与内存的全局策略)。 -
ATMS
与AMS
均运行在具有特权的system_server
进程内,该进程独立于你的应用之外。 -
由于进程隔离,跨进程通信必须依赖 IPC 机制。你的应用(进程 A)与 AMS (进程 S)分属不同进程,无法直接交互,必须通过 IPC ------具体而言即 Binder------来传递消息。
-
整个交互过程采用 IPC 完成:你应用通过 Binder IPC 向 AMS 发送
startActivity
请求;AMS 处理请求后,再通过 Binder IPC 向你的应用进程回传启动ActivityB
的具体指令。
因此,即使在看似进程内操作的场景(例如启动本地 Activity
)中,由于需要与运行在独立系统进程里的 AMS 服务进行通信协调,仍然必须依赖 Binder IPC 机制。
只要你的应用通过 Context
请求 Android 系统执行管理组件生命周期等重要操作,这种基础交互模式就会始终应用。
Context:通往 Android 系统的把手

我们已将 Context
描述为系统服务的"连接组织"。从本质上看,不妨将 Context
对象视为应用与 Android 系统交互的"把手"。它是你应用进程中代表应用环境与系统身份的实体。
这个"把手"如何运作的呢?
当你的应用需要执行由操作系统管理的操作时------比如启动 Activity
、通过系统服务访问设备硬件、获取资源或发送广播------它会调用 Context
实例的方法(例如 startActivity()
、getSystemService()
、getString()
)。虽然这些在你应用中看似是标准的方法调用,但它们经常触发与核心系统组件(如 AMS 或 PMS )的通信,而这些组件运行在不同特权的系统进程(如 system_server
)中。
由于这些交互通常需要跨越进程边界,它们必须借助 Android 的 Binder 框架。正如我们刚才讨论的,Binder 是基于 RPC 构建的专用 IPC 机制。因此,Context
实际上充当了这个"把手"------它提供必要的方法和身份凭证,代表你的应用触发 Binder IPC 调用。它就像一座桥梁,让你的应用请求能够通过 IPC 安全抵达对应的系统服务,从而实现与操作系统的交互。理解这个关联逻辑------Context
作为"把手",Binder IPC 作为底层机制------是掌握 Android 组件化架构的关键所在。
幕后指挥家:ActivityThread

在深入探讨不同类型的 Context
之前,有必要先理解一个基础但非公开的类------它默默编排着应用生命周期与初始化的诸多环节:ActivityThread
。
需要特别说明的是,尽管名称中包含 "Activity",但
ActivityThread
的职责远不止管理Activity
组件。这一命名源于早期
Activity
作为最核心组件的时期。实际上,该类是应用主线程上整个应用进程运行的中枢,不仅负责管理Activity
,还涉及为所有核心应用组件(包括Application
对象本身、Service
以及BroadcastReceiver
)建立执行环境并处理其生命周期事件。或许,以现在的眼光来看,叫 "AppThread" 更为贴切。
AMS 也有类似的遗留原因,可能 "AppManagerService" 是更适合当代的叫法。
虽然你的应用代码不会直接与 ActivityThread
交互(它是框架内部运作的一部分),但它扮演着至关重要的角色:
- 主线程管家:本质上,
ActivityThread
是运行应用主线程(即 UI 线程)的核心类。它负责建立消息循环(Looper
),专门处理 UI 事件、系统回调及其他消息。 - 进程初始化:当你的应用进程启动时,
ActivityThread
的main()
方法就是程序入口。它负责初始化整个应用环境。 - 组件生命周期编排:它通过 Binder IPC 接收来自系统(特别是 AMS )的指令,以启动、暂停、恢复和销毁诸如
Activity
和Service
等组件。 Context
的创建:对于本次讨论尤为关键的是,ActivityThread
负责为你的应用及其组件(Application
、Activity
、Service
)创建初始的Context
对象。它通过实例化底层的ContextImpl
并将其与对应的包装器(Application
、Activity
或Service
)进行关联来实现这一过程。
理解 ActivityThread
作为应用进程内核心协调者的角色,有助于厘清不同 Context
对象在应用生命周期中创建和管理的具体方式与原因。在后续讨论进程与组件创建时,我们将再次看到它所扮演的关键角色。
理解 Android 系统服务
在之前的讨论过程中,我们经常提到 Context
是系统服务的"连接组织"。
那么这些服务究竟是什么?Context
又是如何与它们交互的呢?
什么是系统服务?
Android 系统服务是 Android 操作系统的基本组成部分,它们在后台持续运行。这些服务负责管理设备的核心功能,包括硬件访问(如摄像头、传感器、定位)、系统状态(如网络连接、电池电量)、应用间通信、窗口管理、用户通知等等。它们提供 API 接口,供应用程序调用这些功能。
系统服务在哪里运行?
大多数核心系统服务并不运行在你的应用进程中。它们驻留在专用的、长期运行的特权系统进程中。其中最重要的是 system_server
进程------该进程由 Zygote
在 Android 启动序列的早期阶段创建,并承载了大量关键服务(如 AMS 、WMS 、PMS)。这种进程隔离机制对系统稳定性和安全性至关重要:单个应用的崩溃不会导致核心操作系统服务失效。
如何访问系统服务?
通过 Context
与 Binder 。你的应用无法直接调用运行在其他进程中的服务对象的方法。相反,Android 通过 Context
提供了一套受控的访问机制:
Context.getSystemService
:你的应用调用此方法,并传入一个用于定义目标服务的常量(例如Context.LOCATION_SERVICE
)。- 管理/代理对象:此方法不会返回实际的远程服务对象,而是返回一个客户端管理器类实例(例如
LocationManager
、NotificationManager
、ConnectivityManager
)。该管理器运行在你的应用进程中(后面会讲到 AMS 与ActivityManager
的区别)。 - Binder IPC :第二步的管理器充当代理角色。当你调用管理器的方法(例如
locationManager.requestLocationUpdates
)时,管理器会在内部使用 Binder IPC 机制(Android 的 RPC 框架)将你的请求序列化,并跨越进程边界发送至实际运行在system_server
或其他系统进程中的系统服务。 - 服务执行与响应:系统服务执行请求(例如与 GPS 硬件交互),并通过 Binder IPC 将结果或回调信息传回你进程中的管理器。随后,管理器将这些信息传递给你的应用代码。
系统服务抽象化了复杂操作并执行系统级策略。
例如:
- ATMS 与 AMS :这两个系统服务通过
ActivityManager
或隐藏的IActivityTaskManager
Binder 接口间接访问。调用getSystemService(Context.ACTIVITY_SERVICE)
将返回ActivityManager
。当前 ATMS 负责活动与任务栈管理,而 AMS 专注于进程与内存策略。 - PMS :可通过
Context.getPackageManager
或getSystemService(Context.PACKAGE_SERVICE)
访问。该服务负责管理已安装应用、权限,并根据AndroidManifest.xml
解析Intent
。 - WMS :通过
getSystemService(Context.WINDOW_SERVICE)
获取WindowManager
。负责管理屏幕窗口、Surface
以及输入事件分发。 NotificationManagerService
:通过getSystemService(Context.NOTIFICATION_SERVICE)
获取NotificationManager
。负责管理系统状态栏通知。LocationManagerService
:通过getSystemService(Context.LOCATION_SERVICE)
获取LocationManager
。提供位置数据访问(GPS位置、网络位置)。ConnectivityService
:通过getSystemService(Context.CONNECTIVITY_SERVICE)
获取ConnectivityManager
。监控网络状态与连接。PowerManagerService
:通过getSystemService(Context.POWER_SERVICE)
获取PowerManager
。管理设备电源状态与唤醒锁。StorageManagerService
:通过getSystemService(Context.STORAGE_SERVICE)
获取StorageManager
。管理设备存储卷。
可能大家已经看出规律了。
这种
Context
→ 管理器(代理) → Binder IPC → 系统服务
的调用模式至关重要。它清晰揭示了 Context
如何作为应用访问 Android 系统的句柄或网关:既提供经过验证的入口点和身份凭证,又通过其方法启动 Binder 框架通信,从而建立必要的 IPC,最终安全地与运行在独立系统进程中的核心操作系统服务进行交互。
Context 的层次与特化

Context
并非单一的、统一的实体,Context
的每个实现都是针对特定组件的生命周期和特性进行优化的,同时每种实现都有自己特定的层级。
该层级体系的核心是由两个协同工作的关键类构成:ContextImpl
与 ContextWrapper
:
ContextImpl
(具体实现):可以将ContextImpl
看作是执行Context
任务的实际引擎。它是隐藏在安卓框架中的一个具体(非抽象)类,保存着对应用资源、包信息、系统服务管理器的实际引用,并且包含文件操作、权限检查等功能的逻辑。在进程和组件初始化期间,系统(具体是ActivityThread
)会创建ContextImpl
实例。作为开发者,永远不会直接持有或创建ContextImpl
实例。它的存在属于内部实现细节。ContextWrapper
:由于ContextImpl
是内部类,安卓提供了ContextWrapper
。顾名思义,这个类包装了另一个Context
实例(通常在底层是ContextImpl
)。它的主要工作是将对其调用的方法(如getResources()
、getSystemService()
、startActivity()
)转发到它所包含的底层 "基础"Context
。这种设计的精妙之处在于,ContextWrapper
是开发者实际与之交互的Context
类型(如Application
、Activity
、Service
)的基类。这使得框架(开发者在极少数情况下也可能)可以通过继承ContextWrapper
并重写特定方法,轻松扩展或修改Context
的行为,而无需更改核心的ContextImpl
。
Context 的继承链
-
ContextImpl
:基础具体实现- 包含资源访问、文件操作和系统服务连接的实际功能。
- 在进程初始化和组件创建期间创建。
- 不直接暴露给应用开发者。
-
ContextWrapper
:围绕ContextImpl
的委托包装器- 将方法调用转发到被包装的
ContextImpl
。 - 作为特定的
Context
类型的基类。 - 可以在不修改
ContextImpl
的情况下扩展Context
功能。
- 将方法调用转发到被包装的
Application Context
Application
Context
在应用程序进程初始化时创建,并始终与应用程序的生命周期相关联。只要进程存在,它就会一直存在,提供对应用程序级资源、文件和偏好设置的访问。
虽然 Application
Context
用途广泛,但也有显著的局限性。它没有默认的用户界面主题,因此通常不建议进行布局填充或对话框创建操作,除非事先提供主题或 ContextThemeWrapper
,否则 UI 资源可能无法正确解析或导致程序崩溃。它也无法执行 Activity
管理功能或访问窗口特性 。
尽管存在这些限制,Application
Context
对于单例或静态引用中的长期存储来说却是理想之选。当你需要一个超出任何组件生命周期的 Context
时,Application
Context
就是你的首选。它为长时间运行的操作提供了所需的稳定性,而不会有内存泄漏的风险。
那么,Application
Context
是如何创建的呢?
- 在进程初始化期间,
ActivityThread
会创建Application
实例; - 为应用程序创建一个
ContextImpl
; - 将
Application
Context
包装器与这个ContextImpl
连接起来; - 在建立此
Context
后调用Application.onCreate()
方法。
Activity Context
Activity
Context
构建于 Application
Context
基础之上,不仅继承了其所有能力,还通过 ContextThemeWrapper
新增了关键的 UI 专属功能。它完整保留了应用级资源访问权限,并进一步扩展了以下特性:主题信息与样式支持、布局加载能力、窗口特性与装饰管理,以及对话框的创建与管理。
该 Context
与 Activity
生命周期深度绑定,当 Activity
销毁时,它也会随之销毁。
此外,它还提供了独特的 Activity
专属方法(例如 startActivityForResult()
),这些方法是其它 Context
类型所不具备的。
创建
ActivityThread
会创建一个新的针对该Activity
的ContextImpl
。这个ContextImpl
共享应用资源,但包含Activity
特定的配置;- 一个
ContextThemeWrapper
(即Activity
)会连接到这个ContextImpl
; - 该
Context
会进一步通过Manifest
中的主题信息和样式、Activity
特定的功能以及窗口和 UI 特定的服务连接来实现特化。
getApplicationContext
当 Activity
调用 getApplicationContext()
时:
Activity
Context
(ContextThemeWrapper
)会委托给其包装的ContextImpl
;ContextImpl
返回应用全局的Context
实例。
Service Context
Service
Context
基于 Application
Context
的能力构建,当然,也额外提供了服务专属功能(如服务生命周期管理和前台服务能力)。与 Application
Context
类似,它不具备 UI 功能,且严格绑定到服务生命周期。
开发者应仅在服务生命周期内使用 Service
Context
。与 Application
Context
相同,若用其显示 UI 元素会导致崩溃。对于可能超出服务生命周期的操作,应改用 getApplicationContext()
返回的 Application
Context
以避免内存泄露或者崩溃问题。
创建
- 与
Activity
类似,系统会创建一个新的ContextImpl
; - 一个
Service
包装器(ServiceWrapper
)会连接到这个ContextImpl
; - 该
Context
通过服务专属能力进行特化。
ReceiverRestrictedContext
该 Context
生命周期短暂,与其他 Context
类型有显著差异。它专为广播临时创建,仅存在于 onReceive()
方法执行期间,提供专注于广播即时需求的受限能力。
重要区别在于:ReceiverRestrictedContext
并非基于 Application
Context
的能力构建------它是一个具有独特约束条件的专用 Context
。开发者绝不应在 onReceive()
之外存储或缓存该 Context
。
在较新 Android 版本中,它无法启动后台服务,且可能根据广播类型存在特定权限限制。
如果是通过
Manifest
注册的广播,该Context
由系统创建。如果是动态注册(通过代码)的广播,接收器直接使用用于注册它的
Context
,继承该Context
的能力和约束。
创建
广播既可以通过在 Manifest
中声明,从而在应用未运行时也能接收广播;也可以动态注册,此时广播仅在注册期间起效。
那么,它的创建过程也会有所不同了。
对于 Manifest
注册的广播:
- 如果目标组件的进程未运行,
Zygote
会创建该进程; - AMS 会向应用发送广播
Intent
; ActivityThread
会专门为处理该广播创建一个ReceiverRestrictedContext
;- 这个
ReceiverRestrictedContext
是以受限权限和能力创建的; - 系统会实例化
BroadcastReceiver
类; - 接收器的
onReceive()
方法会使用这个临时Context
被调用; - 在
onReceive()
完成后,ReceiverRestrictedContext
通常会被丢弃。
而对于动态注册的广播,即通过 Context.registerReceiver()
注册的广播:
- 该接收器与注册时使用的
Context
生命周期相关联; - 当该接收器收到广播时,系统会使用现有的
Context
(Activity
、Service
或Application
); - 通常不会单独创建
ReceiverRestrictedContext
; - 接收器的
onReceive()
方法会使用注册组件的Context
。
非 Context 组件

在 Android 四大核心组件类型中,BroadcastReceiver
和 ContentProvider
不属于 Context
的子类。这一架构层面的重要差异,直接影响着这些组件与 Android 系统的交互方式。
广播与 Context 的联系
与直接继承自 Context
(具体而言,Activity
继承自 ContextThemeWrapper
,Service
继承自 ContextWrapper
)的 Activity
和 Service
不同,BroadcastReceiver
根本就不是 Context
的子类。这种类层次结构上的根本差异,造就了广播与 Context
系统之间截然不同的关系。
BroadcastReceiver
本身并非 Context
,而是在其 onReceive()
方法中通过参数获取 Context
:
Kotlin
override fun onReceive(context: Context, intent: Intent) {
// 第一个参数是 Context
// 该 Context 是专门为该接收器创建或关联的
}
这一设计意味着广播使用 Context
但不继承自它。
不同的广播注册方式,提供的 Context
存在显著差异,这对功能能力和生命周期管理具有重要影响。
ContentProvider 与 Context 的联系
同样地,ContentProvider
也不是 Context
的子类。它是通过与应用建立关联来获取 Context
的。
Kotlin
override fun onCreate(): Boolean {
// 此时 'context' 属性可用,但它并不指向 'this'
val myContext = context // 此处是 Kotlin 代码,所以其实是 getContext() 方法
// 直接使用 Context 来访问资源或服务
val databaseName = context.getString(R.string.database_name)
val dbHelper = DatabaseHelper(context, databaseName)
return true
}
ContentProvider
通过 getContext()
方法获取其 Context
,该方法返回一个在初始化期间与提供者关联的 Context
实例。该 Context
通常与应用程序的进程和生命周期绑定,使提供者能够访问资源、首选项和数据库。
与可能根据注册方式接收不同 Context
类型的 BroadcastReceiver
不同,ContentProvider
几乎总是使用Application
Context
。
这是因为 ContentProvider
是生命周期较长的组件,通常在整个应用程序进程持续期间都存在,而不受其他组件生命周期的影响。
Context 与 Zygote 进程:奠定基础

Android 的进程创建模型始于 Zygote
进程建立 Context
。
Android 中的"Zygote"一词源自生物学概念------在生物学中,受精卵(zygote)是最初的单细胞,最终将发育成完整的有机体。Android 系统特意选用这个名称,用以形象地表示其独特的进程创建模型:所有应用进程都是从一个父进程的副本开始创建的。
从概念层面看,Zygote
是解决复杂技术难题的巧妙方案:如何在高效管理内存的同时实现 Android 应用的快速启动。如果每个应用都必须从头开始启动------加载 Java 虚拟机、初始化整个 Android 框架以及加载公共类------那么应用的启动时间将慢得令人无法接受。Zygote
通过以下方式解决了这个问题:
- 系统启动时创建一个完全初始化的单一进程;
- 将所有通用框架类和资源加载到该进程中;
- 保持该进程处于随时可用的就绪状态;
- 通过
fork
这个就绪进程来创建新的应用进程; - 让每个应用启动时都已预加载所有通用资源。
Zygote
进程是 Android 系统架构中的基础组件,充当着所有应用进程的父进程角色。
可以说,Android 的 Zygote
就是所有应用进程的起源点。
Zygote
进程本质上是一个专门的初始化机制,其核心功能包括:
- 启动时机:在 Android 启动序列早期运行。
- 预加载资源:加载 Android 框架类、资源和库。
- 运行时初始化:设置 Android 运行时(ART )或 Dalvik 虚拟机。
- 提供模板:作为预初始化的模板供快速复制。
Zygote
的主要目的是性能优化。与其为每个应用都从头加载 Android 框架类和初始化运行时环境(这将极其耗时),Android
创建了一个已预加载这些组件的预初始化进程。
当需要启动新应用时,系统只需创建这个 Zygote
进程的副本(即 fork
),这比从零开始启动要快得多。
理解 Zygote fork 进程
Zygote
是一个在启动时就初始化了应用所需一切的进程。
它处于这种"随时可用"的空闲状态,等待应用启动请求。
当收到应用启动请求时,Zygote
会进行 fork
以创建新的应用进程,新进程继承已初始化的状态(类、资源、虚拟机等)。
与冷启动相比,这大大节省了时间。
随着 Android 10 引入了 USAP ,Zygote
fork
的性能又有了显著提升。
我们来比较一下 Android 10 前后的 Fork
差异。
Android 10 之前,Zygote 基于一种简单的按需 fork
模式运行:
Zygote
会在加载完所有框架类后处于空闲状态,等待应用启动请求;- 当某个应用需要启动时,AMS 会请求
Zygote
fork
出一个新进程; Zygote
调用fork()
,创建一个自身的副本,其中包含所有预先加载的资源;- 新
fork
出的进程随后会使用应用的 UID /GID 以及安全上下文进行特化; - 最后,
ActivityThread
会在这个进程中开始执行。
虽然相比冷启动初始化能节省大量时间,但同步 fork
操作仍会给每次应用启动增加可观的毫秒级延迟。
Android 10 引入了 USAP ------这从根本上改变了进程创建方式。系统不再在应用启动时进行 fork
操作,而是维护一个预 fork
进程池,随时可供特化快速使用。
什么是 USAP?
USAP 是一种已从 Zygote
fork
出来但尚未分配给任何特定应用程序的进程:
- 无应用标识:暂时在没有特定用户 ID/组 ID的情况下运行;
- 无安全上下文:没有 SELinux 上下文或特定于应用的功能;
- 框架就绪:所有安卓框架类已加载并初始化;
- 等待状态:挂起在池子里,消耗极少的资源。
可以将 USAP 视为"空白"的应用程序进程------它们已经完成了所有耗时的初始化工作(fork
、框架加载等),但还没有进行任何特定于应用程序的配置。
各位可以想象一下购买汽车的流程:在 Android 10 之前,是你下单之后才生产汽车,然后生产完成之后办理手续;而 USAP 意味着,车厂已经生产好汽车了,当你下单的时候,立马给你办手续。
USAP 进程池是如何工作的?
现代 Android 系统(Android 10 及以上版本)维护着一个由这些通用进程构成的复杂进程池:
- 池大小:默认情况下最多可有 10 个 USAP 。池大小由
persist.device_config.runtime.usap_pool_size
属性控制(许多 OEM 会自定义这个设置); - 双池:为 32 位和 64 位进程分别设置独立的池;
- 动态管理:池大小会根据系统条件(可用资源)进行调整;
- 补充:当一个 USAP 被占用后,会异步创建一个替代进程。
USAP 进程池会根据系统状态动态调整:
- 空闲时:进程池填充至最大容量;
- 内存压力大时:进程池缩减或完全清空;
- 设备锁定时:可能清空进程池以节省资源;
- 应用启动频率高时:保持进程池最大规模;
- 低电量时:可能缩减进程池规模。
实际上,系统会维护多个已特化的预热进程:
- 标准应用进程(用于常规应用程序);
WebView
进程(预初始化包含WebView
组件);- 系统 UI 进程(针对 UI 组件优化)。
每种进程都针对不同类型的应用启动需求而设计。
Android 系统内部各个服务也会明确分工:
system_server
负责协调该进程池;- AMS 根据需要从池中请求进程;
- 进程特化通过
Zygote
套接字通信完成处理(不是 Binder)。
现在,让我们大致直观了解一下在使用 USAP 前后的进程 fork
过程。
传统加载进程方式:
用户点击 → fork 进程 → 特化 → 启动应用
USAP 的加载方式(在用户点击之前,USAP 进程池中已经 fork
完成了进程):
用户点击 → 从进程池中获取一个新的进程 → 特化 → 启动应用
从简单的进程 fork
到智能进程池的这种演进,体现了安卓在性能优化方面的努力。
安卓如今不再是按需创建资源,而是预先初始化好进程并随时待命,同时采用精密的管理方式,在性能与资源限制之间取得平衡。
进程特化

我们在进程 fork
部分提到了"特化",但并未加以解释。
当一个应用在 fork
后进行特化时,它会经历一个安全转换过程,这个过程确立了应用的身份和沙盒。这种特化涉及几个关键步骤:
- UID /GID 分配
- UID :在安卓系统中,每个应用在安装时都会获得一个唯一的 Linux UID 。这不是指真实用户,而是安卓用于隔离应用的方式。例如,应用 A 可能获得 UID 10001,应用 B 获得 UID 10002 。
- GID :应用还会获得一组 GID ,这些 GID 决定额外的权限(如上网权限、使用摄像头的权限)。一个应用可能属于多个组。
- 重要性:由 UID 10001 创建的文件无法被 UID 10002 访问,这在内核层面强化了应用隔离。
- 安全上下文(SELinux)。安卓使用 SELinux(安全增强型 Linux)来实现超越传统 Linux 权限的强制访问控制
- 特化之前:未特化的应用启动器进程(USAP)在特权上下文中运行。
- 特化之后:进程被限制在特定应用的 SELinux 域中。
Zygote 和 Context 的初始化
当安卓系统启动时,它会初始化 Zygote
进程,这个进程是所有应用进程的模板。
基础 Context 创建
在系统启动期间,Zygote
会预加载 Context
(如 ContextImpl
)和资源系统所需的类,但它不会实例化任何 ContextImpl
对象。实际的 Context
实例是在稍后,每个 fork
的应用进程运行 ActivityThread.attach()
时创建的。
系统会创建一个基础 Context
框架,所有应用都将继承该框架。
预热进程和 Context 组件
Zygote
本身已预热,即已加载了框架类(包括 ContextImpl
的字节码),这样每个派生的应用一旦启动就能快速构建自己的 ContextImpl
。
从 Android 10 的 USAP 开始,系统还在一个池中维护预热(预先 fork
)进程。
一个预热进程,就是其中的 Context
组件已完全初始化(未特化)的进程:
ContextImpl
类已加载并优化;- 资源系统已初始化;
- 基本的
Context
与系统通信通道已建立;
这种预热状态包含了一个功能完备的 Context
系统所需的一切。
Zygote 的作用范围
明确 Zygote
在何时以及在哪些方面参与安卓的进程管理,这一点很重要:
-
应用首次启动:
- 当应用首次启动时,
Zygote
会为其创建初始进程。 - 除非在
Manifest
中另有指定,否则所有应用组件(活动、服务等)都在这个单一进程中运行。
- 当应用首次启动时,
-
多进程应用:
- 当你在
Manifest
中指定android:process
属性时,Zygote
会在首次访问这些组件时创建额外的进程。 - 这些进程仍被视为应用的一部分,但在单独的进程中运行。
- 当你在
-
Zygote
作用范围之外,也就是Zygote
不涉及哪些方面:- 不参与创建或管理原生系统进程。
- 不管理现有的系统服务和守护进程。
- 不参与访问外部数据库引擎(如 SQLite 本身 )。
- 不为标准的安卓进程间通信机制创建子进程。
外部进程与应用进程
与数据库交互
SQLite 作为应用进程内的一个库运行,而非作为一个单独的进程。
当你调用 Context.openOrCreateDatabase()
或使用 SQLiteOpenHelper
时:
- 不会创建新的进程;
- 数据库引擎在现有的应用进程中运行;
Context
用于确定文件位置和权限,而非与Zygote
进行通信。
与外部 ContentProvider 交互
在访问另一个应用的 ContentProvider
时,由 AMS 来协调连接。
- 如果目标应用的进程尚未运行,则由
Zygote
启动它; - 你的
Context
用于确定用于权限检查的身份,而不是用于与Zygote
直接通信。
与系统服务交互
系统服务(如 LocationManager
、AudioManager
)在系统进程中运行:
- 这些进程在系统启动期间启动,而非由
Zygote
按需启动; - 你的
Context
通过 Binder IPC 与这些服务进行通信; - 当你调用
Context.getSystemService()
时,你获取的是现有服务的代理,而不是创建新的进程。
Context 在 Activity 管理和进程决策中的作用
当启动 Activity
时,Context
既是推动者,也是决策者。
当用户在设备启动后首次点击应用程序图标时,一个涉及 Zygote
、AMS 和 Context
创建的复杂过程就开始了。
处理启动请求
第一步包括定位目标应用程序的活动信息,若该应用程序未运行则启动它,若其在后台运行则将其置于前台:
- 启动器向 AMS 发送一个
Intent
; - AMS 判定目标应用程序尚未运行;
- AMS 查找
Manifest
信息,以确定要启动的Activity
和进程的要求。
通过 Zygote 创建进程
此过程 Zygote
利用 ActivityThread
创建一个新的特化进程:
- AMS 通过一个专用的套接字连接与
Zygote
进行通信; - AMS 请求
Zygote
为该应用程序创建一个新进程; Zygote
通过自我复制创建新进程,并提供预先加载的框架类;- 新进程使用
ActivityThread
进行初始化。
Application Context 的建立
这一步是创建 Application
Context
的所有操作发生的阶段,Application
Context
是一个相当复杂的功能,它包含了一些基本组件,其中就包括主线程的 Looper
和消息队列。
- 在新进程中调用
ActivityThread
的main()
方法; - 它设置主线程的
Looper
和消息队列; - 它通过调用
makeApplication()
创建Application
对象; - 专门为应用程序创建一个新的
ContextImpl
; - 这个
ContextImpl
被附加到Application
对象上; - 调用
Application.onCreate()
,建立应用程序范围的Context
。
原神,哦不,Activity,启动!
现在我们已经有了应用程序,该创建启动 Activity
了。这正是此步骤的意义所在:
- AMS 发送一个事务来创建启动
Activity
; ActivityThread
通过为该Activity
创建一个新的ContextImpl
来处理此事务;- 这个
ContextImpl
通过ContextThemeWrapper
具备了用户界面相关功能特性的定制; Activity
通过Activity.attach()
方法接收这个特定的Context
;- 正常的
Activity
生命周期开始(onCreate
、onStart
、onResume
)。
这一过程表明,应用程序的首次启动比拉起已经启动的应用程序,需要做多得多的工作。
进程的创建和 Context
层次结构的建立是基础性步骤,这些步骤只在应用程序首次启动时才会发生。
Context 与进程决策

在接下来的章节中,我们将讨论如何在一个正在运行的应用程序中,通过 Intent
创建一个活动。这既可以在同一个进程内进行(不涉及 Zygote
),也可以通过创建一个新进程来实现(涉及 Zygote
)。
当通过 Intent
启动一个 Activity
时,Context
在进程确定中起着关键作用。
通过 Context 创建 Intent
调用方 Activity
使用其自身的 Context
来创建 Intent
。
该 Context
会将调用方的身份附加到这个 Intent
上,并通过 Context.startActivity()
启动启动流程。
基于 Context 的进程解析
Context
通过 Binder IPC 将启动请求传递给 AMS。
AMS 使用 Context
信息来确定:
- 目标
Activity
所属的应用程序包。 Activity
应运行在哪个进程中(基于Manifest)。- 该进程是否已经存在。
Manifest 中的 Context 信息
Manifest
中的 android:process
属性会影响 Context
的创建方式。
Context
利用此信息来确定组件是共享同一个 Context
还是需要单独的 Context
。
同进程创建 Activity
上面提到过,除非通过 Manifest
中的 android:process
另有要求,否则 Activity
将通过 IPC 绑定在与调用方 Activity
相同的进程中启动。
所以,当一个 Activity
通过 Intent
创建同进程中另一个 Activity
时,会发生以下情况。
Context 与系统通信
第一步,Context
会向安卓系统发出请求,要求创建一个新的 Activity
:
- AMS 通过 Binder IPC 与应用程序的
ActivityThread
进行通信。 - 这种通信使用应用程序现有的
Context
通道。 - 一条
SCHEDULE_LAUNCH_ACTIVITY
消息通过这个由Context
建立的通道进行转发。
创建新的 Activity Context
第二步,新 Activity
的 Context
被创建。
ActivityThread
通过调用 createBaseContextForActivity()
专门为该 Activity
创建一个新的 ContextImpl
。
这个 ContextImpl
派生自应用的 Context
,并包含特定于应用的信息(包名、资源等)。
它与进程中的其他 Context
保持相同的系统服务连接。
Context 的附着与特化
到目前为止,新的 Context
类似于 Application
Context
。此时的第三步才是让它进行用户界面(UI)相关的特化,并将其生命周期更新为新创建 Activity
的生命周期了。
- 新的
ContextImpl
被包装在一个针对该Activity
的ContextThemeWrapper
中; - 这个经过特化的
Context
通过Activity.attach()
附着到Activity
上。
此时,Context
既提供了特定于 Activity
的功能,又保持了进程范围内的连接。
注意:整个 Context
创建过程都在现有进程内发生,没有涉及到 Zygote
。
跨进程创建 Activity
基于 Context 的进程发现
在第一步中,我们需要确定是否已经存在目标进程:
- AMS 使用通过
Intent
传递的Context
信息,来检查目标进程是否存在; - 如果目标进程没有运行,AMS 会请求
Zygote
孵化一个新进程; - 新进程会使用一个基础
Context
框架进行初始化。
Application Context 的建立
在此步骤中,Zygote
创建新进程,并为新创建的进程生成一个新的 Application
Context
。
- 在目标进程中创建一个新的
Application
Context
。 - 这个
Context
会接收应用程序的标识和资源信息。 - 它会建立特定于该进程的全新系统服务连接。
在新进程中创建 Activity 的 Context
现在我们已经完成了新进程及其 Application
Context
的创建,接下来将创建新的 Activity
(Activity
也是一种 Context
)。
- AMS 指示新进程创建该
Activity
; - 在这个独立的进程中创建一个特定于新
Activity
的Context
; - 这个
Context
包含了在其隔离环境中运行所需的所有必要信息; - 该
Context
在与调用方进程隔离的同时,仍保持与系统的连接。
通过 Context 进行 Activity 生命周期管理
Android 中的 Activity
生命周期从根本上是通过 Context
系统来协调的。与普通的 Java 对象不同,Activity
会经历由 Android 框架管理的复杂生命周期 ------ 在这个过程中,Context
充当着关键的通信渠道。
当 Activity
在各个生命周期状态间转换时,Context
充当着关键的通信载体。
Activity 的创建与 Context 的建立
这部分内容我们之前已经了解过,是关于 Activity
的 Context
创建的。这是生命周期管理中至关重要的一环:
ActivityThread
会在任何生命周期方法调用之前为Activity
创建一个特定的ContextImpl
;- 此
Context
包含对系统服务、配置以及资源信息的引用; Context
通过Activity.attach()
方法附加到Activity
上;Context
的建立为后续所有生命周期事件创建了通信渠道。
通过 Context 执行生命周期回调
Context
现在充当应用程序与 Android 系统之间的通信总线:
- 系统通过
Context
通道发送消息来触发生命周期变化; ActivityManager
通过 Binder IPC 与应用程序的Context
进行通信;- 每个生命周期状态对应的消息都会通过此通道传输;
Context
有助于确定哪个特定的Activity
应该接收每个生命周期事件;ActivityThread
处理这些由Context
传递的消息,并调用相应的生命周期方法。
配置变更与 Context 重建
好的,我们来看看当发生配置变更(例如屏幕旋转或明暗主题切换)时会发生什么。
- 当配置变更发生时,系统会通过
Activity
的Context
连接来通知它们; - 会创建一个新的
Context
,其中包含更新后的配置值; - 之前的
Context
会通过onSaveInstanceState
协助保存状态; - 新的
Context
会附加到重建的Activity
上; - 这种
Context
转换确保Activity
能够使用当前的配置值进行运作。
Context 的统一管理
Context
将 Android 的组件模型、进程模型和生命周期管理绑定在一起:
- 标识:
Context
提供标识信息,使系统能够定位到特定组件; - 通信:它建立了生命周期指令传递的渠道;
- 资源访问:确保组件在其整个生命周期中都能获取适当的资源;
- 系统集成:将组件连接到更广泛的 Android 环境中;
- 安全边界:在敏感的生命周期转换过程中,它有助于执行权限检查;
AMS 与 ATMS:Context 的忠实伙伴
Android 的 Activity
和进程管理依赖于一个与 Context
紧密协作的关键系统组件,即 ActivityManager
及其底层服务实现 ------AMS。
理解 Context
与这些系统组件之间的关系,对于掌握 Android 的进程模型至关重要。
ActivityManager 与 AMS
许多开发者会混淆 ActivityManager
和 AMS,但它们在 Android 架构中扮演着不同的角色。
ActivityManager
ActivityManager
是一个客户端类,应用程序通过它与 AMS 进行交互。
它可以通过 Context.getSystemService(Context.ACTIVITY_SERVICE)
获取,并提供了查询正在运行的应用程序、进程和内存信息的方法。
因此,它充当实际 AMS 的代理或外观,并且在应用程序进程中运行。
AMS
另一方面,AMS 是一个系统服务,运行在 system_server
进程中(而非任何应用进程)。
它在系统启动期间随着 system_server
的初始化而启动。
- 它用于管理
Activity
、Service
和进程的生命周期; - 通过与
Zygote
通信来协调应用进程的创建; - 跟踪所有正在运行的进程及其状态;
- 对进程的优先级和生命周期做出决策。
Context 与 AMS
AMS 是一个基础性的系统服务,负责协调 Android 的组件生命周期和进程管理。了解 Context
对象如何与 AMS 通信,能让我们深入认识 Android 的内部架构,尤其是不同组件类型之间的架构关系。这种通信不仅限于 Activity
,还涵盖了所有 Android 组件。
尽管名为 ActivityManagerService
(AMS ),但 AMS 负责管理所有 Android 组件类型,而不仅仅是 Activity
。
这个名称是 Android 早期开发时的历史遗留产物,当时 Activity
是主要关注点。我上面提到过,可能大家理解为 AppManagerService 更为贴切。
如今,AMS 充当着 Activity
、Service
、广播和 Content-Provider
的中央协调服务,同时也负责整个平台的通用进程管理。
每种 Context
类型都通过相同的基本机制与 AMS 通信,但会根据其组件角色存在重要差异。
在所有这些情况下,ActivityManager
客户端类都充当代理。当任何 Context
类型调用与组件相关的方法时,Context
实现会将这些请求转发给其内部的 ActivityManager
实例。
然后,这个客户端类会处理与 system_server
进程中 AMS 的跨进程通信。不同之处并不在于通信机制本身,而在于每个请求所附带的标识、权限和功能。
Activity Context 与 AMS
Activity
Context
与 AMS 的通信可能是最频繁且最复杂的。
当 Activity
Context
调用 startActivity()
、finish()
或 requestPermissions()
等方法时,它会包含标识信息,这些信息能让 AMS 正确管理 Activity
栈、处理转场并维持正确的生命周期顺序。
AMS 会利用这些特定于 Activity
的 Context
信息,来跟踪哪些 Activity
对用户可见、管理任务亲和性关系,以及与窗口管理器协调转场操作。
这种 Activity
与 AMS 的通信路径始终处于活跃状态,即便是 Activity
处于前台时也是如此,因为 AMS 会持续监控 Activity
状态,以合理管理系统资源。
Application Context 与 AMS
Application
Context
与 AMS 的通信主要集中在应用范围的操作上。
当你的 Application
Context
启动服务或注册广播接收器时,它会提供标识信息,这些信息用于识别你的应用,但不会涉及应用内的任何特定组件。
这一点对进程管理有着重要影响------由于 Application
Context
与应用的进程生命周期相关联,AMS 知道这些请求应该在应用进程存活期间一直有效,而不受单个组件状态的影响。
Service Context 与 AMS
Service
Context
与 AMS 在服务生命周期管理方面有着特殊的关系。
当 Service
Context
与 AMS 通信时,尤其是在执行 startForeground()
或 stopSelf()
等操作时,它会携带特定于服务的标识信息。
AMS 利用这些信息来跟踪哪些服务正在运行、管理它们的优先级,并执行后台服务限制。这种 Service
与 AMS 的通信对于绑定服务等功能至关重要,因为此时 AMS 必须跨组件(甚至可能跨进程)跟踪服务连接。
BroadcastReceiver Context 与 AMS
BroadcastReceiver
与 AMS 的通信方式体现了其独特的生命周期。
对于在 Manifest
中声明的广播,初始通信是通过 AMS 指示 ActivityThread
创建临时 Context
来完成的。
对于动态注册的广播,注册时的 Context
会与 AMS 通信以设置广播过滤。
在这两种情况下,AMS 都会维护一个广播注册表,记录它们正在监听哪些 Intent
,并据此分发广播。
后台进程与系统管理
AMS 与 Context
的关系不仅限于简单的组件创建和通信,还延伸到复杂的进程和系统管理:
AMS 会根据进程中运行的 Context
的可见性和重要性,不断评估进程优先级。包含前台 Activity
Context
的进程会获得高优先级,而仅包含后台 Service
Context
的进程可能会被分配较低的优先级。在系统资源受限的情况下,这些优先级决策就变得至关重要。
当出现内存压力时,AMS 会利用其对每个进程的 Context
层次结构的了解,做出合理的终止决策。
仅包含后台 Context
的进程会被首先终止,而包含用户可见 Context
的进程则会被保留。当进程稍后被重新创建时,AMS 会通过已保存的 savedInstanceState
Bundle
,帮助恢复必要的 Context
及其相应的状态信息。
总结
好的,终于看到这里了。
Android 的 Context
系统是连接应用组件与系统环境的关键纽带。从通过 Zygote
创建进程到 Activity
生命周期管理,Context
提供了 Android 组件模型正常运行所需的通信渠道、资源访问方式和身份验证机制。
Context
的层次结构体现了 Android 精妙的设计------针对不同组件类型有专门的 Context
实现,其中 Activity
Context
不仅具备 Application
Context
的全部功能,还增加了特定于 UI 的功能。
在多进程场景中,理解 Context
的隔离性并使用合适的、具备 Context
感知能力的 IPC 机制,对于有效维护共享资源至关重要。通过在进程边界正确使用 Context
,开发者可以打造功能复杂的应用,既能充分利用 Android 的进程模型,又能保证数据完整性和性能。
从 Context
的角度审视 Android 架构,我们能更深入地理解系统各元素之间的关联方式,以及自己的应用如何与更广泛的 Android 环境相融合。
最后的最后
我总结出几条关于 Context
的要点,再强化一下关于 Context
的理解。
Context
的特化是 Android 开发的基础。
务必为不同任务使用合适的 Context
:
Activity
Context
用于 UI 操作。Application
Context
用于长期存在的引用。Service
Context
用于服务特定操作。- 而广播
Context
仅在广播处理期间使用。
正确处理 Context
后,内存管理会变得简单得多。
不要将 Activity
或 Service
Context
存储在静态字段或单例中,以避免内存泄漏。
对长期存在的对象使用 getApplicationContext()
,并且在组件销毁时始终清除 Context
引用。
开发多进程应用时,请记住每个进程都有自己的 Context
层次结构。静态变量和单例不会在进程间共享,因此需要使用 IPC 机制(如 ContentProvider
或绑定服务)进行跨进程通信。
理解 Context
的生命周期对于构建健壮的应用至关重要。
Activity
Context
会随Activity
一同消亡。Service
Context
会随服务一同消亡。ReceiverRestrictedContext
在onReceive()
期间是临时存在的。- 而
Application
Context
则会随进程存在。
让 Context
的使用与其生命周期保持一致,可避免许多常见的 Android 应用漏洞。