Android中binderDied()以及"Unknown binder error code" 出现的原因说明

本文深入剖析Android系统中的Binder机制,探讨binderDied()方法的触发条件及未知Binder错误0xfffffff7的成因,帮助开发者有效避免和解决相关问题。

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

 

                                                                                                                                                              转载请注明出处:http://blog.youkuaiyun.com/qinjuning

 

 

                   Binder机制是Android系统进程间通信的核心机制,它很大而且很复杂,不过对它有一定程度的理解和掌握是真正接触    

          Android核心的必备。网上关于它的介绍很多,希望大家能耐着性子认真地学习Binder机制的实现。在此,给大家分享一个

         我认为挺好地学习Binder机制基础的博客《Android系统中Binder机制的分析系列》,希望对大家有用。 本来也准备自己

          写点关于Binder机制的,但无奈自己的理解程度很肤浅,只好放弃了。

 

                   自己从事的模块开发采用了Binder机制进行功能的开发,对Binder机制的不熟悉,导致了很多Bug的出现,可谓“一Bug

         未解,一Bug又起”,伤脑筋。今天对Binder运用过程中可能出现的两个问题做下总结,希望帮大家有所启发。

 

 

  为了下面叙述的清楚,假设我们存在如下的Binder交互对象:

 

                                  

                    

 

  1 、 binderDied()方法的触发时机

         当客户端对象A死掉时或者其他情况导致该Binder发生结束了,就会回调binderDied()方法,用户可以在这个方法里

     进行捕捉binder死掉。

    

      其方法原型在:IBinder.h文件中 (frameworks/base/include/binder/Ibinder.h)

          

 /**
     * This method allows you to add data that is transported through
     * IPC along with your IBinder pointer.  When implementing a Binder
     * object, override it to write your desired data in to @a outData.
     * You can then call getConstantData() on your IBinder to retrieve
     * that data, from any process.  You MUST return the number of bytes
     * written in to the parcel (including padding).
     */
    class DeathRecipient : public virtual RefBase
    {
    public:
        virtual void binderDied(const wp<IBinder>& who) = 0;
    };

 

      通常而言,我们可以在服务端BnXXX 里实现该虚函数去捕获Binder死掉事件,例如:

 

//Binder机制服务端的具体实现类
class BnXXX: public BnInterface<IXX>
{
public:
    virtual status_t    onTransact( uint32_t code,
                                    const Parcel& data,
                                    Parcel* reply,
                                    uint32_t flags = 0);
                                    
    //当Binder机制的客户端死掉,导致了该Binder结束,会回调此方法                                
    void FMRadio::binderDied(const wp<IBinder>& who) {
        //输出该Binder进程所在的信息 包括进程Id(pid)等
        LOGD("binderDied() 1 %p, tid %d, calling tid %d", who.unsafe_get(), gettid(),
                           IPCThreadState::self()->getCallingPid());        
        // do something 
    }
}      



     

  2、 Unknown binder error code 0xfffffff7 出现的原因。

             

                当客户端与服务端正在通过Binder机制交互时,例如A正在通过Binder机制与B对象进行交互,即A请求B do something,

       这个过程中如果Binder机制发生了异常,导致A与B的交互不能正常进行,例如代码中显示调用System.exit(0)结束应用程序

        (说明:System.exit(0)方法会 清空该Process的一切资源,包括Activity、Service、BroadcastReceiver等资源,Binder交互

      也结束),系统就打印如下Log信息:“Error: JavaBinder  Unknown binder error code. 0xfffffff7”。接下来,C++层会调用

       binderDied() 法,其Binder客户端也死掉了,。

 

 

 

    最后,希望大家在此基础上能少找些弯路,多解几个Bug吧 ,善莫大焉 !

 

 

 

