openharmony摄像头驱动到应用浏览显示 第8章 调试方法与证据模板
本文为《开源鸿蒙相机:驱动到应用预览显示》系列发布版。
当前章节:第8章 调试方法与证据模板
代码基线:~/work/ohos5.1/nt_backclip_vendor(基于 OpenHarmony 5.1.0 Release 移植)
发布说明:使用ai codex移植调试开源鸿蒙摄像头的任务全流程在链接https://github.com/chenlong3388/codex_fix_OpenHarmony_Camera
第8章 调试方法与证据模板
本章只解决一个问题
不依赖当前测试环境,只用“历史日志 + 源码锚点 + 命令组合”说明调试技巧为什么有效。
本章边界
- 不讲脚本入口,不讲脚本门禁,不讲“跑脚本通过/失败”。
- 只讲命令怎么组合、每条命令在判定链里的作用、组合后的效果。
- 所有技巧都配“源码节选 + 历史日志片段”。
调试命令分层(先总览)
层1:目标与窗口
hdc list targets / 固定日志窗口文件
层2:控制链提取
rg 过滤 Create/Open/Start/ValidateOutputProfile
层3:显示链提取
rg 过滤 createPreviewOutput/repeatStream/QUERYBUF/SetMetadata
层4:源码回锚
rg 函数名 + nl/sed 取行级片段
层5:结论整形
控制链结论 + 显示链结论 + 联合结论
技巧1:双链分流过滤(最核心)
命令组合:
rg -n "GetCameraIds|CreateCameraDevice|OpenCamera|HCaptureSession::Start|ValidateOutputProfile" <hilog.txt> -S
rg -n "createPreviewOutput failed|repeatStream is nullptr|VIDIOC_QUERYBUF failed|SetMetadata Failed with -5" <hilog.txt> -S
为什么这样组合:
- 第一条先看控制链推进状态。
- 第二条再看显示链是否闭环。
- 两条链分开后,
Start success和黑屏可以同时成立,不冲突。
源码节选:foundation/multimedia/camera_framework/frameworks/native/camera/src/session/capture_session.cpp
if (output->GetOutputType() == CAPTURE_OUTPUT_TYPE_PREVIEW) {
repeatStream = static_cast<IStreamRepeat*>(stream.GetRefPtr());
}
if (repeatStream) {
errItemCode = repeatStream->SetCameraApi(apiCompatibleVersion);
} else {
MEDIA_ERR_LOG("PreviewOutput::SetCameraApi() repeatStream is nullptr");
}
历史日志片段:tmp_test/ov5648_api_debug_0402_162846/hilog_x.txt
04-02 16:28:56.241 ... PreviewOutput::SetCameraApi() repeatStream is nullptr
04-02 16:28:56.299 ... HCaptureSession::Start prepare execute, sessionID: 3
04-02 16:28:56.310 ... HCaptureSession::Start execute success, sessionID: 3
效果:
- 直接避免“只看到 Start success 就判定预览成功”的误判。
技巧2:参数非法要先回到输入创建点
命令组合:
rg -n "createPreviewOutput failed: \{\"code\":\"7400101\"\}|selected profile|previewProfile" <hilog.txt> -S
rg -n "CreatePreviewOutput\(" foundation/multimedia/camera_framework/frameworks/native/camera/src/input/camera_manager.cpp -S
为什么这样组合:
- 先看 App 是否选到了合法 profile。
- 再看 Framework
CreatePreviewOutput参数门禁是否被触发。
源码节选:foundation/multimedia/camera_framework/frameworks/native/camera/src/input/camera_manager.cpp
CHECK_ERROR_RETURN_RET_LOG((serviceProxy == nullptr) || (surface == nullptr), CameraErrorCode::INVALID_ARGUMENT,
"CreatePreviewOutput serviceProxy is null or previewOutputSurface/profile is null");
CHECK_ERROR_RETURN_RET_LOG((profile.GetCameraFormat() == CAMERA_FORMAT_INVALID) || (profile.GetSize().width == 0)
|| (profile.GetSize().height == 0), CameraErrorCode::INVALID_ARGUMENT,
"CreatePreviewOutput invalid fomrat or width or height is zero");
历史日志片段:tmp_test/ov5648_api_debug_0402_091325/hilog_x.txt
04-02 09:13:35.701 ... createPreviewOutput failed: {"code":"7400101"}
04-02 09:13:35.725 ... mPreviewOutput: undefined
04-02 09:13:35.764 ... createSession failed: {"code":"7400101"}
效果:
- 避免把“参数非法”误改成“驱动问题”。
技巧3:模式不匹配先看 fallback 语义,不要先改显示链
命令组合:
rg -n "ValidateOutputProfile in mode\(|fallback to NORMAL|Not in the profiles set" <hilog.txt> -S
nl -ba foundation/multimedia/camera_framework/frameworks/native/camera/src/session/capture_session.cpp | sed -n '4467,4496p'
为什么这样组合:
mode(x)失败通常是能力语义问题。- 先看是否进入
NORMALfallback,再决定是否回到 HCS 能力定义。
源码节选:foundation/multimedia/camera_framework/frameworks/native/camera/src/session/capture_session.cpp
auto modeIt = profileMap.find(modeName);
if (modeIt != profileMap.end() && validateOutputProfileFunc(validateProfile, modeIt->second)) {
return true;
}
if (modeName != SceneMode::NORMAL) {
auto normalIt = profileMap.find(SceneMode::NORMAL);
...
}
历史日志片段:tmp_test/ov5648_api_debug_0402_162846/hilog_x.txt
04-02 16:28:56.240 ... ValidateOutputProfile in mode(1): w(1280),h(960),f(2000), profiles size is:1
04-02 16:28:56.240 ... CaptureSession::ValidateOutputProfile fail!
效果:
- 降低“显示链表象故障”覆盖“模式能力根因”的概率。
技巧4:看到 QUERYBUF 失败先做缓冲语义定位
命令组合:
rg -n "VIDIOC_QUERYBUF failed|ReqBuffers|V4L2AllocBuffer" <hilog.txt> -S
nl -ba drivers/peripheral/camera/vdi_base/common/adapter/platform/v4l2/src/driver_adapter/src/v4l2_buffer.cpp | sed -n '369,380p'
为什么这样组合:
- 先确认
ReqBuffers是否已成功。 - 再看
QUERYBUF失败,说明 type/memory/plane 组合有问题。
源码节选:drivers/peripheral/camera/vdi_base/common/adapter/platform/v4l2/src/driver_adapter/src/v4l2_buffer.cpp
buf.type = bufferType_;
buf.memory = memoryType_;
...
if (ioctl(fd, VIDIOC_QUERYBUF, &buf) < 0) {
CAMERA_LOGE("error: ioctl VIDIOC_QUERYBUF failed: %{public}s\n", strerror(errno));
return RC_ERROR;
}
历史日志片段:tmp_test/ov5648_api_debug_0402_122831/hilog_x.txt
04-02 12:28:41.537 ... V4L2AllocBuffer() V4L2AllocBuffer enter fd 9
04-02 12:28:41.537 ... ioctl VIDIOC_QUERYBUF failed: Invalid argument
04-02 12:28:41.537 ... Creatbuffer: V4L2AllocBuffer error
效果:
- 避免在上层反复试错,把定位快速收敛到 V4L2 缓冲协商层。
技巧5:控制链成功与显示链失败要写成并行结论
命令组合:
rg -n "HCaptureSession::Start execute success|SetMetadata Failed with -5" <hilog.txt> -S
nl -ba foundation/graphic/graphic_surface/surface/src/surface_buffer_impl.cpp | sed -n '602,611p'
为什么这样组合:
Start execute success属于控制链信号。SetMetadata Failed with -5属于显示消费链信号。- 两者同窗共现时应输出“并行结论”,不是互相否定。
源码节选:foundation/graphic/graphic_surface/surface/src/surface_buffer_impl.cpp
auto dRet = displayBuffer->SetMetadata(*handle_, key, value);
...
BLOGE("SetMetadata Failed with %{public}d", dRet);
return GSERROR_HDI_ERROR;
历史日志片段:tmp_test/ov5648_api_debug_0402_091325/hilog_x.txt
04-02 09:13:35.757 ... SetMetadata Failed with -5
04-02 09:13:35.763 ... PreviewOutput::SetCameraApi() repeatStream is nullptr
效果:
- 避免“只看一条链就下全局结论”。
命令组合模板(可直接复用在历史日志回放)
- 先跑双链过滤:控制链一条、显示链一条。
- 对每个关键信号回锚一个函数片段。
- 输出三句:控制链结论、显示链结论、联合结论。
常见误用与纠偏
| 误用 | 后果 | 纠偏 |
|---|---|---|
只过滤 Start 相关日志 |
误判“一定有画面” | 同时过滤 SetMetadata/QUERYBUF/repeatStream |
| 不做源码回锚 | 结论停留在关键词层 | 每个结论补一段函数片段 |
| 把同窗共现当直接因果 | 结论越界 | 明确“并行结论”与“直接因果”分层 |
| 一次解释太多信号 | 归因混乱 | 先一个信号一段分析,再汇总 |
本章最小动作
不连设备也可做:任选一个历史 hilog_x.txt,按“信号过滤 -> 源码回锚 -> 三元结论”完成一份离线分析。
下一跳建议
读第9章:看这些技巧在完整实战过程里如何按时间顺序串起来,直到问题闭环。
知识点依赖与跨章连接
| 本章方法块 | 前置章节 | 后续章节 | 跳转理由 |
|---|---|---|---|
| 双链分流过滤 | 第1章 主链调用总览 | 第9章 实战演练与复盘 | 先有总览分段,复盘时才能稳定落三元结论 |
| 参数门禁回锚 | 第5章 输出创建与显示绑定 | 第7章 异常挂点与主链归因 | 先确认输入语义,再做挂点归因 |
| mode/fallback 检查 | 第3章 能力注入与流桥接 + 第4章 会话编排与门禁 | 第9章 实战演练与复盘 | 能力定义与会话门禁是同一条判定链 |
| QUERYBUF 缓冲定位 | 第2章 驱动与硬件基线 | 第7章 异常挂点与主链归因 | 硬件缓冲语义先收敛,再归因到主链节点 |
| 显示消费链并行结论 | 第5章 输出创建与显示绑定 | 第9章 实战演练与复盘 | 避免把显示侧失败误写成控制链失败 |
信号 -> 判断 -> 动作
| 信号 | 判断 | 动作 |
|---|---|---|
Start execute success 且 repeatStream is nullptr |
控制链推进,但预览对象链断裂 | 执行双链分流,回锚 AddOutput/SetCameraApi |
createPreviewOutput failed: 7400101 |
输入参数语义不成立 | 核 selected profile 与 CreatePreviewOutput 参数门禁 |
ValidateOutputProfile ... fail |
mode/profile 匹配失败 | 核 ParseCapability 输入并回看 fallback 路径 |
VIDIOC_QUERYBUF failed |
底层缓冲协商失败 | 核 type/memory/plane/index,必要时分辨率降档 |
SetMetadata Failed with -5 |
显示消费链独立失败 | 与控制链并列写结论,不做单链覆盖判断 |
发布后补链
- 上一篇:https://laval.csdn.net/69d8b9d054b52172bc6860dc.html
- 下一篇:https://laval.csdn.net/69d8ba4754b52172bc6860f3.html
全章导航
- 第0章 导读学习指南:https://laval.csdn.net/69d77a0554b52172bc6802aa.html
- 第1章 主链调用总览(图表):https://laval.csdn.net/69d8b75f54b52172bc686020.html
- 第2章 驱动与硬件基线:https://laval.csdn.net/69d8b7fd0a2f6a37c59e6f33.html
- 第3章 能力注入与流桥接(HDF/HDI/VDI):https://laval.csdn.net/69d8b86154b52172bc68609a.html
- 第4章 会话编排与门禁(Framework/Service):https://laval.csdn.net/69d8b8d154b52172bc6860ae.html
- 第5章 输出创建与显示绑定(ArkTS/HAP):https://laval.csdn.net/69d8b91954b52172bc6860be.html
- 第6章 函数级链路走读(驱动到显示):https://laval.csdn.net/69d8b96854b52172bc6860cd.html
- 第7章 异常挂点与主链归因:https://laval.csdn.net/69d8b9d054b52172bc6860dc.html
- 第8章 调试方法与证据模板:https://laval.csdn.net/69d8ba1454b52172bc6860e4.html
- 第9章 实战演练与复盘:https://laval.csdn.net/69d8ba4754b52172bc6860f3.html
更多推荐
所有评论(0)