当手机满足一定的条件时,会进入休眠状态。从手机进入休眠到唤醒,主要分为三个阶段:

early suspend

suspend

late resume

early suspend执行在休眠前需要完成的一些工作,late resume完成在退出休眠后进行的一些扫尾工作。early suspend与late resume执行的操作是一一对应的。

early_suspend的结构

需要early suspend和late resume执行的操作,通过函数register_early_suspend注册,unregister_early_suspend取消注册。

early_suspend的结构体如下:

struct early_suspend {

struct list_head link;

int level;//节点的级别,控制执行顺序

void (*suspend)(struct early_suspend *h);//early_suspend执行的函数

void (*resume)(struct early_suspend *h);//late_resume执行的函数

};

register_early_suspend(struct early_suspend *handler)

{

struct list_head *pos;

list_for_each(pos, &early_suspend_handlers) {

struct early_suspend *e;

e = list_entry(pos, struct early_suspend, link);

if (e->level > handler->level)

break;

}

list_add_tail(&handler->link, pos);

if ((state & SUSPENDED) && handler->suspend)

handler->suspend(handler);

}

注册early_suspend变量,就是在链表early_suspend_handlers中增加该节点,level小的节点排前面。所有early_suspend注册结束后,early_suspend_handlers就是按照节点的level从小到大排列的链表。

early suspend的执行

在文件系统中有一个虚拟的文件:/sys/power/state

向该文件写入字符串“mem”,则启动进入休眠的过程。

向该文件写入字符串“on”,则手机退出休眠状态。

其中Constchar*const pm_states[PM_SUSPEND_MAX] = {

[PM_SUSPEND_ON]="on",

...................

[PM_SUSPEND_MEM]= "mem",

};

向state文件写入字符串,对应函数的操作如下:

static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,

const char *buf, size_t n)

{

suspend_state_t state = PM_SUSPEND_ON;//初始化值为“on”=0

const char * const *s;

char *p;

int len;

p = memchr(buf, '\n', n);

len = p ? p - buf : n;//取出输入字符串的长度

for (s = &pm_states[state]; state

if (*s && len == strlen(*s) && !strncmp(buf, *s, len))

break;//找到对应的输入状态

}

if (state

if (state == PM_SUSPEND_ON || valid_state(state)) {//如果状态为“on”或者“mem”

request_suspend_state(state);//调用该函数

}

}

——————————————————————————————————————————————————————————————————————————————

/*回调函数的注册与实现*/

static struct platform_suspend_opsmsm_pm_ops= {

.enter = msm_pm_enter,

.valid = suspend_valid_only_mem,

};

static int __init msm_pm_init(void)

suspend_set_ops(&msm_pm_ops);

suspend_ops = ops;

其中static const struct platform_suspend_ops *suspend_ops;是本文件的全局变量

bool valid_state(suspend_state_t state)

{

//调用上面注册valid函数

returnsuspend_ops&&suspend_ops->valid &&suspend_ops->valid(state);

}

上面注册的valid函数如下:

int suspend_valid_only_mem(suspend_state_t state)

{

return state ==PM_SUSPEND_MEM;

}

这些枚举变量定义如下:

#define PM_SUSPEND_ON((__force suspend_state_t) 0)

#define PM_SUSPEND_STANDBY((__force suspend_state_t) 1)

#define PM_SUSPEND_MEM((__force suspend_state_t) 3)

#define PM_SUSPEND_MAX((__force suspend_state_t) 4)

还有一个函数是msm_pm_enter

static int msm_pm_enter(suspend_state_t state)

{

................................

rs_limits = msm_rpmrs_lowest_limits(false,

MSM_PM_SLEEP_MODE_POWER_COLLAPSE, -1, -1);

...........................

if (rs_limits) {

ret = msm_rpmrs_enter_sleep(msm_pm_max_sleep_time, rs_limits, false, true);

if (!ret) {

int collapsed = msm_pm_power_collapse(false);//进入休眠,等待中断

collapsed = msm_pm_spm_power_collapse(cpu, from_idle, true);

collapsed = msm_pm_l2x0_power_collapse();

msm_pm_collapse();

ENTRY(msm_pm_collapse)//idle-v7.S(arch\arm\mach-msm)

....................

Wfi//休眠在此

............

msm_rpmrs_exit_sleep(rs_limits, false, true, collapsed);//退出休眠

}

}

enter_exit:

if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)

pr_info("%s: return\n", __func__);

return 0;

}

