電子產(chǎn)業(yè)一站式賦能平臺

PCB聯(lián)盟網(wǎng)

搜索
查看: 612|回復(fù): 0
收起左側(cè)

品讀鴻蒙HDF架構(gòu)(三)

[復(fù)制鏈接]

2607

主題

2607

帖子

7472

積分

高級會員

Rank: 5Rank: 5

積分
7472
跳轉(zhuǎn)到指定樓層
樓主
發(fā)表于 2020-12-16 15:56:35 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
品讀鴻蒙HDF架構(gòu)(三), 現(xiàn)在我們繼續(xù)研究鴻蒙HDF架構(gòu),上回書說到經(jīng)由HdfDeviceAttach(),HdfDevice節(jié)點不但添加進(jìn)了DevHostService的devices列表,而且還和一個DeviceNodeExt聯(lián)系起來了,呈現(xiàn)的示意圖大致如下: 接著,HdfDeviceAttach()最后會調(diào)用nodeIf->LaunchNode(),這一步實際上調(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”本就是啟動之意,在這里就是指啟動與HdfDevice對應(yīng)的驅(qū)動服務(wù)。所以此處會先調(diào)用一下driverEntry->Init(),并傳入?yún)?shù)&devNode->deviceObject。這意味著要求驅(qū)動程序在初始化時,回填一下deviceObject里的service域。

接著,主要執(zhí)行了兩個動作:

1)發(fā)布驅(qū)動服務(wù)

2)掛接設(shè)備

我們會分兩小節(jié)來闡述。


1.發(fā)布驅(qū)動服務(wù)

初始化完成后,就可以“發(fā)布”這個驅(qū)動服務(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) {
      
  •             // 其實調(diào)用的是 DeviceNodeExtPublishService()
      
  •             status = nodeIf->PublishService(devNode, deviceInfo->svcName);
      
  •         }
      
  •     }
      
  •     if (status == HDF_SUCCESS) {
      
  •         status = HdfDeviceNodePublishLocalService(devNode, deviceInfo);
      
  •     }
      
  •     return status;
      
  • }

復(fù)制代碼 從字面上理解,如果一個設(shè)備是“公共型”或“功能型”的,則會調(diào)用nodeIf->PublishService()發(fā)布對應(yīng)的驅(qū)動服務(wù)。而我們以前研究過,在HdfDeviceNode構(gòu)造之時,我們可以看到為PublishService域設(shè)定了DeviceNodeExtPublishService()函數(shù)指針,因此上面代碼中調(diào)用PublishService的地方,其實就是在調(diào)用這個函數(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ù)制代碼 這樣說來,發(fā)布服務(wù)時其實分了兩個部分,一個是發(fā)布public部分,一個是發(fā)布local部分。分別對應(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;
      
  •     . . . . . .
      
  •     // 其實調(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)中有一個“設(shè)備服務(wù)管理器”(DevSvcManager),那些功能型設(shè)備都會把自己注冊進(jìn)它。這個倒有點兒像Android里的SMS(Service Manager Service),所有系統(tǒng)核心服務(wù)都會向SMS里注冊自己,以便其他應(yīng)用可以從SMS查詢并獲取服務(wù)代理。實際上,鴻蒙系統(tǒng)在不少方面倒的確和Android有一定類比性,這個以后我們再對比看看,目前先放下不談。



注冊設(shè)備服務(wù)的那句serviceManager->AddService()實際上調(diào)用的是DevSvcManagerAddService(),該函數(shù)會嘗試向“設(shè)備服務(wù)管理器”里添加一個管理節(jié)點(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ù)制代碼

對于“設(shè)備服務(wù)管理器”而言,當(dāng)它要管理一個設(shè)備服務(wù)時,主要需要兩個Record:

1)DevSvcRecord:每個服務(wù)對應(yīng)一個DevSvcRecord,這個節(jié)點會插入DevSvcManager內(nèi)部的services鏈表。如果發(fā)布服務(wù)時,發(fā)現(xiàn)對應(yīng)的DevSvcRecord已經(jīng)存在了,則會向所有訂閱者發(fā)出通知。



2)HdfServiceObserverRecord:每個服務(wù)對應(yīng)一個HdfServiceObserverRecord,這個節(jié)點會插入DevSvcManager內(nèi)的observer部分(內(nèi)部的services鏈表)里。每個HdfServiceObserverRecord負(fù)責(zé)維護(hù)一個“訂閱者”鏈表,記錄所有對該服務(wù)感興趣的訂閱者。



