В 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 отслеживает количество запретов блокировки, выданных с помощью счетчика приостановки. У него два потока выполнения:
- Цепочка main отвечает на вызовы Binder.
- Поток suspend управляет приостановкой системы.
Основной поток
Основной поток отвечает на запросы клиентов о выделении новых запретов блокировки, увеличивая или уменьшая счетчик приостановки.
Приостановить цепочку
Поток приостановки выполняет в цикле следующие действия:
- Прочитай текст из
/sys/power/wakeup_count. - Получите мьютекс. Это гарантирует, что поток приостановки не затронет счетчик приостановок, пока основной поток пытается увеличить или уменьшить его. Основной поток заблокирован при выдаче или удалении запретов блокировки, когда счетчик приостановки достиг нуля и поток приостановки пытается запуститься.
- Дождитесь, пока счетчик не достигнет нуля.
- Запишите в этот файл значение, считанное из
/sys/power /wakeup_count(на шаге 1). Если запись не удалась, вернитесь в начало цикла. - Чтобы запустить переход системы в спящий режим, запишите
memв файл/sys/power/state. - Освободите мьютекс.
Если запрос на запрет блокировки успешно возвращается, поток приостановки блокируется.
SystemSuspend API
SystemSuspend API состоит из двух интерфейсов. Интерфейс HIDL используется нативными процессами для получения запретов блокировки, а интерфейс AIDL – для связи между SystemServer и SystemSuspend.
Интерфейс HIDL ISystemSuspend
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();
}
Использование HIDL в Android дает следующие преимущества:
- Если процесс, блокирующий приостановку, завершается, SystemSuspend может получить уведомление.
- Поток, отвечающий за приостановку системы, может получить обратный вызов.