其中wfi指令定义如下:

#define wfi()__asm__ __volatile__ ("wfi" : : : "memory")

WFI(Wait For Interrupt)指令,讓ARM等待外部中斷例如:IRQ或FIQ,對產品端而言就是手機的按鍵或是透過Real-Time Clock的中斷,喚醒處理器,恢復正常的執行.

WFI 会暂时将执行中断挂起,直至发生以下事件后再恢复执行:

发生 IRQ中断,不考虑CPSR I位

发生 FIQ中断,不考虑CPSR F位

发生不精确的数据中止,除非被 CPSR A位屏蔽

出现调试进入请求,无论是否启用调试

——————————————————————————————————————————————————————————————————————————————

接着上面的函数讲request_suspend_state()

enum {

SUSPEND_REQUESTED = 0x1,

SUSPENDED = 0x2,

SUSPEND_REQUESTED_AND_SUSPENDED=SUSPEND_REQUESTED| SUSPENDED,

};

static int state;// state全局变量

void request_suspend_state(suspend_state_t new_state)

{

unsigned long irqflags;

int old_sleep;

old_sleep = state & SUSPEND_REQUESTED; //保存旧的suspend状态

//如果旧的状态不为SUSPEND_REQUESTED,并且新请求的状态为“mem”

if (!old_sleep && new_state != PM_SUSPEND_ON) {

state |= SUSPEND_REQUESTED;//把state的状态置为SUSPEND_REQUESTED

queue_work(suspend_work_queue, &early_suspend_work);//进入early suspend的处理

} else if (old_sleep && new_state == PM_SUSPEND_ON) {

//如果旧的状态为SUSPEND_REQUESTED,并且新请求的状态为“on”

state &= ~SUSPEND_REQUESTED;//清除SUSPEND_REQUESTED标记

wake_lock(&main_wake_lock);//锁定main_wake_lock,进入late resume处理流程

queue_work(suspend_work_queue, &late_resume_work);

}

requested_suspend_state= new_state;//保存请求的状态

}

下面看下early_suspend_work,late_resume_work的注册处理Wakelock.c (kernel\power)

static DEFINE_SPINLOCK(list_lock);

static LIST_HEAD(inactive_locks);

static struct list_headactive_wake_locks[WAKE_LOCK_TYPE_COUNT];

struct workqueue_struct *suspend_work_queue;

struct wake_lockmain_wake_lock;

suspend_state_trequested_suspend_state= PM_SUSPEND_MEM;

static int __init wakelocks_init(void)

{

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);

..................

suspend_work_queue= create_singlethread_workqueue("suspend");

}

下面看下两个work的声明

static DECLARE_WORK(early_suspend_work, early_suspend);

static DECLARE_WORK(late_resume_work, late_resume);

处理函数如下

static void early_suspend(struct work_struct *work)

{

struct early_suspend *pos;

if (state == SUSPEND_REQUESTED)

state |= SUSPENDED;//如果为request,则继续置位suspend

else

abort = 1;

if (abort) {

goto abort;

}

suspend_sys_sync_queue();

abort:

if (state == SUSPEND_REQUESTED_AND_SUSPENDED)//如果状态为3

wake_unlock(&main_wake_lock);//解锁main_wake_lock

}

下面是该函数的实现:suspend_sys_sync_queue

static DECLARE_WORK(suspend_sys_sync_work,suspend_sys_sync);

void suspend_sys_sync_queue(void)

{

ret = queue_work(suspend_sys_sync_work_queue, &suspend_sys_sync_work);

if (ret)

suspend_sys_sync_count++;//该work还没执行完

}

static voidsuspend_sys_sync(struct work_struct *work)