<think>好的,我需要帮助用户了解Android Binder中onTransact函数的实现细节和调试方法。首先,我得回顾一下Binder的基本机制,确保自己对整体流程的理解正确。根据引用[1],IBinder的transact()函数用于通信,而具体的实现由继承类完成,比如BBinder。引用[2]提到BBinder的transact函数会调用自身的onTransact,这说明onTransact是实际处理请求的地方。 接下来,用户想知道如何查看onTransact的实现。根据引用[2],BBinder的transact直接调用onTransact,所以需要查看具体子类如BnInterface的实现。可能需要参考Android源码中的BnXXXService类,比如BnSurfaceComposer,这些类会重写onTransact来处理不同的请求码。 关于调试方法,用户可能需要在Native层添加日志或者使用gdb。引用[4]提到了libbinder.so中的IPCThreadState::executeCommand,这可能涉及调用栈,所以调试时需要附加到目标进程,设置断点在onTransact函数。另外,dump函数可能用于输出当前状态,需要检查是否有重写dump方法,或者使用dumpsys工具。 另外,引用[3]提到Binder的数据拷贝机制更高效,这可能影响性能分析时的考虑因素。但用户的问题主要在于实现和调试,所以重点应放在代码结构和调试工具上。 总结步骤:首先分析onTransact的代码路径,然后讨论如何添加日志或使用调试器,最后提到dump函数和dumpsys工具的使用。需要确保回答覆盖实现细节和多种调试方法,并引用提供的资料支持每个观点。</think>### Android Binder onTransact 函数实现与调试方法 #### 1. **onTransact 函数的作用与实现路径** onTransact 是 Binder 通信中处理远程请求的核心函数。当客户端调用 `transact()` 时,服务端的 `onTransact()` 会根据**请求码(code)**解析参数(`Parcel data`),执行逻辑,并通过 `Parcel reply` 返回结果[^2]。 - **实现路径**: - 所有 Binder 服务类继承自 `BBinder`,需重写 `onTransact()` 以处理自定义请求码。例如,`BnSurfaceComposer`(显示服务)会实现类似以下逻辑: ```cpp status_t BnSurfaceComposer::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { switch(code) { case CREATE_DISPLAY: // 处理具体业务逻辑 ... return NO_ERROR; default: return BBinder::onTransact(code, data, reply, flags); } } ``` - 若未覆盖 `onTransact()`,默认会返回 `UNKNOWN_TRANSACTION` 错误。 #### 2. **调试方法** ##### (1) **添加 Native 层日志** 在 `onTransact()` 中添加 `ALOGD` 打印请求码和参数: ```cpp status_t MyService::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { ALOGD("Received transaction code: %d", code); // 打印请求码 int32_t param = data.readInt32(); // 解析参数示例 ALOGD("Parameter: %d", param); ... } ``` 通过 `logcat` 过滤日志: ```bash adb logcat | grep "MyService" ``` ##### (2) **使用 GDB 调试** - 附加到目标进程: ```bash adb shell ps -A | grep <service_name> # 获取进程PID adb forward tcp:5039 tcp:5039 adb shell gdbserver :5039 --attach <PID> ``` - 在本地 GDB 中设置断点: ```gdb break android::BnMyService::onTransact continue ``` ##### (3) **利用 dump() 函数** 若服务类实现了 `dump()`,可通过 `dumpsys` 工具获取运行时状态: ```cpp status_t MyService::dump(int fd, const Vector<String16>& args) { dprintf(fd, "Current service state: ..."); // 输出调试信息 return NO_ERROR; } ``` 调用命令: ```bash adb shell dumpsys <service_name> ``` ##### (4) **分析 Binder 调用栈** 当发生 `onTransact()` 调用失败时(如引用[4]),可通过 **libbinder.so 的堆栈**定位问题: - 检查 `IPCThreadState::executeCommand` 的调用链,确认参数解析是否异常[^4]。 #### 3. **关键注意事项** - **线程模型**:`onTransact()` 默认在 Binder 线程池中执行,需避免阻塞操作。 - **权限校验**:在 `onTransact()` 中需通过 `IPCThreadState::getCallingUid()` 验证调用方身份。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值