当前位置: 首页 > news >正文

【OpenHarmony】外部设备管理器架构

外部设备管理器(External Device Manager)架构

1. 模块概述

源码:https://gitee.com/openharmony/drivers_external_device_manager

1.1 功能与目标

外部设备管理器(External Device Manager)是OpenHarmony系统中用于管理可插拔外部设备的核心组件。主要功能包括:

  • 设备生命周期管理:实现外部设备的注册、查询、绑定和解绑定
  • 驱动包管理:支持扩展驱动包的安装、更新、卸载和运行
  • 总线扩展支持:提供USB等总线的扩展插件机制
  • 设备驱动匹配:自动匹配设备与驱动包
  • DDK接口开放:为驱动开发者提供USB、HID、SCSI等DDK接口

设计目标

  • 为设备厂商提供低成本的扩展外部设备驱动开发方案
  • 实现即插即用的用户体验
  • 支持非标准协议的可插拔设备驱动接入
  • 提供安全、高效的驱动包生命周期管理

1.2 系统位置

本模块位于OpenHarmony驱动子系统(HDF)中,作为核心系统服务运行:

  • 子系统:HDF(Hardware Driver Framework)
  • 部件名称:external_device_manager
  • 系统能力
    • SystemCapability.Driver.ExternalDevice
    • SystemCapability.Driver.USB.Extension
    • SystemCapability.Driver.DDK.Extension
  • 服务ID:5110(系统服务)

模块在系统中的位置

内核层
HDF驱动层
DDK接口层
总线扩展插件层
核心服务层
IPC通信层
NAPI/JS_API层
应用层
IPC
USB Controller
HID Driver
SCSI Driver
Hardware Driver Framework
USB DDK API
HID DDK API
SCSI DDK API
UsbBusExtension
USB总线
HidBusExtension
HID总线
ScsiExtension
SCSI总线
ExtDeviceManager
设备管理
DriverPkgManager
包管理
BusExtensionCore
总线核心
DriverExtController
能力控制
DriverExtMgrClient
Client Proxy
DriverExtMgr
System Ability 5110
device_manager_napi
driver_extension_context_napi
driver_ext_ability_napi
三方应用
系统服务
驱动扩展包

1.3 设计思路与模式

设计思路

  1. 分层架构:采用经典的分层设计,从应用接口层到驱动访问层逐层解耦
  2. 插件化扩展:总线扩展采用插件机制,支持动态加载不同总线类型
  3. 事件驱动:设备热插拔通过事件订阅机制通知上层
  4. 能力化驱动:驱动包基于Ability框架,实现标准化管理

设计模式

  • 单例模式:核心管理类(ExtDeviceManager、DriverPkgManager、BusExtensionCore)采用单例模式
  • 工厂模式:设备信息和驱动信息的创建使用工厂方法
  • 观察者模式:设备变化回调、驱动变化回调采用观察者模式
  • 策略模式:不同总线类型的匹配策略通过IBusExtension接口实现
  • 代理模式:客户端通过DriverExtMgrClient代理访问系统服务

1.4 系统框图

内核驱动层
DDK接口层
总线扩展插件层
核心服务层
IPC通信层
NAPI/JS API层
应用层
IPC
USB Controller
HID Driver
SCSI Driver
USB DDK API
HID DDK API
SCSI DDK API
HDF Driver Framework
UsbBusExtension
HidBusExtension
ScsiExtension
设备订阅器
设备信息解析
驱动匹配器
ExtDeviceManager
设备管理
DriverPkgManager
包管理
BusExtensionCore
总线核心
DriverExtController
能力控制
Device对象管理
驱动匹配表
总线插件管理
DriverExtMgrClient
DriverExtMgr SA5110
device_manager
driver_extension_context
driver_ext_ability
三方应用
系统服务
驱动扩展包

2. 模块结构

2.1 源文件与头文件

2.1.1 核心服务模块

服务主入口

  • services/native/driver_extension_manager/src/driver_ext_mgr.cpp
  • services/native/driver_extension_manager/include/driver_ext_mgr.h

设备管理模块

  • services/native/driver_extension_manager/src/device_manager/etx_device_mgr.cpp
  • services/native/driver_extension_manager/src/device_manager/device.cpp
  • services/native/driver_extension_manager/include/device_manager/etx_device_mgr.h
  • services/native/driver_extension_manager/include/device_manager/device.h

驱动包管理模块

  • services/native/driver_extension_manager/src/drivers_pkg_manager/driver_pkg_manager.cpp
  • services/native/driver_extension_manager/include/drivers_pkg_manager/driver_pkg_manager.h
  • services/native/driver_extension_manager/include/drivers_pkg_manager/pkg_database.h

驱动能力控制器

  • services/native/driver_extension_manager/src/device_manager/driver_extension_controller.cpp
  • services/native/driver_extension_manager/include/device_manager/driver_extension_controller.h

总线扩展核心

  • services/native/driver_extension_manager/src/bus_extension/core/bus_extension_core.cpp
  • services/native/driver_extension_manager/include/bus_extension/core/bus_extension_core.h

USB总线扩展插件

  • services/native/driver_extension_manager/src/bus_extension/usb/usb_bus_extension.cpp
  • services/native/driver_extension_manager/include/bus_extension/usb/usb_bus_extension.h
  • services/native/driver_extension_manager/include/bus_extension/usb/usb_device_info.h
2.1.2 客户端接口模块

内部接口

  • interfaces/innerkits/driver_ext_mgr_client.h
  • interfaces/innerkits/driver_ext_mgr_types.h
  • frameworks/native/driver_ext_mgr_client.cpp

IDL接口定义

  • interfaces/innerkits/IDriverExtMgr.idl
  • interfaces/innerkits/IDriverExtMgrCallback.idl
2.1.3 DDK接口模块

USB DDK

  • interfaces/ddk/usb/usb_ddk_api.h
  • interfaces/ddk/usb/usb_ddk_types.h
  • frameworks/ddk/usb/usb_ddk_api.cpp

基础DDK

  • interfaces/ddk/base/ddk_api.h
  • interfaces/ddk/base/ddk_types.h
  • frameworks/ddk/base/ddk_api.cpp

其他DDK

  • HID DDK: interfaces/ddk/hid/
  • SCSI DDK: interfaces/ddk/scsi/
  • USB Serial DDK: interfaces/ddk/usb_serial/
2.1.4 工具类模块

公共工具

  • utils/include/edm_errors.h - 错误码定义
  • utils/include/ext_object.h - 基础对象定义
  • utils/include/ibus_extension.h - 总线扩展接口
  • utils/include/hilog_wrapper.h - 日志封装

