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