常见问题

通用问题

任务创建或提交后返回HB_UCP_INVALID_ARGUMENT错误码是什么原因?

可根据UCP的错误日志来判断可能的问题,可能存在如下情况:

  • 算子约束问题:大部分加速算子在创建时应满足使用约束,否则会返回错误码。
  • 如果遇到日志打印 op $1 of task has no proper backend, user expect $2,表示没有合适的后端可执行;其中$1表示任务的类型,$2是任务提交时的backend参数,以二进制形式打印,需要按照J6系列每种backend可支持的core数量进行配置。

如何理解hbUCPSysMem的物理地址和虚拟地址?

在J6计算平台架构中,所有硬件的DDR内存共享,通过 hbUCPMallocCachedhbUCPMalloc 接口可以申请到一段物理空间连续的内存,其函数返回值被包装在 hbUCPSysMem 数据结构体中,phyAddrvirAddr 两个字段分别对应其内存空间的物理地址和虚拟地址,虚拟地址可直接被CPU访问,物理地址不可访问。

如何理解cacheable和非cacheable的hbmem?

ucp的内存管理接口提供了hbUCPMallocCachedhbUCPMalloc 来分配DDR读写内存,这种内存都是物理地址连续,可被bpu/dsp等ip访问使用的,其中 hbUCPMallocCached表示分配cacheable属性的内存,并配套了 hbUCPMemFlush 函数来对Cache进行刷新。 Cache机制是由计算平台的内存架构来决定的,可参考如下图所示。CPU与主存之间存在的Cache会缓存数据,而BPU/DSP/JPU/VPU(Video Processing Unit)/PYRAMID/STITCH/GDC等其他后端硬件与主存之间则没有cache。此时若错误使用Cache将会直接影响最终数据读写的准确性和效率。

runtime_dev_faq
  • 当CPU写完数据后,需要主动将Cache中的数据flush到memory中,否则其他硬件访问同一块内存空间时可能会读取到之前的旧数据。
  • 而当其他后端硬件写完数据后,CPU在访问之前也需要主动将Cache中的数据invalidate掉,否则CPU可能会优先读取到之前缓存在cache中的旧数据。
  • 在模型连续推理过程中,需要cpu读的,比如模型输出,建议申请带cacheable的内存,以加速CPU反复读写的效率,而不需要读的,只写的,比如模型输入,可以申请非cacheable的内存。

应用侧在异常处理中是否可以使用 exit 退出?

由于UCP内部存在资源管理单例,应用侧(包括重写的信号处理函数)调用exit/std::exit退出时会引发单例析构,若此时仍有线程访问单例资源,容易引发异常。因此,UCP更推荐使用_exit/std::quick_exit,若您必须使用exit/std::exit,请保证退出时没有线程访问UCP的任何资源。

应用异常退出时如何保证日志完整性?

为了确保关键的日志信息不会因进程异常退出而丢失,建议应用在异常退出前调用 hbUCPFlushLog 接口刷新缓冲的日志,确保所有日志消息都被写入磁盘。这在调试异常问题和追踪系统故障时尤为重要。

模型推理

导致模型推理hbUCPWaitTaskDone接口timeout超时的原因可能有哪些?

  • 模型本身执行的时间较长,而异步等待接口设置的超时时间不足,或者当前计算资源负载较高导致任务排队时间较长,可能引发接口超时。

  • 存在内存泄露情况。在系统内存不足的情况下,分配内存慢,可能会导致推理超时。

  • CPU负载过高。调度线程获取不到CPU,此时即使任务完成也无法及时同步到用户接口,导致推理超时情况。

模型推理卡住的原因

模型问题:模型指令原因导致的底层运行错误,错误没有上报,导致hang住。此时,可通过cat /sys/devices/system/bpu/bpu0/task_running对bpu任务情况进行查看,如下图所示:

task_running

s_time不为空表示任务已经正常开始,而p_time如果为空则表示没有正常返回,即可认为BPU任务hang住了,可联系sr或者编译器团队解决。

ROI输入模型约束有哪些?

您可参考 ROI简介及约束 中对ROI限制的介绍。

模型推理结果一致性问题排查

  1. 请确保用于比对一致性的输出已经去除 padding。
  2. 若模型存在动态形状输出,请确保调用了 hbDNNGetTaskOutputTensorProperties 接口获取真正输出形状。
  3. 请确保对输入输出内存正确执行了 Flush 操作。
  4. 关闭 UCP ARM 优化算子后若一致性问题解决则为优化算子问题。关闭方法:
