Android的休眠唤醒主要基于wake_lock机制,只要系统中存在任一有效的wake_lock,系统就不能进入深度休眠,但可以进行设备的浅度休眠操作。wake_lock一般在关闭lcd、tp但系统仍然需要正常运行的情况下使用,比如听歌、传输很大的文件等。本文主要分析driver层wake_lock的实现。

一、wake_lock 定义和接口

enum {
WAKE_LOCK_SUSPEND, // 阻止进入深度休眠模式
WAKE_LOCK_IDLE, // 阻止进入空闲模式
WAKE_LOCK_TYPE_COUNT
}; struct wake_lock {
#ifdef CONFIG_HAS_WAKELOCK
struct list_head link; // 链表节点
int flags; // 标志
const char *name; // 名称
unsigned long expires; // 超时时间
#ifdef CONFIG_WAKELOCK_STAT
struct {
int count; // 使用计数
int expire_count; // 超时计数
int wakeup_count; // 唤醒计数
ktime_t total_time; // 锁使用时间
ktime_t prevent_suspend_time; // 锁阻止休眠的时间
ktime_t max_time; // 锁使用时间最长的一次
ktime_t last_time; // 锁上次操作时间
} stat;
#endif
#endif
};

可以看到wake_lock按功能分为休眠锁和空闲锁两种类型,用于阻止系统进入深度休眠模式或者空闲模式。wake_lock的主要部件有锁名称、链表节点、标志位、超时时间,另外还有一个内嵌的结构用于统计锁的使用信息。接下来我们看看wake_lock对外提供的操作接口:

1、内核空间接口

void wake_lock_init(struct wake_lock *lock, int type, const char *name);
void wake_lock_destroy(struct wake_lock *lock);
void wake_lock(struct wake_lock *lock);
void wake_lock_timeout(struct wake_lock *lock, long timeout);
void wake_unlock(struct wake_lock *lock);

其中wake_lock_init()用于初始化一个新锁,type参数指定了锁的类型;wake_lock_destroy()则注销一个锁;wake_lock()和wake_lock_timeout()用于将初始化完成的锁激活,使之成为有效的永久锁或者超时锁;wake_unlock()用于解锁使之成为无效锁。另外还有两个接口:

int wake_lock_active(struct wake_lock *lock);
long has_wake_lock(int type);

其中wake_lock_active()用于判断锁当前是否有效,如果有效则返回非0值;has_wake_lock()用于判断系统中是否还存在有效的type型锁,如果存在超时锁则返回最长的一个锁的超时时间,如果存在永久锁则返回-1,如果系统中不存在有效锁则返回0。

2、用户空间接口

wake_lock向用户空间提供了两个文件节点用于申请锁和解锁:

// wack_lock文件的读函数,显示用户空间定义的有效锁
ssize_t wake_lock_show(
struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
char *s = buf;
char *end = buf + PAGE_SIZE;
struct rb_node *n;
struct user_wake_lock *l; mutex_lock(&tree_lock); for (n = rb_first(&user_wake_locks); n != NULL; n = rb_next(n)) {
l = rb_entry(n, struct user_wake_lock, node);
if (wake_lock_active(&l->wake_lock))
s += scnprintf(s, end - s, "%s ", l->name);
}
s += scnprintf(s, end - s, "\n"); mutex_unlock(&tree_lock);
return (s - buf);
} // wack_lock文件的写函数,初始化并激活用户空间定义的锁
ssize_t wake_lock_store(
struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t n)
{
long timeout;
struct user_wake_lock *l; mutex_lock(&tree_lock);
l = lookup_wake_lock_name(buf, 1, &timeout);
if (IS_ERR(l)) {
n = PTR_ERR(l);
goto bad_name;
} if (debug_mask & DEBUG_ACCESS)
pr_info("wake_lock_store: %s, timeout %ld\n", l->name, timeout); if (timeout)
wake_lock_timeout(&l->wake_lock, timeout);
else
wake_lock(&l->wake_lock);
bad_name:
mutex_unlock(&tree_lock);
return n;
} // wack_unlock文件的读函数,显示用户空间的无效锁
ssize_t wake_unlock_show(
struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
char *s = buf;
char *end = buf + PAGE_SIZE;
struct rb_node *n;
struct user_wake_lock *l; mutex_lock(&tree_lock); for (n = rb_first(&user_wake_locks); n != NULL; n = rb_next(n)) {
l = rb_entry(n, struct user_wake_lock, node);
if (!wake_lock_active(&l->wake_lock))
s += scnprintf(s, end - s, "%s ", l->name);
}
s += scnprintf(s, end - s, "\n"); mutex_unlock(&tree_lock);
return (s - buf);
} // wack_unlock文件的写函数,用于用户空间解锁
ssize_t wake_unlock_store(
struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t n)
{
struct user_wake_lock *l; mutex_lock(&tree_lock);
l = lookup_wake_lock_name(buf, 0, NULL);
if (IS_ERR(l)) {
n = PTR_ERR(l);
goto not_found;
} if (debug_mask & DEBUG_ACCESS)
pr_info("wake_unlock_store: %s\n", l->name); wake_unlock(&l->wake_lock);
not_found:
mutex_unlock(&tree_lock);
return n;
} power_attr(wake_lock);
power_attr(wake_unlock);

