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类里。

安卓MediaPlayer框架之Binder机制的更多相关文章

  1. Android系统进程间通信Binder机制在应用程序框架层的Java接口源代码分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6642463 在前面几篇文章中,我们详细介绍了A ...

  2. Android Binder机制(一) Binder的设计和框架

    这是关于Android中Binder机制的一系列纯技术贴.花了一个多礼拜的时间,才终于将其整理完毕.行文于此,以做记录:也是将自己所得与大家分享.和以往一样,介绍Binder时,先讲解框架,然后再从设 ...

  3. 从mediaserver入手快速理解binder机制(最简单理解binder)【转】

    本文转载自;https://blog.csdn.net/u010164190/article/details/53015194 Android的binder机制提供一种进程间通信的方法,使一个进程可以 ...

  4. Android中的Binder机制的简要理解

    转载自:http://www.linuxidc.com/Linux/2012-07/66195.htm http://blog.csdn.net/sunxingzhesunjinbiao/articl ...

  5. Android 核心分析 之六 IPC框架分析 Binder,Service,Service manager

    IPC框架分析 Binder,Service,Service manager 我首先从宏观的角度观察Binder,Service,Service Manager,并阐述各自的概念.从Linux的概念空 ...

  6. Binder机制1---Binder原理介绍

    1.Binder通信机制介绍 这篇文章会先对照Binder机制与Linux的通信机制的区别,了解为什么Android会另起炉灶,採用Binder.接着,会依据Binder的机制,去理解什么是Servi ...

  7. Android Binder机制简单了解

    Binder -- 一种进程间通信(IPC)机制, 基于OpenBinder来实现 毫无疑问, 老罗的文章是不得不看的 Android进程间通信(IPC)机制Binder简要介绍和学习计划 浅谈Ser ...

  8. Binder机制,从Java到C (2. IPC in System Service :AMS)

    1.建立Activity和Service的IPC之前 在上一篇 Binder机制,从Java到C (1. IPC in Application Remote Service)  里面有说到Activi ...

  9. 深入理解Android IPC机制之Binder机制

    Binder是Android系统进程间通信(IPC)方式之一.Linux已经拥有的进程间通信IPC手段包括(Internet Process Connection): 管道(Pipe).信号(Sign ...

随机推荐

  1. git clone速度太慢的解决办法(亲测还有效)

    https://www.linuxidc.com/Linux/2019-05/158461.htm 1.查找域名对应的ip地址,并修改hosts文件 linuxidc@linuxidc:~/linux ...

  2. django 表操作

    添加表纪录 # Create your models here. class Book(models.Model): id = models.AutoField(primary_key=True) t ...

  3. EasyDSS高性能RTMP、HLS(m3u8)、HTTP-FLV、RTSP流媒体服务器的视频直播录像、检索、回放方案

    需求背景: 近期遇到客户反馈对于直播摄像机录像功能是有一定的需求点的,其实EasyDarwin团队早就研发出对应功能,只是用户对于产品没有足够了解,因此本篇将对录像功能来做一次介绍. 首先,录像就是对 ...

  4. 人工智能新编程语言-Gen

    MIT 的一个研究小组正努力让初学者更容易入门人工智能,同时也帮助专家进一步推进这个领域的发展. 在 PLDI 大会(Programming Language Design and Implement ...

  5. js 二叉树算法

    //生成二叉树 function binarySearchTree() { let Node = function(key) { this.key = key; this.left = null; t ...

  6. Java之变量和数据类型

    变量 什么是变量 变量就是初中的代数的概念.例如一个简单的方程,x,y都是变量 y=x+1 在Java中,变量分为两种:基本类型的变量和引用类型的变量 在Java中,变量必须先定义后使用,在定义变量的 ...

  7. Dubbo版本升级

    一.背景 早期内部使用的是当当网fork的Dubbox,由于现在Dubbo又开始重新维护,而且阿里将其捐献给了Apache,并成为了Apache的顶级项目.因此dubbo版本升级到2.7.1势在必行. ...

  8. Elasticsearch集群+kibana

    目录: 软件及环境准备 JDK安装配置 ElasticSearch安装及配置 启动ES集群 es常规操作 安装及配置ES前端图形化操作工具 kibana汉化及时区修改 ElasticSearch和ki ...

  9. 2、Maven的简介和配置

    1.下载Maven  apche-maven-3.5.2 2. 三.maven简介 1.基于Ant的构建工具,Ant有的功能Maven都有,额外添加了其他的功能 2.运行原理图 2.1本地仓库:计算机 ...

  10. java8新特性1--Lambda表达式

    一.Lambda表达式是什么? Lambda表达式有两个特点 一是匿名函数,二是可传递. 匿名函数的应用场景是 通常是在需要一个函数,但是又不想费神去命名一个函数的场合下使用Lambda表达式.lam ...