Android AMS创建进程不用Binder而用Socket?

核心原因

Binder需要进程已经存在

Binder的工作原理

复制代码
┌─────────────────┐         ┌─────────────────┐
│    进程 A        │         │    进程 B        │
│                 │         │                 │
│  ┌───────────┐  │  Binder  │  ┌───────────┐  │
│  │ BpXXX     │──┼─────────┼──│ BnXXX     │  │
│  │ (代理端)  │  │         │  │ (stub端)  │  │
│  └───────────┘  │         │  └───────────┘  │
│       │         │         │       │         │
│       │         │         │       ▼         │
│       ▼         │         │  ┌───────────┐  │
│  ┌───────────┐  │         │  │ 服务端    │  │
│  │  服务端   │◄─┼─────────┼──│ 实现      │  │
│  │  在进程A  │  │         │  │          │  │
│  └───────────┘  │         │  └───────────┘  │
└─────────────────┘         └─────────────────┘

关键点 :Binder通信需要两个进程都存在 !

进程A需要先存在,才能注册Binder服务

进程 B 需要先存在,才能获取到进程 A 的 Binder 代理

问题来了:创建进程时,哪个进程都不存在!

复制代码
情况:用户点击图标,要启动微信
     │
     ▼
     需要创建一个全新的进程来运行微信
     │
     ▼
     但是!Binder 需要进程已经存在才能通信
     │
     ▼
     矛盾!要创建进程需要通信,但通信需要进程已存在

为什么必须用 Socket?

Socket + fork 的工作原理

复制代码
┌────────────────────────────────────────────────────────────────────┐
│                        AMS (已存在的进程)                          │
│                                                                     │
│   1. AMS 通过 Socket 发送命令给 Zygote                             │
│      socket.send("start:com.tencent.mm")                          │
│                           │                                        │
└───────────────────────────┼────────────────────────────────────────┘
                            │ Socket 连接(Zygote 已监听 socket)
                            ▼
┌────────────────────────────────────────────────────────────────────┐
│                    Zygote (已存在的进程)                            │
│                                                                     │
│   2. Zygote 收到命令,调用 fork() 创建新进程                       │
│                                                                     │
│      pid = fork();  // Linux 系统调用                               │
│                                                                     │
│      子进程(微信):PID = 0(fork 返回值)                         │
│      父进程(Zygote):PID = 微信的 PID(fork 返回值)              │
│                                                                     │
│                           │                                        │
│                           │ fork() 后子进程继承 socket 连接         │
│                           ▼                                        │
│      ┌──────────────────────────────────────────────┐              │
│      │           微信进程(全新创建)                │              │
│      │                                              │              │
│      │   - 继承 Zygote 的内存空间(写时复制)       │              │
│      │   - 继承打开的文件描述符(包括 socket)      │              │
│      │   - 然后 exec() 加载微信代码                │              │
│      │                                              │              │
│      │   微信进程创建成功后,就可以使用 Binder 了    │              │
│      └──────────────────────────────────────────────┘              │
└────────────────────────────────────────────────────────────────────┘

Socket vs Binder 对比

完整的进程创建流程

第一步:AMS 通过 Socket 通知 Zygote

复制代码
// AMS 发送启动命令
Process.start("com.tencent.mm",    // 进程名
              "android.app.ActivityThread",  // 入口类
              app.uid, app.gids, ...);

// Process.start() 内部
private static ProcessStartResult start(...) {
    // 1. 通过 socket 发送命令到 Zygote
    return Zygote.startChildProcess(
        socket,  // Zygote 的 socket 描述符
        processName, entryPoint, ...
    );
}

第二步:Zygote fork 出新进程

复制代码
// ZygoteServer.runSelectLoop() 收到命令后
Runnable runSelectLoop() {
    // 接收 AMS 的命令
    ZygoteConnection connection = acceptCommandPeer();
    
    // 处理命令,fork 子进程
    return connection.processOneCommand(this);
}

// ZygoteConnection.processOneCommand()
int pid = forkAndSpecialize(uid, gids, ...);

if (pid == 0) {
    // 子进程(微信)中执行
    // 这里子进程已经可以用了!
    return handleChildProcess();
}

第三步:新进程初始化并使用 Binder

复制代码
// 子进程(微信)执行
ActivityThread.main() {
    // 1. 创建 Looper
    Looper.prepareMainLooper();
    
    // 2. 绑定到 AMS(这时可以用 Binder 了!)
    IActivityManager mgr = ActivityManager.getService();
    mgr.attachApplication(mAppThread);  // ← Binder 通信
    
    // 3. 进入消息循环
    Looper.loop();
}

为什么 Binder 不能用于进程创建?

Binder 的前提条件

复制代码
Binder 通信的必要条件:
     │
     ├─► 1. 两个进程都必须已经存在
     │
     ├─► 2. 服务端必须已经注册到 Binder 驱动
     │
     ├─► 3. 客户端必须能够获取到服务端的引用
     │
     └─► 4. 需要通过 /dev/binder 设备进行通信

创建新进程时的问题

复制代码
┌─────────────────────────────────────────────────────────────┐
│                      创建新进程场景                          │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  问题:我们要创建一个全新的进程                                │
│                                                              │
│  但是:                                                       │
│  - 新进程不存在 → 无法建立 Binder 连接                        │
│  - 无法获取新进程的 Binder 引用                              │
│  - /dev/binder 还没准备好                                    │
│                                                              │
│  结论:Binder 在进程创建阶段完全无法使用!                    │
│                                                              │
└─────────────────────────────────────────────────────────────┘

Socket 为什么可以?

复制代码
Socket 的优势:
     │
     ├─► 1. Zygote 进程已经存在,并且监听着 socket
     │
     ├─► 2. Socket 不需要对方进程存在,只需要对方在监听
     │
     ├─► 3. Socket 可以触发 fork() 系统调用
     │
     ├─► 4. fork() 可以在 Zygote 进程中创建新的进程
     │
     └─► 5. 新进程继承 Zygote 的 socket 连接

总结

核心设计

  1. Socket = 用于 触发进程创建 (因为可以调用 fork())

  2. Binder = 用于 进程间通信 (进程创建后使用,效率更高)

这是 Android 系统设计的精妙之处: 用 Socket 创建进程,用 Binder 通信 ,两者各司其职!

相关推荐
程序员老邢3 小时前
【技术底稿 37】Spring Boot 3.x 自动装配 “死锁” 排查:3 个注解实现条件化装配与 Mock 兜底
java·spring boot·后端·自动装配·rag·技术底稿
日月云棠4 小时前
JAVA数据结构与算法 - 基础:链表
java·后端
日月云棠4 小时前
JAVA数据结构与算法 - 基础:栈 (Stack) 深度解析
java·后端
xiguolangzi4 小时前
java使用Map映射遍历方法
java·后端
日月云棠4 小时前
JAVA数据结构与算法 - 基础:队列 (Queue) 全方位解析
java·后端
JAVA面经实录9174 小时前
Java集合大全终极手册(一)
java·开发语言
Cosolar4 小时前
吃透 Spring Cloud Gateway:基于 Spring Boot 3 的核心原理、企业级实战与避坑指南
java·spring cloud·架构
千里马-horse4 小时前
gRPC -- Java 基础教程
java·开发语言·grpc
甲方大人请饶命4 小时前
Java-面向对象进阶(qqbb知识点)
java·开发语言