Android/Linux 電源管理核心在於 autosleep 機制與 wake_lock 協同。本文從內核源碼角度梳理:用戶態接口 → 內核核心邏輯 → 設備模型掛起/恢復 → 平台相關操作 → wake_lock 防休眠機制。
用戶態寫入 /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;
}
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); // 進入待機/內存睡眠
}
pm_suspend() 核心流程suspend_prepare():分配控制台、發送 PM_SUSPEND_PREPARE 通知、凍結所有用戶態進程 (suspend_freeze_processes())。suspend_devices_and_enter(state):設備掛起 + 平台進入低功耗態。
suspend_ops->begin() (如有)。suspend_console())。dpm_suspend_start(PMSG_SUSPEND) → 遍歷 dpm_list 設備鏈表,調用各設備 suspend() 回調 (依序:domain → type → class → bus)。suspend_enter(state, &wakeup) → 禁用非引導 CPU → 核心掛起 (syscore_suspend()) → 平台進入睡眠 (suspend_ops->enter(state)) → **CPU 停止執行,此處阻塞直到喚醒中斷** → 核心恢復 → 啟用 CPU → 平台 wake() → 設備恢復 (dpm_resume_start()) → 恢復控制台 → 平台 end()。設備註冊 (device_register() → device_pm_add()) 將 struct device 的 power.entry 加入全局 dpm_list。掛起時按拓撲序遍歷,調用優先級:pm_domain->ops > type->pm > class->pm > bus->pm > legacy suspend。恢復順序相反。
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; // 開始阻止睡眠時間
// ... 統計字段
};
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 停機)**
↑ ↑
└────────────── 喚醒中斷 ──────────────────┘
↓
恢復流程對稱反向執行