Hi3861的SAMGR--系統(tǒng)服務(wù)框架子系統(tǒng)-2
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)
接前文《Hi3861的SAMGR--系統(tǒng)服務(wù)框架子系統(tǒng)-1》
4 結(jié)構(gòu)體的分解
4.1 先上samgr的展開圖【附件有原圖】
4.2 Samgr:SamgrLiteImpl g_samgrImpl
- typedef struct SamgrLiteImpl SamgrLiteImpl;
- struct SamgrLiteImpl {
- A: SamgrLite vtbl; //SAMGR_GetInstance() return this SamgrLite Instance
- B: MutexId mutex;
- C: BootStatus status; //see BootStatus
- D: Vector services; //a vector to record all services
- E: TaskPool *sharedPool[MAX_POOL_NUM];
- };
注冊(cè)第一個(gè)服務(wù)的時(shí)候,首先要通過SAMGR_GetInstance()從全局變量g_samgrImpl獲取一個(gè)samgr的實(shí)例對(duì)象,g_samgrImpl已經(jīng)初始化過了的話,可以直接返回samgr對(duì)象的引用,g_samgrImpl沒有初始化的話,就需要通過Init函數(shù)進(jìn)行初始化相關(guān)的配置之后,才能返回samgr對(duì)象的引用。
以后的各種service/feature的操作,基本是都是需要通過g_samgrImpl進(jìn)行管理的。下面把這個(gè)全局變量展開來看一下:
A: SamgrLite vtbl;
vtbl 就是SamgrLite 的實(shí)例,SAMGR_GetInstance() 時(shí),返回的就是指向它的指針。SamgrLite結(jié)構(gòu)體(或者直接說類)定義了四組十個(gè)函數(shù)指針,如下圖,同一組用同一個(gè)顏色框起來:
在g_samgrImpl的初始化(init)時(shí)與對(duì)應(yīng)的實(shí)現(xiàn)函數(shù)對(duì)應(yīng)關(guān)聯(lián)起來,之后就可以通過這四組函數(shù)來對(duì)service/ feature進(jìn)行注冊(cè)、注銷、獲取API等操作了。
而具體的service、feature在各自INIT時(shí),會(huì)通過g_samgrImpl的samgr實(shí)例調(diào)用這里的Register接口,向g_samgrImpl注冊(cè)自己和API,把自己納入samgr的管理體系中,然后就是samgr為service、feature創(chuàng)建queue/taskpool/task等運(yùn)行環(huán)境了。
B: MutexId mutex;
互斥鎖。關(guān)鍵代碼段的操作要加鎖,保證多線程下對(duì)共享數(shù)據(jù)的操作的完整性。
在g_samgrImpl的初始化(init)時(shí)就會(huì)通過MUTEX_InitValue() 生成互斥鎖,MUTEX_InitValue()聲明在thread_adapter.h,它的實(shí)現(xiàn)則取決于平臺(tái)使用的內(nèi)核,M核平臺(tái)用cmsis接口來實(shí)現(xiàn),A核/Linux平臺(tái),則使用posix接口來實(shí)現(xiàn)。
類似的還有內(nèi)存、隊(duì)列、線程、timer的相關(guān)操作,代碼見:
- Hi3861/foundation/distributedschedule/samgr_lite/samgr/adapter/
理論上,全局對(duì)象g_samgrImpl初始化(init)時(shí)就會(huì)生成一個(gè)mutex,且只要g_samgrImpl沒有重新初始化,這個(gè)mutex就應(yīng)該是不變的,Hi3861平臺(tái)上我看到的也確實(shí)如此。
但是Hi3516平臺(tái)上我看到了一個(gè)奇怪的地方,見前文《鴻蒙系統(tǒng)框架層的啟動(dòng)細(xì)節(jié)》的附件log,搜索關(guān)鍵字“SAMGR_GetInstance|StartServiceByName|Invoke: msg”可以看到:
有若干處mutex是為NULL的,需要重新初始化g_samgrImpl,這樣豈不是會(huì)把之前注冊(cè)的service Vector/TaskPool等清除掉嗎?先存疑,待進(jìn)一步仔細(xì)閱讀Hi3516的代碼后再確認(rèn)。
C: BootStatus status;
系統(tǒng)的啟動(dòng)階段狀態(tài)標(biāo)記。
Hi3861平臺(tái)上電啟動(dòng)到 system_init.c 的
- void HOS_SystemInit(void)
- {
- ......
- SYS_INIT(service);
- SYS_INIT(feature);
- SAMGR_Bootstrap();
- }
這一步時(shí),通過SYS_INIT() 啟動(dòng)的都是用SYS_SERVICE_INIT()和SYS_FEATURE_INIT() 標(biāo)記的service和feature,而通過SYSEX_SERVICE_INIT/APP_SERVICE_INIT/ SYSEX_FEATURE_INIT/APP_FEATURE_INIT 標(biāo)記的service和feature,則會(huì)在系統(tǒng)啟動(dòng)到 BOOT_APP 這一步時(shí),由Bootstrap service來啟動(dòng),見 bootstrap_service.c 的MessageHandle()函數(shù)內(nèi)的 INIT_APP_CALL() 的調(diào)用:
系統(tǒng)啟動(dòng)狀態(tài)標(biāo)記到 BOOT_DYNAMIC 這一步時(shí),意味著系統(tǒng)所有的應(yīng)用服務(wù)也啟動(dòng)完畢了,進(jìn)入了一個(gè)比較穩(wěn)定的狀態(tài),至于BOOT_DYNAMIC狀態(tài)還會(huì)做其他什么事情,我暫時(shí)還沒有更多的了解。
為了理解例程代碼如何工作,我在這里加了 BOOT_DEBUG和BOOT_DEBUG_WAIT兩個(gè)狀態(tài),用來調(diào)用例程里的INIT_TEST_CALL(),跑相關(guān)的測(cè)試流程,通過相關(guān)的log來驗(yàn)證自己的分析,詳見附件的log。
D: Vector services;
g_samgrImpl 初始化時(shí):
- g_samgrImpl.services = VECTOR_Make((VECTOR_Key)GetServiceName, (VECTOR_Compare)strcmp);
創(chuàng)建了一個(gè)Vector:{0, 0, 0, NULL, key, compare},Vector的定義如下:
其中:
- max:表示下面的**data指針數(shù)組的大小,也就是data[max]所能存儲(chǔ)的最大指針數(shù)目;
- top: 當(dāng)前使用到了的指針數(shù)組的最高位置data[top],當(dāng)top==max,同時(shí)free為0時(shí),表示data[max]已經(jīng)裝滿了,需要擴(kuò)容,一次擴(kuò)容增加4個(gè)element位置,變成data[max+4],詳情見VECTOR_Add()函數(shù)的實(shí)現(xiàn)。
- free:當(dāng)前0~top之間,釋放了的位置的數(shù)量。當(dāng)已注冊(cè)在冊(cè)的service unregister時(shí),對(duì)應(yīng)記錄這個(gè)service的data[i]會(huì)被清空,free+1;下次有新的service注冊(cè)時(shí),會(huì)優(yōu)先使用data[i]來記錄新service的Impl對(duì)象指針,free-1。詳情見VECTOR_Swap()函數(shù)的實(shí)現(xiàn)
- **data:指針數(shù)組data[max],每一個(gè)data[i]記錄了一個(gè)注冊(cè)進(jìn)來的service對(duì)應(yīng)的ServiceImpl 對(duì)象的指針,初始化為NULL,通過VECTOR_Add()函數(shù)內(nèi)的操作擴(kuò)容。
- key:是samgr_lite.c定義的GetServiceName(ServiceImpl*)函數(shù)指針,它可以通過參數(shù)來獲取對(duì)應(yīng)的service Name。
- compare:是strcmp函數(shù)指針,也就是string標(biāo)準(zhǔn)庫提供的字符串比較函數(shù)。
Samgr通過這個(gè)Vector來管理所有注冊(cè)進(jìn)來的service(實(shí)際上管理的是serviceImpl對(duì)象,通過serviceImpl來關(guān)聯(lián)具體的service和service對(duì)應(yīng)的feature)。
每個(gè)service可以有0個(gè)/1個(gè)或多個(gè)feature,每個(gè)service(serviceImpl對(duì)象)也是通過自己的Vector來管理feature。
對(duì)Vector的操作,全部定義在:
Hi3861/foundation/distributedschedule/services/samgr_lite/samgr/source/common.c
里面了,需要仔細(xì)閱讀分析,去理解相關(guān)操作。
下面是幾處要點(diǎn):
- VECTOR_Make() 會(huì)創(chuàng)建一個(gè){0, 0, 0, NULL, key, compare} Vector,當(dāng)需要往Vector中添加element時(shí),會(huì)在VECTOR_Add()中擴(kuò)容。
- VECTOR_Add(Vector *vector, void *element) 的時(shí)候,發(fā)現(xiàn)Vector的data[max] 空間用盡了,就會(huì)重新申請(qǐng)一塊增大了4個(gè)element的內(nèi)存空間Newdata[max+4],把舊的data[x]全部拷貝進(jìn)去(還有4個(gè)新的空余的element位置),g_samgrImpl.services.data重新指向Newdata,再把舊的data[x]占用的空間釋放掉,這樣,新的element (ServiceImpl 對(duì)象的指針)就可以記錄進(jìn)來了。
- VECTOR_Swap()用來刪除一個(gè)已經(jīng)記錄在案的element(也就是unregister一個(gè)service),把它對(duì)應(yīng)的 data[x] 置為NULL,free+1,空出的位置會(huì)給未來新注冊(cè)的service 優(yōu)先使用。
- VECTOR_Find()/VECTOR_FindByKey() 可以查找element(serviceImpl),并返回它的index。
特別是VECTOR_FindByKey(Vector *vector, const void *key),第二個(gè)參數(shù)“void *key”實(shí)際上是一個(gè)service的名字字符串,如“Broadcast”。
FindByKey會(huì)循環(huán)獲取data[0~top]的ServiceImpl 對(duì)象的指針,并將其作為key函數(shù)指針(GetServiceName())的參數(shù)來獲取service的Name,將Name其與上面的第二個(gè)參數(shù)的service Name,用compare函數(shù)指針(strcmp)進(jìn)行對(duì)比,匹配則返回對(duì)應(yīng)的data[i]的 index i。
E: TaskPool *sharedPool[MAX_POOL_NUM]; // MAX_POOL_NUM 是8
Hi3861平臺(tái)啟動(dòng)到 system_init.c 的最后一步時(shí):
- void HOS_SystemInit(void)
- {
- ......
- SAMGR_Bootstrap();
- }
調(diào)用SAMGR_Bootstrap()去啟動(dòng)已經(jīng)注冊(cè)了的service,會(huì)為service創(chuàng)建queue和taskPool資源,每個(gè)service有一個(gè)GetTaskConfig()接口,可以返回這個(gè)service運(yùn)行起來的task配置參數(shù),如 bootstrap service的TaskConfig為:
請(qǐng)自行查看 TaskConfig的定義。
這里需要關(guān)注的是 SHARED_TASK 這個(gè)標(biāo)記,在samgr的 AddTaskPool()這一步時(shí):
bootstrap service的TaskConfig配置會(huì)被修改成默認(rèn)的DEFAULT_TASK_CFG,意味著在bootstrap_service.c 中定義的TaskConfig 參數(shù)(stackSize和queueSize)其實(shí)并沒有起作用,想要修改SHARED_TASK的stackSize和queueSize,要去修改DEFAULT_TASK_CFG的配置。
而上面case SHARED_TASK的操作以及g_samgrImpl.sharedPool[]的存在,可以為若干個(gè)共同標(biāo)記了SHARED_TASK的service共享一個(gè)Queue和taskPool資源(這樣可以節(jié)約好多資源),TaskEntry在Queue中收到msg時(shí),可以通過Exchange 消息里面的Identity字段解析出Sid/Fid/Qid信息,以此來確認(rèn)到底是哪個(gè)service/feature需要處理這個(gè)消息。
TaskConfig里的priority字段,則確定了service用的是哪個(gè)sharePool[x],優(yōu)先級(jí)越高,x越大。
我在代碼里全局搜索了一下“SHARED_TASK”關(guān)鍵字,得到如下結(jié)果:
主要是在samgr例程里,不同優(yōu)先級(jí)別的service,共享著不同x的sharedPool[x]資源。
不是SHARED_TASK的service則有自己獨(dú)立的Queue和taskPool,不會(huì)直接記錄在g_samgrImpl.sharedPool[]里,而是記錄在各自service的serviceImpl對(duì)象的taskPool* 里。
4.3 ServiceImpl 類
- struct ServiceImpl {
- A: Service* service;
- B: IUnknown* defaultApi;
- C: TaskPool* taskPool;
- D: Vector features;
- E: int16 serviceId;
- F: uint8 inited;
- G: Operations ops;
- };
g_samgrImpl 全局變量的services Vector里,只直接記錄ServiceImpl對(duì)象的指針,并不直接記錄和管理service、feature對(duì)象本身。service在向samgr注冊(cè)自己時(shí),samgr會(huì)首先生成一個(gè)ServiceImpl對(duì)象,將service對(duì)象的指針記錄在ServiceImpl的Service* service里,而ServiceImpl對(duì)象本身的指針,則記錄在g_samgrImpl.services.data[i] 中,這樣就建立了g_samgrImpl 到具體service的聯(lián)系,見本文上面的展開圖。
A: Service* service;
指向當(dāng)前ServiceImpl對(duì)象所對(duì)應(yīng)的具體的service對(duì)象,這些具體的service對(duì)象都是Service類的子類對(duì)象。
B: IUnknown* defaultApi;
繼承了IUnknown接口(INHERIT_IUNKNOWN)的service或者feature,都會(huì)有IUnknown的一組三個(gè)默認(rèn)的接口,這組接口主要是記錄service/feature對(duì)象的引用數(shù)量,還可以通過其中的QueryInterface接口實(shí)現(xiàn)父類(IUnknown)指針到具體的service/feature子類對(duì)象指針的類型轉(zhuǎn)換,以獲取子類提供的功能。
詳情見下面對(duì)IUnknown的分析。
我在《鴻蒙的DFX子系統(tǒng) 》一文中,有對(duì)hiview service做過一個(gè)展開,可以去那里了解一下。
C: TaskPool* taskPool;
這就是上一小節(jié)中,samgr為service創(chuàng)建的taskPool的指針(同時(shí)創(chuàng)建的還有消息隊(duì)列,queueId同時(shí)保存在taskPool里面)。
如果service task是SHARED_TASK類型的,那就會(huì)有多個(gè)service共享一個(gè)taskPool和queue,這里的taskPool指針就會(huì)指向同一塊內(nèi)存空間,同時(shí),g_samgrImpl的對(duì)應(yīng)優(yōu)先級(jí)別的sharedPool[x]也會(huì)記錄著這個(gè)taskPool指針。
如果service task不是SHARED_TASK類型的,那就只會(huì)在這里記錄service的taskPool(包括queue),而不會(huì)在g_samgrImpl中做記錄。
D: Vector features;
feature需要依賴于對(duì)應(yīng)的service才能注冊(cè)和運(yùn)行,一個(gè)service可以有0個(gè)、1個(gè)或多個(gè)feature。service本身不記錄它對(duì)應(yīng)的feature的信息,而是由這個(gè)ServiceImpl.features來記錄。ServiceImpl 的這個(gè)Vector features類似于g_samgrImpl用于記錄serviceImpl的Vector services。
一個(gè)service沒有feature時(shí),features Vector就保持初始化的樣子,對(duì)應(yīng)的features.data 是NULL。
一個(gè)service有若干個(gè)feature時(shí),就會(huì)在feature注冊(cè)時(shí),由samgr生成對(duì)應(yīng)FeatureImpl類對(duì)象,將此對(duì)象與具體的feature關(guān)聯(lián)起來,再將此對(duì)象的指針保存在Vector features.data[x]里,并將這個(gè) x 作為對(duì)應(yīng)feature的ID,另做保存。以后samgr就可以通過它自己的vector找到serviceImpl,再進(jìn)一步通過這個(gè)vector找到對(duì)應(yīng)的featureImpl,從而找到最終的feature。
E: int16 serviceId;
當(dāng)前的ServiceImpl 對(duì)象指針保存在g_samgrImpl.services vector內(nèi)的data[x]上的這個(gè) x 序號(hào),就作為當(dāng)前service的ID,保存在這里。這個(gè)serviceId也可能同時(shí)保存在具體的service對(duì)象的Identity 結(jié)構(gòu)體里。
F: uint8 inited;
標(biāo)記當(dāng)前ServiceImpl 對(duì)應(yīng)的service的狀態(tài),service沒有init起來是不能注冊(cè)feature的,service在處理消息事件的時(shí)候,狀態(tài)也要對(duì)應(yīng)置為 BUSY,處理完消息又要將狀態(tài)寫回IDLE。具體可自行查閱代碼。
G: Operations ops;
主要記錄了service處理消息事件的時(shí)間戳、msg數(shù)量(編號(hào)?)、步驟和是否存在異常等信息,估計(jì)與跨設(shè)備的服務(wù)/消息處理的同步有關(guān),對(duì)此暫未做深入理解,待作進(jìn)一步的理解。
4.4 FeatureImpl類
- typedef struct FeatureImpl FeatureImpl;
- struct FeatureImpl {
- A: Feature *feature;
- B: IUnknown *iUnknown;
- };
FeatureImpl 類看起來相對(duì)簡單,直接是一個(gè)Feature指針(A)指向?qū)?yīng)的具體的feature對(duì)象。
有些feature除了繼承自Feature類之外,還繼承了某些interface,為feature提供額外的功能,這些interface 都是繼承了最原始的IUnknown接口類(INHERIT_IUNKNOWN)。
這里的IUnknown *iUnknown與上面的ServiceImpl 的IUnknown* defaultApi; 其實(shí)是同一個(gè)東西,它們都指 向了一個(gè)feature或者service所繼承/實(shí)現(xiàn)的接口中,IUnknown接口所在的位置,見上面ServiceImpl對(duì)IUnknown* defaultApi;的說明。
更多詳情見下面對(duì)IUnknown的分析。
4.5 Service類及其子類
- struct Service {
- const char *(*GetName)(Service *service); //獲取service名稱
- BOOL (*Initialize)(Service *service, Identity identity); //service的初始化
- BOOL (*MessageHandle)(Service *service, Request *request); //service的消息處理函數(shù)
- TaskConfig (*GetTaskConfig)(Service *service); //獲取service 任務(wù)運(yùn)行的配置
- }
Service類是所有service類的父類,它聲明了四個(gè)函數(shù)指針,這是每一個(gè)服務(wù)都必須要實(shí)現(xiàn)的生命周期函數(shù),見上面的注釋。
每一個(gè)具體的服務(wù)類都繼承自這個(gè)Service類,然后可以擴(kuò)展自己獨(dú)特的功能。
下面分別看一下Hi3861默認(rèn)的三個(gè)具體的服務(wù)。
A: Bootstrap service
- typedef struct Bootstrap {
- INHERIT_SERVICE; //繼承上面的Sevice類
- Identity identity; //bootstrap service對(duì)象的id信息
- uint8 flag;
- } Bootstrap;
Bootstrap 除了繼承Service之外,還增加了一個(gè)Identity identity 和 uint8 flag。
- Identity identity
這是Bootstrap service具體對(duì)象的身份信息,里面包括了: serviceId/featureId/queueId三個(gè)信息。
serviceId:Bootstrap service 對(duì)應(yīng)的 serviceImpl對(duì)象,在g_samgrImpl.services這個(gè)Vector.data[]中存放位置 的index,這里值為0.
featureId:Bootstrap service不帶feature,所以值為 -1。
queueId: Bootstrap service啟動(dòng)時(shí),samgr會(huì)為其創(chuàng)建消息隊(duì)列,這就是消息隊(duì)列的ID,是一串?dāng)?shù)字。
- uint8 flag
一個(gè)標(biāo)記,主要是LOAD_FLAG 0x01這一個(gè)位,用來標(biāo)記非系統(tǒng)service/feature是否已經(jīng)加載和注冊(cè),見 bootstrap_service.c的MessageHandle()內(nèi)對(duì)flag的使用。
B. Broadcast service
- typedef struct BroadcastService BroadcastService;
- struct BroadcastService {
- INHERIT_SERVICE;
- };
Broadcast service僅僅直接繼承了Service類,確保它的service對(duì)象的生命周期的完整,因?yàn)樗€會(huì)有feature,會(huì)在具體的feature對(duì)象中保存id信息和其它擴(kuò)展信息,詳見下面的PubSubFeature類的解析。
C. Hiview service
- typedef struct {
- INHERIT_IUNKNOWN;
- void (*Output)(IUnknown *iUnknown, int16 msgId, uint16 type);
- } HiviewInterface;
- typedef struct {
- INHERIT_SERVICE;
- INHERIT_IUNKNOWNENTRY(HiviewInterface);
- Identity identity;
- } HiviewService;
Hiview service除了繼承自Service類實(shí)現(xiàn)service的生命周期函數(shù)之外,還繼承了HiviewInterface,這個(gè)HiviewInterface又繼承了最原始的IUnknown接口類(INHERIT_IUNKNOWN)。通過這種多繼承機(jī)制,既實(shí)現(xiàn)了服務(wù)所需的生命周期,又具備了類似feature所提供的部分接口功能(Hiview service實(shí)際上又不帶feature)。
詳情見下面對(duì)IUnknown類的分析。
identity則是Hiview service對(duì)象的身份信息,同樣包括了: serviceId/featureId/queueId三個(gè)信息。
4.6 Feature類及其子類
- struct Feature {
- const char *(*GetName)(Feature *feature); //獲取feature的名字
- void (*OnInitialize)(Feature *feature, Service *parent, Identity identity); //feature 的初始化
- void (*OnStop)(Feature *feature, Identity identity); //停止對(duì)外提供feature功能
- BOOL (*OnMessage)(Feature *feature, Request *request); //對(duì)本feature的消息處理
- };
Feature類是所有feature類的父類,也是聲明了四個(gè)函數(shù)指針,這是每一個(gè)feature都必須要實(shí)現(xiàn)的生命周期函數(shù),見上面的注釋。
每一個(gè)具體的feature類都繼承自這個(gè)Feature類,然后擴(kuò)展自己獨(dú)特的功能。
下面是Hi3861的Broadcast service 提供的feature類及Impl類的定義:
A: PubSubFeature g_broadcastFeature
- typedef struct PubSubFeature PubSubFeature;
- struct PubSubFeature {
- INHERIT_FEATURE; //繼承 Feature 類
- Relation *(*GetRelation)(PubSubFeature *feature, const Topic *topic);
- MutexId mutex;
- Relation relations;
- Identity identity;
- };
PubSubFeature 本尊,它被FeatureImpl 對(duì)象以及下面的PubSubImplement 對(duì)象引用。
FeatureImpl 對(duì)象又會(huì)被記錄在 ServiceImpl 的Features Vector向量里,獲得一個(gè)Fid,連同Sid/Qid一起記錄在PubSubFeature 的identity里。
PubSubFeature 還提供一個(gè)雙向鏈表結(jié)構(gòu)的Relation,以及基于這個(gè)雙向鏈表結(jié)構(gòu)的查找節(jié)點(diǎn)的函數(shù)GetRelation(),這個(gè)結(jié)構(gòu)及其作用,我后面再另寫文章詳細(xì)分析。
B: PubSubImplement g_pubSubImplement
- typedef struct PubSubInterface PubSubInterface;
- struct PubSubInterface {
- INHERIT_IUNKNOWN;
- Subscriber subscriber;
- Provider provider;
- };
- typedef struct PubSubImplement {
- INHERIT_IUNKNOWNENTRY(PubSubInterface);
- PubSubFeature *feature;
- } PubSubImplement;
PubSubImplement 對(duì)象會(huì)引用上面的PubSubFeature對(duì)象,記錄在這里的PubSubFeature *feature上。
PubSubImplement 還繼承了PubSubInterface,實(shí)現(xiàn)了Subscriber 和Provider的功能。
它們的關(guān)系,見本文最上面的展開圖。
這個(gè)PubSubFeature 和PubSubImplement 深究下去就有點(diǎn)復(fù)雜了,它們是SOA(面向服務(wù)的架構(gòu))的具體實(shí)現(xiàn):
- Provider:服務(wù)的提供者,為系統(tǒng)提供能力(對(duì)外接口)。
- Consumer:服務(wù)的消費(fèi)者,調(diào)用服務(wù)提供的功能(對(duì)外接口)。
- Samgr:作為中介者,管理Provider提供的能力,同時(shí)幫助Consumer發(fā)現(xiàn)Provider的能力。
如下是官方readme上畫的架構(gòu)圖。
這里我就先不做進(jìn)一步詳細(xì)的分析了,后面會(huì)結(jié)合broadcast_example.c示例程序來做分析和驗(yàn)證,再單獨(dú)寫一篇文章來做總結(jié)。
4.7 IUnknown 接口類及其相關(guān)定義
首先需要理解,C語言的struct本質(zhì)上與C++中的class是一樣的,都是一塊存儲(chǔ)區(qū)域,里面有數(shù)據(jù)和對(duì)數(shù)據(jù)的操作。C++通過“:”關(guān)鍵字來標(biāo)記繼承關(guān)系,如Aa繼承自A表示為“class Aa : public A”,而C語言直接是struct Aa內(nèi)嵌套struct A來標(biāo)記“繼承關(guān)系”:
- struct A {
- dataA;
- funcPtr* funcA;
- }
- struct Aa {
- struct A;
- dataAa;
- funcPtr* funcAa;
- }
更具體的一些細(xì)節(jié),可以自行在網(wǎng)上搜索和學(xué)習(xí)。
接下來,我們仔細(xì)對(duì)比一下HivieService 和PubSubImplement,它們都分別通過INHERIT_IUNKNOWNENTRY() 這個(gè)關(guān)鍵字來分別繼承HiviewInterface和PubSubInterface,而這HiviewInterface和PubSubInterface又都通過INHERIT_IUNKNOWN來繼承IUnknown接口類。
下面我們就跟著Hi3861/foundation/distributedschedule/interfaces/innerkits/samgr_lite/samgr/iunknown.h中的定義去展開和理解一下這兩個(gè)宏(類)。
INHERIT_IUNKNOWN 宏定義是為了方便用C語言的形式“繼承”IUnknown接口類。
INHERIT_IUNKNOWNENTRY() 宏定義是為了方便用C語言的形式“繼承”【實(shí)現(xiàn)了IUnknown接口的】 IUnknownEntry接口類。
這兩個(gè)宏之間的關(guān)系,就是上面struct A和struct Aa之間的父類子類關(guān)系,換回struct 的形式,就是:
IUnknown 是父類,IUnknownEntry 是子類,子類是父類的一個(gè)implement。
按上面的定義把HiviewService類(或結(jié)構(gòu)體)的定義徹底展開,就是如下的樣子:
把HiviewService的全局對(duì)象 g_hiviewService的初始化也按上面的形式展開,也會(huì)如下:
這樣一來,.iUnknown的地址、HiviewService類型、g_hiviewService對(duì)象的地址(引用/指針)之間的關(guān)系,就可以通過計(jì)算和類型轉(zhuǎn)換來互相獲取了,這就是下面三個(gè)宏的作用:
a. GET_IUNKNOWN(T)
定義在://foundation/distributedschedule/interfaces/innerkits/samgr_lite/samgr/iunknown.h
簡單理解為:從g_hiviewService對(duì)象中獲取其內(nèi)部的.iUnknown對(duì)象的地址。
b. GET_OFFSIZE(T, member)
c. GET_OBJECT(Ptr, T, member)
這兩個(gè)定義在://foundation/distributedschedule/interfaces/innerkits/samgr_lite/samgr/common.h
簡單理解為:從.iUnknown父類對(duì)象下轉(zhuǎn)換得到子類HiviewInterface對(duì)象或者g_hiviewService對(duì)象的地址。
如本文開頭的第一張展開圖所示,BroadcastImpl和HiviewImpl都有自己的 IUnknown* defaultApi,分別是通過GET_IUNKNOWN(g_pubSubImplement) 和GET_IUNKNOWN(g_hiviewService)來得到的,得到了.iUnknown的地址,也就是得到了(*QueryInterface)/(*AddRef)/(*Release)這三個(gè)defaultApi的地址,就可以使用它們了,實(shí)際只直接使用(*QueryInterface)這個(gè)API,它的作用是“Queries the subclass object of the IUnknown interface of a specified version”
查詢/獲取指定的版本的IUnknown接口的子類對(duì)象(同時(shí)增加對(duì)該對(duì)象的引用次數(shù)),調(diào)用者通過這個(gè)子類對(duì)象就可以調(diào)用子類中定義的其它接口了。
對(duì)于上面的g_hiviewService例子來說,調(diào)用QueryInterface接口的例子在hiview_service.c 的HiviewSendMessage() 里,它返回的實(shí)際上就是g_hiviewService 這個(gè)service對(duì)象內(nèi)部的一個(gè)區(qū)域的起始地址,這個(gè)區(qū)域就是HiviewInterface這個(gè)類的對(duì)象,同時(shí)增加了對(duì)這個(gè)對(duì)象的引用次數(shù),之后,就可以通過這個(gè)對(duì)象來調(diào)用HiviewInterface所定義的全部API了(這里主要是Output函數(shù))。
4.8 其它類/結(jié)構(gòu)體
samgr子系統(tǒng)中還有其他的一些很重要的類或結(jié)構(gòu)體,比如Request/Response/Exchange 等等,這里就先不進(jìn)一步展開了,以后應(yīng)該還會(huì)繼續(xù)補(bǔ)充完整的,或者在接下來的流程分析中按需進(jìn)行分解,也請(qǐng)各位自行做一下理解。
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)