这两个文件节点分别为"/sys/power/wake_lock"和"/sys/power/wake_unlock",应用程序可以根据HAL层的接口读写这两个节点。

二、wake_lock 实现

在linux/kernel/power/wakelock.c中我们可以看到wake_lock的实现代码,首先看看其定义的一些初始化信息:

#define WAKE_LOCK_TYPE_MASK              (0x0f)     // 锁类型标志掩码
#define WAKE_LOCK_INITIALIZED (1U << 8) // 锁已经初始化标志
#define WAKE_LOCK_ACTIVE (1U << 9) // 锁有效标志
#define WAKE_LOCK_AUTO_EXPIRE (1U << 10) // 超时锁标志
#define WAKE_LOCK_PREVENTING_SUSPEND (1U << 11) // 正在阻止休眠标志 static DEFINE_SPINLOCK(list_lock); // 读写锁链表的自旋锁
static LIST_HEAD(inactive_locks); // 内核维护的无效锁链表
static struct list_head active_wake_locks[WAKE_LOCK_TYPE_COUNT]; // 有效锁链表
static int current_event_num; // 休眠锁使用计数器
struct workqueue_struct *suspend_work_queue; // 执行系统休眠的工作队列
struct workqueue_struct *sys_sync_work_queue; // 执行系统同步的工作队列
struct wake_lock main_wake_lock; // 内核休眠锁
struct wake_lock sys_sync_wake_lock; // 缓存同步锁
suspend_state_t requested_suspend_state = PM_SUSPEND_MEM; // 系统休眠状态
static struct wake_lock unknown_wakeup; // 未知锁

在后面的分析中我们会看到这些变量的具体用途。

1、wake_lock系统初始化

