一、Linux系统休眠
在嵌入式设备中由于省电功耗等原因我们需要让系统在不忙的时候进入休眠模式,Linux pm core提供给我们wakelock及autoslepp内核休眠机制。
autosleep 和 wakelock是并行存在,只有 wakelock 唤醒锁全部释放且 autosleep 为 enable 时候系统才能进入休眠;
二、autosleep功能
节点路径为/sys/power/autosleep,该值为mem表示打开autoslepp功能,如果值为off表示关闭。
如果没有此节点路径,我们需要在内核配置打开autosleep功能的宏控。
/面朝大海0902/
三、wakelock唤醒锁使用及查看
Kernel wakelock 使用方法:
Step1, 初始化
wake_lock_init(&wake_lock, WAKE_LOCK_SUSPEND, “name”);
Step2, 加锁
wake_lock(&wake_lock); //与 wake_unlock 成对使用, lock 后系统不允许休眠
wake_lock_timeout(&wake_lock, msecs_to_jiffies(timeout)); //超时锁, 超时时间到后自动释放
Step3, 解锁
wake_unlock(&wake_lock); //unlock 后系统允许休眠
app wakelock 使用方法:
Step1, 加锁
write_lockfile("/sys/power/wake_lock", “wakelock_name”);
Step2, 解锁
write_lockfile("/sys/power/wake_unlock", “wakelock_name”);
设置超时锁
static void wake_timeout_lock(char *lockname, ULONG interval);
/面朝大海0902/
查看当前系统持锁情况:
如果系统未休眠,按照上面说的内容肯定是当前系统有持锁,我们需要查看系统持锁情况,使用如下命令
awk ‘$6 != 0 {print $1" "$6}’ /sys/kernel/debug/wakeup_sources
该命令实际就是打印出wakeup_sources节点下active_since项为非0的锁的名称,如下
1.~ # awk '$6 != 0 {print $1" "$6}' /sys/kernel/debug/wakeup_sources
2.name active_since
3.dwc_otg_pm 4442570
表示当前USB持锁导致系统未进入休眠模式。
==========================================================================================================
如何分析wakelock(wakeup source)持锁问题
锁一般分为:APP透过PowerManager拿锁,以及kernel wakelock.
分析上层持锁的问题:
目前PowerManagerService的log 默认不会打开,可以通过修改:
/frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
private static final boolean DEBUG = true; private static final boolean DEBUG_SPEW = DEBUG && false; 修改为: private static final boolean DEBUG = true; private static final boolean DEBUG_SPEW = true; 打开上层的log
通过syslog:搜索关键字:total_time=来确定持锁的时间.
PowerManagerService: releaseWakeLockInternal: lock=31602562 [*job*/DownloadManager:com.android.providers.downloads], flags=0x0, total_time=600051ms
或者通过正则表达式:total_time=[\d]{4,}ms 过滤出持锁时间比较长的锁.
PowerManagerService: releaseWakeLockInternal: lock=31602562 [*job*/DownloadManager:com.android.providers.downloads], flags=0x0, total_time=600051ms
PowerManagerService: releaseWakeLockInternal: lock=56317918 [*job*/DownloadManager:com.android.providers.downloads], flags=0x0, total_time=283062ms
PowerManagerService: releaseWakeLockInternal: lock=216012597 [AudioMix], flags=0x0, total_time=120003ms
PowerManagerService: releaseWakeLockInternal: lock=41036921 [AudioMix], flags=0x0, total_time=167984ms
PowerManagerService: releaseWakeLockInternal: lock=70859243 [GsmInboundSmsHandler], flags=0x0, total_time=3206ms
PowerManagerService: releaseWakeLockInternal: lock=242046348 [AudioMix], flags=0x0, total_time=122205ms
kernel的锁默认不会打印出来,一般是待机结束后通过节点来获取:
adb shell cat /sys/kernel/debug/wakeup_sources > wakeup_sources.log
active_count:对应wakeup source被激活的次数.
event_count:被信号唤醒的次数
wakeup_count:中止suspend的次数.
expire_count:对应wakeup source超时的次数.
active_since:上一次还活跃的时间点.时间单位跟kernel log前缀时间是一样(kernel单调递增时间).
total_time:对应wakeup source活跃的总时长.
max_time:对应的wakeup source持续活跃最长的一次时间.
last_change:上一次wakeup source变化的时间(从持锁到释放or释放到持锁),时间单位跟kernel log前缀时间是一样(kernel单调递增时间).
prevent_suspend_time:对应wakeup source阻止进入autosleep的总累加时间.