Android睡眠唤醒机制--HAL-->Kernel

转自: http://blog.csdn.net/myarrow/article/details/8137566

相关资料:http://blog.csdn.net/MyArrow/article/category/1271219

一、Kernel与HAL接口分析

        Kernel与HAL接口是通过/sys/power下面的一系统文件来实现的,如:/sys/power/state

        Kernel中/sys/power下的文件实现过程如下:

1. sysfs的属性文件

     在kernel/power/main.c中,定义了一组sysfs的属性文件: 

static struct attribute * g[] = {
    &state_attr.attr,
#ifdef CONFIG_PM_TRACE
    &pm_trace_attr.attr,
    &pm_trace_dev_match_attr.attr,
#endif
#ifdef CONFIG_PM_SLEEP
    &pm_async_attr.attr,
    &wakeup_count_attr.attr,
#ifdef CONFIG_PM_DEBUG
    &pm_test_attr.attr,
#endif
#ifdef CONFIG_USER_WAKELOCK
    &wake_lock_attr.attr,
    &wake_unlock_attr.attr,
#endif
#endif
    NULL,
};

static struct attribute_group attr_group = {
    .attrs = g,
};

 

如state_attr定义如下:

power_attr(state);
#define power_attr(_name) \
static struct kobj_attribute _name##_attr = {    \
    .attr    = {                \
        .name = __stringify(_name),    \
        .mode = 0644,            \
    },                    \
    .show    = _name##_show,            \
    .store    = _name##_store,        \
}

即:
static struct kobj_attribute state_attr = {    \
    .attr    = {                \
        .name = "state",    \
        .mode = 0644,            \
    },                    \
    .show    = state_show,            \
    .store    = state_store,        \
}

2. 创建sysfs文件

static int __init pm_init(void)
{
    int error = pm_start_workqueue();
    if (error)
        return error;
    hibernate_image_size_init();
    hibernate_reserved_size_init();
    power_kobj = kobject_create_and_add("power", NULL);
    if (!power_kobj)
        return -ENOMEM;
    return sysfs_create_group(power_kobj, &attr_group);
}

  pm_init函数执行后,会创建/sys/power目录,且目录下会建立一系列属性文件,其中一个是/sys/power/state文件。用户空间该文件将会导致state_store被调用,该文件将会导致state_show函数被调用。

 二、HAL代码分析

         HAL代码位于hardware/libhardware_legacy/power/power.c

1. 路径及写入字符串定义      

const char * const NEW_PATHS[] = {
    "/sys/power/wake_lock",
    "/sys/power/wake_unlock",
    "/sys/power/state"
};

static const char *off_state = "mem";
static const char *on_state = "on";

2. 打开上面定义的三个文件

static int
open_file_descriptors(const char * const paths[])
{
    int i;
    for (i=0; i<OUR_FD_COUNT; i++) {
        int fd = open(paths[i], O_RDWR);
        if (fd < 0) {
            fprintf(stderr, "fatal error opening \"%s\"\n", paths[i]);
            g_error = errno;
            return -1;
        }
        g_fds[i] = fd;
    }

    g_error = 0;
    return 0;
}

3. 修改状态
      用户态的电源管理系统会调用set_screen_state函数来触发suspend的流程,该函数实际上就是往/sys/power/state文件写入"mem"或"on"命令字符串。

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)
        goto failure;

    char buf[32];
    int len;
    if(on)
        len = snprintf(buf, sizeof(buf), "%s", on_state);
    else
        len = snprintf(buf, sizeof(buf), "%s", off_state);

    buf[sizeof(buf) - 1] = '\0';
    len = write(g_fds[REQUEST_STATE], buf, len);
    if(len < 0) {
    failure:
        LOGE("Failed setting last user activity: g_error=%d\n", g_error);
    }
    return 0;
}

 

posted @ 2015-12-09 16:43  oho_yoho  阅读(259)  评论(0)    收藏  举报