Binder进程与线程ProcessState以及IPCThreadState

本文深入探讨了Android系统中Binder机制的实现原理,重点分析了ProcessState和IPCThreadState两个核心组件的作用。ProcessState负责打开Binder节点并进行内存映射,而IPCThreadState则负责与Binder驱动进行具体命令交互,确保线程单实例。文章详细解释了这两个组件的构造函数及关键方法,如self()和transact(),揭示了Binder机制在Android系统中的运作细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ProcessState以及IPCThreadState

ProcessState是负责打开Binder节点并做mmap映射,IPCThreadState是负责与Binder驱动进行具体的命令交互。

ProcessState

  1. 实现ProcessState的主要关键点有以下几个:
  • 保证同一进程只有一个ProcessState实例,且只有在ProcessState对象建立时才打开Binder设备以及做内存映射
  • 向上层提供IPc服务
  • 与IPCThreadState分工
  1. 首先分析第一个点:
    源码位置:/frameworks/native/libs/binder/ProcessState.cpp  http://androidxref.com/6.0.1_r10/xref/frameworks/native/libs/binder/ProcessState.cpp
sp<ProcessState> ProcessState::self()
{
    if (gProcess != NULL) return gProcess;

    AutoMutex _l(gProcessMutex);
    if (gProcess == NULL) gProcess = new ProcessState;
    return gProcess;
}

可以看到,在这里也是先检查是否存在一个已经实例化的prosessstate,否则创建一个,所以获取ProcessState对象,需要通过这个self方法。
接下来需要一步步的观察这个新建的过程当中实现的原理。

  1. 分析构造函数:
ProcessState::ProcessState()
    : mDriverFD(open_driver())
    , mVMStart(MAP_FAILED)
    , mManagesContexts(false)
    , mBinderContextCheckFunc(NULL)
    , mBinderContextUserData(NULL)
    , mThreadPoolStarted(false)
    , mThreadPoolSeq(1)
{
    if (mDriverFD >= 0) {
        mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
        if (mVMStart == MAP_FAILED) {
            // *sigh*
            LOGE("Using /dev/binder failed: unable to mmap transaction memory.\n");
            close(mDriverFD);
            mDriverFD = -1;
        }
#else
        mDriverFD = -1;
#endif
    }
    if (mDriverFD < 0) {
        // Need to run without the driver, starting our own thread pool.
    }
}

可以看到有两个之前学习的时候了解到了,与Binder驱动紧密相关的方法:
一个是open_driver(),另一个是下面的mmap(),也就是最终打开了Binder结点以及进行了内存块的映射。

  1. 接下来分析在之前用到的获取IBinder的对象时的一个方法:getContextObject
    在这个方法中,传入了一个handel,最终得到了一个BpBinder,而这个BpBinder是Binder在Native层的代理。
sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
{
    return getStrongProxyForHandle(0);
}
ProcessState::getStrongProxyForHandle
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
    sp<IBinder> result;
 
    AutoMutex _l(mLock);
 
    handle_entry* e = lookupHandleLocked(handle);
 
    if (e != NULL) {
        ......
        IBinder* b = e->binder;
        if (b == NULL || !e->refs->attemptIncWeak(this)) {
            if (handle == 0) {
               ......
                Parcel data;
                status_t status = IPCThreadState::self()->transact(
                        0, IBinder::PING_TRANSACTION, data, NULL, 0);
                if (status == DEAD_OBJECT)
                   return NULL;
            }
 
            b = new BpBinder(handle); 
            e->binder = b;
            if (b) e->refs = b->getWeakRefs();
            result = b;
        } else {
            // This little bit of nastyness is to allow us to add a primary
            // reference to the remote proxy when this team doesn't have one
            // but another team is sending the handle to us.
            result.force_set(b);
            e->refs->decWeak(this);
        }
    }
 
    return result;
}

ProcessState::lookupHandleLocked

ProcessState::handle_entry* ProcessState::lookupHandleLocked(int32_t handle)
{
    const size_t N=mHandleToObject.size();
    if (N <= (size_t)handle) {
        handle_entry e;
        e.binder = NULL;
        e.refs = NULL;
        status_t err = mHandleToObject.insertAt(e, N, handle+1-N);
        if (err < NO_ERROR) return NULL;
    }
    return &mHandleToObject.editItemAt(handle);
}

