Android休眠唤醒驱动流程分析(四)

来源:互联网 发布:淘宝宝贝裂变软件免费 编辑:程序博客网 时间:2024/04/28 22:30

关于wake_lock

在上文中,已经介绍了wakelock机制,下面从代码的角度进行介绍。

wakelock2种类型,常用为WAKE_LOCK_SUSPEND,作用是防止系统进入睡眠。WAKE_LOCK_IDLE

这种锁不会影响到系统进入休眠,但是如果这种锁被持有,那么系统将无法进入idle空闲模式。

enum {

WAKE_LOCK_SUSPEND, 

WAKE_LOCK_IDLE,    

WAKE_LOCK_TYPE_COUNT

};

 

Wakelock有加锁和解锁2种操作,加锁有2种方式,第一种是永久加锁(wake_lock),这种锁必须手动的解锁;另一种是超时锁(wake_lock_timeout),这种锁在过去指定时间后,会自动解锁。

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

}

 

对于wakelocktimeout has_timeout 0;直接加锁后,然后退出;

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.lu\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);

if (expire_in == 0)

queue_work(suspend_work_queue, &suspend_work);

}

}

spin_unlock_irqrestore(&list_lock, irqflags);

}

而对于wake_lock_timeout,在经过timeout时间后,才加锁。再判断当前持有wakelock时,启动另一个定时器,在expire_timer的回调函数中再次判断是否持有wakelock

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

 

wakelock中,有2个地方可以让系统从early_suspend进入suspend状态。分别是:

wake_unlock中,解锁之后,若没有其他的wakelock,则进入suspend

在超时锁的定时器超时后,定时器的回调函数,会判断有没有其他的wakelock,若没有,则进入suspend

0 0
原创粉丝点击