ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

车机Android STR唤醒后相机与语音失效的根因分析及修复方案

车机Android STR唤醒后相机与语音失效的根因分析及修复方案 前段时间在一个车机集成项目里遇到一个很典型的Android STR问题最开始的现象描述只有一句话车机低功耗挂起Suspend to RAM唤醒后相机和语音全部失效必须重启车机才能恢复。就这一句话让我和系统、音频、前舱几个团队来回折腾了将近一周。问题本身说穿了并不难难的是它牵扯的链路太长电源管理、内核驱动、HAL、framework服务、上层应用每个环节都可能处于“看起来正常但实际没恢复”的状态。如果你也是做车机BSP或者Android Framework的这篇文章会比较对胃口即使你主要写应用层这套排查思路对你日后做稳定性问题分析也会有帮助。下面我按实际推进的节奏把现象、定位、根因和两种修复方案完整写一遍尽量做到每一步都能直接参考。1. 故障现场与复现路径1.1 故障现象记录这个问题的触发条件非常固定车机进入STR低功耗状态然后通过按键、CAN信号或定时器唤醒。唤醒之后屏幕、触摸、蓝牙、网络这些常规功能都正常唯独媒体相关的能力异常具体表现分成两块。相机侧的表现为系统自带的相机应用打开后黑屏无预览偶尔能出一帧画面但直接卡死第三方使用Camera2接口的应用调用openCamera时返回错误日志里报“Camera device was already closed”或者“CameraDevice in error state”部分场景下相机的进程会反复闪退杀掉重启后仍然打不开。更奇怪的是此时摄像头模组的供电和数据线检查下来都是正常的用示波器量MCLK也有信号。语音侧的表现同样很彻底语音助手无法唤醒“你好车机”这类唤醒词没有任何反应用麦克风录制的应用也拿不到数据录音文件时长在走但数据全是静音如果把唤醒词引擎单独拉起来会报底层音频设备打开失败。由于唤醒词识别一般跑在DSP或者独立的音频DSP固件里这一块异常通常不是简单的权限或路由问题。这两类问题必须重启系统才能恢复重启后一切都正常说明不是硬件烧毁而是软件运行状态进入了一种“假死”模式。这种“永久失效”的定性很重要它直接决定了后续排查的重心需要找出为什么软件唤醒后没有把相关硬件恢复到可用状态。1.2 复现步骤与影响范围复现步骤其实不复杂简单来说就是“挂起-唤醒-操作相机/语音”三连。我整理成了一条标准测试路径车辆上电启动系统等待系统完全冷启动完成。打开相机和语音助手各一次确认功能正常作为对照组。让系统进入STR挂起状态在测试环境里一般是执行echo mem /sys/power/state或者直接用电源键短按触发。等待30秒以上确保挂起流程彻底完成。通过电源键或CAN指令唤醒系统等待屏幕和触摸恢复。唤醒后立刻依次打开相机、触发语音对话、尝试录音。在这个步骤下问题复现率非常高基本上唤醒后立刻去操作十次里面有八九次必现。如果把等待时间拉长到唤醒后5分钟再操作有时能自己恢复这说明底层可能在某个时机做了迟到的资源恢复但用户的实际体验等不起这个时间。影响范围看下来主要集中在前路摄像头、环视摄像头、语音唤醒引擎和通话麦克风这四类设备上而车内音响的播放功能却不受影响这是一个非常重要的线索。1.3 STR是什么在车机上为什么特别容易出问题STR全称Suspend to RAM对应Linux电源管理里的S3状态。简单理解就是系统把所有运行现场保存到内存里内存保持供电CPU和大部分外设直接断电或者进入极低功耗模式。这个状态和电脑的“睡眠”是一个道理按下唤醒键后CPU从内存里恢复现场接着跑原来没跑完的代码所以应用程序不会感知到系统重启过。问题在于STR唤醒后硬件恢复的完整性依赖驱动层的resume回调而车机的外设数量远多于手机摄像头、麦克风阵列、DSP、功放、收音机、GNSS、环视芯片每一个都和电源域、时钟、复位、I2C总线强相关。手机在STR唤醒后只需要恢复少量外设车机却需要在几十毫秒内把所有外设恢复到可用状态其中任何一步依赖关系没理清就会出现“系统起来了但某个设备没起来”的问题。再加上车机的软件栈比手机更依赖定制方案厂商提供的BSP里经常默认使用低功耗模式但对接的应用层和服务框架不一定做了对应的恢复适配。所以STR在车机上出问题的概率比手机要高一个数量级。对参与车机项目的人来说STR相关的功耗和稳定性问题几乎是绕不过去的功课。2. 排查过程从日志到节点状态逐层收网2.1 第一轮从 dmesg 和 logcat 里找“第一句报错”排查这类问题我习惯先把两套日志同时抓下来一套内核日志一套Android日志。很多人只盯logcat但车机Media相关的设备故障第一现场往往在dmesg里。我的做法是先正常启动一次执行完整的功能测试抓一份“正常日志”作为基准然后复现问题再抓一份“异常日志”。两份日志摆在一起对比效率比单看一份高很多。下面截取几段我当时看到的关键日志片段。异常状态下打开相机时dmesg里能看到典型的CCI篇[CAM:CCI] cci_error: timeout, virtual_channel0, client2, status0x00000004 [CAM:ISP] hal_isp i2c fail, reg0x3038, val0x0000 [CAM:ICP] icp_iram_load failed, ret-110audio侧能看到DSP固件相关的报错[audio_dsp] adsp firmware download fail, status0x0004 [audio_dsp] voice smmu register error, ret-22 [audio_dsp] afe send cmd timeout, opcode0x100alogcat里则比较干净偶尔能看到MediaProvider和Camera HAL的连接断开11-25 14:33:55.123 1234 5678 E CameraService: CameraService::connect: Camera 0 is in error state 11-25 14:33:55.130 1234 5678 E MediaProvider: Failed to acquire camera: CameraAccessException: CAMERA_ERROR 11-25 14:34:01.002 9999 8888 E AudioFlinger: RecordThread: thread couldnt open input, status-22从日志里能确定两件事一是底层确实发生了I2C通信超时和DSP固件下载失败二是上层服务并没有被杀死而是处于“活着的错误状态”。这基本排除了上层进程异常退出导致的路径丢失把问题圈定在驱动恢复和HAL状态这两个层面。2.2 第二轮构造最小样本跨过上层干扰定位到HAL和驱动层之后我建议不要再继续用系统相机应用或语音助手做验证了。上层应用往往会缓存错误状态、做重试、做超时处理这些逻辑会掩盖底层真相。最好直接用最底层的方式验证设备是否恢复了。相机这块可以先绕过CameraService直接调用HAL或vendor层提供的测试工具。不同平台叫法不一样有的叫mm-camera-ext有的叫ia_test高通平台通常有camx相关的vendor测试代码。如果没有专用工具也可以用V4L2的接口试一下v4l2-ctl --list-devices v4l2-ctl -d /dev/video0 --set-fmt-videowidth1280,height720,pixelformatNV12 v4l2-ctl -d /dev/video0 --stream-mmap --stream-count10如果这步能出帧说明内核驱动和sensor的链路已经恢复问题在Camera HAL以上如果这步黑屏或超时说明问题基本在驱动或物理链路往上找也没用。语音侧我用的是tinyalsa工具直接打开PCM设备读数据tinycap /data/local/tmp/test.wav -D 0 -d 0 -c 2 -r 48000 -b 16 -T 3然后播放这个文件用软件看RMS电平。如果采集到全零数据说明PCM设备和DSP路径仍然不通。我用这个方式复现了语音问题它在没有上层语音助手干扰的情况下稳定出现所以基本能够确认底层DSP固件或音频驱动没有恢复成功。2.3 第三轮对照正常与异常唤醒日志圈定差异点最小样本确认底层问题后我重新把两份dmesg里和电源、时钟、reset、固件加载相关的关键节点打出来做了一次逐行对比。这里把对比结果简化成表格方便看懂检查项正常唤醒异常唤醒PMIC上电顺序CAM_PWR_EN先拉高30ms后MCLK输出CAM_PWR_EN确实拉高了但MCLK输出延迟了300ms摄像头I2C枚举一次通过所有sensor地址都能正常读到ID首个sensor地址读取超时重试3次后超时DSP固件状态adsp boot response ok, firmware version 0x2031固件下载超时状态寄存器是0x0004音频PCM节点打开成功读数据正常打开成功但读到全零数据内核pm状态/sys/power/pm_print_state 显示设备全部resume完成多个设备进入dtor状态但resume回调没有完成这里最让我在意的是“GPIO已经拉高但MCLK输出晚”和“DSP固件下载超时”这两条。前者说明外设的供电使能确实做了但被依赖的时钟或电源轨没有按预期准备好后者说明DSP在STR期间固件丢失唤醒后虽然进行了下载动作但没有得到正确的响应。把这两个异常点放回设备树和电源管理框架里看思路就清晰了这不是一个设备的问题而是多个设备之间、以及设备与电源域之间的恢复顺序问题。3. 根因分析多媒体设备为什么唤醒后“永久”失效3.1 底层状态恢复的“时序错位”STR唤醒后Linux内核会依次执行每个设备的resume回调但这个“依次”并不是完全按照我们想要的外设依赖顺序来执行的。内核会参考设备树中的phandle、power-domains、clocks、regulators等属性来建立依赖关系但车机BSP里很多外设都是通过GPIO控制的没有在设备树中显式声明和PMIC regulator之间的供电依赖导致恢复顺序变成“谁注册得早谁先恢复”。在我们的平台上摄像头和DSP所依赖的regulator属于PMIC的某个LDO输出而控制这个LDO的驱动注册顺序排在摄像头和音频驱动之后。结果是唤醒时摄像头驱动先执行了resume读GPIO发现电源使能脚已经是高电平就去初始化I2C但实际上LDO的输出电压还没建立起来I2C设备自然不应答。这种情况在冷启动时不会出现因为冷启动时整个电源域是同时上电的不会有人去检查时序但在STR唤醒时这种“先设备后电源”的时序错位就被放大了。3.2 用户态服务对失败的“永久缓存”底层设备没恢复是一方面但真正导致“永久失效”的其实是上层服务对这个失败的处理方式。在Android 10之后的高版本系统上CameraProvider是独立的vendor进程它启动时会枚举所有摄像头设备并缓存设备信息。当唤醒后第一次openCamera失败Provider会把对应的CameraDevice标记为error状态之后无论上层怎么调用它都会直接返回错误而不会重新去探测底层设备。音频这边也类似AudioFlinger的RecordThread在打开输入流失败后会进入一个错误状态唤醒词引擎检测到这个失败后会直接关闭自己而不会周期性重试。这种现象本质上是一种错误缓存。硬件可能已经恢复了但软件仍然固守着自己的失败状态必须重启进程才能让它们重新探测一次。所以这也就是为什么不管你在上层怎么杀应用、怎么清后台都没有用必须要重启整套vendor相关服务或者整个系统。3.3 语音与相机同时坏为什么不是巧合这次问题的排查中语音和相机同时失效并不是偶然而是因为它们共享了同一个PMIC电源轨。看硬件设计图发现摄像头模组的模拟供电、ISP的IO供电、DSP唤醒词引擎的电源轨全部挂在同一颗LDO的输出上。STR唤醒时这颗LDO恢复慢直接导致两条硬件链路同时受影响。还有一个隐蔽的共享点是DSP固件下载使用的DMA/内存映射区域和ISP的IOMMU区域在物理上属于同一块内存控制器域。电源没恢复好时IOMMU的映射关系也可能丢失导致DSP固件加载时SMMU页面错误。这类问题用“共享资源”的角度去看就能解释为什么看起来完全不相干的设备会一起挂掉。后面排查其他平台问题时我养成了一个习惯先看有没有共用的regulator、GPIO、时钟或内存域很多时候能直接指向根因。4. 修复方案一驱动层恢复完整上电序列4.1 设计思路把“probe”重新做一遍既然根因是驱动resume时没有执行“完整的上电初始化序列”那最直接的修复方式就是修改驱动让它在resume回调里重新执行一遍类似probe阶段的上电流程。这里的重点不是简单拉一个GPIO而是要把供电、时钟、复位、I2C枚举、固件下载这些步骤按顺序补全。我在这个方案里给摄像头驱动补了一套resume_media_power_sequence大致的逻辑是先通过regulator框架把相关LDO重新enable然后等20毫秒让电源稳定再通知时钟框架使能MCLK最后再去做sensor ID的重新读取。实际分析完寄存器后发现还需要把sensor的reset脚先拉低再拉高一次才能保证sensor状态机复位干净。4.2 关键实现以摄像头驱动为例代码片段可以说明问题下面这个函数是我们在摄像头驱动的resume_early阶段调用的static int cam_sensor_resume_sequence(struct device *dev) { struct cam_sensor_ctrl_t *s_ctrl dev_get_drvdata(dev); int rc; /* 1. 恢复供电域 */ rc regulator_bulk_enable(s_ctrl-num_regs, s_ctrl-regs); if (rc 0) { dev_err(dev, regulator enable failed, rc%d\n, rc); return rc; } /* 2. 等待电源稳定这里必须延时否则后续读取sensor ID会超时 */ usleep_range(20000, 25000); /* 3. 恢复MCLK */ rc clk_prepare_enable(s_ctrl-mclk); if (rc 0) { dev_err(dev, mclk enable failed, rc%d\n, rc); return rc; } /* 4. 复位Sensor先拉低再拉高 */ gpiod_set_value_cansleep(s_ctrl-reset_gpio, 0); usleep_range(5000, 6000); gpiod_set_value_cansleep(s_ctrl-reset_gpio, 1); usleep_range(10000, 12000); /* 5. 重新初始化CCI并读取sensor ID */ cci_init(s_ctrl-cci_client); rc cam_sensor_read_id(s_ctrl); if (rc 0) { dev_err(dev, sensor ID read failed after resume, rc%d\n, rc); return rc; } dev_info(dev, sensor resumed, id0x%02x\n, s_ctrl-sensor_id); return 0; }音频DSP驱动那边修复思路相同但重点是补了固件重新下载的触发条件。由于DSP有自己的状态寄存器我让驱动在resume后先读一次状态发现固件未加载或校验失败时主动调用snd_audio_dsp_fw_download重新下载固件而不是像原来那样跳过下载。4.3 修复效果与需要注意的点方案一修复后唤醒后立刻打开相机和语音都能正常使用连续100次STR唤醒回归测试没有出现一次复现。这个修复从根本上解决了问题对功耗和唤醒时间的影响也很小。但要注意驱动层修复有两个门槛一是你需要拿到对应平台的BSP源码和硬件手册特别是平台提供方SoC厂商的电源树和DP状态说明不然很容易改错寄存器二是改动驱动层风险较高回归测试周期长生产环境里如果final的固件已经封版走这个方案的流程成本会比较大。还有一个容易踩的坑不要在resume回调里做太重的操作。resume阶段如果耗时太久Android系统的屏幕亮起、ServiceManager恢复都会卡住用户会感觉唤醒变慢。我当时把I2C重枚举和固件下载这类耗时操作放到了resume阶段的workqueue里执行保证resume本身能快速返回同时通过完成量等待这些初始化全部结束之后再往上抛状态。5. 修复方案二框架层重初始化兜底5.1 设计思路不动驱动也要让系统自愈驱动层修复很美好但在一些项目里你根本改不了驱动芯片厂商的BSP是黑盒或者final阶段的固件已经被锁定。这种时候我们需要一个框架层的兜底方案目标是让系统在唤醒后检测到多媒体设备异常时主动去触发服务重启或HAL重载绕开“错误状态缓存”的问题。这个方案的逻辑可以简单概括成一句话我不保证硬件在唤醒瞬间一定恢复但我保证系统在检测到故障后有能力自愈。把“永久失效”变成“短暂不可用后自动恢复”对用户来说体验就完全不同了。5.2 实现路径监听唤醒广播并触发服务重建我这里提供一种比较通用的实现通过监听系统的power mode变化广播在唤醒后延迟几秒主动检测摄像头和录音设备状态发现异常就通过setprop触发init重启对应的vendor服务。先写一个系统级BroadcastReceiver或者在SystemServer里注册一个PowerManager的Callback。我这里用一个更通用的Receiver写法public class MediaSelfHealReceiver extends BroadcastReceiver { private static final String TAG MediaSelfHeal; Override public void onReceive(Context context, Intent intent) { String action intent.getAction(); if (!Intent.ACTION_POWER_CONNECTED.equals(action) !android.intent.action.POWER_MODE_CHANGED.equals(action)) { return; } // 唤醒后不能立刻做检测等系统各项服务完全就绪 HandlerThread ht new HandlerThread(self-heal); ht.start(); Handler handler new Handler(ht.getLooper()); handler.postDelayed(new Runnable() { Override public void run() { checkAndHeal(context); } }, 5000); } private void checkAndHeal(Context context) { CameraManager cm (CameraManager) context.getSystemService(Context.CAMERA_SERVICE); if (cm ! null) { try { String[] ids cm.getCameraIdList(); Log.i(TAG, camera ids: ids.length); return; } catch (CameraAccessException e) { Log.e(TAG, camera not available, restart camera provider); // 触发vendor服务重启等价于adb shell setprop ctl.restart vendor.camera-provider SystemProperties.set(ctl.restart, vendor.camera-provider); } } AudioManager am (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); if (am ! null) { // 检测录音通路可以用AudioRecord短暂打开再释放 boolean micOk checkMic(); if (!micOk) { SystemProperties.set(ctl.restart, vendor.audio-hal); } } } }在init.rc里除了需要定义该服务还可以通过property触发状态回复指令。如果你用的平台支持也可以直接在shell层面快速验证adb shell setprop ctl.restart vendor.camera-provider adb shell setprop ctl.restart vendor.audio-hal5.3 这个方案的副作用方案二最大的问题在于重启服务的过程中正在使用相机的用户会看到画面中断或应用闪退正在通话的用户可能听到几秒钟的断续。所以重启动作一定要做防抖并且要带策略比如可以优先尝试恢复音频路由不行再重启audio HAL相机那边可以先杀CameraProvider再拉起要比直接重启整个audioserver轻量得多。另外一个需要注意的点是如果DSP固件恢复存在竞态重启服务的同时底层电源还在初始化可能导致服务启动后仍然打开失败。稳妥的做法是加上重试逻辑每次启动间隔给足时间不要一次性疯狂重置服务。我在项目里虽然用方案二做了临时止血但也同步push了驱动侧的修复最终让方案二退居为长期防御机制。6. 两种方案横向对比与选型建议6.1 优缺点对照表两种方案从原理、成本和实际效果来说各有优劣这里整理成一个表格方便在项目评审时直接参考维度方案一驱动层恢复上电序列方案二框架层重初始化兜底修复层级内核驱动 / BSPAndroid framework / 服务问题根除程度彻底解决硬件恢复时序问题不能修根因只做到自愈用户可见影响几乎无感知唤醒时间基本不变重启服务期间可能有短暂黑屏或卡顿开发成本较高需要驱动源码和硬件手册较低Java/Binder层即可完成依赖条件需要厂商BSP开放程度足够只需系统权限平台无关回归测试范围全设备STR、功耗、内存稳定性多媒体功能、服务重启稳定性适用场景发版前窗口大、能改驱动的项目固件锁定、需要紧急止血的场景6.2 不同项目阶段怎么选如果你还在项目的BSP调试阶段强烈建议优先上方案一。根因明确又是电源时序问题拖到后期只会被更多上层问题掩盖。如果你的项目已经到了交付阶段final固件不能大改那方案二是比较现实的止血方式。我自己在实际项目里选择了组合方案音频DSP驱动改动较小直接按方案一改了固件重下载相机因为涉及ISP和CameraProvider两层临时先用方案二兜底同时协调SoC厂商更新BSP。这套组合拳在项目里跑了两轮完整验证后续没有收到复现报告。需要强调的是无论选择哪种方案都要先拉通硬件、BSP、framework三个角色的评审。STR唤醒后的行为不只是软件问题硬件上复位脚和电源轨的设计方式也直接决定修复的可靠性。7. 验证方法、回归测试与后续优化7.1 休眠唤醒自动化回归脚本修复完成之后的验证比修复本身更重要因为这个Bug是低频高影响的类型手动测试根本无法覆盖完整的回归量。我写了一个简单的Shell脚本循环执行STR休眠和唤醒操作并在唤醒后主动打开相机和录音收集结果。#!/system/bin/sh COUNT100 FAIL0 for i in $(seq 1 $COUNT) do echo STR loop $i # 拉低屏幕背光模拟进入挂起前状态 input keyevent 26 sleep 3 # 直接写入系统电源节点触发STR echo mem /sys/power/state # 等待挂起和唤醒周期完成 sleep 15 # 唤醒后延迟几秒让用户态服务恢复 input keyevent KEYCODE_WAKEUP sleep 8 # 测试相机是否能出帧 if ! v4l2-ctl -d /dev/video0 --stream-mmap --stream-count3; then echo camera stream failed at loop $i FAIL$((FAIL1)) fi # 测试录音通路是否有数据 tinycap /data/local/tmp/test_$i.wav -D 0 -d 0 -c 2 -r 48000 -b 16 -T 2 SIZE$(stat -c%s /data/local/tmp/test_$i.wav 2/dev/null || echo 0) echo capture size: $SIZE done echo total loops: $COUNT, failed: $FAIL这个脚本看起来简单但里面有几个关键参数需要根据项目调整。/sys/power/state的路径和触发方式是内核配置决定的部分平台需要mem_sleep设置为s2idle或deep才能正确进入STRv4l2-ctl的--stream-count不能设置太大否则会拖慢整个循环。脚本里的每次录音文件我保留了原始数据方便排查时直接看是“无数据”还是“有噪声”。7.2 相机与语音功能专项验证自动化脚本只能验证底层链路是否通但真实用户场景里的相机预览、拍照、录像、人像模式、语音识别语义理解这些功能还是需要手动测试。我的建议是分三级验证第一级是底层链路验证用V4L2和tinycap确认设备能出数据第二级是Android接口验证写一个测试APK循环调用Camera2的openCamera、createCaptureSession和AudioRecord的read方法第三级是全流程验证找测试人员按用户习惯连续操作相机和语音助手确认没有界面卡顿、没有ANR、没有低概率复现。在Camera2接口测试里有个容易忽略的参数是CameraDevice.StateCallback和CaptureSession.StateCallback。因为STR唤醒后系统可能没有立即投递回调测试时务必用带超时的CountDownLatch等待回调避免测试程序自己先超时误判系统故障CountDownLatch latch new CountDownLatch(1); cameraManager.openCamera(cameraId, new CameraDevice.StateCallback() { Override public void onOpened(CameraDevice camera) { latch.countDown(); } Override public void onDisconnected(CameraDevice camera) { latch.countDown(); } Override public void onError(CameraDevice camera, int error) { latch.countDown(); } }, handler); if (!latch.await(5, TimeUnit.SECONDS)) { throw new AssertionError(camera open callback timeout); }7.3 功耗与稳定性监测STR相关的修复最担心两件事一是挂起电流变大导致整车亏电二是唤醒后某个设备没有完全进入低功耗状态导致持续耗电。所以在功能回归通过后还需要做一轮功耗专项测试。功耗测量的方法是在车载电源线上串接高精度电流计分别记录冷启动待机电流、STR挂起电流、唤醒后待机电流。正常的车机STR挂起电流一般在几毫安到几十毫安级别具体数值取决于车载网络和常电设备数量。如果修复后挂起电流比修复前明显增大很可能某个传感器的电源在suspend阶段没有被正常切断需要回到suspend回调里检查。稳定性方面我会在测试机上跑100次循环STR唤醒同时用dmesg -w持续记录内核日志确保没有suspend失败、regulator错误、IOMMU错误这些隐藏问题。还要测试边充电边STR唤醒的场景因为充电状态下PMIC的行为和电池状态不同电源轨上电时序会有差异这个场景容易暴露新的时序问题。8. 排查中踩过的坑与实战经验8.1 别被logcat的表象带偏最开始看到logcat里CameraService报error state我下意识以为是Camera HAL进程崩溃或者被LMK杀掉花了大量时间去看服务的启动和重启逻辑完全没怀疑底层驱动。直到后来在dmesg里看到I2C timeout和DSP fw下载失败才意识到问题在底层。这类问题里logcat只是表象真正的根因往往在更底层的那一层一定要先分清“设备没恢复”和“服务没恢复”。8.2 一定要保留正常唤醒日志做对比排查这类间歇性问题最大的困难是没有一个明确的“错误行”可以单点断句。如果你手里只有一份坏日志很多看起来异常但不致命的报错会干扰判断但如果你有一份正常唤醒的日志做对照每一处差异都会变得异常显眼。我在项目里让测试同事每轮测试前都先执行一次唤醒并抓取日志这个习惯让后续的根因定位快了很多。8.3 设备树里看不到的依赖要主动找硬件确认设备树里没有声明不代表依赖不存在。我们的设备树里camera和audio完全独立谁也想不到它们会共享同一个LDO。后面我把硬件原理图调出来看才发现PMIC输出的某一路LDO同时给sensor、ISP和DSP部分供电。在排查嵌入式系统问题时软件日志只是参考硬件原理图才是最终的“上帝视角”。建议在STR问题排查初期就把硬件同事拉上直接确认电源树和复位信号的连接关系能省掉至少一半的弯路。8.4 最后再说一个有效的小习惯我后来在每个车机项目的测试机上都会预置一个抓取完整诊断信息的脚本触发一次就同时抓取dmesg、logcat、power节点的状态、所有regulator状态、时钟状态和固件版本。这个习惯在这次排查中帮了大忙因为很多关键信息在修复后的重启过程中会被覆盖掉有脚本才能保证在问题复现的第一时间留下证据。做STR这类涉及多模块联动的问题日志的完整性和抓取时机经常比你的分析能力更决定排查效率。
返回列表