通过BinderDriver和MediaPlayer通信的过程

下面看看客户端是如何获得服务的代理并和服务器端通信的。以MediaPlayer的业务函数解码解析播放一个网络视频的URL为例

android 驱动层怎么设置gpio android驱动深度开发视频教程_音视频

这里主要分析getMediaPlayerService,即客户端是如何向ServiceManager总管查询服务并获得代理的

android 驱动层怎么设置gpio android驱动深度开发视频教程_音视频_02

上图先获得BpServiceManager的代理,然后调用getService函数向服务总管ServiceManager查询名叫String16("media.player")的服务,其处于frameworks/base/libs/binder/IServiceManager.cpp中(仅展示部分代码)

android 驱动层怎么设置gpio android驱动深度开发视频教程_android_03

这里首先将请求打包成Parcel格式,然后调用remote->transact函数,前面我们分析过BpServiceManager::remote返回的就是new BpBinder(0),对应的句柄为ServiceManager,在frameworks/base/libs/binder/BpBinder.cpp中可以找到实现代码

android 驱动层怎么设置gpio android驱动深度开发视频教程_android 驱动层怎么设置gpio_04

最后调用IPCThreadStatetransact函数,在Android中ProcessState是客户端和服务器端公共的部分,作为Binder通信的基础,ProcessState是一个singleton类,每个进程只有一个对象,这个对象负责打开Binder驱动,建立线程池,让其进程里面的所有线程都能通过Binder通信

与之相关的是IPCThreadState,每个线程都有一个IPCThreadState实例登记在Linux线程的上下文附属数据中主要负责Binder的读取、写入和请求处理框架。IPCThreadState在构造的时候获取进程的ProcessState并记录在自己的成员变量中

IPCThreadState::transact中(部分代码)

android 驱动层怎么设置gpio android驱动深度开发视频教程_android 驱动层怎么设置gpio_05


android 驱动层怎么设置gpio android驱动深度开发视频教程_音视频_06

通过writeTransactionData函数来填充mOut结构体,mOut内容如下

android 驱动层怎么设置gpio android驱动深度开发视频教程_音视频_07

tr内容如下

android 驱动层怎么设置gpio android驱动深度开发视频教程_android_08

tr.data内容如下

android 驱动层怎么设置gpio android驱动深度开发视频教程_音视频_09


android 驱动层怎么设置gpio android驱动深度开发视频教程_音视频_10

waitForResponse函数是关键

android 驱动层怎么设置gpio android驱动深度开发视频教程_音视频_11


android 驱动层怎么设置gpio android驱动深度开发视频教程_android 驱动层怎么设置gpio_12

返回的是reply.readStrongBinder().在waitForResponse方法中,收到消息以后这个reply不为空,此时进入reply的ipcSetDataReference方法中,这个reply是Parcel对象,调用了Parcel的ipcSetDataReference方法将ServiceManager返回过来的数据设置到parcel对象中。waitForResponse()执行完BR_REPLY之后,便返回到IPCThreadState::transact()中;然后返回,到退回到Java层的ServiceManagerProxy.getService方法时,调用reply的readStrongBinder方法

android 驱动层怎么设置gpio android驱动深度开发视频教程_句柄_13


android 驱动层怎么设置gpio android驱动深度开发视频教程_句柄_14

这里的flat->typeBINDER_TYPE_HANDLE,所以调用ProcessState::getStrongProxyForHandle函数

android 驱动层怎么设置gpio android驱动深度开发视频教程_音视频_15

这里的handle就是ServiceManager内维护的MediaPlayerService对应的Binder句柄,这个ProcessState根据这个句柄新建了一个BpBinder,并将其保存起来,这样下次需要从ServiceManager请求获取相同句柄的时候就可以直接返回了

根据这个从getService中返回的BpBinder获得MediaPlayerService的代理

android 驱动层怎么设置gpio android驱动深度开发视频教程_android 驱动层怎么设置gpio_16

和前面的ServiceManager一样,调用IMediaPlayerService的asInterface宏函数,这样就获得了一个代理BpMediaPlayerService对象,它的remote为BpBinder(handle),这个handle就是向服务总管ServiceManager查询到的MediaPlayerServicer对应的Binder句柄

总结

1.在实际业务中,当MediaPlayer::setDataSource返回时,会创建一个与MediaPlayerService::Client对应的BpMediaPlayer,用于获取MediaPlayerService::Client的各项功能

2.MediaPlayer要想找到MediaPlayerService::Client必须MediaPlayerService向ServiceManager进行注册才可以,所以MediaPlayer必须先获取BpMediaPlayerService,然后通过BpMediaPlayerService的管理功能创建一个MediaPlayerService::Client

3.MediaPlayerService包含的功能不仅是Client,还有AudioOutput、AudioCache、MediaConfigClient功能。MediaPlayerService就是一个媒体服务的窗口(Driver类似一个场地,在场地内沟通好信息),MediaPlayerService把生意谈好,合同签回来,再根据合同上的要求安排不同的开发人员去做

创建播放器

在MediaPlayer的构造函数中,会预先注册一些播放器的Factory。很多ROM厂商如果要应用自己写的播放器,也需要有一个Factory

android 驱动层怎么设置gpio android驱动深度开发视频教程_android 驱动层怎么设置gpio_17


android 驱动层怎么设置gpio android驱动深度开发视频教程_学习_18

通过StagefrightPlayerFactory创建一个StagefrightPlayer(高版本中已经没有该播放器了)

android 驱动层怎么设置gpio android驱动深度开发视频教程_句柄_19

通过NuPlayerFactory可以创建一个NuPlayer

android 驱动层怎么设置gpio android驱动深度开发视频教程_句柄_20

这里没有直接创建一个NuPlayer,而是创建了一个NuPlayerDriver,实际上是在NuPlayerDriver的构造函数中创建了一个NuPlayer

建立StageFright层交互

前面建立的NuPlayer要和StageFright层进行交互,下图是它们两个的关系

android 驱动层怎么设置gpio android驱动深度开发视频教程_音视频_21

从上图可以看出StagefrightPlayer/StagefrightRecorder以及NuPlayer都属于MediaPlayerService层,源码libmediaplayerservice目录如下(没有StagefrightPlayer是因为版本问题)

android 驱动层怎么设置gpio android驱动深度开发视频教程_句柄_22

上面的文件在编译后会生成libmediaplayerservice.so文件,当要继续处理从MediaPlayer传过来的事件时,就需要到达libstagefright.so中,如AwesomePlayer、MediaExtractor、MediaMuxer、MediaBuffer、MediaSource、MediaCodec等,可以看出这些都是多媒体框架的核心部分,用于数据解析、解码

一个数据源会先分离出音视频数据,如果是视频流,通过OMX组件解码,如果是音频流,通过音频解码器解码,如AACDecoder、AC3Decoder等。解码完成后做音视频同步,最终将视频渲染到屏幕上,音频通过音频系统进行播放

android 驱动层怎么设置gpio android驱动深度开发视频教程_android_23