oneway
が付いたメソッドはブロックを実行しません。oneway
が付いていないメソッドの場合、クライアントがメソッドを呼び出すと、サーバーが実行を完了するか、同期コールバックを呼び出すまでブロックが実行されます。サーバーのメソッド実装では、同期コールバックを 1 回だけ呼び出すことができます。エクストラ
破棄され、エラーとして記録されます。メソッドの実行が想定されている場合
コールバックを呼び出さない場合、コールバックとしてログに記録されます。
クライアントにトランスポート エラーとして報告されます。
パススルー モードのスレッド
パススルー モードでは、ほとんどの呼び出しが同期します。ただし、oneway
呼び出しがクライアントをブロックしないよう、プロセスごとにスレッドが作成されます。詳しくは、HIDL の概要をご覧ください。
バインダー化された HAL のスレッド
着信 RPC 呼び出し(HAL から HAL ユーザーへの非同期コールバックを含む)と終了通知に対処できるように、スレッドプールは HIDL を使用する各プロセスに関連付けられています。1 つのプロセスが複数の HIDL インターフェースや終了通知ハンドラを実装している場合、それらすべてでスレッドプールが共有されます。プロセスは、クライアントから着信メソッド呼び出しを受け取ると、スレッドプールから空きスレッドを選択し、そのスレッドで呼び出しを実行します。使用できる空きスレッドがない場合は、いずれかのスレッドが使用可能になるまでブロックを実行します。
サーバーにあるスレッドが 1 つのみの場合は、サーバーへの呼び出しが順番に完了します。複数のスレッドがあるサーバーが順不同で呼び出しを完了する可能性がある
クライアントのスレッドが 1 つしかない場合でも、ただし、特定のインターフェース オブジェクトについては、oneway
呼び出しの順序が保証されます(サーバー スレッドモデルをご覧ください)。マルチスレッド サーバーの場合は、
複数のインターフェースをホストする、異なるインターフェースへの oneway
呼び出し
他のブロッキング呼び出しと同時に処理されます。
複数のネスト呼び出しが、同じ hwbinder スレッドで送信されます。たとえば プロセス(A)が hwbinder スレッドからプロセス(B)に同期呼び出しを行うと、 プロセス(B)がプロセス(A)に同期コールバックを行うと、 (A)の元の hwbinder スレッドで実行され、 あります。この最適化により、単一のスレッド サーバーで ネストされた呼び出しを処理しますが、呼び出しが IPC 呼び出しの別のシーケンスですたとえば、プロセス(B)がプロセス(C)に binder / vndbinder 呼び出しを行った後にプロセス(C)が(A)にコールバックしても、(A)の元のスレッドでは処理できません。
サーバー スレッドモデル
パススルー モード以外では、HIDL インターフェースのサーバー実装はクライアントとは別のプロセスで実行され、着信メソッド呼び出しを待機する 1 つ以上のスレッドを必要とします。これらのスレッドがサーバーのスレッドプールです。サーバーが スレッドプールで実行するスレッド数を決定できます。また、 そのインターフェース上のすべての呼び出しをシリアル化するには、スレッドプールのサイズを 1 に設定します。サーバーのスレッドプールに複数のスレッドがある場合、いずれかのインターフェースで同時着信呼び出しを受信できます(つまり、C++ では共有データを慎重にロックする必要があります)。
同じインターフェースへの oneway 呼び出しはシリアル化されます。マルチスレッド クライアントがインターフェース IFoo
で method1
と method2
、インターフェース IBar
で method3
を呼び出した場合、method1
と method2
は常にシリアル化されますが、method3
は method1
および method2
と並列実行される可能性があります。
1 つのクライアント実行スレッドが、次の 2 つの方法で、スレッドが複数あるサーバーでの同時実行を引き起こす場合があります。
oneway
の呼び出しはブロックを実行しません。oneway
の呼び出しが 実行されてからoneway
以外が呼び出されると、サーバーはoneway
呼び出しとoneway
以外の呼び出し できます。- 同期コールバックを使用してデータを返すサーバー メソッドでは、コールバックがサーバーから呼び出されるとすぐにクライアントのブロックを解除できます。
2 つ目の方法では、サーバー関数のコードの実行後に 呼び出されたコールバックは同時に実行でき、後続の処理は 呼び出すことができます。これには、サーバー関数のコードと、関数の最後に実行される自動デストラクタが含まれます。サーバーのスレッドプールに複数のスレッドがある場合は、1 つのクライアント スレッドからのみ呼び出しを着信しても、同時実行の問題が発生します(プロセスによって提供される HAL に すべての HAL には複数のスレッドが存在します。これは、 プロセスごとに共有されます。)
サーバーが指定のコールバックを呼び出すとすぐに、トランスポートはクライアントで実装されたコールバックを呼び出して、クライアントのブロックを解除できます。クライアントが 呼び出し後にサーバー実装が行う処理と並行して、 呼び出します(デストラクタの実行も含まれる場合があります)。サーバーのスレッドプールに着信呼び出しを処理できる十分なスレッドがあれば、コールバック後のサーバー関数のコードによってクライアントのブロックが解除されますが、クライアントからの以降の呼び出しが同時に実行される可能性があります(サーバーのスレッドプールにスレッドが 1 つしかない場合を除きます)。
同期コールバックに加えて、シングルスレッド クライアントからの oneway
呼び出しは、スレッドプールに複数のスレッドがあるサーバーによって同時に処理されることがあります。ただしこれは、oneway
呼び出しが異なるインターフェースで実行される場合のみです。同じインターフェース上の oneway
呼び出しは常にシリアル化されます。
注: コールバック関数を呼び出した直後にサーバー関数を返すことを強くおすすめします。
C++ の例:
Return<void> someMethod(someMethod_cb _cb) { // Do some processing, then call callback with return data hidl_vec<uint32_t> vec = ... _cb(vec); // At this point, the client's callback is called, // and the client resumes execution. ... return Void(); // is basically a no-op };
クライアント スレッドモデル
クライアントのスレッドモデルは、非ブロッキング呼び出し間で異なる
(oneway
キーワードでマークされた関数)とブロック
呼び出し(oneway
キーワードが指定されていない関数)。
通話をブロックする
ブロッキング呼び出しの場合、クライアントは次のいずれかが発生するまでブロックを実行します。
- トランスポート エラーが発生する(
Return
オブジェクトにReturn::isOk()
で取得できるエラー状態が含まれている)。 - サーバー実装がコールバックを呼び出す(該当する場合)。
- サーバー実装が値を返す(コールバック パラメータがない場合)。
成功した場合にクライアントが引数として渡すコールバック関数は、関数自体が返す前に常にサーバーによって呼び出されます。コールバックは関数呼び出しと同じスレッドで実行されるため、関数呼び出し中のロックの保持に注意する(可能であれば完全に回避する)必要があります。generates
ステートメントまたは oneway
キーワードがない関数は、引き続きブロックを実行します。クライアントはサーバーが Return<void>
オブジェクトを返すまでブロックを実行します。
一方向の呼び出し
関数が oneway
とマークされると、クライアントはすぐに結果を返す
サーバーが関数呼び出しを完了するのを待たずに実行します。実行されるのがコードの半分であるため、表面的にも総体的にも、これは関数呼び出しに要する時間が半分であることを意味します。なお、パフォーマンス重視の実装を記述する場合、これはスケジュール設定に影響します。通常、oneway 呼び出しを使用すると、呼び出し元はスケジュール設定されたままになりますが、通常の同期呼び出しを使用すると、スケジューラが呼び出し元から呼び出し先プロセスに直ちに転送されます。これは、バインダーでのパフォーマンスの最適化です。ターゲット プロセスで一方向の呼び出しを実行する必要があるサービスの場合
受信側のサービスのスケジューリング ポリシーを
変更されました。C++ で libhidltransport
のメソッド setMinSchedulerPolicy
と、sched.h
で定義されたスケジューラの優先度およびポリシーを使用すると、サービスへのすべての呼び出しが、少なくとも設定されたスケジュール ポリシーと優先度で実行されます。