安卓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
超強干貨來襲 云風專訪:近40年碼齡,通宵達旦的技術人生總結
以上是生活随笔為你收集整理的安卓MediaPlayer框架之Binder机制的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: BigDecimal 与double 转
- 下一篇: vs 本地调试(IIS)