Android kernel wakelock分析

本文详细介绍了Android内核中的wakelock机制,包括wakelock的定义、相关编译标志、/proc/wakelocks文件格式,以及内核锁函数的使用,特别强调了wakelock在系统挂起过程中的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. Linux kernel wakelock 定义

A wake_lock prevents the system from entering suspend or other low power states when active. If the type is set to WAKE_LOCK_SUSPEND, the wake_lock prevents a full system suspend. If the type is WAKE_LOCK_IDLE, low power

states that cause large interrupt latencies or that disable a set of interrupts will not entered from idle until the wake_locks are released.


当唤醒锁被激活的时候,它能阻止系统进入挂起状态或者其他低功耗模式。

如果锁类型被设置为 WAKE_LOCK_SUSPEND,该锁阻止整个系统进入挂起状态。

如果锁类型被设置为 WAKE_LOCK_IDLE,  除非该锁被释放,产生中断大延迟或者失能中断集的系统低功耗模式将被阻止进入。但是系统可以进入挂起睡眠状态。


2. 编译标志

根据Kconfig 文件, 相关的内核编译标志分别为:

CONFIG_HAS_WAKELOCK    选择是否使能 wakelock模块。

CONFIG_WAKELOCK:   依赖CONFIG_HAS_WAKELOCK。当用户空间请求睡眠状态时,该请求将被延置直到没有唤醒锁为使能状态。

CONFIG_WAKELOCK_STAT:      报告唤醒锁状态并写入到 /proc/wakelocks 文件

CONFIG_USER_WAKELOCK     用户空间唤醒锁。写入"锁名称" 或者“超时锁名称” 到 /sys/power/wake_lock文件来使能唤醒锁 ( 根据需要与否来创建一个唤醒锁)

                                                          写入“锁名称”到 /sys/power/wake_unlock 文件来解锁一个用户空间唤醒锁。

CONFIG_EARLYSUSPEND        当用户空间请求睡眠状态改变时, 调用early suspend handlers 

                                                          该标志依赖于 CONFIG_WAKELOCK编译标志。


3. /proc/wakelocks 格式

示例如下

root@android:/ # cat /proc/wakelocks
cat /proc/wakelocks
name    count    expire_count    wake_count      active_since    total_time           sleep_time          max_time          last_change
"em"      4899               0                             0                   0          129695047374    123649908727  2367225591    29445791758668
"alarm_rtc"     2360    474     0       0       1613420206524   1611455462922   1949640000      27899269419825
"bcmpmu_i2c"    244500  0       1876    0       275160569412    268463363255    996054076       29445791728151
"KeyEvents"     11133   0       0       0       1853662043      601848424       231933595       29439508921751


4. 内核锁函数

初始化锁模块

static int __init wakelocks_init(void)
{
	int ret;
	int i;

        // 初始化suspend, idle 两个类型锁的链表
	for (i = 0; i < ARRAY_SIZE(active_wake_locks); i++)
		INIT_LIST_HEAD(&active_wake_locks[i]);

#ifdef CONFIG_WAKELOCK_STAT
	wake_lock_init(&deleted_wake_locks, WAKE_LOCK_SUSPEND,
			"deleted_wake_locks");
#endif
       //初始化 main 锁并上锁。 何处解main锁?early_suspend()
	wake_lock_init(&main_wake_lock, WAKE_LOCK_SUSPEND, "main");
	wake_lock(&main_wake_lock);
       //初始化 unknown_wakeups 锁
	wake_lock_init(&unknown_wakeup, WAKE_LOCK_SUSPEND, "unknown_wakeups");
       //初始化 suspend_backoff 锁
       //以上几个都是suspend 锁。 用户空间锁也是 suspend 类型。
	wake_lock_init(&suspend_backoff_lock, WAKE_LOCK_SUSPEND,
		       "suspend_backoff");

	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_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/active_wakelocks 节点输出锁状态信息
	proc_create("wakelocks", S_IRUGO, NULL, &wakelock_stats_fops);
	proc_create("active_wakelocks", S_IRUGO, NULL, &active_wakelocks_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(&suspend_backoff_lock);
	wake_lock_destroy(&unknown_wakeup);
	wake_lock_destroy(&main_wake_lock);
#ifdef CONFIG_WAKELOCK_STAT
	wake_lock_destroy(&deleted_wake_locks);
#endif
	return ret;
}
初始化锁
void wake_lock_init(struct wake_lock *lock, int type, const char *name)
wake_lock_init() 设置锁的名字,类型,最后将新建的锁挂接到一个专门链接这些非锁状态的链表inactive_locks上。


上锁函数

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);
}
wake_lock()和wake_lock_timeout() 分别对 inactive 的锁进行上锁。后者是超时锁。调用同一个内部函数 wake_lock_internal()

static void wake_lock_internal(struct wake_lock *lock, long timeout, int has_timeout)
{
	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
       //检查 wait_for_wakeup 标志
	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);
		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++;
#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;
		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);
                     //如果超时锁为0, 且无非超时锁时, expire_in为0, 启动suspend流程
			if (expire_in == 0)
				queue_work(suspend_work_queue, &suspend_work);
		}
	}
	spin_unlock_irqrestore(&list_lock, irqflags);
}

解锁函数

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);
       //该锁从 active列表移除, 加入inactive列表
	list_del(&lock->link);
	list_add(&lock->link, &inactive_locks);
	if (type == WAKE_LOCK_SUSPEND) {
              //检查是否需要启动suspend流程
		long has_lock = has_wake_lock_locked(type);
		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 {
			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);
}


expire_wake_locks() 检查是否所有锁已经超时。 如果has_wake_lock_locked() 返回0,

针对suspend锁,必然是超时锁为0且非超时锁为0, 则启动suspend流程。

expire_wake_locks()是 expire_timer 的超时回调函数。

static DEFINE_TIMER(expire_timer, expire_wake_locks, 0, 0);

5. suspend函数

static void suspend(struct work_struct *work)
{
	int ret;
	int entry_event_num;
	struct timespec ts_entry, ts_exit;

        //如果还有suspend锁,直接abort
	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");
	getnstimeofday(&ts_entry);
       //系统suspend
       ret = pm_suspend(requested_suspend_state);
	getnstimeofday(&ts_exit);

	if (debug_mask & DEBUG_EXIT_SUSPEND) {
		struct rtc_time tm;
		rtc_time_to_tm(ts_exit.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_exit.tv_nsec);
	}

	if (ts_exit.tv_sec - ts_entry.tv_sec <= 1) {
		++suspend_short_count;

		if (suspend_short_count == SUSPEND_BACKOFF_THRESHOLD) {
			suspend_backoff();
			suspend_short_count = 0;
		}
	} else {
		suspend_short_count = 0;
	}

	if (current_event_num == entry_event_num) {
		if (debug_mask & DEBUG_SUSPEND)
			pr_info("suspend: pm_suspend returned with no event\n");
		wake_lock_timeout(&unknown_wakeup, HZ / 2);
	}
}
static DECLARE_WORK(suspend_work, suspend);





评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值