可爱的BpXXX-图

1. 说BpXXX(如BpMediaPlayer)可爱,是因为它总是默默无闻地工作做,且基本上不露面(有点害羞的样子),但却总是做着重要的工作,没有它你如何调用mediaserver中为你准备好的各种功能呢?有了它,我们告诉它要听流行的“伤不起”,它就帮你放。你说它是不是一个听话的孩子呢?老板是不是很喜欢这样的员工呢偷笑

2. 既然它如此重要,但又基本上不露面,这可太为难我们这些天天if else的兄弟了。因为要找它难,没找到它之前,对这些if else的理解就更难了。所以做人也不能太害羞了,否则害了自己也害了大家,当然像MediaPlayer这样过于高调也不好,啥事不做,只当一个传话筒,还哪么高调,天天到处叫,来调我吧,来用我吧微笑

3. 在上一篇文章《Android媒体播放器框架--图》中讲过,MediaPlayer在setDataSource中调用BpMediaPlayerService::create时创建了BpMediaPlayer,并把它保存在MediaPlayer的mPlayer中,以供后面的调用。

4. 本文重点分析这个BpMediaPlayer是如何创建出来的。下面不得不看代码了。

status_t MediaPlayer::setDataSource(
        const char *url, const KeyedVector<String8, String8> *headers)
{
    LOGV("setDataSource(%s)", url);
    status_t err = BAD_VALUE;
    if (url != NULL) {

        const sp<IMediaPlayerService>& service(getMediaPlayerService());

        if (service != 0) {
            //调用BpMediaPlayerService::create
            sp<IMediaPlayer> player(service->create(getpid(), this, url, headers));

            //把新创建的BpMediaPlayer保存在MediaPlayer的成员变量mPlayer中
            err = setDataSource(player);
        }
    }
    return err;
}

自从这个MediaPlayer有了这个mPlayer之后,什么事就叫mPlayer来做,自已就成了领导了。

5.这明明是返回的是IMediaPlayer,为什么偏说是BpMediaPlayer呢?其原因有二。

   1)得益于C++中,只要这个指针指向派生类的对象,可把它转换为基类的指针来保存,调用方法时,会执行对应派生类中的方法。

   2)先看看MediaPlayer的家族图谱:

    

现在有两个问题需要解答:

1)为什么说上面代码中创建的player为指向BpMediaPlayer的指针?

2)为什么说BpMediaPlayer中的mRemote为指向BpBinder的指针?

 

6. 为什么说上面代码中创建的player为指向BpMediaPlayer的指针

这个还是让代码自己来讲吧:

class BpMediaPlayerService: public BpInterface<IMediaPlayerService>
{
public:
    ...
    virtual sp<IMediaPlayer> create(
            pid_t pid, const sp<IMediaPlayerClient>& client,
            const char* url, const KeyedVector<String8, String8> *headers) {
        Parcel data, reply;
        data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
        data.writeInt32(pid);
        data.writeStrongBinder(client->asBinder());
        data.writeCString(url);

        if (headers == NULL) {
            data.writeInt32(0);
        } else {
            // serialize the headers
            data.writeInt32(headers->size());
            for (size_t i = 0; i < headers->size(); ++i) {
                data.writeString8(headers->keyAt(i));
                data.writeString8(headers->valueAt(i));
            }
        }
        //通过Binder发送请求给MediaPlayerService
        remote()->transact(CREATE_URL, data, &reply);
        //这就是重点??? reply.readStrongBinder()); 的返回值为一个new的BpBinder
        return interface_cast<IMediaPlayer>(reply.readStrongBinder()); //返回值为一个new的BpMediaPlayer
    }
    ...
}

interface_cast<IMediaPlayer>(reply.readStrongBinder());结果是什么呢? 是IMediaPlayer还是BpMediaPlayer?期待其中的答案...(让我轻轻地告诉你,它是一个BpMeidaPlayer)

 

看似简单的一行代码,其内容可不简单,因为它涉及一个又一个模板。好玩吧!

