通过MediaPlayer理解Binder的使用

理解Binder的使用是一件不容易的事,尤其由浅入深,本文参考Android深入浅出之Binder机制Android Binder设计与实现这两文章为基础,从Java层的MediaPlayer开始分析Client, Server ServiceManager!至于Binder的实现可以搜索CSDN老罗的文章,也可以看http://blog.csdn.net/bathinbreeze/article/details/8989431,涉及到kernel这里不讨论,本文只作为分析android代码记忆用

 

首先,先从JAVA层的mediaplayer类看起

(framework/base/media/java/android/media/MediaPlayer)

app调用MediaPlayer时,我们是先new 一个Mediaplayer,然后setDataSource,prepare,start


那这些函数在MediaPlayer是怎么实现的呢?我们看看MediaPlayer


不看hanlder,直接看native_setup


Native_setup是一个jni函数,也就是说mediaplayer的建立不在java层,而setDataSource,start这些函数也一样不在java


既然这样,我们就必须跑去jni层看看到底mediaplayer是怎么工作的

根据mediaplayer的包名,我可以锁定mediaplayer jnic文件

(framework/base/media/jni/android_media_MediaPlayer.cpp)

jni层里找到native_setupsetDataSource注册的原型


那看看这两个函数怎么实现



native_setup主要是创建了C++层的MediaPlayer对象


而setDatasource则是通过创建的mediaplayer对象,调用对象的setDataSource

 

从这里可以看出jni层实际上是通过调用C++mediaplayer实现javamediaplayer的功能。

 

为了进一步了解,我们跟踪到c++mediaplayer类,同样以初始化和setdatasource为例

framework/av/media/libmedia/mediaplayer.cpp




从初始化看,Mediaplayer初始化只是初始化一些变量

那我们看看setdatasource函数




在这里面我们发送好像跟service有关的东西,对了,这就是Mediaplayer的客户端(Mediaplayer类是binder中的client)通过BinderServiceManger获取Mediaplayer服务端(MediaPlayerServicebinder的 Server)实例,并调用服务端实例的函数!那Mediaplayer服务端在那里,servicemanager又是怎么一回事呢,我们继续往下分析,但这里不采取继续跟踪代码下去,我们先去了解Binder ServiceManagerMediaplayerSerice,从而了解bindermanagerserver,然后再回到这边!但是我们要记住有个IServiceManagerIBinderIMediaPlayerService这些类,等下我们就靠这些把ServiceManager,  Mediaplayer Server

Mediaplayer client贯通起来,从而建立起binder servicemanagerserverclient的使用流程

 

 

 

 

Binder ServiceManagerMediaplayer Server在系统开机时都被启动。

 

首先我们看看servicemanager

(framework/Native/cmds/ServiceManager/)



从这里可以看到SeviceManager打开了binder设备,并向binder发送命令,告诉binder成为binder manager,并进入循环。







而循环主要是通过控制读取或写入binder设备,等待请求到来,如果有有请求则对所读到的

内容进行解析,解析之后回调给svcmgr_handler


从代码binder_transaction_data里面code知,servicemanager分了SVC_MGR_GET_SERVICE

SVC_MGR_CHECK_SERVICESVC_MGR_ADD_SERVICESVC_MGR_LIST_SERVICES

几个消息

另外从代码中知道, addservice getservice都是从 svcinfolist增查,而svcinfo的结构如下

struct svcinfo 
{
    struct svcinfo *next;
    void *ptr; // service pointer
    struct binder_death death;
    int allow_isolated;
    unsigned len;
    uint16_t name[0]; // service名字
};
增加时,回复成功



而获取service时则需把引用填充如reply,最后发到binder里





而其中要注意的






要知道svcmgr_hanlde被赋值为0,在回调函数,遇到非0的都直接return -1,不做任何操作

 

附:




在这些命令中,最常用的是BC_TRANSACTION/BC_REPLY命令对,Binder数据通过这对命令发送给接收方。这对命令所承载的数 据包由结构体struct binder_transaction_data定义。Binder交互有同步和异步之分,利用binder_transaction_data中 flag域区分。如果flag域的TF_ONE_WAY位为1则为异步交互,即Client端发送完请求交互即结束, Server端不再返回BC_REPLY数据包;否则Server会返回BC_REPLY数据包,Client端必须等待接收完该数据包方才完成一次交 互。


写数据一样,其中最重要的消息是BR_TRANSACTION 或BR_REPLY,表明收到了一个格式为binder_transaction_data的请求数据包(BR_TRANSACTION)或返回数据包 (BR_REPLY)

