SystemSuspend サービス

Android 9 以下では、libsuspend にシステムの停止を開始するためのスレッドがあります。Android 10 では、同等の機能が SystemSuspend HIDL サービスで導入されています。このサービスはシステム イメージ内にあり、Android プラットフォームによって提供されます。 ロジックは libsuspend とほぼ同じですが、システムの停止をブロックするすべてのユーザー空間プロセスが SystemSuspend と通信する必要がある点が異なります。

libsuspend と libpower

Android 10 では、libsuspend が SystemSuspend サービスで置き換えられました。libpower は再実装され、/sys/power/wake[un]lock ではなく SystemSuspend サービスに依存するようになりました。C API の変更は不要です。

以下の擬似コードは、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 の数をトラッキングします。SystemSuspend サービスには 2 つの実行スレッドがあります。

  • main スレッドは、バインダ呼び出しに応答します。
  • suspend スレッドは、システムの停止を制御します。

main スレッド

main スレッドは、停止カウンタのインクリメントまたはデクリメントを行いながら、クライアントからの新しい wake lock の割り当てリクエストに応答します。

suspend スレッド

suspend スレッドは次の処理をループ内で実行します。

  1. /sys/power/wakeup_count から値を読み取ります。
  2. ミューテックスを取得します。これにより、main スレッドがインクリメントまたはデクリメントしようとしている間、suspend スレッドが停止カウンタに接続しないようにします。停止カウンタがゼロになって suspend スレッドが実行されようとしているとき、main スレッドによる wake lock の発行 / 削除はブロックされます。
  3. カウンタがゼロになるまで待ちます。
  4. ステップ 1 で /sys/power /wakeup_count から読み取った値をこのファイルに書き込みます。 書き込みが失敗した場合は、ループの先頭に戻ります。
  5. mem/sys/power/state に書き込むことで、システムの停止を開始します。
  6. ミューテックスを解放します。

wake lock のリクエストが正常に実行されて結果を返すと、suspend スレッドはブロックされます。

図 1: 停止スレッドのループ

SystemSuspend API

SystemSuspend API は 2 つのインターフェースで構成されます。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 インスタンスを受け取ります。これは /sys/power/wake_lock とは別であるため、複数のクライアントは同じ名前の 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 が通知されます。
  • システムの停止を担当するスレッドにコールバックを渡すことができます。