Dịch vụ SystemSuspend

Trong Android 9 trở xuống, có một luồng trong libsuspend chịu trách nhiệm khởi tạo quá trình tạm ngưng hệ thống. Android 10 giới thiệu một chức năng tương đương trong dịch vụ SystemSuspend HIDL. Dịch vụ này nằm trong hình ảnh hệ thống và do nền tảng Android cung cấp. Logic từ libsuspend phần lớn vẫn giữ nguyên, ngoại trừ mọi quy trình chặn hệ thống tạm ngưng của không gian người dùng cần giao tiếp với SystemSuspend.

libsuspend và libpower

Trong Android 10, dịch vụ SystemSuspend sẽ thay thế libsuspend. libpower được triển khai lại để dựa vào dịch vụ SystemSuspend thay vì /sys/power/wake[un]lock mà không thay đổi C API.

Mã giả này cho biết cách triển khai 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;
}

Luồng thực thi

Dịch vụ SystemSuspend theo dõi số lượng khoá đánh thức được phát hành bằng bộ đếm tạm ngưng. Nó có 2 luồng thực thi:

  • Luồng chính trả lời các lệnh gọi liên kết.
  • Luồng suspend kiểm soát trạng thái tạm ngưng của hệ thống.

Luồng chính

Luồng chính trả lời các yêu cầu của ứng dụng để phân bổ khoá đánh thức mới, tăng/giảm bộ đếm tạm ngưng.

Tạm ngưng chuỗi

Luồng tạm ngưng thực hiện những thao tác sau trong một vòng lặp:

  1. Đọc từ /sys/power/wakeup_count.
  2. Thu nạp mutex. Điều này đảm bảo rằng luồng tạm ngưng không chạm vào bộ đếm tạm ngưng trong khi luồng main đang cố gắng tăng hoặc giảm bộ đếm đó. Luồng chính bị chặn khi phát hành hoặc xoá khoá đánh thức khi bộ đếm tạm ngưng đạt đến 0 và luồng tạm ngưng đang cố gắng chạy.
  3. Chờ cho đến khi bộ đếm bằng 0.
  4. Ghi giá trị đọc được từ /sys/power /wakeup_count (từ bước 1) vào tệp này. Nếu thao tác ghi không thành công, hãy quay lại đầu vòng lặp
  5. Bắt đầu quá trình tạm ngưng hệ thống bằng cách ghi mem vào /sys/power/state.
  6. Giải phóng mutex.

Khi một yêu cầu khoá đánh thức trả về thành công, luồng tạm ngưng sẽ bị chặn.

Hình 1. Tạm dừng vòng lặp luồng

SystemSuspend API

SystemSuspend API bao gồm 2 giao diện. Các quy trình gốc sử dụng giao diện HIDL để lấy khoá đánh thức và giao diện AIDL được dùng để giao tiếp giữa SystemServer và SystemSuspend.

Giao diện HIDL ISystemSuspend


enum WakeLockType : uint32_t {
    PARTIAL,
    FULL
};

interface IWakeLock {
    oneway release();
};

interface ISystemSuspend {
    acquireWakeLock(WakeLockType type, string debugName)
        generates (IWakeLock lock);
};

Mỗi ứng dụng yêu cầu khoá đánh thức sẽ nhận được một thực thể IWakeLock duy nhất. Điều này khác với /sys/power/wake_lock, cho phép nhiều ứng dụng sử dụng khoá đánh thức có cùng tên. Nếu một ứng dụng khách giữ phiên bản IWakeLock kết thúc, trình điều khiển liên kết và dịch vụ SystemSuspend sẽ dọn dẹp phiên bản đó.

Giao diện ISuspendControlService AIDL

ISuspendControlService chỉ dành cho SystemServer.


interface ISuspendCallback {
     void notifyWakeup(boolean success);
}

interface ISuspendControlService {
    boolean enableAutosuspend();
    boolean registerCallback(ISuspendCallback callback);
    boolean forceSuspend();
}

Việc tận dụng HIDL của Android mang lại những lợi ích sau:

  • Nếu một quy trình chặn tạm ngưng bị tắt, SystemSuspend có thể được thông báo.
  • Bạn có thể cung cấp một lệnh gọi lại cho luồng chịu trách nhiệm tạm ngưng hệ thống.