|
品讀鴻蒙HDF架構(gòu)(三), 現(xiàn)在我們繼續(xù)研究鴻蒙HDF架構(gòu),上回書(shū)說(shuō)到經(jīng)由HdfDeviceAttach(),HdfDevice節(jié)點(diǎn)不但添加進(jìn)了DevHostService的devices列表,而且還和一個(gè)DeviceNodeExt聯(lián)系起來(lái)了,呈現(xiàn)的示意圖大致如下: 接著,HdfDeviceAttach()最后會(huì)調(diào)用nodeIf->LaunchNode(),這一步實(shí)際上調(diào)用的是HdfDeviceLaunchNode(),代碼截選如下:
【drivers/hdf/frameworks/core/host/src/Hdf_device_node.c】
- int HdfDeviceLaunchNode(struct HdfDeviceNode *devNode, struct IHdfDevice *devInst)
- {
- struct HdfDevice *device = (struct HdfDevice *)devInst;
- . . . . . .
- struct HdfDriverEntry *driverEntry = devNode->driverEntry;
- const struct HdfDeviceInfo *deviceInfo = devNode->deviceInfo;
- struct IHdfDeviceToken *deviceToken = NULL;
-
- . . . . . .
- int ret = driverEntry->Init(&devNode->deviceObject);
- . . . . . .
- ret = HdfDeviceNodePublishService(devNode, deviceInfo, devInst);
- . . . . . .
- deviceToken = devNode->token;
- ret = DevmgrServiceClntAttachDevice(deviceInfo, deviceToken);
- . . . . . .
- return ret;
- }
復(fù)制代碼 “Launch”本就是啟動(dòng)之意,在這里就是指啟動(dòng)與HdfDevice對(duì)應(yīng)的驅(qū)動(dòng)服務(wù)。所以此處會(huì)先調(diào)用一下driverEntry->Init(),并傳入?yún)?shù)&devNode->deviceObject。這意味著要求驅(qū)動(dòng)程序在初始化時(shí),回填一下deviceObject里的service域。
接著,主要執(zhí)行了兩個(gè)動(dòng)作:
1)發(fā)布驅(qū)動(dòng)服務(wù)
2)掛接設(shè)備
我們會(huì)分兩小節(jié)來(lái)闡述。
1.發(fā)布驅(qū)動(dòng)服務(wù)
初始化完成后,就可以“發(fā)布”這個(gè)驅(qū)動(dòng)服務(wù)了,HdfDeviceNodePublishService()的代碼截選如下:
【drivers/hdf/frameworks/core/host/src/Hdf_device_node.c】
- static int HdfDeviceNodePublishService(struct HdfDeviceNode *devNode,
- const struct HdfDeviceInfo *deviceInfo,
- struct IHdfDevice *device)
- {
- int status = HDF_SUCCESS;
- . . . . . .
- struct IDeviceNode *nodeIf = &devNode->super;
- if ((deviceInfo->policy == SERVICE_POLICY_PUBLIC) ||
- (deviceInfo->policy == SERVICE_POLICY_CAPACITY)) {
- if (nodeIf->PublishService != NULL) {
- // 其實(shí)調(diào)用的是 DeviceNodeExtPublishService()
- status = nodeIf->PublishService(devNode, deviceInfo->svcName);
- }
- }
- if (status == HDF_SUCCESS) {
- status = HdfDeviceNodePublishLocalService(devNode, deviceInfo);
- }
- return status;
- }
復(fù)制代碼 從字面上理解,如果一個(gè)設(shè)備是“公共型”或“功能型”的,則會(huì)調(diào)用nodeIf->PublishService()發(fā)布對(duì)應(yīng)的驅(qū)動(dòng)服務(wù)。而我們以前研究過(guò),在HdfDeviceNode構(gòu)造之時(shí),我們可以看到為PublishService域設(shè)定了DeviceNodeExtPublishService()函數(shù)指針,因此上面代碼中調(diào)用PublishService的地方,其實(shí)就是在調(diào)用這個(gè)函數(shù)。
【drivers/hdf/lite/manager/src/Hdf_device_node_ext.c】
- static int DeviceNodeExtPublishService(struct HdfDeviceNode *inst, const char *serviceName)
- {
- const struct HdfDeviceInfo *deviceInfo = NULL;
- struct HdfDeviceObject *deviceObject = NULL;
- struct DeviceNodeExt *devNodeExt = (struct DeviceNodeExt *)inst;
- . . . . . .
- int ret = HdfDeviceNodePublishPublicService(inst, serviceName);
- . . . . . .
- deviceInfo = inst->deviceInfo;
- deviceObject = &devNodeExt->super.deviceObject;
- . . . . . .
- if (deviceInfo->policy == SERVICE_POLICY_CAPACITY) {
- devNodeExt->ioService = HdfIoServiceBind(serviceName, deviceInfo->permission);
- if (devNodeExt->ioService != NULL) {
- devNodeExt->ioService->target = (struct HdfObject*)(&inst->deviceObject);
- static struct HdfIoDispatcher dispatcher = {
- .Dispatch = DeviceNodeExtDispatch
- };
- devNodeExt->ioService->dispatcher = &dispatcher;
- } else {
- . . . . . .
- }
- }
- return HDF_SUCCESS;
- }
復(fù)制代碼 這樣說(shuō)來(lái),發(fā)布服務(wù)時(shí)其實(shí)分了兩個(gè)部分,一個(gè)是發(fā)布public部分,一個(gè)是發(fā)布local部分。分別對(duì)應(yīng)HdfDeviceNodePublishPublicService()和HdfDeviceNodePublishLocalService()。
1.1 發(fā)布Public Service部分【drivers/hdf/frameworks/core/host/src/Hdf_device_node.c】
- int HdfDeviceNodePublishPublicService(struct HdfDeviceNode *devNode, const char *svcName)
- {
- if ((devNode == NULL) || (devNode->deviceObject.service == NULL)) {
- HDF_LOGE(“device method is null“);
- return HDF_FAILURE;
- }
- return DevSvcManagerClntAddService(svcName, &devNode->deviceObject);
- }
- 【drivers/hdf/frameworks/core/host/src/Devsvc_manager_clnt.c】
- int DevSvcManagerClntAddService(const char *svcName, struct HdfDeviceObject *service)
- {
- struct DevSvcManagerClnt *devSvcMgrClnt = DevSvcManagerClntGetInstance();
- . . . . . .
- struct IDevSvcManager *serviceManager = devSvcMgrClnt->devSvcMgrIf;
- . . . . . .
- // 其實(shí)調(diào)用的是 DevSvcManagerAddService()
- return serviceManager->AddService(serviceManager, svcName, service);
- }
- 【drivers/hdf/frameworks/core/host/src/Devsvc_manager_clnt.c】
- struct DevSvcManagerClnt *DevSvcManagerClntGetInstance()
- {
- static struct DevSvcManagerClnt *instance = NULL;
- if (instance == NULL) {
- static struct DevSvcManagerClnt singletonInstance;
- DevSvcManagerClntConstruct(&singletonInstance);
- instance = &singletonInstance;
- }
- return instance;
- }
復(fù)制代碼 從代碼看,系統(tǒng)中有一個(gè)“設(shè)備服務(wù)管理器”(DevSvcManager),那些功能型設(shè)備都會(huì)把自己注冊(cè)進(jìn)它。這個(gè)倒有點(diǎn)兒像Android里的SMS(Service Manager Service),所有系統(tǒng)核心服務(wù)都會(huì)向SMS里注冊(cè)自己,以便其他應(yīng)用可以從SMS查詢并獲取服務(wù)代理。實(shí)際上,鴻蒙系統(tǒng)在不少方面倒的確和Android有一定類(lèi)比性,這個(gè)以后我們?cè)賹?duì)比看看,目前先放下不談。
注冊(cè)設(shè)備服務(wù)的那句serviceManager->AddService()實(shí)際上調(diào)用的是DevSvcManagerAddService(),該函數(shù)會(huì)嘗試向“設(shè)備服務(wù)管理器”里添加一個(gè)管理節(jié)點(diǎn)(DevSvcRecord):
【drivers/hdf/frameworks/core/manager/src/Devsvc_manager.c】
- int DevSvcManagerAddService(struct IDevSvcManager *inst, const char *svcName, struct HdfDeviceObject *service)
- {
- struct DevSvcManager *devSvcManager = (struct DevSvcManager *)inst;
- . . . . . .
- struct DevSvcRecord *record = DevSvcRecordNewInstance();
- . . . . . .
- record->key = HdfStringMakeHashKey(svcName, 0);
- record->value = service;
- OsalMutexLock(&devSvcManager->mutex);
- HdfSListAdd(&devSvcManager->services, &record->entry);
- OsalMutexUnlock(&devSvcManager->mutex);
- return HdfServiceObserverPublishService(&devSvcManager->observer, svcName, 0, SERVICE_POLICY_PUBLIC, (struct HdfObject *)service->service);
- }
復(fù)制代碼
【drivers/hdf/frameworks/core/host/src/Hdf_service_observer.c】
- int HdfServiceObserverPublishService(struct HdfServiceObserver *observer,
- const char *svcName, uint32_t matchId, uint16_t policy, struct HdfObject *service)
- {
- struct HdfServiceObserverRecord *serviceRecord = NULL;
- uint32_t serviceKey = HdfStringMakeHashKey(svcName, 0);
- . . . . . .
- serviceRecord = (struct HdfServiceObserverRecord *)HdfSListSearch(&observer->services, serviceKey, HdfServiceObserverRecordCompare);
- if (serviceRecord == NULL) {
- serviceRecord = HdfServiceObserverRecordObtain(serviceKey);
- if (serviceRecord == NULL) {
- HDF_LOGE(“PublishService faiLED, serviceRecord is null“);
- return HDF_FAILURE;
- }
- serviceRecord->publisher = service;
- serviceRecord->matchId = matchId;
- serviceRecord->policy = policy;
- HdfSListAdd(&observer->services, &serviceRecord->entry);
- } else {
- serviceRecord->publisher = service;
- HdfServiceObserverRecordNotifySubscribers(serviceRecord, matchId, policy);
- }
- return HDF_SUCCESS;
- }
復(fù)制代碼
對(duì)于“設(shè)備服務(wù)管理器”而言,當(dāng)它要管理一個(gè)設(shè)備服務(wù)時(shí),主要需要兩個(gè)Record:
1)DevSvcRecord:每個(gè)服務(wù)對(duì)應(yīng)一個(gè)DevSvcRecord,這個(gè)節(jié)點(diǎn)會(huì)插入DevSvcManager內(nèi)部的services鏈表。如果發(fā)布服務(wù)時(shí),發(fā)現(xiàn)對(duì)應(yīng)的DevSvcRecord已經(jīng)存在了,則會(huì)向所有訂閱者發(fā)出通知。
2)HdfServiceObserverRecord:每個(gè)服務(wù)對(duì)應(yīng)一個(gè)HdfServiceObserverRecord,這個(gè)節(jié)點(diǎn)會(huì)插入DevSvcManager內(nèi)的observer部分(內(nèi)部的services鏈表)里。每個(gè)HdfServiceObserverRecord負(fù)責(zé)維護(hù)一個(gè)“訂閱者”鏈表,記錄所有對(duì)該服務(wù)感興趣的訂閱者。
DevSvcRecord的value域是個(gè)HdfDeviceObject *指針,其實(shí)指向的就是和設(shè)備對(duì)應(yīng)的DeviceNodeExt節(jié)點(diǎn)的deviceObject部分,根據(jù)我們以前儲(chǔ)備的知識(shí),我們知道這個(gè)deviceObject部分的service域指向的就是設(shè)備驅(qū)動(dòng)實(shí)現(xiàn)的IDeviceIoService接口。
另外,從前面代碼的serviceRecord->publisher = service一句,可以看到HdfServiceObserverRecord的publisher域,其實(shí)也是指向設(shè)備驅(qū)動(dòng)實(shí)現(xiàn)的IDeviceIoService接口的。這樣我們可以繪制如下的示意圖:
當(dāng)然,一開(kāi)始HdfServiceObserverRecord里是“訂閱者”鏈表為空啦,不過(guò)日后如果有其他服務(wù)注冊(cè)為訂閱者了,HdfServiceObserverRecordNotifySubscribers()就可以向它們發(fā)送通知了。發(fā)通知函數(shù)的代碼如下:
【drivers/hdf/frameworks/core/host/src/Hdf_observer_record.c】
- void HdfServiceObserverRecordNotifySubscribers(struct HdfServiceObserverRecord *record, uint32_t matchId, uint16_t policy)
- {
- struct HdfSListIterator it;
- . . . . . .
- OsalMutexLock(&record->obsRecMutex);
- HdfSListIteratorInit(&it, &record->subscribers);
- while (HdfSListIteratorHasNext(&it)) {
- struct HdfServiceSubscriber *subscriber = (struct HdfServiceSubscriber *)HdfSListIteratorNext(&it);
- if ((matchId == subscriber->matchId) || (policy != SERVICE_POLICY_PRIVATE)) {
- subscriber->state = HDF_SUBSCRIBER_STATE_READY;
- if (subscriber->callback.OnServiceConnected != NULL) {
- subscriber->callback.OnServiceConnected(subscriber->callback.deviceObject, record->publisher);
- }
- }
- }
- OsalMutexUnlock(&record->obsRecMutex);
- }
復(fù)制代碼
其實(shí)就是在遍歷訂閱者鏈表,回調(diào)其callback部分的OnServiceConnected()函數(shù)。
訂閱者鏈表里的每個(gè)節(jié)點(diǎn)是一個(gè)HdfServiceSubscriber,示意圖如下:
以上這些其實(shí)都體現(xiàn)了鴻蒙系統(tǒng)里的一個(gè)觀念,那就是“設(shè)備”其實(shí)可以被理解為“服務(wù)”。在單機(jī)系統(tǒng)里,一個(gè)設(shè)備的驅(qū)動(dòng)程序可以被理解為一種特殊的庫(kù),上層軟件通過(guò)類(lèi)似函數(shù)調(diào)用的方式來(lái)調(diào)用庫(kù),從而操作這個(gè)設(shè)備。但如果要跨機(jī)器地操作設(shè)備,那么就不能直接調(diào)用函數(shù)了。一種較好地方式是將目標(biāo)設(shè)備包裝成一個(gè)邏輯上的服務(wù),然后供大家使用。所以就必須把“驅(qū)動(dòng)層次”和“服務(wù)層次”關(guān)聯(lián)起來(lái),這才有了前文所說(shuō)的那么多數(shù)據(jù)機(jī)構(gòu)。現(xiàn)在我們畫(huà)一張大一點(diǎn)的示意圖,把以上概念串一下:
圖中畫(huà)出了體現(xiàn)“設(shè)備(驅(qū)動(dòng))層次”和“服務(wù)層次”的兩大管理者——DevmgrService和DevSvcManager,可供大家參考。
1.2 發(fā)布Local Service部分
看完了發(fā)布Public Service的部分,我們接著看HdfDeviceNodePublishService()里發(fā)布Local Service的部分。此時(shí)調(diào)用的是HdfDeviceNodePublishLocalService()。
【drivers/hdf/frameworks/core/host/src/Hdf_device_node.c】
- static int HdfDeviceNodePublishLocalService(
- struct HdfDeviceNode *devNode, const struct HdfDeviceInfo *deviceInfo)
- {
- uint32_t matchId;
- . . . . . .
- struct DevHostService *hostService = devNode->hostService;
- . . . . . .
- matchId = HdfMakeHardwareId(deviceInfo->hostId, deviceInfo->deviceId);
- return HdfServiceObserverPublishService(&hostService->observer, deviceInfo->svcName,
- matchId, deviceInfo->policy, (struct HdfObject *)devNode->deviceObject.service);
- }
復(fù)制代碼
請(qǐng)注意,雖然也是在調(diào)用HdfServiceObserverPublishService(),但傳入的第一個(gè)參數(shù)是&hostService->observer。也就是說(shuō),Public Service對(duì)應(yīng)的監(jiān)聽(tīng)部分,記錄在DevSvcManager里,而Local Service對(duì)應(yīng)的監(jiān)聽(tīng)部分,則記錄在其所屬的DevHostService里。
現(xiàn)在我們可以畫(huà)一張發(fā)布驅(qū)動(dòng)的調(diào)用關(guān)系圖:
2 掛接設(shè)備我們回過(guò)頭繼續(xù)說(shuō)前文的HdfDeviceLaunchNode()部分。該函數(shù)在調(diào)用完HdfDeviceNodePublishService()之后,接著就會(huì)調(diào)用DevmgrServiceClntAttachDevice()。
【drivers/hdf/frameworks/core/host/src/Devmgr_service_clnt.c】
- int DevmgrServiceClntAttachDevice(const struct HdfDeviceInfo *deviceInfo, struct IHdfDeviceToken *deviceToken)
- {
- struct IDevmgrService *devMgrSvcIf = NULL;
- struct DevmgrServiceClnt *inst = DevmgrServiceClntGetInstance();
- . . . . . .
- devMgrSvcIf = inst->devMgrSvcIf;
- . . . . . .
- // 實(shí)際調(diào)用的是 DevmgrServiceAttachDevice()
- return devMgrSvcIf->AttachDevice(devMgrSvcIf, deviceInfo, deviceToken);
- }
復(fù)制代碼
此處調(diào)用了DevmgrServiceAttachDevice():
【drivers/hdf/frameworks/core/manager/src/Devmgr_service.c】
- static int DevmgrServiceAttachDevice(struct IDevmgrService *inst,
- const struct HdfDeviceInfo *deviceInfo, struct IHdfDeviceToken *token)
- {
- . . . . . .
- struct DevHostServiceClnt *hostClnt = DevmgrServiceFindDeviceHost(inst, deviceInfo->hostId);
- . . . . . .
- struct IDevHostService *hostService = hostClnt->hostService;
- . . . . . .
- struct DeviceTokenClnt *tokenClnt = DeviceTokenClntNewInstance(token);
- . . . . . .
- tokenClnt->deviceInfo = deviceInfo;
- HdfSListAdd(&hostClnt->devices, &tokenClnt->node);
- return HDF_SUCCESS;
- }
復(fù)制代碼
主要就是向?qū)?yīng)的DevHostServiceClnt的devices鏈表里,添加一個(gè)DeviceTokenClnt節(jié)點(diǎn)。簡(jiǎn)單地說(shuō)就是,一個(gè)DevHostServiceClnt和一個(gè)DevHostService對(duì)應(yīng),每當(dāng)向DevHostService里添加一個(gè)HdfDevice節(jié)點(diǎn),相應(yīng)地就需要在DevHostServiceClnt里添加一個(gè)DeviceTokenClnt節(jié)點(diǎn)。該節(jié)點(diǎn)的tokenIf域記錄的IHdfDeviceToken指針,來(lái)自于DeviceNodeExt的token域。
說(shuō)起來(lái),DeviceNodeExt的token其實(shí)在DeviceNodeExt構(gòu)造之時(shí)就創(chuàng)建了:
【drivers/hdf/frameworks/core/host/src/Hdf_device_node.c】
- void HdfDeviceNodeConstruct(struct HdfDeviceNode *devNode)
- {
- if (devNode != NULL) {
- struct IDeviceNode *nodeIf = &devNode->super;
- HdfDeviceObjectConstruct(&devNode->deviceObject);
- devNode->token = HdfDeviceTokenNewInstance();
- nodeIf->LaunchNode = HdfDeviceLaunchNode;
- nodeIf->PublishService = HdfDeviceNodePublishPublicService;
- }
- }
復(fù)制代碼
其中創(chuàng)建token時(shí),調(diào)用的是HdfDeviceTokenNewInstance()。
【drivers/hdf/frameworks/core/host/src/Hdf_device_token.c】
- struct IHdfDeviceToken *HdfDeviceTokenNewInstance()
- {
- return (struct IHdfDeviceToken *)HdfObjectManagerGetObject(HDF_OBJECT_ID_DEVICE_TOKEN);
- }
復(fù)制代碼
【drivers/hdf/frameworks/core/host/src/Hdf_device_token.c】
- struct HdfObject *HdfDeviceTokenCreate()
- {
- struct HdfDeviceToken *token = (struct HdfDeviceToken *)OsalMemcalloc(sizeof(struct HdfDeviceToken));
- if (token != NULL) {
- HdfDeviceTokenConstruct(token);
- }
- return (struct HdfObject *)token;
- }
復(fù)制代碼
其中HdfDeviceToken的定義如下:
- struct HdfDeviceToken {
- struct HdfSListNode node;
- struct IHdfDeviceToken super;
- };
復(fù)制代碼
咦,怎么又有bug的味道,HdfDeviceToken里應(yīng)該把super放到第一個(gè)吧,否則怎么強(qiáng)制轉(zhuǎn)化成struct HdfObject*呢?好在這個(gè)bug的危害不太大,后續(xù)版本可以調(diào)整一下。
現(xiàn)在我們可以再畫(huà)一張圖看看:
3 小結(jié)
經(jīng)過(guò)以上分析,我們頭腦中已經(jīng)可以形成一套比較清楚的HDF邏輯結(jié)構(gòu)了?傊褪菍ⅰ霸O(shè)備(驅(qū)動(dòng))層次”和“服務(wù)層次”聯(lián)系起來(lái),該加的observer機(jī)制加上。好了,這次就先寫(xiě)到這兒,以后我們?cè)傺a(bǔ)充其他內(nèi)容。
文章轉(zhuǎn)自: 侯亮(悠然紅茶) |
|