1. 先看准 thermal-engine 的完整链路配置才不会瞎改这几年给好几台骁龙平台设备调过散热策略有骁龙660、骁龙710也碰过835和865。说实话同一颗SoC装在不同牌子的手机上发热手感可以差非常多。原因一半在散热模组另一半就在/vendor/etc/thermal-engine.conf这个文件里。它不是很多朋友以为的“温度显示配置”而是高通热管理守护进程的核心决策表系统读哪些温度、算出什么热点、多大温度触发限制、CPU频率被压到多少全都由它决定。如果你只想稍微压低游戏时的温度或者反过来希望让温度墙松一点、把性能放出来改这个文件通常比刷内核更直接风险也相对可控。先把链路讲明白。thermal-engine是个常驻用户态守护进程和内核里的热驱动配合工作。内核负责把各个物理传感器的数据暴露到/sys/class/thermal/thermal_zone*/下面用户态守护进程周期性地读取这些温度值经过自身配置里的算法处理得到“当前设备热不热”的结论然后去写冷却设备的接口比如调低CPU最高频率、触发核心隔离、限制GPU频率等。整个过程可以拆成四层感知层物理传感器包括SoC内部的tsens温度节点、电池温度、充电IC温度、外壳热敏电阻等。计算层虚拟传感器把若干个物理量加工成“外温”“热点温度”这类不可直接测量的值。判断层算法根据虚拟传感器或物理传感器的数值决定当前进入哪一级温控状态。执行层冷却设备包括CPUfreq、CPU隔离、GPU限制、LCD背光降低等。很多朋友改配置时一上来就盯[VIRTUAL_SENSOR]或[ALGORITHM]里的数字忽略了整体结构结果改了之后要么完全不生效要么一进游戏就锁核卡成PPT。所以我建议你先理解整条链路再动数值。另外要提醒一点thermal-engine.conf不是Android标准接口每家用高通方案的厂商都会做二次开发字段名、段落名、甚至文件路径都可能不同。本文给的是一种通用语义层面的拆解你拿自己手机里的实际文件对照时会发现段名前缀可能有差异但“物理传感器、虚拟传感器、算法、冷却设备”这套结构基本不会跑偏。2. 物理传感器到虚拟传感器温度数据的两次加工2.1 物理传感器从 sysfs 读到的温度究竟长什么样物理传感器是温度数据的源头。高通的SoC内部一般有好几组tsens温度传感器分布在CPU大核、小核、GPU、DSP等区域附近。设备上还有电池温度、充电IC温度、无线充线圈温度等。这些传感器会被内核注册为一个个thermal zone暴露在/sys/class/thermal/thermal_zone*目录下。连接设备后可以用下面的命令快速看一眼cat /sys/class/thermal/thermal_zone0/type cat /sys/class/thermal/thermal_zone0/temptype文件告诉你这个zone是什么temp就是当前温度。这里有个非常容易看走眼的地方高通大部分温度节点的输出单位是“毫摄氏度”读出来47890代表47.89℃。但个别平台或个别节点可能直接输出摄氏度空载时温度显示30~100之间的整数那就是摄氏度格式如果是30000~100000这种四位以上数值就是毫摄氏度。我遇到过一个朋友把配置里的温度阈值从55000改成了55结果热管理从来没触发过因为守护进程拿到的物理量级是毫摄氏度55这个数值远远低于实际温度量级等于白改。所以改配置前先确认你手上设备到底用哪个单位。常见的物理传感器包括名称假设对应sysfs type典型用途tsens_tz_sensor0tsens_tz_sensor0CPU/SoC内部温度tsens_tz_sensor5tsens_tz_sensor5GPU或CPUSS附近温度bcl_socbattery电池电流限制相关batt_thermbattery电池热敏电阻chg_thermcharger充电IC温度skin_thermthermistor机身或外壳温度这些名称只是典型举例你机器上实际出现什么名字以thermal_zone*/type输出为准。物理传感器段在配置文件里的作用就是把这些sysfs节点名称和逻辑名称关联起来方便后面的虚拟传感器引用。2.2 虚拟传感器为什么要“无中生有”出一个温度虚拟传感器是thermal-engine配置里最有意思的部分。字面意思就是它不是一个真实的物理传感器而是根据多个物理输入计算出来的温度值。为什么要这么干因为芯片上很多位置的温度无法直接测量。比如“机身外壳温度”厂商不可能在每个外壳位置都放一个热敏电阻通常只在子板或边框放一两个。但温控策略需要的是“用户手感受到的温度”这时候就可以用CPU温度、电池温度、充电温度按一定权重合成一个“虚拟外壳温度”。再比如“SoC热点温度”CPU大核和小核温度可能差异很大单看某一个核容易误判断合成一个综合热点反而更稳定。虚拟传感器的作用是把物理层的零散读数变成策略层能用的几个核心指标。这样配置后面做温度判断时不需要面对十个原始传感器而是面对两三个虚拟传感器逻辑会清晰很多。合成虚拟传感器的三种常见算法是取多个传感器的最大值、按权重加权平均、在结果上加偏移量。取最大值适合用来做保护性判断比如任何一个核心过热就触发降频加权平均适合模拟一个区域的综合温度加偏移量适合把一个传感器硬性映射成另一个位置的估算值。2.3 温度数据的“滞后”设计配置里还有一个容易被忽略的概念温度滞后hysteresis。没有滞后的话温度到阈值就触发降频降下去之后温度稍微降一点又立刻恢复频率结果就是频率在短时间内反复横跳用户感受到的就是卡顿和帧率抖动。正确做法是触发降频用某个阈值恢复频率用另一个更低的阈值两者之间留出温差这个温差就是滞后。实际配置中滞后通常以两个参数出现一个是触发阈值一个是恢复阈值或者一个阈值加一个滞后值。我看到很多小白改配置时只关注降频阈值完全不设恢复阈值导致“频率过山车”频发。这个在后面写示例配置时还会具体演示。3. 配置语法逐段拆解传感器、算法、设备三大类段配置文件本体是INI风格的文本以#开头的是注释段落名用方括号包起来段落下面是一堆keyvalue。不同平台的段名前缀略有不同但大体上可以分成三类描述传感器的段、描述算法的段、描述冷却设备的段。3.1 传感器段把 sysfs 节点变成配置里的逻辑对象传感器段通常长这样[SENSOR_cpu0_temp] name tsens_tz_sensor0 polling_ms 1000这个段的意思是把tsens_tz_sensor0这个物理传感器在配置里命名为cpu0_temp并且每1000毫秒采样一次。polling_ms非常重要采样周期越短温控响应越及时但守护进程的CPU占用和功耗也会增加。默认1000毫秒比较保险如果希望温控更激进可以缩到500毫秒追求省电的话2000毫秒也可以只是温度突变时响应会慢半拍。有的配置里传感器段没有name字段而是直接把物理节点名当段名字段里只有enable和polling_ms。判断方法很简单看后面的虚拟传感器引用的是段名还是字段值。如果引用的是cpu0_temp说明配置用的是逻辑名如果引用的是tsens_tz_sensor0说明配置直接用物理名。3.2 虚拟传感器段定义计算规则虚拟传感器段一般长这样[VIRTUAL_SENSOR_soc_temp] name soc_temp algorithm WEIGHTED_AVG input cpu0_temp, cpu1_temp weights 60, 40 offset 0这里algorithm的值有几类可能WEIGHTED_AVG代表加权平均MAX代表取最大值MIN代表取最小值ADD_OFFSET代表在指定传感器上直接加偏移量。input字段填的是前面传感器段定义的逻辑名weights是对应权重offset是结果修正值。权重数值的具体含义不同平台有差异有的用百分数有的用千分数。稳妥做法是看配置里已有内容如果已经有vendor默认的虚拟传感器参考它权重的写法保持同样的数量级。3.3 算法段温度阈值与状态的对应关系算法段是温控策略的核心判断区常见的写法是[ALGORITHM_soc_throttle] input soc_temp algorithm LIMITS temperatures 55000, 60000, 70000 hysteresis 2000 action cpu_limiter, cpu_isolatetemperatures是一组阈值按从低到高排列。温度超过55000时进入第一级限制超过60000时进入第二级超过70000时进入第三级。hysteresis是滞后温度触发后要等温度回落到“当前阈值减滞后值”以下才能解除当前级别。这里我建议新手记住一个原则阈值之间至少留出10℃以上的间距。如果第一级55℃、第二级56℃、第三级57℃那任何轻微波动都会让系统飞速切换状态体验非常差。合理设计可能是55℃、65℃、75℃每级之间留10℃给散热硬件和系统调度都留出反应时间。3.4 冷却设备段最终动作落到 sysfs 节点上冷却设备段把算法段的动作映射到实际设备上[COOL_DEV_cpu_limiter] device cpufreq cluster_id 0 states 0, 1, 2, 3简单说这个段定义了一个名为cpu_limiter的冷却设备它控制的节点最终会通过内核的cpufreq冷却框架去限制CPU最高频率。states对应该设备支持的冷却等级0通常是不限制1、2、3依次对应更高的限制程度。高通平台里冷却设备最终的动作路径一般有两个一个是cpufreq冷却通过限制最高频率来降功耗一个是核心隔离直接让某个CPU核心离线。频率限制适合日常轻负载场景核心隔离适合极限游戏场景但核心隔离如果配置激进可能导致系统只剩小核在工作卡顿非常明显。4. CPU 频率控制是怎么被串起来的阈值、冷却等级与执行4.1 从温度到频率的完整链路CPU频率控制不会是“温度一高就直接锁频到最低”这种粗暴逻辑而是一级一级递进。以常见的双簇平台为例大核簇和小核簇分别有各自的频率策略。温度上来之后先是把大核最高频率从顶频降一档如果还压不住再降一档同时小核也可能跟着降到温度非常高时才考虑隔离核心。链路是这样的物理传感器提供原始温度 → 虚拟传感器合成热点温度 → 算法段判断当前应该进入第几级冷却状态 → 冷却设备段将等级映射到cpufreq的冷却等级 → 内核把对应等级转换成具体的最高频率限制。举个例子某平台大核最高频率是2.2GHzcpufreq冷却等级1对应最高1.8GHz等级2对应最高1.4GHz等级3对应最高902MHz。那么配置里定义好四档温度和四个冷却等级的对应关系系统就会按照“温度升档频率降、温度回落档位恢复”的节奏工作。4.2 频率映射表到底由谁决定这里要澄清一个容易误解的点thermal-engine.conf里通常不直接写“2.2GHz对应冷却等级0”这种映射。频率表由内核的cpufreq驱动和DeviceTree里的冷却设备定义决定。配置文件里定义的states数量必须和内核暴露的冷却等级数量对得上如果配置里写了3个等级但内核只有2个等级多余的等级不会生效甚至可能导致守护进程报错。所以判断一个冷却设备有多少等级最直接的方法是看sysfscat /sys/class/thermal/cooling_device*/type cat /sys/class/thermal/cooling_device*/max_statemax_state显示0到N说明有N1个等级。配置里写等级数量时千万不要超过这个值。4.3 双簇平台的频率控制实例很多骁龙平台大核小核是分开的比如大核簇对应policy0小核簇对应policy4或policy6。我在配置时会分别建两个冷却设备一个控大核一个控小核并且让大核先降频、小核后降频。这样可以尽量保证系统在高负载下仍有基础响应能力。[COOL_DEV_BIG_LIMITER] device cpufreq cluster_id 0 states 0, 1, 2, 3 [COOL_DEV_LITTLE_LIMITER] device cpufreq cluster_id 1 states 0, 1我在实际调校里习惯让大核分三挡甚至四挡降小核最多降一挡。原因是日常应用和系统UI对CPU响应很敏感过度限制小核会让滑动都变卡。如果你只是玩游戏时压大核温度小核保持全速反而更合理因为游戏主线程通常还在小核上跑一部分逻辑。5. 一套可直接上手的完整配置示例5.1 配置前先收集信息动手改之前先别急着打开编辑器。先在终端执行几个命令把设备当前状态摸清楚cat /sys/class/thermal/thermal_zone*/type cat /sys/class/thermal/cooling_device*/type cat /sys/class/thermal/cooling_device*/max_state cat /sys/class/thermal/cooling_device*/cur_state你需要确认以下信息实际有哪些物理传感器type名称是什么。温度节点单位是毫摄氏度还是摄氏度。有几个CPU冷却设备每个支持多少等级。当前各冷却设备的状态方便改完配置后对比。5.2 一份精简但完整的配置示例下面是一份面向通用骁龙平台的示意配置。我在每个段后面加了注释。请注意字段名和段名前缀在不同平台有差异你需要把自己的实际文件名对照之后微调。# 物理传感器段CPU综合温度 [SENSOR_cpu0_temp] name tsens_tz_sensor0 polling_ms 1000 [SENSOR_cpu1_temp] name tsens_tz_sensor5 polling_ms 1000 # 物理传感器段电池温度 [SENSOR_batt_temp] name bcl_soc polling_ms 2000 # 虚拟传感器段SoC热点温度由两个CPU传感器加权合成 [VIRTUAL_SENSOR_soc_temp] name soc_temp algorithm MAX input cpu0_temp, cpu1_temp offset 0 # 虚拟传感器段模拟机身温度电池占大头CPU热点占小头 [VIRTUAL_SENSOR_skin_temp] name skin_temp algorithm WEIGHTED_AVG input soc_temp, batt_temp weights 40, 60 offset 2000 # 算法段soc_temp 触发多级限制 [ALGORITHM_soc_throttle] input soc_temp algorithm LIMITS temperatures 60000, 72000, 84000 hysteresis 3000 action big_limiter, little_limiter # 算法段skin_temp 超过阈值时额外限制大核 [ALGORITHM_skin_throttle] input skin_temp algorithm LIMITS temperatures 48000, 52000 hysteresis 2000 action big_limiter # 冷却设备段大核冷却设备4个等级 [COOL_DEV_big_limiter] device cpufreq cluster_id 0 states 0, 1, 2, 3 # 冷却设备段小核冷却设备2个等级 [COOL_DEV_little_limiter] device cpufreq cluster_id 1 states 0, 1这段配置的意图是SoC热点到60℃大核开始降频72℃再降84℃进入最深限制机身模拟温度到48℃就开始限制大核52℃进一步加强。滞后的存在避免了频率反复横跳。5.3 这套配置背后的取舍思路我给大核设置了三个降频档而不是只设一个最低档是因为我自己吃过亏。之前只设一道高温墙平时不降频一到温度墙就直接锁到最低频结果游戏必然卡死。分级降频的本质是让性能平滑回落虽然温度降得没有“一刀切”快但用户体验好非常多。机身虚拟传感器我采用了“电池占大头、CPU占小头”的权重。原因是日常使用中手机发热最直接的感知就是电池附近鼓起来的位置而CPU热点通常被金属屏蔽罩和散热膜挡住了传到外壳时已经弱很多。这个权重你可以根据自己设备手感微调。温度阈值用毫摄氏度是为了跟高通大部分节点保持一致。60000就是60℃72000是72℃84000是84℃。如果你机器温度节点是摄氏度格式记得把这里改成60、72、84。6. 验证配置是否生效的方法以及我踩过的几个坑6.1 用 sysfs 实时观察配置效果配置改完后重启守护进程或重启系统然后开始验证。最直观的方法是边施加负载边观察sysfs。watch -n 1 cat /sys/class/thermal/thermal_zone*/temp watch -n 1 cat /sys/class/thermal/cooling_device*/cur_state同时跑一个压力测试比如用stress压CPU或者直接开一个大型游戏。观察温度起来后冷却设备的cur_state是否跟着变化各个thermal_zone的温度是否开始回落。如果温度到了阈值但cur_state始终不变通常是三段没对上虚拟传感器的输入名称和传感器段逻辑名不一致。算法段的input没引用虚拟传感器的name。冷却设备的cluster_id或states数量和内核不匹配。然后用dmesg查一下有没有解析错误dmesg | grep -i thermal能看到类似“unknown sensor”或者“invalid state”之类的提示说明配置里引用了不存在的对象。这是最常见的问题没有之一。6.2 我实际踩过的坑第一个坑是温度单位没确认就照抄网上配置。早期我拿到一台设备网上流传的配置文件里写的是毫摄氏度阈值但我这台机器某些温度节点直接输出摄氏度格式结果阈值永远达不到散热策略形同虚设。后来我把所有节点的量级全部打印出来对比才发现问题。所以不管你从哪抄的配置第一步永远是确认单位。第二个坑是滞后值设太小。我曾经把滞后设成500也就是0.5℃结果系统在高负载边缘反复触发和解除限制游戏帧率像心电图一样上下跳。后来把滞后加到3000也就是3℃频率切换频率明显降下来了。温度控制不是越灵敏越好要给硬件一点反应时间。第三个坑是盲目加冷却等级。有个平台上内核只暴露了3个等级我配置里写了4个结果守护进程启动后频繁报错CPU频率控制完全失效温度一路冲到了触发系统重启。后来我通过cat /sys/class/thermal/cooling_device*/max_state确认等级数量改回3个才恢复正常。第四个坑是忘了考虑多个算法同时控制同一个冷却设备的冲突。比如我在示例里让soc_temp和skin_temp都能控制大核限频两个算法可能给出不同的冷却等级此时看具体平台策略有的平台取最大值有的平台取最后一个。如果你发现某段配置不生效很可能是被另一个算法覆盖了。稳妥做法是同一时间段只让一个算法控制一个冷却设备或者明确了解平台的仲裁逻辑。6.3 最后分享一个小技巧调温度阈值时别一上来就大改。我习惯每次只改一个参数比如先把soc_temp的阈值从72000改到68000重启后跑同一款游戏对比帧率和温度曲线。如果同时改了好几个阈值出了问题你根本不知道是哪一项造成的。用perf或者游戏自带的帧率记录工具拉一条曲线配合cat /sys/class/thermal/thermal_zone*/temp采样改起来会高效得多。另外如果你发现自己只是想让手机凉快但不想牺牲太多性能优先改“虚拟传感器的偏移量”和“滞后值”而不是直接猛降阈值。偏移量可以让虚拟温度更贴近手摸起来的真实温度滞后值可以减少频率抖动。这两个参数是性价比最高的调整项。热管理配置这活儿本质上是寻找一个属于你自己使用习惯的平衡点。没有一套配置能同时满足“满载不热”和“一直满血”这两个需求你能做的只是把性能曲线从悬崖式改成平滑式让体感温度更可控。多试几轮记录数据你会发现它并没有想象中那么玄。
