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

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

相关推荐
蒸鱼Yuzheng40 分钟前
移动端 CPU 调度分析:线程亲和性、大小核迁移与卡顿
android·perfetto·性能分析·线程优化·cpu调度
booboosui1 小时前
安卓唤醒词:12 维 MFCC 加 DTW,阈值 1.8
android
传奇开心果1 小时前
Compose Multiplatform 共享边界实战:架构契约、互操作同步与可回退设计
android·kotlin
事圆则缓1 小时前
从开机到首帧:Android 系统与应用启动流程源码分析
android
AI吃大瓜2 小时前
指针压力表读数4:Android实现指针压力表读数(可实时检测)
android·指针读数·指针压力表·压力表·压力表读数
fengci.2 小时前
CTF2刷题记录(困难部分)
android·开发语言·前端·学习·php
hunterandroid2 小时前
[Android 从零到一] ARouter 路由框架原理:APT 生成路由表与组件化通信
android
最好一梦2 小时前
佳维视安卓工控机在堆垛机中的应用
android
传奇开心果编程3 小时前
组合优先开发范式:从汉字造字原理到声明式UI组件组合思想
android·flutter·ios·swiftui·移动开发·harmonyos·android jetpack
腾讯端服务4 小时前
一码Duo端-Kuikly-iOS折叠屏新UI适配实践
android·ui·ios·kotlin·鸿蒙