Hi3516的SAMGR--系統(tǒng)服務(wù)框架子系統(tǒng)-11-Client與Client的IPC來(lái)往
想了解更多內(nèi)容,請(qǐng)?jiān)L問(wèn):
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)
進(jìn)程A中的線程Aa(也就是service Aa)想要調(diào)用某個(gè)service/feature的接口,這個(gè)接口可能是進(jìn)程A自己的線程Ab(也就是service Ab)提供的,也可能是進(jìn)程B的線程Bc(也就是service Bc)提供的。
如果是同進(jìn)程的不同服務(wù)提供的接口,那Aa只需要向自己進(jìn)程的SamgrLiteImpl g_samgrImpl查詢(xún)service/feature名字就可以拿到對(duì)應(yīng)的IUnknown *iUnknown接口,因?yàn)槭峭M(jìn)程內(nèi)的相同虛擬地址空間,所以可以直接跨線程調(diào)用。如《系統(tǒng)服務(wù)框架子系統(tǒng)-4-面向服務(wù)架構(gòu)的實(shí)現(xiàn)》中的測(cè)試程序所做的那樣。
也就是通過(guò)調(diào)用SAMGR_GetInstance()->GetDefaultFeatureApi(SERVICE_NAME) 或者SAMGR_GetInstance()->FeatureApi(SERVICE_NAME,F(xiàn)EATURE_NAME)來(lái)查詢(xún)接口。
如果Aa想調(diào)用的service/feature接口是B進(jìn)程提供的,那首先這個(gè)service,肯定在Aa所在進(jìn)程的SamgrLiteImpl g_samgrImpl里面是找不到記錄的,也就是serviceImpl = NULL:

所以,跨進(jìn)程的服務(wù)/特性的調(diào)用,入口就在上面的SAMGR_FindServiceApi(service, feature)。
結(jié)合我們的log,搜索一下“%%%%%%%%%%%”這樣一個(gè)字符串,這是我標(biāo)記的一處入口(實(shí)際上搜索“SAMGR_FindServiceApi”也差不多)。
看一下log:
- {[bundle_daemon_client]} Initialize: GetDefaultFeatureApi(bundle_daemon)
這是“bundle_daemon_client”在Initialize的時(shí)候,向自己所在進(jìn)程的SamgrLiteImpl g_samgrImpl查詢(xún)名字為“bundle_daemon”的服務(wù)的DefaultFeatureApi。
通過(guò)前后的log,我們可以知道bundle_daemon_client所在進(jìn)程的信息“pid[ 5]/uid[ 7]/(*)handle[61](*)”,5號(hào)進(jìn)程是“foundation”,而“bundle_daemon”服務(wù)是6號(hào)進(jìn)程提供的。
所以會(huì)通過(guò)SAMGR_FindServiceApi(S[bundle_daemon],F[(null)])來(lái)查詢(xún)“bundle_daemon”服務(wù)提供的接口。
SAMGR_FindServiceApi()及其輔助函數(shù),涉及到了g_remoteRegister.clients 這個(gè)字段,我們先來(lái)理解一下。
這是一個(gè)向量,在本進(jìn)程的 g_remoteRegister 初始化的時(shí)候,也對(duì)這個(gè)向量做了配置:
- g_remoteRegister.clients = VECTOR_Make((VECTOR_Key)SAMGR_GetSAName, (VECTOR_Compare)SAMGR_CompareSAName);
向量的element:data[x]是一個(gè)IUnknown *proxy類(lèi)型的指針,指向的是一個(gè)客戶端代理的接口entry.iUnknown,通過(guò)這個(gè)指針,可以轉(zhuǎn)換回IClientProxy類(lèi)對(duì)象、IClientEntry類(lèi)對(duì)象、IDefaultClient類(lèi)對(duì)象,再通過(guò)IClientProxy類(lèi)對(duì)象指針去訪問(wèn)后面的Invoke函數(shù),或者通過(guò)IDefaultClient類(lèi)對(duì)象指針去訪問(wèn)上面的IClientHeader header字段內(nèi)的key、target等字段。
向量中每一個(gè)element,記錄了本進(jìn)程EP調(diào)用過(guò)的別的進(jìn)程提供的服務(wù)接口相關(guān)的重要身份信息如名字、handle、token等,這樣下次再調(diào)用的時(shí)候,直接在這里查詢(xún)就能獲得這些信息,不需要再次通過(guò)IPC去向samgr EP查詢(xún)了,它的展開(kāi)圖如下:

