這篇文章給大家介紹Android中怎么利用Binder機制實現進程間通信,內容非常詳細,感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。
第一步:獲取ManagerService服務代理BpBinder(0)和BpManagerService
第二步:通過BpManagerService中得addService方法將服務的一些信息打包,然后通過BpBinder(0)將信息發送到內核,等待ManagerService進程來讀取,因為ManagerService進程中有一個Loop一直讀取內核信息,所以很快就獲取了service發給內核的信息,ManagerService進程就將service服務的一些信息添加到維護的列表中,將添加的結果發送給內核,然后service等到內核有回復后返回,將返回的信息解碼分析。
第三步:執行一個Loop來從內核讀取client的請求
代碼
如下是添加一個service的代碼
第一步:
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm = defaultServiceManager();
第二步:
defaultServiceManager()->addService(String16("media.player"),new MediaPlayerService());
第三步:
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
代碼分析
sp<ProcessState> proc(ProcessState::self());
創建一個ProcessState實例
ProcessState::mDriverFD=open_driver()
ProcessState::mVMstart = mmap(…,mDriverFD,…);
mmap(0,…,mDriverFD,0);//只是讓通信更快,可以當作沒有,直接用read/write(mDriverFD);
sp<IServiceManager> sm = defaultServiceManager();
主要執行如下代碼
sp<IServiceManager> gDefaultServiceManager =interface_cast<IServiceManager>(PorcessState::self()->getContextObject(NULL));
其中PorcessState::self()->getContextObject(NULL)就是執行PorcessState::getStrongProxyForHandle(0);其主要是根據給定的參數(此處為0)創建對應的sp<IBinder> b = new BpBinder(0);
這邊先說明interface_case這個模版類,這個模版類作用是將服務xxxService對應的BpBinder(x)轉化為對應的BpxxxService如下:
sp<IxxxService> BpxxxService= interface_cast<IxxxService>(newBpBinder(x));
其本質是調用給定類型參數的asInterface方法,也就是IxxxService::asInterface(new BpBinder(x)),IxxxService繼承publicIInterface
IxxxService用宏DECLARE_META_INTERFACE(xxxService)和IMPLEMENT_META_INTERFACE(xxxService,”android.os.IxxxService”)來實現asInterface方法,展開后如 new BpxxxService(new BpBinder(x)),這樣就從BpBinder(x)得到了BpxxxService
如本例中給定的類型參數是IServiceManager,所以上述等價于
sp<IServiceManager> gDefaultServiceManager =IServiceManager::asInterface(new BpBinder(0)); IServiceManager繼承publicIInterface
其中用宏DECLARE_META_INTERFACE(ServiceManager) 和IMPLEMENT_META_INTERFACE(ServiceManager,”android.os.IServiceManager”)來實現asInterface方法,這個asInterface方法最終執行new BpServiceManager(new BpBinder(0));
也就是sp<IServiceManager> sm = newBpServiceManager(new BpBinder(0));
由此得到BpBinder(0)和BpServiceManager
從這里可以得出,如果自己創建服務xxxService,按如下步驟
創建類 class IxxxService:publice IInterface
{
DECLARE_META_INTERFACE(xxxService);//聲明asInterface方法
virtual function();//虛函數,由BpxxxService實現
…
}
IMPLEMENT_META_INTERFACE(xxxService,”android.os.IxxxService”);//定義asInterface
展開相當于sp<IxxxService>IxxxService::asInterface(BpBinder){
return new BpxxxService
}
當有這個服務的Bpbinder(x)后可通過如下獲取BpxxxService
sp<IxxxService>sm = new BpxxxService (new BpBinder(x));
注意:
1:BpxxxService類型為sp<IxxxService>
2:BpBinder(x)相當于xxxService對應binder實體的代理
3:客戶端為什么要通過BpBinder(X)再創建一個BpxxxService呢?因為BpxxxService對象的基類中的一個mRemote變量就是Bpbinder(x),那為什么不直接用BpBinder(x)呢?因為BpxxxService對象中還實現了一些BpBinder(x)沒有的業務邏輯(實現基類IxxxService中的方法)如BpServiceManager中提供了addService方法,這些方法在服務端有對應的服務,如addService方法將請求的命令”addService”和數據打包成Parcel類型,然后通過BpBinder(x)發送給xxxService,其實先發給驅動中binder設備,xxxService服務中會有Loop循環一直讀取binder設備的消息,讀取消息后解析成命令+數據,然后根據命令如”addService”會調取對應的服務,然后將結果反饋給binder設備,客戶端接收到binder設備的反饋后將返回的數據也解析成命令+數據,然后根據命令和數據執行相應的邏輯
客戶端 通過BpxxxService中方法將數據打包 -->Bpbinder(x)--> binder設備 --> 服務端Loop 獲取數據解析成命令+數據-->調取命令指定的服務其中會涉及BBinder和BnxxxService,返回數據
客戶端 解析返回的數據并執行相應邏輯 <--Bpbinder(x)<-- binder設備 <-- 服務端返回數據
由上可知,創建的服務還需創建BnxxxService和BpxxxService
class BpxxxService : public BpInterface<IxxxService>
{
…
vitural function(){
Parcel data,reply;
data.writeInterfaceToken(IxxxService::getInterfaceDescriptor());
data.writeInt32(pid);
remote()->transact(命令碼,data,&reply);
}
}
class BnxxxService: public BnInterface<IxxxService>
{
public:
vitrual status_t onTransact(uint32_tcode,const Parcel& data,Parcel* reply,uint32_t flags = 0);
}
IMPLEMENT_META_INTERFACE(xxxService,”android.xxxService.IxxxService”);
status_t BnxxxService::onTransact(uint32_tcode,const Parcel& data,Parcel* reply,uint32_t flags)
{
switch(code){
case 命令碼:
CHECK_INTERFACE(IxxxService,data,reply);
function()//自己實現的邏輯
break;
…
}
defaultServiceManager()->addService(String16("media.player"),new MediaPlayerService());
通過BpServiceManager(類型為sp<IServiceManager>)將數據打包成含”addService”命令,類型為parcel data的數據,調用BpBinder(0)這個對象的transact(),最終調到IPCThreadState::self()->transact(),
下面分析IPCThreadState,你暫時只需要知道每個線程有一個IPCThreadState實例,實例有屬性mIn,mOut,其中mIn用來接受來自binder設備的parcel類型數據,mOut用來存儲發往binder設備的parcel類型數據,IPCThreadState::self()->transact()最終完成與binder設備的交互,這個接口中先調用writeTransactionData把parcel類型的數據和int32_t類型的命令碼封裝成binder_transaction_data類型數據放到IPCThreadState實例的mOut中去,接下來IPCThreadState::self()->transact()會調用IPCThreadState::self()->waitForResponse接口,其中會調用talkWithDriver()與binder設備交換數據(talkwithDriver主要是實現是ioctl(mProcess->mDriverFD,BINDER_WRITE_READ, &bwr)),將返回來的數據存于IPCThreadState實例的mIn,然后調用executeCommand()根據mIn中得命令碼和數據來解析,來調用各種業務邏輯
ServiceManager這個服務的Loop循環實現代碼見下面:
struct binder_state *bs;
void *svcmgr = BINDER_SERVICE_MANAGER;
bs = binder_open(128*1024);//應該是打開binder設備吧
binder_become_context_manager(bs) //成為manager
svcmgr_handle = svcmgr;
binder_loop(bs, svcmgr_handler);//Loop
new MediaPlayerService(),MediaPlayerService繼承BnMediaPlayService,BnMediaPlayService繼承BnInterface, BnInterface繼承BBinder ,BBinder繼承 IBinder,所以MediaPlayerService繼承了IBinder,addService第二個參數類型是IBinder 實例一個MediaPlayService也就是實例一個BnMediaPlaySerivce
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
創建一個MediaPlayerService服務后(也就是創建一個BnMediaPlaySerivce)后,將其加入serviceManage維護的一個列表中,接下來,BnMediaPlaySerivce也該起到服務的作用,創建一個Loop等待客戶端client的請求,所以應該也有一個循環,也就是如下兩段代碼的作用
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
先分析ProcessState::self()->startThreadPool();
其調用
sp<Thread> t = new PoolThread(isMain);isMain是TRUE
t->run(buf);//這句話會導致t->threadLoop調用,這里面執行了IPCThreadState::self()->joinThreadPool(mIsMain);
所以歸根結底最后都調用IPCThreadState::self()->joinThreadPool(mIsMain);
這里面主要是執行一個循環,
do {
int32_tcmd;
result =talkWithDriver();
result =executeCommand(cmd);
}
} while (result != -ECONNREFUSED && result !=-EBADF);
總結:調用talkWithDriver()與binder設備交換數據(talkwithDriver主要是實現是ioctl(mProcess->mDriverFD,BINDER_WRITE_READ, &bwr)),將返回來的數據存于IPCThreadState實例的mIn,然后調用executeCommand()根據mIn中得命令碼和數據來解析,來調用自己(此處是BnMediaPlaySerivce)的各種業務邏輯,例如如果受到的命令是BR_TRANSACTION則會調用reinterpret_cast<BBinder*>(tr.cookie)->transact(tr.code,buffer, &reply, tr.flags);結果調用BnMediaPlaySerivce的oNTransact方法
這里面會根據獲取的mIn中得命令碼和數據來調用不同的業務邏輯,然后派發到派生類MediaService(自己創建的)的函數,由他們完成實際的工作
常用有如下情形2:client訪問某個服務service
過程
第一步:獲取ManagerService服務代理BpBinder(0)和BpManagerService
第二步:通過BpManagerService中得getService方法將服務的一些信息打包,然后通過BpBinder(0)將信息發送到內核,等待ManagerService進程來讀取,因為ManagerService進程中有一個Loop一直讀取內核信息,所以很快就獲取了client發給內核的信息,ManagerService進程將client想知道的東西發送給內核,client等到內核有回復后返回,將返回的信息解碼分析已得知有無某個service服務,如果有這個service則返回的信息中有這個service的Bpbinder(x),client可以通過sp<Iservice>Bpservice = interface_cast<Iservice>( Bpbinder(x));來獲取BpService,BpService中有與service對應的服務
第三步:訪問服務
client訪問這些服務前先調BpService中對應特定服務其將數據及命令打包,通過Bpbinder(x)將信息發送到內核,應為service也有一個Loop一直在讀取內核信息,所以service很快就獲取了client發來的信息,解析后根據信息中得命令碼將數據發送到Bnservice對象包含的方法中進行解析,然后將處理后的數據發送給內核,client等到內核的受到的消息后返回,將返回的消息解碼然后處理
代碼
如下是client獲取service的的代碼
第一步:
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm=defaultServiceManager();
見上
第二步:
sp<IBinder> binder = sm->getServices(String16(“media.player”));
sp<IMediaPlayService> sMediaPlayService =interface_cast<IMediaPlayService>(binder);
關于Android中怎么利用Binder機制實現進程間通信就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。