static int __init wakelocks_init(void)
{
int ret;
int i;
// 初始化有效锁链表,内核维护了2个有效锁链表
// WAKE_LOCK_SUSPEND 用于阻止进入深度休眠模式
// WAKE_LOCK_IDLE 用于阻止进入空闲模式
for (i = 0; i < ARRAY_SIZE(active_wake_locks); i++)
INIT_LIST_HEAD(&active_wake_locks[i]); #ifdef CONFIG_WAKELOCK_STAT
// 初始化deleted_wake_locks
wake_lock_init(&deleted_wake_locks, WAKE_LOCK_SUSPEND,
"deleted_wake_locks");
#endif
// 初始化内核休眠锁
wake_lock_init(&main_wake_lock, WAKE_LOCK_SUSPEND, "main");
// 初始化同步锁
wake_lock_init(&sys_sync_wake_lock, WAKE_LOCK_SUSPEND, "sys_sync");
// 激活内核休眠锁
wake_lock(&main_wake_lock);
// 初始化未知锁
wake_lock_init(&unknown_wakeup, WAKE_LOCK_SUSPEND, "unknown_wakeups"); // 注册power_device,power_driver
ret = platform_device_register(&power_device);
if (ret) {
pr_err("wakelocks_init: platform_device_register failed\n");
goto err_platform_device_register;
}
ret = platform_driver_register(&power_driver);
if (ret) {
pr_err("wakelocks_init: platform_driver_register failed\n");
goto err_platform_driver_register;
}
// 创建fs_sync内核进程
sys_sync_work_queue = create_singlethread_workqueue("fs_sync");
if (sys_sync_work_queue == NULL) {
pr_err ("fs_sync workqueue create failed.\n");
}
// 创建suspend内核进程
suspend_work_queue = create_singlethread_workqueue("suspend");
if (suspend_work_queue == NULL) {
ret = -ENOMEM;
goto err_suspend_work_queue;
} #ifdef CONFIG_WAKELOCK_STAT
// 在proc下创建wakelocks文件
proc_create("wakelocks", S_IRUGO, NULL, &wakelock_stats_fops);
#endif return 0; err_suspend_work_queue:
platform_driver_unregister(&power_driver);
err_platform_driver_register:
platform_device_unregister(&power_device);
err_platform_device_register:
wake_lock_destroy(&unknown_wakeup);
wake_lock_destroy(&main_wake_lock);
#ifdef CONFIG_WAKELOCK_STAT
wake_lock_destroy(&deleted_wake_locks);
#endif
return ret;
}
core_initcall(wakelocks_init);

可以看到内核通过core_initcall调用了wake_lock系统的初始化函数,函数首先初始化了两个有效锁的链表,用于管理系统中的有效锁;接下来初始化了deleted_wake_locks用于处理统计信息,main_wake_lock用于锁定内核(系统启动时会激活这个锁,深度休眠时需要释放这个锁),sys_sync_wake_lock用于浅度休眠阶段同步缓存时阻止内核进入深度休眠,unknown_wakeup用于唤醒时延迟0.5s进入下一次可能的深度休眠;还注册了一个platform_device用于深度休眠阶段检测是否存在有效锁;后面创建了内核进程fs_sync用于浅度休眠阶段同步缓存,内核进程suspend用于进行浅度休眠和深度休眠;还在/proc下面创建了wakelocks节点用于显示wake_lock的统计信息。

2、wake_lock初始化

void wake_lock_init(struct wake_lock *lock, int type, const char *name)
{
unsigned long irqflags = 0;
// 初始化名称
if (name)
lock->name = name;
BUG_ON(!lock->name); if (debug_mask & DEBUG_WAKE_LOCK)
pr_info("wake_lock_init name=%s\n", lock->name);
#ifdef CONFIG_WAKELOCK_STAT
lock->stat.count = 0;
lock->stat.expire_count = 0;
lock->stat.wakeup_count = 0;
lock->stat.total_time = ktime_set(0, 0);
lock->stat.prevent_suspend_time = ktime_set(0, 0);
lock->stat.max_time = ktime_set(0, 0);
lock->stat.last_time = ktime_set(0, 0);
#endif
// 初始化flag
lock->flags = (type & WAKE_LOCK_TYPE_MASK) | WAKE_LOCK_INITIALIZED;
// 初始化链表节点
INIT_LIST_HEAD(&lock->link);
spin_lock_irqsave(&list_lock, irqflags);
// 将锁加入无效锁链表
list_add(&lock->link, &inactive_locks);
spin_unlock_irqrestore(&list_lock, irqflags);
}
EXPORT_SYMBOL(wake_lock_init);

其中参数lock为被初始化对象,type代表锁的类型,name表示锁的名称, 函数主要初始化锁的名称并设置 WAKE_LOCK_INITIALIZED 标志位,并将锁加入无效锁链表inactive_locks,当需要使用锁的时候通过wake_lock()或者wake_lock_timeout()激活该锁:

