首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C >> 關於C

Linux 內核電源管理子系統深度解析:autosleep、wake_lock 與掛起/恢復流程

     編輯:關於C

Android/Linux 電源管理核心在於 autosleep 機制與 wake_lock 協同。本文從內核源碼角度梳理:用戶態接口 → 內核核心邏輯 → 設備模型掛起/恢復 → 平台相關操作 → wake_lock 防休眠機制。

1. Autosleep 入口與狀態機

用戶態寫入 /sys/power/autosleep (值:off/standby/mem/disk) → autosleep_store() → pm_autosleep_set_state()。


static ssize_t autosleep_store(...) {
    suspend_state_t state = decode_state(buf, n); // 解析字符串為枚舉
    return pm_autosleep_set_state(state) ? -EINVAL : n;
}

int pm_autosleep_set_state(suspend_state_t state) {
    mutex_lock(&autosleep_lock);
    autosleep_state = state; // 全局狀態變量
    if (state > PM_SUSPEND_ON) {
        pm_wakep_autosleep_enabled(true);  // 所有 wake source 標記 autosleep_enabled
        mod_timer(&unattended_timer, ...); // 設置無人值守超時定時器
        queue_up_suspend_work();           // 排程掛起工作隊列
    } else {
        pm_wakep_autosleep_enabled(false);
        del_timer(&unattended_timer);
    }
    mutex_unlock(&autosleep_lock);
    return 0;
}

2. 掛起工作隊列與 try_to_suspend()


static DECLARE_WORK(suspend_work, try_to_suspend);

static void try_to_suspend(struct work_struct *work) {
    if (autosleep_state >= PM_SUSPEND_MAX) hibernate(); // 休眠到磁盤
    else pm_suspend(autosleep_state);                   // 進入待機/內存睡眠
}

3. pm_suspend() 核心流程

  1. suspend_prepare():分配控制台、發送 PM_SUSPEND_PREPARE 通知、凍結所有用戶態進程 (suspend_freeze_processes())。
  2. suspend_devices_and_enter(state):設備掛起 + 平台進入低功耗態。
    • 平台 suspend_ops->begin() (如有)。
    • 掛起控制台 (suspend_console())。
    • 設備模型掛起:dpm_suspend_start(PMSG_SUSPEND) → 遍歷 dpm_list 設備鏈表,調用各設備 suspend() 回調 (依序:domain → type → class → bus)。
    • 進入 CPU 低功耗態:suspend_enter(state, &wakeup) → 禁用非引導 CPU → 核心掛起 (syscore_suspend()) → 平台進入睡眠 (suspend_ops->enter(state)) → **CPU 停止執行,此處阻塞直到喚醒中斷** → 核心恢復 → 啟用 CPU → 平台 wake() → 設備恢復 (dpm_resume_start()) → 恢復控制台 → 平台 end()。

4. 設備模型與電源域回調鏈

設備註冊 (device_register() → device_pm_add()) 將 struct device 的 power.entry 加入全局 dpm_list。掛起時按拓撲序遍歷,調用優先級:pm_domain->ops > type->pm > class->pm > bus->pm > legacy suspend。恢復順序相反。

5. Wake Lock 機制詳解

用戶態 → 內核路徑

App: PowerManager.acquire() → JNI: acquire_wake_lock() → HAL: write(/sys/power/wake_lock, "name")
      ↓
Kernel: wake_lock_store() → pm_wake_lock() → wakelock_lookup_add() → wakeup_source_add()
      ↓
      分配/查找 wakeup_source 結構體,加入全局 wakeup_sources 鏈表 (RCU 保護)
      設置 ws->active = true,ws->autosleep_enabled 由 pm_wakep_autosleep_enabled() 同步

防休眠判斷

try_to_suspend() 入口前,內核遍歷 wakeup_sources,若存在 ws->active == true 且 ws->autosleep_enabled == true,則 **中止掛起**,直接返回錯誤,系統保持喚醒。

關鍵數據結構


struct wakeup_source {
    const char *name;
    struct list_head entry;      // 全局鏈表節點
    spinlock_t lock;
    bool active;                 // 當前是否被持有
    bool autosleep_enabled;      // 是否參與 autosleep 判斷
    ktime_t start_prevent_time;  // 開始阻止睡眠時間
    // ... 統計字段
};

6. 平台相關 suspend_ops (以 MSM 8x60 為例)


static const struct platform_suspend_ops msm_pm_ops = {
    .enter = msm_pm_enter,           // 核心:配置 CPU 寄存器、切換電源域、執行 WFI/WFE 指令 **CPU 停在此**
    .valid = suspend_valid_only_mem, // 僅支援 mem sleep
    .prepare_late = msm_suspend_prepare,
    .wake = msm_suspend_wake,        // 喚醒後恢復硬件狀態
};
// 註冊: suspend_set_ops(&msm_pm_ops);

關鍵認知:msm_pm_enter() 執行 asm("wfi") 等指令,**CPU 管線停止**,代碼執行流凍結。喚醒中斷 (Power Key、RTC、Modem 等) 觸發 CPU 重新啟動,從 wfi 後繼續執行,進入恢復流程。

總結圖譜

用戶態 autosleep/wake_lock
       ↓ 寫 sysfs
內核 pm_autosleep_set_state / pm_wake_lock
       ↓ 修改全局狀態 / wakeup_source.active
工作隊列 try_to_suspend()
       ↓
pm_suspend() → suspend_prepare() → freeze processes
       ↓
suspend_devices_and_enter() → dpm_suspend_start() → 設備逐個 suspend()
       ↓
suspend_enter() → disable CPUs → syscore_suspend() → **platform_ops->enter() (CPU 停機)**
       ↑                                            ↑
       └────────────── 喚醒中斷 ──────────────────┘
       ↓
恢復流程對稱反向執行
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved