<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    posts - 101,  comments - 29,  trackbacks - 0

            在Android系統(tǒng)中,針對(duì)移動(dòng)設(shè)備內(nèi)存空間有限的特點(diǎn),提供了一種在進(jìn)程間共享數(shù)據(jù)的機(jī)制:匿名共享內(nèi)存,它能夠輔助內(nèi)存管理系統(tǒng)來(lái)有效地管理內(nèi)存,它的實(shí)現(xiàn)原理我們?cè)谇懊嬉呀?jīng)分析過(guò)了。為了方便使用匿名共享內(nèi)存機(jī)制,系統(tǒng)還提供了Java調(diào)用接口(MemoryFile)和C++調(diào)用接口(MemoryHeapBase、MemoryBase),Java接口在前面也已經(jīng)分析過(guò)了,本文中將繼續(xù)分析它的C++接口。

            在前面一篇文章Android系統(tǒng)匿名共享內(nèi)存Ashmem(Anonymous Shared Memory)驅(qū)動(dòng)程序源代碼分析中,我們分析了匿名共享內(nèi)存驅(qū)動(dòng)程序Ashmem的實(shí)現(xiàn),重點(diǎn)介紹了它是如何輔助內(nèi)存管理系統(tǒng)來(lái)有效地管理內(nèi)存的,簡(jiǎn)單來(lái)說(shuō),它就是給使用者提供鎖機(jī)制來(lái)輔助管理內(nèi)存,當(dāng)我們申請(qǐng)了一大塊匿名共享內(nèi)存時(shí),中間過(guò)程有一部分不需要使用時(shí),我們就可以將這一部分內(nèi)存塊解鎖,這樣內(nèi)存管理系統(tǒng)就可以把它回收回去了。接著又在前面一篇文章Android系統(tǒng)匿名共享內(nèi)存Ashmem(Anonymous Shared Memory)在進(jìn)程間共享的原理分析中,我們分析了匿名共享內(nèi)存是如何通過(guò)Binder進(jìn)程間通信機(jī)制來(lái)實(shí)現(xiàn)在進(jìn)程間共享的,簡(jiǎn)單來(lái)說(shuō),就是每一個(gè)匿名共享內(nèi)存塊都是一個(gè)文件,當(dāng)我們需要在進(jìn)程間共享時(shí),就把這個(gè)文件的打開(kāi)描述符通過(guò)Binder進(jìn)程間通信機(jī)制傳遞給另一外進(jìn)程,在傳遞的過(guò)程中,Binder驅(qū)動(dòng)程序就通過(guò)這個(gè)復(fù)制這個(gè)打開(kāi)文件描述符到目標(biāo)進(jìn)程中去,從而實(shí)現(xiàn)數(shù)據(jù)共享。在文章Android系統(tǒng)匿名共享內(nèi)存Ashmem(Anonymous Shared Memory)簡(jiǎn)要介紹和學(xué)習(xí)計(jì)劃中,我們介紹了如何在Android應(yīng)用程序中使用匿名共享內(nèi)存,主要是通過(guò)應(yīng)用程序框架層提供的MemoryFile接口來(lái)使用的,而MemoryFile接口是通過(guò)JNI方法調(diào)用到系統(tǒng)運(yùn)行時(shí)庫(kù)層中的匿名共享內(nèi)存C接口,最終通過(guò)這些C接口來(lái)使用內(nèi)核空間中的匿名共享內(nèi)存驅(qū)動(dòng)模塊。為了方便開(kāi)發(fā)者靈活地使用匿名共享內(nèi)存,Android系統(tǒng)在應(yīng)用程序框架層中還提供了使用匿名共享內(nèi)存的C++接口,例如,Android應(yīng)用程序四大組件之一Content Provider,它在應(yīng)用程序間共享數(shù)據(jù)時(shí),就是通過(guò)匿名共享內(nèi)存機(jī)制來(lái)實(shí)現(xiàn),但是它并不是通過(guò)MemoryFile接口來(lái)使用,而是通過(guò)調(diào)用C++接口中的MemoryBase類和MemoryHeapBase類來(lái)使用。在接下來(lái)的內(nèi)容中,我們就詳細(xì)分析MemoryHeapBase類和MemoryBase類的實(shí)現(xiàn),以及它們是如何實(shí)現(xiàn)在進(jìn)程間共享數(shù)據(jù)的。

            如果我們想在進(jìn)程間共享一個(gè)完整的匿名共享內(nèi)存塊,可以通過(guò)使用MemoryHeapBase接口來(lái)實(shí)現(xiàn),如果我們只想在進(jìn)程間共享一個(gè)匿名共享內(nèi)存塊中的其中一部分時(shí),就可以通過(guò)MemoryBase接口來(lái)實(shí)現(xiàn)。MemoryBase接口是建立在MemoryHeapBase接口的基礎(chǔ)上面的,它們都可以作為一個(gè)Binder對(duì)象來(lái)在進(jìn)程間傳輸,因此,希望讀者在繼續(xù)閱讀本文之前,對(duì)Android系統(tǒng)的Binder進(jìn)程間通信機(jī)制有一定的了解,具體可以參考前面一篇文章Android進(jìn)程間通信(IPC)機(jī)制Binder簡(jiǎn)要介紹和學(xué)習(xí)計(jì)劃。下面我們就首先分析MemoryHeapBase接口的實(shí)現(xiàn),然后再分析MemoryBase接口的實(shí)現(xiàn),最后,通過(guò)一個(gè)實(shí)例來(lái)說(shuō)明它們是如何使用的。

            1. MemoryHeapBase

             前面說(shuō)到,MemoryHeapBase類的對(duì)象可以作為Binder對(duì)象在進(jìn)程間傳輸,作為一個(gè)Binder對(duì)象,就有Server端對(duì)象和Client端引用的概念,其中,Server端對(duì)象必須要實(shí)現(xiàn)一個(gè)BnInterface接口,而Client端引用必須要實(shí)現(xiàn)一個(gè)BpInterface接口。下面我們就先看一下MemoryHeapBase在Server端實(shí)現(xiàn)的類圖:


             這個(gè)類圖中的類可以劃分為兩部分,一部分是和業(yè)務(wù)相關(guān)的,即跟匿名共享內(nèi)存操作相關(guān)的類,包括MemoryHeapBase、IMemoryBase和RefBase三個(gè)類,另一部分是和Binder機(jī)制相關(guān)的,包括IInterface、BnInterface、BnMemoryHeap、IBinder、BBinder、ProcessState和IPCThreadState七個(gè)類。

            我們先來(lái)看跟匿名共享內(nèi)存業(yè)務(wù)相關(guān)的這部分類的邏輯關(guān)系。IMemoryBase定義了匿名共享內(nèi)操作的接口,而MemoryHeapBase是作為Binder機(jī)制中的Server角色的,因此,它需要實(shí)現(xiàn)IMemoryBase接口,此外,MemoryHeapBase還繼承了RefBase類。從前面一篇文章Android系統(tǒng)的智能指針(輕量級(jí)指針、強(qiáng)指針和弱指針)的實(shí)現(xiàn)原理分析中,我們知道,繼承了RefBase類的子類,它們的對(duì)象都可以結(jié)合Android系統(tǒng)的智能指針來(lái)使用,因此,我們?cè)趯?shí)例化MemoryHeapBase類時(shí),可以通過(guò)智能指針來(lái)管理它們的生命周期。

            再來(lái)看和Binder機(jī)制相關(guān)的這部分類的邏輯關(guān)系。從Android系統(tǒng)進(jìn)程間通信(IPC)機(jī)制Binder中的Server啟動(dòng)過(guò)程源代碼分析這篇文章中,我們知道,所有的Binder對(duì)象都必須實(shí)現(xiàn)IInterface接口,無(wú)論是Server端實(shí)體對(duì)象,還是Client端引用對(duì)象,通過(guò)這個(gè)接口的asBinder成員函數(shù)我們可以獲得Binder對(duì)象的IBinder接口,然后通過(guò)Binder驅(qū)動(dòng)程序把它傳輸給另外一個(gè)進(jìn)程。當(dāng)一個(gè)類的對(duì)象作為Server端的實(shí)體對(duì)象時(shí),它還必須實(shí)現(xiàn)一個(gè)模板類BnInterface,這里負(fù)責(zé)實(shí)例化模板類BnInterface的類便是BnMemoryHeap類了,它里面有一個(gè)重要的成員函數(shù)onTransact,當(dāng)Client端引用請(qǐng)求Server端對(duì)象執(zhí)行命令時(shí),Binder系統(tǒng)就會(huì)調(diào)用BnMemoryHeap類的onTransact成員函數(shù)來(lái)執(zhí)行具體的命令。當(dāng)一個(gè)類的對(duì)象作為Server端的實(shí)體對(duì)象時(shí),它還要繼承于BBinder類,這是一個(gè)實(shí)現(xiàn)了IBinder接口的類,它里面有一個(gè)重要的成員函數(shù)transact,當(dāng)我們從Server端線程中接收到Client端的請(qǐng)求時(shí),就會(huì)調(diào)用注冊(cè)在這個(gè)線程中的BBinder對(duì)象的transact函數(shù)來(lái)處理這個(gè)請(qǐng)求,而這個(gè)transact函數(shù)會(huì)將這些Client端請(qǐng)求轉(zhuǎn)發(fā)給BnMemoryHeap類的onTransact成員函數(shù)來(lái)處理。最后,ProcessState和IPCThreadState兩個(gè)類是負(fù)責(zé)和Binder驅(qū)動(dòng)程序打交道的,其中,ProcessState負(fù)責(zé)打開(kāi)Binder設(shè)備文件/dev/binder,打開(kāi)了這個(gè)Binder設(shè)備文件后,就會(huì)得到一個(gè)打開(kāi)設(shè)備文件描述符,而IPCThreadState就是通過(guò)這個(gè)設(shè)備文件描述符來(lái)和Binder驅(qū)動(dòng)程序進(jìn)行交互的,例如它通過(guò)一個(gè)for循環(huán)來(lái)不斷地等待Binder驅(qū)動(dòng)程序通知它有新的Client端請(qǐng)求到來(lái)了,一旦有新的Client端請(qǐng)求到來(lái),它就會(huì)調(diào)用相應(yīng)的BBinder對(duì)象的transact函數(shù)來(lái)處理。

            本文我們主要是要關(guān)注和匿名共享內(nèi)存業(yè)務(wù)相關(guān)的這部分類,即IMemoryBase和MemoryHeapBase類的實(shí)現(xiàn),和Binder機(jī)制相關(guān)的這部分類的實(shí)現(xiàn),可以參考Android進(jìn)程間通信(IPC)機(jī)制Binder簡(jiǎn)要介紹和學(xué)習(xí)計(jì)劃一文。

            IMemoryBase類主要定義了幾個(gè)重要的操作匿名共享內(nèi)存的方法,它定義在frameworks/base/include/binder/IMemory.h文件中:

     

    class IMemoryHeap : public IInterface
    {
    public:
    	......
    
    	virtual int         getHeapID() const = 0;
    	virtual void*       getBase() const = 0;
    	virtual size_t      getSize() const = 0;
    
    	......
    };

     

            成員函數(shù)getHeapID是用來(lái)獲得匿名共享內(nèi)存塊的打開(kāi)文件描述符的;成員函數(shù)getBase是用來(lái)獲得匿名共享內(nèi)存塊的基地址的,有了這個(gè)地址之后,我們就可以在程序里面直接訪問(wèn)這塊共享內(nèi)存了;成員函數(shù)getSize是用來(lái)獲得匿名共享內(nèi)存塊的大小的。
            MemoryHeapBase類主要用來(lái)實(shí)現(xiàn)上面IMemoryBase類中列出來(lái)的幾個(gè)成員函數(shù)的,這個(gè)類聲明在frameworks/base/include/binder/MemoryHeapBase.h文件中:

     

    class MemoryHeapBase : public virtual BnMemoryHeap
    {
    public:
    	......
    
    	/*
    	* maps memory from ashmem, with the given name for debugging
    	*/
    	MemoryHeapBase(size_t size, uint32_t flags = 0, char const* name = NULL);
    
    	......
    
    	/* implement IMemoryHeap interface */
    	virtual int         getHeapID() const;
    	virtual void*       getBase() const;
    	virtual size_t      getSize() const;
    
    	......
    private:
    	int         mFD;
    	size_t      mSize;
    	void*       mBase;
    
    	......
    }
             MemoryHeapBase類的實(shí)現(xiàn)定義在frameworks/base/libs/binder/MemoryHeapBase.cpp文件中,我們先來(lái)看一下它的構(gòu)造函數(shù)的實(shí)現(xiàn):

     

     

    MemoryHeapBase::MemoryHeapBase(size_t size, uint32_t flags, char const * name)
    : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
    mDevice(0), mNeedUnmap(false)
    {
    	const size_t pagesize = getpagesize();
    	size = ((size + pagesize-1) & ~(pagesize-1));
    	int fd = ashmem_create_region(name == NULL ? "MemoryHeapBase" : name, size);
    	LOGE_IF(fd<0, "error creating ashmem region: %s", strerror(errno));
    	if (fd >= 0) {
    		if (mapfd(fd, size) == NO_ERROR) {
    			if (flags & READ_ONLY) {
    				ashmem_set_prot_region(fd, PROT_READ);
    			}
    		}
    	}
    }
            這個(gè)構(gòu)造函數(shù)有三個(gè)參數(shù),其中size表示要?jiǎng)?chuàng)建的匿名共享內(nèi)存的大小,flags是用來(lái)設(shè)置這塊匿名共享內(nèi)存的屬性的,例如是可讀寫(xiě)的還是只讀的,name是用來(lái)標(biāo)識(shí)這個(gè)匿名共享內(nèi)存的名字的,可以傳空值進(jìn)來(lái),這個(gè)參數(shù)只是作為調(diào)試信息使用的。

     

            MemoryHeapBase類創(chuàng)建的匿名共享內(nèi)存是以頁(yè)為單位的,頁(yè)的大小一般為4K,但是是可以設(shè)置的,這個(gè)函數(shù)首先通過(guò)getpagesize函數(shù)獲得系統(tǒng)中一頁(yè)內(nèi)存的大小值,然后把size參數(shù)對(duì)齊到頁(yè)大小去,即如果size不是頁(yè)大小的整數(shù)倍時(shí),就增加它的大小,使得它的值為頁(yè)大小的整數(shù)倍:

     

    const size_t pagesize = getpagesize();
    size = ((size + pagesize-1) & ~(pagesize-1));
            調(diào)整好size的大小后,就調(diào)用系統(tǒng)運(yùn)行時(shí)庫(kù)層的C接口ashmem_create_region來(lái)創(chuàng)建一塊共享內(nèi)存了:

     

     

    int fd = ashmem_create_region(name == NULL ? "MemoryHeapBase" : name, size);
            這個(gè)函數(shù)我們?cè)谇懊嬉黄恼?a >Android系統(tǒng)匿名共享內(nèi)存Ashmem(Anonymous Shared Memory)驅(qū)動(dòng)程序源代碼分析中可以介紹過(guò)了,這里不再詳細(xì),它只要就是通過(guò)Ashmem驅(qū)動(dòng)程序來(lái)創(chuàng)建一個(gè)匿名共享內(nèi)存文件,因此,它的返回值是一個(gè)文件描述符。

     

            得到了這個(gè)匿名共享內(nèi)存的文件描述符后,還需要調(diào)用mapfd成函數(shù)把它映射到進(jìn)程地址空間去:

     

    status_t MemoryHeapBase::mapfd(int fd, size_t size, uint32_t offset)
    {
    	......
    
    	if ((mFlags & DONT_MAP_LOCALLY) == 0) {
    		void* base = (uint8_t*)mmap(0, size,
    			PROT_READ|PROT_WRITE, MAP_SHARED, fd, offset);
    		......
    		mBase = base;
    		......
    	} else  {
    		......
    	}
    
    	mFD = fd;
    	mSize = size;
    	return NO_ERROR;
    }
            一般我們創(chuàng)建MemoryHeapBase類的實(shí)例時(shí),都是需要把匿名共享內(nèi)存映射到本進(jìn)程的地址空間去的,因此,這里的條件(mFlags & DONT_MAP_LOCALLY == 0)為true,于是執(zhí)行系統(tǒng)調(diào)用mmap來(lái)執(zhí)行內(nèi)存映射的操作。
    void* base = (uint8_t*)mmap(0, size,
    	PROT_READ|PROT_WRITE, MAP_SHARED, fd, offset);
            傳進(jìn)去的第一個(gè)參數(shù)0表示由內(nèi)核來(lái)決定這個(gè)匿名共享內(nèi)存文件在進(jìn)程地址空間的起始位置,第二個(gè)參數(shù)size表示要映射的匿名共享內(nèi)文件的大小,第三個(gè)參數(shù)PROT_READ|PROT_WRITE表示這個(gè)匿名共享內(nèi)存是可讀寫(xiě)的,第四個(gè)參數(shù)fd指定要映射的匿名共享內(nèi)存的文件描述符,第五個(gè)參數(shù)offset表示要從這個(gè)文件的哪個(gè)偏移位置開(kāi)始映射。調(diào)用了這個(gè)函數(shù)之后,最后會(huì)進(jìn)入到內(nèi)核空間的ashmem驅(qū)動(dòng)程序模塊中去執(zhí)行ashmem_map函數(shù),這個(gè)函數(shù)的實(shí)現(xiàn)具體可以參考Android系統(tǒng)匿名共享內(nèi)存Ashmem(Anonymous Shared Memory)驅(qū)動(dòng)程序源代碼分析一文,這里就不同詳細(xì)描述了。調(diào)用mmap函數(shù)返回之后,就得這塊匿名共享內(nèi)存在本進(jìn)程地址空間中的起始訪問(wèn)地址了,將這個(gè)地址保存在成員變量mBase中,最后,還將這個(gè)匿名共享內(nèi)存的文件描述符和以及大小分別保存在成員變量mFD和mSize中。

     

            回到前面MemoryHeapBase類的構(gòu)造函數(shù)中,將匿名共享內(nèi)存映射到本進(jìn)程的地址空間去后,還看繼續(xù)設(shè)置這塊匿名共享內(nèi)存的讀寫(xiě)屬性:

     

    if (fd >= 0) {
    	if (mapfd(fd, size) == NO_ERROR) {
    		if (flags & READ_ONLY) {
    			ashmem_set_prot_region(fd, PROT_READ);
    		}
    	}
    }
            上面調(diào)用mapfd函數(shù)來(lái)映射匿名共享內(nèi)存時(shí),指定這塊內(nèi)存是可讀寫(xiě)的,但是如果傳進(jìn)來(lái)的參數(shù)flags設(shè)置了只讀屬性,那么還需要調(diào)用系統(tǒng)運(yùn)行時(shí)庫(kù)存層的ashmem_set_prot_region函數(shù)來(lái)設(shè)置這塊匿名共享內(nèi)存為只讀,這個(gè)函數(shù)定義在system/core/libcutils/ashmem-dev.c文件,有興趣的讀者可以自己去研究一下。

     

            這樣,通過(guò)這個(gè)構(gòu)造函數(shù),一塊匿名共享內(nèi)存就建立好了,其余的三個(gè)成員函數(shù)getHeapID、getBase和getSize就簡(jiǎn)單了:

     

    int MemoryHeapBase::getHeapID() const {
        return mFD;
    }
    
    void* MemoryHeapBase::getBase() const {
        return mBase;
    }
    
    size_t MemoryHeapBase::getSize() const {
        return mSize;
    }
           接下來(lái)我們?cè)賮?lái)看一下MemoryHeapBase在Client端實(shí)現(xiàn)的類圖:

     


             這個(gè)類圖中的類也是可以劃分為兩部分,一部分是和業(yè)務(wù)相關(guān)的,即跟匿名共享內(nèi)存操作相關(guān)的類,包括BpMemoryHeap、IMemoryBase和RefBase三個(gè)類,另一部分是和Binder機(jī)制相關(guān)的,包括IInterface、BpInterface、BpRefBase、IBinder、BpBinder、ProcessState和IPCThreadState七個(gè)類。

            在和匿名共享內(nèi)存操作相關(guān)的類中,BpMemoryHeap類是前面分析的MemoryHeapBase類在Client端進(jìn)程的遠(yuǎn)接接口類,當(dāng)Client端進(jìn)程從Service Manager或者其它途徑獲得了一個(gè)MemoryHeapBase對(duì)象的引用之后,就會(huì)在本地創(chuàng)建一個(gè)BpMemoryHeap對(duì)象來(lái)代表這個(gè)引用。BpMemoryHeap類同樣是要實(shí)現(xiàn)IMemoryHeap接口,同時(shí),它是從RefBase類繼承下來(lái)的,因此,它可以與智能指針來(lái)結(jié)合使用。

            在和Binder機(jī)制相關(guān)的類中,和Server端實(shí)現(xiàn)不一樣的地方是,Client端不需要實(shí)現(xiàn)BnInterface和BBinder兩個(gè)類,但是需要實(shí)現(xiàn)BpInterface、BpRefBase和BpBinder三個(gè)類。BpInterface類繼承于BpRefBase類,而在BpRefBase類里面,有一個(gè)成員變量mRemote,它指向一個(gè)BpBinder對(duì)象,當(dāng)BpMemoryHeap類需要向Server端對(duì)象發(fā)出請(qǐng)求時(shí),它就會(huì)通過(guò)這個(gè)BpBinder對(duì)象的transact函數(shù)來(lái)發(fā)出這個(gè)請(qǐng)求。這里的BpBinder對(duì)象是如何知道要向哪個(gè)Server對(duì)象發(fā)出請(qǐng)深圳市的呢?它里面有一個(gè)成員變量mHandle,它表示的是一個(gè)Server端Binder對(duì)象的引用值,BpBinder對(duì)象就是要通過(guò)這個(gè)引用值來(lái)把請(qǐng)求發(fā)送到相應(yīng)的Server端對(duì)象去的了,這個(gè)引用值與Server端Binder對(duì)象的對(duì)應(yīng)關(guān)系是在Binder驅(qū)動(dòng)程序內(nèi)部維護(hù)的。這里的ProcessSate類和IPCThreadState類的作用和在Server端的作用是類似的,它們都是負(fù)責(zé)和底層的Binder驅(qū)動(dòng)程序進(jìn)行交互,例如,BpBinder對(duì)象的transact函數(shù)就通過(guò)線程中的IPCThreadState對(duì)象來(lái)將Client端請(qǐng)求發(fā)送出去的。這些實(shí)現(xiàn)具體可以參考Android系統(tǒng)進(jìn)程間通信(IPC)機(jī)制Binder中的Client獲得Server遠(yuǎn)程接口過(guò)程源代碼分析一文。

            這里我們主要關(guān)注BpMemoryHeap類是如何實(shí)現(xiàn)IMemoryHeap接口的,這個(gè)類聲明和定義在frameworks/base/libs/binder/IMemory.cpp文件中:

     

    class BpMemoryHeap : public BpInterface<IMemoryHeap>
    {
    public:
    	BpMemoryHeap(const sp<IBinder>& impl);
    	......
    
    	virtual int getHeapID() const;
    	virtual void* getBase() const;
    	virtual size_t getSize() const;
    
    	......
    private:
    	mutable volatile int32_t mHeapId;
    	mutable void*       mBase;
    	mutable size_t      mSize;
    
    	......
    }
            先來(lái)看構(gòu)造函數(shù)BpMemoryHeap的實(shí)現(xiàn):

     

     

    BpMemoryHeap::BpMemoryHeap(const sp<IBinder>& impl)
        : BpInterface<IMemoryHeap>(impl),
            mHeapId(-1), mBase(MAP_FAILED), mSize(0), mFlags(0), mRealHeap(false)
    {
    }
            它的實(shí)現(xiàn)很簡(jiǎn)單,只是初始化一下各個(gè)成員變量,例如,表示匿名共享內(nèi)存文件描述符的mHeapId值初化為-1、表示匿名內(nèi)共享內(nèi)存基地址的mBase值初始化為MAP_FAILED以及表示匿名共享內(nèi)存大小的mSize初始為為0,它們都表示在Client端進(jìn)程中,這個(gè)匿名共享內(nèi)存還未準(zhǔn)備就緒,要等到第一次使用時(shí)才會(huì)去創(chuàng)建。這里還需要注意的一點(diǎn),參數(shù)impl指向的是一個(gè)BpBinder對(duì)象,它里面包含了一個(gè)指向Server端Binder對(duì)象,即MemoryHeapBase對(duì)象的引用。

     

            其余三個(gè)成員函數(shù)getHeapID、getBase和getSize的實(shí)現(xiàn)是類似的:

     

    int BpMemoryHeap::getHeapID() const {
        assertMapped();
        return mHeapId;
    }
    
    void* BpMemoryHeap::getBase() const {
        assertMapped();
        return mBase;
    }
    
    size_t BpMemoryHeap::getSize() const {
        assertMapped();
        return mSize;
    }
            即它們?cè)谑褂弥埃紩?huì)首先調(diào)用assertMapped函數(shù)來(lái)保證在Client端的匿名共享內(nèi)存是已經(jīng)準(zhǔn)備就緒了的:

     

     

    void BpMemoryHeap::assertMapped() const
    {
        if (mHeapId == -1) {
            sp<IBinder> binder(const_cast<BpMemoryHeap*>(this)->asBinder());
            sp<BpMemoryHeap> heap(static_cast<BpMemoryHeap*>(find_heap(binder).get()));
            heap->assertReallyMapped();
            if (heap->mBase != MAP_FAILED) {
                Mutex::Autolock _l(mLock);
                if (mHeapId == -1) {
                    mBase   = heap->mBase;
                    mSize   = heap->mSize;
                    android_atomic_write( dup( heap->mHeapId ), &mHeapId );
                }
            } else {
                // something went wrong
                free_heap(binder);
            }
        }
    }
           在解釋這個(gè)函數(shù)之前,我們需要先了解一下BpMemoryHeap是如何知道自己內(nèi)部維護(hù)的這塊匿名共享內(nèi)存有沒(méi)有準(zhǔn)備就緒的。
           在frameworks/base/libs/binder/IMemory.cpp文件中,定義了一個(gè)全局變量gHeapCache:

     

     

    static sp<HeapCache> gHeapCache = new HeapCache();

     

           它的類型為HeapCache,這也是一個(gè)定義在frameworks/base/libs/binder/IMemory.cpp文件的類,它里面維護(hù)了本進(jìn)程中所有的MemoryHeapBase對(duì)象的引用。由于在Client端進(jìn)程中,可能會(huì)有多個(gè)引用,即多個(gè)BpMemoryHeap對(duì)象,對(duì)應(yīng)同一個(gè)MemoryHeapBase對(duì)象(這是由于可以用同一個(gè)BpBinder對(duì)象來(lái)創(chuàng)建多個(gè)BpMemoryHeap對(duì)象),因此,當(dāng)?shù)谝粋€(gè)BpMemoryHeap對(duì)象在本進(jìn)程中映射好這塊匿名共享內(nèi)存之后,后面的BpMemoryHeap對(duì)象就可以直接使用了,不需要再映射一次,當(dāng)然重新再映射一次沒(méi)有害處,但是會(huì)是多此一舉,Google在設(shè)計(jì)這個(gè)類時(shí),可以說(shuō)是考慮得非常周到的。

           我們來(lái)看一下HeapCache的實(shí)現(xiàn):

     

    class HeapCache : public IBinder::DeathRecipient
    {
    public:
        HeapCache();
        virtual ~HeapCache();
    
        ......
    
        sp<IMemoryHeap> find_heap(const sp<IBinder>& binder);
        void free_heap(const sp<IBinder>& binder);
        sp<IMemoryHeap> get_heap(const sp<IBinder>& binder);
        ......
    
    private:
        // For IMemory.cpp
        struct heap_info_t {
            sp<IMemoryHeap> heap;
            int32_t         count;
        };
    
        ......
    
        Mutex mHeapCacheLock;
        KeyedVector< wp<IBinder>, heap_info_t > mHeapCache;
    };
           它里面定義了一個(gè)成員變量mHeapCache,用來(lái)維護(hù)本進(jìn)程中的所有BpMemoryHeap對(duì)象,同時(shí)還提供了find_heap和get_heap函數(shù)來(lái)查找內(nèi)部所維護(hù)的BpMemoryHeap對(duì)象的功能。函數(shù)find_heap和get_heap的區(qū)別是,在find_heap函數(shù)中,如果在mHeapCache找不到相應(yīng)的BpMemoryHeap對(duì)象,就會(huì)把這個(gè)BpMemoryHeap對(duì)象加入到mHeapCache中去,而在get_heap函數(shù)中,則不會(huì)自動(dòng)把這個(gè)BpMemoryHeap對(duì)象加入到mHeapCache中去。

     

           這里,我們主要看一下find_heap函數(shù)的實(shí)現(xiàn):

     

    sp<IMemoryHeap> HeapCache::find_heap(const sp<IBinder>& binder)
    {
        Mutex::Autolock _l(mHeapCacheLock);
        ssize_t i = mHeapCache.indexOfKey(binder);
        if (i>=0) {
            heap_info_t& info = mHeapCache.editValueAt(i);
            LOGD_IF(VERBOSE,
                    "found binder=%p, heap=%p, size=%d, fd=%d, count=%d",
                    binder.get(), info.heap.get(),
                    static_cast<BpMemoryHeap*>(info.heap.get())->mSize,
                    static_cast<BpMemoryHeap*>(info.heap.get())->mHeapId,
                    info.count);
            android_atomic_inc(&info.count);
            return info.heap;
        } else {
            heap_info_t info;
            info.heap = interface_cast<IMemoryHeap>(binder);
            info.count = 1;
            //LOGD("adding binder=%p, heap=%p, count=%d",
            //      binder.get(), info.heap.get(), info.count);
            mHeapCache.add(binder, info);
            return info.heap;
        }
    }
            這個(gè)函數(shù)很簡(jiǎn)單,首先它以傳進(jìn)來(lái)的參數(shù)binder為關(guān)鍵字,在mHeapCache中查找,看看是否有對(duì)應(yīng)的heap_info對(duì)象info存在,如果有的話,就增加它的引用計(jì)數(shù)info.count值,表示這個(gè)BpBinder對(duì)象多了一個(gè)使用者;如果沒(méi)有的話,那么就需要?jiǎng)?chuàng)建一個(gè)heap_info對(duì)象info,并且將它加放到mHeapCache中去了。

     

            回到前面BpMemoryHeap類中的assertMapped函數(shù)中,如果本BpMemoryHeap對(duì)象中的mHeapID等于-1,那么就說(shuō)明這個(gè)BpMemoryHeap對(duì)象中的匿名共享內(nèi)存還沒(méi)準(zhǔn)備就緒,因此,需要執(zhí)行一次映射匿名共享內(nèi)存的操作。

            在執(zhí)行映射操作之作,先要看看在本進(jìn)程中是否有其它映射到同一個(gè)MemoryHeapBase對(duì)象的BpMemoryHeap對(duì)象存在:

     

    sp<IBinder> binder(const_cast<BpMemoryHeap*>(this)->asBinder());
    sp<BpMemoryHeap> heap(static_cast<BpMemoryHeap*>(find_heap(binder).get()));
           這里的find_heap函數(shù)是BpMemoryHeap的成員函數(shù),最終它調(diào)用了前面提到的全局變量gHeapCache來(lái)直正執(zhí)行查找的操作:

     

     

    class BpMemoryHeap : public BpInterface<IMemoryHeap>
    {	
    ......
    
    private:
    	static inline sp<IMemoryHeap> find_heap(const sp<IBinder>& binder) {
    		return gHeapCache->find_heap(binder);
    	}
    
    	......
    }
            注意,這里通過(guò)find_heap函數(shù)得到BpMemoryHeap對(duì)象可能是和正在執(zhí)行assertMapped函數(shù)中的BpMemoryHeap對(duì)象一樣,也可能不一樣,但是這沒(méi)有關(guān)系,這兩種情況的處理方式都是一樣的,都是通過(guò)調(diào)用這個(gè)通過(guò)find_heap函數(shù)得到BpMemoryHeap對(duì)象的assertReallyMapped函數(shù)來(lái)進(jìn)一步確認(rèn)它內(nèi)部的匿名共享內(nèi)存是否已經(jīng)映射到進(jìn)程空間了:

     

     

    void BpMemoryHeap::assertReallyMapped() const
    {
    	if (mHeapId == -1) {
    
    		// remote call without mLock held, worse case scenario, we end up
    		// calling transact() from multiple threads, but that's not a problem,
    		// only mmap below must be in the critical section.
    
    		Parcel data, reply;
    		data.writeInterfaceToken(IMemoryHeap::getInterfaceDescriptor());
    		status_t err = remote()->transact(HEAP_ID, data, &reply);
    		int parcel_fd = reply.readFileDescriptor();
    		ssize_t size = reply.readInt32();
    		uint32_t flags = reply.readInt32();
    
    		LOGE_IF(err, "binder=%p transaction failed fd=%d, size=%ld, err=%d (%s)",
    			asBinder().get(), parcel_fd, size, err, strerror(-err));
    
    		int fd = dup( parcel_fd );
    		LOGE_IF(fd==-1, "cannot dup fd=%d, size=%ld, err=%d (%s)",
    			parcel_fd, size, err, strerror(errno));
    
    		int access = PROT_READ;
    		if (!(flags & READ_ONLY)) {
    			access |= PROT_WRITE;
    		}
    
    		Mutex::Autolock _l(mLock);
    		if (mHeapId == -1) {
    			mRealHeap = true;
    			mBase = mmap(0, size, access, MAP_SHARED, fd, 0);
    			if (mBase == MAP_FAILED) {
    				LOGE("cannot map BpMemoryHeap (binder=%p), size=%ld, fd=%d (%s)",
    					asBinder().get(), size, fd, strerror(errno));
    				close(fd);
    			} else {
    				mSize = size;
    				mFlags = flags;
    				android_atomic_write(fd, &mHeapId);
    			}
    		}
    	}
    }
            如果成員變量mHeapId的值為-1,就說(shuō)明還沒(méi)有把在Server端的MemoryHeapBase對(duì)象中的匿名共享內(nèi)存映射到本進(jìn)程空間來(lái),于是,就通過(guò)一個(gè)Binder進(jìn)程間調(diào)用把Server端的MemoryHeapBase對(duì)象中的匿名共享內(nèi)存對(duì)象信息取回來(lái):

     

     

    Parcel data, reply;
    data.writeInterfaceToken(IMemoryHeap::getInterfaceDescriptor());
    status_t err = remote()->transact(HEAP_ID, data, &reply);
    int parcel_fd = reply.readFileDescriptor();
    ssize_t size = reply.readInt32();
    uint32_t flags = reply.readInt32();
    
    ......
    
    int fd = dup( parcel_fd );
    		
    ......
            取回來(lái)的信息包括MemoryHeapBase對(duì)象中的匿名共享內(nèi)存在本進(jìn)程中的文件描述符fd、大小size以及訪問(wèn)屬性flags。如何把MemoryHeapBase對(duì)象中的匿名共享內(nèi)存作為本進(jìn)程的一個(gè)打開(kāi)文件描述符,請(qǐng)參考前面一篇文章Android系統(tǒng)匿名共享內(nèi)存Ashmem(Anonymous Shared Memory)在進(jìn)程間共享的原理分析。有了這個(gè)文件描述符fd后,就可以對(duì)它進(jìn)行內(nèi)存映射操作了:

     

     

    Mutex::Autolock _l(mLock);
    if (mHeapId == -1) {
    	mRealHeap = true;
    	mBase = mmap(0, size, access, MAP_SHARED, fd, 0);
    	if (mBase == MAP_FAILED) {
    		LOGE("cannot map BpMemoryHeap (binder=%p), size=%ld, fd=%d (%s)",
    			asBinder().get(), size, fd, strerror(errno));
    		close(fd);
    	} else {
    		mSize = size;
    		mFlags = flags;
    		android_atomic_write(fd, &mHeapId);
    	}
    }
            前面已經(jīng)判斷過(guò)mHeapId是否為-1了,這里為什么又要重新判斷一次呢?這里因?yàn)椋谏厦鎴?zhí)行Binder進(jìn)程間調(diào)用的過(guò)程中,很有可能也有其它的線程也對(duì)這個(gè)BpMemoryHeap對(duì)象執(zhí)行匿名共享內(nèi)存映射的操作,因此,這里還要重新判斷一下mHeapId的值是否為-1,如果是的話,就要執(zhí)行匿名共享內(nèi)存映射的操作了,這是通過(guò)調(diào)用mmap函數(shù)來(lái)進(jìn)行的,這個(gè)函數(shù)我們前面在分析MemoryHeapBase類的實(shí)現(xiàn)時(shí)已經(jīng)見(jiàn)過(guò)了。

     

            從assertReallyMapped函數(shù)返回到assertMapped函數(shù)中:

     

    if (heap->mBase != MAP_FAILED) {
        Mutex::Autolock _l(mLock);
        if (mHeapId == -1) {
            mBase   = heap->mBase;
            mSize   = heap->mSize;
            android_atomic_write( dup( heap->mHeapId ), &mHeapId );
        }
    } else {
        // something went wrong
        free_heap(binder);
    }
            如果heap->mBase的值不為MAP_FAILED,就說(shuō)明這個(gè)heap對(duì)象中的匿名共享內(nèi)存已經(jīng)映射好了。進(jìn)入到里面的if語(yǔ)句,如果本BpMemoryHeap對(duì)象中的mHeap成員變量的值不等待-1,就說(shuō)明前面通過(guò)find_heap函數(shù)得到的BpMemoryHeap對(duì)象和正在執(zhí)行assertMapped函數(shù)的BpMemoryHeap對(duì)象是同一個(gè)對(duì)象了,因此,什么也不用做就可以返回了,否則的話,就要初始化一下本BpMemoryHeap對(duì)象的相關(guān)成員變量了:

     

     

    mBase   = heap->mBase;
    mSize   = heap->mSize;
    android_atomic_write( dup( heap->mHeapId ), &mHeapId );
            注意,由于這塊匿名共享內(nèi)存已經(jīng)在本進(jìn)程中映射好了,因此,這里不需要再執(zhí)行一次mmap操作,只需要把heap對(duì)象的相應(yīng)成員變量的值拷貝過(guò)來(lái)就行了,不過(guò)對(duì)于文件描述符,需要通過(guò)dup函數(shù)來(lái)復(fù)制一個(gè)。

     

            這樣,BpMemoryHeap對(duì)象中的匿名共享內(nèi)存就準(zhǔn)備就緒了,可以通過(guò)使用的它mBase成員變量來(lái)直接訪問(wèn)這塊匿名共享內(nèi)存。

            至此,MemoryHeapBase類的實(shí)現(xiàn)就分析完了,下面我們繼續(xù)分析MemoryBase類的實(shí)現(xiàn)。

            2. MemoryBase

            文章開(kāi)始時(shí)說(shuō)過(guò),MemoryBase接口是建立在MemoryHeapBase接口的基礎(chǔ)上的,它們都可以作為一個(gè)Binder對(duì)象來(lái)在進(jìn)程間進(jìn)行數(shù)據(jù)共享,它們的關(guān)系如下所示:


            MemoryBase類包含了一個(gè)成員變量mHeap,它的類型的IMemoryHeap,MemoryBase類所代表的匿名共享內(nèi)存就是通過(guò)這個(gè)成員變量來(lái)實(shí)現(xiàn)的。

            與MemoryHeapBase的分析過(guò)程一樣,我們先來(lái)看MemoryBase類在Server端的實(shí)現(xiàn),然后再來(lái)看它在Client端的實(shí)現(xiàn)。

            MemoryBase在Server端實(shí)現(xiàn)的類圖如下所示:


            MemoryBase類在Server端的實(shí)現(xiàn)與MemoryHeapBase類在Server端的實(shí)現(xiàn)是類似的,這里只要把IMemory類換成IMemoryHeap類、把BnMemory類換成BnMemoryHeap類以及MemoryBase類換成MemoryHeapBase類就變成是MemoryHeapBase類在Server端的實(shí)現(xiàn)了,因此,我們這里只簡(jiǎn)單分析IMemory類和MemoryBase類的實(shí)現(xiàn)。

            IMemory類定義了MemoryBase類所需要實(shí)現(xiàn)的接口,這個(gè)類定義在frameworks/base/include/binder/IMemory.h文件中:

    class IMemory : public IInterface
    {
    public:
    	......
    
    	virtual sp<IMemoryHeap> getMemory(ssize_t* offset=0, size_t* size=0) const = 0;
    
    	......
    	void* pointer() const;
    	size_t size() const;
    	ssize_t offset() const;
    };
            成員函數(shù)getMemory用來(lái)獲取內(nèi)部的MemoryHeapBase對(duì)象的IMemoryHeap接口;成員函數(shù)pointer()用來(lái)獲取內(nèi)部所維護(hù)的匿名共享內(nèi)存的基地址;成員函數(shù)size()用來(lái)獲取內(nèi)部所維護(hù)的匿名共享內(nèi)存的大小;成員函數(shù)offset()用來(lái)獲取內(nèi)部所維護(hù)的這部分匿名共享內(nèi)存在整個(gè)匿名共享內(nèi)存中的偏移量。

     

            IMemory類本身實(shí)現(xiàn)了pointer、size和offset三個(gè)成員函數(shù),因此,它的子類,即MemoryBase類,只需要實(shí)現(xiàn)getMemory成員函數(shù)就可以了。IMemory類的實(shí)現(xiàn)定義在frameworks/base/libs/binder/IMemory.cpp文件中:

    void* IMemory::pointer() const {
        ssize_t offset;
        sp<IMemoryHeap> heap = getMemory(&offset);
        void* const base = heap!=0 ? heap->base() : MAP_FAILED;
        if (base == MAP_FAILED)
            return 0;
        return static_cast<char*>(base) + offset;
    }
    
    size_t IMemory::size() const {
        size_t size;
        getMemory(NULL, &size);
        return size;
    }
    
    ssize_t IMemory::offset() const {
        ssize_t offset;
        getMemory(&offset);
        return offset;
    }
            MemoryBase類聲明在frameworks/base/include/binder/MemoryBase.h文件中:

     

    class MemoryBase : public BnMemory
    {
    public:
    	MemoryBase(const sp<IMemoryHeap>& heap, ssize_t offset, size_t size);
    	......
    	virtual sp<IMemoryHeap> getMemory(ssize_t* offset, size_t* size) const;
    
        ......
    private:
    	size_t          mSize;
    	ssize_t         mOffset;
    	sp<IMemoryHeap> mHeap;
    };
           MemoryBase類實(shí)現(xiàn)在frameworks/base/libs/binder/MemoryBase.cpp文件中:

     

    MemoryBase::MemoryBase(const sp<IMemoryHeap>& heap,
            ssize_t offset, size_t size)
        : mSize(size), mOffset(offset), mHeap(heap)
    {
    }
    
    sp<IMemoryHeap> MemoryBase::getMemory(ssize_t* offset, size_t* size) const
    {
        if (offset) *offset = mOffset;
        if (size)   *size = mSize;
        return mHeap;
    }
            在它的構(gòu)造函數(shù)中,接受三個(gè)參數(shù),參數(shù)heap指向的是一個(gè)MemoryHeapBase對(duì)象,真正的匿名共享內(nèi)存就是由它來(lái)維護(hù)的,參數(shù)offset表示這個(gè)MemoryBase對(duì)象所要維護(hù)的這部分匿名共享內(nèi)存在整個(gè)匿名共享內(nèi)存塊中的起始位置,參數(shù)size表示這個(gè)MemoryBase對(duì)象所要維護(hù)的這部分匿名共享內(nèi)存的大小。

     

            成員函數(shù)getMemory的實(shí)現(xiàn)很簡(jiǎn)單,只是簡(jiǎn)單地返回內(nèi)部的MemoryHeapBase對(duì)象的IMemoryHeap接口,如果傳進(jìn)來(lái)的參數(shù)offset和size不為NULL,還會(huì)把其內(nèi)部維護(hù)的這部分匿名共享內(nèi)存在整個(gè)匿名共享內(nèi)存塊中的偏移位置以及這部分匿名共享內(nèi)存的大小返回給調(diào)用者。

            這里我們可以看出,MemoryBase在Server端的實(shí)現(xiàn)只是簡(jiǎn)單地封裝了MemoryHeapBase的實(shí)現(xiàn)。

            下面我們?cè)賮?lái)看MemoryBase類在Client端的實(shí)現(xiàn),同樣,先看它們的類圖關(guān)系:


            這個(gè)圖中我們可以看出,MemoryBase類在Client端的實(shí)現(xiàn)與MemoryHeapBase類在Client端的實(shí)現(xiàn)是類似的,這里只要把IMemory類換成IMemoryHeap類以及把BpMemory類換成BpMemoryHeap類就變成是MemoryHeapBase類在Client端的實(shí)現(xiàn)了,因此,我們這里只簡(jiǎn)單分析BpMemory類的實(shí)現(xiàn),前面已經(jīng)分析過(guò)IMemory類的實(shí)現(xiàn)了。

            BpMemory類實(shí)現(xiàn)在frameworks/base/libs/binder/IMemory.cpp文件中,我們先看它的聲明:

    class BpMemory : public BpInterface<IMemory>
    {
    public:
        BpMemory(const sp<IBinder>& impl);
        virtual ~BpMemory();
        virtual sp<IMemoryHeap> getMemory(ssize_t* offset=0, size_t* size=0) const;
    
    private:
        mutable sp<IMemoryHeap> mHeap;
        mutable ssize_t mOffset;
        mutable size_t mSize;
    };
           和MemoryBase類一樣,它實(shí)現(xiàn)了IMemory類的getMemory成員函數(shù),在它的成員變量中,mHeap的類型為IMemoryHeap,它指向的是一個(gè)BpMemoryHeap對(duì)象,mOffset表示這個(gè)BpMemory對(duì)象所要維護(hù)的這部分匿名共享內(nèi)存在整個(gè)匿名共享內(nèi)存塊中的起始位置,mSize表示這個(gè)BpMemory對(duì)象所要維護(hù)的這部分匿名共享內(nèi)存的大小。

     

           下面我們就看一下BpMemory類的成員函數(shù)getMemory的實(shí)現(xiàn):

    sp<IMemoryHeap> BpMemory::getMemory(ssize_t* offset, size_t* size) const
    {
        if (mHeap == 0) {
            Parcel data, reply;
            data.writeInterfaceToken(IMemory::getInterfaceDescriptor());
            if (remote()->transact(GET_MEMORY, data, &reply) == NO_ERROR) {
                sp<IBinder> heap = reply.readStrongBinder();
                ssize_t o = reply.readInt32();
                size_t s = reply.readInt32();
                if (heap != 0) {
                    mHeap = interface_cast<IMemoryHeap>(heap);
                    if (mHeap != 0) {
                        mOffset = o;
                        mSize = s;
                    }
                }
            }
        }
        if (offset) *offset = mOffset;
        if (size) *size = mSize;
        return mHeap;
    }
            如果成員變量mHeap的值為NULL,就表示這個(gè)BpMemory對(duì)象尚未建立好匿名共享內(nèi)存,于是,就會(huì)通過(guò)一個(gè)Binder進(jìn)程間調(diào)用去Server端請(qǐng)求匿名共享內(nèi)存信息,在這些信息中,最重要的就是這個(gè)Server端的MemoryHeapBase對(duì)象的引用heap了,通過(guò)這個(gè)引用可以在Client端進(jìn)程中創(chuàng)建一個(gè)BpMemoryHeap遠(yuǎn)程接口,最后將這個(gè)BpMemoryHeap遠(yuǎn)程接口保存在成員變量mHeap中,同時(shí),從Server端獲得的信息還包括這塊匿名共享內(nèi)存在整個(gè)匿名共享內(nèi)存中的偏移位置以及大小。這樣,這個(gè)BpMemory對(duì)象中的匿名共享內(nèi)存就準(zhǔn)備就緒了。

     

            至此,MemoryBase類的實(shí)現(xiàn)就分析完了,下面我們將通過(guò)一個(gè)實(shí)例來(lái)說(shuō)明如何使用MemoryBase類在進(jìn)程間進(jìn)行內(nèi)存共享,因?yàn)镸emoryBase內(nèi)部使用了MemoryHeapBase類,所以,這個(gè)例子同時(shí)也可以說(shuō)明MemoryHeapBase類的使用方法。

            3. MemoryHeapBas類e和MemoryBase類的使用示例

            在這個(gè)例子中,我們將在Android源代碼工程的external目錄中創(chuàng)建一個(gè)ashmem源代碼工程,它里面包括兩個(gè)應(yīng)用程序,一個(gè)是Server端應(yīng)用程序SharedBufferServer,它提供一段共享內(nèi)存來(lái)給Client端程序使用,一個(gè)是Client端應(yīng)用程序SharedBufferClient,它簡(jiǎn)單地對(duì)Server端提供的共享內(nèi)存進(jìn)行讀和寫(xiě)的操作。Server端應(yīng)用程序SharedBufferServer和Client端應(yīng)用程序SharedBufferClient通過(guò)Binder進(jìn)程間通信機(jī)制來(lái)交互,因此,我們需要定義自己的Binder對(duì)象接口ISharedBuffer。Server端應(yīng)用程序SharedBufferServer在內(nèi)部實(shí)現(xiàn)了一個(gè)服務(wù)SharedBufferService,這個(gè)服務(wù)托管給Service Manager來(lái)管理,因此,Client端應(yīng)用程序SharedBufferClient可以向Service Manager請(qǐng)求這個(gè)SharedBufferService服務(wù)的一個(gè)遠(yuǎn)接接口,然后就可以通過(guò)這個(gè)服務(wù)來(lái)操作Server端提供的這段共享內(nèi)存了。

            這個(gè)工程由三個(gè)模塊組成,第一個(gè)模塊定義服務(wù)接口,它的相關(guān)源代碼位于external/ashmem/common目錄下,第二個(gè)模塊實(shí)現(xiàn)Server端應(yīng)用程序SharedBufferServer,它的相關(guān)源代碼位于external/ashmem/server目錄下,第三個(gè)模塊實(shí)現(xiàn)Client端應(yīng)用程序SharedBufferClient,它的相關(guān)源代碼碼位于external/ashmem/client目錄下。

            首先來(lái)看common模塊中的服務(wù)接口的定義。在external/ashmem/common目錄下,有兩個(gè)源文件ISharedBuffer.h和ISharedBuffer.cpp。源文件ISharedBuffer.h定義了服務(wù)的接口:

    #ifndef ISHAREDBUFFER_H_
    #define ISHAREDBUFFER_H_
    
    #include <utils/RefBase.h>
    #include <binder/IInterface.h>
    #include <binder/Parcel.h>
    
    #define SHARED_BUFFER_SERVICE "shy.luo.SharedBuffer"
    #define SHARED_BUFFER_SIZE 4
    
    using namespace android;
    
    class ISharedBuffer: public IInterface
    {
    public:
            DECLARE_META_INTERFACE(SharedBuffer);
            virtual sp<IMemory> getBuffer() = 0;
    };
    
    class BnSharedBuffer: public BnInterface<ISharedBuffer>
    {
    public:
            virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0);
    };
    
    #endif
            這個(gè)文件定義了一個(gè)ISharedBuffer接口,里面只有一個(gè)成員函數(shù)getBuffer,通過(guò)這個(gè)成員函數(shù),Client端可以從Server端獲得一個(gè)匿名共享內(nèi)存,這塊匿名共享內(nèi)存通過(guò)我們上面分析的MemoryBase類來(lái)維護(hù)。這個(gè)文件同時(shí)也定義了一個(gè)必須要在Server端實(shí)現(xiàn)的BnSharedBuffer接口,它里面只有一個(gè)成員函數(shù)onTransact,這個(gè)成員函數(shù)是用來(lái)處理Client端發(fā)送過(guò)來(lái)的請(qǐng)求的。除了定義這兩個(gè)接口之外,這個(gè)文件還定義了兩個(gè)公共信息,一個(gè)是定義常量SHARED_BUFFER_SERVICE,它是Server端提供的內(nèi)存共享服務(wù)的名稱,即這個(gè)內(nèi)存共享服務(wù)在Service Manager中是以SHARED_BUFFER_SERVICE來(lái)作關(guān)鍵字索引的,另外一個(gè)是定義常量SHARED_BUFFER_SIZE,它定義了Server端共享的內(nèi)存塊的大小,它的大小設(shè)置為4個(gè)字節(jié),在這個(gè)例子,將把這個(gè)共享內(nèi)存當(dāng)作一個(gè)整型變量來(lái)訪問(wèn)。

     

            源代文件ISharedBuffer.cpp文件定義了一個(gè)在Client端使用的BpSharedBuffer接口,它是指向運(yùn)行在Server端的實(shí)現(xiàn)了ISharedBuffer接口的內(nèi)存共享服務(wù)的遠(yuǎn)程接口,同時(shí),在這個(gè)文件里面,也實(shí)現(xiàn)了BnSharedBuffer類的onTransact成員函數(shù):

    #define LOG_TAG "ISharedBuffer"
    
    #include <utils/Log.h>
    #include <binder/MemoryBase.h>
    
    #include "ISharedBuffer.h"
    
    using namespace android;
    
    enum
    {
    	GET_BUFFER = IBinder::FIRST_CALL_TRANSACTION
    };
    
    class BpSharedBuffer: public BpInterface<ISharedBuffer>
    {
    public:
    	BpSharedBuffer(const sp<IBinder>& impl)
    		: BpInterface<ISharedBuffer>(impl)
    	{
    
    	}
    
    public:
    	sp<IMemory> getBuffer()
    	{
    		Parcel data;
    		data.writeInterfaceToken(ISharedBuffer::getInterfaceDescriptor());
    
    		Parcel reply;
    		remote()->transact(GET_BUFFER, data, &reply);
    
    		sp<IMemory> buffer = interface_cast<IMemory>(reply.readStrongBinder());
    
    		return buffer;
    	}
    };
    
    IMPLEMENT_META_INTERFACE(SharedBuffer, "shy.luo.ISharedBuffer");
    
    status_t BnSharedBuffer::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
    {
    	switch(code)
    	{
    	case GET_BUFFER:
    		{
    			CHECK_INTERFACE(ISharedBuffer, data, reply);
    
    			sp<IMemory> buffer = getBuffer();
    			if(buffer != NULL)
    			{
    				reply->writeStrongBinder(buffer->asBinder());
    			}
    
    			return NO_ERROR;
    		}
    	default:
    		{
    			return BBinder::onTransact(code, data, reply, flags);
    		}
    	}
    }
            在BpSharedBuffer類的成員函數(shù)transact中,向Server端發(fā)出了一個(gè)請(qǐng)求代碼為GET_BUFFER的Binder進(jìn)程間調(diào)用請(qǐng)求,請(qǐng)求Server端返回一個(gè)匿名共享內(nèi)存對(duì)象的遠(yuǎn)程接口IMemory,它實(shí)際指向的是一個(gè)BpMemory對(duì)象,獲得了這個(gè)對(duì)象之后,就將它返回給調(diào)用者;在BnSharedBuffer類的成員函數(shù)onTransact中,當(dāng)它接收到從Client端發(fā)送過(guò)來(lái)的代碼為GET_BUFFER的Binder進(jìn)程間調(diào)用請(qǐng)求后,便調(diào)用其子類的getBuffer成員函數(shù)來(lái)獲一個(gè)匿名共享內(nèi)存對(duì)象接口IMemory,它實(shí)際指向的是一個(gè)MemoryBase對(duì)象,獲得了這個(gè)對(duì)象之后,就把它返回給Client端。

     

            接下來(lái),我們?cè)賮?lái)看看server模塊的實(shí)現(xiàn)。在external/ashmem/common目錄下,只有一個(gè)源文件SharedBufferServer.cpp,它實(shí)現(xiàn)了內(nèi)存共享服務(wù)SharedBufferService:

    #define LOG_TAG "SharedBufferServer"
    
    #include <utils/Log.h>
    #include <binder/MemoryBase.h>
    #include <binder/MemoryHeapBase.h>
    #include <binder/IServiceManager.h>
    #include <binder/IPCThreadState.h>
    
    #include "../common/ISharedBuffer.h"
    
    class SharedBufferService : public BnSharedBuffer
    {
    public:
    	SharedBufferService()
    	{
    		sp<MemoryHeapBase> heap = new MemoryHeapBase(SHARED_BUFFER_SIZE, 0, "SharedBuffer");
    		if(heap != NULL)
    		{
    			mMemory = new MemoryBase(heap, 0, SHARED_BUFFER_SIZE);
    
    			int32_t* data = (int32_t*)mMemory->pointer();
    			if(data != NULL)
    			{
    				*data = 0;
    			}
    		}
    	}
    
    	virtual ~SharedBufferService()
    	{
    		mMemory = NULL;
    	}
    
    public:
    	static void instantiate()
    	{
    		defaultServiceManager()->addService(String16(SHARED_BUFFER_SERVICE), new SharedBufferService());
    	}
    
    	virtual sp<IMemory> getBuffer()
    	{
    		return mMemory;
    	}
    
    private:
    	sp<MemoryBase> mMemory;
    };
    
    int main(int argc, char** argv)
    {
    	SharedBufferService::instantiate();
    
    	ProcessState::self()->startThreadPool();
    	IPCThreadState::self()->joinThreadPool();
    
    	return 0;
    }
            SharedBufferService服務(wù)實(shí)現(xiàn)了BnSharedBuffer接口。在它的構(gòu)造函數(shù)里面,首先是使用MemoryHeapBase類創(chuàng)建了一個(gè)匿名共享內(nèi)存,大小為SHARED_BUFFER_SIZE。接著,又以這個(gè)MemoryHeapBase對(duì)象為參數(shù),創(chuàng)建一個(gè)MemoryBase對(duì)象,這個(gè)MemoryBase對(duì)象指定要維護(hù)的匿名共享內(nèi)存的的偏移位置為0,大小為SHARED_BUFFER_SIZE,并且,將這個(gè)匿名共享內(nèi)存當(dāng)作一個(gè)整型變量地址,將它初始化為0。最終,這個(gè)匿名共享內(nèi)存對(duì)象保存在SharedBufferService類的成員變量mMemory中,這個(gè)匿名共享內(nèi)存對(duì)象可以通過(guò)成員函數(shù)getBuffer來(lái)獲得。

     

            在Server端應(yīng)用程序的入口函數(shù)main中,首先是調(diào)用SharedBufferService靜態(tài)成員函數(shù)instantiate函數(shù)來(lái)創(chuàng)建一個(gè)SharedBufferService實(shí)例,然后通過(guò)defaultServiceManager函數(shù)來(lái)獲得系統(tǒng)中的Service Manager接口,最后通過(guò)這個(gè)Service Manager接口的addService函數(shù)來(lái)把這個(gè)SharedBufferService服務(wù)添加到Service Manager中去,這樣,Client端就可以通過(guò)Service Manager來(lái)獲得這個(gè)共享內(nèi)存服務(wù)了。有關(guān)Service Manager的實(shí)現(xiàn),請(qǐng)參考前面一篇文章淺談Service Manager成為Android進(jìn)程間通信(IPC)機(jī)制Binder守護(hù)進(jìn)程之路,而用來(lái)獲取Service Manager接口的defaultServiceManager函數(shù)的實(shí)現(xiàn)可以參考另外一篇文章淺談Android系統(tǒng)進(jìn)程間通信(IPC)機(jī)制Binder中的Server和Client獲得Service Manager接口之路。初始化好這個(gè)共享內(nèi)存服務(wù)之后,程序就通過(guò)ProcessState::self()->startThreadPool()函數(shù)來(lái)創(chuàng)建一個(gè)線程等待Client端來(lái)請(qǐng)求服務(wù)了,最后,程序的主線程也通過(guò)IPCThreadState::self()->joinThreadPool()函數(shù)來(lái)進(jìn)入到等待Client端來(lái)請(qǐng)求服務(wù)的狀態(tài)中。

           我們還需要為這個(gè)Server端應(yīng)用程序編譯一個(gè)編譯腳本,在external/ashmem/server目錄下,新建一個(gè)Android.mk文件,它的內(nèi)容如下所示:

    LOCAL_PATH := $(call my-dir)
    
    include $(CLEAR_VARS)
    
    LOCAL_MODULE_TAGS := optional
    
    LOCAL_SRC_FILES := ../common/ISharedBuffer.cpp \
            SharedBufferServer.cpp
    
    LOCAL_SHARED_LIBRARIES:= libcutils libutils libbinder
    
    LOCAL_MODULE := SharedBufferServer
    
    include $(BUILD_EXECUTABLE)
            最后,我們?cè)賮?lái)看看client模塊的實(shí)現(xiàn)。在external/ashmem/client目錄下,只有一個(gè)源文件SharedBufferClient.cpp,它的內(nèi)容如下所示:

     

    #define LOG_TAG "SharedBufferClient"
    
    #include <utils/Log.h>
    #include <binder/MemoryBase.h>
    #include <binder/IServiceManager.h>
    
    #include "../common/ISharedBuffer.h"
    
    int main()
    {
            sp<IBinder> binder = defaultServiceManager()->getService(String16(SHARED_BUFFER_SERVICE));
            if(binder == NULL)
            {
                    printf("Failed to get service: %s.\n", SHARED_BUFFER_SERVICE);
                    return -1;
            }
    
            sp<ISharedBuffer> service = ISharedBuffer::asInterface(binder);
            if(service == NULL)
            {
                    return -2;
            }
    
            sp<IMemory> buffer = service->getBuffer();
            if(buffer == NULL)
            {
                    return -3;
            }
    
            int32_t* data = (int32_t*)buffer->pointer();
            if(data == NULL)
            {
                    return -4;
            }
    
            printf("The value of the shared buffer is %d.\n", *data);
    
            *data = *data + 1;
    
            printf("Add value 1 to the shared buffer.\n");
    
            return 0;
    }
            在這個(gè)文件中,主要就是定義了Client端應(yīng)用程序的入口函數(shù)main,在這個(gè)main函數(shù)里面,首先通過(guò)Service Manager接口獲得前面所實(shí)現(xiàn)的匿名共享內(nèi)存服務(wù)SharedBufferService的遠(yuǎn)程接口service,然后通過(guò)這個(gè)遠(yuǎn)程接口的getBuffer成員函數(shù)獲得由Server端提供的一塊匿名共享內(nèi)存接口buffer,最后通過(guò)這個(gè)匿名共享內(nèi)存接口獲得這個(gè)匿名共享內(nèi)存的基地址data。有了這個(gè)匿名共享內(nèi)存的地址data之后,我們就可以對(duì)它進(jìn)行讀寫(xiě)了,先是把這個(gè)匿名共享內(nèi)存當(dāng)作是一個(gè)整型變量地址進(jìn)行訪問(wèn),并輸出它的值的大小,然后對(duì)這個(gè)整量變量進(jìn)行加1的操作,并寫(xiě)回到原來(lái)的共享內(nèi)存空間中去。這樣,當(dāng)Server端應(yīng)用程序運(yùn)行之后,第一次運(yùn)行這個(gè)Client端應(yīng)用程序時(shí),輸出的值為0,第二次運(yùn)行這個(gè)個(gè)Client端應(yīng)用程序時(shí),輸出的值為1,第三次運(yùn)行這個(gè)個(gè)Client端應(yīng)用程序時(shí),輸出的值為3......依次類推,后面我們將在模擬器中對(duì)這個(gè)分析進(jìn)行驗(yàn)證,如果驗(yàn)證成功的話,就說(shuō)明這個(gè)匿名共享內(nèi)存成功地在Server端和Client端實(shí)現(xiàn)共享了。

     

            同樣,我們需要為這個(gè)Client端應(yīng)用程序編譯一個(gè)編譯腳本,在external/ashmem/client目錄下,新建一個(gè)Android.mk文件,它的內(nèi)容如下所示:

    LOCAL_PATH := $(call my-dir)
    
    include $(CLEAR_VARS)
    
    LOCAL_MODULE_TAGS := optional
    
    LOCAL_SRC_FILES := ../common/ISharedBuffer.cpp \
            SharedBufferClient.cpp
    
    LOCAL_SHARED_LIBRARIES:= libcutils libutils libbinder
    
    LOCAL_MODULE := SharedBufferClient
    
    include $(BUILD_EXECUTABLE)
           源代碼都準(zhǔn)備好了之后,就可以對(duì)Server端和Client端應(yīng)用程序進(jìn)行編譯了。關(guān)于如何單獨(dú)編譯Android源代碼工程中的模塊,以及如何打包system.img,請(qǐng)參考如何單獨(dú)編譯Android源代碼中的模塊一文。

     

           執(zhí)行以下命令進(jìn)行編譯和打包:

    USER-NAME@MACHINE-NAME:~/Android$ mmm external/ashmem/server   
    USER-NAME@MACHINE-NAME:~/Android$ mmm external/ashmem/client           
    USER-NAME@MACHINE-NAME:~/Android$ make snod 
           這樣,打包好的Android系統(tǒng)鏡像文件system.img就包含我們前面創(chuàng)建的Server端應(yīng)用程序SharedBufferServer和Client端應(yīng)用程序SharedBufferClient了。
           至此,我們就可以運(yùn)行模擬器來(lái)驗(yàn)證我們的程序了。關(guān)于如何在Android源代碼工程中運(yùn)行模擬器,請(qǐng)參考在Ubuntu上下載、編譯和安裝Android最新源代碼一文。
           執(zhí)行以下命令啟動(dòng)模擬器:

     

    USER-NAME@MACHINE-NAME:~/Android$ emulator  
           模擬器運(yùn)行起來(lái)后,就可以通過(guò)adb shell命令連上它:

     

    USER-NAME@MACHINE-NAME:~/Android$ adb shell  
           最后,進(jìn)入到/system/bin/目錄下:

     

    luo@ubuntu-11-04:~/Android$ adb shell
    root@android:/ # cd system/bin 
           進(jìn)入到/system/bin/目錄后,首先在后臺(tái)中運(yùn)行Server端應(yīng)用程序SharedBufferServer:

     

    root@android:/system/bin # ./SharedBufferServer &
           然后再在前臺(tái)中重復(fù)運(yùn)行Client端應(yīng)用程序SharedBufferClient,以便驗(yàn)證程序的正確性:

     

    root@android:/system/bin # ./SharedBufferClient                                
    The value of the shared buffer is 0.
    Add value 1 to the shared buffer.
    root@android:/system/bin # ./SharedBufferClient                                
    The value of the shared buffer is 1.
    Add value 1 to the shared buffer.
    root@android:/system/bin # ./SharedBufferClient                                
    The value of the shared buffer is 2.
    Add value 1 to the shared buffer.
    root@android:/system/bin # ./SharedBufferClient                                
    The value of the shared buffer is 3.
    Add value 1 to the shared buffer.
           如果我們看到這樣的輸出,就說(shuō)明我們成功地在Server端應(yīng)用程序SharedBufferServer和Client端應(yīng)用程序SharedBufferClietn共享內(nèi)存中的數(shù)據(jù)了。

     

           至此,Android系統(tǒng)匿名共享內(nèi)存的C++調(diào)用接口MemoryHeapBase和MemoryBase就分析完成了。

    作者:Luoshengyang 發(fā)表于2011-11-7 0:58:05 原文鏈接
    閱讀:4950 評(píng)論:6 查看評(píng)論
    posted on 2012-04-17 21:32 mixer-a 閱讀(3767) 評(píng)論(0)  編輯  收藏

    只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 亚洲欧洲日本天天堂在线观看| 亚洲国产精品VA在线看黑人| 成人自慰女黄网站免费大全| 二个人看的www免费视频| 国产精品免费观看调教网| 91九色老熟女免费资源站| 好爽又高潮了毛片免费下载| 亚洲AV无码不卡在线观看下载| 国产一精品一AV一免费孕妇| 国产又大又黑又粗免费视频| 妞干网免费视频观看| 亚洲国产一区明星换脸| 亚洲午夜未满十八勿入| 亚洲永久网址在线观看| 亚洲看片无码在线视频| 免费手机在线看片| 久久一区二区三区免费播放| 四虎影视成人永久免费观看视频 | 国产亚洲精品91| 亚洲AV无码精品国产成人| 亚洲精品无码成人片久久不卡| 特黄aa级毛片免费视频播放| 日韩在线一区二区三区免费视频| a级男女仿爱免费视频| 国产在线观看免费观看不卡| 拨牐拨牐x8免费| 久久国产成人精品国产成人亚洲| 精品国产人成亚洲区| 亚洲影视一区二区| 男女啪啪免费体验区| 91香蕉在线观看免费高清| 久久精品网站免费观看| 亚洲色大成网站WWW久久九九| 亚洲Av熟妇高潮30p| 亚洲大码熟女在线观看| 精品视频在线免费观看| 国产亚洲福利一区二区免费看| 亚洲福利在线视频| 国产综合成人亚洲区| 黄色网址免费观看| 中文字幕亚洲日本岛国片|