6.1 先看看其参数是什么东东...(先偷偷地告诉你,一个新new的BpBinder)

reply.readStrongBinder()代码如下:

sp<IBinder> Parcel::readStrongBinder() const
{
    sp<IBinder> val;
    unflatten_binder(ProcessState::self(), *this, &val);
    return val;
}

没什么,再向下看,不是什么东东都可以向下看的,否则别人会骂的。

status_t unflatten_binder(const sp<ProcessState>& proc,
    const Parcel& in, sp<IBinder>* out)
{
    const flat_binder_object* flat = in.readObject(false);
    
    if (flat) {
        switch (flat->type) {
            case BINDER_TYPE_BINDER:
                *out = static_cast<IBinder*>(flat->cookie);
                return finish_unflatten_binder(NULL, *flat, in);
            case BINDER_TYPE_HANDLE: //因为我们是Client,当然会调用这个
                *out = proc->getStrongProxyForHandle(flat->handle);
                return finish_unflatten_binder(
                    static_cast<BpBinder*>(out->get()), *flat, in);
        }        
    }
    return BAD_TYPE;
}

6.1.1 还是哪么简单,只有两行代码,可内容还是不简单,再深入一步,看看第一行代码out返回的是什么东东?

sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
    sp<IBinder> result;

    AutoMutex _l(mLock);

    handle_entry* e = lookupHandleLocked(handle);

    if (e != NULL) {
        // We need to create a new BpBinder if there isn't currently one, OR we
        // are unable to acquire a weak reference on this current one.  See comment
        // in getWeakProxyForHandle() for more info about this.
        IBinder* b = e->binder;
        if (b == NULL || !e->refs->attemptIncWeak(this)) {
            //第一次调用肯定走这儿
            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;
}

呵呵,终于看到了,这个返回的就是一个BpBinder,其handle为传入的handle.现在已经看到reply.readStrongBinder()的返回值为一个BpBinder,即interface_cast<IMediaPlayer>(reply.readStrongBinder());的参数为一个BpBinder.


6.1.2 返回值已经产生,第二行代码finish_unflatten_binder( static_cast<BpBinder*>(out->get()), *flat, in);做什么呢?

inline static status_t finish_unflatten_binder(
    BpBinder* proxy, const flat_binder_object& flat, const Parcel& in)
{
    return NO_ERROR;
}

啥事没干,而且游戏嘎然而止。至此,参数已经分析完成,其结果就是一个指向BpBinder的一个指针。

 

7. 看看interface_cast<IMediaPlayer>(reply.readStrongBinder())即interface_cast<IMediaPlayer>(BpBinder)做了些什么,且返回值是什么? 老规距,让代码自己说话。以下就要与模板打交道了。

 7.1 寻找asInterface的真身

template<typename INTERFACE>
inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
{
    return INTERFACE::asInterface(obj);
}

又是一很简单。还原后代码为:

inline sp<IMediaPlayer> interface_cast(const sp<IBinder>& obj)
{
    return IMediaPlayer::asInterface(obj);
}      

原来以刚new的BpBinder对象为参数,调用IMediaPlayer::asInterface,还不快进去看其中的代码...,你以为你想进就进啊,你以为你是谁,告诉你没地方可进,代码中没看到这个函数,怎么办呢。只能看看IMedialayer的定义了。其定义中发现这么一行代码:

class IMediaPlayer: public IInterface
{
public:
    DECLARE_META_INTERFACE(MediaPlayer);
    ...
}


很显然这是一个宏,这个可以看看吧!

#define DECLARE_META_INTERFACE(INTERFACE)                               \
    static const String16 descriptor;                                   \
    static sp<I##INTERFACE> asInterface(const sp<IBinder>& obj);        \
    virtual const String16& getInterfaceDescriptor() const;             \
    I##INTERFACE();                                                     \
    virtual ~I##INTERFACE();  


我终于明白了你,原来在这儿定义了这个一直找寻的IMedaiPlayer::asInterface,老办法,还原啊!

    static const String16 descriptor;                                   
    static sp<IMediaPlayer> asInterface(const sp<IBinder>& obj);        
    virtual const String16& getInterfaceDescriptor() const;             
    IMediaPlayer();                                                     
    virtual ~IMediaPlayer();  


asInterface的定义是有了,实现呢? asInterface啊asInterface,你怎么这么喜欢折腾人呢? 原来还认为你的BpXXX很可爱,现在觉得有点狡猾了。没办法,谁叫我们是搞if esle的呢! 继续找啊,相信有定义就有实现。找啊找,找到一个有意思的东东IMPLEMENT_META_INTERFACE(INTERFACE, NAME),Search下,在IMediaPlayer发现了IMPLEMENT_META_INTERFACE(MediaPlayer, "android.media.IMediaPlayer");此宏定义如下:

#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME)                       \
    const String16 I##INTERFACE::descriptor(NAME);                      \
    const String16& I##INTERFACE::getInterfaceDescriptor() const {      \
        return I##INTERFACE::descriptor;                                \
    }                                                                   \
    sp<I##INTERFACE> I##INTERFACE::asInterface(const sp<IBinder>& obj)  \
    {                                                                   \
        sp<I##INTERFACE> intr;                                          \
        if (obj != NULL) {                                              \
            intr = static_cast<I##INTERFACE*>(                          \
                obj->queryLocalInterface(                               \
                        I##INTERFACE::descriptor).get());               \
            if (intr == NULL) {                                         \
                intr = new Bp##INTERFACE(obj);                          \
            }                                                           \
        }                                                               \
        return intr;                                                    \
    }                                                                   \
    I##INTERFACE::I##INTERFACE() { }                                    \
    I##INTERFACE::~I##INTERFACE() { }     


还原之后为:

  const String16 IMediaPlayer::descriptor("android.media.IMediaPlayer");                      
    const String16& IMediaPlayer::getInterfaceDescriptor() const {      
        return IMediaPlayer::descriptor;                                
    }                                                                   
    sp<IMediaPlayer> IMediaPlayer::asInterface(const sp<IBinder>& obj)  
    {                                                                   
        sp<IMediaPlayer> intr;                                          
        if (obj != NULL) {                                              
            intr = static_cast<IMediaPlayer*>(                          
                obj->queryLocalInterface(                               
                        IMediaPlayer::descriptor).get());               
            if (intr == NULL) {                                         
                intr = new BpMediaPlayer(obj);                          
            }                                                           
        }                                                               
        return intr;                                                    
    }                                                                   
    IMediaPlayer::IMediaPlayer() { }                                    
    IMediaPlayer::~IMediaPlayer() { }     


终于有asInterface的实现了,急切的心情看看他都做了些什么,单独拿出来品品吧!

    sp<IMediaPlayer> IMediaPlayer::asInterface(const sp<IBinder>& obj)  
    {                                                                   
        sp<IMediaPlayer> intr;                                          
        if (obj != NULL) {                                              
            intr = static_cast<IMediaPlayer*>(                          
                obj->queryLocalInterface(                               
                        IMediaPlayer::descriptor).get());               
            if (intr == NULL) {                                         
                intr = new BpMediaPlayer(obj); //第一次肯定执行这儿                         
            }                                                           
        }                                                               
        return intr;                                                    
    } 

看到intr = new BpMediaPlayer(obj),obj为刚创建的BpBinder, 看到没有,BpMediaPlayer(常说的BpXXX)以如此低调的方式登场,难怪我们一时找不到它。
 
至此,已经很明确了,interface_cast<IMediaPlayer>(reply.readStrongBinder());的结果是上面创建的BpMediaPlayer.大笑



7.2 看看new BpMediaPlayer都做了些什么?
还是让代码自己讲吧!

    BpMediaPlayer(const sp<IBinder>& impl)
        : BpInterface<IMediaPlayer>(impl)
    {
    }

impl为刚创建的BpBinder, 再看看BpInterface<IMediaPlayer>(impl)做了什么。

template<typename INTERFACE>
inline BpInterface<INTERFACE>::BpInterface(const sp<IBinder>& remote)
    : BpRefBase(remote)
{
}


我的乖乖,又是一个模板,继续还原:

inline BpInterface<IMediaPlayer>::BpInterface(const sp<IBinder>& remote)
    : BpRefBase(remote)
{
}


深入看看BpRefBase(remote)做了些什么?

BpRefBase::BpRefBase(const sp<IBinder>& o)
    : mRemote(o.get()), mRefs(NULL), mState(0)
{
    extendObjectLifetime(OBJECT_LIFETIME_WEAK);

    if (mRemote) {
        mRemote->incStrong(this);           // Removed on first IncStrong().
        mRefs = mRemote->createWeak(this);  // Held for our entire lifetime.
    }
}



Oh,my God, 把刚创建的BpBinder赋值给了BpRefBase中的mRemote,所以上面的图上说mRemote本质上是一个BpBinder.现在得到证实了。










                
<think>我们正在讨论Android Binder机制中的BnInterface和BpInterface。根据之前的对话历史,用户已经询问了BnInterface的作用,现在他们想了解BnInterface和BpInterface的具体区别。我们需要清晰地解释这两者的区别,包括它们的角色、位置、功能以及如何协作。 关键点: 1. BnInterface(Binder Native Interface)位于服务端,用于实现服务接口,处理来自客户端的请求。 2. BpInterface(Binder Proxy Interface)位于客户端,作为代理,将客户端的调用转换为Binder事务并发送给服务端。 我们参考了引用[1]中的内容:它提到了IMediaPlayer接口(继承自IInterface)以及BpRefBase。在Binder机制中,BpRefBase是BpInterface的基类,它持有一个IBinder对象(即Binder代理对象),通过这个IBinder对象来跨进程发送请求。 因此,我们需要从以下几个方面进行区分: 角色: - BnInterface:服务端本地对象,实现具体的服务功能。 - BpInterface:客户端代理对象,代表远程服务,将方法调用转换为IPC调用。 继承关系: - BnInterface 通常继承自 Binder 和 服务接口(例如 IMyService)。 - BpInterface 通常继承自 BpRefBase 和 服务接口(例如 IMyService)。 核心方法: - BnInterface: 实现 onTransact() 方法,用于接收客户端请求并分派到具体的服务方法。 - BpInterface: 实现服务接口的方法,在这些方法中,将参数打包成Parcel,通过 transact() 方法发送给Binder驱动。 存在位置: - BnInterface 存在于服务进程。 - BpInterface 存在于客户端进程。 协作过程: 当客户端调用BpInterface的方法时,BpInterface将方法调用(包括参数)序列化,通过transact()发送到Binder驱动,驱动将请求路由到服务端进程的BnInterface,BnInterface的onTransact()方法被调用,解析参数并调用真正的服务方法,然后将结果返回给客户端。 另外,同一个服务接口(例如 IMyService)会被两边使用: - 客户端:通过BpInterface(实现了IMyService)来调用远程服务。 - 服务端:通过BnInterface(实现了IMyService)来提供具体实现。 为了清晰,我们可以用代码示例(伪代码)说明: 假设我们有一个AIDL接口: ```java interface IMyService { int add(int a, int b); } ``` 自动生成的代码中会有: 1. BnMyService(BnInterface): ```java public abstract class BnMyService extends Binder implements IMyService { @Override protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) { switch (code) { case TRANSACTION_add: int a = data.readInt(); int b = data.readInt(); int result = this.add(a, b); // 调用服务端实现的add方法 reply.writeInt(result); return true; // ... } } } ``` 2. BpMyService(BpInterface): ```java public class BpMyService extends BpInterface<IMyService> implements IMyService { public BpMyService(IBinder remote) { super(remote); } @Override public int add(int a, int b) { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInt(a); data.writeInt(b); // 通过持有的IBinder对象(mRemote)发送事务 mRemote.transact(TRANSACTION_add, data, reply, 0); int result = reply.readInt(); data.recycle(); reply.recycle(); return result; } } ``` 总结区别表格: | 特性 | BnInterface | BpInterface | |--------------|----------------------------------|----------------------------------| | 角色 | 服务端实现 | 客户端代理 | | 所在进程 | 服务进程 | 客户端进程 | | 核心方法 | `onTransact()` | 服务接口方法(如`add()`) | | 继承 | `Binder` 和 服务接口 | `BpRefBase` 和 服务接口 | | 功能 | 处理请求,执行实际服务逻辑 | 打包请求,发送事务,接收结果 | | 与IBinder关系| 本身是IBinder(Binder对象) | 持有IBinder(Binder代理对象) | 注意:在同一个进程内调用时,为了效率,可能会直接调用而不经过Binder驱动(直接调用服务端对象的方法),但通常情况下,我们讨论的是跨进程的情况。 最后,我们按照要求生成相关问题。 </think> ### BnInterface与BpInterface在Android Binder机制中的区别 在Android Binder IPC机制中,**BnInterface**(Binder Native Interface)和**BpInterface**(Binder Proxy Interface)是协同工作的两个核心组件,分别位于服务端和客户端。它们的核心区别如下: #### 1. **角色定位** | 组件 | 角色 | 位置 | 功能描述 | |---------------|------------|----------|------------------------------| | **BnInterface** | 服务实现端 | 服务进程 | 接收并处理客户端请求 | | **BpInterface** | 客户端代理 | 调用进程 | 封装远程调用,发送请求到服务端 | #### 2. **核心功能对比** - **BnInterface**: - 实现`onTransact()`方法,处理事务请求 - 解析客户端发送的数据包(Parcel) - 执行实际的服务逻辑 - 将结果打包返回给客户端 ```java // 示例:服务端事务处理 protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) { switch (code) { case TRANSACTION_getData: int input = data.readInt(); int result = this.getData(input); // 实际业务逻辑 reply.writeInt(result); // 返回结果 return true; } } ``` - **BpInterface**: - 实现服务接口的代理方法 - 将方法调用转换为Binder事务 - 序列化参数并通过`transact()`发送请求 ```java // 示例:客户端代理调用 public int getData(int input) { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInt(input); mRemote.transact(TRANSACTION_getData, data, reply, 0); // 发送请求 int result = reply.readInt(); // 接收结果 return result; } ``` #### 3. **继承关系** - **BnInterface** 继承链: `BnXXX → Binder → IBinder` (例如:`BnMyService`继承自`Binder`) - **BpInterface** 继承链: `BpXXX → BpRefBase → IBinder` (例如:`BpMyService`通过`BpRefBase`持有`IBinder`代理对象)[^1] #### 4. **工作流程对比** ```mermaid graph LR A[客户端] -->|1. 调用代理方法| B(BpInterface) B -->|2. 打包参数| C[Binder驱动] C -->|3. 路由请求| D(BnInterface) D -->|4. 执行业务逻辑| E[服务实现] E -->|5. 返回结果| D D -->|6. 打包结果| C C -->|7. 传递结果| B B -->|8. 返回数据| A ``` #### 5. **关键差异总结** | 特性 | BnInterface | BpInterface | |---------------------|---------------------------------|---------------------------------| | **对象性质** | 服务实体(Binder对象) | 服务代理(Proxy对象) | | **IBinder关系** | 本身是IBinder实现 | 持有IBinder引用(mRemote) | | **线程模型** | 在Binder线程池执行 | 在调用方线程执行 | | **进程位置** | 服务端进程 | 客户端进程 | | **主要责任** | 请求处理和业务执行 | 请求封装和结果解析 | #### 6. **设计模式关联** - **代理模式**:BpInterface作为远程服务的本地代理 - **桥接模式**:通过IBinder接口连接代理和实现 - **模板方法**:`onTransact()`提供事务处理框架 > ⚡ **性能提示**:同进程调用时,Binder机制会优化为直接调用,跳过IPC开销[^1]。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值