找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 16363|回復: 0
打印 上一主題 下一主題
收起左側

Android 休眠機制->wake_lock機制淺析

[復制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:71922 發(fā)表于 2015-1-10 19:09 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
這段時間因為我們產(chǎn)品在休眠后耗電量還是非常大,而自己又對android那套休眠機制又不清除,不知道問題出在哪里,根據(jù)網(wǎng)上搜集的資料,總結一些心得,記錄在這,方便日后復習。
參考資料:
http://www.torrancerestoration.com/bbs/dpj-30357-1.html

由于事情較多,所以斷斷續(xù)續(xù)的分析。其中很多地方都不是很清晰,那么就學會一點就積累一點。
Android的休眠喚醒主要基于wake_lock機制,只要系統(tǒng)中存在任一有效的wake_lock,系統(tǒng)就不能進入深度休眠,但可以進行設備的淺度休眠操作。wake_lock一般在關閉lcd、tp,但系統(tǒng)仍然需要正常運行的情況下使用,比如聽歌、傳輸很大的文件等。
-----------------------------------------------------------------------------
深度休眠:
深度休眠的機制主要是鎖,只要系統(tǒng)中存在任一有效的wake_lock,系統(tǒng)就不能進入深度休眠。
當所有的鎖都無效時,那么系統(tǒng)就會進入深度休眠狀態(tài)。以下我對wake_lock鎖機制的理解?赡苡行┢睢

分析driver層wake_lock的實現(xiàn),我的講解流程是從鎖到全局。

數(shù)據(jù)結構定義:linux-3.4\kernel\power\wakelock.h
enum {
WAKE_LOCK_SUSPEND,    // 阻止進入深度休眠模式
WAKE_LOCK_IDLE,       // 阻止進入空閑模式
WAKE_LOCK_TYPE_COUNT  // 鎖的數(shù)量
};

#define WAKE_LOCK_TYPE_MASK              (0x0f)    // 標志掩碼
#define WAKE_LOCK_INITIALIZED            (1U << 8)   // 鎖已經(jīng)初始化
#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;     // 鏈表節(jié)點
int                 flags;    // 標志
const char         *name;     // 名稱
unsigned long       expires;  // 超時時間
#ifdef CONFIG_WAKELOCK_STAT
struct {        // 統(tǒng)計信息機構體
  int             count;         // 使用計數(shù)
  int             expire_count;  // 超時計數(shù)
  int             wakeup_count;  // 喚醒計數(shù)
  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);

// 判斷系統(tǒng)中是否還存在有效的type類型的鎖,如果存在則返回最長的一個鎖的超時時間,
// 如果存在永久鎖則返回-1,如果系統(tǒng)中不存在有效鎖則返回0
long has_wake_lock(int type);

這些接口都被EXPORT_SYMBOL()導出,可以為其他模塊所用。

它們都是通過維護兩個鎖鏈表(有效鎖鏈表、無效鎖鏈表)實現(xiàn)整套鎖機制。
有效鎖鏈表:
active_wake_locks[0]維護的是 WAKE_LOCK_SUSPEND.
active_wake_locks[1]維護的是 WAKE_LOCK_IDLE.
無效鎖鏈表:
inactive_locks  

調(diào)試信息輸出:(這個挺有意思的,可以指定輸出調(diào)試類型的信息)
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;

/* 初始化鎖 參數(shù): 鎖對象,類型,名字
* 主要是初始化了鎖的數(shù)據(jù)結構,并且將該節(jié)點加入到無效鎖鏈表中
* 在激活的時候就可以將該鎖從無效鎖鏈表中加到有效鎖鏈表*/
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);     // 斷言 參數(shù)檢查

if (debug_mask & DEBUG_WAKE_LOCK)
  pr_info("wake_lock_init name=%s\n", lock->name);
#ifdef CONFIG_WAKELOCK_STAT     // 初始化狀態(tài)信息
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 表示已經(jīng)初始化過
lock->flags = (type & WAKE_LOCK_TYPE_MASK) | WAKE_LOCK_INITIALIZED;
    // 初始化鏈表節(jié)點
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);

