日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

安卓MediaPlayer框架之Binder机制

發(fā)布時間:2024/4/15 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 安卓MediaPlayer框架之Binder机制 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

  Binder簡介

  Binder是Android系統(tǒng)進程間通信的主要方式之一。

  1.在ASOP中,Binder使用傳統(tǒng)的C/S通信方式:即一個進程作為服務(wù)端提供諸如視音頻解封裝,解碼渲染,地址查詢等各種服務(wù),眾多進程作為客戶端向服務(wù)端發(fā)起請求,獲得所需的服務(wù)。

  2.面向?qū)ο蟮姆庋b模式:首先Binder是作為一個實體類存在于Server端,該對象擁有一系列的借口來實現(xiàn)對服務(wù)端的各種操作,而在諸多的Client端,都存在一個Binder入口,通往了特定的Server端,就像是Server端的Binder實體擁有許許多多的指針遍布于各個Client中,Client就通過這個指針實現(xiàn)了向服務(wù)端的請求。

  二、Binder結(jié)構(gòu)

  首先看一下安卓的整體架構(gòu),可其遍布于整個安卓系統(tǒng)中,自地向上形成了一個統(tǒng)一的接口:(轉(zhuǎn)載)

  當(dāng)然,Client和Service端都通過一個ServiceManager進行統(tǒng)一管理,具體通信模型如下:

  三、結(jié)合代碼講解

  當(dāng)然,要細(xì)說Binder機制可不是一朝一夕的事情,我們今天結(jié)合安卓MediaPlayer的native層代碼,來看看Binder是如何實現(xiàn)跨進程通信的。如果沒有這方面知識還是建議先去小補一下。附上類圖:

  我們知道MediaPlayer的java層代碼調(diào)用的就是再往下的native層C/C++代碼,其中setDataSource()函數(shù)作為開路先鋒帶動了往下的各個類,所以我們就抓住它來分析一下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機制獲取一個遠(yuǎn)程服務(wù)

  if (service != 0) {

  sp player(service->create(this, mAudioSessionId));//通過MediaPlayerService端創(chuàng)建了一個Client

  if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||

  (NO_ERROR != player->setDataSource(fd, offset, length))) {//調(diào)用Client的setDataSource()

  player.clear();

  }

  err = attachNewPlayer(player);

  }

  return err;

  }

  getMediaPlayerService()函數(shù):一眼望去,就是請求Service無疑了。MediaPlayer.cpp中并沒有這個函數(shù)的實現(xiàn)方法,所以我們?nèi)ニ母割怚MediaDeathNotify尋找,嘿,果然在這兒!

  //代碼碼目錄:/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端的請求服務(wù)了,通過調(diào)用defaultServiceManager()得到IServiceManager,通過調(diào)用IServiceManager的getService()函數(shù)來查詢“media.player”是否注冊,如果注冊則返回對應(yīng)的IBinder,留給Client進行通信。然后就是通過interface_cast將IBinder轉(zhuǎn)化為服務(wù)端IMediaPlayerService的指針返回。可是這個inteface_cast()是什么呢?是一個強制類型轉(zhuǎn)換嗎?不不不,一葉障目罷了,我們來看看它的定義:

  代碼目錄:frameworks/native/include/binder/IInterface.h

  template

  inline sp interface_cast(const sp& obj)

  {

  return INTERFACE::asInterface(obj);

  }

  好家伙,直接返回自身的,即IMediaPlayerService::asInteface(),我們繼續(xù)追,額,我就不貼代碼了,你會發(fā)現(xiàn)IMediaPlayerService中并沒有這個函數(shù)的定義,怎么回事兒?去父類看看!一對比就能發(fā)現(xiàn)蹊蹺了:

  /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中有這么一段奇怪的代碼段,不妨,仔細(xì)看一下,哦,原來是一對宏聲明和定義!而IMediaPlayerService里剛好有這兩個宏的調(diào)用!那么就見泰山了。我們將IMediaPlayerService置換進去,就能看到IBinder轉(zhuǎn)IMediaPlayerService的實現(xiàn)了!我就不再貼出了。

  好了扯遠(yuǎn)了,我們通過getDefaultService得到了一個注冊名為“mediapalyer"的服務(wù),并通過interface_cast轉(zhuǎn)換為一個IMediaPlayerService的指針返回。我們繼續(xù)往下看:

  sp player(service->create(this, mAudioSessionId));

  原來是調(diào)用IMediaPlayer的creat函數(shù),我們?nèi)タ纯?#xff1a;

  代碼目錄:/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轉(zhuǎn)化為binder接口,而沒有經(jīng)過ServiceManager這個中介,說明這是個匿名管道,只能在這兩個進程間進行通信。來看一下:

  // static

  sp IInterface::asBinder(const sp& iface)

  {

  if (iface == NULL) return NULL;

  return iface->onAsBinder();

  }

  template inline IBinder* BpInterface::onAsBinder() { return remote(); }

  remote()得到的就是遠(yuǎn)端的BpBinder。

  remote() ->transact(),這個函數(shù)要好好說道一下:

  1.BpBinder,BBinder,IBinder是安桌Binder機制的抽象,其中BpBinder不在這些繼承關(guān)系中。

  2.remote()是在BpRefBase的子類中實現(xiàn)的,返回的就是一個BpBinder。

  3.BpBinder的transact實現(xiàn),就是直接調(diào)用IPCThreadState::self()->transact()發(fā)送數(shù)據(jù)。

  4.Service端通過IPCThreadState接收到client的請求后,首先會調(diào)用BBinder的transact()方法。

  5.BBinder的transact方法又會調(diào)用子類實現(xiàn)的虛擬方法onTransact。這個虛擬方法是在BnXXXService中實現(xiàn)的

  所以,我們直接在BnMediaPlayerService中尋找onTransact()的CREAT實現(xiàn):

  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轉(zhuǎn)回了sp,然后調(diào)用了creat()方法,可是我們發(fā)現(xiàn)BnMediaPlayerService中只有一個onTransact()的實現(xiàn),所以這個creat()我們要去它的子類尋找,果然就在MediaPlayerService中:無錫人流醫(yī)院 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;

  }

  代碼簡單易懂,創(chuàng)建了它一個自身類Client并返回指針供遠(yuǎn)端調(diào)用,這個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機制獲取一個遠(yuǎn)程服務(wù)

  if (service != 0) {

  sp player(service->create(this, mAudioSessionId));//通過MediaPlayerService端創(chuàng)建了一個Client

  if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||

  (NO_ERROR != player->setDataSource(fd, offset, length))) {//調(diào)用Client的setDataSource()

  player.clear();

  }

  err = attachNewPlayer(player);

  }

  return err;

  }

  后面就沒啥說的了,直接調(diào)用Client的setDataSource進入了下一步處理。

  總結(jié)一下:我們發(fā)現(xiàn)native層的大部分類都是采用IXXX,BpXXX,BnXXX形式的。在MediaPlayer框架層,由IMediaPlayer,IMediaPlayerService,IMediaPlayerClient三大元老組成了基本框架,由IBinder,BBinder(準(zhǔn)確來說叫BnBinder比較合適),BpBinder將其粘合。

  我們發(fā)現(xiàn),IXXX里總是一些虛抽象函數(shù),不存在定義,由BpXXX和BnXXX繼承它,BpXXX作為Client端的代理類,發(fā)起服務(wù)的請求,服務(wù)的實現(xiàn)則統(tǒng)一放在BnXXX類里。

轉(zhuǎn)載于:https://www.cnblogs.com/djw12333/p/11096641.html

超強干貨來襲 云風(fēng)專訪:近40年碼齡,通宵達旦的技術(shù)人生

總結(jié)

以上是生活随笔為你收集整理的安卓MediaPlayer框架之Binder机制的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。