目录

USB设备管理(C/C++)

概述

OH_UsbManager是HarmonyOS提供的USB设备管理C接口模块,支持开发者在C/C++层完成USB Host侧的设备枚举、权限管理、设备连接和底层通信等操作。该接口与ArkTS层的@ohos.usbManager接口功能对应,适用于需要使用C/C++进行原生USB设备管理的开发场景。

系统能力:SystemCapability.USB.USBManager

[h2]核心能力

OH_UsbManager C API主要提供以下能力:

[h2]基本概念

[h2]适用场景

OH_UsbManager C API适用于以下典型场景:

[h2]运作机制

USB服务系统包含USB API、USB Service、USB HAL三层架构。

图1 USB服务运作机制

在Host模式下,当前设备作为主设备负责数据传输及端口管理,连接的USB设备为被管理的从设备。应用程序通过OH_UsbManager C接口枚举设备、获取权限、建立UsbPipe通信通道,并通过文件描述符进行底层I/O操作。

开发前准备

[h2]环境要求

开发工具及配置

DevEco Studio是进行USB设备驱动开发的必备工具,开发者可以使用该工具进行开发、调试、打包等操作。请下载安装该工具,并参考DevEco Studio使用指南中的创建工程及运行进行基本的操作验证,保证DevEco Studio可正常运行。

SDK版本配置

OH_UsbManager提供的C接口,所需SDK版本为API 26.0.1及以上才可使用。

HDC配置

HDC(HarmonyOS Device Connector)是为开发人员提供的用于调试的命令行工具,通过该工具可以在Windows/Linux/Mac系统上与真实设备或者模拟器进行交互,详细参考HDC配置。

"配置环境变量hdc_server_port"和"全局环境变量"为必须操作。

[h2]搭建环境

  1. 在PC上安装DevEco Studio,要求版本在4.1及以上。
  2. 将public-SDK更新到API 26.0.1或以上。
  3. PC安装HDC工具,通过该工具可以在Windows/Linux/Mac系统上与真实设备或者模拟器进行交互。
  4. 用USB线缆将搭载HarmonyOS的设备连接到PC。

[h2]检验环境是否搭建成功

检查DevEco Studio是否已连接上HarmonyOS设备。

[h2]权限配置

调用OH_UsbManager_RequestPermission请求设备权限时,系统会弹窗请求用户授权。该接口本身不需要在module.json5中声明特定权限,但需要用户在弹窗中确认。

[h2]约束与限制

接口说明

[h2]接口

名称 描述
OH_UsbManager_ErrorCode OH_UsbManager_GetUsbDeviceList(OH_UsbManager_UsbDevice **devices, uint32_t *deviceCount) 获取已连接的所有USB设备列表。函数会分配设备数组及内部字符串缓冲区,调用者必须通过OH_UsbManager_FreeUsbDeviceList释放,不能单独释放各字段。
void OH_UsbManager_FreeUsbDeviceList(OH_UsbManager_UsbDevice *devices, uint32_t deviceCount) 释放由OH_UsbManager_GetUsbDeviceList返回的设备数组。调用后指针失效,传入null或count为0时为安全空操作。
OH_UsbManager_ErrorCode OH_UsbManager_HasPermission(const char *deviceName, bool *result) 检查应用是否有权限访问指定设备。设备名称格式为<总线号>-<设备地址>。
OH_UsbManager_ErrorCode OH_UsbManager_RequestPermission(const char *deviceName, OH_UsbManager_PermissionCallback callback, void *userContext) 异步请求访问指定USB设备的权限。可能触发系统弹窗请求用户授权,函数立即返回,结果通过回调返回。
OH_UsbManager_ErrorCode OH_UsbManager_ConnectDevice(const OH_UsbManager_UsbDevice *device, OH_UsbManager_UsbPipe *pipe) 连接USB设备并打开通信管道。仅需device中的busNum和devAddress字段,其他字段被忽略。返回的管道必须通过OH_UsbManager_ClosePipe关闭。
OH_UsbManager_ErrorCode OH_UsbManager_GetFileDescriptor(const OH_UsbManager_UsbPipe *pipe, int32_t *fd) 获取已打开USB设备管道的文件描述符。该fd可用于基于ioctl的底层USB传输。
OH_UsbManager_ErrorCode OH_UsbManager_ClosePipe(const OH_UsbManager_UsbPipe *pipe) 关闭USB设备管道并释放底层资源。管道必须由OH_UsbManager_ConnectDevice获取。

详细的接口说明请参考OH_UsbManager和ohusb_manager.h。

[h2]数据结构

结构体 描述
OH_UsbManager_UsbDevice USB设备信息,包含总线号、设备地址、名称、厂商信息、产品ID、配置列表等。
OH_UsbManager_UsbConfig USB配置信息,包含配置ID、属性、最大功率、接口列表等。一个UsbDevice可包含多个UsbConfig。
OH_UsbManager_UsbInterface USB接口信息,包含接口ID、协议、类别、端点列表等。一个UsbConfig可包含多个UsbInterface。
OH_UsbManager_UsbEndpoint USB端点信息,包含端点地址、属性、传输类型、方向等。一个UsbInterface可包含多个UsbEndpoint。
OH_UsbManager_UsbPipe USB设备管道,包含总线号和设备地址,用于标识已打开的设备通信通道。