DevSvcRecord的value域是個HdfDeviceObject *指針,其實指向的就是和設(shè)備對應(yīng)的DeviceNodeExt節(jié)點的deviceObject部分,根據(jù)我們以前儲備的知識,我們知道這個deviceObject部分的service域指向的就是設(shè)備驅(qū)動實現(xiàn)的IDeviceIoService接口。



另外,從前面代碼的serviceRecord->publisher = service一句,可以看到HdfServiceObserverRecord的publisher域,其實也是指向設(shè)備驅(qū)動實現(xiàn)的IDeviceIoService接口的。這樣我們可以繪制如下的示意圖:

當(dāng)然,一開始HdfServiceObserverRecord里是“訂閱者”鏈表為空啦,不過日后如果有其他服務(wù)注冊為訂閱者了,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ù)制代碼

其實就是在遍歷訂閱者鏈表,回調(diào)其callback部分的OnServiceConnected()函數(shù)。

訂閱者鏈表里的每個節(jié)點是一個HdfServiceSubscriber,示意圖如下:

以上這些其實都體現(xiàn)了鴻蒙系統(tǒng)里的一個觀念,那就是“設(shè)備”其實可以被理解為“服務(wù)”。在單機(jī)系統(tǒng)里,一個設(shè)備的驅(qū)動程序可以被理解為一種特殊的庫,上層軟件通過類似函數(shù)調(diào)用的方式來調(diào)用庫,從而操作這個設(shè)備。但如果要跨機(jī)器地操作設(shè)備,那么就不能直接調(diào)用函數(shù)了。一種較好地方式是將目標(biāo)設(shè)備包裝成一個邏輯上的服務(wù),然后供大家使用。所以就必須把“驅(qū)動層次”和“服務(wù)層次”關(guān)聯(lián)起來,這才有了前文所說的那么多數(shù)據(jù)機(jī)構(gòu),F(xiàn)在我們畫一張大一點的示意圖,把以上概念串一下:

圖中畫出了體現(xiàn)“設(shè)備(驅(qū)動)層次”和“服務(wù)層次”的兩大管理者——DevmgrService和DevSvcManager,可供大家參考。




1.2 發(fā)布Local Service部分

看完了發(fā)布Public Service的部分,我們接著看HdfDeviceNodePublishService()里發(fā)布Local Service的部分。此時調(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ù)制代碼

請注意,雖然也是在調(diào)用HdfServiceObserverPublishService(),但傳入的第一個參數(shù)是&hostService->observer。也就是說,Public Service對應(yīng)的監(jiān)聽部分,記錄在DevSvcManager里,而Local Service對應(yīng)的監(jiān)聽部分,則記錄在其所屬的DevHostService里。

現(xiàn)在我們可以畫一張發(fā)布驅(qū)動的調(diào)用關(guān)系圖:



2 掛接設(shè)備
我們回過頭繼續(xù)說前文的HdfDeviceLaunchNode()部分。該函數(shù)在調(diào)用完HdfDeviceNodePublishService()之后,接著就會調(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;
      
  •     . . . . . .
      
  •     // 實際調(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鏈表里,添加一個DeviceTokenClnt節(jié)點。簡單地說就是,一個DevHostServiceClnt和一個DevHostService對應(yīng),每當(dāng)向DevHostService里添加一個HdfDevice節(jié)點,相應(yīng)地就需要在DevHostServiceClnt里添加一個DeviceTokenClnt節(jié)點。該節(jié)點的tokenIf域記錄的IHdfDeviceToken指針,來自于DeviceNodeExt的token域。

說起來,DeviceNodeExt的token其實在DeviceNodeExt構(gòu)造之時就創(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時,調(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放到第一個吧,否則怎么強制轉(zhuǎn)化成struct HdfObject*呢?好在這個bug的危害不太大,后續(xù)版本可以調(diào)整一下。

現(xiàn)在我們可以再畫一張圖看看:



3 小結(jié)


經(jīng)過以上分析,我們頭腦中已經(jīng)可以形成一套比較清楚的HDF邏輯結(jié)構(gòu)了?傊褪菍ⅰ霸O(shè)備(驅(qū)動)層次”和“服務(wù)層次”聯(lián)系起來,該加的observer機(jī)制加上。好了,這次就先寫到這兒,以后我們再補充其他內(nèi)容。



文章轉(zhuǎn)自: 侯亮(悠然紅茶)
回復(fù)

使用道具 舉報

發(fā)表回復(fù)

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則


聯(lián)系客服 關(guān)注微信 下載APP 返回頂部 返回列表