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)orSimple 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_NETWORKpermission. - General Connectivity: The
NsdManagerincludes 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_NETWORKin theAndroidManifest.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_NETWORKpermission is part of theNEARBY_DEVICESpermission 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_NETWORKpermission.Browsers: Handling errors requires different approaches based on the protocol. UDP errors result in
EPERMerror code. For TCP connections, browsers should use the NDK APIandroid_getnetworkblockedreason(int sockFd)to determine if a packet was blocked by LNP this API returnsANDROID_NETWORK_BLOCKED_REASON_LNP.Other Use Cases (for example, IoT): Applications that find devices using mDNS should use
android.net.nsd.DiscoveryRequest#FLAG_SHOW_PICKERwhich allows finding devices without the permission, andNsdManager#registerServiceInfoCallback/NsdManager#resolveServiceto obtain IP addresses. Connections to IP addresses obtained this way don't require theACCESS_LOCAL_NETWORKpermission.
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:
- Flash your device to a build with Android 16 Beta 3 or later
- Install the app to be tested
Toggle the Appcompat config by using adb
adb shell am compat enable RESTRICT_LOCAL_NETWORK <package_name>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_DEVICESpermission in itsmanifest. - 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