N-N通信を比較的かんたんに実現するマルチプラットフォームなメッセージングライブラリにZeroMQちゅうのがあります。詳しくはこちら。ZeroMQの本家Webページ。
この中にzyreというP2P通信のライブラリがあります。特定のピアやグループにメッセージを送ったり受け取ったり、グループへの参加・退出のイベントを受け取ったり出来るライブラリです。本家のJavaバインディングもピュアJava版もAndroid上で実行しようとすると色々よろしくないという話はおいといて、うまく動かないんじゃ仕方がないので自前でnative側のJNI層とJavaバインディングを作って使っています。
zyreがハンドリングするイベントにはENTER, EXIT, JOIN, LEAVE, EVASIVE, WHISPER, SHOUTの7つがあります。このうちEVASIVE以外は普通に使っているとよく飛んでくるイベントですので特に問題はないのですが、問題はEVASIVEです。zyreはユーザーが通信していないときにも定期的に生存確認のためのパケットを送っており、一定時間(デフォルトでは5000ミリ秒=5秒)以内に特定ピアの生存確認が出来なかった場合に、まずEVASIVEイベントが発生します。その後一定時間(デフォルトでは30000ミリ秒=30秒)以内に生存確認ができなければexpiredということでEXITイベントが発生します。
自分の記憶では今まではEVASIVEイベントが飛んで来ることはなかったのですが、ある時を境に何故か頻発するようになったので調べてみました。
で、結論から言うと、Android6.x以降でスリープ状態(画面が消えている状態)だと、たとえフォアグラウンドサービスからの呼び出しであっても、EVASIVEイベントが発生します。ただしEXITイベントにはなりません。つまり相手ピアの生存確認に5秒以上30秒未満かかっていると言うことになります。一方、Android5以下ではスリープ状態にしてもEVASIVEイベントは起こりませんでした。
zyreとは別にlibzmq経由でリアルタイム伝送しているデータについては、スリープ状態かどうかに関わらず大きな遅延はないようですが、時々キューに入ってしまっているデータが多くなっているような気もします。具体的にはスリープ状態の方が、しばらくフレームレートが少し下がったかと思うとそのあとまとめて届くことが多い感じです。ただし通信相手の状態やネットワークの状態の問題もあるのであくまでも、「気がする」レベルです。
Android6(APIレベル23)でDozeが導入されました。Android Developersによると、次のような記述があります。
Android 6.0(API レベル 23)で Doze が導入されました。これは、ユーザーが端末を電源と接続せずに静止状態にし、画面をオフにすると、CPU とネットワークのアクティビティを保留して電池の寿命を改善するものです。Android 7.0 では、Doze が改良されています。端末を電源と接続せずに画面をオフにすると、端末が静止していなくても(たとえば、ユーザーがハンドセットをポケットに入れて持ち歩いている場合)、CPU およびネットワーク制限のサブセットがアプリに適用されます。
zyreの方はもろにこのネットワーク制限のサブセットの影響を受けている感じです。libzmq経由の通信の方には大きな影響がないので今のところはいいのですが、影響が大きくなるようであればアプリスタンバイ最適化の対象から除外するするようにしないといけないかもしれないです。「ホワイトリスト登録が可能なユースケース」には該当するので、ホワイトリストに登録するようにしてもいいんですけどね。暫く様子見です。
ちゃんちゃん。(^.^)/~~~