1. 模块概述

Connected NFC Tag模块是OpenHarmony NFC子系统的一部分,专门用于处理有源NFC标签的读写操作。与基础NFC模块不同,该模块专注于与已连接的有源NFC标签进行交互,提供更高层次的API供应用层使用。

设备必须具备有源NFC标签芯片,才能使用有源NFC标签的读和写服务

1.1 模块功能

  • 提供有源NFC标签的初始化和去初始化功能
  • 支持有源NFC标签的NDEF数据读写操作
  • 提供事件回调机制,通知应用层标签状态变化

1.2 模块架构

Connected NFC Tag模块采用分层架构设计,从上到下分为:

  1. 应用层接口:为应用提供访问有源NFC标签的API
  2. 服务层:实现核心业务逻辑,包括权限检查、HDI适配等
  3. HDI层:与硬件抽象层交互,实现具体的读写操作

关于NFC通信技术的讲解可以参考我的文章:- 深度拆解OpenHarmony NFC服务:从开关到卡模拟掌握近场通信技术

2. 关键类及函数调用流程

2.1 服务启动流程

NfcTagService::OnStart
NfcTagService::ServiceInit
Publish Service
Service Running

2.2 NFC标签初始化流程

INfcTagService::Init
NfcTagService::Init
VerifyPermissions
NfcTagHdiAdapter::Init
Get HDI Proxy
Call HDI Init

2.3 NFC标签读取流程

INfcTagService::ReadNdefTag
NfcTagService::ReadNdefTag
VerifyPermissions
NfcTagHdiAdapter::ReadNdefTag
Get HDI Proxy
Call HDI ReadNdefTag

2.4 NFC标签写入流程

INfcTagService::WriteNdefTag
NfcTagService::WriteNdefTag
VerifyPermissions
NfcTagHdiAdapter::WriteNdefTag
Get HDI Proxy
Call HDI WriteNdefTag

2.5 事件回调注册流程

INfcTagService::RegListener
NfcTagService::RegListener
VerifyPermissions
Create CallbackManager
NfcTagHdiAdapter::RegisterCallBack
Call HDI RegisterCallBack

3. 关键接口及实现

3.1 INfcTagService接口

INfcTagService是Connected NFC Tag模块对外提供的核心接口,定义了有源NFC标签的基本操作。

接口定义文件:foundation/communication/connected_nfc_tag/interfaces/inner_api/include/infc_tag_service.h

主要方法:

  • Init(): 初始化NFC标签服务
  • Uninit(): 去初始化NFC标签服务
  • ReadNdefTag(std::string &response): 读取NFC标签的NDEF数据
  • WriteNdefTag(const std::string &data): 向NFC标签写入NDEF数据
  • ReadNdefData(std::vector<uint8_t> &data): 读取NFC标签的原始数据
  • WriteNdefData(const std::vector<uint8_t> &data): 向NFC标签写入原始数据
  • RegListener(const sptr<INfcTagCallback> &callback): 注册事件回调
  • UnregListener(const sptr<INfcTagCallback> &callback): 注销事件回调

3.2 INfcTagCallback接口

INfcTagCallback是Connected NFC Tag模块的事件回调接口,用于通知应用层标签状态变化。

接口定义文件:foundation/communication/connected_nfc_tag/interfaces/inner_api/include/infc_tag_callback.h

主要方法:

  • OnNotify(int nfcRfState): 当NFC标签状态发生变化时调用

3.3 NfcTagService实现类

NfcTagService是INfcTagService接口的具体实现类,负责处理业务逻辑。

实现文件:foundation/communication/connected_nfc_tag/services/src/nfc_tag_service.cpp

关键方法实现:

  • OnStart(): 服务启动入口
  • ServiceInit(): 服务初始化
  • Init(): 初始化NFC标签服务,包含权限检查
  • ReadNdefTag(): 读取NFC标签的NDEF数据,包含权限检查
  • WriteNdefTag(): 写入NFC标签的NDEF数据,包含权限检查
  • RegListener(): 注册事件回调

3.4 NfcTagHdiAdapter实现类

NfcTagHdiAdapter是HDI适配器类,负责与HDI层交互。

实现文件:foundation/communication/connected_nfc_tag/services/src/hdi/src/nfc_tag_hdi_adapter.cpp

关键方法实现:

  • Init(): 调用HDI层的初始化方法
  • ReadNdefTag(): 调用HDI层的读取方法
  • WriteNdefTag(): 调用HDI层的写入方法
  • RegisterCallBack(): 注册回调到HDI层

4. 模块间关系

Connected NFC Tag模块与基础NFC模块的关系:

  1. Connected NFC Tag模块是基础NFC模块的扩展,专注于有源NFC标签的处理
  2. 两个模块都使用了HDI层进行硬件交互,但处理的设备类型不同
  3. Connected NFC Tag模块通过系统能力ID NFC_CONNECTED_TAG_ABILITY_ID注册到系统中

5. 设计模式与最佳实践

5.1 使用的设计模式

  1. 单例模式:

    • NfcTagHdiAdapter使用单例模式确保全局只有一个实例
    • 通过GetInstance()方法获取实例
  2. Pimpl惯用法:

    • NfcTagHdiAdapter使用Pimpl惯用法隐藏实现细节
    • 通过Impl类封装具体实现,降低编译依赖
  3. 代理模式:

    • NfcTagHdiAdapter作为HDI服务的代理
    • 隐藏了与HDI服务交互的复杂性
  4. 观察者模式:

    • 通过INfcTagCallback接口实现事件回调机制
    • NfcTagCallBackManager管理多个观察者

5.2 最佳实践

  1. 权限检查:

    • 在每个对外接口中都进行了权限检查
    • 使用VerifyPermissionsBeforeEntry()方法统一处理权限验证
  2. 线程安全:

    • 使用std::mutex保护共享资源
    • 在回调管理器和HDI适配器中都有锁保护
  3. 错误处理:

    • 定义了详细的错误码nfc_tag_errcode.h
    • 每个方法都有明确的错误返回值
  4. 资源管理:

    • 使用智能指针管理对象生命周期
    • 在析构函数中释放资源
  5. 日志记录:

    • 使用HILOG记录关键操作和错误信息
    • 便于调试和问题定位

5. 底层数据传输原理

Connected NFC Tag模块的数据传输基于HDI(Hardware Device Interface)机制:

  1. 服务层通过HDI代理获取HDI服务实例
  2. 调用HDI服务的方法执行具体的读写操作
  3. HDI层负责与硬件驱动交互,完成实际的数据传输
  4. 通过回调机制将硬件事件通知到服务层

5.1 数据传输时序图

应用层 NfcTagService NfcTagHdiAdapter HDI服务 硬件层 调用Init() 调用Init() 获取代理并调用Init() 初始化硬件 返回结果 返回结果 返回结果 返回结果 调用ReadNdefTag() 调用ReadNdefTag() 获取代理并调用ReadNdefTag() 读取标签数据 返回数据 返回数据 返回数据 返回数据 应用层 NfcTagService NfcTagHdiAdapter HDI服务 硬件层

5.2 回调机制时序图

硬件层 HDI服务 NfcTagHdiAdapter NfcTagService 应用层 触发事件 调用OnChipEvent() 调用回调管理器的OnNotify() 调用注册的回调函数 硬件层 HDI服务 NfcTagHdiAdapter NfcTagService 应用层

6. 关键数据结构

6.1 NfcTagService

服务类,包含服务状态、回调管理器等信息。该类继承自系统能力框架,负责管理Connected NFC Tag服务的生命周期。

关键成员变量:

  • published_: 服务发布状态,标识服务是否已成功发布到系统能力管理器
  • state_: 服务运行状态,标识服务当前是否处于运行状态
  • callbackManager_: 回调管理器实例,用于管理所有注册的事件回调监听器

关键方法:

  • OnStart(): 系统能力启动入口,当系统能力被激活时调用
  • OnStop(): 系统能力停止入口,当系统能力被停用时调用
  • ServiceInit(): 服务初始化,负责发布服务到系统能力管理器
  • VerifyPermissionsBeforeEntry(): 权限检查,在每个对外接口调用前验证调用者权限

构造函数与析构函数:

  • NfcTagService(): 构造函数,初始化成员变量
  • ~NfcTagService(): 析构函数,清理资源并注销所有回调监听器