2.2 核心类结构

2.2.1 DriverExtMgr类

功能:系统服务主类,负责整体协调和对外接口提供

class DriverExtMgr : public SystemAbility, public DriverExtMgrStub {
public:// 系统能力生命周期void OnStart() override;void OnStop() override;void OnAddSystemAbility(int32_t systemAbilityId, const std::string &deviceId);// 设备操作接口ErrCode QueryDevice(int32_t &errorCode, uint32_t busType,std::vector<std::shared_ptr<DeviceData>> &devices);ErrCode BindDevice(int32_t &errorCode, uint64_t deviceId,const sptr<IDriverExtMgrCallback> &connectCallback);ErrCode UnBindDevice(int32_t &errorCode, uint64_t deviceId);// 设备和驱动信息查询ErrCode QueryDeviceInfo(int32_t &errorCode,std::vector<std::shared_ptr<DeviceInfoData>> &deviceInfos,bool isByDeviceId, const uint64_t deviceId);ErrCode QueryDriverInfo(int32_t &errorCode,std::vector<std::shared_ptr<DriverInfoData>> &driverInfos,bool isByDriverUid, const std::string &driverUid);private:std::mutex connectCallbackMutex;std::map<uint64_t, std::vector<sptr<IDriverExtMgrCallback>>> connectCallbackMap;EventConfig eventConfig_;
};

关键成员

  • connectCallbackMap: 设备连接回调映射表
  • eventConfig_: 事件配置管理器
2.2.2 ExtDeviceManager类

功能:设备管理器,负责设备注册、查询、绑定、解绑定

class ExtDeviceManager final {DECLARE_SINGLE_INSTANCE_BASE(ExtDeviceManager);public:// 初始化int32_t Init();// 设备注册与注销int32_t RegisterDevice(shared_ptr<DeviceInfo> devInfo);int32_t UnRegisterDevice(const shared_ptr<DeviceInfo> devInfo);// 设备查询vector<shared_ptr<DeviceInfo>> QueryDevice(const BusType busType);vector<shared_ptr<Device>> QueryAllDevices();vector<shared_ptr<Device>> QueryDevicesById(const uint64_t deviceId);// 设备连接与断开int32_t ConnectDevice(uint64_t deviceId, uint32_t callingTokenId,const sptr<IDriverExtMgrCallback> &connectCallback);int32_t DisConnectDevice(uint64_t deviceId, uint32_t callingTokenId);// 驱动匹配void MatchDriverInfos(std::unordered_set<uint64_t> deviceIds);void SetDriverChangeCallback(shared_ptr<IDriverChangeCallback> &callback);private:// 设备映射表:总线类型 -> 设备ID -> Device对象unordered_map<BusType, unordered_map<uint64_t, shared_ptr<Device>>> deviceMap_;// 驱动匹配表:驱动UID -> 设备ID集合unordered_map<string, unordered_set<uint64_t>> bundleMatchMap_;mutex deviceMapMutex_;mutex bundleMatchMapMutex_;
};

关键数据结构

  • deviceMap_: 按总线类型和设备ID组织的设备对象映射
  • bundleMatchMap_: 驱动包与设备的匹配关系表
2.2.3 Device类

功能:设备对象,表示一个具体的外部设备

class Device : public std::enable_shared_from_this<Device> {
public:explicit Device(std::shared_ptr<DeviceInfo> info);// 连接与断开int32_t Connect();int32_t Connect(const sptr<IDriverExtMgrCallback> &connectCallback,uint32_t callingTokenId);int32_t Disconnect(const bool isFromBind);// 驱动信息管理bool HasDriver() const;std::shared_ptr<DriverInfo> GetDriverInfo() const;void AddBundleInfo(const std::string &bundleInfo,const std::shared_ptr<DriverInfo> &driverInfo);void RemoveBundleInfo();// 远程对象管理sptr<IRemoteObject> GetDrvExtRemote();void UpdateDrvExtRemote(const sptr<IRemoteObject> &remote);private:std::shared_ptr<DeviceInfo> info_;           // 设备信息std::shared_ptr<DriverInfo> driverInfo_;     // 匹配的驱动信息std::string bundleInfo_;                     // Bundle信息sptr<IRemoteObject> drvExtRemote_;           // 驱动Extension远程对象std::set<sptr<IDriverExtMgrCallback>> callbacks_; // 回调集合std::unordered_map<uint32_t, CallerInfo> boundCallerInfos_; // 调用者信息
};
2.2.4 DriverPkgManager类

功能:驱动包管理器,负责驱动包的安装、更新、查询和匹配

class DriverPkgManager {DECLARE_SINGLE_INSTANCE_BASE(DriverPkgManager);public:// 初始化int32_t Init();int32_t Init(shared_future<int32_t> bmsFuture,shared_future<int32_t> accountFuture,shared_future<int32_t> commEventFuture);// 驱动查询与匹配shared_ptr<DriverInfo> QueryMatchDriver(shared_ptr<DeviceInfo> devInfo,const std::string &type = "");int32_t QueryDriverInfo(vector<shared_ptr<DriverInfo>> &driverInfos,bool isByDriverUid, const std::string &driverUid);// 驱动包更新回调int32_t RegisterOnBundleUpdate(PCALLBACKFUN pFun);int32_t RegisterBundleCallback(std::shared_ptr<IBundleUpdateCallback> callback);private:shared_ptr<BundleMonitor> bundleMonitor_;sptr<DrvBundleStateCallback> bundleStateCallback_;
};
2.2.5 BusExtensionCore类

功能:总线扩展核心,管理各种总线类型的扩展插件

class BusExtensionCore {DECLARE_SINGLE_INSTANCE_BASE(BusExtensionCore);public:// 初始化int32_t Init(std::shared_ptr<IDevChangeCallback> callback);// 总线扩展注册int32_t Register(BusType busType, std::shared_ptr<IBusExtension> busExtension);// 获取总线扩展std::shared_ptr<IBusExtension> GetBusExtensionByName(std::string busName);static BusType GetBusTypeByName(const std::string &busName);// 加载总线扩展库void LoadBusExtensionLibs();// 驱动变化回调std::shared_ptr<IDriverChangeCallback> AcquireDriverChangeCallback(BusType busType);private:std::unordered_map<BusType, std::shared_ptr<IBusExtension>> busExtensions_;static std::unordered_map<std::string, BusType> busTypeMap_;
};
2.2.6 IBusExtension接口

功能:总线扩展接口,定义各总线类型插件需实现的方法

