android 休眠唤醒机制分析(二) — early_suspend
本文转自:http://blog.csdn.net/g_salamander/article/details/7982170
early_suspend是Android休眠流程的第一阶段即浅度休眠,不会受到wake_lock的阻止,一般用于关闭lcd、tp等设备为运行的应用节约电能。Android的PowerManagerService会根据用户的操作情况调整电源状态,如果需要休眠则会调用到HAL层的set_screen_state()接口,在set_screen_state()中会向/sys/power/state节点写入"mem"值让驱动层开始进入休眠流程。
一、休眠唤醒机制及其用户空间接口
Linux系统支持如下休眠唤醒等级
[cpp] view plain copy- constchar*constpm_states[PM_SUSPEND_MAX]={
- #ifdefCONFIG_EARLYSUSPEND
- [PM_SUSPEND_ON]="on",
- #endif
- [PM_SUSPEND_STANDBY]="standby",
- [PM_SUSPEND_MEM]="mem",
- };
但在Android中一般只支持"on"和"mem",其中"on"为唤醒设备,"mem"为休眠设备。/sys/power/state节点的读写操作如下:
[cpp] view plain copy- staticssize_tstate_show(structkobject*kobj,structkobj_attribute*attr,
- char*buf)
- {
- char*s=buf;
- #ifdefCONFIG_SUSPEND
- inti;
- for(i=0;i<PM_SUSPEND_MAX;i++){
- if(pm_states[i]&&valid_state(i))
- s+=sprintf(s,"%s",pm_states[i]);//打印系统支持的休眠等级
- }
- #endif
- #ifdefCONFIG_HIBERNATION
- s+=sprintf(s,"%s\n","disk");
- #else
- if(s!=buf)
- /*convertthelastspacetoanewline*/
- *(s-1)='\n';
- #endif
- return(s-buf);
- }
- staticssize_tstate_store(structkobject*kobj,structkobj_attribute*attr,
- constchar*buf,size_tn)
- {
- #ifdefCONFIG_SUSPEND
- #ifdefCONFIG_EARLYSUSPEND
- suspend_state_tstate=PM_SUSPEND_ON;
- #else
- suspend_state_tstate=PM_SUSPEND_STANDBY;
- #endif
- constchar*const*s;
- #endif
- char*p;
- intlen;
- interror=-EINVAL;
- p=memchr(buf,'\n',n);
- len=p?p-buf:n;
- /*First,checkifwearerequestedtohibernate*/
- if(len==4&&!strncmp(buf,"disk",len)){
- error=hibernate();
- gotoExit;
- }
- #ifdefCONFIG_SUSPEND
- for(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)
- #ifdefCONFIG_EARLYSUSPEND
- if(state==PM_SUSPEND_ON||valid_state(state)){
- error=0;
- request_suspend_state(state);//请求进入android的休眠流程
- }
- #else
- error=enter_state(state);//linux的标准休眠流程
- #endif
- #endif
- Exit:
- returnerror?error:n;
- }
- power_attr(state);
其中state_show()为节点的读函数,主要打印出系统支持的休眠等级;state_store()为节点的写函数,根据参数请求休眠或者唤醒流程。节点的创建代码如下:
[cpp] view plain copy- staticstructattribute*g[]={
- &state_attr.attr,//state节点
- #ifdefCONFIG_PM_TRACE
- &pm_trace_attr.attr,
- #endif
- #ifdefined(CONFIG_PM_SLEEP)&&defined(CONFIG_PM_DEBUG)
- &pm_test_attr.attr,//pm_test节点
- #endif
- #ifdefCONFIG_USER_WAKELOCK
- &wake_lock_attr.attr,//wake_lock节点
- &wake_unlock_attr.attr,//wake_unlock节点
- #endif
- NULL,
- };
- staticstructattribute_groupattr_group={
- .attrs=g,
- };
- staticint__initpm_init(void)
- {
- interror=pm_start_workqueue();
- if(error)
- returnerror;
- power_kobj=kobject_create_and_add("power",NULL);//创建power节点
- if(!power_kobj)
- return-ENOMEM;
- returnsysfs_create_group(power_kobj,&attr_group);//创建一组属性节点
- }
- core_initcall(pm_init);
二、early_suspend 实现
1、early_suspend 定义、接口及其用法
[cpp] view plain copy- enum{
- EARLY_SUSPEND_LEVEL_BLANK_SCREEN=50,
- EARLY_SUSPEND_LEVEL_STOP_DRAWING=100,
- EARLY_SUSPEND_LEVEL_DISABLE_FB=150,
- };
- structearly_suspend{
- #ifdefCONFIG_HAS_EARLYSUSPEND
- structlist_headlink;//链表节点
- intlevel;//优先等级
- void(*suspend)(structearly_suspend*h);
- void(*resume)(structearly_suspend*h);
- #endif
- };
可以看到early_suspend由两个函数指针、链表节点、优先等级组成;内核默认定义了3个优先等级,在suspend的时候先执行优先等级低的handler,在resume的时候则先执行等级高的handler,用户可以定义自己的优先等级;early_suspend向内核空间提供了2个接口用于注册和注销handler:
[cpp] view plain copy- voidregister_early_suspend(structearly_suspend*handler);
- voidunregister_early_suspend(structearly_suspend*handler);
其中register_early_suspend()用于注册,unregister_early_suspend用于注销;一般early_suspend的使用方式如下:
[cpp] view plain copy- ts->earlysuspend.suspend=sitronix_i2c_suspend_early;
- ts->earlysuspend.resume=sitronix_i2c_resume_late;
- ts->earlysuspend.level=EARLY_SUSPEND_LEVEL_BLANK_SCREEN;
- register_early_suspend(&ts->earlysuspend);
设置好suspend和resume接口,定义优先等级,然后注册结构即可。
2、初始化信息
我们看一下early_suspend需要用到的一些数据:
[cpp] view plain copy- staticDEFINE_MUTEX(early_suspend_lock);
- staticLIST_HEAD(early_suspend_handlers);//初始化浅度休眠链表
- //声明3个工作队列用于同步、浅度休眠和唤醒
- staticvoidearly_sys_sync(structwork_struct*work);
- staticvoidearly_suspend(structwork_struct*work);
- staticvoidlate_resume(structwork_struct*work);
- staticDECLARE_WORK(early_sys_sync_work,early_sys_sync);
- staticDECLARE_WORK(early_suspend_work,early_suspend);
- staticDECLARE_WORK(late_resume_work,late_resume);
- staticDEFINE_SPINLOCK(state_lock);
- enum{
- SUSPEND_REQUESTED=0x1,//当前正在请求浅度休眠
- SUSPENDED=0x2,//浅度休眠完成
- SUSPEND_REQUESTED_AND_SUSPENDED=SUSPEND_REQUESTED|SUSPENDED,
- };
- staticintstate;
初始化了一个链表early_suspend_handlers用于管理early_suspend,还定义读写链表用到的互斥体;另外还声明了3个工作队列,分别用于缓存同步、浅度休眠和唤醒;还声明了early_suspend操作的3个状态。
3、register_early_suspend 和unregister_early_suspend
- voidregister_early_suspend(structearly_suspend*handler)
- {
- structlist_head*pos;
- mutex_lock(&early_suspend_lock);
- //遍历浅度休眠链表
- list_for_each(pos,&early_suspend_handlers){
- structearly_suspend*e;
- e=list_entry(pos,structearly_suspend,link);
- //判断当前节点的优先等级是否大于handler的优先等级
- //以此决定handler在链表中的顺序
- if(e->level>handler->level)
- break;
- }
- //将handler加入当前节点之前,优先等级越低越靠前
- list_add_tail(&handler->link,pos);
- if((state&SUSPENDED)&&handler->suspend)
- handler->suspend(handler);
- mutex_unlock(&early_suspend_lock);
- }
- EXPORT_SYMBOL(register_early_suspend);
注册的流程比较简单,首先遍历链表,依次比较每个节点的优先等级,如果遇到优先等级比新节点优先等级高则跳出,然后将新节点加入优先等级较高的节点前面,这样就确保了链表是优先等级低在前高在后的顺序;在将节点加入链表后查看当前状态是否为浅度休眠完成状态,如果是则执行handler的suspend函数。
[cpp] view plain copy- voidunregister_early_suspend(structearly_suspend*handler)
- {
- mutex_lock(&early_suspend_lock);
- list_del(&handler->link);
- mutex_unlock(&early_suspend_lock);
- }
- EXPORT_SYMBOL(unregister_early_suspend);
注销流程则只是将节点从链表中移除。
4、request_suspend_state
前面我们看到用户空间在写/sys/power/state节点的时候会执行request_suspend_state()函数,该函数代码如下:
[cpp] view plain copy- voidrequest_suspend_state(suspend_state_tnew_state)
- {
- unsignedlongirqflags;
- intold_sleep;
- spin_lock_irqsave(&state_lock,irqflags);
- old_sleep=state&SUSPEND_REQUESTED;
- //打印当前状态
- if(debug_mask&DEBUG_USER_STATE){
- structtimespects;
- structrtc_timetm;
- 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.%09luUTC)\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_mday,
- tm.tm_hour,tm.tm_min,tm.tm_sec,ts.tv_nsec);
- }
- //如果新状态是休眠状态
- if(!old_sleep&&new_state!=PM_SUSPEND_ON){
- state|=SUSPEND_REQUESTED;
- pr_info("sys_sync_work_queueearly_sys_sync_work.\n");
- //执行缓存同步与浅度休眠的工作队列
- queue_work(sys_sync_work_queue,&early_sys_sync_work);
- queue_work(suspend_work_queue,&early_suspend_work);
- }elseif(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);
- }
函数首先打印出当前状态变化的log,然后判断新状态,如果是休眠状态则置位SUSPEND_REQUESTED标志,然后将同步缓存、浅度休眠工作队列加入相应的内核线程执行;如果新状态是唤醒则首先将main_wake_lock激活,然后再将浅度唤醒工作队列加入内核线程执行;最后更新全局状态变量,因为提供了一个内核空间接口用于获取当前休眠唤醒状态:
[cpp] view plain copy- //返回系统状态值
- suspend_state_tget_suspend_state(void)
- {
- returnrequested_suspend_state;
- }
5、early_suspend_work、late_resume_work 和early_sys_sync
[cpp] view plain copy- staticvoidearly_suspend(structwork_struct*work)
- {
- structearly_suspend*pos;
- unsignedlongirqflags;
- intabort=0;
- mutex_lock(&early_suspend_lock);
- spin_lock_irqsave(&state_lock,irqflags);
- if(state==SUSPEND_REQUESTED)//判断当前状态是否在请求浅度休眠
- state|=SUSPENDED;//如果是则置位SUSPENDED
- else
- abort=1;
- spin_unlock_irqrestore(&state_lock,irqflags);
- if(abort){//取消early_suspend
- if(debug_mask&DEBUG_SUSPEND)
- pr_info("early_suspend:abort,state%d\n",state);
- mutex_unlock(&early_suspend_lock);
- gotoabort;
- }
- if(debug_mask&DEBUG_SUSPEND)
- pr_info("early_suspend:callhandlers\n");
- //遍历浅度休眠链表并执行其中所有suspend函数
- //执行顺序根据优先等级而定,等级越低越先执行
- list_for_each_entry(pos,&early_suspend_handlers,link){
- if(pos->suspend!=NULL)
- pos->suspend(pos);
- }
- mutex_unlock(&early_suspend_lock);
- if(debug_mask&DEBUG_SUSPEND)
- pr_info("early_suspend:sync\n");
- /*Removesys_syncfromearly_suspend,anduseworkqueuetocompletesys_sync*/
- //sys_sync();
- abort:
- spin_lock_irqsave(&state_lock,irqflags);
- if(state==SUSPEND_REQUESTED_AND_SUSPENDED)
- wake_unlock(&main_wake_lock);
- spin_unlock_irqrestore(&state_lock,irqflags);
- }
在suspend流程中首先判断当前状态是否为SUSPEND_REQUESTED,如果是则置位SUSPENDED标志,如果不是则取消suspend流程;然后遍历浅度休眠链表,从链表头部到尾部依次调用各节点的suspend()函数,执行完后判断当前状态是否为SUSPEND_REQUESTED_AND_SUSPENDED,如果是则释放main_wake_lock,当前系统中如果只存在main_wake_lock这个有效锁,则会在wake_unlock()里面启动深度休眠线程,如果还有其他其他wake_lock则保持当前状态。
[cpp] view plain copy- staticvoidlate_resume(structwork_struct*work)
- {
- structearly_suspend*pos;
- unsignedlongirqflags;
- intabort=0;
- mutex_lock(&early_suspend_lock);
- spin_lock_irqsave(&state_lock,irqflags);
- if(state==SUSPENDED)//清除浅度休眠完成标志
- state&=~SUSPENDED;
- else
- abort=1;
- spin_unlock_irqrestore(&state_lock,irqflags);
- if(abort){
- if(debug_mask&DEBUG_SUSPEND)
- pr_info("late_resume:abort,state%d\n",state);
- gotoabort;
- }
- if(debug_mask&DEBUG_SUSPEND)
- pr_info("late_resume:callhandlers\n");
- //反向遍历浅度休眠链表并执行其中所有resume函数
- //执行顺序根据优先等级而定,等级越高越先执行
- list_for_each_entry_reverse(pos,&early_suspend_handlers,link)
- if(pos->resume!=NULL)
- pos->resume(pos);
- if(debug_mask&DEBUG_SUSPEND)
- pr_info("late_resume:done\n");
- abort:
- mutex_unlock(&early_suspend_lock);
- }
在resume流程中同样首先判断当前状态是否为SUSPENDED,如果是则清除SUSPENDED标志,然后反向遍历浅度休眠链表,按照优先等级从高到低的顺序执行节点的resume()函数。
更多相关文章
- Android Activity生命周期和状态
- Android 判断网络状态,并且在没有网络的时候,提示网络未开启
- Android中程序的停止状态详细介绍
- android(java)对网络状态(socket)判断的方法
- Android存储设备(U盘,SD卡)状态监测(《Android 2.3 SD卡挂载流程
- Android 设置状态栏及Activity横屏或竖屏。
- Android获取屏幕高度、标题高度、状态栏高度详解
- Android 沉浸式状态栏 头部可拉伸带有一键置顶功能
- Android Studio设置 标题栏隐藏, 状态栏隐藏, 改变状态栏文字颜