(一) 概述 android
android的binder機制提供一種進程間通訊的方法,使一個進程能夠以相似遠程過程調用的形式調用另外一個進程所提供的功能。binder機制在Java環境和C/C++環境都有提供。程序員
android的代碼中,與C/C++的binder包括一些類型和接口的定義和實現,相關的代碼在下面這幾個文件中:編程
frameworks\base\include\utils\IInterface.h
frameworks\base\include\utils\Binder.h
frameworks\base\include\utils\BpBinder.h
frameworks\base\include\utils\IBinder
frameworks\base\include\utils\Parcel.h
frameworks\base\include\utils\IPCThreadState.h
frameworks\base\include\utils\ProcessState.h
frameworks\base\libs\utils\Binder.cpp
frameworks\base\libs\utils\BpBinder.cpp
frameworks\base\libs\utils\IInterface.cpp
frameworks\base\libs\utils\IPCThreadState.cpp
frameworks\base\libs\utils\Parcel.cpp
frameworks\base\libs\utils\ProcessState.cpp
爲了瞭解這些類、接口之間的關係以及binder的實現機制,最好是結合一個例子來進行研究。我選擇的例子是android自帶的媒體播放器的實現。其媒體播放器的相關代碼在下面這些目錄中: frameworks\base\include\media
frameworks\base\media網絡
使用startUML的反向工程功能分析上面這些代碼,並進行了必定的整理以後,獲得下面這幅類圖(點擊可查看原尺寸圖片)。socket

android的媒體播放功能分紅兩部分,一部分是媒體播放應用,一部分是媒體播放服務(MediaServer,在系統啓動時由init所啓動,具可參考init.rc文件)。這兩部分分別跑在不一樣的進程中。媒體播放應用包括Java程序和部分C++代碼,媒體播放服務是C++代碼,而且須要調用外部模塊opencore來實現真正的媒體播放。媒體播放應用和媒體播放服務之間須要經過binder機制來進行相互調用,這些調用包括:函數
(1)媒體播放應用向媒體播放服務發控制指令
(2)媒體播放服務向媒體播放應用發事件通知(notify)字體
媒體播放服務對外提供多個接口,在上面得圖中包括其中的2個接口:IMediaService和IMediaPlayer,IMediaplayer用於建立和管理播放實例,而IMediaplayer接口則是播放接口,用於實現指定媒體文件的播放以及播放過程的控制。ui
上面的圖中還有媒體播放應用向媒體播放服務提供的1個接口:IMediaPlayerClient,用於接收notify。url
這些接口由於須要跨進程調用,所以須要用到binder機制。每一個接口包括兩部分實現,一部分是接口功能的真正實現(BnInterface),這部分運行在接口提供進程中;另外一部分是接口的proxy(BpInterface),這部分運行在調用接口的進程中。binder的做用就是讓這兩部分之間創建聯繫。下圖是整個播放器的一個概要說明。spa

