在 Android 9 及更低版本中, libsuspend中有一個執行緒負責啟動系統掛起。 Android 10 在 SystemSuspend HIDL 服務中引進了等效功能。該服務位於系統映像中,由 Android 平台提供服務。除了阻止系統掛起的每個用戶空間程序都需要與 SystemSuspend 通訊之外, libsuspend
的邏輯基本上保持不變。
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
啟動系統掛起。 - 釋放互斥體。
當喚醒鎖定請求成功返回時,掛起執行緒將被阻塞。
系統掛起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
實例的用戶端終止,binder 驅動程式和 SystemSuspend 服務會將其清除。
ISuspendControlService AIDL 介面
ISuspendControlService 僅供 SystemServer 使用。
interface ISuspendCallback {
void notifyWakeup(boolean success);
}
interface ISuspendControlService {
boolean enableAutosuspend();
boolean registerCallback(ISuspendCallback callback);
boolean forceSuspend();
}
利用 Android HIDL 有以下優點:
- 如果掛起阻塞程序終止,則可以通知 SystemSuspend。
- 負責系統掛起的執行緒可以被給予回呼。