class IBusExtension {
public:virtual ~IBusExtension() = default;// 解析驱动信息virtual shared_ptr<DriverInfoExt> ParseDriverInfo(const map<string, string> &metadata) = 0;// 创建驱动信息扩展对象virtual shared_ptr<DriverInfoExt> GetNewDriverInfoExtObject() = 0;// 匹配驱动virtual bool MatchDriver(const DriverInfo &driver,const DeviceInfo &device, const std::string &type = "") = 0;// 设置设备变化回调virtual int32_t SetDevChangeCallback(shared_ptr<IDevChangeCallback> callback) = 0;// 获取总线类型virtual BusType GetBusType() = 0;// 获取驱动变化回调virtual shared_ptr<IDriverChangeCallback> AcquireDriverChangeCallback() = 0;
};
2.2.7 UsbBusExtension类

功能:USB总线扩展实现

class UsbBusExtension : public IBusExtension {
public:UsbBusExtension();~UsbBusExtension();// 实现IBusExtension接口int32_t SetDevChangeCallback(shared_ptr<IDevChangeCallback> callback) override;bool MatchDriver(const DriverInfo &driver, const DeviceInfo &device,const std::string &type = "") override;shared_ptr<DriverInfoExt> ParseDriverInfo(const map<string, string> &metadata) override;BusType GetBusType() override;// USB特定接口void SetUsbInferface(sptr<IUsbInterface> iusb);void SetUsbDdk(sptr<IUsbDdk> iUsbDdk);private:sptr<UsbDevSubscriber> subScriber_;      // USB设备订阅器sptr<IUsbDdk> iUsbDdk_;                  // USB DDK接口sptr<IUsbInterface> usbInterface_;       // USB HDI接口
};
2.2.8 DriverExtensionController类

功能:驱动扩展能力控制器,管理驱动Extension的生命周期

class DriverExtensionController {DECLARE_SINGLE_INSTANCE_BASE(DriverExtensionController);public:// 启动和停止扩展int32_t StartDriverExtension(const std::string& bundleName,const std::string& abilityName);int32_t StopDriverExtension(const std::string& bundleName,const std::string& abilityName, int32_t userId = -1);// 连接和断开扩展int32_t ConnectDriverExtension(const std::string& bundleName,const std::string& abilityName,std::shared_ptr<IDriverExtensionConnectCallback> callback,uint32_t deviceId = 0);int32_t DisconnectDriverExtension(const std::string& bundleName,const std::string& abilityName,std::shared_ptr<IDriverExtensionConnectCallback> callback,uint32_t deviceId = 0);
};

2.3 基础数据结构

2.3.1 DeviceInfo类
class DeviceInfo {
public:DeviceInfo(uint32_t busDeviceId, BusType busType, const std::string &description);BusType GetBusType() const;uint64_t GetDeviceId() const;uint32_t GetBusDevId() const;const std::string& GetDeviceDescription() const;private:union DevInfo {uint64_t deviceId;struct {BusType busType;uint32_t busDeviceId;} devBusInfo;} devInfo_;std::string description_;
};
2.3.2 DriverInfo类
class DriverInfo : public DriverInfoExt {
public:DriverInfo(const std::string &bundleName, const std::string &driverName,const std::string &driverUid = "", const int32_t userId = -1);// Getter方法std::string GetBusName() const;BusType GetBusType() const;std::string GetDriverUid() const;std::string GetBundleName() const;std::string GetDriverName() const;bool GetLaunchOnBind() const;private:std::string bus_;BusType busType_;std::string driverUid_;int32_t userId_;std::string bundleName_;std::string driverName_;std::string version_;std::string description_;bool launchOnBind_;std::shared_ptr<DriverInfoExt> driverInfoExt_;
};
2.3.3 错误码定义
enum UsbErrCode : int32_t {EDM_OK = 0,EDM_NOK,EDM_ERR_GET_SYSTEM_ABILITY_MANAGER_FAILED,EDM_ERR_GET_SERVICE_FAILED,EDM_ERR_CONNECTION_FAILED,EDM_ERR_NOT_SUPPORT,EDM_ERR_INVALID_PARAM,EDM_ERR_INVALID_OBJECT,EDM_EER_MALLOC_FAIL,EDM_ERR_TIMEOUT,EDM_ERR_DEVICE_BUSY,EDM_ERR_IO,EDM_ERR_NO_PERM,EDM_ERR_OUT_OF_RANGE,EDM_ERR_JSON_PARSE_FAIL,EDM_ERR_JSON_OBJ_ERR,EDM_ERR_USB_ERR,EDM_ERR_NOT_SYSTEM_APP,EDM_ERR_SERVICE_NOT_ALLOW_ACCESS,EDM_ERR_SERVICE_NOT_BOUND,
};

2.4 类图

uses
uses
uses
manages
has
has
uses
contains
implements
creates
«SystemAbility»
DriverExtMgr
-map<uint64_t, vector>Callback<> connectCallbackMap
-EventConfig eventConfig_
+QueryDevice() : ErrCode
+BindDevice() : ErrCode
+UnBindDevice() : ErrCode
+QueryDeviceInfo() : ErrCode
+QueryDriverInfo() : ErrCode
+OnStart()
+OnStop()
«Singleton»
ExtDeviceManager
-unordered_map deviceMap_
-unordered_map bundleMatchMap_
-mutex deviceMapMutex_
+Init() : int32_t
+RegisterDevice() : int32_t
+UnRegisterDevice() : int32_t
+QueryDevice() : vector
+ConnectDevice() : int32_t
+DisConnectDevice() : int32_t
+MatchDriverInfos()
«Singleton»
DriverPkgManager
-shared_ptr<BundleMonitor> bundleMonitor_
-sptr<DrvBundleStateCallback> bundleStateCallback_
+Init() : int32_t
+QueryMatchDriver() : shared_ptr<DriverInfo>
+QueryDriverInfo() : int32_t
+RegisterBundleCallback() : int32_t
«Singleton»
BusExtensionCore
-unordered_map<BusType, shared_ptr> busExtensions_
+Init() : int32_t
+Register() : int32_t
+GetBusExtensionByName() : shared_ptr
+LoadBusExtensionLibs()
Device
-shared_ptr<DeviceInfo> info_
-shared_ptr<DriverInfo> driverInfo_
-string bundleInfo_
-sptr<IRemoteObject> drvExtRemote_
-set<Callback> callbacks_
+Connect() : int32_t
+Disconnect() : int32_t
+HasDriver() : bool
+GetDriverInfo() : shared_ptr
+AddBundleInfo()
+RemoveBundleInfo()
DeviceInfo
-union DevInfo devInfo_
-string description_
+GetBusType() : BusType
+GetDeviceId() : uint64_t
+GetBusDevId() : uint32_t
+GetDeviceDescription() : string
DriverInfo
-string bus_
-BusType busType_
-string driverUid_
-string bundleName_
-string driverName_
-string version_
-bool launchOnBind_
+GetBusType() : BusType
+GetDriverUid() : string
+GetBundleName() : string
+GetDriverName() : string
+Serialize() : int32_t
+UnSerialize() : int32_t
«interface»
IBusExtension
+ParseDriverInfo() : shared_ptr
+GetNewDriverInfoExtObject() : shared_ptr
+MatchDriver() : bool
+SetDevChangeCallback() : int32_t
+GetBusType() : BusType
+AcquireDriverChangeCallback() : shared_ptr
UsbBusExtension
-sptr<UsbDevSubscriber> subScriber_
-sptr<IUsbDdk> iUsbDdk_
-sptr<IUsbInterface> usbInterface_
+SetDevChangeCallback() : int32_t
+MatchDriver() : bool
+ParseDriverInfo() : shared_ptr
+GetBusType() : BusType
«Singleton»
DriverExtensionController
+StartDriverExtension() : int32_t
+StopDriverExtension() : int32_t
+ConnectDriverExtension() : int32_t
+DisconnectDriverExtension() : int32_t

2.5 模块内部依赖框图

通用工具
总线扩展模块
驱动包管理模块
设备管理模块
主服务
实现
实现
实现
使用
使用
使用
使用
使用
使用
使用
使用
使用
使用
使用
使用
edm_errors.h
错误码定义
ext_object.h
基础对象
hilog_wrapper.h
日志封装
single_instance.h
单例模板
BusExtensionCore
总线扩展核心
IBusExtension
总线扩展接口
UsbBusExtension
USB总线
HidBusExtension
HID总线
ScsiBusExtension
SCSI总线
UsbDevSubscriber
设备订阅
IUsbInterface
USB HDI
IUsbDdk
USB DDK
DriverPkgManager
驱动包管理
BundleMonitor
包监控
DrvBundleStateCallback
包状态回调
PkgDatabase
包数据库
ExtDeviceManager
设备管理
Device
设备对象
DeviceInfo
设备信息
DriverInfo
驱动信息
DriverExtensionController
能力控制
IDevChangeCallback
设备变化回调
DriverExtMgr

3. 模块间交互

3.1 与应用层交互

交互方式

  • JS API层:通过NAPI(Native API)提供JavaScript接口
  • 跨进程通信:使用OpenHarmony IPC机制(基于Binder)
  • 回调机制:通过IDriverExtMgrCallback接口异步通知应用

主要接口

  1. 查询设备

    // JS侧调用
    deviceManager.queryDevices(BusType.USB)// C++侧处理流程:
    NAPI -> IPC -> DriverExtMgr::QueryDevice()-> ExtDeviceManager::QueryDevice()-> 返回设备列表
    
  2. 绑定设备

    // JS侧调用
    deviceManager.bindDevice(deviceId, callback)// C++侧处理流程:
    NAPI -> IPC -> DriverExtMgr::BindDevice()-> ExtDeviceManager::ConnectDevice()-> Device::Connect()-> DriverExtensionController::ConnectDriverExtension()-> Ability Framework启动驱动Extension-> 回调通知: IDriverExtMgrCallback::OnConnect()
    

3.2 与Bundle子系统交互

交互描述

  • 监听驱动包的安装、更新、卸载事件
  • 查询已安装的驱动包信息
  • 解析驱动包的metadata元数据

实现机制

DriverPkgManager├── BundleMonitor (包监控器)│   └── 订阅CommonEvent事件│       - COMMON_EVENT_PACKAGE_ADDED│       - COMMON_EVENT_PACKAGE_CHANGED│       - COMMON_EVENT_PACKAGE_REMOVED│└── DrvBundleStateCallback└── 实现BundleStatusCallback接口- OnBundleAdded()- OnBundleUpdated()- OnBundleRemoved()

数据流

Bundle子系统CommonEventBundleMonitorDrvBundleStateCallbackDriverPkgManagerExtDeviceManagerDevice对象驱动包安装/更新/卸载事件通知解析包信息更新驱动信息触发驱动匹配MatchDriverInfos()更新设备匹配状态状态更新完成Bundle子系统CommonEventBundleMonitorDrvBundleStateCallbackDriverPkgManagerExtDeviceManagerDevice对象

3.3 与HDF驱动框架交互

交互描述

  • 通过HDI接口访问USB/HID等硬件设备
  • 订阅设备热插拔事件
  • 提供DDK接口给驱动扩展包使用

USB总线交互示例

UsbBusExtension├── 依赖IUsbInterface (USB HDI v1.0)│   ├── GetDevices() - 获取USB设备列表│   ├── GetPorts() - 获取USB端口状态│   └── SubscribeDeviceEvent() - 订阅设备事件│└── 依赖IUsbDdk (USB DDK v1.1)├── Init() - 初始化DDK├── GetDeviceDescriptor() - 获取设备描述符├── ClaimInterface() - 声明接口└── SendPipeRequest() - 发送管道请求

设备热插拔流程

内核驱动层HDF USB ServiceIUsbInterfaceUsbDevSubscriberUsbBusExtensionIDevChangeCallbackExtDeviceManagerDriverPkgManagerDeviceUSB Device插入设备插入事件DeviceEventOnReceiveEvent()解析设备信息ParseDeviceInfo()OnDeviceAdd(devInfo)RegisterDevice()QueryMatchDriver(devInfo)返回匹配的DriverInfoMatchDriverInfos()创建Device对象AddBundleInfo()设备状态: 已匹配内核驱动层HDF USB ServiceIUsbInterfaceUsbDevSubscriberUsbBusExtensionIDevChangeCallbackExtDeviceManagerDriverPkgManagerDevice

3.4 与Ability Framework交互

交互描述

  • 启动和停止Driver Extension Ability
  • 连接和断开Driver Extension服务
  • 管理Extension生命周期

Driver Extension能力管理

DriverExtensionController↓ (使用Ability Manager)
AbilityManagerClient↓ (IPC调用)
Ability Manager Service↓ (启动Extension)
Driver Extension Ability├── OnCreate() - 创建├── OnConnect() - 连接├── OnDisconnect() - 断开└── OnDestroy() - 销毁

连接流程