// 根据参数激活锁
static void wake_lock_internal(
struct wake_lock *lock, long timeout, int has_timeout)
{
int type;
unsigned long irqflags;
long expire_in; spin_lock_irqsave(&list_lock, irqflags);
// 获取锁的类型
type = lock->flags & WAKE_LOCK_TYPE_MASK;
BUG_ON(type >= WAKE_LOCK_TYPE_COUNT);
BUG_ON(!(lock->flags & WAKE_LOCK_INITIALIZED));
#ifdef CONFIG_WAKELOCK_STAT
if (type == WAKE_LOCK_SUSPEND && wait_for_wakeup) {
if (debug_mask & DEBUG_WAKEUP)
pr_info("wakeup wake lock: %s\n", lock->name);
wait_for_wakeup = 0;
lock->stat.wakeup_count++;
}
if ((lock->flags & WAKE_LOCK_AUTO_EXPIRE) &&
(long)(lock->expires - jiffies) <= 0) {
wake_unlock_stat_locked(lock, 0);
lock->stat.last_time = ktime_get();
}
#endif
// 设置锁有效的标志位
if (!(lock->flags & WAKE_LOCK_ACTIVE)) {
lock->flags |= WAKE_LOCK_ACTIVE;
#ifdef CONFIG_WAKELOCK_STAT
lock->stat.last_time = ktime_get();
#endif
}
// 将锁从无效锁链表中删除
list_del(&lock->link);
// 如果是超时锁
if (has_timeout) {
if (debug_mask & DEBUG_WAKE_LOCK)
pr_info("wake_lock: %s, type %d, timeout %ld.%03lu\n",
lock->name, type, timeout / HZ,
(timeout % HZ) * MSEC_PER_SEC / HZ);
// 设置锁超时时间,以当前jiffies为基准
lock->expires = jiffies + timeout;
// 设置锁的超时锁标志
lock->flags |= WAKE_LOCK_AUTO_EXPIRE;
// 将锁加入有效锁链表
list_add_tail(&lock->link, &active_wake_locks[type]);
} else { // 如果是永久锁
if (debug_mask & DEBUG_WAKE_LOCK)
pr_info("wake_lock: %s, type %d\n", lock->name, type);
// 设置超时时间为极限
lock->expires = LONG_MAX;
// 清除超时锁标志
lock->flags &= ~WAKE_LOCK_AUTO_EXPIRE;
// 将锁加入有效锁链表
list_add(&lock->link, &active_wake_locks[type]);
}
// 如果是休眠锁
if (type == WAKE_LOCK_SUSPEND) {
current_event_num++; // 休眠锁使用计数器加1
#ifdef CONFIG_WAKELOCK_STAT
// 如果是内核休眠锁
if (lock == &main_wake_lock)
update_sleep_wait_stats_locked(1);
// 如果内核休眠锁无效
else if (!wake_lock_active(&main_wake_lock))
update_sleep_wait_stats_locked(0);
#endif
// 如果是超时锁
if (has_timeout)
expire_in = has_wake_lock_locked(type);
else
expire_in = -1;
// 当前存在有效超时锁,并且最长的一个到期时间间隔为expire_in
if (expire_in > 0) {
if (debug_mask & DEBUG_EXPIRE)
pr_info("wake_lock: %s, start expire timer, "
"%ld\n", lock->name, expire_in);
mod_timer(&expire_timer, jiffies + expire_in);
} else { // 如果有永久锁或者无有效锁
if (del_timer(&expire_timer))
if (debug_mask & DEBUG_EXPIRE)
pr_info("wake_lock: %s, stop expire timer\n",
lock->name);
if (expire_in == 0) // 无有效锁
queue_work(suspend_work_queue, &suspend_work);
}
}
spin_unlock_irqrestore(&list_lock, irqflags);
} // 激活永久锁
void wake_lock(struct wake_lock *lock)
{
wake_lock_internal(lock, 0, 0);
}
EXPORT_SYMBOL(wake_lock); // 激活超时锁
void wake_lock_timeout(struct wake_lock *lock, long timeout)
{
wake_lock_internal(lock, timeout, 1);
}
EXPORT_SYMBOL(wake_lock_timeout);