实现细节:

  • OnStart()方法首先调用ServiceInit()进行服务初始化,然后将服务发布到系统能力管理器
  • OnStop()方法负责清理资源,包括注销回调监听器和停止服务
  • ServiceInit()方法通过调用Publish(this)将服务实例发布到系统能力管理器
  • VerifyPermissionsBeforeEntry()方法使用系统权限检查API验证调用者是否具有访问NFC功能的权限

6.2 NfcTagCallBackManager

回调管理器,负责管理注册的回调监听器。该类使用线程安全的映射表存储回调监听器,并提供注册、注销和通知功能。

关键成员变量:

  • listenerMap_: 回调监听器映射表,使用std::map存储回调监听器,键为监听器ID,值为监听器实例
  • listenerMapLock_: 回调监听器映射表锁,使用std::mutex保护映射表的线程安全访问

关键方法:

  • RegisterListener(): 注册回调监听器,将回调监听器添加到映射表中
  • UnRegisterListener(): 注销回调监听器,从映射表中移除指定的回调监听器
  • OnNotify(): 通知所有注册的监听器,遍历映射表并调用每个监听器的回调方法

构造函数与析构函数:

  • NfcTagCallBackManager(): 构造函数,初始化成员变量
  • ~NfcTagCallBackManager(): 析构函数,清理资源

实现细节:

  • RegisterListener()方法首先获取映射表锁,然后将回调监听器添加到映射表中
  • UnRegisterListener()方法首先获取映射表锁,然后从映射表中移除指定的回调监听器
  • OnNotify()方法首先获取映射表锁,复制映射表以避免在遍历过程中修改映射表,然后释放锁并遍历复制的映射表调用每个监听器的回调方法

6.3 NfcTagHdiAdapter

HDI适配器,负责与HDI层交互。该类使用单例模式和Pimpl惯用法,隐藏了与HDI服务交互的复杂性。

关键成员变量:

  • pimpl_: 指向Impl类的智能指针,封装了具体的HDI服务交互逻辑
  • implMutex_: Impl类实例锁,确保多线程环境下Impl类实例的安全访问

关键方法:

  • GetInstance(): 获取单例实例,确保全局只有一个NfcTagHdiAdapter实例
  • Init(): 初始化HDI适配器,获取HDI服务代理并调用HDI层的初始化方法
  • Uninit(): 去初始化HDI适配器,释放HDI服务代理并调用HDI层的去初始化方法
  • ReadNdefTag(): 读取NDEF标签数据,通过HDI服务代理调用HDI层的读取方法
  • WriteNdefTag(): 写入NDEF标签数据,通过HDI服务代理调用HDI层的写入方法
  • RegisterCallBack(): 注册回调,将上层回调注册到HDI服务
  • UnRegisterCallBack(): 注销回调,从HDI服务注销上层回调

构造函数与析构函数:

  • NfcTagHdiAdapter(): 构造函数,初始化Impl类实例
  • ~NfcTagHdiAdapter(): 析构函数,释放Impl类实例

实现细节:

  • GetInstance()方法使用双重检查锁定模式确保线程安全的单例实例获取,避免了不必要的加锁开销
  • Init()方法首先获取Impl类实例锁,然后调用Impl类的Init()方法,确保多线程环境下Impl类实例的安全访问
  • ReadNdefTag()WriteNdefTag()方法通过Impl类实例与HDI服务交互,确保所有HDI操作都在保护下进行
  • RegisterCallBack()方法将上层回调传递给Impl类,由Impl类负责注册到HDI服务,实现了回调机制的分层处理

线程安全考虑:

  • 使用implMutex_保护Impl类实例的访问,防止多个线程同时操作Impl类实例
  • 在所有对外接口方法中都获取了Impl类实例锁,确保方法执行的原子性
  • Impl类内部也使用了锁机制保护HDI服务代理和回调接口的访问

6.4 NfcTagHdiAdapter::Impl

HDI适配器的具体实现类,负责与HDI服务交互。该类封装了所有与HDI服务直接交互的逻辑,包括获取服务代理、调用服务方法以及处理回调事件。