/* 注銷鎖,參數(shù):鎖對象
* 清除已經(jīng)初始化的標志、將鎖的狀態(tài)信息放入 deleted_wake_locks
* 不知道為什么要進去,網(wǎng)上有一份資料說是統(tǒng)計信息,但是我沒有看到有哪些地方用上
*/
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);
    // 清除已經(jīng)初始化的標志
lock->flags &= ~WAKE_LOCK_INITIALIZED;
#ifdef CONFIG_WAKELOCK_STAT
if (lock->stat.count) {   //  將該鎖的狀態(tài)復制給 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);

/* 真正激活鎖操作,參數(shù):鎖對象,若是超時鎖則為超時值否則為0,是否超時鎖
* 將該鎖從無效鏈表中刪除,加入到有效鏈表,
* 如果是超時鎖則設置其超時值,遍歷并取有效鏈表中超時值最長的超時鎖,將該超時值更新到定時器中
* (在遍歷過程中,會將已經(jīng)超時的超時鎖移除 具體看 static long has_wake_lock_locked()的實現(xiàn))
* 如果是永久鎖就將其超時值設置為極限,并清除超時鎖的標志
* 如果所有沒有超時鎖則刪除定時器,如果也沒有永久鎖則啟動深度休眠流程
* 注意,超時鎖是用 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++;        // 休眠鎖使用計數(shù)加1
  
#ifdef CONFIG_WAKELOCK_STAT
        // 如果是內(nèi)核休眠鎖
  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);
   // 更新定時器的超時時間 為最長有效鎖的超時時間 當時間到了,就會觸發(fā) expire_wake_locks()
   // 該函數(shù)會重新檢查所有的超時鎖,過期則從有效鏈表中移除過期的鎖
   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);
}

/* 遍歷指定類型的有效鎖鏈表,參數(shù)指定類型的有效鎖鏈表: WAKE_LOCK_SUSPEND、WAKE_LOCK_IDLE
* 遍歷有效鎖鏈表中斷超時鎖,并將已經(jīng)過期的鎖移除,取沒有過期并且超時時間最長的鎖時間
* 如果沒有有效的超時鎖則返回-1,如果有效鏈表沒有鎖則返回0
* 這個函數(shù)每次調(diào)用都會遍歷鎖鏈表就是因為要處理已經(jīng)過期的鎖,并取得最長的鎖時間用于更新定時器
* 重點鏈表結構: --永久鎖--鏈表頭--超時鎖--
* 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);
    // 遍歷指定鎖類型有效鎖鏈表 如果有效鎖鏈表里面沒有鎖則不會執(zhí)行下面的代碼塊
list_for_each_entry_safe(lock, n, &active_wake_locks[type], link)
{       // <-- 進入了代碼塊說明有效鏈表上有鎖
        // 如果是超時鎖
        if (lock->flags & WAKE_LOCK_AUTO_EXPIRE)
  {      // <-- 進入這個代碼塊說明有效鏈表上有超時鎖
            // 計算超時剩余時間
   long timeout = lock->expires - jiffies;
            // 如果鎖已經(jīng)過期 則移除過期鎖
   if (timeout <= 0)
    expire_wake_lock(lock);
            // 如果鎖沒有過期 則取最長的一個超時時間的鎖
   else if (timeout > max_timeout)
    max_timeout = timeout;  
  }
  else  // 如果不是超時鎖說明超時鎖已經(jīng)遍歷完,剩下的就是永久鎖了,返回 -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);

/*
* 定時器的回調(diào)函數(shù),因為定時器的定時值一直會被 wake_lock_internal()\wake_unlock()
* 更新為當前有效鏈表中時間最長的超時鎖的超時值,當最長的超時鎖時間來到,這函數(shù)就會被執(zhí)行
* 這個函數(shù)會調(diào)用 has_wake_lock_locked() 來清理過期鎖,同時檢測到?jīng)]鎖就會進入深度休眠模式
*/
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);
    // 如果是調(diào)試模式則打印當前有效鎖
if (debug_mask & DEBUG_SUSPEND)
  print_active_locks(WAKE_LOCK_SUSPEND);
    // 檢測系統(tǒng)是否持有休眠鎖 重點 ->
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);
    // 如果系統(tǒng)當前沒有持有有效的鎖
    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);


