posts - 101,  comments - 29,  trackbacks - 0

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

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

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

                  1. MemoryHeapBase

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


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

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

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

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

                  IMemoryBase類主要定義了幾個重要的操作匿名共享內(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是用來獲得匿名共享內(nèi)存塊的打開文件描述符的;成員函數(shù)getBase是用來獲得匿名共享內(nèi)存塊的基地址的,有了這個地址之后,我們就可以在程序里面直接訪問這塊共享內(nèi)存了;成員函數(shù)getSize是用來獲得匿名共享內(nèi)存塊的大小的。
                  MemoryHeapBase類主要用來實現(xiàn)上面IMemoryBase類中列出來的幾個成員函數(shù)的,這個類聲明在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類的實現(xiàn)定義在frameworks/base/libs/binder/MemoryHeapBase.cpp文件中,我們先來看一下它的構(gòu)造函數(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òu)造函數(shù)有三個參數(shù),其中size表示要創(chuàng)建的匿名共享內(nèi)存的大小,flags是用來設(shè)置這塊匿名共享內(nèi)存的屬性的,例如是可讀寫的還是只讀的,name是用來標(biāo)識這個匿名共享內(nèi)存的名字的,可以傳空值進(jìn)來,這個參數(shù)只是作為調(diào)試信息使用的。

           

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

           

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

           

           

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

           

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

           

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

           

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

           

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

           

          int MemoryHeapBase::getHeapID() const {
              return mFD;
          }
          
          void* MemoryHeapBase::getBase() const {
              return mBase;
          }
          
          size_t MemoryHeapBase::getSize() const {
              return mSize;
          }
                 接下來我們再來看一下MemoryHeapBase在Client端實現(xiàn)的類圖:

           


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

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

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

                  這里我們主要關(guān)注BpMemoryHeap類是如何實現(xiàn)IMemoryHeap接口的,這個類聲明和定義在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;
          
          	......
          }
                  先來看構(gòu)造函數(shù)BpMemoryHeap的實現(xiàn):

           

           

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

           

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

           

          int BpMemoryHeap::getHeapID() const {
              assertMapped();
              return mHeapId;
          }
          
          void* BpMemoryHeap::getBase() const {
              assertMapped();
              return mBase;
          }
          
          size_t BpMemoryHeap::getSize() const {
              assertMapped();
              return mSize;
          }
                  即它們在使用之前,都會首先調(diào)用assertMapped函數(shù)來保證在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);
                  }
              }
          }
                 在解釋這個函數(shù)之前,我們需要先了解一下BpMemoryHeap是如何知道自己內(nèi)部維護(hù)的這塊匿名共享內(nèi)存有沒有準(zhǔn)備就緒的。
                 在frameworks/base/libs/binder/IMemory.cpp文件中,定義了一個全局變量gHeapCache:

           

           

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

           

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

                 我們來看一下HeapCache的實現(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;
          };
                 它里面定義了一個成員變量mHeapCache,用來維護(hù)本進(jìn)程中的所有BpMemoryHeap對象,同時還提供了find_heap和get_heap函數(shù)來查找內(nèi)部所維護(hù)的BpMemoryHeap對象的功能。函數(shù)find_heap和get_heap的區(qū)別是,在find_heap函數(shù)中,如果在mHeapCache找不到相應(yīng)的BpMemoryHeap對象,就會把這個BpMemoryHeap對象加入到mHeapCache中去,而在get_heap函數(shù)中,則不會自動把這個BpMemoryHeap對象加入到mHeapCache中去。

           

                 這里,我們主要看一下find_heap函數(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;
              }
          }
                  這個函數(shù)很簡單,首先它以傳進(jìn)來的參數(shù)binder為關(guān)鍵字,在mHeapCache中查找,看看是否有對應(yīng)的heap_info對象info存在,如果有的話,就增加它的引用計數(shù)info.count值,表示這個BpBinder對象多了一個使用者;如果沒有的話,那么就需要創(chuàng)建一個heap_info對象info,并且將它加放到mHeapCache中去了。

           

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

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

           

          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來直正執(zhí)行查找的操作:

           

           

          class BpMemoryHeap : public BpInterface<IMemoryHeap>
          {	
          ......
          
          private:
          	static inline sp<IMemoryHeap> find_heap(const sp<IBinder>& binder) {
          		return gHeapCache->find_heap(binder);
          	}
          
          	......
          }
                  注意,這里通過find_heap函數(shù)得到BpMemoryHeap對象可能是和正在執(zhí)行assertMapped函數(shù)中的BpMemoryHeap對象一樣,也可能不一樣,但是這沒有關(guān)系,這兩種情況的處理方式都是一樣的,都是通過調(diào)用這個通過find_heap函數(shù)得到BpMemoryHeap對象的assertReallyMapped函數(shù)來進(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,就說明還沒有把在Server端的MemoryHeapBase對象中的匿名共享內(nèi)存映射到本進(jìn)程空間來,于是,就通過一個Binder進(jìn)程間調(diào)用把Server端的MemoryHeapBase對象中的匿名共享內(nè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 );
          		
          ......
                  取回來的信息包括MemoryHeapBase對象中的匿名共享內(nèi)存在本進(jìn)程中的文件描述符fd、大小size以及訪問屬性flags。如何把MemoryHeapBase對象中的匿名共享內(nèi)存作為本進(jìn)程的一個打開文件描述符,請參考前面一篇文章Android系統(tǒng)匿名共享內(nèi)存Ashmem(Anonymous Shared Memory)在進(jìn)程間共享的原理分析。有了這個文件描述符fd后,就可以對它進(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)判斷過mHeapId是否為-1了,這里為什么又要重新判斷一次呢?這里因為,在上面執(zhí)行Binder進(jìn)程間調(diào)用的過程中,很有可能也有其它的線程也對這個BpMemoryHeap對象執(zhí)行匿名共享內(nèi)存映射的操作,因此,這里還要重新判斷一下mHeapId的值是否為-1,如果是的話,就要執(zhí)行匿名共享內(nèi)存映射的操作了,這是通過調(diào)用mmap函數(shù)來進(jìn)行的,這個函數(shù)我們前面在分析MemoryHeapBase類的實現(xiàn)時已經(jīng)見過了。

           

                  從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,就說明這個heap對象中的匿名共享內(nèi)存已經(jīng)映射好了。進(jìn)入到里面的if語句,如果本BpMemoryHeap對象中的mHeap成員變量的值不等待-1,就說明前面通過find_heap函數(shù)得到的BpMemoryHeap對象和正在執(zhí)行assertMapped函數(shù)的BpMemoryHeap對象是同一個對象了,因此,什么也不用做就可以返回了,否則的話,就要初始化一下本BpMemoryHeap對象的相關(guān)成員變量了:

           

           

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

           

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

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

                  2. MemoryBase

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


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

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

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


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

                  IMemory類定義了MemoryBase類所需要實現(xiàn)的接口,這個類定義在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用來獲取內(nèi)部的MemoryHeapBase對象的IMemoryHeap接口;成員函數(shù)pointer()用來獲取內(nèi)部所維護(hù)的匿名共享內(nèi)存的基地址;成員函數(shù)size()用來獲取內(nèi)部所維護(hù)的匿名共享內(nèi)存的大小;成員函數(shù)offset()用來獲取內(nèi)部所維護(hù)的這部分匿名共享內(nèi)存在整個匿名共享內(nèi)存中的偏移量。

           

                  IMemory類本身實現(xiàn)了pointer、size和offset三個成員函數(shù),因此,它的子類,即MemoryBase類,只需要實現(xiàn)getMemory成員函數(shù)就可以了。IMemory類的實現(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類實現(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ù)中,接受三個參數(shù),參數(shù)heap指向的是一個MemoryHeapBase對象,真正的匿名共享內(nèi)存就是由它來維護(hù)的,參數(shù)offset表示這個MemoryBase對象所要維護(hù)的這部分匿名共享內(nèi)存在整個匿名共享內(nèi)存塊中的起始位置,參數(shù)size表示這個MemoryBase對象所要維護(hù)的這部分匿名共享內(nèi)存的大小。

           

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

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

                  下面我們再來看MemoryBase類在Client端的實現(xiàn),同樣,先看它們的類圖關(guān)系:


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

                  BpMemory類實現(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類一樣,它實現(xiàn)了IMemory類的getMemory成員函數(shù),在它的成員變量中,mHeap的類型為IMemoryHeap,它指向的是一個BpMemoryHeap對象,mOffset表示這個BpMemory對象所要維護(hù)的這部分匿名共享內(nèi)存在整個匿名共享內(nèi)存塊中的起始位置,mSize表示這個BpMemory對象所要維護(hù)的這部分匿名共享內(nèi)存的大小。

           

                 下面我們就看一下BpMemory類的成員函數(shù)getMemory的實現(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,就表示這個BpMemory對象尚未建立好匿名共享內(nèi)存,于是,就會通過一個Binder進(jìn)程間調(diào)用去Server端請求匿名共享內(nèi)存信息,在這些信息中,最重要的就是這個Server端的MemoryHeapBase對象的引用heap了,通過這個引用可以在Client端進(jìn)程中創(chuàng)建一個BpMemoryHeap遠(yuǎn)程接口,最后將這個BpMemoryHeap遠(yuǎn)程接口保存在成員變量mHeap中,同時,從Server端獲得的信息還包括這塊匿名共享內(nèi)存在整個匿名共享內(nèi)存中的偏移位置以及大小。這樣,這個BpMemory對象中的匿名共享內(nèi)存就準(zhǔn)備就緒了。

           

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

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

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

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

                  首先來看common模塊中的服務(wù)接口的定義。在external/ashmem/common目錄下,有兩個源文件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
                  這個文件定義了一個ISharedBuffer接口,里面只有一個成員函數(shù)getBuffer,通過這個成員函數(shù),Client端可以從Server端獲得一個匿名共享內(nèi)存,這塊匿名共享內(nèi)存通過我們上面分析的MemoryBase類來維護(hù)。這個文件同時也定義了一個必須要在Server端實現(xiàn)的BnSharedBuffer接口,它里面只有一個成員函數(shù)onTransact,這個成員函數(shù)是用來處理Client端發(fā)送過來的請求的。除了定義這兩個接口之外,這個文件還定義了兩個公共信息,一個是定義常量SHARED_BUFFER_SERVICE,它是Server端提供的內(nèi)存共享服務(wù)的名稱,即這個內(nèi)存共享服務(wù)在Service Manager中是以SHARED_BUFFER_SERVICE來作關(guān)鍵字索引的,另外一個是定義常量SHARED_BUFFER_SIZE,它定義了Server端共享的內(nèi)存塊的大小,它的大小設(shè)置為4個字節(jié),在這個例子,將把這個共享內(nèi)存當(dāng)作一個整型變量來訪問。

           

                  源代文件ISharedBuffer.cpp文件定義了一個在Client端使用的BpSharedBuffer接口,它是指向運行在Server端的實現(xiàn)了ISharedBuffer接口的內(nèi)存共享服務(wù)的遠(yuǎn)程接口,同時,在這個文件里面,也實現(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ā)出了一個請求代碼為GET_BUFFER的Binder進(jìn)程間調(diào)用請求,請求Server端返回一個匿名共享內(nèi)存對象的遠(yuǎn)程接口IMemory,它實際指向的是一個BpMemory對象,獲得了這個對象之后,就將它返回給調(diào)用者;在BnSharedBuffer類的成員函數(shù)onTransact中,當(dāng)它接收到從Client端發(fā)送過來的代碼為GET_BUFFER的Binder進(jìn)程間調(diào)用請求后,便調(diào)用其子類的getBuffer成員函數(shù)來獲一個匿名共享內(nèi)存對象接口IMemory,它實際指向的是一個MemoryBase對象,獲得了這個對象之后,就把它返回給Client端。

           

                  接下來,我們再來看看server模塊的實現(xiàn)。在external/ashmem/common目錄下,只有一個源文件SharedBufferServer.cpp,它實現(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ù)實現(xiàn)了BnSharedBuffer接口。在它的構(gòu)造函數(shù)里面,首先是使用MemoryHeapBase類創(chuàng)建了一個匿名共享內(nèi)存,大小為SHARED_BUFFER_SIZE。接著,又以這個MemoryHeapBase對象為參數(shù),創(chuàng)建一個MemoryBase對象,這個MemoryBase對象指定要維護(hù)的匿名共享內(nèi)存的的偏移位置為0,大小為SHARED_BUFFER_SIZE,并且,將這個匿名共享內(nèi)存當(dāng)作一個整型變量地址,將它初始化為0。最終,這個匿名共享內(nèi)存對象保存在SharedBufferService類的成員變量mMemory中,這個匿名共享內(nèi)存對象可以通過成員函數(shù)getBuffer來獲得。

           

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

                 我們還需要為這個Server端應(yīng)用程序編譯一個編譯腳本,在external/ashmem/server目錄下,新建一個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)
                  最后,我們再來看看client模塊的實現(xiàn)。在external/ashmem/client目錄下,只有一個源文件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;
          }
                  在這個文件中,主要就是定義了Client端應(yīng)用程序的入口函數(shù)main,在這個main函數(shù)里面,首先通過Service Manager接口獲得前面所實現(xiàn)的匿名共享內(nèi)存服務(wù)SharedBufferService的遠(yuǎn)程接口service,然后通過這個遠(yuǎn)程接口的getBuffer成員函數(shù)獲得由Server端提供的一塊匿名共享內(nèi)存接口buffer,最后通過這個匿名共享內(nèi)存接口獲得這個匿名共享內(nèi)存的基地址data。有了這個匿名共享內(nèi)存的地址data之后,我們就可以對它進(jìn)行讀寫了,先是把這個匿名共享內(nèi)存當(dāng)作是一個整型變量地址進(jìn)行訪問,并輸出它的值的大小,然后對這個整量變量進(jìn)行加1的操作,并寫回到原來的共享內(nèi)存空間中去。這樣,當(dāng)Server端應(yīng)用程序運行之后,第一次運行這個Client端應(yīng)用程序時,輸出的值為0,第二次運行這個個Client端應(yīng)用程序時,輸出的值為1,第三次運行這個個Client端應(yīng)用程序時,輸出的值為3......依次類推,后面我們將在模擬器中對這個分析進(jìn)行驗證,如果驗證成功的話,就說明這個匿名共享內(nèi)存成功地在Server端和Client端實現(xiàn)共享了。

           

                  同樣,我們需要為這個Client端應(yīng)用程序編譯一個編譯腳本,在external/ashmem/client目錄下,新建一個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)備好了之后,就可以對Server端和Client端應(yīng)用程序進(jìn)行編譯了。關(guān)于如何單獨編譯Android源代碼工程中的模塊,以及如何打包system.img,請參考如何單獨編譯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了。
                 至此,我們就可以運行模擬器來驗證我們的程序了。關(guān)于如何在Android源代碼工程中運行模擬器,請參考在Ubuntu上下載、編譯和安裝Android最新源代碼一文。
                 執(zhí)行以下命令啟動模擬器:

           

          USER-NAME@MACHINE-NAME:~/Android$ emulator  
                 模擬器運行起來后,就可以通過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/目錄后,首先在后臺中運行Server端應(yīng)用程序SharedBufferServer:

           

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

           

          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.
                 如果我們看到這樣的輸出,就說明我們成功地在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 評論:6 查看評論
          posted on 2012-04-17 21:32 mixer-a 閱讀(3769) 評論(0)  編輯  收藏

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


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 且末县| 栾城县| 丰原市| 泰安市| 扎囊县| 忻城县| 贡觉县| 焉耆| 英吉沙县| 自贡市| 廉江市| 金塔县| 丹阳市| 大同县| 本溪市| 金华市| 佳木斯市| 美姑县| 得荣县| 来宾市| 宣城市| 元江| 眉山市| 巴南区| 集贤县| 日喀则市| 洞口县| 虎林市| 祁东县| 云梦县| 吴桥县| 拉孜县| 陵川县| 古丈县| 江达县| 罗平县| 洛浦县| 大连市| 黄浦区| 洞头县| 布拖县|