系統暫停服務

在 Android 9 及更低版本中, libsuspend中有一個線程負責啟動系統掛起。 Android 10 在 SystemSuspend HIDL 服務中引入了等效功能。該服務位於系統映像中,由 Android 平台提供服務。 libsuspend中的邏輯基本保持不變,除了阻塞系統掛起的每個用戶空間進程都需要與 SystemSuspend 通信。

libsuspend 和 libpower

在 Android 10 中, SystemSuspend 服務取代了libsuspendlibpower被重新實現以依賴 SystemSuspend 服務而不是/sys/ power /wake[un]lock而不更改 C API。

這個偽代碼展示瞭如何實現acquire_wake_lockrelease_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 服務跟踪使用掛起計數器發出的喚醒鎖的數量。它有兩個執行線程:

  • 線程響應活頁夾調用。
  • 掛起線程控制系統掛起。

主線程

主線程響應來自客戶端的請求以分配新的喚醒鎖,增加/減少掛起計數器。

掛起線程

掛起線程在循環中執行以下操作:

  1. /sys/ power /wakeup_count
  2. 獲取互斥鎖。這確保了掛起線程在線程嘗試遞增或遞減它時不會觸及掛起計數器。當掛起計數器達到零並且掛起線程正在嘗試運行時,線程在發出或刪除喚醒鎖時被阻塞。
  3. 等到計數器為零。
  4. 將從/sys/ power /wakeup_count (從步驟 1)讀取的值寫入此文件。如果寫入失敗,則返回循環開頭
  5. 通過將mem寫入/sys/power/ state來啟動系統掛起。
  6. 釋放互斥鎖。

當喚醒鎖請求成功返回時,掛起線程被阻塞。

圖 1.掛起線程循環

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。
  • 可以給負責系統掛起的線程一個回調。