SystemSuspend 服务

在 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 服务使用挂起计数器跟踪已发出的唤醒锁的数量。它有两个执行线程

  • 线程响应 Binder 调用。
  • 挂起线程控制系统挂起。

主线程

主线程响应来自客户端的请求以分配新的唤醒锁,从而递增/递减挂起计数器。

挂起线程

挂起线程在循环中执行以下操作

  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 实例的客户端终止,则 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。
  • 可以为负责系统挂起的线程提供回调。