Android的休眠唤醒主要基于wake_lock机制,只要系统中存在任一有效的wake_lock,系统就不能进入深度休眠,但可以进行设备的浅度休眠操作。wake_lock一般在关闭lcd、tp,但系统仍然需要正常运行的情况下使用,比如听歌、传输很大的文件等。
-----------------------------------------------------------------------------
深度休眠:
深度休眠的机制主要是锁,只要系统中存在任一有效的wake_lock,系统就不能进入深度休眠。
当所有的锁都无效时,那么系统就会进入深度休眠状态。以下我对wake_lock锁机制的理解。可能有些偏差。
分析driver层wake_lock的实现,我的讲解流程是从锁到全局。
数据结构定义:linux-3.4\kernel\power\wakelock.h
enum {
WAKE_LOCK_SUSPEND, // 阻止进入深度休眠模式
WAKE_LOCK_IDLE, // 阻止进入空闲模式
WAKE_LOCK_TYPE_COUNT // 锁的数量
};
#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) // 正在阻止休眠标志
锁的结构:
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
};
安卓提供了操作锁的接口:linux-3.4\kernel\power\wakelock.c
// 初始化新锁,type指定了锁的类型
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);
// 判断当前锁是否有效,有效返回非 0
int wake_lock_active(struct wake_lock *lock);
// 判断系统中是否还存在有效的type类型的锁,如果存在则返回最长的一个锁的超时时间,
// 如果存在永久锁则返回-1,如果系统中不存在有效锁则返回0
long has_wake_lock(int type);
这些接口都被EXPORT_SYMBOL()导出,可以为其他模块所用。
它们都是通过维护两个锁链表(有效锁链表、无效锁链表)实现整套锁机制。
有效锁链表:
active_wake_locks[0]维护的是 WAKE_LOCK_SUSPEND.
active_wake_locks[1]维护的是 WAKE_LOCK_IDLE.
无效锁链表:
inactive_locks
调试信息输出:(这个挺有意思的,可以指定输出调试类型的信息)
enum {
DEBUG_EXIT_SUSPEND = 1U << 0,
DEBUG_WAKEUP = 1U << 1,
DEBUG_SUSPEND = 1U << 2,
DEBUG_EXPIRE = 1U << 3,
DEBUG_WAKE_LOCK = 1U << 4,
};
static int debug_mask = DEBUG_EXIT_SUSPEND | DEBUG_WAKEUP | DEBUG_SUSPEND;
/* 初始化锁 参数: 锁对象,类型,名字
* 主要是初始化了锁的数据结构,并且将该节点加入到无效锁链表中
* 在激活的时候就可以将该锁从无效锁链表中加到有效锁链表*/
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 ,WAKE_LOCK_INITIALIZED 表示已经初始化过
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);
/* 注销锁,参数:锁对象
* 清除已经初始化的标志、将锁的状态信息放入 deleted_wake_locks
* 不知道为什么要进去,网上有一份资料说是统计信息,但是我没有看到有哪些地方用上
*/
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
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);
/* 激活永久锁 */
void wake_lock(struct wake_lock *lock)
{
POWER_DEBUGOUT();
wake_lock_internal(lock, 0, 0);
}
EXPORT_SYMBOL(wake_lock);
/* 激活超时锁 */
void wake_lock_timeout(struct wake_lock *lock, long timeout)
{
POWER_DEBUGOUT();
wake_lock_internal(lock, timeout, 1);
}
EXPORT_SYMBOL(wake_lock_timeout);
/* 真正激活锁操作,参数:锁对象,若是超时锁则为超时值否则为0,是否超时锁
* 将该锁从无效链表中删除,加入到有效链表,
* 如果是超时锁则设置其超时值,遍历并取有效链表中超时值最长的超时锁,将该超时值更新到定时器中
* (在遍历过程中,会将已经超时的超时锁移除 具体看 static long has_wake_lock_locked()的实现)
* 如果是永久锁就将其超时值设置为极限,并清除超时锁的标志
* 如果所有没有超时锁则删除定时器,如果也没有永久锁则启动深度休眠流程
* 注意,超时锁是用 list_add_tail() 加入有效锁链表,而永久锁是用 list_add() 加入有效锁链表
* 所以有效链表的结构是这样: --永久锁--链表头--超时锁--
* 这种方式是为了提高has_wake_lock_locked()遍历效率
*/
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;
// 将超时锁加入到 active_wake_locks[type] 链表头的后面
// 注意,超时锁在链表的后面,永久锁在链表的前面 --永久锁--链表头--超时锁--
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;
// 将锁加入有效锁链表 active_wake_locks[type] 链表头的前面
// 注意,超时锁在链表的后面,永久锁在链表的前面 --永久锁--链表头--超时锁--
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); // 遍历WAKE_LOCK_SUSPEND锁类型的有效锁链表
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);
// 更新定时器的超时时间 为最长有效锁的超时时间 当时间到了,就会触发 expire_wake_locks()
// 该函数会重新检查所有的超时锁,过期则从有效链表中移除过期的锁
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);
}
// 无有效锁 启动 suspend_work_queue队列 进入深度休眠流程
if (expire_in == 0)
queue_work(suspend_work_queue, &suspend_work);
}
}
spin_unlock_irqrestore(&list_lock, irqflags);
}
/* 遍历指定类型的有效锁链表,参数指定类型的有效锁链表: WAKE_LOCK_SUSPEND、WAKE_LOCK_IDLE
* 遍历有效锁链表中断超时锁,并将已经过期的锁移除,取没有过期并且超时时间最长的锁时间
* 如果没有有效的超时锁则返回-1,如果有效链表没有锁则返回0
* 这个函数每次调用都会遍历锁链表就是因为要处理已经过期的锁,并取得最长的锁时间用于更新定时器
* 重点链表结构: --永久锁--链表头--超时锁--
* has_wake_lock_locked()是从链表头后面开始遍历的,即从超时锁遍历。
*/
static long has_wake_lock_locked(int type)
{
struct wake_lock *lock, *n;
long max_timeout = 0; // 取默认值为 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;
}
/* 移除过期超时锁 */
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);
}
static DEFINE_TIMER(expire_timer, expire_wake_locks, 0, 0);
/* 判断锁是否有效 这个是直接判断标志位*/
int wake_lock_active(struct wake_lock *lock)
{
return !!(lock->flags & WAKE_LOCK_ACTIVE);
}
EXPORT_SYMBOL(wake_lock_active);
/*
* 定时器的回调函数,因为定时器的定时值一直会被 wake_lock_internal()\wake_unlock()
* 更新为当前有效链表中时间最长的超时锁的超时值,当最长的超时锁时间来到,这函数就会被执行
* 这个函数会调用 has_wake_lock_locked() 来清理过期锁,同时检测到没锁就会进入深度休眠模式
*/
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);
}
static DEFINE_TIMER(expire_timer, expire_wake_locks, 0, 0);
/* 该函数用于释放一个锁,首先将锁从有效锁链表中移除并加入无效锁链表,并判断系统是否
* 还持有有效锁,如果没有则删除定时器并进入深度休眠流程,如果有则取其中延时最长的超
* 时锁时间用于更新定时器的定时值,当时间到达时就会调用 expire_wake_locks()
*/
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;
#ifdef CONFIG_WAKELOCK_STAT
// 更新锁的状态
wake_unlock_stat_locked(lock, 0);
#endif
if (debug_mask & DEBUG_WAKE_LOCK)
pr_info("wake_unlock: %s\n", lock->name);
// 清除有效锁和超时锁标志
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);
// 如果还持有锁,设置timer到超时时间点触发
if (has_lock > 0)
{
if (debug_mask & DEBUG_EXPIRE)
pr_info("wake_unlock: %s, start expire timer, "
"%ld\n", lock->name, has_lock);
mod_timer(&expire_timer, jiffies + has_lock);
}
else
{
// 删除 timer
if (del_timer(&expire_timer))
if (debug_mask & DEBUG_EXPIRE)
pr_info("wake_unlock: %s, stop expire "
"timer\n", lock->name);
if (has_lock == 0) // 启动深度休眠工作队列
queue_work(suspend_work_queue, &suspend_work);
}
// 如果是内核锁 则打印当前有效锁信息
if (lock == &main_wake_lock)
{
if (debug_mask & DEBUG_SUSPEND)
print_active_locks(WAKE_LOCK_SUSPEND);
#ifdef CONFIG_WAKELOCK_STAT
update_sleep_wait_stats_locked(0);
#endif
}
}
spin_unlock_irqrestore(&list_lock, irqflags);
}
EXPORT_SYMBOL(wake_unlock);
/* 判断系统是否还持有有效锁 */
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_WAKEUP) && type == WAKE_LOCK_SUSPEND)
print_active_locks(type);
spin_unlock_irqrestore(&list_lock, irqflags);
return ret;
}
从以上函数的解析来看,整个锁机制都已经呼之欲出了。
当系统已经没有锁的时候,就会启动 queue_work(suspend_work_queue, &suspend_work); 队列,从而进入深度休眠的流程。
当系统有一个锁,都不会启动深度休眠。所以安卓启动的时候会初始化并激活一把永久锁->main,在需要深度休眠的时候会移除这把锁。
我们初始化锁的时候,调用 wake_lock_init(); 它会初始化锁对象的名字、状态信息等,并将其加入无效锁链表中。
当激活时调用 wake_lock()\wake_lock_timeout()->wake_lock_internal() 会将锁加入到有效链表中,如果是超时锁会调用list_add_tail()
将该锁加入到链表头的后面,如果是永久锁则调用list_add()将该锁加入链表头的前面,有效链表的结构是这样:--永久锁--链表头--超时锁-- ,
这种方式是为了提高has_wake_lock_locked()遍历效率。如果激活的是超时锁,会调用has_wake_lock_locked() 函数遍历 active_wake_locks[0]
->WAKE_LOCK_SUSPEND 类型的有效链表,移除过期锁并取该链表中超时锁中超时值最长的值,将该值作为定时器的值更新到定时器中。如果没有锁
则进入深度休眠流程:queue_work(suspend_work_queue, &suspend_work);
当超时最长的锁的时间到了,那么定时器函数expire_wake_locks()自然也就被回调,定时器函数被回调后就会再次调用 has_wake_lock_locked(WAKE_LOCK_SUSPEND), 将过期的锁移除,定时器根据其返回值知道链表上还有没有锁,如果没有锁则进入深度休眠流程:queue_work(suspend_work_queue, &suspend_work);
当我们要释放锁的时候,调用wake_unlock() 将该锁从有效链表中移到无效链表中,并调用 has_wake_lock_locked(),该函数的功能不再复述,
当有效链表中没有锁时,则进入深度休眠流程:queue_work(suspend_work_queue, &suspend_work);
当我们要销毁一个锁的时候则调用wake_lock_destroy(),就会将锁从链表中删除。
由此可见,android 进入深度休眠时的入口出现在:expire_wake_locks()、wake_lock_internal()、wake_unlock(),这三个地方。每个地方都一定会
调用has_wake_lock_locked()去清除过期锁并得到有效锁链表是否还有锁,如果没有都会启动休眠队列queue_work(suspend_work_queue, &suspend_work);进入深度休眠流程。
我不太明白为什么要大费周章实现这个锁机制,如果有一个APK注册了锁而又忘记了释放锁,那岂不是系统一直都会无法进入深度休眠状态?
可能只进入了浅度休眠状态,而我们以为进入了深度休眠状态导致电池的电量浪费。
不过这锁机制有一个地方很有意思,就是有效锁链表的组织上很巧妙,一点小小的改动就很好的将超时锁和永久锁分好,很大的优化了遍历的性能。
这点表现在wake_lock_internal()函数中,将超时锁加在链表头的后面,而将永久锁加在链表头的前面。
这个链表是双向循环链表,当遍历的时候,就从链表头的后面开始,也就是遍历超时锁,当遍历到的节点不是超时锁,这就意味着是永久锁,
就不需要再继续无谓的遍历了。
--------------------------------------------------- 零散记录 ------------------------------------------------------
驱动代码:linux-3.5\kernel\power\wakelock.c
core_initcall(wakelocks_init); // 驱动入口 最高优先级 最先加载的驱动
module_exit(wakelocks_exit);
驱动入口函数主要做了如下的事情 static int __init wakelocks_init(void):
1、初始化两个有效锁链表:用于阻止进入深度休眠模式的锁和用于阻止进入浅度休眠模式的锁
当初始化好并被激活的锁都会被加入到相应的有效链表锁里。
2、如果定义了 CONFIG_WAKELOCK_STAT 初始化 deleted_wake_locks 用于处理统计信息
3、初始化内核休眠锁 main_wake_lock ,并激活这个锁,深度休眠时需要释放这个锁
4、初始化同步锁 sync_wake_lock 用于浅度休眠阶段同步缓存时阻止内核进入深度休眠
5、初始化未知锁 用于唤醒时延迟0.5s进入下一次可能的深度休眠
6、如果定义了 CONFIG_EARLYSUSPEND_DELAY 则初始化并激活 ealysuspend_delay_work 浅度休眠锁
7、 注册 power_device power_driver 用于深度休眠阶段检测是否存在有效锁
8、创建 suspend内核工作队列 用于进行浅度休眠和深度休眠
9、创建 同步系统锁内核队列
10、在proc下创建wakelocks文件 节点用于提供节点显示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(&sync_wake_lock, WAKE_LOCK_SUSPEND, "sync_system");
// 激活内核休眠锁 系统启动时会激活这个锁,深度休眠时需要释放这个锁
wake_lock(&main_wake_lock);
// 初始化未知锁 用于唤醒时延迟0.5s进入下一次可能的深度休眠
wake_lock_init(&unknown_wakeup, WAKE_LOCK_SUSPEND, "unknown_wakeups");
wake_lock_init(&suspend_backoff_lock, WAKE_LOCK_SUSPEND, "suspend_backoff");
#ifdef CONFIG_EARLYSUSPEND_DELAY
wake_lock_init(&ealysuspend_delay_work, WAKE_LOCK_SUSPEND, "suspend_delay");
// 激活 浅度休眠锁
wake_lock(&ealysuspend_delay_work);
#endif
// 注册 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;
}
// 创建 suspend内核工作队列 用于进行浅度休眠和深度休眠
suspend_work_queue = create_singlethread_workqueue("suspend");
if (suspend_work_queue == NULL) {
ret = -ENOMEM;
goto err_suspend_work_queue;
}
// 创建 同步系统锁内核队列
sync_work_queue = create_singlethread_workqueue("sync_system_work");
if (sync_work_queue == NULL) {
ret = -ENOMEM;
goto err_sync_work_queue;
}
#ifdef CONFIG_WAKELOCK_STAT
// 在proc下创建wakelocks文件 节点用于显示wake_lock的统计信息
proc_create("wakelocks", S_IRUGO, NULL, &wakelock_stats_fops);
#endif
return 0;
// 出错处理
err_sync_work_queue:
destroy_workqueue(suspend_work_queue);
err_suspend_work_queue:
platform_driver_unregister(&power_driver);
err_platform_driver_register:
platform_device_unregister(&power_device);
err_platform_device_register:
#ifdef CONFIG_EARLYSUSPEND_DELAY
wake_lock_destroy(&ealysuspend_delay_work);
#endif
wake_lock_destroy(&suspend_backoff_lock);
wake_lock_destroy(&unknown_wakeup);
wake_lock_destroy(&sync_wake_lock);
wake_lock_destroy(&main_wake_lock);
#ifdef CONFIG_WAKELOCK_STAT
wake_lock_destroy(&deleted_wake_locks);
#endif
return ret;
}
-----------------------------------------------------------------------------
深度休眠:
深度休眠的机制主要是锁,只要系统中存在任一有效的wake_lock,系统就不能进入深度休眠。
当所有的锁都无效时,那么系统就会进入深度休眠状态。以下我对wake_lock锁机制的理解。可能有些偏差。
分析driver层wake_lock的实现,我的讲解流程是从锁到全局。
数据结构定义:linux-3.4\kernel\power\wakelock.h
enum {
WAKE_LOCK_SUSPEND, // 阻止进入深度休眠模式
WAKE_LOCK_IDLE, // 阻止进入空闲模式
WAKE_LOCK_TYPE_COUNT // 锁的数量
};
#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) // 正在阻止休眠标志
锁的结构:
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
};
安卓提供了操作锁的接口:linux-3.4\kernel\power\wakelock.c
// 初始化新锁,type指定了锁的类型
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);
// 判断当前锁是否有效,有效返回非 0
int wake_lock_active(struct wake_lock *lock);
// 判断系统中是否还存在有效的type类型的锁,如果存在则返回最长的一个锁的超时时间,
// 如果存在永久锁则返回-1,如果系统中不存在有效锁则返回0
long has_wake_lock(int type);
这些接口都被EXPORT_SYMBOL()导出,可以为其他模块所用。
它们都是通过维护两个锁链表(有效锁链表、无效锁链表)实现整套锁机制。
有效锁链表:
active_wake_locks[0]维护的是 WAKE_LOCK_SUSPEND.
active_wake_locks[1]维护的是 WAKE_LOCK_IDLE.
无效锁链表:
inactive_locks
调试信息输出:(这个挺有意思的,可以指定输出调试类型的信息)
enum {
DEBUG_EXIT_SUSPEND = 1U << 0,
DEBUG_WAKEUP = 1U << 1,
DEBUG_SUSPEND = 1U << 2,
DEBUG_EXPIRE = 1U << 3,
DEBUG_WAKE_LOCK = 1U << 4,
};
static int debug_mask = DEBUG_EXIT_SUSPEND | DEBUG_WAKEUP | DEBUG_SUSPEND;
/* 初始化锁 参数: 锁对象,类型,名字
* 主要是初始化了锁的数据结构,并且将该节点加入到无效锁链表中
* 在激活的时候就可以将该锁从无效锁链表中加到有效锁链表*/
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 ,WAKE_LOCK_INITIALIZED 表示已经初始化过
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);
/* 注销锁,参数:锁对象
* 清除已经初始化的标志、将锁的状态信息放入 deleted_wake_locks
* 不知道为什么要进去,网上有一份资料说是统计信息,但是我没有看到有哪些地方用上
*/
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
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);
/* 激活永久锁 */
void wake_lock(struct wake_lock *lock)
{
POWER_DEBUGOUT();
wake_lock_internal(lock, 0, 0);
}
EXPORT_SYMBOL(wake_lock);
/* 激活超时锁 */
void wake_lock_timeout(struct wake_lock *lock, long timeout)
{
POWER_DEBUGOUT();
wake_lock_internal(lock, timeout, 1);
}
EXPORT_SYMBOL(wake_lock_timeout);
/* 真正激活锁操作,参数:锁对象,若是超时锁则为超时值否则为0,是否超时锁
* 将该锁从无效链表中删除,加入到有效链表,
* 如果是超时锁则设置其超时值,遍历并取有效链表中超时值最长的超时锁,将该超时值更新到定时器中
* (在遍历过程中,会将已经超时的超时锁移除 具体看 static long has_wake_lock_locked()的实现)
* 如果是永久锁就将其超时值设置为极限,并清除超时锁的标志
* 如果所有没有超时锁则删除定时器,如果也没有永久锁则启动深度休眠流程
* 注意,超时锁是用 list_add_tail() 加入有效锁链表,而永久锁是用 list_add() 加入有效锁链表
* 所以有效链表的结构是这样: --永久锁--链表头--超时锁--
* 这种方式是为了提高has_wake_lock_locked()遍历效率
*/
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;
// 将超时锁加入到 active_wake_locks[type] 链表头的后面
// 注意,超时锁在链表的后面,永久锁在链表的前面 --永久锁--链表头--超时锁--
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;
// 将锁加入有效锁链表 active_wake_locks[type] 链表头的前面
// 注意,超时锁在链表的后面,永久锁在链表的前面 --永久锁--链表头--超时锁--
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); // 遍历WAKE_LOCK_SUSPEND锁类型的有效锁链表
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);
// 更新定时器的超时时间 为最长有效锁的超时时间 当时间到了,就会触发 expire_wake_locks()
// 该函数会重新检查所有的超时锁,过期则从有效链表中移除过期的锁
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);
}
// 无有效锁 启动 suspend_work_queue队列 进入深度休眠流程
if (expire_in == 0)
queue_work(suspend_work_queue, &suspend_work);
}
}
spin_unlock_irqrestore(&list_lock, irqflags);
}
/* 遍历指定类型的有效锁链表,参数指定类型的有效锁链表: WAKE_LOCK_SUSPEND、WAKE_LOCK_IDLE
* 遍历有效锁链表中断超时锁,并将已经过期的锁移除,取没有过期并且超时时间最长的锁时间
* 如果没有有效的超时锁则返回-1,如果有效链表没有锁则返回0
* 这个函数每次调用都会遍历锁链表就是因为要处理已经过期的锁,并取得最长的锁时间用于更新定时器
* 重点链表结构: --永久锁--链表头--超时锁--
* has_wake_lock_locked()是从链表头后面开始遍历的,即从超时锁遍历。
*/
static long has_wake_lock_locked(int type)
{
struct wake_lock *lock, *n;
long max_timeout = 0; // 取默认值为 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;
}
/* 移除过期超时锁 */
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);
}
static DEFINE_TIMER(expire_timer, expire_wake_locks, 0, 0);
/* 判断锁是否有效 这个是直接判断标志位*/
int wake_lock_active(struct wake_lock *lock)
{
return !!(lock->flags & WAKE_LOCK_ACTIVE);
}
EXPORT_SYMBOL(wake_lock_active);
/*
* 定时器的回调函数,因为定时器的定时值一直会被 wake_lock_internal()\wake_unlock()
* 更新为当前有效链表中时间最长的超时锁的超时值,当最长的超时锁时间来到,这函数就会被执行
* 这个函数会调用 has_wake_lock_locked() 来清理过期锁,同时检测到没锁就会进入深度休眠模式
*/
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);
}
static DEFINE_TIMER(expire_timer, expire_wake_locks, 0, 0);
/* 该函数用于释放一个锁,首先将锁从有效锁链表中移除并加入无效锁链表,并判断系统是否
* 还持有有效锁,如果没有则删除定时器并进入深度休眠流程,如果有则取其中延时最长的超
* 时锁时间用于更新定时器的定时值,当时间到达时就会调用 expire_wake_locks()
*/
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;
#ifdef CONFIG_WAKELOCK_STAT
// 更新锁的状态
wake_unlock_stat_locked(lock, 0);
#endif
if (debug_mask & DEBUG_WAKE_LOCK)
pr_info("wake_unlock: %s\n", lock->name);
// 清除有效锁和超时锁标志
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);
// 如果还持有锁,设置timer到超时时间点触发
if (has_lock > 0)
{
if (debug_mask & DEBUG_EXPIRE)
pr_info("wake_unlock: %s, start expire timer, "
"%ld\n", lock->name, has_lock);
mod_timer(&expire_timer, jiffies + has_lock);
}
else
{
// 删除 timer
if (del_timer(&expire_timer))
if (debug_mask & DEBUG_EXPIRE)
pr_info("wake_unlock: %s, stop expire "
"timer\n", lock->name);
if (has_lock == 0) // 启动深度休眠工作队列
queue_work(suspend_work_queue, &suspend_work);
}
// 如果是内核锁 则打印当前有效锁信息
if (lock == &main_wake_lock)
{
if (debug_mask & DEBUG_SUSPEND)
print_active_locks(WAKE_LOCK_SUSPEND);
#ifdef CONFIG_WAKELOCK_STAT
update_sleep_wait_stats_locked(0);
#endif
}
}
spin_unlock_irqrestore(&list_lock, irqflags);
}
EXPORT_SYMBOL(wake_unlock);
/* 判断系统是否还持有有效锁 */
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_WAKEUP) && type == WAKE_LOCK_SUSPEND)
print_active_locks(type);
spin_unlock_irqrestore(&list_lock, irqflags);
return ret;
}
从以上函数的解析来看,整个锁机制都已经呼之欲出了。
当系统已经没有锁的时候,就会启动 queue_work(suspend_work_queue, &suspend_work); 队列,从而进入深度休眠的流程。
当系统有一个锁,都不会启动深度休眠。所以安卓启动的时候会初始化并激活一把永久锁->main,在需要深度休眠的时候会移除这把锁。
我们初始化锁的时候,调用 wake_lock_init(); 它会初始化锁对象的名字、状态信息等,并将其加入无效锁链表中。
当激活时调用 wake_lock()\wake_lock_timeout()->wake_lock_internal() 会将锁加入到有效链表中,如果是超时锁会调用list_add_tail()
将该锁加入到链表头的后面,如果是永久锁则调用list_add()将该锁加入链表头的前面,有效链表的结构是这样:--永久锁--链表头--超时锁-- ,
这种方式是为了提高has_wake_lock_locked()遍历效率。如果激活的是超时锁,会调用has_wake_lock_locked() 函数遍历 active_wake_locks[0]
->WAKE_LOCK_SUSPEND 类型的有效链表,移除过期锁并取该链表中超时锁中超时值最长的值,将该值作为定时器的值更新到定时器中。如果没有锁
则进入深度休眠流程:queue_work(suspend_work_queue, &suspend_work);
当超时最长的锁的时间到了,那么定时器函数expire_wake_locks()自然也就被回调,定时器函数被回调后就会再次调用 has_wake_lock_locked(WAKE_LOCK_SUSPEND), 将过期的锁移除,定时器根据其返回值知道链表上还有没有锁,如果没有锁则进入深度休眠流程:queue_work(suspend_work_queue, &suspend_work);
当我们要释放锁的时候,调用wake_unlock() 将该锁从有效链表中移到无效链表中,并调用 has_wake_lock_locked(),该函数的功能不再复述,
当有效链表中没有锁时,则进入深度休眠流程:queue_work(suspend_work_queue, &suspend_work);
当我们要销毁一个锁的时候则调用wake_lock_destroy(),就会将锁从链表中删除。
由此可见,android 进入深度休眠时的入口出现在:expire_wake_locks()、wake_lock_internal()、wake_unlock(),这三个地方。每个地方都一定会
调用has_wake_lock_locked()去清除过期锁并得到有效锁链表是否还有锁,如果没有都会启动休眠队列queue_work(suspend_work_queue, &suspend_work);进入深度休眠流程。
我不太明白为什么要大费周章实现这个锁机制,如果有一个APK注册了锁而又忘记了释放锁,那岂不是系统一直都会无法进入深度休眠状态?
可能只进入了浅度休眠状态,而我们以为进入了深度休眠状态导致电池的电量浪费。
不过这锁机制有一个地方很有意思,就是有效锁链表的组织上很巧妙,一点小小的改动就很好的将超时锁和永久锁分好,很大的优化了遍历的性能。
这点表现在wake_lock_internal()函数中,将超时锁加在链表头的后面,而将永久锁加在链表头的前面。
这个链表是双向循环链表,当遍历的时候,就从链表头的后面开始,也就是遍历超时锁,当遍历到的节点不是超时锁,这就意味着是永久锁,
就不需要再继续无谓的遍历了。
--------------------------------------------------- 零散记录 ------------------------------------------------------
驱动代码:linux-3.5\kernel\power\wakelock.c
core_initcall(wakelocks_init); // 驱动入口 最高优先级 最先加载的驱动
module_exit(wakelocks_exit);
驱动入口函数主要做了如下的事情 static int __init wakelocks_init(void):
1、初始化两个有效锁链表:用于阻止进入深度休眠模式的锁和用于阻止进入浅度休眠模式的锁
当初始化好并被激活的锁都会被加入到相应的有效链表锁里。
2、如果定义了 CONFIG_WAKELOCK_STAT 初始化 deleted_wake_locks 用于处理统计信息
3、初始化内核休眠锁 main_wake_lock ,并激活这个锁,深度休眠时需要释放这个锁
4、初始化同步锁 sync_wake_lock 用于浅度休眠阶段同步缓存时阻止内核进入深度休眠
5、初始化未知锁 用于唤醒时延迟0.5s进入下一次可能的深度休眠
6、如果定义了 CONFIG_EARLYSUSPEND_DELAY 则初始化并激活 ealysuspend_delay_work 浅度休眠锁
7、 注册 power_device power_driver 用于深度休眠阶段检测是否存在有效锁
8、创建 suspend内核工作队列 用于进行浅度休眠和深度休眠
9、创建 同步系统锁内核队列
10、在proc下创建wakelocks文件 节点用于提供节点显示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(&sync_wake_lock, WAKE_LOCK_SUSPEND, "sync_system");
// 激活内核休眠锁 系统启动时会激活这个锁,深度休眠时需要释放这个锁
wake_lock(&main_wake_lock);
// 初始化未知锁 用于唤醒时延迟0.5s进入下一次可能的深度休眠
wake_lock_init(&unknown_wakeup, WAKE_LOCK_SUSPEND, "unknown_wakeups");
wake_lock_init(&suspend_backoff_lock, WAKE_LOCK_SUSPEND, "suspend_backoff");
#ifdef CONFIG_EARLYSUSPEND_DELAY
wake_lock_init(&ealysuspend_delay_work, WAKE_LOCK_SUSPEND, "suspend_delay");
// 激活 浅度休眠锁
wake_lock(&ealysuspend_delay_work);
#endif
// 注册 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;
}
// 创建 suspend内核工作队列 用于进行浅度休眠和深度休眠
suspend_work_queue = create_singlethread_workqueue("suspend");
if (suspend_work_queue == NULL) {
ret = -ENOMEM;
goto err_suspend_work_queue;
}
// 创建 同步系统锁内核队列
sync_work_queue = create_singlethread_workqueue("sync_system_work");
if (sync_work_queue == NULL) {
ret = -ENOMEM;
goto err_sync_work_queue;
}
#ifdef CONFIG_WAKELOCK_STAT
// 在proc下创建wakelocks文件 节点用于显示wake_lock的统计信息
proc_create("wakelocks", S_IRUGO, NULL, &wakelock_stats_fops);
#endif
return 0;
// 出错处理
err_sync_work_queue:
destroy_workqueue(suspend_work_queue);
err_suspend_work_queue:
platform_driver_unregister(&power_driver);
err_platform_driver_register:
platform_device_unregister(&power_device);
err_platform_device_register:
#ifdef CONFIG_EARLYSUSPEND_DELAY
wake_lock_destroy(&ealysuspend_delay_work);
#endif
wake_lock_destroy(&suspend_backoff_lock);
wake_lock_destroy(&unknown_wakeup);
wake_lock_destroy(&sync_wake_lock);
wake_lock_destroy(&main_wake_lock);
#ifdef CONFIG_WAKELOCK_STAT
wake_lock_destroy(&deleted_wake_locks);
#endif
return ret;
}