export _HB_NN_DISABLE_UDE_EXTENSION_=true

模型推理性能优化建议

  1. 尽量优化掉模型中的 CPU 算子。
  2. 推荐推理内存统一申请,分散使用,内存复用。
  3. 在实现模型输入输出内存复用前提下,开启 Map LRU Cache 策略缓解 BPU Map 耗时。开启方式:
export HB_NN_ENABLE_MEM_LRU_CACHE=true
  1. 调整线程优先级。建议调高调度线程优先级,若仅使用模型推理功能,建议禁用 DSP、ISP 等未使用的后端以减少线程数量。参考示例:
# 设置 UCP 调度线程优先级至最高
export HB_UCP_SCHEDULE_PRIORITY=99
# 禁用未使用后端
export HB_UCP_ENABLE_DSP_BACKEND_CORE_NUM=0
export HB_UCP_ENABLE_ISP_BACKEND_CORE_NUM=0
  1. 推理时指定 BPU 核心,用以在多核硬件上减少 Memory Map 的次数。

自定义算子开发

DSP 相关

J6选用的DSP型号?

J6 选用了 Cadence 公司的 Tensilica Vision Q8 DSP IP(以下简称 Q8), 是专用于视觉/图像处理的数字信号处理器,DSP IP数量根据开发板型号略有不同。更多信息可见:DSP开发文档Cadence 官方文档

如何获取 Cadence 官方文档?

安装步骤可参考:DSP开发文档 章节;安装完成Cadence开发套件后,可以在开发包内查看部分文档,获取完整文档包请联系地平线技术支持人员。

DSP 支持哪些计算精度?

支持 int8/int16/int32 的整型计算,以及 float32、double 的浮点计算。

如何查看 DSP 侧的日志输出?

在X86 仿真环境中,可以通过在执行示例脚本时修改日志打印等级环境变量 HB_DSP_VDSP_LOG_LEVEL 来查看日志输出,日志等级设置方法与UCP一致,修改方式请参考脚本内容;

在开发板中,可以通过监听日志文件的方式查看DSP侧的日志。具体方法如下:

  1. 增加环境变量 export HB_DSP_WRITE_VDSP_LOG_TO_ARM=true,使能DSP日志输出。
export HB_DSP_VDSP_LOG_LEVEL=3
export HB_DSP_WRITE_DSP_LOG_TO_ARM=true
export HB_DSP_ENABLE_CONFIG_VDSP=true
  1. 修改DSP日志打印等级环境变量 HB_DSP_VDSP_LOG_LEVEL。

  2. 使用如下命令启用文件监听。

hrut_remoteproc_log -b /sys/class/remoteproc/remoteproc1/log

DSP 自定义算子示例是否可以直接运行?

不可以。自定义算子需要重新编译 DSP 镜像,才可以将算子实现注册到 DSP 的调用框架中。因此需要先编译 DSP 镜像,然后将镜像拷贝到开发板上,再运行示例。 编译及运行步骤请参考: 自定义算子示例 章节。

但若您想进行相关代码开发,或者编译新的镜像,则需要 DSP 开发软件 Xplorer 和对应的 License 授权文件,获取方式请联系地平线技术支持人员。

DSP 调试常用命令有哪些?

  1. 获取vdsp对应core的状态,分为offline 和 online两种状态。
# get vdsp core0 state
root@hobot:~# cat /sys/class/remoteproc/remoteproc1/state
offline
# get vdsp core1 state in J6P
root@hobot:~# cat /sys/class/remoteproc/remoteproc2/state
offline
  1. 获取vdsp镜像名字及版本,version中包含了编译版本、编译日期、hash_id等信息,可用于版本追溯。
# get vdsp core0 name
root@hobot:~# cat /sys/class/remoteproc/remoteproc1/name
soc:remoteproc_vdsp0
# get vdsp core0 version
root@hobot:~# cat /sys/class/remoteproc/remoteproc1/version
version = VDSP0_V1.4.17_20251210144524_debug
compile_time = 20251210144524
git_hash_id = eccb27563e71f9f43585cadf7ddc0e9da0d1af1
# get vdsp core1 name in J6P
root@hobot:~# cat /sys/class/remoteproc/remoteproc2/name
soc:remoteproc_vdsp1
# get vdsp core1 version in J6P
root@hobot:~# cat /sys/class/remoteproc/remoteproc2/version
version = VDSP0_V1.4.17_20251210144524_debug
compile_time = 20251210144524
git_hash_id = eccb27563e71f9f43585cadf7ddc0e9da0d1af1
注解