详细的数据结构说明请参考OH_UsbManager和ohusb_manager.h。

[h2]错误码

OH_UsbManager C接口通过OH_UsbManager_ErrorCode枚举返回错误码,具体如下:

错误码 值 说明
OH_USBMANAGER_SUCCESS 0 操作成功。
OH_USBMANAGER_ERROR_PERMISSION_DENIED 14400001 权限被拒绝。
OH_USBMANAGER_ERROR_SERVICE_EXCEPTION 14400004 服务异常。
OH_USBMANAGER_ERROR_NO_DEVICE 14400008 不存在该设备(可能已被断开连接)。
OH_USBMANAGER_ERROR_NO_MEMORY 14400009 内存不足。
OH_USBMANAGER_ERROR_IO_ERROR 14400012 传输I/O错误。
OH_USBMANAGER_ERROR_INVALID_PARAMETER 14400014 无效参数。对不可为空的参数传入了空指针。

详细的错误码说明请参考ohusb_manager.h。

开发步骤

USB设备管理C API的完整开发流程包括:设备发现 → 权限授权 → 设备连接 → 底层通信 → 资源关闭。以下逐步说明各阶段的操作。

添加动态链接库

CMakeLists.txt中添加以下lib。

libohusb_manager.so

头文件

#include "BasicServicesKit/ohusb_manager.h"

[h2]设备发现

调用OH_UsbManager_GetUsbDeviceList获取当前连接的所有USB设备列表。该函数会分配设备数组及内部所有字符串缓冲区,调用者不得单独释放各字段内存。返回的设备数组包含完整的描述符层级信息(配置、接口、端点),可通过遍历设备列表查找目标设备。

使用完毕后必须调用OH_UsbManager_FreeUsbDeviceList释放设备数组。

OH_UsbManager_UsbDevice *devices = nullptr;
uint32_t deviceCount = 0;
OH_UsbManager_ErrorCode code = OH_UsbManager_GetUsbDeviceList(&devices, &deviceCount);
if (code != OH_USBMANAGER_SUCCESS) {
    ThrowUsbError(env, "OH_UsbManager_GetUsbDeviceList", code);
    return nullptr;
}
OH_UsbManager_UsbDevice *devices = nullptr;
uint32_t deviceCount = 0;
bool freed = false;
{
    std::lock_guard<std::mutex> lock(g_deviceListMutex);
    devices = g_heldDevices;
    deviceCount = g_heldDeviceCount;
    if (devices != nullptr) {
        OH_UsbManager_FreeUsbDeviceList(devices, deviceCount);
        g_heldDevices = nullptr;
        g_heldDeviceCount = 0;
        freed = true;
    }
}

[h2]授权

通过OH_UsbManager_HasPermission检查当前应用是否已有设备访问权限。设备名称格式为<总线号>-<设备地址>。

若无权限,调用OH_UsbManager_RequestPermission异步请求权限。该函数会立即返回,请求结果通过OH_UsbManager_PermissionCallback回调通知。仅在授权成功后才可进行设备连接操作。

std::string deviceName;
if (!GetDeviceNameArg(env, info, deviceName)) {
    return nullptr;
}
bool result = false;
OH_UsbManager_ErrorCode code = OH_UsbManager_HasPermission(deviceName.c_str(), &result);
if (code != OH_USBMANAGER_SUCCESS) {
    ThrowUsbError(env, "OH_UsbManager_HasPermission", code);
    return nullptr;
}
RequestPermissionContext *context = static_cast<RequestPermissionContext *>(data);
OH_UsbManager_ErrorCode code =
    OH_UsbManager_RequestPermission(context->deviceName.c_str(), OnPermissionCallback, context);
std::unique_lock<std::mutex> lock(context->mutex);
if (code != OH_USBMANAGER_SUCCESS) {
    context->apiCode = code;
    context->completed = true;
    return;
}

[h2]连接

权限获取后,调用OH_UsbManager_ConnectDevice连接目标USB设备,打开通信管道。连接时仅需OH_UsbManager_UsbDevice结构体中的busNum和devAddress字段,其他字段将被忽略。返回的OH_UsbManager_UsbPipe包含设备的总线号和设备地址,用于后续所有设备操作。

连接成功后,可调用OH_UsbManager_GetFileDescriptor获取设备管道的文件描述符(fd),该fd可用于基于ioctl的底层USB传输操作。

uint32_t busNum = 0;
uint32_t devAddress = 0;
napi_get_value_uint32(env, args[0], &busNum);
napi_get_value_uint32(env, args[1], &devAddress);

