android 休眠唤醒机制分析(一)
2015-11-27 10:42
537 查看
Android的休眠唤醒主要基于wake_lock机制,只要系统中存在任一有效的wake_lock,系统就不能进入深度休眠,但可以进行设备的浅度休眠操作。wake_lock一般在关闭lcd、tp但系统仍然需要正常运行的情况下使用,比如听歌、传输很大的文件等。本文主要分析driver层wake_lock的实现。
一、wake_lock 定义和接口
[cpp] view
plaincopy
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、内核空间接口
[cpp] view
plaincopy
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()用于解锁使之成为无效锁。另外还有两个接口:
[cpp] view
plaincopy
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向用户空间提供了两个文件节点用于申请锁和解锁:
[cpp] view
plaincopy
// 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的实现代码,首先看看其定义的一些初始化信息:
[cpp] view
plaincopy
#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系统初始化
[cpp] view
plaincopy
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
一、wake_lock 定义和接口
[cpp] view
plaincopy
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、内核空间接口
[cpp] view
plaincopy
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()用于解锁使之成为无效锁。另外还有两个接口:
[cpp] view
plaincopy
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向用户空间提供了两个文件节点用于申请锁和解锁:
[cpp] view
plaincopy
// 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的实现代码,首先看看其定义的一些初始化信息:
[cpp] view
plaincopy
#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系统初始化
[cpp] view
plaincopy
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
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories