RK3568 Android 13 屏蔽 healthd 电池日志经验分享

目录

​​​​背景

怎么屏蔽

为什么只屏蔽日志,而不是干掉整个电池服务/驱动

总结


背景

板子直接供电、没有电池,但 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
}

两个注意点

  1. Android 编译开启了 -Wall -Werror,空函数体会报 unused parameter 错误,因此需加 (void)props;(void)healthd_config; 消除警告。

  2. #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 崩溃等连锁问题。

  • 适用场景:无电池设备、设备树方案无效、只需消除日志刷屏的调试场景。

相关推荐
古法安卓5 小时前
Android-Fork 机制详解
android·java·android studio
Android打工仔5 小时前
不要在 Data 层随意把 Cold Flow 转换成 Hot Flow
android·架构·kotlin
峥嵘life6 小时前
2026免费的 opencode 使用分享:Windows端 + 服务器CLI 实战总结
android·大数据·开发语言
杉氧6 小时前
拒绝重复造轮子:我写了一个生产级的 Kotlin 协程与 Flow 工具库(CoroutineKit)
android·kotlin·workflow
恋猫de小郭7 小时前
Flutter GSoC 2026 提案进度解读,补上 DevTools、FFI 和原生平台的关键缺口
android·前端·flutter
2501_915909067 小时前
怎么用 FlutterFlow 把应用发布到 App Store?
android·ios·小程序·https·uni-app·iphone·webview
峥嵘life7 小时前
2026华为AI码道 CodeArts 使用分享:Windows端 + 服务器CLI 实战总结
android·大数据·开发语言·python
yxlalm7 小时前
对话记忆持久化-Redis热与MySQL冷
android·redis·mysql