安卓MediaPlayer框架之Binder机制
Binder简介
Binder是Android系统进程间通信的主要方式之一。
1.在ASOP中,Binder使用传统的C/S通信方式:即一个进程作为服务端提供诸如视音频解封装,解码渲染,地址查询等各种服务,众多进程作为客户端向服务端发起请求,获得所需的服务。
2.面向对象的封装模式:首先Binder是作为一个实体类存在于Server端,该对象拥有一系列的借口来实现对服务端的各种操作,而在诸多的Client端,都存在一个Binder入口,通往了特定的Server端,就像是Server端的Binder实体拥有许许多多的指针遍布于各个Client中,Client就通过这个指针实现了向服务端的请求。
二、Binder结构
首先看一下安卓的整体架构,可其遍布于整个安卓系统中,自地向上形成了一个统一的接口:(转载)
当然,Client和Service端都通过一个ServiceManager进行统一管理,具体通信模型如下:
三、结合代码讲解
当然,要细说Binder机制可不是一朝一夕的事情,我们今天结合安卓MediaPlayer的native层代码,来看看Binder是如何实现跨进程通信的。如果没有这方面知识还是建议先去小补一下。附上类图:
我们知道MediaPlayer的java层代码调用的就是再往下的native层C/C++代码,其中setDataSource()函数作为开路先锋带动了往下的各个类,所以我们就抓住它来分析一下Binder机制。直接看MediaPlayer.cpp的setDataSource()代码吧。
//代码目录:/frameworks/av/media/libmedia/mediaplayer.cpp
status_t MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length)
{
ALOGV("setDataSource(%d, %" PRId64 ", %" PRId64 ")", fd, offset, length);
status_t err = UNKNOWN_ERROR;
const sp service(getMediaPlayerService());//通过IPC机制获取一个远程服务
if (service != 0) {
sp player(service->create(this, mAudioSessionId));//通过MediaPlayerService端创建了一个Client
if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
(NO_ERROR != player->setDataSource(fd, offset, length))) {//调用Client的setDataSource()
player.clear();
}
err = attachNewPlayer(player);
}
return err;
}
getMediaPlayerService()函数:一眼望去,就是请求Service无疑了。MediaPlayer.cpp中并没有这个函数的实现方法,所以我们去他的父类IMediaDeathNotify寻找,嘿,果然在这儿!
//代码码目录:/frameworks/av/media/libmedia/IMediaDeathNotifier.cpp
/*static*/const sp
IMediaDeathNotifier::getMediaPlayerService()
{
ALOGV("getMediaPlayerService");
Mutex::Autolock _l(sServiceLock);
if (sMediaPlayerService == 0) {
sp sm = defaultServiceManager();
sp binder;
do {
binder = sm->getService(String16("media.player"));
if (binder != 0) {
break;
}
ALOGW("Media player service not published, waiting...");
usleep(500000); // 0.5 s
} while (true);
if (sDeathNotifier == NULL) {
sDeathNotifier = new DeathNotifier();
}
binder->linkToDeath(sDeathNotifier);
sMediaPlayerService = interface_cast(binder);
}
ALOGE_IF(sMediaPlayerService == 0, "no media player service!?");
return sMediaPlayerService;
}
这段代码就是Client端的请求服务了,通过调用defaultServiceManager()得到IServiceManager,通过调用IServiceManager的getService()函数来查询“media.player”是否注册,如果注册则返回对应的IBinder,留给Client进行通信。然后就是通过interface_cast将IBinder转化为服务端IMediaPlayerService的指针返回。可是这个inteface_cast()是什么呢?是一个强制类型转换吗?不不不,一叶障目罢了,我们来看看它的定义:
代码目录:frameworks/native/include/binder/IInterface.h
template
inline sp interface_cast(const sp& obj)
{
return INTERFACE::asInterface(obj);
}
好家伙,直接返回自身的,即IMediaPlayerService::asInteface(),我们继续追,额,我就不贴代码了,你会发现IMediaPlayerService中并没有这个函数的定义,怎么回事儿?去父类看看!一对比就能发现蹊跷了:
/frameworks/native/include/binder/IInterface.h
// ----------------------------------------------------------------------
#define DECLARE_META_INTERFACE(INTERFACE) \
static const ::android::String16 descriptor; \
static ::android::sp asInterface( \
const ::android::sp<::android::IBinder>& obj); \
virtual const ::android::String16& getInterfaceDescriptor() const; \
I##INTERFACE(); \
virtual ~I##INTERFACE(); \
#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME) \
const ::android::String16 I##INTERFACE::descriptor(NAME); \
const ::android::String16& \
I##INTERFACE::getInterfaceDescriptor() const { \
return I##INTERFACE::descriptor; \
} \
::android::sp I##INTERFACE::asInterface( \
const ::android::sp<::android::IBinder>& obj) \
{ \
::android::sp intr; \
if (obj != NULL) { \
intr = static_cast( \
obj->queryLocalInterface( \
I##INTERFACE::descriptor).get()); \
if (intr == NULL) { \
intr = new Bp##INTERFACE(obj); \
} \
} \
return intr; \
} \
I##INTERFACE::I##INTERFACE() { } \
I##INTERFACE::~I##INTERFACE() { } \
#define CHECK_INTERFACE(interface, data, reply) \
if (!(data).checkInterface(this)) { return PERMISSION_DENIED; } \
IInterface中有这么一段奇怪的代码段,不妨,仔细看一下,哦,原来是一对宏声明和定义!而IMediaPlayerService里刚好有这两个宏的调用!那么就见泰山了。我们将IMediaPlayerService置换进去,就能看到IBinder转IMediaPlayerService的实现了!我就不再贴出了。
好了扯远了,我们通过getDefaultService得到了一个注册名为“mediapalyer"的服务,并通过interface_cast转换为一个IMediaPlayerService的指针返回。我们继续往下看:
sp player(service->create(this, mAudioSessionId));
原来是调用IMediaPlayer的creat函数,我们去看看:
代码目录:/frameworks/av/media/libmedia/IMediaPlayerService.cpp
virtual sp create(
const sp& client, audio_session_t audioSessionId) {
Parcel data, reply;
data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
data.writeStrongBinder(IInterface::asBinder(client));
data.writeInt32(audioSessionId);
remote()->transact(CREATE, data, &reply);
return interface_cast(reply.readStrongBinder());
}
asBinder()是直接将client转化为binder接口,而没有经过ServiceManager这个中介,说明这是个匿名管道,只能在这两个进程间进行通信。来看一下:
// static
sp IInterface::asBinder(const sp& iface)
{
if (iface == NULL) return NULL;
return iface->onAsBinder();
}
template inline IBinder* BpInterface::onAsBinder() { return remote(); }
remote()得到的就是远端的BpBinder。
remote() ->transact(),这个函数要好好说道一下:
1.BpBinder,BBinder,IBinder是安桌Binder机制的抽象,其中BpBinder不在这些继承关系中。
2.remote()是在BpRefBase的子类中实现的,返回的就是一个BpBinder。
3.BpBinder的transact实现,就是直接调用IPCThreadState::self()->transact()发送数据。
4.Service端通过IPCThreadState接收到client的请求后,首先会调用BBinder的transact()方法。
5.BBinder的transact方法又会调用子类实现的虚拟方法onTransact。这个虚拟方法是在BnXXXService中实现的
所以,我们直接在BnMediaPlayerService中寻找onTransact()的CREAT实现:
xref: /frameworks/av/media/libmedia/IMediaPlayerService.cpp
status_t BnMediaPlayerService::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch (code) {
case CREATE: {
CHECK_INTERFACE(IMediaPlayerService, data, reply);
sp client =
interface_cast(data.readStrongBinder());
audio_session_t audioSessionId = (audio_session_t) data.readInt32();
sp player = create(client, audioSessionId);
reply->writeStrongBinder(IInterface::asBinder(player));
return NO_ERROR;
} break;
...}
}
首先又将BpBinder转回了sp,然后调用了creat()方法,可是我们发现BnMediaPlayerService中只有一个onTransact()的实现,所以这个creat()我们要去它的子类寻找,果然就在MediaPlayerService中:无锡人流医院 http://xmobile.wxbhnk120.com/
sp MediaPlayerService::create(const sp& client,
audio_session_t audioSessionId)
{
pid_t pid = IPCThreadState::self()->getCallingPid();
int32_t connId = android_atomic_inc(&mNextConnId);
sp c = new Client(
this, pid, connId, client, audioSessionId,
IPCThreadState::self()->getCallingUid());
ALOGD("Create new client(%d) from pid %d, uid %d, ", connId, pid,
IPCThreadState::self()->getCallingUid());
wp w = c;
{
Mutex::Autolock lock(mLock);
mClients.add(w);
}
return c;
}
代码简单易懂,创建了它一个自身类Client并返回指针供远端调用,这个Client包含了上层java的大部分接口。好了,回到我们的开始地方:
//代码目录:/frameworks/av/media/libmedia/mediaplayer.cpp
status_t MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length)
{
ALOGV("setDataSource(%d, %" PRId64 ", %" PRId64 ")", fd, offset, length);
status_t err = UNKNOWN_ERROR;
const sp service(getMediaPlayerService());//通过IPC机制获取一个远程服务
if (service != 0) {
sp player(service->create(this, mAudioSessionId));//通过MediaPlayerService端创建了一个Client
if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
(NO_ERROR != player->setDataSource(fd, offset, length))) {//调用Client的setDataSource()
player.clear();
}
err = attachNewPlayer(player);
}
return err;
}
后面就没啥说的了,直接调用Client的setDataSource进入了下一步处理。
总结一下:我们发现native层的大部分类都是采用IXXX,BpXXX,BnXXX形式的。在MediaPlayer框架层,由IMediaPlayer,IMediaPlayerService,IMediaPlayerClient三大元老组成了基本框架,由IBinder,BBinder(准确来说叫BnBinder比较合适),BpBinder将其粘合。
我们发现,IXXX里总是一些虚抽象函数,不存在定义,由BpXXX和BnXXX继承它,BpXXX作为Client端的代理类,发起服务的请求,服务的实现则统一放在BnXXX类里。
转载于:https://www.cnblogs.com/djw12333/p/11096641.html
安卓MediaPlayer框架之Binder机制相关推荐
- 安卓binder机制浅析
Binder机制是android系统中跨进程通信的重要手段.其中,Service与Activity的交互通信使用到了这一机制.为此,我写了service的小案例,以此来方便更好地理解binder通信机 ...
- Binder机制(一)
binder的介绍: 由于不同的进程不可以直接互相访问,所以需要一些机制来确保进程间能够通信,在linxu中,有以下几种: 1.管道(Pipe)及有名管道(named pipe):管道可用于具有亲缘关 ...
- binder 从c到java_Android系统进程间通信Binder机制在应用程序框架层的Java接口源代码分析...
在前面几篇文章中,我们详细介绍了Android系统进程间通信机制Binder的原理,并且深入分析了系统提供的Binder运行库和驱动程序的源代码.细心的读者会发现,这几篇文章分析的Binder接口都是 ...
- android binder机制分析 以MediaPlayer为例子
(一) 概述 android的binder机制提供一种进程间通信的方法,使不同一个进程可以以类 似远程过程调用的形式调用另一个进程所提供的功能.binder机制在Java环境和 C/C++环境都有提供 ...
- Android - Binder机制 - Binder框架总结
以下几篇文章是较深入分析binder机制. 目录 1. Android - Binder机制 - ServiceManager 2. Android - Binder机制 - 普通service注册 ...
- 安卓MediaPlayer源码跟读解析
简介: 安卓通过MediaPlayer这个类提供了一整套接口呈现给给客户实现视音频的播放.可是凡事必究其根,我们今天就来看看安卓的MediaPlayer框架(基于Android 8.0)究竟是怎么实现 ...
- service层中有某个事物要立马提交_硬货你要的,binder机制来了
欢迎关注专栏:里面定期分享Android和Flutter架构技术知识点及解析,还会不断更新的BATJ面试专题,欢迎大家前来探讨交流,如有好的文章也欢迎投稿. Android高级进阶zhuanlan. ...
- 从mediaserver入手快速理解binder机制(最简单理解binder)
(一) 概述 Android的binder机制提供一种进程间通信的方法,使一个进程可以以类似远程过程调用的形式调用另一个进程所提供的功能.binder机制在Java环境和C/C++环境都有提供. ...
- Android Binder机制(1):Binder架构分析
从这篇博客开始,将进入Binder机制的分析系列,顺序是先讲解Binder机制的框架,理解了整体思想后,再深入分析各层的细节实现,最后会实现一个自己的本地服务. 1.Binder的历史 BeOS是Be ...
最新文章
- 数字图像处理3:取样和量化
- 《Adobe Illustrator CS4中文版经典教程》目录—导读
- http post,get,put,delete区别(收集整理)
- ORACLE和MYSQL函数
- Go语言学习(七)-----练练笔之递归
- 阿里云人脸识别公测使用说明
- 计算机名生成,如何让输出的文本名字自动生成计算机名字?
- @Resource注解使用详解
- mapxtreme java 版本分布式部署。自己的应用和mapxtreme渲染器不在同一台机器上
- 寒心!一个开发者就这样离开了!
- 网易云音乐NCM格式转化为mp3
- ORACLE临时表空间总结
- 最是人间四月天,细雨点洒樱花前
- 电驴emule使用教程
- opcode php 5.4,为PHP5.4开启Zend OPCode缓存
- FME数据处理04:面自相交拓扑检查
- 大数据 - 指标 - 流量
- METHODS FOR NON-LINEAR LEAST SQUARES PROBLEMS 翻译(六)
- 2020年4月TIOBE语言排行榜-你知道少儿编程语言Scratch吗
- Java开发技巧!java语言程序设计第四版答案