{

pr_info("PM: Syncing filesystems...\n");

sys_sync();//具体做同步文件系统的操作

pr_info("sync done.\n");

suspend_sys_sync_count--;//执行完毕,减一

}

static void late_resume(struct work_struct *work)

{

if (state == SUSPENDED)

state &= ~SUSPENDED;//把全局变量状态state取反

pr_info("late_resume: done\n");

}

下面进入wakelock的操作:

一个线程运行时,如果要防止手机进入休眠,则需要定义一个wake_lock,并且锁定该wake_lock。当允许睡眠时,解锁该wake_lock。以alarm设置的wake_lock (kernel\drivers\rtc\ alarm.c)为例:

定义:

static struct wake_lock alarm_rtc_wake_lock;

初始化

wake_lock_init(&alarm_rtc_wake_lock, WAKE_LOCK_SUSPEND, "alarm_rtc");

阻止手机进入睡眠时,锁定该wake_lock:

wake_lock(&alarm_rtc_wake_lock);

wake_lock_timeout(&alarm_rtc_wake_lock, 1 * HZ);

允许手机进入睡眠时,解除锁定:

wake_unlock(&alarm_rtc_wake_lock);

wake_lock结构体的定义如下:(用于统计的字段没有列出)

struct wake_lock {

struct list_head   link;//加入链表时用

int                flags;//wake_lock的标志

const char         *name;//名称

unsigned long      expires;//超时记录

};

其中,flags各个bit的定义如下:

#define WAKE_LOCK_TYPE_MASK              (0x0f)

#define WAKE_LOCK_INITIALIZED            (1U /初始化时设置

#define WAKE_LOCK_ACTIVE                 (1U /锁定时设置

#define WAKE_LOCK_AUTO_EXPIRE            (1U /定时锁定时设置

#define WAKE_LOCK_PREVENTING_SUSPEND     (1U <

wake_lock的类型定义如下:

enum {

WAKE_LOCK_SUSPEND, /* Prevent suspend */

WAKE_LOCK_IDLE,    /* Prevent low power idle */

WAKE_LOCK_TYPE_COUNT

};

void wake_lock_init(struct wake_lock *lock, int type, const char *name)

{

lock->name = name;

lock->flags = (type & WAKE_LOCK_TYPE_MASK) | WAKE_LOCK_INITIALIZED;

INIT_LIST_HEAD(&lock->link);

list_add(&lock->link, &inactive_locks);

}

初始化时,把该wake_lock放入不活动的链表inactive_locks。

static LIST_HEAD(inactive_locks);

以下时刻会把一个wake_lock放入inactive_locks链表:

初始化wake_lock_init

解锁wake_lock

定时锁定超时expire_wake_lock

以下两个函数执行锁定wake_lock的操作:

void wake_lock(struct wake_lock *lock)

{

wake_lock_internal(lock, 0, 0);

}

void wake_lock_timeout(struct wake_lock *lock, long timeout)

{

wake_lock_internal(lock, timeout, 1);

}

wake_lock是硬锁定,只有通过wake_unlock才能解锁。

wake_lock_timeout则只锁定一段时间,超时后,自动解除锁定。

两个函数都调用wake_lock_internal。

wake_lock_internal的主要操作:

static void wake_lock_internal(struct wake_lock *lock, long timeout, int has_timeout)

