android 电源管理
2015-12-16 15:40
615 查看
在 Android 的上层是使用 goToSleep() 这个函数让系统进入休眠的。但是这个命令为什么会让 Android 进入 Suspend Mode。
以前在做其他系统的时候, 一般都要自己手工去控制 apm_bios 这个设备的,比如使用 ioctl() 调用 apm_bios。所有的系统其原理都是差不多的。只是 Android 加入了一个封装, 使程序员可以更简单的操作, 可以不理会底层是如何操作的, 现在解析一个 goToSleep() 是如何工作的。
PowerManagerService.java 是 framework 层负责管理 PowerManager 的。goToSleep 就是在这个函数中定义的:
goToSleep()->
goToSleepLocked()->
setPowerState()->
setScreenStateLocked()->
Power.setScreenState(on); // android_os_Power.cpp
goToSleep() 在 PowerManagerService.java 中经过一系列的处理之后, 最终会进入 android_os_Power.cpp 文件中的 setScreenState() 这个函数中。
看一下 setScreenState() 的实现:
// android_os_Power.cpp
static int
setScreenState(JNIEnv *env, jobject clazz, jboolean on)
{
return set_screen_state(on);
}
而 set_screen_state() 在 power.c 文件中实现:
int
set_screen_state(int on)
{
QEMU_FALLBACK(set_screen_state(on));
LOGI("*** set_screen_state %d", on);
initialize_fds();
//LOGI("go_to_sleep eventTime=%lld now=%lld g_error=%s\n", eventTime,
// systemTime(), strerror(g_error));
if (g_error) return g_error;
char buf[32];
int len;
if(on)
len = sprintf(buf, on_state);
else
len = sprintf(buf, off_state);
len = write(g_fds[REQUEST_STATE], buf, len);
if(len < 0) {
LOGE("Failed setting last user activity: g_error=%d\n", g_error);
}
return 0;
}
可以发现, 其最终是通过 write(g_fds[REQUEST_STATE], buf, len); 令系统进入休眠的。
通过分析这个文件的代码, g_fds[REQUEST_STATE] = open("/sys/power/state", O_RDWR);
on_state = "wake", off_state = "standby", 也就是写 standby 到 /sys/power/state 就可以令系统进行休眠了。
/sys/power/state 的实现代码可以看 $(Kernel)/kernel/power/main.c 这个文件是怎么实现的。
所以,当文件系统起来的时候可以 echo standby > /sys/power/state 令系统进入休眠。
KERNEL层
1, Android中支持的电源状态:
PM_SUSPEND_ON -- 设备处于全电源状态,也就是正常工作状态;
PM_SUSPEND_MEM -- suspend to memory,设备进入睡眠状态,但所有的数据还保存在内存中,只有某些外部中断才可以唤醒设备。
PM_SUSPEND_STANDBY ----- 在大部分的Android设备中均不支持。
2, Early Suspend / Late Resume
在Android中,增加了系统休眠的层次,把休眠划分为深度睡眠(sleep)和浅度睡眠(idle)。
因此当系统往 /sys/power/state 节点写入 mem (如在命令行 写入: echo mem > /sys/power/state) 将会使系统进入睡眠。参考HAL中:hardware/libhardware_legacy/power/power.c : set_screen_state ------> write (on / mem ) to /sys/power/state
浅度睡眠 仅仅是关掉背光,fb, sensor,触摸屏等在关屏状态下不需要使用的设备,而整个CPU和大部分外设还是正常工作的。
深度睡眠sleep 与 浅度睡眠 idle 之间切换的过程如上所示。
3, Android的 Wake Lock
Android系统提供了两种类型的锁:
WAKE_LOCK_SUSPEND -- 阻止系统进入suspend状态;
WAKE_LOCK_IDLE -- 阻止系统进入idle状态;
wake lock 可以设置超时释放,在持有wake lock一个固定时间之后自动释放。一般应用在系统正在处理一些事情的时候,防止系统进入深度睡眠而干扰了正在处理的任务; 尤其是在做了硬件唤醒的,当唤醒之后要处理一些响应,为了防止系统马上再次进入休眠,在设置一个超时锁。
如系统能否进入深度睡眠,当系统处在idle时,会不断判断是否还有WAKE_LOCK_SUSPEND
4, 电源状态切换的调试:
/sys/power/state
/sys/power/wake_lock
/sys/power/wake_unlock
1) cat /sys/power/state -----查看系统状态, echo mem > /sys/power/state ---- 将系统设置为进入休眠
2) echo "name" > /sys/power/wake_lock ----- 申请一个锁
cat /sys/power/wake_lock -----查看系统的wake lock 情况
wake_unlock 同样。
3) echo 15 > /sys/module/wakelock/parameters/debug_mask ------------
这样wakelock的驱动会把每次的wakelock操作都打印在console上,对于调试为什么suspend不下去这类的问题很有用。如下所示:
[ 1062.912297] wake_lock: mmc_delayed_work, stop expire timer
[ 1062.922395] wake_unlock: mmc_delayed_work, start expire timer, 990
[ 1062.931174] wake_lock: event0-79, start expire timer, 989
[ 1062.933710] wake_lock: event0-79, start expire timer, 989
[ 1062.939081] wake_lock: event0-79, start expire timer, 989
[ 1062.961143] wake_lock: event0-79, start expire timer, 989
以前在做其他系统的时候, 一般都要自己手工去控制 apm_bios 这个设备的,比如使用 ioctl() 调用 apm_bios。所有的系统其原理都是差不多的。只是 Android 加入了一个封装, 使程序员可以更简单的操作, 可以不理会底层是如何操作的, 现在解析一个 goToSleep() 是如何工作的。
PowerManagerService.java 是 framework 层负责管理 PowerManager 的。goToSleep 就是在这个函数中定义的:
goToSleep()->
goToSleepLocked()->
setPowerState()->
setScreenStateLocked()->
Power.setScreenState(on); // android_os_Power.cpp
goToSleep() 在 PowerManagerService.java 中经过一系列的处理之后, 最终会进入 android_os_Power.cpp 文件中的 setScreenState() 这个函数中。
看一下 setScreenState() 的实现:
// android_os_Power.cpp
static int
setScreenState(JNIEnv *env, jobject clazz, jboolean on)
{
return set_screen_state(on);
}
而 set_screen_state() 在 power.c 文件中实现:
int
set_screen_state(int on)
{
QEMU_FALLBACK(set_screen_state(on));
LOGI("*** set_screen_state %d", on);
initialize_fds();
//LOGI("go_to_sleep eventTime=%lld now=%lld g_error=%s\n", eventTime,
// systemTime(), strerror(g_error));
if (g_error) return g_error;
char buf[32];
int len;
if(on)
len = sprintf(buf, on_state);
else
len = sprintf(buf, off_state);
len = write(g_fds[REQUEST_STATE], buf, len);
if(len < 0) {
LOGE("Failed setting last user activity: g_error=%d\n", g_error);
}
return 0;
}
可以发现, 其最终是通过 write(g_fds[REQUEST_STATE], buf, len); 令系统进入休眠的。
通过分析这个文件的代码, g_fds[REQUEST_STATE] = open("/sys/power/state", O_RDWR);
on_state = "wake", off_state = "standby", 也就是写 standby 到 /sys/power/state 就可以令系统进行休眠了。
/sys/power/state 的实现代码可以看 $(Kernel)/kernel/power/main.c 这个文件是怎么实现的。
所以,当文件系统起来的时候可以 echo standby > /sys/power/state 令系统进入休眠。
KERNEL层
1, Android中支持的电源状态:
PM_SUSPEND_ON -- 设备处于全电源状态,也就是正常工作状态;
PM_SUSPEND_MEM -- suspend to memory,设备进入睡眠状态,但所有的数据还保存在内存中,只有某些外部中断才可以唤醒设备。
PM_SUSPEND_STANDBY ----- 在大部分的Android设备中均不支持。
2, Early Suspend / Late Resume
在Android中,增加了系统休眠的层次,把休眠划分为深度睡眠(sleep)和浅度睡眠(idle)。
因此当系统往 /sys/power/state 节点写入 mem (如在命令行 写入: echo mem > /sys/power/state) 将会使系统进入睡眠。参考HAL中:hardware/libhardware_legacy/power/power.c : set_screen_state ------> write (on / mem ) to /sys/power/state
浅度睡眠 仅仅是关掉背光,fb, sensor,触摸屏等在关屏状态下不需要使用的设备,而整个CPU和大部分外设还是正常工作的。
深度睡眠sleep 与 浅度睡眠 idle 之间切换的过程如上所示。
3, Android的 Wake Lock
Android系统提供了两种类型的锁:
WAKE_LOCK_SUSPEND -- 阻止系统进入suspend状态;
WAKE_LOCK_IDLE -- 阻止系统进入idle状态;
wake lock 可以设置超时释放,在持有wake lock一个固定时间之后自动释放。一般应用在系统正在处理一些事情的时候,防止系统进入深度睡眠而干扰了正在处理的任务; 尤其是在做了硬件唤醒的,当唤醒之后要处理一些响应,为了防止系统马上再次进入休眠,在设置一个超时锁。
如系统能否进入深度睡眠,当系统处在idle时,会不断判断是否还有WAKE_LOCK_SUSPEND
4, 电源状态切换的调试:
/sys/power/state
/sys/power/wake_lock
/sys/power/wake_unlock
1) cat /sys/power/state -----查看系统状态, echo mem > /sys/power/state ---- 将系统设置为进入休眠
2) echo "name" > /sys/power/wake_lock ----- 申请一个锁
cat /sys/power/wake_lock -----查看系统的wake lock 情况
wake_unlock 同样。
3) echo 15 > /sys/module/wakelock/parameters/debug_mask ------------
这样wakelock的驱动会把每次的wakelock操作都打印在console上,对于调试为什么suspend不下去这类的问题很有用。如下所示:
[ 1062.912297] wake_lock: mmc_delayed_work, stop expire timer
[ 1062.922395] wake_unlock: mmc_delayed_work, start expire timer, 990
[ 1062.931174] wake_lock: event0-79, start expire timer, 989
[ 1062.933710] wake_lock: event0-79, start expire timer, 989
[ 1062.939081] wake_lock: event0-79, start expire timer, 989
[ 1062.961143] wake_lock: event0-79, start expire timer, 989
相关文章推荐
- Android入门之文件系统/File操作
- android 如何正确使用 泛型 和 多参数 “偷懒”
- Android初识-Intent的用法
- Android版使用移动广告平台集成Google Mobile Ads SDK教程
- Android编程之Activity中onDestroy()调用分析
- Android开源控件
- Android 获取系统图库和相机照片 裁剪并显示
- Android操作短信
- Android端实现Cookie机制
- Android Animation动画(很详细)
- Android 6.0 运行时请求权限
- Android不使用自定义布局情况下实现自定义通知栏图标的方法
- Android如何在Java代码里设置Button的margin
- android接入第三方apk的解决方法
- Android ListView分类/分组效果 - 第二种实现方式
- [转]Android中时间和时区的自动更新(NITZ+ZONE)
- Android:解决DatePickerDialog只有完成按钮、没有取消按钮的问题
- android系统编译kernel出错:file not recognized: File truncated
- android学习摘记——TabHost使用代码
- Android编程实现禁止系统锁屏与解锁亮屏的方法