在 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 这个文件是怎么实现的。
所以,当文件系统起来的时候可以 cat standby > /sys/power/state 令系统进入休眠。
对 Android 研究的时间还不长, 错误之处请大家多多包涵。
==============================================
今天在我们的板子上发现一个问题
#echo mem > /sys/power/state
之后, 系统进入 Suspend 之后会马上被 Wakeup,
不管是
#echo mem > /sys/power/state 或
#echo standby > /sys/power/state
都没有作用.
因为加载 Android OS后其休眠又是正常的, 说明 Kernel 不存在问题的, 百思不得其解.
后来对比有跑Android OS与没有跑的输出信息:
正常的是:
request_suspend_state: sleep (0->3) at 64613571728 (2000-01-01 18:34:01.877766147 UTC)
而错误的是:
request_suspend_state: sleep (3->3) at 103919983424 (2000-01-01 01:22:09.094231074 UTC)
看一下代码,
0 代表 PM_SUSPEND_ON, 而 3 代表 PM_SUSPEND_MEM
所以在休眠之前先输入:
#echo on > /sys/power/state
再输入:
#echo mem > /sys/power/state
现在信息输出正常了, 但还是会 Suspend->Wakeup->Suspend->Wakeup->Suspend->....
为什么呢?
后来又发现如果是正常的话其会输出如下一行:
request_suspend_state: wakeup (3->0) at 104713517891 (2000-01-01 01:22:20.620285229 UTC)
哦, 原来问题在这里.
当系统被 Wakeup 之后, 必须马上又发一个命令让系统回到 Active Mode.
但是要怎么加呢?系统起来之后又要马上输入 #echo on > /sys/power/state
这样子就可以了:
echo on > state;echo mem > state;sleep 2;echo on > state
但是还有一个问题没有弄明白, 当没有跑 Android OS 时, 其 wakeup 后输出:
wakeup wake lock: unknown event
有 Android OS 时, 其输出:
wakeup wake lock: evdev
不知道为什么会这样?
阅读(13730) | 评论(1) | 转发(2) |