Local network permission

Devices on a Local Area Network (LAN) can be accessed by any app that has the INTERNET permission. This makes it easy for apps to connect to local devices, but also carries privacy implications such as forming a fingerprint of the user and being a proxy for location.

The Local Network Protections project aims to protect the user's privacy by gating access to the local network behind a new runtime permission.

Impact

During Android 16, this permission is an opt-in feature which means only the apps that opt-in will be affected. The goal of the opt-in is for app developers to understand which parts of their app depend on implicit local network access such that they can prepare to permission guard them on a future Android release.

Apps will be affected if they access the user's local network using:

  • Direct or library use of raw sockets on local network addresses, for example, Multicast DNS (mDNS) or Simple Service Discovery Protocol (SSDP).
  • Use of framework-level classes that access the local network, for example, NsdManager.

Details of impact

Traffic to and from a local network address requires local network access permission. The following table lists some common cases:

App Low Level Network Operation Local Network Permission Required
Making an outgoing TCP connection yes
Accepting an incoming TCP connection yes
Sending a UDP unicast, multicast, broadcast yes
Receiving a incoming UDP unicast, multicast, broadcast yes

These restrictions are implemented deep in the networking stack, and thus they apply to all networking APIs. This includes sockets created in the platform or managed code, networking libraries like Cronet and OkHttp, and any APIs implemented on top of those. Trying to resolve services on the local network that have a .local suffix requires local network permission.

Exceptions to the preceding rules:

  • If a device's DNS server is on a local network, traffic to / from it (at port 53) doesn't require local network access permission.
  • Applications using Output Switcher as their in-app picker won't need local network permissions (more guidance to come at a later release).

Android 17 Enforcement

Starting in Android 17, local network protections are mandatory and enforced for apps targeting Android 17 or higher.

Aspect Android 16 Android 17
Target SDK 36 37 or higher
Permission Temporarily used NEARBY_WIFI_DEVICES ACCESS_LOCAL_NETWORK
Default Access Local network access is open Local network is blocked by default for all apps that update their target SDK
Permission Group Part of the existing NEARBY_DEVICES permission group

To verify app functionality isn't broken after the enforcement, applications targeting SDK 37 or higher must adopt one of the following paths to manage local network access:

Path A: Using privacy-preserving pickers

For system-mediated discovery and connection tasks, use pickers to avoid requesting the broad runtime permission entirely. Use the following pickers based on your use case:

  • Media Streaming: For applications that support Google Cast they can use the output switcher feature. This enables developers to allow users to select specific streaming devices without the app needing to request the broad ACCESS_LOCAL_NETWORK permission.
  • General Connectivity: The NsdManager includes a system-run service picker for mDNS discovery. Instead of the app scanning the entire network, the system displays a dialog allowing the user to select a single device for the app to access.
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
    }
})

Path B: Requesting runtime permission (broad access)

This path is required for complex use cases like home automation or IoT device management that need broad, persistent access to the local network.

  • Declare Permission in Manifest: Developers must explicitly declare ACCESS_LOCAL_NETWORK in the AndroidManifest.xml.

  • Request Permission at Runtime: Before attempting any local network access, applications must check if the permission has been granted. If not, they must call Activity.requestPermission() to trigger the standard system prompt.

  • Pre-granted scenario: The ACCESS_LOCAL_NETWORK permission is part of the NEARBY_DEVICES permission group. If a user has already granted another permission in this group (such as Bluetooth permissions), they won't be re-prompted for local network access.

  • Handling Denial and Revocation: Apps must gracefully handle cases where the user denies the request or later revokes permission in system settings. In such scenarios, local network traffic will be blocked.

Permission request reset counter strategy

The platform implements a counter reset strategy that addresses scenarios where an app's prior denial of the NEARBY_DEVICES permission group (which now includes ACCESS_LOCAL_NETWORK) prevented the app from asking for the permission after adequately presenting its rationale. This mechanism grants additional opportunities for the app to invoke the requestPermission() API, effectively resetting the denial count for the ACCESS_LOCAL_NETWORK permission. This allows for a more nuanced re-engagement with the user, especially when the initial denial occurred before the app could convey the necessity of local network access for its core functionality.

Split permission model

Local Network Permission utilizes a split permission migration strategy to handle new and legacy applications differently, based on their target SDK

Category Target SDK level Local network access behavior Required developer action
New Apps / Updated Apps >= 37 (Android 17) Blocked By Default Declare and request ACCESS_LOCAL_NETWORK runtime permission
Legacy Apps < 37 Apps with INTERNET permission receive an implicit permission grant for ACCESS_LOCAL_NETWORK, allowing them to retain access. This is temporary and will be blocked by default once app bumps target SDK to 37 No immediate code change needed

LNP Strategy by Use Case

  • Casting: For media casting functionalities, the most appropriate and privacy-preserving strategy is to use the output switcher. This method allows the system to handle local network discovery and connection on the user's behalf, eliminating the need for the app to request ACCESS_LOCAL_NETWORK permission.

  • Browsers: Handling errors requires different approaches based on the protocol. UDP errors result in EPERM error code. For TCP connections, browsers should use the NDK API android_getnetworkblockedreason(int sockFd) to determine if a packet was blocked by LNP this API returns ANDROID_NETWORK_BLOCKED_REASON_LNP.

  • Other Use Cases (for example, IoT): Applications that find devices using mDNS should use android.net.nsd.DiscoveryRequest#FLAG_SHOW_PICKER which allows finding devices without the permission, and NsdManager#registerServiceInfoCallback / NsdManager#resolveService to obtain IP addresses. Connections to IP addresses obtained this way don't require the ACCESS_LOCAL_NETWORK permission.

For applications that require direct local network communication and cannot use system-mediated pickers, the suggested approach is to use the permission reset counter strategy. If the ACCESS_LOCAL_NETWORK permission is revoked by the user, this mechanism provides additional opportunities for the app to re-request the permission, allowing developers to present a clearer rationale for the user.

Android 16 Guidance

To opt into local network restrictions, do the following:

  1. Flash your device to a build with Android 16 Beta 3 or later
  2. Install the app to be tested
  3. Toggle the Appcompat config by using adb

    adb shell am compat enable RESTRICT_LOCAL_NETWORK <package_name>
    
  4. Reboot the device

Now your app's access to the local network is restricted and any attempt to access the local network leads to socket errors. If you are using APIs that perform local network operations outside of your app process (for example, NsdManager) they aren't affected during the opt-in.

To restore access, you must grant your app permission to NEARBY_WIFI_DEVICES.

  • Make sure the app declares the NEARBY_WIFI_DEVICES permission in its manifest.
  • Go to Settings > Apps > [App Name] > Permissions > Nearby devices > Allow

Now your app's access to the local network should be restored and all your scenarios should work as they did prior to opting the app in. Here is how the app network traffic is impacted.

Permission Outbound LAN Request Outbound/Inbound Internet Request Inbound LAN Request
Granted Works Works Works
Not Granted Fails Works Fails

Use the following command to toggle-off the Appcompat config

adb shell am compat disable RESTRICT_LOCAL_NETWORK <package_name>

Errors

If a local network access request fails due to missing permission:

  • TCP Connections will typically result in a timeout error.

  • UDP errors and general permission denials will typically result in an EPERM error code

Bugs

Submit bugs and feedback for:

  • Discrepancies in LAN access (you don't think a certain access should be considered "local network" access)
  • Bugs where LAN access should be blocked but isn't
  • Bugs where LAN access shouldn't be blocked but is

The following should be unaffected by this change:

  • Access to the Internet
  • Mobile Network