/* 該函數(shù)用于釋放一個鎖,首先將鎖從有效鎖鏈表中移除并加入無效鎖鏈表,并判斷系統(tǒng)是否
* 還持有有效鎖,如果沒有則刪除定時器并進入深度休眠流程,如果有則取其中延時最長的超
* 時鎖時間用于更新定時器的定時值,當時間到達時就會調(diào)用  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
    // 更新鎖的狀態(tài)
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)
{
        // 判斷系統(tǒng)當前是否還持有鎖
  long has_lock = has_wake_lock_locked(type);
        // 如果還持有鎖,設置timer到超時時間點觸發(fā)
  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);
  }
        // 如果是內(nèi)核鎖 則打印當前有效鎖信息
  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);

/* 判斷系統(tǒng)是否還持有有效鎖 */
long has_wake_lock(int type)
{
long ret;
unsigned long irqflags;
spin_lock_irqsave(&list_lock, irqflags);
    // 開始判斷流程
ret = has_wake_lock_locked(type);
    // 如果還有休眠鎖有效則打印狀態(tài)信息
if (ret && (debug_mask & DEBUG_WAKEUP) && type == WAKE_LOCK_SUSPEND)
  print_active_locks(type);
spin_unlock_irqrestore(&list_lock, irqflags);
return ret;
}


從以上函數(shù)的解析來看,整個鎖機制都已經(jīng)呼之欲出了。

當系統(tǒng)已經(jīng)沒有鎖的時候,就會啟動 queue_work(suspend_work_queue, &suspend_work); 隊列,從而進入深度休眠的流程。
當系統(tǒng)有一個鎖,都不會啟動深度休眠。所以安卓啟動的時候會初始化并激活一把永久鎖->main,在需要深度休眠的時候會移除這把鎖。
我們初始化鎖的時候,調(diào)用 wake_lock_init(); 它會初始化鎖對象的名字、狀態(tài)信息等,并將其加入無效鎖鏈表中。

當激活時調(diào)用 wake_lock()\wake_lock_timeout()->wake_lock_internal() 會將鎖加入到有效鏈表中,如果是超時鎖會調(diào)用list_add_tail()
將該鎖加入到鏈表頭的后面,如果是永久鎖則調(diào)用list_add()將該鎖加入鏈表頭的前面,有效鏈表的結構是這樣:--永久鎖--鏈表頭--超時鎖-- ,
這種方式是為了提高has_wake_lock_locked()遍歷效率。如果激活的是超時鎖,會調(diào)用has_wake_lock_locked() 函數(shù)遍歷 active_wake_locks[0]
->WAKE_LOCK_SUSPEND 類型的有效鏈表,移除過期鎖并取該鏈表中超時鎖中超時值最長的值,將該值作為定時器的值更新到定時器中。如果沒有鎖
則進入深度休眠流程:queue_work(suspend_work_queue, &suspend_work);

當超時最長的鎖的時間到了,那么定時器函數(shù)expire_wake_locks()自然也就被回調(diào),定時器函數(shù)被回調(diào)后就會再次調(diào)用 has_wake_lock_locked(WAKE_LOCK_SUSPEND), 將過期的鎖移除,定時器根據(jù)其返回值知道鏈表上還有沒有鎖,如果沒有鎖則進入深度休眠流程:queue_work(suspend_work_queue, &suspend_work);

當我們要釋放鎖的時候,調(diào)用wake_unlock() 將該鎖從有效鏈表中移到無效鏈表中,并調(diào)用 has_wake_lock_locked(),該函數(shù)的功能不再復述,
當有效鏈表中沒有鎖時,則進入深度休眠流程:queue_work(suspend_work_queue, &suspend_work);

當我們要銷毀一個鎖的時候則調(diào)用wake_lock_destroy(),就會將鎖從鏈表中刪除。

由此可見,android 進入深度休眠時的入口出現(xiàn)在:expire_wake_locks()、wake_lock_internal()、wake_unlock(),這三個地方。每個地方都一定會
調(diào)用has_wake_lock_locked()去清除過期鎖并得到有效鎖鏈表是否還有鎖,如果沒有都會啟動休眠隊列queue_work(suspend_work_queue, &suspend_work);進入深度休眠流程。