可以看到激活过程都是通过调用wake_lock_internal()完成的,该函数首先完成一些统计信息的初始化,设置 WAKE_LOCK_ACTIVE 标志位并将锁从无效锁链表中移除;然后根据是否是超时锁设置 WAKE_LOCK_AUTO_EXPIRE 标志位,并设置超时锁的超时时间,再将锁加入有效锁链表;最后再根据锁的类型判断是否为休眠锁,如果是休眠锁且为超时锁则通过has_wake_lock_locked()获取系统中存在的超时锁中时间最长的到期时间值,并以此值设置expire_timer,has_wake_lock_locked()返回0则表示系统中不存在有效锁则启动suspend进程开始进入深度休眠状态。

3、expire_timer

static void expire_wake_locks(unsigned long data)
{
long has_lock;
unsigned long irqflags;
if (debug_mask & DEBUG_EXPIRE)
pr_info("expire_wake_locks: start\n");
spin_lock_irqsave(&list_lock, irqflags);
// 打印当前的有效锁
if (debug_mask & DEBUG_SUSPEND)
print_active_locks(WAKE_LOCK_SUSPEND);
// 检测系统是否持有休眠锁
has_lock = has_wake_lock_locked(WAKE_LOCK_SUSPEND);
if (debug_mask & DEBUG_EXPIRE)
pr_info("expire_wake_locks: done, has_lock %ld\n", has_lock);
// 如果系统当前没有持有有效地休眠锁
if (has_lock == 0)
// 则启动深度休眠工作队列
queue_work(suspend_work_queue, &suspend_work);
spin_unlock_irqrestore(&list_lock, irqflags);
}
// 定义timer,运行函数为expire_wake_locks
static DEFINE_TIMER(expire_timer, expire_wake_locks, 0, 0);

该timer会在多个地方用到,在激活锁的函数中注册用于超时锁到期后检测系统的有效锁状态,如果系统不存在有效锁了则启动suspend进程。

4、suspend_work

static void suspend(struct work_struct *work)
{
int ret;
int entry_event_num; // 判断系统是否还持有有效锁,如果有则直接返回
if (has_wake_lock(WAKE_LOCK_SUSPEND)) {
if (debug_mask & DEBUG_SUSPEND)
pr_info("suspend: abort suspend\n");
return;
} // 记录函数进入时休眠锁的使用次数
entry_event_num = current_event_num;
sys_sync(); // 将缓存中的数据写入磁盘
if (debug_mask & DEBUG_SUSPEND)
pr_info("suspend: enter suspend\n");
// 开始深度休眠
ret = pm_suspend(requested_suspend_state);
// 退出深度休眠,打印信息
if (debug_mask & DEBUG_EXIT_SUSPEND) {
struct timespec ts;
struct rtc_time tm;
getnstimeofday(&ts);
rtc_time_to_tm(ts.tv_sec, &tm);
pr_info("suspend: exit suspend, ret = %d "
"(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n", ret,
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec);
}
// 如果深度休眠前和深度休眠后锁的使用次数一致,即唤醒过程中没有激活新的锁
if (current_event_num == entry_event_num) {
if (debug_mask & DEBUG_SUSPEND)
pr_info("suspend: pm_suspend returned with no event\n");
// 激活unknown_wakeup,0.5s超时
wake_lock_timeout(&unknown_wakeup, HZ / 2);
}
}
// 声明工作队列,运行函数为suspend
static DECLARE_WORK(suspend_work, suspend);

声明工作队列用于内核深度休眠,可以看到一个正常的休眠流程会三次调用sys_sync()用于同步缓存(之前一次在浅度休眠,之后一次在深度休眠),然后调用pm_suspend()开始执行深度休眠流程。

5、has_wake_lock