SAMGR_FindServiceApi()的流程如下:


我們接著上面的log往下看一下,

這是第一次bundle_daemon_client 向samgr EP查詢(xún)FeatureAPI,但是返回的 handle 是 -1,從接下來(lái)的DbgParse_g_server的信息來(lái)看,這個(gè)時(shí)候提供bundle_daemon服務(wù)的6號(hào)進(jìn)程,還沒(méi)有向samge EP注冊(cè)EP和Feature,所以samgr EP自己也查不到。
再看第二次bundle_daemon_client 向samgr EP查詢(xún)FeatureAPI,這回查到了,handle是38,token是0,也就是說(shuō),SAMGR_CreateIProxy()的第一步,拿到了SvcIdentity identity= {38, 0, 0},跟著接下來(lái)的流程跑,就會(huì)得到一個(gè)完整有效的IDefaultClient對(duì)象,把這個(gè)對(duì)象中的 .iUnknown 地址先保存到g_remoteRegister.clients 向量中去,然后通過(guò)這個(gè).iUnknown 地址,就可以調(diào)用客戶端代理的Invoke()接口,從而再通過(guò)IPC去遠(yuǎn)程調(diào)用bundle_daemon服務(wù)了。

Privider: Pid[6]/Uid[8]/handle[38]:bundle_daemon -> (null)Consumer: Pid[5]/Uid[7]/Tid[53]
從這兩句log可以看出,6號(hào)進(jìn)程的bundle_daemon 服務(wù)是provider,查詢(xún)并使用該服務(wù)的5號(hào)進(jìn)程是consumer,這也是面向服務(wù)的架構(gòu)的一種實(shí)現(xiàn)。
我們?cè)倏戳硗庖粋€(gè)更明顯的跨進(jìn)程調(diào)用服務(wù)的例子:第一個(gè)應(yīng)用進(jìn)程launcher的孵化啟動(dòng)。
Log搜索“AppAppAppApp”,這是5號(hào)進(jìn)程通過(guò)app_manager準(zhǔn)備調(diào)用7號(hào)進(jìn)程提供的“appspawn”服務(wù)來(lái)孵化launcher應(yīng)用,它拿到了“appspawn”的handle 74、token 0和.iUnknown地址,并把該地址以及相關(guān)的重要信息添加到自己的clients向量中。


接下來(lái)app_spawn_client調(diào)用上面的Invoke{0x249cc84c},這個(gè)Invoke{0x249cc84c}就是ProxyInvoke()函數(shù),通過(guò)它發(fā)送IPC消息給IpcMsg Rceiver::handle[74],token[0],讓它的EP收到和處理該消息,這就到了上一小節(jié)提到的Dispatch()和HandleIpc()對(duì)IPC消息的處理流程了。

經(jīng)過(guò)消息的轉(zhuǎn)發(fā)和處理,最后是appspawn_service的Invoke()函數(shù)開(kāi)始孵化launcher應(yīng)用進(jìn)程,桌面應(yīng)用開(kāi)始提供服務(wù)。
跨進(jìn)程的服務(wù)接口調(diào)用到此結(jié)束。
剛好剛才去瀏覽標(biāo)準(zhǔn)系統(tǒng)的 //base/startup/appspawn_standard/目錄,看了一下README_zh,看到下面這張圖就貼過(guò)來(lái)了,除了通信方式不一樣之外,大體流程是一樣的。

想了解更多內(nèi)容,請(qǐng)?jiān)L問(wèn):
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)