SystemSuspend 서비스

Android 9 이하의 libsuspend에는 시스템 정지를 시작하는 스레드가 있습니다. Android 10에는 SystemSuspend HIDL 서비스의 동일한 기능이 도입되었습니다. 이 서비스는 시스템 이미지에 위치하며, Android 플랫폼에서 제공됩니다. libsuspend의 논리는 대부분 동일하게 유지되지만 시스템 정지를 막는 모든 사용자 공간 프로세스를 SystemSuspend로 통신해야 한다는 점이 다릅니다.

libsuspend 및 libpower

Android 10에서는 SystemSuspend 서비스가 libsuspend를 대체합니다. libpower는 C API를 변경하지 않고 /sys/power/wake[un]lock 대신 SystemSuspend 서비스에 의존하도록 재구현되었습니다.

이 의사코드는 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 서비스는 정지 카운터로 발행된 wake lock의 수를 추적합니다. 여기에는 두 개의 실행 스레드가 있습니다.

  • 기본 스레드는 바인더 호출에 응답합니다.
  • 정지 스레드는 시스템 정지를 제어합니다.

기본 스레드

기본 스레드는 클라이언트의 요청에 응답하여 새로운 wake lock을 할당하고 정지 카운터를 늘리거나 줄입니다.

정지 스레드

정지 스레드는 루프에서 다음을 실행합니다.

  1. /sys/power/wakeup_count에서 읽습니다.
  2. 뮤텍스를 가져옵니다. 그러면 기본 스레드가 증분 또는 감소를 시도하는 동안 정지 스레드가 정지 카운터를 건드리지 않습니다. 정지 카운터가 0에 도달하고 정지 스레드가 실행을 시도하는 경우에는 wake lock 발행 또는 제거 시 기본 스레드가 차단됩니다.
  3. 카운터가 0이 될 때까지 기다립니다.
  4. 1단계의 /sys/power /wakeup_count에서 읽은 값을 이 파일에 씁니다. 쓰기에 실패하면 루프의 처음으로 돌아갑니다.
  5. mem/sys/power/state에 써서 시스템 정지를 시작합니다.
  6. 뮤텍스를 해제합니다.

wake lock 요청이 성공적으로 반환되면 정지 스레드가 차단됩니다.

그림 1. 정지 스레드 루프

SystemSuspend API

SystemSuspend API는 두 개의 인터페이스로 구성됩니다. HIDL 인터페이스는 네이티브 프로세스에서 wake lock을 획득하는 데 사용되며, 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);
};

wake lock을 요청하는 각 클라이언트는 고유한 IWakeLock 인스턴스를 수신합니다. 이는 여러 클라이언트가 같은 이름으로 wake lock을 사용할 수 있도록 허용하는 /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에 이를 알릴 수 있습니다.
  • 시스템 정지를 담당하는 스레드가 콜백을 수신할 수 있습니다.