收发都是 消息ID+消息数据(binder_transaction_data)




在android代码为数据接口binder_txn


其中其data在android表示为如下


Servicemanager就分析到这里,在这里没发现跟mediaplayer一点有关的东西,那我们去看看Mediaplayer Server

framework/av/Media/MediaServer/Main_mediaserver.cpp

在main函数中我们看到,创建了一个proc,获取了servicemanager,并初始化了MediaplayerService,并开启了线程池!在这里我们发现了跟media有关的MediaplayerService,暂时不理会,我们代码从第一个看起!

 

首先是ProcessState:self()



从代码中我们看出processstate构造函数初始化列表打开了binder设备,并向binder设备发送了两条命令,我们可以说processstate 记录着打开的binder设备,以便提供给后面提供操作。



代码的第二步是获取一个servicemanager对象,我们跟踪进去看他是怎么获取的!


首先通过processstate获取了servicemanagerIBinder对象,并转化为IServiceManager前面的MediaplayerClient也是这样获取哦),即获取了servicemanager对象

 

继续跟踪程序,看怎么获取IBinder对象和转化为IServiceManager

 

1.IBinder对象的获取



从代码可以看到,IBinder对象的获取实际上是new BpBinder(0);

 

BpBinder是什么呢?



BpBinder继承于IBinder,而IBinder实际是ServiceManager抽象出来的接口类,为Server提供接口操作binder,而BpBinder则是IBinder的实现,也可以说代理了Binder的操作( transact等)


2.IBinder转化为IServiceManager


从代码可以看出interface_cast 模版函数把IBinder转化成ISeriviceManager实际上调用的是IServiceManagerasInteface函数,那我跟踪到IServiceManager类看看



在IServiceManager类中没看到asInterface函数哦,但是有个DECLARE_META_INTERFACE的宏,我们往这个走下去,看能找到asInterface不!



果然,asInterface用连接的方式写在了宏里面,那我们看看是怎么转,在前面


我们是传入了IServiceManager.asInterface(new BpBinder(0));

asInterfaceIBinder转化成IserviceManager,确是

New BpServiceManager(new BpBinder(0));也就是把IBinder对象赋予了IServiceManager子类BpServiceManager


而BpServiceManager则是代理了IBinder的操作,

如果addService,调用了BpBinderIBinder)的transact函数,发送ADD_SERVICE_TRANSACTIONBinder

BpBinder


则通过IPCThreadState:self()transact发送数据给Binder

 

ServiceManager已经获得(通过new bpBinder0),并转化成BpSeriviceManager),

接着MediaplayerService把自己注册到ServiceManager里面





可以看到是调用BpServiceManageraddService(前面说到addService实际上就是通过new BpBinder(0)transact函数,而BpBinder则是通过IPCThreadStatetransact把数据发送给了binder),把自己注册给了ServiceManager,而ServiceManager也把他记录了起来

 



到这里我们就知道ServiceManagerMediaServer大概工作方式








从继承结构可以看出这是一个对象适配器模式,而不是代理模式,因为他们没有共同的父类,更多的是对象的适配,而IBinderBnBinder,和BpBinder才是代理模式,IServiceManagerBnServiceManagerBpServiceManger也是代理模式


void MediaPlayerService::instantiate() {
    defaultServiceManager()->addService(
            String16("media.player"), new MediaPlayerService());
}

 virtual status_t addService(const String16& name, const sp<IBinder>& service,
            bool allowIsolated = false)
    {
        Parcel data, reply;
        data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
        data.writeString16(name);
        data.writeStrongBinder(service);
        data.writeInt32(allowIsolated ? 1 : 0);
        status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
        return err == NO_ERROR ? reply.readExceptionCode() : err;
    }


 


