在 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 服务使用挂起计数器跟踪已发出的唤醒锁的数量。它有两个执行线程
- 主线程响应 Binder 调用。
- 挂起线程控制系统挂起。
主线程
主线程响应来自客户端的请求以分配新的唤醒锁,从而递增/递减挂起计数器。
挂起线程
挂起线程在循环中执行以下操作
- 从
/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
实例的客户端终止,则 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。
- 可以为负责系统挂起的线程提供回调。