Linux 电源管理机制为设备低功耗的实现提供了方法。 在不同内核版本Linux、Android,休眠机制、流程有所差异。这里DLT-RK3288 Android 5.1 源码为例。 标准Linux 的电源状态: - On(on) S0- Working
- 正常的工作状态
- Standby (standby) S1 - CPU andRAM are powered but not executed
- CPU和DDR都供着电,但没执行任何命令。
- Suspend to RAM(mem) S3 - RAM is powered andthe running content is saved to RAM
- 挂起到内存,简称待机。CPU、EMMC、LCD等都断了电,只有DDR供着电,以保存休眠前的工作状态。
- Suspend to Disk,Hibernation(disk) S4 - All content is saved to Disk and power down
- 挂起到硬盘,简称休眠。机器运行状态保存到硬盘中,并关机。
DLT-RK3288的kernel/include/linux/suspend.h 中 可以看到常用的几种状态 1. #definePM_SUSPEND_ON ((__forcesuspend_state_t) 0) 2. #definePM_SUSPEND_FREEZE ((__force suspend_state_t) 1) 3. #definePM_SUSPEND_STANDBY ((__force suspend_state_t) 2) 4. #definePM_SUSPEND_MEM ((__forcesuspend_state_t) 3) 休眠相关内核源码:
kernel/kernel/power/main.c
kernel/kernel/power/suspend.c
kernel/kernel/power/wakelock.c
kernel/kernel/power/autosleep.c
main.c 主要是向用户空间提供文件接口。文件接口有以下:
suspend.c 是进入休眠前所执行的代码。主要函数调用流程: pm_suspend -- enter_state -- suspend_prepare --suspend_devices_and_enter 。
autosleep.c 主要负责自动进入休眠流程。
低版本的linux内核 还有earlysuspend.c,earlysuspend是假休眠(只关闭部分外设的电源)的一种机制,linux 3.10中已被抛弃。
如何进入休眠?
1、当autosleep开启,当所有wakelock都释放时,自动进入休眠。
autosleep.c 中,try_to_suspend 函数调用 pm_get_wakeup_count ,执行: 1. for(;;) { 2. prepare_to_wait(&wakeup_count_wait_queue, &wait, 3. TASK_INTERRUPTIBLE); 复制代码 可以看出,一直等到wakelock 被释放,pm_get_wakeup_count 才返回。进入调用 pm_suspend或hibernate休眠。
2、echo mem > /sys/power/state ,强制进入休眠。
执行该命令,系统会直接进入休眠,不再判断是否有没释放的wakelock。(低版本内核中,执行该命令,仍需要等待wakelock释放)。
wakelock 是为休眠唤醒而存在的。可以查询相关资料进一步了解。
cat /sys/power/wake_lock可以看到当前哪个Android锁处于激活状态。(/sys/power/wake_lock 并不统计内核的锁)。
如何禁止自动进入休眠?
1、在驱动源码中,初始化一个wakelock,并上锁,不释放。 1. #include<linux/wakelock.h> 2. structwake_lock no_suspend_lock; 复制代码 内核中的锁类型很简单,只有WAKE_LOCK_SUSPEND。(低版本内核中多了WAKE_LOCK_IDLE)。
缺点: 只能保证不进入休眠,屏幕却被灭了。
2、在Android中加锁
Android 定义了以下几种WakeLock类型:
* FULL_WAKE_LOCK 保持屏幕全亮、键盘背光灯点亮和CPU运行。
* SCREEN_BRIGHT_WAKE_LOCK 保持屏幕全亮和CPU运行。
* SCREEN_DIM_WAKE_LOCK 保持屏幕开启(但是让它变暗)和CPU运行。
* PARTIAL_WAKE_LOCK 保持CPU运行。
可以根据需要,申请不同的锁类型。
|