J6E/M的QNX操作系统中不包含name信息,请根据具体环境进行查看。

  1. dmesg 命令查看底软log信息。
  2. 查看最新落盘的vdsp日志。
# get dsp core0 log
root@hobot:~# cat /log/dsp0/message
# get dsp core1 log in J6P
root@hobot:~# cat /log/dsp1/message
  1. dsp 启停命令。
# echo dsp image path to firmware path
echo -n $image_path > /sys/module/firmware_class/parameters/path
# set firmware name of dsp core0
echo vdsp0 > /sys/class/remoteproc/remoteproc1/firmware
# start dsp core0
echo start > /sys/class/remoteproc/remoteproc1/state
# stop dsp core0
echo stop > /sys/class/remoteproc/remoteproc1/state
# set firmware name of dsp core1 in J6P
echo vdsp1 > /sys/class/remoteproc/remoteproc2/firmware
# start dsp core1 in J6P
echo start > /sys/class/remoteproc/remoteproc2/state
# stop dsp core1 in J6P
echo stop > /sys/class/remoteproc/remoteproc2/state

DSP 自定义算子卡死应该怎么排查?

  1. 通过打印的日志信息,查看 DSP 侧是否有报错信息。
  2. 判断 DSP 是卡死还是coredump,可以通过 dmesg 命令查看内核日志,查看是否有具体打印信息。
  3. 排查 ARM 侧代码,是否存在内存 Map/Unmap 和 cache 刷新问题。
  4. 排查 DSP 侧代码,是否存在 cache 刷新问题,可以通过全局刷新、逻辑二分退出等方法判断错误位置。
  5. 排查 DSP 侧代码,是否存在逻辑或者内存访问错误。可以使用 dmesg 命令查看内核日志,查看是否有打印信息。

DSP 自定义算子ddr cache未同步可能导致的问题有什么?

  1. ARM 和 DSP 侧双方写入和读取到的数据不一致。
  2. DSP 异常卡死或者无响应,可能是 DSP 侧使用了未刷新的内存。
  3. DSP coredump,此时会有错误日志打印,可以通过 dmesg 命令查看内核日志,可以根据日志定位到具体的地址。

DSP VP/HPL算子如何进一步优化性能?

当前VP/HPL DSP算子每次提交都会被视为一个单独的任务,需要经过地址map、任务调度、rpc通信、地址unmap等流程,若存在大量算子重复调用的场景, 地址map和unmap的开销会比较大。针对这种情况,可以通过以下方式进行性能优化:

  1. 复用相同地址的输入输出,使用 hbDSPAddrMap 接口进行地址预映射,重复map只是增加引用计数,不会真正执行底软地址映射逻辑, 减少VP/HPL每次提交底软中的map和unmap开销。全部使用完成后注意及时调用 hbDSPAddrUnmap 进行地址释放。

#include "hb_dsp_addr_map.h"
void repeat_process_sample(){
  // prepare memory
  hbUCPSysMem input_mem, output_mem;
  hbUCPMallocCached(&input_mem, 1920 * 1080, 0);
  hbUCPMallocCached(&output_mem, 1920 * 1080, 0);
  // pre map
  hbDSPAddrMap(&input_mem, &input_mem);
  hbDSPAddrMap(&output_mem, &output_mem);
  // multiply process operator
  int32_t process_count = 100;
  for(int i = 0; i < process_count; i++){
    hbVPImage src{HB_VP_IMAGE_FORMAT_Y,
                HB_VP_IMAGE_TYPE_U8C1,
                1920,
                1080,
                1920,
                input_mem.virAddr,
                input_mem.phyAddr,
                0,
                0,
                0};
    hbVPImage dst{HB_VP_IMAGE_FORMAT_Y,
                HB_VP_IMAGE_TYPE_U8C1,
                1920,
                1080,
                1920,
                output_mem.virAddr,
                output_mem.phyAddr,
                0,
                0,
                0};
    hbVPInterpolationType interp = HB_VP_INTER_LINEAR;
    // run operator
    hbVPResize(nullptr, &dst, &src, interp);
    // post process logic
  }
  // post unmap
  hbDSPAddrUnmap(&input_mem);
  hbDSPAddrUnmap(&output_mem);
}
  1. 通过自定义算子将VP/HPL算子和其他算子进行融合,减少算子调用的次数,从而减少map和unmap的开销。