// 移除过期超时锁
static void expire_wake_lock(struct wake_lock *lock)
{
#ifdef CONFIG_WAKELOCK_STAT
wake_unlock_stat_locked(lock, 1);
#endif
// 清除锁有效和超时锁标志
lock->flags &= ~(WAKE_LOCK_ACTIVE | WAKE_LOCK_AUTO_EXPIRE);
// 从当前链表中删除
list_del(&lock->link);
// 加入无效锁链表
list_add(&lock->link, &inactive_locks);
if (debug_mask & (DEBUG_WAKE_LOCK | DEBUG_EXPIRE))
pr_info("expired wake lock %s\n", lock->name);
} // 打印有效锁信息,调用者需持有list_lock
static void print_active_locks(int type)
{
struct wake_lock *lock;
bool print_expired = true; BUG_ON(type >= WAKE_LOCK_TYPE_COUNT);
// 遍历有效锁链表
list_for_each_entry(lock, &active_wake_locks[type], link) {
// 如果是超时锁
if (lock->flags & WAKE_LOCK_AUTO_EXPIRE) {
// 计算超时剩余时间
long timeout = lock->expires - jiffies;
if (timeout > 0)
pr_info("active wake lock %s, time left %ld\n",
lock->name, timeout);
else if (print_expired)
pr_info("wake lock %s, expired\n", lock->name);
} else { // 如果不是超时锁
pr_info("active wake lock %s\n", lock->name);
if (!debug_mask & DEBUG_EXPIRE)
print_expired = false;
}
}
} static long has_wake_lock_locked(int type)
{
struct wake_lock *lock, *n;
long max_timeout = 0; BUG_ON(type >= WAKE_LOCK_TYPE_COUNT);
// 遍历有效锁链表
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 // 如果不是超时锁则返回-1
return -1;
}
return max_timeout;
} // 判断系统是否还持有有效锁
long has_wake_lock(int type)
{
long ret;
unsigned long irqflags;
spin_lock_irqsave(&list_lock, irqflags);
// 开始判断流程
ret = has_wake_lock_locked(type);
// 如果还有休眠锁有效则打印状态信息
if (ret && (debug_mask & DEBUG_SUSPEND) && type == WAKE_LOCK_SUSPEND)
print_active_locks(type);
spin_unlock_irqrestore(&list_lock, irqflags);
return ret;
}

该函数用于释放一个锁,首先将锁从有效锁链表中移除并加入无效锁链表,并判断系统是否还持有有效锁,如果没有则进入深度休眠流程。

7、wake_lock_active

// 判断锁是否有效
int wake_lock_active(struct wake_lock *lock)
{
return !!(lock->flags & WAKE_LOCK_ACTIVE);
}
EXPORT_SYMBOL(wake_lock_active);

8、wake_lock_destroy

void wake_lock_destroy(struct wake_lock *lock)
{
unsigned long irqflags;
if (debug_mask & DEBUG_WAKE_LOCK)
pr_info("wake_lock_destroy name=%s\n", lock->name);
spin_lock_irqsave(&list_lock, irqflags);
// 清除已经初始化的标志
lock->flags &= ~WAKE_LOCK_INITIALIZED;
#ifdef CONFIG_WAKELOCK_STAT
if (lock->stat.count) {
deleted_wake_locks.stat.count += lock->stat.count;
deleted_wake_locks.stat.expire_count += lock->stat.expire_count;
deleted_wake_locks.stat.total_time =
ktime_add(deleted_wake_locks.stat.total_time,
lock->stat.total_time);
deleted_wake_locks.stat.prevent_suspend_time =
ktime_add(deleted_wake_locks.stat.prevent_suspend_time,
lock->stat.prevent_suspend_time);
deleted_wake_locks.stat.max_time =
ktime_add(deleted_wake_locks.stat.max_time,
lock->stat.max_time);
}
#endif
// 从当前链表中删除
list_del(&lock->link);
spin_unlock_irqrestore(&list_lock, irqflags);
}
EXPORT_SYMBOL(wake_lock_destroy);

该函数用于注销wake_lock,首先清除 WAKE_LOCK_INITIALIZED 标志位,然后更新统计信息,最后将锁从链表中删除。

9、proc节点