从这儿看,先调用lookupHandleLocked方法,由于是第一次调用,因此新建一个handle_entry,并返回,而且其binder和refs为NULL
那么getStrongProxyForHandle方法接着往下走,由于binder为NULL,mHandle传入的是0,因此进入判断条件中,最后new BpBinder,且参数为0

因此,返回的是new BpBinder(0)

sp<IBinder> b = ProcessState::self()->getContextObject(NULL);

 

 

IPCThreadState

代码位置:/frameworks/native/libs/binder/IPCThreadState.cpp

http://androidxref.com/6.0.1_r10/xref/frameworks/native/libs/binder/IPCThreadState.cpp

  1. 单实例构造函数:
IPCThreadState* IPCThreadState::self()
{
    if (gHaveTLS) { 
    //当执行完第一次之后,再次运行的时候就已经有IPCThreadState实例,只需要获取就可以使用
restart:
        const pthread_key_t k = gTLS;
        IPCThreadState* st = (IPCThreadState*)pthread_getspecific(k);
        if (st) return st;
        return new IPCThreadState;
    }

    if (gShutdown) {
        ALOGW("Calling IPCThreadState::self() during shutdown is dangerous, expect a crash.\n");
        return NULL;
    }

    pthread_mutex_lock(&gTLSMutex);
    if (!gHaveTLS) {       
    //初始的gHaveTLS的值false,所以第一次调用的时候,会执行这里的代码
    //随后将gHaveTLS设置为true
        int key_create_value = pthread_key_create(&gTLS, threadDestructor);
        if (key_create_value != 0) {
            pthread_mutex_unlock(&gTLSMutex);
            ALOGW("IPCThreadState::self() unable to create TLS key, expect a crash: %s\n",
                    strerror(key_create_value));
            return NULL;
        }
        gHaveTLS = true;
    }
    pthread_mutex_unlock(&gTLSMutex);
    goto restart;
}

通过上面的方法,就能保证“线程单实例”的目的

  1. 现有的调用分析顺序是:
    getService@ServiceManagerProxy-->transact@BinderProxy-->transact@BpBinder-->transact@IPCThreadState
  2. 不管是读取还是写入,Binder驱动都只是发挥中间人的作用,真正处理请求的还是Binder Client以及Binder Server双方。
  3. 真正与Binder打交道的地方时talkWithDriver中的ioctl()

转载于:https://www.cnblogs.com/mingfeng002/p/10989200.html