addServiceMediaPlayerService传给了ServiceManagerBnMediaPlayerServiceonTransact则负责接收实现功能(进程中开启的IPCThreadState::self()->joinThreadPool();里面调用BBinder接收信息,而MediaplayerService的父类BnMediaPlayerService则实现接收信息处理onTransact


同时也开放了代理类,让客户端调用。




根据服务端,我们再回头看看 Media Client端,他是怎么通过ServiceManagerMediaServer进行通讯的

代码中,先获取了Mediaplayer server,跟踪进去看看做了什么


首先获取了serviceManager,这个是media server是一样的!

然后通过获取到的serviceManagergetService函数获取到mediaplayer servergetService其实跟addService是一样的,但是我们为了清楚,跟踪进去看看

打开BpManagerService类,


getService函数,实际上就是根据名字向binder发送CHECK_SERVICE_TRANSACTION命令,从而让serviceManager回应获取到Mediaplayer server



我们到ServiceManger那边看看他怎么解析这些数据,并返回了什么

int svcmgr_handler(struct binder_state *bs,
                   struct binder_txn *txn,
                   struct binder_io *msg, /** 是data */
                   struct binder_io *reply)
{
struct svcinfo *si;
    uint16_t *s;
    unsigned len;
    void *ptr;
    uint32_t strict_policy;
    int allow_isolated;

//    ALOGI("target=%p code=%d pid=%d uid=%d\n",
//         txn->target, txn->code, txn->sender_pid, txn->sender_euid);

    if (txn->target != svcmgr_handle)
        return -1;

    // Equivalent to Parcel::enforceInterface(), reading the RPC
    // header with the strict mode policy mask and the interface name.
    // Note that we ignore the strict_policy and don't propagate it
    // further (since we do no outbound RPCs anyway).
    strict_policy = bio_get_uint32(msg);
    s = bio_get_string16(msg, &len);
    if ((len != (sizeof(svcmgr_id) / 2)) ||
        memcmp(svcmgr_id, s, sizeof(svcmgr_id))) {
        fprintf(stderr,"invalid id %s\n", str8(s));
        return -1;
    }

    switch(txn->code) {
    case SVC_MGR_GET_SERVICE:
    case SVC_MGR_CHECK_SERVICE:
        s = bio_get_string16(msg, &len);
        ptr = do_find_service(bs, s, len, txn->sender_euid);
        if (!ptr)
            break;
	// 如果找到则填充ptr入reply
        bio_put_ref(reply, ptr);
        return 0;

.....
}
}

从代码看出是通过do_find_service找出Media.Player

void *do_find_service(struct binder_state *bs, uint16_t *s, unsigned len, unsigned uid)
{
    struct svcinfo *si;
    si = find_svc(s, len);

//    ALOGI("check_service('%s') ptr = %p\n", str8(s), si ? si->ptr : 0);
    if (si && si->ptr) {
        if (!si->allow_isolated) {
            // If this service doesn't allow access from isolated processes,
            // then check the uid to see if it is isolated.
            unsigned appid = uid % AID_USER;
            if (appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END) {
                return 0;
            }
        }
        return si->ptr;
    } else {
        return 0;
    }
}

看到返回的是SVCINFOptr,而这个就是MediaplayserService被写成flat_binder_object对象的引用

bio_put_ref(reply, ptr);
void bio_put_ref(struct binder_io *bio, void *ptr)
{
    struct binder_object *obj;

    if (ptr)
        obj = bio_alloc_obj(bio);
    else
        obj = bio_alloc(bio, sizeof(*obj));

    if (!obj)
        return;

    obj->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
    obj->type = BINDER_TYPE_HANDLE;
    obj->pointer = ptr;
    obj->cookie = 0;
}


flat_binder_object赋值给了binder_object,通过Binder发回给MediaClient

MediaClientBpMediaPlayerService)则

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

解出里面的BinderMediaPlayerService




ServiceManager那边返回的flat->type都为handle,所以获取Binder也是

通过*out = proc->getStrongProxyForHandle(flat->handle); 只不过这里的handler不是为0

相当于new BpBinder(flat->handle);





这样MediaClient获取获取到了mediaserver的对象,但获取到是binder对象,还需要转化成IMediaPlayerService这样,MediaClient才能跟MediaServer对话



从代码看出binder对象转化成了BpMediaPlayerService( new BpMediaPlayerService(binder))

我们看看BpMediaPlayerService



BpMediaPlayerServiceBpServiceManager类似,代理了bindermediaplayerservice的之间交互。




此时这里的mHandle不为0哦

用MediaPlayer ServerbinderMediaplayerService)发送 create命令,而MediaPlayerServiceMediaPlayerService继承BnMediaPlayerService继承BBinder继承IBinder)接收到create命令后



在BR_TRANSACTION回调给MediaplayerService(BPBinder)






创建了Mediaplayerclient

 

其他Mediaplayer client startsotp等函数都类似!

 

 

最后总结下binder server client servicemanager模式


第一步:通过binderservicemanager注册自己的service


第二步:client通过servicemanager获取server


第三步:获取到server后,client通过binder跟sserver进行通讯





  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值