溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Android中怎么利用Binder機制實現進程間通信

發布時間:2021-06-28 14:59:38 來源:億速云 閱讀:208 作者:Leah 欄目:互聯網科技

這篇文章給大家介紹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機制實現進程間通信就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女