媒體播放器比較複雜一些,總共實現了3個接口,不過要了解binder的機制,只須要研究其中一個接口就足夠了。在這裏選擇IMediaPlayerService接口來看一下。
IMediaPlayerService接口包括六個功能函數:create(url)、create(fd)、decode(url)、decode(fd)、createMediaRecord()、createMetadataRetriever()。在這裏不介紹這些函數是作什麼的,咱們只關注如何經過binder還提供這些函數接口。
(二) 接口定義
(1) 定義接口類
首先定義IMediaPlayerService類,這是一個接口類(C++的術語應該叫純虛類)。該接口類定義在文件frameworks\base\include\media\IMediaPlayerService.h。代碼以下:
class IMediaPlayerService: public IInterface
{
public:
DECLARE_META_INTERFACE(MediaPlayerService);
virtual sp<IMediaRecorder> createMediaRecorder(pid_t pid) = 0;
virtual sp<IMediaMetadataRetriever> createMetadataRetriever(pid_t pid) = 0;
virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client, const char* url) = 0;
virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client, int fd, int64_t offset, int64_t length) = 0;
virtual sp<IMemory> decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat) = 0;
virtual sp<IMemory> decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat) = 0;
};
|
|
能夠看到,在這個接口類中定義了IMediaPlayerService須要提供的6個函數接口,由於是接口類,因此定義爲純虛函數。須要注意這個接口類的名稱有嚴格要求,必須是以大寫字母I開始。 重點關注在這些函數前面的一個宏定義: DECLARE_META_INTERFACE(MediaPlayerService)。這個宏定義必需要有,其中封裝了實現binder所須要的一些類成員變量和成員函數經過這些成員函數能夠爲一個binder實現建立proxy。這個宏定義在問價frameworks\base\include\utils\IInterface.h裏,在後面還會講到。這個宏定義的參數必須是接口類的名稱去除字母I後剩下的部分。
另外說明一下,能夠看到接口類中所定義的函數的返回值都是sp<xxxx>的形式,看起來有點怪異。sp是android中定義的一個模板類,用於實現智能指針功能。sp<IMediaPlayer>就是IMediaPlayer的智能指針,能夠簡單地把它當作是標準C++中的指針定義即 IMediaPlayer* 便可。
(2) 定義和實現binder類
binder類包括兩個,一個是接口實現類,一個接口代理類。接口代理類繼承自BpInterface,接口實現類繼承自BnInterface。這兩個基類都是模板類,封裝了binder的進程間通訊機制,這樣使用者無需關注底層通訊實現細節。
對於IMediaPlayerService接口,其binder接口實現類爲BnMediaPlayerService,接口代理類爲BpMediaPlayerService。需注意這兩個類的名稱有嚴格要求,必須以Bn和Bp開頭,而且後面的部分必須是前面所定義的接口類的名稱去除字母'I’。好比前面所定義的接口類爲IMediaPlayerService,去除字母I後是MediaPlayerService,因此兩個binder類的名稱分別是BnMediaPlayerService和BpMediaPlayerService。爲何有這樣的要求?緣由就在前面提到的宏定義DECLARE_META_INTERFACE()和另外一個宏定義IMPLEMENT_META_INTERFACE()裏面。有興趣的話能夠去看一下,這兩個宏定義都在文件frameworks\base\include\utils\IInterface.h裏。
BpMediaPlayerService是一個最終實現類。定義而且實如今在文件frameworks\base\media\libmidia\IMediaPlayerService.cpp中。在看BpMediaPlayerService的代碼以前,先看一下在IMediaPlayerService.cpp文件的開始部分的一個枚舉定義:
enum {
CREATE_URL = IBinder::FIRST_CALL_TRANSACTION,
CREATE_FD,
DECODE_URL,
DECODE_FD,
CREATE_MEDIA_RECORDER,
CREATE_METADATA_RETRIEVER,
};
這些6個枚舉定義對應於IMediaPlayerService接口所提供的6個功能函數,能夠稱爲這些功能函數的功能代碼,用於在進程之間進行RPC是標識須要調用哪一個函數。若是不想定義這些枚舉值,在後面須要用到這些值的地方直接寫上1,2,3,4,5,6也是能夠的,不過……一個合適的程序員會這麼幹嘛?
下面看一下BpMediaPlayerService的代碼。
(3) BpMediaPlayerService代碼分析
class BpMediaPlayerService: public BpInterface<IMediaPlayerService>
{
public:
BpMediaPlayerService(const sp<IBinder>& impl)
: BpInterface<IMediaPlayerService>(impl)
{
}
virtual sp<IMediaMetadataRetriever> createMetadataRetriever(pid_t pid)
{
Parcel data, reply;
data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
data.writeInt32(pid);
remote()->transact(CREATE_METADATA_RETRIEVER, data, &reply);
return interface_cast<IMediaMetadataRetriever>(reply.readStrongBinder());
}
virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client, const char* url)
{
Parcel data, reply;
data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
data.writeInt32(pid);
data.writeStrongBinder(client->asBinder());
data.writeCString(url);
remote()->transact(CREATE_URL, data, &reply);
return interface_cast<IMediaPlayer>(reply.readStrongBinder());
}
virtual sp<IMediaRecorder> createMediaRecorder(pid_t pid)
{
Parcel data, reply;
data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
data.writeInt32(pid);
remote()->transact(CREATE_MEDIA_RECORDER, data, &reply);
return interface_cast<IMediaRecorder>(reply.readStrongBinder());
}
virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client, int fd, int64_t offset, int64_t length)
{
Parcel data, reply;
data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
data.writeInt32(pid);
data.writeStrongBinder(client->asBinder());
data.writeFileDescriptor(fd);
data.writeInt64(offset);
data.writeInt64(length);
remote()->transact(CREATE_FD, data, &reply);
return interface_cast<IMediaPlayer>(reply.readStrongBinder());
}
virtual sp<IMemory> decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)
{
Parcel data, reply;
data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
data.writeCString(url);
remote()->transact(DECODE_URL, data, &reply);
*pSampleRate = uint32_t(reply.readInt32());
*pNumChannels = reply.readInt32();
*pFormat = reply.readInt32();
return interface_cast<IMemory>(reply.readStrongBinder());
}
virtual sp<IMemory> decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)
{
Parcel data, reply;
data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
data.writeFileDescriptor(fd);
data.writeInt64(offset);
data.writeInt64(length);
remote()->transact(DECODE_FD, data, &reply);
*pSampleRate = uint32_t(reply.readInt32());
*pNumChannels = reply.readInt32();
*pFormat = reply.readInt32();
return interface_cast<IMemory>(reply.readStrongBinder());
}
};
首先能夠看到,這個類繼承自模板類BpInterface,指定類型爲接口類IMediaPlayerService。BpInterface模板類定義在文件IInterface.h。看一下BpInterface的定義就能夠發現,BpMediaPlayerService這樣定義了之後,事實上間接繼承了IMediaPlayerService,從而能夠提供IMediaPlayerService接口所定義的接口函數。BpMediaPlayerService須要實現這些接口函數。在一個簡單的構造函數以後,就是這些接口函數的實現。能夠看到,全部的接口函數的實現方法都是一致的,都是經過binder所提供的機制將參數仍給binder的實現類,並獲取返回值。這也就是這個類之因此成爲代理類的緣由。下面具體看一下一個接口函數。這裏選的是函數create(url)。
virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client, const char* url)
{
Parcel data, reply;
data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
data.writeInt32(pid);
data.writeStrongBinder(client->asBinder());
data.writeCString(url);
remote()->transact(CREATE_URL, data, &reply);
return interface_cast<IMediaPlayer>(reply.readStrongBinder());
}
這個接口函數的參數指定了一個URL,函數將爲這個URL建立一個播放器實例用於播放該URL。
函數首先定義了兩個局部變量data和reply,變量的類型都是Parcel。Parcel是一個專爲binder通訊的數據傳送而定義的類,該類提供了對多種類型的數據的封裝功能,同時提供多個數據讀取和寫入函數,用於多種類型的數據的寫入和讀取,支持的數據類型既包括簡單數據類型,也包括對象。這裏定義的變量data是用於封裝create()函數調用所須要的輸入參數,而reply則是用於封裝調用的返回數據(包括輸出參數的值和函數返回值)。
函數首先向data中寫入各類數據。第一個寫入的是接口的一個描述字符串,binder的實現類中會用這個字符串來對接口作驗證,防止調用錯誤。這個字符串也能夠不寫,若是不寫,在binder實現類中相應的也就不要作驗證了。跟在描述字符串後面寫入的是該接口函數所須要的各類的輸入參數。須要說明的是,Pacel提供一種先入先出的數據存儲方式,即數據的寫入順序和讀取順序必須嚴格一致,不然將會出錯。
完成數據寫入後,函數調用remote()->transact()用於完成binder通訊。transact()函數的第一個參數就是前面提到過的功能代碼。transact()的功能是將data中的數據傳給binder的實現類,函數調用結束後,reply中將包含返回數據。首先來看看remote()成員函數。前面講到過BpMediaPlayerService經過繼承BpInterface模板類間接繼承了IMediaPlayerService接口類,其實BpInterface類是一個有兩個父類的多重繼承子類,另外一個父類是BpRefbase(frameworks\base\include\utils\Binder.h)。remote()就是繼承自BpRefBase類的一個成員函數,該函數返回BpRefBase類中定義的一個私有屬性mRemote。mRemote是對IBinder接口類的子類BpBinder的一個對象的引用(參考前面的類關係圖)。transact()函數在IBinder接口類中定義(frameworks\base\include\utils\Binder.h),並在BpBinder類中實現(frameworks\base\include\utils\BpBinder.h、frameworks\base\libs\utils\BpBinder.cpp)。在transact()函數中將調用IPCThreadState類的transact()函數,並進而經過Lniux內核中的android共享內存驅動來實現進程間通訊。不過這些細節這裏就很少說了。在這裏BpBinder類對象是一個關鍵,是實現Binder代理的核心之一。BpBinder類能夠當作是一個通訊handle(相似於網絡編程中的socket),用於實現進程間通訊。接下來須要研究的是這個BpBinder類對象(即mRemote成員變量的值)是從哪裏來的。
回過頭來BpMediaPlayerService的構造函數(看前面的代碼)。該構造函數的參數是一個IBinder對象的引用。mRemote的值就是在這裏傳進來的這個對象。那麼這個對象又是怎麼來的呢?要搞清楚這一點就須要找到建立BpMediaPlayerService類的實例的代碼,這個代碼就就跟在該類的定義代碼的下面。繼續看IMediaPlayerService.cpp文件,在BpMediaPlayerService類定義的後面,是下面這樣一行代碼:
IMPLEMENT_META_INTERFACE(MediaPlayerService, "android.hardware.IMediaPlayerService");
這行代碼調用了一個宏定義IMPLEMENT_META_INTERFACE()。這個宏定義與前面提到過的DECLARE_META_INTERFACE()相呼應。看名字就知道,IMPLEMENT_META_INTERFACE()宏是對DECLARE_META_INTERFACE()所定義的成員函數的具體實現。這個宏的第一個參數與DECLARE_META_INTERFACE()的參數需徹底同樣,第二參數是接口的描述字符串(這個字符串前面也已經講到過了)。描述字符串不重要,重要的是宏裏面定義的一個靜態成員函數asInterface()。BpMediaPlayerService的類實例是在IMediaPlayerService的靜態成員函數asInterface()中建立的,在IInterface.h中定義了一個內聯函數interface_cast(),對這個成員函數進行了封裝。經過看代碼容易知道,BpMediaPlayerService的構造函數的參數是經過interface_cast()的參數傳進來的。
好,下面就該看看這個interface_cast()是在哪裏調用的,它的參數究竟是什麼。找到frameworks\base\media\libmedia\mediaplayer.cpp文件,其中的MediaPlayer::getMediaPlayerService()的實現代碼:
const sp<IMediaPlayerService>& MediaPlayer::getMediaPlayerService()
{
Mutex::Autolock _l(sServiceLock);
if (sMediaPlayerService.get() == 0) {
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder;
do {
binder = sm->getService(String16("media.player"));
if (binder != 0)
break;
LOGW("MediaPlayerService not published, waiting...");
usleep(500000); // 0.5 s
} while(true);
if (sDeathNotifier == NULL) {
sDeathNotifier = new DeathNotifier();
}
binder->linkToDeath(sDeathNotifier);
sMediaPlayerService = interface_cast<IMediaPlayerService>(binder);
}
LOGE_IF(sMediaPlayerService==0, "no MediaPlayerService!?");
return sMediaPlayerService;
}
看一下上面這段代碼中的紅色字體部分。結合前面的分析,可知BpBinder類的對象實例是從android的服務管理器的getService()函數中獲取,進一步追進去,會發現下面這樣一段代碼:
{
Parcel data, reply;
data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
data.writeString16(name);
remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply);
return reply.readStrongBinder();
}
Android的服務管理器是一個單獨的進程,也向外提供接口。這段代碼的含義,是經過Android的服務管理器的接口代理,請求調用服務管理器的checkService()接口函數,查找指定的服務(上面就是查找media.player服務),查找成功後返回一個BpBinder類的對象實例,用於供IMediaPlayerService代理使用。這個對象BpBinder是在Parcel::readStrongBinder()函數裏面建立的。那麼究竟是怎麼建立出來的呢?在這裏沒有必要追到ServiceManager的實現代碼裏去,畢竟咱們只是想知道BpBinder的對象是如何建立的,咱們能夠換一個例子來看。回到前面的BpMediaPlayerService::create()函數的實現,是否是很眼熟。沒錯,在那個函數裏也建立了一個BpBinder類對象,那個對象是是給IMediaPlayer接口代理使用的。雖然接口不一樣,可是建立原理是同樣的。咱們繼續,下面該到binder的另外一個類——實現類的代碼了。
(3) BnMediaPlayerService代碼分析
BnMediaPlayerService類的定義在文件frameworks\base\include\media\IMediaPlayService.h,實現則與BpMediaPlayerService同樣是在文件frameworks\base\media\libmidia\IMediaPlayerService.cpp中。類定義的代碼以下:
class BnMediaPlayerService: public BnInterface<IMediaPlayerService>
{
public:
virtual status_t onTransact( uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags = 0);
};
這個類繼承自BnInterface模板類,約束類型爲IMediaPlayerService。看一下BnInterface模板類的定義(IInterface.h)就能夠知道,BnMediaPlayerService間接繼承了IMediaPlayerService接口類。不過BnInterface類並無實現IMediaPlayerService所定義的6個接口函數,所以BnInterface仍是一個純虛類。這些接口須要在BnMediaPlayerService的子類中真正實現,這個子類就是MediaPlayerService(frameworks\base\media\libmidiaservice\MediaPlayerService.h,frameworks\base\media\libmidiaservice\MediaPlayerService.cpp)。在BnMediaPlayerService的成員函數onTransact()中,須要調用這6個接口函數。BnMediaPlayerService中主要就是定義並實現了onTransact()函數。當在代理那邊調用了transact()函數後,這邊的onTransact()函數就會被調用。BnMediaPlayerService的實現代碼以下:
#define CHECK_INTERFACE(interface, data, reply) \
do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
LOGW("Call incorrectly routed to " #interface); \
return PERMISSION_DENIED; \
} } while (0)
status_t BnMediaPlayerService::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch(code) {
case CREATE_URL: {
CHECK_INTERFACE(IMediaPlayerService, data, reply);
pid_t pid = data.readInt32();
sp<IMediaPlayerClient> client = interface_cast<IMediaPlayerClient>(data.readStrongBinder());
const char* url = data.readCString();
sp<IMediaPlayer> player = create(pid, client, url);
reply->writeStrongBinder(player->asBinder());
return NO_ERROR;
} break;
case CREATE_FD: {
CHECK_INTERFACE(IMediaPlayerService, data, reply);
pid_t pid = data.readInt32();
sp<IMediaPlayerClient> client = interface_cast<IMediaPlayerClient>(data.readStrongBinder());
int fd = dup(data.readFileDescriptor());
int64_t offset = data.readInt64();
int64_t length = data.readInt64();
sp<IMediaPlayer> player = create(pid, client, fd, offset, length);
reply->writeStrongBinder(player->asBinder());
return NO_ERROR;
} break;
case DECODE_URL: {
CHECK_INTERFACE(IMediaPlayerService, data, reply);
const char* url = data.readCString();
uint32_t sampleRate;
int numChannels;
int format;
sp<IMemory> player = decode(url, &sampleRate, &numChannels, &format);
reply->writeInt32(sampleRate);
reply->writeInt32(numChannels);
reply->writeInt32(format);
reply->writeStrongBinder(player->asBinder());
return NO_ERROR;
} break;
case DECODE_FD: {
CHECK_INTERFACE(IMediaPlayerService, data, reply);
int fd = dup(data.readFileDescriptor());
int64_t offset = data.readInt64();
int64_t length = data.readInt64();
uint32_t sampleRate;
int numChannels;
int format;
sp<IMemory> player = decode(fd, offset, length, &sampleRate, &numChannels, &format);
reply->writeInt32(sampleRate);
reply->writeInt32(numChannels);
reply->writeInt32(format);
reply->writeStrongBinder(player->asBinder());
return NO_ERROR;
} break;
case CREATE_MEDIA_RECORDER: {
CHECK_INTERFACE(IMediaPlayerService, data, reply);
pid_t pid = data.readInt32();
sp<IMediaRecorder> recorder = createMediaRecorder(pid);
reply->writeStrongBinder(recorder->asBinder());
return NO_ERROR;
} break;
case CREATE_METADATA_RETRIEVER: {
CHECK_INTERFACE(IMediaPlayerService, data, reply);
pid_t pid = data.readInt32();
sp<IMediaMetadataRetriever> retriever = createMetadataRetriever(pid);
reply->writeStrongBinder(retriever->asBinder());
return NO_ERROR;
} break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
}
首先是一個宏定義CHECK_INTERFACE(),這個宏定義的做用是檢查接口的描述字符串,這個前面也提到過,不需細說。而後就是onTrasact()函數的實現。這個函數的結構也很簡單,就是根據參數code的值分別執行不一樣的功能調用。code的取值就是前面提到過的接口功能代碼。函數的參數除了code,還包括Parcel類的兩個對象data和reply,分別用於傳送輸入參數和返回數據,與transact()函數的參數相對應。還有一個參數flag在這裏用不上,不討論。對應咱們前面所選擇的接口函數的例子create(url),看看這邊對應的實現:
case CREATE_URL: {
CHECK_INTERFACE(IMediaPlayerService, data, reply);
pid_t pid = data.readInt32();
sp<IMediaPlayerClient> client = interface_cast<IMediaPlayerClient>(data.readStrongBinder());
const char* url = data.readCString();
sp<IMediaPlayer> player = create(pid, client, url);
reply->writeStrongBinder(player->asBinder());
return NO_ERROR;
}
首先是從data對象中依次取出各項輸入參數,而後調用接口函數create()(將在子類MediaPlayerService中實現),最後向reply中寫入返回數據。這個函數返回後,代理那邊的transact()也會跟着返回。
那麼onTransact()函數是怎麼被調用的呢?經過查看BnInterface模板類的定義能夠看到,這個類也是一個多重繼承類,另外一個父類是BBinder(frameworks\base\include\utils\Binder.h,frameworks\base\libs\utils\Binder.cpp)。BBinder類繼承自IBinder,也實現了transact()函數,在這個函數中調用onTransact()函數。而BBinder對象的transact()函數則是在IPCThreadState類的executeCommand()成員函數中調用的。這已經涉及到較底層的實現,在這裏再也不多說。
上面這部分代碼還與前面提到過的BpBinder對象的建立有關係。看其中的紅色字體部分,經過create()函數調用會建立一個IMediaPlayer接口類的子類的對象,這個對象實際上是MediaPlayerService::Client類(能夠看一下MediaPlayerService的定義)的對象實例,而MediaPlayerService::Client類是繼承自BnMediaPlayer類的,與BnMediaPlayerService類相似,BnMediaPlayer其實也是一個binder實現類(是BBinder的子類,進而也是IBinder的子類)。在上述代碼中,經過Parcel的writeStrongBinder()函數將這個對象寫入reply,而在代理側,經過Parcel的readStrongBinder()函數讀取則能夠獲得一個BpBinder的對象。至於類的具體建立過程已經封裝在Parcel類的定義中,這裏就再也不多說了。
(4) 接口功能的真正實現
到這裏兩個binder類就已經定義完了,下面就是IMediaPlayerService接口函數的真正實現。前面已經說過這些函數在類MediaPlayerService中實現。這個類繼承自BnMediaPlayerService,也間接地繼承了IMediaPlayerService接口類定義的6個功能函數,只須要按照正常方式實現這6個功能函數便可,固然爲了實現這6個函數就須要其它一大堆的東西,不過這些具體的實現方法已經與binder機制無關,再也不多說。
在MediaPlayerService類中定義了一個靜態函數instantiate(),在這個函數中建立MediaPlayerService的對象實例,並將這個對象註冊到服務管理器中。這樣須要使用的時候就能夠從服務管理器獲取IMediaPlayerService的代理對象。這個instantiate()是在MediaServer程序的main()函數中調用的。
void MediaPlayerService::instantiate() {
defaultServiceManager()->addService(
String16("media.player"), new MediaPlayerService());
}
(三) 總結一下
說了這麼多,總結一下。下圖是binder機制的層次模型。
若是一個服務須要經過binder機制對外提供跨進程的接口,須要作下面這些事情。 (1) 第一步,須要爲這個接口定義一個繼承自IInterface的接口類,假設叫作IMyService。 (2) 第二步,須要定義兩個binder類,其中一個是代理類BpMyService,需繼承自BpInterface;另外一個是實現類BnMyService,需繼承自BnInterface。 (3) 第三步,定義BnMyService的子類,這個子類能夠是任何名字,好比就叫MyService,在其中真正實現接口所提供的各個函數。 (4) 第四步,建立MyService的實例,註冊到服務管理器(如IMediaPlayerService),也能夠在其它接口的函數中建立(如上面的IMediaPlayer)。