做Camera这些年,我有个体会:Camera问题十有八九不是靠看代码看出来的,而是靠日志"顺藤摸瓜"找到的。
但问题来了——一个Camera Bug的日志动辄上万行,一打开全是密密麻麻的英文,很多人第一反应是"算了,从头看吧"。结果看了半天,时间线对不上,关键字也没抓到,最后还是靠猜。
这篇文章把我这几年踩坑攒下来的7个核心日志场景整理出来。每个场景配了过滤命令、示例日志和我的解读思路。不是教程式的"知识点罗列",而是实战中真正会用到的东西。
建议先收藏,排查的时候直接翻到对应章节。
先说方法论:30秒定位法
在看具体场景之前,先说一个我自己总结的"30秒定位法"。拿到一份Camera日志,不要从头读,按这个顺序做:
第一步(5秒):grep "CameraServer::connect"
确认是哪个App在调用、调的是哪个cameraId、用的API1还是API2。这一步决定了你后面看哪一层。
第二步(10秒):grep "FindBestSensorMode"
看驱动选了哪组分辨率。如果选错了,后面所有分析都白费——因为数据源就不对。
第三步(10秒):grep "configure_str"
看配了几路流、format是什么。配流不对,预览和拍照肯定出问题。
第四步(5秒):grep "process_capture_request"和"ProcessCaptureResult"
看请求和返回是不是配对。如果请求多、返回少,说明中间卡住了。
四个步骤走完,基本能判断问题出在哪一层。然后再去对应层深入看。
踩坑提醒:很多时候你拿到的是别人抓的日志,但对方可能忘了抓kernel日志。Camera问题如果是驱动层导致的,光看logcat根本找不到根因。所以抓日志的时候,logcat和dmesg一定要同时抓。
场景一:到底是谁在调用相机?
这看起来是最简单的一步,但在实际排查中经常被忽略。
举个例子:线上反馈"相机打不开",你第一反应是什么?去看CameraService的报错?其实你应该先确认——是不是有别的App已经占着Camera了。Android的Camera是独占资源,一个App不释放,另一个就打不开。
你会在日志里看到:
CameraService: CameraService::connect X (client 0x7f8a1234, cameraId 0)
这段信息量很大:
pid 12345:调用方进程号,ps -A | grep 12345就能知道是哪个App
cameraId 0:打开的是哪个摄像头(0是主摄,1是副摄,具体看dtsi配置)
clientName:包名,直接告诉你是谁在调
如果connect之后迟迟没有后续日志,大概率是权限被拒或者资源被占用。这时候去看CameraService的error日志,通常会有一行Device is busy之类的话。
实战经验:多摄场景下,cameraId的编号不一定按物理位置排。有些平台0是主摄、1是超广角、2是长焦,有些平台反过来。查dtsi里的sensor顺序最靠谱,别凭经验猜。
场景二:配流到底配了什么?
配流(Configure Streams)是Camera2 API的核心步骤。简单说就是App告诉HAL:"我要几路数据流、每路什么格式什么分辨率"。这一步出了问题,后面全废。
HAL层看什么
CamX: [INFO][CORE ] configure_streams: stream[0] format=33 width=4000 height=3000
CamX: [INFO][CORE ] configure_streams: stream[1] format=34 width=1920 height=1080
CamX: [INFO][CORE ] configure_streams: stream[2] format=35 width=640 height=480
format那几个数字很多人看不懂,其实对应的是Android的HAL_PIXEL_FORMAT定义。我整理了个对照:
排查思路:App申请了3路但日志只显示2路,说明有一路没配上去。先去App侧查Surface有没有正确创建,再去HAL查usecase有没有覆盖这个组合。
踩坑提醒:format=33(IMPLEMENTATION_DEFINED)是最容易出问题的。因为这个格式"由HAL决定",不同平台实际用的buffer格式可能完全不同。如果要做YUV dump分析,一定要确认HAL实际给的是什么格式,别拿format值去判断。
场景三:驱动到底选了哪组分辨率?
这个场景高通和MTK的关键字不一样。
高通平台:
MTK平台:
CamX: [INFO][SENSOR] sensorMode[2]: width=4000 height=3000 fps=30
为什么要关注这个?因为Sensor一般会注册多组分辨率模式,HAL根据App的需求"挑"一个最合适的。但"最合适"不一定是对的。
举个真实案例:有次用户反馈预览卡顿,查了半天发现App只要了1920x1080的预览,但HAL选了4000x3000的sensor mode(因为它"最接近"),然后再缩放到1080P。大分辨率缩放不仅浪费带宽,还增加了处理延迟,预览自然卡。
这种情况怎么排查?看FindBestSensorMode选了哪个mode,再对比App实际需要的分辨率,差距太大就是问题。
实战经验:如果你在改sensor driver,注册SensorMode的时候注意一下fps配置。有些sensor的高分辨率模式只支持15fps,如果HAL选了这个模式,预览帧率会被拖到15fps,用户一看就知道有问题。
场景四:帧的请求和返回,到底卡在哪一步?
这是排查黑屏、卡顿、帧率低的核心场景。Camera数据流的本质就是一个循环:App请求帧→驱动出帧→HAL处理→返回给App。任何一步断了,现象都不同。
我用一张链路图来说明:
(App发请求) (驱动回帧给HAL) (HAL回帧给FW) (FW给Surface显示)
1. process_capture_request不出现 → App侧没发请求。查App的CaptureSession.Builder有没有正确配置,或者是不是生命周期没走完就被打断了。
2. CSLMessageHandler不出现(高通平台)→ 驱动没出帧。这时候必须看kernel日志,查ISP有没有报错、CSI有没有数据。MTK平台对应的关键字不太一样,搜handleMessage或ISP相关的回调。
3. CSLMessageHandler有但ProcessCaptureResult不出现 → 帧到了HAL但HAL没处理完。这种情况通常是HAL内部的pipeline某个node卡住了,搜node相关的error日志。
4. ProcessCaptureResult有但returnBuffer不出现 → Framework的buffer管理有问题。这种比较少见,通常和bufferqueue的slot分配有关。
踩坑提醒:还有一种隐蔽的情况——日志里频繁出现frameMessage:requestId=0。这表示驱动已经开始丢帧了。requestId一直是0不是正常的,正常情况下requestId应该递增。出现这种情况说明buffer supply跟不上了,可能的原因是preview buffer数量太少或者处理太慢。
场景五:Tuning参数生效了没有?
这个场景在什么情况下用到?用户反馈"拍照效果差"、"颜色不对"、"太暗了"——这些都可能和Tuning参数有关。
sensorMode=0:当前用的第0组分辨率模式
feature1=3, feature2=6:当前生效的feature组合
如果feature组合不对(比如该开HDR的时候没开),效果自然差。这种情况需要去查usecase的feature selection逻辑,或者Tuning XML配置文件。
实战经验:Tuning参数的调试和芯片平台强相关。高通的Camx用XML配置,MTK用的是另一套体系。如果是跨平台调试,别用高通的思路直接套MTK,参数结构完全不同。
场景六:dumpsys media.camera——被忽视的神器
很多人排查Camera问题只用logcat,但其实dumpsys media.camera输出的信息比logcat全面得多。
这个命令输出的是Camera系统的"快照"——当前有哪些App在用Camera、配了什么流、session状态如何。
1. 搜availableStreamConfigurations → 看sensor注册了哪些分辨率。排查"App要的分辨率不支持"类问题时第一个看这个。
2. 搜Active Camera Client → 看当前谁在占用Camera。排查"Camera被占用打不开"时直接定位到是哪个App。
3. 搜Session → 看当前session的pipeline配置。排查"配流和预期不符"时对比这里的配置和App侧的申请。
踩坑提醒:dumpsys输出的是"执行那一刻"的状态。如果你的问题是偶发的,要在问题复现的瞬间抓dumpsys。可以写个小脚本轮询抓取,或者用watch -n 1 'dumpsys media.camera | grep Active'持续监控。
场景七:Kernel日志——驱动层问题的终极武器
当HAL层日志看不出问题时,Kernel日志是最后的希望。很多Camera硬件层的故障(I2C通信失败、CSI丢包、上电时序错误)只会在Kernel日志里体现。
怎么抓
adb shell dmesg -w > dmesg.txt
# 抓取全部历史
adb shell cat /proc/kmsg > kmsg.txt
第一步:搜sensor名称确认probe是否成功
[ 3.215678] gc08a3_front_camera_sensor probe success, sensor_id=0x08a3
[ 3.218901] imgsensor 0-0010: sensor name: gc08a3_mipi_raw
# Probe失败
[ 7.009427] imgsensor 0-0010: Read sensor id fail, write id: 0x20, id: 0x0
[ 7.011459] imgsensor 0-0010: i2c transfer failed (-6)
看到i2c transfer failed,基本就是I2C通信有问题。常见原因:上电时序不对、I2C地址错误、GPIO冲突。
第二步:搜CSI相关错误
CSI(MIPI CSI-2)是sensor和ISP之间的数据通道。如果这里报错,数据根本传不过来,表现就是黑屏或者花屏。
踩坑提醒:Kernel日志的时间戳是从开机开始算的秒数,和logcat的时间戳不一样。要把两个日志的事件对上,需要找一个共同的时间点(比如App打开Camera的那条日志),然后算时间差。
速查表(建议截图保存)
adb logcat | grep -E "CameraServer::connect|configure_str|FindBestSensorMode|process_capture_request|ProcessCaptureResult|CSLMessageHandler|returnBuffer"
我的调试习惯
最后说几点个人经验,不是方法论,就是习惯:
1. 抓日志先清缓存。adb logcat -c清掉旧日志,然后复现问题。否则一堆历史日志干扰判断。
2. logcat和dmesg同时抓。Camera问题经常跨层,只抓一个很容易漏掉关键信息。
3. dumpsys别忘了用。排查分辨率和配置类问题时,dumpsys比logcat直觉得多。
4. 抓完整buffer。adb logcat -b all抓所有buffer(main+system+crash),有些crash日志不在main buffer里。
5. 时间戳对齐。一份日志里可能有多个时间线(logcat时间、kernel时间、uptime),先搞清楚每个时间线是什么基准,再对齐。
以上就是我这几年排查Camera问题总结的7个核心场景。这些关键字不是背出来的,是踩出来的。每个关键字背后都对应着一类问题,多查几次就记住了。
如果你在做Camera开发,遇到具体问题拿不准怎么排查,欢迎在评论区留言交流。
关注公众号「小驰行动派」
回复「Camera日志」获取本文速查手册PDF版 + 高清排查流程图
更多Camera开发实战内容
欢迎加入知识星球「小驰成长圈」
评论 (0)