Служба SystemSuspend

В 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 отслеживает количество блокировок пробуждения, выданных с помощью счетчика приостановки. Он имеет два потока выполнения:

  • Основной поток отвечает на вызовы связывателя.
  • Поток приостановки управляет системой приостановки.

Основная нить

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

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

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

  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 , завершает работу, драйвер связывателя и служба SystemSuspend очищают его.

AIDL-интерфейс ISuspendControlService

ISuspendControlService предназначен для использования только SystemServer.


interface ISuspendCallback {
     void notifyWakeup(boolean success);
}

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

Использование Android HIDL дает следующие преимущества:

  • Если процесс, блокирующий приостановку, умирает, SystemSuspend может быть уведомлен.
  • Поток, ответственный за приостановку системы, может получить обратный вызов.