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 通信 ,两者各司其职!

相关推荐
骄马之死31 分钟前
SpringMVC + SpringBoot 核心知识点总结
java·spring boot·后端
郑洁文2 小时前
基于Spring Boot的流浪动物救助网站
java·spring boot·后端·毕设·流浪动物救助
螺丝钉code3 小时前
JAVA项目 Claude code CLAUDE.md 到底应该怎么写
java·人工智能·claude code
摇滚侠4 小时前
Maven 入门+高深 单一架构案例 54-59
java·架构·maven·intellij-idea
VidDown4 小时前
Webhook 调试器:让第三方回调“原形毕露”
java·开发语言·javascript·编辑器·postman
折哥的程序人生 · 物流技术专研4 小时前
Java 23 种设计模式:从踩坑到精通 | 原型模式 —— 克隆对象,深拷贝与浅拷贝的坑你踩过吗?
java·设计模式·架构·原型模式·单一职责原则
装不满的克莱因瓶5 小时前
基于 OpenResty 扩展开发实现动态服务注册与发现能力
java·开发语言·架构·openresty
程序员小羊!5 小时前
06Java 异常机制与常用类
java
weixin_523185325 小时前
Java基础知识总结(四):引用数据类型与参数传递机制
java·开发语言·python
故渊at6 小时前
第二板块:Android 四大组件标准化学理 | 第六篇:四大组件架构总论与 Manifest 规范
android·架构·zygote·manifest·四大组件