目录
背景
板子直接供电、没有电池,但 healthd 仍认为电池存在,于是每隔约 60 秒就往内核日志打印一行电池状态:
[ 2056.816449][ T331] healthd> battery l=50 v=3 t=2.6 h=2 st=3 c=-1600 fc=100 chg=au
这类日志来自驱动上报的默认占位值,并非真实电池数据,持续刷屏会干扰其他调试信息。
设备树方案尝试后无效,因此改用最直接的办法:从 healthd 源码层屏蔽日志打印。
怎么屏蔽
修改文件 :system/core/healthd/BatteryMonitor.cpp
日志最终由 doLogValues() 函数中的 KLOG_WARNING 输出。由于该函数只负责打印、不参与任何业务逻辑,直接整体屏蔽即可:
cpp
static void doLogValues(const HealthInfo& props, const struct healthd_config& healthd_config) {
(void)props;
(void)healthd_config;
#if(0)
char dmesgline[256];
size_t len;
if (props.batteryPresent) {
snprintf(dmesgline, sizeof(dmesgline), "battery l=%d v=%d t=%s%d.%d h=%d st=%d",
props.batteryLevel, props.batteryVoltageMillivolts,
props.batteryTemperatureTenthsCelsius < 0 ? "-" : "",
abs(props.batteryTemperatureTenthsCelsius / 10),
abs(props.batteryTemperatureTenthsCelsius % 10), props.batteryHealth,
props.batteryStatus);
len = strlen(dmesgline);
if (!healthd_config.batteryCurrentNowPath.isEmpty()) {
len += snprintf(dmesgline + len, sizeof(dmesgline) - len, " c=%d",
props.batteryCurrentMicroamps);
}
if (!healthd_config.batteryFullChargePath.isEmpty()) {
len += snprintf(dmesgline + len, sizeof(dmesgline) - len, " fc=%d",
props.batteryFullChargeUah);
}
if (!healthd_config.batteryCycleCountPath.isEmpty()) {
len += snprintf(dmesgline + len, sizeof(dmesgline) - len, " cc=%d",
props.batteryCycleCount);
}
} else {
len = snprintf(dmesgline, sizeof(dmesgline), "battery none");
}
snprintf(dmesgline + len, sizeof(dmesgline) - len, " chg=%s%s%s%s",
props.chargerAcOnline ? "a" : "", props.chargerUsbOnline ? "u" : "",
props.chargerWirelessOnline ? "w" : "", props.chargerDockOnline ? "d" : "");
KLOG_WARNING(LOG_TAG, "%s\n", dmesgline);
#endif
}
两个注意点:
-
Android 编译开启了
-Wall -Werror,空函数体会报unused parameter错误,因此需加(void)props;和(void)healthd_config;消除警告。 -
用
#if(0)而非直接删除代码,便于后续需要时快速恢复。
为什么只屏蔽日志,而不是干掉整个电池服务/驱动
这是本次修改中最关键的决策点。看似"直接把电池服务或驱动干掉"更彻底,实际上隐患很大:
1. 会触发"幽灵关机"风险
Android 13 的电池状态由 android.hardware.health AIDL HAL 提供,healthd 作为守护进程采集数据。如果直接移除服务,系统拿不到有效电量,在 SELinux Permissive 模式下极可能误判为低电量而自动关机,反而引入更严重的问题。
2. 上层 UI 和 API 会报错
SystemUI、Settings 等模块会持续查询电池状态。服务缺失会导致这些模块异常、报错甚至崩溃,问题比日志刷屏严重得多。
3. 日志本身无害,只是"吵"
doLogValues() 是纯打印函数,不修改任何全局状态、不返回任何值、不参与数据采集与上报。屏蔽它只是让内核日志安静下来,对系统功能零影响。
4. 改动范围最小
-
干掉服务/驱动:涉及 HAL、SELinux、设备树、上层适配,牵一发动全身。
-
屏蔽日志:改一个函数、三行代码,编译刷机即验证。
一句话总结:日志只是"噪音",不是"故障"。我们要消除的是噪音,而不是把发声的整个系统拆掉。
总结
-
定位准确 :日志由
doLogValues()中的KLOG_WARNING打印,该函数纯输出、无副作用,可安全屏蔽。 -
方案最简 :一行
#if(0)加两行(void)即可,无需改动设备树或驱动。 -
风险为零:电池检测、状态上报、上层 API 均不受影响,只是不再往内核日志写内容。
-
思路清晰:只消除"噪音"而非移除"服务",避免引入关机、UI 崩溃等连锁问题。
-
适用场景:无电池设备、设备树方案无效、只需消除日志刷屏的调试场景。