侯 亮
现在我们继续研究鸿蒙HDF架构,上回书说到经由HdfDeviceAttach(),HdfDevice节点不但添加进了DevHostService的devices列表,而且还和一个DeviceNodeExt联系起来了,呈现的示意图大致如下:
接着,HdfDeviceAttach()最后会调用nodeIf->LaunchNode(),这一步实际上调用的是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; }“Launch”本就是启动之意,在这里就是指启动与HdfDevice对应的驱动服务。所以此处会先调用一下driverEntry->Init(),并传入参数&devNode->deviceObject。这意味着要求驱动程序在初始化时,回填一下deviceObject里的service域。
接着,主要执行了两个动作: 1)发布驱动服务 2)挂接设备 我们会分两小节来阐述。
初始化完成后,就可以“发布”这个驱动服务了,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) { // 其实调用的是 DeviceNodeExtPublishService() status = nodeIf->PublishService(devNode, deviceInfo->svcName); } } if (status == HDF_SUCCESS) { status = HdfDeviceNodePublishLocalService(devNode, deviceInfo); } return status; }从字面上理解,如果一个设备是“公共型”或“功能型”的,则会调用nodeIf->PublishService()发布对应的驱动服务。而我们以前研究过,在HdfDeviceNode构造之时,我们可以看到为PublishService域设定了DeviceNodeExtPublishService()函数指针,因此上面代码中调用PublishService的地方,其实就是在调用这个函数。
【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; }这样说来,发布服务时其实分了两个部分,一个是发布public部分,一个是发布local部分。分别对应HdfDeviceNodePublishPublicService()和HdfDeviceNodePublishLocalService()。
【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; . . . . . . // 其实调用的是 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; }从代码看,系统中有一个“设备服务管理器”(DevSvcManager),那些功能型设备都会把自己注册进它。这个倒有点儿像Android里的SMS(Service Manager Service),所有系统核心服务都会向SMS里注册自己,以便其他应用可以从SMS查询并获取服务代理。实际上,鸿蒙系统在不少方面倒的确和Android有一定类比性,这个以后我们再对比看看,目前先放下不谈。
注册设备服务的那句serviceManager->AddService()实际上调用的是DevSvcManagerAddService(),该函数会尝试向“设备服务管理器”里添加一个管理节点(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); }【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; }对于“设备服务管理器”而言,当它要管理一个设备服务时,主要需要两个Record: 1)DevSvcRecord:每个服务对应一个DevSvcRecord,这个节点会插入DevSvcManager内部的services链表。如果发布服务时,发现对应的DevSvcRecord已经存在了,则会向所有订阅者发出通知。 2)HdfServiceObserverRecord:每个服务对应一个HdfServiceObserverRecord,这个节点会插入DevSvcManager内的observer部分(内部的services链表)里。每个HdfServiceObserverRecord负责维护一个“订阅者”链表,记录所有对该服务感兴趣的订阅者。
DevSvcRecord的value域是个HdfDeviceObject *指针,其实指向的就是和设备对应的DeviceNodeExt节点的deviceObject部分,根据我们以前储备的知识,我们知道这个deviceObject部分的service域指向的就是设备驱动实现的IDeviceIoService接口。
另外,从前面代码的serviceRecord->publisher = service一句,可以看到HdfServiceObserverRecord的publisher域,其实也是指向设备驱动实现的IDeviceIoService接口的。这样我们可以绘制如下的示意图:
当然,一开始HdfServiceObserverRecord里是“订阅者”链表为空啦,不过日后如果有其他服务注册为订阅者了,HdfServiceObserverRecordNotifySubscribers()就可以向它们发送通知了。发通知函数的代码如下: 【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); }其实就是在遍历订阅者链表,回调其callback部分的OnServiceConnected()函数。
订阅者链表里的每个节点是一个HdfServiceSubscriber,示意图如下:
以上这些其实都体现了鸿蒙系统里的一个观念,那就是“设备”其实可以被理解为“服务”。在单机系统里,一个设备的驱动程序可以被理解为一种特殊的库,上层软件通过类似函数调用的方式来调用库,从而操作这个设备。但如果要跨机器地操作设备,那么就不能直接调用函数了。一种较好地方式是将目标设备包装成一个逻辑上的服务,然后供大家使用。所以就必须把“驱动层次”和“服务层次”关联起来,这才有了前文所说的那么多数据机构。现在我们画一张大一点的示意图,把以上概念串一下:
图中画出了体现“设备(驱动)层次”和“服务层次”的两大管理者——DevmgrService和DevSvcManager,可供大家参考。
看完了发布Public Service的部分,我们接着看HdfDeviceNodePublishService()里发布Local Service的部分。此时调用的是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); }请注意,虽然也是在调用HdfServiceObserverPublishService(),但传入的第一个参数是&hostService->observer。也就是说,Public Service对应的监听部分,记录在DevSvcManager里,而Local Service对应的监听部分,则记录在其所属的DevHostService里。
现在我们可以画一张发布驱动的调用关系图:
我们回过头继续说前文的HdfDeviceLaunchNode()部分。该函数在调用完HdfDeviceNodePublishService()之后,接着就会调用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; . . . . . . // 实际调用的是 DevmgrServiceAttachDevice() return devMgrSvcIf->AttachDevice(devMgrSvcIf, deviceInfo, deviceToken); }此处调用了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; }主要就是向对应的DevHostServiceClnt的devices链表里,添加一个DeviceTokenClnt节点。简单地说就是,一个DevHostServiceClnt和一个DevHostService对应,每当向DevHostService里添加一个HdfDevice节点,相应地就需要在DevHostServiceClnt里添加一个DeviceTokenClnt节点。该节点的tokenIf域记录的IHdfDeviceToken指针,来自于DeviceNodeExt的token域。
说起来,DeviceNodeExt的token其实在DeviceNodeExt构造之时就创建了: 【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; } }其中创建token时,调用的是HdfDeviceTokenNewInstance()。
【drivers/hdf/frameworks/core/host/src/Hdf_device_token.c】
struct IHdfDeviceToken *HdfDeviceTokenNewInstance() { return (struct IHdfDeviceToken *)HdfObjectManagerGetObject(HDF_OBJECT_ID_DEVICE_TOKEN); }【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; }其中HdfDeviceToken的定义如下:
struct HdfDeviceToken { struct HdfSListNode node; struct IHdfDeviceToken super; };咦,怎么又有bug的味道,HdfDeviceToken里应该把super放到第一个吧,否则怎么强制转化成struct HdfObject*呢?好在这个bug的危害不太大,后续版本可以调整一下。
现在我们可以再画一张图看看:
经过以上分析,我们头脑中已经可以形成一套比较清楚的HDF逻辑结构了。总之就是将“设备(驱动)层次”和“服务层次”联系起来,该加的observer机制加上。好了,这次就先写到这儿,以后我们再补充其他内容。
(我正在参加 的【鸿蒙技术征文】活动,请给我点赞支持。)