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_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 サービスは、停止カウンタで発行された wake lock の数をトラッキングします。SystemSuspend サービスには 2 つの実行スレッドがあります。
- main スレッドは、バインダ呼び出しに応答します。
- suspend スレッドは、システムの停止を制御します。
main スレッド
main スレッドは、停止カウンタのインクリメントまたはデクリメントを行いながら、クライアントからの新しい wake lock の割り当てリクエストに応答します。
suspend スレッド
suspend スレッドは次の処理をループ内で実行します。
/sys/power/wakeup_count
から値を読み取ります。- ミューテックスを取得します。これにより、main スレッドがインクリメントまたはデクリメントしようとしている間、suspend スレッドが停止カウンタに接続しないようにします。停止カウンタがゼロになって suspend スレッドが実行されようとしているとき、main スレッドによる wake lock の発行 / 削除はブロックされます。
- カウンタがゼロになるまで待ちます。
- ステップ 1 で
/sys/power /wakeup_count
から読み取った値をこのファイルに書き込みます。 書き込みが失敗した場合は、ループの先頭に戻ります。 mem
を/sys/power/state
に書き込むことで、システムの停止を開始します。- ミューテックスを解放します。
wake lock のリクエストが正常に実行されて結果を返すと、suspend スレッドはブロックされます。
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 が通知されます。
- システムの停止を担当するスレッドにコールバックを渡すことができます。