int dsp_custom_operator(void *spec, void *non, void *tm){
  // get operator spec, and split to resize and flip
  spec_resize = spec.resize;
  spec_flip = spec.flip;
  // process resize
  hb_dsp_resize(spec_resize, nullptr, tm);
  // process flip
  hb_dsp_flip(spec_flip, nullptr, tm);
  return 0;
}
  1. 将VP/HPL算子功能进行拆解,封装为自定义算子,手动控制算子内的地址map和unmap时机,从而减少map和unmap的开销。 自定义算子的方法和步骤请参考 DSP自定义算子开发 章节。 其中算子通信结构体定义和 DSP 实现源码在示例 ucp_tutorial/deps_aarch64/ucp/plugin/dsp_plugin/hobot/hb_dsp_algo 目录下, 算子 cmd 值在示例 ucp_tutorial/deps_aarch64/ucp/plugin/dsp_plugin/hobot/include 目录下,可以根据实际需求进行修改和扩展。

如何避免 acore 异常退出导致的 DSP 挂死?

在当前的 DSP 框架中,内存由 ARM 侧申请并映射到 DSP 侧使用,若 ARM 侧发生异常退出(例如 coredump),会造成申请的内存被系统回收。 若此时 DSP 侧任务由于调度等原因,在资源回收后才被执行,会导致 DSP 侧访问内存时发生异常, 进而引发 DSP 挂死。为避免此类情况发生,可以通过以下两种方式进行优化:

  1. 对 ARM 侧内存的释放时机进行优化,在 ARM 侧发生异常退出时,延迟一段时间再释放内存,给 DSP 侧足够的时间完成当前任务并退出,避免 DSP 侧访问已释放的内存。 具体延迟的时间可以通过以下命令控制。
# get current unmap delay time, default is 1000ms
cat /sys/devices/virtual/misc/vdsp0/vdsp_ctrl/unmap_delay
# set unmap delay time to 500ms
echo '500' > /sys/devices/virtual/misc/vdsp0/vdsp_ctrl/unmap_delay
注解

由于 DSP 任务的执行时机无法预测,该方案只能降低 ARM 侧异常退出导致 DSP 挂死的概率,但无法完全避免。 可以通过第二种方案,通过切换到 vdsp_msg 通信协议来彻底避免该问题。

  1. 在 UCP 中使用 vdsp_msg 通信协议,具体启用方法如下:
# ARM 侧环境变量设置,启用 vdsp_msg 协议。默认为 0,为 ipcf 协议;设置为 1 或 vdsp_msg 后,表示启用 vdsp_msg 协议。
export HB_DSP_RPC_MODE=1

# DSP 侧在镜像启动前配置对应的启动参数,msg_mode配置为 1 表示启用vdsp_msg协议,其余两个参数为底软相关,需同时配置。
echo 'msg_mode=1 vdsp0.msgmode=1 vdsp1.msgmode=1' > /sys/module/hobot_remoteproc/parameters/bootargs
注解
  1. vdsp_msg 协议需要 ARM 侧和 DSP 侧同时启用才能生效。
  2. 需要确保 UCP 版本在 3.14.6 及以上,且底软版本支持 vdsp_msg 协议。支持 vdsp_msg 协议的底软版本要求请咨询地平线技术支持人员。

J6B 环境如何使用 fusa 版本的 VDSP?

VDSP Q8默认支持功能安全,而VDSP V130支持有限的功能安全,包括功能安全版本的 libxos.a 和头文件、libxi.a、libtile_manager.a,以及 xt-clang 的功能安全编译参数,需要主动适配并启用相关选项。

VDSP自定义算子编译示例中已经提供了 -fusa 编译参数,在编译VDSP V130镜像时,可以通过以下步骤保证功能安全:

  1. 适配功能安全版本的 libxos.a 与头文件。
  2. 参考示例中 -fusa 编译参数说明,保证启用 xt-clang 的功能安全编译参数进行镜像编译。
  3. 在启动VDSP镜像脚本中,配置功能安全相关的启动参数。

