Служба SystemSuspend

В Android 9 и более ранних версиях в libsuspend есть поток, отвечающий за инициализацию режима ожидания системы. В Android 10 аналогичная функциональность представлена ​​в HIDL-сервисе SystemSuspend. Этот сервис расположен в образе системы и обслуживается платформой 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 отслеживает количество блокировок пробуждения с помощью счётчика приостановки. Она имеет два потока выполнения:

  • Основной поток отвечает на запросы связующего звена.
  • Система управления приостановкой потока приостанавливает работу системы.

Основная тема

Основной поток отвечает на запросы клиентов о выделении новых блокировок пробуждения, увеличивая/уменьшая счетчик приостановки.

Приостановить поток

Приостановленный поток выполняет в цикле следующее:

  1. Прочитать из /sys/ power /wakeup_count .
  2. Захватите мьютекс. Это гарантирует, что приостановленный поток не коснётся счётчика приостановки, пока основной поток пытается увеличить или уменьшить его. Основной поток блокируется при установке или снятии блокировок пробуждения, когда счётчик приостановки достигает нуля, а приостановленный поток пытается продолжить работу.
  3. Подождите, пока счетчик не станет равен нулю.
  4. Записать значение, считанное из /sys/ power /wakeup_count (на шаге 1), в этот файл. Если запись не удалась, вернуться к началу цикла.
  5. Запустите режим ожидания системы, записав mem в /sys/power/ state .
  6. Освободить мьютекс.

При успешном возврате запроса на блокировку пробуждения поток приостановки блокируется.

Рисунок 1. Подвесная петля из нити

API SystemSuspend

API SystemSuspend состоит из двух интерфейсов: интерфейс 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 может быть уведомлен об этом.
  • Потоку, ответственному за приостановку системы, можно назначить обратный вызов.