可以这样理解这句话:
Intent是 Android 上层提供的“通信载体/请求描述”,真正跨进程通信时,底层靠的是Binder IPC;而 Binder 为了提高效率,会通过mmap等方式在进程和内核之间建立一块映射内存区域,减少数据拷贝,所以有人说“物理层通过共享内存实现”。
但要注意:Intent 本身不是通信机制,Binder 才是通信机制。
1. Intent 是什么?
Intent 可以理解为一个“消息对象”或者“请求对象”。
它里面描述了:
Intent intent = new Intent(this, SecondActivity.class);
intent.putExtra("name", "Tom");
startActivity(intent);
这个 Intent 表达的是:
我要启动
SecondActivity,并且传递一些参数。
Intent 常用于四大组件之间:
| 组件 | 使用方式 |
|---|---|
| Activity | startActivity(intent) |
| Service | startService(intent) / bindService(intent) |
| BroadcastReceiver | sendBroadcast(intent) |
| ContentProvider | 通常通过 Uri + ContentResolver 间接访问 |
Intent 可以用于:
- 同一个 App 内部组件通信
- 不同 App 之间通信
- 应用和系统服务之间通信
例如调用系统相机:
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivity(intent);
这时就是 App 和其他 App/系统组件之间通信。
2. Intent 本身不负责通信
很多人容易误解:
Intent 是不是像 Socket 一样负责把数据发过去?
不是。
Intent 只是一个数据结构,类似于:
我要做什么?
目标是谁?
带了什么参数?
真正把这个请求从一个进程传给另一个进程的,是 Android 的 Binder 机制。
3. startActivity 背后的大致流程
比如你调用:
startActivity(intent);
表面上看是 Activity 启动另一个 Activity,实际上大致流程是:
App 进程
|
| startActivity(intent)
|
v
ActivityTaskManagerService / ActivityManagerService
|
| Binder IPC
|
v
目标 App 进程
|
v
启动目标 Activity
更具体一点:
你的 Activity
|
| startActivity(intent)
|
v
Instrumentation
|
v
ActivityTaskManagerService,系统进程中
|
| 判断目标 Activity、权限、任务栈等
|
v
如果目标进程不存在,先启动进程
|
v
通过 Binder 通知目标进程创建 Activity
|
v
目标 Activity.onCreate()
所以,两个 Activity 即使在不同 App 中,也不是直接通信,而是通过系统服务中转。
4. Binder 是什么?
Binder 是 Android 中最核心的跨进程通信机制,简称 IPC:
IPC = Inter-Process Communication
Android 中很多系统服务都基于 Binder,例如:
- ActivityManagerService
- WindowManagerService
- PackageManagerService
- LocationManagerService
- InputMethodManagerService
- MediaService
App 和系统服务交互,基本都要经过 Binder。
例如:
startActivity()
getSystemService()
bindService()
sendBroadcast()
ContentResolver.query()
底层都可能涉及 Binder 通信。
5. 为什么需要 Binder?
Android 中每个 App 通常运行在独立进程中。
例如:
微信进程
支付宝进程
系统服务进程
你的 App 进程
进程之间的内存是隔离的:
进程 A 不能直接访问进程 B 的内存
所以如果你的 App 想让系统启动一个 Activity,不能直接改系统进程的数据,只能通过某种 IPC 机制告诉系统。
Android 选择 Binder 作为主要 IPC 机制。
6. Intent 和 Binder 的关系
可以这样理解:
Intent 是上层消息内容
Binder 是底层传输通道
类似寄快递:
Intent = 快递包裹里的物品和说明
Binder = 快递运输系统
AMS/ATMS = 快递中转站
目标组件 = 收件人
比如:
Intent intent = new Intent(this, SecondActivity.class);
intent.putExtra("age", 18);
startActivity(intent);
这个 Intent 会被序列化成底层可以传输的数据,然后通过 Binder 发送给系统服务,系统服务再通知目标进程。
7. Intent 数据怎么通过 Binder 传递?
Intent 实现了 Parcelable 接口。
public class Intent implements Parcelable
Parcelable 是 Android 专门为 Binder IPC 设计的序列化机制。
当 Intent 需要跨进程传输时,会被写入 Parcel:
Intent
|
v
Parcel
|
v
Binder 驱动
|
v
目标进程
|
v
反序列化成 Intent
大致过程:
发送方进程中的 Intent 对象
|
| writeToParcel()
v
Parcel 数据
|
| Binder IPC
v
接收方进程
|
| createFromParcel()
v
新的 Intent 对象
注意:
目标进程拿到的不是原来那个 Intent 对象,而是反序列化后的新对象。
8. “物理层通过共享内存实现”怎么理解?
这句话需要稍微严谨一点。
Binder 通信不是简单地说“两个进程直接共享一块内存”。实际上 Binder 的核心包括:
- 用户空间的 Binder 调用
- 内核空间的 Binder 驱动
mmap映射的 Binder 缓冲区- 数据拷贝和对象引用管理
传统 IPC,比如普通管道、Socket,可能需要多次数据拷贝:
发送进程用户空间
-> 内核空间
-> 接收进程用户空间
可能会发生两次拷贝。
Binder 为了提高效率,会让接收方进程通过 mmap 映射一块内核缓冲区。数据传输时,大致可以理解为:
发送进程用户空间
-> Binder 内核缓冲区,接收进程可映射访问
-> 接收进程读取
所以 Binder 通常被称为“一次拷贝”。
更通俗地说:
普通方式:
A 把数据复制给内核,内核再复制给 B。
Binder:
A 把数据复制到 Binder 驱动管理的缓冲区,
B 可以通过映射区域读取这份数据,
减少了一次拷贝。
所以“物理层通过共享内存实现”可以理解为:
Binder 底层使用内核驱动和内存映射机制,让进程之间通过一块受内核管理的映射缓冲区高效传输数据。
但不要理解成:
A 进程和 B 进程随便共享一块普通内存,互相直接读写。
不是这样。
Binder 的共享/映射内存是受 Binder 驱动严格管理的。
9. Intent 跨进程传递的完整理解
以启动另一个 App 的 Activity 为例:
Intent intent = new Intent();
intent.setComponent(new ComponentName(
"com.example.target",
"com.example.target.TargetActivity"
));
intent.putExtra("msg", "hello");
startActivity(intent);
大致流程:
你的 App 进程
|
| 1. 创建 Intent
|
| 2. 调用 startActivity()
|
| 3. Intent 被写入 Parcel
|
| 4. 通过 Binder 发送给系统服务 ATMS/AMS
v
系统进程
|
| 5. 解析 Intent,查找目标 Activity
| 6. 做权限检查、任务栈处理
| 7. 如果目标进程未启动,先 fork 目标进程
|
| 8. 通过 Binder 通知目标 App 进程启动 Activity
v
目标 App 进程
|
| 9. 从 Parcel 还原 Intent
| 10. 创建 Activity
| 11. 调用 onCreate()
v
TargetActivity.onCreate()
目标 Activity 中:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String msg = getIntent().getStringExtra("msg");
}
这里的 getIntent() 拿到的是经过 Binder/Parcel 传过来的数据。
10. 为什么 Intent 传大数据会出问题?
因为 Intent 通过 Binder 传输,而 Binder 的事务缓冲区是有限制的。
如果你这样做:
Intent intent = new Intent(this, SecondActivity.class);
intent.putExtra("bitmap", largeBitmap);
startActivity(intent);
可能会报:
TransactionTooLargeException
原因是:
Intent extras 太大,超过 Binder 事务大小限制。
常见限制一般约为 1MB 左右,但不同版本和场景会有差异。
所以 Intent 不适合传大数据。
11. 大数据应该怎么传?
不要直接通过 Intent 传大对象,例如:
- 大 Bitmap
- 大 List
- 大 JSON
- 大 byte[]
- 大文件内容
推荐做法:
方式一:传 id
Intent intent = new Intent(this, DetailActivity.class);
intent.putExtra("userId", 1001);
startActivity(intent);
目标页面再根据 userId 查询数据。
方式二:传 Uri
例如图片、文件:
Intent intent = new Intent(this, PreviewActivity.class);
intent.setData(imageUri);
startActivity(intent);
或者:
intent.putExtra(Intent.EXTRA_STREAM, imageUri);
实际文件通过文件系统或 ContentProvider 访问。
方式三:使用 ViewModel / Repository / 数据库 / 缓存
同一 App 内可以:
- 数据库
- 内存缓存
- Repository
- ViewModel
- 单例管理器,谨慎使用
方式四:跨进程大数据用 ContentProvider / 文件 / AIDL + 共享内存
如果是跨进程大数据:
ContentProvider- 文件共享
MemoryFileSharedMemoryParcelFileDescriptor
更合适。
12. Binder 和共享内存的区别
严格来说,Binder 和共享内存是两类 IPC 思想:
| 方式 | 特点 |
|---|---|
| Binder | 面向对象、支持权限、安全身份、适合控制命令和小数据 |
| 共享内存 | 适合大数据、高性能数据交换 |
| Socket | 通用网络/本地通信 |
| Pipe | 简单字节流 |
| ContentProvider | 面向结构化数据共享 |
Binder 底层用了内存映射优化,但它不等同于普通共享内存。
所以更准确的说法是:
Android 中 Intent 跨进程传输依赖 Binder;Binder 底层通过内核驱动和 mmap 映射缓冲区来减少数据拷贝,提高 IPC 效率。
13. 一句话总结
可以这样理解:
Intent 是上层传递的消息内容;
Parcelable/Parcel 负责把 Intent 序列化;
Binder 负责跨进程传输;
Binder Driver 负责在内核中完成进程间数据转发;
mmap 映射缓冲区用于提高传输效率。
更简洁地说:
Intent 不是真正的通信通道,它只是通信数据;Android 组件之间真正跨进程通信靠 Binder。Binder 底层通过内核驱动和内存映射机制实现高效、安全的进程间通信。