Android 是如何进入休眠的 - 日记

来源:互联网 发布:steam淘宝 国区 编辑:程序博客网 时间:2024/06/05 11:29
06:38

分类: LINUX

在 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
 
不知道为什么会这样?

0 0
原创粉丝点击