一、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;
- }
复制代码 |