{

type = lock->flags & WAKE_LOCK_TYPE_MASK;  // WAKE_LOCK_SUSPEND = 0

lock->flags |= WAKE_LOCK_ACTIVE;

list_del(&lock->link);//从inactive_locks链表中删除

if (has_timeout) {

lock->expires = jiffies + timeout;

lock->flags |= WAKE_LOCK_AUTO_EXPIRE;

list_add_tail(&lock->link, &active_wake_locks[type]);

}

else {

lock->expires = LONG_MAX;

lock->flags &= ~WAKE_LOCK_AUTO_EXPIRE;

list_add(&lock->link, &active_wake_locks[type]);

}

if (type == WAKE_LOCK_SUSPEND) { //如果类型为WAKE_LOCK_SUSPEND

current_event_num++;

if (has_timeout)

expire_in = has_wake_lock_locked(type);//检查活动的wake_locks链表

else

expire_in = -1;

if (expire_in > 0) {

mod_timer(&expire_timer, jiffies + expire_in);//超时时间没到期

} else {

del_timer(&expire_timer)//没有超时

if (expire_in == 0)//没有锁定的wakelock,则suspend_work压入工作队列

queue_work(suspend_work_queue, &suspend_work);

}

}

锁定wake_lock时,把该wake_lock从inactive_locks链表中删除,然后加入active_wake_locks[type]链表,其定义如下:

static struct list_head active_wake_locks[WAKE_LOCK_TYPE_COUNT];

enum {

WAKE_LOCK_SUSPEND, /* Prevent suspend */

WAKE_LOCK_IDLE,    /* Prevent low power idle */

WAKE_LOCK_TYPE_COUNT

};

void wake_unlock(struct wake_lock *lock)

{

int type;

unsigned long irqflags;

spin_lock_irqsave(&list_lock, irqflags);

type = lock->flags & WAKE_LOCK_TYPE_MASK;

lock->flags &= ~(WAKE_LOCK_ACTIVE | WAKE_LOCK_AUTO_EXPIRE);

list_del(&lock->link);

list_add(&lock->link, &inactive_locks);

if (type == WAKE_LOCK_SUSPEND) {

long has_lock = has_wake_lock_locked(type);//检查活动的wake_locks链表

if (has_lock > 0) {

mod_timer(&expire_timer, jiffies + has_lock);

} else {

del_timer(&expire_timer)

if (has_lock == 0)

queue_work(suspend_work_queue, &suspend_work);

}

}

}

解锁一个wake_lock时,先设置其flag,然后把该wake_lock从活动的wake_locks链表中删除,加入非活动的wake_locks链表中。

上面两个函数同时都调到has_wake_lock_locked函数,来检查活动的wake_locks链表

static long has_wake_lock_locked(int type) {

long max_timeout = 0;

list_for_each_entry_safe(lock, n, &active_wake_locks[type], link) {

if (lock->flags & WAKE_LOCK_AUTO_EXPIRE) {

long timeout = lock->expires - jiffies;

if (timeout <= 0)

expire_wake_lock(lock);

else if (timeout > max_timeout)

max_timeout = timeout;

} else

return -1;

}

return max_timeout;

}

has_wake_lock_locked返回三类数值:

大于0,活动的wake_lock中没有硬锁定的wake_lock,有定时锁定的wake_lock,返回值为最大的超时时间与当前时间的差。这时会启动定时器expire_timer,该定时器超时后执行函数expire_wake_locks,这时会再次检查是否有活动的wake_lock,如果没有了,则把suspend_work压入工作队列。

等于0,活动的wake_lock中没有硬锁定的wake_lock,定时锁定的wake_lock都已超时,解除了锁定(expire_wake_lock)。此时已没有任何锁定的wake_lock,可以执行休眠的操作了,把suspend_work压入工作队列。

小于0,-1,活动的wake_lock中有硬锁定的wake_lock。此时只能等待调用wake_unlock解除对应wake_lock的锁定。

static DECLARE_WORK(suspend_work, suspend);//所有的wakelock都解锁后,执行该函数

static DEFINE_TIMER(expire_timer, expire_wake_locks, 0, 0); //超时后,执行该函数

static void expire_wake_locks(unsigned long data)

{

long has_lock;

has_lock = has_wake_lock_locked(WAKE_LOCK_SUSPEND);//检查有没有锁定?

if (has_lock == 0)

queue_work(suspend_work_queue, &suspend_work);

}

无论通过哪种途径,只要最后检测到没有锁定的wake_lock,则把suspend对应的work放入工作队列suspend_work_queue。

工作队列suspend_work_queue专门处理休眠唤醒相关的操作,在文件Wakelock.c (kernel\power)中定义:

struct workqueue_struct *suspend_work_queue;

在函数wakelocks_init中初始化:

suspend_work_queue = create_singlethread_workqueue("suspend");

static void suspend(struct work_struct *work)

{

suspend_sys_sync_queue();//同步文件系统

pr_info("suspend: enter suspend\n");

ret = pm_suspend(requested_suspend_state);

}

跟踪调用关系:

int pm_suspend(suspend_state_t state)

enter_state(state);

suspend_sys_sync_queue(); //同步文件系统

suspend_prepare();//(1)

suspend_devices_and_enter(state);//(2)

suspend_finish();//(3)与suspend_prepare函数的后半部分对比,完全相同。

挂起用户空间进程

——————————————————————————————————————

(1)suspend_prepare();

static int suspend_prepare(void)

{

pm_prepare_console();

error = pm_notifier_call_chain(PM_SUSPEND_PREPARE);

if (error)

goto Finish;

error = usermodehelper_disable();

if (error)

goto Finish;

error = suspend_freeze_processes();// 让各个进程进入休眠,可能某些进程不能进入休眠,// 则返回失败

if (!error)//如果顺利,正常进入休眠,从这里返回,否则,唤醒进程

return 0;

suspend_thaw_processes();// 后半部分恢复的操作,与suspend_finish的操作相同

usermodehelper_enable();

Finish:

pm_notifier_call_chain(PM_POST_SUSPEND);

pm_restore_console();

return error;

}

其中suspend_freeze_processes();

int freeze_processes(void)//从串口打出来的log就是从该函数输出

{

printk("Freezing user space processes ... ");

error = try_to_freeze_tasks(true);

printk("done.\n");

error = suspend_sys_sync_wait();

printk("Freezing remaining freezable tasks ... ");

error = try_to_freeze_tasks(false);

printk("done.");

}

其中suspend_thaw_processes();

void thaw_processes(void)

{

printk("Restarting tasks ... ");

................

printk("done.\n");

}

——————————————————————————————————

设备的挂起,唤醒过程

——————————————————————————————————

(2)suspend_devices_and_enter()

int suspend_devices_and_enter(suspend_state_t state)

{

...............

suspend_console(); // 禁止控制台打印,此后,串口没有打印输出,此时会输出log://"Suspending console(s) (use no_console_suspend to debug)

..........

error = dpm_suspend_start(PMSG_SUSPEND);(2-1)

.....................

error = suspend_enter(state);(2-2)//休眠于此

Resume_devices:

dpm_resume_end(PMSG_RESUME);(2-3)

resume_console();

}

(2-1)dpm_suspend_start()//进入休眠

int dpm_suspend_start(pm_message_t state)

{

dpm_prepare(state);// 逐个执行每个device注册的prepare函数

dpm_suspend(state);// 逐个执行每个device注册的suspend函数

}

(2-2)suspend_enter(state);

suspend_ops->enter(state);//该函数已在前面分析过(msm_pm_enter),设备休眠在此

//唤醒后,继续向下执行

(2-3)dpm_resume_end()//退出休眠

void dpm_resume_end(pm_message_t state)

{

dpm_resume(state);// 逐个执行每个device的resume函数

dpm_complete(state);// 逐个执行每个device的complete函数

}

android 休眠唤醒驱动流程分析,Android4.0.4休眠唤醒机制分析(基于MSM8260)相关推荐

  1. android移植wifi驱动流程porting

    android载入wifi驱动流程 wifi_load_driver check_wifi_chip_type_string get_wifi_device_id save_wifi_chip_typ ...

  2. 华为荣耀android是什么系统,华为荣耀Android4.0系统正式发布

    查看原图 腾讯数码讯(水蓝)华为荣耀Honor手机自发布以来便有着超高的关注度,尤其是最近CDMA版本的亮相更是引人瞩目.不过,现在这款手机真正吸引人的则是最新Android 4.0 商用版的正式发布 ...

  3. android智能云电视,率先升级Android4.0 TCL3D智能云电视独领技术风潮

    自去年底全新Android4.0操作系统发布,就以其超炫的UI界面及大幅提升的流畅体验迅速俘获了千万时尚人士的"芳心",搭载该系统更成为了高端智能产品的标志之一.权威彩电专家指出, ...

  4. android休眠唤醒驱动流程分析【转】

    转自:http://blog.csdn.net/hanmengaidudu/article/details/11777501 标准linux休眠过程: l        power managemen ...

  5. android 休眠唤醒驱动流程分析,Android 电源管理——gotosleep和userActivity关注

    一.Android power management应用层分析 Android提供了android.os.PowerManager类,该类用于控制设备的电源状态的切换. 该类对外有三个接口函数: 1. ...

  6. android gallery2源码分析,Android4.2.2 Gallery2源码分析(8)——假装的Activity

    两周的奋战,终于对Gallery的结构有了个大致的了解.Gallery是一个很好的Android系统知识的学习源码,不仅仅因为它设计到了多线程,布局优化,Opengl的结合等等内容.还有两点必须说明的 ...

  7. android高仿股票源码,从0到1开发 股票分析APP(附源码)

    前言:再给自己挖个坑吧. 我想写个什么东西呢? 一:可以浏览当下相关资讯,以及大盘指数实时更新. 二:添加自选股票,可以查看该股票的走势图,相关资讯以及基本数据. 三:通过 server 端定义相关指 ...

  8. Android中级第十一讲之MotionEvent的分发、拦截机制分析

    最近在研究事件分发机制,一方面在看内核剖析,一方面找测试小例子,最终找到,内容如下,--下载地址 咱们就借这个小例子来讲一些问题 一开始只关注了onTouch事件,应用于Window层,用于对操作事件 ...

  9. [网络安全自学篇] 七十.WannaCry勒索病毒复现及分析(三)蠕虫传播机制分析及IDA和OD逆向

    这是作者网络安全自学教程系列,主要是关于安全工具和实践操作的在线笔记,特分享出来与博友们学习,希望您们喜欢,一起进步.前文分享了宏病毒相关知识,包括宏病毒基础原理.防御措施.自发邮件及APT28样本分 ...

最新文章

  1. 使用 AFNetworking 进行 XML 和 JSON 数据请求
  2. 数据结构之二叉搜索树/二叉查找数/有序二叉树/排序二叉树
  3. 解决fragment replace 重叠现象
  4. 移动端html游戏开发,GitHub - PromeYang/GameBuilder: GameBuilder 是移动端轻量HTML5游戏快速开发框架,主要应用于活动推广。...
  5. hive olap 数据仓库_数据仓库系统的实现和使用(含OLAP重点讲解)
  6. mysql索引篇之覆盖索引、联合索引、索引下推
  7. RPC远程过程调用之Hessian 基于HTTP
  8. 这个开源组织里的项目都是精品
  9. 玩游戏提示计算机性能过低,如果玩游戏的fps低怎么办?八个问题和九个解决方案...
  10. redis怎么连接mysql数据库_Golang连接Redis数据库的方法
  11. 我的docker随笔3:实现加速器,加快拉取镜像速度
  12. arm linux输出到lcd,求助 armlinux中实现lcd显示
  13. Kubeflow:连接云计算和机器学习的“桥梁”
  14. php 非常简单的导入sql文件
  15. 如何删除电脑里的android驱动程序,驱动安装失败 如何手动清除旧驱动程序
  16. 使用JS访问本地数据库
  17. 用LED驱动框架注册led设备的示例代码
  18. java floor(),Java floor()用法及代码示例
  19. eNSP模拟简单网络环境
  20. HSB/HSV/HSL区别

热门文章

  1. 如何编写Ruby控制台程序(一)
  2. CCIE基础知识之EIGRP 二
  3. Catlyst 6509告警信息--把trunk口配置成access
  4. 详细整理Spring事务失效的具体场景及解决方案
  5. java的异常处理块的形式_Java 异常处理详细解读
  6. 解决eclipse 文件更新不自动刷新的问题
  7. 对抗神经机器翻译:GAN+NMT 模型,中国研究者显著提升机翻质量
  8. 【Linux】Linux 标准目录结构
  9. Ubuntu查看及修改IP地址
  10. sql where 1=1 妙用之一方面