电源管理常见问题:唤醒锁泄漏、Wakeup源配置错误与中断冲突

做Android电源管理这些年,我踩过的坑真不少。今天聊三个最让人头疼的问题——唤醒锁泄漏、Wakeup源配置错误、中断冲突。说白了,这三个问题就像三座大山,翻不过去,你的设备就别想省电,也别想稳定。

一、唤醒锁泄漏:看不见的电老虎

唤醒锁泄漏,是我在项目中遇到最多的问题。你想想看,一个App申请了唤醒锁,用完却不释放,系统就没法进入深度睡眠。电池就这么被白白耗掉了。

核心原因:申请了wake lock,但未在合适的时机释放。

我见过最典型的场景——某个视频App播放完视频后,后台线程还持有一个PARTIAL_WAKE_LOCK。用户以为退出了,实际上CPU一直在跑。一晚上能掉电30%。

怎么排查?我习惯用这个命令:

adb shell dumpsys power

输出里找Wake Locks部分,看看有没有长时间持有的锁。更直接的办法:

adb shell dumpsys batterystats --reset
# 使用一段时间后
adb shell dumpsys batterystats | grep "Wake lock"
唤醒锁类型 泄漏后果 典型场景
PARTIAL_WAKE_LOCK CPU持续运行,无法休眠 后台下载、定位服务
FULL_WAKE_LOCK 屏幕+CPU全开 视频播放、游戏
SCREEN_DIM_WAKE_LOCK 屏幕半亮,无法灭屏 阅读类App

我的经验:写代码时,我习惯用try-finally块来保证释放。或者用acquire带超时参数——acquire(long timeout),这样就算忘了释放,系统也会帮你收尾。

二、Wakeup源配置错误:手机睡死了

这个问题比泄漏更可怕。唤醒锁泄漏只是费电,Wakeup源配错了——设备直接叫不醒。

我记得有一次,客户反馈说手机充电时偶尔无法唤醒屏幕。查了两天,最后发现是GPIO配置问题。某个按键的中断引脚,在休眠时被拉低了,导致系统无法检测到唤醒事件。

Wakeup源的核心逻辑其实不复杂:

// 设备树中配置唤醒源
wakeup-source;
gpios = <&gpio1 3 GPIO_ACTIVE_LOW>;

// 驱动中使能唤醒
device_init_wakeup(&pdev->dev, true);
enable_irq_wake(irq);

这里有个坑——enable_irq_wake必须在中断注册之后调用。我曾经因为顺序搞反,调试了一整个下午。

注意:不是所有中断都适合做唤醒源。比如触摸屏的中断,如果配置成唤醒源,放在口袋里可能会被误触唤醒。我建议只把电源键、耳机插拔、USB插入这类关键事件配成唤醒源。

常见的Wakeup源配置错误:

  • 设备树中缺少wakeup-source属性
  • GPIO的pull-up/pull-down配置与硬件不匹配
  • 中断触发方式错误(边沿触发 vs 电平触发)
  • 多个唤醒源共享同一个中断号

三、中断冲突:系统不稳定的元凶

中断冲突这个问题,说白了就是多个设备抢同一个中断线。你想想看,两个外设共用一根中断线,一个发信号,另一个也响应,系统不崩才怪。

我遇到过最离谱的一次——TP和指纹模块共用中断线。手指按在指纹上,触摸屏也跟着乱跳。最后只能改硬件,把中断线分开。

软件层面怎么排查?看/proc/interrupts

cat /proc/interrupts
           CPU0       CPU1       
 29:       1234       5678     GIC-0  47  edge      gpio_keys
 30:          0          0     GIC-0  48  level     touchscreen

如果两个设备的中断号相同,那就是共享中断。共享本身没问题,但处理不好就会出乱子。

中断共享的黄金法则:每个中断处理函数必须能区分是不是自己的设备触发了中断。做不到这一点,就别共享。

我习惯在中断处理函数开头加一个状态检查:

static irqreturn_t my_irq_handler(int irq, void *dev_id)
{
    struct my_device *dev = dev_id;
    
    // 检查是不是自己的设备触发了中断
    if (!(readl(dev->regs + INT_STATUS) & dev->int_mask)) {
        return IRQ_NONE;  // 不是我的,返回
    }
    
    // 处理中断
    ...
    return IRQ_HANDLED;
}

这样做的好处是——即使共享中断,也不会误处理别人的事件。

知识体系总览

下面这张图,是我梳理的这三个问题的核心逻辑。你看一眼就能明白它们之间的关系:

电源管理三大常见问题 唤醒锁泄漏 Wake Lock Leak Wakeup源配置错误 Wakeup Source Misconfig 中断冲突 IRQ Conflict CPU无法休眠 电池快速耗尽 设备无法唤醒 系统死机 功能异常 系统不稳定 用户体验严重下降 耗电 + 死机 + 功能异常 排查方法 dumpsys power 排查方法 /proc/interrupts 三个问题相互关联,一个出问题可能引发连锁反应

你看这张图就明白了——这三个问题虽然表现不同,但最终都指向同一个结果:用户体验严重下降。而且它们之间还会互相影响。比如中断冲突可能导致唤醒源失效,唤醒源失效又可能让系统误以为有唤醒锁泄漏。

我的建议:遇到电源管理问题,别急着改代码。先看dumpsys power/proc/interrupts,把现状摸清楚。我曾经花了一周追一个bug,最后发现只是GPIO配置少了一个上拉电阻。

嗯,这三个问题今天就聊到这儿。每个问题背后都有不少细节,但核心思路是一样的——理解硬件行为,检查软件配置,用工具验证。做到这三点,大部分问题都能迎刃而解。


公众号:蓝海资料掘金营,微信deep3321