ローカル エリア ネットワーク(LAN)上のデバイスには、INTERNET 権限を持つアプリからアクセスできます。これにより、アプリはローカル デバイスに簡単に接続できますが、ユーザーのフィンガープリントの作成や位置情報のプロキシなど、プライバシーに関する影響もあります。
ローカル ネットワーク保護プロジェクトは、新しいランタイム権限によってローカル ネットワークへのアクセスを制限することで、ユーザーのプライバシーを保護することを目的としています。
影響
Android 16 では、この権限はオプトイン機能です。つまり、オプトインしたアプリのみが影響を受けます。オプトインの目的は、アプリのどの部分が暗黙的なローカル ネットワーク アクセスに依存しているかをアプリ デベロッパーが把握し、将来の Android リリースでそれらの部分の権限を保護する準備をできるようにすることです。
アプリが次の方法でユーザーのローカル ネットワークにアクセスする場合、アプリは影響を受けます。
- ローカル ネットワーク アドレス(
Multicast DNS (mDNS)やSimple Service Discovery Protocol (SSDP)など)でのロー ソケットの直接使用またはライブラリ使用。 - ローカル ネットワークにアクセスするフレームワーク レベルのクラス(
NsdManagerなど)の使用。
影響の詳細
ローカル ネットワーク アドレスとの間のトラフィックには、ローカル ネットワーク アクセス権限が必要です。次の表に、一般的なケースを示します。
| アプリの低レベル ネットワーク オペレーション | ローカル ネットワークへのアクセス権が必要です |
|---|---|
| アウトバウンド TCP 接続を行う | はい |
| 受信 TCP 接続を受け入れる | はい |
| UDP ユニキャスト、マルチキャスト、ブロードキャストの送信 | はい |
| 受信 UDP ユニキャスト、マルチキャスト、ブロードキャスト | はい |
これらの制限はネットワーク スタックの奥深くに実装されているため、すべてのネットワーク API に適用されます。これには、プラットフォームまたはマネージド コードで作成されたソケット、Cronet や OkHttp などのネットワーキング ライブラリ、それらの上に実装された API が含まれます。.local 接尾辞を持つローカル ネットワーク上のサービスの解決を試みるには、ローカル ネットワークの権限が必要です。
上記のルールの例外:
- デバイスの DNS サーバーがローカル ネットワーク上にある場合、そのサーバーとの間のトラフィック(ポート 53)にはローカル ネットワーク アクセス権限は必要ありません。
- アプリ内ピッカーとして出力スイッチャーを使用するアプリは、ローカル ネットワーク権限を必要としません(詳細なガイダンスは今後のリリースで提供予定です)。
Android 17 の適用
Android 17 以降では、ローカル ネットワーク保護が必須となり、Android 17 以降をターゲットとするアプリに適用されます。
| 側面 | Android 16 | Android 17 |
|---|---|---|
| 対象 SDK | 36 | 37 以降 |
| 権限 | 一時的に NEARBY_WIFI_DEVICES を使用 | ACCESS_LOCAL_NETWORK |
| デフォルトのアクセス | ローカル ネットワークへのアクセスが開いている | ターゲット SDK を更新するすべてのアプリでローカル ネットワークがデフォルトでブロックされる |
| 権限グループ | 既存の NEARBY_DEVICES 権限グループの一部 |
施行後にアプリの機能が損なわれないようにするには、SDK 37 以上をターゲットとするアプリは、ローカル ネットワーク アクセスを管理するために次のいずれかの方法を採用する必要があります。
パス A: プライバシー保護のピッカーを使用する
システムが仲介する検出タスクと接続タスクでは、ピッカーを使用して、広範なランタイム権限のリクエストを完全に回避します。ユースケースに応じて、次のピッカーを使用します。
- メディア ストリーミング: Google Cast をサポートするアプリでは、出力スイッチャー機能を使用できます。これにより、デベロッパーは、アプリが広範な
ACCESS_LOCAL_NETWORK権限をリクエストしなくても、ユーザーが特定のストリーミング デバイスを選択できるようにすることができます。 - 一般的な接続:
NsdManagerには、mDNS 検出用のシステム実行サービス ピッカーが含まれています。アプリがネットワーク全体をスキャンする代わりに、ユーザーがアプリからアクセスする単一のデバイスを選択できるダイアログが表示されます。
val discoveryRequest = DiscoveryRequest.Builder("_http._tcp")
.setFlags(DiscoveryRequest.FLAG_SHOW_PICKER)
.build()
nsdManager.registerServiceInfoCallback(discoveryRequest, executor, object : NsdManager.ServiceInfoCallback {
override fun onServiceUpdated(serviceInfo: NsdServiceInfo) {
// Handle the user-selected and discovered service
// NsdServiceInfo.getHostAddresses() can now be connected to
// without ACCESS_LOCAL_NETWORK permission
}
})
パス B: 実行時の権限(広範なアクセス)をリクエストする
このパスは、ローカル ネットワークへの広範で永続的なアクセスを必要とするスマートホームや IoT デバイス管理などの複雑なユースケースに必要です。
マニフェストで権限を宣言する: デベロッパーは、
AndroidManifest.xmlでACCESS_LOCAL_NETWORKを明示的に宣言する必要があります。実行時に権限をリクエストする: ローカル ネットワークへのアクセスを試みる前に、アプリは権限が付与されているかどうかを確認する必要があります。そうでない場合は、
Activity.requestPermission()を呼び出して標準のシステム プロンプトをトリガーする必要があります。事前付与シナリオ:
ACCESS_LOCAL_NETWORK権限はNEARBY_DEVICES権限グループに含まれます。ユーザーがこのグループの別の権限(Bluetooth 権限など)をすでに付与している場合、ローカル ネットワーク アクセスのプロンプトが再度表示されることはありません。拒否と取り消しの処理: ユーザーがリクエストを拒否した場合や、後でシステム設定で権限を取り消した場合、アプリは適切に処理する必要があります。このようなシナリオでは、ローカル ネットワーク トラフィックがブロックされます。
権限リクエストのリセット カウンタ戦略
プラットフォームは、アプリが NEARBY_DEVICES 権限グループ(現在は ACCESS_LOCAL_NETWORK を含む)を以前に拒否したことで、十分な理由を提示した後に権限をリクエストできなくなるシナリオに対応するカウンタ リセット戦略を実装しています。このメカニズムにより、アプリが requestPermission() API を呼び出す機会が増え、事実上 ACCESS_LOCAL_NETWORK 権限の拒否回数がリセットされます。これにより、特にアプリがコア機能でローカル ネットワーク アクセスが必要であることを伝える前に、ユーザーが最初に拒否した場合に、ユーザーとの再エンゲージメントをより細かく調整できます。
分割権限モデル
ローカル ネットワーク権限は、ターゲット SDK に基づいて新しいアプリと以前のアプリを別々に処理するために、分割権限移行戦略を利用します。
| カテゴリ | ターゲット SDK レベル | ローカル ネットワーク アクセスの動作 | デベロッパーに必要な対応 |
|---|---|---|---|
| 新着アプリ / 更新されたアプリ | >= 37(Android 17) | デフォルトでブロック | ACCESS_LOCAL_NETWORK 実行時の権限を宣言してリクエストする |
| レガシーアプリ | 37 未満 | INTERNET 権限を持つアプリは ACCESS_LOCAL_NETWORK の暗黙的な権限付与を受け、アクセスを維持できます。これは一時的なものであり、アプリのターゲット SDK が 37 になるとデフォルトでブロックされます |
コードをすぐに変更する必要はない |
ユースケース別の LNP 戦略
キャスト: メディア キャスト機能については、出力スイッチャーを使用するのが、最も適切でプライバシーを保護する戦略です。このメソッドを使用すると、システムがユーザーに代わってローカル ネットワークの検出と接続を処理できるため、アプリが
ACCESS_LOCAL_NETWORK権限をリクエストする必要がなくなります。ブラウザ: エラーの処理には、プロトコルに応じたさまざまなアプローチが必要です。UDP エラーが発生すると、
EPERMエラーコードが返されます。TCP 接続の場合、ブラウザは NDK APIandroid_getnetworkblockedreason(int sockFd)を使用して、パケットが LNP によってブロックされたかどうかを判断する必要があります。この API はANDROID_NETWORK_BLOCKED_REASON_LNPを返します。その他のユースケース(IoT など): mDNS を使用してデバイスを検出するアプリは、権限なしでデバイスを検出できる
android.net.nsd.DiscoveryRequest#FLAG_SHOW_PICKERと、IP アドレスを取得するためのNsdManager#registerServiceInfoCallback/NsdManager#resolveServiceを使用する必要があります。この方法で取得した IP アドレスへの接続には、ACCESS_LOCAL_NETWORK権限は必要ありません。
ローカル ネットワークでの直接通信が必要で、システム仲介型のピッカーを使用できないアプリでは、権限リセット カウンタ戦略を使用することをおすすめします。ユーザーによって ACCESS_LOCAL_NETWORK 権限が取り消された場合、このメカニズムにより、アプリが権限を再リクエストする機会が追加で提供され、デベロッパーはユーザーに対してより明確な理由を提示できます。
Android 16 のガイダンス
ローカル ネットワークの制限を有効にする手順は次のとおりです。
- Android 16 ベータ版 3 以降のビルドにデバイスをフラッシュする
- テスト対象のアプリをインストールする
adb を使用して Appcompat 構成を切り替える
adb shell am compat enable RESTRICT_LOCAL_NETWORK <package_name>デバイスを再起動する
これで、アプリのローカル ネットワークへのアクセスが制限され、ローカル ネットワークにアクセスしようとするとソケット エラーが発生します。アプリのプロセス外でローカル ネットワーク オペレーションを実行する API(NsdManager など)を使用している場合、オプトイン中に影響を受けることはありません。
アクセス権を復元するには、アプリに NEARBY_WIFI_DEVICES への権限を付与する必要があります。
- アプリが
manifestでNEARBY_WIFI_DEVICES権限を宣言していることを確認します。 - [設定] > [アプリ] > [[アプリ名]] > [権限] > [付近のデバイス] > [許可] に移動します。
これで、アプリのローカル ネットワークへのアクセスが復元され、アプリを有効にする前と同じようにすべてのシナリオが動作するはずです。アプリのネットワーク トラフィックへの影響は次のとおりです。
| 権限 | アウトバウンド LAN リクエスト | アウトバウンド/インバウンドのインターネット リクエスト | インバウンド LAN リクエスト |
|---|---|---|---|
| 許可 | Works | Works | Works |
| 未許可 | ハプニング集 | Works | ハプニング集 |
次のコマンドを使用して、AppCompat 構成をオフに切り替えます。
adb shell am compat disable RESTRICT_LOCAL_NETWORK <package_name>
エラー
権限がないためローカル ネットワーク アクセス リクエストが失敗した場合:
通常、TCP 接続ではタイムアウト エラーが発生します。
通常、UDP エラーと一般的な権限拒否は EPERM エラーコードになります。
バグ
- LAN アクセスの不一致(特定のアクセスが「ローカル ネットワーク」アクセスと見なされるべきではないと思われる場合)
- LAN アクセスがブロックされるべきなのにブロックされないバグ
- LAN アクセスがブロックされるべきではないのにブロックされるバグ
この変更の影響を受けないものは次のとおりです。
- インターネットへのアクセス
- モバイル ネットワーク