android的binder機制研究二

轉載:android的binder機制研究(C++部分)
2010年10月16日 星期六 14:31

http://kahweh.blog.sohu.com/160696746.html

(一) 概述   

    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的反向工程功能分析上面這些代碼,並進行了一定的整理之後,得到下面這幅類圖(點擊可查看原尺寸圖片)。

 

   android的媒體播放功能分成兩部分,一部分是媒體播放應用,一部分是媒體播放服務(MediaServer,在系統啓動時由init所啓動,具可參 考init.rc文件)。這兩部分分別跑在不同的進程中。媒體播放應用包括Java程序和部分C++代碼,媒體播放服務是C++代碼,並且需要調用外部模 塊opencore來實現真正的媒體播放。媒體播放應用和媒體播放服務之間需要通過binder機制來進行相互調用,這些調用包括:

   (1)媒體播放應用向媒體播放服務發控制指令
(2)媒體播放服務向媒體播放應用發事件通知(notify)

   媒體播放服務對外提供多個接口,在上面得圖中包括其中的2個接口:IMediaService和IMediaPlayer,IMediaplayer用於 創建和管理播放實例,而IMediaplayer接口則是播放接口,用於實現指定媒體文件的播放以及播放過程的控制。

   上面的圖中還有媒體播放應用向媒體播放服務提供的1個接口:IMediaPlayerClient,用於接收notify。

   這些接口因爲需要跨進程調用,因此需要用到binder機制。每個接口包括兩部分實現,一部分是接口功能的真正實現(BnInterface),這部分運 行在接口提供進程中;另一部分是接口的proxy(BpInterface),這部分運行在調用接口的進程中。binder的作用就是讓這兩部分之間建立 聯繫。下圖是整個播放器的一個概要說明。

  

     媒體播放器比較複雜一些,總共實現了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)。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章