应用DeviceDrvExtConnNotifyDriverExtensionControllerAbilityManagerClientAbility Manager ServiceDriver ExtensionIDriverExtMgrCallbackConnect()创建连接通知器ConnectDriverExtension()ConnectAbility()IPC调用启动Driver Extension进程OnCreate()OnConnect()回调OnConnectDone(remote)更新设备状态OnConnect()UpdateDrvExtRemote()OnConnect(deviceId, remote)应用获取驱动Extension对象应用DeviceDrvExtConnNotifyDriverExtensionControllerAbilityManagerClientAbility Manager ServiceDriver ExtensionIDriverExtMgrCallback

3.5 与账户子系统交互

交互描述

  • 监听用户账户切换事件
  • 根据用户账户管理驱动包权限
  • 多用户场景下的驱动包隔离

实现

DriverOsAccountSubscriber↓ (订阅账户事件)
OS Account Manager↓ (账户切换通知)
DriverPkgManager↓ (清理旧用户驱动)
ExtDeviceManager::ClearMatchedDrivers(userId)↓ (加载新用户驱动)
重新匹配驱动

3.6 外部依赖框图

外部系统服务
外部设备管理服务
应用进程
JS API / NAPI
IPC
IPC
IPC
IPC
IPC
IPC
驱动包信息
Extension控制
系统事件
账户事件
设备事件
DDK接口
BMS
包管理服务
Bundle Manager
AMS
能力管理服务
Ability Manager
CES
公共事件服务
Common Event
OAM
账户管理服务
OS Account
USB HDI
USB硬件接口
Hardware Device Interface
HDF
驱动框架
Hardware Driver Foundation
DriverExtMgr
SA 5110
应用
Application

说明

  • BMS: Bundle Manager Service (包管理服务)
  • AMS: Ability Manager Service (能力管理服务)
  • CES: Common Event Service (公共事件服务)
  • OAM: OS Account Manager (账户管理服务)
  • USB HDI: USB Hardware Device Interface
  • HDF: Hardware Driver Foundation

4. 状态机转换图

4.1 设备状态机模型

设备对象(Device)在其生命周期中会经历多种状态转换:

状态定义

  • 未注册(Unregistered): 设备尚未在系统中注册
  • 已注册(Registered): 设备已注册但未匹配驱动
  • 已匹配(Matched): 设备已匹配到驱动但未连接
  • 连接中(Connecting): 正在建立与驱动Extension的连接
  • 已连接(Connected): 已成功连接到驱动Extension
  • 断开中(Disconnecting): 正在断开连接
  • 已注销(Unregistered): 设备已从系统中注销

4.2 设备状态机树图

设备状态机根节点
未注册
Unregistered
已注册
Registered
已注销
Unregistered
未匹配驱动
NoDriverMatched
已匹配驱动
DriverMatched
未连接
Disconnected
连接中
Connecting
已连接
Connected
断开中
Disconnecting
启动Extension中
StartingExtension
等待连接回调
WaitingCallback
单应用绑定
SingleBound
多应用绑定
MultiBound
停止Extension中
StoppingExtension
清理资源中
CleaningUp
等待资源释放
WaitingCleanup

4.3 设备状态转换图

初始状态
RegisterDevice()
[设备插入]
MatchDriverInfos()
[找到匹配驱动]
Connect()
[应用绑定]
OnConnectDone()
[连接成功]
OnConnectDone()
[连接失败]
Disconnect()
[应用解绑]
OnDisconnectDone()
[断开完成]
UnRegisterDevice()
[设备拔出]
UnRegisterDevice()
[设备拔出]
UnRegisterDevice()
[设备拔出]
UnRegisterDevice()
[设备拔出]
UnRegisterDevice()
[设备拔出]
RemoveDriverInfo()
[驱动包卸载]
结束
Unregistered
Registered
Matched
Connecting
Connected
Disconnecting
UnregisteredFinal
设备尚未注册
设备已注册
但未匹配驱动
设备已匹配驱动
等待应用绑定
设备已连接
可供应用使用

4.4 状态机切换规则

4.4.1 状态转换条件
当前状态触发事件转换条件目标状态
未注册RegisterDevice()设备插入事件已注册
已注册MatchDriverInfos()找到匹配的驱动包已匹配
已匹配Connect()应用调用绑定接口连接中
连接中OnConnectDone()Extension连接成功已连接
连接中OnConnectDone() (失败)Extension连接失败已匹配
已连接Disconnect()应用调用解绑接口断开中
断开中OnDisconnectDone()Extension断开完成已匹配
任意状态UnRegisterDevice()设备拔出事件已注销
已匹配RemoveDriverInfo()驱动包卸载已注册
4.4.2 事件触发机制

外部事件

  • 设备插入/拔出:由USB总线扩展监听底层事件触发
  • 驱动包安装/卸载:由Bundle子系统通知触发
  • 应用绑定/解绑:由应用通过API调用触发

内部事件

  • 驱动匹配完成:内部匹配算法执行后触发
  • Extension连接回调:Ability Framework回调触发
  • 超时事件:定时器触发

事件处理流程

// 设备插入事件处理
void OnDeviceAdd(shared_ptr<DeviceInfo> devInfo) {// 1. 注册设备ExtDeviceManager::RegisterDevice(devInfo);// 2. 触发驱动匹配auto driverInfo = DriverPkgManager::QueryMatchDriver(devInfo);if (driverInfo != nullptr) {// 3. 状态转换: 已注册 -> 已匹配device->AddBundleInfo(bundleInfo, driverInfo);}
}// 应用绑定事件处理
int32_t ConnectDevice(uint64_t deviceId, Callback callback) {auto device = QueryDeviceByDeviceID(deviceId);if (!device->HasDriver()) {return EDM_ERR_NO_DRIVER_MATCHED;}// 状态转换: 已匹配 -> 连接中return device->Connect(callback);
}// Extension连接成功回调
void OnConnectDone(IRemoteObject *remote, int resultCode) {if (resultCode == SUCCESS) {// 状态转换: 连接中 -> 已连接device->UpdateDrvExtRemote(remote);// 通知应用callback->OnConnect(deviceId, remote, errMsg);} else {// 状态转换: 连接中 -> 已匹配device->ClearDrvExtRemote();callback->OnConnect(deviceId, nullptr, errMsg);}
}

4.5 驱动包状态机

驱动包(Driver Package)也有自己的生命周期状态:

状态定义

  • 未安装(NotInstalled): 驱动包尚未安装
  • 已安装(Installed): 驱动包已安装
  • 已加载(Loaded): 驱动包信息已加载到内存
  • 运行中(Running): 驱动Extension正在运行
  • 更新中(Updating): 驱动包正在更新
  • 卸载中(Uninstalling): 驱动包正在卸载

驱动包状态转换图

初始状态
OnBundleAdded()
[驱动包安装]
ParseDriverInfo()
[解析驱动信息]
StartDriverExtension()
[启动驱动Extension]
StopDriverExtension()
[停止驱动Extension]
OnBundleUpdated()
[驱动包更新]
OnBundleUpdated()
[驱动包更新]
更新完成
OnBundleRemoved()
[驱动包卸载]
OnBundleRemoved()
[驱动包卸载]
OnBundleRemoved()
[驱动包卸载]
卸载完成
结束
NotInstalled
Installed
Loaded
Running
Updating
Uninstalling
驱动包未安装
驱动包已安装
信息已存储
驱动信息已加载
可以匹配设备
驱动Extension运行中
正在服务设备

5. 接口设计

5.1 公共接口

5.1.1 DriverExtMgrClient客户端接口

头文件interfaces/innerkits/driver_ext_mgr_client.h

接口列表

class DriverExtMgrClient {
public:// 查询设备接口UsbErrCode QueryDevice(uint32_t busType,std::vector<std::shared_ptr<DeviceData>> &devices);// 绑定设备接口UsbErrCode BindDevice(uint64_t deviceId,const sptr<IDriverExtMgrCallback> &connectCallback);// 解绑设备接口UsbErrCode UnBindDevice(uint64_t deviceId);// 通过设备ID绑定驱动UsbErrCode BindDriverWithDeviceId(uint64_t deviceId,const sptr<IDriverExtMgrCallback> &connectCallback);// 通过设备ID解绑驱动UsbErrCode UnbindDriverWithDeviceId(uint64_t deviceId);// 查询设备信息UsbErrCode QueryDeviceInfo(std::vector<std::shared_ptr<DeviceInfoData>> &deviceInfos);// 根据设备ID查询设备信息UsbErrCode QueryDeviceInfo(const uint64_t deviceId,std::vector<std::shared_ptr<DeviceInfoData>> &deviceInfos);// 查询驱动信息UsbErrCode QueryDriverInfo(std::vector<std::shared_ptr<DriverInfoData>> &driverInfos);// 根据驱动UID查询驱动信息UsbErrCode QueryDriverInfo(const std::string &driverUid,std::vector<std::shared_ptr<DriverInfoData>> &driverInfos);// 通知USB外设故障UsbErrCode NotifyUsbPeripheralFault(const std::string &domain,const std::string &faultName);
};

接口详细说明

  1. QueryDevice - 查询设备

    • 功能:根据总线类型查询当前系统中的外部设备列表
    • 参数
      • busType: 总线类型(1-USB, 其他类型待扩展)
      • devices: [输出] 设备数据列表
    • 返回值:错误码(0表示成功)
    • 异常处理:连接服务失败返回EDM_ERR_GET_SERVICE_FAILED
  2. BindDevice - 绑定设备

    • 功能:绑定指定设备并获取驱动Extension对象
    • 参数
      • deviceId: 设备ID(由查询接口获得)
      • connectCallback: 连接回调接口
    • 返回值:错误码
    • 异常处理
      • 设备不存在返回EDM_ERR_INVALID_OBJECT
      • 无匹配驱动返回EDM_ERR_NOT_SUPPORT
      • 权限不足返回EDM_ERR_NO_PERM
    • 异步通知:通过回调接口OnConnect通知连接结果
  3. UnBindDevice - 解绑设备

    • 功能:解绑已绑定的设备,释放资源
    • 参数
      • deviceId: 设备ID
    • 返回值:错误码
    • 异常处理:设备未绑定返回EDM_ERR_SERVICE_NOT_BOUND
  4. QueryDeviceInfo - 查询设备信息

    • 功能:查询设备详细信息,包括匹配的驱动信息
    • 参数
      • deviceInfos: [输出] 设备信息列表
      • deviceId: [可选] 指定设备ID查询单个设备
    • 返回值:错误码
    • 说明:返回信息包括设备ID、是否匹配驱动、驱动UID等
  5. QueryDriverInfo - 查询驱动信息

    • 功能:查询已安装的驱动包信息
    • 参数
      • driverInfos: [输出] 驱动信息列表
      • driverUid: [可选] 指定驱动UID查询单个驱动
    • 返回值:错误码
    • 说明:返回信息包括驱动名称、版本、描述、支持的设备等
5.1.2 IDriverExtMgrCallback回调接口

IDL定义interfaces/innerkits/IDriverExtMgrCallback.idl

class IDriverExtMgrCallback {
public:// 连接成功回调virtual void OnConnect(uint64_t deviceId,const sptr<IRemoteObject> &drvExtObj,const ErrMsg &errMsg) = 0;// 断开连接回调virtual void OnDisconnect(uint64_t deviceId,const ErrMsg &errMsg) = 0;// 解绑回调virtual void OnUnBind(uint64_t deviceId,const ErrMsg &errMsg) = 0;
};

回调说明

  1. OnConnect - 连接成功回调

    • 触发时机:设备绑定成功或失败时触发
    • 参数
      • deviceId: 设备ID
      • drvExtObj: 驱动Extension远程对象(成功时非空)
      • errMsg: 错误信息(包含错误码和描述)
    • 用途:应用通过此回调获取驱动Extension对象,进行后续通信
  2. OnDisconnect - 断开连接回调

    • 触发时机:设备断开连接时触发
    • 参数:设备ID和错误信息
    • 用途:通知应用设备已断开
  3. OnUnBind - 解绑回调

    • 触发时机:设备解绑完成时触发
    • 参数:设备ID和错误信息
    • 用途:通知应用解绑操作已完成

5.2 DDK接口

5.2.1 USB DDK接口

头文件interfaces/ddk/usb/usb_ddk_api.h

权限要求ohos.permission.ACCESS_DDK_USB

接口列表

// 初始化DDK
int32_t OH_Usb_Init(void);// 释放DDK资源
void OH_Usb_Release(void);
int32_t OH_Usb_ReleaseResource(void);// 获取设备描述符
int32_t OH_Usb_GetDeviceDescriptor(uint64_t deviceId,struct UsbDeviceDescriptor *desc
);// 获取配置描述符
int32_t OH_Usb_GetConfigDescriptor(uint64_t deviceId,uint8_t configIndex,struct UsbDdkConfigDescriptor ** const config
);// 释放配置描述符
void OH_Usb_FreeConfigDescriptor(struct UsbDdkConfigDescriptor * const config
);// 声明USB接口
int32_t OH_Usb_ClaimInterface(uint64_t deviceId,uint8_t interfaceIndex,uint64_t *interfaceHandle
);// 释放USB接口
int32_t OH_Usb_ReleaseInterface(uint64_t interfaceHandle);// 选择接口设置
int32_t OH_Usb_SelectInterfaceSetting(uint64_t interfaceHandle,uint8_t settingIndex
);// 控制传输(读)
int32_t OH_Usb_SendControlReadRequest(uint64_t interfaceHandle,const struct UsbControlRequestSetup *setup,uint32_t timeout,uint8_t *data,uint32_t *dataLen
);// 控制传输(写)
int32_t OH_Usb_SendControlWriteRequest(uint64_t interfaceHandle,const struct UsbControlRequestSetup *setup,uint32_t timeout,const uint8_t *data,uint32_t dataLen
);// 管道传输(批量/中断传输)
int32_t OH_Usb_SendPipeRequest(const struct UsbRequestPipe *pipe,UsbDeviceMemMap *devMmap
);// 创建设备内存映射
int32_t OH_Usb_CreateDeviceMemMap(uint64_t deviceId,size_t size,UsbDeviceMemMap **devMmap
);// 销毁设备内存映射
void OH_Usb_DestroyDeviceMemMap(UsbDeviceMemMap *devMmap);// 获取USB设备列表
int32_t OH_Usb_GetDevices(struct Usb_DeviceArray *devices);

接口使用示例

// 1. 初始化USB DDK
int32_t ret = OH_Usb_Init();
if (ret != 0) {// 处理错误return ret;
}// 2. 获取设备描述符
struct UsbDeviceDescriptor desc;
ret = OH_Usb_GetDeviceDescriptor(deviceId, &desc);
if (ret == 0) {printf("VendorID: 0x%04x, ProductID: 0x%04x\n",desc.idVendor, desc.idProduct);
}// 3. 获取配置描述符
struct UsbDdkConfigDescriptor *config;
ret = OH_Usb_GetConfigDescriptor(deviceId, 0, &config);
if (ret == 0) {// 解析配置描述符// ...// 释放描述符OH_Usb_FreeConfigDescriptor(config);
}// 4. 声明接口
uint64_t interfaceHandle;
ret = OH_Usb_ClaimInterface(deviceId, 0, &interfaceHandle);
if (ret == 0) {// 使用接口进行数据传输// ...// 释放接口OH_Usb_ReleaseInterface(interfaceHandle);
}// 5. 释放DDK资源
OH_Usb_Release();
5.2.2 HID DDK接口

头文件interfaces/ddk/hid/hid_ddk_api.h

权限要求ohos.permission.ACCESS_DDK_HID

接口列表(简要):

  • HID设备报告发送/接收
  • HID输入事件注入
  • HID设备信息查询
5.2.3 SCSI DDK接口

头文件interfaces/ddk/scsi/scsi_peripheral_api.h

接口列表(简要):

  • SCSI命令发送
  • SCSI设备信息查询
  • SCSI块设备访问

5.3 数据交换协议

5.3.1 IPC数据序列化

设备数据序列化

// DeviceData序列化
bool DeviceData::Marshalling(Parcel &parcel) const {WRITE_PARCEL_RETURN(parcel, Uint32, static_cast<uint32_t>(busType));WRITE_PARCEL_RETURN(parcel, Uint64, deviceId);WRITE_PARCEL_RETURN(parcel, String, descripton);return true;
}// DeviceData反序列化
DeviceData* DeviceData::Unmarshalling(Parcel &data) {auto object = new DeviceData();object->busType = static_cast<BusType>(data.ReadUint32());object->deviceId = data.ReadUint64();object->descripton = data.ReadString();return object;
}

驱动信息序列化

// DriverInfoData序列化
bool DriverInfoData::Marshalling(Parcel &parcel) const {WRITE_PARCEL_RETURN(parcel, Uint32, static_cast<uint32_t>(busType));WRITE_PARCEL_RETURN(parcel, String, driverUid);WRITE_PARCEL_RETURN(parcel, String, driverName);WRITE_PARCEL_RETURN(parcel, String, bundleSize);WRITE_PARCEL_RETURN(parcel, String, version);WRITE_PARCEL_RETURN(parcel, String, description);return true;
}
5.3.2 内部模块调用方式

设备注册流程

// USB设备插入 -> 注册设备
void UsbDevSubscriber::OnReceiveEvent(const EventFwk::CommonEventData &data) {// 1. 解析USB设备信息auto usbDevInfo = ParseUsbDeviceInfo(data);// 2. 创建DeviceInfo对象auto devInfo = std::make_shared<DeviceInfo>(usbDevInfo->busDeviceId,BusType::BUS_TYPE_USB,usbDevInfo->description);// 3. 调用设备变化回调if (devChangeCallback_) {devChangeCallback_->OnDeviceAdd(devInfo);}
}// 设备管理器处理
void ExtDeviceManager::OnDeviceAdd(shared_ptr<DeviceInfo> devInfo) {// 1. 注册设备RegisterDevice(devInfo);// 2. 查询匹配的驱动auto driverInfo = DriverPkgManager::GetInstance().QueryMatchDriver(devInfo);// 3. 更新设备驱动信息if (driverInfo != nullptr) {auto device = QueryDeviceByDeviceID(devInfo->GetDeviceId());device->AddBundleInfo(bundleInfo, driverInfo);}
}

设备绑定流程

// 应用调用绑定接口
ErrCode DriverExtMgr::BindDevice(int32_t &errorCode,uint64_t deviceId,const sptr<IDriverExtMgrCallback> &connectCallback
) {// 1. 获取调用者TokenIDuint32_t callingTokenId = IPCSkeleton::GetCallingTokenID();// 2. 调用设备管理器连接设备errorCode = ExtDeviceManager::GetInstance().ConnectDevice(deviceId, callingTokenId, connectCallback);return ERR_OK;
}// 设备管理器处理
int32_t ExtDeviceManager::ConnectDevice(uint64_t deviceId,uint32_t callingTokenId,const sptr<IDriverExtMgrCallback> &connectCallback
) {// 1. 查询设备对象auto device = QueryDeviceByDeviceID(deviceId);if (device == nullptr) {return EDM_ERR_INVALID_OBJECT;}// 2. 检查是否有匹配的驱动if (!device->HasDriver()) {return EDM_ERR_NOT_SUPPORT;}// 3. 连接设备return device->Connect(connectCallback, callingTokenId);
}// 设备对象处理
int32_t Device::Connect(const sptr<IDriverExtMgrCallback> &connectCallback,uint32_t callingTokenId
) {// 1. 注册回调RegisterDrvExtMgrCallback(connectCallback);// 2. 创建连接通知器AddDrvExtConnNotify();// 3. 调用驱动能力控制器连接Extensionstd::string bundleName = GetBundleName(bundleInfo_);std::string abilityName = GetAbilityName(bundleInfo_);return DriverExtensionController::GetInstance().ConnectDriverExtension(bundleName,abilityName,connectNofitier_,info_->GetBusDevId());
}

5.4 接口调用时序图

5.4.1 设备查询时序图
应用进程NAPI层IPC客户端DriverExtMgrExtDeviceManagerQueryDevices()queryDevices()QueryDevice() [IPC]QueryDevice(busType)查询deviceMap_根据总线类型过滤返回设备列表返回设备数据返回结果设备列表获取设备信息成功应用进程NAPI层IPC客户端DriverExtMgrExtDeviceManager
5.4.2 设备绑定时序图
应用NAPIIPC客户端DriverExtMgrExtDevMgrDeviceDrvExtCtrlAbilityMgrDriverExtBindDevice(deviceId, callback)bindDevice()BindDevice() [IPC]ConnectDevice(deviceId)Connect(callback)注册回调创建连接通知器ConnectExtension()ConnectAbility()Start ExtensionExtension启动OnCreate()OnConnect()CallbackOnConnectDone(remote)更新drvExtRemote_OnConnect(deviceId, remote)回调通知OnConnect(drvExtObj)应用获取驱动Extension远程对象,可进行RPC调用应用NAPIIPC客户端DriverExtMgrExtDevMgrDeviceDrvExtCtrlAbilityMgrDriverExt
5.4.3 设备热插拔事件时序图
KernelHDF USBIUsbInterfaceUsbDevSubscriberUsbBusExtExtDevMgrDriverPkgMgrDeviceUSB设备插入USB EventDeviceEventOnReceiveEvent()ParseDeviceInfo()解析USB设备信息(VID/PID/接口等)OnDeviceAdd(devInfo)RegisterDevice()QueryMatchDriver(devInfo)执行驱动匹配算法检查VID/PID/接口类返回DriverInfoMatchDriverInfos()创建Device对象AddBundleInfo()设备状态: 已匹配等待应用绑定设备注册完成KernelHDF USBIUsbInterfaceUsbDevSubscriberUsbBusExtExtDevMgrDriverPkgMgrDevice

6. 总结与扩展

6.1 架构优势

  1. 模块化设计:各模块职责清晰,低耦合高内聚
  2. 可扩展性:总线扩展插件化,易于支持新总线类型
  3. 安全性:基于Ability框架,具备完善的权限管理
  4. 用户体验:即插即用,自动匹配驱动

6.2 性能优化

  1. 单例模式:核心管理类采用单例,减少对象创建开销
  2. 异步处理:设备连接、驱动加载采用异步机制,不阻塞主线程
  3. 按需加载:总线扩展库按需动态加载
  4. 资源回收:定时器自动卸载空闲服务,节省系统资源

6.3 扩展方向

  1. 新总线类型支持:可扩展支持蓝牙、网络设备等
  2. 设备权限细化:支持更精细的设备访问权限控制
  3. 设备共享机制:支持多应用共享访问同一设备
  4. 驱动热更新:支持驱动包在线更新而无需重启

6.4 关键技术点

  1. IPC通信:基于OpenHarmony IPC机制的跨进程通信
  2. DDK接口:为驱动开发者提供的硬件访问接口
  3. Ability框架:驱动Extension基于Ability框架实现
  4. 事件驱动:设备热插拔、驱动包变化采用事件驱动机制
  5. 状态机管理:设备和驱动包的生命周期采用状态机模型

附录

A. 目录结构

/drivers/external_device_manager
├── frameworks              # 框架层实现
│   ├── ddk                # DDK接口实现
│   ├── js                 # JS API实现
│   └── native             # Native客户端实现
├── interfaces             # 对外接口定义
│   ├── ddk                # DDK接口头文件
│   └── innerkits          # 内部接口头文件
├── services               # 系统服务实现
│   └── native
│       ├── driver_extension              # 驱动Extension定义
│       └── driver_extension_manager      # 核心服务实现
│           ├── include
│           │   ├── bus_extension         # 总线扩展
│           │   ├── device_manager        # 设备管理
│           │   └── drivers_pkg_manager   # 驱动包管理
│           └── src                       # 源代码实现
├── utils                  # 工具类
├── test                   # 测试代码
└── sa_profile             # 系统服务配置

B. 编译构建

# 编译32位ARM系统
./build.sh --product-name rk3568 --ccache --build-target external_device_manager# 编译64位ARM系统
./build.sh --product-name rk3568 --ccache --target-cpu arm64 --build-target external_device_manager
http://www.dtcms.com/a/499665.html

相关文章:

  • 从头开始为 ARM 创建 Ubuntu 映像
  • Android 开发 | 如何使用命令使 Android 应用进入调试状态
  • 在线下单网站怎么做国家企业信用信息查询公示系统广东
  • 企业营销网站建设策划书邯郸市人社局
  • 中山哪里可以做网站产品推广方案ppt
  • 城管综合执法办案系统的技术体系解析:从移动端到云端
  • 开发基于AKS能运维开工单的智能体应用
  • 3D生成软件Rodin 2.0 简单测试案例
  • vivado 从已实现的设计工程创建自定义PL IBIS文件方法
  • TFword:从字符到片段,解析一个“小而精”的字符串处理工具的设计智慧
  • 甘肃网站备案审核flash网站源码带asp后台
  • 网站模板 手机app展示西安seo外包平台
  • F - 算符优先分析
  • 深入剖析RocketMQ3-底层原理
  • 网站建设所出现的问题电影网站域名
  • ROS趣味题25-26-1版本
  • 网络编程的基础知识
  • 【GESP】C++三级、四级练习 luogu-P1597 语句解析-系列题目3
  • 广告公司网站源码下载巴西网站域名
  • Java基础入门
  • 网站建设的价code wordpress
  • 自己做的网站项目面试为什么要做营销型的网站建设
  • 网站开发公众号开发网易企业邮箱网页版登录入口
  • 斯坦福大学生物医学数据科学(BMDS)项目概览
  • 手机转SIP-手机做中继网关-落地线路对接软交换呼叫中心
  • Redis 在订单系统中的实战应用:防重、限流与库存扣减
  • flex 做网站去成都旅游攻略怎么做
  • PHP网站开发涉及的工具有哪些秦皇岛市海港区建设局网站
  • 如何定期清理电脑垃圾文件
  • 网站怎么做现场直播视频全国企业信息公示系统查询