下面对每个步骤逐一讲解:

步骤一:适配功能安全版本的 libxos.a 与头文件。

需要将 RJ-2025.5 的 XOS(QM 版本,XOS_v3.06)升级到功能安全所需的 FuSa 版本(XOS_FuSa_v3.02.00S), 可参考以下步骤完成 libxos.a 与头文件更新,并结合 xt-clang 的功能安全编译参数进行构建验证。

  1. 获取 FuSa 版本库

    1. FuSa 版本库(XOS FuSa 源码与编译指南)由地平线技术支持人员提供,请联系技术支持人员获取。
    2. 版本包信息:Horizon_v3_XS1a.zip(FuSa 版本 XOS 源码与 XOS 编译指南手册)、Horizon_v3_XS1b.zip(XOS/XTOS/HAL/libiDMA/XT-CLANG 等用户手册)。
  2. XOS 升级步骤(以安装在 /opt/xtensa 目录为示例)

    1. 备份当前版本 xos
    cd /opt/xtensa/XtDevTools/install/tools/RJ-2025.5-linux/XtensaTools/xtensa-elf/src/
    mkdir xos_v3.06_bak
    mv xos/src xos/testsuite xos_v3.06_bak/
    1. 解压 FuSa 版本压缩包,并拷贝 srctestsuite
    cp -ra src /opt/xtensa/XtDevTools/install/tools/RJ-2025.5-linux/XtensaTools/xtensa-elf/src/xos/
    cp -ra testsuite /opt/xtensa/XtDevTools/install/tools/RJ-2025.5-linux/XtensaTools/xtensa-elf/src/xos/
    1. 编译 XOS
    cd /opt/xtensa/XtDevTools/install/tools/RJ-2025.5-linux/XtensaTools/xtensa-elf/src/xos/src
    export PATH=$PATH:/opt/xtensa/XtDevTools/install/tools/RJ-2025.5-linux/XtensaTools/bin
    xt-make clean
    xt-make MODE=OPT all
    
    # 生成的 libxos.a
    ls -lh /opt/xtensa/XtDevTools/install/tools/RJ-2025.5-linux/XtensaTools/xtensa-elf/src/xos/bin/libxos.a
    
    # 生成的头文件
    ls -lh /opt/xtensa/XtDevTools/install/tools/RJ-2025.5-linux/XtensaTools/xtensa-elf/src/xos/include/xtensa/
    1. 备份当前版本 libxos.a 与头文件
    cp /opt/xtensa/XtDevTools/install/builds/RJ-2025.5-linux/v130_real_config/xtensa-elf/arch/lib/libxos.a \
       /opt/xtensa/XtDevTools/install/builds/RJ-2025.5-linux/v130_real_config/xtensa-elf/arch/lib/libxos.a.bak
    
    cp -r /opt/xtensa/XtDevTools/install/tools/RJ-2025.5-linux/XtensaTools/xtensa-elf/include/xtensa \
       /opt/xtensa/XtDevTools/install/tools/RJ-2025.5-linux/XtensaTools/xtensa-elf/include/xtensa_bak
    1. 替换为 FuSa 编译产物
    # 替换 libxos.a
    cp /opt/xtensa/XtDevTools/install/tools/RJ-2025.5-linux/XtensaTools/xtensa-elf/src/xos/bin/libxos.a \
       /opt/xtensa/XtDevTools/install/builds/RJ-2025.5-linux/v130_real_config/xtensa-elf/arch/lib/libxos.a
    
    # 替换头文件
    cp /opt/xtensa/XtDevTools/install/tools/RJ-2025.5-linux/XtensaTools/xtensa-elf/src/xos/include/xtensa/* \
       /opt/xtensa/XtDevTools/install/tools/RJ-2025.5-linux/XtensaTools/xtensa-elf/include/xtensa/
    1. 验证 构造工程链接 libxos.a(例如 LDFLAGS += -lxos),建议使用新编译后的 xos/libxos.a 重新编译并验证 vdsp 可执行文件运行结果。
    //xos.h头文件里有版本号的定义,格式如下
    //-----------------------------------------------------------------------------
    // XOS version.
    //-----------------------------------------------------------------------------
    #define XOS_VERSION_MAJOR       3
    #define XOS_VERSION_MINOR       2
    #define XOS_VERSION_PATCH       0
    #define XOS_VERSION_STRING      "3.02.00S"      ///< XOS version string.
    
    //在编译工程时添加编译宏,将版本信息打印出来
    #define STR(x) #x
    #define XSTR(x) STR(x)
    #pragma message "XOS Version: " XSTR(XOS_VERSION_STRING)
    #error "Only for Test Version"
Info

xos_idma.c 集成说明

Vendor 明确 xos_idma.c 不在功能安全认证范围,因此按上述步骤编译得到的 libxos.a FuSa 版本不包含其中相关函数;如您确需使用与 xos_idma.c 相关的函数,需要自行补齐并完成功能验证(仅用于功能集成,不保证功能安全)。

  1. 方法一:将 xos_idma.clibxos 其它源码一起编译到 libxos.a
    • 需要参考 FuSa 源码包内 xos/srcMakefile,将 NONFUSA_OBJS 中的 xos_idma.o 移入 OBJS 后重新编译,以生成包含 xos_idmalibxos.a
    • 推荐使用 v3.06 的 xos_idma.c 替换/集成到 FuSa 源码对应位置(v3.02 的包内缺少 idma_chan_buf_clear 等能力,可能导致编译报错)。
  2. 方法二:将 xos_idma.c 放入您的 vdsp 工程,并与 vdsp 一起编译为静态库或可执行文件。

步骤二:启用 xt-clang 的功能安全编译参数。

功能安全指南要求使用 xt-clang 编译功能安全版本时,需要在编译参数中加入 -safety。其中有以下限制,在VDSP自定义算子开发示例中已经做了相应的适配, 可以定位 -fusa 编译选项查看具体适配细节。此外,在自定义算子开发过程中也需要注意。

  1. 限制一:--whole-archive 不支持

解决:从 MakefileCMAKE 中移除 --whole-archive,并对比移除前后编译出的 vdsp 可执行文件差异;需要在差异分析后补齐可能缺失的 .o 依赖。


# 带有 --whole-archive 时
readelf -a vdsp0 | grep FILE | sed 's/.*FILE/FILE/' | sort > safety_with_whole-archive.txt

# 移除 --whole-archive 后
readelf -a vdsp0 | grep FILE | sed 's/.*FILE/FILE/' | sort > safety_no_whole-archive.txt
  1. 限制二:不支持 -LNO:simd

解决:移除 -LNO:simd;移除后可能降低访问带宽,可在合适场景下使用 __vec_memcpy 代替普通 memcpy(注意:__vec_memcpy 不能用于中断处理函数)。


extern void *__vec_memcpy(char *__restrict dest, const char *__restrict src, int n);
  1. 限制三:汇编中不支持 .extern

解决:移除汇编里的 .extern 相关用法。

  1. 限制四:线程栈起始地址对齐

使用 xos_thread_create 创建线程时,线程栈起始地址需保证 4 字节对齐,可参考:


uint8_t stack[XOS_STACK_MIN_SIZE] __attribute__((aligned(4)));
  1. 限制五:需要移除 -safety 编译选项冲突的若干选项

-rdynamic-rpath-fvectorize等,其余可能存在冲突的编译选项请参考文档中 -safety 相关章节进行确认。

步骤三:配置功能安全相关的启动参数。

在启动VDSP镜像的脚本中,增加配置以启用功能安全相关的启动参数。该功能为在系统负载较低时周期调用idma自检,以监测潜在的内存错误。 在系统负载高的情况下,idma自检频率会降低,以避免过度占用系统资源,频率最低为原周期的10倍。

echo 'idma_stl_enable=1' > /sys/module/hobot_remoteproc/parameters/bootargs
预编译获取与使用(仅调试用途)

如果您希望快速验证集成效果,可向地平线对接人员获取预编译产物(例如 heads.tar.gzlibxos.a 以及对应 xos_idma.c 版本等)。 省去了上述步骤中的 XOS 升级和编译过程,直接替换 libxos.a 与头文件后进行验证即可。

注意事项
  • 预编译产物仅供调试参考,不可用于量产,不会更新维护;量产场景仍需基于 Vendor 源码自行编译出 FuSa 版本 libxos.a
  • 使用时请将附件中的 libxos.a 与头文件替换到与上述步骤一致的位置(替换前建议先备份 libxos.a 与头文件)。