ARTICLE DETAIL

资讯详情

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

Android 12高通平台thermal-engine日志开启与CPU降频排查实战

Android 12高通平台thermal-engine日志开启与CPU降频排查实战 做高通平台性能调试的兄弟十有八九都跟 thermal-engine 打过交道。用户反馈“跑分一上强度就锁频”“游戏到后半程帧率掉一半”下意识第一反应都是去拉 thermal 日志结果发现默认日志被压得死死的什么都看不到只能干瞪眼。这种情况在 Android 12 的高通平台上尤其常见AOSP 和 CAF kernel 对热管理链路做了一轮调整日志开关、节点权限、Selinux 策略全变了老经验经常不好使。这篇东西就从我的实战视角把 Android 12 高通平台上 thermal-engine 的 debug 日志打开方式完整捋一遍再顺着日志教你怎么定位 CPU 降频的真正根因。整个过程不涉及玄学全是能直接落地复现的命令、配置和排查思路。适合 BSP、底层驱动、性能功耗组的工程师自己刷机的玩家也能照葫芦画瓢。1. 先把问题框定Android 12高通平台thermal-engine到底在干什么1.1 一段代码定位thermal-engine的前世今生thermal-engine 是高通私有的一套用户态热管理守护进程一般跑在/vendor/bin/thermal-engine它不属于 AOSP 原生代码而是在 CAFCode Aurora Forum的 vendor/qcom/proprietary/thermal 目录下面维护。从 Android 8 开始高通平台上的热管理主路径就分化成两套老一些的方案继续用 thermal-engine新平台慢慢迁到 thermal-halThermal HAL 2.0 的 vendor 实现。但到今天大量在产的高通手机、平板、IoT 设备和车机项目仍然在用 thermal-engine或者叠加了 thermal-hal 做迁移兼容。标题既然点名 thermal-engine我们就聚焦这套体系。搞清楚它是什么才能理解后面所有调试动作的意义。thermal-engine 做的是多传感器融合和策略控制内核侧的 TSENSthermal sensor温度传感器和各类 ADC 通道不断上报温度thermal-engine 通过 netlink 或轮询拿到这些温度后再对照配置文件里预先定义的策略表决定要不要限 CPU、降 GPU、控充电电流、开风扇。我用一个生活化的比喻整个系统就像一栋大楼的中央空调。温度传感器是装在每个房间的温度计cpufreq 是制冷功率thermal-engine 就是物业的中控室。它看到某层楼超过 28 度就开始关掉一部分空调功率避免整栋楼跳闸。如果你不小心把中控室的监控屏关掉了空调照样会动作只是没人知道它为什么动作这就是我们调试时最痛苦的地方。1.2 降频不是玄学thermal-engine的决策链路CPU 降频的直接操作者往往不是 thermal-engine 本身而是内核的 cpufreq 驱动和 cooling device冷却设备。thermal-engine 的决策链路大体是这样的传感器读数通过 IIO 或平台驱动进入 sysfs比如/sys/class/thermal/thermal_zone*/temp和 tsens 调试节点thermal-engine 从内核获取温度变化事件结合配置文件里配置的 sensor 阈值threshold和 hysteresis迟滞触发策略策略触发后thermal-engine 通过cooling device接口比如 cpufreq cooling、regulator cooling下发约束常见表现为写/sys/devices/system/cpu/cpu*/cpufreq/scaling_max_freq或通过 msm-thermal 提供的 sysfs 接口降频内核最终在 cpufreq governor如 schedutil、walt调度频率时把 thermal 的限制一并考虑进去。所以当你看到 CPU 频率被压在某个频率上不去首先不能默认是 thermal-engine 的锅也有可能是 cpufreq governor 的调频策略、其它进程的 power hint、低电量限频、甚至是 GPU 抢功耗。能第一时间排除这些干扰项的就是一份完整的 thermal debug 日志。1.3 为什么Android 12上调试方式变了Android 12 相比之前在热管理上做了一些调整最明显的是 AOSP 提高了 system server 里热服务ThermalManagerService的参与度并且强化了 thermal HAL 与框架层的回调链路。但对 thermal-engine 方案来说感知最强的其实是两点第一Selinux 策略收紧了。Android 12 开始很多 vendor 节点默认只能由特定 domain 访问非 root 状态下去 cat 某些 sensor 节点会被直接拦截logcat 里会报avc: denied。因此调试的前提是手上有 userdebug 或 eng 版本并且必要时能临时setenforce 0。第二日志属性名不规范。高通各 release 对 thermal 的 debug 开关键名并不统一有些是persist.vendor.thermal.debug有些是vendor.debug.thermal还见过直接编译期写死的版本。如果你遇到设置属性后毫无反应先别急着怀疑自己很可能只是平台改键名了。2. 调试前的准备工具链、代码路径和环境配置2.1 必备工具和平台代码干这个活儿我的常备工具不多但少了哪个都难受adb / fastboot并建议配好 udev 规则免得频繁弹权限serial console串口虽然大多数场景 adb 足够但在 thermal 导致系统睡死或者 kernel panic 场景下串口的 kernel log 是最可靠的对应平台的代码环境至少要能拿到 vendor/qcom/proprietary/thermal 和 CAF kernel 两份代码如果是商用项目直接找你们 BSP 团队要 release tag 对应的 git 仓库地址比自己在网上大海捞针靠谱得多一台能跑起来的 Ubuntu 编译机器用来单独编译 thermal-engine 模块或者至少能解包/重打包 vendor 镜像。拿到代码后我的习惯是先确认版本打开thermal-engine/Android.bp或thermal-engine/Android.mk看依赖了哪些库、目标名是什么。再看代码目录下有哪些模块名。不同平台把 thermal-engine、thermal-daemon、thermal-hal 打包成不同 target搞错目标名会浪费很多时间。2.2 关键节点和配置文件开调之前先花五分钟把下面这些关键路径梳理清楚后面排查起来心里有底类型路径 / 节点说明主程序/vendor/bin/thermal-engine用户态守护进程本体配置文件/vendor/etc/thermal-engine.conf策略配置不同项目可能改名为 thermal_engine_config运行时数据目录/data/vendor/thermal/日志文件一般落在这里需 root 查看内核温度节点/sys/class/thermal/thermal_zone*/temp与type每类 sensor 对应一个 zone温度单位 m℃tsens 调试节点/sys/kernel/debug/tsens/需 root 和 debugfs 挂载可看各传感器即时温度CPU 频率节点/sys/devices/system/cpu/cpu*/cpufreq/scaling_max_freq等观察当前频率上限和被谁限制日志开关属性persist.vendor.thermal.debug等用 getprop怎么快速定位配置文件到底在哪个目录一条命令解决adb root adb shell find /vendor/etc /system/etc /data/vendor -iname *thermal* -type f 2/dev/null命中的文件里重点看.conf或者.xml结尾的那个这基本就是策略配置。如果找不到先用ps -A | grep thermal确认进程的启动参数再看它的启动命令里有没有指定配置文件路径。2.3 环境变量与编译配置如果项目需要在本地编译 thermal-engine我一般不用整包编译单独编模块更快。比如在 CAF 环境下source build/envsetup.sh lunch your-product-userdebug cd vendor/qcom/proprietary/thermal mma -j$(nproc)编完后产物在$OUT/vendor/bin/thermal-engine和对应的.so通过 adb push 到设备后先adb shell chmod 755 /vendor/bin/thermal-engine再 kill 掉旧进程让 init 拉起来。当然这个做法要求你的设备已经 root并且关闭了验证启动AVB否则 /vendor 分区只读push 不进去。如果只是想快速验证配置文件里某个阈值不需要重新编译直接 push 一个改好的 thermal-engine.conf 到 /data/vendor/etc具体路径看平台然后设置setprop ctl.restart thermal-engine重启进程即可。注意 Android 12 上ctl.restart的使用经常会被权限拦必要时用stop thermal-engine start thermal-engine。3. 实操如何快速开启debug日志3.1 动态开关不用重新编译就能打开日志这是我日常最常用的方式因为不用动镜像也不影响编译流程现场调试响应最快。整体分三步第一步找到当前平台的 debug 属性键名。不同 release 实在不统一先跑一条adb shell getprop | grep -iE thermal|debug重点看有没有persist.vendor.thermal.debug、persist.vendor.thermal.log、vendor.thermal.debug这类键。如果找到了直接设置成 1 或 trueadb shell setprop persist.vendor.thermal.debug 1 adb shell setprop persist.vendor.thermal.log 1第二步确认属性生效。部分平台的 thermal-engine 只在上电启动时读取一次属性改完属性后进程不会自动感知需要手动重启 thermal-engine。adb shell stop thermal-engine adb shell start thermal-engine如果stop权限被拒可以直接 kill 进程Android init 会自动拉起adb shell kill $(pidof thermal-engine)第三步验证日志是否落盘。绝大多数方案会把日志输出到/data/vendor/thermal/目录下常见的日志文件有thermal-engine.log、thermal-daemon.log部分平台会多一个thermal-cpu.log。用adb shell ls -l /data/vendor/thermal/查看文件大小和时间戳如果时间戳在重启进程后更新了说明日志开关已经生效。有一个坑需要特别提醒persist.*属性在重启后依然保留但你在调试完之后如果不改回来后续测试机连续跑几天这个日志文件会一直膨胀最终占满 /data 分区。所以调完一定要清理属性。3.2 静态修改改配置、改代码、重编如果动态开关打开了还是看不到日志那就得走静态修改路线了。先看配置文件不同平台的 thermal-engine.conf 里会有一组跟日志或调试相关的选项。常见的有[THERMAL_ENGINE]段下的logging_enabledDEBUG/VERBOSE/TRACE级别参数log_period、log_time等控制日志频率的参数。举个例子很多项目会在配置里写[THERMAL_ENGINE] logging_enabled true log_level TRACE如果你把log_level改成TRACE后依然没日志就去代码里找硬编码的日志开关。高通 thermal-engine 代码里常见的宏是THERMAL_ENGINE_DEBUG搜一下msg()、debug_log()的调用条件。然后打开它#ifdef THERMAL_ENGINE_DEBUG debug_msg(TRUE, sensor%s temp%d, sensor_name, temp); #endif把它改成强制输出或者定义对应的宏重新编译模块。这种做法适合问题复现条件苛刻的场景因为你能把日志打到源码最细节的位置包括每个 sensor 进入 trip 点的前后状态。3.3 两种日志视角logcat和内核同时抓thermal-engine 是用户态进程它的日志不一定只写文件很多版本同时支持 logcat 输出。开启方式通常是adb logcat -c adb logcat -s thermal:V thermal-engine:V如果你发现 logcat 没有任何 thermal 相关输出不要死磕多半是代码只在文件描述符里写。直接切到/data/vendor/thermal/看文件更靠谱。但只看用户态日志还远远不够。thermal-engine 报出的温度是否真实、内核有没有偷偷执行其它限频动作最终都要靠 kernel log 交叉验证。所以我会同时开三个终端# 终端一实时看 thermal-engine 日志文件尾部 adb shell tail -f /data/vendor/thermal/thermal-engine.log # 终端二实时看内核热相关日志 adb shell dmesg -w # 终端三实时看 CPU 频率和温度节点 adb shell watch -n 0.5 cat /sys/devices/system/cpu/cpu4/cpufreq/scaling_cur_freq /sys/class/thermal/thermal_zone*/temp三端同时看基本能定位到是“thermal-engine 主动限频”还是“内核侧被动限频”这是排查降频问题最关键的一步。3.4 高负载场景用Perfetto抓频率状态长图如果问题只在高负载游戏场景出现单纯靠 tail 日志很难还原频率变化曲线。这时候我建议用 PerfettoAndroid 12 自带抓一段长 trace重点看cpu.frequency、thermal和cpufreq三条轨道adb shell perfetto -o /data/misc/perfetto-traces/trace.perfetto-trace \ -c /data/misc/perfetto-traces/config.pb \ -w 120s配置里要开启 Linux ftrace 的 power 相关 category否则抓不到 cpufreq 切换事件。抓完拉到本地用 Perfetto UI 打开把 CPU 频率轨道和 thermal 事件叠在一起看如果频率跌落的瞬间对应某个 sensor 的温度变化十有八九就是温控策略命中如果频率跌落的瞬间没有温度触发那就得去查 power hint 或 cpufreq governor 自己做的调频。这里分享一个经验不要只抓一次 trace。负载场景最好复跑三次第一次用原始配置第二次把散热条件改善比如拆机加风扇第三次把 thermal-engine 直接停掉。三次对比能快速判断降频到底是温控主导还是 SystemUI 的省电策略主导。4. 排查实战从日志到CPU降频根因的定位方法4.1 第一个案例跑分一开CPU就被限制到最低频有次碰到一台工程机跑 AnTuTu 大核只能到最低频 300MHz整机卡成幻灯片。一开始大家以为是 thermald 配置写错把温度阈值设得太低了但看了 thermal-engine 日志后发现有意思的现象CPU 温度其实只有 36℃根本没有摸到阈值但日志里反复出现某个 sensor 的名字触发了cpu_cooling的 high trip。日志大概是这样的[TRACE] sensor tsens_tz_sensor10 temp91000 throttle1 [TEMP] sensor tsens_tz_sensor10 max91000 min36000 avg54000 [TRIP] tsens_tz_sensor10 high trip 90000, actionCPU_COOLINGsensor10 显示的是 91℃而平台其它传感器都很凉快。顺着/sys/kernel/debug/tsens/去查 tsens_tz_sensor10 对应的物理位置发现它是 CPU 内部某一路温度传感器不同平台代号不同怀疑是散热硅脂没贴好导致局部热点或者就是传感器单片本身有偏差。处理方式分两种如果在开发阶段可以先做板级散热确认重新贴合导热材料后再复测如果散热没问题、传感器确实有偏差就在 thermal-engine.conf 里对这个 sensor 做 offset 修正或者直接把它的 high trip 阈值抬高。改配置的格式因平台而异但大思路是一致的把某个 sensor 的温度修正到一个合理范围再配一个合理的 hysteresis迟滞避免阈值来回抖动。这个案例给我的教训是降频不一定因为整体温度高一个局部传感器的假高温就能把 CPU 锁死。所以排查热问题绝对不能只看 CPU 温度一定要把 readable 的 sensor 全部打出来。4.2 第二个案例sensor读到0或异常值导致策略误判有些时候传感器读数不是偏高而是直接读到 0。别以为读 0 就没问题thermal-engine 的策略引擎如果做了归一化或平均值计算一个非法 0 会直接把平均温度拉低导致真正的温控失效。而反过来如果策略里对 sensor 异常有惩罚逻辑读到 0 也可能被判定为传感器故障进而触发保守策略直接把频率限制到很低。有个印象很深的 case某平台 battery 温度传感器在某些低温环境下会读到 -40℃读数为 -40000 或者 0底层策略认为电池温度不可信直接切到最大降频保护模式整机 CPU 锁到低频率。从 thermal-engine 日志里可以看到这种特征[ERR] sensor battery_temp read fail, use default value! [WARN] sensor battery_temp value invalid, fallback [TRIP] battery_temp invalid - max cooling action!这类问题的解决方向有两个一是检查 sensor 驱动和硬件上拉/滤波电路确认是不是信号稳定性问题二是在配置里将非法值处理策略改为“丢弃”而不是“fallback 到最高保护”。但强烈不建议在没有硬件确认的情况下动第二条万一电池真的过热保护没了会出安全事故。4.3 第三个案例thermal日志干净CPU还是被降频这个案例最坑。现象是跑王者荣耀时频率周期性掉落用户体感卡顿但 thermal-engine 日志里一条 trip 都没有kernel log 里也没看到 tsens 告警。这时候就要怀疑根本不是 thermal-engine 干的事。我的排查路径是先用 Perfetto 抓 trace发现每个频率回落点之前power HAL或者perf HAL有一个 event 出现频率被某个进程通过QoS request拉低。继续查发现是某厂商的 game mode 服务在检测到功耗超过阈值后主动向 perfd 请求限频把大核从 2.8GHz 限制到了 1.7GHz。这是在用户态做功耗墙不是 thermal 层级的动作。处理方式是要在 perf 配置里调整功耗预算或者让游戏模式服务不要对 CPU 频率做这么激进的收敛。这个 case 告诉我们CPU 降频有三大类来源——thermal、power/perf HAL、cpufreq governor 自身策略。千万不要因为项目标题里写了 thermal-engine就把所有降频都归罪于它。日志能帮你排除掉最明显的嫌疑但最终定位还是要结合 trace 和多端日志交叉验证。4.4 如何量化降频影响写一个节点监控脚本定位完根因之后我们还得向产品、测试、项目经理证明“降频到底影响了多少性能”。我习惯写一个轻量 shell 脚本持续采样关键节点然后导成 CSV计算降频持续时间和幅度。#!/system/bin/sh # /data/local/tmp/monitor_thermal.sh LOG_DIR/data/local/tmp/monitor mkdir -p $LOG_DIR : $LOG_DIR/cpu_temp.csv while true; do TIME$(date %s) TEMP$(cat /sys/class/thermal/thermal_zone*/temp 2/dev/null | tr \n ,) FREQ$(cat /sys/devices/system/cpu/cpu?/cpufreq/scaling_cur_freq 2/dev/null | tr \n ,) FMAX$(cat /sys/devices/system/cpu/cpu?/cpufreq/scaling_max_freq 2/dev/null | tr \n ,) echo $TIME,$TEMP,$FREQ,$FMAX $LOG_DIR/cpu_temp.csv sleep 0.5 done这个脚本跑几分钟后把 CSV 拉到 PC 上用 Excel 或 Python 画曲线可以直观看到温度上升和频率跌落的时间对应关系。我个人实测下来0.5 秒的采样间隔在绝大多数场景足够太频繁反而会因为cat本身占用 CPU 影响测试结果。5. 常见问题与避坑指南实录版5.1 常见问题速查表现象可能原因解决方向设置属性后无日志生成键名不对进程未重启Selinux 拦截搜全部属性确认键名重启 thermal-engine必要时 setenforce 0日志文件一直不更新日志级别太低写到了 logcat 而不是文件改配置 log_level用 logcat 侧观察修改配置文件不生效路径不对缓存进程未重启用 find 确认实际配置文件路径kill 进程让 init 重启日志里温度全部为 0debugfs 未挂载权限不足driver 未初始化先mount -t debugfs none /sys/kernel/debug再检查 sensor probeCPU 降频但 thermal 日志里无 trip不是 thermal 导致抓 perfetto查 perf HAL / power HAL / governorpush /vendor 失败AVB 验证、分区只读关闭验证启动或改 push 到 /data 后 symlink仅支持部分平台debug 日志把 /data 写满日志无滚动机制长时间开启调完立刻关属性定期清理日志文件5.2 几条调试顺序建议第一先看 kernel dmesg 再看用户态日志。dmesg 里如果已经有tsens_tz_sensor的警告说明问题在驱动层就已经暴露用户态分析只是确认一遍。不要一上来就翻 conf 文件顺序反了容易把自己的思路带偏。第二长时间抓日志要考虑存储压力。曾经有一台测试机连续开 debug 日志跑了一晚上第二天发现 /data/vendor/thermal 目录下日志文件已经好几个 GB直接把系统拖卡了。调试要带着“及时清理”的意识并且尽量在复现完问题后第一时间把日志拉走。第三跟 MTK 平台的对比建议。做过多平台项目的都知道MTK 的 thermal 是内核态为主、用户态配置为辅而高通传统方案是用户态 thermal-engine 主导。所以拿到一台新平台设备第一件事不是找“通用”的降频定位方法而是先确认当前平台热管理的主体是谁。一个平台上好用的命令放到另一个平台上可能就是无效的。第四改任何配置前先备份原文件。这个大家都会嫌啰嗦但我确实见过不止一次有人把 conf 改坏导致 thermal-engine 起不来板子温度失控自动关机最后又找不到原始配置。宁可先cp thermal-engine.conf thermal-engine.conf.bak再动手改。第五日志确实打不开时优先怀疑 Selinux。Android 12 上很多调试节点和日志文件都需要特定 SELinux label。临时setenforce 0是最快的验证手段但务必记得调回setenforce 1我在开发板上忘过一次后面所有权限检查全失效被坑了一把。我在实际项目里体会最深的一点是thermal-engine 调试七成靠思路三成靠工具。日志开关只是把黑盒打开一条缝真正有价值的是你顺着这条缝把温度、频率、策略和执行路径完整串起来的能力。希望你把这套方法带进自己的项目里下次再遇到 CPU 降频能少走几条弯路。
返回列表