// 获取锁的剩余超时时间,通过*expire_time传递
int get_expired_time(struct wake_lock *lock, ktime_t *expire_time)
{
struct timespec ts;
struct timespec kt;
struct timespec tomono;
struct timespec delta;
unsigned long seq;
long timeout; // 如果不是超时锁则直接返回
if (!(lock->flags & WAKE_LOCK_AUTO_EXPIRE))
return 0; do {
seq = read_seqbegin(&xtime_lock);
// 计算超时时间点与当前时间的差值
timeout = lock->expires - jiffies;
// 如果时间没有到期,返回0
if (timeout > 0)
return 0;
// 获取当前时间
kt = current_kernel_time();
tomono = wall_to_monotonic;
} while (read_seqretry(&xtime_lock, seq));
// 时间格式转换
jiffies_to_timespec(-timeout, &delta);
// 设置timespec的成员
set_normalized_timespec(&ts, kt.tv_sec + tomono.tv_sec - delta.tv_sec,
kt.tv_nsec + tomono.tv_nsec - delta.tv_nsec);
// 返回ts值
*expire_time = timespec_to_ktime(ts);
return 1;
} // 打印出锁的状态信息
static int print_lock_stat(struct seq_file *m, struct wake_lock *lock)
{
int lock_count = lock->stat.count;
int expire_count = lock->stat.expire_count;
ktime_t active_time = ktime_set(0, 0);
ktime_t total_time = lock->stat.total_time;
ktime_t max_time = lock->stat.max_time; ktime_t prevent_suspend_time = lock->stat.prevent_suspend_time;
// 如果锁有效
if (lock->flags & WAKE_LOCK_ACTIVE) {
ktime_t now, add_time;
// 获取超时剩余时间
int expired = get_expired_time(lock, &now);
if (!expired)
now = ktime_get();
// 计算当前时间和上次操作时间的差值
add_time = ktime_sub(now, lock->stat.last_time);
lock_count++; // 使用计数加1
if (!expired) // 如果没有到期
active_time = add_time;
else // 锁已经到期
expire_count++; // 超时计数加1
total_time = ktime_add(total_time, add_time); // 锁使用时间增加
if (lock->flags & WAKE_LOCK_PREVENTING_SUSPEND)
prevent_suspend_time = ktime_add(prevent_suspend_time,
ktime_sub(now, last_sleep_time_update));
if (add_time.tv64 > max_time.tv64)
max_time = add_time;
} return seq_printf(m,
"\"%s\"\t%d\t%d\t%d\t%lld\t%lld\t%lld\t%lld\t%lld\n",
lock->name, lock_count, expire_count,
lock->stat.wakeup_count, ktime_to_ns(active_time),
ktime_to_ns(total_time),
ktime_to_ns(prevent_suspend_time), ktime_to_ns(max_time),
ktime_to_ns(lock->stat.last_time));
} // 打印锁状态
static int wakelock_stats_show(struct seq_file *m, void *unused)
{
unsigned long irqflags;
struct wake_lock *lock;
int ret;
int type; spin_lock_irqsave(&list_lock, irqflags);
// 输出菜单
ret = seq_puts(m, "name\tcount\texpire_count\twake_count\tactive_since"
"\ttotal_time\tsleep_time\tmax_time\tlast_change\n");
// 遍历无效锁链表并打印锁的状态信息
list_for_each_entry(lock, &inactive_locks, link)
ret = print_lock_stat(m, lock);
// 遍历有效锁链表并打印锁的状态信息
for (type = 0; type < WAKE_LOCK_TYPE_COUNT; type++) {
list_for_each_entry(lock, &active_wake_locks[type], link)
ret = print_lock_stat(m, lock);
}
spin_unlock_irqrestore(&list_lock, irqflags);
return 0;
} // proc文件打开函数,调用show函数显示当前所有的锁信息
static int wakelock_stats_open(struct inode *inode, struct file *file)
{
return single_open(file, wakelock_stats_show, NULL);
} // proc文件系统操作函数
static const struct file_operations wakelock_stats_fops = {
.owner = THIS_MODULE,
.open = wakelock_stats_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};

以上是proc节点的操作接口,在wakelocks_init中注册。

总结:通过以上分析我们可以看到启动深度休眠流程有四个可能的地方,分别为expire_timer、wake_lock、wake_lock_timeout、wake_unlock,其中expire_timer和wake_unlock最常见。