<think>我们正在讨论的是Android Binder IPC机制中的两个关键部分:`IPCThreadState::self()->flushCommands()`和`onTransact`。它们分别位于客户端和服务端,共同完成跨进程通信(IPC)。下面我将详细解释它们之间的关系。 ### 1. **基本概念** - **`flushCommands()`**: - 位于客户端(调用者进程),由`IPCThreadState`类实现。 - 作用:立即将当前线程中缓存的Binder命令(即`mOut`中的`Parcel`数据)通过Binder驱动发送到服务端。 - 调用时机:当客户端需要确保命令被立即执行时(如UI刷新、动画等需要低延迟的场景)。 - **`onTransact()`**: - 位于服务端(被调用者进程),是`Binder`类的一个方法。 - 作用:接收来自Binder驱动的请求,解析请求数据(`Parcel`),调用对应的服务方法,并将结果写回。 - 调用时机:当Binder驱动将客户端的请求传递到服务端时自动触发。 ### 2. **工作流程中的关系** 我们可以将一次完整的Binder IPC调用分为以下几个步骤(结合引用[1]的内容): 1. **客户端准备数据**:客户端通过`writeTransactionData()`将请求数据写入`mOut`(一个`Parcel`对象)。 2. **客户端发送数据**: - 默认情况下,Binder命令可能会被缓存(为了合并多次调用,减少IPC次数)。 - 调用`flushCommands()`会立即触发将`mOut`中的数据写入Binder驱动(即发送到服务端)。 3. **Binder驱动传递**:Binder驱动将数据传递到服务端进程的接收队列。 4. **服务端处理**:服务端的Binder线程(如`Binder:xxx_1`线程)从队列中取出请求,调用`onTransact()`方法。 5. **服务端执行**:`onTransact()`根据请求的`code`(如`TRANSACTION_addUser`)解析数据,调用实际的服务方法。 6. **返回结果**:服务端将结果写回`reply`,通过Binder驱动返回给客户端。 ```mermaid sequenceDiagram participant Client as 客户端进程 participant IPC as IPCThreadState(客户端) participant Driver as Binder驱动 participant Server as 服务端进程 participant Binder as Binder对象(服务端) Client->>IPC: 1. writeTransactionData()写入mOut Client->>IPC: 2. flushCommands() IPC->>Driver: 3. 发送mOut中的数据 Driver->>Server: 4. 传递请求 Server->>Binder: 5. 调用onTransact(code, data, reply, flags) Binder->>Binder: 6. 解析code,执行对应方法 Binder->>Server: 7. 将结果写入reply Server->>Driver: 8. 返回结果 Driver->>IPC: 9. 结果返回 IPC->>Client: 10. 处理结果 ``` ### 3. **关键交互点** - **`flushCommands()`触发`onTransact()`**: 客户端调用`flushCommands()`是显式触发命令发送的动作,这会导致服务端的`onTransact()`被调用(通过Binder驱动)。如果没有调用`flushCommands()`,命令可能会在后续某个时机(如缓冲区满或等待超时)自动发送。 - **数据流**: - 客户端通过`mOut`(`Parcel`)存储待发送的数据。 - `flushCommands()`将`mOut`中的数据推送至Binder驱动。 - 服务端在`onTransact()`中通过`Parcel data`参数接收这些数据。 ### 4. **性能优化角度** - **批量处理**: 默认情况下,客户端可能会累积多个Binder调用再一次性发送(减少IPC次数)。`flushCommands()`允许在关键点强制刷新,平衡延迟吞吐量。 - 例如:在UI渲染中,多次更新视图后调用`flushCommands()`确保立即生效。 - **避免阻塞**: 服务端`onTransact()`应快速处理请求。若耗时较长,需异步处理或转移到其他线程,否则会阻塞Binder线程池,导致ANR。 ### 5. **实际代码示例** #### 客户端(调用flushCommands) ```cpp // 示例:SurfaceComposerClient.cpp (AOSP) void SurfaceComposerClient::setLayer(uint32_t layer) { sp<ISurfaceComposer> sf(ComposerService::getComposerService()); Parcel data; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); data.writeStrongBinder(mHandle); data.writeUint32(layer); // 写入mOut后立即刷新 IPCThreadState::self()->flushCommands(); } ``` #### 服务端(onTransact处理) ```cpp // 示例:ISurfaceComposer.cpp (AOSP) status_t BnSurfaceComposer::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { switch(code) { case SET_LAYER: { data.enforceInterface(ISurfaceComposer::getInterfaceDescriptor()); sp<IBinder> handle = data.readStrongBinder(); uint32_t layer = data.readUint32(); setLayer(handle, layer); // 实际业务逻辑 reply->writeNoException(); return NO_ERROR; } // 其他case... } } ``` ### 6. **总结关系** | **维度** | `flushCommands()` | `onTransact()` | |----------------|--------------------------------------------|------------------------------------------| | **位置** | 客户端(调用者进程) | 服务端(被调用者进程) | | **作用** | 立即发送缓存的Binder命令 | 接收并处理来自客户端的Binder请求 | | **触发方式** | 客户端主动调用 | 由Binder驱动自动触发(响应客户端请求) | | **数据载体** | 客户端`mOut`(`Parcel`) | 服务端`data`(`Parcel`) | | **性能影响** | 控制命令发送时机(延迟 vs 吞吐量) | 影响服务端响应速度(需避免阻塞) | **核心关系**: `flushCommands()`是客户端**推送命令的触发器**,而`onTransact()`是服务端**执行命令的处理器**。两者通过Binder驱动连接,共同完成一次跨进程调用。 ### 相关问题 §§相关问题§§ 1. Android Binder 机制中,除了 `flushCommands()`,还有哪些方法可以优化 IPC 性能? 2. 在服务端 `onTransact()` 方法中,如何避免因长时间阻塞导致 ANR? 3. 设计自定义 Binder 服务时,如何确保通信接口的高效性?</think>### IPCThreadState::flushCommands() onTransact() 的关系详解 在 Android Binder IPC 机制中,`IPCThreadState::flushCommands()` 和 `onTransact()` 是跨进程通信的核心组件,它们分别位于通信链路的两端,协同完成 IPC 调用: ```mermaid sequenceDiagram participant Client as 客户端进程 participant Driver as Binder驱动 participant Server as 服务端进程 Client->>Client: 1. 累积命令到mOut(Parcel) Client->>Client: 2. 调用flushCommands() Client->>Driver: 3. 提交mOut数据 Driver->>Server: 4. 分发请求 Server->>Server: 5. 触发onTransact() Server->>Server: 6. 执行服务方法 Server->>Client: 7. 返回结果 ``` #### 1. **核心功能对比** | **方法** | **执行位置** | **数据结构** | **作用** | |------------------------------|---------------|----------------|-------------------------------------------------------------------------| | `IPCThreadState::flushCommands()` | **客户端** | `mOut` (Parcel) | 强制刷新命令缓冲区,将累积的 Binder 事务立即发送到 Binder 驱动[^1] | | `onTransact()` | **服务端** | `data` (Parcel) | 接收并解析来自客户端的请求,执行对应的服务方法,并返回结果 | #### 2. **协同工作流程** 1. **客户端命令累积** 客户端通过 `writeTransactionData()` 将多个操作写入 `mOut`(一个 Parcel 对象): ```cpp // IPCThreadState.cpp status_t IPCThreadState::writeTransactionData(...) { mOut.writeInt32(BC_TRANSACTION); // 命令类型 mOut.write(&tr, sizeof(tr)); // 事务数据 } ``` 2. **命令刷新触发** `flushCommands()` 强制立即发送缓冲区的命令,避免等待自动刷新: ```cpp // 关键代码 void IPCThreadState::flushCommands() { if (mOut.dataSize() > 0) { talkWithDriver(false); // 立即驱动通信 } } ``` 3. **服务端请求处理** Binder 驱动将请求路由到服务端后,触发 `onTransact()`: ```java // 服务端Binder子类 protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) { switch (code) { case TRANSACTION_ADD_USER: User user = User.CREATOR.createFromParcel(data); // 反序列化 addUser(user); // 执行业务逻辑 reply.writeNoException(); return true; } } ``` #### 3. **关键交互点** - **数据流传递** `flushCommands()` 发送的 `mOut` 数据 → 通过 Binder 驱动 → 成为 `onTransact()` 的 `data` 参数 - **执行触发关系** 客户端调用 `flushCommands()` 是服务端 `onTransact()` 被触发的**必要条件**(除非命令被合并发送) - **性能平衡** - 客户端:通过延迟刷新(默认)合并多个操作,减少 IPC 次数 - 服务端:`onTransact()` 需快速响应,避免阻塞 Binder 线程池 #### 4. **实际应用场景** ```cpp // 窗口系统示例 void updateViews() { view1.update(); // 写入mOut view2.update(); // 写入mOut IPCThreadState::self()->flushCommands(); // 强制立即刷新 // 后续依赖刷新结果的操作 } ``` 此场景中: 1. 两个 view 更新操作被合并到同一次 IPC 2. `flushCommands()` 确保更新立即生效 3. 服务端 `onTransact()` 处理 `VIEW_UPDATE` 事务码 #### 5. **设计差异总结** | **维度** | `flushCommands()` | `onTransact()` | |------------------|------------------------------------|---------------------------------| | **调用方** | 客户端主动调用 | Binder 驱动自动触发 | | **执行线程** | 客户端调用线程 | 服务端 Binder 线程池 | | **性能目标** | 减少 IPC 次数 (批处理) | 降低延迟 (快速响应) | | **数据状态** | 原始序列化数据 (`mOut`) | 已反序列化的请求对象 | ### 总结 `flushCommands()` 是客户端**命令提交的终止点**,负责将累积的 IPC 请求推送至 Binder 驱动;`onTransact()` 是服务端**请求处理的起点**,解析并执行客户端请求。两者通过 Binder 驱动连接,构成 Android IPC 的核心通路。正确使用 `flushCommands()` 可优化吞吐量,而高效的 `onTransact()` 实现则是避免 ANR 的关键[^1]。 --- ### 相关问题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值