我不太明白為什么要大費周章實現(xiàn)這個鎖機制,如果有一個APK注冊了鎖而又忘記了釋放鎖,那豈不是系統(tǒng)一直都會無法進入深度休眠狀態(tài)?
可能只進入了淺度休眠狀態(tài),而我們以為進入了深度休眠狀態(tài)導致電池的電量浪費。

不過這鎖機制有一個地方很有意思,就是有效鎖鏈表的組織上很巧妙,一點小小的改動就很好的將超時鎖和永久鎖分好,很大的優(yōu)化了遍歷的性能。
這點表現(xiàn)在wake_lock_internal()函數(shù)中,將超時鎖加在鏈表頭的后面,而將永久鎖加在鏈表頭的前面。
這個鏈表是雙向循環(huán)鏈表,當遍歷的時候,就從鏈表頭的后面開始,也就是遍歷超時鎖,當遍歷到的節(jié)點不是超時鎖,這就意味著是永久鎖,
就不需要再繼續(xù)無謂的遍歷了。

--------------------------------------------------- 零散記錄 ------------------------------------------------------
驅(qū)動代碼:linux-3.5\kernel\power\wakelock.c

core_initcall(wakelocks_init);  // 驅(qū)動入口 最高優(yōu)先級 最先加載的驅(qū)動
module_exit(wakelocks_exit);

驅(qū)動入口函數(shù)主要做了如下的事情 static int __init wakelocks_init(void):
1、初始化兩個有效鎖鏈表:用于阻止進入深度休眠模式的鎖和用于阻止進入淺度休眠模式的鎖
當初始化好并被激活的鎖都會被加入到相應的有效鏈表鎖里。
2、如果定義了 CONFIG_WAKELOCK_STAT 初始化 deleted_wake_locks 用于處理統(tǒng)計信息
3、初始化內(nèi)核休眠鎖 main_wake_lock ,并激活這個鎖,深度休眠時需要釋放這個鎖
4、初始化同步鎖 sync_wake_lock 用于淺度休眠階段同步緩存時阻止內(nèi)核進入深度休眠
5、初始化未知鎖 用于喚醒時延遲0.5s進入下一次可能的深度休眠
6、如果定義了 CONFIG_EARLYSUSPEND_DELAY 則初始化并激活 ealysuspend_delay_work 淺度休眠鎖
7、 注冊 power_device power_driver 用于深度休眠階段檢測是否存在有效鎖
8、創(chuàng)建 suspend內(nèi)核工作隊列 用于進行淺度休眠和深度休眠
9、創(chuàng)建 同步系統(tǒng)鎖內(nèi)核隊列
10、在proc下創(chuàng)建wakelocks文件  節(jié)點用于提供節(jié)點顯示wake_lock的統(tǒng)計信息

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

    // 初始化有效鎖鏈表,內(nè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 用于處理統(tǒng)計信息
wake_lock_init(&deleted_wake_locks, WAKE_LOCK_SUSPEND, "deleted_wake_locks");
#endif
    // 初始化內(nèi)核休眠鎖
wake_lock_init(&main_wake_lock, WAKE_LOCK_SUSPEND, "main");
    // 初始化同步鎖 用于淺度休眠階段同步緩存時阻止內(nèi)核進入深度休眠
wake_lock_init(&sync_wake_lock, WAKE_LOCK_SUSPEND, "sync_system");
    // 激活內(nèi)核休眠鎖 系統(tǒng)啟動時會激活這個鎖,深度休眠時需要釋放這個鎖
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;
}
    // 創(chuàng)建 suspend內(nèi)核工作隊列 用于進行淺度休眠和深度休眠
suspend_work_queue = create_singlethread_workqueue("suspend");
if (suspend_work_queue == NULL) {
  ret = -ENOMEM;
  goto err_suspend_work_queue;
}
    // 創(chuàng)建 同步系統(tǒng)鎖內(nèi)核隊列
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下創(chuàng)建wakelocks文件  節(jié)點用于顯示wake_lock的統(tǒng)計信息
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;
}


分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏 分享淘帖 頂 踩
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網(wǎng)

快速回復 返回頂部 返回列表