android 休眠唤醒机制分析(一) — wake_lock【转】的更多相关文章

  1. android 休眠唤醒机制分析(一) — wake_lock

    本文转自:http://blog.csdn.net/g_salamander/article/details/7978772 Android的休眠唤醒主要基于wake_lock机制,只要系统中存在任一 ...

  2. android 休眠唤醒机制分析(二) — early_suspend

    本文转自:http://blog.csdn.net/g_salamander/article/details/7982170 early_suspend是Android休眠流程的第一阶段即浅度休眠,不 ...

  3. android 休眠唤醒机制分析(三) — suspend

    本文转自:http://blog.csdn.net/g_salamander/article/details/7988340 前面我们分析了休眠的第一个阶段即浅度休眠,现在我们继续看休眠的第二个阶段 ...

  4. Android休眠唤醒机制简介(二)

    本文转载自:http://blog.csdn.net/zhaoxiaoqiang10_/article/details/24408911 Android休眠唤醒机制简介(二)************* ...

  5. Android休眠唤醒机制简介(一)【转】

    本文转载自:http://blog.csdn.net/zhaoxiaoqiang10_/article/details/24408129 Android休眠唤醒机制简介(一) ************ ...

  6. Android休眠唤醒机制

    有四种方式可以引起休眠 ①在wake_unlock()中, 如果发现解锁以后没有任何其他的wake lock了, 就开始休眠 ②在定时器到时间以后, 定时器的回调函数会查看是否有其他的wake loc ...

  7. linux驱动程序之电源管理之标准linux休眠和唤醒机制分析(二)

    三.pm_test属性文件读写 int pm_test_level = TEST_NONE; static const char * const  pm_tests[__TEST_AFTER_LAST ...

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

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

  9. Android睡眠唤醒机制--Kernel态

    一.简介 Android系统中定义了几种低功耗状态:earlysuspend.suspend.hibernation.       1) earlysuspend: 是一种低功耗的状态,某些设备可以选 ...

随机推荐

  1. 面试题·HashMap和Hashtable的区别(转载再整理)

    原文链接: Javarevisited 翻译: ImportNew.com- 唐小娟 译文链接: http://www.importnew.com/7010.html HashMap和Hashtabl ...

  2. sql server 获取自增列下一个值或者获取指定表的主键值

    IDENT_CURRENT('TableName')为当前的最大标识值, IDENT_INCR('TableName')为设置的标识值增量, 两者相加即为下一个标识值 如: SELECT IDENT_ ...

  3. 为Spring Cloud Config插上管理的翅膀

    最近一致在更新Spring Cloud Config的相关内容,主要也是为这篇埋个伏笔,相信不少调研过Spring Cloud Config的用户都会吐槽它的管理能力太弱.因此,就有了下面为讲推荐的这 ...

  4. websocket 初识

    websocket 初识 前言 其实很早就知道了 websocket 这个概念了,像现在大火的直播等使用的就是 websocket.之前找爬虫工作,对面问我爬过 websocket 网站没,很汗颜,那 ...

  5. python安装第三方库的最简单方式

    一.准备工作 (只做一次准备工作,以后都会很方便) 1. 安装pip (1)下载pip到D:\download pip下载地址:https://pypi.python.org/pypi/pip#dow ...

  6. 南大算法设计与分析课程复习笔记(2)L2 - Asymptotics

    一.几种比较复杂度的符号 数据结构有描述,相关严格数学定义也不想说了,就这么过了吧. 二.最大子数组的几种解决方法 从最复杂的暴力解法过渡到最简单的动态规划 解析和代码见这里:http://www.c ...

  7. [转]启动container的时候出现iptables: No chain/target/match by that name

    本文转自:https://blog.csdn.net/u013948858/article/details/83115388 问题: Error response from daemon: drive ...

  8. c# 项目之间循环引用vs弹窗提醒

    circular dependencies in projects' graph ! Projects in cycle are:ProjectImp(Name:FrameWork.Entity,Pl ...

  9. [angularjs] angularjs系列笔记(二)指令

    重复HTML元素 ng-repeat指令可以重复HTML元素 <body> <div ng-app="Home" ng-controller="inde ...

  10. Hibernate(十四)抓取策略

    抓取策略: 抓取策略是当应用程序需要在(Hibernate实体对象图的)关联关系间进行导航的时候,Hibernate如何获取关联对象的策略.Hibernate的抓取策略是Hibernate提升性能的一 ...