ネットワークに関する問題のトラブルシューティング

アプリが生成するネットワーク トラフィックは、デバイスのバッテリー駆動時間に大きく影響することがあります。トラフィックを最適化するには、トラフィックを測定して、ソースを識別する必要があります。ネットワーク リクエストの直接的な発生源となるのは、ユーザー アクションや、アプリコード、アプリと通信するサーバーです。

このトピックでは、ネットワーク トラフィックをモニタリングして分類する方法と、問題の特定と解決に関するガイダンスについて説明します。

Network Profiler を使用してリクエストをモニタリングする

ネットワーク プロファイラを使用して、アプリのネットワーク リクエストを追跡します。アプリがデータを転送する方法とタイミングを監視して、基盤となるコードを適切に最適化できます。



図 1. ネットワーク トラフィックを追跡する。ネットワーク トラフィック パターンから、リクエストのプリフェッチまたはアップロードのバンドルによって効率を大幅に改善できることが示唆されます。

データ転送の頻度と、各接続で転送されるデータの量をモニタリングすることで、アプリのどの部分を修正すればバッテリー効率を向上できるか判断できるようになります。一般に、遅延を発生させる可能性がある、転送の短期的な急増を探します。

転送が急増する原因を正確に特定するには、Traffic Stats API を使用します。この API の TrafficStats.setThreadStatsTag() を使用すると、特定のスレッド内のソケットから発生するデータ転送にタグを付けることができます。この関数を呼び出しても、特定のスレッドのすべてのトラフィックに自動的にタグが付けられるわけではありません。タグはソケットに適用する必要があります。

スレッドタグを設定したら、TrafficStats.tagSocket()TrafficStats.untagSocket() を使用して、個々のソケットを手動でタグ付けまたはタグ解除できます。タグは、スレッドでソケットが開かれた場合や、サーバー ソケットが接続を受け入れた場合にも適用されます。

複数のスレッドが同じソケットに同時にアクセスする場合、ネットワーク パケットが送受信されたときにソケットに設定されていたタグが使用されます(バッファリングと再送信が原因で、ユーザーがデータを書き込んだときや読み取ったときとは異なる場合があります)。

たとえば、次のコードサンプルに示すように、さまざまなタイプのネットワーク トラフィックを表す定数を定義できます。

Kotlin

const val USER_INITIATED = 0x1000
const val APP_INITIATED = 0x2000
const val SERVER_INITIATED = 0x3000

Java

public static final int USER_INITIATED = 0x1000;
public static final int APP_INITIATED = 0x2000;
public static final int SERVER_INITIATED = 0x3000;

それに応じて、ネットワーク リクエストにタグを付けることができます。

Kotlin

TrafficStats.setThreadStatsTag(USER_INITIATED)
TrafficStats.tagSocket(outputSocket)
// Transfer data using socket
TrafficStats.untagSocket(outputSocket)

Java

TrafficStats.setThreadStatsTag(USER_INITIATED);
TrafficStats.tagSocket(outputSocket);
// Transfer data using socket
TrafficStats.untagSocket(outputSocket);

HttpURLConnection ライブラリは、現在の TrafficStats.getThreadStatsTag() 値に基づいて、自動的にソケットにタグを付けます。また、このライブラリは、次のコードサンプルに示すように、キープアライブ プールを通じてリサイクルする際も、ソケットに対してタグの付け外しを行います。

Kotlin

class IdentifyTransferSpikeTask {
    @WorkerThread
    fun request(url: String) {
        TrafficStats.setThreadStatsTag(APP_INITIATED)
        // Make network request using HttpURLConnection.connect()
        ...
        TrafficStats.clearThreadStatsTag()
    }
}

Java

public class IdentifyTransferSpikeTask {
    @WorkerThread
    public void request(String url) {
        TrafficStats.setThreadStatsTag(APP_INITIATED);
        // Make network request using HttpURLConnection.connect()
        ...
        TrafficStats.clearThreadStatsTag();
    }
}

ネットワーク トラフィックのタイプを分析する

アプリが生成したネットワーク トラフィックについて調査する際は、トラフィックのソースを把握する必要があります。これにより、ネットワーク トラフィックを適切に最適化できます。アプリが頻繁にネットワーク アクティビティを生成している場合でも、それがユーザーのアクションに応答したものであれば完全に適切です。しかし、アプリがフォアグラウンドにいなかった場合や、デバイスがポケットやかばんに入っていた場合は、完全に不適切です。

ユーザー開始型トラフィックを分析する

ユーザー開始型ネットワーク トラフィックは、ユーザーがアプリ内で特定のタスクを実行している間は効率的にグループ化され、ユーザーがアプリで取得する必要がある追加情報をリクエストすると均等に分散されない可能性があります。ユーザー開始型ネットワーク トラフィックを分析する目的は、ネットワークを頻繁に使用するパターンを調べて、リクエストをグループ化することでその頻度を減らすことを目指します。

ユーザー リクエストは予測不可能であるため、アプリでこのタイプのネットワーク使用を最適化することは困難です。また、ユーザーはアプリのアクティブ使用時に迅速なレスポンスを期待するため、効率向上のためのリクエストを遅らせると、ユーザー エクスペリエンスが低下する可能性があります。一般的に、ユーザーがアプリを直接操作しているときは、ネットワーク使用の効率化よりも、迅速なレスポンスを優先することをおすすめします。

ユーザー開始型トラフィックを最適化するための推奨事項については、ユーザー開始型リクエストを最適化するをご覧ください。

アプリ開始型トラフィックを分析する

一般的に、アプリ開始型ネットワーク トラフィックは、ネットワーク帯域幅の効率的な使用に大きく影響します。アプリのネットワーク アクティビティを分析する際は、非アクティブになっている期間を探し出し、それを増やすことができるかどうかを判断します。アプリからのネットワーク アクセスに一貫したパターンが見つかった場合は、このトラフィックをバッチ処理して、アクティビティの合間にデバイスの無線通信を低消費電力モードに戻すようにします。

アプリ開始型トラフィックを最適化するための推奨事項については、アプリ開始型リクエストを最適化するをご覧ください。

サーバー開始型トラフィックを分析する

サーバーがアプリと通信する際に開始するネットワーク アクティビティも、ネットワーク帯域幅の効率的な使用に大きく影響します。Firebase Cloud Messaging(FCM)は、サーバーから特定のアプリ インスタンスにデータを送信するために使用される軽量のメカニズムです。FCM を使用すると、サーバーは特定のデバイスで実行されているアプリに、利用可能な新しいデータがあることを通知できます。

サーバー開始型トラフィックを最適化するための推奨事項については、サーバー開始型リクエストを最適化するをご覧ください。

Battery Historian を使用してネットワーク トラフィックへの影響を可視化する

Battery Historian は、一定期間におけるデバイスのバッテリー消費量を可視化するツールです。このツールを使用すると、ネットワーク アクティビティがバッテリー消費にどのように影響するかを分析できます。たとえば、Battery Historian では、アプリが想定よりも頻繁にセル無線通信を使用しているかどうかを確認できます。Battery Historian の使用方法については、Batterystats と Battery Historian を使用してバッテリー使用量をプロファイリングするをご覧ください。