1.用户空间的接口
在kernel/power/main.c中,定义了一组sysfs的属性文件,其中一个定义是:
power_attr(state);
把这个宏展开后:
[cpp]view plaincopy
staticstructkobj_attributestate_attr={\
.attr={\
.name=state,\
.mode=0644,\
},\
.show=state_show,\
.store=state_store,\
}
我们再看看main.c的入口:
[cpp]view plaincopy
staticint__initpm_init(void)
{
......
power_kobj=kobject_create_and_add(power,null);
if(!power_kobj)
return-enomem;
returnsysfs_create_group(power_kobj,&attr_group);
}
显然,该函数执行后,会在生成/sys/power目录,该目录下会建立一系列属性文件,其中一个就是/sys/power/state文件。用户空间向该文件的写入将会导致state_store被调用,读取该文件将会导致state_show函数被调用。
现在回到android的hal层中,查看一下代码:hardware/libhardware_legacy/power/power.c:
[cpp]view plaincopy
//定义写入/sys/power/state的命令字符串
staticconstchar*off_state=mem;
staticconstchar*on_state=on;
//打开/sys/power/state等属性文件,保存相应的文件描述符
staticint
open_file_descriptors(constchar*constpaths[])
{
inti;
for(i=0;i
intfd=open(paths[i],o_rdwr);
if(fd<0){
fprintf(stderr,fatalerroropening\%s\\n,paths[i]);
g_error=errno;
return-1;
}
g_fds[i]=fd;
}
g_error=0;
return0;
}
最终,用户空间的电源管理系统会调用set_screen_state函数来触发suspend的流程,该函数实际上就是往/sys/power/state文件写入mem或on命令字符串。
[cpp]view plaincopy
int
set_screen_state(inton)
{
......
initialize_fds();
......
charbuf[32];
intlen;
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);
......
return0;
}
/********************************************************************************************/
声明:本博内容均由http://blog.csdn.net/droidphone原创,转载请注明出处,谢谢!
/********************************************************************************************/
2.内核中数据结构和接口
与earlysuspend相关的数据结构和接口都在earlysuspend.h中进行了定义。
- early_suspend 结构
[cpp]view plaincopy
structearly_suspend{
#ifdefconfig_has_earlysuspend
structlist_headlink;
intlevel;
void(*suspend)(structearly_suspend*h);
void(*resume)(structearly_suspend*h);
#endif
};
希望执行early suspend的设备,他的设备驱动程序需要向电源管理系统注册,该结构体用于向电源管理系统注册earlysuspend/lateresume,当电源管理系统启动suspend流程时,回调函数suspend会被调用,相反,resume的最后阶段,回调函数resume会被调用,level字段用于调整该结构体在注册链表中的位置,suspend时,level的数值越小,回调函数的被调用的时间越早,resume时则反过来。android预先定义了3个level等级:
[cpp]view plaincopy
enum{
early_suspend_level_blank_screen=50,
early_suspend_level_stop_drawing=100,
early_suspend_level_disable_fb=150,
};
[cpp]view plaincopy
如果你想你的设备在fb设备被禁止之前执行他的earlysuspend回调,设备驱动程序应该把level值设定为小于150的某个数值,然后向系统注册early_suspend结构。注册和反注册函数是:
void register_early_suspend(struct early_suspend *handler);
void unregister_early_suspend(struct early_suspend *handler);
- early_suspend_handlers链表
所有注册到系统中的early_suspend结构都会按level值按顺序加入到全局链表early_suspend_handlers中。
3.工作流程
首先,我们从kernel/power/wakelock.c中的初始化函数开始:
[cpp]view plaincopy
staticint__initwakelocks_init(void)
{
intret;
inti;
......
for(i=0;i
init_list_head(&active_wake_locks[i]);
......
wake_lock_init(&main_wake_lock,wake_lock_suspend,main);
wake_lock(&main_wake_lock);
wake_lock_init(&unknown_wakeup,wake_lock_suspend,unknown_wakeups);
......
ret=platform_device_register(&power_device);
ret=platform_driver_register(&power_driver);
......
suspend_work_queue=create_singlethread_workqueue(suspend);
......
return0;
}
可以看到,显示初始化active_wake_locks链表数组,然后初始化并且锁住main_wake_lock,注册平台设备power_device,这些数组、锁和power_device我们在后续文章再讨论,这里我们关注的最后一个动作:创建了一个工作队列线程suspend_work_queue,该工作队列是earlysuspend的核心所在。
系统启动完成后,相关的驱动程序通过register_early_suspend()函数注册了early suspend特性,等待一段时间后,如果没有用户活动(例如按键、触控等操作),用户空间的电源管理服务最终会调用第一节提到的set_screen_state()函数,透过sysfs,进而会调用到内核中的state_store():
[cpp]view plaincopy
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
if(*s&&len==strlen(*s)&&!strncmp(buf,*s,len))
break;
}
if(statesuspend != null) {
if (debug_mask &debug_suspend)
printk(kern_debugpos->suspend: %pf begin\n, pos->suspend);
pos->suspend(pos);
if (debug_mask &debug_suspend)
printk(kern_debugpos->suspend: %pf finish\n, pos->suspend);
}
}
mutex_unlock(&early_suspend_lock);
if (debug_mask & debug_suspend)
pr_info(early_suspend:sync\n);
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);
}
终于看到啦,early_suspend()遍历early_suspend_handlers链表,从中取出各个驱动程序注册的early_suspend结构,然后调用它的suspend回调函数。最后,释放main_wake_lock锁,至此整个earlysuspend的流程完成。下面的序列图清晰地表明了整个调用的过程:
图3.1 early suspend调用流程
但是,这时整个系统只是处于所谓的idle状态,cpu还在工作,后台进程也在工作中,那什么时候系统会真正地进入睡眠状态?注意到最后一句关键的调用了没有:
wake_unlock(&main_wake_lock);
使用obd接口有何风险
使用VPLC控制器进行图像拼接的实例
实时频谱分析仪中如何选择合适的FFT窗函数
三星推出新款Galaxy Note 9希望能够吸引iPhone用户
AI种的草莓,确实没有人工的甜
基于Android的Linux内核的电源管理:Early Suspend
英飞凌针对中国市场推出全新XMC1000工业和消费类单片机家族
摩托罗拉XT701 3G手机开始预售
外资PCB厂商处于领先地位,内资PCB厂商迎头赶上
智慧路灯如何实现盈利
FHX机架式光纤配线箱的特点和安装说明
浅谈AFC(AFT)电路
智能仪表非线性自动校正方法探讨
具有领先性能、功率和面积比的GPU IP——The PowerVR Series8XT
构成区块链安全漏洞的主要因素有哪些
dfrobot10段 LED光柱简介
四个特征定义大数据,完善大数据的定义
亚马逊Alexa引领,智能语音助手掀新篇章
CVPR 2023 | 华科&MSRA新作:基于CLIP的轻量级开放词汇语义分割架构
半导体收音机的电流是多少_半导体收音机对人体有辐射吗