关键成员变量:

  • nfcTagProxy_: HDI服务代理,通过HDI框架获取的IConnectedNfcTagV1_1接口实例
  • proxyMutex_: HDI服务代理锁,确保多线程环境下代理实例的安全访问
  • upperCallBack_: 上层回调,保存注册的上层回调接口
  • callbackMutex_: 上层回调锁,确保多线程环境下回调接口的安全访问
  • inited: 初始化状态,标识HDI服务是否已成功初始化

关键方法:

  • GetProxy(): 获取HDI服务代理,通过HDI框架获取IConnectedNfcTagV1_1接口实例
  • Init(): 初始化HDI服务,获取服务代理并调用HDI层的初始化方法
  • Uninit(): 去初始化HDI服务,释放服务代理并调用HDI层的去初始化方法
  • ReadNdefTag(): 读取NDEF标签数据,通过服务代理调用HDI层的读取方法
  • WriteNdefTag(): 写入NDEF标签数据,通过服务代理调用HDI层的写入方法
  • RegisterCallBack(): 注册回调到HDI服务,将上层回调注册到HDI服务
  • UnRegisterCallBack(): 从HDI服务注销回调,从HDI服务注销上层回调
  • OnChipEvent(): 处理芯片事件回调,接收来自HDI服务的事件通知并转发给上层回调

构造函数与析构函数:

  • Impl(): 构造函数,初始化成员变量
  • ~Impl(): 析构函数,释放资源并注销回调

实现细节:

  • GetProxy()方法使用HDI框架的HdiGetProxy函数获取IConnectedNfcTagV1_1接口实例,并检查获取结果以确保代理有效
  • Init()方法首先调用GetProxy()获取服务代理,检查代理有效性后调用代理的Init()方法,并更新初始化状态
  • ReadNdefTag()WriteNdefTag()方法通过服务代理调用相应的HDI服务方法,处理返回结果并转换为上层需要的格式
  • OnChipEvent()方法作为HDI服务回调函数,接收硬件事件并转发给上层回调接口,在转发前会检查回调接口的有效性

线程安全考虑:

  • 使用proxyMutex_保护HDI服务代理的访问,防止多个线程同时操作代理实例
  • 使用callbackMutex_保护上层回调接口的访问,确保回调注册和注销操作的线程安全
  • 在所有涉及共享资源的方法中都正确使用了锁机制

7. 附录

7.1 相关源码文件

  • 接口定义:

    • foundation/communication/connected_nfc_tag/interfaces/inner_api/include/infc_tag_service.h
    • foundation/communication/connected_nfc_tag/interfaces/inner_api/include/infc_tag_callback.h
  • 服务实现:

    • foundation/communication/connected_nfc_tag/services/src/nfc_tag_service.cpp
    • foundation/communication/connected_nfc_tag/services/src/nfc_tag_service.h
  • HDI适配器:

    • foundation/communication/connected_nfc_tag/services/src/hdi/include/nfc_tag_hdi_adapter.h
    • foundation/communication/connected_nfc_tag/services/src/hdi/src/nfc_tag_hdi_adapter.cpp

7.2 参考文档

  • OpenHarmony NFC子系统设计文档
  • HDI开发指南
  • OpenHarmony系统能力开发指南

7.3 错误码

Connected NFC Tag模块定义了详细的错误码,用于标识各种错误情况。错误码定义在nfc_tag_errcode.h文件中,主要包括:

  • NFC_TAG_ERR_PERMISSION_DENIED: 权限不足,无法执行操作
  • NFC_TAG_ERR_NOT_INITIALIZED: 模块未初始化,无法执行操作
  • NFC_TAG_ERR_ALREADY_INITIALIZED: 模块已初始化,重复初始化
  • NFC_TAG_ERR_IO_ERROR: IO错误,与硬件通信失败
  • NFC_TAG_ERR_INVALID_PARAM: 参数无效
  • NFC_TAG_ERR_NO_TAG: 未检测到标签
  • NFC_TAG_ERR_TAG_LOST: 标签丢失
  • NFC_TAG_ERR_NOT_SUPPORTED: 不支持的操作

所有对外接口方法都应正确处理这些错误码,并在发生错误时返回相应的错误值。

Logo

社区规范:仅讨论OpenHarmony相关问题。

更多推荐