一、应用层当系统未处于 Suspend 状态下用户按下Power键时会在产生一个信号,上层的 WindowManager? 会收到这个上节点的变化而得知当前应该进入休眠状态, 通知PowerManagerService, 它会做如下调用,
路径:./frameworks/base/services/java/com/android/server/PowerManagerService.java" line 1452
private int setScreenStateLocked(boolean on) {int err = Power.setScreenState(on); ------------------------------------------>在这里调用setScreenState()if (err == 0) {mLastScreenOnTime = (on ? SystemClock.elapsedRealtime() : 0);if (mUseSoftwareAutoBrightness) {enableLightSensor(on);if (!on) {// make sure button and key backlights are off toomButtonLight.turnOff();mKeyboardLight.turnOff();// clear current value so we will update based on the new conditions// when the sensor is reenabled.mLightSensorValue = -1;// reset our highest light sensor value when the screen turns offmHighestLightSensorValue = -1;}}}return err;}
setScreenState最终会调到hardware/libhardware_legacy/power/power.c 中的set_screen_state
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";下边这个函数打开NEW_PATHS[]中的三个描述符 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; }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=%sn", eventTime,// systemTime(), strerror(g_error));if (g_error) return g_error;char buf[32];int len;if(on){len = sprintf(buf, on_state);len = write(g_fds[REQUEST_STATE], buf, len);sys_file = fopen(FILENAME_SYS_3G_RESTART, "w");if(sys_file){fputc(2, sys_file);fclose(sys_file);}}else{len = sprintf(buf, off_state);len = write(g_fds[REQUEST_STATE], buf, len); ===> echo mem > /sys/power/statesys_file = fopen(FILENAME_SYS_3G_RESTART, "w");if(sys_file){fputc(0, sys_file);fclose(sys_file);}write_resume_state(1);}if(len < 0) {LOGE("Failed setting last user activity: g_error=%dn", g_error);}return 0; }
到些完成了从按下power键到 echo mem > /sys/power/state 的过程,接下来就是进入内核中
二、内核中的休眠过程分析1、创建 /sys/power/state节点在内核中 kernel/power/main.cpower_attr(state);这是一个宏(定义在kernel/power/power.h),它实现在/sys/power/ 下创建对应节点state,对这个结点进行读写对应的函数为
//写结点时调用的函数 static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,const char *buf, size_t n) //读结点时调用的函数 static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr,char *buf)
接上边echo mem > /sys/power/state后state_store被调用
static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,const char *buf, size_t n) { #ifdef CONFIG_SUSPEND #ifdef CONFIG_EARLYSUSPENDsuspend_state_t state = PM_SUSPEND_ON; #elsesuspend_state_t state = PM_SUSPEND_STANDBY; #endifconst char * const *s; #endifchar *p;int len;int error = -EINVAL;p = memchr(buf, 'n', n);len = p ? p - buf : n;/* First, check if we are requested to hibernate */if (len == 4 && !strncmp(buf, "disk", len)) {error = hibernate();goto Exit;}#ifdef CONFIG_SUSPENDfor (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++) {if (*s && len == strlen(*s) && !strncmp(buf, *s, len))break;}if (state < PM_SUSPEND_MAX && *s) #ifdef CONFIG_EARLYSUSPEND ---------------------------------------------------------------if (state == PM_SUSPEND_ON || valid_state(state)) { |error = 0; |->android 添加的部分,如果定义了request_suspend_state(state); |->earlysuspend则调用request_suspend_state(state); (定义在kernel/power/earlysuspend.c)} | #else ---------------------------------------------------------------------------------------error = enter_state(state); ===========================>标准linux进入休眠的路径 #endif #endifExit:return error ? error : n; }
request_suspend_state 位于: kernel/power/earlysuspend.c
void request_suspend_state(suspend_state_t new_state) { unsigned long irqflags;int old_sleep;spin_lock_irqsave(&state_lock, irqflags);old_sleep = state & SUSPEND_REQUESTED;if (debug_mask & DEBUG_USER_STATE) {struct timespec ts;struct rtc_time tm;getnstimeofday(&ts);rtc_time_to_tm(ts.tv_sec, &tm);pr_info("request_suspend_state: %s (%d->%d) at %lld ""(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)n",new_state != PM_SUSPEND_ON ? "sleep" : "wakeup",requested_suspend_state, new_state,ktime_to_ns(ktime_get()),tm.tm_year + 1900, tm.tm_mon + 1, tm.tm__hour, tm.tm_min, tm.tm_sec, ts.tv_nsec);}if (!old_sleep && new_state != PM_SUSPEND_ON) {state |= SUSPEND_REQUESTED;queue_work(suspend_work_queue, &early_suspend_work);------------- >这个是把工作early_suspend_work添加到工作队列suspend_work_queue中requested_suspend_state = new_state;spin_unlock_irqrestore(&state_lock, irqflags);} else if (old_sleep && new_state == PM_SUSPEND_ON) {state &= ~SUSPEND_REQUESTED;wake_lock(&main_wake_lock);queue_work(suspend_work_queue, &late_resume_work);requested_suspend_state = new_state;spin_unlock_irqrestore(&state_lock, irqflags);mdelay(300);}else {requested_suspend_state = new_state;spin_unlock_irqrestore(&state_lock, irqflags);} }
工作队列suspend_work_queue定义在kernel/power/wakelock.c中在wakelocks_init()函数中对这个工作队列初始化
static int __init wakelocks_init(void) {。。。。suspend_work_queue = create_singlethread_workqueue("suspend"); 创建一个单线程休眠工作队列if (suspend_work_queue == NULL) {ret = -ENOMEM;goto err_suspend_work_queue;}。。。。。return ret; }
本文发布于:2024-01-28 02:17:35,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/17063794634072.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |