在 Android 9 及更低版本中, libsuspend中有一個線程負責啟動系統掛起。 Android 10 在 SystemSuspend HIDL 服務中引入了等效功能。該服務位於系統映像中,由 Android 平台提供服務。 libsuspend
中的邏輯基本保持不變,除了阻塞系統掛起的每個用戶空間進程都需要與 SystemSuspend 通信。
libsuspend 和 libpower
在 Android 10 中, SystemSuspend 服務取代了libsuspend
。 libpower
被重新實現以依賴 SystemSuspend 服務而不是/sys/ power /wake[un]lock
而不更改 C API。
這個偽代碼展示瞭如何實現acquire_wake_lock
和release_wake_lock
。
static std::unordered_map<std::string, sp<IWakeLock>> gWakeLockMap;
int acquire_wake_lock(int, const char* id) {
...
if (!gWakeLockMap[id]) {
gWakeLockMap[id] = suspendService->acquireWakeLock(WakeLockType::PARTIAL, id);
}
...
return 0;
}
int release_wake_lock(const char* id) {
...
if (gWakeLockMap[id]) {
auto ret = gWakeLockMap[id]->release();
gWakeLockMap[id].clear();
return 0;
}
...
return -1;
}
執行線程
SystemSuspend 服務跟踪使用掛起計數器發出的喚醒鎖的數量。它有兩個執行線程:
- 主線程響應活頁夾調用。
- 掛起線程控制系統掛起。
主線程
主線程響應來自客戶端的請求以分配新的喚醒鎖,增加/減少掛起計數器。
掛起線程
掛起線程在循環中執行以下操作:
- 從
/sys/ power /wakeup_count
。 - 獲取互斥鎖。這確保了掛起線程在主線程嘗試遞增或遞減它時不會觸及掛起計數器。當掛起計數器達到零並且掛起線程正在嘗試運行時,主線程在發出或刪除喚醒鎖時被阻塞。
- 等到計數器為零。
- 將從
/sys/ power /wakeup_count
(從步驟 1)讀取的值寫入此文件。如果寫入失敗,則返回循環開頭 - 通過將
mem
寫入/sys/power/ state
來啟動系統掛起。 - 釋放互斥鎖。
當喚醒鎖請求成功返回時,掛起線程被阻塞。

SystemSuspend API
SystemSuspend API 由兩個接口組成。本機進程使用 HIDL 接口來獲取喚醒鎖,而 AIDL 接口用於 SystemServer 和 SystemSuspend 之間的通信。
ISystemSuspend HIDL 接口
enum WakeLockType : uint32_t {
PARTIAL,
FULL
};
interface IWakeLock {
oneway release();
};
interface ISystemSuspend {
acquireWakeLock(WakeLockType type, string debugName)
generates (IWakeLock lock);
};
每個請求喚醒鎖的客戶端都會收到一個唯一的IWakeLock
實例。這與/sys/ power /wake_lock
,後者允許多個客戶端使用同名的喚醒鎖。如果持有IWakeLock
實例的客戶端終止,則綁定器驅動程序和 SystemSuspend 服務將清除它。
ISuspendControlService AIDL 接口
ISuspendControlService 僅供 SystemServer 使用。
interface ISuspendCallback {
void notifyWakeup(boolean success);
}
interface ISuspendControlService {
boolean enableAutosuspend();
boolean registerCallback(ISuspendCallback callback);
boolean forceSuspend();
}
利用 Android HIDL 具有以下優勢:
- 如果掛起阻塞進程終止,則可以通知 SystemSuspend。
- 可以給負責系統掛起的線程一個回調。