分布式調(diào)度子系統(tǒng)--初步研究
?
1.?總體描述
1.1.?總體介紹
分布式任務(wù)調(diào)度基于分布式軟總線、分布式數(shù)據(jù)管理、分布式Profile等技術(shù)特性,構(gòu)建統(tǒng)一的分布式服務(wù)管理(發(fā)現(xiàn)、同步、注冊(cè)、調(diào)用)機(jī)制,支持對(duì)跨設(shè)備的應(yīng)用進(jìn)行遠(yuǎn)程啟動(dòng)、遠(yuǎn)程調(diào)用、遠(yuǎn)程連接以及遷移等操作,能夠根據(jù)不同設(shè)備的能力、位置、業(yè)務(wù)運(yùn)行狀態(tài)、資源使用情況,以及用戶的習(xí)慣和意圖,選擇合適的設(shè)備運(yùn)行分布式任務(wù)。
下圖是分布式調(diào)度子系統(tǒng)在整個(gè)鴻蒙系統(tǒng)中的位置:
?
下圖表示分布式調(diào)度的示意圖:
?
從A設(shè)備的某個(gè)FA(Feature Ability代表有界面的元能力)應(yīng)用調(diào)用設(shè)備B上的FA應(yīng)用。這里的調(diào)用的含義包含了:
a、啟動(dòng)和關(guān)閉:?jiǎn)?dòng)和關(guān)閉遠(yuǎn)程設(shè)備上的ability(包括:基于Page的ability、基于Service的ability、基于Data模板的ability)
b、連接和斷開:向開發(fā)者提供跨設(shè)備控制服務(wù)的能力。這里的服務(wù)表示:基于Server和Data模板的ability。
c、遷移能力:向開發(fā)者提供跨設(shè)備的業(yè)務(wù)無縫遷移能力。開發(fā)者可以通過基于Page的ability的遷移接口,將本地的業(yè)務(wù)遷移到指定的設(shè)備中。
?
1.2.?分布式調(diào)度中的兩種設(shè)備
在分布式調(diào)度中,存在兩個(gè)角色。按照上圖有設(shè)備A和設(shè)備B。一般來說設(shè)備A是指智慧屏設(shè)備,設(shè)備B只一般的輕量設(shè)備。智慧屏設(shè)備一般指智能TV、手機(jī)等。輕量設(shè)備一般只Camera、手表等
下面圖示表示這兩種設(shè)備的系統(tǒng)架構(gòu)圖:
?
(約束:如果要實(shí)現(xiàn)分布式調(diào)度,目前智慧屏設(shè)備和輕量設(shè)備必須處于同一個(gè)局域網(wǎng)段內(nèi))
從鴻蒙系統(tǒng)的整體系統(tǒng)框架圖可以看出,分布式調(diào)度子系統(tǒng)及周邊的依賴模塊如下圖:
?
?
1.3.?分布式調(diào)度代碼示例--啟動(dòng)遠(yuǎn)程FA
1.3.1.?智慧屏上的代碼示例
1.獲取目標(biāo)在線從設(shè)備的設(shè)備ID
// 引入設(shè)備選擇頭文件
import ohos.distributedschedule.interwork.DeviceInfo;
import ohos.distributedschedule.interwork.DeviceManager;
?
// 獲取在線設(shè)備列表
List
String remote_device_id;
if (deviceInfoListOnline.size() > 0)
{
????remote_device_id = deviceInfoListOnline[0].GetDeviceId(); // 獲取在線列表中第一臺(tái)設(shè)備的設(shè)備ID
}
2.構(gòu)造want,首先使用ElementName類表明需要啟動(dòng)的遠(yuǎn)端設(shè)備ID,包名,元能力類名,傳入want中,然后設(shè)置want中的分布式標(biāo)志位Want.FLAG_ABILITYSLICE_MULTI_DEVICE表示需要遠(yuǎn)程啟動(dòng)
// 引入相關(guān)頭文件
import ohos.aafwk.ability.Ability;
import ohos.aafwk.content.Want;
import ohos.bundle.ElementName;
?
// 啟動(dòng)遠(yuǎn)程設(shè)備FA
Want want = new Want(); // 封裝啟動(dòng)遠(yuǎn)端FA的Want
// 使用步驟2中獲取的設(shè)備ID,并指定FA信息
ElementName name = new ElementName(remote_device_id, "com.huawei.remote_package_name", "remote_class_name");
want.setElement(name); // 將待啟動(dòng)的FA信息添加到Want中
want.setFlags(Want.FLAG_ABILITYSLICE_MULTI_DEVICE); // 設(shè)置分布式標(biāo)記,若不設(shè)置將無法使用分布式能力
startAbility(want); // 按照Want啟動(dòng)指定FA,Want參數(shù)命名以實(shí)際開發(fā)平臺(tái)API為準(zhǔn)
?
1.3.2.?輕量設(shè)備上的代碼示例
輕量設(shè)備上代碼可以參考鴻蒙Java的API參考手冊(cè)中,如何創(chuàng)建基于Page的Ability。
https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ability-page-concepts-0000000000033573
?
2.?代碼目錄結(jié)構(gòu)
分布式調(diào)度的代碼在foundation/distributedschedule目錄中,目錄結(jié)構(gòu)如下:
?
其中interfaces中包含了所有的頭文件,如下:
?
Services目錄下包含了如下目錄:
?
其中,dtbschedmgr_lite目錄是輕量級(jí)分布式調(diào)度模塊代碼。
?
safwk_lite目錄中是foundation 這個(gè)bin文件的main函數(shù),用于samgr啟動(dòng),初始化所有注冊(cè)的Service。
samgr_lite目錄是系統(tǒng)服務(wù)框架子系統(tǒng)代碼,這個(gè)目錄是系統(tǒng)的基礎(chǔ)系統(tǒng)服務(wù)框架代碼,分布式調(diào)度子系統(tǒng)也是一個(gè)系統(tǒng)服務(wù),將會(huì)注冊(cè)在samgr里面。并且依賴系統(tǒng)服務(wù)框架進(jìn)行服務(wù)的發(fā)布,注冊(cè)等功能。
?
3.?代碼分析
3.1.?輕量設(shè)備子系統(tǒng)代碼分析
輕量設(shè)備分布式調(diào)度子系統(tǒng)的源碼主要是以下的7個(gè)文件:
1.?distributed_schedule_service.c ??????分布式調(diào)度對(duì)外接口
2.?dmslite.c ????????????????????????分布式調(diào)度服務(wù)實(shí)現(xiàn)
3.?dmslite_check_remote_permission.c ?分布式調(diào)度權(quán)限管理模塊
4.?dmslite_famgr.c ??????????????????分布式調(diào)度FA管理模塊
5.?dmslite_msg_parser.c ?????????????分布式消息解析模塊
6.?dmslite_session.c ?????????????????跨設(shè)備通信收發(fā)模塊
7.?dmslite_tlv_common.c ????????????TLV格式數(shù)據(jù)解析模塊
下面我們將分三個(gè)過程來分析源碼:1、分布式調(diào)度服務(wù)的初始化。2、協(xié)議報(bào)文的接收和解析。3、輕量設(shè)備端拉起FA。
?
3.1.1.?分布式調(diào)度服務(wù)初始化
分布式調(diào)度的服務(wù)和特性定義和初始化在distributed_schedule_service.c和dmslite.c文件中。
1.?服務(wù)和特性的的定義和注冊(cè)
服務(wù)的定義和初始化
服務(wù)的定義和初始化在distributed_schedule_service.c中。下面的代碼定義了全局唯一的服務(wù)對(duì)象(用C語言實(shí)現(xiàn)了C++類的概念)
?
g_distributedService 就是全局唯一的服務(wù)對(duì)象結(jié)構(gòu)體,而DistributedService定義繼承了INHERIT_SERVICE,這是所有服務(wù)都必須繼承的。
?
?
從上面的代碼可以看出,所有的服務(wù)都必須要有4個(gè)成員。
GetName()成員就是讓samgr可以得到這個(gè)服務(wù)的名稱。
Initialize()成員就是服務(wù)的初始化過程,在samgr的SAMGR_Bootstrap()函數(shù)中會(huì)調(diào)用所有注冊(cè)服務(wù)的初始化過程。
MessageHandle()成員是服務(wù)對(duì)外的消息處理函數(shù)。
GetTaskConfig()成員是向samgr上報(bào)服務(wù)的基本配置,包括:level,priority, stackSize,queueSize,taskFlag。
最后我們?cè)?/span>distributed_schedule_service.c文件中看到如下的初始化定義:
?
上面的這段代碼首先用SYS_SERVICE_INIT宏定義了分布式調(diào)度服務(wù)的初始化函數(shù)。這個(gè)函數(shù)被寫入zinitcall這個(gè)數(shù)據(jù)段中(或者通過__attribute__((constructor)) 定義在bin文件的初始化過程中)。所以由SYS_SERVICE_INIT宏定義的函數(shù)都會(huì)在main函數(shù)之前被執(zhí)行。
?
因此,在main()函數(shù)執(zhí)行前,Init()(注意是distributed_schedule_service.c中的)會(huì)先被執(zhí)行。我們看到在Init函數(shù)中,調(diào)用了SAMGR_GetInstance()->RegisterService((Service *)&g_distributedService); 注冊(cè)了分布式調(diào)度子系統(tǒng)服務(wù)。下面我們?cè)诜?wù)的初始化中介紹這個(gè)函數(shù)調(diào)用。
特性的定義和初始化
特性的定義在dmslite.c 中。如下代碼:
?
g_dmslite是全局唯一的特性對(duì)象。DmsLite的定義如下:
?
INHERIT_FEATURE宏定義了所有的特性都要有的成員(也就是C++中繼承的概念)
?
GetName:返回特性的字符串名稱。
OnInitialize:特性的初始化函數(shù)。下面的初始化流程中有介紹。
OnStop:特性終止時(shí)調(diào)用。
OnMessage:特性的消息處理函數(shù)。用戶可以通過IUnknown接口發(fā)送消息。
在dmslite.c中有如下的特性初始化定義:
?
SYS_FEATURE_INIT宏與SYS_SERVICE_INIT宏類似,會(huì)在main函數(shù)調(diào)用前被調(diào)用。這個(gè)宏用來注冊(cè)特性的初始化函數(shù)入口Init(注意:是dmslite.c中的Init()函數(shù))。
Init()函數(shù)調(diào)用SAMGR_GetInstance()取得系統(tǒng)服務(wù)框架子系統(tǒng)的全局唯一對(duì)象,然后調(diào)用RegisterFeature來注冊(cè)Feature和FeatureApi。
?
2.?服務(wù)的初始化
這個(gè)分布式調(diào)度子系統(tǒng)的初始化過程是在系統(tǒng)服務(wù)框架子系統(tǒng)中完成。上面說過在foundation/distributedschedule/services目錄下有三個(gè)子目錄,分別是samgr_lite、safwk_lite、dtbschedmgr_lite。其中safwk_lite目錄中只包含了一個(gè)main.c文件,這個(gè)文件就是系統(tǒng)服務(wù)框架子系統(tǒng)的主入口。而samgr_lit和dtbschedmgr_lite目錄下的源碼將分別編譯出庫(kù)文件,然后跟safwk_lite下的main.c一起編譯成foundation 這個(gè)bin文件。
我們先來看一下main.c這個(gè)文件。
?
從上面的代碼可以看到,main()函數(shù)調(diào)用了 SAMGR_Bootstrap()后,進(jìn)入了一個(gè)死循環(huán)。這個(gè)函數(shù)定義在samgr_lite/samgr/source/samgr_lite.c中,我們來看看這個(gè)函數(shù)。
?
這個(gè)函數(shù)的實(shí)現(xiàn)大體上看分為3個(gè)部分:
?獲取全局唯一的samgr系統(tǒng)服務(wù)對(duì)象
?
g_samgrImpl 是samgr的全局唯一對(duì)象,我們來看看這個(gè)對(duì)象這么定義和初始化的。
?
?
從上面的初始化函數(shù)Init可以看到,g_samgrImpl被賦值了許多函數(shù)指針,其中RegisterService就是給其他服務(wù)調(diào)用注冊(cè)服務(wù)用的,而RegisterFeature、RegisterFeatureApi就是給服務(wù)注冊(cè)特性用的。
那這個(gè)Init()什么時(shí)候被調(diào)用呢?經(jīng)過搜索,我們發(fā)現(xiàn)是在SAMGR_GetInstance()函數(shù)中被調(diào)用,而前面我們說的分布式調(diào)度初始化過程的Init()函數(shù)中就會(huì)調(diào)用這個(gè)函數(shù)。我們看看這個(gè)函數(shù)的實(shí)現(xiàn)。
?
這個(gè)函數(shù)首先通過判斷 g_samgrImpl.mutex 這個(gè)變量是否初始化過。如果沒有,那么調(diào)用Init來初始化g_samgrImpl這個(gè)全局對(duì)象,然后返回g_samgrImpl這個(gè)全局對(duì)象中的函數(shù)指針表,這個(gè)指針表中就包含了注冊(cè)服務(wù)、注冊(cè)特性等函數(shù)。(這里有個(gè)疑問:這個(gè)函數(shù)一會(huì)直接使用g_samgrImpl全局變量,一會(huì)使用GetImplement()函數(shù)間接的使用這個(gè)全局變量,不知道為什么?)
我們的分布式調(diào)度子系統(tǒng)的服務(wù)注冊(cè)初始化函數(shù)Init(注意是distributed_schedule_service.c中的)在調(diào)用了SAMGR_GetInstance()后,得到的函數(shù)指針表,然后調(diào)用了RegisterService注冊(cè)服務(wù)對(duì)象,我們來看看RegisterService()干什么了。
?
我們看到RegisterService()函數(shù)大致也分為三個(gè)部分:
A、 查看需要注冊(cè)的service是否已經(jīng)注冊(cè)過了。
B、 根據(jù)要注冊(cè)的sevice對(duì)象構(gòu)造一個(gè)serviceImpl對(duì)象。serviceImpl對(duì)象的結(jié)構(gòu)定義如下:
?
上面我們可以看出:
service:就是我們自己的服務(wù)對(duì)象,也就是分布式調(diào)度的全局唯一的服務(wù)對(duì)象g_distributedService(前面有過介紹)
defaultApi: 是默認(rèn)的IUnknown對(duì)象指針
taskPool: ?是這個(gè)服務(wù)的任務(wù)池對(duì)象
features: ?是這個(gè)服務(wù)的特性列表,使用SYS_FEATURE_INIT宏可以初始化一個(gè)服務(wù)的特性
serviceId: ?這個(gè)應(yīng)該是服務(wù)的編號(hào)
ops: ?這個(gè)應(yīng)該是服務(wù)的操作消息結(jié)構(gòu)
評(píng)論
查看更多