Android待机的suspend_sys_sync_queue分析


Android的4.0在待机机制上和之前版本大同小异,也可以说是机制相对完善并没多大的问题反馈出来。不过有个细节的地方,改动幅度较大,来看看


在linux待机机制中,开始待机的时候会调用sys_sync函数,sys_sync系统调用被用户空间函数调用,

用来将缓存中的数据写入块设备,sys_sync系统调用将buffer、inode和super在缓存中的数据写入设备。

此函数的介绍参看博文链接http://blog.chinaunix.net/uid-24237502-id-106067.html。


sys_sync函数执行时间长度依文件系统而定,长至上百毫秒,也有若干毫秒。函数执行的必要性如何呢?

如果有种需求,在很短时间(毫秒级)内需要连续进出待机,sys_sync函数是否需要每次都执行一遍呢?

如果只第一次执行,会有什么隐患问题呢?


由于待机请求有自动超时待机和按键进入待机,自动进入待机问题不大,基本上是闹钟或者计时时间发起事件,

而按键进入待机不同,按键时间贯穿kernel到android上层,涉及节点处理,文件系统操作,

所以对同步设备节点数据sys_sync就有需求,可以看出来,android4.0在对sys_sync的调用修改上,也是考虑到按键进入待机的隐藏问题。

那到底做了哪些修改呢?


suspend_sys_sync_queue有三个地方在调用

Earlysuspend.c (kernel\power)

Suspend.c (kernel\power):

Wakelock.c (kernel\power):

定义是在Wakelock.c (kernel\power)中

这个函数实现执行队列中suspend_sys_sync_work

void suspend_sys_sync_queue(void){int ret;spin_lock(&suspend_sys_sync_lock);ret = queue_work(suspend_sys_sync_work_queue, &suspend_sys_sync_work);if (ret)suspend_sys_sync_count++;spin_unlock(&suspend_sys_sync_lock);}

suspend_sys_sync_work_queue =create_singlethread_workqueue("suspend_sys_sync");

static void suspend_sys_sync(struct work_struct *work){if (debug_mask & DEBUG_SUSPEND)pr_info("PM: Syncing filesystems...\n");sys_sync();if (debug_mask & DEBUG_SUSPEND)pr_info("sync done.\n");spin_lock(&suspend_sys_sync_lock);suspend_sys_sync_count--;spin_unlock(&suspend_sys_sync_lock);}static DECLARE_WORK(suspend_sys_sync_work, suspend_sys_sync);

所以调用 suspend_sys_sync_queue,其实最后还是调用sys_sync,只是增加对sys_sync执行次数的计数,以及队列方式执行并非立即执行。

队列方式执行,是对执行的时间上有要求,那么它到底需要等待多少时间呢?相对什么等待呢?

待机,对系统而言,就是冻结,退出待机时候,对系统而言相当于什么事情都没发生。

标准linux待机在待机的开始阶段,就会冻结所有的进程和任务,在唤醒时候恢复它们。

由于进程在kernel空间处理的复杂度,linux在冻结进程和任务的时候,不支持进程还跑在kernel空间,否则就是abort处理。

问题就出来了,最后一次按键进入待机,按键时间从键值采集、键值上报、上层对上报值的轮询、对按键事件分发、对按键时间的处理等,

都需要一定时间,如果在进程未能较快回到用户空间,freeze_processes的时候,如下

printk("Freezing user space processes ... ");error = try_to_freeze_tasks(true);if (error)goto Exit;printk("done.\n");

在freezing user space processes会abort。

补充一下说明:这里针对的不全是最后一次按键,我们知道android为了增加用户体验,在超时进入待机时候,会启动一个5秒的定时闹钟,

从而阻止5秒内真正进入待机,在用户体验上,就是屏幕暗下来的5秒内,只要用户及时点亮屏幕,系统就没真正待机,不会有锁屏界面。

开发员在此过程中会看到freezing user space processes abort,是因为系统启动了alarm,从而推出待机,系统恢复。

这里增加了一个timer,用于等待sys_sync执行完毕

error = suspend_sys_sync_wait();if (error)goto Exit;

int suspend_sys_sync_wait(void){suspend_sys_sync_abort = false;if (suspend_sys_sync_count != 0) {mod_timer(&suspend_sys_sync_timer, jiffies +SUSPEND_SYS_SYNC_TIMEOUT);wait_for_completion(&suspend_sys_sync_comp);}if (suspend_sys_sync_abort) {pr_info("suspend aborted....while waiting for sys_sync\n");return -EAGAIN;}return 0;}

static bool suspend_sys_sync_abort;static void suspend_sys_sync_handler(unsigned long);static DEFINE_TIMER(suspend_sys_sync_timer, suspend_sys_sync_handler, 0, 0);/* value should be less then half of input event wake lock timeout value * which is currently set to 5*HZ (see drivers/input/evdev.c) */#define SUSPEND_SYS_SYNC_TIMEOUT (HZ/4)static void suspend_sys_sync_handler(unsigned long arg){if (suspend_sys_sync_count == 0) {complete(&suspend_sys_sync_comp);} else if (has_wake_lock(WAKE_LOCK_SUSPEND)) {suspend_sys_sync_abort = true;complete(&suspend_sys_sync_comp);} else {mod_timer(&suspend_sys_sync_timer, jiffies +SUSPEND_SYS_SYNC_TIMEOUT);}}

等待的时间should be less then half of input event wake lock timeout value,

evdev事件会超时50ms,这里的timeout需要小于25ms,此处设置为2.5ms。

对timeout的要求,应该是为了能够更快地在evdev超时后执行timer的handler。


以上这些代码,都可以追踪CONFIG_SUSPEND_SYNC_WORKQUEUE宏定义。






更多相关文章

  1. Android(安卓)ActionBar的源代码分析(二)
  2. Android(安卓)Dev Guide -> User Interface
  3. Android中程序与Service交互的方式(三)-总结
  4. Android(安卓)root原理
  5. 浅析android系统设计中的回调思想
  6. Android多媒体学习三:实现自己的Camera
  7. Android中执行java命令的方法及java代码执行并解析shell命令
  8. Android应用开发提高系列(4)――Android动态加载(上)――加载未安装A
  9. Android清单文件详解(四) ---- backupAgent的用法

随机推荐

  1. MySQL 实现lastInfdexOf的功能案例
  2. 深入了解Mysql逻辑架构
  3. MySQL null的一些易错点
  4. MySQL SHOW STATUS语句的使用
  5. MySQL查询缓存的小知识
  6. Mysql技术内幕之InnoDB锁的深入讲解
  7. MySQL 主从同步,事务回滚的实现原理
  8. MySQL 有关MHA搭建与切换的几个错误log汇
  9. MySQL数据归档小工具mysql_archiver详解
  10. 详解MySQL 数据分组