OH_UsbManager_UsbDevice device = {0};
device.busNum = static_cast<uint8_t>(busNum);
device.devAddress = static_cast<uint8_t>(devAddress);
OH_UsbManager_UsbPipe pipe = {0};
OH_UsbManager_ErrorCode code = OH_UsbManager_ConnectDevice(&device, &pipe);
if (code != OH_USBMANAGER_SUCCESS) {
    ThrowUsbError(env, "OH_UsbManager_ConnectDevice", code);
    return nullptr;
}
(void)info;
OH_UsbManager_UsbPipe pipe = {0};
{
    std::lock_guard<std::mutex> lock(g_pipeMutex);
    if (!g_pipeConnected) {
        napi_throw_error(env, nullptr, "pipe is not open, call connectDevice first");
        return nullptr;
    }
    pipe = g_pipe;
}
int32_t fd = -1;
OH_UsbManager_ErrorCode code = OH_UsbManager_GetFileDescriptor(&pipe, &fd);
if (code != OH_USBMANAGER_SUCCESS) {
    ThrowUsbError(env, "OH_UsbManager_GetFileDescriptor", code);
    return nullptr;
}

[h2]通信

通过OH_UsbManager_GetFileDescriptor获取的文件描述符,开发者可使用标准文件I/O或ioctl进行底层USB通信。常见的通信方式包括:

底层通信的具体ioctl命令和数据格式取决于USB设备协议和内核驱动实现,开发者需参考相关USB协议规范。

[h2]关闭

使用完毕后,按以下顺序释放资源:

  1. 调用OH_UsbManager_ClosePipe关闭设备管道,释放底层资源。
  2. 调用OH_UsbManager_FreeUsbDeviceList释放由OH_UsbManager_GetUsbDeviceList分配的设备数组内存。

重要:

资源释放顺序为先关闭管道,再释放设备数组。确保异常退出路径上也执行释放操作,避免资源泄漏。

(void)info;
OH_UsbManager_UsbPipe pipe = {0};
{
    std::lock_guard<std::mutex> lock(g_pipeMutex);
    if (!g_pipeConnected) {
        napi_throw_error(env, nullptr, "pipe is not open, call connectDevice first");
        return nullptr;
    }
    pipe = g_pipe;
}
OH_UsbManager_ErrorCode code = OH_UsbManager_ClosePipe(&pipe);
if (code != OH_USBMANAGER_SUCCESS) {
    ThrowUsbError(env, "OH_UsbManager_ClosePipe", code);
    return nullptr;
}

完整示例代码请参考USBManager C API Sample。

常见问题

问题现象 可能原因 解决措施
调用OH_UsbManager_GetUsbDeviceList获取设备列表时,返回的deviceCount为0。

- 当前设备作为USB Device模式而非Host模式。

- 没有USB设备接入。

确保当前设备作为USB Host模式,所连接的设备为Device模式。部分设备支持主、从两种USB设备模式,需要将设备设置为Host模式方可枚举到从设备。
调用OH_UsbManager_ConnectDevice连接设备时返回OH_USBMANAGER_ERROR_PERMISSION_DENIED(14400001)。

- 应用未获取设备访问权限。

- 用户在权限弹窗中拒绝了授权请求。

1. 连接设备前,先调用OH_UsbManager_HasPermission检查是否有访问权限。

2. 若无权限,调用OH_UsbManager_RequestPermission请求权限,在回调中确认授权结果。

3. 仅在权限授予后才调用OH_UsbManager_ConnectDevice。

调用OH_UsbManager_RequestPermission后,回调函数OH_UsbManager_PermissionCallback未被调用。

- deviceName参数格式不正确。

- USB服务异常,无法处理权限请求。

- 回调函数指针为null。

1. 确认deviceName从OH_UsbManager_UsbDevice的name字段获取,格式正确。

2. 检查回调函数指针是否有效。

3. 通过日志确认USB服务是否正常运行。

多次调用OH_UsbManager_GetUsbDeviceList后,应用内存持续增长。

- 调用OH_UsbManager_GetUsbDeviceList后未调用OH_UsbManager_FreeUsbDeviceList释放设备数组。

- 调用OH_UsbManager_ConnectDevice后未调用OH_UsbManager_ClosePipe关闭管道。

- 释放时传入的deviceCount与获取时不一致。

1. 每次调用OH_UsbManager_GetUsbDeviceList后,必须调用OH_UsbManager_FreeUsbDeviceList释放内存,传入的deviceCount应与获取时一致。

2. 每次调用OH_UsbManager_ConnectDevice后,必须调用OH_UsbManager_ClosePipe关闭管道。

3. 确保异常退出路径上也执行释放操作。

调用OH_UsbManager_GetFileDescriptor时返回OH_USBMANAGER_ERROR_NO_DEVICE(14400008)。

- USB设备在获取文件描述符前已断开。

- 传入的OH_UsbManager_UsbPipe无效。

1. 确认设备仍在连接状态,可通过OH_UsbManager_GetUsbDeviceList确认设备是否在列表中。

2. 确认OH_UsbManager_UsbPipe由OH_UsbManager_ConnectDevice成功返回。

3. 设备重新连接后,需重新执行完整的连接流程。