From a31d72986318194bfdbd7ffefa87b335239cac7e Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Fri, 15 Jan 2021 18:08:24 +0900 Subject: Move module sources to packages/Connectivity Files that are planned to be part of the connectivity module are grouped in packages/Connectivity, so they can be built separately and moved in one operation with their history into packages/modules/Connectivity. This places the files in the existing framework-connectivity-sources filegroup instead of the current framework-core-sources filegroup. Both are used the same way in framework-non-updatable-sources. Bug: 171540887 Test: m Change-Id: I62d9d91574ace6f5c4624035d190260c3126b91e --- core/java/android/net/CaptivePortal.java | 171 - core/java/android/net/CaptivePortalData.aidl | 19 - core/java/android/net/CaptivePortalData.java | 305 -- core/java/android/net/ConnectionInfo.aidl | 20 - core/java/android/net/ConnectionInfo.java | 83 - .../net/ConnectivityDiagnosticsManager.aidl | 21 - .../net/ConnectivityDiagnosticsManager.java | 777 --- core/java/android/net/ConnectivityManager.java | 5058 -------------------- .../java/android/net/ConnectivityMetricsEvent.aidl | 20 - core/java/android/net/ConnectivityThread.java | 56 - core/java/android/net/DhcpInfo.aidl | 19 - core/java/android/net/DhcpInfo.java | 105 - core/java/android/net/DnsResolver.java | 577 --- core/java/android/net/ICaptivePortal.aidl | 27 - .../net/IConnectivityDiagnosticsCallback.aidl | 28 - core/java/android/net/IConnectivityManager.aidl | 246 - .../java/android/net/ISocketKeepaliveCallback.aidl | 34 - core/java/android/net/ITestNetworkManager.aidl | 39 - core/java/android/net/InetAddresses.java | 65 - core/java/android/net/InterfaceConfiguration.aidl | 19 - core/java/android/net/InvalidPacketException.java | 66 - core/java/android/net/IpConfiguration.aidl | 19 - core/java/android/net/IpConfiguration.java | 223 - core/java/android/net/IpPrefix.aidl | 22 - core/java/android/net/IpPrefix.java | 300 -- core/java/android/net/KeepalivePacketData.aidl | 19 - core/java/android/net/KeepalivePacketData.java | 119 - core/java/android/net/LinkAddress.aidl | 21 - core/java/android/net/LinkAddress.java | 549 --- core/java/android/net/LinkProperties.aidl | 20 - core/java/android/net/LinkProperties.java | 1823 ------- core/java/android/net/MacAddress.aidl | 20 - core/java/android/net/MacAddress.java | 400 -- core/java/android/net/NattKeepalivePacketData.java | 144 - core/java/android/net/NattSocketKeepalive.java | 77 - core/java/android/net/Network.aidl | 20 - core/java/android/net/Network.java | 535 --- core/java/android/net/NetworkAgent.java | 1185 ----- core/java/android/net/NetworkAgentConfig.aidl | 19 - core/java/android/net/NetworkAgentConfig.java | 440 -- core/java/android/net/NetworkCapabilities.aidl | 21 - core/java/android/net/NetworkCapabilities.java | 2517 ---------- core/java/android/net/NetworkConfig.java | 80 - core/java/android/net/NetworkInfo.aidl | 19 - core/java/android/net/NetworkInfo.java | 626 --- core/java/android/net/NetworkProvider.java | 162 - core/java/android/net/NetworkRequest.aidl | 20 - core/java/android/net/NetworkRequest.java | 582 --- core/java/android/net/NetworkUtils.java | 425 -- core/java/android/net/PacProxySelector.java | 138 - core/java/android/net/Proxy.java | 294 -- core/java/android/net/ProxyInfo.aidl | 21 - core/java/android/net/ProxyInfo.java | 367 -- core/java/android/net/RouteInfo.aidl | 19 - core/java/android/net/RouteInfo.java | 658 --- core/java/android/net/SocketKeepalive.java | 301 -- core/java/android/net/StaticIpConfiguration.aidl | 20 - core/java/android/net/StaticIpConfiguration.java | 332 -- core/java/android/net/TcpKeepalivePacketData.java | 163 - core/java/android/net/TcpRepairWindow.java | 48 - core/java/android/net/TcpSocketKeepalive.java | 77 - core/java/android/net/TestNetworkInterface.aidl | 20 - core/java/android/net/TestNetworkInterface.java | 78 - core/java/android/net/TestNetworkManager.java | 178 - core/java/android/net/TransportInfo.java | 63 - core/java/android/net/UidRange.aidl | 24 - core/java/android/net/VpnManager.java | 164 - core/java/android/net/VpnService.java | 903 ---- core/java/android/net/apf/ApfCapabilities.aidl | 20 - core/java/android/net/apf/ApfCapabilities.java | 133 - core/java/android/net/util/DnsUtils.java | 379 -- core/java/android/net/util/KeepaliveUtils.java | 115 - .../net/util/MultinetworkPolicyTracker.java | 217 - core/java/android/net/util/SocketUtils.java | 121 - .../framework/src/android/net/CaptivePortal.java | 171 + .../src/android/net/CaptivePortalData.aidl | 19 + .../src/android/net/CaptivePortalData.java | 305 ++ .../framework/src/android/net/ConnectionInfo.aidl | 20 + .../framework/src/android/net/ConnectionInfo.java | 83 + .../net/ConnectivityDiagnosticsManager.aidl | 21 + .../net/ConnectivityDiagnosticsManager.java | 777 +++ .../src/android/net/ConnectivityManager.java | 5058 ++++++++++++++++++++ .../src/android/net/ConnectivityMetricsEvent.aidl | 20 + .../src/android/net/ConnectivityThread.java | 56 + .../framework/src/android/net/DhcpInfo.aidl | 19 + .../framework/src/android/net/DhcpInfo.java | 105 + .../framework/src/android/net/DnsResolver.java | 577 +++ .../framework/src/android/net/ICaptivePortal.aidl | 27 + .../net/IConnectivityDiagnosticsCallback.aidl | 28 + .../src/android/net/IConnectivityManager.aidl | 246 + .../src/android/net/ISocketKeepaliveCallback.aidl | 34 + .../src/android/net/ITestNetworkManager.aidl | 39 + .../framework/src/android/net/InetAddresses.java | 65 + .../src/android/net/InterfaceConfiguration.aidl | 19 + .../src/android/net/InvalidPacketException.java | 66 + .../framework/src/android/net/IpConfiguration.aidl | 19 + .../framework/src/android/net/IpConfiguration.java | 223 + .../framework/src/android/net/IpPrefix.aidl | 22 + .../framework/src/android/net/IpPrefix.java | 300 ++ .../src/android/net/KeepalivePacketData.aidl | 19 + .../src/android/net/KeepalivePacketData.java | 119 + .../framework/src/android/net/LinkAddress.aidl | 21 + .../framework/src/android/net/LinkAddress.java | 549 +++ .../framework/src/android/net/LinkProperties.aidl | 20 + .../framework/src/android/net/LinkProperties.java | 1823 +++++++ .../framework/src/android/net/MacAddress.aidl | 20 + .../framework/src/android/net/MacAddress.java | 400 ++ .../src/android/net/NattKeepalivePacketData.java | 144 + .../src/android/net/NattSocketKeepalive.java | 77 + .../framework/src/android/net/Network.aidl | 20 + .../framework/src/android/net/Network.java | 535 +++ .../framework/src/android/net/NetworkAgent.java | 1185 +++++ .../src/android/net/NetworkAgentConfig.aidl | 19 + .../src/android/net/NetworkAgentConfig.java | 440 ++ .../src/android/net/NetworkCapabilities.aidl | 21 + .../src/android/net/NetworkCapabilities.java | 2517 ++++++++++ .../framework/src/android/net/NetworkConfig.java | 80 + .../framework/src/android/net/NetworkInfo.aidl | 19 + .../framework/src/android/net/NetworkInfo.java | 626 +++ .../framework/src/android/net/NetworkProvider.java | 162 + .../framework/src/android/net/NetworkRequest.aidl | 20 + .../framework/src/android/net/NetworkRequest.java | 582 +++ .../framework/src/android/net/NetworkUtils.java | 425 ++ .../src/android/net/PacProxySelector.java | 138 + .../framework/src/android/net/Proxy.java | 294 ++ .../framework/src/android/net/ProxyInfo.aidl | 21 + .../framework/src/android/net/ProxyInfo.java | 367 ++ .../framework/src/android/net/RouteInfo.aidl | 19 + .../framework/src/android/net/RouteInfo.java | 658 +++ .../framework/src/android/net/SocketKeepalive.java | 301 ++ .../src/android/net/StaticIpConfiguration.aidl | 20 + .../src/android/net/StaticIpConfiguration.java | 332 ++ .../src/android/net/TcpKeepalivePacketData.java | 163 + .../framework/src/android/net/TcpRepairWindow.java | 48 + .../src/android/net/TcpSocketKeepalive.java | 77 + .../src/android/net/TestNetworkInterface.aidl | 20 + .../src/android/net/TestNetworkInterface.java | 78 + .../src/android/net/TestNetworkManager.java | 178 + .../framework/src/android/net/TransportInfo.java | 63 + .../framework/src/android/net/UidRange.aidl | 24 + .../framework/src/android/net/VpnManager.java | 164 + .../framework/src/android/net/VpnService.java | 903 ++++ .../src/android/net/apf/ApfCapabilities.aidl | 20 + .../src/android/net/apf/ApfCapabilities.java | 133 + .../framework/src/android/net/util/DnsUtils.java | 379 ++ .../src/android/net/util/KeepaliveUtils.java | 115 + .../net/util/MultinetworkPolicyTracker.java | 217 + .../src/android/net/util/SocketUtils.java | 121 + 148 files changed, 23015 insertions(+), 23015 deletions(-) delete mode 100644 core/java/android/net/CaptivePortal.java delete mode 100644 core/java/android/net/CaptivePortalData.aidl delete mode 100644 core/java/android/net/CaptivePortalData.java delete mode 100644 core/java/android/net/ConnectionInfo.aidl delete mode 100644 core/java/android/net/ConnectionInfo.java delete mode 100644 core/java/android/net/ConnectivityDiagnosticsManager.aidl delete mode 100644 core/java/android/net/ConnectivityDiagnosticsManager.java delete mode 100644 core/java/android/net/ConnectivityManager.java delete mode 100644 core/java/android/net/ConnectivityMetricsEvent.aidl delete mode 100644 core/java/android/net/ConnectivityThread.java delete mode 100644 core/java/android/net/DhcpInfo.aidl delete mode 100644 core/java/android/net/DhcpInfo.java delete mode 100644 core/java/android/net/DnsResolver.java delete mode 100644 core/java/android/net/ICaptivePortal.aidl delete mode 100644 core/java/android/net/IConnectivityDiagnosticsCallback.aidl delete mode 100644 core/java/android/net/IConnectivityManager.aidl delete mode 100644 core/java/android/net/ISocketKeepaliveCallback.aidl delete mode 100644 core/java/android/net/ITestNetworkManager.aidl delete mode 100644 core/java/android/net/InetAddresses.java delete mode 100644 core/java/android/net/InterfaceConfiguration.aidl delete mode 100644 core/java/android/net/InvalidPacketException.java delete mode 100644 core/java/android/net/IpConfiguration.aidl delete mode 100644 core/java/android/net/IpConfiguration.java delete mode 100644 core/java/android/net/IpPrefix.aidl delete mode 100644 core/java/android/net/IpPrefix.java delete mode 100644 core/java/android/net/KeepalivePacketData.aidl delete mode 100644 core/java/android/net/KeepalivePacketData.java delete mode 100644 core/java/android/net/LinkAddress.aidl delete mode 100644 core/java/android/net/LinkAddress.java delete mode 100644 core/java/android/net/LinkProperties.aidl delete mode 100644 core/java/android/net/LinkProperties.java delete mode 100644 core/java/android/net/MacAddress.aidl delete mode 100644 core/java/android/net/MacAddress.java delete mode 100644 core/java/android/net/NattKeepalivePacketData.java delete mode 100644 core/java/android/net/NattSocketKeepalive.java delete mode 100644 core/java/android/net/Network.aidl delete mode 100644 core/java/android/net/Network.java delete mode 100644 core/java/android/net/NetworkAgent.java delete mode 100644 core/java/android/net/NetworkAgentConfig.aidl delete mode 100644 core/java/android/net/NetworkAgentConfig.java delete mode 100644 core/java/android/net/NetworkCapabilities.aidl delete mode 100644 core/java/android/net/NetworkCapabilities.java delete mode 100644 core/java/android/net/NetworkConfig.java delete mode 100644 core/java/android/net/NetworkInfo.aidl delete mode 100644 core/java/android/net/NetworkInfo.java delete mode 100644 core/java/android/net/NetworkProvider.java delete mode 100644 core/java/android/net/NetworkRequest.aidl delete mode 100644 core/java/android/net/NetworkRequest.java delete mode 100644 core/java/android/net/NetworkUtils.java delete mode 100644 core/java/android/net/PacProxySelector.java delete mode 100644 core/java/android/net/Proxy.java delete mode 100644 core/java/android/net/ProxyInfo.aidl delete mode 100644 core/java/android/net/ProxyInfo.java delete mode 100644 core/java/android/net/RouteInfo.aidl delete mode 100644 core/java/android/net/RouteInfo.java delete mode 100644 core/java/android/net/SocketKeepalive.java delete mode 100644 core/java/android/net/StaticIpConfiguration.aidl delete mode 100644 core/java/android/net/StaticIpConfiguration.java delete mode 100644 core/java/android/net/TcpKeepalivePacketData.java delete mode 100644 core/java/android/net/TcpRepairWindow.java delete mode 100644 core/java/android/net/TcpSocketKeepalive.java delete mode 100644 core/java/android/net/TestNetworkInterface.aidl delete mode 100644 core/java/android/net/TestNetworkInterface.java delete mode 100644 core/java/android/net/TestNetworkManager.java delete mode 100644 core/java/android/net/TransportInfo.java delete mode 100644 core/java/android/net/UidRange.aidl delete mode 100644 core/java/android/net/VpnManager.java delete mode 100644 core/java/android/net/VpnService.java delete mode 100644 core/java/android/net/apf/ApfCapabilities.aidl delete mode 100644 core/java/android/net/apf/ApfCapabilities.java delete mode 100644 core/java/android/net/util/DnsUtils.java delete mode 100644 core/java/android/net/util/KeepaliveUtils.java delete mode 100644 core/java/android/net/util/MultinetworkPolicyTracker.java delete mode 100644 core/java/android/net/util/SocketUtils.java create mode 100644 packages/Connectivity/framework/src/android/net/CaptivePortal.java create mode 100644 packages/Connectivity/framework/src/android/net/CaptivePortalData.aidl create mode 100644 packages/Connectivity/framework/src/android/net/CaptivePortalData.java create mode 100644 packages/Connectivity/framework/src/android/net/ConnectionInfo.aidl create mode 100644 packages/Connectivity/framework/src/android/net/ConnectionInfo.java create mode 100644 packages/Connectivity/framework/src/android/net/ConnectivityDiagnosticsManager.aidl create mode 100644 packages/Connectivity/framework/src/android/net/ConnectivityDiagnosticsManager.java create mode 100644 packages/Connectivity/framework/src/android/net/ConnectivityManager.java create mode 100644 packages/Connectivity/framework/src/android/net/ConnectivityMetricsEvent.aidl create mode 100644 packages/Connectivity/framework/src/android/net/ConnectivityThread.java create mode 100644 packages/Connectivity/framework/src/android/net/DhcpInfo.aidl create mode 100644 packages/Connectivity/framework/src/android/net/DhcpInfo.java create mode 100644 packages/Connectivity/framework/src/android/net/DnsResolver.java create mode 100644 packages/Connectivity/framework/src/android/net/ICaptivePortal.aidl create mode 100644 packages/Connectivity/framework/src/android/net/IConnectivityDiagnosticsCallback.aidl create mode 100644 packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl create mode 100644 packages/Connectivity/framework/src/android/net/ISocketKeepaliveCallback.aidl create mode 100644 packages/Connectivity/framework/src/android/net/ITestNetworkManager.aidl create mode 100644 packages/Connectivity/framework/src/android/net/InetAddresses.java create mode 100644 packages/Connectivity/framework/src/android/net/InterfaceConfiguration.aidl create mode 100644 packages/Connectivity/framework/src/android/net/InvalidPacketException.java create mode 100644 packages/Connectivity/framework/src/android/net/IpConfiguration.aidl create mode 100644 packages/Connectivity/framework/src/android/net/IpConfiguration.java create mode 100644 packages/Connectivity/framework/src/android/net/IpPrefix.aidl create mode 100644 packages/Connectivity/framework/src/android/net/IpPrefix.java create mode 100644 packages/Connectivity/framework/src/android/net/KeepalivePacketData.aidl create mode 100644 packages/Connectivity/framework/src/android/net/KeepalivePacketData.java create mode 100644 packages/Connectivity/framework/src/android/net/LinkAddress.aidl create mode 100644 packages/Connectivity/framework/src/android/net/LinkAddress.java create mode 100644 packages/Connectivity/framework/src/android/net/LinkProperties.aidl create mode 100644 packages/Connectivity/framework/src/android/net/LinkProperties.java create mode 100644 packages/Connectivity/framework/src/android/net/MacAddress.aidl create mode 100644 packages/Connectivity/framework/src/android/net/MacAddress.java create mode 100644 packages/Connectivity/framework/src/android/net/NattKeepalivePacketData.java create mode 100644 packages/Connectivity/framework/src/android/net/NattSocketKeepalive.java create mode 100644 packages/Connectivity/framework/src/android/net/Network.aidl create mode 100644 packages/Connectivity/framework/src/android/net/Network.java create mode 100644 packages/Connectivity/framework/src/android/net/NetworkAgent.java create mode 100644 packages/Connectivity/framework/src/android/net/NetworkAgentConfig.aidl create mode 100644 packages/Connectivity/framework/src/android/net/NetworkAgentConfig.java create mode 100644 packages/Connectivity/framework/src/android/net/NetworkCapabilities.aidl create mode 100644 packages/Connectivity/framework/src/android/net/NetworkCapabilities.java create mode 100644 packages/Connectivity/framework/src/android/net/NetworkConfig.java create mode 100644 packages/Connectivity/framework/src/android/net/NetworkInfo.aidl create mode 100644 packages/Connectivity/framework/src/android/net/NetworkInfo.java create mode 100644 packages/Connectivity/framework/src/android/net/NetworkProvider.java create mode 100644 packages/Connectivity/framework/src/android/net/NetworkRequest.aidl create mode 100644 packages/Connectivity/framework/src/android/net/NetworkRequest.java create mode 100644 packages/Connectivity/framework/src/android/net/NetworkUtils.java create mode 100644 packages/Connectivity/framework/src/android/net/PacProxySelector.java create mode 100644 packages/Connectivity/framework/src/android/net/Proxy.java create mode 100644 packages/Connectivity/framework/src/android/net/ProxyInfo.aidl create mode 100644 packages/Connectivity/framework/src/android/net/ProxyInfo.java create mode 100644 packages/Connectivity/framework/src/android/net/RouteInfo.aidl create mode 100644 packages/Connectivity/framework/src/android/net/RouteInfo.java create mode 100644 packages/Connectivity/framework/src/android/net/SocketKeepalive.java create mode 100644 packages/Connectivity/framework/src/android/net/StaticIpConfiguration.aidl create mode 100644 packages/Connectivity/framework/src/android/net/StaticIpConfiguration.java create mode 100644 packages/Connectivity/framework/src/android/net/TcpKeepalivePacketData.java create mode 100644 packages/Connectivity/framework/src/android/net/TcpRepairWindow.java create mode 100644 packages/Connectivity/framework/src/android/net/TcpSocketKeepalive.java create mode 100644 packages/Connectivity/framework/src/android/net/TestNetworkInterface.aidl create mode 100644 packages/Connectivity/framework/src/android/net/TestNetworkInterface.java create mode 100644 packages/Connectivity/framework/src/android/net/TestNetworkManager.java create mode 100644 packages/Connectivity/framework/src/android/net/TransportInfo.java create mode 100644 packages/Connectivity/framework/src/android/net/UidRange.aidl create mode 100644 packages/Connectivity/framework/src/android/net/VpnManager.java create mode 100644 packages/Connectivity/framework/src/android/net/VpnService.java create mode 100644 packages/Connectivity/framework/src/android/net/apf/ApfCapabilities.aidl create mode 100644 packages/Connectivity/framework/src/android/net/apf/ApfCapabilities.java create mode 100644 packages/Connectivity/framework/src/android/net/util/DnsUtils.java create mode 100644 packages/Connectivity/framework/src/android/net/util/KeepaliveUtils.java create mode 100644 packages/Connectivity/framework/src/android/net/util/MultinetworkPolicyTracker.java create mode 100644 packages/Connectivity/framework/src/android/net/util/SocketUtils.java diff --git a/core/java/android/net/CaptivePortal.java b/core/java/android/net/CaptivePortal.java deleted file mode 100644 index 269bbf20c8b1..000000000000 --- a/core/java/android/net/CaptivePortal.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed urnder the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.net; - -import android.annotation.NonNull; -import android.annotation.RequiresPermission; -import android.annotation.SystemApi; -import android.os.IBinder; -import android.os.Parcel; -import android.os.Parcelable; -import android.os.RemoteException; - -/** - * A class allowing apps handling the {@link ConnectivityManager#ACTION_CAPTIVE_PORTAL_SIGN_IN} - * activity to indicate to the system different outcomes of captive portal sign in. This class is - * passed as an extra named {@link ConnectivityManager#EXTRA_CAPTIVE_PORTAL} with the - * {@code ACTION_CAPTIVE_PORTAL_SIGN_IN} activity. - */ -public class CaptivePortal implements Parcelable { - /** - * Response code from the captive portal application, indicating that the portal was dismissed - * and the network should be re-validated. - * @see ICaptivePortal#appResponse(int) - * @see android.net.INetworkMonitor#notifyCaptivePortalAppFinished(int) - * @hide - */ - @SystemApi - public static final int APP_RETURN_DISMISSED = 0; - /** - * Response code from the captive portal application, indicating that the user did not login and - * does not want to use the captive portal network. - * @see ICaptivePortal#appResponse(int) - * @see android.net.INetworkMonitor#notifyCaptivePortalAppFinished(int) - * @hide - */ - @SystemApi - public static final int APP_RETURN_UNWANTED = 1; - /** - * Response code from the captive portal application, indicating that the user does not wish to - * login but wants to use the captive portal network as-is. - * @see ICaptivePortal#appResponse(int) - * @see android.net.INetworkMonitor#notifyCaptivePortalAppFinished(int) - * @hide - */ - @SystemApi - public static final int APP_RETURN_WANTED_AS_IS = 2; - /** Event offset of request codes from captive portal application. */ - private static final int APP_REQUEST_BASE = 100; - /** - * Request code from the captive portal application, indicating that the network condition may - * have changed and the network should be re-validated. - * @see ICaptivePortal#appRequest(int) - * @see android.net.INetworkMonitor#forceReevaluation(int) - * @hide - */ - @SystemApi - public static final int APP_REQUEST_REEVALUATION_REQUIRED = APP_REQUEST_BASE + 0; - - private final IBinder mBinder; - - /** @hide */ - public CaptivePortal(@NonNull IBinder binder) { - mBinder = binder; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel out, int flags) { - out.writeStrongBinder(mBinder); - } - - public static final @android.annotation.NonNull Parcelable.Creator CREATOR - = new Parcelable.Creator() { - @Override - public CaptivePortal createFromParcel(Parcel in) { - return new CaptivePortal(in.readStrongBinder()); - } - - @Override - public CaptivePortal[] newArray(int size) { - return new CaptivePortal[size]; - } - }; - - /** - * Indicate to the system that the captive portal has been - * dismissed. In response the framework will re-evaluate the network's - * connectivity and might take further action thereafter. - */ - public void reportCaptivePortalDismissed() { - try { - ICaptivePortal.Stub.asInterface(mBinder).appResponse(APP_RETURN_DISMISSED); - } catch (RemoteException e) { - } - } - - /** - * Indicate to the system that the user does not want to pursue signing in to the - * captive portal and the system should continue to prefer other networks - * without captive portals for use as the default active data network. The - * system will not retest the network for a captive portal so as to avoid - * disturbing the user with further sign in to network notifications. - */ - public void ignoreNetwork() { - try { - ICaptivePortal.Stub.asInterface(mBinder).appResponse(APP_RETURN_UNWANTED); - } catch (RemoteException e) { - } - } - - /** - * Indicate to the system the user wants to use this network as is, even though - * the captive portal is still in place. The system will treat the network - * as if it did not have a captive portal when selecting the network to use - * as the default active data network. This may result in this network - * becoming the default active data network, which could disrupt network - * connectivity for apps because the captive portal is still in place. - * @hide - */ - @SystemApi - public void useNetwork() { - try { - ICaptivePortal.Stub.asInterface(mBinder).appResponse(APP_RETURN_WANTED_AS_IS); - } catch (RemoteException e) { - } - } - - /** - * Request that the system reevaluates the captive portal status. - * @hide - */ - @SystemApi - @RequiresPermission(android.Manifest.permission.NETWORK_STACK) - public void reevaluateNetwork() { - try { - ICaptivePortal.Stub.asInterface(mBinder).appRequest(APP_REQUEST_REEVALUATION_REQUIRED); - } catch (RemoteException e) { - } - } - - /** - * Log a captive portal login event. - * @param eventId one of the CAPTIVE_PORTAL_LOGIN_* constants in metrics_constants.proto. - * @param packageName captive portal application package name. - * @hide - */ - @SystemApi - public void logEvent(int eventId, @NonNull String packageName) { - try { - ICaptivePortal.Stub.asInterface(mBinder).logEvent(eventId, packageName); - } catch (RemoteException e) { - } - } -} diff --git a/core/java/android/net/CaptivePortalData.aidl b/core/java/android/net/CaptivePortalData.aidl deleted file mode 100644 index 1d57ee759136..000000000000 --- a/core/java/android/net/CaptivePortalData.aidl +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -@JavaOnlyStableParcelable parcelable CaptivePortalData; diff --git a/core/java/android/net/CaptivePortalData.java b/core/java/android/net/CaptivePortalData.java deleted file mode 100644 index 18467fad8ec4..000000000000 --- a/core/java/android/net/CaptivePortalData.java +++ /dev/null @@ -1,305 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.SystemApi; -import android.os.Parcel; -import android.os.Parcelable; - -import java.util.Objects; - -/** - * Metadata sent by captive portals, see https://www.ietf.org/id/draft-ietf-capport-api-03.txt. - * @hide - */ -@SystemApi -public final class CaptivePortalData implements Parcelable { - private final long mRefreshTimeMillis; - @Nullable - private final Uri mUserPortalUrl; - @Nullable - private final Uri mVenueInfoUrl; - private final boolean mIsSessionExtendable; - private final long mByteLimit; - private final long mExpiryTimeMillis; - private final boolean mCaptive; - private final String mVenueFriendlyName; - - private CaptivePortalData(long refreshTimeMillis, Uri userPortalUrl, Uri venueInfoUrl, - boolean isSessionExtendable, long byteLimit, long expiryTimeMillis, boolean captive, - String venueFriendlyName) { - mRefreshTimeMillis = refreshTimeMillis; - mUserPortalUrl = userPortalUrl; - mVenueInfoUrl = venueInfoUrl; - mIsSessionExtendable = isSessionExtendable; - mByteLimit = byteLimit; - mExpiryTimeMillis = expiryTimeMillis; - mCaptive = captive; - mVenueFriendlyName = venueFriendlyName; - } - - private CaptivePortalData(Parcel p) { - this(p.readLong(), p.readParcelable(null), p.readParcelable(null), p.readBoolean(), - p.readLong(), p.readLong(), p.readBoolean(), p.readString()); - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeLong(mRefreshTimeMillis); - dest.writeParcelable(mUserPortalUrl, 0); - dest.writeParcelable(mVenueInfoUrl, 0); - dest.writeBoolean(mIsSessionExtendable); - dest.writeLong(mByteLimit); - dest.writeLong(mExpiryTimeMillis); - dest.writeBoolean(mCaptive); - dest.writeString(mVenueFriendlyName); - } - - /** - * A builder to create new {@link CaptivePortalData}. - */ - public static class Builder { - private long mRefreshTime; - private Uri mUserPortalUrl; - private Uri mVenueInfoUrl; - private boolean mIsSessionExtendable; - private long mBytesRemaining = -1; - private long mExpiryTime = -1; - private boolean mCaptive; - private String mVenueFriendlyName; - - /** - * Create an empty builder. - */ - public Builder() {} - - /** - * Create a builder copying all data from existing {@link CaptivePortalData}. - */ - public Builder(@Nullable CaptivePortalData data) { - if (data == null) return; - setRefreshTime(data.mRefreshTimeMillis) - .setUserPortalUrl(data.mUserPortalUrl) - .setVenueInfoUrl(data.mVenueInfoUrl) - .setSessionExtendable(data.mIsSessionExtendable) - .setBytesRemaining(data.mByteLimit) - .setExpiryTime(data.mExpiryTimeMillis) - .setCaptive(data.mCaptive) - .setVenueFriendlyName(data.mVenueFriendlyName); - } - - /** - * Set the time at which data was last refreshed, as per {@link System#currentTimeMillis()}. - */ - @NonNull - public Builder setRefreshTime(long refreshTime) { - mRefreshTime = refreshTime; - return this; - } - - /** - * Set the URL to be used for users to login to the portal, if captive. - */ - @NonNull - public Builder setUserPortalUrl(@Nullable Uri userPortalUrl) { - mUserPortalUrl = userPortalUrl; - return this; - } - - /** - * Set the URL that can be used by users to view information about the network venue. - */ - @NonNull - public Builder setVenueInfoUrl(@Nullable Uri venueInfoUrl) { - mVenueInfoUrl = venueInfoUrl; - return this; - } - - /** - * Set whether the portal supports extending a user session on the portal URL page. - */ - @NonNull - public Builder setSessionExtendable(boolean sessionExtendable) { - mIsSessionExtendable = sessionExtendable; - return this; - } - - /** - * Set the number of bytes remaining on the network before the portal closes. - */ - @NonNull - public Builder setBytesRemaining(long bytesRemaining) { - mBytesRemaining = bytesRemaining; - return this; - } - - /** - * Set the time at the session will expire, as per {@link System#currentTimeMillis()}. - */ - @NonNull - public Builder setExpiryTime(long expiryTime) { - mExpiryTime = expiryTime; - return this; - } - - /** - * Set whether the network is captive (portal closed). - */ - @NonNull - public Builder setCaptive(boolean captive) { - mCaptive = captive; - return this; - } - - /** - * Set the venue friendly name. - */ - @NonNull - public Builder setVenueFriendlyName(@Nullable String venueFriendlyName) { - mVenueFriendlyName = venueFriendlyName; - return this; - } - - /** - * Create a new {@link CaptivePortalData}. - */ - @NonNull - public CaptivePortalData build() { - return new CaptivePortalData(mRefreshTime, mUserPortalUrl, mVenueInfoUrl, - mIsSessionExtendable, mBytesRemaining, mExpiryTime, mCaptive, - mVenueFriendlyName); - } - } - - /** - * Get the time at which data was last refreshed, as per {@link System#currentTimeMillis()}. - */ - public long getRefreshTimeMillis() { - return mRefreshTimeMillis; - } - - /** - * Get the URL to be used for users to login to the portal, or extend their session if - * {@link #isSessionExtendable()} is true. - */ - @Nullable - public Uri getUserPortalUrl() { - return mUserPortalUrl; - } - - /** - * Get the URL that can be used by users to view information about the network venue. - */ - @Nullable - public Uri getVenueInfoUrl() { - return mVenueInfoUrl; - } - - /** - * Indicates whether the user portal URL can be used to extend sessions, when the user is logged - * in and the session has a time or byte limit. - */ - public boolean isSessionExtendable() { - return mIsSessionExtendable; - } - - /** - * Get the remaining bytes on the captive portal session, at the time {@link CaptivePortalData} - * was refreshed. This may be different from the limit currently enforced by the portal. - * @return The byte limit, or -1 if not set. - */ - public long getByteLimit() { - return mByteLimit; - } - - /** - * Get the time at the session will expire, as per {@link System#currentTimeMillis()}. - * @return The expiry time, or -1 if unset. - */ - public long getExpiryTimeMillis() { - return mExpiryTimeMillis; - } - - /** - * Get whether the network is captive (portal closed). - */ - public boolean isCaptive() { - return mCaptive; - } - - /** - * Get the venue friendly name - */ - @Nullable - public String getVenueFriendlyName() { - return mVenueFriendlyName; - } - - @NonNull - public static final Creator CREATOR = new Creator() { - @Override - public CaptivePortalData createFromParcel(Parcel source) { - return new CaptivePortalData(source); - } - - @Override - public CaptivePortalData[] newArray(int size) { - return new CaptivePortalData[size]; - } - }; - - @Override - public int hashCode() { - return Objects.hash(mRefreshTimeMillis, mUserPortalUrl, mVenueInfoUrl, - mIsSessionExtendable, mByteLimit, mExpiryTimeMillis, mCaptive, mVenueFriendlyName); - } - - @Override - public boolean equals(Object obj) { - if (!(obj instanceof CaptivePortalData)) return false; - final CaptivePortalData other = (CaptivePortalData) obj; - return mRefreshTimeMillis == other.mRefreshTimeMillis - && Objects.equals(mUserPortalUrl, other.mUserPortalUrl) - && Objects.equals(mVenueInfoUrl, other.mVenueInfoUrl) - && mIsSessionExtendable == other.mIsSessionExtendable - && mByteLimit == other.mByteLimit - && mExpiryTimeMillis == other.mExpiryTimeMillis - && mCaptive == other.mCaptive - && Objects.equals(mVenueFriendlyName, other.mVenueFriendlyName); - } - - @Override - public String toString() { - return "CaptivePortalData {" - + "refreshTime: " + mRefreshTimeMillis - + ", userPortalUrl: " + mUserPortalUrl - + ", venueInfoUrl: " + mVenueInfoUrl - + ", isSessionExtendable: " + mIsSessionExtendable - + ", byteLimit: " + mByteLimit - + ", expiryTime: " + mExpiryTimeMillis - + ", captive: " + mCaptive - + ", venueFriendlyName: " + mVenueFriendlyName - + "}"; - } -} diff --git a/core/java/android/net/ConnectionInfo.aidl b/core/java/android/net/ConnectionInfo.aidl deleted file mode 100644 index 07faf8bbbed8..000000000000 --- a/core/java/android/net/ConnectionInfo.aidl +++ /dev/null @@ -1,20 +0,0 @@ -/* -** -** Copyright (C) 2018 The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -package android.net; - -parcelable ConnectionInfo; diff --git a/core/java/android/net/ConnectionInfo.java b/core/java/android/net/ConnectionInfo.java deleted file mode 100644 index 4514a8484d96..000000000000 --- a/core/java/android/net/ConnectionInfo.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import android.os.Parcel; -import android.os.Parcelable; - -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.UnknownHostException; - -/** - * Describe a network connection including local and remote address/port of a connection and the - * transport protocol. - * - * @hide - */ -public final class ConnectionInfo implements Parcelable { - public final int protocol; - public final InetSocketAddress local; - public final InetSocketAddress remote; - - @Override - public int describeContents() { - return 0; - } - - public ConnectionInfo(int protocol, InetSocketAddress local, InetSocketAddress remote) { - this.protocol = protocol; - this.local = local; - this.remote = remote; - } - - @Override - public void writeToParcel(Parcel out, int flags) { - out.writeInt(protocol); - out.writeByteArray(local.getAddress().getAddress()); - out.writeInt(local.getPort()); - out.writeByteArray(remote.getAddress().getAddress()); - out.writeInt(remote.getPort()); - } - - public static final @android.annotation.NonNull Creator CREATOR = new Creator() { - public ConnectionInfo createFromParcel(Parcel in) { - int protocol = in.readInt(); - InetAddress localAddress; - try { - localAddress = InetAddress.getByAddress(in.createByteArray()); - } catch (UnknownHostException e) { - throw new IllegalArgumentException("Invalid InetAddress"); - } - int localPort = in.readInt(); - InetAddress remoteAddress; - try { - remoteAddress = InetAddress.getByAddress(in.createByteArray()); - } catch (UnknownHostException e) { - throw new IllegalArgumentException("Invalid InetAddress"); - } - int remotePort = in.readInt(); - InetSocketAddress local = new InetSocketAddress(localAddress, localPort); - InetSocketAddress remote = new InetSocketAddress(remoteAddress, remotePort); - return new ConnectionInfo(protocol, local, remote); - } - - public ConnectionInfo[] newArray(int size) { - return new ConnectionInfo[size]; - } - }; -} diff --git a/core/java/android/net/ConnectivityDiagnosticsManager.aidl b/core/java/android/net/ConnectivityDiagnosticsManager.aidl deleted file mode 100644 index 82ba0ca113c5..000000000000 --- a/core/java/android/net/ConnectivityDiagnosticsManager.aidl +++ /dev/null @@ -1,21 +0,0 @@ -/** - * - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -parcelable ConnectivityDiagnosticsManager.ConnectivityReport; -parcelable ConnectivityDiagnosticsManager.DataStallReport; \ No newline at end of file diff --git a/core/java/android/net/ConnectivityDiagnosticsManager.java b/core/java/android/net/ConnectivityDiagnosticsManager.java deleted file mode 100644 index 523449497345..000000000000 --- a/core/java/android/net/ConnectivityDiagnosticsManager.java +++ /dev/null @@ -1,777 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.StringDef; -import android.content.Context; -import android.os.Binder; -import android.os.Parcel; -import android.os.Parcelable; -import android.os.PersistableBundle; -import android.os.RemoteException; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.Preconditions; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.Map; -import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.Executor; - -/** - * Class that provides utilities for collecting network connectivity diagnostics information. - * Connectivity information is made available through triggerable diagnostics tools and by listening - * to System validations. Some diagnostics information may be permissions-restricted. - * - *

ConnectivityDiagnosticsManager is intended for use by applications offering network - * connectivity on a user device. These tools will provide several mechanisms for these applications - * to be alerted to network conditions as well as diagnose potential network issues themselves. - * - *

The primary responsibilities of this class are to: - * - *

    - *
  • Allow permissioned applications to register and unregister callbacks for network event - * notifications - *
  • Invoke callbacks for network event notifications, including: - *
      - *
    • Network validations - *
    • Data stalls - *
    • Connectivity reports from applications - *
    - *
- */ -public class ConnectivityDiagnosticsManager { - /** @hide */ - @VisibleForTesting - public static final Map - sCallbacks = new ConcurrentHashMap<>(); - - private final Context mContext; - private final IConnectivityManager mService; - - /** @hide */ - public ConnectivityDiagnosticsManager(Context context, IConnectivityManager service) { - mContext = Preconditions.checkNotNull(context, "missing context"); - mService = Preconditions.checkNotNull(service, "missing IConnectivityManager"); - } - - /** @hide */ - @VisibleForTesting - public static boolean persistableBundleEquals( - @Nullable PersistableBundle a, @Nullable PersistableBundle b) { - if (a == b) return true; - if (a == null || b == null) return false; - if (!Objects.equals(a.keySet(), b.keySet())) return false; - for (String key : a.keySet()) { - if (!Objects.equals(a.get(key), b.get(key))) return false; - } - return true; - } - - /** Class that includes connectivity information for a specific Network at a specific time. */ - public static final class ConnectivityReport implements Parcelable { - /** - * The overall status of the network is that it is invalid; it neither provides - * connectivity nor has been exempted from validation. - */ - public static final int NETWORK_VALIDATION_RESULT_INVALID = 0; - - /** - * The overall status of the network is that it is valid, this may be because it provides - * full Internet access (all probes succeeded), or because other properties of the network - * caused probes not to be run. - */ - // TODO: link to INetworkMonitor.NETWORK_VALIDATION_RESULT_VALID - public static final int NETWORK_VALIDATION_RESULT_VALID = 1; - - /** - * The overall status of the network is that it provides partial connectivity; some - * probed services succeeded but others failed. - */ - // TODO: link to INetworkMonitor.NETWORK_VALIDATION_RESULT_PARTIAL; - public static final int NETWORK_VALIDATION_RESULT_PARTIALLY_VALID = 2; - - /** - * Due to the properties of the network, validation was not performed. - */ - public static final int NETWORK_VALIDATION_RESULT_SKIPPED = 3; - - /** @hide */ - @IntDef( - prefix = {"NETWORK_VALIDATION_RESULT_"}, - value = { - NETWORK_VALIDATION_RESULT_INVALID, - NETWORK_VALIDATION_RESULT_VALID, - NETWORK_VALIDATION_RESULT_PARTIALLY_VALID, - NETWORK_VALIDATION_RESULT_SKIPPED - }) - @Retention(RetentionPolicy.SOURCE) - public @interface NetworkValidationResult {} - - /** - * The overall validation result for the Network being reported on. - * - *

The possible values for this key are: - * {@link #NETWORK_VALIDATION_RESULT_INVALID}, - * {@link #NETWORK_VALIDATION_RESULT_VALID}, - * {@link #NETWORK_VALIDATION_RESULT_PARTIALLY_VALID}, - * {@link #NETWORK_VALIDATION_RESULT_SKIPPED}. - * - * @see android.net.NetworkCapabilities#NET_CAPABILITY_VALIDATED - */ - @NetworkValidationResult - public static final String KEY_NETWORK_VALIDATION_RESULT = "networkValidationResult"; - - /** DNS probe. */ - // TODO: link to INetworkMonitor.NETWORK_VALIDATION_PROBE_DNS - public static final int NETWORK_PROBE_DNS = 0x04; - - /** HTTP probe. */ - // TODO: link to INetworkMonitor.NETWORK_VALIDATION_PROBE_HTTP - public static final int NETWORK_PROBE_HTTP = 0x08; - - /** HTTPS probe. */ - // TODO: link to INetworkMonitor.NETWORK_VALIDATION_PROBE_HTTPS; - public static final int NETWORK_PROBE_HTTPS = 0x10; - - /** Captive portal fallback probe. */ - // TODO: link to INetworkMonitor.NETWORK_VALIDATION_FALLBACK - public static final int NETWORK_PROBE_FALLBACK = 0x20; - - /** Private DNS (DNS over TLS) probd. */ - // TODO: link to INetworkMonitor.NETWORK_VALIDATION_PROBE_PRIVDNS - public static final int NETWORK_PROBE_PRIVATE_DNS = 0x40; - - /** @hide */ - @IntDef( - prefix = {"NETWORK_PROBE_"}, - value = { - NETWORK_PROBE_DNS, - NETWORK_PROBE_HTTP, - NETWORK_PROBE_HTTPS, - NETWORK_PROBE_FALLBACK, - NETWORK_PROBE_PRIVATE_DNS - }) - @Retention(RetentionPolicy.SOURCE) - public @interface NetworkProbe {} - - /** - * A bitmask of network validation probes that succeeded. - * - *

The possible bits values reported by this key are: - * {@link #NETWORK_PROBE_DNS}, - * {@link #NETWORK_PROBE_HTTP}, - * {@link #NETWORK_PROBE_HTTPS}, - * {@link #NETWORK_PROBE_FALLBACK}, - * {@link #NETWORK_PROBE_PRIVATE_DNS}. - */ - @NetworkProbe - public static final String KEY_NETWORK_PROBES_SUCCEEDED_BITMASK = - "networkProbesSucceeded"; - - /** - * A bitmask of network validation probes that were attempted. - * - *

These probes may have failed or may be incomplete at the time of this report. - * - *

The possible bits values reported by this key are: - * {@link #NETWORK_PROBE_DNS}, - * {@link #NETWORK_PROBE_HTTP}, - * {@link #NETWORK_PROBE_HTTPS}, - * {@link #NETWORK_PROBE_FALLBACK}, - * {@link #NETWORK_PROBE_PRIVATE_DNS}. - */ - @NetworkProbe - public static final String KEY_NETWORK_PROBES_ATTEMPTED_BITMASK = - "networkProbesAttempted"; - - /** @hide */ - @StringDef(prefix = {"KEY_"}, value = { - KEY_NETWORK_VALIDATION_RESULT, KEY_NETWORK_PROBES_SUCCEEDED_BITMASK, - KEY_NETWORK_PROBES_ATTEMPTED_BITMASK}) - @Retention(RetentionPolicy.SOURCE) - public @interface ConnectivityReportBundleKeys {} - - /** The Network for which this ConnectivityReport applied */ - @NonNull private final Network mNetwork; - - /** - * The timestamp for the report. The timestamp is taken from {@link - * System#currentTimeMillis}. - */ - private final long mReportTimestamp; - - /** LinkProperties available on the Network at the reported timestamp */ - @NonNull private final LinkProperties mLinkProperties; - - /** NetworkCapabilities available on the Network at the reported timestamp */ - @NonNull private final NetworkCapabilities mNetworkCapabilities; - - /** PersistableBundle that may contain additional info about the report */ - @NonNull private final PersistableBundle mAdditionalInfo; - - /** - * Constructor for ConnectivityReport. - * - *

Apps should obtain instances through {@link - * ConnectivityDiagnosticsCallback#onConnectivityReportAvailable} instead of instantiating - * their own instances (unless for testing purposes). - * - * @param network The Network for which this ConnectivityReport applies - * @param reportTimestamp The timestamp for the report - * @param linkProperties The LinkProperties available on network at reportTimestamp - * @param networkCapabilities The NetworkCapabilities available on network at - * reportTimestamp - * @param additionalInfo A PersistableBundle that may contain additional info about the - * report - */ - public ConnectivityReport( - @NonNull Network network, - long reportTimestamp, - @NonNull LinkProperties linkProperties, - @NonNull NetworkCapabilities networkCapabilities, - @NonNull PersistableBundle additionalInfo) { - mNetwork = network; - mReportTimestamp = reportTimestamp; - mLinkProperties = new LinkProperties(linkProperties); - mNetworkCapabilities = new NetworkCapabilities(networkCapabilities); - mAdditionalInfo = additionalInfo; - } - - /** - * Returns the Network for this ConnectivityReport. - * - * @return The Network for which this ConnectivityReport applied - */ - @NonNull - public Network getNetwork() { - return mNetwork; - } - - /** - * Returns the epoch timestamp (milliseconds) for when this report was taken. - * - * @return The timestamp for the report. Taken from {@link System#currentTimeMillis}. - */ - public long getReportTimestamp() { - return mReportTimestamp; - } - - /** - * Returns the LinkProperties available when this report was taken. - * - * @return LinkProperties available on the Network at the reported timestamp - */ - @NonNull - public LinkProperties getLinkProperties() { - return new LinkProperties(mLinkProperties); - } - - /** - * Returns the NetworkCapabilities when this report was taken. - * - * @return NetworkCapabilities available on the Network at the reported timestamp - */ - @NonNull - public NetworkCapabilities getNetworkCapabilities() { - return new NetworkCapabilities(mNetworkCapabilities); - } - - /** - * Returns a PersistableBundle with additional info for this report. - * - * @return PersistableBundle that may contain additional info about the report - */ - @NonNull - public PersistableBundle getAdditionalInfo() { - return new PersistableBundle(mAdditionalInfo); - } - - @Override - public boolean equals(@Nullable Object o) { - if (this == o) return true; - if (!(o instanceof ConnectivityReport)) return false; - final ConnectivityReport that = (ConnectivityReport) o; - - // PersistableBundle is optimized to avoid unparcelling data unless fields are - // referenced. Because of this, use {@link ConnectivityDiagnosticsManager#equals} over - // {@link PersistableBundle#kindofEquals}. - return mReportTimestamp == that.mReportTimestamp - && mNetwork.equals(that.mNetwork) - && mLinkProperties.equals(that.mLinkProperties) - && mNetworkCapabilities.equals(that.mNetworkCapabilities) - && persistableBundleEquals(mAdditionalInfo, that.mAdditionalInfo); - } - - @Override - public int hashCode() { - return Objects.hash( - mNetwork, - mReportTimestamp, - mLinkProperties, - mNetworkCapabilities, - mAdditionalInfo); - } - - /** {@inheritDoc} */ - @Override - public int describeContents() { - return 0; - } - - /** {@inheritDoc} */ - @Override - public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeParcelable(mNetwork, flags); - dest.writeLong(mReportTimestamp); - dest.writeParcelable(mLinkProperties, flags); - dest.writeParcelable(mNetworkCapabilities, flags); - dest.writeParcelable(mAdditionalInfo, flags); - } - - /** Implement the Parcelable interface */ - public static final @NonNull Creator CREATOR = - new Creator() { - public ConnectivityReport createFromParcel(Parcel in) { - return new ConnectivityReport( - in.readParcelable(null), - in.readLong(), - in.readParcelable(null), - in.readParcelable(null), - in.readParcelable(null)); - } - - public ConnectivityReport[] newArray(int size) { - return new ConnectivityReport[size]; - } - }; - } - - /** Class that includes information for a suspected data stall on a specific Network */ - public static final class DataStallReport implements Parcelable { - /** - * Indicates that the Data Stall was detected using DNS events. - */ - public static final int DETECTION_METHOD_DNS_EVENTS = 1; - - /** - * Indicates that the Data Stall was detected using TCP metrics. - */ - public static final int DETECTION_METHOD_TCP_METRICS = 2; - - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef( - prefix = {"DETECTION_METHOD_"}, - value = {DETECTION_METHOD_DNS_EVENTS, DETECTION_METHOD_TCP_METRICS}) - public @interface DetectionMethod {} - - /** - * This key represents the period in milliseconds over which other included TCP metrics - * were measured. - * - *

This key will be included if the data stall detection method is - * {@link #DETECTION_METHOD_TCP_METRICS}. - * - *

This value is an int. - */ - public static final String KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS = - "tcpMetricsCollectionPeriodMillis"; - - /** - * This key represents the fail rate of TCP packets when the suspected data stall was - * detected. - * - *

This key will be included if the data stall detection method is - * {@link #DETECTION_METHOD_TCP_METRICS}. - * - *

This value is an int percentage between 0 and 100. - */ - public static final String KEY_TCP_PACKET_FAIL_RATE = "tcpPacketFailRate"; - - /** - * This key represents the consecutive number of DNS timeouts that have occurred. - * - *

The consecutive count will be reset any time a DNS response is received. - * - *

This key will be included if the data stall detection method is - * {@link #DETECTION_METHOD_DNS_EVENTS}. - * - *

This value is an int. - */ - public static final String KEY_DNS_CONSECUTIVE_TIMEOUTS = "dnsConsecutiveTimeouts"; - - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @StringDef(prefix = {"KEY_"}, value = { - KEY_TCP_PACKET_FAIL_RATE, - KEY_DNS_CONSECUTIVE_TIMEOUTS - }) - public @interface DataStallReportBundleKeys {} - - /** The Network for which this DataStallReport applied */ - @NonNull private final Network mNetwork; - - /** - * The timestamp for the report. The timestamp is taken from {@link - * System#currentTimeMillis}. - */ - private long mReportTimestamp; - - /** A bitmask of the detection methods used to identify the suspected data stall */ - @DetectionMethod private final int mDetectionMethod; - - /** LinkProperties available on the Network at the reported timestamp */ - @NonNull private final LinkProperties mLinkProperties; - - /** NetworkCapabilities available on the Network at the reported timestamp */ - @NonNull private final NetworkCapabilities mNetworkCapabilities; - - /** PersistableBundle that may contain additional information on the suspected data stall */ - @NonNull private final PersistableBundle mStallDetails; - - /** - * Constructor for DataStallReport. - * - *

Apps should obtain instances through {@link - * ConnectivityDiagnosticsCallback#onDataStallSuspected} instead of instantiating their own - * instances (unless for testing purposes). - * - * @param network The Network for which this DataStallReport applies - * @param reportTimestamp The timestamp for the report - * @param detectionMethod The detection method used to identify this data stall - * @param linkProperties The LinkProperties available on network at reportTimestamp - * @param networkCapabilities The NetworkCapabilities available on network at - * reportTimestamp - * @param stallDetails A PersistableBundle that may contain additional info about the report - */ - public DataStallReport( - @NonNull Network network, - long reportTimestamp, - @DetectionMethod int detectionMethod, - @NonNull LinkProperties linkProperties, - @NonNull NetworkCapabilities networkCapabilities, - @NonNull PersistableBundle stallDetails) { - mNetwork = network; - mReportTimestamp = reportTimestamp; - mDetectionMethod = detectionMethod; - mLinkProperties = new LinkProperties(linkProperties); - mNetworkCapabilities = new NetworkCapabilities(networkCapabilities); - mStallDetails = stallDetails; - } - - /** - * Returns the Network for this DataStallReport. - * - * @return The Network for which this DataStallReport applied - */ - @NonNull - public Network getNetwork() { - return mNetwork; - } - - /** - * Returns the epoch timestamp (milliseconds) for when this report was taken. - * - * @return The timestamp for the report. Taken from {@link System#currentTimeMillis}. - */ - public long getReportTimestamp() { - return mReportTimestamp; - } - - /** - * Returns the bitmask of detection methods used to identify this suspected data stall. - * - * @return The bitmask of detection methods used to identify the suspected data stall - */ - public int getDetectionMethod() { - return mDetectionMethod; - } - - /** - * Returns the LinkProperties available when this report was taken. - * - * @return LinkProperties available on the Network at the reported timestamp - */ - @NonNull - public LinkProperties getLinkProperties() { - return new LinkProperties(mLinkProperties); - } - - /** - * Returns the NetworkCapabilities when this report was taken. - * - * @return NetworkCapabilities available on the Network at the reported timestamp - */ - @NonNull - public NetworkCapabilities getNetworkCapabilities() { - return new NetworkCapabilities(mNetworkCapabilities); - } - - /** - * Returns a PersistableBundle with additional info for this report. - * - *

Gets a bundle with details about the suspected data stall including information - * specific to the monitoring method that detected the data stall. - * - * @return PersistableBundle that may contain additional information on the suspected data - * stall - */ - @NonNull - public PersistableBundle getStallDetails() { - return new PersistableBundle(mStallDetails); - } - - @Override - public boolean equals(@Nullable Object o) { - if (this == o) return true; - if (!(o instanceof DataStallReport)) return false; - final DataStallReport that = (DataStallReport) o; - - // PersistableBundle is optimized to avoid unparcelling data unless fields are - // referenced. Because of this, use {@link ConnectivityDiagnosticsManager#equals} over - // {@link PersistableBundle#kindofEquals}. - return mReportTimestamp == that.mReportTimestamp - && mDetectionMethod == that.mDetectionMethod - && mNetwork.equals(that.mNetwork) - && mLinkProperties.equals(that.mLinkProperties) - && mNetworkCapabilities.equals(that.mNetworkCapabilities) - && persistableBundleEquals(mStallDetails, that.mStallDetails); - } - - @Override - public int hashCode() { - return Objects.hash( - mNetwork, - mReportTimestamp, - mDetectionMethod, - mLinkProperties, - mNetworkCapabilities, - mStallDetails); - } - - /** {@inheritDoc} */ - @Override - public int describeContents() { - return 0; - } - - /** {@inheritDoc} */ - @Override - public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeParcelable(mNetwork, flags); - dest.writeLong(mReportTimestamp); - dest.writeInt(mDetectionMethod); - dest.writeParcelable(mLinkProperties, flags); - dest.writeParcelable(mNetworkCapabilities, flags); - dest.writeParcelable(mStallDetails, flags); - } - - /** Implement the Parcelable interface */ - public static final @NonNull Creator CREATOR = - new Creator() { - public DataStallReport createFromParcel(Parcel in) { - return new DataStallReport( - in.readParcelable(null), - in.readLong(), - in.readInt(), - in.readParcelable(null), - in.readParcelable(null), - in.readParcelable(null)); - } - - public DataStallReport[] newArray(int size) { - return new DataStallReport[size]; - } - }; - } - - /** @hide */ - @VisibleForTesting - public static class ConnectivityDiagnosticsBinder - extends IConnectivityDiagnosticsCallback.Stub { - @NonNull private final ConnectivityDiagnosticsCallback mCb; - @NonNull private final Executor mExecutor; - - /** @hide */ - @VisibleForTesting - public ConnectivityDiagnosticsBinder( - @NonNull ConnectivityDiagnosticsCallback cb, @NonNull Executor executor) { - this.mCb = cb; - this.mExecutor = executor; - } - - /** @hide */ - @VisibleForTesting - public void onConnectivityReportAvailable(@NonNull ConnectivityReport report) { - final long token = Binder.clearCallingIdentity(); - try { - mExecutor.execute(() -> { - mCb.onConnectivityReportAvailable(report); - }); - } finally { - Binder.restoreCallingIdentity(token); - } - } - - /** @hide */ - @VisibleForTesting - public void onDataStallSuspected(@NonNull DataStallReport report) { - final long token = Binder.clearCallingIdentity(); - try { - mExecutor.execute(() -> { - mCb.onDataStallSuspected(report); - }); - } finally { - Binder.restoreCallingIdentity(token); - } - } - - /** @hide */ - @VisibleForTesting - public void onNetworkConnectivityReported( - @NonNull Network network, boolean hasConnectivity) { - final long token = Binder.clearCallingIdentity(); - try { - mExecutor.execute(() -> { - mCb.onNetworkConnectivityReported(network, hasConnectivity); - }); - } finally { - Binder.restoreCallingIdentity(token); - } - } - } - - /** - * Abstract base class for Connectivity Diagnostics callbacks. Used for notifications about - * network connectivity events. Must be extended by applications wanting notifications. - */ - public abstract static class ConnectivityDiagnosticsCallback { - /** - * Called when the platform completes a data connectivity check. This will also be invoked - * immediately upon registration for each network matching the request with the latest - * report, if a report has already been generated for that network. - * - *

The Network specified in the ConnectivityReport may not be active any more when this - * method is invoked. - * - * @param report The ConnectivityReport containing information about a connectivity check - */ - public void onConnectivityReportAvailable(@NonNull ConnectivityReport report) {} - - /** - * Called when the platform suspects a data stall on some Network. - * - *

The Network specified in the DataStallReport may not be active any more when this - * method is invoked. - * - * @param report The DataStallReport containing information about the suspected data stall - */ - public void onDataStallSuspected(@NonNull DataStallReport report) {} - - /** - * Called when any app reports connectivity to the System. - * - * @param network The Network for which connectivity has been reported - * @param hasConnectivity The connectivity reported to the System - */ - public void onNetworkConnectivityReported( - @NonNull Network network, boolean hasConnectivity) {} - } - - /** - * Registers a ConnectivityDiagnosticsCallback with the System. - * - *

Only apps that offer network connectivity to the user should be registering callbacks. - * These are the only apps whose callbacks will be invoked by the system. Apps considered to - * meet these conditions include: - * - *

    - *
  • Carrier apps with active subscriptions - *
  • Active VPNs - *
  • WiFi Suggesters - *
- * - *

Callbacks registered by apps not meeting the above criteria will not be invoked. - * - *

If a registering app loses its relevant permissions, any callbacks it registered will - * silently stop receiving callbacks. - * - *

Each register() call MUST use a ConnectivityDiagnosticsCallback instance that is - * not currently registered. If a ConnectivityDiagnosticsCallback instance is registered with - * multiple NetworkRequests, an IllegalArgumentException will be thrown. - * - *

To avoid performance issues due to apps leaking callbacks, the system will limit the - * number of outstanding requests to 100 per app (identified by their UID), shared with - * callbacks in {@link ConnectivityManager}. Registering a callback with this method will count - * toward this limit. If this limit is exceeded, an exception will be thrown. To avoid hitting - * this issue and to conserve resources, make sure to unregister the callbacks with - * {@link #unregisterConnectivityDiagnosticsCallback}. - * - * @param request The NetworkRequest that will be used to match with Networks for which - * callbacks will be fired - * @param e The Executor to be used for running the callback method invocations - * @param callback The ConnectivityDiagnosticsCallback that the caller wants registered with the - * System - * @throws IllegalArgumentException if the same callback instance is registered with multiple - * NetworkRequests - * @throws RuntimeException if the app already has too many callbacks registered. - */ - public void registerConnectivityDiagnosticsCallback( - @NonNull NetworkRequest request, - @NonNull Executor e, - @NonNull ConnectivityDiagnosticsCallback callback) { - final ConnectivityDiagnosticsBinder binder = new ConnectivityDiagnosticsBinder(callback, e); - if (sCallbacks.putIfAbsent(callback, binder) != null) { - throw new IllegalArgumentException("Callback is currently registered"); - } - - try { - mService.registerConnectivityDiagnosticsCallback( - binder, request, mContext.getOpPackageName()); - } catch (RemoteException exception) { - exception.rethrowFromSystemServer(); - } - } - - /** - * Unregisters a ConnectivityDiagnosticsCallback with the System. - * - *

If the given callback is not currently registered with the System, this operation will be - * a no-op. - * - * @param callback The ConnectivityDiagnosticsCallback to be unregistered from the System. - */ - public void unregisterConnectivityDiagnosticsCallback( - @NonNull ConnectivityDiagnosticsCallback callback) { - // unconditionally removing from sCallbacks prevents race conditions here, since remove() is - // atomic. - final ConnectivityDiagnosticsBinder binder = sCallbacks.remove(callback); - if (binder == null) return; - - try { - mService.unregisterConnectivityDiagnosticsCallback(binder); - } catch (RemoteException exception) { - exception.rethrowFromSystemServer(); - } - } -} diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java deleted file mode 100644 index 7f07bba668a3..000000000000 --- a/core/java/android/net/ConnectivityManager.java +++ /dev/null @@ -1,5058 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.net; - -import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; -import static android.net.IpSecManager.INVALID_RESOURCE_ID; -import static android.net.NetworkRequest.Type.BACKGROUND_REQUEST; -import static android.net.NetworkRequest.Type.LISTEN; -import static android.net.NetworkRequest.Type.REQUEST; -import static android.net.NetworkRequest.Type.TRACK_DEFAULT; -import static android.net.QosCallback.QosCallbackRegistrationException; - -import android.annotation.CallbackExecutor; -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.RequiresPermission; -import android.annotation.SdkConstant; -import android.annotation.SdkConstant.SdkConstantType; -import android.annotation.SuppressLint; -import android.annotation.SystemApi; -import android.annotation.SystemService; -import android.app.PendingIntent; -import android.compat.annotation.UnsupportedAppUsage; -import android.content.Context; -import android.content.Intent; -import android.net.IpSecManager.UdpEncapsulationSocket; -import android.net.SocketKeepalive.Callback; -import android.net.TetheringManager.StartTetheringCallback; -import android.net.TetheringManager.TetheringEventCallback; -import android.net.TetheringManager.TetheringRequest; -import android.os.Binder; -import android.os.Build; -import android.os.Build.VERSION_CODES; -import android.os.Bundle; -import android.os.Handler; -import android.os.IBinder; -import android.os.INetworkActivityListener; -import android.os.INetworkManagementService; -import android.os.Looper; -import android.os.Message; -import android.os.Messenger; -import android.os.ParcelFileDescriptor; -import android.os.PersistableBundle; -import android.os.Process; -import android.os.RemoteException; -import android.os.ResultReceiver; -import android.os.ServiceManager; -import android.os.ServiceSpecificException; -import android.provider.Settings; -import android.telephony.SubscriptionManager; -import android.telephony.TelephonyManager; -import android.util.ArrayMap; -import android.util.Log; -import android.util.Range; -import android.util.SparseIntArray; - -import com.android.connectivity.aidl.INetworkAgent; -import com.android.internal.annotations.GuardedBy; -import com.android.internal.util.Preconditions; -import com.android.internal.util.Protocol; - -import libcore.net.event.NetworkEventDispatcher; - -import java.io.IOException; -import java.io.UncheckedIOException; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.net.DatagramSocket; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.Socket; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.concurrent.Executor; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.RejectedExecutionException; - -/** - * Class that answers queries about the state of network connectivity. It also - * notifies applications when network connectivity changes. - *

- * The primary responsibilities of this class are to: - *

    - *
  1. Monitor network connections (Wi-Fi, GPRS, UMTS, etc.)
  2. - *
  3. Send broadcast intents when network connectivity changes
  4. - *
  5. Attempt to "fail over" to another network when connectivity to a network - * is lost
  6. - *
  7. Provide an API that allows applications to query the coarse-grained or fine-grained - * state of the available networks
  8. - *
  9. Provide an API that allows applications to request and select networks for their data - * traffic
  10. - *
- */ -@SystemService(Context.CONNECTIVITY_SERVICE) -public class ConnectivityManager { - private static final String TAG = "ConnectivityManager"; - private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); - - /** - * A change in network connectivity has occurred. A default connection has either - * been established or lost. The NetworkInfo for the affected network is - * sent as an extra; it should be consulted to see what kind of - * connectivity event occurred. - *

- * Apps targeting Android 7.0 (API level 24) and higher do not receive this - * broadcast if they declare the broadcast receiver in their manifest. Apps - * will still receive broadcasts if they register their - * {@link android.content.BroadcastReceiver} with - * {@link android.content.Context#registerReceiver Context.registerReceiver()} - * and that context is still valid. - *

- * If this is a connection that was the result of failing over from a - * disconnected network, then the FAILOVER_CONNECTION boolean extra is - * set to true. - *

- * For a loss of connectivity, if the connectivity manager is attempting - * to connect (or has already connected) to another network, the - * NetworkInfo for the new network is also passed as an extra. This lets - * any receivers of the broadcast know that they should not necessarily - * tell the user that no data traffic will be possible. Instead, the - * receiver should expect another broadcast soon, indicating either that - * the failover attempt succeeded (and so there is still overall data - * connectivity), or that the failover attempt failed, meaning that all - * connectivity has been lost. - *

- * For a disconnect event, the boolean extra EXTRA_NO_CONNECTIVITY - * is set to {@code true} if there are no connected networks at all. - * - * @deprecated apps should use the more versatile {@link #requestNetwork}, - * {@link #registerNetworkCallback} or {@link #registerDefaultNetworkCallback} - * functions instead for faster and more detailed updates about the network - * changes they care about. - */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - @Deprecated - public static final String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE"; - - /** - * The device has connected to a network that has presented a captive - * portal, which is blocking Internet connectivity. The user was presented - * with a notification that network sign in is required, - * and the user invoked the notification's action indicating they - * desire to sign in to the network. Apps handling this activity should - * facilitate signing in to the network. This action includes a - * {@link Network} typed extra called {@link #EXTRA_NETWORK} that represents - * the network presenting the captive portal; all communication with the - * captive portal must be done using this {@code Network} object. - *

- * This activity includes a {@link CaptivePortal} extra named - * {@link #EXTRA_CAPTIVE_PORTAL} that can be used to indicate different - * outcomes of the captive portal sign in to the system: - *

    - *
  • When the app handling this action believes the user has signed in to - * the network and the captive portal has been dismissed, the app should - * call {@link CaptivePortal#reportCaptivePortalDismissed} so the system can - * reevaluate the network. If reevaluation finds the network no longer - * subject to a captive portal, the network may become the default active - * data network.
  • - *
  • When the app handling this action believes the user explicitly wants - * to ignore the captive portal and the network, the app should call - * {@link CaptivePortal#ignoreNetwork}.
  • - *
- */ - @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) - public static final String ACTION_CAPTIVE_PORTAL_SIGN_IN = "android.net.conn.CAPTIVE_PORTAL"; - - /** - * The lookup key for a {@link NetworkInfo} object. Retrieve with - * {@link android.content.Intent#getParcelableExtra(String)}. - * - * @deprecated The {@link NetworkInfo} object is deprecated, as many of its properties - * can't accurately represent modern network characteristics. - * Please obtain information about networks from the {@link NetworkCapabilities} - * or {@link LinkProperties} objects instead. - */ - @Deprecated - public static final String EXTRA_NETWORK_INFO = "networkInfo"; - - /** - * Network type which triggered a {@link #CONNECTIVITY_ACTION} broadcast. - * - * @see android.content.Intent#getIntExtra(String, int) - * @deprecated The network type is not rich enough to represent the characteristics - * of modern networks. Please use {@link NetworkCapabilities} instead, - * in particular the transports. - */ - @Deprecated - public static final String EXTRA_NETWORK_TYPE = "networkType"; - - /** - * The lookup key for a boolean that indicates whether a connect event - * is for a network to which the connectivity manager was failing over - * following a disconnect on another network. - * Retrieve it with {@link android.content.Intent#getBooleanExtra(String,boolean)}. - * - * @deprecated See {@link NetworkInfo}. - */ - @Deprecated - public static final String EXTRA_IS_FAILOVER = "isFailover"; - /** - * The lookup key for a {@link NetworkInfo} object. This is supplied when - * there is another network that it may be possible to connect to. Retrieve with - * {@link android.content.Intent#getParcelableExtra(String)}. - * - * @deprecated See {@link NetworkInfo}. - */ - @Deprecated - public static final String EXTRA_OTHER_NETWORK_INFO = "otherNetwork"; - /** - * The lookup key for a boolean that indicates whether there is a - * complete lack of connectivity, i.e., no network is available. - * Retrieve it with {@link android.content.Intent#getBooleanExtra(String,boolean)}. - */ - public static final String EXTRA_NO_CONNECTIVITY = "noConnectivity"; - /** - * The lookup key for a string that indicates why an attempt to connect - * to a network failed. The string has no particular structure. It is - * intended to be used in notifications presented to users. Retrieve - * it with {@link android.content.Intent#getStringExtra(String)}. - */ - public static final String EXTRA_REASON = "reason"; - /** - * The lookup key for a string that provides optionally supplied - * extra information about the network state. The information - * may be passed up from the lower networking layers, and its - * meaning may be specific to a particular network type. Retrieve - * it with {@link android.content.Intent#getStringExtra(String)}. - * - * @deprecated See {@link NetworkInfo#getExtraInfo()}. - */ - @Deprecated - public static final String EXTRA_EXTRA_INFO = "extraInfo"; - /** - * The lookup key for an int that provides information about - * our connection to the internet at large. 0 indicates no connection, - * 100 indicates a great connection. Retrieve it with - * {@link android.content.Intent#getIntExtra(String, int)}. - * {@hide} - */ - public static final String EXTRA_INET_CONDITION = "inetCondition"; - /** - * The lookup key for a {@link CaptivePortal} object included with the - * {@link #ACTION_CAPTIVE_PORTAL_SIGN_IN} intent. The {@code CaptivePortal} - * object can be used to either indicate to the system that the captive - * portal has been dismissed or that the user does not want to pursue - * signing in to captive portal. Retrieve it with - * {@link android.content.Intent#getParcelableExtra(String)}. - */ - public static final String EXTRA_CAPTIVE_PORTAL = "android.net.extra.CAPTIVE_PORTAL"; - - /** - * Key for passing a URL to the captive portal login activity. - */ - public static final String EXTRA_CAPTIVE_PORTAL_URL = "android.net.extra.CAPTIVE_PORTAL_URL"; - - /** - * Key for passing a {@link android.net.captiveportal.CaptivePortalProbeSpec} to the captive - * portal login activity. - * {@hide} - */ - @SystemApi - public static final String EXTRA_CAPTIVE_PORTAL_PROBE_SPEC = - "android.net.extra.CAPTIVE_PORTAL_PROBE_SPEC"; - - /** - * Key for passing a user agent string to the captive portal login activity. - * {@hide} - */ - @SystemApi - public static final String EXTRA_CAPTIVE_PORTAL_USER_AGENT = - "android.net.extra.CAPTIVE_PORTAL_USER_AGENT"; - - /** - * Broadcast action to indicate the change of data activity status - * (idle or active) on a network in a recent period. - * The network becomes active when data transmission is started, or - * idle if there is no data transmission for a period of time. - * {@hide} - */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_DATA_ACTIVITY_CHANGE = - "android.net.conn.DATA_ACTIVITY_CHANGE"; - /** - * The lookup key for an enum that indicates the network device type on which this data activity - * change happens. - * {@hide} - */ - public static final String EXTRA_DEVICE_TYPE = "deviceType"; - /** - * The lookup key for a boolean that indicates the device is active or not. {@code true} means - * it is actively sending or receiving data and {@code false} means it is idle. - * {@hide} - */ - public static final String EXTRA_IS_ACTIVE = "isActive"; - /** - * The lookup key for a long that contains the timestamp (nanos) of the radio state change. - * {@hide} - */ - public static final String EXTRA_REALTIME_NS = "tsNanos"; - - /** - * Broadcast Action: The setting for background data usage has changed - * values. Use {@link #getBackgroundDataSetting()} to get the current value. - *

- * If an application uses the network in the background, it should listen - * for this broadcast and stop using the background data if the value is - * {@code false}. - *

- * - * @deprecated As of {@link VERSION_CODES#ICE_CREAM_SANDWICH}, availability - * of background data depends on several combined factors, and - * this broadcast is no longer sent. Instead, when background - * data is unavailable, {@link #getActiveNetworkInfo()} will now - * appear disconnected. During first boot after a platform - * upgrade, this broadcast will be sent once if - * {@link #getBackgroundDataSetting()} was {@code false} before - * the upgrade. - */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - @Deprecated - public static final String ACTION_BACKGROUND_DATA_SETTING_CHANGED = - "android.net.conn.BACKGROUND_DATA_SETTING_CHANGED"; - - /** - * Broadcast Action: The network connection may not be good - * uses {@code ConnectivityManager.EXTRA_INET_CONDITION} and - * {@code ConnectivityManager.EXTRA_NETWORK_INFO} to specify - * the network and it's condition. - * @hide - */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - @UnsupportedAppUsage - public static final String INET_CONDITION_ACTION = - "android.net.conn.INET_CONDITION_ACTION"; - - /** - * Broadcast Action: A tetherable connection has come or gone. - * Uses {@code ConnectivityManager.EXTRA_AVAILABLE_TETHER}, - * {@code ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY}, - * {@code ConnectivityManager.EXTRA_ACTIVE_TETHER}, and - * {@code ConnectivityManager.EXTRA_ERRORED_TETHER} to indicate - * the current state of tethering. Each include a list of - * interface names in that state (may be empty). - * @hide - */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public static final String ACTION_TETHER_STATE_CHANGED = - TetheringManager.ACTION_TETHER_STATE_CHANGED; - - /** - * @hide - * gives a String[] listing all the interfaces configured for - * tethering and currently available for tethering. - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public static final String EXTRA_AVAILABLE_TETHER = TetheringManager.EXTRA_AVAILABLE_TETHER; - - /** - * @hide - * gives a String[] listing all the interfaces currently in local-only - * mode (ie, has DHCPv4+IPv6-ULA support and no packet forwarding) - */ - public static final String EXTRA_ACTIVE_LOCAL_ONLY = TetheringManager.EXTRA_ACTIVE_LOCAL_ONLY; - - /** - * @hide - * gives a String[] listing all the interfaces currently tethered - * (ie, has DHCPv4 support and packets potentially forwarded/NATed) - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public static final String EXTRA_ACTIVE_TETHER = TetheringManager.EXTRA_ACTIVE_TETHER; - - /** - * @hide - * gives a String[] listing all the interfaces we tried to tether and - * failed. Use {@link #getLastTetherError} to find the error code - * for any interfaces listed here. - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public static final String EXTRA_ERRORED_TETHER = TetheringManager.EXTRA_ERRORED_TETHER; - - /** - * Broadcast Action: The captive portal tracker has finished its test. - * Sent only while running Setup Wizard, in lieu of showing a user - * notification. - * @hide - */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_CAPTIVE_PORTAL_TEST_COMPLETED = - "android.net.conn.CAPTIVE_PORTAL_TEST_COMPLETED"; - /** - * The lookup key for a boolean that indicates whether a captive portal was detected. - * Retrieve it with {@link android.content.Intent#getBooleanExtra(String,boolean)}. - * @hide - */ - public static final String EXTRA_IS_CAPTIVE_PORTAL = "captivePortal"; - - /** - * Action used to display a dialog that asks the user whether to connect to a network that is - * not validated. This intent is used to start the dialog in settings via startActivity. - * - * @hide - */ - public static final String ACTION_PROMPT_UNVALIDATED = "android.net.conn.PROMPT_UNVALIDATED"; - - /** - * Action used to display a dialog that asks the user whether to avoid a network that is no - * longer validated. This intent is used to start the dialog in settings via startActivity. - * - * @hide - */ - public static final String ACTION_PROMPT_LOST_VALIDATION = - "android.net.conn.PROMPT_LOST_VALIDATION"; - - /** - * Action used to display a dialog that asks the user whether to stay connected to a network - * that has not validated. This intent is used to start the dialog in settings via - * startActivity. - * - * @hide - */ - public static final String ACTION_PROMPT_PARTIAL_CONNECTIVITY = - "android.net.conn.PROMPT_PARTIAL_CONNECTIVITY"; - - /** - * Invalid tethering type. - * @see #startTethering(int, boolean, OnStartTetheringCallback) - * @hide - */ - public static final int TETHERING_INVALID = TetheringManager.TETHERING_INVALID; - - /** - * Wifi tethering type. - * @see #startTethering(int, boolean, OnStartTetheringCallback) - * @hide - */ - @SystemApi - public static final int TETHERING_WIFI = TetheringManager.TETHERING_WIFI; - - /** - * USB tethering type. - * @see #startTethering(int, boolean, OnStartTetheringCallback) - * @hide - */ - @SystemApi - public static final int TETHERING_USB = TetheringManager.TETHERING_USB; - - /** - * Bluetooth tethering type. - * @see #startTethering(int, boolean, OnStartTetheringCallback) - * @hide - */ - @SystemApi - public static final int TETHERING_BLUETOOTH = TetheringManager.TETHERING_BLUETOOTH; - - /** - * Wifi P2p tethering type. - * Wifi P2p tethering is set through events automatically, and don't - * need to start from #startTethering(int, boolean, OnStartTetheringCallback). - * @hide - */ - public static final int TETHERING_WIFI_P2P = TetheringManager.TETHERING_WIFI_P2P; - - /** - * Extra used for communicating with the TetherService. Includes the type of tethering to - * enable if any. - * @hide - */ - public static final String EXTRA_ADD_TETHER_TYPE = TetheringConstants.EXTRA_ADD_TETHER_TYPE; - - /** - * Extra used for communicating with the TetherService. Includes the type of tethering for - * which to cancel provisioning. - * @hide - */ - public static final String EXTRA_REM_TETHER_TYPE = TetheringConstants.EXTRA_REM_TETHER_TYPE; - - /** - * Extra used for communicating with the TetherService. True to schedule a recheck of tether - * provisioning. - * @hide - */ - public static final String EXTRA_SET_ALARM = TetheringConstants.EXTRA_SET_ALARM; - - /** - * Tells the TetherService to run a provision check now. - * @hide - */ - public static final String EXTRA_RUN_PROVISION = TetheringConstants.EXTRA_RUN_PROVISION; - - /** - * Extra used for communicating with the TetherService. Contains the {@link ResultReceiver} - * which will receive provisioning results. Can be left empty. - * @hide - */ - public static final String EXTRA_PROVISION_CALLBACK = - TetheringConstants.EXTRA_PROVISION_CALLBACK; - - /** - * The absence of a connection type. - * @hide - */ - @SystemApi - public static final int TYPE_NONE = -1; - - /** - * A Mobile data connection. Devices may support more than one. - * - * @deprecated Applications should instead use {@link NetworkCapabilities#hasTransport} or - * {@link #requestNetwork(NetworkRequest, NetworkCallback)} to request an - * appropriate network. {@see NetworkCapabilities} for supported transports. - */ - @Deprecated - public static final int TYPE_MOBILE = 0; - - /** - * A WIFI data connection. Devices may support more than one. - * - * @deprecated Applications should instead use {@link NetworkCapabilities#hasTransport} or - * {@link #requestNetwork(NetworkRequest, NetworkCallback)} to request an - * appropriate network. {@see NetworkCapabilities} for supported transports. - */ - @Deprecated - public static final int TYPE_WIFI = 1; - - /** - * An MMS-specific Mobile data connection. This network type may use the - * same network interface as {@link #TYPE_MOBILE} or it may use a different - * one. This is used by applications needing to talk to the carrier's - * Multimedia Messaging Service servers. - * - * @deprecated Applications should instead use {@link NetworkCapabilities#hasCapability} or - * {@link #requestNetwork(NetworkRequest, NetworkCallback)} to request a network that - * provides the {@link NetworkCapabilities#NET_CAPABILITY_MMS} capability. - */ - @Deprecated - public static final int TYPE_MOBILE_MMS = 2; - - /** - * A SUPL-specific Mobile data connection. This network type may use the - * same network interface as {@link #TYPE_MOBILE} or it may use a different - * one. This is used by applications needing to talk to the carrier's - * Secure User Plane Location servers for help locating the device. - * - * @deprecated Applications should instead use {@link NetworkCapabilities#hasCapability} or - * {@link #requestNetwork(NetworkRequest, NetworkCallback)} to request a network that - * provides the {@link NetworkCapabilities#NET_CAPABILITY_SUPL} capability. - */ - @Deprecated - public static final int TYPE_MOBILE_SUPL = 3; - - /** - * A DUN-specific Mobile data connection. This network type may use the - * same network interface as {@link #TYPE_MOBILE} or it may use a different - * one. This is sometimes by the system when setting up an upstream connection - * for tethering so that the carrier is aware of DUN traffic. - * - * @deprecated Applications should instead use {@link NetworkCapabilities#hasCapability} or - * {@link #requestNetwork(NetworkRequest, NetworkCallback)} to request a network that - * provides the {@link NetworkCapabilities#NET_CAPABILITY_DUN} capability. - */ - @Deprecated - public static final int TYPE_MOBILE_DUN = 4; - - /** - * A High Priority Mobile data connection. This network type uses the - * same network interface as {@link #TYPE_MOBILE} but the routing setup - * is different. - * - * @deprecated Applications should instead use {@link NetworkCapabilities#hasTransport} or - * {@link #requestNetwork(NetworkRequest, NetworkCallback)} to request an - * appropriate network. {@see NetworkCapabilities} for supported transports. - */ - @Deprecated - public static final int TYPE_MOBILE_HIPRI = 5; - - /** - * A WiMAX data connection. - * - * @deprecated Applications should instead use {@link NetworkCapabilities#hasTransport} or - * {@link #requestNetwork(NetworkRequest, NetworkCallback)} to request an - * appropriate network. {@see NetworkCapabilities} for supported transports. - */ - @Deprecated - public static final int TYPE_WIMAX = 6; - - /** - * A Bluetooth data connection. - * - * @deprecated Applications should instead use {@link NetworkCapabilities#hasTransport} or - * {@link #requestNetwork(NetworkRequest, NetworkCallback)} to request an - * appropriate network. {@see NetworkCapabilities} for supported transports. - */ - @Deprecated - public static final int TYPE_BLUETOOTH = 7; - - /** - * Fake data connection. This should not be used on shipping devices. - * @deprecated This is not used any more. - */ - @Deprecated - public static final int TYPE_DUMMY = 8; - - /** - * An Ethernet data connection. - * - * @deprecated Applications should instead use {@link NetworkCapabilities#hasTransport} or - * {@link #requestNetwork(NetworkRequest, NetworkCallback)} to request an - * appropriate network. {@see NetworkCapabilities} for supported transports. - */ - @Deprecated - public static final int TYPE_ETHERNET = 9; - - /** - * Over the air Administration. - * @deprecated Use {@link NetworkCapabilities} instead. - * {@hide} - */ - @Deprecated - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562) - public static final int TYPE_MOBILE_FOTA = 10; - - /** - * IP Multimedia Subsystem. - * @deprecated Use {@link NetworkCapabilities#NET_CAPABILITY_IMS} instead. - * {@hide} - */ - @Deprecated - @UnsupportedAppUsage - public static final int TYPE_MOBILE_IMS = 11; - - /** - * Carrier Branded Services. - * @deprecated Use {@link NetworkCapabilities#NET_CAPABILITY_CBS} instead. - * {@hide} - */ - @Deprecated - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562) - public static final int TYPE_MOBILE_CBS = 12; - - /** - * A Wi-Fi p2p connection. Only requesting processes will have access to - * the peers connected. - * @deprecated Use {@link NetworkCapabilities#NET_CAPABILITY_WIFI_P2P} instead. - * {@hide} - */ - @Deprecated - @SystemApi - public static final int TYPE_WIFI_P2P = 13; - - /** - * The network to use for initially attaching to the network - * @deprecated Use {@link NetworkCapabilities#NET_CAPABILITY_IA} instead. - * {@hide} - */ - @Deprecated - @UnsupportedAppUsage - public static final int TYPE_MOBILE_IA = 14; - - /** - * Emergency PDN connection for emergency services. This - * may include IMS and MMS in emergency situations. - * @deprecated Use {@link NetworkCapabilities#NET_CAPABILITY_EIMS} instead. - * {@hide} - */ - @Deprecated - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562) - public static final int TYPE_MOBILE_EMERGENCY = 15; - - /** - * The network that uses proxy to achieve connectivity. - * @deprecated Use {@link NetworkCapabilities} instead. - * {@hide} - */ - @Deprecated - @SystemApi - public static final int TYPE_PROXY = 16; - - /** - * A virtual network using one or more native bearers. - * It may or may not be providing security services. - * @deprecated Applications should use {@link NetworkCapabilities#TRANSPORT_VPN} instead. - */ - @Deprecated - public static final int TYPE_VPN = 17; - - /** - * A network that is exclusively meant to be used for testing - * - * @deprecated Use {@link NetworkCapabilities} instead. - * @hide - */ - @Deprecated - public static final int TYPE_TEST = 18; // TODO: Remove this once NetworkTypes are unused. - - /** - * @deprecated Use {@link NetworkCapabilities} instead. - * @hide - */ - @Deprecated - @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = { "TYPE_" }, value = { - TYPE_NONE, - TYPE_MOBILE, - TYPE_WIFI, - TYPE_MOBILE_MMS, - TYPE_MOBILE_SUPL, - TYPE_MOBILE_DUN, - TYPE_MOBILE_HIPRI, - TYPE_WIMAX, - TYPE_BLUETOOTH, - TYPE_DUMMY, - TYPE_ETHERNET, - TYPE_MOBILE_FOTA, - TYPE_MOBILE_IMS, - TYPE_MOBILE_CBS, - TYPE_WIFI_P2P, - TYPE_MOBILE_IA, - TYPE_MOBILE_EMERGENCY, - TYPE_PROXY, - TYPE_VPN, - TYPE_TEST - }) - public @interface LegacyNetworkType {} - - // Deprecated constants for return values of startUsingNetworkFeature. They used to live - // in com.android.internal.telephony.PhoneConstants until they were made inaccessible. - private static final int DEPRECATED_PHONE_CONSTANT_APN_ALREADY_ACTIVE = 0; - private static final int DEPRECATED_PHONE_CONSTANT_APN_REQUEST_STARTED = 1; - private static final int DEPRECATED_PHONE_CONSTANT_APN_REQUEST_FAILED = 3; - - /** {@hide} */ - public static final int MAX_RADIO_TYPE = TYPE_TEST; - - /** {@hide} */ - public static final int MAX_NETWORK_TYPE = TYPE_TEST; - - private static final int MIN_NETWORK_TYPE = TYPE_MOBILE; - - /** - * If you want to set the default network preference,you can directly - * change the networkAttributes array in framework's config.xml. - * - * @deprecated Since we support so many more networks now, the single - * network default network preference can't really express - * the hierarchy. Instead, the default is defined by the - * networkAttributes in config.xml. You can determine - * the current value by calling {@link #getNetworkPreference()} - * from an App. - */ - @Deprecated - public static final int DEFAULT_NETWORK_PREFERENCE = TYPE_WIFI; - - /** - * @hide - */ - public static final int REQUEST_ID_UNSET = 0; - - /** - * Static unique request used as a tombstone for NetworkCallbacks that have been unregistered. - * This allows to distinguish when unregistering NetworkCallbacks those that were never - * registered from those that were already unregistered. - * @hide - */ - private static final NetworkRequest ALREADY_UNREGISTERED = - new NetworkRequest.Builder().clearCapabilities().build(); - - /** - * A NetID indicating no Network is selected. - * Keep in sync with bionic/libc/dns/include/resolv_netid.h - * @hide - */ - public static final int NETID_UNSET = 0; - - /** - * Private DNS Mode values. - * - * The "private_dns_mode" global setting stores a String value which is - * expected to be one of the following. - */ - - /** - * @hide - */ - public static final String PRIVATE_DNS_MODE_OFF = "off"; - /** - * @hide - */ - public static final String PRIVATE_DNS_MODE_OPPORTUNISTIC = "opportunistic"; - /** - * @hide - */ - public static final String PRIVATE_DNS_MODE_PROVIDER_HOSTNAME = "hostname"; - /** - * The default Private DNS mode. - * - * This may change from release to release or may become dependent upon - * the capabilities of the underlying platform. - * - * @hide - */ - public static final String PRIVATE_DNS_DEFAULT_MODE_FALLBACK = PRIVATE_DNS_MODE_OPPORTUNISTIC; - - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562) - private final IConnectivityManager mService; - /** - * A kludge to facilitate static access where a Context pointer isn't available, like in the - * case of the static set/getProcessDefaultNetwork methods and from the Network class. - * TODO: Remove this after deprecating the static methods in favor of non-static methods or - * methods that take a Context argument. - */ - private static ConnectivityManager sInstance; - - private final Context mContext; - - private INetworkManagementService mNMService; - private INetworkPolicyManager mNPManager; - private final TetheringManager mTetheringManager; - - /** - * Tests if a given integer represents a valid network type. - * @param networkType the type to be tested - * @return a boolean. {@code true} if the type is valid, else {@code false} - * @deprecated All APIs accepting a network type are deprecated. There should be no need to - * validate a network type. - */ - @Deprecated - public static boolean isNetworkTypeValid(int networkType) { - return MIN_NETWORK_TYPE <= networkType && networkType <= MAX_NETWORK_TYPE; - } - - /** - * Returns a non-localized string representing a given network type. - * ONLY used for debugging output. - * @param type the type needing naming - * @return a String for the given type, or a string version of the type ("87") - * if no name is known. - * @deprecated Types are deprecated. Use {@link NetworkCapabilities} instead. - * {@hide} - */ - @Deprecated - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public static String getNetworkTypeName(int type) { - switch (type) { - case TYPE_NONE: - return "NONE"; - case TYPE_MOBILE: - return "MOBILE"; - case TYPE_WIFI: - return "WIFI"; - case TYPE_MOBILE_MMS: - return "MOBILE_MMS"; - case TYPE_MOBILE_SUPL: - return "MOBILE_SUPL"; - case TYPE_MOBILE_DUN: - return "MOBILE_DUN"; - case TYPE_MOBILE_HIPRI: - return "MOBILE_HIPRI"; - case TYPE_WIMAX: - return "WIMAX"; - case TYPE_BLUETOOTH: - return "BLUETOOTH"; - case TYPE_DUMMY: - return "DUMMY"; - case TYPE_ETHERNET: - return "ETHERNET"; - case TYPE_MOBILE_FOTA: - return "MOBILE_FOTA"; - case TYPE_MOBILE_IMS: - return "MOBILE_IMS"; - case TYPE_MOBILE_CBS: - return "MOBILE_CBS"; - case TYPE_WIFI_P2P: - return "WIFI_P2P"; - case TYPE_MOBILE_IA: - return "MOBILE_IA"; - case TYPE_MOBILE_EMERGENCY: - return "MOBILE_EMERGENCY"; - case TYPE_PROXY: - return "PROXY"; - case TYPE_VPN: - return "VPN"; - default: - return Integer.toString(type); - } - } - - /** - * @hide - * TODO: Expose for SystemServer when becomes a module. - */ - public void systemReady() { - try { - mService.systemReady(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Checks if a given type uses the cellular data connection. - * This should be replaced in the future by a network property. - * @param networkType the type to check - * @return a boolean - {@code true} if uses cellular network, else {@code false} - * @deprecated Types are deprecated. Use {@link NetworkCapabilities} instead. - * {@hide} - */ - @Deprecated - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562) - public static boolean isNetworkTypeMobile(int networkType) { - switch (networkType) { - case TYPE_MOBILE: - case TYPE_MOBILE_MMS: - case TYPE_MOBILE_SUPL: - case TYPE_MOBILE_DUN: - case TYPE_MOBILE_HIPRI: - case TYPE_MOBILE_FOTA: - case TYPE_MOBILE_IMS: - case TYPE_MOBILE_CBS: - case TYPE_MOBILE_IA: - case TYPE_MOBILE_EMERGENCY: - return true; - default: - return false; - } - } - - /** - * Checks if the given network type is backed by a Wi-Fi radio. - * - * @deprecated Types are deprecated. Use {@link NetworkCapabilities} instead. - * @hide - */ - @Deprecated - public static boolean isNetworkTypeWifi(int networkType) { - switch (networkType) { - case TYPE_WIFI: - case TYPE_WIFI_P2P: - return true; - default: - return false; - } - } - - /** - * Specifies the preferred network type. When the device has more - * than one type available the preferred network type will be used. - * - * @param preference the network type to prefer over all others. It is - * unspecified what happens to the old preferred network in the - * overall ordering. - * @deprecated Functionality has been removed as it no longer makes sense, - * with many more than two networks - we'd need an array to express - * preference. Instead we use dynamic network properties of - * the networks to describe their precedence. - */ - @Deprecated - public void setNetworkPreference(int preference) { - } - - /** - * Retrieves the current preferred network type. - * - * @return an integer representing the preferred network type - * - * @deprecated Functionality has been removed as it no longer makes sense, - * with many more than two networks - we'd need an array to express - * preference. Instead we use dynamic network properties of - * the networks to describe their precedence. - */ - @Deprecated - @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) - public int getNetworkPreference() { - return TYPE_NONE; - } - - /** - * Returns details about the currently active default data network. When - * connected, this network is the default route for outgoing connections. - * You should always check {@link NetworkInfo#isConnected()} before initiating - * network traffic. This may return {@code null} when there is no default - * network. - * Note that if the default network is a VPN, this method will return the - * NetworkInfo for one of its underlying networks instead, or null if the - * VPN agent did not specify any. Apps interested in learning about VPNs - * should use {@link #getNetworkInfo(android.net.Network)} instead. - * - * @return a {@link NetworkInfo} object for the current default network - * or {@code null} if no default network is currently active - * @deprecated See {@link NetworkInfo}. - */ - @Deprecated - @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) - @Nullable - public NetworkInfo getActiveNetworkInfo() { - try { - return mService.getActiveNetworkInfo(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Returns a {@link Network} object corresponding to the currently active - * default data network. In the event that the current active default data - * network disconnects, the returned {@code Network} object will no longer - * be usable. This will return {@code null} when there is no default - * network. - * - * @return a {@link Network} object for the current default network or - * {@code null} if no default network is currently active - */ - @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) - @Nullable - public Network getActiveNetwork() { - try { - return mService.getActiveNetwork(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Returns a {@link Network} object corresponding to the currently active - * default data network for a specific UID. In the event that the default data - * network disconnects, the returned {@code Network} object will no longer - * be usable. This will return {@code null} when there is no default - * network for the UID. - * - * @return a {@link Network} object for the current default network for the - * given UID or {@code null} if no default network is currently active - * - * @hide - */ - @RequiresPermission(android.Manifest.permission.NETWORK_STACK) - @Nullable - public Network getActiveNetworkForUid(int uid) { - return getActiveNetworkForUid(uid, false); - } - - /** {@hide} */ - public Network getActiveNetworkForUid(int uid, boolean ignoreBlocked) { - try { - return mService.getActiveNetworkForUid(uid, ignoreBlocked); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Checks if a VPN app supports always-on mode. - * - * In order to support the always-on feature, an app has to - *

    - *
  • target {@link VERSION_CODES#N API 24} or above, and - *
  • not opt out through the {@link VpnService#SERVICE_META_DATA_SUPPORTS_ALWAYS_ON} - * meta-data field. - *
- * - * @param userId The identifier of the user for whom the VPN app is installed. - * @param vpnPackage The canonical package name of the VPN app. - * @return {@code true} if and only if the VPN app exists and supports always-on mode. - * @hide - */ - public boolean isAlwaysOnVpnPackageSupportedForUser(int userId, @Nullable String vpnPackage) { - try { - return mService.isAlwaysOnVpnPackageSupported(userId, vpnPackage); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Configures an always-on VPN connection through a specific application. - * This connection is automatically granted and persisted after a reboot. - * - *

The designated package should declare a {@link VpnService} in its - * manifest guarded by {@link android.Manifest.permission.BIND_VPN_SERVICE}, - * otherwise the call will fail. - * - * @param userId The identifier of the user to set an always-on VPN for. - * @param vpnPackage The package name for an installed VPN app on the device, or {@code null} - * to remove an existing always-on VPN configuration. - * @param lockdownEnabled {@code true} to disallow networking when the VPN is not connected or - * {@code false} otherwise. - * @param lockdownAllowlist The list of packages that are allowed to access network directly - * when VPN is in lockdown mode but is not running. Non-existent packages are ignored so - * this method must be called when a package that should be allowed is installed or - * uninstalled. - * @return {@code true} if the package is set as always-on VPN controller; - * {@code false} otherwise. - * @hide - */ - @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN) - public boolean setAlwaysOnVpnPackageForUser(int userId, @Nullable String vpnPackage, - boolean lockdownEnabled, @Nullable List lockdownAllowlist) { - try { - return mService.setAlwaysOnVpnPackage( - userId, vpnPackage, lockdownEnabled, lockdownAllowlist); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Returns the package name of the currently set always-on VPN application. - * If there is no always-on VPN set, or the VPN is provided by the system instead - * of by an app, {@code null} will be returned. - * - * @return Package name of VPN controller responsible for always-on VPN, - * or {@code null} if none is set. - * @hide - */ - @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN) - public String getAlwaysOnVpnPackageForUser(int userId) { - try { - return mService.getAlwaysOnVpnPackage(userId); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * @return whether always-on VPN is in lockdown mode. - * - * @hide - **/ - @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN) - public boolean isVpnLockdownEnabled(int userId) { - try { - return mService.isVpnLockdownEnabled(userId); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - - } - - /** - * @return the list of packages that are allowed to access network when always-on VPN is in - * lockdown mode but not connected. Returns {@code null} when VPN lockdown is not active. - * - * @hide - **/ - @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN) - public List getVpnLockdownWhitelist(int userId) { - try { - return mService.getVpnLockdownWhitelist(userId); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Adds or removes a requirement for given UID ranges to use the VPN. - * - * If set to {@code true}, informs the system that the UIDs in the specified ranges must not - * have any connectivity except if a VPN is connected and applies to the UIDs, or if the UIDs - * otherwise have permission to bypass the VPN (e.g., because they have the - * {@link android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS} permission, or when - * using a socket protected by a method such as {@link VpnService#protect(DatagramSocket)}. If - * set to {@code false}, a previously-added restriction is removed. - *

- * Each of the UID ranges specified by this method is added and removed as is, and no processing - * is performed on the ranges to de-duplicate, merge, split, or intersect them. In order to - * remove a previously-added range, the exact range must be removed as is. - *

- * The changes are applied asynchronously and may not have been applied by the time the method - * returns. Apps will be notified about any changes that apply to them via - * {@link NetworkCallback#onBlockedStatusChanged} callbacks called after the changes take - * effect. - *

- * This method should be called only by the VPN code. - * - * @param ranges the UID ranges to restrict - * @param requireVpn whether the specified UID ranges must use a VPN - * - * TODO: expose as @SystemApi. - * @hide - */ - @RequiresPermission(anyOf = { - NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, - android.Manifest.permission.NETWORK_STACK}) - public void setRequireVpnForUids(boolean requireVpn, - @NonNull Collection> ranges) { - Objects.requireNonNull(ranges); - // The Range class is not parcelable. Convert to UidRange, which is what is used internally. - // This method is not necessarily expected to be used outside the system server, so - // parceling may not be necessary, but it could be used out-of-process, e.g., by the network - // stack process, or by tests. - UidRange[] rangesArray = new UidRange[ranges.size()]; - int index = 0; - for (Range range : ranges) { - rangesArray[index++] = new UidRange(range.getLower(), range.getUpper()); - } - try { - mService.setRequireVpnForUids(requireVpn, rangesArray); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Returns details about the currently active default data network - * for a given uid. This is for internal use only to avoid spying - * other apps. - * - * @return a {@link NetworkInfo} object for the current default network - * for the given uid or {@code null} if no default network is - * available for the specified uid. - * - * {@hide} - */ - @RequiresPermission(android.Manifest.permission.NETWORK_STACK) - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public NetworkInfo getActiveNetworkInfoForUid(int uid) { - return getActiveNetworkInfoForUid(uid, false); - } - - /** {@hide} */ - public NetworkInfo getActiveNetworkInfoForUid(int uid, boolean ignoreBlocked) { - try { - return mService.getActiveNetworkInfoForUid(uid, ignoreBlocked); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Returns connection status information about a particular - * network type. - * - * @param networkType integer specifying which networkType in - * which you're interested. - * @return a {@link NetworkInfo} object for the requested - * network type or {@code null} if the type is not - * supported by the device. If {@code networkType} is - * TYPE_VPN and a VPN is active for the calling app, - * then this method will try to return one of the - * underlying networks for the VPN or null if the - * VPN agent didn't specify any. - * - * @deprecated This method does not support multiple connected networks - * of the same type. Use {@link #getAllNetworks} and - * {@link #getNetworkInfo(android.net.Network)} instead. - */ - @Deprecated - @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) - @Nullable - public NetworkInfo getNetworkInfo(int networkType) { - try { - return mService.getNetworkInfo(networkType); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Returns connection status information about a particular - * Network. - * - * @param network {@link Network} specifying which network - * in which you're interested. - * @return a {@link NetworkInfo} object for the requested - * network or {@code null} if the {@code Network} - * is not valid. - * @deprecated See {@link NetworkInfo}. - */ - @Deprecated - @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) - @Nullable - public NetworkInfo getNetworkInfo(@Nullable Network network) { - return getNetworkInfoForUid(network, Process.myUid(), false); - } - - /** {@hide} */ - public NetworkInfo getNetworkInfoForUid(Network network, int uid, boolean ignoreBlocked) { - try { - return mService.getNetworkInfoForUid(network, uid, ignoreBlocked); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Returns connection status information about all network - * types supported by the device. - * - * @return an array of {@link NetworkInfo} objects. Check each - * {@link NetworkInfo#getType} for which type each applies. - * - * @deprecated This method does not support multiple connected networks - * of the same type. Use {@link #getAllNetworks} and - * {@link #getNetworkInfo(android.net.Network)} instead. - */ - @Deprecated - @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) - @NonNull - public NetworkInfo[] getAllNetworkInfo() { - try { - return mService.getAllNetworkInfo(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Returns the {@link Network} object currently serving a given type, or - * null if the given type is not connected. - * - * @hide - * @deprecated This method does not support multiple connected networks - * of the same type. Use {@link #getAllNetworks} and - * {@link #getNetworkInfo(android.net.Network)} instead. - */ - @Deprecated - @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) - @UnsupportedAppUsage - public Network getNetworkForType(int networkType) { - try { - return mService.getNetworkForType(networkType); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Returns an array of all {@link Network} currently tracked by the - * framework. - * - * @return an array of {@link Network} objects. - */ - @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) - @NonNull - public Network[] getAllNetworks() { - try { - return mService.getAllNetworks(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Returns an array of {@link android.net.NetworkCapabilities} objects, representing - * the Networks that applications run by the given user will use by default. - * @hide - */ - @UnsupportedAppUsage - public NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser(int userId) { - try { - return mService.getDefaultNetworkCapabilitiesForUser( - userId, mContext.getOpPackageName()); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Returns the IP information for the current default network. - * - * @return a {@link LinkProperties} object describing the IP info - * for the current default network, or {@code null} if there - * is no current default network. - * - * {@hide} - * @deprecated please use {@link #getLinkProperties(Network)} on the return - * value of {@link #getActiveNetwork()} instead. In particular, - * this method will return non-null LinkProperties even if the - * app is blocked by policy from using this network. - */ - @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 109783091) - public LinkProperties getActiveLinkProperties() { - try { - return mService.getActiveLinkProperties(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Returns the IP information for a given network type. - * - * @param networkType the network type of interest. - * @return a {@link LinkProperties} object describing the IP info - * for the given networkType, or {@code null} if there is - * no current default network. - * - * {@hide} - * @deprecated This method does not support multiple connected networks - * of the same type. Use {@link #getAllNetworks}, - * {@link #getNetworkInfo(android.net.Network)}, and - * {@link #getLinkProperties(android.net.Network)} instead. - */ - @Deprecated - @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562) - public LinkProperties getLinkProperties(int networkType) { - try { - return mService.getLinkPropertiesForType(networkType); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Get the {@link LinkProperties} for the given {@link Network}. This - * will return {@code null} if the network is unknown. - * - * @param network The {@link Network} object identifying the network in question. - * @return The {@link LinkProperties} for the network, or {@code null}. - */ - @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) - @Nullable - public LinkProperties getLinkProperties(@Nullable Network network) { - try { - return mService.getLinkProperties(network); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Get the {@link android.net.NetworkCapabilities} for the given {@link Network}. This - * will return {@code null} if the network is unknown. - * - * @param network The {@link Network} object identifying the network in question. - * @return The {@link android.net.NetworkCapabilities} for the network, or {@code null}. - */ - @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) - @Nullable - public NetworkCapabilities getNetworkCapabilities(@Nullable Network network) { - try { - return mService.getNetworkCapabilities(network, mContext.getOpPackageName()); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Gets a URL that can be used for resolving whether a captive portal is present. - * 1. This URL should respond with a 204 response to a GET request to indicate no captive - * portal is present. - * 2. This URL must be HTTP as redirect responses are used to find captive portal - * sign-in pages. Captive portals cannot respond to HTTPS requests with redirects. - * - * The system network validation may be using different strategies to detect captive portals, - * so this method does not necessarily return a URL used by the system. It only returns a URL - * that may be relevant for other components trying to detect captive portals. - * - * @hide - * @deprecated This API returns URL which is not guaranteed to be one of the URLs used by the - * system. - */ - @Deprecated - @SystemApi - @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) - public String getCaptivePortalServerUrl() { - try { - return mService.getCaptivePortalServerUrl(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Tells the underlying networking system that the caller wants to - * begin using the named feature. The interpretation of {@code feature} - * is completely up to each networking implementation. - * - *

This method requires the caller to hold either the - * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission - * or the ability to modify system settings as determined by - * {@link android.provider.Settings.System#canWrite}.

- * - * @param networkType specifies which network the request pertains to - * @param feature the name of the feature to be used - * @return an integer value representing the outcome of the request. - * The interpretation of this value is specific to each networking - * implementation+feature combination, except that the value {@code -1} - * always indicates failure. - * - * @deprecated Deprecated in favor of the cleaner - * {@link #requestNetwork(NetworkRequest, NetworkCallback)} API. - * In {@link VERSION_CODES#M}, and above, this method is unsupported and will - * throw {@code UnsupportedOperationException} if called. - * @removed - */ - @Deprecated - public int startUsingNetworkFeature(int networkType, String feature) { - checkLegacyRoutingApiAccess(); - NetworkCapabilities netCap = networkCapabilitiesForFeature(networkType, feature); - if (netCap == null) { - Log.d(TAG, "Can't satisfy startUsingNetworkFeature for " + networkType + ", " + - feature); - return DEPRECATED_PHONE_CONSTANT_APN_REQUEST_FAILED; - } - - NetworkRequest request = null; - synchronized (sLegacyRequests) { - LegacyRequest l = sLegacyRequests.get(netCap); - if (l != null) { - Log.d(TAG, "renewing startUsingNetworkFeature request " + l.networkRequest); - renewRequestLocked(l); - if (l.currentNetwork != null) { - return DEPRECATED_PHONE_CONSTANT_APN_ALREADY_ACTIVE; - } else { - return DEPRECATED_PHONE_CONSTANT_APN_REQUEST_STARTED; - } - } - - request = requestNetworkForFeatureLocked(netCap); - } - if (request != null) { - Log.d(TAG, "starting startUsingNetworkFeature for request " + request); - return DEPRECATED_PHONE_CONSTANT_APN_REQUEST_STARTED; - } else { - Log.d(TAG, " request Failed"); - return DEPRECATED_PHONE_CONSTANT_APN_REQUEST_FAILED; - } - } - - /** - * Tells the underlying networking system that the caller is finished - * using the named feature. The interpretation of {@code feature} - * is completely up to each networking implementation. - * - *

This method requires the caller to hold either the - * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission - * or the ability to modify system settings as determined by - * {@link android.provider.Settings.System#canWrite}.

- * - * @param networkType specifies which network the request pertains to - * @param feature the name of the feature that is no longer needed - * @return an integer value representing the outcome of the request. - * The interpretation of this value is specific to each networking - * implementation+feature combination, except that the value {@code -1} - * always indicates failure. - * - * @deprecated Deprecated in favor of the cleaner - * {@link #unregisterNetworkCallback(NetworkCallback)} API. - * In {@link VERSION_CODES#M}, and above, this method is unsupported and will - * throw {@code UnsupportedOperationException} if called. - * @removed - */ - @Deprecated - public int stopUsingNetworkFeature(int networkType, String feature) { - checkLegacyRoutingApiAccess(); - NetworkCapabilities netCap = networkCapabilitiesForFeature(networkType, feature); - if (netCap == null) { - Log.d(TAG, "Can't satisfy stopUsingNetworkFeature for " + networkType + ", " + - feature); - return -1; - } - - if (removeRequestForFeature(netCap)) { - Log.d(TAG, "stopUsingNetworkFeature for " + networkType + ", " + feature); - } - return 1; - } - - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private NetworkCapabilities networkCapabilitiesForFeature(int networkType, String feature) { - if (networkType == TYPE_MOBILE) { - switch (feature) { - case "enableCBS": - return networkCapabilitiesForType(TYPE_MOBILE_CBS); - case "enableDUN": - case "enableDUNAlways": - return networkCapabilitiesForType(TYPE_MOBILE_DUN); - case "enableFOTA": - return networkCapabilitiesForType(TYPE_MOBILE_FOTA); - case "enableHIPRI": - return networkCapabilitiesForType(TYPE_MOBILE_HIPRI); - case "enableIMS": - return networkCapabilitiesForType(TYPE_MOBILE_IMS); - case "enableMMS": - return networkCapabilitiesForType(TYPE_MOBILE_MMS); - case "enableSUPL": - return networkCapabilitiesForType(TYPE_MOBILE_SUPL); - default: - return null; - } - } else if (networkType == TYPE_WIFI && "p2p".equals(feature)) { - return networkCapabilitiesForType(TYPE_WIFI_P2P); - } - return null; - } - - private int legacyTypeForNetworkCapabilities(NetworkCapabilities netCap) { - if (netCap == null) return TYPE_NONE; - if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_CBS)) { - return TYPE_MOBILE_CBS; - } - if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_IMS)) { - return TYPE_MOBILE_IMS; - } - if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_FOTA)) { - return TYPE_MOBILE_FOTA; - } - if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_DUN)) { - return TYPE_MOBILE_DUN; - } - if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_SUPL)) { - return TYPE_MOBILE_SUPL; - } - if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS)) { - return TYPE_MOBILE_MMS; - } - if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) { - return TYPE_MOBILE_HIPRI; - } - if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_WIFI_P2P)) { - return TYPE_WIFI_P2P; - } - return TYPE_NONE; - } - - private static class LegacyRequest { - NetworkCapabilities networkCapabilities; - NetworkRequest networkRequest; - int expireSequenceNumber; - Network currentNetwork; - int delay = -1; - - private void clearDnsBinding() { - if (currentNetwork != null) { - currentNetwork = null; - setProcessDefaultNetworkForHostResolution(null); - } - } - - NetworkCallback networkCallback = new NetworkCallback() { - @Override - public void onAvailable(Network network) { - currentNetwork = network; - Log.d(TAG, "startUsingNetworkFeature got Network:" + network); - setProcessDefaultNetworkForHostResolution(network); - } - @Override - public void onLost(Network network) { - if (network.equals(currentNetwork)) clearDnsBinding(); - Log.d(TAG, "startUsingNetworkFeature lost Network:" + network); - } - }; - } - - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private static final HashMap sLegacyRequests = - new HashMap<>(); - - private NetworkRequest findRequestForFeature(NetworkCapabilities netCap) { - synchronized (sLegacyRequests) { - LegacyRequest l = sLegacyRequests.get(netCap); - if (l != null) return l.networkRequest; - } - return null; - } - - private void renewRequestLocked(LegacyRequest l) { - l.expireSequenceNumber++; - Log.d(TAG, "renewing request to seqNum " + l.expireSequenceNumber); - sendExpireMsgForFeature(l.networkCapabilities, l.expireSequenceNumber, l.delay); - } - - private void expireRequest(NetworkCapabilities netCap, int sequenceNum) { - int ourSeqNum = -1; - synchronized (sLegacyRequests) { - LegacyRequest l = sLegacyRequests.get(netCap); - if (l == null) return; - ourSeqNum = l.expireSequenceNumber; - if (l.expireSequenceNumber == sequenceNum) removeRequestForFeature(netCap); - } - Log.d(TAG, "expireRequest with " + ourSeqNum + ", " + sequenceNum); - } - - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private NetworkRequest requestNetworkForFeatureLocked(NetworkCapabilities netCap) { - int delay = -1; - int type = legacyTypeForNetworkCapabilities(netCap); - try { - delay = mService.getRestoreDefaultNetworkDelay(type); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - LegacyRequest l = new LegacyRequest(); - l.networkCapabilities = netCap; - l.delay = delay; - l.expireSequenceNumber = 0; - l.networkRequest = sendRequestForNetwork( - netCap, l.networkCallback, 0, REQUEST, type, getDefaultHandler()); - if (l.networkRequest == null) return null; - sLegacyRequests.put(netCap, l); - sendExpireMsgForFeature(netCap, l.expireSequenceNumber, delay); - return l.networkRequest; - } - - private void sendExpireMsgForFeature(NetworkCapabilities netCap, int seqNum, int delay) { - if (delay >= 0) { - Log.d(TAG, "sending expire msg with seqNum " + seqNum + " and delay " + delay); - CallbackHandler handler = getDefaultHandler(); - Message msg = handler.obtainMessage(EXPIRE_LEGACY_REQUEST, seqNum, 0, netCap); - handler.sendMessageDelayed(msg, delay); - } - } - - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private boolean removeRequestForFeature(NetworkCapabilities netCap) { - final LegacyRequest l; - synchronized (sLegacyRequests) { - l = sLegacyRequests.remove(netCap); - } - if (l == null) return false; - unregisterNetworkCallback(l.networkCallback); - l.clearDnsBinding(); - return true; - } - - private static final SparseIntArray sLegacyTypeToTransport = new SparseIntArray(); - static { - sLegacyTypeToTransport.put(TYPE_MOBILE, NetworkCapabilities.TRANSPORT_CELLULAR); - sLegacyTypeToTransport.put(TYPE_MOBILE_CBS, NetworkCapabilities.TRANSPORT_CELLULAR); - sLegacyTypeToTransport.put(TYPE_MOBILE_DUN, NetworkCapabilities.TRANSPORT_CELLULAR); - sLegacyTypeToTransport.put(TYPE_MOBILE_FOTA, NetworkCapabilities.TRANSPORT_CELLULAR); - sLegacyTypeToTransport.put(TYPE_MOBILE_HIPRI, NetworkCapabilities.TRANSPORT_CELLULAR); - sLegacyTypeToTransport.put(TYPE_MOBILE_IMS, NetworkCapabilities.TRANSPORT_CELLULAR); - sLegacyTypeToTransport.put(TYPE_MOBILE_MMS, NetworkCapabilities.TRANSPORT_CELLULAR); - sLegacyTypeToTransport.put(TYPE_MOBILE_SUPL, NetworkCapabilities.TRANSPORT_CELLULAR); - sLegacyTypeToTransport.put(TYPE_WIFI, NetworkCapabilities.TRANSPORT_WIFI); - sLegacyTypeToTransport.put(TYPE_WIFI_P2P, NetworkCapabilities.TRANSPORT_WIFI); - sLegacyTypeToTransport.put(TYPE_BLUETOOTH, NetworkCapabilities.TRANSPORT_BLUETOOTH); - sLegacyTypeToTransport.put(TYPE_ETHERNET, NetworkCapabilities.TRANSPORT_ETHERNET); - } - - private static final SparseIntArray sLegacyTypeToCapability = new SparseIntArray(); - static { - sLegacyTypeToCapability.put(TYPE_MOBILE_CBS, NetworkCapabilities.NET_CAPABILITY_CBS); - sLegacyTypeToCapability.put(TYPE_MOBILE_DUN, NetworkCapabilities.NET_CAPABILITY_DUN); - sLegacyTypeToCapability.put(TYPE_MOBILE_FOTA, NetworkCapabilities.NET_CAPABILITY_FOTA); - sLegacyTypeToCapability.put(TYPE_MOBILE_IMS, NetworkCapabilities.NET_CAPABILITY_IMS); - sLegacyTypeToCapability.put(TYPE_MOBILE_MMS, NetworkCapabilities.NET_CAPABILITY_MMS); - sLegacyTypeToCapability.put(TYPE_MOBILE_SUPL, NetworkCapabilities.NET_CAPABILITY_SUPL); - sLegacyTypeToCapability.put(TYPE_WIFI_P2P, NetworkCapabilities.NET_CAPABILITY_WIFI_P2P); - } - - /** - * Given a legacy type (TYPE_WIFI, ...) returns a NetworkCapabilities - * instance suitable for registering a request or callback. Throws an - * IllegalArgumentException if no mapping from the legacy type to - * NetworkCapabilities is known. - * - * @deprecated Types are deprecated. Use {@link NetworkCallback} or {@link NetworkRequest} - * to find the network instead. - * @hide - */ - public static NetworkCapabilities networkCapabilitiesForType(int type) { - final NetworkCapabilities nc = new NetworkCapabilities(); - - // Map from type to transports. - final int NOT_FOUND = -1; - final int transport = sLegacyTypeToTransport.get(type, NOT_FOUND); - Preconditions.checkArgument(transport != NOT_FOUND, "unknown legacy type: " + type); - nc.addTransportType(transport); - - // Map from type to capabilities. - nc.addCapability(sLegacyTypeToCapability.get( - type, NetworkCapabilities.NET_CAPABILITY_INTERNET)); - nc.maybeMarkCapabilitiesRestricted(); - return nc; - } - - /** @hide */ - public static class PacketKeepaliveCallback { - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public PacketKeepaliveCallback() { - } - /** The requested keepalive was successfully started. */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public void onStarted() {} - /** The keepalive was successfully stopped. */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public void onStopped() {} - /** An error occurred. */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public void onError(int error) {} - } - - /** - * Allows applications to request that the system periodically send specific packets on their - * behalf, using hardware offload to save battery power. - * - * To request that the system send keepalives, call one of the methods that return a - * {@link ConnectivityManager.PacketKeepalive} object, such as {@link #startNattKeepalive}, - * passing in a non-null callback. If the callback is successfully started, the callback's - * {@code onStarted} method will be called. If an error occurs, {@code onError} will be called, - * specifying one of the {@code ERROR_*} constants in this class. - * - * To stop an existing keepalive, call {@link PacketKeepalive#stop}. The system will call - * {@link PacketKeepaliveCallback#onStopped} if the operation was successful or - * {@link PacketKeepaliveCallback#onError} if an error occurred. - * - * @deprecated Use {@link SocketKeepalive} instead. - * - * @hide - */ - public class PacketKeepalive { - - private static final String TAG = "PacketKeepalive"; - - /** @hide */ - public static final int SUCCESS = 0; - - /** @hide */ - public static final int NO_KEEPALIVE = -1; - - /** @hide */ - public static final int BINDER_DIED = -10; - - /** The specified {@code Network} is not connected. */ - public static final int ERROR_INVALID_NETWORK = -20; - /** The specified IP addresses are invalid. For example, the specified source IP address is - * not configured on the specified {@code Network}. */ - public static final int ERROR_INVALID_IP_ADDRESS = -21; - /** The requested port is invalid. */ - public static final int ERROR_INVALID_PORT = -22; - /** The packet length is invalid (e.g., too long). */ - public static final int ERROR_INVALID_LENGTH = -23; - /** The packet transmission interval is invalid (e.g., too short). */ - public static final int ERROR_INVALID_INTERVAL = -24; - - /** The hardware does not support this request. */ - public static final int ERROR_HARDWARE_UNSUPPORTED = -30; - /** The hardware returned an error. */ - public static final int ERROR_HARDWARE_ERROR = -31; - - /** The NAT-T destination port for IPsec */ - public static final int NATT_PORT = 4500; - - /** The minimum interval in seconds between keepalive packet transmissions */ - public static final int MIN_INTERVAL = 10; - - private final Network mNetwork; - private final ISocketKeepaliveCallback mCallback; - private final ExecutorService mExecutor; - - private volatile Integer mSlot; - - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public void stop() { - try { - mExecutor.execute(() -> { - try { - if (mSlot != null) { - mService.stopKeepalive(mNetwork, mSlot); - } - } catch (RemoteException e) { - Log.e(TAG, "Error stopping packet keepalive: ", e); - throw e.rethrowFromSystemServer(); - } - }); - } catch (RejectedExecutionException e) { - // The internal executor has already stopped due to previous event. - } - } - - private PacketKeepalive(Network network, PacketKeepaliveCallback callback) { - Preconditions.checkNotNull(network, "network cannot be null"); - Preconditions.checkNotNull(callback, "callback cannot be null"); - mNetwork = network; - mExecutor = Executors.newSingleThreadExecutor(); - mCallback = new ISocketKeepaliveCallback.Stub() { - @Override - public void onStarted(int slot) { - final long token = Binder.clearCallingIdentity(); - try { - mExecutor.execute(() -> { - mSlot = slot; - callback.onStarted(); - }); - } finally { - Binder.restoreCallingIdentity(token); - } - } - - @Override - public void onStopped() { - final long token = Binder.clearCallingIdentity(); - try { - mExecutor.execute(() -> { - mSlot = null; - callback.onStopped(); - }); - } finally { - Binder.restoreCallingIdentity(token); - } - mExecutor.shutdown(); - } - - @Override - public void onError(int error) { - final long token = Binder.clearCallingIdentity(); - try { - mExecutor.execute(() -> { - mSlot = null; - callback.onError(error); - }); - } finally { - Binder.restoreCallingIdentity(token); - } - mExecutor.shutdown(); - } - - @Override - public void onDataReceived() { - // PacketKeepalive is only used for Nat-T keepalive and as such does not invoke - // this callback when data is received. - } - }; - } - } - - /** - * Starts an IPsec NAT-T keepalive packet with the specified parameters. - * - * @deprecated Use {@link #createSocketKeepalive} instead. - * - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public PacketKeepalive startNattKeepalive( - Network network, int intervalSeconds, PacketKeepaliveCallback callback, - InetAddress srcAddr, int srcPort, InetAddress dstAddr) { - final PacketKeepalive k = new PacketKeepalive(network, callback); - try { - mService.startNattKeepalive(network, intervalSeconds, k.mCallback, - srcAddr.getHostAddress(), srcPort, dstAddr.getHostAddress()); - } catch (RemoteException e) { - Log.e(TAG, "Error starting packet keepalive: ", e); - throw e.rethrowFromSystemServer(); - } - return k; - } - - // Construct an invalid fd. - private ParcelFileDescriptor createInvalidFd() { - final int invalidFd = -1; - return ParcelFileDescriptor.adoptFd(invalidFd); - } - - /** - * Request that keepalives be started on a IPsec NAT-T socket. - * - * @param network The {@link Network} the socket is on. - * @param socket The socket that needs to be kept alive. - * @param source The source address of the {@link UdpEncapsulationSocket}. - * @param destination The destination address of the {@link UdpEncapsulationSocket}. - * @param executor The executor on which callback will be invoked. The provided {@link Executor} - * must run callback sequentially, otherwise the order of callbacks cannot be - * guaranteed. - * @param callback A {@link SocketKeepalive.Callback}. Used for notifications about keepalive - * changes. Must be extended by applications that use this API. - * - * @return A {@link SocketKeepalive} object that can be used to control the keepalive on the - * given socket. - **/ - public @NonNull SocketKeepalive createSocketKeepalive(@NonNull Network network, - @NonNull UdpEncapsulationSocket socket, - @NonNull InetAddress source, - @NonNull InetAddress destination, - @NonNull @CallbackExecutor Executor executor, - @NonNull Callback callback) { - ParcelFileDescriptor dup; - try { - // Dup is needed here as the pfd inside the socket is owned by the IpSecService, - // which cannot be obtained by the app process. - dup = ParcelFileDescriptor.dup(socket.getFileDescriptor()); - } catch (IOException ignored) { - // Construct an invalid fd, so that if the user later calls start(), it will fail with - // ERROR_INVALID_SOCKET. - dup = createInvalidFd(); - } - return new NattSocketKeepalive(mService, network, dup, socket.getResourceId(), source, - destination, executor, callback); - } - - /** - * Request that keepalives be started on a IPsec NAT-T socket file descriptor. Directly called - * by system apps which don't use IpSecService to create {@link UdpEncapsulationSocket}. - * - * @param network The {@link Network} the socket is on. - * @param pfd The {@link ParcelFileDescriptor} that needs to be kept alive. The provided - * {@link ParcelFileDescriptor} must be bound to a port and the keepalives will be sent - * from that port. - * @param source The source address of the {@link UdpEncapsulationSocket}. - * @param destination The destination address of the {@link UdpEncapsulationSocket}. The - * keepalive packets will always be sent to port 4500 of the given {@code destination}. - * @param executor The executor on which callback will be invoked. The provided {@link Executor} - * must run callback sequentially, otherwise the order of callbacks cannot be - * guaranteed. - * @param callback A {@link SocketKeepalive.Callback}. Used for notifications about keepalive - * changes. Must be extended by applications that use this API. - * - * @return A {@link SocketKeepalive} object that can be used to control the keepalive on the - * given socket. - * @hide - */ - @SystemApi - @RequiresPermission(android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD) - public @NonNull SocketKeepalive createNattKeepalive(@NonNull Network network, - @NonNull ParcelFileDescriptor pfd, - @NonNull InetAddress source, - @NonNull InetAddress destination, - @NonNull @CallbackExecutor Executor executor, - @NonNull Callback callback) { - ParcelFileDescriptor dup; - try { - // TODO: Consider remove unnecessary dup. - dup = pfd.dup(); - } catch (IOException ignored) { - // Construct an invalid fd, so that if the user later calls start(), it will fail with - // ERROR_INVALID_SOCKET. - dup = createInvalidFd(); - } - return new NattSocketKeepalive(mService, network, dup, - INVALID_RESOURCE_ID /* Unused */, source, destination, executor, callback); - } - - /** - * Request that keepalives be started on a TCP socket. - * The socket must be established. - * - * @param network The {@link Network} the socket is on. - * @param socket The socket that needs to be kept alive. - * @param executor The executor on which callback will be invoked. This implementation assumes - * the provided {@link Executor} runs the callbacks in sequence with no - * concurrency. Failing this, no guarantee of correctness can be made. It is - * the responsibility of the caller to ensure the executor provides this - * guarantee. A simple way of creating such an executor is with the standard - * tool {@code Executors.newSingleThreadExecutor}. - * @param callback A {@link SocketKeepalive.Callback}. Used for notifications about keepalive - * changes. Must be extended by applications that use this API. - * - * @return A {@link SocketKeepalive} object that can be used to control the keepalive on the - * given socket. - * @hide - */ - @SystemApi - @RequiresPermission(android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD) - public @NonNull SocketKeepalive createSocketKeepalive(@NonNull Network network, - @NonNull Socket socket, - @NonNull Executor executor, - @NonNull Callback callback) { - ParcelFileDescriptor dup; - try { - dup = ParcelFileDescriptor.fromSocket(socket); - } catch (UncheckedIOException ignored) { - // Construct an invalid fd, so that if the user later calls start(), it will fail with - // ERROR_INVALID_SOCKET. - dup = createInvalidFd(); - } - return new TcpSocketKeepalive(mService, network, dup, executor, callback); - } - - /** - * Ensure that a network route exists to deliver traffic to the specified - * host via the specified network interface. An attempt to add a route that - * already exists is ignored, but treated as successful. - * - *

This method requires the caller to hold either the - * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission - * or the ability to modify system settings as determined by - * {@link android.provider.Settings.System#canWrite}.

- * - * @param networkType the type of the network over which traffic to the specified - * host is to be routed - * @param hostAddress the IP address of the host to which the route is desired - * @return {@code true} on success, {@code false} on failure - * - * @deprecated Deprecated in favor of the - * {@link #requestNetwork(NetworkRequest, NetworkCallback)}, - * {@link #bindProcessToNetwork} and {@link Network#getSocketFactory} API. - * In {@link VERSION_CODES#M}, and above, this method is unsupported and will - * throw {@code UnsupportedOperationException} if called. - * @removed - */ - @Deprecated - public boolean requestRouteToHost(int networkType, int hostAddress) { - return requestRouteToHostAddress(networkType, NetworkUtils.intToInetAddress(hostAddress)); - } - - /** - * Ensure that a network route exists to deliver traffic to the specified - * host via the specified network interface. An attempt to add a route that - * already exists is ignored, but treated as successful. - * - *

This method requires the caller to hold either the - * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission - * or the ability to modify system settings as determined by - * {@link android.provider.Settings.System#canWrite}.

- * - * @param networkType the type of the network over which traffic to the specified - * host is to be routed - * @param hostAddress the IP address of the host to which the route is desired - * @return {@code true} on success, {@code false} on failure - * @hide - * @deprecated Deprecated in favor of the {@link #requestNetwork} and - * {@link #bindProcessToNetwork} API. - */ - @Deprecated - @UnsupportedAppUsage - public boolean requestRouteToHostAddress(int networkType, InetAddress hostAddress) { - checkLegacyRoutingApiAccess(); - try { - return mService.requestRouteToHostAddress(networkType, hostAddress.getAddress(), - mContext.getOpPackageName(), getAttributionTag()); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * @return the context's attribution tag - */ - // TODO: Remove method and replace with direct call once R code is pushed to AOSP - private @Nullable String getAttributionTag() { - return null; - } - - /** - * Returns the value of the setting for background data usage. If false, - * applications should not use the network if the application is not in the - * foreground. Developers should respect this setting, and check the value - * of this before performing any background data operations. - *

- * All applications that have background services that use the network - * should listen to {@link #ACTION_BACKGROUND_DATA_SETTING_CHANGED}. - *

- * @deprecated As of {@link VERSION_CODES#ICE_CREAM_SANDWICH}, availability of - * background data depends on several combined factors, and this method will - * always return {@code true}. Instead, when background data is unavailable, - * {@link #getActiveNetworkInfo()} will now appear disconnected. - * - * @return Whether background data usage is allowed. - */ - @Deprecated - public boolean getBackgroundDataSetting() { - // assume that background data is allowed; final authority is - // NetworkInfo which may be blocked. - return true; - } - - /** - * Sets the value of the setting for background data usage. - * - * @param allowBackgroundData Whether an application should use data while - * it is in the background. - * - * @attr ref android.Manifest.permission#CHANGE_BACKGROUND_DATA_SETTING - * @see #getBackgroundDataSetting() - * @hide - */ - @Deprecated - @UnsupportedAppUsage - public void setBackgroundDataSetting(boolean allowBackgroundData) { - // ignored - } - - /** - * @hide - * @deprecated Talk to TelephonyManager directly - */ - @Deprecated - @UnsupportedAppUsage - public boolean getMobileDataEnabled() { - TelephonyManager tm = mContext.getSystemService(TelephonyManager.class); - if (tm != null) { - int subId = SubscriptionManager.getDefaultDataSubscriptionId(); - Log.d("ConnectivityManager", "getMobileDataEnabled()+ subId=" + subId); - boolean retVal = tm.createForSubscriptionId(subId).isDataEnabled(); - Log.d("ConnectivityManager", "getMobileDataEnabled()- subId=" + subId - + " retVal=" + retVal); - return retVal; - } - Log.d("ConnectivityManager", "getMobileDataEnabled()- remote exception retVal=false"); - return false; - } - - /** - * Callback for use with {@link ConnectivityManager#addDefaultNetworkActiveListener} - * to find out when the system default network has gone in to a high power state. - */ - public interface OnNetworkActiveListener { - /** - * Called on the main thread of the process to report that the current data network - * has become active, and it is now a good time to perform any pending network - * operations. Note that this listener only tells you when the network becomes - * active; if at any other time you want to know whether it is active (and thus okay - * to initiate network traffic), you can retrieve its instantaneous state with - * {@link ConnectivityManager#isDefaultNetworkActive}. - */ - void onNetworkActive(); - } - - private INetworkManagementService getNetworkManagementService() { - synchronized (this) { - if (mNMService != null) { - return mNMService; - } - IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); - mNMService = INetworkManagementService.Stub.asInterface(b); - return mNMService; - } - } - - private final ArrayMap - mNetworkActivityListeners = new ArrayMap<>(); - - /** - * Start listening to reports when the system's default data network is active, meaning it is - * a good time to perform network traffic. Use {@link #isDefaultNetworkActive()} - * to determine the current state of the system's default network after registering the - * listener. - *

- * If the process default network has been set with - * {@link ConnectivityManager#bindProcessToNetwork} this function will not - * reflect the process's default, but the system default. - * - * @param l The listener to be told when the network is active. - */ - public void addDefaultNetworkActiveListener(final OnNetworkActiveListener l) { - INetworkActivityListener rl = new INetworkActivityListener.Stub() { - @Override - public void onNetworkActive() throws RemoteException { - l.onNetworkActive(); - } - }; - - try { - getNetworkManagementService().registerNetworkActivityListener(rl); - mNetworkActivityListeners.put(l, rl); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Remove network active listener previously registered with - * {@link #addDefaultNetworkActiveListener}. - * - * @param l Previously registered listener. - */ - public void removeDefaultNetworkActiveListener(@NonNull OnNetworkActiveListener l) { - INetworkActivityListener rl = mNetworkActivityListeners.get(l); - Preconditions.checkArgument(rl != null, "Listener was not registered."); - try { - getNetworkManagementService().unregisterNetworkActivityListener(rl); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Return whether the data network is currently active. An active network means that - * it is currently in a high power state for performing data transmission. On some - * types of networks, it may be expensive to move and stay in such a state, so it is - * more power efficient to batch network traffic together when the radio is already in - * this state. This method tells you whether right now is currently a good time to - * initiate network traffic, as the network is already active. - */ - public boolean isDefaultNetworkActive() { - try { - return getNetworkManagementService().isNetworkActive(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * {@hide} - */ - public ConnectivityManager(Context context, IConnectivityManager service) { - mContext = Preconditions.checkNotNull(context, "missing context"); - mService = Preconditions.checkNotNull(service, "missing IConnectivityManager"); - mTetheringManager = (TetheringManager) mContext.getSystemService(Context.TETHERING_SERVICE); - sInstance = this; - } - - /** {@hide} */ - @UnsupportedAppUsage - public static ConnectivityManager from(Context context) { - return (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); - } - - /** @hide */ - public NetworkRequest getDefaultRequest() { - try { - // This is not racy as the default request is final in ConnectivityService. - return mService.getDefaultRequest(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /* TODO: These permissions checks don't belong in client-side code. Move them to - * services.jar, possibly in com.android.server.net. */ - - /** {@hide} */ - public static final void enforceChangePermission(Context context, - String callingPkg, String callingAttributionTag) { - int uid = Binder.getCallingUid(); - checkAndNoteChangeNetworkStateOperation(context, uid, callingPkg, - callingAttributionTag, true /* throwException */); - } - - /** - * Check if the package is a allowed to change the network state. This also accounts that such - * an access happened. - * - * @return {@code true} iff the package is allowed to change the network state. - */ - // TODO: Remove method and replace with direct call once R code is pushed to AOSP - private static boolean checkAndNoteChangeNetworkStateOperation(@NonNull Context context, - int uid, @NonNull String callingPackage, @Nullable String callingAttributionTag, - boolean throwException) { - return Settings.checkAndNoteChangeNetworkStateOperation(context, uid, callingPackage, - throwException); - } - - /** - * Check if the package is a allowed to write settings. This also accounts that such an access - * happened. - * - * @return {@code true} iff the package is allowed to write settings. - */ - // TODO: Remove method and replace with direct call once R code is pushed to AOSP - private static boolean checkAndNoteWriteSettingsOperation(@NonNull Context context, int uid, - @NonNull String callingPackage, @Nullable String callingAttributionTag, - boolean throwException) { - return Settings.checkAndNoteWriteSettingsOperation(context, uid, callingPackage, - throwException); - } - - /** - * @deprecated - use getSystemService. This is a kludge to support static access in certain - * situations where a Context pointer is unavailable. - * @hide - */ - @Deprecated - static ConnectivityManager getInstanceOrNull() { - return sInstance; - } - - /** - * @deprecated - use getSystemService. This is a kludge to support static access in certain - * situations where a Context pointer is unavailable. - * @hide - */ - @Deprecated - @UnsupportedAppUsage - private static ConnectivityManager getInstance() { - if (getInstanceOrNull() == null) { - throw new IllegalStateException("No ConnectivityManager yet constructed"); - } - return getInstanceOrNull(); - } - - /** - * Get the set of tetherable, available interfaces. This list is limited by - * device configuration and current interface existence. - * - * @return an array of 0 or more Strings of tetherable interface names. - * - * @deprecated Use {@link TetheringEventCallback#onTetherableInterfacesChanged(List)} instead. - * {@hide} - */ - @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) - @UnsupportedAppUsage - @Deprecated - public String[] getTetherableIfaces() { - return mTetheringManager.getTetherableIfaces(); - } - - /** - * Get the set of tethered interfaces. - * - * @return an array of 0 or more String of currently tethered interface names. - * - * @deprecated Use {@link TetheringEventCallback#onTetherableInterfacesChanged(List)} instead. - * {@hide} - */ - @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) - @UnsupportedAppUsage - @Deprecated - public String[] getTetheredIfaces() { - return mTetheringManager.getTetheredIfaces(); - } - - /** - * Get the set of interface names which attempted to tether but - * failed. Re-attempting to tether may cause them to reset to the Tethered - * state. Alternatively, causing the interface to be destroyed and recreated - * may cause them to reset to the available state. - * {@link ConnectivityManager#getLastTetherError} can be used to get more - * information on the cause of the errors. - * - * @return an array of 0 or more String indicating the interface names - * which failed to tether. - * - * @deprecated Use {@link TetheringEventCallback#onError(String, int)} instead. - * {@hide} - */ - @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) - @UnsupportedAppUsage - @Deprecated - public String[] getTetheringErroredIfaces() { - return mTetheringManager.getTetheringErroredIfaces(); - } - - /** - * Get the set of tethered dhcp ranges. - * - * @deprecated This method is not supported. - * TODO: remove this function when all of clients are removed. - * {@hide} - */ - @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) - @Deprecated - public String[] getTetheredDhcpRanges() { - throw new UnsupportedOperationException("getTetheredDhcpRanges is not supported"); - } - - /** - * Attempt to tether the named interface. This will setup a dhcp server - * on the interface, forward and NAT IP packets and forward DNS requests - * to the best active upstream network interface. Note that if no upstream - * IP network interface is available, dhcp will still run and traffic will be - * allowed between the tethered devices and this device, though upstream net - * access will of course fail until an upstream network interface becomes - * active. - * - *

This method requires the caller to hold either the - * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission - * or the ability to modify system settings as determined by - * {@link android.provider.Settings.System#canWrite}.

- * - *

WARNING: New clients should not use this function. The only usages should be in PanService - * and WifiStateMachine which need direct access. All other clients should use - * {@link #startTethering} and {@link #stopTethering} which encapsulate proper provisioning - * logic.

- * - * @param iface the interface name to tether. - * @return error a {@code TETHER_ERROR} value indicating success or failure type - * @deprecated Use {@link TetheringManager#startTethering} instead - * - * {@hide} - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @Deprecated - public int tether(String iface) { - return mTetheringManager.tether(iface); - } - - /** - * Stop tethering the named interface. - * - *

This method requires the caller to hold either the - * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission - * or the ability to modify system settings as determined by - * {@link android.provider.Settings.System#canWrite}.

- * - *

WARNING: New clients should not use this function. The only usages should be in PanService - * and WifiStateMachine which need direct access. All other clients should use - * {@link #startTethering} and {@link #stopTethering} which encapsulate proper provisioning - * logic.

- * - * @param iface the interface name to untether. - * @return error a {@code TETHER_ERROR} value indicating success or failure type - * - * {@hide} - */ - @UnsupportedAppUsage - @Deprecated - public int untether(String iface) { - return mTetheringManager.untether(iface); - } - - /** - * Check if the device allows for tethering. It may be disabled via - * {@code ro.tether.denied} system property, Settings.TETHER_SUPPORTED or - * due to device configuration. - * - *

If this app does not have permission to use this API, it will always - * return false rather than throw an exception.

- * - *

If the device has a hotspot provisioning app, the caller is required to hold the - * {@link android.Manifest.permission.TETHER_PRIVILEGED} permission.

- * - *

Otherwise, this method requires the caller to hold the ability to modify system - * settings as determined by {@link android.provider.Settings.System#canWrite}.

- * - * @return a boolean - {@code true} indicating Tethering is supported. - * - * @deprecated Use {@link TetheringEventCallback#onTetheringSupported(boolean)} instead. - * {@hide} - */ - @SystemApi - @RequiresPermission(anyOf = {android.Manifest.permission.TETHER_PRIVILEGED, - android.Manifest.permission.WRITE_SETTINGS}) - public boolean isTetheringSupported() { - return mTetheringManager.isTetheringSupported(); - } - - /** - * Callback for use with {@link #startTethering} to find out whether tethering succeeded. - * - * @deprecated Use {@link TetheringManager.StartTetheringCallback} instead. - * @hide - */ - @SystemApi - @Deprecated - public static abstract class OnStartTetheringCallback { - /** - * Called when tethering has been successfully started. - */ - public void onTetheringStarted() {} - - /** - * Called when starting tethering failed. - */ - public void onTetheringFailed() {} - } - - /** - * Convenient overload for - * {@link #startTethering(int, boolean, OnStartTetheringCallback, Handler)} which passes a null - * handler to run on the current thread's {@link Looper}. - * - * @deprecated Use {@link TetheringManager#startTethering} instead. - * @hide - */ - @SystemApi - @Deprecated - @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) - public void startTethering(int type, boolean showProvisioningUi, - final OnStartTetheringCallback callback) { - startTethering(type, showProvisioningUi, callback, null); - } - - /** - * Runs tether provisioning for the given type if needed and then starts tethering if - * the check succeeds. If no carrier provisioning is required for tethering, tethering is - * enabled immediately. If provisioning fails, tethering will not be enabled. It also - * schedules tether provisioning re-checks if appropriate. - * - * @param type The type of tethering to start. Must be one of - * {@link ConnectivityManager.TETHERING_WIFI}, - * {@link ConnectivityManager.TETHERING_USB}, or - * {@link ConnectivityManager.TETHERING_BLUETOOTH}. - * @param showProvisioningUi a boolean indicating to show the provisioning app UI if there - * is one. This should be true the first time this function is called and also any time - * the user can see this UI. It gives users information from their carrier about the - * check failing and how they can sign up for tethering if possible. - * @param callback an {@link OnStartTetheringCallback} which will be called to notify the caller - * of the result of trying to tether. - * @param handler {@link Handler} to specify the thread upon which the callback will be invoked. - * - * @deprecated Use {@link TetheringManager#startTethering} instead. - * @hide - */ - @SystemApi - @Deprecated - @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) - public void startTethering(int type, boolean showProvisioningUi, - final OnStartTetheringCallback callback, Handler handler) { - Preconditions.checkNotNull(callback, "OnStartTetheringCallback cannot be null."); - - final Executor executor = new Executor() { - @Override - public void execute(Runnable command) { - if (handler == null) { - command.run(); - } else { - handler.post(command); - } - } - }; - - final StartTetheringCallback tetheringCallback = new StartTetheringCallback() { - @Override - public void onTetheringStarted() { - callback.onTetheringStarted(); - } - - @Override - public void onTetheringFailed(final int error) { - callback.onTetheringFailed(); - } - }; - - final TetheringRequest request = new TetheringRequest.Builder(type) - .setShouldShowEntitlementUi(showProvisioningUi).build(); - - mTetheringManager.startTethering(request, executor, tetheringCallback); - } - - /** - * Stops tethering for the given type. Also cancels any provisioning rechecks for that type if - * applicable. - * - * @param type The type of tethering to stop. Must be one of - * {@link ConnectivityManager.TETHERING_WIFI}, - * {@link ConnectivityManager.TETHERING_USB}, or - * {@link ConnectivityManager.TETHERING_BLUETOOTH}. - * - * @deprecated Use {@link TetheringManager#stopTethering} instead. - * @hide - */ - @SystemApi - @Deprecated - @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) - public void stopTethering(int type) { - mTetheringManager.stopTethering(type); - } - - /** - * Callback for use with {@link registerTetheringEventCallback} to find out tethering - * upstream status. - * - * @deprecated Use {@link TetheringManager#OnTetheringEventCallback} instead. - * @hide - */ - @SystemApi - @Deprecated - public abstract static class OnTetheringEventCallback { - - /** - * Called when tethering upstream changed. This can be called multiple times and can be - * called any time. - * - * @param network the {@link Network} of tethering upstream. Null means tethering doesn't - * have any upstream. - */ - public void onUpstreamChanged(@Nullable Network network) {} - } - - @GuardedBy("mTetheringEventCallbacks") - private final ArrayMap - mTetheringEventCallbacks = new ArrayMap<>(); - - /** - * Start listening to tethering change events. Any new added callback will receive the last - * tethering status right away. If callback is registered when tethering has no upstream or - * disabled, {@link OnTetheringEventCallback#onUpstreamChanged} will immediately be called - * with a null argument. The same callback object cannot be registered twice. - * - * @param executor the executor on which callback will be invoked. - * @param callback the callback to be called when tethering has change events. - * - * @deprecated Use {@link TetheringManager#registerTetheringEventCallback} instead. - * @hide - */ - @SystemApi - @Deprecated - @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) - public void registerTetheringEventCallback( - @NonNull @CallbackExecutor Executor executor, - @NonNull final OnTetheringEventCallback callback) { - Preconditions.checkNotNull(callback, "OnTetheringEventCallback cannot be null."); - - final TetheringEventCallback tetherCallback = - new TetheringEventCallback() { - @Override - public void onUpstreamChanged(@Nullable Network network) { - callback.onUpstreamChanged(network); - } - }; - - synchronized (mTetheringEventCallbacks) { - mTetheringEventCallbacks.put(callback, tetherCallback); - mTetheringManager.registerTetheringEventCallback(executor, tetherCallback); - } - } - - /** - * Remove tethering event callback previously registered with - * {@link #registerTetheringEventCallback}. - * - * @param callback previously registered callback. - * - * @deprecated Use {@link TetheringManager#unregisterTetheringEventCallback} instead. - * @hide - */ - @SystemApi - @Deprecated - @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) - public void unregisterTetheringEventCallback( - @NonNull final OnTetheringEventCallback callback) { - Objects.requireNonNull(callback, "The callback must be non-null"); - synchronized (mTetheringEventCallbacks) { - final TetheringEventCallback tetherCallback = - mTetheringEventCallbacks.remove(callback); - mTetheringManager.unregisterTetheringEventCallback(tetherCallback); - } - } - - - /** - * Get the list of regular expressions that define any tetherable - * USB network interfaces. If USB tethering is not supported by the - * device, this list should be empty. - * - * @return an array of 0 or more regular expression Strings defining - * what interfaces are considered tetherable usb interfaces. - * - * @deprecated Use {@link TetheringEventCallback#onTetherableInterfaceRegexpsChanged} instead. - * {@hide} - */ - @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) - @UnsupportedAppUsage - @Deprecated - public String[] getTetherableUsbRegexs() { - return mTetheringManager.getTetherableUsbRegexs(); - } - - /** - * Get the list of regular expressions that define any tetherable - * Wifi network interfaces. If Wifi tethering is not supported by the - * device, this list should be empty. - * - * @return an array of 0 or more regular expression Strings defining - * what interfaces are considered tetherable wifi interfaces. - * - * @deprecated Use {@link TetheringEventCallback#onTetherableInterfaceRegexpsChanged} instead. - * {@hide} - */ - @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) - @UnsupportedAppUsage - @Deprecated - public String[] getTetherableWifiRegexs() { - return mTetheringManager.getTetherableWifiRegexs(); - } - - /** - * Get the list of regular expressions that define any tetherable - * Bluetooth network interfaces. If Bluetooth tethering is not supported by the - * device, this list should be empty. - * - * @return an array of 0 or more regular expression Strings defining - * what interfaces are considered tetherable bluetooth interfaces. - * - * @deprecated Use {@link TetheringEventCallback#onTetherableInterfaceRegexpsChanged( - *TetheringManager.TetheringInterfaceRegexps)} instead. - * {@hide} - */ - @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) - @UnsupportedAppUsage - @Deprecated - public String[] getTetherableBluetoothRegexs() { - return mTetheringManager.getTetherableBluetoothRegexs(); - } - - /** - * Attempt to both alter the mode of USB and Tethering of USB. A - * utility method to deal with some of the complexity of USB - will - * attempt to switch to Rndis and subsequently tether the resulting - * interface on {@code true} or turn off tethering and switch off - * Rndis on {@code false}. - * - *

This method requires the caller to hold either the - * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission - * or the ability to modify system settings as determined by - * {@link android.provider.Settings.System#canWrite}.

- * - * @param enable a boolean - {@code true} to enable tethering - * @return error a {@code TETHER_ERROR} value indicating success or failure type - * @deprecated Use {@link TetheringManager#startTethering} instead - * - * {@hide} - */ - @UnsupportedAppUsage - @Deprecated - public int setUsbTethering(boolean enable) { - return mTetheringManager.setUsbTethering(enable); - } - - /** - * @deprecated Use {@link TetheringManager#TETHER_ERROR_NO_ERROR}. - * {@hide} - */ - @SystemApi - @Deprecated - public static final int TETHER_ERROR_NO_ERROR = TetheringManager.TETHER_ERROR_NO_ERROR; - /** - * @deprecated Use {@link TetheringManager#TETHER_ERROR_UNKNOWN_IFACE}. - * {@hide} - */ - @Deprecated - public static final int TETHER_ERROR_UNKNOWN_IFACE = - TetheringManager.TETHER_ERROR_UNKNOWN_IFACE; - /** - * @deprecated Use {@link TetheringManager#TETHER_ERROR_SERVICE_UNAVAIL}. - * {@hide} - */ - @Deprecated - public static final int TETHER_ERROR_SERVICE_UNAVAIL = - TetheringManager.TETHER_ERROR_SERVICE_UNAVAIL; - /** - * @deprecated Use {@link TetheringManager#TETHER_ERROR_UNSUPPORTED}. - * {@hide} - */ - @Deprecated - public static final int TETHER_ERROR_UNSUPPORTED = TetheringManager.TETHER_ERROR_UNSUPPORTED; - /** - * @deprecated Use {@link TetheringManager#TETHER_ERROR_UNAVAIL_IFACE}. - * {@hide} - */ - @Deprecated - public static final int TETHER_ERROR_UNAVAIL_IFACE = - TetheringManager.TETHER_ERROR_UNAVAIL_IFACE; - /** - * @deprecated Use {@link TetheringManager#TETHER_ERROR_INTERNAL_ERROR}. - * {@hide} - */ - @Deprecated - public static final int TETHER_ERROR_MASTER_ERROR = - TetheringManager.TETHER_ERROR_INTERNAL_ERROR; - /** - * @deprecated Use {@link TetheringManager#TETHER_ERROR_TETHER_IFACE_ERROR}. - * {@hide} - */ - @Deprecated - public static final int TETHER_ERROR_TETHER_IFACE_ERROR = - TetheringManager.TETHER_ERROR_TETHER_IFACE_ERROR; - /** - * @deprecated Use {@link TetheringManager#TETHER_ERROR_UNTETHER_IFACE_ERROR}. - * {@hide} - */ - @Deprecated - public static final int TETHER_ERROR_UNTETHER_IFACE_ERROR = - TetheringManager.TETHER_ERROR_UNTETHER_IFACE_ERROR; - /** - * @deprecated Use {@link TetheringManager#TETHER_ERROR_ENABLE_FORWARDING_ERROR}. - * {@hide} - */ - @Deprecated - public static final int TETHER_ERROR_ENABLE_NAT_ERROR = - TetheringManager.TETHER_ERROR_ENABLE_FORWARDING_ERROR; - /** - * @deprecated Use {@link TetheringManager#TETHER_ERROR_DISABLE_FORWARDING_ERROR}. - * {@hide} - */ - @Deprecated - public static final int TETHER_ERROR_DISABLE_NAT_ERROR = - TetheringManager.TETHER_ERROR_DISABLE_FORWARDING_ERROR; - /** - * @deprecated Use {@link TetheringManager#TETHER_ERROR_IFACE_CFG_ERROR}. - * {@hide} - */ - @Deprecated - public static final int TETHER_ERROR_IFACE_CFG_ERROR = - TetheringManager.TETHER_ERROR_IFACE_CFG_ERROR; - /** - * @deprecated Use {@link TetheringManager#TETHER_ERROR_PROVISIONING_FAILED}. - * {@hide} - */ - @SystemApi - @Deprecated - public static final int TETHER_ERROR_PROVISION_FAILED = - TetheringManager.TETHER_ERROR_PROVISIONING_FAILED; - /** - * @deprecated Use {@link TetheringManager#TETHER_ERROR_DHCPSERVER_ERROR}. - * {@hide} - */ - @Deprecated - public static final int TETHER_ERROR_DHCPSERVER_ERROR = - TetheringManager.TETHER_ERROR_DHCPSERVER_ERROR; - /** - * @deprecated Use {@link TetheringManager#TETHER_ERROR_ENTITLEMENT_UNKNOWN}. - * {@hide} - */ - @SystemApi - @Deprecated - public static final int TETHER_ERROR_ENTITLEMENT_UNKONWN = - TetheringManager.TETHER_ERROR_ENTITLEMENT_UNKNOWN; - - /** - * Get a more detailed error code after a Tethering or Untethering - * request asynchronously failed. - * - * @param iface The name of the interface of interest - * @return error The error code of the last error tethering or untethering the named - * interface - * - * @deprecated Use {@link TetheringEventCallback#onError(String, int)} instead. - * {@hide} - */ - @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @Deprecated - public int getLastTetherError(String iface) { - int error = mTetheringManager.getLastTetherError(iface); - if (error == TetheringManager.TETHER_ERROR_UNKNOWN_TYPE) { - // TETHER_ERROR_UNKNOWN_TYPE was introduced with TetheringManager and has never been - // returned by ConnectivityManager. Convert it to the legacy TETHER_ERROR_UNKNOWN_IFACE - // instead. - error = TetheringManager.TETHER_ERROR_UNKNOWN_IFACE; - } - return error; - } - - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(value = { - TETHER_ERROR_NO_ERROR, - TETHER_ERROR_PROVISION_FAILED, - TETHER_ERROR_ENTITLEMENT_UNKONWN, - }) - public @interface EntitlementResultCode { - } - - /** - * Callback for use with {@link #getLatestTetheringEntitlementResult} to find out whether - * entitlement succeeded. - * - * @deprecated Use {@link TetheringManager#OnTetheringEntitlementResultListener} instead. - * @hide - */ - @SystemApi - @Deprecated - public interface OnTetheringEntitlementResultListener { - /** - * Called to notify entitlement result. - * - * @param resultCode an int value of entitlement result. It may be one of - * {@link #TETHER_ERROR_NO_ERROR}, - * {@link #TETHER_ERROR_PROVISION_FAILED}, or - * {@link #TETHER_ERROR_ENTITLEMENT_UNKONWN}. - */ - void onTetheringEntitlementResult(@EntitlementResultCode int resultCode); - } - - /** - * Get the last value of the entitlement check on this downstream. If the cached value is - * {@link #TETHER_ERROR_NO_ERROR} or showEntitlementUi argument is false, it just return the - * cached value. Otherwise, a UI-based entitlement check would be performed. It is not - * guaranteed that the UI-based entitlement check will complete in any specific time period - * and may in fact never complete. Any successful entitlement check the platform performs for - * any reason will update the cached value. - * - * @param type the downstream type of tethering. Must be one of - * {@link #TETHERING_WIFI}, - * {@link #TETHERING_USB}, or - * {@link #TETHERING_BLUETOOTH}. - * @param showEntitlementUi a boolean indicating whether to run UI-based entitlement check. - * @param executor the executor on which callback will be invoked. - * @param listener an {@link OnTetheringEntitlementResultListener} which will be called to - * notify the caller of the result of entitlement check. The listener may be called zero - * or one time. - * @deprecated Use {@link TetheringManager#requestLatestTetheringEntitlementResult} instead. - * {@hide} - */ - @SystemApi - @Deprecated - @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) - public void getLatestTetheringEntitlementResult(int type, boolean showEntitlementUi, - @NonNull @CallbackExecutor Executor executor, - @NonNull final OnTetheringEntitlementResultListener listener) { - Preconditions.checkNotNull(listener, "TetheringEntitlementResultListener cannot be null."); - ResultReceiver wrappedListener = new ResultReceiver(null) { - @Override - protected void onReceiveResult(int resultCode, Bundle resultData) { - Binder.withCleanCallingIdentity(() -> - executor.execute(() -> { - listener.onTetheringEntitlementResult(resultCode); - })); - } - }; - - mTetheringManager.requestLatestTetheringEntitlementResult(type, wrappedListener, - showEntitlementUi); - } - - /** - * Report network connectivity status. This is currently used only - * to alter status bar UI. - *

This method requires the caller to hold the permission - * {@link android.Manifest.permission#STATUS_BAR}. - * - * @param networkType The type of network you want to report on - * @param percentage The quality of the connection 0 is bad, 100 is good - * @deprecated Types are deprecated. Use {@link #reportNetworkConnectivity} instead. - * {@hide} - */ - public void reportInetCondition(int networkType, int percentage) { - printStackTrace(); - try { - mService.reportInetCondition(networkType, percentage); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Report a problem network to the framework. This provides a hint to the system - * that there might be connectivity problems on this network and may cause - * the framework to re-evaluate network connectivity and/or switch to another - * network. - * - * @param network The {@link Network} the application was attempting to use - * or {@code null} to indicate the current default network. - * @deprecated Use {@link #reportNetworkConnectivity} which allows reporting both - * working and non-working connectivity. - */ - @Deprecated - public void reportBadNetwork(@Nullable Network network) { - printStackTrace(); - try { - // One of these will be ignored because it matches system's current state. - // The other will trigger the necessary reevaluation. - mService.reportNetworkConnectivity(network, true); - mService.reportNetworkConnectivity(network, false); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Report to the framework whether a network has working connectivity. - * This provides a hint to the system that a particular network is providing - * working connectivity or not. In response the framework may re-evaluate - * the network's connectivity and might take further action thereafter. - * - * @param network The {@link Network} the application was attempting to use - * or {@code null} to indicate the current default network. - * @param hasConnectivity {@code true} if the application was able to successfully access the - * Internet using {@code network} or {@code false} if not. - */ - public void reportNetworkConnectivity(@Nullable Network network, boolean hasConnectivity) { - printStackTrace(); - try { - mService.reportNetworkConnectivity(network, hasConnectivity); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Set a network-independent global http proxy. This is not normally what you want - * for typical HTTP proxies - they are general network dependent. However if you're - * doing something unusual like general internal filtering this may be useful. On - * a private network where the proxy is not accessible, you may break HTTP using this. - * - * @param p A {@link ProxyInfo} object defining the new global - * HTTP proxy. A {@code null} value will clear the global HTTP proxy. - * @hide - */ - @RequiresPermission(android.Manifest.permission.NETWORK_STACK) - public void setGlobalProxy(ProxyInfo p) { - try { - mService.setGlobalProxy(p); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Retrieve any network-independent global HTTP proxy. - * - * @return {@link ProxyInfo} for the current global HTTP proxy or {@code null} - * if no global HTTP proxy is set. - * @hide - */ - public ProxyInfo getGlobalProxy() { - try { - return mService.getGlobalProxy(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Retrieve the global HTTP proxy, or if no global HTTP proxy is set, a - * network-specific HTTP proxy. If {@code network} is null, the - * network-specific proxy returned is the proxy of the default active - * network. - * - * @return {@link ProxyInfo} for the current global HTTP proxy, or if no - * global HTTP proxy is set, {@code ProxyInfo} for {@code network}, - * or when {@code network} is {@code null}, - * the {@code ProxyInfo} for the default active network. Returns - * {@code null} when no proxy applies or the caller doesn't have - * permission to use {@code network}. - * @hide - */ - public ProxyInfo getProxyForNetwork(Network network) { - try { - return mService.getProxyForNetwork(network); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Get the current default HTTP proxy settings. If a global proxy is set it will be returned, - * otherwise if this process is bound to a {@link Network} using - * {@link #bindProcessToNetwork} then that {@code Network}'s proxy is returned, otherwise - * the default network's proxy is returned. - * - * @return the {@link ProxyInfo} for the current HTTP proxy, or {@code null} if no - * HTTP proxy is active. - */ - @Nullable - public ProxyInfo getDefaultProxy() { - return getProxyForNetwork(getBoundNetworkForProcess()); - } - - /** - * Returns true if the hardware supports the given network type - * else it returns false. This doesn't indicate we have coverage - * or are authorized onto a network, just whether or not the - * hardware supports it. For example a GSM phone without a SIM - * should still return {@code true} for mobile data, but a wifi only - * tablet would return {@code false}. - * - * @param networkType The network type we'd like to check - * @return {@code true} if supported, else {@code false} - * @deprecated Types are deprecated. Use {@link NetworkCapabilities} instead. - * @hide - */ - @Deprecated - @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562) - public boolean isNetworkSupported(int networkType) { - try { - return mService.isNetworkSupported(networkType); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Returns if the currently active data network is metered. A network is - * classified as metered when the user is sensitive to heavy data usage on - * that connection due to monetary costs, data limitations or - * battery/performance issues. You should check this before doing large - * data transfers, and warn the user or delay the operation until another - * network is available. - * - * @return {@code true} if large transfers should be avoided, otherwise - * {@code false}. - */ - @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) - public boolean isActiveNetworkMetered() { - try { - return mService.isActiveNetworkMetered(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * If the LockdownVpn mechanism is enabled, updates the vpn - * with a reload of its profile. - * - * @return a boolean with {@code} indicating success - * - *

This method can only be called by the system UID - * {@hide} - */ - public boolean updateLockdownVpn() { - try { - return mService.updateLockdownVpn(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Set sign in error notification to visible or invisible - * - * @hide - * @deprecated Doesn't properly deal with multiple connected networks of the same type. - */ - @Deprecated - public void setProvisioningNotificationVisible(boolean visible, int networkType, - String action) { - try { - mService.setProvisioningNotificationVisible(visible, networkType, action); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Set the value for enabling/disabling airplane mode - * - * @param enable whether to enable airplane mode or not - * - * @hide - */ - @RequiresPermission(anyOf = { - android.Manifest.permission.NETWORK_AIRPLANE_MODE, - android.Manifest.permission.NETWORK_SETTINGS, - android.Manifest.permission.NETWORK_SETUP_WIZARD, - android.Manifest.permission.NETWORK_STACK}) - @SystemApi - public void setAirplaneMode(boolean enable) { - try { - mService.setAirplaneMode(enable); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** {@hide} - returns the factory serial number */ - @UnsupportedAppUsage - @RequiresPermission(anyOf = { - NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, - android.Manifest.permission.NETWORK_FACTORY}) - public int registerNetworkFactory(Messenger messenger, String name) { - try { - return mService.registerNetworkFactory(messenger, name); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** {@hide} */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) - @RequiresPermission(anyOf = { - NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, - android.Manifest.permission.NETWORK_FACTORY}) - public void unregisterNetworkFactory(Messenger messenger) { - try { - mService.unregisterNetworkFactory(messenger); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Registers the specified {@link NetworkProvider}. - * Each listener must only be registered once. The listener can be unregistered with - * {@link #unregisterNetworkProvider}. - * - * @param provider the provider to register - * @return the ID of the provider. This ID must be used by the provider when registering - * {@link android.net.NetworkAgent}s. - * @hide - */ - @SystemApi - @RequiresPermission(anyOf = { - NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, - android.Manifest.permission.NETWORK_FACTORY}) - public int registerNetworkProvider(@NonNull NetworkProvider provider) { - if (provider.getProviderId() != NetworkProvider.ID_NONE) { - throw new IllegalStateException("NetworkProviders can only be registered once"); - } - - try { - int providerId = mService.registerNetworkProvider(provider.getMessenger(), - provider.getName()); - provider.setProviderId(providerId); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - return provider.getProviderId(); - } - - /** - * Unregisters the specified NetworkProvider. - * - * @param provider the provider to unregister - * @hide - */ - @SystemApi - @RequiresPermission(anyOf = { - NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, - android.Manifest.permission.NETWORK_FACTORY}) - public void unregisterNetworkProvider(@NonNull NetworkProvider provider) { - try { - mService.unregisterNetworkProvider(provider.getMessenger()); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - provider.setProviderId(NetworkProvider.ID_NONE); - } - - - /** @hide exposed via the NetworkProvider class. */ - @RequiresPermission(anyOf = { - NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, - android.Manifest.permission.NETWORK_FACTORY}) - public void declareNetworkRequestUnfulfillable(@NonNull NetworkRequest request) { - try { - mService.declareNetworkRequestUnfulfillable(request); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - // TODO : remove this method. It is a stopgap measure to help sheperding a number - // of dependent changes that would conflict throughout the automerger graph. Having this - // temporarily helps with the process of going through with all these dependent changes across - // the entire tree. - /** - * @hide - * Register a NetworkAgent with ConnectivityService. - * @return Network corresponding to NetworkAgent. - */ - @RequiresPermission(anyOf = { - NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, - android.Manifest.permission.NETWORK_FACTORY}) - public Network registerNetworkAgent(INetworkAgent na, NetworkInfo ni, LinkProperties lp, - NetworkCapabilities nc, int score, NetworkAgentConfig config) { - return registerNetworkAgent(na, ni, lp, nc, score, config, NetworkProvider.ID_NONE); - } - - /** - * @hide - * Register a NetworkAgent with ConnectivityService. - * @return Network corresponding to NetworkAgent. - */ - @RequiresPermission(anyOf = { - NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, - android.Manifest.permission.NETWORK_FACTORY}) - public Network registerNetworkAgent(INetworkAgent na, NetworkInfo ni, LinkProperties lp, - NetworkCapabilities nc, int score, NetworkAgentConfig config, int providerId) { - try { - return mService.registerNetworkAgent(na, ni, lp, nc, score, config, providerId); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Base class for {@code NetworkRequest} callbacks. Used for notifications about network - * changes. Should be extended by applications wanting notifications. - * - * A {@code NetworkCallback} is registered by calling - * {@link #requestNetwork(NetworkRequest, NetworkCallback)}, - * {@link #registerNetworkCallback(NetworkRequest, NetworkCallback)}, - * or {@link #registerDefaultNetworkCallback(NetworkCallback)}. A {@code NetworkCallback} is - * unregistered by calling {@link #unregisterNetworkCallback(NetworkCallback)}. - * A {@code NetworkCallback} should be registered at most once at any time. - * A {@code NetworkCallback} that has been unregistered can be registered again. - */ - public static class NetworkCallback { - /** - * Called when the framework connects to a new network to evaluate whether it satisfies this - * request. If evaluation succeeds, this callback may be followed by an {@link #onAvailable} - * callback. There is no guarantee that this new network will satisfy any requests, or that - * the network will stay connected for longer than the time necessary to evaluate it. - *

- * Most applications should not act on this callback, and should instead use - * {@link #onAvailable}. This callback is intended for use by applications that can assist - * the framework in properly evaluating the network — for example, an application that - * can automatically log in to a captive portal without user intervention. - * - * @param network The {@link Network} of the network that is being evaluated. - * - * @hide - */ - public void onPreCheck(@NonNull Network network) {} - - /** - * Called when the framework connects and has declared a new network ready for use. - * This callback may be called more than once if the {@link Network} that is - * satisfying the request changes. - * - * @param network The {@link Network} of the satisfying network. - * @param networkCapabilities The {@link NetworkCapabilities} of the satisfying network. - * @param linkProperties The {@link LinkProperties} of the satisfying network. - * @param blocked Whether access to the {@link Network} is blocked due to system policy. - * @hide - */ - public void onAvailable(@NonNull Network network, - @NonNull NetworkCapabilities networkCapabilities, - @NonNull LinkProperties linkProperties, boolean blocked) { - // Internally only this method is called when a new network is available, and - // it calls the callback in the same way and order that older versions used - // to call so as not to change the behavior. - onAvailable(network); - if (!networkCapabilities.hasCapability( - NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED)) { - onNetworkSuspended(network); - } - onCapabilitiesChanged(network, networkCapabilities); - onLinkPropertiesChanged(network, linkProperties); - onBlockedStatusChanged(network, blocked); - } - - /** - * Called when the framework connects and has declared a new network ready for use. - * - *

For callbacks registered with {@link #registerNetworkCallback}, multiple networks may - * be available at the same time, and onAvailable will be called for each of these as they - * appear. - * - *

For callbacks registered with {@link #requestNetwork} and - * {@link #registerDefaultNetworkCallback}, this means the network passed as an argument - * is the new best network for this request and is now tracked by this callback ; this - * callback will no longer receive method calls about other networks that may have been - * passed to this method previously. The previously-best network may have disconnected, or - * it may still be around and the newly-best network may simply be better. - * - *

Starting with {@link android.os.Build.VERSION_CODES#O}, this will always immediately - * be followed by a call to {@link #onCapabilitiesChanged(Network, NetworkCapabilities)} - * then by a call to {@link #onLinkPropertiesChanged(Network, LinkProperties)}, and a call - * to {@link #onBlockedStatusChanged(Network, boolean)}. - * - *

Do NOT call {@link #getNetworkCapabilities(Network)} or - * {@link #getLinkProperties(Network)} or other synchronous ConnectivityManager methods in - * this callback as this is prone to race conditions (there is no guarantee the objects - * returned by these methods will be current). Instead, wait for a call to - * {@link #onCapabilitiesChanged(Network, NetworkCapabilities)} and - * {@link #onLinkPropertiesChanged(Network, LinkProperties)} whose arguments are guaranteed - * to be well-ordered with respect to other callbacks. - * - * @param network The {@link Network} of the satisfying network. - */ - public void onAvailable(@NonNull Network network) {} - - /** - * Called when the network is about to be lost, typically because there are no outstanding - * requests left for it. This may be paired with a {@link NetworkCallback#onAvailable} call - * with the new replacement network for graceful handover. This method is not guaranteed - * to be called before {@link NetworkCallback#onLost} is called, for example in case a - * network is suddenly disconnected. - * - *

Do NOT call {@link #getNetworkCapabilities(Network)} or - * {@link #getLinkProperties(Network)} or other synchronous ConnectivityManager methods in - * this callback as this is prone to race conditions ; calling these methods while in a - * callback may return an outdated or even a null object. - * - * @param network The {@link Network} that is about to be lost. - * @param maxMsToLive The time in milliseconds the system intends to keep the network - * connected for graceful handover; note that the network may still - * suffer a hard loss at any time. - */ - public void onLosing(@NonNull Network network, int maxMsToLive) {} - - /** - * Called when a network disconnects or otherwise no longer satisfies this request or - * callback. - * - *

If the callback was registered with requestNetwork() or - * registerDefaultNetworkCallback(), it will only be invoked against the last network - * returned by onAvailable() when that network is lost and no other network satisfies - * the criteria of the request. - * - *

If the callback was registered with registerNetworkCallback() it will be called for - * each network which no longer satisfies the criteria of the callback. - * - *

Do NOT call {@link #getNetworkCapabilities(Network)} or - * {@link #getLinkProperties(Network)} or other synchronous ConnectivityManager methods in - * this callback as this is prone to race conditions ; calling these methods while in a - * callback may return an outdated or even a null object. - * - * @param network The {@link Network} lost. - */ - public void onLost(@NonNull Network network) {} - - /** - * Called if no network is found within the timeout time specified in - * {@link #requestNetwork(NetworkRequest, NetworkCallback, int)} call or if the - * requested network request cannot be fulfilled (whether or not a timeout was - * specified). When this callback is invoked the associated - * {@link NetworkRequest} will have already been removed and released, as if - * {@link #unregisterNetworkCallback(NetworkCallback)} had been called. - */ - public void onUnavailable() {} - - /** - * Called when the network corresponding to this request changes capabilities but still - * satisfies the requested criteria. - * - *

Starting with {@link android.os.Build.VERSION_CODES#O} this method is guaranteed - * to be called immediately after {@link #onAvailable}. - * - *

Do NOT call {@link #getLinkProperties(Network)} or other synchronous - * ConnectivityManager methods in this callback as this is prone to race conditions : - * calling these methods while in a callback may return an outdated or even a null object. - * - * @param network The {@link Network} whose capabilities have changed. - * @param networkCapabilities The new {@link android.net.NetworkCapabilities} for this - * network. - */ - public void onCapabilitiesChanged(@NonNull Network network, - @NonNull NetworkCapabilities networkCapabilities) {} - - /** - * Called when the network corresponding to this request changes {@link LinkProperties}. - * - *

Starting with {@link android.os.Build.VERSION_CODES#O} this method is guaranteed - * to be called immediately after {@link #onAvailable}. - * - *

Do NOT call {@link #getNetworkCapabilities(Network)} or other synchronous - * ConnectivityManager methods in this callback as this is prone to race conditions : - * calling these methods while in a callback may return an outdated or even a null object. - * - * @param network The {@link Network} whose link properties have changed. - * @param linkProperties The new {@link LinkProperties} for this network. - */ - public void onLinkPropertiesChanged(@NonNull Network network, - @NonNull LinkProperties linkProperties) {} - - /** - * Called when the network the framework connected to for this request suspends data - * transmission temporarily. - * - *

This generally means that while the TCP connections are still live temporarily - * network data fails to transfer. To give a specific example, this is used on cellular - * networks to mask temporary outages when driving through a tunnel, etc. In general this - * means read operations on sockets on this network will block once the buffers are - * drained, and write operations will block once the buffers are full. - * - *

Do NOT call {@link #getNetworkCapabilities(Network)} or - * {@link #getLinkProperties(Network)} or other synchronous ConnectivityManager methods in - * this callback as this is prone to race conditions (there is no guarantee the objects - * returned by these methods will be current). - * - * @hide - */ - public void onNetworkSuspended(@NonNull Network network) {} - - /** - * Called when the network the framework connected to for this request - * returns from a {@link NetworkInfo.State#SUSPENDED} state. This should always be - * preceded by a matching {@link NetworkCallback#onNetworkSuspended} call. - - *

Do NOT call {@link #getNetworkCapabilities(Network)} or - * {@link #getLinkProperties(Network)} or other synchronous ConnectivityManager methods in - * this callback as this is prone to race conditions : calling these methods while in a - * callback may return an outdated or even a null object. - * - * @hide - */ - public void onNetworkResumed(@NonNull Network network) {} - - /** - * Called when access to the specified network is blocked or unblocked. - * - *

Do NOT call {@link #getNetworkCapabilities(Network)} or - * {@link #getLinkProperties(Network)} or other synchronous ConnectivityManager methods in - * this callback as this is prone to race conditions : calling these methods while in a - * callback may return an outdated or even a null object. - * - * @param network The {@link Network} whose blocked status has changed. - * @param blocked The blocked status of this {@link Network}. - */ - public void onBlockedStatusChanged(@NonNull Network network, boolean blocked) {} - - private NetworkRequest networkRequest; - } - - /** - * Constant error codes used by ConnectivityService to communicate about failures and errors - * across a Binder boundary. - * @hide - */ - public interface Errors { - int TOO_MANY_REQUESTS = 1; - } - - /** @hide */ - public static class TooManyRequestsException extends RuntimeException {} - - private static RuntimeException convertServiceException(ServiceSpecificException e) { - switch (e.errorCode) { - case Errors.TOO_MANY_REQUESTS: - return new TooManyRequestsException(); - default: - Log.w(TAG, "Unknown service error code " + e.errorCode); - return new RuntimeException(e); - } - } - - private static final int BASE = Protocol.BASE_CONNECTIVITY_MANAGER; - /** @hide */ - public static final int CALLBACK_PRECHECK = BASE + 1; - /** @hide */ - public static final int CALLBACK_AVAILABLE = BASE + 2; - /** @hide arg1 = TTL */ - public static final int CALLBACK_LOSING = BASE + 3; - /** @hide */ - public static final int CALLBACK_LOST = BASE + 4; - /** @hide */ - public static final int CALLBACK_UNAVAIL = BASE + 5; - /** @hide */ - public static final int CALLBACK_CAP_CHANGED = BASE + 6; - /** @hide */ - public static final int CALLBACK_IP_CHANGED = BASE + 7; - /** @hide obj = NetworkCapabilities, arg1 = seq number */ - private static final int EXPIRE_LEGACY_REQUEST = BASE + 8; - /** @hide */ - public static final int CALLBACK_SUSPENDED = BASE + 9; - /** @hide */ - public static final int CALLBACK_RESUMED = BASE + 10; - /** @hide */ - public static final int CALLBACK_BLK_CHANGED = BASE + 11; - - /** @hide */ - public static String getCallbackName(int whichCallback) { - switch (whichCallback) { - case CALLBACK_PRECHECK: return "CALLBACK_PRECHECK"; - case CALLBACK_AVAILABLE: return "CALLBACK_AVAILABLE"; - case CALLBACK_LOSING: return "CALLBACK_LOSING"; - case CALLBACK_LOST: return "CALLBACK_LOST"; - case CALLBACK_UNAVAIL: return "CALLBACK_UNAVAIL"; - case CALLBACK_CAP_CHANGED: return "CALLBACK_CAP_CHANGED"; - case CALLBACK_IP_CHANGED: return "CALLBACK_IP_CHANGED"; - case EXPIRE_LEGACY_REQUEST: return "EXPIRE_LEGACY_REQUEST"; - case CALLBACK_SUSPENDED: return "CALLBACK_SUSPENDED"; - case CALLBACK_RESUMED: return "CALLBACK_RESUMED"; - case CALLBACK_BLK_CHANGED: return "CALLBACK_BLK_CHANGED"; - default: - return Integer.toString(whichCallback); - } - } - - private class CallbackHandler extends Handler { - private static final String TAG = "ConnectivityManager.CallbackHandler"; - private static final boolean DBG = false; - - CallbackHandler(Looper looper) { - super(looper); - } - - CallbackHandler(Handler handler) { - this(Preconditions.checkNotNull(handler, "Handler cannot be null.").getLooper()); - } - - @Override - public void handleMessage(Message message) { - if (message.what == EXPIRE_LEGACY_REQUEST) { - expireRequest((NetworkCapabilities) message.obj, message.arg1); - return; - } - - final NetworkRequest request = getObject(message, NetworkRequest.class); - final Network network = getObject(message, Network.class); - final NetworkCallback callback; - synchronized (sCallbacks) { - callback = sCallbacks.get(request); - if (callback == null) { - Log.w(TAG, - "callback not found for " + getCallbackName(message.what) + " message"); - return; - } - if (message.what == CALLBACK_UNAVAIL) { - sCallbacks.remove(request); - callback.networkRequest = ALREADY_UNREGISTERED; - } - } - if (DBG) { - Log.d(TAG, getCallbackName(message.what) + " for network " + network); - } - - switch (message.what) { - case CALLBACK_PRECHECK: { - callback.onPreCheck(network); - break; - } - case CALLBACK_AVAILABLE: { - NetworkCapabilities cap = getObject(message, NetworkCapabilities.class); - LinkProperties lp = getObject(message, LinkProperties.class); - callback.onAvailable(network, cap, lp, message.arg1 != 0); - break; - } - case CALLBACK_LOSING: { - callback.onLosing(network, message.arg1); - break; - } - case CALLBACK_LOST: { - callback.onLost(network); - break; - } - case CALLBACK_UNAVAIL: { - callback.onUnavailable(); - break; - } - case CALLBACK_CAP_CHANGED: { - NetworkCapabilities cap = getObject(message, NetworkCapabilities.class); - callback.onCapabilitiesChanged(network, cap); - break; - } - case CALLBACK_IP_CHANGED: { - LinkProperties lp = getObject(message, LinkProperties.class); - callback.onLinkPropertiesChanged(network, lp); - break; - } - case CALLBACK_SUSPENDED: { - callback.onNetworkSuspended(network); - break; - } - case CALLBACK_RESUMED: { - callback.onNetworkResumed(network); - break; - } - case CALLBACK_BLK_CHANGED: { - boolean blocked = message.arg1 != 0; - callback.onBlockedStatusChanged(network, blocked); - } - } - } - - private T getObject(Message msg, Class c) { - return (T) msg.getData().getParcelable(c.getSimpleName()); - } - } - - private CallbackHandler getDefaultHandler() { - synchronized (sCallbacks) { - if (sCallbackHandler == null) { - sCallbackHandler = new CallbackHandler(ConnectivityThread.getInstanceLooper()); - } - return sCallbackHandler; - } - } - - private static final HashMap sCallbacks = new HashMap<>(); - private static CallbackHandler sCallbackHandler; - - private NetworkRequest sendRequestForNetwork(NetworkCapabilities need, NetworkCallback callback, - int timeoutMs, NetworkRequest.Type reqType, int legacyType, CallbackHandler handler) { - printStackTrace(); - checkCallbackNotNull(callback); - Preconditions.checkArgument( - reqType == TRACK_DEFAULT || need != null, "null NetworkCapabilities"); - final NetworkRequest request; - final String callingPackageName = mContext.getOpPackageName(); - try { - synchronized(sCallbacks) { - if (callback.networkRequest != null - && callback.networkRequest != ALREADY_UNREGISTERED) { - // TODO: throw exception instead and enforce 1:1 mapping of callbacks - // and requests (http://b/20701525). - Log.e(TAG, "NetworkCallback was already registered"); - } - Messenger messenger = new Messenger(handler); - Binder binder = new Binder(); - if (reqType == LISTEN) { - request = mService.listenForNetwork( - need, messenger, binder, callingPackageName); - } else { - request = mService.requestNetwork( - need, reqType.ordinal(), messenger, timeoutMs, binder, legacyType, - callingPackageName, getAttributionTag()); - } - if (request != null) { - sCallbacks.put(request, callback); - } - callback.networkRequest = request; - } - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } catch (ServiceSpecificException e) { - throw convertServiceException(e); - } - return request; - } - - /** - * Helper function to request a network with a particular legacy type. - * - * This API is only for use in internal system code that requests networks with legacy type and - * relies on CONNECTIVITY_ACTION broadcasts instead of NetworkCallbacks. New caller should use - * {@link #requestNetwork(NetworkRequest, NetworkCallback, Handler)} instead. - * - * @param request {@link NetworkRequest} describing this request. - * @param timeoutMs The time in milliseconds to attempt looking for a suitable network - * before {@link NetworkCallback#onUnavailable()} is called. The timeout must - * be a positive value (i.e. >0). - * @param legacyType to specify the network type(#TYPE_*). - * @param handler {@link Handler} to specify the thread upon which the callback will be invoked. - * @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note - * the callback must not be shared - it uniquely specifies this request. - * - * @hide - */ - @SystemApi - @RequiresPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) - public void requestNetwork(@NonNull NetworkRequest request, - int timeoutMs, int legacyType, @NonNull Handler handler, - @NonNull NetworkCallback networkCallback) { - if (legacyType == TYPE_NONE) { - throw new IllegalArgumentException("TYPE_NONE is meaningless legacy type"); - } - CallbackHandler cbHandler = new CallbackHandler(handler); - NetworkCapabilities nc = request.networkCapabilities; - sendRequestForNetwork(nc, networkCallback, timeoutMs, REQUEST, legacyType, cbHandler); - } - - /** - * Request a network to satisfy a set of {@link android.net.NetworkCapabilities}. - * - *

This method will attempt to find the best network that matches the passed - * {@link NetworkRequest}, and to bring up one that does if none currently satisfies the - * criteria. The platform will evaluate which network is the best at its own discretion. - * Throughput, latency, cost per byte, policy, user preference and other considerations - * may be factored in the decision of what is considered the best network. - * - *

As long as this request is outstanding, the platform will try to maintain the best network - * matching this request, while always attempting to match the request to a better network if - * possible. If a better match is found, the platform will switch this request to the now-best - * network and inform the app of the newly best network by invoking - * {@link NetworkCallback#onAvailable(Network)} on the provided callback. Note that the platform - * will not try to maintain any other network than the best one currently matching the request: - * a network not matching any network request may be disconnected at any time. - * - *

For example, an application could use this method to obtain a connected cellular network - * even if the device currently has a data connection over Ethernet. This may cause the cellular - * radio to consume additional power. Or, an application could inform the system that it wants - * a network supporting sending MMSes and have the system let it know about the currently best - * MMS-supporting network through the provided {@link NetworkCallback}. - * - *

The status of the request can be followed by listening to the various callbacks described - * in {@link NetworkCallback}. The {@link Network} object passed to the callback methods can be - * used to direct traffic to the network (although accessing some networks may be subject to - * holding specific permissions). Callers will learn about the specific characteristics of the - * network through - * {@link NetworkCallback#onCapabilitiesChanged(Network, NetworkCapabilities)} and - * {@link NetworkCallback#onLinkPropertiesChanged(Network, LinkProperties)}. The methods of the - * provided {@link NetworkCallback} will only be invoked due to changes in the best network - * matching the request at any given time; therefore when a better network matching the request - * becomes available, the {@link NetworkCallback#onAvailable(Network)} method is called - * with the new network after which no further updates are given about the previously-best - * network, unless it becomes the best again at some later time. All callbacks are invoked - * in order on the same thread, which by default is a thread created by the framework running - * in the app. - * {@see #requestNetwork(NetworkRequest, NetworkCallback, Handler)} to change where the - * callbacks are invoked. - * - *

This{@link NetworkRequest} will live until released via - * {@link #unregisterNetworkCallback(NetworkCallback)} or the calling application exits, at - * which point the system may let go of the network at any time. - * - *

A version of this method which takes a timeout is - * {@link #requestNetwork(NetworkRequest, NetworkCallback, int)}, that an app can use to only - * wait for a limited amount of time for the network to become unavailable. - * - *

It is presently unsupported to request a network with mutable - * {@link NetworkCapabilities} such as - * {@link NetworkCapabilities#NET_CAPABILITY_VALIDATED} or - * {@link NetworkCapabilities#NET_CAPABILITY_CAPTIVE_PORTAL} - * as these {@code NetworkCapabilities} represent states that a particular - * network may never attain, and whether a network will attain these states - * is unknown prior to bringing up the network so the framework does not - * know how to go about satisfying a request with these capabilities. - * - *

This method requires the caller to hold either the - * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission - * or the ability to modify system settings as determined by - * {@link android.provider.Settings.System#canWrite}.

- * - *

To avoid performance issues due to apps leaking callbacks, the system will limit the - * number of outstanding requests to 100 per app (identified by their UID), shared with - * all variants of this method, of {@link #registerNetworkCallback} as well as - * {@link ConnectivityDiagnosticsManager#registerConnectivityDiagnosticsCallback}. - * Requesting a network with this method will count toward this limit. If this limit is - * exceeded, an exception will be thrown. To avoid hitting this issue and to conserve resources, - * make sure to unregister the callbacks with - * {@link #unregisterNetworkCallback(NetworkCallback)}. - * - * @param request {@link NetworkRequest} describing this request. - * @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note - * the callback must not be shared - it uniquely specifies this request. - * The callback is invoked on the default internal Handler. - * @throws IllegalArgumentException if {@code request} contains invalid network capabilities. - * @throws SecurityException if missing the appropriate permissions. - * @throws RuntimeException if the app already has too many callbacks registered. - */ - public void requestNetwork(@NonNull NetworkRequest request, - @NonNull NetworkCallback networkCallback) { - requestNetwork(request, networkCallback, getDefaultHandler()); - } - - /** - * Request a network to satisfy a set of {@link android.net.NetworkCapabilities}. - * - * This method behaves identically to {@link #requestNetwork(NetworkRequest, NetworkCallback)} - * but runs all the callbacks on the passed Handler. - * - *

This method has the same permission requirements as - * {@link #requestNetwork(NetworkRequest, NetworkCallback)}, is subject to the same limitations, - * and throws the same exceptions in the same conditions. - * - * @param request {@link NetworkRequest} describing this request. - * @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note - * the callback must not be shared - it uniquely specifies this request. - * @param handler {@link Handler} to specify the thread upon which the callback will be invoked. - */ - public void requestNetwork(@NonNull NetworkRequest request, - @NonNull NetworkCallback networkCallback, @NonNull Handler handler) { - CallbackHandler cbHandler = new CallbackHandler(handler); - NetworkCapabilities nc = request.networkCapabilities; - sendRequestForNetwork(nc, networkCallback, 0, REQUEST, TYPE_NONE, cbHandler); - } - - /** - * Request a network to satisfy a set of {@link android.net.NetworkCapabilities}, limited - * by a timeout. - * - * This function behaves identically to the non-timed-out version - * {@link #requestNetwork(NetworkRequest, NetworkCallback)}, but if a suitable network - * is not found within the given time (in milliseconds) the - * {@link NetworkCallback#onUnavailable()} callback is called. The request can still be - * released normally by calling {@link #unregisterNetworkCallback(NetworkCallback)} but does - * not have to be released if timed-out (it is automatically released). Unregistering a - * request that timed out is not an error. - * - *

Do not use this method to poll for the existence of specific networks (e.g. with a small - * timeout) - {@link #registerNetworkCallback(NetworkRequest, NetworkCallback)} is provided - * for that purpose. Calling this method will attempt to bring up the requested network. - * - *

This method has the same permission requirements as - * {@link #requestNetwork(NetworkRequest, NetworkCallback)}, is subject to the same limitations, - * and throws the same exceptions in the same conditions. - * - * @param request {@link NetworkRequest} describing this request. - * @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note - * the callback must not be shared - it uniquely specifies this request. - * @param timeoutMs The time in milliseconds to attempt looking for a suitable network - * before {@link NetworkCallback#onUnavailable()} is called. The timeout must - * be a positive value (i.e. >0). - */ - public void requestNetwork(@NonNull NetworkRequest request, - @NonNull NetworkCallback networkCallback, int timeoutMs) { - checkTimeout(timeoutMs); - NetworkCapabilities nc = request.networkCapabilities; - sendRequestForNetwork(nc, networkCallback, timeoutMs, REQUEST, TYPE_NONE, - getDefaultHandler()); - } - - /** - * Request a network to satisfy a set of {@link android.net.NetworkCapabilities}, limited - * by a timeout. - * - * This method behaves identically to - * {@link #requestNetwork(NetworkRequest, NetworkCallback, int)} but runs all the callbacks - * on the passed Handler. - * - *

This method has the same permission requirements as - * {@link #requestNetwork(NetworkRequest, NetworkCallback)}, is subject to the same limitations, - * and throws the same exceptions in the same conditions. - * - * @param request {@link NetworkRequest} describing this request. - * @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note - * the callback must not be shared - it uniquely specifies this request. - * @param handler {@link Handler} to specify the thread upon which the callback will be invoked. - * @param timeoutMs The time in milliseconds to attempt looking for a suitable network - * before {@link NetworkCallback#onUnavailable} is called. - */ - public void requestNetwork(@NonNull NetworkRequest request, - @NonNull NetworkCallback networkCallback, @NonNull Handler handler, int timeoutMs) { - checkTimeout(timeoutMs); - CallbackHandler cbHandler = new CallbackHandler(handler); - NetworkCapabilities nc = request.networkCapabilities; - sendRequestForNetwork(nc, networkCallback, timeoutMs, REQUEST, TYPE_NONE, cbHandler); - } - - /** - * The lookup key for a {@link Network} object included with the intent after - * successfully finding a network for the applications request. Retrieve it with - * {@link android.content.Intent#getParcelableExtra(String)}. - *

- * Note that if you intend to invoke {@link Network#openConnection(java.net.URL)} - * then you must get a ConnectivityManager instance before doing so. - */ - public static final String EXTRA_NETWORK = "android.net.extra.NETWORK"; - - /** - * The lookup key for a {@link NetworkRequest} object included with the intent after - * successfully finding a network for the applications request. Retrieve it with - * {@link android.content.Intent#getParcelableExtra(String)}. - */ - public static final String EXTRA_NETWORK_REQUEST = "android.net.extra.NETWORK_REQUEST"; - - - /** - * Request a network to satisfy a set of {@link android.net.NetworkCapabilities}. - * - * This function behaves identically to the version that takes a NetworkCallback, but instead - * of {@link NetworkCallback} a {@link PendingIntent} is used. This means - * the request may outlive the calling application and get called back when a suitable - * network is found. - *

- * The operation is an Intent broadcast that goes to a broadcast receiver that - * you registered with {@link Context#registerReceiver} or through the - * <receiver> tag in an AndroidManifest.xml file - *

- * The operation Intent is delivered with two extras, a {@link Network} typed - * extra called {@link #EXTRA_NETWORK} and a {@link NetworkRequest} - * typed extra called {@link #EXTRA_NETWORK_REQUEST} containing - * the original requests parameters. It is important to create a new, - * {@link NetworkCallback} based request before completing the processing of the - * Intent to reserve the network or it will be released shortly after the Intent - * is processed. - *

- * If there is already a request for this Intent registered (with the equality of - * two Intents defined by {@link Intent#filterEquals}), then it will be removed and - * replaced by this one, effectively releasing the previous {@link NetworkRequest}. - *

- * The request may be released normally by calling - * {@link #releaseNetworkRequest(android.app.PendingIntent)}. - *

It is presently unsupported to request a network with either - * {@link NetworkCapabilities#NET_CAPABILITY_VALIDATED} or - * {@link NetworkCapabilities#NET_CAPABILITY_CAPTIVE_PORTAL} - * as these {@code NetworkCapabilities} represent states that a particular - * network may never attain, and whether a network will attain these states - * is unknown prior to bringing up the network so the framework does not - * know how to go about satisfying a request with these capabilities. - * - *

To avoid performance issues due to apps leaking callbacks, the system will limit the - * number of outstanding requests to 100 per app (identified by their UID), shared with - * all variants of this method, of {@link #registerNetworkCallback} as well as - * {@link ConnectivityDiagnosticsManager#registerConnectivityDiagnosticsCallback}. - * Requesting a network with this method will count toward this limit. If this limit is - * exceeded, an exception will be thrown. To avoid hitting this issue and to conserve resources, - * make sure to unregister the callbacks with {@link #unregisterNetworkCallback(PendingIntent)} - * or {@link #releaseNetworkRequest(PendingIntent)}. - * - *

This method requires the caller to hold either the - * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission - * or the ability to modify system settings as determined by - * {@link android.provider.Settings.System#canWrite}.

- * - * @param request {@link NetworkRequest} describing this request. - * @param operation Action to perform when the network is available (corresponds - * to the {@link NetworkCallback#onAvailable} call. Typically - * comes from {@link PendingIntent#getBroadcast}. Cannot be null. - * @throws IllegalArgumentException if {@code request} contains invalid network capabilities. - * @throws SecurityException if missing the appropriate permissions. - * @throws RuntimeException if the app already has too many callbacks registered. - */ - public void requestNetwork(@NonNull NetworkRequest request, - @NonNull PendingIntent operation) { - printStackTrace(); - checkPendingIntentNotNull(operation); - try { - mService.pendingRequestForNetwork( - request.networkCapabilities, operation, mContext.getOpPackageName(), - getAttributionTag()); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } catch (ServiceSpecificException e) { - throw convertServiceException(e); - } - } - - /** - * Removes a request made via {@link #requestNetwork(NetworkRequest, android.app.PendingIntent)} - *

- * This method has the same behavior as - * {@link #unregisterNetworkCallback(android.app.PendingIntent)} with respect to - * releasing network resources and disconnecting. - * - * @param operation A PendingIntent equal (as defined by {@link Intent#filterEquals}) to the - * PendingIntent passed to - * {@link #requestNetwork(NetworkRequest, android.app.PendingIntent)} with the - * corresponding NetworkRequest you'd like to remove. Cannot be null. - */ - public void releaseNetworkRequest(@NonNull PendingIntent operation) { - printStackTrace(); - checkPendingIntentNotNull(operation); - try { - mService.releasePendingNetworkRequest(operation); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - private static void checkPendingIntentNotNull(PendingIntent intent) { - Preconditions.checkNotNull(intent, "PendingIntent cannot be null."); - } - - private static void checkCallbackNotNull(NetworkCallback callback) { - Preconditions.checkNotNull(callback, "null NetworkCallback"); - } - - private static void checkTimeout(int timeoutMs) { - Preconditions.checkArgumentPositive(timeoutMs, "timeoutMs must be strictly positive."); - } - - /** - * Registers to receive notifications about all networks which satisfy the given - * {@link NetworkRequest}. The callbacks will continue to be called until - * either the application exits or {@link #unregisterNetworkCallback(NetworkCallback)} is - * called. - * - *

To avoid performance issues due to apps leaking callbacks, the system will limit the - * number of outstanding requests to 100 per app (identified by their UID), shared with - * all variants of this method, of {@link #requestNetwork} as well as - * {@link ConnectivityDiagnosticsManager#registerConnectivityDiagnosticsCallback}. - * Requesting a network with this method will count toward this limit. If this limit is - * exceeded, an exception will be thrown. To avoid hitting this issue and to conserve resources, - * make sure to unregister the callbacks with - * {@link #unregisterNetworkCallback(NetworkCallback)}. - * - * @param request {@link NetworkRequest} describing this request. - * @param networkCallback The {@link NetworkCallback} that the system will call as suitable - * networks change state. - * The callback is invoked on the default internal Handler. - * @throws RuntimeException if the app already has too many callbacks registered. - */ - @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) - public void registerNetworkCallback(@NonNull NetworkRequest request, - @NonNull NetworkCallback networkCallback) { - registerNetworkCallback(request, networkCallback, getDefaultHandler()); - } - - /** - * Registers to receive notifications about all networks which satisfy the given - * {@link NetworkRequest}. The callbacks will continue to be called until - * either the application exits or {@link #unregisterNetworkCallback(NetworkCallback)} is - * called. - * - *

To avoid performance issues due to apps leaking callbacks, the system will limit the - * number of outstanding requests to 100 per app (identified by their UID), shared with - * all variants of this method, of {@link #requestNetwork} as well as - * {@link ConnectivityDiagnosticsManager#registerConnectivityDiagnosticsCallback}. - * Requesting a network with this method will count toward this limit. If this limit is - * exceeded, an exception will be thrown. To avoid hitting this issue and to conserve resources, - * make sure to unregister the callbacks with - * {@link #unregisterNetworkCallback(NetworkCallback)}. - * - * - * @param request {@link NetworkRequest} describing this request. - * @param networkCallback The {@link NetworkCallback} that the system will call as suitable - * networks change state. - * @param handler {@link Handler} to specify the thread upon which the callback will be invoked. - * @throws RuntimeException if the app already has too many callbacks registered. - */ - @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) - public void registerNetworkCallback(@NonNull NetworkRequest request, - @NonNull NetworkCallback networkCallback, @NonNull Handler handler) { - CallbackHandler cbHandler = new CallbackHandler(handler); - NetworkCapabilities nc = request.networkCapabilities; - sendRequestForNetwork(nc, networkCallback, 0, LISTEN, TYPE_NONE, cbHandler); - } - - /** - * Registers a PendingIntent to be sent when a network is available which satisfies the given - * {@link NetworkRequest}. - * - * This function behaves identically to the version that takes a NetworkCallback, but instead - * of {@link NetworkCallback} a {@link PendingIntent} is used. This means - * the request may outlive the calling application and get called back when a suitable - * network is found. - *

- * The operation is an Intent broadcast that goes to a broadcast receiver that - * you registered with {@link Context#registerReceiver} or through the - * <receiver> tag in an AndroidManifest.xml file - *

- * The operation Intent is delivered with two extras, a {@link Network} typed - * extra called {@link #EXTRA_NETWORK} and a {@link NetworkRequest} - * typed extra called {@link #EXTRA_NETWORK_REQUEST} containing - * the original requests parameters. - *

- * If there is already a request for this Intent registered (with the equality of - * two Intents defined by {@link Intent#filterEquals}), then it will be removed and - * replaced by this one, effectively releasing the previous {@link NetworkRequest}. - *

- * The request may be released normally by calling - * {@link #unregisterNetworkCallback(android.app.PendingIntent)}. - * - *

To avoid performance issues due to apps leaking callbacks, the system will limit the - * number of outstanding requests to 100 per app (identified by their UID), shared with - * all variants of this method, of {@link #requestNetwork} as well as - * {@link ConnectivityDiagnosticsManager#registerConnectivityDiagnosticsCallback}. - * Requesting a network with this method will count toward this limit. If this limit is - * exceeded, an exception will be thrown. To avoid hitting this issue and to conserve resources, - * make sure to unregister the callbacks with {@link #unregisterNetworkCallback(PendingIntent)} - * or {@link #releaseNetworkRequest(PendingIntent)}. - * - * @param request {@link NetworkRequest} describing this request. - * @param operation Action to perform when the network is available (corresponds - * to the {@link NetworkCallback#onAvailable} call. Typically - * comes from {@link PendingIntent#getBroadcast}. Cannot be null. - * @throws RuntimeException if the app already has too many callbacks registered. - */ - @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) - public void registerNetworkCallback(@NonNull NetworkRequest request, - @NonNull PendingIntent operation) { - printStackTrace(); - checkPendingIntentNotNull(operation); - try { - mService.pendingListenForNetwork( - request.networkCapabilities, operation, mContext.getOpPackageName()); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } catch (ServiceSpecificException e) { - throw convertServiceException(e); - } - } - - /** - * Registers to receive notifications about changes in the system default network. The callbacks - * will continue to be called until either the application exits or - * {@link #unregisterNetworkCallback(NetworkCallback)} is called. - * - *

To avoid performance issues due to apps leaking callbacks, the system will limit the - * number of outstanding requests to 100 per app (identified by their UID), shared with - * all variants of this method, of {@link #requestNetwork} as well as - * {@link ConnectivityDiagnosticsManager#registerConnectivityDiagnosticsCallback}. - * Requesting a network with this method will count toward this limit. If this limit is - * exceeded, an exception will be thrown. To avoid hitting this issue and to conserve resources, - * make sure to unregister the callbacks with - * {@link #unregisterNetworkCallback(NetworkCallback)}. - * - * @param networkCallback The {@link NetworkCallback} that the system will call as the - * system default network changes. - * The callback is invoked on the default internal Handler. - * @throws RuntimeException if the app already has too many callbacks registered. - */ - @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) - public void registerDefaultNetworkCallback(@NonNull NetworkCallback networkCallback) { - registerDefaultNetworkCallback(networkCallback, getDefaultHandler()); - } - - /** - * Registers to receive notifications about changes in the system default network. The callbacks - * will continue to be called until either the application exits or - * {@link #unregisterNetworkCallback(NetworkCallback)} is called. - * - *

To avoid performance issues due to apps leaking callbacks, the system will limit the - * number of outstanding requests to 100 per app (identified by their UID), shared with - * all variants of this method, of {@link #requestNetwork} as well as - * {@link ConnectivityDiagnosticsManager#registerConnectivityDiagnosticsCallback}. - * Requesting a network with this method will count toward this limit. If this limit is - * exceeded, an exception will be thrown. To avoid hitting this issue and to conserve resources, - * make sure to unregister the callbacks with - * {@link #unregisterNetworkCallback(NetworkCallback)}. - * - * @param networkCallback The {@link NetworkCallback} that the system will call as the - * system default network changes. - * @param handler {@link Handler} to specify the thread upon which the callback will be invoked. - * @throws RuntimeException if the app already has too many callbacks registered. - */ - @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) - public void registerDefaultNetworkCallback(@NonNull NetworkCallback networkCallback, - @NonNull Handler handler) { - // This works because if the NetworkCapabilities are null, - // ConnectivityService takes them from the default request. - // - // Since the capabilities are exactly the same as the default request's - // capabilities, this request is guaranteed, at all times, to be - // satisfied by the same network, if any, that satisfies the default - // request, i.e., the system default network. - CallbackHandler cbHandler = new CallbackHandler(handler); - sendRequestForNetwork(null /* NetworkCapabilities need */, networkCallback, 0, - TRACK_DEFAULT, TYPE_NONE, cbHandler); - } - - /** - * Requests bandwidth update for a given {@link Network} and returns whether the update request - * is accepted by ConnectivityService. Once accepted, ConnectivityService will poll underlying - * network connection for updated bandwidth information. The caller will be notified via - * {@link ConnectivityManager.NetworkCallback} if there is an update. Notice that this - * method assumes that the caller has previously called - * {@link #registerNetworkCallback(NetworkRequest, NetworkCallback)} to listen for network - * changes. - * - * @param network {@link Network} specifying which network you're interested. - * @return {@code true} on success, {@code false} if the {@link Network} is no longer valid. - */ - public boolean requestBandwidthUpdate(@NonNull Network network) { - try { - return mService.requestBandwidthUpdate(network); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Unregisters a {@code NetworkCallback} and possibly releases networks originating from - * {@link #requestNetwork(NetworkRequest, NetworkCallback)} and - * {@link #registerNetworkCallback(NetworkRequest, NetworkCallback)} calls. - * If the given {@code NetworkCallback} had previously been used with - * {@code #requestNetwork}, any networks that had been connected to only to satisfy that request - * will be disconnected. - * - * Notifications that would have triggered that {@code NetworkCallback} will immediately stop - * triggering it as soon as this call returns. - * - * @param networkCallback The {@link NetworkCallback} used when making the request. - */ - public void unregisterNetworkCallback(@NonNull NetworkCallback networkCallback) { - printStackTrace(); - checkCallbackNotNull(networkCallback); - final List reqs = new ArrayList<>(); - // Find all requests associated to this callback and stop callback triggers immediately. - // Callback is reusable immediately. http://b/20701525, http://b/35921499. - synchronized (sCallbacks) { - Preconditions.checkArgument(networkCallback.networkRequest != null, - "NetworkCallback was not registered"); - if (networkCallback.networkRequest == ALREADY_UNREGISTERED) { - Log.d(TAG, "NetworkCallback was already unregistered"); - return; - } - for (Map.Entry e : sCallbacks.entrySet()) { - if (e.getValue() == networkCallback) { - reqs.add(e.getKey()); - } - } - // TODO: throw exception if callback was registered more than once (http://b/20701525). - for (NetworkRequest r : reqs) { - try { - mService.releaseNetworkRequest(r); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - // Only remove mapping if rpc was successful. - sCallbacks.remove(r); - } - networkCallback.networkRequest = ALREADY_UNREGISTERED; - } - } - - /** - * Unregisters a callback previously registered via - * {@link #registerNetworkCallback(NetworkRequest, android.app.PendingIntent)}. - * - * @param operation A PendingIntent equal (as defined by {@link Intent#filterEquals}) to the - * PendingIntent passed to - * {@link #registerNetworkCallback(NetworkRequest, android.app.PendingIntent)}. - * Cannot be null. - */ - public void unregisterNetworkCallback(@NonNull PendingIntent operation) { - releaseNetworkRequest(operation); - } - - /** - * Informs the system whether it should switch to {@code network} regardless of whether it is - * validated or not. If {@code accept} is true, and the network was explicitly selected by the - * user (e.g., by selecting a Wi-Fi network in the Settings app), then the network will become - * the system default network regardless of any other network that's currently connected. If - * {@code always} is true, then the choice is remembered, so that the next time the user - * connects to this network, the system will switch to it. - * - * @param network The network to accept. - * @param accept Whether to accept the network even if unvalidated. - * @param always Whether to remember this choice in the future. - * - * @hide - */ - @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) - public void setAcceptUnvalidated(Network network, boolean accept, boolean always) { - try { - mService.setAcceptUnvalidated(network, accept, always); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Informs the system whether it should consider the network as validated even if it only has - * partial connectivity. If {@code accept} is true, then the network will be considered as - * validated even if connectivity is only partial. If {@code always} is true, then the choice - * is remembered, so that the next time the user connects to this network, the system will - * switch to it. - * - * @param network The network to accept. - * @param accept Whether to consider the network as validated even if it has partial - * connectivity. - * @param always Whether to remember this choice in the future. - * - * @hide - */ - @RequiresPermission(android.Manifest.permission.NETWORK_STACK) - public void setAcceptPartialConnectivity(Network network, boolean accept, boolean always) { - try { - mService.setAcceptPartialConnectivity(network, accept, always); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Informs the system to penalize {@code network}'s score when it becomes unvalidated. This is - * only meaningful if the system is configured not to penalize such networks, e.g., if the - * {@code config_networkAvoidBadWifi} configuration variable is set to 0 and the {@code - * NETWORK_AVOID_BAD_WIFI setting is unset}. - * - * @param network The network to accept. - * - * @hide - */ - @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) - public void setAvoidUnvalidated(Network network) { - try { - mService.setAvoidUnvalidated(network); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Requests that the system open the captive portal app on the specified network. - * - * @param network The network to log into. - * - * @hide - */ - @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) - public void startCaptivePortalApp(Network network) { - try { - mService.startCaptivePortalApp(network); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Requests that the system open the captive portal app with the specified extras. - * - *

This endpoint is exclusively for use by the NetworkStack and is protected by the - * corresponding permission. - * @param network Network on which the captive portal was detected. - * @param appExtras Extras to include in the app start intent. - * @hide - */ - @SystemApi - @RequiresPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) - public void startCaptivePortalApp(@NonNull Network network, @NonNull Bundle appExtras) { - try { - mService.startCaptivePortalAppInternal(network, appExtras); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Determine whether the device is configured to avoid bad wifi. - * @hide - */ - @SystemApi - @RequiresPermission(anyOf = { - NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, - android.Manifest.permission.NETWORK_STACK}) - public boolean shouldAvoidBadWifi() { - try { - return mService.shouldAvoidBadWifi(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * It is acceptable to briefly use multipath data to provide seamless connectivity for - * time-sensitive user-facing operations when the system default network is temporarily - * unresponsive. The amount of data should be limited (less than one megabyte for every call to - * this method), and the operation should be infrequent to ensure that data usage is limited. - * - * An example of such an operation might be a time-sensitive foreground activity, such as a - * voice command, that the user is performing while walking out of range of a Wi-Fi network. - */ - public static final int MULTIPATH_PREFERENCE_HANDOVER = 1 << 0; - - /** - * It is acceptable to use small amounts of multipath data on an ongoing basis to provide - * a backup channel for traffic that is primarily going over another network. - * - * An example might be maintaining backup connections to peers or servers for the purpose of - * fast fallback if the default network is temporarily unresponsive or disconnects. The traffic - * on backup paths should be negligible compared to the traffic on the main path. - */ - public static final int MULTIPATH_PREFERENCE_RELIABILITY = 1 << 1; - - /** - * It is acceptable to use metered data to improve network latency and performance. - */ - public static final int MULTIPATH_PREFERENCE_PERFORMANCE = 1 << 2; - - /** - * Return value to use for unmetered networks. On such networks we currently set all the flags - * to true. - * @hide - */ - public static final int MULTIPATH_PREFERENCE_UNMETERED = - MULTIPATH_PREFERENCE_HANDOVER | - MULTIPATH_PREFERENCE_RELIABILITY | - MULTIPATH_PREFERENCE_PERFORMANCE; - - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(flag = true, value = { - MULTIPATH_PREFERENCE_HANDOVER, - MULTIPATH_PREFERENCE_RELIABILITY, - MULTIPATH_PREFERENCE_PERFORMANCE, - }) - public @interface MultipathPreference { - } - - /** - * Provides a hint to the calling application on whether it is desirable to use the - * multinetwork APIs (e.g., {@link Network#openConnection}, {@link Network#bindSocket}, etc.) - * for multipath data transfer on this network when it is not the system default network. - * Applications desiring to use multipath network protocols should call this method before - * each such operation. - * - * @param network The network on which the application desires to use multipath data. - * If {@code null}, this method will return the a preference that will generally - * apply to metered networks. - * @return a bitwise OR of zero or more of the {@code MULTIPATH_PREFERENCE_*} constants. - */ - @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) - public @MultipathPreference int getMultipathPreference(@Nullable Network network) { - try { - return mService.getMultipathPreference(network); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Resets all connectivity manager settings back to factory defaults. - * @hide - */ - @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) - public void factoryReset() { - try { - mService.factoryReset(); - mTetheringManager.stopAllTethering(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Binds the current process to {@code network}. All Sockets created in the future - * (and not explicitly bound via a bound SocketFactory from - * {@link Network#getSocketFactory() Network.getSocketFactory()}) will be bound to - * {@code network}. All host name resolutions will be limited to {@code network} as well. - * Note that if {@code network} ever disconnects, all Sockets created in this way will cease to - * work and all host name resolutions will fail. This is by design so an application doesn't - * accidentally use Sockets it thinks are still bound to a particular {@link Network}. - * To clear binding pass {@code null} for {@code network}. Using individually bound - * Sockets created by Network.getSocketFactory().createSocket() and - * performing network-specific host name resolutions via - * {@link Network#getAllByName Network.getAllByName} is preferred to calling - * {@code bindProcessToNetwork}. - * - * @param network The {@link Network} to bind the current process to, or {@code null} to clear - * the current binding. - * @return {@code true} on success, {@code false} if the {@link Network} is no longer valid. - */ - public boolean bindProcessToNetwork(@Nullable Network network) { - // Forcing callers to call through non-static function ensures ConnectivityManager - // instantiated. - return setProcessDefaultNetwork(network); - } - - /** - * Binds the current process to {@code network}. All Sockets created in the future - * (and not explicitly bound via a bound SocketFactory from - * {@link Network#getSocketFactory() Network.getSocketFactory()}) will be bound to - * {@code network}. All host name resolutions will be limited to {@code network} as well. - * Note that if {@code network} ever disconnects, all Sockets created in this way will cease to - * work and all host name resolutions will fail. This is by design so an application doesn't - * accidentally use Sockets it thinks are still bound to a particular {@link Network}. - * To clear binding pass {@code null} for {@code network}. Using individually bound - * Sockets created by Network.getSocketFactory().createSocket() and - * performing network-specific host name resolutions via - * {@link Network#getAllByName Network.getAllByName} is preferred to calling - * {@code setProcessDefaultNetwork}. - * - * @param network The {@link Network} to bind the current process to, or {@code null} to clear - * the current binding. - * @return {@code true} on success, {@code false} if the {@link Network} is no longer valid. - * @deprecated This function can throw {@link IllegalStateException}. Use - * {@link #bindProcessToNetwork} instead. {@code bindProcessToNetwork} - * is a direct replacement. - */ - @Deprecated - public static boolean setProcessDefaultNetwork(@Nullable Network network) { - int netId = (network == null) ? NETID_UNSET : network.netId; - boolean isSameNetId = (netId == NetworkUtils.getBoundNetworkForProcess()); - - if (netId != NETID_UNSET) { - netId = network.getNetIdForResolv(); - } - - if (!NetworkUtils.bindProcessToNetwork(netId)) { - return false; - } - - if (!isSameNetId) { - // Set HTTP proxy system properties to match network. - // TODO: Deprecate this static method and replace it with a non-static version. - try { - Proxy.setHttpProxySystemProperty(getInstance().getDefaultProxy()); - } catch (SecurityException e) { - // The process doesn't have ACCESS_NETWORK_STATE, so we can't fetch the proxy. - Log.e(TAG, "Can't set proxy properties", e); - } - // Must flush DNS cache as new network may have different DNS resolutions. - InetAddress.clearDnsCache(); - // Must flush socket pool as idle sockets will be bound to previous network and may - // cause subsequent fetches to be performed on old network. - NetworkEventDispatcher.getInstance().onNetworkConfigurationChanged(); - } - - return true; - } - - /** - * Returns the {@link Network} currently bound to this process via - * {@link #bindProcessToNetwork}, or {@code null} if no {@link Network} is explicitly bound. - * - * @return {@code Network} to which this process is bound, or {@code null}. - */ - @Nullable - public Network getBoundNetworkForProcess() { - // Forcing callers to call thru non-static function ensures ConnectivityManager - // instantiated. - return getProcessDefaultNetwork(); - } - - /** - * Returns the {@link Network} currently bound to this process via - * {@link #bindProcessToNetwork}, or {@code null} if no {@link Network} is explicitly bound. - * - * @return {@code Network} to which this process is bound, or {@code null}. - * @deprecated Using this function can lead to other functions throwing - * {@link IllegalStateException}. Use {@link #getBoundNetworkForProcess} instead. - * {@code getBoundNetworkForProcess} is a direct replacement. - */ - @Deprecated - @Nullable - public static Network getProcessDefaultNetwork() { - int netId = NetworkUtils.getBoundNetworkForProcess(); - if (netId == NETID_UNSET) return null; - return new Network(netId); - } - - private void unsupportedStartingFrom(int version) { - if (Process.myUid() == Process.SYSTEM_UID) { - // The getApplicationInfo() call we make below is not supported in system context. Let - // the call through here, and rely on the fact that ConnectivityService will refuse to - // allow the system to use these APIs anyway. - return; - } - - if (mContext.getApplicationInfo().targetSdkVersion >= version) { - throw new UnsupportedOperationException( - "This method is not supported in target SDK version " + version + " and above"); - } - } - - // Checks whether the calling app can use the legacy routing API (startUsingNetworkFeature, - // stopUsingNetworkFeature, requestRouteToHost), and if not throw UnsupportedOperationException. - // TODO: convert the existing system users (Tethering, GnssLocationProvider) to the new APIs and - // remove these exemptions. Note that this check is not secure, and apps can still access these - // functions by accessing ConnectivityService directly. However, it should be clear that doing - // so is unsupported and may break in the future. http://b/22728205 - private void checkLegacyRoutingApiAccess() { - unsupportedStartingFrom(VERSION_CODES.M); - } - - /** - * Binds host resolutions performed by this process to {@code network}. - * {@link #bindProcessToNetwork} takes precedence over this setting. - * - * @param network The {@link Network} to bind host resolutions from the current process to, or - * {@code null} to clear the current binding. - * @return {@code true} on success, {@code false} if the {@link Network} is no longer valid. - * @hide - * @deprecated This is strictly for legacy usage to support {@link #startUsingNetworkFeature}. - */ - @Deprecated - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public static boolean setProcessDefaultNetworkForHostResolution(Network network) { - return NetworkUtils.bindProcessToNetworkForHostResolution( - (network == null) ? NETID_UNSET : network.getNetIdForResolv()); - } - - /** - * Device is not restricting metered network activity while application is running on - * background. - */ - public static final int RESTRICT_BACKGROUND_STATUS_DISABLED = 1; - - /** - * Device is restricting metered network activity while application is running on background, - * but application is allowed to bypass it. - *

- * In this state, application should take action to mitigate metered network access. - * For example, a music streaming application should switch to a low-bandwidth bitrate. - */ - public static final int RESTRICT_BACKGROUND_STATUS_WHITELISTED = 2; - - /** - * Device is restricting metered network activity while application is running on background. - *

- * In this state, application should not try to use the network while running on background, - * because it would be denied. - */ - public static final int RESTRICT_BACKGROUND_STATUS_ENABLED = 3; - - /** - * A change in the background metered network activity restriction has occurred. - *

- * Applications should call {@link #getRestrictBackgroundStatus()} to check if the restriction - * applies to them. - *

- * This is only sent to registered receivers, not manifest receivers. - */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_RESTRICT_BACKGROUND_CHANGED = - "android.net.conn.RESTRICT_BACKGROUND_CHANGED"; - - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(flag = false, value = { - RESTRICT_BACKGROUND_STATUS_DISABLED, - RESTRICT_BACKGROUND_STATUS_WHITELISTED, - RESTRICT_BACKGROUND_STATUS_ENABLED, - }) - public @interface RestrictBackgroundStatus { - } - - private INetworkPolicyManager getNetworkPolicyManager() { - synchronized (this) { - if (mNPManager != null) { - return mNPManager; - } - mNPManager = INetworkPolicyManager.Stub.asInterface(ServiceManager - .getService(Context.NETWORK_POLICY_SERVICE)); - return mNPManager; - } - } - - /** - * Determines if the calling application is subject to metered network restrictions while - * running on background. - * - * @return {@link #RESTRICT_BACKGROUND_STATUS_DISABLED}, - * {@link #RESTRICT_BACKGROUND_STATUS_ENABLED}, - * or {@link #RESTRICT_BACKGROUND_STATUS_WHITELISTED} - */ - public @RestrictBackgroundStatus int getRestrictBackgroundStatus() { - try { - return getNetworkPolicyManager().getRestrictBackgroundByCaller(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * The network watchlist is a list of domains and IP addresses that are associated with - * potentially harmful apps. This method returns the SHA-256 of the watchlist config file - * currently used by the system for validation purposes. - * - * @return Hash of network watchlist config file. Null if config does not exist. - */ - @Nullable - public byte[] getNetworkWatchlistConfigHash() { - try { - return mService.getNetworkWatchlistConfigHash(); - } catch (RemoteException e) { - Log.e(TAG, "Unable to get watchlist config hash"); - throw e.rethrowFromSystemServer(); - } - } - - /** - * Returns the {@code uid} of the owner of a network connection. - * - * @param protocol The protocol of the connection. Only {@code IPPROTO_TCP} and {@code - * IPPROTO_UDP} currently supported. - * @param local The local {@link InetSocketAddress} of a connection. - * @param remote The remote {@link InetSocketAddress} of a connection. - * @return {@code uid} if the connection is found and the app has permission to observe it - * (e.g., if it is associated with the calling VPN app's VpnService tunnel) or {@link - * android.os.Process#INVALID_UID} if the connection is not found. - * @throws {@link SecurityException} if the caller is not the active VpnService for the current - * user. - * @throws {@link IllegalArgumentException} if an unsupported protocol is requested. - */ - public int getConnectionOwnerUid( - int protocol, @NonNull InetSocketAddress local, @NonNull InetSocketAddress remote) { - ConnectionInfo connectionInfo = new ConnectionInfo(protocol, local, remote); - try { - return mService.getConnectionOwnerUid(connectionInfo); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - private void printStackTrace() { - if (DEBUG) { - final StackTraceElement[] callStack = Thread.currentThread().getStackTrace(); - final StringBuffer sb = new StringBuffer(); - for (int i = 3; i < callStack.length; i++) { - final String stackTrace = callStack[i].toString(); - if (stackTrace == null || stackTrace.contains("android.os")) { - break; - } - sb.append(" [").append(stackTrace).append("]"); - } - Log.d(TAG, "StackLog:" + sb.toString()); - } - } - - /** - * Simulates a Data Stall for the specified Network. - * - *

This method should only be used for tests. - * - *

The caller must be the owner of the specified Network. - * - * @param detectionMethod The detection method used to identify the Data Stall. - * @param timestampMillis The timestamp at which the stall 'occurred', in milliseconds. - * @param network The Network for which a Data Stall is being simluated. - * @param extras The PersistableBundle of extras included in the Data Stall notification. - * @throws SecurityException if the caller is not the owner of the given network. - * @hide - */ - @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) - @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_TEST_NETWORKS, - android.Manifest.permission.NETWORK_STACK}) - public void simulateDataStall(int detectionMethod, long timestampMillis, - @NonNull Network network, @NonNull PersistableBundle extras) { - try { - mService.simulateDataStall(detectionMethod, timestampMillis, network, extras); - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } - } - - private void setOemNetworkPreference(@NonNull OemNetworkPreferences preference) { - Log.d(TAG, "setOemNetworkPreference called with preference: " - + preference.toString()); - } - - @NonNull - private final List mQosCallbackConnections = new ArrayList<>(); - - /** - * Registers a {@link QosSocketInfo} with an associated {@link QosCallback}. The callback will - * receive available QoS events related to the {@link Network} and local ip + port - * specified within socketInfo. - *

- * The same {@link QosCallback} must be unregistered before being registered a second time, - * otherwise {@link QosCallbackRegistrationException} is thrown. - *

- * This API does not, in itself, require any permission if called with a network that is not - * restricted. However, the underlying implementation currently only supports the IMS network, - * which is always restricted. That means non-preinstalled callers can't possibly find this API - * useful, because they'd never be called back on networks that they would have access to. - * - * @throws SecurityException if {@link QosSocketInfo#getNetwork()} is restricted and the app is - * missing CONNECTIVITY_USE_RESTRICTED_NETWORKS permission. - * @throws QosCallback.QosCallbackRegistrationException if qosCallback is already registered. - * @throws RuntimeException if the app already has too many callbacks registered. - * - * Exceptions after the time of registration is passed through - * {@link QosCallback#onError(QosCallbackException)}. see: {@link QosCallbackException}. - * - * @param socketInfo the socket information used to match QoS events - * @param callback receives qos events that satisfy socketInfo - * @param executor The executor on which the callback will be invoked. The provided - * {@link Executor} must run callback sequentially, otherwise the order of - * callbacks cannot be guaranteed. - * - * @hide - */ - @SystemApi - public void registerQosCallback(@NonNull final QosSocketInfo socketInfo, - @NonNull final QosCallback callback, - @CallbackExecutor @NonNull final Executor executor) { - Objects.requireNonNull(socketInfo, "socketInfo must be non-null"); - Objects.requireNonNull(callback, "callback must be non-null"); - Objects.requireNonNull(executor, "executor must be non-null"); - - try { - synchronized (mQosCallbackConnections) { - if (getQosCallbackConnection(callback) == null) { - final QosCallbackConnection connection = - new QosCallbackConnection(this, callback, executor); - mQosCallbackConnections.add(connection); - mService.registerQosSocketCallback(socketInfo, connection); - } else { - Log.e(TAG, "registerQosCallback: Callback already registered"); - throw new QosCallbackRegistrationException(); - } - } - } catch (final RemoteException e) { - Log.e(TAG, "registerQosCallback: Error while registering ", e); - - // The same unregister method method is called for consistency even though nothing - // will be sent to the ConnectivityService since the callback was never successfully - // registered. - unregisterQosCallback(callback); - e.rethrowFromSystemServer(); - } catch (final ServiceSpecificException e) { - Log.e(TAG, "registerQosCallback: Error while registering ", e); - unregisterQosCallback(callback); - throw convertServiceException(e); - } - } - - /** - * Unregisters the given {@link QosCallback}. The {@link QosCallback} will no longer receive - * events once unregistered and can be registered a second time. - *

- * If the {@link QosCallback} does not have an active registration, it is a no-op. - * - * @param callback the callback being unregistered - * - * @hide - */ - @SystemApi - public void unregisterQosCallback(@NonNull final QosCallback callback) { - Objects.requireNonNull(callback, "The callback must be non-null"); - try { - synchronized (mQosCallbackConnections) { - final QosCallbackConnection connection = getQosCallbackConnection(callback); - if (connection != null) { - connection.stopReceivingMessages(); - mService.unregisterQosCallback(connection); - mQosCallbackConnections.remove(connection); - } else { - Log.d(TAG, "unregisterQosCallback: Callback not registered"); - } - } - } catch (final RemoteException e) { - Log.e(TAG, "unregisterQosCallback: Error while unregistering ", e); - e.rethrowFromSystemServer(); - } - } - - /** - * Gets the connection related to the callback. - * - * @param callback the callback to look up - * @return the related connection - */ - @Nullable - private QosCallbackConnection getQosCallbackConnection(final QosCallback callback) { - for (final QosCallbackConnection connection : mQosCallbackConnections) { - // Checking by reference here is intentional - if (connection.getCallback() == callback) { - return connection; - } - } - return null; - } - - /** - * Request a network to satisfy a set of {@link android.net.NetworkCapabilities}, but - * does not cause any networks to retain the NET_CAPABILITY_FOREGROUND capability. This can - * be used to request that the system provide a network without causing the network to be - * in the foreground. - * - *

This method will attempt to find the best network that matches the passed - * {@link NetworkRequest}, and to bring up one that does if none currently satisfies the - * criteria. The platform will evaluate which network is the best at its own discretion. - * Throughput, latency, cost per byte, policy, user preference and other considerations - * may be factored in the decision of what is considered the best network. - * - *

As long as this request is outstanding, the platform will try to maintain the best network - * matching this request, while always attempting to match the request to a better network if - * possible. If a better match is found, the platform will switch this request to the now-best - * network and inform the app of the newly best network by invoking - * {@link NetworkCallback#onAvailable(Network)} on the provided callback. Note that the platform - * will not try to maintain any other network than the best one currently matching the request: - * a network not matching any network request may be disconnected at any time. - * - *

For example, an application could use this method to obtain a connected cellular network - * even if the device currently has a data connection over Ethernet. This may cause the cellular - * radio to consume additional power. Or, an application could inform the system that it wants - * a network supporting sending MMSes and have the system let it know about the currently best - * MMS-supporting network through the provided {@link NetworkCallback}. - * - *

The status of the request can be followed by listening to the various callbacks described - * in {@link NetworkCallback}. The {@link Network} object passed to the callback methods can be - * used to direct traffic to the network (although accessing some networks may be subject to - * holding specific permissions). Callers will learn about the specific characteristics of the - * network through - * {@link NetworkCallback#onCapabilitiesChanged(Network, NetworkCapabilities)} and - * {@link NetworkCallback#onLinkPropertiesChanged(Network, LinkProperties)}. The methods of the - * provided {@link NetworkCallback} will only be invoked due to changes in the best network - * matching the request at any given time; therefore when a better network matching the request - * becomes available, the {@link NetworkCallback#onAvailable(Network)} method is called - * with the new network after which no further updates are given about the previously-best - * network, unless it becomes the best again at some later time. All callbacks are invoked - * in order on the same thread, which by default is a thread created by the framework running - * in the app. - * - *

This{@link NetworkRequest} will live until released via - * {@link #unregisterNetworkCallback(NetworkCallback)} or the calling application exits, at - * which point the system may let go of the network at any time. - * - *

It is presently unsupported to request a network with mutable - * {@link NetworkCapabilities} such as - * {@link NetworkCapabilities#NET_CAPABILITY_VALIDATED} or - * {@link NetworkCapabilities#NET_CAPABILITY_CAPTIVE_PORTAL} - * as these {@code NetworkCapabilities} represent states that a particular - * network may never attain, and whether a network will attain these states - * is unknown prior to bringing up the network so the framework does not - * know how to go about satisfying a request with these capabilities. - * - *

To avoid performance issues due to apps leaking callbacks, the system will limit the - * number of outstanding requests to 100 per app (identified by their UID), shared with - * all variants of this method, of {@link #registerNetworkCallback} as well as - * {@link ConnectivityDiagnosticsManager#registerConnectivityDiagnosticsCallback}. - * Requesting a network with this method will count toward this limit. If this limit is - * exceeded, an exception will be thrown. To avoid hitting this issue and to conserve resources, - * make sure to unregister the callbacks with - * {@link #unregisterNetworkCallback(NetworkCallback)}. - * - * @param request {@link NetworkRequest} describing this request. - * @param handler {@link Handler} to specify the thread upon which the callback will be invoked. - * If null, the callback is invoked on the default internal Handler. - * @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note - * the callback must not be shared - it uniquely specifies this request. - * @throws IllegalArgumentException if {@code request} contains invalid network capabilities. - * @throws SecurityException if missing the appropriate permissions. - * @throws RuntimeException if the app already has too many callbacks registered. - * - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - @SuppressLint("ExecutorRegistration") - @RequiresPermission(anyOf = { - android.Manifest.permission.NETWORK_SETTINGS, - android.Manifest.permission.NETWORK_STACK, - NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK - }) - public void requestBackgroundNetwork(@NonNull NetworkRequest request, - @Nullable Handler handler, @NonNull NetworkCallback networkCallback) { - final NetworkCapabilities nc = request.networkCapabilities; - sendRequestForNetwork(nc, networkCallback, 0, BACKGROUND_REQUEST, - TYPE_NONE, handler == null ? getDefaultHandler() : new CallbackHandler(handler)); - } -} diff --git a/core/java/android/net/ConnectivityMetricsEvent.aidl b/core/java/android/net/ConnectivityMetricsEvent.aidl deleted file mode 100644 index 1c541dc4c8cc..000000000000 --- a/core/java/android/net/ConnectivityMetricsEvent.aidl +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -/** {@hide} */ -parcelable ConnectivityMetricsEvent; diff --git a/core/java/android/net/ConnectivityThread.java b/core/java/android/net/ConnectivityThread.java deleted file mode 100644 index 0b218e738b77..000000000000 --- a/core/java/android/net/ConnectivityThread.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import android.os.HandlerThread; -import android.os.Looper; - -/** - * Shared singleton connectivity thread for the system. This is a thread for - * connectivity operations such as AsyncChannel connections to system services. - * Various connectivity manager objects can use this singleton as a common - * resource for their handlers instead of creating separate threads of their own. - * @hide - */ -public final class ConnectivityThread extends HandlerThread { - - // A class implementing the lazy holder idiom: the unique static instance - // of ConnectivityThread is instantiated in a thread-safe way (guaranteed by - // the language specs) the first time that Singleton is referenced in get() - // or getInstanceLooper(). - private static class Singleton { - private static final ConnectivityThread INSTANCE = createInstance(); - } - - private ConnectivityThread() { - super("ConnectivityThread"); - } - - private static ConnectivityThread createInstance() { - ConnectivityThread t = new ConnectivityThread(); - t.start(); - return t; - } - - public static ConnectivityThread get() { - return Singleton.INSTANCE; - } - - public static Looper getInstanceLooper() { - return Singleton.INSTANCE.getLooper(); - } -} diff --git a/core/java/android/net/DhcpInfo.aidl b/core/java/android/net/DhcpInfo.aidl deleted file mode 100644 index 29cd21fe7652..000000000000 --- a/core/java/android/net/DhcpInfo.aidl +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2008, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -parcelable DhcpInfo; diff --git a/core/java/android/net/DhcpInfo.java b/core/java/android/net/DhcpInfo.java deleted file mode 100644 index 912df67a0b45..000000000000 --- a/core/java/android/net/DhcpInfo.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import android.os.Parcel; -import android.os.Parcelable; - -/** - * A simple object for retrieving the results of a DHCP request. - */ -public class DhcpInfo implements Parcelable { - public int ipAddress; - public int gateway; - public int netmask; - public int dns1; - public int dns2; - public int serverAddress; - - public int leaseDuration; - - public DhcpInfo() { - super(); - } - - /** copy constructor {@hide} */ - public DhcpInfo(DhcpInfo source) { - if (source != null) { - ipAddress = source.ipAddress; - gateway = source.gateway; - netmask = source.netmask; - dns1 = source.dns1; - dns2 = source.dns2; - serverAddress = source.serverAddress; - leaseDuration = source.leaseDuration; - } - } - - public String toString() { - StringBuffer str = new StringBuffer(); - - str.append("ipaddr "); putAddress(str, ipAddress); - str.append(" gateway "); putAddress(str, gateway); - str.append(" netmask "); putAddress(str, netmask); - str.append(" dns1 "); putAddress(str, dns1); - str.append(" dns2 "); putAddress(str, dns2); - str.append(" DHCP server "); putAddress(str, serverAddress); - str.append(" lease ").append(leaseDuration).append(" seconds"); - - return str.toString(); - } - - private static void putAddress(StringBuffer buf, int addr) { - buf.append(NetworkUtils.intToInetAddress(addr).getHostAddress()); - } - - /** Implement the Parcelable interface */ - public int describeContents() { - return 0; - } - - /** Implement the Parcelable interface */ - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(ipAddress); - dest.writeInt(gateway); - dest.writeInt(netmask); - dest.writeInt(dns1); - dest.writeInt(dns2); - dest.writeInt(serverAddress); - dest.writeInt(leaseDuration); - } - - /** Implement the Parcelable interface */ - public static final @android.annotation.NonNull Creator CREATOR = - new Creator() { - public DhcpInfo createFromParcel(Parcel in) { - DhcpInfo info = new DhcpInfo(); - info.ipAddress = in.readInt(); - info.gateway = in.readInt(); - info.netmask = in.readInt(); - info.dns1 = in.readInt(); - info.dns2 = in.readInt(); - info.serverAddress = in.readInt(); - info.leaseDuration = in.readInt(); - return info; - } - - public DhcpInfo[] newArray(int size) { - return new DhcpInfo[size]; - } - }; -} diff --git a/core/java/android/net/DnsResolver.java b/core/java/android/net/DnsResolver.java deleted file mode 100644 index 3f7660f5709a..000000000000 --- a/core/java/android/net/DnsResolver.java +++ /dev/null @@ -1,577 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import static android.net.NetworkUtils.getDnsNetwork; -import static android.net.NetworkUtils.resNetworkCancel; -import static android.net.NetworkUtils.resNetworkQuery; -import static android.net.NetworkUtils.resNetworkResult; -import static android.net.NetworkUtils.resNetworkSend; -import static android.net.util.DnsUtils.haveIpv4; -import static android.net.util.DnsUtils.haveIpv6; -import static android.net.util.DnsUtils.rfc6724Sort; -import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_ERROR; -import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT; -import static android.system.OsConstants.ENONET; - -import android.annotation.CallbackExecutor; -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.os.CancellationSignal; -import android.os.Looper; -import android.os.MessageQueue; -import android.system.ErrnoException; -import android.util.Log; - -import com.android.net.module.util.DnsPacket; - -import java.io.FileDescriptor; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.Executor; - -/** - * Dns resolver class for asynchronous dns querying - * - * Note that if a client sends a query with more than 1 record in the question section but - * the remote dns server does not support this, it may not respond at all, leading to a timeout. - * - */ -public final class DnsResolver { - private static final String TAG = "DnsResolver"; - private static final int FD_EVENTS = EVENT_INPUT | EVENT_ERROR; - private static final int MAXPACKET = 8 * 1024; - private static final int SLEEP_TIME_MS = 2; - - @IntDef(prefix = { "CLASS_" }, value = { - CLASS_IN - }) - @Retention(RetentionPolicy.SOURCE) - @interface QueryClass {} - public static final int CLASS_IN = 1; - - @IntDef(prefix = { "TYPE_" }, value = { - TYPE_A, - TYPE_AAAA - }) - @Retention(RetentionPolicy.SOURCE) - @interface QueryType {} - public static final int TYPE_A = 1; - public static final int TYPE_AAAA = 28; - - @IntDef(prefix = { "FLAG_" }, value = { - FLAG_EMPTY, - FLAG_NO_RETRY, - FLAG_NO_CACHE_STORE, - FLAG_NO_CACHE_LOOKUP - }) - @Retention(RetentionPolicy.SOURCE) - @interface QueryFlag {} - public static final int FLAG_EMPTY = 0; - public static final int FLAG_NO_RETRY = 1 << 0; - public static final int FLAG_NO_CACHE_STORE = 1 << 1; - public static final int FLAG_NO_CACHE_LOOKUP = 1 << 2; - - @IntDef(prefix = { "ERROR_" }, value = { - ERROR_PARSE, - ERROR_SYSTEM - }) - @Retention(RetentionPolicy.SOURCE) - @interface DnsError {} - /** - * Indicates that there was an error parsing the response the query. - * The cause of this error is available via getCause() and is a {@link ParseException}. - */ - public static final int ERROR_PARSE = 0; - /** - * Indicates that there was an error sending the query. - * The cause of this error is available via getCause() and is an ErrnoException. - */ - public static final int ERROR_SYSTEM = 1; - - private static final int NETID_UNSET = 0; - - private static final DnsResolver sInstance = new DnsResolver(); - - /** - * Get instance for DnsResolver - */ - public static @NonNull DnsResolver getInstance() { - return sInstance; - } - - private DnsResolver() {} - - /** - * Base interface for answer callbacks - * - * @param The type of the answer - */ - public interface Callback { - /** - * Success response to - * {@link android.net.DnsResolver#query query()} or - * {@link android.net.DnsResolver#rawQuery rawQuery()}. - * - * Invoked when the answer to a query was successfully parsed. - * - * @param answer answer to the query. - * @param rcode The response code in the DNS response. - * - * {@see android.net.DnsResolver#query query()} - */ - void onAnswer(@NonNull T answer, int rcode); - /** - * Error response to - * {@link android.net.DnsResolver#query query()} or - * {@link android.net.DnsResolver#rawQuery rawQuery()}. - * - * Invoked when there is no valid answer to - * {@link android.net.DnsResolver#query query()} - * {@link android.net.DnsResolver#rawQuery rawQuery()}. - * - * @param error a {@link DnsException} object with additional - * detail regarding the failure - */ - void onError(@NonNull DnsException error); - } - - /** - * Class to represent DNS error - */ - public static class DnsException extends Exception { - /** - * DNS error code as one of the ERROR_* constants - */ - @DnsError public final int code; - - DnsException(@DnsError int code, @Nullable Throwable cause) { - super(cause); - this.code = code; - } - } - - /** - * Send a raw DNS query. - * The answer will be provided asynchronously through the provided {@link Callback}. - * - * @param network {@link Network} specifying which network to query on. - * {@code null} for query on default network. - * @param query blob message to query - * @param flags flags as a combination of the FLAGS_* constants - * @param executor The {@link Executor} that the callback should be executed on. - * @param cancellationSignal used by the caller to signal if the query should be - * cancelled. May be {@code null}. - * @param callback a {@link Callback} which will be called to notify the caller - * of the result of dns query. - */ - public void rawQuery(@Nullable Network network, @NonNull byte[] query, @QueryFlag int flags, - @NonNull @CallbackExecutor Executor executor, - @Nullable CancellationSignal cancellationSignal, - @NonNull Callback callback) { - if (cancellationSignal != null && cancellationSignal.isCanceled()) { - return; - } - final Object lock = new Object(); - final FileDescriptor queryfd; - try { - queryfd = resNetworkSend((network != null) - ? network.getNetIdForResolv() : NETID_UNSET, query, query.length, flags); - } catch (ErrnoException e) { - executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e))); - return; - } - - synchronized (lock) { - registerFDListener(executor, queryfd, callback, cancellationSignal, lock); - if (cancellationSignal == null) return; - addCancellationSignal(cancellationSignal, queryfd, lock); - } - } - - /** - * Send a DNS query with the specified name, class and query type. - * The answer will be provided asynchronously through the provided {@link Callback}. - * - * @param network {@link Network} specifying which network to query on. - * {@code null} for query on default network. - * @param domain domain name to query - * @param nsClass dns class as one of the CLASS_* constants - * @param nsType dns resource record (RR) type as one of the TYPE_* constants - * @param flags flags as a combination of the FLAGS_* constants - * @param executor The {@link Executor} that the callback should be executed on. - * @param cancellationSignal used by the caller to signal if the query should be - * cancelled. May be {@code null}. - * @param callback a {@link Callback} which will be called to notify the caller - * of the result of dns query. - */ - public void rawQuery(@Nullable Network network, @NonNull String domain, - @QueryClass int nsClass, @QueryType int nsType, @QueryFlag int flags, - @NonNull @CallbackExecutor Executor executor, - @Nullable CancellationSignal cancellationSignal, - @NonNull Callback callback) { - if (cancellationSignal != null && cancellationSignal.isCanceled()) { - return; - } - final Object lock = new Object(); - final FileDescriptor queryfd; - try { - queryfd = resNetworkQuery((network != null) - ? network.getNetIdForResolv() : NETID_UNSET, domain, nsClass, nsType, flags); - } catch (ErrnoException e) { - executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e))); - return; - } - synchronized (lock) { - registerFDListener(executor, queryfd, callback, cancellationSignal, lock); - if (cancellationSignal == null) return; - addCancellationSignal(cancellationSignal, queryfd, lock); - } - } - - private class InetAddressAnswerAccumulator implements Callback { - private final List mAllAnswers; - private final Network mNetwork; - private int mRcode; - private DnsException mDnsException; - private final Callback> mUserCallback; - private final int mTargetAnswerCount; - private int mReceivedAnswerCount = 0; - - InetAddressAnswerAccumulator(@NonNull Network network, int size, - @NonNull Callback> callback) { - mNetwork = network; - mTargetAnswerCount = size; - mAllAnswers = new ArrayList<>(); - mUserCallback = callback; - } - - private boolean maybeReportError() { - if (mRcode != 0) { - mUserCallback.onAnswer(mAllAnswers, mRcode); - return true; - } - if (mDnsException != null) { - mUserCallback.onError(mDnsException); - return true; - } - return false; - } - - private void maybeReportAnswer() { - if (++mReceivedAnswerCount != mTargetAnswerCount) return; - if (mAllAnswers.isEmpty() && maybeReportError()) return; - mUserCallback.onAnswer(rfc6724Sort(mNetwork, mAllAnswers), mRcode); - } - - @Override - public void onAnswer(@NonNull byte[] answer, int rcode) { - // If at least one query succeeded, return an rcode of 0. - // Otherwise, arbitrarily return the first rcode received. - if (mReceivedAnswerCount == 0 || rcode == 0) { - mRcode = rcode; - } - try { - mAllAnswers.addAll(new DnsAddressAnswer(answer).getAddresses()); - } catch (DnsPacket.ParseException e) { - // Convert the com.android.net.module.util.DnsPacket.ParseException to an - // android.net.ParseException. This is the type that was used in Q and is implied - // by the public documentation of ERROR_PARSE. - // - // DnsPacket cannot throw android.net.ParseException directly because it's @hide. - ParseException pe = new ParseException(e.reason, e.getCause()); - pe.setStackTrace(e.getStackTrace()); - mDnsException = new DnsException(ERROR_PARSE, pe); - } - maybeReportAnswer(); - } - - @Override - public void onError(@NonNull DnsException error) { - mDnsException = error; - maybeReportAnswer(); - } - } - - /** - * Send a DNS query with the specified name on a network with both IPv4 and IPv6, - * get back a set of InetAddresses with rfc6724 sorting style asynchronously. - * - * This method will examine the connection ability on given network, and query IPv4 - * and IPv6 if connection is available. - * - * If at least one query succeeded with valid answer, rcode will be 0 - * - * The answer will be provided asynchronously through the provided {@link Callback}. - * - * @param network {@link Network} specifying which network to query on. - * {@code null} for query on default network. - * @param domain domain name to query - * @param flags flags as a combination of the FLAGS_* constants - * @param executor The {@link Executor} that the callback should be executed on. - * @param cancellationSignal used by the caller to signal if the query should be - * cancelled. May be {@code null}. - * @param callback a {@link Callback} which will be called to notify the - * caller of the result of dns query. - */ - public void query(@Nullable Network network, @NonNull String domain, @QueryFlag int flags, - @NonNull @CallbackExecutor Executor executor, - @Nullable CancellationSignal cancellationSignal, - @NonNull Callback> callback) { - if (cancellationSignal != null && cancellationSignal.isCanceled()) { - return; - } - final Object lock = new Object(); - final Network queryNetwork; - try { - queryNetwork = (network != null) ? network : getDnsNetwork(); - } catch (ErrnoException e) { - executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e))); - return; - } - final boolean queryIpv6 = haveIpv6(queryNetwork); - final boolean queryIpv4 = haveIpv4(queryNetwork); - - // This can only happen if queryIpv4 and queryIpv6 are both false. - // This almost certainly means that queryNetwork does not exist or no longer exists. - if (!queryIpv6 && !queryIpv4) { - executor.execute(() -> callback.onError( - new DnsException(ERROR_SYSTEM, new ErrnoException("resNetworkQuery", ENONET)))); - return; - } - - final FileDescriptor v4fd; - final FileDescriptor v6fd; - - int queryCount = 0; - - if (queryIpv6) { - try { - v6fd = resNetworkQuery(queryNetwork.getNetIdForResolv(), domain, CLASS_IN, - TYPE_AAAA, flags); - } catch (ErrnoException e) { - executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e))); - return; - } - queryCount++; - } else v6fd = null; - - // Avoiding gateways drop packets if queries are sent too close together - try { - Thread.sleep(SLEEP_TIME_MS); - } catch (InterruptedException ex) { - Thread.currentThread().interrupt(); - } - - if (queryIpv4) { - try { - v4fd = resNetworkQuery(queryNetwork.getNetIdForResolv(), domain, CLASS_IN, TYPE_A, - flags); - } catch (ErrnoException e) { - if (queryIpv6) resNetworkCancel(v6fd); // Closes fd, marks it invalid. - executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e))); - return; - } - queryCount++; - } else v4fd = null; - - final InetAddressAnswerAccumulator accumulator = - new InetAddressAnswerAccumulator(queryNetwork, queryCount, callback); - - synchronized (lock) { - if (queryIpv6) { - registerFDListener(executor, v6fd, accumulator, cancellationSignal, lock); - } - if (queryIpv4) { - registerFDListener(executor, v4fd, accumulator, cancellationSignal, lock); - } - if (cancellationSignal == null) return; - cancellationSignal.setOnCancelListener(() -> { - synchronized (lock) { - if (queryIpv4) cancelQuery(v4fd); - if (queryIpv6) cancelQuery(v6fd); - } - }); - } - } - - /** - * Send a DNS query with the specified name and query type, get back a set of - * InetAddresses with rfc6724 sorting style asynchronously. - * - * The answer will be provided asynchronously through the provided {@link Callback}. - * - * @param network {@link Network} specifying which network to query on. - * {@code null} for query on default network. - * @param domain domain name to query - * @param nsType dns resource record (RR) type as one of the TYPE_* constants - * @param flags flags as a combination of the FLAGS_* constants - * @param executor The {@link Executor} that the callback should be executed on. - * @param cancellationSignal used by the caller to signal if the query should be - * cancelled. May be {@code null}. - * @param callback a {@link Callback} which will be called to notify the caller - * of the result of dns query. - */ - public void query(@Nullable Network network, @NonNull String domain, - @QueryType int nsType, @QueryFlag int flags, - @NonNull @CallbackExecutor Executor executor, - @Nullable CancellationSignal cancellationSignal, - @NonNull Callback> callback) { - if (cancellationSignal != null && cancellationSignal.isCanceled()) { - return; - } - final Object lock = new Object(); - final FileDescriptor queryfd; - final Network queryNetwork; - try { - queryNetwork = (network != null) ? network : getDnsNetwork(); - queryfd = resNetworkQuery(queryNetwork.getNetIdForResolv(), domain, CLASS_IN, nsType, - flags); - } catch (ErrnoException e) { - executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e))); - return; - } - final InetAddressAnswerAccumulator accumulator = - new InetAddressAnswerAccumulator(queryNetwork, 1, callback); - synchronized (lock) { - registerFDListener(executor, queryfd, accumulator, cancellationSignal, lock); - if (cancellationSignal == null) return; - addCancellationSignal(cancellationSignal, queryfd, lock); - } - } - - /** - * Class to retrieve DNS response - * - * @hide - */ - public static final class DnsResponse { - public final @NonNull byte[] answerbuf; - public final int rcode; - public DnsResponse(@NonNull byte[] answerbuf, int rcode) { - this.answerbuf = answerbuf; - this.rcode = rcode; - } - } - - private void registerFDListener(@NonNull Executor executor, - @NonNull FileDescriptor queryfd, @NonNull Callback answerCallback, - @Nullable CancellationSignal cancellationSignal, @NonNull Object lock) { - final MessageQueue mainThreadMessageQueue = Looper.getMainLooper().getQueue(); - mainThreadMessageQueue.addOnFileDescriptorEventListener( - queryfd, - FD_EVENTS, - (fd, events) -> { - // b/134310704 - // Unregister fd event listener before resNetworkResult is called to prevent - // race condition caused by fd reused. - // For example when querying v4 and v6, it's possible that the first query ends - // and the fd is closed before the second request starts, which might return - // the same fd for the second request. By that time, the looper must have - // unregistered the fd, otherwise another event listener can't be registered. - mainThreadMessageQueue.removeOnFileDescriptorEventListener(fd); - - executor.execute(() -> { - DnsResponse resp = null; - ErrnoException exception = null; - synchronized (lock) { - if (cancellationSignal != null && cancellationSignal.isCanceled()) { - return; - } - try { - resp = resNetworkResult(fd); // Closes fd, marks it invalid. - } catch (ErrnoException e) { - Log.e(TAG, "resNetworkResult:" + e.toString()); - exception = e; - } - } - if (exception != null) { - answerCallback.onError(new DnsException(ERROR_SYSTEM, exception)); - return; - } - answerCallback.onAnswer(resp.answerbuf, resp.rcode); - }); - - // The file descriptor has already been unregistered, so it does not really - // matter what is returned here. In spirit 0 (meaning "unregister this FD") - // is still the closest to what the looper needs to do. When returning 0, - // Looper knows to ignore the fd if it has already been unregistered. - return 0; - }); - } - - private void cancelQuery(@NonNull FileDescriptor queryfd) { - if (!queryfd.valid()) return; - Looper.getMainLooper().getQueue().removeOnFileDescriptorEventListener(queryfd); - resNetworkCancel(queryfd); // Closes fd, marks it invalid. - } - - private void addCancellationSignal(@NonNull CancellationSignal cancellationSignal, - @NonNull FileDescriptor queryfd, @NonNull Object lock) { - cancellationSignal.setOnCancelListener(() -> { - synchronized (lock) { - cancelQuery(queryfd); - } - }); - } - - private static class DnsAddressAnswer extends DnsPacket { - private static final String TAG = "DnsResolver.DnsAddressAnswer"; - private static final boolean DBG = false; - - private final int mQueryType; - - DnsAddressAnswer(@NonNull byte[] data) throws ParseException { - super(data); - if ((mHeader.flags & (1 << 15)) == 0) { - throw new ParseException("Not an answer packet"); - } - if (mHeader.getRecordCount(QDSECTION) == 0) { - throw new ParseException("No question found"); - } - // Expect only one question in question section. - mQueryType = mRecords[QDSECTION].get(0).nsType; - } - - public @NonNull List getAddresses() { - final List results = new ArrayList(); - if (mHeader.getRecordCount(ANSECTION) == 0) return results; - - for (final DnsRecord ansSec : mRecords[ANSECTION]) { - // Only support A and AAAA, also ignore answers if query type != answer type. - int nsType = ansSec.nsType; - if (nsType != mQueryType || (nsType != TYPE_A && nsType != TYPE_AAAA)) { - continue; - } - try { - results.add(InetAddress.getByAddress(ansSec.getRR())); - } catch (UnknownHostException e) { - if (DBG) { - Log.w(TAG, "rr to address fail"); - } - } - } - return results; - } - } - -} diff --git a/core/java/android/net/ICaptivePortal.aidl b/core/java/android/net/ICaptivePortal.aidl deleted file mode 100644 index fe21905c7002..000000000000 --- a/core/java/android/net/ICaptivePortal.aidl +++ /dev/null @@ -1,27 +0,0 @@ -/** - * Copyright (c) 2015, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -/** - * Interface to inform NetworkMonitor of decisions of app handling captive portal. - * @hide - */ -oneway interface ICaptivePortal { - void appRequest(int request); - void appResponse(int response); - void logEvent(int eventId, String packageName); -} diff --git a/core/java/android/net/IConnectivityDiagnosticsCallback.aidl b/core/java/android/net/IConnectivityDiagnosticsCallback.aidl deleted file mode 100644 index 82b64a928000..000000000000 --- a/core/java/android/net/IConnectivityDiagnosticsCallback.aidl +++ /dev/null @@ -1,28 +0,0 @@ -/** - * - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import android.net.ConnectivityDiagnosticsManager; -import android.net.Network; - -/** @hide */ -oneway interface IConnectivityDiagnosticsCallback { - void onConnectivityReportAvailable(in ConnectivityDiagnosticsManager.ConnectivityReport report); - void onDataStallSuspected(in ConnectivityDiagnosticsManager.DataStallReport report); - void onNetworkConnectivityReported(in Network n, boolean hasConnectivity); -} \ No newline at end of file diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl deleted file mode 100644 index 1b4d2e413943..000000000000 --- a/core/java/android/net/IConnectivityManager.aidl +++ /dev/null @@ -1,246 +0,0 @@ -/** - * Copyright (c) 2008, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import android.app.PendingIntent; -import android.net.ConnectionInfo; -import android.net.ConnectivityDiagnosticsManager; -import android.net.IConnectivityDiagnosticsCallback; -import android.net.IQosCallback; -import android.net.ISocketKeepaliveCallback; -import android.net.LinkProperties; -import android.net.Network; -import android.net.NetworkAgentConfig; -import android.net.NetworkCapabilities; -import android.net.NetworkInfo; -import android.net.NetworkRequest; -import android.net.NetworkState; -import android.net.ProxyInfo; -import android.net.UidRange; -import android.net.QosSocketInfo; -import android.os.Bundle; -import android.os.IBinder; -import android.os.INetworkActivityListener; -import android.os.Messenger; -import android.os.ParcelFileDescriptor; -import android.os.PersistableBundle; -import android.os.ResultReceiver; - -import com.android.connectivity.aidl.INetworkAgent; -import com.android.internal.net.LegacyVpnInfo; -import com.android.internal.net.VpnConfig; -import com.android.internal.net.VpnProfile; - -/** - * Interface that answers queries about, and allows changing, the - * state of network connectivity. - */ -/** {@hide} */ -interface IConnectivityManager -{ - Network getActiveNetwork(); - Network getActiveNetworkForUid(int uid, boolean ignoreBlocked); - @UnsupportedAppUsage - NetworkInfo getActiveNetworkInfo(); - NetworkInfo getActiveNetworkInfoForUid(int uid, boolean ignoreBlocked); - @UnsupportedAppUsage(maxTargetSdk = 28) - NetworkInfo getNetworkInfo(int networkType); - NetworkInfo getNetworkInfoForUid(in Network network, int uid, boolean ignoreBlocked); - @UnsupportedAppUsage - NetworkInfo[] getAllNetworkInfo(); - Network getNetworkForType(int networkType); - Network[] getAllNetworks(); - NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser( - int userId, String callingPackageName); - - boolean isNetworkSupported(int networkType); - - @UnsupportedAppUsage - LinkProperties getActiveLinkProperties(); - LinkProperties getLinkPropertiesForType(int networkType); - LinkProperties getLinkProperties(in Network network); - - NetworkCapabilities getNetworkCapabilities(in Network network, String callingPackageName); - - @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553) - NetworkState[] getAllNetworkState(); - - boolean isActiveNetworkMetered(); - - boolean requestRouteToHostAddress(int networkType, in byte[] hostAddress, - String callingPackageName, String callingAttributionTag); - - @UnsupportedAppUsage(maxTargetSdk = 29, - publicAlternatives = "Use {@code TetheringManager#getLastTetherError} as alternative") - int getLastTetherError(String iface); - - @UnsupportedAppUsage(maxTargetSdk = 29, - publicAlternatives = "Use {@code TetheringManager#getTetherableIfaces} as alternative") - String[] getTetherableIfaces(); - - @UnsupportedAppUsage(maxTargetSdk = 29, - publicAlternatives = "Use {@code TetheringManager#getTetheredIfaces} as alternative") - String[] getTetheredIfaces(); - - @UnsupportedAppUsage(maxTargetSdk = 29, - publicAlternatives = "Use {@code TetheringManager#getTetheringErroredIfaces} " - + "as Alternative") - String[] getTetheringErroredIfaces(); - - @UnsupportedAppUsage(maxTargetSdk = 29, - publicAlternatives = "Use {@code TetheringManager#getTetherableUsbRegexs} as alternative") - String[] getTetherableUsbRegexs(); - - @UnsupportedAppUsage(maxTargetSdk = 29, - publicAlternatives = "Use {@code TetheringManager#getTetherableWifiRegexs} as alternative") - String[] getTetherableWifiRegexs(); - - @UnsupportedAppUsage(maxTargetSdk = 28) - void reportInetCondition(int networkType, int percentage); - - void reportNetworkConnectivity(in Network network, boolean hasConnectivity); - - ProxyInfo getGlobalProxy(); - - void setGlobalProxy(in ProxyInfo p); - - ProxyInfo getProxyForNetwork(in Network nework); - - boolean prepareVpn(String oldPackage, String newPackage, int userId); - - void setVpnPackageAuthorization(String packageName, int userId, int vpnType); - - ParcelFileDescriptor establishVpn(in VpnConfig config); - - boolean provisionVpnProfile(in VpnProfile profile, String packageName); - - void deleteVpnProfile(String packageName); - - void startVpnProfile(String packageName); - - void stopVpnProfile(String packageName); - - VpnConfig getVpnConfig(int userId); - - @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553) - void startLegacyVpn(in VpnProfile profile); - - LegacyVpnInfo getLegacyVpnInfo(int userId); - - boolean updateLockdownVpn(); - boolean isAlwaysOnVpnPackageSupported(int userId, String packageName); - boolean setAlwaysOnVpnPackage(int userId, String packageName, boolean lockdown, - in List lockdownWhitelist); - String getAlwaysOnVpnPackage(int userId); - boolean isVpnLockdownEnabled(int userId); - List getVpnLockdownWhitelist(int userId); - void setRequireVpnForUids(boolean requireVpn, in UidRange[] ranges); - - void setProvisioningNotificationVisible(boolean visible, int networkType, in String action); - - void setAirplaneMode(boolean enable); - - boolean requestBandwidthUpdate(in Network network); - - int registerNetworkFactory(in Messenger messenger, in String name); - void unregisterNetworkFactory(in Messenger messenger); - - int registerNetworkProvider(in Messenger messenger, in String name); - void unregisterNetworkProvider(in Messenger messenger); - - void declareNetworkRequestUnfulfillable(in NetworkRequest request); - - Network registerNetworkAgent(in INetworkAgent na, in NetworkInfo ni, in LinkProperties lp, - in NetworkCapabilities nc, int score, in NetworkAgentConfig config, - in int factorySerialNumber); - - NetworkRequest requestNetwork(in NetworkCapabilities networkCapabilities, int reqType, - in Messenger messenger, int timeoutSec, in IBinder binder, int legacy, - String callingPackageName, String callingAttributionTag); - - NetworkRequest pendingRequestForNetwork(in NetworkCapabilities networkCapabilities, - in PendingIntent operation, String callingPackageName, String callingAttributionTag); - - void releasePendingNetworkRequest(in PendingIntent operation); - - NetworkRequest listenForNetwork(in NetworkCapabilities networkCapabilities, - in Messenger messenger, in IBinder binder, String callingPackageName); - - void pendingListenForNetwork(in NetworkCapabilities networkCapabilities, - in PendingIntent operation, String callingPackageName); - - void releaseNetworkRequest(in NetworkRequest networkRequest); - - void setAcceptUnvalidated(in Network network, boolean accept, boolean always); - void setAcceptPartialConnectivity(in Network network, boolean accept, boolean always); - void setAvoidUnvalidated(in Network network); - void startCaptivePortalApp(in Network network); - void startCaptivePortalAppInternal(in Network network, in Bundle appExtras); - - boolean shouldAvoidBadWifi(); - int getMultipathPreference(in Network Network); - - NetworkRequest getDefaultRequest(); - - int getRestoreDefaultNetworkDelay(int networkType); - - boolean addVpnAddress(String address, int prefixLength); - boolean removeVpnAddress(String address, int prefixLength); - boolean setUnderlyingNetworksForVpn(in Network[] networks); - - void factoryReset(); - - void startNattKeepalive(in Network network, int intervalSeconds, - in ISocketKeepaliveCallback cb, String srcAddr, int srcPort, String dstAddr); - - void startNattKeepaliveWithFd(in Network network, in ParcelFileDescriptor pfd, int resourceId, - int intervalSeconds, in ISocketKeepaliveCallback cb, String srcAddr, - String dstAddr); - - void startTcpKeepalive(in Network network, in ParcelFileDescriptor pfd, int intervalSeconds, - in ISocketKeepaliveCallback cb); - - void stopKeepalive(in Network network, int slot); - - String getCaptivePortalServerUrl(); - - byte[] getNetworkWatchlistConfigHash(); - - int getConnectionOwnerUid(in ConnectionInfo connectionInfo); - boolean isCallerCurrentAlwaysOnVpnApp(); - boolean isCallerCurrentAlwaysOnVpnLockdownApp(); - - void registerConnectivityDiagnosticsCallback(in IConnectivityDiagnosticsCallback callback, - in NetworkRequest request, String callingPackageName); - void unregisterConnectivityDiagnosticsCallback(in IConnectivityDiagnosticsCallback callback); - - IBinder startOrGetTestNetworkService(); - - void simulateDataStall(int detectionMethod, long timestampMillis, in Network network, - in PersistableBundle extras); - - void systemReady(); - - void registerNetworkActivityListener(in INetworkActivityListener l); - - void unregisterNetworkActivityListener(in INetworkActivityListener l); - - boolean isDefaultNetworkActive(); - - void registerQosSocketCallback(in QosSocketInfo socketInfo, in IQosCallback callback); - void unregisterQosCallback(in IQosCallback callback); -} diff --git a/core/java/android/net/ISocketKeepaliveCallback.aidl b/core/java/android/net/ISocketKeepaliveCallback.aidl deleted file mode 100644 index 020fbcacbfef..000000000000 --- a/core/java/android/net/ISocketKeepaliveCallback.aidl +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Copyright (c) 2019, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -/** - * Callback to provide status changes of keepalive offload. - * - * @hide - */ -oneway interface ISocketKeepaliveCallback -{ - /** The keepalive was successfully started. */ - void onStarted(int slot); - /** The keepalive was successfully stopped. */ - void onStopped(); - /** The keepalive was stopped because of an error. */ - void onError(int error); - /** The keepalive on a TCP socket was stopped because the socket received data. */ - void onDataReceived(); -} diff --git a/core/java/android/net/ITestNetworkManager.aidl b/core/java/android/net/ITestNetworkManager.aidl deleted file mode 100644 index 2a863adde581..000000000000 --- a/core/java/android/net/ITestNetworkManager.aidl +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Copyright (c) 2018, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import android.net.LinkAddress; -import android.net.LinkProperties; -import android.net.TestNetworkInterface; -import android.os.IBinder; -import android.os.ParcelFileDescriptor; - -/** - * Interface that allows for creation and management of test-only networks. - * - * @hide - */ -interface ITestNetworkManager -{ - TestNetworkInterface createTunInterface(in LinkAddress[] linkAddrs); - TestNetworkInterface createTapInterface(); - - void setupTestNetwork(in String iface, in LinkProperties lp, in boolean isMetered, - in int[] administratorUids, in IBinder binder); - - void teardownTestNetwork(int netId); -} diff --git a/core/java/android/net/InetAddresses.java b/core/java/android/net/InetAddresses.java deleted file mode 100644 index 01b795e456fa..000000000000 --- a/core/java/android/net/InetAddresses.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import android.annotation.NonNull; - -import libcore.net.InetAddressUtils; - -import java.net.InetAddress; - -/** - * Utility methods for {@link InetAddress} implementations. - */ -public class InetAddresses { - - private InetAddresses() {} - - /** - * Checks to see if the {@code address} is a numeric address (such as {@code "192.0.2.1"} or - * {@code "2001:db8::1:2"}). - * - *

A numeric address is either an IPv4 address containing exactly 4 decimal numbers or an - * IPv6 numeric address. IPv4 addresses that consist of either hexadecimal or octal digits or - * do not have exactly 4 numbers are not treated as numeric. - * - *

This method will never do a DNS lookup. - * - * @param address the address to parse. - * @return true if the supplied address is numeric, false otherwise. - */ - public static boolean isNumericAddress(@NonNull String address) { - return InetAddressUtils.isNumericAddress(address); - } - - /** - * Returns an InetAddress corresponding to the given numeric address (such - * as {@code "192.168.0.1"} or {@code "2001:4860:800d::68"}). - * - *

See {@link #isNumericAddress(String)} (String)} for a definition as to what constitutes a - * numeric address. - * - *

This method will never do a DNS lookup. - * - * @param address the address to parse, must be numeric. - * @return an {@link InetAddress} instance corresponding to the address. - * @throws IllegalArgumentException if {@code address} is not a numeric address. - */ - public static @NonNull InetAddress parseNumericAddress(@NonNull String address) { - return InetAddressUtils.parseNumericAddress(address); - } -} diff --git a/core/java/android/net/InterfaceConfiguration.aidl b/core/java/android/net/InterfaceConfiguration.aidl deleted file mode 100644 index 8aa5e3452853..000000000000 --- a/core/java/android/net/InterfaceConfiguration.aidl +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2008, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -parcelable InterfaceConfiguration; diff --git a/core/java/android/net/InvalidPacketException.java b/core/java/android/net/InvalidPacketException.java deleted file mode 100644 index 1873d778c0f2..000000000000 --- a/core/java/android/net/InvalidPacketException.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import android.annotation.IntDef; -import android.annotation.SystemApi; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * Thrown when a packet is invalid. - * @hide - */ -@SystemApi -public final class InvalidPacketException extends Exception { - private final int mError; - - // Must match SocketKeepalive#ERROR_INVALID_IP_ADDRESS. - /** Invalid IP address. */ - public static final int ERROR_INVALID_IP_ADDRESS = -21; - - // Must match SocketKeepalive#ERROR_INVALID_PORT. - /** Invalid port number. */ - public static final int ERROR_INVALID_PORT = -22; - - // Must match SocketKeepalive#ERROR_INVALID_LENGTH. - /** Invalid packet length. */ - public static final int ERROR_INVALID_LENGTH = -23; - - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = { "ERROR_" }, value = { - ERROR_INVALID_IP_ADDRESS, - ERROR_INVALID_PORT, - ERROR_INVALID_LENGTH - }) - public @interface ErrorCode {} - - /** - * This packet is invalid. - * See the error code for details. - */ - public InvalidPacketException(@ErrorCode final int error) { - this.mError = error; - } - - /** Get error code. */ - public int getError() { - return mError; - } -} diff --git a/core/java/android/net/IpConfiguration.aidl b/core/java/android/net/IpConfiguration.aidl deleted file mode 100644 index 7a30f0e79cad..000000000000 --- a/core/java/android/net/IpConfiguration.aidl +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -parcelable IpConfiguration; diff --git a/core/java/android/net/IpConfiguration.java b/core/java/android/net/IpConfiguration.java deleted file mode 100644 index 0b205642b321..000000000000 --- a/core/java/android/net/IpConfiguration.java +++ /dev/null @@ -1,223 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.SuppressLint; -import android.annotation.SystemApi; -import android.compat.annotation.UnsupportedAppUsage; -import android.os.Build; -import android.os.Parcel; -import android.os.Parcelable; - -import java.util.Objects; - -/** - * A class representing a configured network. - * @hide - */ -@SystemApi -public final class IpConfiguration implements Parcelable { - private static final String TAG = "IpConfiguration"; - - // This enum has been used by apps through reflection for many releases. - // Therefore they can't just be removed. Duplicating these constants to - // give an alternate SystemApi is a worse option than exposing them. - @SuppressLint("Enum") - public enum IpAssignment { - /* Use statically configured IP settings. Configuration can be accessed - * with staticIpConfiguration */ - STATIC, - /* Use dynamically configured IP settings */ - DHCP, - /* no IP details are assigned, this is used to indicate - * that any existing IP settings should be retained */ - UNASSIGNED - } - - /** @hide */ - public IpAssignment ipAssignment; - - /** @hide */ - public StaticIpConfiguration staticIpConfiguration; - - // This enum has been used by apps through reflection for many releases. - // Therefore they can't just be removed. Duplicating these constants to - // give an alternate SystemApi is a worse option than exposing them. - @SuppressLint("Enum") - public enum ProxySettings { - /* No proxy is to be used. Any existing proxy settings - * should be cleared. */ - NONE, - /* Use statically configured proxy. Configuration can be accessed - * with httpProxy. */ - STATIC, - /* no proxy details are assigned, this is used to indicate - * that any existing proxy settings should be retained */ - UNASSIGNED, - /* Use a Pac based proxy. - */ - PAC - } - - /** @hide */ - public ProxySettings proxySettings; - - /** @hide */ - @UnsupportedAppUsage - public ProxyInfo httpProxy; - - private void init(IpAssignment ipAssignment, - ProxySettings proxySettings, - StaticIpConfiguration staticIpConfiguration, - ProxyInfo httpProxy) { - this.ipAssignment = ipAssignment; - this.proxySettings = proxySettings; - this.staticIpConfiguration = (staticIpConfiguration == null) ? - null : new StaticIpConfiguration(staticIpConfiguration); - this.httpProxy = (httpProxy == null) ? - null : new ProxyInfo(httpProxy); - } - - public IpConfiguration() { - init(IpAssignment.UNASSIGNED, ProxySettings.UNASSIGNED, null, null); - } - - /** @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public IpConfiguration(IpAssignment ipAssignment, - ProxySettings proxySettings, - StaticIpConfiguration staticIpConfiguration, - ProxyInfo httpProxy) { - init(ipAssignment, proxySettings, staticIpConfiguration, httpProxy); - } - - public IpConfiguration(@NonNull IpConfiguration source) { - this(); - if (source != null) { - init(source.ipAssignment, source.proxySettings, - source.staticIpConfiguration, source.httpProxy); - } - } - - public @NonNull IpAssignment getIpAssignment() { - return ipAssignment; - } - - public void setIpAssignment(@NonNull IpAssignment ipAssignment) { - this.ipAssignment = ipAssignment; - } - - public @Nullable StaticIpConfiguration getStaticIpConfiguration() { - return staticIpConfiguration; - } - - public void setStaticIpConfiguration(@Nullable StaticIpConfiguration staticIpConfiguration) { - this.staticIpConfiguration = staticIpConfiguration; - } - - public @NonNull ProxySettings getProxySettings() { - return proxySettings; - } - - public void setProxySettings(@NonNull ProxySettings proxySettings) { - this.proxySettings = proxySettings; - } - - public @Nullable ProxyInfo getHttpProxy() { - return httpProxy; - } - - public void setHttpProxy(@Nullable ProxyInfo httpProxy) { - this.httpProxy = httpProxy; - } - - @Override - public String toString() { - StringBuilder sbuf = new StringBuilder(); - sbuf.append("IP assignment: " + ipAssignment.toString()); - sbuf.append("\n"); - if (staticIpConfiguration != null) { - sbuf.append("Static configuration: " + staticIpConfiguration.toString()); - sbuf.append("\n"); - } - sbuf.append("Proxy settings: " + proxySettings.toString()); - sbuf.append("\n"); - if (httpProxy != null) { - sbuf.append("HTTP proxy: " + httpProxy.toString()); - sbuf.append("\n"); - } - - return sbuf.toString(); - } - - @Override - public boolean equals(Object o) { - if (o == this) { - return true; - } - - if (!(o instanceof IpConfiguration)) { - return false; - } - - IpConfiguration other = (IpConfiguration) o; - return this.ipAssignment == other.ipAssignment && - this.proxySettings == other.proxySettings && - Objects.equals(this.staticIpConfiguration, other.staticIpConfiguration) && - Objects.equals(this.httpProxy, other.httpProxy); - } - - @Override - public int hashCode() { - return 13 + (staticIpConfiguration != null ? staticIpConfiguration.hashCode() : 0) + - 17 * ipAssignment.ordinal() + - 47 * proxySettings.ordinal() + - 83 * httpProxy.hashCode(); - } - - /** Implement the Parcelable interface */ - public int describeContents() { - return 0; - } - - /** Implement the Parcelable interface */ - public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeString(ipAssignment.name()); - dest.writeString(proxySettings.name()); - dest.writeParcelable(staticIpConfiguration, flags); - dest.writeParcelable(httpProxy, flags); - } - - /** Implement the Parcelable interface */ - public static final @NonNull Creator CREATOR = - new Creator() { - public IpConfiguration createFromParcel(Parcel in) { - IpConfiguration config = new IpConfiguration(); - config.ipAssignment = IpAssignment.valueOf(in.readString()); - config.proxySettings = ProxySettings.valueOf(in.readString()); - config.staticIpConfiguration = in.readParcelable(null); - config.httpProxy = in.readParcelable(null); - return config; - } - - public IpConfiguration[] newArray(int size) { - return new IpConfiguration[size]; - } - }; -} diff --git a/core/java/android/net/IpPrefix.aidl b/core/java/android/net/IpPrefix.aidl deleted file mode 100644 index 0d70f2a1ed2c..000000000000 --- a/core/java/android/net/IpPrefix.aidl +++ /dev/null @@ -1,22 +0,0 @@ -/** - * - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -// @JavaOnlyStableParcelable only affects the parcelable when built as stable aidl (aidl_interface -// build rule). IpPrefix is also used in cpp but only as non-stable aidl. -@JavaOnlyStableParcelable parcelable IpPrefix cpp_header "binder/IpPrefix.h"; diff --git a/core/java/android/net/IpPrefix.java b/core/java/android/net/IpPrefix.java deleted file mode 100644 index e7c801475c4d..000000000000 --- a/core/java/android/net/IpPrefix.java +++ /dev/null @@ -1,300 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import android.annotation.IntRange; -import android.annotation.NonNull; -import android.annotation.SystemApi; -import android.os.Parcel; -import android.os.Parcelable; -import android.util.Pair; - -import java.net.Inet4Address; -import java.net.Inet6Address; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.Arrays; -import java.util.Comparator; - -/** - * This class represents an IP prefix, i.e., a contiguous block of IP addresses aligned on a - * power of two boundary (also known as an "IP subnet"). A prefix is specified by two pieces of - * information: - * - *

    - *
  • A starting IP address (IPv4 or IPv6). This is the first IP address of the prefix. - *
  • A prefix length. This specifies the length of the prefix by specifing the number of bits - * in the IP address, starting from the most significant bit in network byte order, that - * are constant for all addresses in the prefix. - *
- * - * For example, the prefix 192.0.2.0/24 covers the 256 IPv4 addresses from - * 192.0.2.0 to 192.0.2.255, inclusive, and the prefix - * 2001:db8:1:2 covers the 2^64 IPv6 addresses from 2001:db8:1:2:: to - * 2001:db8:1:2:ffff:ffff:ffff:ffff, inclusive. - * - * Objects of this class are immutable. - */ -public final class IpPrefix implements Parcelable { - private final byte[] address; // network byte order - private final int prefixLength; - - private void checkAndMaskAddressAndPrefixLength() { - if (address.length != 4 && address.length != 16) { - throw new IllegalArgumentException( - "IpPrefix has " + address.length + " bytes which is neither 4 nor 16"); - } - NetworkUtils.maskRawAddress(address, prefixLength); - } - - /** - * Constructs a new {@code IpPrefix} from a byte array containing an IPv4 or IPv6 address in - * network byte order and a prefix length. Silently truncates the address to the prefix length, - * so for example {@code 192.0.2.1/24} is silently converted to {@code 192.0.2.0/24}. - * - * @param address the IP address. Must be non-null and exactly 4 or 16 bytes long. - * @param prefixLength the prefix length. Must be >= 0 and <= (32 or 128) (IPv4 or IPv6). - * - * @hide - */ - public IpPrefix(@NonNull byte[] address, @IntRange(from = 0, to = 128) int prefixLength) { - this.address = address.clone(); - this.prefixLength = prefixLength; - checkAndMaskAddressAndPrefixLength(); - } - - /** - * Constructs a new {@code IpPrefix} from an IPv4 or IPv6 address and a prefix length. Silently - * truncates the address to the prefix length, so for example {@code 192.0.2.1/24} is silently - * converted to {@code 192.0.2.0/24}. - * - * @param address the IP address. Must be non-null. - * @param prefixLength the prefix length. Must be >= 0 and <= (32 or 128) (IPv4 or IPv6). - * @hide - */ - @SystemApi - public IpPrefix(@NonNull InetAddress address, @IntRange(from = 0, to = 128) int prefixLength) { - // We don't reuse the (byte[], int) constructor because it calls clone() on the byte array, - // which is unnecessary because getAddress() already returns a clone. - this.address = address.getAddress(); - this.prefixLength = prefixLength; - checkAndMaskAddressAndPrefixLength(); - } - - /** - * Constructs a new IpPrefix from a string such as "192.0.2.1/24" or "2001:db8::1/64". - * Silently truncates the address to the prefix length, so for example {@code 192.0.2.1/24} - * is silently converted to {@code 192.0.2.0/24}. - * - * @param prefix the prefix to parse - * - * @hide - */ - @SystemApi - public IpPrefix(@NonNull String prefix) { - // We don't reuse the (InetAddress, int) constructor because "error: call to this must be - // first statement in constructor". We could factor out setting the member variables to an - // init() method, but if we did, then we'd have to make the members non-final, or "error: - // cannot assign a value to final variable address". So we just duplicate the code here. - Pair ipAndMask = NetworkUtils.parseIpAndMask(prefix); - this.address = ipAndMask.first.getAddress(); - this.prefixLength = ipAndMask.second; - checkAndMaskAddressAndPrefixLength(); - } - - /** - * Compares this {@code IpPrefix} object against the specified object in {@code obj}. Two - * objects are equal if they have the same startAddress and prefixLength. - * - * @param obj the object to be tested for equality. - * @return {@code true} if both objects are equal, {@code false} otherwise. - */ - @Override - public boolean equals(Object obj) { - if (!(obj instanceof IpPrefix)) { - return false; - } - IpPrefix that = (IpPrefix) obj; - return Arrays.equals(this.address, that.address) && this.prefixLength == that.prefixLength; - } - - /** - * Gets the hashcode of the represented IP prefix. - * - * @return the appropriate hashcode value. - */ - @Override - public int hashCode() { - return Arrays.hashCode(address) + 11 * prefixLength; - } - - /** - * Returns a copy of the first IP address in the prefix. Modifying the returned object does not - * change this object's contents. - * - * @return the address in the form of a byte array. - */ - public @NonNull InetAddress getAddress() { - try { - return InetAddress.getByAddress(address); - } catch (UnknownHostException e) { - // Cannot happen. InetAddress.getByAddress can only throw an exception if the byte - // array is the wrong length, but we check that in the constructor. - throw new IllegalArgumentException("Address is invalid"); - } - } - - /** - * Returns a copy of the IP address bytes in network order (the highest order byte is the zeroth - * element). Modifying the returned array does not change this object's contents. - * - * @return the address in the form of a byte array. - */ - public @NonNull byte[] getRawAddress() { - return address.clone(); - } - - /** - * Returns the prefix length of this {@code IpPrefix}. - * - * @return the prefix length. - */ - @IntRange(from = 0, to = 128) - public int getPrefixLength() { - return prefixLength; - } - - /** - * Determines whether the prefix contains the specified address. - * - * @param address An {@link InetAddress} to test. - * @return {@code true} if the prefix covers the given address. {@code false} otherwise. - */ - public boolean contains(@NonNull InetAddress address) { - byte[] addrBytes = address.getAddress(); - if (addrBytes == null || addrBytes.length != this.address.length) { - return false; - } - NetworkUtils.maskRawAddress(addrBytes, prefixLength); - return Arrays.equals(this.address, addrBytes); - } - - /** - * Returns whether the specified prefix is entirely contained in this prefix. - * - * Note this is mathematical inclusion, so a prefix is always contained within itself. - * @param otherPrefix the prefix to test - * @hide - */ - public boolean containsPrefix(@NonNull IpPrefix otherPrefix) { - if (otherPrefix.getPrefixLength() < prefixLength) return false; - final byte[] otherAddress = otherPrefix.getRawAddress(); - NetworkUtils.maskRawAddress(otherAddress, prefixLength); - return Arrays.equals(otherAddress, address); - } - - /** - * @hide - */ - public boolean isIPv6() { - return getAddress() instanceof Inet6Address; - } - - /** - * @hide - */ - public boolean isIPv4() { - return getAddress() instanceof Inet4Address; - } - - /** - * Returns a string representation of this {@code IpPrefix}. - * - * @return a string such as {@code "192.0.2.0/24"} or {@code "2001:db8:1:2::/64"}. - */ - public String toString() { - try { - return InetAddress.getByAddress(address).getHostAddress() + "/" + prefixLength; - } catch(UnknownHostException e) { - // Cosmic rays? - throw new IllegalStateException("IpPrefix with invalid address! Shouldn't happen.", e); - } - } - - /** - * Implement the Parcelable interface. - */ - public int describeContents() { - return 0; - } - - /** - * Implement the Parcelable interface. - */ - public void writeToParcel(Parcel dest, int flags) { - dest.writeByteArray(address); - dest.writeInt(prefixLength); - } - - /** - * Returns a comparator ordering IpPrefixes by length, shorter to longer. - * Contents of the address will break ties. - * @hide - */ - public static Comparator lengthComparator() { - return new Comparator() { - @Override - public int compare(IpPrefix prefix1, IpPrefix prefix2) { - if (prefix1.isIPv4()) { - if (prefix2.isIPv6()) return -1; - } else { - if (prefix2.isIPv4()) return 1; - } - final int p1len = prefix1.getPrefixLength(); - final int p2len = prefix2.getPrefixLength(); - if (p1len < p2len) return -1; - if (p2len < p1len) return 1; - final byte[] a1 = prefix1.address; - final byte[] a2 = prefix2.address; - final int len = a1.length < a2.length ? a1.length : a2.length; - for (int i = 0; i < len; ++i) { - if (a1[i] < a2[i]) return -1; - if (a1[i] > a2[i]) return 1; - } - if (a2.length < len) return 1; - if (a1.length < len) return -1; - return 0; - } - }; - } - - /** - * Implement the Parcelable interface. - */ - public static final @android.annotation.NonNull Creator CREATOR = - new Creator() { - public IpPrefix createFromParcel(Parcel in) { - byte[] address = in.createByteArray(); - int prefixLength = in.readInt(); - return new IpPrefix(address, prefixLength); - } - - public IpPrefix[] newArray(int size) { - return new IpPrefix[size]; - } - }; -} diff --git a/core/java/android/net/KeepalivePacketData.aidl b/core/java/android/net/KeepalivePacketData.aidl deleted file mode 100644 index d456b53fd188..000000000000 --- a/core/java/android/net/KeepalivePacketData.aidl +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -parcelable KeepalivePacketData; diff --git a/core/java/android/net/KeepalivePacketData.java b/core/java/android/net/KeepalivePacketData.java deleted file mode 100644 index 5877f1f4e269..000000000000 --- a/core/java/android/net/KeepalivePacketData.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import static android.net.InvalidPacketException.ERROR_INVALID_IP_ADDRESS; -import static android.net.InvalidPacketException.ERROR_INVALID_PORT; - -import android.annotation.IntRange; -import android.annotation.NonNull; -import android.annotation.SystemApi; -import android.util.Log; - -import com.android.net.module.util.IpUtils; - -import java.net.InetAddress; - -/** - * Represents the actual packets that are sent by the - * {@link android.net.SocketKeepalive} API. - * @hide - */ -@SystemApi -public class KeepalivePacketData { - private static final String TAG = "KeepalivePacketData"; - - /** Source IP address */ - @NonNull - private final InetAddress mSrcAddress; - - /** Destination IP address */ - @NonNull - private final InetAddress mDstAddress; - - /** Source port */ - private final int mSrcPort; - - /** Destination port */ - private final int mDstPort; - - /** Packet data. A raw byte string of packet data, not including the link-layer header. */ - private final byte[] mPacket; - - // Note: If you add new fields, please modify the parcelling code in the child classes. - - - // This should only be constructed via static factory methods, such as - // nattKeepalivePacket. - /** - * A holding class for data necessary to build a keepalive packet. - */ - protected KeepalivePacketData(@NonNull InetAddress srcAddress, - @IntRange(from = 0, to = 65535) int srcPort, @NonNull InetAddress dstAddress, - @IntRange(from = 0, to = 65535) int dstPort, - @NonNull byte[] data) throws InvalidPacketException { - this.mSrcAddress = srcAddress; - this.mDstAddress = dstAddress; - this.mSrcPort = srcPort; - this.mDstPort = dstPort; - this.mPacket = data; - - // Check we have two IP addresses of the same family. - if (srcAddress == null || dstAddress == null || !srcAddress.getClass().getName() - .equals(dstAddress.getClass().getName())) { - Log.e(TAG, "Invalid or mismatched InetAddresses in KeepalivePacketData"); - throw new InvalidPacketException(ERROR_INVALID_IP_ADDRESS); - } - - // Check the ports. - if (!IpUtils.isValidUdpOrTcpPort(srcPort) || !IpUtils.isValidUdpOrTcpPort(dstPort)) { - Log.e(TAG, "Invalid ports in KeepalivePacketData"); - throw new InvalidPacketException(ERROR_INVALID_PORT); - } - } - - /** Get source IP address. */ - @NonNull - public InetAddress getSrcAddress() { - return mSrcAddress; - } - - /** Get destination IP address. */ - @NonNull - public InetAddress getDstAddress() { - return mDstAddress; - } - - /** Get source port number. */ - public int getSrcPort() { - return mSrcPort; - } - - /** Get destination port number. */ - public int getDstPort() { - return mDstPort; - } - - /** - * Returns a byte array of the given packet data. - */ - @NonNull - public byte[] getPacket() { - return mPacket.clone(); - } - -} diff --git a/core/java/android/net/LinkAddress.aidl b/core/java/android/net/LinkAddress.aidl deleted file mode 100644 index 9c804db08d61..000000000000 --- a/core/java/android/net/LinkAddress.aidl +++ /dev/null @@ -1,21 +0,0 @@ -/** - * - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -@JavaOnlyStableParcelable parcelable LinkAddress; - diff --git a/core/java/android/net/LinkAddress.java b/core/java/android/net/LinkAddress.java deleted file mode 100644 index 44d25a1ab0af..000000000000 --- a/core/java/android/net/LinkAddress.java +++ /dev/null @@ -1,549 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import static android.system.OsConstants.IFA_F_DADFAILED; -import static android.system.OsConstants.IFA_F_DEPRECATED; -import static android.system.OsConstants.IFA_F_OPTIMISTIC; -import static android.system.OsConstants.IFA_F_PERMANENT; -import static android.system.OsConstants.IFA_F_TENTATIVE; -import static android.system.OsConstants.RT_SCOPE_HOST; -import static android.system.OsConstants.RT_SCOPE_LINK; -import static android.system.OsConstants.RT_SCOPE_SITE; -import static android.system.OsConstants.RT_SCOPE_UNIVERSE; - -import android.annotation.IntRange; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.SystemApi; -import android.compat.annotation.UnsupportedAppUsage; -import android.os.Build; -import android.os.Parcel; -import android.os.Parcelable; -import android.os.SystemClock; -import android.util.Pair; - -import java.net.Inet4Address; -import java.net.Inet6Address; -import java.net.InetAddress; -import java.net.InterfaceAddress; -import java.net.UnknownHostException; -import java.util.Objects; - -/** - * Identifies an IP address on a network link. - * - * A {@code LinkAddress} consists of: - *
    - *
  • An IP address and prefix length (e.g., {@code 2001:db8::1/64} or {@code 192.0.2.1/24}). - * The address must be unicast, as multicast addresses cannot be assigned to interfaces. - *
  • Address flags: A bitmask of {@code OsConstants.IFA_F_*} values representing properties - * of the address (e.g., {@code android.system.OsConstants.IFA_F_OPTIMISTIC}). - *
  • Address scope: One of the {@code OsConstants.IFA_F_*} values; defines the scope in which - * the address is unique (e.g., - * {@code android.system.OsConstants.RT_SCOPE_LINK} or - * {@code android.system.OsConstants.RT_SCOPE_UNIVERSE}). - *
- */ -public class LinkAddress implements Parcelable { - - /** - * Indicates the deprecation or expiration time is unknown - * @hide - */ - @SystemApi - public static final long LIFETIME_UNKNOWN = -1; - - /** - * Indicates this address is permanent. - * @hide - */ - @SystemApi - public static final long LIFETIME_PERMANENT = Long.MAX_VALUE; - - /** - * IPv4 or IPv6 address. - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) - private InetAddress address; - - /** - * Prefix length. - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) - private int prefixLength; - - /** - * Address flags. A bitmask of {@code IFA_F_*} values. Note that {@link #getFlags()} may not - * return these exact values. For example, it may set or clear the {@code IFA_F_DEPRECATED} - * flag depending on the current preferred lifetime. - */ - private int flags; - - /** - * Address scope. One of the RT_SCOPE_* constants. - */ - private int scope; - - /** - * The time, as reported by {@link SystemClock#elapsedRealtime}, when this LinkAddress will be - * or was deprecated. At the time existing connections can still use this address until it - * expires, but new connections should use the new address. {@link #LIFETIME_UNKNOWN} indicates - * this information is not available. {@link #LIFETIME_PERMANENT} indicates this - * {@link LinkAddress} will never be deprecated. - */ - private long deprecationTime; - - /** - * The time, as reported by {@link SystemClock#elapsedRealtime}, when this {@link LinkAddress} - * will expire and be removed from the interface. {@link #LIFETIME_UNKNOWN} indicates this - * information is not available. {@link #LIFETIME_PERMANENT} indicates this {@link LinkAddress} - * will never expire. - */ - private long expirationTime; - - /** - * Utility function to determines the scope of a unicast address. Per RFC 4291 section 2.5 and - * RFC 6724 section 3.2. - * @hide - */ - private static int scopeForUnicastAddress(InetAddress addr) { - if (addr.isAnyLocalAddress()) { - return RT_SCOPE_HOST; - } - - if (addr.isLoopbackAddress() || addr.isLinkLocalAddress()) { - return RT_SCOPE_LINK; - } - - // isSiteLocalAddress() returns true for private IPv4 addresses, but RFC 6724 section 3.2 - // says that they are assigned global scope. - if (!(addr instanceof Inet4Address) && addr.isSiteLocalAddress()) { - return RT_SCOPE_SITE; - } - - return RT_SCOPE_UNIVERSE; - } - - /** - * Utility function to check if |address| is a Unique Local IPv6 Unicast Address - * (a.k.a. "ULA"; RFC 4193). - * - * Per RFC 4193 section 8, fc00::/7 identifies these addresses. - */ - private boolean isIpv6ULA() { - if (isIpv6()) { - byte[] bytes = address.getAddress(); - return ((bytes[0] & (byte)0xfe) == (byte)0xfc); - } - return false; - } - - /** - * @return true if the address is IPv6. - * @hide - */ - @SystemApi - public boolean isIpv6() { - return address instanceof Inet6Address; - } - - /** - * For backward compatibility. - * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely - * just yet. - * @return true if the address is IPv6. - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) - public boolean isIPv6() { - return isIpv6(); - } - - /** - * @return true if the address is IPv4 or is a mapped IPv4 address. - * @hide - */ - @SystemApi - public boolean isIpv4() { - return address instanceof Inet4Address; - } - - /** - * Utility function for the constructors. - */ - private void init(InetAddress address, int prefixLength, int flags, int scope, - long deprecationTime, long expirationTime) { - if (address == null || - address.isMulticastAddress() || - prefixLength < 0 || - (address instanceof Inet4Address && prefixLength > 32) || - (prefixLength > 128)) { - throw new IllegalArgumentException("Bad LinkAddress params " + address + - "/" + prefixLength); - } - - // deprecation time and expiration time must be both provided, or neither. - if ((deprecationTime == LIFETIME_UNKNOWN) != (expirationTime == LIFETIME_UNKNOWN)) { - throw new IllegalArgumentException( - "Must not specify only one of deprecation time and expiration time"); - } - - // deprecation time needs to be a positive value. - if (deprecationTime != LIFETIME_UNKNOWN && deprecationTime < 0) { - throw new IllegalArgumentException("invalid deprecation time " + deprecationTime); - } - - // expiration time needs to be a positive value. - if (expirationTime != LIFETIME_UNKNOWN && expirationTime < 0) { - throw new IllegalArgumentException("invalid expiration time " + expirationTime); - } - - // expiration time can't be earlier than deprecation time - if (deprecationTime != LIFETIME_UNKNOWN && expirationTime != LIFETIME_UNKNOWN - && expirationTime < deprecationTime) { - throw new IllegalArgumentException("expiration earlier than deprecation (" - + deprecationTime + ", " + expirationTime + ")"); - } - - this.address = address; - this.prefixLength = prefixLength; - this.flags = flags; - this.scope = scope; - this.deprecationTime = deprecationTime; - this.expirationTime = expirationTime; - } - - /** - * Constructs a new {@code LinkAddress} from an {@code InetAddress} and prefix length, with - * the specified flags and scope. Flags and scope are not checked for validity. - * - * @param address The IP address. - * @param prefixLength The prefix length. Must be >= 0 and <= (32 or 128) (IPv4 or IPv6). - * @param flags A bitmask of {@code IFA_F_*} values representing properties of the address. - * @param scope An integer defining the scope in which the address is unique (e.g., - * {@link OsConstants#RT_SCOPE_LINK} or {@link OsConstants#RT_SCOPE_SITE}). - * @hide - */ - @SystemApi - public LinkAddress(@NonNull InetAddress address, @IntRange(from = 0, to = 128) int prefixLength, - int flags, int scope) { - init(address, prefixLength, flags, scope, LIFETIME_UNKNOWN, LIFETIME_UNKNOWN); - } - - /** - * Constructs a new {@code LinkAddress} from an {@code InetAddress}, prefix length, with - * the specified flags, scope, deprecation time, and expiration time. Flags and scope are not - * checked for validity. The value of the {@code IFA_F_DEPRECATED} and {@code IFA_F_PERMANENT} - * flag will be adjusted based on the passed-in lifetimes. - * - * @param address The IP address. - * @param prefixLength The prefix length. Must be >= 0 and <= (32 or 128) (IPv4 or IPv6). - * @param flags A bitmask of {@code IFA_F_*} values representing properties of the address. - * @param scope An integer defining the scope in which the address is unique (e.g., - * {@link OsConstants#RT_SCOPE_LINK} or {@link OsConstants#RT_SCOPE_SITE}). - * @param deprecationTime The time, as reported by {@link SystemClock#elapsedRealtime}, when - * this {@link LinkAddress} will be or was deprecated. At the time - * existing connections can still use this address until it expires, but - * new connections should use the new address. {@link #LIFETIME_UNKNOWN} - * indicates this information is not available. - * {@link #LIFETIME_PERMANENT} indicates this {@link LinkAddress} will - * never be deprecated. - * @param expirationTime The time, as reported by {@link SystemClock#elapsedRealtime}, when this - * {@link LinkAddress} will expire and be removed from the interface. - * {@link #LIFETIME_UNKNOWN} indicates this information is not available. - * {@link #LIFETIME_PERMANENT} indicates this {@link LinkAddress} will - * never expire. - * @hide - */ - @SystemApi - public LinkAddress(@NonNull InetAddress address, @IntRange(from = 0, to = 128) int prefixLength, - int flags, int scope, long deprecationTime, long expirationTime) { - init(address, prefixLength, flags, scope, deprecationTime, expirationTime); - } - - /** - * Constructs a new {@code LinkAddress} from an {@code InetAddress} and a prefix length. - * The flags are set to zero and the scope is determined from the address. - * @param address The IP address. - * @param prefixLength The prefix length. Must be >= 0 and <= (32 or 128) (IPv4 or IPv6). - * @hide - */ - @SystemApi - public LinkAddress(@NonNull InetAddress address, - @IntRange(from = 0, to = 128) int prefixLength) { - this(address, prefixLength, 0, 0); - this.scope = scopeForUnicastAddress(address); - } - - /** - * Constructs a new {@code LinkAddress} from an {@code InterfaceAddress}. - * The flags are set to zero and the scope is determined from the address. - * @param interfaceAddress The interface address. - * @hide - */ - public LinkAddress(@NonNull InterfaceAddress interfaceAddress) { - this(interfaceAddress.getAddress(), - interfaceAddress.getNetworkPrefixLength()); - } - - /** - * Constructs a new {@code LinkAddress} from a string such as "192.0.2.5/24" or - * "2001:db8::1/64". The flags are set to zero and the scope is determined from the address. - * @param address The string to parse. - * @hide - */ - @SystemApi - public LinkAddress(@NonNull String address) { - this(address, 0, 0); - this.scope = scopeForUnicastAddress(this.address); - } - - /** - * Constructs a new {@code LinkAddress} from a string such as "192.0.2.5/24" or - * "2001:db8::1/64", with the specified flags and scope. - * @param address The string to parse. - * @param flags The address flags. - * @param scope The address scope. - * @hide - */ - @SystemApi - public LinkAddress(@NonNull String address, int flags, int scope) { - // This may throw an IllegalArgumentException; catching it is the caller's responsibility. - // TODO: consider rejecting mapped IPv4 addresses such as "::ffff:192.0.2.5/24". - Pair ipAndMask = NetworkUtils.parseIpAndMask(address); - init(ipAndMask.first, ipAndMask.second, flags, scope, LIFETIME_UNKNOWN, LIFETIME_UNKNOWN); - } - - /** - * Returns a string representation of this address, such as "192.0.2.1/24" or "2001:db8::1/64". - * The string representation does not contain the flags and scope, just the address and prefix - * length. - */ - @Override - public String toString() { - return address.getHostAddress() + "/" + prefixLength; - } - - /** - * Compares this {@code LinkAddress} instance against {@code obj}. Two addresses are equal if - * their address, prefix length, flags and scope are equal. Thus, for example, two addresses - * that have the same address and prefix length are not equal if one of them is deprecated and - * the other is not. - * - * @param obj the object to be tested for equality. - * @return {@code true} if both objects are equal, {@code false} otherwise. - */ - @Override - public boolean equals(Object obj) { - if (!(obj instanceof LinkAddress)) { - return false; - } - LinkAddress linkAddress = (LinkAddress) obj; - return this.address.equals(linkAddress.address) - && this.prefixLength == linkAddress.prefixLength - && this.flags == linkAddress.flags - && this.scope == linkAddress.scope - && this.deprecationTime == linkAddress.deprecationTime - && this.expirationTime == linkAddress.expirationTime; - } - - /** - * Returns a hashcode for this address. - */ - @Override - public int hashCode() { - return Objects.hash(address, prefixLength, flags, scope, deprecationTime, expirationTime); - } - - /** - * Determines whether this {@code LinkAddress} and the provided {@code LinkAddress} - * represent the same address. Two {@code LinkAddresses} represent the same address - * if they have the same IP address and prefix length, even if their properties are - * different. - * - * @param other the {@code LinkAddress} to compare to. - * @return {@code true} if both objects have the same address and prefix length, {@code false} - * otherwise. - * @hide - */ - @SystemApi - public boolean isSameAddressAs(@Nullable LinkAddress other) { - if (other == null) { - return false; - } - return address.equals(other.address) && prefixLength == other.prefixLength; - } - - /** - * Returns the {@link InetAddress} of this {@code LinkAddress}. - */ - public InetAddress getAddress() { - return address; - } - - /** - * Returns the prefix length of this {@code LinkAddress}. - */ - @IntRange(from = 0, to = 128) - public int getPrefixLength() { - return prefixLength; - } - - /** - * Returns the prefix length of this {@code LinkAddress}. - * TODO: Delete all callers and remove in favour of getPrefixLength(). - * @hide - */ - @UnsupportedAppUsage - @IntRange(from = 0, to = 128) - public int getNetworkPrefixLength() { - return getPrefixLength(); - } - - /** - * Returns the flags of this {@code LinkAddress}. - */ - public int getFlags() { - int flags = this.flags; - if (deprecationTime != LIFETIME_UNKNOWN) { - if (SystemClock.elapsedRealtime() >= deprecationTime) { - flags |= IFA_F_DEPRECATED; - } else { - // If deprecation time is in the future, or permanent. - flags &= ~IFA_F_DEPRECATED; - } - } - - if (expirationTime == LIFETIME_PERMANENT) { - flags |= IFA_F_PERMANENT; - } else if (expirationTime != LIFETIME_UNKNOWN) { - // If we know this address expired or will expire in the future, then this address - // should not be permanent. - flags &= ~IFA_F_PERMANENT; - } - - // Do no touch the original flags. Return the adjusted flags here. - return flags; - } - - /** - * Returns the scope of this {@code LinkAddress}. - */ - public int getScope() { - return scope; - } - - /** - * Get the deprecation time, as reported by {@link SystemClock#elapsedRealtime}, when this - * {@link LinkAddress} will be or was deprecated. At the time existing connections can still use - * this address until it expires, but new connections should use the new address. - * - * @return The deprecation time in milliseconds. {@link #LIFETIME_UNKNOWN} indicates this - * information is not available. {@link #LIFETIME_PERMANENT} indicates this {@link LinkAddress} - * will never be deprecated. - * - * @hide - */ - @SystemApi - public long getDeprecationTime() { - return deprecationTime; - } - - /** - * Get the expiration time, as reported by {@link SystemClock#elapsedRealtime}, when this - * {@link LinkAddress} will expire and be removed from the interface. - * - * @return The expiration time in milliseconds. {@link #LIFETIME_UNKNOWN} indicates this - * information is not available. {@link #LIFETIME_PERMANENT} indicates this {@link LinkAddress} - * will never expire. - * - * @hide - */ - @SystemApi - public long getExpirationTime() { - return expirationTime; - } - - /** - * Returns true if this {@code LinkAddress} is global scope and preferred (i.e., not currently - * deprecated). - * - * @hide - */ - @SystemApi - public boolean isGlobalPreferred() { - /** - * Note that addresses flagged as IFA_F_OPTIMISTIC are - * simultaneously flagged as IFA_F_TENTATIVE (when the tentative - * state has cleared either DAD has succeeded or failed, and both - * flags are cleared regardless). - */ - int flags = getFlags(); - return (scope == RT_SCOPE_UNIVERSE - && !isIpv6ULA() - && (flags & (IFA_F_DADFAILED | IFA_F_DEPRECATED)) == 0L - && ((flags & IFA_F_TENTATIVE) == 0L || (flags & IFA_F_OPTIMISTIC) != 0L)); - } - - /** - * Implement the Parcelable interface. - */ - public int describeContents() { - return 0; - } - - /** - * Implement the Parcelable interface. - */ - public void writeToParcel(Parcel dest, int flags) { - dest.writeByteArray(address.getAddress()); - dest.writeInt(prefixLength); - dest.writeInt(this.flags); - dest.writeInt(scope); - dest.writeLong(deprecationTime); - dest.writeLong(expirationTime); - } - - /** - * Implement the Parcelable interface. - */ - public static final @android.annotation.NonNull Creator CREATOR = - new Creator() { - public LinkAddress createFromParcel(Parcel in) { - InetAddress address = null; - try { - address = InetAddress.getByAddress(in.createByteArray()); - } catch (UnknownHostException e) { - // Nothing we can do here. When we call the constructor, we'll throw an - // IllegalArgumentException, because a LinkAddress can't have a null - // InetAddress. - } - int prefixLength = in.readInt(); - int flags = in.readInt(); - int scope = in.readInt(); - long deprecationTime = in.readLong(); - long expirationTime = in.readLong(); - return new LinkAddress(address, prefixLength, flags, scope, deprecationTime, - expirationTime); - } - - public LinkAddress[] newArray(int size) { - return new LinkAddress[size]; - } - }; -} diff --git a/core/java/android/net/LinkProperties.aidl b/core/java/android/net/LinkProperties.aidl deleted file mode 100644 index a8b3c7b0392f..000000000000 --- a/core/java/android/net/LinkProperties.aidl +++ /dev/null @@ -1,20 +0,0 @@ -/* -** -** Copyright (C) 2010 The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -package android.net; - -@JavaOnlyStableParcelable parcelable LinkProperties; diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java deleted file mode 100644 index 486e2d74dd05..000000000000 --- a/core/java/android/net/LinkProperties.java +++ /dev/null @@ -1,1823 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.SystemApi; -import android.compat.annotation.UnsupportedAppUsage; -import android.os.Build; -import android.os.Parcel; -import android.os.Parcelable; -import android.text.TextUtils; - -import com.android.net.module.util.LinkPropertiesUtils; - -import java.net.Inet4Address; -import java.net.Inet6Address; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Hashtable; -import java.util.List; -import java.util.Objects; -import java.util.StringJoiner; - -/** - * Describes the properties of a network link. - * - * A link represents a connection to a network. - * It may have multiple addresses and multiple gateways, - * multiple dns servers but only one http proxy and one - * network interface. - * - * Note that this is just a holder of data. Modifying it - * does not affect live networks. - * - */ -public final class LinkProperties implements Parcelable { - // The interface described by the network link. - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) - private String mIfaceName; - private final ArrayList mLinkAddresses = new ArrayList<>(); - private final ArrayList mDnses = new ArrayList<>(); - // PCSCF addresses are addresses of SIP proxies that only exist for the IMS core service. - private final ArrayList mPcscfs = new ArrayList(); - private final ArrayList mValidatedPrivateDnses = new ArrayList<>(); - private boolean mUsePrivateDns; - private String mPrivateDnsServerName; - private String mDomains; - private ArrayList mRoutes = new ArrayList<>(); - private Inet4Address mDhcpServerAddress; - private ProxyInfo mHttpProxy; - private int mMtu; - // in the format "rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max" - private String mTcpBufferSizes; - private IpPrefix mNat64Prefix; - private boolean mWakeOnLanSupported; - private Uri mCaptivePortalApiUrl; - private CaptivePortalData mCaptivePortalData; - - /** - * Indicates whether parceling should preserve fields that are set based on permissions of - * the process receiving the {@link LinkProperties}. - */ - private final transient boolean mParcelSensitiveFields; - - private static final int MIN_MTU = 68; - - private static final int MIN_MTU_V6 = 1280; - - private static final int MAX_MTU = 10000; - - private static final int INET6_ADDR_LENGTH = 16; - - // Stores the properties of links that are "stacked" above this link. - // Indexed by interface name to allow modification and to prevent duplicates being added. - private Hashtable mStackedLinks = new Hashtable<>(); - - /** - * @hide - */ - @UnsupportedAppUsage(implicitMember = - "values()[Landroid/net/LinkProperties$ProvisioningChange;") - public enum ProvisioningChange { - @UnsupportedAppUsage - STILL_NOT_PROVISIONED, - @UnsupportedAppUsage - LOST_PROVISIONING, - @UnsupportedAppUsage - GAINED_PROVISIONING, - @UnsupportedAppUsage - STILL_PROVISIONED, - } - - /** - * Compare the provisioning states of two LinkProperties instances. - * - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public static ProvisioningChange compareProvisioning( - LinkProperties before, LinkProperties after) { - if (before.isProvisioned() && after.isProvisioned()) { - // On dual-stack networks, DHCPv4 renewals can occasionally fail. - // When this happens, IPv6-reachable services continue to function - // normally but IPv4-only services (naturally) fail. - // - // When an application using an IPv4-only service reports a bad - // network condition to the framework, attempts to re-validate - // the network succeed (since we support IPv6-only networks) and - // nothing is changed. - // - // For users, this is confusing and unexpected behaviour, and is - // not necessarily easy to diagnose. Therefore, we treat changing - // from a dual-stack network to an IPv6-only network equivalent to - // a total loss of provisioning. - // - // For one such example of this, see b/18867306. - // - // Additionally, losing IPv6 provisioning can result in TCP - // connections getting stuck until timeouts fire and other - // baffling failures. Therefore, loss of either IPv4 or IPv6 on a - // previously dual-stack network is deemed a lost of provisioning. - if ((before.isIpv4Provisioned() && !after.isIpv4Provisioned()) - || (before.isIpv6Provisioned() && !after.isIpv6Provisioned())) { - return ProvisioningChange.LOST_PROVISIONING; - } - return ProvisioningChange.STILL_PROVISIONED; - } else if (before.isProvisioned() && !after.isProvisioned()) { - return ProvisioningChange.LOST_PROVISIONING; - } else if (!before.isProvisioned() && after.isProvisioned()) { - return ProvisioningChange.GAINED_PROVISIONING; - } else { // !before.isProvisioned() && !after.isProvisioned() - return ProvisioningChange.STILL_NOT_PROVISIONED; - } - } - - /** - * Constructs a new {@code LinkProperties} with default values. - */ - public LinkProperties() { - mParcelSensitiveFields = false; - } - - /** - * @hide - */ - @SystemApi - public LinkProperties(@Nullable LinkProperties source) { - this(source, false /* parcelSensitiveFields */); - } - - /** - * Create a copy of a {@link LinkProperties} that may preserve fields that were set - * based on the permissions of the process that originally received it. - * - *

By default {@link LinkProperties} does not preserve such fields during parceling, as - * they should not be shared outside of the process that receives them without appropriate - * checks. - * @param parcelSensitiveFields Whether the sensitive fields should be kept when parceling - * @hide - */ - @SystemApi - public LinkProperties(@Nullable LinkProperties source, boolean parcelSensitiveFields) { - mParcelSensitiveFields = parcelSensitiveFields; - if (source == null) return; - mIfaceName = source.mIfaceName; - mLinkAddresses.addAll(source.mLinkAddresses); - mDnses.addAll(source.mDnses); - mValidatedPrivateDnses.addAll(source.mValidatedPrivateDnses); - mUsePrivateDns = source.mUsePrivateDns; - mPrivateDnsServerName = source.mPrivateDnsServerName; - mPcscfs.addAll(source.mPcscfs); - mDomains = source.mDomains; - mRoutes.addAll(source.mRoutes); - mHttpProxy = (source.mHttpProxy == null) ? null : new ProxyInfo(source.mHttpProxy); - for (LinkProperties l: source.mStackedLinks.values()) { - addStackedLink(l); - } - setMtu(source.mMtu); - setDhcpServerAddress(source.getDhcpServerAddress()); - mTcpBufferSizes = source.mTcpBufferSizes; - mNat64Prefix = source.mNat64Prefix; - mWakeOnLanSupported = source.mWakeOnLanSupported; - mCaptivePortalApiUrl = source.mCaptivePortalApiUrl; - mCaptivePortalData = source.mCaptivePortalData; - } - - /** - * Sets the interface name for this link. All {@link RouteInfo} already set for this - * will have their interface changed to match this new value. - * - * @param iface The name of the network interface used for this link. - */ - public void setInterfaceName(@Nullable String iface) { - mIfaceName = iface; - ArrayList newRoutes = new ArrayList<>(mRoutes.size()); - for (RouteInfo route : mRoutes) { - newRoutes.add(routeWithInterface(route)); - } - mRoutes = newRoutes; - } - - /** - * Gets the interface name for this link. May be {@code null} if not set. - * - * @return The interface name set for this link or {@code null}. - */ - public @Nullable String getInterfaceName() { - return mIfaceName; - } - - /** - * @hide - */ - @SystemApi - public @NonNull List getAllInterfaceNames() { - List interfaceNames = new ArrayList<>(mStackedLinks.size() + 1); - if (mIfaceName != null) interfaceNames.add(mIfaceName); - for (LinkProperties stacked: mStackedLinks.values()) { - interfaceNames.addAll(stacked.getAllInterfaceNames()); - } - return interfaceNames; - } - - /** - * Returns all the addresses on this link. We often think of a link having a single address, - * however, particularly with Ipv6 several addresses are typical. Note that the - * {@code LinkProperties} actually contains {@link LinkAddress} objects which also include - * prefix lengths for each address. This is a simplified utility alternative to - * {@link LinkProperties#getLinkAddresses}. - * - * @return An unmodifiable {@link List} of {@link InetAddress} for this link. - * @hide - */ - @SystemApi - public @NonNull List getAddresses() { - final List addresses = new ArrayList<>(); - for (LinkAddress linkAddress : mLinkAddresses) { - addresses.add(linkAddress.getAddress()); - } - return Collections.unmodifiableList(addresses); - } - - /** - * Returns all the addresses on this link and all the links stacked above it. - * @hide - */ - @UnsupportedAppUsage - public @NonNull List getAllAddresses() { - List addresses = new ArrayList<>(); - for (LinkAddress linkAddress : mLinkAddresses) { - addresses.add(linkAddress.getAddress()); - } - for (LinkProperties stacked: mStackedLinks.values()) { - addresses.addAll(stacked.getAllAddresses()); - } - return addresses; - } - - private int findLinkAddressIndex(LinkAddress address) { - for (int i = 0; i < mLinkAddresses.size(); i++) { - if (mLinkAddresses.get(i).isSameAddressAs(address)) { - return i; - } - } - return -1; - } - - /** - * Adds a {@link LinkAddress} to this {@code LinkProperties} if a {@link LinkAddress} of the - * same address/prefix does not already exist. If it does exist it is replaced. - * @param address The {@code LinkAddress} to add. - * @return true if {@code address} was added or updated, false otherwise. - * @hide - */ - @SystemApi - public boolean addLinkAddress(@NonNull LinkAddress address) { - if (address == null) { - return false; - } - int i = findLinkAddressIndex(address); - if (i < 0) { - // Address was not present. Add it. - mLinkAddresses.add(address); - return true; - } else if (mLinkAddresses.get(i).equals(address)) { - // Address was present and has same properties. Do nothing. - return false; - } else { - // Address was present and has different properties. Update it. - mLinkAddresses.set(i, address); - return true; - } - } - - /** - * Removes a {@link LinkAddress} from this {@code LinkProperties}. Specifically, matches - * and {@link LinkAddress} with the same address and prefix. - * - * @param toRemove A {@link LinkAddress} specifying the address to remove. - * @return true if the address was removed, false if it did not exist. - * @hide - */ - @SystemApi - public boolean removeLinkAddress(@NonNull LinkAddress toRemove) { - int i = findLinkAddressIndex(toRemove); - if (i >= 0) { - mLinkAddresses.remove(i); - return true; - } - return false; - } - - /** - * Returns all the {@link LinkAddress} on this link. Typically a link will have - * one IPv4 address and one or more IPv6 addresses. - * - * @return An unmodifiable {@link List} of {@link LinkAddress} for this link. - */ - public @NonNull List getLinkAddresses() { - return Collections.unmodifiableList(mLinkAddresses); - } - - /** - * Returns all the addresses on this link and all the links stacked above it. - * @hide - */ - @SystemApi - public @NonNull List getAllLinkAddresses() { - List addresses = new ArrayList<>(mLinkAddresses); - for (LinkProperties stacked: mStackedLinks.values()) { - addresses.addAll(stacked.getAllLinkAddresses()); - } - return addresses; - } - - /** - * Replaces the {@link LinkAddress} in this {@code LinkProperties} with - * the given {@link Collection} of {@link LinkAddress}. - * - * @param addresses The {@link Collection} of {@link LinkAddress} to set in this - * object. - */ - public void setLinkAddresses(@NonNull Collection addresses) { - mLinkAddresses.clear(); - for (LinkAddress address: addresses) { - addLinkAddress(address); - } - } - - /** - * Adds the given {@link InetAddress} to the list of DNS servers, if not present. - * - * @param dnsServer The {@link InetAddress} to add to the list of DNS servers. - * @return true if the DNS server was added, false if it was already present. - * @hide - */ - @SystemApi - public boolean addDnsServer(@NonNull InetAddress dnsServer) { - if (dnsServer != null && !mDnses.contains(dnsServer)) { - mDnses.add(dnsServer); - return true; - } - return false; - } - - /** - * Removes the given {@link InetAddress} from the list of DNS servers. - * - * @param dnsServer The {@link InetAddress} to remove from the list of DNS servers. - * @return true if the DNS server was removed, false if it did not exist. - * @hide - */ - @SystemApi - public boolean removeDnsServer(@NonNull InetAddress dnsServer) { - return mDnses.remove(dnsServer); - } - - /** - * Replaces the DNS servers in this {@code LinkProperties} with - * the given {@link Collection} of {@link InetAddress} objects. - * - * @param dnsServers The {@link Collection} of DNS servers to set in this object. - */ - public void setDnsServers(@NonNull Collection dnsServers) { - mDnses.clear(); - for (InetAddress dnsServer: dnsServers) { - addDnsServer(dnsServer); - } - } - - /** - * Returns all the {@link InetAddress} for DNS servers on this link. - * - * @return An unmodifiable {@link List} of {@link InetAddress} for DNS servers on - * this link. - */ - public @NonNull List getDnsServers() { - return Collections.unmodifiableList(mDnses); - } - - /** - * Set whether private DNS is currently in use on this network. - * - * @param usePrivateDns The private DNS state. - * @hide - */ - @SystemApi - public void setUsePrivateDns(boolean usePrivateDns) { - mUsePrivateDns = usePrivateDns; - } - - /** - * Returns whether private DNS is currently in use on this network. When - * private DNS is in use, applications must not send unencrypted DNS - * queries as doing so could reveal private user information. Furthermore, - * if private DNS is in use and {@link #getPrivateDnsServerName} is not - * {@code null}, DNS queries must be sent to the specified DNS server. - * - * @return {@code true} if private DNS is in use, {@code false} otherwise. - */ - public boolean isPrivateDnsActive() { - return mUsePrivateDns; - } - - /** - * Set the name of the private DNS server to which private DNS queries - * should be sent when in strict mode. This value should be {@code null} - * when private DNS is off or in opportunistic mode. - * - * @param privateDnsServerName The private DNS server name. - * @hide - */ - @SystemApi - public void setPrivateDnsServerName(@Nullable String privateDnsServerName) { - mPrivateDnsServerName = privateDnsServerName; - } - - /** - * Set DHCP server address. - * - * @param serverAddress the server address to set. - */ - public void setDhcpServerAddress(@Nullable Inet4Address serverAddress) { - mDhcpServerAddress = serverAddress; - } - - /** - * Get DHCP server address - * - * @return The current DHCP server address. - */ - public @Nullable Inet4Address getDhcpServerAddress() { - return mDhcpServerAddress; - } - - /** - * Returns the private DNS server name that is in use. If not {@code null}, - * private DNS is in strict mode. In this mode, applications should ensure - * that all DNS queries are encrypted and sent to this hostname and that - * queries are only sent if the hostname's certificate is valid. If - * {@code null} and {@link #isPrivateDnsActive} is {@code true}, private - * DNS is in opportunistic mode, and applications should ensure that DNS - * queries are encrypted and sent to a DNS server returned by - * {@link #getDnsServers}. System DNS will handle each of these cases - * correctly, but applications implementing their own DNS lookups must make - * sure to follow these requirements. - * - * @return The private DNS server name. - */ - public @Nullable String getPrivateDnsServerName() { - return mPrivateDnsServerName; - } - - /** - * Adds the given {@link InetAddress} to the list of validated private DNS servers, - * if not present. This is distinct from the server name in that these are actually - * resolved addresses. - * - * @param dnsServer The {@link InetAddress} to add to the list of validated private DNS servers. - * @return true if the DNS server was added, false if it was already present. - * @hide - */ - public boolean addValidatedPrivateDnsServer(@NonNull InetAddress dnsServer) { - if (dnsServer != null && !mValidatedPrivateDnses.contains(dnsServer)) { - mValidatedPrivateDnses.add(dnsServer); - return true; - } - return false; - } - - /** - * Removes the given {@link InetAddress} from the list of validated private DNS servers. - * - * @param dnsServer The {@link InetAddress} to remove from the list of validated private DNS - * servers. - * @return true if the DNS server was removed, false if it did not exist. - * @hide - */ - public boolean removeValidatedPrivateDnsServer(@NonNull InetAddress dnsServer) { - return mValidatedPrivateDnses.remove(dnsServer); - } - - /** - * Replaces the validated private DNS servers in this {@code LinkProperties} with - * the given {@link Collection} of {@link InetAddress} objects. - * - * @param dnsServers The {@link Collection} of validated private DNS servers to set in this - * object. - * @hide - */ - @SystemApi - public void setValidatedPrivateDnsServers(@NonNull Collection dnsServers) { - mValidatedPrivateDnses.clear(); - for (InetAddress dnsServer: dnsServers) { - addValidatedPrivateDnsServer(dnsServer); - } - } - - /** - * Returns all the {@link InetAddress} for validated private DNS servers on this link. - * These are resolved from the private DNS server name. - * - * @return An unmodifiable {@link List} of {@link InetAddress} for validated private - * DNS servers on this link. - * @hide - */ - @SystemApi - public @NonNull List getValidatedPrivateDnsServers() { - return Collections.unmodifiableList(mValidatedPrivateDnses); - } - - /** - * Adds the given {@link InetAddress} to the list of PCSCF servers, if not present. - * - * @param pcscfServer The {@link InetAddress} to add to the list of PCSCF servers. - * @return true if the PCSCF server was added, false otherwise. - * @hide - */ - @SystemApi - public boolean addPcscfServer(@NonNull InetAddress pcscfServer) { - if (pcscfServer != null && !mPcscfs.contains(pcscfServer)) { - mPcscfs.add(pcscfServer); - return true; - } - return false; - } - - /** - * Removes the given {@link InetAddress} from the list of PCSCF servers. - * - * @param pcscfServer The {@link InetAddress} to remove from the list of PCSCF servers. - * @return true if the PCSCF server was removed, false otherwise. - * @hide - */ - public boolean removePcscfServer(@NonNull InetAddress pcscfServer) { - return mPcscfs.remove(pcscfServer); - } - - /** - * Replaces the PCSCF servers in this {@code LinkProperties} with - * the given {@link Collection} of {@link InetAddress} objects. - * - * @param pcscfServers The {@link Collection} of PCSCF servers to set in this object. - * @hide - */ - @SystemApi - public void setPcscfServers(@NonNull Collection pcscfServers) { - mPcscfs.clear(); - for (InetAddress pcscfServer: pcscfServers) { - addPcscfServer(pcscfServer); - } - } - - /** - * Returns all the {@link InetAddress} for PCSCF servers on this link. - * - * @return An unmodifiable {@link List} of {@link InetAddress} for PCSCF servers on - * this link. - * @hide - */ - @SystemApi - public @NonNull List getPcscfServers() { - return Collections.unmodifiableList(mPcscfs); - } - - /** - * Sets the DNS domain search path used on this link. - * - * @param domains A {@link String} listing in priority order the comma separated - * domains to search when resolving host names on this link. - */ - public void setDomains(@Nullable String domains) { - mDomains = domains; - } - - /** - * Get the DNS domains search path set for this link. May be {@code null} if not set. - * - * @return A {@link String} containing the comma separated domains to search when resolving host - * names on this link or {@code null}. - */ - public @Nullable String getDomains() { - return mDomains; - } - - /** - * Sets the Maximum Transmission Unit size to use on this link. This should not be used - * unless the system default (1500) is incorrect. Values less than 68 or greater than - * 10000 will be ignored. - * - * @param mtu The MTU to use for this link. - */ - public void setMtu(int mtu) { - mMtu = mtu; - } - - /** - * Gets any non-default MTU size set for this link. Note that if the default is being used - * this will return 0. - * - * @return The mtu value set for this link. - */ - public int getMtu() { - return mMtu; - } - - /** - * Sets the tcp buffers sizes to be used when this link is the system default. - * Should be of the form "rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max". - * - * @param tcpBufferSizes The tcp buffers sizes to use. - * - * @hide - */ - @SystemApi - public void setTcpBufferSizes(@Nullable String tcpBufferSizes) { - mTcpBufferSizes = tcpBufferSizes; - } - - /** - * Gets the tcp buffer sizes. May be {@code null} if not set. - * - * @return the tcp buffer sizes to use when this link is the system default or {@code null}. - * - * @hide - */ - @SystemApi - public @Nullable String getTcpBufferSizes() { - return mTcpBufferSizes; - } - - private RouteInfo routeWithInterface(RouteInfo route) { - return new RouteInfo( - route.getDestination(), - route.getGateway(), - mIfaceName, - route.getType(), - route.getMtu()); - } - - private int findRouteIndexByRouteKey(RouteInfo route) { - for (int i = 0; i < mRoutes.size(); i++) { - if (mRoutes.get(i).getRouteKey().equals(route.getRouteKey())) { - return i; - } - } - return -1; - } - - /** - * Adds a {@link RouteInfo} to this {@code LinkProperties}, if a {@link RouteInfo} - * with the same {@link RouteInfo.RouteKey} with different properties - * (e.g., different MTU), it will be updated. If the {@link RouteInfo} had an - * interface name set and that differs from the interface set for this - * {@code LinkProperties} an {@link IllegalArgumentException} will be thrown. - * The proper course is to add either un-named or properly named {@link RouteInfo}. - * - * @param route A {@link RouteInfo} to add to this object. - * @return {@code true} was added or updated, false otherwise. - */ - public boolean addRoute(@NonNull RouteInfo route) { - String routeIface = route.getInterface(); - if (routeIface != null && !routeIface.equals(mIfaceName)) { - throw new IllegalArgumentException( - "Route added with non-matching interface: " + routeIface - + " vs. " + mIfaceName); - } - route = routeWithInterface(route); - - int i = findRouteIndexByRouteKey(route); - if (i == -1) { - // Route was not present. Add it. - mRoutes.add(route); - return true; - } else if (mRoutes.get(i).equals(route)) { - // Route was present and has same properties. Do nothing. - return false; - } else { - // Route was present and has different properties. Update it. - mRoutes.set(i, route); - return true; - } - } - - /** - * Removes a {@link RouteInfo} from this {@code LinkProperties}, if present. The route must - * specify an interface and the interface must match the interface of this - * {@code LinkProperties}, or it will not be removed. - * - * @param route A {@link RouteInfo} specifying the route to remove. - * @return {@code true} if the route was removed, {@code false} if it was not present. - * - * @hide - */ - @SystemApi - public boolean removeRoute(@NonNull RouteInfo route) { - return Objects.equals(mIfaceName, route.getInterface()) && mRoutes.remove(route); - } - - /** - * Returns all the {@link RouteInfo} set on this link. - * - * @return An unmodifiable {@link List} of {@link RouteInfo} for this link. - */ - public @NonNull List getRoutes() { - return Collections.unmodifiableList(mRoutes); - } - - /** - * Make sure this LinkProperties instance contains routes that cover the local subnet - * of its link addresses. Add any route that is missing. - * @hide - */ - public void ensureDirectlyConnectedRoutes() { - for (LinkAddress addr : mLinkAddresses) { - addRoute(new RouteInfo(addr, null, mIfaceName)); - } - } - - /** - * Returns all the routes on this link and all the links stacked above it. - * @hide - */ - @SystemApi - public @NonNull List getAllRoutes() { - List routes = new ArrayList<>(mRoutes); - for (LinkProperties stacked: mStackedLinks.values()) { - routes.addAll(stacked.getAllRoutes()); - } - return routes; - } - - /** - * Sets the recommended {@link ProxyInfo} to use on this link, or {@code null} for none. - * Note that Http Proxies are only a hint - the system recommends their use, but it does - * not enforce it and applications may ignore them. - * - * @param proxy A {@link ProxyInfo} defining the HTTP Proxy to use on this link. - */ - public void setHttpProxy(@Nullable ProxyInfo proxy) { - mHttpProxy = proxy; - } - - /** - * Gets the recommended {@link ProxyInfo} (or {@code null}) set on this link. - * - * @return The {@link ProxyInfo} set on this link or {@code null}. - */ - public @Nullable ProxyInfo getHttpProxy() { - return mHttpProxy; - } - - /** - * Returns the NAT64 prefix in use on this link, if any. - * - * @return the NAT64 prefix or {@code null}. - */ - public @Nullable IpPrefix getNat64Prefix() { - return mNat64Prefix; - } - - /** - * Sets the NAT64 prefix in use on this link. - * - * Currently, only 96-bit prefixes (i.e., where the 32-bit IPv4 address is at the end of the - * 128-bit IPv6 address) are supported or {@code null} for no prefix. - * - * @param prefix the NAT64 prefix. - */ - public void setNat64Prefix(@Nullable IpPrefix prefix) { - if (prefix != null && prefix.getPrefixLength() != 96) { - throw new IllegalArgumentException("Only 96-bit prefixes are supported: " + prefix); - } - mNat64Prefix = prefix; // IpPrefix objects are immutable. - } - - /** - * Adds a stacked link. - * - * If there is already a stacked link with the same interface name as link, - * that link is replaced with link. Otherwise, link is added to the list - * of stacked links. - * - * @param link The link to add. - * @return true if the link was stacked, false otherwise. - * @hide - */ - @UnsupportedAppUsage - public boolean addStackedLink(@NonNull LinkProperties link) { - if (link.getInterfaceName() != null) { - mStackedLinks.put(link.getInterfaceName(), link); - return true; - } - return false; - } - - /** - * Removes a stacked link. - * - * If there is a stacked link with the given interface name, it is - * removed. Otherwise, nothing changes. - * - * @param iface The interface name of the link to remove. - * @return true if the link was removed, false otherwise. - * @hide - */ - public boolean removeStackedLink(@NonNull String iface) { - LinkProperties removed = mStackedLinks.remove(iface); - return removed != null; - } - - /** - * Returns all the links stacked on top of this link. - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public @NonNull List getStackedLinks() { - if (mStackedLinks.isEmpty()) { - return Collections.emptyList(); - } - final List stacked = new ArrayList<>(); - for (LinkProperties link : mStackedLinks.values()) { - stacked.add(new LinkProperties(link)); - } - return Collections.unmodifiableList(stacked); - } - - /** - * Clears this object to its initial state. - */ - public void clear() { - if (mParcelSensitiveFields) { - throw new UnsupportedOperationException( - "Cannot clear LinkProperties when parcelSensitiveFields is set"); - } - - mIfaceName = null; - mLinkAddresses.clear(); - mDnses.clear(); - mUsePrivateDns = false; - mPrivateDnsServerName = null; - mPcscfs.clear(); - mDomains = null; - mRoutes.clear(); - mHttpProxy = null; - mStackedLinks.clear(); - mMtu = 0; - mDhcpServerAddress = null; - mTcpBufferSizes = null; - mNat64Prefix = null; - mWakeOnLanSupported = false; - mCaptivePortalApiUrl = null; - mCaptivePortalData = null; - } - - /** - * Implement the Parcelable interface - */ - public int describeContents() { - return 0; - } - - @Override - public String toString() { - // Space as a separator, so no need for spaces at start/end of the individual fragments. - final StringJoiner resultJoiner = new StringJoiner(" ", "{", "}"); - - if (mIfaceName != null) { - resultJoiner.add("InterfaceName:"); - resultJoiner.add(mIfaceName); - } - - resultJoiner.add("LinkAddresses: ["); - if (!mLinkAddresses.isEmpty()) { - resultJoiner.add(TextUtils.join(",", mLinkAddresses)); - } - resultJoiner.add("]"); - - resultJoiner.add("DnsAddresses: ["); - if (!mDnses.isEmpty()) { - resultJoiner.add(TextUtils.join(",", mDnses)); - } - resultJoiner.add("]"); - - if (mUsePrivateDns) { - resultJoiner.add("UsePrivateDns: true"); - } - - if (mPrivateDnsServerName != null) { - resultJoiner.add("PrivateDnsServerName:"); - resultJoiner.add(mPrivateDnsServerName); - } - - if (!mPcscfs.isEmpty()) { - resultJoiner.add("PcscfAddresses: ["); - resultJoiner.add(TextUtils.join(",", mPcscfs)); - resultJoiner.add("]"); - } - - if (!mValidatedPrivateDnses.isEmpty()) { - final StringJoiner validatedPrivateDnsesJoiner = - new StringJoiner(",", "ValidatedPrivateDnsAddresses: [", "]"); - for (final InetAddress addr : mValidatedPrivateDnses) { - validatedPrivateDnsesJoiner.add(addr.getHostAddress()); - } - resultJoiner.add(validatedPrivateDnsesJoiner.toString()); - } - - resultJoiner.add("Domains:"); - resultJoiner.add(mDomains); - - resultJoiner.add("MTU:"); - resultJoiner.add(Integer.toString(mMtu)); - - if (mWakeOnLanSupported) { - resultJoiner.add("WakeOnLanSupported: true"); - } - - if (mDhcpServerAddress != null) { - resultJoiner.add("ServerAddress:"); - resultJoiner.add(mDhcpServerAddress.toString()); - } - - if (mCaptivePortalApiUrl != null) { - resultJoiner.add("CaptivePortalApiUrl: " + mCaptivePortalApiUrl); - } - - if (mCaptivePortalData != null) { - resultJoiner.add("CaptivePortalData: " + mCaptivePortalData); - } - - if (mTcpBufferSizes != null) { - resultJoiner.add("TcpBufferSizes:"); - resultJoiner.add(mTcpBufferSizes); - } - - resultJoiner.add("Routes: ["); - if (!mRoutes.isEmpty()) { - resultJoiner.add(TextUtils.join(",", mRoutes)); - } - resultJoiner.add("]"); - - if (mHttpProxy != null) { - resultJoiner.add("HttpProxy:"); - resultJoiner.add(mHttpProxy.toString()); - } - - if (mNat64Prefix != null) { - resultJoiner.add("Nat64Prefix:"); - resultJoiner.add(mNat64Prefix.toString()); - } - - final Collection stackedLinksValues = mStackedLinks.values(); - if (!stackedLinksValues.isEmpty()) { - final StringJoiner stackedLinksJoiner = new StringJoiner(",", "Stacked: [", "]"); - for (final LinkProperties lp : stackedLinksValues) { - stackedLinksJoiner.add("[ " + lp + " ]"); - } - resultJoiner.add(stackedLinksJoiner.toString()); - } - - return resultJoiner.toString(); - } - - /** - * Returns true if this link has an IPv4 address. - * - * @return {@code true} if there is an IPv4 address, {@code false} otherwise. - * @hide - */ - @SystemApi - public boolean hasIpv4Address() { - for (LinkAddress address : mLinkAddresses) { - if (address.getAddress() instanceof Inet4Address) { - return true; - } - } - return false; - } - - /** - * For backward compatibility. - * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely - * just yet. - * @return {@code true} if there is an IPv4 address, {@code false} otherwise. - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) - public boolean hasIPv4Address() { - return hasIpv4Address(); - } - - /** - * Returns true if this link or any of its stacked interfaces has an IPv4 address. - * - * @return {@code true} if there is an IPv4 address, {@code false} otherwise. - */ - private boolean hasIpv4AddressOnInterface(String iface) { - // mIfaceName can be null. - return (Objects.equals(iface, mIfaceName) && hasIpv4Address()) - || (iface != null && mStackedLinks.containsKey(iface) - && mStackedLinks.get(iface).hasIpv4Address()); - } - - /** - * Returns true if this link has a global preferred IPv6 address. - * - * @return {@code true} if there is a global preferred IPv6 address, {@code false} otherwise. - * @hide - */ - @SystemApi - public boolean hasGlobalIpv6Address() { - for (LinkAddress address : mLinkAddresses) { - if (address.getAddress() instanceof Inet6Address && address.isGlobalPreferred()) { - return true; - } - } - return false; - } - - /** - * Returns true if this link has an IPv4 unreachable default route. - * - * @return {@code true} if there is an IPv4 unreachable default route, {@code false} otherwise. - * @hide - */ - public boolean hasIpv4UnreachableDefaultRoute() { - for (RouteInfo r : mRoutes) { - if (r.isIPv4UnreachableDefault()) { - return true; - } - } - return false; - } - - /** - * For backward compatibility. - * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely - * just yet. - * @return {@code true} if there is a global preferred IPv6 address, {@code false} otherwise. - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) - public boolean hasGlobalIPv6Address() { - return hasGlobalIpv6Address(); - } - - /** - * Returns true if this link has an IPv4 default route. - * - * @return {@code true} if there is an IPv4 default route, {@code false} otherwise. - * @hide - */ - @SystemApi - public boolean hasIpv4DefaultRoute() { - for (RouteInfo r : mRoutes) { - if (r.isIPv4Default()) { - return true; - } - } - return false; - } - - /** - * Returns true if this link has an IPv6 unreachable default route. - * - * @return {@code true} if there is an IPv6 unreachable default route, {@code false} otherwise. - * @hide - */ - public boolean hasIpv6UnreachableDefaultRoute() { - for (RouteInfo r : mRoutes) { - if (r.isIPv6UnreachableDefault()) { - return true; - } - } - return false; - } - - /** - * For backward compatibility. - * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely - * just yet. - * @return {@code true} if there is an IPv4 default route, {@code false} otherwise. - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) - public boolean hasIPv4DefaultRoute() { - return hasIpv4DefaultRoute(); - } - - /** - * Returns true if this link has an IPv6 default route. - * - * @return {@code true} if there is an IPv6 default route, {@code false} otherwise. - * @hide - */ - @SystemApi - public boolean hasIpv6DefaultRoute() { - for (RouteInfo r : mRoutes) { - if (r.isIPv6Default()) { - return true; - } - } - return false; - } - - /** - * For backward compatibility. - * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely - * just yet. - * @return {@code true} if there is an IPv6 default route, {@code false} otherwise. - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) - public boolean hasIPv6DefaultRoute() { - return hasIpv6DefaultRoute(); - } - - /** - * Returns true if this link has an IPv4 DNS server. - * - * @return {@code true} if there is an IPv4 DNS server, {@code false} otherwise. - * @hide - */ - @SystemApi - public boolean hasIpv4DnsServer() { - for (InetAddress ia : mDnses) { - if (ia instanceof Inet4Address) { - return true; - } - } - return false; - } - - /** - * For backward compatibility. - * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely - * just yet. - * @return {@code true} if there is an IPv4 DNS server, {@code false} otherwise. - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) - public boolean hasIPv4DnsServer() { - return hasIpv4DnsServer(); - } - - /** - * Returns true if this link has an IPv6 DNS server. - * - * @return {@code true} if there is an IPv6 DNS server, {@code false} otherwise. - * @hide - */ - @SystemApi - public boolean hasIpv6DnsServer() { - for (InetAddress ia : mDnses) { - if (ia instanceof Inet6Address) { - return true; - } - } - return false; - } - - /** - * For backward compatibility. - * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely - * just yet. - * @return {@code true} if there is an IPv6 DNS server, {@code false} otherwise. - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) - public boolean hasIPv6DnsServer() { - return hasIpv6DnsServer(); - } - - /** - * Returns true if this link has an IPv4 PCSCF server. - * - * @return {@code true} if there is an IPv4 PCSCF server, {@code false} otherwise. - * @hide - */ - public boolean hasIpv4PcscfServer() { - for (InetAddress ia : mPcscfs) { - if (ia instanceof Inet4Address) { - return true; - } - } - return false; - } - - /** - * Returns true if this link has an IPv6 PCSCF server. - * - * @return {@code true} if there is an IPv6 PCSCF server, {@code false} otherwise. - * @hide - */ - public boolean hasIpv6PcscfServer() { - for (InetAddress ia : mPcscfs) { - if (ia instanceof Inet6Address) { - return true; - } - } - return false; - } - - /** - * Returns true if this link is provisioned for global IPv4 connectivity. - * This requires an IP address, default route, and DNS server. - * - * @return {@code true} if the link is provisioned, {@code false} otherwise. - * @hide - */ - @SystemApi - public boolean isIpv4Provisioned() { - return (hasIpv4Address() - && hasIpv4DefaultRoute() - && hasIpv4DnsServer()); - } - - /** - * Returns true if this link is provisioned for global IPv6 connectivity. - * This requires an IP address, default route, and DNS server. - * - * @return {@code true} if the link is provisioned, {@code false} otherwise. - * @hide - */ - @SystemApi - public boolean isIpv6Provisioned() { - return (hasGlobalIpv6Address() - && hasIpv6DefaultRoute() - && hasIpv6DnsServer()); - } - - /** - * For backward compatibility. - * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely - * just yet. - * @return {@code true} if the link is provisioned, {@code false} otherwise. - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) - public boolean isIPv6Provisioned() { - return isIpv6Provisioned(); - } - - - /** - * Returns true if this link is provisioned for global connectivity, - * for at least one Internet Protocol family. - * - * @return {@code true} if the link is provisioned, {@code false} otherwise. - * @hide - */ - @SystemApi - public boolean isProvisioned() { - return (isIpv4Provisioned() || isIpv6Provisioned()); - } - - /** - * Evaluate whether the {@link InetAddress} is considered reachable. - * - * @return {@code true} if the given {@link InetAddress} is considered reachable, - * {@code false} otherwise. - * @hide - */ - @SystemApi - public boolean isReachable(@NonNull InetAddress ip) { - final List allRoutes = getAllRoutes(); - // If we don't have a route to this IP address, it's not reachable. - final RouteInfo bestRoute = RouteInfo.selectBestRoute(allRoutes, ip); - if (bestRoute == null) { - return false; - } - - // TODO: better source address evaluation for destination addresses. - - if (ip instanceof Inet4Address) { - // For IPv4, it suffices for now to simply have any address. - return hasIpv4AddressOnInterface(bestRoute.getInterface()); - } else if (ip instanceof Inet6Address) { - if (ip.isLinkLocalAddress()) { - // For now, just make sure link-local destinations have - // scopedIds set, since transmits will generally fail otherwise. - // TODO: verify it matches the ifindex of one of the interfaces. - return (((Inet6Address)ip).getScopeId() != 0); - } else { - // For non-link-local destinations check that either the best route - // is directly connected or that some global preferred address exists. - // TODO: reconsider all cases (disconnected ULA networks, ...). - return (!bestRoute.hasGateway() || hasGlobalIpv6Address()); - } - } - - return false; - } - - /** - * Compares this {@code LinkProperties} interface name against the target - * - * @param target LinkProperties to compare. - * @return {@code true} if both are identical, {@code false} otherwise. - * @hide - */ - @UnsupportedAppUsage - public boolean isIdenticalInterfaceName(@NonNull LinkProperties target) { - return LinkPropertiesUtils.isIdenticalInterfaceName(target, this); - } - - /** - * Compares this {@code LinkProperties} DHCP server address against the target - * - * @param target LinkProperties to compare. - * @return {@code true} if both are identical, {@code false} otherwise. - * @hide - */ - public boolean isIdenticalDhcpServerAddress(@NonNull LinkProperties target) { - return Objects.equals(mDhcpServerAddress, target.mDhcpServerAddress); - } - - /** - * Compares this {@code LinkProperties} interface addresses against the target - * - * @param target LinkProperties to compare. - * @return {@code true} if both are identical, {@code false} otherwise. - * @hide - */ - @UnsupportedAppUsage - public boolean isIdenticalAddresses(@NonNull LinkProperties target) { - return LinkPropertiesUtils.isIdenticalAddresses(target, this); - } - - /** - * Compares this {@code LinkProperties} DNS addresses against the target - * - * @param target LinkProperties to compare. - * @return {@code true} if both are identical, {@code false} otherwise. - * @hide - */ - @UnsupportedAppUsage - public boolean isIdenticalDnses(@NonNull LinkProperties target) { - return LinkPropertiesUtils.isIdenticalDnses(target, this); - } - - /** - * Compares this {@code LinkProperties} private DNS settings against the - * target. - * - * @param target LinkProperties to compare. - * @return {@code true} if both are identical, {@code false} otherwise. - * @hide - */ - public boolean isIdenticalPrivateDns(@NonNull LinkProperties target) { - return (isPrivateDnsActive() == target.isPrivateDnsActive() - && TextUtils.equals(getPrivateDnsServerName(), - target.getPrivateDnsServerName())); - } - - /** - * Compares this {@code LinkProperties} validated private DNS addresses against - * the target - * - * @param target LinkProperties to compare. - * @return {@code true} if both are identical, {@code false} otherwise. - * @hide - */ - public boolean isIdenticalValidatedPrivateDnses(@NonNull LinkProperties target) { - Collection targetDnses = target.getValidatedPrivateDnsServers(); - return (mValidatedPrivateDnses.size() == targetDnses.size()) - ? mValidatedPrivateDnses.containsAll(targetDnses) : false; - } - - /** - * Compares this {@code LinkProperties} PCSCF addresses against the target - * - * @param target LinkProperties to compare. - * @return {@code true} if both are identical, {@code false} otherwise. - * @hide - */ - public boolean isIdenticalPcscfs(@NonNull LinkProperties target) { - Collection targetPcscfs = target.getPcscfServers(); - return (mPcscfs.size() == targetPcscfs.size()) ? - mPcscfs.containsAll(targetPcscfs) : false; - } - - /** - * Compares this {@code LinkProperties} Routes against the target - * - * @param target LinkProperties to compare. - * @return {@code true} if both are identical, {@code false} otherwise. - * @hide - */ - @UnsupportedAppUsage - public boolean isIdenticalRoutes(@NonNull LinkProperties target) { - return LinkPropertiesUtils.isIdenticalRoutes(target, this); - } - - /** - * Compares this {@code LinkProperties} HttpProxy against the target - * - * @param target LinkProperties to compare. - * @return {@code true} if both are identical, {@code false} otherwise. - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) - public boolean isIdenticalHttpProxy(@NonNull LinkProperties target) { - return LinkPropertiesUtils.isIdenticalHttpProxy(target, this); - } - - /** - * Compares this {@code LinkProperties} stacked links against the target - * - * @param target LinkProperties to compare. - * @return {@code true} if both are identical, {@code false} otherwise. - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public boolean isIdenticalStackedLinks(@NonNull LinkProperties target) { - if (!mStackedLinks.keySet().equals(target.mStackedLinks.keySet())) { - return false; - } - for (LinkProperties stacked : mStackedLinks.values()) { - // Hashtable values can never be null. - String iface = stacked.getInterfaceName(); - if (!stacked.equals(target.mStackedLinks.get(iface))) { - return false; - } - } - return true; - } - - /** - * Compares this {@code LinkProperties} MTU against the target - * - * @param target LinkProperties to compare. - * @return {@code true} if both are identical, {@code false} otherwise. - * @hide - */ - public boolean isIdenticalMtu(@NonNull LinkProperties target) { - return getMtu() == target.getMtu(); - } - - /** - * Compares this {@code LinkProperties} Tcp buffer sizes against the target. - * - * @param target LinkProperties to compare. - * @return {@code true} if both are identical, {@code false} otherwise. - * @hide - */ - public boolean isIdenticalTcpBufferSizes(@NonNull LinkProperties target) { - return Objects.equals(mTcpBufferSizes, target.mTcpBufferSizes); - } - - /** - * Compares this {@code LinkProperties} NAT64 prefix against the target. - * - * @param target LinkProperties to compare. - * @return {@code true} if both are identical, {@code false} otherwise. - * @hide - */ - public boolean isIdenticalNat64Prefix(@NonNull LinkProperties target) { - return Objects.equals(mNat64Prefix, target.mNat64Prefix); - } - - /** - * Compares this {@code LinkProperties} WakeOnLan supported against the target. - * - * @param target LinkProperties to compare. - * @return {@code true} if both are identical, {@code false} otherwise. - * @hide - */ - public boolean isIdenticalWakeOnLan(LinkProperties target) { - return isWakeOnLanSupported() == target.isWakeOnLanSupported(); - } - - /** - * Compares this {@code LinkProperties}'s CaptivePortalApiUrl against the target. - * - * @param target LinkProperties to compare. - * @return {@code true} if both are identical, {@code false} otherwise. - * @hide - */ - public boolean isIdenticalCaptivePortalApiUrl(LinkProperties target) { - return Objects.equals(mCaptivePortalApiUrl, target.mCaptivePortalApiUrl); - } - - /** - * Compares this {@code LinkProperties}'s CaptivePortalData against the target. - * - * @param target LinkProperties to compare. - * @return {@code true} if both are identical, {@code false} otherwise. - * @hide - */ - public boolean isIdenticalCaptivePortalData(LinkProperties target) { - return Objects.equals(mCaptivePortalData, target.mCaptivePortalData); - } - - /** - * Set whether the network interface supports WakeOnLAN - * - * @param supported WakeOnLAN supported value - * - * @hide - */ - public void setWakeOnLanSupported(boolean supported) { - mWakeOnLanSupported = supported; - } - - /** - * Returns whether the network interface supports WakeOnLAN - * - * @return {@code true} if interface supports WakeOnLAN, {@code false} otherwise. - */ - public boolean isWakeOnLanSupported() { - return mWakeOnLanSupported; - } - - /** - * Set the URL of the captive portal API endpoint to get more information about the network. - * @hide - */ - @SystemApi - public void setCaptivePortalApiUrl(@Nullable Uri url) { - mCaptivePortalApiUrl = url; - } - - /** - * Get the URL of the captive portal API endpoint to get more information about the network. - * - *

This is null unless the application has - * {@link android.Manifest.permission.NETWORK_SETTINGS} or - * {@link NetworkStack#PERMISSION_MAINLINE_NETWORK_STACK} permissions, and the network provided - * the URL. - * @hide - */ - @SystemApi - @Nullable - public Uri getCaptivePortalApiUrl() { - return mCaptivePortalApiUrl; - } - - /** - * Set the CaptivePortalData obtained from the captive portal API (RFC7710bis). - * @hide - */ - @SystemApi - public void setCaptivePortalData(@Nullable CaptivePortalData data) { - mCaptivePortalData = data; - } - - /** - * Get the CaptivePortalData obtained from the captive portal API (RFC7710bis). - * - *

This is null unless the application has - * {@link android.Manifest.permission.NETWORK_SETTINGS} or - * {@link NetworkStack#PERMISSION_MAINLINE_NETWORK_STACK} permissions. - * @hide - */ - @SystemApi - @Nullable - public CaptivePortalData getCaptivePortalData() { - return mCaptivePortalData; - } - - /** - * Compares this {@code LinkProperties} instance against the target - * LinkProperties in {@code obj}. Two LinkPropertieses are equal if - * all their fields are equal in values. - * - * For collection fields, such as mDnses, containsAll() is used to check - * if two collections contains the same elements, independent of order. - * There are two thoughts regarding containsAll() - * 1. Duplicated elements. eg, (A, B, B) and (A, A, B) are equal. - * 2. Worst case performance is O(n^2). - * - * @param obj the object to be tested for equality. - * @return {@code true} if both objects are equal, {@code false} otherwise. - */ - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - - if (!(obj instanceof LinkProperties)) return false; - - LinkProperties target = (LinkProperties) obj; - /* - * This method does not check that stacked interfaces are equal, because - * stacked interfaces are not so much a property of the link as a - * description of connections between links. - */ - return isIdenticalInterfaceName(target) - && isIdenticalAddresses(target) - && isIdenticalDhcpServerAddress(target) - && isIdenticalDnses(target) - && isIdenticalPrivateDns(target) - && isIdenticalValidatedPrivateDnses(target) - && isIdenticalPcscfs(target) - && isIdenticalRoutes(target) - && isIdenticalHttpProxy(target) - && isIdenticalStackedLinks(target) - && isIdenticalMtu(target) - && isIdenticalTcpBufferSizes(target) - && isIdenticalNat64Prefix(target) - && isIdenticalWakeOnLan(target) - && isIdenticalCaptivePortalApiUrl(target) - && isIdenticalCaptivePortalData(target); - } - - /** - * Generate hashcode based on significant fields - * - * Equal objects must produce the same hash code, while unequal objects - * may have the same hash codes. - */ - @Override - public int hashCode() { - return ((null == mIfaceName) ? 0 : mIfaceName.hashCode() - + mLinkAddresses.size() * 31 - + mDnses.size() * 37 - + mValidatedPrivateDnses.size() * 61 - + ((null == mDomains) ? 0 : mDomains.hashCode()) - + mRoutes.size() * 41 - + ((null == mHttpProxy) ? 0 : mHttpProxy.hashCode()) - + mStackedLinks.hashCode() * 47) - + mMtu * 51 - + ((null == mTcpBufferSizes) ? 0 : mTcpBufferSizes.hashCode()) - + (mUsePrivateDns ? 57 : 0) - + ((null == mDhcpServerAddress) ? 0 : mDhcpServerAddress.hashCode()) - + mPcscfs.size() * 67 - + ((null == mPrivateDnsServerName) ? 0 : mPrivateDnsServerName.hashCode()) - + Objects.hash(mNat64Prefix) - + (mWakeOnLanSupported ? 71 : 0) - + Objects.hash(mCaptivePortalApiUrl, mCaptivePortalData); - } - - /** - * Implement the Parcelable interface. - */ - public void writeToParcel(Parcel dest, int flags) { - dest.writeString(getInterfaceName()); - dest.writeInt(mLinkAddresses.size()); - for (LinkAddress linkAddress : mLinkAddresses) { - dest.writeParcelable(linkAddress, flags); - } - - writeAddresses(dest, mDnses); - writeAddresses(dest, mValidatedPrivateDnses); - dest.writeBoolean(mUsePrivateDns); - dest.writeString(mPrivateDnsServerName); - writeAddresses(dest, mPcscfs); - dest.writeString(mDomains); - writeAddress(dest, mDhcpServerAddress); - dest.writeInt(mMtu); - dest.writeString(mTcpBufferSizes); - dest.writeInt(mRoutes.size()); - for (RouteInfo route : mRoutes) { - dest.writeParcelable(route, flags); - } - - if (mHttpProxy != null) { - dest.writeByte((byte)1); - dest.writeParcelable(mHttpProxy, flags); - } else { - dest.writeByte((byte)0); - } - dest.writeParcelable(mNat64Prefix, 0); - - ArrayList stackedLinks = new ArrayList<>(mStackedLinks.values()); - dest.writeList(stackedLinks); - - dest.writeBoolean(mWakeOnLanSupported); - dest.writeParcelable(mParcelSensitiveFields ? mCaptivePortalApiUrl : null, 0); - dest.writeParcelable(mParcelSensitiveFields ? mCaptivePortalData : null, 0); - } - - private static void writeAddresses(@NonNull Parcel dest, @NonNull List list) { - dest.writeInt(list.size()); - for (InetAddress d : list) { - writeAddress(dest, d); - } - } - - private static void writeAddress(@NonNull Parcel dest, @Nullable InetAddress addr) { - byte[] addressBytes = (addr == null ? null : addr.getAddress()); - dest.writeByteArray(addressBytes); - if (addr instanceof Inet6Address) { - final Inet6Address v6Addr = (Inet6Address) addr; - final boolean hasScopeId = v6Addr.getScopeId() != 0; - dest.writeBoolean(hasScopeId); - if (hasScopeId) dest.writeInt(v6Addr.getScopeId()); - } - } - - @Nullable - private static InetAddress readAddress(@NonNull Parcel p) throws UnknownHostException { - final byte[] addr = p.createByteArray(); - if (addr == null) return null; - - if (addr.length == INET6_ADDR_LENGTH) { - final boolean hasScopeId = p.readBoolean(); - final int scopeId = hasScopeId ? p.readInt() : 0; - return Inet6Address.getByAddress(null /* host */, addr, scopeId); - } - - return InetAddress.getByAddress(addr); - } - - /** - * Implement the Parcelable interface. - */ - public static final @android.annotation.NonNull Creator CREATOR = - new Creator() { - public LinkProperties createFromParcel(Parcel in) { - LinkProperties netProp = new LinkProperties(); - - String iface = in.readString(); - if (iface != null) { - netProp.setInterfaceName(iface); - } - int addressCount = in.readInt(); - for (int i = 0; i < addressCount; i++) { - netProp.addLinkAddress(in.readParcelable(null)); - } - addressCount = in.readInt(); - for (int i = 0; i < addressCount; i++) { - try { - netProp.addDnsServer(readAddress(in)); - } catch (UnknownHostException e) { } - } - addressCount = in.readInt(); - for (int i = 0; i < addressCount; i++) { - try { - netProp.addValidatedPrivateDnsServer(readAddress(in)); - } catch (UnknownHostException e) { } - } - netProp.setUsePrivateDns(in.readBoolean()); - netProp.setPrivateDnsServerName(in.readString()); - addressCount = in.readInt(); - for (int i = 0; i < addressCount; i++) { - try { - netProp.addPcscfServer(readAddress(in)); - } catch (UnknownHostException e) { } - } - netProp.setDomains(in.readString()); - try { - netProp.setDhcpServerAddress((Inet4Address) InetAddress - .getByAddress(in.createByteArray())); - } catch (UnknownHostException e) { } - netProp.setMtu(in.readInt()); - netProp.setTcpBufferSizes(in.readString()); - addressCount = in.readInt(); - for (int i = 0; i < addressCount; i++) { - netProp.addRoute(in.readParcelable(null)); - } - if (in.readByte() == 1) { - netProp.setHttpProxy(in.readParcelable(null)); - } - netProp.setNat64Prefix(in.readParcelable(null)); - ArrayList stackedLinks = new ArrayList(); - in.readList(stackedLinks, LinkProperties.class.getClassLoader()); - for (LinkProperties stackedLink: stackedLinks) { - netProp.addStackedLink(stackedLink); - } - netProp.setWakeOnLanSupported(in.readBoolean()); - - netProp.setCaptivePortalApiUrl(in.readParcelable(null)); - netProp.setCaptivePortalData(in.readParcelable(null)); - return netProp; - } - - public LinkProperties[] newArray(int size) { - return new LinkProperties[size]; - } - }; - - /** - * Check the valid MTU range based on IPv4 or IPv6. - * @hide - */ - public static boolean isValidMtu(int mtu, boolean ipv6) { - if (ipv6) { - return mtu >= MIN_MTU_V6 && mtu <= MAX_MTU; - } else { - return mtu >= MIN_MTU && mtu <= MAX_MTU; - } - } -} diff --git a/core/java/android/net/MacAddress.aidl b/core/java/android/net/MacAddress.aidl deleted file mode 100644 index 48a18a7ac821..000000000000 --- a/core/java/android/net/MacAddress.aidl +++ /dev/null @@ -1,20 +0,0 @@ -/** - * - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -@JavaOnlyStableParcelable parcelable MacAddress; diff --git a/core/java/android/net/MacAddress.java b/core/java/android/net/MacAddress.java deleted file mode 100644 index c7116b41e80a..000000000000 --- a/core/java/android/net/MacAddress.java +++ /dev/null @@ -1,400 +0,0 @@ -/* - * Copyright 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.compat.annotation.UnsupportedAppUsage; -import android.net.wifi.WifiInfo; -import android.os.Build; -import android.os.Parcel; -import android.os.Parcelable; - -import com.android.internal.util.Preconditions; -import com.android.net.module.util.MacAddressUtils; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.net.Inet6Address; -import java.net.UnknownHostException; -import java.security.SecureRandom; -import java.util.Arrays; - -/** - * Representation of a MAC address. - * - * This class only supports 48 bits long addresses and does not support 64 bits long addresses. - * Instances of this class are immutable. This class provides implementations of hashCode() - * and equals() that make it suitable for use as keys in standard implementations of - * {@link java.util.Map}. - */ -public final class MacAddress implements Parcelable { - - private static final int ETHER_ADDR_LEN = 6; - private static final byte[] ETHER_ADDR_BROADCAST = addr(0xff, 0xff, 0xff, 0xff, 0xff, 0xff); - - /** - * The MacAddress representing the unique broadcast MAC address. - */ - public static final MacAddress BROADCAST_ADDRESS = MacAddress.fromBytes(ETHER_ADDR_BROADCAST); - - /** - * The MacAddress zero MAC address. - * - *

Not publicly exposed or treated specially since the OUI 00:00:00 is registered. - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public static final MacAddress ALL_ZEROS_ADDRESS = new MacAddress(0); - - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = { "TYPE_" }, value = { - TYPE_UNKNOWN, - TYPE_UNICAST, - TYPE_MULTICAST, - TYPE_BROADCAST, - }) - public @interface MacAddressType { } - - /** @hide Indicates a MAC address of unknown type. */ - public static final int TYPE_UNKNOWN = 0; - /** Indicates a MAC address is a unicast address. */ - public static final int TYPE_UNICAST = 1; - /** Indicates a MAC address is a multicast address. */ - public static final int TYPE_MULTICAST = 2; - /** Indicates a MAC address is the broadcast address. */ - public static final int TYPE_BROADCAST = 3; - - private static final long VALID_LONG_MASK = (1L << 48) - 1; - private static final long LOCALLY_ASSIGNED_MASK = MacAddress.fromString("2:0:0:0:0:0").mAddr; - private static final long MULTICAST_MASK = MacAddress.fromString("1:0:0:0:0:0").mAddr; - private static final long OUI_MASK = MacAddress.fromString("ff:ff:ff:0:0:0").mAddr; - private static final long NIC_MASK = MacAddress.fromString("0:0:0:ff:ff:ff").mAddr; - private static final MacAddress BASE_GOOGLE_MAC = MacAddress.fromString("da:a1:19:0:0:0"); - /** Default wifi MAC address used for a special purpose **/ - private static final MacAddress DEFAULT_MAC_ADDRESS = - MacAddress.fromString(WifiInfo.DEFAULT_MAC_ADDRESS); - - // Internal representation of the MAC address as a single 8 byte long. - // The encoding scheme sets the two most significant bytes to 0. The 6 bytes of the - // MAC address are encoded in the 6 least significant bytes of the long, where the first - // byte of the array is mapped to the 3rd highest logical byte of the long, the second - // byte of the array is mapped to the 4th highest logical byte of the long, and so on. - private final long mAddr; - - private MacAddress(long addr) { - mAddr = (VALID_LONG_MASK & addr); - } - - /** - * Returns the type of this address. - * - * @return the int constant representing the MAC address type of this MacAddress. - */ - public @MacAddressType int getAddressType() { - if (equals(BROADCAST_ADDRESS)) { - return TYPE_BROADCAST; - } - if ((mAddr & MULTICAST_MASK) != 0) { - return TYPE_MULTICAST; - } - return TYPE_UNICAST; - } - - /** - * @return true if this MacAddress is a locally assigned address. - */ - public boolean isLocallyAssigned() { - return (mAddr & LOCALLY_ASSIGNED_MASK) != 0; - } - - /** - * Convert this MacAddress to a byte array. - * - * The returned array is in network order. For example, if this MacAddress is 1:2:3:4:5:6, - * the returned array is [1, 2, 3, 4, 5, 6]. - * - * @return a byte array representation of this MacAddress. - */ - public @NonNull byte[] toByteArray() { - return byteAddrFromLongAddr(mAddr); - } - - /** - * Returns a human-readable representation of this MacAddress. - * The exact format is implementation-dependent and should not be assumed to have any - * particular format. - */ - @Override - public @NonNull String toString() { - return stringAddrFromLongAddr(mAddr); - } - - /** - * @return a String representation of the OUI part of this MacAddress made of 3 hexadecimal - * numbers in [0,ff] joined by ':' characters. - */ - public @NonNull String toOuiString() { - return String.format( - "%02x:%02x:%02x", (mAddr >> 40) & 0xff, (mAddr >> 32) & 0xff, (mAddr >> 24) & 0xff); - } - - @Override - public int hashCode() { - return (int) ((mAddr >> 32) ^ mAddr); - } - - @Override - public boolean equals(Object o) { - return (o instanceof MacAddress) && ((MacAddress) o).mAddr == mAddr; - } - - @Override - public void writeToParcel(Parcel out, int flags) { - out.writeLong(mAddr); - } - - @Override - public int describeContents() { - return 0; - } - - public static final @android.annotation.NonNull Parcelable.Creator CREATOR = - new Parcelable.Creator() { - public MacAddress createFromParcel(Parcel in) { - return new MacAddress(in.readLong()); - } - - public MacAddress[] newArray(int size) { - return new MacAddress[size]; - } - }; - - /** - * Returns true if the given byte array is an valid MAC address. - * A valid byte array representation for a MacAddress is a non-null array of length 6. - * - * @param addr a byte array. - * @return true if the given byte array is not null and has the length of a MAC address. - * - * @hide - */ - public static boolean isMacAddress(byte[] addr) { - return MacAddressUtils.isMacAddress(addr); - } - - /** - * Returns the MAC address type of the MAC address represented by the given byte array, - * or null if the given byte array does not represent a MAC address. - * A valid byte array representation for a MacAddress is a non-null array of length 6. - * - * @param addr a byte array representing a MAC address. - * @return the int constant representing the MAC address type of the MAC address represented - * by the given byte array, or type UNKNOWN if the byte array is not a valid MAC address. - * - * @hide - */ - public static int macAddressType(byte[] addr) { - if (!isMacAddress(addr)) { - return TYPE_UNKNOWN; - } - return MacAddress.fromBytes(addr).getAddressType(); - } - - /** - * Converts a String representation of a MAC address to a byte array representation. - * A valid String representation for a MacAddress is a series of 6 values in the - * range [0,ff] printed in hexadecimal and joined by ':' characters. - * - * @param addr a String representation of a MAC address. - * @return the byte representation of the MAC address. - * @throws IllegalArgumentException if the given String is not a valid representation. - * - * @hide - */ - public static @NonNull byte[] byteAddrFromStringAddr(String addr) { - Preconditions.checkNotNull(addr); - String[] parts = addr.split(":"); - if (parts.length != ETHER_ADDR_LEN) { - throw new IllegalArgumentException(addr + " was not a valid MAC address"); - } - byte[] bytes = new byte[ETHER_ADDR_LEN]; - for (int i = 0; i < ETHER_ADDR_LEN; i++) { - int x = Integer.valueOf(parts[i], 16); - if (x < 0 || 0xff < x) { - throw new IllegalArgumentException(addr + "was not a valid MAC address"); - } - bytes[i] = (byte) x; - } - return bytes; - } - - /** - * Converts a byte array representation of a MAC address to a String representation made - * of 6 hexadecimal numbers in [0,ff] joined by ':' characters. - * A valid byte array representation for a MacAddress is a non-null array of length 6. - * - * @param addr a byte array representation of a MAC address. - * @return the String representation of the MAC address. - * @throws IllegalArgumentException if the given byte array is not a valid representation. - * - * @hide - */ - public static @NonNull String stringAddrFromByteAddr(byte[] addr) { - if (!isMacAddress(addr)) { - return null; - } - return String.format("%02x:%02x:%02x:%02x:%02x:%02x", - addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); - } - - private static byte[] byteAddrFromLongAddr(long addr) { - return MacAddressUtils.byteAddrFromLongAddr(addr); - } - - private static long longAddrFromByteAddr(byte[] addr) { - return MacAddressUtils.longAddrFromByteAddr(addr); - } - - // Internal conversion function equivalent to longAddrFromByteAddr(byteAddrFromStringAddr(addr)) - // that avoids the allocation of an intermediary byte[]. - private static long longAddrFromStringAddr(String addr) { - Preconditions.checkNotNull(addr); - String[] parts = addr.split(":"); - if (parts.length != ETHER_ADDR_LEN) { - throw new IllegalArgumentException(addr + " was not a valid MAC address"); - } - long longAddr = 0; - for (int i = 0; i < parts.length; i++) { - int x = Integer.valueOf(parts[i], 16); - if (x < 0 || 0xff < x) { - throw new IllegalArgumentException(addr + "was not a valid MAC address"); - } - longAddr = x + (longAddr << 8); - } - return longAddr; - } - - // Internal conversion function equivalent to stringAddrFromByteAddr(byteAddrFromLongAddr(addr)) - // that avoids the allocation of an intermediary byte[]. - private static @NonNull String stringAddrFromLongAddr(long addr) { - return String.format("%02x:%02x:%02x:%02x:%02x:%02x", - (addr >> 40) & 0xff, - (addr >> 32) & 0xff, - (addr >> 24) & 0xff, - (addr >> 16) & 0xff, - (addr >> 8) & 0xff, - addr & 0xff); - } - - /** - * Creates a MacAddress from the given String representation. A valid String representation - * for a MacAddress is a series of 6 values in the range [0,ff] printed in hexadecimal - * and joined by ':' characters. - * - * @param addr a String representation of a MAC address. - * @return the MacAddress corresponding to the given String representation. - * @throws IllegalArgumentException if the given String is not a valid representation. - */ - public static @NonNull MacAddress fromString(@NonNull String addr) { - return new MacAddress(longAddrFromStringAddr(addr)); - } - - /** - * Creates a MacAddress from the given byte array representation. - * A valid byte array representation for a MacAddress is a non-null array of length 6. - * - * @param addr a byte array representation of a MAC address. - * @return the MacAddress corresponding to the given byte array representation. - * @throws IllegalArgumentException if the given byte array is not a valid representation. - */ - public static @NonNull MacAddress fromBytes(@NonNull byte[] addr) { - return new MacAddress(longAddrFromByteAddr(addr)); - } - - /** - * Returns a generated MAC address whose 24 least significant bits constituting the - * NIC part of the address are randomly selected and has Google OUI base. - * - * The locally assigned bit is always set to 1. The multicast bit is always set to 0. - * - * @return a random locally assigned, unicast MacAddress with Google OUI. - * - * @hide - */ - public static @NonNull MacAddress createRandomUnicastAddressWithGoogleBase() { - return MacAddressUtils.createRandomUnicastAddress(BASE_GOOGLE_MAC, new SecureRandom()); - } - - // Convenience function for working around the lack of byte literals. - private static byte[] addr(int... in) { - if (in.length != ETHER_ADDR_LEN) { - throw new IllegalArgumentException(Arrays.toString(in) - + " was not an array with length equal to " + ETHER_ADDR_LEN); - } - byte[] out = new byte[ETHER_ADDR_LEN]; - for (int i = 0; i < ETHER_ADDR_LEN; i++) { - out[i] = (byte) in[i]; - } - return out; - } - - /** - * Checks if this MAC Address matches the provided range. - * - * @param baseAddress MacAddress representing the base address to compare with. - * @param mask MacAddress representing the mask to use during comparison. - * @return true if this MAC Address matches the given range. - * - */ - public boolean matches(@NonNull MacAddress baseAddress, @NonNull MacAddress mask) { - Preconditions.checkNotNull(baseAddress); - Preconditions.checkNotNull(mask); - return (mAddr & mask.mAddr) == (baseAddress.mAddr & mask.mAddr); - } - - /** - * Create a link-local Inet6Address from the MAC address. The EUI-48 MAC address is converted - * to an EUI-64 MAC address per RFC 4291. The resulting EUI-64 is used to construct a link-local - * IPv6 address per RFC 4862. - * - * @return A link-local Inet6Address constructed from the MAC address. - */ - public @Nullable Inet6Address getLinkLocalIpv6FromEui48Mac() { - byte[] macEui48Bytes = toByteArray(); - byte[] addr = new byte[16]; - - addr[0] = (byte) 0xfe; - addr[1] = (byte) 0x80; - addr[8] = (byte) (macEui48Bytes[0] ^ (byte) 0x02); // flip the link-local bit - addr[9] = macEui48Bytes[1]; - addr[10] = macEui48Bytes[2]; - addr[11] = (byte) 0xff; - addr[12] = (byte) 0xfe; - addr[13] = macEui48Bytes[3]; - addr[14] = macEui48Bytes[4]; - addr[15] = macEui48Bytes[5]; - - try { - return Inet6Address.getByAddress(null, addr, 0); - } catch (UnknownHostException e) { - return null; - } - } -} diff --git a/core/java/android/net/NattKeepalivePacketData.java b/core/java/android/net/NattKeepalivePacketData.java deleted file mode 100644 index c4f8fc281f25..000000000000 --- a/core/java/android/net/NattKeepalivePacketData.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import static android.net.InvalidPacketException.ERROR_INVALID_IP_ADDRESS; -import static android.net.InvalidPacketException.ERROR_INVALID_PORT; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.SystemApi; -import android.os.Parcel; -import android.os.Parcelable; -import android.system.OsConstants; - -import com.android.net.module.util.IpUtils; - -import java.net.Inet4Address; -import java.net.InetAddress; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.util.Objects; - -/** @hide */ -@SystemApi -public final class NattKeepalivePacketData extends KeepalivePacketData implements Parcelable { - private static final int IPV4_HEADER_LENGTH = 20; - private static final int UDP_HEADER_LENGTH = 8; - - // This should only be constructed via static factory methods, such as - // nattKeepalivePacket - public NattKeepalivePacketData(@NonNull InetAddress srcAddress, int srcPort, - @NonNull InetAddress dstAddress, int dstPort, @NonNull byte[] data) throws - InvalidPacketException { - super(srcAddress, srcPort, dstAddress, dstPort, data); - } - - /** - * Factory method to create Nat-T keepalive packet structure. - * @hide - */ - public static NattKeepalivePacketData nattKeepalivePacket( - InetAddress srcAddress, int srcPort, InetAddress dstAddress, int dstPort) - throws InvalidPacketException { - - if (!(srcAddress instanceof Inet4Address) || !(dstAddress instanceof Inet4Address)) { - throw new InvalidPacketException(ERROR_INVALID_IP_ADDRESS); - } - - if (dstPort != NattSocketKeepalive.NATT_PORT) { - throw new InvalidPacketException(ERROR_INVALID_PORT); - } - - int length = IPV4_HEADER_LENGTH + UDP_HEADER_LENGTH + 1; - ByteBuffer buf = ByteBuffer.allocate(length); - buf.order(ByteOrder.BIG_ENDIAN); - buf.putShort((short) 0x4500); // IP version and TOS - buf.putShort((short) length); - buf.putInt(0); // ID, flags, offset - buf.put((byte) 64); // TTL - buf.put((byte) OsConstants.IPPROTO_UDP); - int ipChecksumOffset = buf.position(); - buf.putShort((short) 0); // IP checksum - buf.put(srcAddress.getAddress()); - buf.put(dstAddress.getAddress()); - buf.putShort((short) srcPort); - buf.putShort((short) dstPort); - buf.putShort((short) (length - 20)); // UDP length - int udpChecksumOffset = buf.position(); - buf.putShort((short) 0); // UDP checksum - buf.put((byte) 0xff); // NAT-T keepalive - buf.putShort(ipChecksumOffset, IpUtils.ipChecksum(buf, 0)); - buf.putShort(udpChecksumOffset, IpUtils.udpChecksum(buf, 0, IPV4_HEADER_LENGTH)); - - return new NattKeepalivePacketData(srcAddress, srcPort, dstAddress, dstPort, buf.array()); - } - - /** Parcelable Implementation */ - public int describeContents() { - return 0; - } - - /** Write to parcel */ - public void writeToParcel(@NonNull Parcel out, int flags) { - out.writeString(getSrcAddress().getHostAddress()); - out.writeString(getDstAddress().getHostAddress()); - out.writeInt(getSrcPort()); - out.writeInt(getDstPort()); - } - - /** Parcelable Creator */ - public static final @NonNull Parcelable.Creator CREATOR = - new Parcelable.Creator() { - public NattKeepalivePacketData createFromParcel(Parcel in) { - final InetAddress srcAddress = - InetAddresses.parseNumericAddress(in.readString()); - final InetAddress dstAddress = - InetAddresses.parseNumericAddress(in.readString()); - final int srcPort = in.readInt(); - final int dstPort = in.readInt(); - try { - return NattKeepalivePacketData.nattKeepalivePacket(srcAddress, srcPort, - dstAddress, dstPort); - } catch (InvalidPacketException e) { - throw new IllegalArgumentException( - "Invalid NAT-T keepalive data: " + e.getError()); - } - } - - public NattKeepalivePacketData[] newArray(int size) { - return new NattKeepalivePacketData[size]; - } - }; - - @Override - public boolean equals(@Nullable final Object o) { - if (!(o instanceof NattKeepalivePacketData)) return false; - final NattKeepalivePacketData other = (NattKeepalivePacketData) o; - final InetAddress srcAddress = getSrcAddress(); - final InetAddress dstAddress = getDstAddress(); - return srcAddress.equals(other.getSrcAddress()) - && dstAddress.equals(other.getDstAddress()) - && getSrcPort() == other.getSrcPort() - && getDstPort() == other.getDstPort(); - } - - @Override - public int hashCode() { - return Objects.hash(getSrcAddress(), getDstAddress(), getSrcPort(), getDstPort()); - } -} diff --git a/core/java/android/net/NattSocketKeepalive.java b/core/java/android/net/NattSocketKeepalive.java deleted file mode 100644 index a15d165e65e7..000000000000 --- a/core/java/android/net/NattSocketKeepalive.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import android.annotation.NonNull; -import android.os.ParcelFileDescriptor; -import android.os.RemoteException; -import android.util.Log; - -import java.net.InetAddress; -import java.util.concurrent.Executor; - -/** @hide */ -public final class NattSocketKeepalive extends SocketKeepalive { - /** The NAT-T destination port for IPsec */ - public static final int NATT_PORT = 4500; - - @NonNull private final InetAddress mSource; - @NonNull private final InetAddress mDestination; - private final int mResourceId; - - NattSocketKeepalive(@NonNull IConnectivityManager service, - @NonNull Network network, - @NonNull ParcelFileDescriptor pfd, - int resourceId, - @NonNull InetAddress source, - @NonNull InetAddress destination, - @NonNull Executor executor, - @NonNull Callback callback) { - super(service, network, pfd, executor, callback); - mSource = source; - mDestination = destination; - mResourceId = resourceId; - } - - @Override - void startImpl(int intervalSec) { - mExecutor.execute(() -> { - try { - mService.startNattKeepaliveWithFd(mNetwork, mPfd, mResourceId, - intervalSec, mCallback, - mSource.getHostAddress(), mDestination.getHostAddress()); - } catch (RemoteException e) { - Log.e(TAG, "Error starting socket keepalive: ", e); - throw e.rethrowFromSystemServer(); - } - }); - } - - @Override - void stopImpl() { - mExecutor.execute(() -> { - try { - if (mSlot != null) { - mService.stopKeepalive(mNetwork, mSlot); - } - } catch (RemoteException e) { - Log.e(TAG, "Error stopping socket keepalive: ", e); - throw e.rethrowFromSystemServer(); - } - }); - } -} diff --git a/core/java/android/net/Network.aidl b/core/java/android/net/Network.aidl deleted file mode 100644 index 05622025bf33..000000000000 --- a/core/java/android/net/Network.aidl +++ /dev/null @@ -1,20 +0,0 @@ -/* -** -** Copyright (C) 2014 The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -package android.net; - -@JavaOnlyStableParcelable parcelable Network; diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java deleted file mode 100644 index b07bd68a0f50..000000000000 --- a/core/java/android/net/Network.java +++ /dev/null @@ -1,535 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import android.annotation.NonNull; -import android.annotation.SystemApi; -import android.compat.annotation.UnsupportedAppUsage; -import android.os.Build; -import android.os.Parcel; -import android.os.ParcelFileDescriptor; -import android.os.Parcelable; -import android.system.ErrnoException; -import android.system.Os; -import android.system.OsConstants; -import android.util.proto.ProtoOutputStream; - -import com.android.internal.annotations.GuardedBy; -import com.android.okhttp.internalandroidapi.Dns; -import com.android.okhttp.internalandroidapi.HttpURLConnectionFactory; - -import libcore.io.IoUtils; - -import java.io.FileDescriptor; -import java.io.IOException; -import java.net.DatagramSocket; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.MalformedURLException; -import java.net.Socket; -import java.net.SocketAddress; -import java.net.SocketException; -import java.net.URL; -import java.net.URLConnection; -import java.net.UnknownHostException; -import java.util.Arrays; -import java.util.concurrent.TimeUnit; - -import javax.net.SocketFactory; - -/** - * Identifies a {@code Network}. This is supplied to applications via - * {@link ConnectivityManager.NetworkCallback} in response to the active - * {@link ConnectivityManager#requestNetwork} or passive - * {@link ConnectivityManager#registerNetworkCallback} calls. - * It is used to direct traffic to the given {@code Network}, either on a {@link Socket} basis - * through a targeted {@link SocketFactory} or process-wide via - * {@link ConnectivityManager#bindProcessToNetwork}. - */ -public class Network implements Parcelable { - - /** - * The unique id of the network. - * @hide - */ - @UnsupportedAppUsage - public final int netId; - - // Objects used to perform per-network operations such as getSocketFactory - // and openConnection, and a lock to protect access to them. - private volatile NetworkBoundSocketFactory mNetworkBoundSocketFactory = null; - // mUrlConnectionFactory is initialized lazily when it is first needed. - @GuardedBy("mLock") - private HttpURLConnectionFactory mUrlConnectionFactory; - private final Object mLock = new Object(); - - // Default connection pool values. These are evaluated at startup, just - // like the OkHttp code. Also like the OkHttp code, we will throw parse - // exceptions at class loading time if the properties are set but are not - // valid integers. - private static final boolean httpKeepAlive = - Boolean.parseBoolean(System.getProperty("http.keepAlive", "true")); - private static final int httpMaxConnections = - httpKeepAlive ? Integer.parseInt(System.getProperty("http.maxConnections", "5")) : 0; - private static final long httpKeepAliveDurationMs = - Long.parseLong(System.getProperty("http.keepAliveDuration", "300000")); // 5 minutes. - // Value used to obfuscate network handle longs. - // The HANDLE_MAGIC value MUST be kept in sync with the corresponding - // value in the native/android/net.c NDK implementation. - private static final long HANDLE_MAGIC = 0xcafed00dL; - private static final int HANDLE_MAGIC_SIZE = 32; - - // A boolean to control how getAllByName()/getByName() behaves in the face - // of Private DNS. - // - // When true, these calls will request that DNS resolution bypass any - // Private DNS that might otherwise apply. Use of this feature is restricted - // and permission checks are made by netd (attempts to bypass Private DNS - // without appropriate permission are silently turned into vanilla DNS - // requests). This only affects DNS queries made using this network object. - // - // It it not parceled to receivers because (a) it can be set or cleared at - // anytime and (b) receivers should be explicit about attempts to bypass - // Private DNS so that the intent of the code is easily determined and - // code search audits are possible. - private final transient boolean mPrivateDnsBypass; - - /** - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public Network(int netId) { - this(netId, false); - } - - /** - * @hide - */ - public Network(int netId, boolean privateDnsBypass) { - this.netId = netId; - this.mPrivateDnsBypass = privateDnsBypass; - } - - /** - * @hide - */ - @SystemApi - public Network(@NonNull Network that) { - this(that.netId, that.mPrivateDnsBypass); - } - - /** - * Operates the same as {@code InetAddress.getAllByName} except that host - * resolution is done on this network. - * - * @param host the hostname or literal IP string to be resolved. - * @return the array of addresses associated with the specified host. - * @throws UnknownHostException if the address lookup fails. - */ - public InetAddress[] getAllByName(String host) throws UnknownHostException { - return InetAddress.getAllByNameOnNet(host, getNetIdForResolv()); - } - - /** - * Operates the same as {@code InetAddress.getByName} except that host - * resolution is done on this network. - * - * @param host the hostname to be resolved to an address or {@code null}. - * @return the {@code InetAddress} instance representing the host. - * @throws UnknownHostException - * if the address lookup fails. - */ - public InetAddress getByName(String host) throws UnknownHostException { - return InetAddress.getByNameOnNet(host, getNetIdForResolv()); - } - - /** - * Obtain a Network object for which Private DNS is to be bypassed when attempting - * to use {@link #getAllByName(String)}/{@link #getByName(String)} methods on the given - * instance for hostname resolution. - * - * @hide - */ - @SystemApi - public @NonNull Network getPrivateDnsBypassingCopy() { - return new Network(netId, true); - } - - /** - * Get the unique id of the network. - * - * @hide - */ - @SystemApi - public int getNetId() { - return netId; - } - - /** - * Returns a netid marked with the Private DNS bypass flag. - * - * This flag must be kept in sync with the NETID_USE_LOCAL_NAMESERVERS flag - * in system/netd/include/NetdClient.h. - * - * @hide - */ - public int getNetIdForResolv() { - return mPrivateDnsBypass - ? (int) (0x80000000L | (long) netId) // Non-portable DNS resolution flag. - : netId; - } - - /** - * A {@code SocketFactory} that produces {@code Socket}'s bound to this network. - */ - private class NetworkBoundSocketFactory extends SocketFactory { - private Socket connectToHost(String host, int port, SocketAddress localAddress) - throws IOException { - // Lookup addresses only on this Network. - InetAddress[] hostAddresses = getAllByName(host); - // Try all addresses. - for (int i = 0; i < hostAddresses.length; i++) { - try { - Socket socket = createSocket(); - boolean failed = true; - try { - if (localAddress != null) socket.bind(localAddress); - socket.connect(new InetSocketAddress(hostAddresses[i], port)); - failed = false; - return socket; - } finally { - if (failed) IoUtils.closeQuietly(socket); - } - } catch (IOException e) { - if (i == (hostAddresses.length - 1)) throw e; - } - } - throw new UnknownHostException(host); - } - - @Override - public Socket createSocket(String host, int port, InetAddress localHost, int localPort) - throws IOException { - return connectToHost(host, port, new InetSocketAddress(localHost, localPort)); - } - - @Override - public Socket createSocket(InetAddress address, int port, InetAddress localAddress, - int localPort) throws IOException { - Socket socket = createSocket(); - boolean failed = true; - try { - socket.bind(new InetSocketAddress(localAddress, localPort)); - socket.connect(new InetSocketAddress(address, port)); - failed = false; - } finally { - if (failed) IoUtils.closeQuietly(socket); - } - return socket; - } - - @Override - public Socket createSocket(InetAddress host, int port) throws IOException { - Socket socket = createSocket(); - boolean failed = true; - try { - socket.connect(new InetSocketAddress(host, port)); - failed = false; - } finally { - if (failed) IoUtils.closeQuietly(socket); - } - return socket; - } - - @Override - public Socket createSocket(String host, int port) throws IOException { - return connectToHost(host, port, null); - } - - @Override - public Socket createSocket() throws IOException { - Socket socket = new Socket(); - boolean failed = true; - try { - bindSocket(socket); - failed = false; - } finally { - if (failed) IoUtils.closeQuietly(socket); - } - return socket; - } - } - - /** - * Returns a {@link SocketFactory} bound to this network. Any {@link Socket} created by - * this factory will have its traffic sent over this {@code Network}. Note that if this - * {@code Network} ever disconnects, this factory and any {@link Socket} it produced in the - * past or future will cease to work. - * - * @return a {@link SocketFactory} which produces {@link Socket} instances bound to this - * {@code Network}. - */ - public SocketFactory getSocketFactory() { - if (mNetworkBoundSocketFactory == null) { - synchronized (mLock) { - if (mNetworkBoundSocketFactory == null) { - mNetworkBoundSocketFactory = new NetworkBoundSocketFactory(); - } - } - } - return mNetworkBoundSocketFactory; - } - - private static HttpURLConnectionFactory createUrlConnectionFactory(Dns dnsLookup) { - // Set configuration on the HttpURLConnectionFactory that will be good for all - // connections created by this Network. Configuration that might vary is left - // until openConnection() and passed as arguments. - HttpURLConnectionFactory urlConnectionFactory = new HttpURLConnectionFactory(); - urlConnectionFactory.setDns(dnsLookup); // Let traffic go via dnsLookup - // A private connection pool just for this Network. - urlConnectionFactory.setNewConnectionPool(httpMaxConnections, - httpKeepAliveDurationMs, TimeUnit.MILLISECONDS); - return urlConnectionFactory; - } - - /** - * Opens the specified {@link URL} on this {@code Network}, such that all traffic will be sent - * on this Network. The URL protocol must be {@code HTTP} or {@code HTTPS}. - * - * @return a {@code URLConnection} to the resource referred to by this URL. - * @throws MalformedURLException if the URL protocol is not HTTP or HTTPS. - * @throws IOException if an error occurs while opening the connection. - * @see java.net.URL#openConnection() - */ - public URLConnection openConnection(URL url) throws IOException { - final ConnectivityManager cm = ConnectivityManager.getInstanceOrNull(); - if (cm == null) { - throw new IOException("No ConnectivityManager yet constructed, please construct one"); - } - // TODO: Should this be optimized to avoid fetching the global proxy for every request? - final ProxyInfo proxyInfo = cm.getProxyForNetwork(this); - final java.net.Proxy proxy; - if (proxyInfo != null) { - proxy = proxyInfo.makeProxy(); - } else { - proxy = java.net.Proxy.NO_PROXY; - } - return openConnection(url, proxy); - } - - /** - * Opens the specified {@link URL} on this {@code Network}, such that all traffic will be sent - * on this Network. The URL protocol must be {@code HTTP} or {@code HTTPS}. - * - * @param proxy the proxy through which the connection will be established. - * @return a {@code URLConnection} to the resource referred to by this URL. - * @throws MalformedURLException if the URL protocol is not HTTP or HTTPS. - * @throws IllegalArgumentException if the argument proxy is null. - * @throws IOException if an error occurs while opening the connection. - * @see java.net.URL#openConnection() - */ - public URLConnection openConnection(URL url, java.net.Proxy proxy) throws IOException { - if (proxy == null) throw new IllegalArgumentException("proxy is null"); - // TODO: This creates a connection pool and host resolver for - // every Network object, instead of one for every NetId. This is - // suboptimal, because an app could potentially have more than one - // Network object for the same NetId, causing increased memory footprint - // and performance penalties due to lack of connection reuse (connection - // setup time, congestion window growth time, etc.). - // - // Instead, investigate only having one connection pool and host resolver - // for every NetId, perhaps by using a static HashMap of NetIds to - // connection pools and host resolvers. The tricky part is deciding when - // to remove a map entry; a WeakHashMap shouldn't be used because whether - // a Network is referenced doesn't correlate with whether a new Network - // will be instantiated in the near future with the same NetID. A good - // solution would involve purging empty (or when all connections are timed - // out) ConnectionPools. - final HttpURLConnectionFactory urlConnectionFactory; - synchronized (mLock) { - if (mUrlConnectionFactory == null) { - Dns dnsLookup = hostname -> Arrays.asList(getAllByName(hostname)); - mUrlConnectionFactory = createUrlConnectionFactory(dnsLookup); - } - urlConnectionFactory = mUrlConnectionFactory; - } - SocketFactory socketFactory = getSocketFactory(); - return urlConnectionFactory.openConnection(url, socketFactory, proxy); - } - - /** - * Binds the specified {@link DatagramSocket} to this {@code Network}. All data traffic on the - * socket will be sent on this {@code Network}, irrespective of any process-wide network binding - * set by {@link ConnectivityManager#bindProcessToNetwork}. The socket must not be - * connected. - */ - public void bindSocket(DatagramSocket socket) throws IOException { - // Query a property of the underlying socket to ensure that the socket's file descriptor - // exists, is available to bind to a network and is not closed. - socket.getReuseAddress(); - final ParcelFileDescriptor pfd = ParcelFileDescriptor.fromDatagramSocket(socket); - bindSocket(pfd.getFileDescriptor()); - // ParcelFileDescriptor.fromSocket() creates a dup of the original fd. The original and the - // dup share the underlying socket in the kernel. The socket is never truly closed until the - // last fd pointing to the socket being closed. So close the dup one after binding the - // socket to control the lifetime of the dup fd. - pfd.close(); - } - - /** - * Binds the specified {@link Socket} to this {@code Network}. All data traffic on the socket - * will be sent on this {@code Network}, irrespective of any process-wide network binding set by - * {@link ConnectivityManager#bindProcessToNetwork}. The socket must not be connected. - */ - public void bindSocket(Socket socket) throws IOException { - // Query a property of the underlying socket to ensure that the socket's file descriptor - // exists, is available to bind to a network and is not closed. - socket.getReuseAddress(); - final ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket); - bindSocket(pfd.getFileDescriptor()); - // ParcelFileDescriptor.fromSocket() creates a dup of the original fd. The original and the - // dup share the underlying socket in the kernel. The socket is never truly closed until the - // last fd pointing to the socket being closed. So close the dup one after binding the - // socket to control the lifetime of the dup fd. - pfd.close(); - } - - /** - * Binds the specified {@link FileDescriptor} to this {@code Network}. All data traffic on the - * socket represented by this file descriptor will be sent on this {@code Network}, - * irrespective of any process-wide network binding set by - * {@link ConnectivityManager#bindProcessToNetwork}. The socket must not be connected. - */ - public void bindSocket(FileDescriptor fd) throws IOException { - try { - final SocketAddress peer = Os.getpeername(fd); - final InetAddress inetPeer = ((InetSocketAddress) peer).getAddress(); - if (!inetPeer.isAnyLocalAddress()) { - // Apparently, the kernel doesn't update a connected UDP socket's - // routing upon mark changes. - throw new SocketException("Socket is connected"); - } - } catch (ErrnoException e) { - // getpeername() failed. - if (e.errno != OsConstants.ENOTCONN) { - throw e.rethrowAsSocketException(); - } - } catch (ClassCastException e) { - // Wasn't an InetSocketAddress. - throw new SocketException("Only AF_INET/AF_INET6 sockets supported"); - } - - final int err = NetworkUtils.bindSocketToNetwork(fd, netId); - if (err != 0) { - // bindSocketToNetwork returns negative errno. - throw new ErrnoException("Binding socket to network " + netId, -err) - .rethrowAsSocketException(); - } - } - - /** - * Returns a {@link Network} object given a handle returned from {@link #getNetworkHandle}. - * - * @param networkHandle a handle returned from {@link #getNetworkHandle}. - * @return A {@link Network} object derived from {@code networkHandle}. - */ - public static Network fromNetworkHandle(long networkHandle) { - if (networkHandle == 0) { - throw new IllegalArgumentException( - "Network.fromNetworkHandle refusing to instantiate NETID_UNSET Network."); - } - if ((networkHandle & ((1L << HANDLE_MAGIC_SIZE) - 1)) != HANDLE_MAGIC - || networkHandle < 0) { - throw new IllegalArgumentException( - "Value passed to fromNetworkHandle() is not a network handle."); - } - return new Network((int) (networkHandle >> HANDLE_MAGIC_SIZE)); - } - - /** - * Returns a handle representing this {@code Network}, for use with the NDK API. - */ - public long getNetworkHandle() { - // The network handle is explicitly not the same as the netId. - // - // The netId is an implementation detail which might be changed in the - // future, or which alone (i.e. in the absence of some additional - // context) might not be sufficient to fully identify a Network. - // - // As such, the intention is to prevent accidental misuse of the API - // that might result if a developer assumed that handles and netIds - // were identical and passing a netId to a call expecting a handle - // "just worked". Such accidental misuse, if widely deployed, might - // prevent future changes to the semantics of the netId field or - // inhibit the expansion of state required for Network objects. - // - // This extra layer of indirection might be seen as paranoia, and might - // never end up being necessary, but the added complexity is trivial. - // At some future date it may be desirable to realign the handle with - // Multiple Provisioning Domains API recommendations, as made by the - // IETF mif working group. - if (netId == 0) { - return 0L; // make this zero condition obvious for debugging - } - return (((long) netId) << HANDLE_MAGIC_SIZE) | HANDLE_MAGIC; - } - - // implement the Parcelable interface - public int describeContents() { - return 0; - } - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(netId); - } - - public static final @android.annotation.NonNull Creator CREATOR = - new Creator() { - public Network createFromParcel(Parcel in) { - int netId = in.readInt(); - - return new Network(netId); - } - - public Network[] newArray(int size) { - return new Network[size]; - } - }; - - @Override - public boolean equals(Object obj) { - if (!(obj instanceof Network)) return false; - Network other = (Network)obj; - return this.netId == other.netId; - } - - @Override - public int hashCode() { - return netId * 11; - } - - @Override - public String toString() { - return Integer.toString(netId); - } - - /** @hide */ - public void dumpDebug(ProtoOutputStream proto, long fieldId) { - final long token = proto.start(fieldId); - proto.write(NetworkProto.NET_ID, netId); - proto.end(token); - } -} diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java deleted file mode 100644 index d22d82d1f4d0..000000000000 --- a/core/java/android/net/NetworkAgent.java +++ /dev/null @@ -1,1185 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import android.annotation.IntDef; -import android.annotation.IntRange; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.SystemApi; -import android.compat.annotation.UnsupportedAppUsage; -import android.content.Context; -import android.os.Build; -import android.os.Bundle; -import android.os.ConditionVariable; -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.os.RemoteException; -import android.telephony.data.EpsBearerQosSessionAttributes; -import android.util.Log; - -import com.android.connectivity.aidl.INetworkAgent; -import com.android.connectivity.aidl.INetworkAgentRegistry; -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.Protocol; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.time.Duration; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; -import java.util.concurrent.atomic.AtomicBoolean; - -/** - * A utility class for handling for communicating between bearer-specific - * code and ConnectivityService. - * - * An agent manages the life cycle of a network. A network starts its - * life cycle when {@link register} is called on NetworkAgent. The network - * is then connecting. When full L3 connectivity has been established, - * the agent should call {@link markConnected} to inform the system that - * this network is ready to use. When the network disconnects its life - * ends and the agent should call {@link unregister}, at which point the - * system will clean up and free resources. - * Any reconnection becomes a new logical network, so after a network - * is disconnected the agent cannot be used any more. Network providers - * should create a new NetworkAgent instance to handle new connections. - * - * A bearer may have more than one NetworkAgent if it can simultaneously - * support separate networks (IMS / Internet / MMS Apns on cellular, or - * perhaps connections with different SSID or P2P for Wi-Fi). - * - * This class supports methods to start and stop sending keepalive packets. - * Keepalive packets are typically sent at periodic intervals over a network - * with NAT when there is no other traffic to avoid the network forcefully - * closing the connection. NetworkAgents that manage technologies that - * have hardware support for keepalive should implement the related - * methods to save battery life. NetworkAgent that cannot get support - * without waking up the CPU should not, as this would be prohibitive in - * terms of battery - these agents should simply not override the related - * methods, which results in the implementation returning - * {@link SocketKeepalive.ERROR_UNSUPPORTED} as appropriate. - * - * Keepalive packets need to be sent at relatively frequent intervals - * (a few seconds to a few minutes). As the contents of keepalive packets - * depend on the current network status, hardware needs to be configured - * to send them and has a limited amount of memory to do so. The HAL - * formalizes this as slots that an implementation can configure to send - * the correct packets. Devices typically have a small number of slots - * per radio technology, and the specific number of slots for each - * technology is specified in configuration files. - * {@see SocketKeepalive} for details. - * - * @hide - */ -@SystemApi -public abstract class NetworkAgent { - /** - * The {@link Network} corresponding to this object. - */ - @Nullable - private volatile Network mNetwork; - - @Nullable - private volatile INetworkAgentRegistry mRegistry; - - private interface RegistryAction { - void execute(@NonNull INetworkAgentRegistry registry) throws RemoteException; - } - - private final Handler mHandler; - private final String LOG_TAG; - private static final boolean DBG = true; - private static final boolean VDBG = false; - private final ArrayList mPreConnectedQueue = new ArrayList<>(); - private volatile long mLastBwRefreshTime = 0; - private static final long BW_REFRESH_MIN_WIN_MS = 500; - private boolean mBandwidthUpdateScheduled = false; - private AtomicBoolean mBandwidthUpdatePending = new AtomicBoolean(false); - @NonNull - private NetworkInfo mNetworkInfo; - @NonNull - private final Object mRegisterLock = new Object(); - - /** - * The ID of the {@link NetworkProvider} that created this object, or - * {@link NetworkProvider#ID_NONE} if unknown. - * @hide - */ - public final int providerId; - - private static final int BASE = Protocol.BASE_NETWORK_AGENT; - - /** - * Sent by ConnectivityService to the NetworkAgent to inform it of - * suspected connectivity problems on its network. The NetworkAgent - * should take steps to verify and correct connectivity. - * @hide - */ - public static final int CMD_SUSPECT_BAD = BASE; - - /** - * Sent by the NetworkAgent (note the EVENT vs CMD prefix) to - * ConnectivityService to pass the current NetworkInfo (connection state). - * Sent when the NetworkInfo changes, mainly due to change of state. - * obj = NetworkInfo - * @hide - */ - public static final int EVENT_NETWORK_INFO_CHANGED = BASE + 1; - - /** - * Sent by the NetworkAgent to ConnectivityService to pass the current - * NetworkCapabilties. - * obj = NetworkCapabilities - * @hide - */ - public static final int EVENT_NETWORK_CAPABILITIES_CHANGED = BASE + 2; - - /** - * Sent by the NetworkAgent to ConnectivityService to pass the current - * NetworkProperties. - * obj = NetworkProperties - * @hide - */ - public static final int EVENT_NETWORK_PROPERTIES_CHANGED = BASE + 3; - - /** - * Centralize the place where base network score, and network score scaling, will be - * stored, so as we can consistently compare apple and oranges, or wifi, ethernet and LTE - * @hide - */ - public static final int WIFI_BASE_SCORE = 60; - - /** - * Sent by the NetworkAgent to ConnectivityService to pass the current - * network score. - * arg1 = network score int - * @hide - */ - public static final int EVENT_NETWORK_SCORE_CHANGED = BASE + 4; - - /** - * Sent by the NetworkAgent to ConnectivityService to pass the current - * list of underlying networks. - * obj = array of Network objects - * @hide - */ - public static final int EVENT_UNDERLYING_NETWORKS_CHANGED = BASE + 5; - - /** - * Sent by ConnectivityService to the NetworkAgent to inform the agent of the - * networks status - whether we could use the network or could not, due to - * either a bad network configuration (no internet link) or captive portal. - * - * arg1 = either {@code VALID_NETWORK} or {@code INVALID_NETWORK} - * obj = Bundle containing map from {@code REDIRECT_URL_KEY} to {@code String} - * representing URL that Internet probe was redirect to, if it was redirected, - * or mapping to {@code null} otherwise. - * @hide - */ - public static final int CMD_REPORT_NETWORK_STATUS = BASE + 7; - - - /** - * Network validation suceeded. - * Corresponds to {@link NetworkCapabilities.NET_CAPABILITY_VALIDATED}. - */ - public static final int VALIDATION_STATUS_VALID = 1; - - /** - * Network validation was attempted and failed. This may be received more than once as - * subsequent validation attempts are made. - */ - public static final int VALIDATION_STATUS_NOT_VALID = 2; - - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = { "VALIDATION_STATUS_" }, value = { - VALIDATION_STATUS_VALID, - VALIDATION_STATUS_NOT_VALID - }) - public @interface ValidationStatus {} - - // TODO: remove. - /** @hide */ - public static final int VALID_NETWORK = 1; - /** @hide */ - public static final int INVALID_NETWORK = 2; - - /** - * The key for the redirect URL in the Bundle argument of {@code CMD_REPORT_NETWORK_STATUS}. - * @hide - */ - public static final String REDIRECT_URL_KEY = "redirect URL"; - - /** - * Sent by the NetworkAgent to ConnectivityService to indicate this network was - * explicitly selected. This should be sent before the NetworkInfo is marked - * CONNECTED so it can be given special treatment at that time. - * - * obj = boolean indicating whether to use this network even if unvalidated - * @hide - */ - public static final int EVENT_SET_EXPLICITLY_SELECTED = BASE + 8; - - /** - * Sent by ConnectivityService to the NetworkAgent to inform the agent of - * whether the network should in the future be used even if not validated. - * This decision is made by the user, but it is the network transport's - * responsibility to remember it. - * - * arg1 = 1 if true, 0 if false - * @hide - */ - public static final int CMD_SAVE_ACCEPT_UNVALIDATED = BASE + 9; - - /** - * Sent by ConnectivityService to the NetworkAgent to inform the agent to pull - * the underlying network connection for updated bandwidth information. - * @hide - */ - public static final int CMD_REQUEST_BANDWIDTH_UPDATE = BASE + 10; - - /** - * Sent by ConnectivityService to the NetworkAgent to request that the specified packet be sent - * periodically on the given interval. - * - * arg1 = the hardware slot number of the keepalive to start - * arg2 = interval in seconds - * obj = KeepalivePacketData object describing the data to be sent - * - * Also used internally by ConnectivityService / KeepaliveTracker, with different semantics. - * @hide - */ - public static final int CMD_START_SOCKET_KEEPALIVE = BASE + 11; - - /** - * Requests that the specified keepalive packet be stopped. - * - * arg1 = hardware slot number of the keepalive to stop. - * - * Also used internally by ConnectivityService / KeepaliveTracker, with different semantics. - * @hide - */ - public static final int CMD_STOP_SOCKET_KEEPALIVE = BASE + 12; - - /** - * Sent by the NetworkAgent to ConnectivityService to provide status on a socket keepalive - * request. This may either be the reply to a CMD_START_SOCKET_KEEPALIVE, or an asynchronous - * error notification. - * - * This is also sent by KeepaliveTracker to the app's {@link SocketKeepalive}, - * so that the app's {@link SocketKeepalive.Callback} methods can be called. - * - * arg1 = hardware slot number of the keepalive - * arg2 = error code - * @hide - */ - public static final int EVENT_SOCKET_KEEPALIVE = BASE + 13; - - /** - * Sent by ConnectivityService to inform this network transport of signal strength thresholds - * that when crossed should trigger a system wakeup and a NetworkCapabilities update. - * - * obj = int[] describing signal strength thresholds. - * @hide - */ - public static final int CMD_SET_SIGNAL_STRENGTH_THRESHOLDS = BASE + 14; - - /** - * Sent by ConnectivityService to the NeworkAgent to inform the agent to avoid - * automatically reconnecting to this network (e.g. via autojoin). Happens - * when user selects "No" option on the "Stay connected?" dialog box. - * @hide - */ - public static final int CMD_PREVENT_AUTOMATIC_RECONNECT = BASE + 15; - - /** - * Sent by the KeepaliveTracker to NetworkAgent to add a packet filter. - * - * For TCP keepalive offloads, keepalive packets are sent by the firmware. However, because the - * remote site will send ACK packets in response to the keepalive packets, the firmware also - * needs to be configured to properly filter the ACKs to prevent the system from waking up. - * This does not happen with UDP, so this message is TCP-specific. - * arg1 = hardware slot number of the keepalive to filter for. - * obj = the keepalive packet to send repeatedly. - * @hide - */ - public static final int CMD_ADD_KEEPALIVE_PACKET_FILTER = BASE + 16; - - /** - * Sent by the KeepaliveTracker to NetworkAgent to remove a packet filter. See - * {@link #CMD_ADD_KEEPALIVE_PACKET_FILTER}. - * arg1 = hardware slot number of the keepalive packet filter to remove. - * @hide - */ - public static final int CMD_REMOVE_KEEPALIVE_PACKET_FILTER = BASE + 17; - - /** - * Sent by ConnectivityService to the NetworkAgent to complete the bidirectional connection. - * obj = INetworkAgentRegistry - */ - private static final int EVENT_AGENT_CONNECTED = BASE + 18; - - /** - * Sent by ConnectivityService to the NetworkAgent to inform the agent that it was disconnected. - */ - private static final int EVENT_AGENT_DISCONNECTED = BASE + 19; - - /** - * Sent by QosCallbackTracker to {@link NetworkAgent} to register a new filter with - * callback. - * - * arg1 = QoS agent callback ID - * obj = {@link QosFilter} - * @hide - */ - public static final int CMD_REGISTER_QOS_CALLBACK = BASE + 20; - - /** - * Sent by QosCallbackTracker to {@link NetworkAgent} to unregister a callback. - * - * arg1 = QoS agent callback ID - * @hide - */ - public static final int CMD_UNREGISTER_QOS_CALLBACK = BASE + 21; - - private static NetworkInfo getLegacyNetworkInfo(final NetworkAgentConfig config) { - // The subtype can be changed with (TODO) setLegacySubtype, but it starts - // with 0 (TelephonyManager.NETWORK_TYPE_UNKNOWN) and an empty description. - final NetworkInfo ni = new NetworkInfo(config.legacyType, 0, config.legacyTypeName, ""); - ni.setIsAvailable(true); - ni.setDetailedState(NetworkInfo.DetailedState.CONNECTING, null /* reason */, - config.getLegacyExtraInfo()); - return ni; - } - - /** - * Create a new network agent. - * @param context a {@link Context} to get system services from. - * @param looper the {@link Looper} on which to invoke the callbacks. - * @param logTag the tag for logs - * @param nc the initial {@link NetworkCapabilities} of this network. Update with - * sendNetworkCapabilities. - * @param lp the initial {@link LinkProperties} of this network. Update with sendLinkProperties. - * @param score the initial score of this network. Update with sendNetworkScore. - * @param config an immutable {@link NetworkAgentConfig} for this agent. - * @param provider the {@link NetworkProvider} managing this agent. - */ - public NetworkAgent(@NonNull Context context, @NonNull Looper looper, @NonNull String logTag, - @NonNull NetworkCapabilities nc, @NonNull LinkProperties lp, int score, - @NonNull NetworkAgentConfig config, @Nullable NetworkProvider provider) { - this(looper, context, logTag, nc, lp, score, config, - provider == null ? NetworkProvider.ID_NONE : provider.getProviderId(), - getLegacyNetworkInfo(config)); - } - - private static class InitialConfiguration { - public final Context context; - public final NetworkCapabilities capabilities; - public final LinkProperties properties; - public final int score; - public final NetworkAgentConfig config; - public final NetworkInfo info; - InitialConfiguration(@NonNull Context context, @NonNull NetworkCapabilities capabilities, - @NonNull LinkProperties properties, int score, @NonNull NetworkAgentConfig config, - @NonNull NetworkInfo info) { - this.context = context; - this.capabilities = capabilities; - this.properties = properties; - this.score = score; - this.config = config; - this.info = info; - } - } - private volatile InitialConfiguration mInitialConfiguration; - - private NetworkAgent(@NonNull Looper looper, @NonNull Context context, @NonNull String logTag, - @NonNull NetworkCapabilities nc, @NonNull LinkProperties lp, int score, - @NonNull NetworkAgentConfig config, int providerId, @NonNull NetworkInfo ni) { - mHandler = new NetworkAgentHandler(looper); - LOG_TAG = logTag; - mNetworkInfo = new NetworkInfo(ni); - this.providerId = providerId; - if (ni == null || nc == null || lp == null) { - throw new IllegalArgumentException(); - } - - mInitialConfiguration = new InitialConfiguration(context, - new NetworkCapabilities(nc, /* parcelLocationSensitiveFields */ true), - new LinkProperties(lp), score, config, ni); - } - - private class NetworkAgentHandler extends Handler { - NetworkAgentHandler(Looper looper) { - super(looper); - } - - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case EVENT_AGENT_CONNECTED: { - if (mRegistry != null) { - log("Received new connection while already connected!"); - } else { - if (VDBG) log("NetworkAgent fully connected"); - synchronized (mPreConnectedQueue) { - final INetworkAgentRegistry registry = (INetworkAgentRegistry) msg.obj; - mRegistry = registry; - for (RegistryAction a : mPreConnectedQueue) { - try { - a.execute(registry); - } catch (RemoteException e) { - Log.wtf(LOG_TAG, "Communication error with registry", e); - // Fall through - } - } - mPreConnectedQueue.clear(); - } - } - break; - } - case EVENT_AGENT_DISCONNECTED: { - if (DBG) log("NetworkAgent channel lost"); - // let the client know CS is done with us. - onNetworkUnwanted(); - synchronized (mPreConnectedQueue) { - mRegistry = null; - } - break; - } - case CMD_SUSPECT_BAD: { - log("Unhandled Message " + msg); - break; - } - case CMD_REQUEST_BANDWIDTH_UPDATE: { - long currentTimeMs = System.currentTimeMillis(); - if (VDBG) { - log("CMD_REQUEST_BANDWIDTH_UPDATE request received."); - } - if (currentTimeMs >= (mLastBwRefreshTime + BW_REFRESH_MIN_WIN_MS)) { - mBandwidthUpdateScheduled = false; - if (!mBandwidthUpdatePending.getAndSet(true)) { - onBandwidthUpdateRequested(); - } - } else { - // deliver the request at a later time rather than discard it completely. - if (!mBandwidthUpdateScheduled) { - long waitTime = mLastBwRefreshTime + BW_REFRESH_MIN_WIN_MS - - currentTimeMs + 1; - mBandwidthUpdateScheduled = sendEmptyMessageDelayed( - CMD_REQUEST_BANDWIDTH_UPDATE, waitTime); - } - } - break; - } - case CMD_REPORT_NETWORK_STATUS: { - String redirectUrl = ((Bundle) msg.obj).getString(REDIRECT_URL_KEY); - if (VDBG) { - log("CMD_REPORT_NETWORK_STATUS(" - + (msg.arg1 == VALID_NETWORK ? "VALID, " : "INVALID, ") - + redirectUrl); - } - Uri uri = null; - try { - if (null != redirectUrl) { - uri = Uri.parse(redirectUrl); - } - } catch (Exception e) { - Log.wtf(LOG_TAG, "Surprising URI : " + redirectUrl, e); - } - onValidationStatus(msg.arg1 /* status */, uri); - break; - } - case CMD_SAVE_ACCEPT_UNVALIDATED: { - onSaveAcceptUnvalidated(msg.arg1 != 0); - break; - } - case CMD_START_SOCKET_KEEPALIVE: { - onStartSocketKeepalive(msg.arg1 /* slot */, - Duration.ofSeconds(msg.arg2) /* interval */, - (KeepalivePacketData) msg.obj /* packet */); - break; - } - case CMD_STOP_SOCKET_KEEPALIVE: { - onStopSocketKeepalive(msg.arg1 /* slot */); - break; - } - - case CMD_SET_SIGNAL_STRENGTH_THRESHOLDS: { - onSignalStrengthThresholdsUpdated((int[]) msg.obj); - break; - } - case CMD_PREVENT_AUTOMATIC_RECONNECT: { - onAutomaticReconnectDisabled(); - break; - } - case CMD_ADD_KEEPALIVE_PACKET_FILTER: { - onAddKeepalivePacketFilter(msg.arg1 /* slot */, - (KeepalivePacketData) msg.obj /* packet */); - break; - } - case CMD_REMOVE_KEEPALIVE_PACKET_FILTER: { - onRemoveKeepalivePacketFilter(msg.arg1 /* slot */); - break; - } - case CMD_REGISTER_QOS_CALLBACK: { - onQosCallbackRegistered( - msg.arg1 /* QoS callback id */, - (QosFilter) msg.obj /* QoS filter */); - break; - } - case CMD_UNREGISTER_QOS_CALLBACK: { - onQosCallbackUnregistered( - msg.arg1 /* QoS callback id */); - break; - } - } - } - } - - /** - * Register this network agent with ConnectivityService. - * - * This method can only be called once per network agent. - * - * @return the Network associated with this network agent (which can also be obtained later - * by calling getNetwork() on this agent). - * @throws IllegalStateException thrown by the system server if this network agent is - * already registered. - */ - @NonNull - public Network register() { - if (VDBG) log("Registering NetworkAgent"); - synchronized (mRegisterLock) { - if (mNetwork != null) { - throw new IllegalStateException("Agent already registered"); - } - final ConnectivityManager cm = (ConnectivityManager) mInitialConfiguration.context - .getSystemService(Context.CONNECTIVITY_SERVICE); - mNetwork = cm.registerNetworkAgent(new NetworkAgentBinder(mHandler), - new NetworkInfo(mInitialConfiguration.info), - mInitialConfiguration.properties, mInitialConfiguration.capabilities, - mInitialConfiguration.score, mInitialConfiguration.config, providerId); - mInitialConfiguration = null; // All this memory can now be GC'd - } - return mNetwork; - } - - private static class NetworkAgentBinder extends INetworkAgent.Stub { - private static final String LOG_TAG = NetworkAgentBinder.class.getSimpleName(); - - private final Handler mHandler; - - private NetworkAgentBinder(Handler handler) { - mHandler = handler; - } - - @Override - public void onRegistered(@NonNull INetworkAgentRegistry registry) { - mHandler.sendMessage(mHandler.obtainMessage(EVENT_AGENT_CONNECTED, registry)); - } - - @Override - public void onDisconnected() { - mHandler.sendMessage(mHandler.obtainMessage(EVENT_AGENT_DISCONNECTED)); - } - - @Override - public void onBandwidthUpdateRequested() { - mHandler.sendMessage(mHandler.obtainMessage(CMD_REQUEST_BANDWIDTH_UPDATE)); - } - - @Override - public void onValidationStatusChanged( - int validationStatus, @Nullable String captivePortalUrl) { - // TODO: consider using a parcelable as argument when the interface is structured - Bundle redirectUrlBundle = new Bundle(); - redirectUrlBundle.putString(NetworkAgent.REDIRECT_URL_KEY, captivePortalUrl); - mHandler.sendMessage(mHandler.obtainMessage(CMD_REPORT_NETWORK_STATUS, - validationStatus, 0, redirectUrlBundle)); - } - - @Override - public void onSaveAcceptUnvalidated(boolean acceptUnvalidated) { - mHandler.sendMessage(mHandler.obtainMessage(CMD_SAVE_ACCEPT_UNVALIDATED, - acceptUnvalidated ? 1 : 0, 0)); - } - - @Override - public void onStartNattSocketKeepalive(int slot, int intervalDurationMs, - @NonNull NattKeepalivePacketData packetData) { - mHandler.sendMessage(mHandler.obtainMessage(CMD_START_SOCKET_KEEPALIVE, - slot, intervalDurationMs, packetData)); - } - - @Override - public void onStartTcpSocketKeepalive(int slot, int intervalDurationMs, - @NonNull TcpKeepalivePacketData packetData) { - mHandler.sendMessage(mHandler.obtainMessage(CMD_START_SOCKET_KEEPALIVE, - slot, intervalDurationMs, packetData)); - } - - @Override - public void onStopSocketKeepalive(int slot) { - mHandler.sendMessage(mHandler.obtainMessage(CMD_STOP_SOCKET_KEEPALIVE, slot, 0)); - } - - @Override - public void onSignalStrengthThresholdsUpdated(@NonNull int[] thresholds) { - mHandler.sendMessage(mHandler.obtainMessage( - CMD_SET_SIGNAL_STRENGTH_THRESHOLDS, thresholds)); - } - - @Override - public void onPreventAutomaticReconnect() { - mHandler.sendMessage(mHandler.obtainMessage(CMD_PREVENT_AUTOMATIC_RECONNECT)); - } - - @Override - public void onAddNattKeepalivePacketFilter(int slot, - @NonNull NattKeepalivePacketData packetData) { - mHandler.sendMessage(mHandler.obtainMessage(CMD_ADD_KEEPALIVE_PACKET_FILTER, - slot, 0, packetData)); - } - - @Override - public void onAddTcpKeepalivePacketFilter(int slot, - @NonNull TcpKeepalivePacketData packetData) { - mHandler.sendMessage(mHandler.obtainMessage(CMD_ADD_KEEPALIVE_PACKET_FILTER, - slot, 0, packetData)); - } - - @Override - public void onRemoveKeepalivePacketFilter(int slot) { - mHandler.sendMessage(mHandler.obtainMessage(CMD_REMOVE_KEEPALIVE_PACKET_FILTER, - slot, 0)); - } - - @Override - public void onQosFilterCallbackRegistered(final int qosCallbackId, - final QosFilterParcelable qosFilterParcelable) { - if (qosFilterParcelable.getQosFilter() != null) { - mHandler.sendMessage( - mHandler.obtainMessage(CMD_REGISTER_QOS_CALLBACK, qosCallbackId, 0, - qosFilterParcelable.getQosFilter())); - return; - } - - Log.wtf(LOG_TAG, "onQosFilterCallbackRegistered: qos filter is null."); - } - - @Override - public void onQosCallbackUnregistered(final int qosCallbackId) { - mHandler.sendMessage(mHandler.obtainMessage( - CMD_UNREGISTER_QOS_CALLBACK, qosCallbackId, 0, null)); - } - } - - /** - * Register this network agent with a testing harness. - * - * The returned Messenger sends messages to the Handler. This allows a test to send - * this object {@code CMD_*} messages as if they came from ConnectivityService, which - * is useful for testing the behavior. - * - * @hide - */ - public INetworkAgent registerForTest(final Network network) { - log("Registering NetworkAgent for test"); - synchronized (mRegisterLock) { - mNetwork = network; - mInitialConfiguration = null; - } - return new NetworkAgentBinder(mHandler); - } - - /** - * Waits for the handler to be idle. - * This is useful for testing, and has smaller scope than an accessor to mHandler. - * TODO : move the implementation in common library with the tests - * @hide - */ - @VisibleForTesting - public boolean waitForIdle(final long timeoutMs) { - final ConditionVariable cv = new ConditionVariable(false); - mHandler.post(cv::open); - return cv.block(timeoutMs); - } - - /** - * @return The Network associated with this agent, or null if it's not registered yet. - */ - @Nullable - public Network getNetwork() { - return mNetwork; - } - - private void queueOrSendMessage(@NonNull RegistryAction action) { - synchronized (mPreConnectedQueue) { - if (mRegistry != null) { - try { - action.execute(mRegistry); - } catch (RemoteException e) { - Log.wtf(LOG_TAG, "Error executing registry action", e); - // Fall through: the channel is asynchronous and does not report errors back - } - } else { - mPreConnectedQueue.add(action); - } - } - } - - /** - * Must be called by the agent when the network's {@link LinkProperties} change. - * @param linkProperties the new LinkProperties. - */ - public final void sendLinkProperties(@NonNull LinkProperties linkProperties) { - Objects.requireNonNull(linkProperties); - final LinkProperties lp = new LinkProperties(linkProperties); - queueOrSendMessage(reg -> reg.sendLinkProperties(lp)); - } - - /** - * Must be called by the agent when the network's underlying networks change. - * - *

{@code networks} is one of the following: - *

    - *
  • a non-empty array: an array of one or more {@link Network}s, in - * decreasing preference order. For example, if this VPN uses both wifi and mobile (cellular) - * networks to carry app traffic, but prefers or uses wifi more than mobile, wifi should appear - * first in the array.
  • - *
  • an empty array: a zero-element array, meaning that the VPN has no - * underlying network connection, and thus, app traffic will not be sent or received.
  • - *
  • null: (default) signifies that the VPN uses whatever is the system's - * default network. I.e., it doesn't use the {@code bindSocket} or {@code bindDatagramSocket} - * APIs mentioned above to send traffic over specific channels.
  • - *
- * - * @param underlyingNetworks the new list of underlying networks. - * @see {@link VpnService.Builder#setUnderlyingNetworks(Network[])} - */ - public final void setUnderlyingNetworks(@Nullable List underlyingNetworks) { - final ArrayList underlyingArray = (underlyingNetworks != null) - ? new ArrayList<>(underlyingNetworks) : null; - queueOrSendMessage(reg -> reg.sendUnderlyingNetworks(underlyingArray)); - } - - /** - * Inform ConnectivityService that this agent has now connected. - * Call {@link #unregister} to disconnect. - */ - public void markConnected() { - mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null /* reason */, - mNetworkInfo.getExtraInfo()); - queueOrSendNetworkInfo(mNetworkInfo); - } - - /** - * Unregister this network agent. - * - * This signals the network has disconnected and ends its lifecycle. After this is called, - * the network is torn down and this agent can no longer be used. - */ - public void unregister() { - // When unregistering an agent nobody should use the extrainfo (or reason) any more. - mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, null /* reason */, - null /* extraInfo */); - queueOrSendNetworkInfo(mNetworkInfo); - } - - /** - * Change the legacy subtype of this network agent. - * - * This is only for backward compatibility and should not be used by non-legacy network agents, - * or agents that did not use to set a subtype. As such, only TYPE_MOBILE type agents can use - * this and others will be thrown an exception if they try. - * - * @deprecated this is for backward compatibility only. - * @param legacySubtype the legacy subtype. - * @hide - */ - @Deprecated - public void setLegacySubtype(final int legacySubtype, @NonNull final String legacySubtypeName) { - mNetworkInfo.setSubtype(legacySubtype, legacySubtypeName); - queueOrSendNetworkInfo(mNetworkInfo); - } - - /** - * Set the ExtraInfo of this network agent. - * - * This sets the ExtraInfo field inside the NetworkInfo returned by legacy public API and the - * broadcasts about the corresponding Network. - * This is only for backward compatibility and should not be used by non-legacy network agents, - * who will be thrown an exception if they try. The extra info should only be : - *
    - *
  • For cellular agents, the APN name.
  • - *
  • For ethernet agents, the interface name.
  • - *
- * - * @deprecated this is for backward compatibility only. - * @param extraInfo the ExtraInfo. - * @hide - */ - @Deprecated - public void setLegacyExtraInfo(@Nullable final String extraInfo) { - mNetworkInfo.setExtraInfo(extraInfo); - queueOrSendNetworkInfo(mNetworkInfo); - } - - /** - * Must be called by the agent when it has a new NetworkInfo object. - * @hide TODO: expose something better. - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) - public final void sendNetworkInfo(NetworkInfo networkInfo) { - queueOrSendNetworkInfo(new NetworkInfo(networkInfo)); - } - - private void queueOrSendNetworkInfo(NetworkInfo networkInfo) { - queueOrSendMessage(reg -> reg.sendNetworkInfo(networkInfo)); - } - - /** - * Must be called by the agent when the network's {@link NetworkCapabilities} change. - * @param networkCapabilities the new NetworkCapabilities. - */ - public final void sendNetworkCapabilities(@NonNull NetworkCapabilities networkCapabilities) { - Objects.requireNonNull(networkCapabilities); - mBandwidthUpdatePending.set(false); - mLastBwRefreshTime = System.currentTimeMillis(); - final NetworkCapabilities nc = - new NetworkCapabilities(networkCapabilities, - /* parcelLocationSensitiveFields */ true); - queueOrSendMessage(reg -> reg.sendNetworkCapabilities(nc)); - } - - /** - * Must be called by the agent to update the score of this network. - * - * @param score the new score, between 0 and 99. - */ - public final void sendNetworkScore(@IntRange(from = 0, to = 99) int score) { - if (score < 0) { - throw new IllegalArgumentException("Score must be >= 0"); - } - queueOrSendMessage(reg -> reg.sendScore(score)); - } - - /** - * Must be called by the agent to indicate this network was manually selected by the user. - * This should be called before the NetworkInfo is marked CONNECTED so that this - * Network can be given special treatment at that time. If {@code acceptUnvalidated} is - * {@code true}, then the system will switch to this network. If it is {@code false} and the - * network cannot be validated, the system will ask the user whether to switch to this network. - * If the user confirms and selects "don't ask again", then the system will call - * {@link #saveAcceptUnvalidated} to persist the user's choice. Thus, if the transport ever - * calls this method with {@code acceptUnvalidated} set to {@code false}, it must also implement - * {@link #saveAcceptUnvalidated} to respect the user's choice. - * @hide should move to NetworkAgentConfig. - */ - public void explicitlySelected(boolean acceptUnvalidated) { - explicitlySelected(true /* explicitlySelected */, acceptUnvalidated); - } - - /** - * Must be called by the agent to indicate whether the network was manually selected by the - * user. This should be called before the network becomes connected, so it can be given - * special treatment when it does. - * - * If {@code explicitlySelected} is {@code true}, and {@code acceptUnvalidated} is {@code true}, - * then the system will switch to this network. If {@code explicitlySelected} is {@code true} - * and {@code acceptUnvalidated} is {@code false}, and the network cannot be validated, the - * system will ask the user whether to switch to this network. If the user confirms and selects - * "don't ask again", then the system will call {@link #saveAcceptUnvalidated} to persist the - * user's choice. Thus, if the transport ever calls this method with {@code explicitlySelected} - * set to {@code true} and {@code acceptUnvalidated} set to {@code false}, it must also - * implement {@link #saveAcceptUnvalidated} to respect the user's choice. - * - * If {@code explicitlySelected} is {@code false} and {@code acceptUnvalidated} is - * {@code true}, the system will interpret this as the user having accepted partial connectivity - * on this network. Thus, the system will switch to the network and consider it validated even - * if it only provides partial connectivity, but the network is not otherwise treated specially. - * @hide should move to NetworkAgentConfig. - */ - public void explicitlySelected(boolean explicitlySelected, boolean acceptUnvalidated) { - queueOrSendMessage(reg -> reg.sendExplicitlySelected( - explicitlySelected, acceptUnvalidated)); - } - - /** - * Called when ConnectivityService has indicated they no longer want this network. - * The parent factory should (previously) have received indication of the change - * as well, either canceling NetworkRequests or altering their score such that this - * network won't be immediately requested again. - */ - public void onNetworkUnwanted() { - unwanted(); - } - /** @hide TODO delete once subclasses have moved to onNetworkUnwanted. */ - protected void unwanted() { - } - - /** - * Called when ConnectivityService request a bandwidth update. The parent factory - * shall try to overwrite this method and produce a bandwidth update if capable. - * @hide - */ - public void onBandwidthUpdateRequested() { - pollLceData(); - } - /** @hide TODO delete once subclasses have moved to onBandwidthUpdateRequested. */ - protected void pollLceData() { - } - - /** - * Called when the system determines the usefulness of this network. - * - * The system attempts to validate Internet connectivity on networks that provide the - * {@link NetworkCapabilities#NET_CAPABILITY_INTERNET} capability. - * - * Currently there are two possible values: - * {@code VALIDATION_STATUS_VALID} if Internet connectivity was validated, - * {@code VALIDATION_STATUS_NOT_VALID} if Internet connectivity was not validated. - * - * This is guaranteed to be called again when the network status changes, but the system - * may also call this multiple times even if the status does not change. - * - * @param status one of {@code VALIDATION_STATUS_VALID} or {@code VALIDATION_STATUS_NOT_VALID}. - * @param redirectUri If Internet connectivity is being redirected (e.g., on a captive portal), - * this is the destination the probes are being redirected to, otherwise {@code null}. - */ - public void onValidationStatus(@ValidationStatus int status, @Nullable Uri redirectUri) { - networkStatus(status, null == redirectUri ? "" : redirectUri.toString()); - } - /** @hide TODO delete once subclasses have moved to onValidationStatus */ - protected void networkStatus(int status, String redirectUrl) { - } - - - /** - * Called when the user asks to remember the choice to use this network even if unvalidated. - * The transport is responsible for remembering the choice, and the next time the user connects - * to the network, should explicitlySelected with {@code acceptUnvalidated} set to {@code true}. - * This method will only be called if {@link #explicitlySelected} was called with - * {@code acceptUnvalidated} set to {@code false}. - * @param accept whether the user wants to use the network even if unvalidated. - */ - public void onSaveAcceptUnvalidated(boolean accept) { - saveAcceptUnvalidated(accept); - } - /** @hide TODO delete once subclasses have moved to onSaveAcceptUnvalidated */ - protected void saveAcceptUnvalidated(boolean accept) { - } - - /** - * Requests that the network hardware send the specified packet at the specified interval. - * - * @param slot the hardware slot on which to start the keepalive. - * @param interval the interval between packets, between 10 and 3600. Note that this API - * does not support sub-second precision and will round off the request. - * @param packet the packet to send. - */ - // seconds is from SocketKeepalive.MIN_INTERVAL_SEC to MAX_INTERVAL_SEC, but these should - // not be exposed as constants because they may change in the future (API guideline 4.8) - // and should have getters if exposed at all. Getters can't be used in the annotation, - // so the values unfortunately need to be copied. - public void onStartSocketKeepalive(int slot, @NonNull Duration interval, - @NonNull KeepalivePacketData packet) { - final long intervalSeconds = interval.getSeconds(); - if (intervalSeconds < SocketKeepalive.MIN_INTERVAL_SEC - || intervalSeconds > SocketKeepalive.MAX_INTERVAL_SEC) { - throw new IllegalArgumentException("Interval needs to be comprised between " - + SocketKeepalive.MIN_INTERVAL_SEC + " and " + SocketKeepalive.MAX_INTERVAL_SEC - + " but was " + intervalSeconds); - } - final Message msg = mHandler.obtainMessage(CMD_START_SOCKET_KEEPALIVE, slot, - (int) intervalSeconds, packet); - startSocketKeepalive(msg); - msg.recycle(); - } - /** @hide TODO delete once subclasses have moved to onStartSocketKeepalive */ - protected void startSocketKeepalive(Message msg) { - onSocketKeepaliveEvent(msg.arg1, SocketKeepalive.ERROR_UNSUPPORTED); - } - - /** - * Requests that the network hardware stop a previously-started keepalive. - * - * @param slot the hardware slot on which to stop the keepalive. - */ - public void onStopSocketKeepalive(int slot) { - Message msg = mHandler.obtainMessage(CMD_STOP_SOCKET_KEEPALIVE, slot, 0, null); - stopSocketKeepalive(msg); - msg.recycle(); - } - /** @hide TODO delete once subclasses have moved to onStopSocketKeepalive */ - protected void stopSocketKeepalive(Message msg) { - onSocketKeepaliveEvent(msg.arg1, SocketKeepalive.ERROR_UNSUPPORTED); - } - - /** - * Must be called by the agent when a socket keepalive event occurs. - * - * @param slot the hardware slot on which the event occurred. - * @param event the event that occurred, as one of the SocketKeepalive.ERROR_* - * or SocketKeepalive.SUCCESS constants. - */ - public final void sendSocketKeepaliveEvent(int slot, - @SocketKeepalive.KeepaliveEvent int event) { - queueOrSendMessage(reg -> reg.sendSocketKeepaliveEvent(slot, event)); - } - /** @hide TODO delete once callers have moved to sendSocketKeepaliveEvent */ - public void onSocketKeepaliveEvent(int slot, int reason) { - sendSocketKeepaliveEvent(slot, reason); - } - - /** - * Called by ConnectivityService to add specific packet filter to network hardware to block - * replies (e.g., TCP ACKs) matching the sent keepalive packets. Implementations that support - * this feature must override this method. - * - * @param slot the hardware slot on which the keepalive should be sent. - * @param packet the packet that is being sent. - */ - public void onAddKeepalivePacketFilter(int slot, @NonNull KeepalivePacketData packet) { - Message msg = mHandler.obtainMessage(CMD_ADD_KEEPALIVE_PACKET_FILTER, slot, 0, packet); - addKeepalivePacketFilter(msg); - msg.recycle(); - } - /** @hide TODO delete once subclasses have moved to onAddKeepalivePacketFilter */ - protected void addKeepalivePacketFilter(Message msg) { - } - - /** - * Called by ConnectivityService to remove a packet filter installed with - * {@link #addKeepalivePacketFilter(Message)}. Implementations that support this feature - * must override this method. - * - * @param slot the hardware slot on which the keepalive is being sent. - */ - public void onRemoveKeepalivePacketFilter(int slot) { - Message msg = mHandler.obtainMessage(CMD_REMOVE_KEEPALIVE_PACKET_FILTER, slot, 0, null); - removeKeepalivePacketFilter(msg); - msg.recycle(); - } - /** @hide TODO delete once subclasses have moved to onRemoveKeepalivePacketFilter */ - protected void removeKeepalivePacketFilter(Message msg) { - } - - /** - * Called by ConnectivityService to inform this network agent of signal strength thresholds - * that when crossed should trigger a system wakeup and a NetworkCapabilities update. - * - * When the system updates the list of thresholds that should wake up the CPU for a - * given agent it will call this method on the agent. The agent that implement this - * should implement it in hardware so as to ensure the CPU will be woken up on breach. - * Agents are expected to react to a breach by sending an updated NetworkCapabilities - * object with the appropriate signal strength to sendNetworkCapabilities. - * - * The specific units are bearer-dependent. See details on the units and requests in - * {@link NetworkCapabilities.Builder#setSignalStrength}. - * - * @param thresholds the array of thresholds that should trigger wakeups. - */ - public void onSignalStrengthThresholdsUpdated(@NonNull int[] thresholds) { - setSignalStrengthThresholds(thresholds); - } - /** @hide TODO delete once subclasses have moved to onSetSignalStrengthThresholds */ - protected void setSignalStrengthThresholds(int[] thresholds) { - } - - /** - * Called when the user asks to not stay connected to this network because it was found to not - * provide Internet access. Usually followed by call to {@code unwanted}. The transport is - * responsible for making sure the device does not automatically reconnect to the same network - * after the {@code unwanted} call. - */ - public void onAutomaticReconnectDisabled() { - preventAutomaticReconnect(); - } - /** @hide TODO delete once subclasses have moved to onAutomaticReconnectDisabled */ - protected void preventAutomaticReconnect() { - } - - /** - * Called when a qos callback is registered with a filter. - * @param qosCallbackId the id for the callback registered - * @param filter the filter being registered - */ - public void onQosCallbackRegistered(final int qosCallbackId, final @NonNull QosFilter filter) { - } - - /** - * Called when a qos callback is registered with a filter. - *

- * Any QoS events that are sent with the same callback id after this method is called - * are a no-op. - * - * @param qosCallbackId the id for the callback being unregistered - */ - public void onQosCallbackUnregistered(final int qosCallbackId) { - } - - - /** - * Sends the attributes of Eps Bearer Qos Session back to the Application - * - * @param qosCallbackId the callback id that the session belongs to - * @param sessionId the unique session id across all Eps Bearer Qos Sessions - * @param attributes the attributes of the Eps Qos Session - */ - public final void sendQosSessionAvailable(final int qosCallbackId, final int sessionId, - @NonNull final EpsBearerQosSessionAttributes attributes) { - Objects.requireNonNull(attributes, "The attributes must be non-null"); - queueOrSendMessage(ra -> ra.sendEpsQosSessionAvailable(qosCallbackId, - new QosSession(sessionId, QosSession.TYPE_EPS_BEARER), - attributes)); - } - - /** - * Sends event that the Eps Qos Session was lost. - * - * @param qosCallbackId the callback id that the session belongs to - * @param sessionId the unique session id across all Eps Bearer Qos Sessions - */ - public final void sendQosSessionLost(final int qosCallbackId, final int sessionId) { - queueOrSendMessage(ra -> ra.sendQosSessionLost(qosCallbackId, - new QosSession(sessionId, QosSession.TYPE_EPS_BEARER))); - } - - /** - * Sends the exception type back to the application. - * - * The NetworkAgent should not send anymore messages with this id. - * - * @param qosCallbackId the callback id this exception belongs to - * @param exceptionType the type of exception - */ - public final void sendQosCallbackError(final int qosCallbackId, - @QosCallbackException.ExceptionType final int exceptionType) { - queueOrSendMessage(ra -> ra.sendQosCallbackError(qosCallbackId, exceptionType)); - } - - - /** @hide */ - protected void log(final String s) { - Log.d(LOG_TAG, "NetworkAgent: " + s); - } -} diff --git a/core/java/android/net/NetworkAgentConfig.aidl b/core/java/android/net/NetworkAgentConfig.aidl deleted file mode 100644 index cb70bdd31260..000000000000 --- a/core/java/android/net/NetworkAgentConfig.aidl +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -parcelable NetworkAgentConfig; diff --git a/core/java/android/net/NetworkAgentConfig.java b/core/java/android/net/NetworkAgentConfig.java deleted file mode 100644 index 664c2650ff0c..000000000000 --- a/core/java/android/net/NetworkAgentConfig.java +++ /dev/null @@ -1,440 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.SystemApi; -import android.os.Parcel; -import android.os.Parcelable; - -import java.util.Objects; - -/** - * Allows a network transport to provide the system with policy and configuration information about - * a particular network when registering a {@link NetworkAgent}. This information cannot change once the agent is registered. - * - * @hide - */ -@SystemApi -public final class NetworkAgentConfig implements Parcelable { - - /** - * If the {@link Network} is a VPN, whether apps are allowed to bypass the - * VPN. This is set by a {@link VpnService} and used by - * {@link ConnectivityManager} when creating a VPN. - * - * @hide - */ - public boolean allowBypass; - - /** - * Set if the network was manually/explicitly connected to by the user either from settings - * or a 3rd party app. For example, turning on cell data is not explicit but tapping on a wifi - * ap in the wifi settings to trigger a connection is explicit. A 3rd party app asking to - * connect to a particular access point is also explicit, though this may change in the future - * as we want apps to use the multinetwork apis. - * - * @hide - */ - public boolean explicitlySelected; - - /** - * @return whether this network was explicitly selected by the user. - */ - public boolean isExplicitlySelected() { - return explicitlySelected; - } - - /** - * Set if the user desires to use this network even if it is unvalidated. This field has meaning - * only if {@link explicitlySelected} is true. If it is, this field must also be set to the - * appropriate value based on previous user choice. - * - * TODO : rename this field to match its accessor - * @hide - */ - public boolean acceptUnvalidated; - - /** - * @return whether the system should accept this network even if it doesn't validate. - */ - public boolean isUnvalidatedConnectivityAcceptable() { - return acceptUnvalidated; - } - - /** - * Whether the user explicitly set that this network should be validated even if presence of - * only partial internet connectivity. - * - * TODO : rename this field to match its accessor - * @hide - */ - public boolean acceptPartialConnectivity; - - /** - * @return whether the system should validate this network even if it only offers partial - * Internet connectivity. - */ - public boolean isPartialConnectivityAcceptable() { - return acceptPartialConnectivity; - } - - /** - * Set to avoid surfacing the "Sign in to network" notification. - * if carrier receivers/apps are registered to handle the carrier-specific provisioning - * procedure, a carrier specific provisioning notification will be placed. - * only one notification should be displayed. This field is set based on - * which notification should be used for provisioning. - * - * @hide - */ - public boolean provisioningNotificationDisabled; - - /** - * - * @return whether the sign in to network notification is enabled by this configuration. - * @hide - */ - public boolean isProvisioningNotificationEnabled() { - return !provisioningNotificationDisabled; - } - - /** - * For mobile networks, this is the subscriber ID (such as IMSI). - * - * @hide - */ - public String subscriberId; - - /** - * @return the subscriber ID, or null if none. - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - @Nullable - public String getSubscriberId() { - return subscriberId; - } - - /** - * Set to skip 464xlat. This means the device will treat the network as IPv6-only and - * will not attempt to detect a NAT64 via RFC 7050 DNS lookups. - * - * @hide - */ - public boolean skip464xlat; - - /** - * @return whether NAT64 prefix detection is enabled. - * @hide - */ - public boolean isNat64DetectionEnabled() { - return !skip464xlat; - } - - /** - * The legacy type of this network agent, or TYPE_NONE if unset. - * @hide - */ - public int legacyType = ConnectivityManager.TYPE_NONE; - - /** - * @return the legacy type - */ - @ConnectivityManager.LegacyNetworkType - public int getLegacyType() { - return legacyType; - } - - /** - * Set to true if the PRIVATE_DNS_BROKEN notification has shown for this network. - * Reset this bit when private DNS mode is changed from strict mode to opportunistic/off mode. - * - * This is not parceled, because it would not make sense. - * - * @hide - */ - public transient boolean hasShownBroken; - - /** - * The name of the legacy network type. It's a free-form string used in logging. - * @hide - */ - @NonNull - public String legacyTypeName = ""; - - /** - * @return the name of the legacy network type. It's a free-form string used in logging. - */ - @NonNull - public String getLegacyTypeName() { - return legacyTypeName; - } - - /** - * The legacy extra info of the agent. The extra info should only be : - *

    - *
  • For cellular agents, the APN name.
  • - *
  • For ethernet agents, the interface name.
  • - *
- * @hide - */ - @NonNull - private String mLegacyExtraInfo = ""; - - /** - * The legacy extra info of the agent. - * @hide - */ - @NonNull - public String getLegacyExtraInfo() { - return mLegacyExtraInfo; - } - - /** @hide */ - public NetworkAgentConfig() { - } - - /** @hide */ - public NetworkAgentConfig(@Nullable NetworkAgentConfig nac) { - if (nac != null) { - allowBypass = nac.allowBypass; - explicitlySelected = nac.explicitlySelected; - acceptUnvalidated = nac.acceptUnvalidated; - acceptPartialConnectivity = nac.acceptPartialConnectivity; - subscriberId = nac.subscriberId; - provisioningNotificationDisabled = nac.provisioningNotificationDisabled; - skip464xlat = nac.skip464xlat; - legacyType = nac.legacyType; - legacyTypeName = nac.legacyTypeName; - mLegacyExtraInfo = nac.mLegacyExtraInfo; - } - } - - /** - * Builder class to facilitate constructing {@link NetworkAgentConfig} objects. - */ - public static final class Builder { - private final NetworkAgentConfig mConfig = new NetworkAgentConfig(); - - /** - * Sets whether the network was explicitly selected by the user. - * - * @return this builder, to facilitate chaining. - */ - @NonNull - public Builder setExplicitlySelected(final boolean explicitlySelected) { - mConfig.explicitlySelected = explicitlySelected; - return this; - } - - /** - * Sets whether the system should validate this network even if it is found not to offer - * Internet connectivity. - * - * @return this builder, to facilitate chaining. - */ - @NonNull - public Builder setUnvalidatedConnectivityAcceptable( - final boolean unvalidatedConnectivityAcceptable) { - mConfig.acceptUnvalidated = unvalidatedConnectivityAcceptable; - return this; - } - - /** - * Sets whether the system should validate this network even if it is found to only offer - * partial Internet connectivity. - * - * @return this builder, to facilitate chaining. - */ - @NonNull - public Builder setPartialConnectivityAcceptable( - final boolean partialConnectivityAcceptable) { - mConfig.acceptPartialConnectivity = partialConnectivityAcceptable; - return this; - } - - /** - * Sets the subscriber ID for this network. - * - * @return this builder, to facilitate chaining. - * @hide - */ - @NonNull - @SystemApi(client = MODULE_LIBRARIES) - public Builder setSubscriberId(@Nullable String subscriberId) { - mConfig.subscriberId = subscriberId; - return this; - } - - /** - * Disables active detection of NAT64 (e.g., via RFC 7050 DNS lookups). Used to save power - * and reduce idle traffic on networks that are known to be IPv6-only without a NAT64. - * - * @return this builder, to facilitate chaining. - * @hide - */ - @NonNull - public Builder disableNat64Detection() { - mConfig.skip464xlat = true; - return this; - } - - /** - * Disables the "Sign in to network" notification. Used if the network transport will - * perform its own carrier-specific provisioning procedure. - * - * @return this builder, to facilitate chaining. - * @hide - */ - @NonNull - public Builder disableProvisioningNotification() { - mConfig.provisioningNotificationDisabled = true; - return this; - } - - /** - * Sets the legacy type for this network. - * - * @param legacyType the type - * @return this builder, to facilitate chaining. - */ - @NonNull - public Builder setLegacyType(int legacyType) { - mConfig.legacyType = legacyType; - return this; - } - - /** - * Sets the name of the legacy type of the agent. It's a free-form string used in logging. - * @param legacyTypeName the name - * @return this builder, to facilitate chaining. - */ - @NonNull - public Builder setLegacyTypeName(@NonNull String legacyTypeName) { - mConfig.legacyTypeName = legacyTypeName; - return this; - } - - /** - * Sets the legacy extra info of the agent. - * @param legacyExtraInfo the legacy extra info. - * @return this builder, to facilitate chaining. - * @hide - */ - @NonNull - public Builder setLegacyExtraInfo(@NonNull String legacyExtraInfo) { - mConfig.mLegacyExtraInfo = legacyExtraInfo; - return this; - } - - /** - * Returns the constructed {@link NetworkAgentConfig} object. - */ - @NonNull - public NetworkAgentConfig build() { - return mConfig; - } - } - - @Override - public boolean equals(final Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - final NetworkAgentConfig that = (NetworkAgentConfig) o; - return allowBypass == that.allowBypass - && explicitlySelected == that.explicitlySelected - && acceptUnvalidated == that.acceptUnvalidated - && acceptPartialConnectivity == that.acceptPartialConnectivity - && provisioningNotificationDisabled == that.provisioningNotificationDisabled - && skip464xlat == that.skip464xlat - && legacyType == that.legacyType - && Objects.equals(subscriberId, that.subscriberId) - && Objects.equals(legacyTypeName, that.legacyTypeName) - && Objects.equals(mLegacyExtraInfo, that.mLegacyExtraInfo); - } - - @Override - public int hashCode() { - return Objects.hash(allowBypass, explicitlySelected, acceptUnvalidated, - acceptPartialConnectivity, provisioningNotificationDisabled, subscriberId, - skip464xlat, legacyType, legacyTypeName, mLegacyExtraInfo); - } - - @Override - public String toString() { - return "NetworkAgentConfig {" - + " allowBypass = " + allowBypass - + ", explicitlySelected = " + explicitlySelected - + ", acceptUnvalidated = " + acceptUnvalidated - + ", acceptPartialConnectivity = " + acceptPartialConnectivity - + ", provisioningNotificationDisabled = " + provisioningNotificationDisabled - + ", subscriberId = '" + subscriberId + '\'' - + ", skip464xlat = " + skip464xlat - + ", legacyType = " + legacyType - + ", hasShownBroken = " + hasShownBroken - + ", legacyTypeName = '" + legacyTypeName + '\'' - + ", legacyExtraInfo = '" + mLegacyExtraInfo + '\'' - + "}"; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(@NonNull Parcel out, int flags) { - out.writeInt(allowBypass ? 1 : 0); - out.writeInt(explicitlySelected ? 1 : 0); - out.writeInt(acceptUnvalidated ? 1 : 0); - out.writeInt(acceptPartialConnectivity ? 1 : 0); - out.writeString(subscriberId); - out.writeInt(provisioningNotificationDisabled ? 1 : 0); - out.writeInt(skip464xlat ? 1 : 0); - out.writeInt(legacyType); - out.writeString(legacyTypeName); - out.writeString(mLegacyExtraInfo); - } - - public static final @NonNull Creator CREATOR = - new Creator() { - @Override - public NetworkAgentConfig createFromParcel(Parcel in) { - NetworkAgentConfig networkAgentConfig = new NetworkAgentConfig(); - networkAgentConfig.allowBypass = in.readInt() != 0; - networkAgentConfig.explicitlySelected = in.readInt() != 0; - networkAgentConfig.acceptUnvalidated = in.readInt() != 0; - networkAgentConfig.acceptPartialConnectivity = in.readInt() != 0; - networkAgentConfig.subscriberId = in.readString(); - networkAgentConfig.provisioningNotificationDisabled = in.readInt() != 0; - networkAgentConfig.skip464xlat = in.readInt() != 0; - networkAgentConfig.legacyType = in.readInt(); - networkAgentConfig.legacyTypeName = in.readString(); - networkAgentConfig.mLegacyExtraInfo = in.readString(); - return networkAgentConfig; - } - - @Override - public NetworkAgentConfig[] newArray(int size) { - return new NetworkAgentConfig[size]; - } - }; -} diff --git a/core/java/android/net/NetworkCapabilities.aidl b/core/java/android/net/NetworkCapabilities.aidl deleted file mode 100644 index 01d328605de4..000000000000 --- a/core/java/android/net/NetworkCapabilities.aidl +++ /dev/null @@ -1,21 +0,0 @@ -/* -** -** Copyright (C) 2014 The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -package android.net; - -@JavaOnlyStableParcelable parcelable NetworkCapabilities; - diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java deleted file mode 100644 index 3843b9ab93c2..000000000000 --- a/core/java/android/net/NetworkCapabilities.java +++ /dev/null @@ -1,2517 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE; - -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.RequiresPermission; -import android.annotation.SystemApi; -import android.compat.annotation.UnsupportedAppUsage; -import android.net.ConnectivityManager.NetworkCallback; -import android.os.Build; -import android.os.Parcel; -import android.os.Parcelable; -import android.os.Process; -import android.text.TextUtils; -import android.util.ArraySet; -import android.util.proto.ProtoOutputStream; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.ArrayUtils; -import com.android.internal.util.BitUtils; -import com.android.internal.util.Preconditions; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.Arrays; -import java.util.Objects; -import java.util.Set; -import java.util.StringJoiner; - -/** - * Representation of the capabilities of an active network. Instances are - * typically obtained through - * {@link NetworkCallback#onCapabilitiesChanged(Network, NetworkCapabilities)} - * or {@link ConnectivityManager#getNetworkCapabilities(Network)}. - *

- * This replaces the old {@link ConnectivityManager#TYPE_MOBILE} method of - * network selection. Rather than indicate a need for Wi-Fi because an - * application needs high bandwidth and risk obsolescence when a new, fast - * network appears (like LTE), the application should specify it needs high - * bandwidth. Similarly if an application needs an unmetered network for a bulk - * transfer it can specify that rather than assuming all cellular based - * connections are metered and all Wi-Fi based connections are not. - */ -public final class NetworkCapabilities implements Parcelable { - private static final String TAG = "NetworkCapabilities"; - - // Set to true when private DNS is broken. - private boolean mPrivateDnsBroken; - - /** - * Uid of the app making the request. - */ - private int mRequestorUid; - - /** - * Package name of the app making the request. - */ - private String mRequestorPackageName; - - /** - * Indicates whether parceling should preserve fields that are set based on permissions of - * the process receiving the {@link NetworkCapabilities}. - */ - private final boolean mParcelLocationSensitiveFields; - - public NetworkCapabilities() { - mParcelLocationSensitiveFields = false; - clearAll(); - mNetworkCapabilities = DEFAULT_CAPABILITIES; - } - - public NetworkCapabilities(NetworkCapabilities nc) { - this(nc, false /* parcelLocationSensitiveFields */); - } - - /** - * Make a copy of NetworkCapabilities. - * - * @param nc Original NetworkCapabilities - * @param parcelLocationSensitiveFields Whether to parcel location sensitive data or not. - * @hide - */ - @SystemApi - public NetworkCapabilities( - @Nullable NetworkCapabilities nc, boolean parcelLocationSensitiveFields) { - mParcelLocationSensitiveFields = parcelLocationSensitiveFields; - if (nc != null) { - set(nc); - } - } - - /** - * Completely clears the contents of this object, removing even the capabilities that are set - * by default when the object is constructed. - * @hide - */ - public void clearAll() { - // Ensures that the internal copies maintained by the connectivity stack does not set - // this bit. - if (mParcelLocationSensitiveFields) { - throw new UnsupportedOperationException( - "Cannot clear NetworkCapabilities when parcelLocationSensitiveFields is set"); - } - mNetworkCapabilities = mTransportTypes = mUnwantedNetworkCapabilities = 0; - mLinkUpBandwidthKbps = mLinkDownBandwidthKbps = LINK_BANDWIDTH_UNSPECIFIED; - mNetworkSpecifier = null; - mTransportInfo = null; - mSignalStrength = SIGNAL_STRENGTH_UNSPECIFIED; - mUids = null; - mAdministratorUids = new int[0]; - mOwnerUid = Process.INVALID_UID; - mSSID = null; - mPrivateDnsBroken = false; - mRequestorUid = Process.INVALID_UID; - mRequestorPackageName = null; - } - - /** - * Set all contents of this object to the contents of a NetworkCapabilities. - * - * @param nc Original NetworkCapabilities - * @hide - */ - public void set(@NonNull NetworkCapabilities nc) { - mNetworkCapabilities = nc.mNetworkCapabilities; - mTransportTypes = nc.mTransportTypes; - mLinkUpBandwidthKbps = nc.mLinkUpBandwidthKbps; - mLinkDownBandwidthKbps = nc.mLinkDownBandwidthKbps; - mNetworkSpecifier = nc.mNetworkSpecifier; - if (nc.getTransportInfo() != null) { - setTransportInfo(nc.getTransportInfo().makeCopy(mParcelLocationSensitiveFields)); - } else { - setTransportInfo(null); - } - mSignalStrength = nc.mSignalStrength; - setUids(nc.mUids); // Will make the defensive copy - setAdministratorUids(nc.getAdministratorUids()); - mOwnerUid = nc.mOwnerUid; - mUnwantedNetworkCapabilities = nc.mUnwantedNetworkCapabilities; - mSSID = nc.mSSID; - mPrivateDnsBroken = nc.mPrivateDnsBroken; - mRequestorUid = nc.mRequestorUid; - mRequestorPackageName = nc.mRequestorPackageName; - } - - /** - * Represents the network's capabilities. If any are specified they will be satisfied - * by any Network that matches all of them. - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private long mNetworkCapabilities; - - /** - * If any capabilities specified here they must not exist in the matching Network. - */ - private long mUnwantedNetworkCapabilities; - - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = { "NET_CAPABILITY_" }, value = { - NET_CAPABILITY_MMS, - NET_CAPABILITY_SUPL, - NET_CAPABILITY_DUN, - NET_CAPABILITY_FOTA, - NET_CAPABILITY_IMS, - NET_CAPABILITY_CBS, - NET_CAPABILITY_WIFI_P2P, - NET_CAPABILITY_IA, - NET_CAPABILITY_RCS, - NET_CAPABILITY_XCAP, - NET_CAPABILITY_EIMS, - NET_CAPABILITY_NOT_METERED, - NET_CAPABILITY_INTERNET, - NET_CAPABILITY_NOT_RESTRICTED, - NET_CAPABILITY_TRUSTED, - NET_CAPABILITY_NOT_VPN, - NET_CAPABILITY_VALIDATED, - NET_CAPABILITY_CAPTIVE_PORTAL, - NET_CAPABILITY_NOT_ROAMING, - NET_CAPABILITY_FOREGROUND, - NET_CAPABILITY_NOT_CONGESTED, - NET_CAPABILITY_NOT_SUSPENDED, - NET_CAPABILITY_OEM_PAID, - NET_CAPABILITY_MCX, - NET_CAPABILITY_PARTIAL_CONNECTIVITY, - NET_CAPABILITY_TEMPORARILY_NOT_METERED, - NET_CAPABILITY_OEM_PRIVATE, - NET_CAPABILITY_VEHICLE_INTERNAL, - NET_CAPABILITY_NOT_VCN_MANAGED, - }) - public @interface NetCapability { } - - /** - * Indicates this is a network that has the ability to reach the - * carrier's MMSC for sending and receiving MMS messages. - */ - public static final int NET_CAPABILITY_MMS = 0; - - /** - * Indicates this is a network that has the ability to reach the carrier's - * SUPL server, used to retrieve GPS information. - */ - public static final int NET_CAPABILITY_SUPL = 1; - - /** - * Indicates this is a network that has the ability to reach the carrier's - * DUN or tethering gateway. - */ - public static final int NET_CAPABILITY_DUN = 2; - - /** - * Indicates this is a network that has the ability to reach the carrier's - * FOTA portal, used for over the air updates. - */ - public static final int NET_CAPABILITY_FOTA = 3; - - /** - * Indicates this is a network that has the ability to reach the carrier's - * IMS servers, used for network registration and signaling. - */ - public static final int NET_CAPABILITY_IMS = 4; - - /** - * Indicates this is a network that has the ability to reach the carrier's - * CBS servers, used for carrier specific services. - */ - public static final int NET_CAPABILITY_CBS = 5; - - /** - * Indicates this is a network that has the ability to reach a Wi-Fi direct - * peer. - */ - public static final int NET_CAPABILITY_WIFI_P2P = 6; - - /** - * Indicates this is a network that has the ability to reach a carrier's - * Initial Attach servers. - */ - public static final int NET_CAPABILITY_IA = 7; - - /** - * Indicates this is a network that has the ability to reach a carrier's - * RCS servers, used for Rich Communication Services. - */ - public static final int NET_CAPABILITY_RCS = 8; - - /** - * Indicates this is a network that has the ability to reach a carrier's - * XCAP servers, used for configuration and control. - */ - public static final int NET_CAPABILITY_XCAP = 9; - - /** - * Indicates this is a network that has the ability to reach a carrier's - * Emergency IMS servers or other services, used for network signaling - * during emergency calls. - */ - public static final int NET_CAPABILITY_EIMS = 10; - - /** - * Indicates that this network is unmetered. - */ - public static final int NET_CAPABILITY_NOT_METERED = 11; - - /** - * Indicates that this network should be able to reach the internet. - */ - public static final int NET_CAPABILITY_INTERNET = 12; - - /** - * Indicates that this network is available for general use. If this is not set - * applications should not attempt to communicate on this network. Note that this - * is simply informative and not enforcement - enforcement is handled via other means. - * Set by default. - */ - public static final int NET_CAPABILITY_NOT_RESTRICTED = 13; - - /** - * Indicates that the user has indicated implicit trust of this network. This - * generally means it's a sim-selected carrier, a plugged in ethernet, a paired - * BT device or a wifi the user asked to connect to. Untrusted networks - * are probably limited to unknown wifi AP. Set by default. - */ - public static final int NET_CAPABILITY_TRUSTED = 14; - - /** - * Indicates that this network is not a VPN. This capability is set by default and should be - * explicitly cleared for VPN networks. - */ - public static final int NET_CAPABILITY_NOT_VPN = 15; - - /** - * Indicates that connectivity on this network was successfully validated. For example, for a - * network with NET_CAPABILITY_INTERNET, it means that Internet connectivity was successfully - * detected. - */ - public static final int NET_CAPABILITY_VALIDATED = 16; - - /** - * Indicates that this network was found to have a captive portal in place last time it was - * probed. - */ - public static final int NET_CAPABILITY_CAPTIVE_PORTAL = 17; - - /** - * Indicates that this network is not roaming. - */ - public static final int NET_CAPABILITY_NOT_ROAMING = 18; - - /** - * Indicates that this network is available for use by apps, and not a network that is being - * kept up in the background to facilitate fast network switching. - */ - public static final int NET_CAPABILITY_FOREGROUND = 19; - - /** - * Indicates that this network is not congested. - *

- * When a network is congested, applications should defer network traffic - * that can be done at a later time, such as uploading analytics. - */ - public static final int NET_CAPABILITY_NOT_CONGESTED = 20; - - /** - * Indicates that this network is not currently suspended. - *

- * When a network is suspended, the network's IP addresses and any connections - * established on the network remain valid, but the network is temporarily unable - * to transfer data. This can happen, for example, if a cellular network experiences - * a temporary loss of signal, such as when driving through a tunnel, etc. - * A network with this capability is not suspended, so is expected to be able to - * transfer data. - */ - public static final int NET_CAPABILITY_NOT_SUSPENDED = 21; - - /** - * Indicates that traffic that goes through this network is paid by oem. For example, - * this network can be used by system apps to upload telemetry data. - * @hide - */ - @SystemApi - public static final int NET_CAPABILITY_OEM_PAID = 22; - - /** - * Indicates this is a network that has the ability to reach a carrier's Mission Critical - * servers. - */ - public static final int NET_CAPABILITY_MCX = 23; - - /** - * Indicates that this network was tested to only provide partial connectivity. - * @hide - */ - @SystemApi - public static final int NET_CAPABILITY_PARTIAL_CONNECTIVITY = 24; - - /** - * Indicates that this network is temporarily unmetered. - *

- * This capability will be set for networks that are generally metered, but are currently - * unmetered, e.g., because the user is in a particular area. This capability can be changed at - * any time. When it is removed, applications are responsible for stopping any data transfer - * that should not occur on a metered network. - * Note that most apps should use {@link #NET_CAPABILITY_NOT_METERED} instead. For more - * information, see https://developer.android.com/about/versions/11/features/5g#meteredness. - */ - public static final int NET_CAPABILITY_TEMPORARILY_NOT_METERED = 25; - - /** - * Indicates that this network is private to the OEM and meant only for OEM use. - * @hide - */ - @SystemApi - public static final int NET_CAPABILITY_OEM_PRIVATE = 26; - - /** - * Indicates this is an internal vehicle network, meant to communicate with other - * automotive systems. - * - * @hide - */ - @SystemApi - public static final int NET_CAPABILITY_VEHICLE_INTERNAL = 27; - - /** - * Indicates that this network is not managed by a Virtual Carrier Network (VCN). - * - * TODO(b/177299683): Add additional clarifying javadoc. - * @hide - */ - public static final int NET_CAPABILITY_NOT_VCN_MANAGED = 28; - - private static final int MIN_NET_CAPABILITY = NET_CAPABILITY_MMS; - private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_NOT_VCN_MANAGED; - - /** - * Network capabilities that are expected to be mutable, i.e., can change while a particular - * network is connected. - */ - private static final long MUTABLE_CAPABILITIES = - // TRUSTED can change when user explicitly connects to an untrusted network in Settings. - // http://b/18206275 - (1 << NET_CAPABILITY_TRUSTED) - | (1 << NET_CAPABILITY_VALIDATED) - | (1 << NET_CAPABILITY_CAPTIVE_PORTAL) - | (1 << NET_CAPABILITY_NOT_ROAMING) - | (1 << NET_CAPABILITY_FOREGROUND) - | (1 << NET_CAPABILITY_NOT_CONGESTED) - | (1 << NET_CAPABILITY_NOT_SUSPENDED) - | (1 << NET_CAPABILITY_PARTIAL_CONNECTIVITY) - | (1 << NET_CAPABILITY_TEMPORARILY_NOT_METERED) - | (1 << NET_CAPABILITY_NOT_VCN_MANAGED); - - /** - * Network capabilities that are not allowed in NetworkRequests. This exists because the - * NetworkFactory / NetworkAgent model does not deal well with the situation where a - * capability's presence cannot be known in advance. If such a capability is requested, then we - * can get into a cycle where the NetworkFactory endlessly churns out NetworkAgents that then - * get immediately torn down because they do not have the requested capability. - */ - // Note that as a historical exception, the TRUSTED and NOT_VCN_MANAGED capabilities - // are mutable but requestable. Factories are responsible for not getting - // in an infinite loop about these. - private static final long NON_REQUESTABLE_CAPABILITIES = - MUTABLE_CAPABILITIES - & ~(1 << NET_CAPABILITY_TRUSTED) - & ~(1 << NET_CAPABILITY_NOT_VCN_MANAGED); - - /** - * Capabilities that are set by default when the object is constructed. - */ - private static final long DEFAULT_CAPABILITIES = - (1 << NET_CAPABILITY_NOT_RESTRICTED) - | (1 << NET_CAPABILITY_TRUSTED) - | (1 << NET_CAPABILITY_NOT_VPN); - - /** - * Capabilities that suggest that a network is restricted. - * {@see #maybeMarkCapabilitiesRestricted}, {@see #FORCE_RESTRICTED_CAPABILITIES} - */ - @VisibleForTesting - /* package */ static final long RESTRICTED_CAPABILITIES = - (1 << NET_CAPABILITY_CBS) - | (1 << NET_CAPABILITY_DUN) - | (1 << NET_CAPABILITY_EIMS) - | (1 << NET_CAPABILITY_FOTA) - | (1 << NET_CAPABILITY_IA) - | (1 << NET_CAPABILITY_IMS) - | (1 << NET_CAPABILITY_MCX) - | (1 << NET_CAPABILITY_RCS) - | (1 << NET_CAPABILITY_VEHICLE_INTERNAL) - | (1 << NET_CAPABILITY_XCAP); - - /** - * Capabilities that force network to be restricted. - * {@see #maybeMarkCapabilitiesRestricted}. - */ - private static final long FORCE_RESTRICTED_CAPABILITIES = - (1 << NET_CAPABILITY_OEM_PAID) - | (1 << NET_CAPABILITY_OEM_PRIVATE); - - /** - * Capabilities that suggest that a network is unrestricted. - * {@see #maybeMarkCapabilitiesRestricted}. - */ - @VisibleForTesting - /* package */ static final long UNRESTRICTED_CAPABILITIES = - (1 << NET_CAPABILITY_INTERNET) - | (1 << NET_CAPABILITY_MMS) - | (1 << NET_CAPABILITY_SUPL) - | (1 << NET_CAPABILITY_WIFI_P2P); - - /** - * Capabilities that are managed by ConnectivityService. - */ - private static final long CONNECTIVITY_MANAGED_CAPABILITIES = - (1 << NET_CAPABILITY_VALIDATED) - | (1 << NET_CAPABILITY_CAPTIVE_PORTAL) - | (1 << NET_CAPABILITY_FOREGROUND) - | (1 << NET_CAPABILITY_PARTIAL_CONNECTIVITY); - - /** - * Capabilities that are allowed for test networks. This list must be set so that it is safe - * for an unprivileged user to create a network with these capabilities via shell. As such, - * it must never contain capabilities that are generally useful to the system, such as - * INTERNET, IMS, SUPL, etc. - */ - private static final long TEST_NETWORKS_ALLOWED_CAPABILITIES = - (1 << NET_CAPABILITY_NOT_METERED) - | (1 << NET_CAPABILITY_TEMPORARILY_NOT_METERED) - | (1 << NET_CAPABILITY_NOT_RESTRICTED) - | (1 << NET_CAPABILITY_NOT_VPN) - | (1 << NET_CAPABILITY_NOT_ROAMING) - | (1 << NET_CAPABILITY_NOT_CONGESTED) - | (1 << NET_CAPABILITY_NOT_SUSPENDED) - | (1 << NET_CAPABILITY_NOT_VCN_MANAGED); - - /** - * Adds the given capability to this {@code NetworkCapability} instance. - * Note that when searching for a network to satisfy a request, all capabilities - * requested must be satisfied. - * - * @param capability the capability to be added. - * @return This NetworkCapabilities instance, to facilitate chaining. - * @hide - */ - public @NonNull NetworkCapabilities addCapability(@NetCapability int capability) { - // If the given capability was previously added to the list of unwanted capabilities - // then the capability will also be removed from the list of unwanted capabilities. - // TODO: Consider adding unwanted capabilities to the public API and mention this - // in the documentation. - checkValidCapability(capability); - mNetworkCapabilities |= 1 << capability; - mUnwantedNetworkCapabilities &= ~(1 << capability); // remove from unwanted capability list - return this; - } - - /** - * Adds the given capability to the list of unwanted capabilities of this - * {@code NetworkCapability} instance. Note that when searching for a network to - * satisfy a request, the network must not contain any capability from unwanted capability - * list. - *

- * If the capability was previously added to the list of required capabilities (for - * example, it was there by default or added using {@link #addCapability(int)} method), then - * it will be removed from the list of required capabilities as well. - * - * @see #addCapability(int) - * @hide - */ - public void addUnwantedCapability(@NetCapability int capability) { - checkValidCapability(capability); - mUnwantedNetworkCapabilities |= 1 << capability; - mNetworkCapabilities &= ~(1 << capability); // remove from requested capabilities - } - - /** - * Removes (if found) the given capability from this {@code NetworkCapability} instance. - * - * @param capability the capability to be removed. - * @return This NetworkCapabilities instance, to facilitate chaining. - * @hide - */ - public @NonNull NetworkCapabilities removeCapability(@NetCapability int capability) { - // Note that this method removes capabilities that were added via addCapability(int), - // addUnwantedCapability(int) or setCapabilities(int[], int[]). - checkValidCapability(capability); - final long mask = ~(1 << capability); - mNetworkCapabilities &= mask; - mUnwantedNetworkCapabilities &= mask; - return this; - } - - /** - * Sets (or clears) the given capability on this {@link NetworkCapabilities} - * instance. - * @hide - */ - public @NonNull NetworkCapabilities setCapability(@NetCapability int capability, - boolean value) { - if (value) { - addCapability(capability); - } else { - removeCapability(capability); - } - return this; - } - - /** - * Gets all the capabilities set on this {@code NetworkCapability} instance. - * - * @return an array of capability values for this instance. - * @hide - */ - @UnsupportedAppUsage - public @NetCapability int[] getCapabilities() { - return BitUtils.unpackBits(mNetworkCapabilities); - } - - /** - * Gets all the unwanted capabilities set on this {@code NetworkCapability} instance. - * - * @return an array of unwanted capability values for this instance. - * @hide - */ - public @NetCapability int[] getUnwantedCapabilities() { - return BitUtils.unpackBits(mUnwantedNetworkCapabilities); - } - - - /** - * Sets all the capabilities set on this {@code NetworkCapability} instance. - * This overwrites any existing capabilities. - * - * @hide - */ - public void setCapabilities(@NetCapability int[] capabilities, - @NetCapability int[] unwantedCapabilities) { - mNetworkCapabilities = BitUtils.packBits(capabilities); - mUnwantedNetworkCapabilities = BitUtils.packBits(unwantedCapabilities); - } - - /** - * @deprecated use {@link #setCapabilities(int[], int[])} - * @hide - */ - @Deprecated - public void setCapabilities(@NetCapability int[] capabilities) { - setCapabilities(capabilities, new int[] {}); - } - - /** - * Tests for the presence of a capability on this instance. - * - * @param capability the capabilities to be tested for. - * @return {@code true} if set on this instance. - */ - public boolean hasCapability(@NetCapability int capability) { - return isValidCapability(capability) - && ((mNetworkCapabilities & (1 << capability)) != 0); - } - - /** @hide */ - public boolean hasUnwantedCapability(@NetCapability int capability) { - return isValidCapability(capability) - && ((mUnwantedNetworkCapabilities & (1 << capability)) != 0); - } - - /** - * Check if this NetworkCapabilities has system managed capabilities or not. - * @hide - */ - public boolean hasConnectivityManagedCapability() { - return ((mNetworkCapabilities & CONNECTIVITY_MANAGED_CAPABILITIES) != 0); - } - - /** Note this method may result in having the same capability in wanted and unwanted lists. */ - private void combineNetCapabilities(@NonNull NetworkCapabilities nc) { - this.mNetworkCapabilities |= nc.mNetworkCapabilities; - this.mUnwantedNetworkCapabilities |= nc.mUnwantedNetworkCapabilities; - } - - /** - * Convenience function that returns a human-readable description of the first mutable - * capability we find. Used to present an error message to apps that request mutable - * capabilities. - * - * @hide - */ - public @Nullable String describeFirstNonRequestableCapability() { - final long nonRequestable = (mNetworkCapabilities | mUnwantedNetworkCapabilities) - & NON_REQUESTABLE_CAPABILITIES; - - if (nonRequestable != 0) { - return capabilityNameOf(BitUtils.unpackBits(nonRequestable)[0]); - } - if (mLinkUpBandwidthKbps != 0 || mLinkDownBandwidthKbps != 0) return "link bandwidth"; - if (hasSignalStrength()) return "signalStrength"; - if (isPrivateDnsBroken()) { - return "privateDnsBroken"; - } - return null; - } - - private boolean satisfiedByNetCapabilities(@NonNull NetworkCapabilities nc, - boolean onlyImmutable) { - long requestedCapabilities = mNetworkCapabilities; - long requestedUnwantedCapabilities = mUnwantedNetworkCapabilities; - long providedCapabilities = nc.mNetworkCapabilities; - - if (onlyImmutable) { - requestedCapabilities &= ~MUTABLE_CAPABILITIES; - requestedUnwantedCapabilities &= ~MUTABLE_CAPABILITIES; - } - return ((providedCapabilities & requestedCapabilities) == requestedCapabilities) - && ((requestedUnwantedCapabilities & providedCapabilities) == 0); - } - - /** @hide */ - public boolean equalsNetCapabilities(@NonNull NetworkCapabilities nc) { - return (nc.mNetworkCapabilities == this.mNetworkCapabilities) - && (nc.mUnwantedNetworkCapabilities == this.mUnwantedNetworkCapabilities); - } - - private boolean equalsNetCapabilitiesRequestable(@NonNull NetworkCapabilities that) { - return ((this.mNetworkCapabilities & ~NON_REQUESTABLE_CAPABILITIES) == - (that.mNetworkCapabilities & ~NON_REQUESTABLE_CAPABILITIES)) - && ((this.mUnwantedNetworkCapabilities & ~NON_REQUESTABLE_CAPABILITIES) == - (that.mUnwantedNetworkCapabilities & ~NON_REQUESTABLE_CAPABILITIES)); - } - - /** - * Deduces that all the capabilities it provides are typically provided by restricted networks - * or not. - * - * @return {@code true} if the network should be restricted. - * @hide - */ - public boolean deduceRestrictedCapability() { - // Check if we have any capability that forces the network to be restricted. - final boolean forceRestrictedCapability = - (mNetworkCapabilities & FORCE_RESTRICTED_CAPABILITIES) != 0; - - // Verify there aren't any unrestricted capabilities. If there are we say - // the whole thing is unrestricted unless it is forced to be restricted. - final boolean hasUnrestrictedCapabilities = - (mNetworkCapabilities & UNRESTRICTED_CAPABILITIES) != 0; - - // Must have at least some restricted capabilities. - final boolean hasRestrictedCapabilities = - (mNetworkCapabilities & RESTRICTED_CAPABILITIES) != 0; - - return forceRestrictedCapability - || (hasRestrictedCapabilities && !hasUnrestrictedCapabilities); - } - - /** - * Removes the NET_CAPABILITY_NOT_RESTRICTED capability if deducing the network is restricted. - * - * @hide - */ - public void maybeMarkCapabilitiesRestricted() { - if (deduceRestrictedCapability()) { - removeCapability(NET_CAPABILITY_NOT_RESTRICTED); - } - } - - /** - * Test networks have strong restrictions on what capabilities they can have. Enforce these - * restrictions. - * @hide - */ - public void restrictCapabilitesForTestNetwork(int creatorUid) { - final long originalCapabilities = mNetworkCapabilities; - final long originalTransportTypes = mTransportTypes; - final NetworkSpecifier originalSpecifier = mNetworkSpecifier; - final int originalSignalStrength = mSignalStrength; - final int originalOwnerUid = getOwnerUid(); - final int[] originalAdministratorUids = getAdministratorUids(); - clearAll(); - mTransportTypes = (originalTransportTypes & TEST_NETWORKS_ALLOWED_TRANSPORTS) - | (1 << TRANSPORT_TEST); - mNetworkCapabilities = originalCapabilities & TEST_NETWORKS_ALLOWED_CAPABILITIES; - mNetworkSpecifier = originalSpecifier; - mSignalStrength = originalSignalStrength; - - // Only retain the owner and administrator UIDs if they match the app registering the remote - // caller that registered the network. - if (originalOwnerUid == creatorUid) { - setOwnerUid(creatorUid); - } - if (ArrayUtils.contains(originalAdministratorUids, creatorUid)) { - setAdministratorUids(new int[] {creatorUid}); - } - // There is no need to clear the UIDs, they have already been cleared by clearAll() above. - } - - /** - * Representing the transport type. Apps should generally not care about transport. A - * request for a fast internet connection could be satisfied by a number of different - * transports. If any are specified here it will be satisfied a Network that matches - * any of them. If a caller doesn't care about the transport it should not specify any. - */ - private long mTransportTypes; - - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = { "TRANSPORT_" }, value = { - TRANSPORT_CELLULAR, - TRANSPORT_WIFI, - TRANSPORT_BLUETOOTH, - TRANSPORT_ETHERNET, - TRANSPORT_VPN, - TRANSPORT_WIFI_AWARE, - TRANSPORT_LOWPAN, - TRANSPORT_TEST, - }) - public @interface Transport { } - - /** - * Indicates this network uses a Cellular transport. - */ - public static final int TRANSPORT_CELLULAR = 0; - - /** - * Indicates this network uses a Wi-Fi transport. - */ - public static final int TRANSPORT_WIFI = 1; - - /** - * Indicates this network uses a Bluetooth transport. - */ - public static final int TRANSPORT_BLUETOOTH = 2; - - /** - * Indicates this network uses an Ethernet transport. - */ - public static final int TRANSPORT_ETHERNET = 3; - - /** - * Indicates this network uses a VPN transport. - */ - public static final int TRANSPORT_VPN = 4; - - /** - * Indicates this network uses a Wi-Fi Aware transport. - */ - public static final int TRANSPORT_WIFI_AWARE = 5; - - /** - * Indicates this network uses a LoWPAN transport. - */ - public static final int TRANSPORT_LOWPAN = 6; - - /** - * Indicates this network uses a Test-only virtual interface as a transport. - * - * @hide - */ - @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) - public static final int TRANSPORT_TEST = 7; - - /** @hide */ - public static final int MIN_TRANSPORT = TRANSPORT_CELLULAR; - /** @hide */ - public static final int MAX_TRANSPORT = TRANSPORT_TEST; - - /** @hide */ - public static boolean isValidTransport(@Transport int transportType) { - return (MIN_TRANSPORT <= transportType) && (transportType <= MAX_TRANSPORT); - } - - private static final String[] TRANSPORT_NAMES = { - "CELLULAR", - "WIFI", - "BLUETOOTH", - "ETHERNET", - "VPN", - "WIFI_AWARE", - "LOWPAN", - "TEST" - }; - - /** - * Allowed transports on a test network, in addition to TRANSPORT_TEST. - */ - private static final int TEST_NETWORKS_ALLOWED_TRANSPORTS = 1 << TRANSPORT_TEST - // Test ethernet networks can be created with EthernetManager#setIncludeTestInterfaces - | 1 << TRANSPORT_ETHERNET - // Test VPN networks can be created but their UID ranges must be empty. - | 1 << TRANSPORT_VPN; - - /** - * Adds the given transport type to this {@code NetworkCapability} instance. - * Multiple transports may be applied. Note that when searching - * for a network to satisfy a request, any listed in the request will satisfy the request. - * For example {@code TRANSPORT_WIFI} and {@code TRANSPORT_ETHERNET} added to a - * {@code NetworkCapabilities} would cause either a Wi-Fi network or an Ethernet network - * to be selected. This is logically different than - * {@code NetworkCapabilities.NET_CAPABILITY_*} listed above. - * - * @param transportType the transport type to be added. - * @return This NetworkCapabilities instance, to facilitate chaining. - * @hide - */ - public @NonNull NetworkCapabilities addTransportType(@Transport int transportType) { - checkValidTransportType(transportType); - mTransportTypes |= 1 << transportType; - setNetworkSpecifier(mNetworkSpecifier); // used for exception checking - return this; - } - - /** - * Removes (if found) the given transport from this {@code NetworkCapability} instance. - * - * @param transportType the transport type to be removed. - * @return This NetworkCapabilities instance, to facilitate chaining. - * @hide - */ - public @NonNull NetworkCapabilities removeTransportType(@Transport int transportType) { - checkValidTransportType(transportType); - mTransportTypes &= ~(1 << transportType); - setNetworkSpecifier(mNetworkSpecifier); // used for exception checking - return this; - } - - /** - * Sets (or clears) the given transport on this {@link NetworkCapabilities} - * instance. - * - * @hide - */ - public @NonNull NetworkCapabilities setTransportType(@Transport int transportType, - boolean value) { - if (value) { - addTransportType(transportType); - } else { - removeTransportType(transportType); - } - return this; - } - - /** - * Gets all the transports set on this {@code NetworkCapability} instance. - * - * @return an array of transport type values for this instance. - * @hide - */ - @SystemApi - @NonNull public @Transport int[] getTransportTypes() { - return BitUtils.unpackBits(mTransportTypes); - } - - /** - * Sets all the transports set on this {@code NetworkCapability} instance. - * This overwrites any existing transports. - * - * @hide - */ - public void setTransportTypes(@Transport int[] transportTypes) { - mTransportTypes = BitUtils.packBits(transportTypes); - } - - /** - * Tests for the presence of a transport on this instance. - * - * @param transportType the transport type to be tested for. - * @return {@code true} if set on this instance. - */ - public boolean hasTransport(@Transport int transportType) { - return isValidTransport(transportType) && ((mTransportTypes & (1 << transportType)) != 0); - } - - private void combineTransportTypes(NetworkCapabilities nc) { - this.mTransportTypes |= nc.mTransportTypes; - } - - private boolean satisfiedByTransportTypes(NetworkCapabilities nc) { - return ((this.mTransportTypes == 0) - || ((this.mTransportTypes & nc.mTransportTypes) != 0)); - } - - /** @hide */ - public boolean equalsTransportTypes(NetworkCapabilities nc) { - return (nc.mTransportTypes == this.mTransportTypes); - } - - /** - * UID of the app that owns this network, or Process#INVALID_UID if none/unknown. - * - *

This field keeps track of the UID of the app that created this network and is in charge of - * its lifecycle. This could be the UID of apps such as the Wifi network suggestor, the running - * VPN, or Carrier Service app managing a cellular data connection. - * - *

For NetworkCapability instances being sent from ConnectivityService, this value MUST be - * reset to Process.INVALID_UID unless all the following conditions are met: - * - *

The caller is the network owner, AND one of the following sets of requirements is met: - * - *

    - *
  1. The described Network is a VPN - *
- * - *

OR: - * - *

    - *
  1. The calling app is the network owner - *
  2. The calling app has the ACCESS_FINE_LOCATION permission granted - *
  3. The user's location toggle is on - *
- * - * This is because the owner UID is location-sensitive. The apps that request a network could - * know where the device is if they can tell for sure the system has connected to the network - * they requested. - * - *

This is populated by the network agents and for the NetworkCapabilities instance sent by - * an app to the System Server, the value MUST be reset to Process.INVALID_UID by the system - * server. - */ - private int mOwnerUid = Process.INVALID_UID; - - /** - * Set the UID of the owner app. - * @hide - */ - public @NonNull NetworkCapabilities setOwnerUid(final int uid) { - mOwnerUid = uid; - return this; - } - - /** - * Retrieves the UID of the app that owns this network. - * - *

For user privacy reasons, this field will only be populated if the following conditions - * are met: - * - *

The caller is the network owner, AND one of the following sets of requirements is met: - * - *

    - *
  1. The described Network is a VPN - *
- * - *

OR: - * - *

    - *
  1. The calling app is the network owner - *
  2. The calling app has the ACCESS_FINE_LOCATION permission granted - *
  3. The user's location toggle is on - *
- * - * Instances of NetworkCapabilities sent to apps without the appropriate permissions will have - * this field cleared out. - */ - public int getOwnerUid() { - return mOwnerUid; - } - - private boolean equalsOwnerUid(@NonNull final NetworkCapabilities nc) { - return mOwnerUid == nc.mOwnerUid; - } - - /** - * UIDs of packages that are administrators of this network, or empty if none. - * - *

This field tracks the UIDs of packages that have permission to manage this network. - * - *

Network owners will also be listed as administrators. - * - *

For NetworkCapability instances being sent from the System Server, this value MUST be - * empty unless the destination is 1) the System Server, or 2) Telephony. In either case, the - * receiving entity must have the ACCESS_FINE_LOCATION permission and target R+. - * - *

When received from an app in a NetworkRequest this is always cleared out by the system - * server. This field is never used for matching NetworkRequests to NetworkAgents. - */ - @NonNull private int[] mAdministratorUids = new int[0]; - - /** - * Sets the int[] of UIDs that are administrators of this network. - * - *

UIDs included in administratorUids gain administrator privileges over this Network. - * Examples of UIDs that should be included in administratorUids are: - * - *

    - *
  • Carrier apps with privileges for the relevant subscription - *
  • Active VPN apps - *
  • Other application groups with a particular Network-related role - *
- * - *

In general, user-supplied networks (such as WiFi networks) do not have an administrator. - * - *

An app is granted owner privileges over Networks that it supplies. The owner UID MUST - * always be included in administratorUids. - * - *

The administrator UIDs are set by network agents. - * - * @param administratorUids the UIDs to be set as administrators of this Network. - * @throws IllegalArgumentException if duplicate UIDs are contained in administratorUids - * @see #mAdministratorUids - * @hide - */ - @NonNull - public NetworkCapabilities setAdministratorUids(@NonNull final int[] administratorUids) { - mAdministratorUids = Arrays.copyOf(administratorUids, administratorUids.length); - Arrays.sort(mAdministratorUids); - for (int i = 0; i < mAdministratorUids.length - 1; i++) { - if (mAdministratorUids[i] >= mAdministratorUids[i + 1]) { - throw new IllegalArgumentException("All administrator UIDs must be unique"); - } - } - return this; - } - - /** - * Retrieves the UIDs that are administrators of this Network. - * - *

This is only populated in NetworkCapabilities objects that come from network agents for - * networks that are managed by specific apps on the system, such as carrier privileged apps or - * wifi suggestion apps. This will include the network owner. - * - * @return the int[] of UIDs that are administrators of this Network - * @see #mAdministratorUids - * @hide - */ - @NonNull - @SystemApi - public int[] getAdministratorUids() { - return Arrays.copyOf(mAdministratorUids, mAdministratorUids.length); - } - - /** - * Tests if the set of administrator UIDs of this network is the same as that of the passed one. - * - *

The administrator UIDs must be in sorted order. - * - *

nc is assumed non-null. Else, NPE. - * - * @hide - */ - @VisibleForTesting(visibility = PRIVATE) - public boolean equalsAdministratorUids(@NonNull final NetworkCapabilities nc) { - return Arrays.equals(mAdministratorUids, nc.mAdministratorUids); - } - - /** - * Combine the administrator UIDs of the capabilities. - * - *

This is only legal if either of the administrators lists are empty, or if they are equal. - * Combining administrator UIDs is only possible for combining non-overlapping sets of UIDs. - * - *

If both administrator lists are non-empty but not equal, they conflict with each other. In - * this case, it would not make sense to add them together. - */ - private void combineAdministratorUids(@NonNull final NetworkCapabilities nc) { - if (nc.mAdministratorUids.length == 0) return; - if (mAdministratorUids.length == 0) { - mAdministratorUids = Arrays.copyOf(nc.mAdministratorUids, nc.mAdministratorUids.length); - return; - } - if (!equalsAdministratorUids(nc)) { - throw new IllegalStateException("Can't combine two different administrator UID lists"); - } - } - - /** - * Value indicating that link bandwidth is unspecified. - * @hide - */ - public static final int LINK_BANDWIDTH_UNSPECIFIED = 0; - - /** - * Passive link bandwidth. This is a rough guide of the expected peak bandwidth - * for the first hop on the given transport. It is not measured, but may take into account - * link parameters (Radio technology, allocated channels, etc). - */ - private int mLinkUpBandwidthKbps = LINK_BANDWIDTH_UNSPECIFIED; - private int mLinkDownBandwidthKbps = LINK_BANDWIDTH_UNSPECIFIED; - - /** - * Sets the upstream bandwidth for this network in Kbps. This always only refers to - * the estimated first hop transport bandwidth. - *

- * {@see Builder#setLinkUpstreamBandwidthKbps} - * - * @param upKbps the estimated first hop upstream (device to network) bandwidth. - * @hide - */ - public @NonNull NetworkCapabilities setLinkUpstreamBandwidthKbps(int upKbps) { - mLinkUpBandwidthKbps = upKbps; - return this; - } - - /** - * Retrieves the upstream bandwidth for this network in Kbps. This always only refers to - * the estimated first hop transport bandwidth. - * - * @return The estimated first hop upstream (device to network) bandwidth. - */ - public int getLinkUpstreamBandwidthKbps() { - return mLinkUpBandwidthKbps; - } - - /** - * Sets the downstream bandwidth for this network in Kbps. This always only refers to - * the estimated first hop transport bandwidth. - *

- * {@see Builder#setLinkUpstreamBandwidthKbps} - * - * @param downKbps the estimated first hop downstream (network to device) bandwidth. - * @hide - */ - public @NonNull NetworkCapabilities setLinkDownstreamBandwidthKbps(int downKbps) { - mLinkDownBandwidthKbps = downKbps; - return this; - } - - /** - * Retrieves the downstream bandwidth for this network in Kbps. This always only refers to - * the estimated first hop transport bandwidth. - * - * @return The estimated first hop downstream (network to device) bandwidth. - */ - public int getLinkDownstreamBandwidthKbps() { - return mLinkDownBandwidthKbps; - } - - private void combineLinkBandwidths(NetworkCapabilities nc) { - this.mLinkUpBandwidthKbps = - Math.max(this.mLinkUpBandwidthKbps, nc.mLinkUpBandwidthKbps); - this.mLinkDownBandwidthKbps = - Math.max(this.mLinkDownBandwidthKbps, nc.mLinkDownBandwidthKbps); - } - private boolean satisfiedByLinkBandwidths(NetworkCapabilities nc) { - return !(this.mLinkUpBandwidthKbps > nc.mLinkUpBandwidthKbps - || this.mLinkDownBandwidthKbps > nc.mLinkDownBandwidthKbps); - } - private boolean equalsLinkBandwidths(NetworkCapabilities nc) { - return (this.mLinkUpBandwidthKbps == nc.mLinkUpBandwidthKbps - && this.mLinkDownBandwidthKbps == nc.mLinkDownBandwidthKbps); - } - /** @hide */ - public static int minBandwidth(int a, int b) { - if (a == LINK_BANDWIDTH_UNSPECIFIED) { - return b; - } else if (b == LINK_BANDWIDTH_UNSPECIFIED) { - return a; - } else { - return Math.min(a, b); - } - } - /** @hide */ - public static int maxBandwidth(int a, int b) { - return Math.max(a, b); - } - - private NetworkSpecifier mNetworkSpecifier = null; - private TransportInfo mTransportInfo = null; - - /** - * Sets the optional bearer specific network specifier. - * This has no meaning if a single transport is also not specified, so calling - * this without a single transport set will generate an exception, as will - * subsequently adding or removing transports after this is set. - *

- * - * @param networkSpecifier A concrete, parcelable framework class that extends - * NetworkSpecifier. - * @return This NetworkCapabilities instance, to facilitate chaining. - * @hide - */ - public @NonNull NetworkCapabilities setNetworkSpecifier( - @NonNull NetworkSpecifier networkSpecifier) { - if (networkSpecifier != null && Long.bitCount(mTransportTypes) != 1) { - throw new IllegalStateException("Must have a single transport specified to use " + - "setNetworkSpecifier"); - } - - mNetworkSpecifier = networkSpecifier; - - return this; - } - - /** - * Sets the optional transport specific information. - * - * @param transportInfo A concrete, parcelable framework class that extends - * {@link TransportInfo}. - * @return This NetworkCapabilities instance, to facilitate chaining. - * @hide - */ - public @NonNull NetworkCapabilities setTransportInfo(@NonNull TransportInfo transportInfo) { - mTransportInfo = transportInfo; - return this; - } - - /** - * Gets the optional bearer specific network specifier. May be {@code null} if not set. - * - * @return The optional {@link NetworkSpecifier} specifying the bearer specific network - * specifier or {@code null}. - */ - public @Nullable NetworkSpecifier getNetworkSpecifier() { - return mNetworkSpecifier; - } - - /** - * Returns a transport-specific information container. The application may cast this - * container to a concrete sub-class based on its knowledge of the network request. The - * application should be able to deal with a {@code null} return value or an invalid case, - * e.g. use {@code instanceof} operator to verify expected type. - * - * @return A concrete implementation of the {@link TransportInfo} class or null if not - * available for the network. - */ - @Nullable public TransportInfo getTransportInfo() { - return mTransportInfo; - } - - private void combineSpecifiers(NetworkCapabilities nc) { - if (mNetworkSpecifier != null && !mNetworkSpecifier.equals(nc.mNetworkSpecifier)) { - throw new IllegalStateException("Can't combine two networkSpecifiers"); - } - setNetworkSpecifier(nc.mNetworkSpecifier); - } - - private boolean satisfiedBySpecifier(NetworkCapabilities nc) { - return mNetworkSpecifier == null || mNetworkSpecifier.canBeSatisfiedBy(nc.mNetworkSpecifier) - || nc.mNetworkSpecifier instanceof MatchAllNetworkSpecifier; - } - - private boolean equalsSpecifier(NetworkCapabilities nc) { - return Objects.equals(mNetworkSpecifier, nc.mNetworkSpecifier); - } - - private void combineTransportInfos(NetworkCapabilities nc) { - if (mTransportInfo != null && !mTransportInfo.equals(nc.mTransportInfo)) { - throw new IllegalStateException("Can't combine two TransportInfos"); - } - setTransportInfo(nc.mTransportInfo); - } - - private boolean equalsTransportInfo(NetworkCapabilities nc) { - return Objects.equals(mTransportInfo, nc.mTransportInfo); - } - - /** - * Magic value that indicates no signal strength provided. A request specifying this value is - * always satisfied. - */ - public static final int SIGNAL_STRENGTH_UNSPECIFIED = Integer.MIN_VALUE; - - /** - * Signal strength. This is a signed integer, and higher values indicate better signal. - * The exact units are bearer-dependent. For example, Wi-Fi uses RSSI. - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) - private int mSignalStrength = SIGNAL_STRENGTH_UNSPECIFIED; - - /** - * Sets the signal strength. This is a signed integer, with higher values indicating a stronger - * signal. The exact units are bearer-dependent. For example, Wi-Fi uses the same RSSI units - * reported by wifi code. - *

- * Note that when used to register a network callback, this specifies the minimum acceptable - * signal strength. When received as the state of an existing network it specifies the current - * value. A value of code SIGNAL_STRENGTH_UNSPECIFIED} means no value when received and has no - * effect when requesting a callback. - * - * @param signalStrength the bearer-specific signal strength. - * @hide - */ - public @NonNull NetworkCapabilities setSignalStrength(int signalStrength) { - mSignalStrength = signalStrength; - return this; - } - - /** - * Returns {@code true} if this object specifies a signal strength. - * - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public boolean hasSignalStrength() { - return mSignalStrength > SIGNAL_STRENGTH_UNSPECIFIED; - } - - /** - * Retrieves the signal strength. - * - * @return The bearer-specific signal strength. - */ - public int getSignalStrength() { - return mSignalStrength; - } - - private void combineSignalStrength(NetworkCapabilities nc) { - this.mSignalStrength = Math.max(this.mSignalStrength, nc.mSignalStrength); - } - - private boolean satisfiedBySignalStrength(NetworkCapabilities nc) { - return this.mSignalStrength <= nc.mSignalStrength; - } - - private boolean equalsSignalStrength(NetworkCapabilities nc) { - return this.mSignalStrength == nc.mSignalStrength; - } - - /** - * List of UIDs this network applies to. No restriction if null. - *

- * For networks, mUids represent the list of network this applies to, and null means this - * network applies to all UIDs. - * For requests, mUids is the list of UIDs this network MUST apply to to match ; ALL UIDs - * must be included in a network so that they match. As an exception to the general rule, - * a null mUids field for requests mean "no requirements" rather than what the general rule - * would suggest ("must apply to all UIDs") : this is because this has shown to be what users - * of this API expect in practice. A network that must match all UIDs can still be - * expressed with a set ranging the entire set of possible UIDs. - *

- * mUids is typically (and at this time, only) used by VPN. This network is only available to - * the UIDs in this list, and it is their default network. Apps in this list that wish to - * bypass the VPN can do so iff the VPN app allows them to or if they are privileged. If this - * member is null, then the network is not restricted by app UID. If it's an empty list, then - * it means nobody can use it. - * As a special exception, the app managing this network (as identified by its UID stored in - * mOwnerUid) can always see this network. This is embodied by a special check in - * satisfiedByUids. That still does not mean the network necessarily applies - * to the app that manages it as determined by #appliesToUid. - *

- * Please note that in principle a single app can be associated with multiple UIDs because - * each app will have a different UID when it's run as a different (macro-)user. A single - * macro user can only have a single active VPN app at any given time however. - *

- * Also please be aware this class does not try to enforce any normalization on this. Callers - * can only alter the UIDs by setting them wholesale : this class does not provide any utility - * to add or remove individual UIDs or ranges. If callers have any normalization needs on - * their own (like requiring sortedness or no overlap) they need to enforce it - * themselves. Some of the internal methods also assume this is normalized as in no adjacent - * or overlapping ranges are present. - * - * @hide - */ - private ArraySet mUids = null; - - /** - * Convenience method to set the UIDs this network applies to to a single UID. - * @hide - */ - public @NonNull NetworkCapabilities setSingleUid(int uid) { - final ArraySet identity = new ArraySet<>(1); - identity.add(new UidRange(uid, uid)); - setUids(identity); - return this; - } - - /** - * Set the list of UIDs this network applies to. - * This makes a copy of the set so that callers can't modify it after the call. - * @hide - */ - public @NonNull NetworkCapabilities setUids(Set uids) { - if (null == uids) { - mUids = null; - } else { - mUids = new ArraySet<>(uids); - } - return this; - } - - /** - * Get the list of UIDs this network applies to. - * This returns a copy of the set so that callers can't modify the original object. - * @hide - */ - public @Nullable Set getUids() { - return null == mUids ? null : new ArraySet<>(mUids); - } - - /** - * Test whether this network applies to this UID. - * @hide - */ - public boolean appliesToUid(int uid) { - if (null == mUids) return true; - for (UidRange range : mUids) { - if (range.contains(uid)) { - return true; - } - } - return false; - } - - /** - * Tests if the set of UIDs that this network applies to is the same as the passed network. - *

- * This test only checks whether equal range objects are in both sets. It will - * return false if the ranges are not exactly the same, even if the covered UIDs - * are for an equivalent result. - *

- * Note that this method is not very optimized, which is fine as long as it's not used very - * often. - *

- * nc is assumed nonnull. - * - * @hide - */ - @VisibleForTesting - public boolean equalsUids(@NonNull NetworkCapabilities nc) { - Set comparedUids = nc.mUids; - if (null == comparedUids) return null == mUids; - if (null == mUids) return false; - // Make a copy so it can be mutated to check that all ranges in mUids - // also are in uids. - final Set uids = new ArraySet<>(mUids); - for (UidRange range : comparedUids) { - if (!uids.contains(range)) { - return false; - } - uids.remove(range); - } - return uids.isEmpty(); - } - - /** - * Test whether the passed NetworkCapabilities satisfies the UIDs this capabilities require. - * - * This method is called on the NetworkCapabilities embedded in a request with the - * capabilities of an available network. It checks whether all the UIDs from this listen - * (representing the UIDs that must have access to the network) are satisfied by the UIDs - * in the passed nc (representing the UIDs that this network is available to). - *

- * As a special exception, the UID that created the passed network (as represented by its - * mOwnerUid field) always satisfies a NetworkRequest requiring it (of LISTEN - * or REQUEST types alike), even if the network does not apply to it. That is so a VPN app - * can see its own network when it listens for it. - *

- * nc is assumed nonnull. Else, NPE. - * @see #appliesToUid - * @hide - */ - public boolean satisfiedByUids(@NonNull NetworkCapabilities nc) { - if (null == nc.mUids || null == mUids) return true; // The network satisfies everything. - for (UidRange requiredRange : mUids) { - if (requiredRange.contains(nc.mOwnerUid)) return true; - if (!nc.appliesToUidRange(requiredRange)) { - return false; - } - } - return true; - } - - /** - * Returns whether this network applies to the passed ranges. - * This assumes that to apply, the passed range has to be entirely contained - * within one of the ranges this network applies to. If the ranges are not normalized, - * this method may return false even though all required UIDs are covered because no - * single range contained them all. - * @hide - */ - @VisibleForTesting - public boolean appliesToUidRange(@Nullable UidRange requiredRange) { - if (null == mUids) return true; - for (UidRange uidRange : mUids) { - if (uidRange.containsRange(requiredRange)) { - return true; - } - } - return false; - } - - /** - * Combine the UIDs this network currently applies to with the UIDs the passed - * NetworkCapabilities apply to. - * nc is assumed nonnull. - */ - private void combineUids(@NonNull NetworkCapabilities nc) { - if (null == nc.mUids || null == mUids) { - mUids = null; - return; - } - mUids.addAll(nc.mUids); - } - - - /** - * The SSID of the network, or null if not applicable or unknown. - *

- * This is filled in by wifi code. - * @hide - */ - private String mSSID; - - /** - * Sets the SSID of this network. - * @hide - */ - public @NonNull NetworkCapabilities setSSID(@Nullable String ssid) { - mSSID = ssid; - return this; - } - - /** - * Gets the SSID of this network, or null if none or unknown. - * @hide - */ - @SystemApi - public @Nullable String getSsid() { - return mSSID; - } - - /** - * Tests if the SSID of this network is the same as the SSID of the passed network. - * @hide - */ - public boolean equalsSSID(@NonNull NetworkCapabilities nc) { - return Objects.equals(mSSID, nc.mSSID); - } - - /** - * Check if the SSID requirements of this object are matched by the passed object. - * @hide - */ - public boolean satisfiedBySSID(@NonNull NetworkCapabilities nc) { - return mSSID == null || mSSID.equals(nc.mSSID); - } - - /** - * Combine SSIDs of the capabilities. - *

- * This is only legal if either the SSID of this object is null, or both SSIDs are - * equal. - * @hide - */ - private void combineSSIDs(@NonNull NetworkCapabilities nc) { - if (mSSID != null && !mSSID.equals(nc.mSSID)) { - throw new IllegalStateException("Can't combine two SSIDs"); - } - setSSID(nc.mSSID); - } - - /** - * Combine a set of Capabilities to this one. Useful for coming up with the complete set. - *

- * Note that this method may break an invariant of having a particular capability in either - * wanted or unwanted lists but never in both. Requests that have the same capability in - * both lists will never be satisfied. - * @hide - */ - public void combineCapabilities(@NonNull NetworkCapabilities nc) { - combineNetCapabilities(nc); - combineTransportTypes(nc); - combineLinkBandwidths(nc); - combineSpecifiers(nc); - combineTransportInfos(nc); - combineSignalStrength(nc); - combineUids(nc); - combineSSIDs(nc); - combineRequestor(nc); - combineAdministratorUids(nc); - } - - /** - * Check if our requirements are satisfied by the given {@code NetworkCapabilities}. - * - * @param nc the {@code NetworkCapabilities} that may or may not satisfy our requirements. - * @param onlyImmutable if {@code true}, do not consider mutable requirements such as link - * bandwidth, signal strength, or validation / captive portal status. - * - * @hide - */ - private boolean satisfiedByNetworkCapabilities(NetworkCapabilities nc, boolean onlyImmutable) { - return (nc != null - && satisfiedByNetCapabilities(nc, onlyImmutable) - && satisfiedByTransportTypes(nc) - && (onlyImmutable || satisfiedByLinkBandwidths(nc)) - && satisfiedBySpecifier(nc) - && (onlyImmutable || satisfiedBySignalStrength(nc)) - && (onlyImmutable || satisfiedByUids(nc)) - && (onlyImmutable || satisfiedBySSID(nc))) - && (onlyImmutable || satisfiedByRequestor(nc)); - } - - /** - * Check if our requirements are satisfied by the given {@code NetworkCapabilities}. - * - * @param nc the {@code NetworkCapabilities} that may or may not satisfy our requirements. - * - * @hide - */ - @SystemApi - public boolean satisfiedByNetworkCapabilities(@Nullable NetworkCapabilities nc) { - return satisfiedByNetworkCapabilities(nc, false); - } - - /** - * Check if our immutable requirements are satisfied by the given {@code NetworkCapabilities}. - * - * @param nc the {@code NetworkCapabilities} that may or may not satisfy our requirements. - * - * @hide - */ - public boolean satisfiedByImmutableNetworkCapabilities(@Nullable NetworkCapabilities nc) { - return satisfiedByNetworkCapabilities(nc, true); - } - - /** - * Checks that our immutable capabilities are the same as those of the given - * {@code NetworkCapabilities} and return a String describing any difference. - * The returned String is empty if there is no difference. - * - * @hide - */ - public String describeImmutableDifferences(@Nullable NetworkCapabilities that) { - if (that == null) { - return "other NetworkCapabilities was null"; - } - - StringJoiner joiner = new StringJoiner(", "); - - // Ignore NOT_METERED being added or removed as it is effectively dynamic. http://b/63326103 - // TODO: properly support NOT_METERED as a mutable and requestable capability. - final long mask = ~MUTABLE_CAPABILITIES & ~(1 << NET_CAPABILITY_NOT_METERED); - long oldImmutableCapabilities = this.mNetworkCapabilities & mask; - long newImmutableCapabilities = that.mNetworkCapabilities & mask; - if (oldImmutableCapabilities != newImmutableCapabilities) { - String before = capabilityNamesOf(BitUtils.unpackBits(oldImmutableCapabilities)); - String after = capabilityNamesOf(BitUtils.unpackBits(newImmutableCapabilities)); - joiner.add(String.format("immutable capabilities changed: %s -> %s", before, after)); - } - - if (!equalsSpecifier(that)) { - NetworkSpecifier before = this.getNetworkSpecifier(); - NetworkSpecifier after = that.getNetworkSpecifier(); - joiner.add(String.format("specifier changed: %s -> %s", before, after)); - } - - if (!equalsTransportTypes(that)) { - String before = transportNamesOf(this.getTransportTypes()); - String after = transportNamesOf(that.getTransportTypes()); - joiner.add(String.format("transports changed: %s -> %s", before, after)); - } - - return joiner.toString(); - } - - /** - * Checks that our requestable capabilities are the same as those of the given - * {@code NetworkCapabilities}. - * - * @hide - */ - public boolean equalRequestableCapabilities(@Nullable NetworkCapabilities nc) { - if (nc == null) return false; - return (equalsNetCapabilitiesRequestable(nc) - && equalsTransportTypes(nc) - && equalsSpecifier(nc)); - } - - @Override - public boolean equals(@Nullable Object obj) { - if (obj == null || (obj instanceof NetworkCapabilities == false)) return false; - NetworkCapabilities that = (NetworkCapabilities) obj; - return equalsNetCapabilities(that) - && equalsTransportTypes(that) - && equalsLinkBandwidths(that) - && equalsSignalStrength(that) - && equalsSpecifier(that) - && equalsTransportInfo(that) - && equalsUids(that) - && equalsSSID(that) - && equalsOwnerUid(that) - && equalsPrivateDnsBroken(that) - && equalsRequestor(that) - && equalsAdministratorUids(that); - } - - @Override - public int hashCode() { - return (int) (mNetworkCapabilities & 0xFFFFFFFF) - + ((int) (mNetworkCapabilities >> 32) * 3) - + ((int) (mUnwantedNetworkCapabilities & 0xFFFFFFFF) * 5) - + ((int) (mUnwantedNetworkCapabilities >> 32) * 7) - + ((int) (mTransportTypes & 0xFFFFFFFF) * 11) - + ((int) (mTransportTypes >> 32) * 13) - + mLinkUpBandwidthKbps * 17 - + mLinkDownBandwidthKbps * 19 - + Objects.hashCode(mNetworkSpecifier) * 23 - + mSignalStrength * 29 - + mOwnerUid * 31 - + Objects.hashCode(mUids) * 37 - + Objects.hashCode(mSSID) * 41 - + Objects.hashCode(mTransportInfo) * 43 - + Objects.hashCode(mPrivateDnsBroken) * 47 - + Objects.hashCode(mRequestorUid) * 53 - + Objects.hashCode(mRequestorPackageName) * 59 - + Arrays.hashCode(mAdministratorUids) * 61; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeLong(mNetworkCapabilities); - dest.writeLong(mUnwantedNetworkCapabilities); - dest.writeLong(mTransportTypes); - dest.writeInt(mLinkUpBandwidthKbps); - dest.writeInt(mLinkDownBandwidthKbps); - dest.writeParcelable((Parcelable) mNetworkSpecifier, flags); - dest.writeParcelable((Parcelable) mTransportInfo, flags); - dest.writeInt(mSignalStrength); - dest.writeArraySet(mUids); - dest.writeString(mSSID); - dest.writeBoolean(mPrivateDnsBroken); - dest.writeIntArray(getAdministratorUids()); - dest.writeInt(mOwnerUid); - dest.writeInt(mRequestorUid); - dest.writeString(mRequestorPackageName); - } - - public static final @android.annotation.NonNull Creator CREATOR = - new Creator() { - @Override - public NetworkCapabilities createFromParcel(Parcel in) { - NetworkCapabilities netCap = new NetworkCapabilities(); - - netCap.mNetworkCapabilities = in.readLong(); - netCap.mUnwantedNetworkCapabilities = in.readLong(); - netCap.mTransportTypes = in.readLong(); - netCap.mLinkUpBandwidthKbps = in.readInt(); - netCap.mLinkDownBandwidthKbps = in.readInt(); - netCap.mNetworkSpecifier = in.readParcelable(null); - netCap.mTransportInfo = in.readParcelable(null); - netCap.mSignalStrength = in.readInt(); - netCap.mUids = (ArraySet) in.readArraySet( - null /* ClassLoader, null for default */); - netCap.mSSID = in.readString(); - netCap.mPrivateDnsBroken = in.readBoolean(); - netCap.setAdministratorUids(in.createIntArray()); - netCap.mOwnerUid = in.readInt(); - netCap.mRequestorUid = in.readInt(); - netCap.mRequestorPackageName = in.readString(); - return netCap; - } - @Override - public NetworkCapabilities[] newArray(int size) { - return new NetworkCapabilities[size]; - } - }; - - @Override - public @NonNull String toString() { - final StringBuilder sb = new StringBuilder("["); - if (0 != mTransportTypes) { - sb.append(" Transports: "); - appendStringRepresentationOfBitMaskToStringBuilder(sb, mTransportTypes, - NetworkCapabilities::transportNameOf, "|"); - } - if (0 != mNetworkCapabilities) { - sb.append(" Capabilities: "); - appendStringRepresentationOfBitMaskToStringBuilder(sb, mNetworkCapabilities, - NetworkCapabilities::capabilityNameOf, "&"); - } - if (0 != mUnwantedNetworkCapabilities) { - sb.append(" Unwanted: "); - appendStringRepresentationOfBitMaskToStringBuilder(sb, mUnwantedNetworkCapabilities, - NetworkCapabilities::capabilityNameOf, "&"); - } - if (mLinkUpBandwidthKbps > 0) { - sb.append(" LinkUpBandwidth>=").append(mLinkUpBandwidthKbps).append("Kbps"); - } - if (mLinkDownBandwidthKbps > 0) { - sb.append(" LinkDnBandwidth>=").append(mLinkDownBandwidthKbps).append("Kbps"); - } - if (mNetworkSpecifier != null) { - sb.append(" Specifier: <").append(mNetworkSpecifier).append(">"); - } - if (mTransportInfo != null) { - sb.append(" TransportInfo: <").append(mTransportInfo).append(">"); - } - if (hasSignalStrength()) { - sb.append(" SignalStrength: ").append(mSignalStrength); - } - - if (null != mUids) { - if ((1 == mUids.size()) && (mUids.valueAt(0).count() == 1)) { - sb.append(" Uid: ").append(mUids.valueAt(0).start); - } else { - sb.append(" Uids: <").append(mUids).append(">"); - } - } - if (mOwnerUid != Process.INVALID_UID) { - sb.append(" OwnerUid: ").append(mOwnerUid); - } - - if (!ArrayUtils.isEmpty(mAdministratorUids)) { - sb.append(" AdminUids: ").append(Arrays.toString(mAdministratorUids)); - } - - if (mRequestorUid != Process.INVALID_UID) { - sb.append(" RequestorUid: ").append(mRequestorUid); - } - - if (mRequestorPackageName != null) { - sb.append(" RequestorPkg: ").append(mRequestorPackageName); - } - - if (null != mSSID) { - sb.append(" SSID: ").append(mSSID); - } - - - if (mPrivateDnsBroken) { - sb.append(" PrivateDnsBroken"); - } - - sb.append("]"); - return sb.toString(); - } - - - private interface NameOf { - String nameOf(int value); - } - - /** - * @hide - */ - public static void appendStringRepresentationOfBitMaskToStringBuilder(@NonNull StringBuilder sb, - long bitMask, @NonNull NameOf nameFetcher, @NonNull String separator) { - int bitPos = 0; - boolean firstElementAdded = false; - while (bitMask != 0) { - if ((bitMask & 1) != 0) { - if (firstElementAdded) { - sb.append(separator); - } else { - firstElementAdded = true; - } - sb.append(nameFetcher.nameOf(bitPos)); - } - bitMask >>= 1; - ++bitPos; - } - } - - /** @hide */ - public void dumpDebug(@NonNull ProtoOutputStream proto, long fieldId) { - final long token = proto.start(fieldId); - - for (int transport : getTransportTypes()) { - proto.write(NetworkCapabilitiesProto.TRANSPORTS, transport); - } - - for (int capability : getCapabilities()) { - proto.write(NetworkCapabilitiesProto.CAPABILITIES, capability); - } - - proto.write(NetworkCapabilitiesProto.LINK_UP_BANDWIDTH_KBPS, mLinkUpBandwidthKbps); - proto.write(NetworkCapabilitiesProto.LINK_DOWN_BANDWIDTH_KBPS, mLinkDownBandwidthKbps); - - if (mNetworkSpecifier != null) { - proto.write(NetworkCapabilitiesProto.NETWORK_SPECIFIER, mNetworkSpecifier.toString()); - } - if (mTransportInfo != null) { - // TODO b/120653863: write transport-specific info to proto? - } - - proto.write(NetworkCapabilitiesProto.CAN_REPORT_SIGNAL_STRENGTH, hasSignalStrength()); - proto.write(NetworkCapabilitiesProto.SIGNAL_STRENGTH, mSignalStrength); - - proto.end(token); - } - - /** - * @hide - */ - public static @NonNull String capabilityNamesOf(@Nullable @NetCapability int[] capabilities) { - StringJoiner joiner = new StringJoiner("|"); - if (capabilities != null) { - for (int c : capabilities) { - joiner.add(capabilityNameOf(c)); - } - } - return joiner.toString(); - } - - /** - * @hide - */ - public static @NonNull String capabilityNameOf(@NetCapability int capability) { - switch (capability) { - case NET_CAPABILITY_MMS: return "MMS"; - case NET_CAPABILITY_SUPL: return "SUPL"; - case NET_CAPABILITY_DUN: return "DUN"; - case NET_CAPABILITY_FOTA: return "FOTA"; - case NET_CAPABILITY_IMS: return "IMS"; - case NET_CAPABILITY_CBS: return "CBS"; - case NET_CAPABILITY_WIFI_P2P: return "WIFI_P2P"; - case NET_CAPABILITY_IA: return "IA"; - case NET_CAPABILITY_RCS: return "RCS"; - case NET_CAPABILITY_XCAP: return "XCAP"; - case NET_CAPABILITY_EIMS: return "EIMS"; - case NET_CAPABILITY_NOT_METERED: return "NOT_METERED"; - case NET_CAPABILITY_INTERNET: return "INTERNET"; - case NET_CAPABILITY_NOT_RESTRICTED: return "NOT_RESTRICTED"; - case NET_CAPABILITY_TRUSTED: return "TRUSTED"; - case NET_CAPABILITY_NOT_VPN: return "NOT_VPN"; - case NET_CAPABILITY_VALIDATED: return "VALIDATED"; - case NET_CAPABILITY_CAPTIVE_PORTAL: return "CAPTIVE_PORTAL"; - case NET_CAPABILITY_NOT_ROAMING: return "NOT_ROAMING"; - case NET_CAPABILITY_FOREGROUND: return "FOREGROUND"; - case NET_CAPABILITY_NOT_CONGESTED: return "NOT_CONGESTED"; - case NET_CAPABILITY_NOT_SUSPENDED: return "NOT_SUSPENDED"; - case NET_CAPABILITY_OEM_PAID: return "OEM_PAID"; - case NET_CAPABILITY_MCX: return "MCX"; - case NET_CAPABILITY_PARTIAL_CONNECTIVITY: return "PARTIAL_CONNECTIVITY"; - case NET_CAPABILITY_TEMPORARILY_NOT_METERED: return "TEMPORARILY_NOT_METERED"; - case NET_CAPABILITY_OEM_PRIVATE: return "OEM_PRIVATE"; - case NET_CAPABILITY_VEHICLE_INTERNAL: return "NET_CAPABILITY_VEHICLE_INTERNAL"; - case NET_CAPABILITY_NOT_VCN_MANAGED: return "NOT_VCN_MANAGED"; - default: return Integer.toString(capability); - } - } - - /** - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public static @NonNull String transportNamesOf(@Nullable @Transport int[] types) { - StringJoiner joiner = new StringJoiner("|"); - if (types != null) { - for (int t : types) { - joiner.add(transportNameOf(t)); - } - } - return joiner.toString(); - } - - /** - * @hide - */ - public static @NonNull String transportNameOf(@Transport int transport) { - if (!isValidTransport(transport)) { - return "UNKNOWN"; - } - return TRANSPORT_NAMES[transport]; - } - - private static void checkValidTransportType(@Transport int transport) { - Preconditions.checkArgument( - isValidTransport(transport), "Invalid TransportType " + transport); - } - - private static boolean isValidCapability(@NetworkCapabilities.NetCapability int capability) { - return capability >= MIN_NET_CAPABILITY && capability <= MAX_NET_CAPABILITY; - } - - private static void checkValidCapability(@NetworkCapabilities.NetCapability int capability) { - Preconditions.checkArgument(isValidCapability(capability), - "NetworkCapability " + capability + "out of range"); - } - - /** - * Check if this {@code NetworkCapability} instance is metered. - * - * @return {@code true} if {@code NET_CAPABILITY_NOT_METERED} is not set on this instance. - * @hide - */ - public boolean isMetered() { - return !hasCapability(NET_CAPABILITY_NOT_METERED); - } - - /** - * Check if private dns is broken. - * - * @return {@code true} if {@code mPrivateDnsBroken} is set when private DNS is broken. - * @hide - */ - public boolean isPrivateDnsBroken() { - return mPrivateDnsBroken; - } - - /** - * Set mPrivateDnsBroken to true when private dns is broken. - * - * @param broken the status of private DNS to be set. - * @hide - */ - public void setPrivateDnsBroken(boolean broken) { - mPrivateDnsBroken = broken; - } - - private boolean equalsPrivateDnsBroken(NetworkCapabilities nc) { - return mPrivateDnsBroken == nc.mPrivateDnsBroken; - } - - /** - * Set the UID of the app making the request. - * - * For instances of NetworkCapabilities representing a request, sets the - * UID of the app making the request. For a network created by the system, - * sets the UID of the only app whose requests can match this network. - * This can be set to {@link Process#INVALID_UID} if there is no such app, - * or if this instance of NetworkCapabilities is about to be sent to a - * party that should not learn about this. - * - * @param uid UID of the app. - * @hide - */ - public @NonNull NetworkCapabilities setRequestorUid(int uid) { - mRequestorUid = uid; - return this; - } - - /** - * Returns the UID of the app making the request. - * - * For a NetworkRequest being made by an app, contains the app's UID. For a network - * created by the system, contains the UID of the only app whose requests can match - * this network, or {@link Process#INVALID_UID} if none or if the - * caller does not have permission to learn about this. - * - * @return the uid of the app making the request. - * @hide - */ - public int getRequestorUid() { - return mRequestorUid; - } - - /** - * Set the package name of the app making the request. - * - * For instances of NetworkCapabilities representing a request, sets the - * package name of the app making the request. For a network created by the system, - * sets the package name of the only app whose requests can match this network. - * This can be set to null if there is no such app, or if this instance of - * NetworkCapabilities is about to be sent to a party that should not learn about this. - * - * @param packageName package name of the app. - * @hide - */ - public @NonNull NetworkCapabilities setRequestorPackageName(@NonNull String packageName) { - mRequestorPackageName = packageName; - return this; - } - - /** - * Returns the package name of the app making the request. - * - * For a NetworkRequest being made by an app, contains the app's package name. For a - * network created by the system, contains the package name of the only app whose - * requests can match this network, or null if none or if the caller does not have - * permission to learn about this. - * - * @return the package name of the app making the request. - * @hide - */ - @Nullable - public String getRequestorPackageName() { - return mRequestorPackageName; - } - - /** - * Set the uid and package name of the app causing this network to exist. - * - * {@see #setRequestorUid} and {@link #setRequestorPackageName} - * - * @param uid UID of the app. - * @param packageName package name of the app. - * @hide - */ - public @NonNull NetworkCapabilities setRequestorUidAndPackageName( - int uid, @NonNull String packageName) { - return setRequestorUid(uid).setRequestorPackageName(packageName); - } - - /** - * Test whether the passed NetworkCapabilities satisfies the requestor restrictions of this - * capabilities. - * - * This method is called on the NetworkCapabilities embedded in a request with the - * capabilities of an available network. If the available network, sets a specific - * requestor (by uid and optionally package name), then this will only match a request from the - * same app. If either of the capabilities have an unset uid or package name, then it matches - * everything. - *

- * nc is assumed nonnull. Else, NPE. - */ - private boolean satisfiedByRequestor(NetworkCapabilities nc) { - // No uid set, matches everything. - if (mRequestorUid == Process.INVALID_UID || nc.mRequestorUid == Process.INVALID_UID) { - return true; - } - // uids don't match. - if (mRequestorUid != nc.mRequestorUid) return false; - // No package names set, matches everything - if (null == nc.mRequestorPackageName || null == mRequestorPackageName) return true; - // check for package name match. - return TextUtils.equals(mRequestorPackageName, nc.mRequestorPackageName); - } - - /** - * Combine requestor info of the capabilities. - *

- * This is only legal if either the requestor info of this object is reset, or both info are - * equal. - * nc is assumed nonnull. - */ - private void combineRequestor(@NonNull NetworkCapabilities nc) { - if (mRequestorUid != Process.INVALID_UID && mRequestorUid != nc.mOwnerUid) { - throw new IllegalStateException("Can't combine two uids"); - } - if (mRequestorPackageName != null - && !mRequestorPackageName.equals(nc.mRequestorPackageName)) { - throw new IllegalStateException("Can't combine two package names"); - } - setRequestorUid(nc.mRequestorUid); - setRequestorPackageName(nc.mRequestorPackageName); - } - - private boolean equalsRequestor(NetworkCapabilities nc) { - return mRequestorUid == nc.mRequestorUid - && TextUtils.equals(mRequestorPackageName, nc.mRequestorPackageName); - } - - /** - * Builder class for NetworkCapabilities. - * - * This class is mainly for for {@link NetworkAgent} instances to use. Many fields in - * the built class require holding a signature permission to use - mostly - * {@link android.Manifest.permission.NETWORK_FACTORY}, but refer to the specific - * description of each setter. As this class lives entirely in app space it does not - * enforce these restrictions itself but the system server clears out the relevant - * fields when receiving a NetworkCapabilities object from a caller without the - * appropriate permission. - * - * Apps don't use this builder directly. Instead, they use {@link NetworkRequest} via - * its builder object. - * - * @hide - */ - @SystemApi - public static final class Builder { - private final NetworkCapabilities mCaps; - - /** - * Creates a new Builder to construct NetworkCapabilities objects. - */ - public Builder() { - mCaps = new NetworkCapabilities(); - } - - /** - * Creates a new Builder of NetworkCapabilities from an existing instance. - */ - public Builder(@NonNull final NetworkCapabilities nc) { - Objects.requireNonNull(nc); - mCaps = new NetworkCapabilities(nc); - } - - /** - * Adds the given transport type. - * - * Multiple transports may be added. Note that when searching for a network to satisfy a - * request, satisfying any of the transports listed in the request will satisfy the request. - * For example {@code TRANSPORT_WIFI} and {@code TRANSPORT_ETHERNET} added to a - * {@code NetworkCapabilities} would cause either a Wi-Fi network or an Ethernet network - * to be selected. This is logically different than - * {@code NetworkCapabilities.NET_CAPABILITY_*}. - * - * @param transportType the transport type to be added or removed. - * @return this builder - */ - @NonNull - public Builder addTransportType(@Transport int transportType) { - checkValidTransportType(transportType); - mCaps.addTransportType(transportType); - return this; - } - - /** - * Removes the given transport type. - * - * {@see #addTransportType}. - * - * @param transportType the transport type to be added or removed. - * @return this builder - */ - @NonNull - public Builder removeTransportType(@Transport int transportType) { - checkValidTransportType(transportType); - mCaps.removeTransportType(transportType); - return this; - } - - /** - * Adds the given capability. - * - * @param capability the capability - * @return this builder - */ - @NonNull - public Builder addCapability(@NetCapability final int capability) { - mCaps.setCapability(capability, true); - return this; - } - - /** - * Removes the given capability. - * - * @param capability the capability - * @return this builder - */ - @NonNull - public Builder removeCapability(@NetCapability final int capability) { - mCaps.setCapability(capability, false); - return this; - } - - /** - * Sets the owner UID. - * - * The default value is {@link Process#INVALID_UID}. Pass this value to reset. - * - * Note: for security the system will clear out this field when received from a - * non-privileged source. - * - * @param ownerUid the owner UID - * @return this builder - */ - @NonNull - @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) - public Builder setOwnerUid(final int ownerUid) { - mCaps.setOwnerUid(ownerUid); - return this; - } - - /** - * Sets the list of UIDs that are administrators of this network. - * - *

UIDs included in administratorUids gain administrator privileges over this - * Network. Examples of UIDs that should be included in administratorUids are: - *

    - *
  • Carrier apps with privileges for the relevant subscription - *
  • Active VPN apps - *
  • Other application groups with a particular Network-related role - *
- * - *

In general, user-supplied networks (such as WiFi networks) do not have - * administrators. - * - *

An app is granted owner privileges over Networks that it supplies. The owner - * UID MUST always be included in administratorUids. - * - * The default value is the empty array. Pass an empty array to reset. - * - * Note: for security the system will clear out this field when received from a - * non-privileged source, such as an app using reflection to call this or - * mutate the member in the built object. - * - * @param administratorUids the UIDs to be set as administrators of this Network. - * @return this builder - */ - @NonNull - @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) - public Builder setAdministratorUids(@NonNull final int[] administratorUids) { - Objects.requireNonNull(administratorUids); - mCaps.setAdministratorUids(administratorUids); - return this; - } - - /** - * Sets the upstream bandwidth of the link. - * - * Sets the upstream bandwidth for this network in Kbps. This always only refers to - * the estimated first hop transport bandwidth. - *

- * Note that when used to request a network, this specifies the minimum acceptable. - * When received as the state of an existing network this specifies the typical - * first hop bandwidth expected. This is never measured, but rather is inferred - * from technology type and other link parameters. It could be used to differentiate - * between very slow 1xRTT cellular links and other faster networks or even between - * 802.11b vs 802.11AC wifi technologies. It should not be used to differentiate between - * fast backhauls and slow backhauls. - * - * @param upKbps the estimated first hop upstream (device to network) bandwidth. - * @return this builder - */ - @NonNull - public Builder setLinkUpstreamBandwidthKbps(final int upKbps) { - mCaps.setLinkUpstreamBandwidthKbps(upKbps); - return this; - } - - /** - * Sets the downstream bandwidth for this network in Kbps. This always only refers to - * the estimated first hop transport bandwidth. - *

- * Note that when used to request a network, this specifies the minimum acceptable. - * When received as the state of an existing network this specifies the typical - * first hop bandwidth expected. This is never measured, but rather is inferred - * from technology type and other link parameters. It could be used to differentiate - * between very slow 1xRTT cellular links and other faster networks or even between - * 802.11b vs 802.11AC wifi technologies. It should not be used to differentiate between - * fast backhauls and slow backhauls. - * - * @param downKbps the estimated first hop downstream (network to device) bandwidth. - * @return this builder - */ - @NonNull - public Builder setLinkDownstreamBandwidthKbps(final int downKbps) { - mCaps.setLinkDownstreamBandwidthKbps(downKbps); - return this; - } - - /** - * Sets the optional bearer specific network specifier. - * This has no meaning if a single transport is also not specified, so calling - * this without a single transport set will generate an exception, as will - * subsequently adding or removing transports after this is set. - *

- * - * @param specifier a concrete, parcelable framework class that extends NetworkSpecifier, - * or null to clear it. - * @return this builder - */ - @NonNull - public Builder setNetworkSpecifier(@Nullable final NetworkSpecifier specifier) { - mCaps.setNetworkSpecifier(specifier); - return this; - } - - /** - * Sets the optional transport specific information. - * - * @param info A concrete, parcelable framework class that extends {@link TransportInfo}, - * or null to clear it. - * @return this builder - */ - @NonNull - public Builder setTransportInfo(@Nullable final TransportInfo info) { - mCaps.setTransportInfo(info); - return this; - } - - /** - * Sets the signal strength. This is a signed integer, with higher values indicating a - * stronger signal. The exact units are bearer-dependent. For example, Wi-Fi uses the - * same RSSI units reported by wifi code. - *

- * Note that when used to register a network callback, this specifies the minimum - * acceptable signal strength. When received as the state of an existing network it - * specifies the current value. A value of code SIGNAL_STRENGTH_UNSPECIFIED} means - * no value when received and has no effect when requesting a callback. - * - * Note: for security the system will throw if it receives a NetworkRequest where - * the underlying NetworkCapabilities has this member set from a source that does - * not hold the {@link android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP} - * permission. Apps with this permission can use this indirectly through - * {@link android.net.NetworkRequest}. - * - * @param signalStrength the bearer-specific signal strength. - * @return this builder - */ - @NonNull - @RequiresPermission(android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP) - public Builder setSignalStrength(final int signalStrength) { - mCaps.setSignalStrength(signalStrength); - return this; - } - - /** - * Sets the SSID of this network. - * - * Note: for security the system will clear out this field when received from a - * non-privileged source, like an app using reflection to set this. - * - * @param ssid the SSID, or null to clear it. - * @return this builder - */ - @NonNull - @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) - public Builder setSsid(@Nullable final String ssid) { - mCaps.setSSID(ssid); - return this; - } - - /** - * Set the uid of the app causing this network to exist. - * - * Note: for security the system will clear out this field when received from a - * non-privileged source. - * - * @param uid UID of the app. - * @return this builder - */ - @NonNull - @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) - public Builder setRequestorUid(final int uid) { - mCaps.setRequestorUid(uid); - return this; - } - - /** - * Set the package name of the app causing this network to exist. - * - * Note: for security the system will clear out this field when received from a - * non-privileged source. - * - * @param packageName package name of the app, or null to clear it. - * @return this builder - */ - @NonNull - @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) - public Builder setRequestorPackageName(@Nullable final String packageName) { - mCaps.setRequestorPackageName(packageName); - return this; - } - - /** - * Builds the instance of the capabilities. - * - * @return the built instance of NetworkCapabilities. - */ - @NonNull - public NetworkCapabilities build() { - if (mCaps.getOwnerUid() != Process.INVALID_UID) { - if (!ArrayUtils.contains(mCaps.getAdministratorUids(), mCaps.getOwnerUid())) { - throw new IllegalStateException("The owner UID must be included in " - + " administrator UIDs."); - } - } - return new NetworkCapabilities(mCaps); - } - } -} diff --git a/core/java/android/net/NetworkConfig.java b/core/java/android/net/NetworkConfig.java deleted file mode 100644 index 32a2cda00370..000000000000 --- a/core/java/android/net/NetworkConfig.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import java.util.Locale; - -/** - * Describes the buildtime configuration of a network. - * Holds settings read from resources. - * @hide - */ -public class NetworkConfig { - /** - * Human readable string - */ - public String name; - - /** - * Type from ConnectivityManager - */ - public int type; - - /** - * the radio number from radio attributes config - */ - public int radio; - - /** - * higher number == higher priority when turning off connections - */ - public int priority; - - /** - * indicates the boot time dependencyMet setting - */ - public boolean dependencyMet; - - /** - * indicates the default restoral timer in seconds - * if the network is used as a special network feature - * -1 indicates no restoration of default - */ - public int restoreTime; - - /** - * input string from config.xml resource. Uses the form: - * [Connection name],[ConnectivityManager connection type], - * [associated radio-type],[priority],[dependencyMet] - */ - public NetworkConfig(String init) { - String fragments[] = init.split(","); - name = fragments[0].trim().toLowerCase(Locale.ROOT); - type = Integer.parseInt(fragments[1]); - radio = Integer.parseInt(fragments[2]); - priority = Integer.parseInt(fragments[3]); - restoreTime = Integer.parseInt(fragments[4]); - dependencyMet = Boolean.parseBoolean(fragments[5]); - } - - /** - * Indicates if this network is supposed to be default-routable - */ - public boolean isDefault() { - return (type == radio); - } -} diff --git a/core/java/android/net/NetworkInfo.aidl b/core/java/android/net/NetworkInfo.aidl deleted file mode 100644 index f50187302966..000000000000 --- a/core/java/android/net/NetworkInfo.aidl +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2007, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -parcelable NetworkInfo; diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java deleted file mode 100644 index d752901e2eb0..000000000000 --- a/core/java/android/net/NetworkInfo.java +++ /dev/null @@ -1,626 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.compat.annotation.UnsupportedAppUsage; -import android.os.Parcel; -import android.os.Parcelable; -import android.telephony.Annotation.NetworkType; -import android.text.TextUtils; - -import com.android.internal.annotations.VisibleForTesting; - -import java.util.EnumMap; - -/** - * Describes the status of a network interface. - *

Use {@link ConnectivityManager#getActiveNetworkInfo()} to get an instance that represents - * the current network connection. - * - * @deprecated Callers should instead use the {@link ConnectivityManager.NetworkCallback} API to - * learn about connectivity changes, or switch to use - * {@link ConnectivityManager#getNetworkCapabilities} or - * {@link ConnectivityManager#getLinkProperties} to get information synchronously. Keep - * in mind that while callbacks are guaranteed to be called for every event in order, - * synchronous calls have no such constraints, and as such it is unadvisable to use the - * synchronous methods inside the callbacks as they will often not offer a view of - * networking that is consistent (that is: they may return a past or a future state with - * respect to the event being processed by the callback). Instead, callers are advised - * to only use the arguments of the callbacks, possibly memorizing the specific bits of - * information they need to keep from one callback to another. - */ -@Deprecated -public class NetworkInfo implements Parcelable { - - /** - * Coarse-grained network state. This is probably what most applications should - * use, rather than {@link android.net.NetworkInfo.DetailedState DetailedState}. - * The mapping between the two is as follows: - *

- * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
Detailed stateCoarse-grained state
IDLEDISCONNECTED
SCANNINGDISCONNECTED
CONNECTINGCONNECTING
AUTHENTICATINGCONNECTING
OBTAINING_IPADDRCONNECTING
VERIFYING_POOR_LINKCONNECTING
CAPTIVE_PORTAL_CHECKCONNECTING
CONNECTEDCONNECTED
SUSPENDEDSUSPENDED
DISCONNECTINGDISCONNECTING
DISCONNECTEDDISCONNECTED
FAILEDDISCONNECTED
BLOCKEDDISCONNECTED
- * - * @deprecated See {@link NetworkInfo}. - */ - @Deprecated - public enum State { - CONNECTING, CONNECTED, SUSPENDED, DISCONNECTING, DISCONNECTED, UNKNOWN - } - - /** - * The fine-grained state of a network connection. This level of detail - * is probably of interest to few applications. Most should use - * {@link android.net.NetworkInfo.State State} instead. - * - * @deprecated See {@link NetworkInfo}. - */ - @Deprecated - public enum DetailedState { - /** Ready to start data connection setup. */ - IDLE, - /** Searching for an available access point. */ - SCANNING, - /** Currently setting up data connection. */ - CONNECTING, - /** Network link established, performing authentication. */ - AUTHENTICATING, - /** Awaiting response from DHCP server in order to assign IP address information. */ - OBTAINING_IPADDR, - /** IP traffic should be available. */ - CONNECTED, - /** IP traffic is suspended */ - SUSPENDED, - /** Currently tearing down data connection. */ - DISCONNECTING, - /** IP traffic not available. */ - DISCONNECTED, - /** Attempt to connect failed. */ - FAILED, - /** Access to this network is blocked. */ - BLOCKED, - /** Link has poor connectivity. */ - VERIFYING_POOR_LINK, - /** Checking if network is a captive portal */ - CAPTIVE_PORTAL_CHECK - } - - /** - * This is the map described in the Javadoc comment above. The positions - * of the elements of the array must correspond to the ordinal values - * of DetailedState. - */ - private static final EnumMap stateMap = - new EnumMap(DetailedState.class); - - static { - stateMap.put(DetailedState.IDLE, State.DISCONNECTED); - stateMap.put(DetailedState.SCANNING, State.DISCONNECTED); - stateMap.put(DetailedState.CONNECTING, State.CONNECTING); - stateMap.put(DetailedState.AUTHENTICATING, State.CONNECTING); - stateMap.put(DetailedState.OBTAINING_IPADDR, State.CONNECTING); - stateMap.put(DetailedState.VERIFYING_POOR_LINK, State.CONNECTING); - stateMap.put(DetailedState.CAPTIVE_PORTAL_CHECK, State.CONNECTING); - stateMap.put(DetailedState.CONNECTED, State.CONNECTED); - stateMap.put(DetailedState.SUSPENDED, State.SUSPENDED); - stateMap.put(DetailedState.DISCONNECTING, State.DISCONNECTING); - stateMap.put(DetailedState.DISCONNECTED, State.DISCONNECTED); - stateMap.put(DetailedState.FAILED, State.DISCONNECTED); - stateMap.put(DetailedState.BLOCKED, State.DISCONNECTED); - } - - private int mNetworkType; - private int mSubtype; - private String mTypeName; - private String mSubtypeName; - @NonNull - private State mState; - @NonNull - private DetailedState mDetailedState; - private String mReason; - private String mExtraInfo; - private boolean mIsFailover; - private boolean mIsAvailable; - private boolean mIsRoaming; - - /** - * Create a new instance of NetworkInfo. - * - * This may be useful for apps to write unit tests. - * - * @param type the legacy type of the network, as one of the ConnectivityManager.TYPE_* - * constants. - * @param subtype the subtype if applicable, as one of the TelephonyManager.NETWORK_TYPE_* - * constants. - * @param typeName a human-readable string for the network type, or an empty string or null. - * @param subtypeName a human-readable string for the subtype, or an empty string or null. - */ - public NetworkInfo(int type, @NetworkType int subtype, - @Nullable String typeName, @Nullable String subtypeName) { - if (!ConnectivityManager.isNetworkTypeValid(type) - && type != ConnectivityManager.TYPE_NONE) { - throw new IllegalArgumentException("Invalid network type: " + type); - } - mNetworkType = type; - mSubtype = subtype; - mTypeName = typeName; - mSubtypeName = subtypeName; - setDetailedState(DetailedState.IDLE, null, null); - mState = State.UNKNOWN; - } - - /** {@hide} */ - @UnsupportedAppUsage - public NetworkInfo(NetworkInfo source) { - if (source != null) { - synchronized (source) { - mNetworkType = source.mNetworkType; - mSubtype = source.mSubtype; - mTypeName = source.mTypeName; - mSubtypeName = source.mSubtypeName; - mState = source.mState; - mDetailedState = source.mDetailedState; - mReason = source.mReason; - mExtraInfo = source.mExtraInfo; - mIsFailover = source.mIsFailover; - mIsAvailable = source.mIsAvailable; - mIsRoaming = source.mIsRoaming; - } - } - } - - /** - * Reports the type of network to which the - * info in this {@code NetworkInfo} pertains. - * @return one of {@link ConnectivityManager#TYPE_MOBILE}, {@link - * ConnectivityManager#TYPE_WIFI}, {@link ConnectivityManager#TYPE_WIMAX}, {@link - * ConnectivityManager#TYPE_ETHERNET}, {@link ConnectivityManager#TYPE_BLUETOOTH}, or other - * types defined by {@link ConnectivityManager}. - * @deprecated Callers should switch to checking {@link NetworkCapabilities#hasTransport} - * instead with one of the NetworkCapabilities#TRANSPORT_* constants : - * {@link #getType} and {@link #getTypeName} cannot account for networks using - * multiple transports. Note that generally apps should not care about transport; - * {@link NetworkCapabilities#NET_CAPABILITY_NOT_METERED} and - * {@link NetworkCapabilities#getLinkDownstreamBandwidthKbps} are calls that - * apps concerned with meteredness or bandwidth should be looking at, as they - * offer this information with much better accuracy. - */ - @Deprecated - public int getType() { - synchronized (this) { - return mNetworkType; - } - } - - /** - * @deprecated Use {@link NetworkCapabilities} instead - * @hide - */ - @Deprecated - public void setType(int type) { - synchronized (this) { - mNetworkType = type; - } - } - - /** - * Return a network-type-specific integer describing the subtype - * of the network. - * @return the network subtype - * @deprecated Use {@link android.telephony.TelephonyManager#getDataNetworkType} instead. - */ - @Deprecated - public int getSubtype() { - synchronized (this) { - return mSubtype; - } - } - - /** - * @hide - */ - @UnsupportedAppUsage - public void setSubtype(int subtype, String subtypeName) { - synchronized (this) { - mSubtype = subtype; - mSubtypeName = subtypeName; - } - } - - /** - * Return a human-readable name describe the type of the network, - * for example "WIFI" or "MOBILE". - * @return the name of the network type - * @deprecated Callers should switch to checking {@link NetworkCapabilities#hasTransport} - * instead with one of the NetworkCapabilities#TRANSPORT_* constants : - * {@link #getType} and {@link #getTypeName} cannot account for networks using - * multiple transports. Note that generally apps should not care about transport; - * {@link NetworkCapabilities#NET_CAPABILITY_NOT_METERED} and - * {@link NetworkCapabilities#getLinkDownstreamBandwidthKbps} are calls that - * apps concerned with meteredness or bandwidth should be looking at, as they - * offer this information with much better accuracy. - */ - @Deprecated - public String getTypeName() { - synchronized (this) { - return mTypeName; - } - } - - /** - * Return a human-readable name describing the subtype of the network. - * @return the name of the network subtype - * @deprecated Use {@link android.telephony.TelephonyManager#getDataNetworkType} instead. - */ - @Deprecated - public String getSubtypeName() { - synchronized (this) { - return mSubtypeName; - } - } - - /** - * Indicates whether network connectivity exists or is in the process - * of being established. This is good for applications that need to - * do anything related to the network other than read or write data. - * For the latter, call {@link #isConnected()} instead, which guarantees - * that the network is fully usable. - * @return {@code true} if network connectivity exists or is in the process - * of being established, {@code false} otherwise. - * @deprecated Apps should instead use the - * {@link android.net.ConnectivityManager.NetworkCallback} API to - * learn about connectivity changes. - * {@link ConnectivityManager#registerDefaultNetworkCallback} and - * {@link ConnectivityManager#registerNetworkCallback}. These will - * give a more accurate picture of the connectivity state of - * the device and let apps react more easily and quickly to changes. - */ - @Deprecated - public boolean isConnectedOrConnecting() { - synchronized (this) { - return mState == State.CONNECTED || mState == State.CONNECTING; - } - } - - /** - * Indicates whether network connectivity exists and it is possible to establish - * connections and pass data. - *

Always call this before attempting to perform data transactions. - * @return {@code true} if network connectivity exists, {@code false} otherwise. - * @deprecated Apps should instead use the - * {@link android.net.ConnectivityManager.NetworkCallback} API to - * learn about connectivity changes. See - * {@link ConnectivityManager#registerDefaultNetworkCallback} and - * {@link ConnectivityManager#registerNetworkCallback}. These will - * give a more accurate picture of the connectivity state of - * the device and let apps react more easily and quickly to changes. - */ - @Deprecated - public boolean isConnected() { - synchronized (this) { - return mState == State.CONNECTED; - } - } - - /** - * Indicates whether network connectivity is possible. A network is unavailable - * when a persistent or semi-persistent condition prevents the possibility - * of connecting to that network. Examples include - *

    - *
  • The device is out of the coverage area for any network of this type.
  • - *
  • The device is on a network other than the home network (i.e., roaming), and - * data roaming has been disabled.
  • - *
  • The device's radio is turned off, e.g., because airplane mode is enabled.
  • - *
- * Since Android L, this always returns {@code true}, because the system only - * returns info for available networks. - * @return {@code true} if the network is available, {@code false} otherwise - * @deprecated Apps should instead use the - * {@link android.net.ConnectivityManager.NetworkCallback} API to - * learn about connectivity changes. - * {@link ConnectivityManager#registerDefaultNetworkCallback} and - * {@link ConnectivityManager#registerNetworkCallback}. These will - * give a more accurate picture of the connectivity state of - * the device and let apps react more easily and quickly to changes. - */ - @Deprecated - public boolean isAvailable() { - synchronized (this) { - return mIsAvailable; - } - } - - /** - * Sets if the network is available, ie, if the connectivity is possible. - * @param isAvailable the new availability value. - * @deprecated Use {@link NetworkCapabilities} instead - * - * @hide - */ - @Deprecated - @UnsupportedAppUsage - public void setIsAvailable(boolean isAvailable) { - synchronized (this) { - mIsAvailable = isAvailable; - } - } - - /** - * Indicates whether the current attempt to connect to the network - * resulted from the ConnectivityManager trying to fail over to this - * network following a disconnect from another network. - * @return {@code true} if this is a failover attempt, {@code false} - * otherwise. - * @deprecated This field is not populated in recent Android releases, - * and does not make a lot of sense in a multi-network world. - */ - @Deprecated - public boolean isFailover() { - synchronized (this) { - return mIsFailover; - } - } - - /** - * Set the failover boolean. - * @param isFailover {@code true} to mark the current connection attempt - * as a failover. - * @deprecated This hasn't been set in any recent Android release. - * @hide - */ - @Deprecated - @UnsupportedAppUsage - public void setFailover(boolean isFailover) { - synchronized (this) { - mIsFailover = isFailover; - } - } - - /** - * Indicates whether the device is currently roaming on this network. When - * {@code true}, it suggests that use of data on this network may incur - * extra costs. - * - * @return {@code true} if roaming is in effect, {@code false} otherwise. - * @deprecated Callers should switch to checking - * {@link NetworkCapabilities#NET_CAPABILITY_NOT_ROAMING} - * instead, since that handles more complex situations, such as - * VPNs. - */ - @Deprecated - public boolean isRoaming() { - synchronized (this) { - return mIsRoaming; - } - } - - /** - * @deprecated Use {@link NetworkCapabilities#NET_CAPABILITY_NOT_ROAMING} instead. - * {@hide} - */ - @VisibleForTesting - @Deprecated - @UnsupportedAppUsage - public void setRoaming(boolean isRoaming) { - synchronized (this) { - mIsRoaming = isRoaming; - } - } - - /** - * Reports the current coarse-grained state of the network. - * @return the coarse-grained state - * @deprecated Apps should instead use the - * {@link android.net.ConnectivityManager.NetworkCallback} API to - * learn about connectivity changes. - * {@link ConnectivityManager#registerDefaultNetworkCallback} and - * {@link ConnectivityManager#registerNetworkCallback}. These will - * give a more accurate picture of the connectivity state of - * the device and let apps react more easily and quickly to changes. - */ - @Deprecated - public State getState() { - synchronized (this) { - return mState; - } - } - - /** - * Reports the current fine-grained state of the network. - * @return the fine-grained state - * @deprecated Apps should instead use the - * {@link android.net.ConnectivityManager.NetworkCallback} API to - * learn about connectivity changes. See - * {@link ConnectivityManager#registerDefaultNetworkCallback} and - * {@link ConnectivityManager#registerNetworkCallback}. These will - * give a more accurate picture of the connectivity state of - * the device and let apps react more easily and quickly to changes. - */ - @Deprecated - public @NonNull DetailedState getDetailedState() { - synchronized (this) { - return mDetailedState; - } - } - - /** - * Sets the fine-grained state of the network. - * - * This is only useful for testing. - * - * @param detailedState the {@link DetailedState}. - * @param reason a {@code String} indicating the reason for the state change, - * if one was supplied. May be {@code null}. - * @param extraInfo an optional {@code String} providing addditional network state - * information passed up from the lower networking layers. - * @deprecated Use {@link NetworkCapabilities} instead. - */ - @Deprecated - public void setDetailedState(@NonNull DetailedState detailedState, @Nullable String reason, - @Nullable String extraInfo) { - synchronized (this) { - this.mDetailedState = detailedState; - this.mState = stateMap.get(detailedState); - this.mReason = reason; - this.mExtraInfo = extraInfo; - } - } - - /** - * Set the extraInfo field. - * @param extraInfo an optional {@code String} providing addditional network state - * information passed up from the lower networking layers. - * @deprecated See {@link NetworkInfo#getExtraInfo}. - * @hide - */ - @Deprecated - public void setExtraInfo(String extraInfo) { - synchronized (this) { - this.mExtraInfo = extraInfo; - } - } - - /** - * Report the reason an attempt to establish connectivity failed, - * if one is available. - * @return the reason for failure, or null if not available - * @deprecated This method does not have a consistent contract that could make it useful - * to callers. - */ - public String getReason() { - synchronized (this) { - return mReason; - } - } - - /** - * Report the extra information about the network state, if any was - * provided by the lower networking layers. - * @return the extra information, or null if not available - * @deprecated Use other services e.g. WifiManager to get additional information passed up from - * the lower networking layers. - */ - @Deprecated - public String getExtraInfo() { - synchronized (this) { - return mExtraInfo; - } - } - - @Override - public String toString() { - synchronized (this) { - final StringBuilder builder = new StringBuilder("["); - builder.append("type: ").append(getTypeName()).append("[").append(getSubtypeName()). - append("], state: ").append(mState).append("/").append(mDetailedState). - append(", reason: ").append(mReason == null ? "(unspecified)" : mReason). - append(", extra: ").append(mExtraInfo == null ? "(none)" : mExtraInfo). - append(", failover: ").append(mIsFailover). - append(", available: ").append(mIsAvailable). - append(", roaming: ").append(mIsRoaming). - append("]"); - return builder.toString(); - } - } - - /** - * Returns a brief summary string suitable for debugging. - * @hide - */ - public String toShortString() { - synchronized (this) { - final StringBuilder builder = new StringBuilder(); - builder.append(getTypeName()); - - final String subtype = getSubtypeName(); - if (!TextUtils.isEmpty(subtype)) { - builder.append("[").append(subtype).append("]"); - } - - builder.append(" "); - builder.append(mDetailedState); - if (mIsRoaming) { - builder.append(" ROAMING"); - } - if (mExtraInfo != null) { - builder.append(" extra: ").append(mExtraInfo); - } - return builder.toString(); - } - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - synchronized (this) { - dest.writeInt(mNetworkType); - dest.writeInt(mSubtype); - dest.writeString(mTypeName); - dest.writeString(mSubtypeName); - dest.writeString(mState.name()); - dest.writeString(mDetailedState.name()); - dest.writeInt(mIsFailover ? 1 : 0); - dest.writeInt(mIsAvailable ? 1 : 0); - dest.writeInt(mIsRoaming ? 1 : 0); - dest.writeString(mReason); - dest.writeString(mExtraInfo); - } - } - - public static final @android.annotation.NonNull Creator CREATOR = new Creator() { - @Override - public NetworkInfo createFromParcel(Parcel in) { - int netType = in.readInt(); - int subtype = in.readInt(); - String typeName = in.readString(); - String subtypeName = in.readString(); - NetworkInfo netInfo = new NetworkInfo(netType, subtype, typeName, subtypeName); - netInfo.mState = State.valueOf(in.readString()); - netInfo.mDetailedState = DetailedState.valueOf(in.readString()); - netInfo.mIsFailover = in.readInt() != 0; - netInfo.mIsAvailable = in.readInt() != 0; - netInfo.mIsRoaming = in.readInt() != 0; - netInfo.mReason = in.readString(); - netInfo.mExtraInfo = in.readString(); - return netInfo; - } - - @Override - public NetworkInfo[] newArray(int size) { - return new NetworkInfo[size]; - } - }; -} diff --git a/core/java/android/net/NetworkProvider.java b/core/java/android/net/NetworkProvider.java deleted file mode 100644 index 14cb51c85d06..000000000000 --- a/core/java/android/net/NetworkProvider.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import android.annotation.IntRange; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.RequiresPermission; -import android.annotation.SystemApi; -import android.content.Context; -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.os.Messenger; -import android.util.Log; - -/** - * Base class for network providers such as telephony or Wi-Fi. NetworkProviders connect the device - * to networks and makes them available to the core network stack by creating - * {@link NetworkAgent}s. The networks can then provide connectivity to apps and can be interacted - * with via networking APIs such as {@link ConnectivityManager}. - * - * Subclasses should implement {@link #onNetworkRequested} and {@link #onNetworkRequestWithdrawn} - * to receive {@link NetworkRequest}s sent by the system and by apps. A network that is not the - * best (highest-scoring) network for any request is generally not used by the system, and torn - * down. - * - * @hide - */ -@SystemApi -public class NetworkProvider { - /** - * {@code providerId} value that indicates the absence of a provider. It is the providerId of - * any NetworkProvider that is not currently registered, and of any NetworkRequest that is not - * currently being satisfied by a network. - */ - public static final int ID_NONE = -1; - - /** - * The first providerId value that will be allocated. - * @hide only used by ConnectivityService. - */ - public static final int FIRST_PROVIDER_ID = 1; - - /** @hide only used by ConnectivityService */ - public static final int CMD_REQUEST_NETWORK = 1; - /** @hide only used by ConnectivityService */ - public static final int CMD_CANCEL_REQUEST = 2; - - private final Messenger mMessenger; - private final String mName; - private final Context mContext; - - private int mProviderId = ID_NONE; - - /** - * Constructs a new NetworkProvider. - * - * @param looper the Looper on which to run {@link #onNetworkRequested} and - * {@link #onNetworkRequestWithdrawn}. - * @param name the name of the listener, used only for debugging. - * - * @hide - */ - @SystemApi - public NetworkProvider(@NonNull Context context, @NonNull Looper looper, @NonNull String name) { - Handler handler = new Handler(looper) { - @Override - public void handleMessage(Message m) { - switch (m.what) { - case CMD_REQUEST_NETWORK: - onNetworkRequested((NetworkRequest) m.obj, m.arg1, m.arg2); - break; - case CMD_CANCEL_REQUEST: - onNetworkRequestWithdrawn((NetworkRequest) m.obj); - break; - default: - Log.e(mName, "Unhandled message: " + m.what); - } - } - }; - mContext = context; - mMessenger = new Messenger(handler); - mName = name; - } - - // TODO: consider adding a register() method so ConnectivityManager does not need to call this. - /** @hide */ - public @Nullable Messenger getMessenger() { - return mMessenger; - } - - /** @hide */ - public @NonNull String getName() { - return mName; - } - - /** - * Returns the ID of this provider. This is known only once the provider is registered via - * {@link ConnectivityManager#registerNetworkProvider()}, otherwise the ID is {@link #ID_NONE}. - * This ID must be used when registering any {@link NetworkAgent}s. - */ - public int getProviderId() { - return mProviderId; - } - - /** @hide */ - public void setProviderId(int providerId) { - mProviderId = providerId; - } - - /** - * Called when a NetworkRequest is received. The request may be a new request or an existing - * request with a different score. - * - * @param request the NetworkRequest being received - * @param score the score of the network currently satisfying the request, or 0 if none. - * @param providerId the ID of the provider that created the network currently satisfying this - * request, or {@link #ID_NONE} if none. - * - * @hide - */ - @SystemApi - public void onNetworkRequested(@NonNull NetworkRequest request, - @IntRange(from = 0, to = 99) int score, int providerId) {} - - /** - * Called when a NetworkRequest is withdrawn. - * @hide - */ - @SystemApi - public void onNetworkRequestWithdrawn(@NonNull NetworkRequest request) {} - - /** - * Asserts that no provider will ever be able to satisfy the specified request. The provider - * must only call this method if it knows that it is the only provider on the system capable of - * satisfying this request, and that the request cannot be satisfied. The application filing the - * request will receive an {@link NetworkCallback#onUnavailable()} callback. - * - * @param request the request that permanently cannot be fulfilled - * @hide - */ - @SystemApi - @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) - public void declareNetworkRequestUnfulfillable(@NonNull NetworkRequest request) { - ConnectivityManager.from(mContext).declareNetworkRequestUnfulfillable(request); - } -} diff --git a/core/java/android/net/NetworkRequest.aidl b/core/java/android/net/NetworkRequest.aidl deleted file mode 100644 index 508defc6b497..000000000000 --- a/core/java/android/net/NetworkRequest.aidl +++ /dev/null @@ -1,20 +0,0 @@ -/** - * Copyright (c) 2014, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -parcelable NetworkRequest; - diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java deleted file mode 100644 index 04011fc6816e..000000000000 --- a/core/java/android/net/NetworkRequest.java +++ /dev/null @@ -1,582 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.RequiresPermission; -import android.annotation.SystemApi; -import android.compat.annotation.UnsupportedAppUsage; -import android.net.NetworkCapabilities.NetCapability; -import android.net.NetworkCapabilities.Transport; -import android.os.Build; -import android.os.Parcel; -import android.os.Parcelable; -import android.os.Process; -import android.text.TextUtils; -import android.util.proto.ProtoOutputStream; - -import java.util.Objects; -import java.util.Set; - -/** - * Defines a request for a network, made through {@link NetworkRequest.Builder} and used - * to request a network via {@link ConnectivityManager#requestNetwork} or listen for changes - * via {@link ConnectivityManager#registerNetworkCallback}. - */ -public class NetworkRequest implements Parcelable { - /** - * The first requestId value that will be allocated. - * @hide only used by ConnectivityService. - */ - public static final int FIRST_REQUEST_ID = 1; - - /** - * The requestId value that represents the absence of a request. - * @hide only used by ConnectivityService. - */ - public static final int REQUEST_ID_NONE = -1; - - /** - * The {@link NetworkCapabilities} that define this request. - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public final @NonNull NetworkCapabilities networkCapabilities; - - /** - * Identifies the request. NetworkRequests should only be constructed by - * the Framework and given out to applications as tokens to be used to identify - * the request. - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public final int requestId; - - /** - * Set for legacy requests and the default. Set to TYPE_NONE for none. - * Causes CONNECTIVITY_ACTION broadcasts to be sent. - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) - public final int legacyType; - - /** - * A NetworkRequest as used by the system can be one of the following types: - * - * - LISTEN, for which the framework will issue callbacks about any - * and all networks that match the specified NetworkCapabilities, - * - * - REQUEST, capable of causing a specific network to be created - * first (e.g. a telephony DUN request), the framework will issue - * callbacks about the single, highest scoring current network - * (if any) that matches the specified NetworkCapabilities, or - * - * - TRACK_DEFAULT, a hybrid of the two designed such that the - * framework will issue callbacks for the single, highest scoring - * current network (if any) that matches the capabilities of the - * default Internet request (mDefaultRequest), but which cannot cause - * the framework to either create or retain the existence of any - * specific network. Note that from the point of view of the request - * matching code, TRACK_DEFAULT is identical to REQUEST: its special - * behaviour is not due to different semantics, but to the fact that - * the system will only ever create a TRACK_DEFAULT with capabilities - * that are identical to the default request's capabilities, thus - * causing it to share fate in every way with the default request. - * - * - BACKGROUND_REQUEST, like REQUEST but does not cause any networks - * to retain the NET_CAPABILITY_FOREGROUND capability. A network with - * no foreground requests is in the background. A network that has - * one or more background requests and loses its last foreground - * request to a higher-scoring network will not go into the - * background immediately, but will linger and go into the background - * after the linger timeout. - * - * - The value NONE is used only by applications. When an application - * creates a NetworkRequest, it does not have a type; the type is set - * by the system depending on the method used to file the request - * (requestNetwork, registerNetworkCallback, etc.). - * - * @hide - */ - public static enum Type { - NONE, - LISTEN, - TRACK_DEFAULT, - REQUEST, - BACKGROUND_REQUEST, - }; - - /** - * The type of the request. This is only used by the system and is always NONE elsewhere. - * - * @hide - */ - public final Type type; - - /** - * @hide - */ - public NetworkRequest(NetworkCapabilities nc, int legacyType, int rId, Type type) { - if (nc == null) { - throw new NullPointerException(); - } - requestId = rId; - networkCapabilities = nc; - this.legacyType = legacyType; - this.type = type; - } - - /** - * @hide - */ - public NetworkRequest(NetworkRequest that) { - networkCapabilities = new NetworkCapabilities(that.networkCapabilities); - requestId = that.requestId; - this.legacyType = that.legacyType; - this.type = that.type; - } - - /** - * Builder used to create {@link NetworkRequest} objects. Specify the Network features - * needed in terms of {@link NetworkCapabilities} features - */ - public static class Builder { - private final NetworkCapabilities mNetworkCapabilities; - - /** - * Default constructor for Builder. - */ - public Builder() { - // By default, restrict this request to networks available to this app. - // Apps can rescind this restriction, but ConnectivityService will enforce - // it for apps that do not have the NETWORK_SETTINGS permission. - mNetworkCapabilities = new NetworkCapabilities(); - mNetworkCapabilities.setSingleUid(Process.myUid()); - } - - /** - * Build {@link NetworkRequest} give the current set of capabilities. - */ - public NetworkRequest build() { - // Make a copy of mNetworkCapabilities so we don't inadvertently remove NOT_RESTRICTED - // when later an unrestricted capability could be added to mNetworkCapabilities, in - // which case NOT_RESTRICTED should be returned to mNetworkCapabilities, which - // maybeMarkCapabilitiesRestricted() doesn't add back. - final NetworkCapabilities nc = new NetworkCapabilities(mNetworkCapabilities); - nc.maybeMarkCapabilitiesRestricted(); - return new NetworkRequest(nc, ConnectivityManager.TYPE_NONE, - ConnectivityManager.REQUEST_ID_UNSET, Type.NONE); - } - - /** - * Add the given capability requirement to this builder. These represent - * the requested network's required capabilities. Note that when searching - * for a network to satisfy a request, all capabilities requested must be - * satisfied. - * - * @param capability The capability to add. - * @return The builder to facilitate chaining - * {@code builder.addCapability(...).addCapability();}. - */ - public Builder addCapability(@NetworkCapabilities.NetCapability int capability) { - mNetworkCapabilities.addCapability(capability); - return this; - } - - /** - * Removes (if found) the given capability from this builder instance. - * - * @param capability The capability to remove. - * @return The builder to facilitate chaining. - */ - public Builder removeCapability(@NetworkCapabilities.NetCapability int capability) { - mNetworkCapabilities.removeCapability(capability); - return this; - } - - /** - * Set the {@code NetworkCapabilities} for this builder instance, - * overriding any capabilities that had been previously set. - * - * @param nc The superseding {@code NetworkCapabilities} instance. - * @return The builder to facilitate chaining. - * @hide - */ - public Builder setCapabilities(NetworkCapabilities nc) { - mNetworkCapabilities.set(nc); - return this; - } - - /** - * Set the watched UIDs for this request. This will be reset and wiped out unless - * the calling app holds the CHANGE_NETWORK_STATE permission. - * - * @param uids The watched UIDs as a set of UidRanges, or null for everything. - * @return The builder to facilitate chaining. - * @hide - */ - public Builder setUids(Set uids) { - mNetworkCapabilities.setUids(uids); - return this; - } - - /** - * Add a capability that must not exist in the requested network. - *

- * If the capability was previously added to the list of required capabilities (for - * example, it was there by default or added using {@link #addCapability(int)} method), then - * it will be removed from the list of required capabilities as well. - * - * @see #addCapability(int) - * - * @param capability The capability to add to unwanted capability list. - * @return The builder to facilitate chaining. - * - * @hide - */ - public Builder addUnwantedCapability(@NetworkCapabilities.NetCapability int capability) { - mNetworkCapabilities.addUnwantedCapability(capability); - return this; - } - - /** - * Completely clears all the {@code NetworkCapabilities} from this builder instance, - * removing even the capabilities that are set by default when the object is constructed. - * - * @return The builder to facilitate chaining. - */ - @NonNull - public Builder clearCapabilities() { - mNetworkCapabilities.clearAll(); - return this; - } - - /** - * Adds the given transport requirement to this builder. These represent - * the set of allowed transports for the request. Only networks using one - * of these transports will satisfy the request. If no particular transports - * are required, none should be specified here. - * - * @param transportType The transport type to add. - * @return The builder to facilitate chaining. - */ - public Builder addTransportType(@NetworkCapabilities.Transport int transportType) { - mNetworkCapabilities.addTransportType(transportType); - return this; - } - - /** - * Removes (if found) the given transport from this builder instance. - * - * @param transportType The transport type to remove. - * @return The builder to facilitate chaining. - */ - public Builder removeTransportType(@NetworkCapabilities.Transport int transportType) { - mNetworkCapabilities.removeTransportType(transportType); - return this; - } - - /** - * @hide - */ - public Builder setLinkUpstreamBandwidthKbps(int upKbps) { - mNetworkCapabilities.setLinkUpstreamBandwidthKbps(upKbps); - return this; - } - /** - * @hide - */ - public Builder setLinkDownstreamBandwidthKbps(int downKbps) { - mNetworkCapabilities.setLinkDownstreamBandwidthKbps(downKbps); - return this; - } - - /** - * Sets the optional bearer specific network specifier. - * This has no meaning if a single transport is also not specified, so calling - * this without a single transport set will generate an exception, as will - * subsequently adding or removing transports after this is set. - *

- * If the {@code networkSpecifier} is provided, it shall be interpreted as follows: - *
    - *
  • If the specifier can be parsed as an integer, it will be treated as a - * {@link android.net TelephonyNetworkSpecifier}, and the provided integer will be - * interpreted as a SubscriptionId. - *
  • If the value is an ethernet interface name, it will be treated as such. - *
  • For all other cases, the behavior is undefined. - *
- * - * @param networkSpecifier A {@code String} of either a SubscriptionId in cellular - * network request or an ethernet interface name in ethernet - * network request. - * - * @deprecated Use {@link #setNetworkSpecifier(NetworkSpecifier)} instead. - */ - @Deprecated - public Builder setNetworkSpecifier(String networkSpecifier) { - try { - int subId = Integer.parseInt(networkSpecifier); - return setNetworkSpecifier(new TelephonyNetworkSpecifier.Builder() - .setSubscriptionId(subId).build()); - } catch (NumberFormatException nfe) { - // A StringNetworkSpecifier does not accept null or empty ("") strings. When network - // specifiers were strings a null string and an empty string were considered - // equivalent. Hence no meaning is attached to a null or empty ("") string. - return setNetworkSpecifier(TextUtils.isEmpty(networkSpecifier) ? null - : new StringNetworkSpecifier(networkSpecifier)); - } - } - - /** - * Sets the optional bearer specific network specifier. - * This has no meaning if a single transport is also not specified, so calling - * this without a single transport set will generate an exception, as will - * subsequently adding or removing transports after this is set. - *

- * - * @param networkSpecifier A concrete, parcelable framework class that extends - * NetworkSpecifier. - */ - public Builder setNetworkSpecifier(NetworkSpecifier networkSpecifier) { - if (networkSpecifier instanceof MatchAllNetworkSpecifier) { - throw new IllegalArgumentException("A MatchAllNetworkSpecifier is not permitted"); - } - mNetworkCapabilities.setNetworkSpecifier(networkSpecifier); - return this; - } - - /** - * Sets the signal strength. This is a signed integer, with higher values indicating a - * stronger signal. The exact units are bearer-dependent. For example, Wi-Fi uses the same - * RSSI units reported by WifiManager. - *

- * Note that when used to register a network callback, this specifies the minimum acceptable - * signal strength. When received as the state of an existing network it specifies the - * current value. A value of {@code SIGNAL_STRENGTH_UNSPECIFIED} means no value when - * received and has no effect when requesting a callback. - * - *

This method requires the caller to hold the - * {@link android.Manifest.permission#NETWORK_SIGNAL_STRENGTH_WAKEUP} permission - * - * @param signalStrength the bearer-specific signal strength. - * @hide - */ - @SystemApi - @RequiresPermission(android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP) - public @NonNull Builder setSignalStrength(int signalStrength) { - mNetworkCapabilities.setSignalStrength(signalStrength); - return this; - } - } - - // implement the Parcelable interface - public int describeContents() { - return 0; - } - public void writeToParcel(Parcel dest, int flags) { - networkCapabilities.writeToParcel(dest, flags); - dest.writeInt(legacyType); - dest.writeInt(requestId); - dest.writeString(type.name()); - } - - public static final @android.annotation.NonNull Creator CREATOR = - new Creator() { - public NetworkRequest createFromParcel(Parcel in) { - NetworkCapabilities nc = NetworkCapabilities.CREATOR.createFromParcel(in); - int legacyType = in.readInt(); - int requestId = in.readInt(); - Type type = Type.valueOf(in.readString()); // IllegalArgumentException if invalid. - NetworkRequest result = new NetworkRequest(nc, legacyType, requestId, type); - return result; - } - public NetworkRequest[] newArray(int size) { - return new NetworkRequest[size]; - } - }; - - /** - * Returns true iff. this NetworkRequest is of type LISTEN. - * - * @hide - */ - public boolean isListen() { - return type == Type.LISTEN; - } - - /** - * Returns true iff. the contained NetworkRequest is one that: - * - * - should be associated with at most one satisfying network - * at a time; - * - * - should cause a network to be kept up, but not necessarily in - * the foreground, if it is the best network which can satisfy the - * NetworkRequest. - * - * For full detail of how isRequest() is used for pairing Networks with - * NetworkRequests read rematchNetworkAndRequests(). - * - * @hide - */ - public boolean isRequest() { - return isForegroundRequest() || isBackgroundRequest(); - } - - /** - * Returns true iff. the contained NetworkRequest is one that: - * - * - should be associated with at most one satisfying network - * at a time; - * - * - should cause a network to be kept up and in the foreground if - * it is the best network which can satisfy the NetworkRequest. - * - * For full detail of how isRequest() is used for pairing Networks with - * NetworkRequests read rematchNetworkAndRequests(). - * - * @hide - */ - public boolean isForegroundRequest() { - return type == Type.TRACK_DEFAULT || type == Type.REQUEST; - } - - /** - * Returns true iff. this NetworkRequest is of type BACKGROUND_REQUEST. - * - * @hide - */ - public boolean isBackgroundRequest() { - return type == Type.BACKGROUND_REQUEST; - } - - /** - * @see Builder#addCapability(int) - */ - public boolean hasCapability(@NetCapability int capability) { - return networkCapabilities.hasCapability(capability); - } - - /** - * @see Builder#addUnwantedCapability(int) - * - * @hide - */ - public boolean hasUnwantedCapability(@NetCapability int capability) { - return networkCapabilities.hasUnwantedCapability(capability); - } - - /** - * Returns true if and only if the capabilities requested in this NetworkRequest are satisfied - * by the provided {@link NetworkCapabilities}. - * - * @param nc Capabilities that should satisfy this NetworkRequest. null capabilities do not - * satisfy any request. - */ - public boolean canBeSatisfiedBy(@Nullable NetworkCapabilities nc) { - return networkCapabilities.satisfiedByNetworkCapabilities(nc); - } - - /** - * @see Builder#addTransportType(int) - */ - public boolean hasTransport(@Transport int transportType) { - return networkCapabilities.hasTransport(transportType); - } - - /** - * @see Builder#setNetworkSpecifier(NetworkSpecifier) - */ - @Nullable - public NetworkSpecifier getNetworkSpecifier() { - return networkCapabilities.getNetworkSpecifier(); - } - - /** - * @return the uid of the app making the request. - * - * Note: This could return {@link Process#INVALID_UID} if the {@link NetworkRequest} object was - * not obtained from {@link ConnectivityManager}. - * @hide - */ - @SystemApi - public int getRequestorUid() { - return networkCapabilities.getRequestorUid(); - } - - /** - * @return the package name of the app making the request. - * - * Note: This could return {@code null} if the {@link NetworkRequest} object was not obtained - * from {@link ConnectivityManager}. - * @hide - */ - @SystemApi - @Nullable - public String getRequestorPackageName() { - return networkCapabilities.getRequestorPackageName(); - } - - public String toString() { - return "NetworkRequest [ " + type + " id=" + requestId + - (legacyType != ConnectivityManager.TYPE_NONE ? ", legacyType=" + legacyType : "") + - ", " + networkCapabilities.toString() + " ]"; - } - - private int typeToProtoEnum(Type t) { - switch (t) { - case NONE: - return NetworkRequestProto.TYPE_NONE; - case LISTEN: - return NetworkRequestProto.TYPE_LISTEN; - case TRACK_DEFAULT: - return NetworkRequestProto.TYPE_TRACK_DEFAULT; - case REQUEST: - return NetworkRequestProto.TYPE_REQUEST; - case BACKGROUND_REQUEST: - return NetworkRequestProto.TYPE_BACKGROUND_REQUEST; - default: - return NetworkRequestProto.TYPE_UNKNOWN; - } - } - - /** @hide */ - public void dumpDebug(ProtoOutputStream proto, long fieldId) { - final long token = proto.start(fieldId); - - proto.write(NetworkRequestProto.TYPE, typeToProtoEnum(type)); - proto.write(NetworkRequestProto.REQUEST_ID, requestId); - proto.write(NetworkRequestProto.LEGACY_TYPE, legacyType); - networkCapabilities.dumpDebug(proto, NetworkRequestProto.NETWORK_CAPABILITIES); - - proto.end(token); - } - - public boolean equals(Object obj) { - if (obj instanceof NetworkRequest == false) return false; - NetworkRequest that = (NetworkRequest)obj; - return (that.legacyType == this.legacyType && - that.requestId == this.requestId && - that.type == this.type && - Objects.equals(that.networkCapabilities, this.networkCapabilities)); - } - - public int hashCode() { - return Objects.hash(requestId, legacyType, networkCapabilities, type); - } -} diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java deleted file mode 100644 index 8be4af7b1396..000000000000 --- a/core/java/android/net/NetworkUtils.java +++ /dev/null @@ -1,425 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import android.compat.annotation.UnsupportedAppUsage; -import android.os.Build; -import android.system.ErrnoException; -import android.util.Log; -import android.util.Pair; - -import com.android.net.module.util.Inet4AddressUtils; - -import java.io.FileDescriptor; -import java.math.BigInteger; -import java.net.Inet4Address; -import java.net.InetAddress; -import java.net.SocketException; -import java.net.UnknownHostException; -import java.util.Locale; -import java.util.TreeSet; - -/** - * Native methods for managing network interfaces. - * - * {@hide} - */ -public class NetworkUtils { - - private static final String TAG = "NetworkUtils"; - - /** - * Attaches a socket filter that drops all of incoming packets. - * @param fd the socket's {@link FileDescriptor}. - */ - public static native void attachDropAllBPFFilter(FileDescriptor fd) throws SocketException; - - /** - * Detaches a socket filter. - * @param fd the socket's {@link FileDescriptor}. - */ - public static native void detachBPFFilter(FileDescriptor fd) throws SocketException; - - /** - * Binds the current process to the network designated by {@code netId}. All sockets created - * in the future (and not explicitly bound via a bound {@link SocketFactory} (see - * {@link Network#getSocketFactory}) will be bound to this network. Note that if this - * {@code Network} ever disconnects all sockets created in this way will cease to work. This - * is by design so an application doesn't accidentally use sockets it thinks are still bound to - * a particular {@code Network}. Passing NETID_UNSET clears the binding. - */ - public native static boolean bindProcessToNetwork(int netId); - - /** - * Return the netId last passed to {@link #bindProcessToNetwork}, or NETID_UNSET if - * {@link #unbindProcessToNetwork} has been called since {@link #bindProcessToNetwork}. - */ - public native static int getBoundNetworkForProcess(); - - /** - * Binds host resolutions performed by this process to the network designated by {@code netId}. - * {@link #bindProcessToNetwork} takes precedence over this setting. Passing NETID_UNSET clears - * the binding. - * - * @deprecated This is strictly for legacy usage to support startUsingNetworkFeature(). - */ - @Deprecated - public native static boolean bindProcessToNetworkForHostResolution(int netId); - - /** - * Explicitly binds {@code fd} to the network designated by {@code netId}. This - * overrides any binding via {@link #bindProcessToNetwork}. - * @return 0 on success or negative errno on failure. - */ - public static native int bindSocketToNetwork(FileDescriptor fd, int netId); - - /** - * Protect {@code fd} from VPN connections. After protecting, data sent through - * this socket will go directly to the underlying network, so its traffic will not be - * forwarded through the VPN. - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public static native boolean protectFromVpn(FileDescriptor fd); - - /** - * Protect {@code socketfd} from VPN connections. After protecting, data sent through - * this socket will go directly to the underlying network, so its traffic will not be - * forwarded through the VPN. - */ - public native static boolean protectFromVpn(int socketfd); - - /** - * Determine if {@code uid} can access network designated by {@code netId}. - * @return {@code true} if {@code uid} can access network, {@code false} otherwise. - */ - public native static boolean queryUserAccess(int uid, int netId); - - /** - * DNS resolver series jni method. - * Issue the query {@code msg} on the network designated by {@code netId}. - * {@code flags} is an additional config to control actual querying behavior. - * @return a file descriptor to watch for read events - */ - public static native FileDescriptor resNetworkSend( - int netId, byte[] msg, int msglen, int flags) throws ErrnoException; - - /** - * DNS resolver series jni method. - * Look up the {@code nsClass} {@code nsType} Resource Record (RR) associated - * with Domain Name {@code dname} on the network designated by {@code netId}. - * {@code flags} is an additional config to control actual querying behavior. - * @return a file descriptor to watch for read events - */ - public static native FileDescriptor resNetworkQuery( - int netId, String dname, int nsClass, int nsType, int flags) throws ErrnoException; - - /** - * DNS resolver series jni method. - * Read a result for the query associated with the {@code fd}. - * @return DnsResponse containing blob answer and rcode - */ - public static native DnsResolver.DnsResponse resNetworkResult(FileDescriptor fd) - throws ErrnoException; - - /** - * DNS resolver series jni method. - * Attempts to cancel the in-progress query associated with the {@code fd}. - */ - public static native void resNetworkCancel(FileDescriptor fd); - - /** - * DNS resolver series jni method. - * Attempts to get network which resolver will use if no network is explicitly selected. - */ - public static native Network getDnsNetwork() throws ErrnoException; - - /** - * Get the tcp repair window associated with the {@code fd}. - * - * @param fd the tcp socket's {@link FileDescriptor}. - * @return a {@link TcpRepairWindow} object indicates tcp window size. - */ - public static native TcpRepairWindow getTcpRepairWindow(FileDescriptor fd) - throws ErrnoException; - - /** - * @see Inet4AddressUtils#intToInet4AddressHTL(int) - * @deprecated Use either {@link Inet4AddressUtils#intToInet4AddressHTH(int)} - * or {@link Inet4AddressUtils#intToInet4AddressHTL(int)} - */ - @Deprecated - @UnsupportedAppUsage - public static InetAddress intToInetAddress(int hostAddress) { - return Inet4AddressUtils.intToInet4AddressHTL(hostAddress); - } - - /** - * @see Inet4AddressUtils#inet4AddressToIntHTL(Inet4Address) - * @deprecated Use either {@link Inet4AddressUtils#inet4AddressToIntHTH(Inet4Address)} - * or {@link Inet4AddressUtils#inet4AddressToIntHTL(Inet4Address)} - */ - @Deprecated - public static int inetAddressToInt(Inet4Address inetAddr) - throws IllegalArgumentException { - return Inet4AddressUtils.inet4AddressToIntHTL(inetAddr); - } - - /** - * @see Inet4AddressUtils#prefixLengthToV4NetmaskIntHTL(int) - * @deprecated Use either {@link Inet4AddressUtils#prefixLengthToV4NetmaskIntHTH(int)} - * or {@link Inet4AddressUtils#prefixLengthToV4NetmaskIntHTL(int)} - */ - @Deprecated - @UnsupportedAppUsage - public static int prefixLengthToNetmaskInt(int prefixLength) - throws IllegalArgumentException { - return Inet4AddressUtils.prefixLengthToV4NetmaskIntHTL(prefixLength); - } - - /** - * Convert a IPv4 netmask integer to a prefix length - * @param netmask as an integer (0xff000000 for a /8 subnet) - * @return the network prefix length - */ - public static int netmaskIntToPrefixLength(int netmask) { - return Integer.bitCount(netmask); - } - - /** - * Convert an IPv4 netmask to a prefix length, checking that the netmask is contiguous. - * @param netmask as a {@code Inet4Address}. - * @return the network prefix length - * @throws IllegalArgumentException the specified netmask was not contiguous. - * @hide - * @deprecated use {@link Inet4AddressUtils#netmaskToPrefixLength(Inet4Address)} - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @Deprecated - public static int netmaskToPrefixLength(Inet4Address netmask) { - // This is only here because some apps seem to be using it (@UnsupportedAppUsage). - return Inet4AddressUtils.netmaskToPrefixLength(netmask); - } - - - /** - * Create an InetAddress from a string where the string must be a standard - * representation of a V4 or V6 address. Avoids doing a DNS lookup on failure - * but it will throw an IllegalArgumentException in that case. - * @param addrString - * @return the InetAddress - * @hide - * @deprecated Use {@link InetAddresses#parseNumericAddress(String)}, if possible. - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) - @Deprecated - public static InetAddress numericToInetAddress(String addrString) - throws IllegalArgumentException { - return InetAddress.parseNumericAddress(addrString); - } - - /** - * Masks a raw IP address byte array with the specified prefix length. - */ - public static void maskRawAddress(byte[] array, int prefixLength) { - if (prefixLength < 0 || prefixLength > array.length * 8) { - throw new RuntimeException("IP address with " + array.length + - " bytes has invalid prefix length " + prefixLength); - } - - int offset = prefixLength / 8; - int remainder = prefixLength % 8; - byte mask = (byte)(0xFF << (8 - remainder)); - - if (offset < array.length) array[offset] = (byte)(array[offset] & mask); - - offset++; - - for (; offset < array.length; offset++) { - array[offset] = 0; - } - } - - /** - * Get InetAddress masked with prefixLength. Will never return null. - * @param address the IP address to mask with - * @param prefixLength the prefixLength used to mask the IP - */ - public static InetAddress getNetworkPart(InetAddress address, int prefixLength) { - byte[] array = address.getAddress(); - maskRawAddress(array, prefixLength); - - InetAddress netPart = null; - try { - netPart = InetAddress.getByAddress(array); - } catch (UnknownHostException e) { - throw new RuntimeException("getNetworkPart error - " + e.toString()); - } - return netPart; - } - - /** - * Returns the implicit netmask of an IPv4 address, as was the custom before 1993. - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public static int getImplicitNetmask(Inet4Address address) { - // Only here because it seems to be used by apps - return Inet4AddressUtils.getImplicitNetmask(address); - } - - /** - * Utility method to parse strings such as "192.0.2.5/24" or "2001:db8::cafe:d00d/64". - * @hide - */ - public static Pair parseIpAndMask(String ipAndMaskString) { - InetAddress address = null; - int prefixLength = -1; - try { - String[] pieces = ipAndMaskString.split("/", 2); - prefixLength = Integer.parseInt(pieces[1]); - address = InetAddress.parseNumericAddress(pieces[0]); - } catch (NullPointerException e) { // Null string. - } catch (ArrayIndexOutOfBoundsException e) { // No prefix length. - } catch (NumberFormatException e) { // Non-numeric prefix. - } catch (IllegalArgumentException e) { // Invalid IP address. - } - - if (address == null || prefixLength == -1) { - throw new IllegalArgumentException("Invalid IP address and mask " + ipAndMaskString); - } - - return new Pair(address, prefixLength); - } - - /** - * Convert a 32 char hex string into a Inet6Address. - * throws a runtime exception if the string isn't 32 chars, isn't hex or can't be - * made into an Inet6Address - * @param addrHexString a 32 character hex string representing an IPv6 addr - * @return addr an InetAddress representation for the string - */ - public static InetAddress hexToInet6Address(String addrHexString) - throws IllegalArgumentException { - try { - return numericToInetAddress(String.format(Locale.US, "%s:%s:%s:%s:%s:%s:%s:%s", - addrHexString.substring(0,4), addrHexString.substring(4,8), - addrHexString.substring(8,12), addrHexString.substring(12,16), - addrHexString.substring(16,20), addrHexString.substring(20,24), - addrHexString.substring(24,28), addrHexString.substring(28,32))); - } catch (Exception e) { - Log.e("NetworkUtils", "error in hexToInet6Address(" + addrHexString + "): " + e); - throw new IllegalArgumentException(e); - } - } - - /** - * Trim leading zeros from IPv4 address strings - * Our base libraries will interpret that as octel.. - * Must leave non v4 addresses and host names alone. - * For example, 192.168.000.010 -> 192.168.0.10 - * TODO - fix base libraries and remove this function - * @param addr a string representing an ip addr - * @return a string propertly trimmed - */ - @UnsupportedAppUsage - public static String trimV4AddrZeros(String addr) { - if (addr == null) return null; - String[] octets = addr.split("\\."); - if (octets.length != 4) return addr; - StringBuilder builder = new StringBuilder(16); - String result = null; - for (int i = 0; i < 4; i++) { - try { - if (octets[i].length() > 3) return addr; - builder.append(Integer.parseInt(octets[i])); - } catch (NumberFormatException e) { - return addr; - } - if (i < 3) builder.append('.'); - } - result = builder.toString(); - return result; - } - - /** - * Returns a prefix set without overlaps. - * - * This expects the src set to be sorted from shorter to longer. Results are undefined - * failing this condition. The returned prefix set is sorted in the same order as the - * passed set, with the same comparator. - */ - private static TreeSet deduplicatePrefixSet(final TreeSet src) { - final TreeSet dst = new TreeSet<>(src.comparator()); - // Prefixes match addresses that share their upper part up to their length, therefore - // the only kind of possible overlap in two prefixes is strict inclusion of the longer - // (more restrictive) in the shorter (including equivalence if they have the same - // length). - // Because prefixes in the src set are sorted from shorter to longer, deduplicating - // is done by simply iterating in order, and not adding any longer prefix that is - // already covered by a shorter one. - newPrefixes: - for (IpPrefix newPrefix : src) { - for (IpPrefix existingPrefix : dst) { - if (existingPrefix.containsPrefix(newPrefix)) { - continue newPrefixes; - } - } - dst.add(newPrefix); - } - return dst; - } - - /** - * Returns how many IPv4 addresses match any of the prefixes in the passed ordered set. - * - * Obviously this returns an integral value between 0 and 2**32. - * The behavior is undefined if any of the prefixes is not an IPv4 prefix or if the - * set is not ordered smallest prefix to longer prefix. - * - * @param prefixes the set of prefixes, ordered by length - */ - public static long routedIPv4AddressCount(final TreeSet prefixes) { - long routedIPCount = 0; - for (final IpPrefix prefix : deduplicatePrefixSet(prefixes)) { - if (!prefix.isIPv4()) { - Log.wtf(TAG, "Non-IPv4 prefix in routedIPv4AddressCount"); - } - int rank = 32 - prefix.getPrefixLength(); - routedIPCount += 1L << rank; - } - return routedIPCount; - } - - /** - * Returns how many IPv6 addresses match any of the prefixes in the passed ordered set. - * - * This returns a BigInteger between 0 and 2**128. - * The behavior is undefined if any of the prefixes is not an IPv6 prefix or if the - * set is not ordered smallest prefix to longer prefix. - */ - public static BigInteger routedIPv6AddressCount(final TreeSet prefixes) { - BigInteger routedIPCount = BigInteger.ZERO; - for (final IpPrefix prefix : deduplicatePrefixSet(prefixes)) { - if (!prefix.isIPv6()) { - Log.wtf(TAG, "Non-IPv6 prefix in routedIPv6AddressCount"); - } - int rank = 128 - prefix.getPrefixLength(); - routedIPCount = routedIPCount.add(BigInteger.ONE.shiftLeft(rank)); - } - return routedIPCount; - } - -} diff --git a/core/java/android/net/PacProxySelector.java b/core/java/android/net/PacProxySelector.java deleted file mode 100644 index 326943a27d4e..000000000000 --- a/core/java/android/net/PacProxySelector.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import android.os.ServiceManager; -import android.util.Log; - -import com.android.net.IProxyService; - -import com.google.android.collect.Lists; - -import java.io.IOException; -import java.net.InetSocketAddress; -import java.net.MalformedURLException; -import java.net.Proxy; -import java.net.Proxy.Type; -import java.net.ProxySelector; -import java.net.SocketAddress; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.List; - -/** - * @hide - */ -public class PacProxySelector extends ProxySelector { - private static final String TAG = "PacProxySelector"; - public static final String PROXY_SERVICE = "com.android.net.IProxyService"; - private static final String SOCKS = "SOCKS "; - private static final String PROXY = "PROXY "; - - private IProxyService mProxyService; - private final List mDefaultList; - - public PacProxySelector() { - mProxyService = IProxyService.Stub.asInterface( - ServiceManager.getService(PROXY_SERVICE)); - if (mProxyService == null) { - // Added because of b10267814 where mako is restarting. - Log.e(TAG, "PacProxyInstaller: no proxy service"); - } - mDefaultList = Lists.newArrayList(java.net.Proxy.NO_PROXY); - } - - @Override - public List select(URI uri) { - if (mProxyService == null) { - mProxyService = IProxyService.Stub.asInterface( - ServiceManager.getService(PROXY_SERVICE)); - } - if (mProxyService == null) { - Log.e(TAG, "select: no proxy service return NO_PROXY"); - return Lists.newArrayList(java.net.Proxy.NO_PROXY); - } - String response = null; - String urlString; - try { - // Strip path and username/password from URI so it's not visible to PAC script. The - // path often contains credentials the app does not want exposed to a potentially - // malicious PAC script. - if (!"http".equalsIgnoreCase(uri.getScheme())) { - uri = new URI(uri.getScheme(), null, uri.getHost(), uri.getPort(), "/", null, null); - } - urlString = uri.toURL().toString(); - } catch (URISyntaxException e) { - urlString = uri.getHost(); - } catch (MalformedURLException e) { - urlString = uri.getHost(); - } - try { - response = mProxyService.resolvePacFile(uri.getHost(), urlString); - } catch (Exception e) { - Log.e(TAG, "Error resolving PAC File", e); - } - if (response == null) { - return mDefaultList; - } - - return parseResponse(response); - } - - private static List parseResponse(String response) { - String[] split = response.split(";"); - List ret = Lists.newArrayList(); - for (String s : split) { - String trimmed = s.trim(); - if (trimmed.equals("DIRECT")) { - ret.add(java.net.Proxy.NO_PROXY); - } else if (trimmed.startsWith(PROXY)) { - Proxy proxy = proxyFromHostPort(Type.HTTP, trimmed.substring(PROXY.length())); - if (proxy != null) { - ret.add(proxy); - } - } else if (trimmed.startsWith(SOCKS)) { - Proxy proxy = proxyFromHostPort(Type.SOCKS, trimmed.substring(SOCKS.length())); - if (proxy != null) { - ret.add(proxy); - } - } - } - if (ret.size() == 0) { - ret.add(java.net.Proxy.NO_PROXY); - } - return ret; - } - - private static Proxy proxyFromHostPort(Proxy.Type type, String hostPortString) { - try { - String[] hostPort = hostPortString.split(":"); - String host = hostPort[0]; - int port = Integer.parseInt(hostPort[1]); - return new Proxy(type, InetSocketAddress.createUnresolved(host, port)); - } catch (NumberFormatException|ArrayIndexOutOfBoundsException e) { - Log.d(TAG, "Unable to parse proxy " + hostPortString + " " + e); - return null; - } - } - - @Override - public void connectFailed(URI uri, SocketAddress address, IOException failure) { - - } - -} diff --git a/core/java/android/net/Proxy.java b/core/java/android/net/Proxy.java deleted file mode 100644 index 03b07e080add..000000000000 --- a/core/java/android/net/Proxy.java +++ /dev/null @@ -1,294 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import android.annotation.SdkConstant; -import android.annotation.SdkConstant.SdkConstantType; -import android.compat.annotation.UnsupportedAppUsage; -import android.content.Context; -import android.os.Build; -import android.text.TextUtils; -import android.util.Log; - -import com.android.net.module.util.ProxyUtils; - -import java.net.InetSocketAddress; -import java.net.ProxySelector; -import java.net.URI; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * A convenience class for accessing the user and default proxy - * settings. - */ -public final class Proxy { - - private static final String TAG = "Proxy"; - - private static final ProxySelector sDefaultProxySelector; - - /** - * Used to notify an app that's caching the proxy that either the default - * connection has changed or any connection's proxy has changed. The new - * proxy should be queried using {@link ConnectivityManager#getDefaultProxy()}. - * - *

This is a protected intent that can only be sent by the system - */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String PROXY_CHANGE_ACTION = "android.intent.action.PROXY_CHANGE"; - /** - * Intent extra included with {@link #PROXY_CHANGE_ACTION} intents. - * It describes the new proxy being used (as a {@link ProxyInfo} object). - * @deprecated Because {@code PROXY_CHANGE_ACTION} is sent whenever the proxy - * for any network on the system changes, applications should always use - * {@link ConnectivityManager#getDefaultProxy()} or - * {@link ConnectivityManager#getLinkProperties(Network)}.{@link LinkProperties#getHttpProxy()} - * to get the proxy for the Network(s) they are using. - */ - @Deprecated - public static final String EXTRA_PROXY_INFO = "android.intent.extra.PROXY_INFO"; - - /** @hide */ - public static final int PROXY_VALID = 0; - /** @hide */ - public static final int PROXY_HOSTNAME_EMPTY = 1; - /** @hide */ - public static final int PROXY_HOSTNAME_INVALID = 2; - /** @hide */ - public static final int PROXY_PORT_EMPTY = 3; - /** @hide */ - public static final int PROXY_PORT_INVALID = 4; - /** @hide */ - public static final int PROXY_EXCLLIST_INVALID = 5; - - private static ConnectivityManager sConnectivityManager = null; - - // Hostname / IP REGEX validation - // Matches blank input, ips, and domain names - private static final String NAME_IP_REGEX = - "[a-zA-Z0-9]+(\\-[a-zA-Z0-9]+)*(\\.[a-zA-Z0-9]+(\\-[a-zA-Z0-9]+)*)*"; - - private static final String HOSTNAME_REGEXP = "^$|^" + NAME_IP_REGEX + "$"; - - private static final Pattern HOSTNAME_PATTERN; - - private static final String EXCL_REGEX = - "[a-zA-Z0-9*]+(\\-[a-zA-Z0-9*]+)*(\\.[a-zA-Z0-9*]+(\\-[a-zA-Z0-9*]+)*)*"; - - private static final String EXCLLIST_REGEXP = "^$|^" + EXCL_REGEX + "(," + EXCL_REGEX + ")*$"; - - private static final Pattern EXCLLIST_PATTERN; - - static { - HOSTNAME_PATTERN = Pattern.compile(HOSTNAME_REGEXP); - EXCLLIST_PATTERN = Pattern.compile(EXCLLIST_REGEXP); - sDefaultProxySelector = ProxySelector.getDefault(); - } - - /** - * Return the proxy object to be used for the URL given as parameter. - * @param ctx A Context used to get the settings for the proxy host. - * @param url A URL to be accessed. Used to evaluate exclusion list. - * @return Proxy (java.net) object containing the host name. If the - * user did not set a hostname it returns the default host. - * A null value means that no host is to be used. - * {@hide} - */ - @UnsupportedAppUsage - public static final java.net.Proxy getProxy(Context ctx, String url) { - String host = ""; - if ((url != null) && !isLocalHost(host)) { - URI uri = URI.create(url); - ProxySelector proxySelector = ProxySelector.getDefault(); - - List proxyList = proxySelector.select(uri); - - if (proxyList.size() > 0) { - return proxyList.get(0); - } - } - return java.net.Proxy.NO_PROXY; - } - - - /** - * Return the proxy host set by the user. - * @param ctx A Context used to get the settings for the proxy host. - * @return String containing the host name. If the user did not set a host - * name it returns the default host. A null value means that no - * host is to be used. - * @deprecated Use standard java vm proxy values to find the host, port - * and exclusion list. This call ignores the exclusion list. - */ - @Deprecated - public static final String getHost(Context ctx) { - java.net.Proxy proxy = getProxy(ctx, null); - if (proxy == java.net.Proxy.NO_PROXY) return null; - try { - return ((InetSocketAddress)(proxy.address())).getHostName(); - } catch (Exception e) { - return null; - } - } - - /** - * Return the proxy port set by the user. - * @param ctx A Context used to get the settings for the proxy port. - * @return The port number to use or -1 if no proxy is to be used. - * @deprecated Use standard java vm proxy values to find the host, port - * and exclusion list. This call ignores the exclusion list. - */ - @Deprecated - public static final int getPort(Context ctx) { - java.net.Proxy proxy = getProxy(ctx, null); - if (proxy == java.net.Proxy.NO_PROXY) return -1; - try { - return ((InetSocketAddress)(proxy.address())).getPort(); - } catch (Exception e) { - return -1; - } - } - - /** - * Return the default proxy host specified by the carrier. - * @return String containing the host name or null if there is no proxy for - * this carrier. - * @deprecated Use standard java vm proxy values to find the host, port and - * exclusion list. This call ignores the exclusion list and no - * longer reports only mobile-data apn-based proxy values. - */ - @Deprecated - public static final String getDefaultHost() { - String host = System.getProperty("http.proxyHost"); - if (TextUtils.isEmpty(host)) return null; - return host; - } - - /** - * Return the default proxy port specified by the carrier. - * @return The port number to be used with the proxy host or -1 if there is - * no proxy for this carrier. - * @deprecated Use standard java vm proxy values to find the host, port and - * exclusion list. This call ignores the exclusion list and no - * longer reports only mobile-data apn-based proxy values. - */ - @Deprecated - public static final int getDefaultPort() { - if (getDefaultHost() == null) return -1; - try { - return Integer.parseInt(System.getProperty("http.proxyPort")); - } catch (NumberFormatException e) { - return -1; - } - } - - private static final boolean isLocalHost(String host) { - if (host == null) { - return false; - } - try { - if (host != null) { - if (host.equalsIgnoreCase("localhost")) { - return true; - } - if (InetAddresses.parseNumericAddress(host).isLoopbackAddress()) { - return true; - } - } - } catch (IllegalArgumentException iex) { - } - return false; - } - - /** - * Validate syntax of hostname, port and exclusion list entries - * {@hide} - */ - public static int validate(String hostname, String port, String exclList) { - Matcher match = HOSTNAME_PATTERN.matcher(hostname); - Matcher listMatch = EXCLLIST_PATTERN.matcher(exclList); - - if (!match.matches()) return PROXY_HOSTNAME_INVALID; - - if (!listMatch.matches()) return PROXY_EXCLLIST_INVALID; - - if (hostname.length() > 0 && port.length() == 0) return PROXY_PORT_EMPTY; - - if (port.length() > 0) { - if (hostname.length() == 0) return PROXY_HOSTNAME_EMPTY; - int portVal = -1; - try { - portVal = Integer.parseInt(port); - } catch (NumberFormatException ex) { - return PROXY_PORT_INVALID; - } - if (portVal <= 0 || portVal > 0xFFFF) return PROXY_PORT_INVALID; - } - return PROXY_VALID; - } - - /** @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public static final void setHttpProxySystemProperty(ProxyInfo p) { - String host = null; - String port = null; - String exclList = null; - Uri pacFileUrl = Uri.EMPTY; - if (p != null) { - host = p.getHost(); - port = Integer.toString(p.getPort()); - exclList = ProxyUtils.exclusionListAsString(p.getExclusionList()); - pacFileUrl = p.getPacFileUrl(); - } - setHttpProxySystemProperty(host, port, exclList, pacFileUrl); - } - - /** @hide */ - public static final void setHttpProxySystemProperty(String host, String port, String exclList, - Uri pacFileUrl) { - if (exclList != null) exclList = exclList.replace(",", "|"); - if (false) Log.d(TAG, "setHttpProxySystemProperty :"+host+":"+port+" - "+exclList); - if (host != null) { - System.setProperty("http.proxyHost", host); - System.setProperty("https.proxyHost", host); - } else { - System.clearProperty("http.proxyHost"); - System.clearProperty("https.proxyHost"); - } - if (port != null) { - System.setProperty("http.proxyPort", port); - System.setProperty("https.proxyPort", port); - } else { - System.clearProperty("http.proxyPort"); - System.clearProperty("https.proxyPort"); - } - if (exclList != null) { - System.setProperty("http.nonProxyHosts", exclList); - System.setProperty("https.nonProxyHosts", exclList); - } else { - System.clearProperty("http.nonProxyHosts"); - System.clearProperty("https.nonProxyHosts"); - } - if (!Uri.EMPTY.equals(pacFileUrl)) { - ProxySelector.setDefault(new PacProxySelector()); - } else { - ProxySelector.setDefault(sDefaultProxySelector); - } - } -} diff --git a/core/java/android/net/ProxyInfo.aidl b/core/java/android/net/ProxyInfo.aidl deleted file mode 100644 index a5d0c120e747..000000000000 --- a/core/java/android/net/ProxyInfo.aidl +++ /dev/null @@ -1,21 +0,0 @@ -/* -** -** Copyright (C) 2010 The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -package android.net; - -@JavaOnlyStableParcelable parcelable ProxyInfo; - diff --git a/core/java/android/net/ProxyInfo.java b/core/java/android/net/ProxyInfo.java deleted file mode 100644 index c9bca2876b0a..000000000000 --- a/core/java/android/net/ProxyInfo.java +++ /dev/null @@ -1,367 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.compat.annotation.UnsupportedAppUsage; -import android.os.Parcel; -import android.os.Parcelable; -import android.text.TextUtils; - -import java.net.InetSocketAddress; -import java.net.URLConnection; -import java.util.List; -import java.util.Locale; - -/** - * Describes a proxy configuration. - * - * Proxy configurations are already integrated within the {@code java.net} and - * Apache HTTP stack. So {@link URLConnection} and Apache's {@code HttpClient} will use - * them automatically. - * - * Other HTTP stacks will need to obtain the proxy info from - * {@link Proxy#PROXY_CHANGE_ACTION} broadcast as the extra {@link Proxy#EXTRA_PROXY_INFO}. - */ -public class ProxyInfo implements Parcelable { - - private final String mHost; - private final int mPort; - private final String mExclusionList; - private final String[] mParsedExclusionList; - private final Uri mPacFileUrl; - - /** - *@hide - */ - public static final String LOCAL_EXCL_LIST = ""; - /** - *@hide - */ - public static final int LOCAL_PORT = -1; - /** - *@hide - */ - public static final String LOCAL_HOST = "localhost"; - - /** - * Constructs a {@link ProxyInfo} object that points at a Direct proxy - * on the specified host and port. - */ - public static ProxyInfo buildDirectProxy(String host, int port) { - return new ProxyInfo(host, port, null); - } - - /** - * Constructs a {@link ProxyInfo} object that points at a Direct proxy - * on the specified host and port. - * - * The proxy will not be used to access any host in exclusion list, exclList. - * - * @param exclList Hosts to exclude using the proxy on connections for. These - * hosts can use wildcards such as *.example.com. - */ - public static ProxyInfo buildDirectProxy(String host, int port, List exclList) { - String[] array = exclList.toArray(new String[exclList.size()]); - return new ProxyInfo(host, port, TextUtils.join(",", array), array); - } - - /** - * Construct a {@link ProxyInfo} that will download and run the PAC script - * at the specified URL. - */ - public static ProxyInfo buildPacProxy(Uri pacUri) { - return new ProxyInfo(pacUri); - } - - /** - * Construct a {@link ProxyInfo} object that will download and run the PAC script at the - * specified URL and port. - */ - @NonNull - public static ProxyInfo buildPacProxy(@NonNull Uri pacUrl, int port) { - return new ProxyInfo(pacUrl, port); - } - - /** - * Create a ProxyProperties that points at a HTTP Proxy. - * @hide - */ - @UnsupportedAppUsage - public ProxyInfo(String host, int port, String exclList) { - mHost = host; - mPort = port; - mExclusionList = exclList; - mParsedExclusionList = parseExclusionList(mExclusionList); - mPacFileUrl = Uri.EMPTY; - } - - /** - * Create a ProxyProperties that points at a PAC URL. - * @hide - */ - public ProxyInfo(@NonNull Uri pacFileUrl) { - mHost = LOCAL_HOST; - mPort = LOCAL_PORT; - mExclusionList = LOCAL_EXCL_LIST; - mParsedExclusionList = parseExclusionList(mExclusionList); - if (pacFileUrl == null) { - throw new NullPointerException(); - } - mPacFileUrl = pacFileUrl; - } - - /** - * Only used in PacProxyInstaller after Local Proxy is bound. - * @hide - */ - public ProxyInfo(@NonNull Uri pacFileUrl, int localProxyPort) { - mHost = LOCAL_HOST; - mPort = localProxyPort; - mExclusionList = LOCAL_EXCL_LIST; - mParsedExclusionList = parseExclusionList(mExclusionList); - if (pacFileUrl == null) { - throw new NullPointerException(); - } - mPacFileUrl = pacFileUrl; - } - - private static String[] parseExclusionList(String exclusionList) { - if (exclusionList == null) { - return new String[0]; - } else { - return exclusionList.toLowerCase(Locale.ROOT).split(","); - } - } - - private ProxyInfo(String host, int port, String exclList, String[] parsedExclList) { - mHost = host; - mPort = port; - mExclusionList = exclList; - mParsedExclusionList = parsedExclList; - mPacFileUrl = Uri.EMPTY; - } - - /** - * A copy constructor to hold proxy properties. - */ - public ProxyInfo(@Nullable ProxyInfo source) { - if (source != null) { - mHost = source.getHost(); - mPort = source.getPort(); - mPacFileUrl = source.mPacFileUrl; - mExclusionList = source.getExclusionListAsString(); - mParsedExclusionList = source.mParsedExclusionList; - } else { - mHost = null; - mPort = 0; - mExclusionList = null; - mParsedExclusionList = null; - mPacFileUrl = Uri.EMPTY; - } - } - - /** - * @hide - */ - public InetSocketAddress getSocketAddress() { - InetSocketAddress inetSocketAddress = null; - try { - inetSocketAddress = new InetSocketAddress(mHost, mPort); - } catch (IllegalArgumentException e) { } - return inetSocketAddress; - } - - /** - * Returns the URL of the current PAC script or null if there is - * no PAC script. - */ - public Uri getPacFileUrl() { - return mPacFileUrl; - } - - /** - * When configured to use a Direct Proxy this returns the host - * of the proxy. - */ - public String getHost() { - return mHost; - } - - /** - * When configured to use a Direct Proxy this returns the port - * of the proxy - */ - public int getPort() { - return mPort; - } - - /** - * When configured to use a Direct Proxy this returns the list - * of hosts for which the proxy is ignored. - */ - public String[] getExclusionList() { - return mParsedExclusionList; - } - - /** - * comma separated - * @hide - */ - @Nullable - public String getExclusionListAsString() { - return mExclusionList; - } - - /** - * Return true if the pattern of proxy is valid, otherwise return false. - */ - public boolean isValid() { - if (!Uri.EMPTY.equals(mPacFileUrl)) return true; - return Proxy.PROXY_VALID == Proxy.validate(mHost == null ? "" : mHost, - mPort == 0 ? "" : Integer.toString(mPort), - mExclusionList == null ? "" : mExclusionList); - } - - /** - * @hide - */ - public java.net.Proxy makeProxy() { - java.net.Proxy proxy = java.net.Proxy.NO_PROXY; - if (mHost != null) { - try { - InetSocketAddress inetSocketAddress = new InetSocketAddress(mHost, mPort); - proxy = new java.net.Proxy(java.net.Proxy.Type.HTTP, inetSocketAddress); - } catch (IllegalArgumentException e) { - } - } - return proxy; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - if (!Uri.EMPTY.equals(mPacFileUrl)) { - sb.append("PAC Script: "); - sb.append(mPacFileUrl); - } - if (mHost != null) { - sb.append("["); - sb.append(mHost); - sb.append("] "); - sb.append(Integer.toString(mPort)); - if (mExclusionList != null) { - sb.append(" xl=").append(mExclusionList); - } - } else { - sb.append("[ProxyProperties.mHost == null]"); - } - return sb.toString(); - } - - @Override - public boolean equals(Object o) { - if (!(o instanceof ProxyInfo)) return false; - ProxyInfo p = (ProxyInfo)o; - // If PAC URL is present in either then they must be equal. - // Other parameters will only be for fall back. - if (!Uri.EMPTY.equals(mPacFileUrl)) { - return mPacFileUrl.equals(p.getPacFileUrl()) && mPort == p.mPort; - } - if (!Uri.EMPTY.equals(p.mPacFileUrl)) { - return false; - } - if (mExclusionList != null && !mExclusionList.equals(p.getExclusionListAsString())) { - return false; - } - if (mHost != null && p.getHost() != null && mHost.equals(p.getHost()) == false) { - return false; - } - if (mHost != null && p.mHost == null) return false; - if (mHost == null && p.mHost != null) return false; - if (mPort != p.mPort) return false; - return true; - } - - /** - * Implement the Parcelable interface - * @hide - */ - public int describeContents() { - return 0; - } - - @Override - /* - * generate hashcode based on significant fields - */ - public int hashCode() { - return ((null == mHost) ? 0 : mHost.hashCode()) - + ((null == mExclusionList) ? 0 : mExclusionList.hashCode()) - + mPort; - } - - /** - * Implement the Parcelable interface. - * @hide - */ - public void writeToParcel(Parcel dest, int flags) { - if (!Uri.EMPTY.equals(mPacFileUrl)) { - dest.writeByte((byte)1); - mPacFileUrl.writeToParcel(dest, 0); - dest.writeInt(mPort); - return; - } else { - dest.writeByte((byte)0); - } - if (mHost != null) { - dest.writeByte((byte)1); - dest.writeString(mHost); - dest.writeInt(mPort); - } else { - dest.writeByte((byte)0); - } - dest.writeString(mExclusionList); - dest.writeStringArray(mParsedExclusionList); - } - - public static final @android.annotation.NonNull Creator CREATOR = - new Creator() { - public ProxyInfo createFromParcel(Parcel in) { - String host = null; - int port = 0; - if (in.readByte() != 0) { - Uri url = Uri.CREATOR.createFromParcel(in); - int localPort = in.readInt(); - return new ProxyInfo(url, localPort); - } - if (in.readByte() != 0) { - host = in.readString(); - port = in.readInt(); - } - String exclList = in.readString(); - String[] parsedExclList = in.createStringArray(); - ProxyInfo proxyProperties = new ProxyInfo(host, port, exclList, parsedExclList); - return proxyProperties; - } - - public ProxyInfo[] newArray(int size) { - return new ProxyInfo[size]; - } - }; -} diff --git a/core/java/android/net/RouteInfo.aidl b/core/java/android/net/RouteInfo.aidl deleted file mode 100644 index 7af9fdaef342..000000000000 --- a/core/java/android/net/RouteInfo.aidl +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -@JavaOnlyStableParcelable parcelable RouteInfo; diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java deleted file mode 100644 index 94f849f006f3..000000000000 --- a/core/java/android/net/RouteInfo.java +++ /dev/null @@ -1,658 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.SystemApi; -import android.compat.annotation.UnsupportedAppUsage; -import android.os.Build; -import android.os.Parcel; -import android.os.Parcelable; - -import com.android.net.module.util.NetUtils; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.net.Inet4Address; -import java.net.Inet6Address; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.Collection; -import java.util.Objects; - -/** - * Represents a network route. - *

- * This is used both to describe static network configuration and live network - * configuration information. - * - * A route contains three pieces of information: - *

    - *
  • a destination {@link IpPrefix} specifying the network destinations covered by this route. - * If this is {@code null} it indicates a default route of the address family (IPv4 or IPv6) - * implied by the gateway IP address. - *
  • a gateway {@link InetAddress} indicating the next hop to use. If this is {@code null} it - * indicates a directly-connected route. - *
  • an interface (which may be unspecified). - *
- * Either the destination or the gateway may be {@code null}, but not both. If the - * destination and gateway are both specified, they must be of the same address family - * (IPv4 or IPv6). - */ -public final class RouteInfo implements Parcelable { - /** @hide */ - @IntDef(value = { - RTN_UNICAST, - RTN_UNREACHABLE, - RTN_THROW, - }) - @Retention(RetentionPolicy.SOURCE) - public @interface RouteType {} - - /** - * The IP destination address for this route. - */ - @NonNull - private final IpPrefix mDestination; - - /** - * The gateway address for this route. - */ - @UnsupportedAppUsage - @Nullable - private final InetAddress mGateway; - - /** - * The interface for this route. - */ - @Nullable - private final String mInterface; - - - /** Unicast route. @hide */ - @SystemApi - public static final int RTN_UNICAST = 1; - - /** Unreachable route. @hide */ - @SystemApi - public static final int RTN_UNREACHABLE = 7; - - /** Throw route. @hide */ - @SystemApi - public static final int RTN_THROW = 9; - - /** - * The type of this route; one of the RTN_xxx constants above. - */ - private final int mType; - - /** - * The maximum transmission unit size for this route. - */ - private final int mMtu; - - // Derived data members. - // TODO: remove these. - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) - private final boolean mIsHost; - private final boolean mHasGateway; - - /** - * Constructs a RouteInfo object. - * - * If destination is null, then gateway must be specified and the - * constructed route is either the IPv4 default route 0.0.0.0 - * if the gateway is an instance of {@link Inet4Address}, or the IPv6 default - * route ::/0 if gateway is an instance of - * {@link Inet6Address}. - *

- * destination and gateway may not both be null. - * - * @param destination the destination prefix - * @param gateway the IP address to route packets through - * @param iface the interface name to send packets on - * @param type the type of this route - * - * @hide - */ - @SystemApi - public RouteInfo(@Nullable IpPrefix destination, @Nullable InetAddress gateway, - @Nullable String iface, @RouteType int type) { - this(destination, gateway, iface, type, 0); - } - - /** - * Constructs a RouteInfo object. - * - * If destination is null, then gateway must be specified and the - * constructed route is either the IPv4 default route 0.0.0.0 - * if the gateway is an instance of {@link Inet4Address}, or the IPv6 default - * route ::/0 if gateway is an instance of - * {@link Inet6Address}. - *

- * destination and gateway may not both be null. - * - * @param destination the destination prefix - * @param gateway the IP address to route packets through - * @param iface the interface name to send packets on - * @param type the type of this route - * @param mtu the maximum transmission unit size for this route - * - * @hide - */ - @SystemApi - public RouteInfo(@Nullable IpPrefix destination, @Nullable InetAddress gateway, - @Nullable String iface, @RouteType int type, int mtu) { - switch (type) { - case RTN_UNICAST: - case RTN_UNREACHABLE: - case RTN_THROW: - // TODO: It would be nice to ensure that route types that don't have nexthops or - // interfaces, such as unreachable or throw, can't be created if an interface or - // a gateway is specified. This is a bit too complicated to do at the moment - // because: - // - // - LinkProperties sets the interface on routes added to it, and modifies the - // interfaces of all the routes when its interface name changes. - // - Even when the gateway is null, we store a non-null gateway here. - // - // For now, we just rely on the code that sets routes to do things properly. - break; - default: - throw new IllegalArgumentException("Unknown route type " + type); - } - - if (destination == null) { - if (gateway != null) { - if (gateway instanceof Inet4Address) { - destination = new IpPrefix(Inet4Address.ANY, 0); - } else { - destination = new IpPrefix(Inet6Address.ANY, 0); - } - } else { - // no destination, no gateway. invalid. - throw new IllegalArgumentException("Invalid arguments passed in: " + gateway + "," + - destination); - } - } - // TODO: set mGateway to null if there is no gateway. This is more correct, saves space, and - // matches the documented behaviour. Before we can do this we need to fix all callers (e.g., - // ConnectivityService) to stop doing things like r.getGateway().equals(), ... . - if (gateway == null) { - if (destination.getAddress() instanceof Inet4Address) { - gateway = Inet4Address.ANY; - } else { - gateway = Inet6Address.ANY; - } - } - mHasGateway = (!gateway.isAnyLocalAddress()); - - if ((destination.getAddress() instanceof Inet4Address - && !(gateway instanceof Inet4Address)) - || (destination.getAddress() instanceof Inet6Address - && !(gateway instanceof Inet6Address))) { - throw new IllegalArgumentException("address family mismatch in RouteInfo constructor"); - } - mDestination = destination; // IpPrefix objects are immutable. - mGateway = gateway; // InetAddress objects are immutable. - mInterface = iface; // Strings are immutable. - mType = type; - mIsHost = isHost(); - mMtu = mtu; - } - - /** - * Constructs a {@code RouteInfo} object. - * - * If destination is null, then gateway must be specified and the - * constructed route is either the IPv4 default route 0.0.0.0 - * if the gateway is an instance of {@link Inet4Address}, or the IPv6 default - * route ::/0 if gateway is an instance of {@link Inet6Address}. - *

- * Destination and gateway may not both be null. - * - * @param destination the destination address and prefix in an {@link IpPrefix} - * @param gateway the {@link InetAddress} to route packets through - * @param iface the interface name to send packets on - * - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public RouteInfo(@Nullable IpPrefix destination, @Nullable InetAddress gateway, - @Nullable String iface) { - this(destination, gateway, iface, RTN_UNICAST); - } - - /** - * @hide - */ - @UnsupportedAppUsage - public RouteInfo(@Nullable LinkAddress destination, @Nullable InetAddress gateway, - @Nullable String iface) { - this(destination == null ? null : - new IpPrefix(destination.getAddress(), destination.getPrefixLength()), - gateway, iface); - } - - /** - * Constructs a {@code RouteInfo} object. - * - * If destination is null, then gateway must be specified and the - * constructed route is either the IPv4 default route 0.0.0.0 - * if the gateway is an instance of {@link Inet4Address}, or the IPv6 default - * route ::/0 if gateway is an instance of {@link Inet6Address}. - *

- * Destination and gateway may not both be null. - * - * @param destination the destination address and prefix in an {@link IpPrefix} - * @param gateway the {@link InetAddress} to route packets through - * - * @hide - */ - public RouteInfo(@Nullable IpPrefix destination, @Nullable InetAddress gateway) { - this(destination, gateway, null); - } - - /** - * @hide - * - * TODO: Remove this. - */ - @UnsupportedAppUsage - public RouteInfo(@Nullable LinkAddress destination, @Nullable InetAddress gateway) { - this(destination, gateway, null); - } - - /** - * Constructs a default {@code RouteInfo} object. - * - * @param gateway the {@link InetAddress} to route packets through - * - * @hide - */ - @UnsupportedAppUsage - public RouteInfo(@NonNull InetAddress gateway) { - this((IpPrefix) null, gateway, null); - } - - /** - * Constructs a {@code RouteInfo} object representing a direct connected subnet. - * - * @param destination the {@link IpPrefix} describing the address and prefix - * length of the subnet. - * - * @hide - */ - public RouteInfo(@NonNull IpPrefix destination) { - this(destination, null, null); - } - - /** - * @hide - */ - public RouteInfo(@NonNull LinkAddress destination) { - this(destination, null, null); - } - - /** - * @hide - */ - public RouteInfo(@NonNull IpPrefix destination, @RouteType int type) { - this(destination, null, null, type); - } - - /** - * @hide - */ - public static RouteInfo makeHostRoute(@NonNull InetAddress host, @Nullable String iface) { - return makeHostRoute(host, null, iface); - } - - /** - * @hide - */ - public static RouteInfo makeHostRoute(@Nullable InetAddress host, @Nullable InetAddress gateway, - @Nullable String iface) { - if (host == null) return null; - - if (host instanceof Inet4Address) { - return new RouteInfo(new IpPrefix(host, 32), gateway, iface); - } else { - return new RouteInfo(new IpPrefix(host, 128), gateway, iface); - } - } - - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) - private boolean isHost() { - return (mDestination.getAddress() instanceof Inet4Address && - mDestination.getPrefixLength() == 32) || - (mDestination.getAddress() instanceof Inet6Address && - mDestination.getPrefixLength() == 128); - } - - /** - * Retrieves the destination address and prefix length in the form of an {@link IpPrefix}. - * - * @return {@link IpPrefix} specifying the destination. This is never {@code null}. - */ - @NonNull - public IpPrefix getDestination() { - return mDestination; - } - - /** - * TODO: Convert callers to use IpPrefix and then remove. - * @hide - */ - @NonNull - public LinkAddress getDestinationLinkAddress() { - return new LinkAddress(mDestination.getAddress(), mDestination.getPrefixLength()); - } - - /** - * Retrieves the gateway or next hop {@link InetAddress} for this route. - * - * @return {@link InetAddress} specifying the gateway or next hop. This may be - * {@code null} for a directly-connected route." - */ - @Nullable - public InetAddress getGateway() { - return mGateway; - } - - /** - * Retrieves the interface used for this route if specified, else {@code null}. - * - * @return The name of the interface used for this route. - */ - @Nullable - public String getInterface() { - return mInterface; - } - - /** - * Retrieves the type of this route. - * - * @return The type of this route; one of the {@code RTN_xxx} constants defined in this class. - * - * @hide - */ - @SystemApi - @RouteType - public int getType() { - return mType; - } - - /** - * Retrieves the MTU size for this route. - * - * @return The MTU size, or 0 if it has not been set. - * @hide - */ - @SystemApi - public int getMtu() { - return mMtu; - } - - /** - * Indicates if this route is a default route (ie, has no destination specified). - * - * @return {@code true} if the destination has a prefix length of 0. - */ - public boolean isDefaultRoute() { - return mType == RTN_UNICAST && mDestination.getPrefixLength() == 0; - } - - /** - * Indicates if this route is an unreachable default route. - * - * @return {@code true} if it's an unreachable route with prefix length of 0. - * @hide - */ - private boolean isUnreachableDefaultRoute() { - return mType == RTN_UNREACHABLE && mDestination.getPrefixLength() == 0; - } - - /** - * Indicates if this route is an IPv4 default route. - * @hide - */ - public boolean isIPv4Default() { - return isDefaultRoute() && mDestination.getAddress() instanceof Inet4Address; - } - - /** - * Indicates if this route is an IPv4 unreachable default route. - * @hide - */ - public boolean isIPv4UnreachableDefault() { - return isUnreachableDefaultRoute() && mDestination.getAddress() instanceof Inet4Address; - } - - /** - * Indicates if this route is an IPv6 default route. - * @hide - */ - public boolean isIPv6Default() { - return isDefaultRoute() && mDestination.getAddress() instanceof Inet6Address; - } - - /** - * Indicates if this route is an IPv6 unreachable default route. - * @hide - */ - public boolean isIPv6UnreachableDefault() { - return isUnreachableDefaultRoute() && mDestination.getAddress() instanceof Inet6Address; - } - - /** - * Indicates if this route is a host route (ie, matches only a single host address). - * - * @return {@code true} if the destination has a prefix length of 32 or 128 for IPv4 or IPv6, - * respectively. - * @hide - */ - public boolean isHostRoute() { - return mIsHost; - } - - /** - * Indicates if this route has a next hop ({@code true}) or is directly-connected - * ({@code false}). - * - * @return {@code true} if a gateway is specified - */ - public boolean hasGateway() { - return mHasGateway; - } - - /** - * Determines whether the destination and prefix of this route includes the specified - * address. - * - * @param destination A {@link InetAddress} to test to see if it would match this route. - * @return {@code true} if the destination and prefix length cover the given address. - */ - public boolean matches(InetAddress destination) { - return mDestination.contains(destination); - } - - /** - * Find the route from a Collection of routes that best matches a given address. - * May return null if no routes are applicable. - * @param routes a Collection of RouteInfos to chose from - * @param dest the InetAddress your trying to get to - * @return the RouteInfo from the Collection that best fits the given address - * - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @Nullable - public static RouteInfo selectBestRoute(Collection routes, InetAddress dest) { - return NetUtils.selectBestRoute(routes, dest); - } - - /** - * Returns a human-readable description of this object. - */ - public String toString() { - String val = ""; - if (mDestination != null) val = mDestination.toString(); - if (mType == RTN_UNREACHABLE) { - val += " unreachable"; - } else if (mType == RTN_THROW) { - val += " throw"; - } else { - val += " ->"; - if (mGateway != null) val += " " + mGateway.getHostAddress(); - if (mInterface != null) val += " " + mInterface; - if (mType != RTN_UNICAST) { - val += " unknown type " + mType; - } - } - val += " mtu " + mMtu; - return val; - } - - /** - * Compares this RouteInfo object against the specified object and indicates if they are equal. - * @return {@code true} if the objects are equal, {@code false} otherwise. - */ - public boolean equals(Object obj) { - if (this == obj) return true; - - if (!(obj instanceof RouteInfo)) return false; - - RouteInfo target = (RouteInfo) obj; - - return Objects.equals(mDestination, target.getDestination()) && - Objects.equals(mGateway, target.getGateway()) && - Objects.equals(mInterface, target.getInterface()) && - mType == target.getType() && mMtu == target.getMtu(); - } - - /** - * A helper class that contains the destination, the gateway and the interface in a - * {@code RouteInfo}, used by {@link ConnectivityService#updateRoutes} or - * {@link LinkProperties#addRoute} to calculate the list to be updated. - * {@code RouteInfo} objects with different interfaces are treated as different routes because - * *usually* on Android different interfaces use different routing tables, and moving a route - * to a new routing table never constitutes an update, but is always a remove and an add. - * - * @hide - */ - public static class RouteKey { - @NonNull private final IpPrefix mDestination; - @Nullable private final InetAddress mGateway; - @Nullable private final String mInterface; - - RouteKey(@NonNull IpPrefix destination, @Nullable InetAddress gateway, - @Nullable String iface) { - mDestination = destination; - mGateway = gateway; - mInterface = iface; - } - - @Override - public boolean equals(Object o) { - if (!(o instanceof RouteKey)) { - return false; - } - RouteKey p = (RouteKey) o; - // No need to do anything special for scoped addresses. Inet6Address#equals does not - // consider the scope ID, but the netd route IPCs (e.g., INetd#networkAddRouteParcel) - // and the kernel ignore scoped addresses both in the prefix and in the nexthop and only - // look at RTA_OIF. - return Objects.equals(p.mDestination, mDestination) - && Objects.equals(p.mGateway, mGateway) - && Objects.equals(p.mInterface, mInterface); - } - - @Override - public int hashCode() { - return Objects.hash(mDestination, mGateway, mInterface); - } - } - - /** - * Get {@code RouteKey} of this {@code RouteInfo}. - * @return a {@code RouteKey} object. - * - * @hide - */ - @NonNull - public RouteKey getRouteKey() { - return new RouteKey(mDestination, mGateway, mInterface); - } - - /** - * Returns a hashcode for this RouteInfo object. - */ - public int hashCode() { - return (mDestination.hashCode() * 41) - + (mGateway == null ? 0 :mGateway.hashCode() * 47) - + (mInterface == null ? 0 :mInterface.hashCode() * 67) - + (mType * 71) + (mMtu * 89); - } - - /** - * Implement the Parcelable interface - */ - public int describeContents() { - return 0; - } - - /** - * Implement the Parcelable interface - */ - public void writeToParcel(Parcel dest, int flags) { - dest.writeParcelable(mDestination, flags); - byte[] gatewayBytes = (mGateway == null) ? null : mGateway.getAddress(); - dest.writeByteArray(gatewayBytes); - dest.writeString(mInterface); - dest.writeInt(mType); - dest.writeInt(mMtu); - } - - /** - * Implement the Parcelable interface. - */ - public static final @android.annotation.NonNull Creator CREATOR = - new Creator() { - public RouteInfo createFromParcel(Parcel in) { - IpPrefix dest = in.readParcelable(null); - - InetAddress gateway = null; - byte[] addr = in.createByteArray(); - try { - gateway = InetAddress.getByAddress(addr); - } catch (UnknownHostException e) {} - - String iface = in.readString(); - int type = in.readInt(); - int mtu = in.readInt(); - - return new RouteInfo(dest, gateway, iface, type, mtu); - } - - public RouteInfo[] newArray(int size) { - return new RouteInfo[size]; - } - }; -} diff --git a/core/java/android/net/SocketKeepalive.java b/core/java/android/net/SocketKeepalive.java deleted file mode 100644 index d007a9520cb5..000000000000 --- a/core/java/android/net/SocketKeepalive.java +++ /dev/null @@ -1,301 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import android.annotation.IntDef; -import android.annotation.IntRange; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.SystemApi; -import android.os.Binder; -import android.os.ParcelFileDescriptor; -import android.os.RemoteException; - -import java.io.IOException; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.concurrent.Executor; - -/** - * Allows applications to request that the system periodically send specific packets on their - * behalf, using hardware offload to save battery power. - * - * To request that the system send keepalives, call one of the methods that return a - * {@link SocketKeepalive} object, such as {@link ConnectivityManager#createSocketKeepalive}, - * passing in a non-null callback. If the {@link SocketKeepalive} is successfully - * started, the callback's {@code onStarted} method will be called. If an error occurs, - * {@code onError} will be called, specifying one of the {@code ERROR_*} constants in this - * class. - * - * To stop an existing keepalive, call {@link SocketKeepalive#stop}. The system will call - * {@link SocketKeepalive.Callback#onStopped} if the operation was successful or - * {@link SocketKeepalive.Callback#onError} if an error occurred. - * - * For cellular, the device MUST support at least 1 keepalive slot. - * - * For WiFi, the device SHOULD support keepalive offload. If it does not, it MUST reply with - * {@link SocketKeepalive.Callback#onError} with {@code ERROR_UNSUPPORTED} to any keepalive offload - * request. If it does, it MUST support at least 3 concurrent keepalive slots. - */ -public abstract class SocketKeepalive implements AutoCloseable { - static final String TAG = "SocketKeepalive"; - - /** - * No errors. - * @hide - */ - @SystemApi - public static final int SUCCESS = 0; - - /** @hide */ - public static final int NO_KEEPALIVE = -1; - - /** @hide */ - public static final int DATA_RECEIVED = -2; - - /** @hide */ - public static final int BINDER_DIED = -10; - - /** The specified {@code Network} is not connected. */ - public static final int ERROR_INVALID_NETWORK = -20; - /** The specified IP addresses are invalid. For example, the specified source IP address is - * not configured on the specified {@code Network}. */ - public static final int ERROR_INVALID_IP_ADDRESS = -21; - /** The requested port is invalid. */ - public static final int ERROR_INVALID_PORT = -22; - /** The packet length is invalid (e.g., too long). */ - public static final int ERROR_INVALID_LENGTH = -23; - /** The packet transmission interval is invalid (e.g., too short). */ - public static final int ERROR_INVALID_INTERVAL = -24; - /** The target socket is invalid. */ - public static final int ERROR_INVALID_SOCKET = -25; - /** The target socket is not idle. */ - public static final int ERROR_SOCKET_NOT_IDLE = -26; - /** - * The stop reason is uninitialized. This should only be internally used as initial state - * of stop reason, instead of propagating to application. - * @hide - */ - public static final int ERROR_STOP_REASON_UNINITIALIZED = -27; - - /** The device does not support this request. */ - public static final int ERROR_UNSUPPORTED = -30; - /** @hide TODO: delete when telephony code has been updated. */ - public static final int ERROR_HARDWARE_UNSUPPORTED = ERROR_UNSUPPORTED; - /** The hardware returned an error. */ - public static final int ERROR_HARDWARE_ERROR = -31; - /** The limitation of resource is reached. */ - public static final int ERROR_INSUFFICIENT_RESOURCES = -32; - - - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = { "ERROR_" }, value = { - ERROR_INVALID_NETWORK, - ERROR_INVALID_IP_ADDRESS, - ERROR_INVALID_PORT, - ERROR_INVALID_LENGTH, - ERROR_INVALID_INTERVAL, - ERROR_INVALID_SOCKET, - ERROR_SOCKET_NOT_IDLE - }) - public @interface ErrorCode {} - - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(value = { - SUCCESS, - ERROR_INVALID_LENGTH, - ERROR_UNSUPPORTED, - ERROR_INSUFFICIENT_RESOURCES, - ERROR_HARDWARE_UNSUPPORTED - }) - public @interface KeepaliveEvent {} - - /** - * The minimum interval in seconds between keepalive packet transmissions. - * - * @hide - **/ - public static final int MIN_INTERVAL_SEC = 10; - - /** - * The maximum interval in seconds between keepalive packet transmissions. - * - * @hide - **/ - public static final int MAX_INTERVAL_SEC = 3600; - - /** - * An exception that embarks an error code. - * @hide - */ - public static class ErrorCodeException extends Exception { - public final int error; - public ErrorCodeException(final int error, final Throwable e) { - super(e); - this.error = error; - } - public ErrorCodeException(final int error) { - this.error = error; - } - } - - /** - * This socket is invalid. - * See the error code for details, and the optional cause. - * @hide - */ - public static class InvalidSocketException extends ErrorCodeException { - public InvalidSocketException(final int error, final Throwable e) { - super(error, e); - } - public InvalidSocketException(final int error) { - super(error); - } - } - - @NonNull final IConnectivityManager mService; - @NonNull final Network mNetwork; - @NonNull final ParcelFileDescriptor mPfd; - @NonNull final Executor mExecutor; - @NonNull final ISocketKeepaliveCallback mCallback; - // TODO: remove slot since mCallback could be used to identify which keepalive to stop. - @Nullable Integer mSlot; - - SocketKeepalive(@NonNull IConnectivityManager service, @NonNull Network network, - @NonNull ParcelFileDescriptor pfd, - @NonNull Executor executor, @NonNull Callback callback) { - mService = service; - mNetwork = network; - mPfd = pfd; - mExecutor = executor; - mCallback = new ISocketKeepaliveCallback.Stub() { - @Override - public void onStarted(int slot) { - final long token = Binder.clearCallingIdentity(); - try { - mExecutor.execute(() -> { - mSlot = slot; - callback.onStarted(); - }); - } finally { - Binder.restoreCallingIdentity(token); - } - } - - @Override - public void onStopped() { - final long token = Binder.clearCallingIdentity(); - try { - executor.execute(() -> { - mSlot = null; - callback.onStopped(); - }); - } finally { - Binder.restoreCallingIdentity(token); - } - } - - @Override - public void onError(int error) { - final long token = Binder.clearCallingIdentity(); - try { - executor.execute(() -> { - mSlot = null; - callback.onError(error); - }); - } finally { - Binder.restoreCallingIdentity(token); - } - } - - @Override - public void onDataReceived() { - final long token = Binder.clearCallingIdentity(); - try { - executor.execute(() -> { - mSlot = null; - callback.onDataReceived(); - }); - } finally { - Binder.restoreCallingIdentity(token); - } - } - }; - } - - /** - * Request that keepalive be started with the given {@code intervalSec}. See - * {@link SocketKeepalive}. If the remote binder dies, or the binder call throws an exception - * when invoking start or stop of the {@link SocketKeepalive}, a {@link RemoteException} will be - * thrown into the {@code executor}. This is typically not important to catch because the remote - * party is the system, so if it is not in shape to communicate through binder the system is - * probably going down anyway. If the caller cares regardless, it can use a custom - * {@link Executor} to catch the {@link RemoteException}. - * - * @param intervalSec The target interval in seconds between keepalive packet transmissions. - * The interval should be between 10 seconds and 3600 seconds, otherwise - * {@link #ERROR_INVALID_INTERVAL} will be returned. - */ - public final void start(@IntRange(from = MIN_INTERVAL_SEC, to = MAX_INTERVAL_SEC) - int intervalSec) { - startImpl(intervalSec); - } - - abstract void startImpl(int intervalSec); - - /** - * Requests that keepalive be stopped. The application must wait for {@link Callback#onStopped} - * before using the object. See {@link SocketKeepalive}. - */ - public final void stop() { - stopImpl(); - } - - abstract void stopImpl(); - - /** - * Deactivate this {@link SocketKeepalive} and free allocated resources. The instance won't be - * usable again if {@code close()} is called. - */ - @Override - public final void close() { - stop(); - try { - mPfd.close(); - } catch (IOException e) { - // Nothing much can be done. - } - } - - /** - * The callback which app can use to learn the status changes of {@link SocketKeepalive}. See - * {@link SocketKeepalive}. - */ - public static class Callback { - /** The requested keepalive was successfully started. */ - public void onStarted() {} - /** The keepalive was successfully stopped. */ - public void onStopped() {} - /** An error occurred. */ - public void onError(@ErrorCode int error) {} - /** The keepalive on a TCP socket was stopped because the socket received data. This is - * never called for UDP sockets. */ - public void onDataReceived() {} - } -} diff --git a/core/java/android/net/StaticIpConfiguration.aidl b/core/java/android/net/StaticIpConfiguration.aidl deleted file mode 100644 index 8aac701fe7e1..000000000000 --- a/core/java/android/net/StaticIpConfiguration.aidl +++ /dev/null @@ -1,20 +0,0 @@ -/* -** -** Copyright (C) 2019 The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -package android.net; - -@JavaOnlyStableParcelable parcelable StaticIpConfiguration; \ No newline at end of file diff --git a/core/java/android/net/StaticIpConfiguration.java b/core/java/android/net/StaticIpConfiguration.java deleted file mode 100644 index ce545974f5cb..000000000000 --- a/core/java/android/net/StaticIpConfiguration.java +++ /dev/null @@ -1,332 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.SystemApi; -import android.compat.annotation.UnsupportedAppUsage; -import android.os.Build; -import android.os.Parcel; -import android.os.Parcelable; - -import com.android.internal.util.Preconditions; -import com.android.net.module.util.InetAddressUtils; - -import java.net.InetAddress; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - -/** - * Class that describes static IP configuration. - * - *

This class is different from {@link LinkProperties} because it represents - * configuration intent. The general contract is that if we can represent - * a configuration here, then we should be able to configure it on a network. - * The intent is that it closely match the UI we have for configuring networks. - * - *

In contrast, {@link LinkProperties} represents current state. It is much more - * expressive. For example, it supports multiple IP addresses, multiple routes, - * stacked interfaces, and so on. Because LinkProperties is so expressive, - * using it to represent configuration intent as well as current state causes - * problems. For example, we could unknowingly save a configuration that we are - * not in fact capable of applying, or we could save a configuration that the - * UI cannot display, which has the potential for malicious code to hide - * hostile or unexpected configuration from the user. - * - * @hide - */ -@SystemApi -public final class StaticIpConfiguration implements Parcelable { - /** @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @Nullable - public LinkAddress ipAddress; - /** @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @Nullable - public InetAddress gateway; - /** @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @NonNull - public final ArrayList dnsServers; - /** @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @Nullable - public String domains; - - public StaticIpConfiguration() { - dnsServers = new ArrayList<>(); - } - - public StaticIpConfiguration(@Nullable StaticIpConfiguration source) { - this(); - if (source != null) { - // All of these except dnsServers are immutable, so no need to make copies. - ipAddress = source.ipAddress; - gateway = source.gateway; - dnsServers.addAll(source.dnsServers); - domains = source.domains; - } - } - - public void clear() { - ipAddress = null; - gateway = null; - dnsServers.clear(); - domains = null; - } - - /** - * Get the static IP address included in the configuration. - */ - public @Nullable LinkAddress getIpAddress() { - return ipAddress; - } - - /** - * Get the gateway included in the configuration. - */ - public @Nullable InetAddress getGateway() { - return gateway; - } - - /** - * Get the DNS servers included in the configuration. - */ - public @NonNull List getDnsServers() { - return dnsServers; - } - - /** - * Get a {@link String} containing the comma separated domains to search when resolving host - * names on this link, in priority order. - */ - public @Nullable String getDomains() { - return domains; - } - - /** - * Helper class to build a new instance of {@link StaticIpConfiguration}. - */ - public static final class Builder { - private LinkAddress mIpAddress; - private InetAddress mGateway; - private Iterable mDnsServers; - private String mDomains; - - /** - * Set the IP address to be included in the configuration; null by default. - * @return The {@link Builder} for chaining. - */ - public @NonNull Builder setIpAddress(@Nullable LinkAddress ipAddress) { - mIpAddress = ipAddress; - return this; - } - - /** - * Set the address of the gateway to be included in the configuration; null by default. - * @return The {@link Builder} for chaining. - */ - public @NonNull Builder setGateway(@Nullable InetAddress gateway) { - mGateway = gateway; - return this; - } - - /** - * Set the addresses of the DNS servers included in the configuration; empty by default. - * @return The {@link Builder} for chaining. - */ - public @NonNull Builder setDnsServers(@NonNull Iterable dnsServers) { - Preconditions.checkNotNull(dnsServers); - mDnsServers = dnsServers; - return this; - } - - /** - * Sets the DNS domain search path to be used on the link; null by default. - * @param newDomains A {@link String} containing the comma separated domains to search when - * resolving host names on this link, in priority order. - * @return The {@link Builder} for chaining. - */ - public @NonNull Builder setDomains(@Nullable String newDomains) { - mDomains = newDomains; - return this; - } - - /** - * Create a {@link StaticIpConfiguration} from the parameters in this {@link Builder}. - * @return The newly created StaticIpConfiguration. - */ - public @NonNull StaticIpConfiguration build() { - final StaticIpConfiguration config = new StaticIpConfiguration(); - config.ipAddress = mIpAddress; - config.gateway = mGateway; - if (mDnsServers != null) { - for (InetAddress server : mDnsServers) { - config.dnsServers.add(server); - } - } - config.domains = mDomains; - return config; - } - } - - /** - * Add a DNS server to this configuration. - */ - public void addDnsServer(@NonNull InetAddress server) { - dnsServers.add(server); - } - - /** - * Returns the network routes specified by this object. Will typically include a - * directly-connected route for the IP address's local subnet and a default route. - * @param iface Interface to include in the routes. - */ - public @NonNull List getRoutes(@Nullable String iface) { - List routes = new ArrayList(3); - if (ipAddress != null) { - RouteInfo connectedRoute = new RouteInfo(ipAddress, null, iface); - routes.add(connectedRoute); - // If the default gateway is not covered by the directly-connected route, also add a - // host route to the gateway as well. This configuration is arguably invalid, but it - // used to work in K and earlier, and other OSes appear to accept it. - if (gateway != null && !connectedRoute.matches(gateway)) { - routes.add(RouteInfo.makeHostRoute(gateway, iface)); - } - } - if (gateway != null) { - routes.add(new RouteInfo((IpPrefix) null, gateway, iface)); - } - return routes; - } - - /** - * Returns a LinkProperties object expressing the data in this object. Note that the information - * contained in the LinkProperties will not be a complete picture of the link's configuration, - * because any configuration information that is obtained dynamically by the network (e.g., - * IPv6 configuration) will not be included. - * @hide - */ - public @NonNull LinkProperties toLinkProperties(String iface) { - LinkProperties lp = new LinkProperties(); - lp.setInterfaceName(iface); - if (ipAddress != null) { - lp.addLinkAddress(ipAddress); - } - for (RouteInfo route : getRoutes(iface)) { - lp.addRoute(route); - } - for (InetAddress dns : dnsServers) { - lp.addDnsServer(dns); - } - lp.setDomains(domains); - return lp; - } - - @NonNull - @Override - public String toString() { - StringBuffer str = new StringBuffer(); - - str.append("IP address "); - if (ipAddress != null ) str.append(ipAddress).append(" "); - - str.append("Gateway "); - if (gateway != null) str.append(gateway.getHostAddress()).append(" "); - - str.append(" DNS servers: ["); - for (InetAddress dnsServer : dnsServers) { - str.append(" ").append(dnsServer.getHostAddress()); - } - - str.append(" ] Domains "); - if (domains != null) str.append(domains); - return str.toString(); - } - - @Override - public int hashCode() { - int result = 13; - result = 47 * result + (ipAddress == null ? 0 : ipAddress.hashCode()); - result = 47 * result + (gateway == null ? 0 : gateway.hashCode()); - result = 47 * result + (domains == null ? 0 : domains.hashCode()); - result = 47 * result + dnsServers.hashCode(); - return result; - } - - @Override - public boolean equals(@Nullable Object obj) { - if (this == obj) return true; - - if (!(obj instanceof StaticIpConfiguration)) return false; - - StaticIpConfiguration other = (StaticIpConfiguration) obj; - - return other != null && - Objects.equals(ipAddress, other.ipAddress) && - Objects.equals(gateway, other.gateway) && - dnsServers.equals(other.dnsServers) && - Objects.equals(domains, other.domains); - } - - /** Implement the Parcelable interface */ - public static final @android.annotation.NonNull Creator CREATOR = - new Creator() { - public StaticIpConfiguration createFromParcel(Parcel in) { - return readFromParcel(in); - } - - public StaticIpConfiguration[] newArray(int size) { - return new StaticIpConfiguration[size]; - } - }; - - /** Implement the Parcelable interface */ - @Override - public int describeContents() { - return 0; - } - - /** Implement the Parcelable interface */ - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeParcelable(ipAddress, flags); - InetAddressUtils.parcelInetAddress(dest, gateway, flags); - dest.writeInt(dnsServers.size()); - for (InetAddress dnsServer : dnsServers) { - InetAddressUtils.parcelInetAddress(dest, dnsServer, flags); - } - dest.writeString(domains); - } - - /** @hide */ - public static StaticIpConfiguration readFromParcel(Parcel in) { - final StaticIpConfiguration s = new StaticIpConfiguration(); - s.ipAddress = in.readParcelable(null); - s.gateway = InetAddressUtils.unparcelInetAddress(in); - s.dnsServers.clear(); - int size = in.readInt(); - for (int i = 0; i < size; i++) { - s.dnsServers.add(InetAddressUtils.unparcelInetAddress(in)); - } - s.domains = in.readString(); - return s; - } -} diff --git a/core/java/android/net/TcpKeepalivePacketData.java b/core/java/android/net/TcpKeepalivePacketData.java deleted file mode 100644 index ddb3a6a72fb4..000000000000 --- a/core/java/android/net/TcpKeepalivePacketData.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.net; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.SystemApi; -import android.os.Parcel; -import android.os.Parcelable; - -import java.net.InetAddress; -import java.util.Objects; - -/** - * Represents the actual tcp keep alive packets which will be used for hardware offload. - * @hide - */ -@SystemApi -public final class TcpKeepalivePacketData extends KeepalivePacketData implements Parcelable { - private static final String TAG = "TcpKeepalivePacketData"; - - /** TCP sequence number. */ - public final int tcpSeq; - - /** TCP ACK number. */ - public final int tcpAck; - - /** TCP RCV window. */ - public final int tcpWindow; - - /** TCP RCV window scale. */ - public final int tcpWindowScale; - - /** IP TOS. */ - public final int ipTos; - - /** IP TTL. */ - public final int ipTtl; - - public TcpKeepalivePacketData(@NonNull final InetAddress srcAddress, int srcPort, - @NonNull final InetAddress dstAddress, int dstPort, @NonNull final byte[] data, - int tcpSeq, int tcpAck, int tcpWindow, int tcpWindowScale, int ipTos, int ipTtl) - throws InvalidPacketException { - super(srcAddress, srcPort, dstAddress, dstPort, data); - this.tcpSeq = tcpSeq; - this.tcpAck = tcpAck; - this.tcpWindow = tcpWindow; - this.tcpWindowScale = tcpWindowScale; - this.ipTos = ipTos; - this.ipTtl = ipTtl; - } - - @Override - public boolean equals(@Nullable final Object o) { - if (!(o instanceof TcpKeepalivePacketData)) return false; - final TcpKeepalivePacketData other = (TcpKeepalivePacketData) o; - final InetAddress srcAddress = getSrcAddress(); - final InetAddress dstAddress = getDstAddress(); - return srcAddress.equals(other.getSrcAddress()) - && dstAddress.equals(other.getDstAddress()) - && getSrcPort() == other.getSrcPort() - && getDstPort() == other.getDstPort() - && this.tcpAck == other.tcpAck - && this.tcpSeq == other.tcpSeq - && this.tcpWindow == other.tcpWindow - && this.tcpWindowScale == other.tcpWindowScale - && this.ipTos == other.ipTos - && this.ipTtl == other.ipTtl; - } - - @Override - public int hashCode() { - return Objects.hash(getSrcAddress(), getDstAddress(), getSrcPort(), getDstPort(), - tcpAck, tcpSeq, tcpWindow, tcpWindowScale, ipTos, ipTtl); - } - - /** - * Parcelable Implementation. - * Note that this object implements parcelable (and needs to keep doing this as it inherits - * from a class that does), but should usually be parceled as a stable parcelable using - * the toStableParcelable() and fromStableParcelable() methods. - */ - @Override - public int describeContents() { - return 0; - } - - /** Write to parcel. */ - @Override - public void writeToParcel(@NonNull Parcel out, int flags) { - out.writeString(getSrcAddress().getHostAddress()); - out.writeString(getDstAddress().getHostAddress()); - out.writeInt(getSrcPort()); - out.writeInt(getDstPort()); - out.writeByteArray(getPacket()); - out.writeInt(tcpSeq); - out.writeInt(tcpAck); - out.writeInt(tcpWindow); - out.writeInt(tcpWindowScale); - out.writeInt(ipTos); - out.writeInt(ipTtl); - } - - private static TcpKeepalivePacketData readFromParcel(Parcel in) throws InvalidPacketException { - InetAddress srcAddress = InetAddresses.parseNumericAddress(in.readString()); - InetAddress dstAddress = InetAddresses.parseNumericAddress(in.readString()); - int srcPort = in.readInt(); - int dstPort = in.readInt(); - byte[] packet = in.createByteArray(); - int tcpSeq = in.readInt(); - int tcpAck = in.readInt(); - int tcpWnd = in.readInt(); - int tcpWndScale = in.readInt(); - int ipTos = in.readInt(); - int ipTtl = in.readInt(); - return new TcpKeepalivePacketData(srcAddress, srcPort, dstAddress, dstPort, packet, tcpSeq, - tcpAck, tcpWnd, tcpWndScale, ipTos, ipTtl); - } - - /** Parcelable Creator. */ - public static final @NonNull Parcelable.Creator CREATOR = - new Parcelable.Creator() { - public TcpKeepalivePacketData createFromParcel(Parcel in) { - try { - return readFromParcel(in); - } catch (InvalidPacketException e) { - throw new IllegalArgumentException( - "Invalid TCP keepalive data: " + e.getError()); - } - } - - public TcpKeepalivePacketData[] newArray(int size) { - return new TcpKeepalivePacketData[size]; - } - }; - - @Override - public String toString() { - return "saddr: " + getSrcAddress() - + " daddr: " + getDstAddress() - + " sport: " + getSrcPort() - + " dport: " + getDstPort() - + " seq: " + tcpSeq - + " ack: " + tcpAck - + " window: " + tcpWindow - + " windowScale: " + tcpWindowScale - + " tos: " + ipTos - + " ttl: " + ipTtl; - } -} diff --git a/core/java/android/net/TcpRepairWindow.java b/core/java/android/net/TcpRepairWindow.java deleted file mode 100644 index f062fa9034ea..000000000000 --- a/core/java/android/net/TcpRepairWindow.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import android.annotation.SystemApi; - -/** - * Corresponds to C's {@code struct tcp_repair_window} from - * include/uapi/linux/tcp.h - * - * @hide - */ -@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) -public final class TcpRepairWindow { - public final int sndWl1; - public final int sndWnd; - public final int maxWindow; - public final int rcvWnd; - public final int rcvWup; - public final int rcvWndScale; - - /** - * Constructs an instance with the given field values. - */ - public TcpRepairWindow(final int sndWl1, final int sndWnd, final int maxWindow, - final int rcvWnd, final int rcvWup, final int rcvWndScale) { - this.sndWl1 = sndWl1; - this.sndWnd = sndWnd; - this.maxWindow = maxWindow; - this.rcvWnd = rcvWnd; - this.rcvWup = rcvWup; - this.rcvWndScale = rcvWndScale; - } -} diff --git a/core/java/android/net/TcpSocketKeepalive.java b/core/java/android/net/TcpSocketKeepalive.java deleted file mode 100644 index d89814d49bd0..000000000000 --- a/core/java/android/net/TcpSocketKeepalive.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import android.annotation.NonNull; -import android.os.ParcelFileDescriptor; -import android.os.RemoteException; -import android.util.Log; - -import java.util.concurrent.Executor; - -/** @hide */ -final class TcpSocketKeepalive extends SocketKeepalive { - - TcpSocketKeepalive(@NonNull IConnectivityManager service, - @NonNull Network network, - @NonNull ParcelFileDescriptor pfd, - @NonNull Executor executor, - @NonNull Callback callback) { - super(service, network, pfd, executor, callback); - } - - /** - * Starts keepalives. {@code mSocket} must be a connected TCP socket. - * - * - The application must not write to or read from the socket after calling this method, until - * onDataReceived, onStopped, or onError are called. If it does, the keepalive will fail - * with {@link #ERROR_SOCKET_NOT_IDLE}, or {@code #ERROR_INVALID_SOCKET} if the socket - * experienced an error (as in poll(2) returned POLLERR or POLLHUP); if this happens, the data - * received from the socket may be invalid, and the socket can't be recovered. - * - If the socket has data in the send or receive buffer, then this call will fail with - * {@link #ERROR_SOCKET_NOT_IDLE} and can be retried after the data has been processed. - * An app could ensure this by using an application-layer protocol to receive acknowledgement - * that indicates all data has been delivered to server, e.g. HTTP 200 OK. - * Then the app could go into keepalive mode after reading all remaining data within the - * acknowledgement. - */ - @Override - void startImpl(int intervalSec) { - mExecutor.execute(() -> { - try { - mService.startTcpKeepalive(mNetwork, mPfd, intervalSec, mCallback); - } catch (RemoteException e) { - Log.e(TAG, "Error starting packet keepalive: ", e); - throw e.rethrowFromSystemServer(); - } - }); - } - - @Override - void stopImpl() { - mExecutor.execute(() -> { - try { - if (mSlot != null) { - mService.stopKeepalive(mNetwork, mSlot); - } - } catch (RemoteException e) { - Log.e(TAG, "Error stopping packet keepalive: ", e); - throw e.rethrowFromSystemServer(); - } - }); - } -} diff --git a/core/java/android/net/TestNetworkInterface.aidl b/core/java/android/net/TestNetworkInterface.aidl deleted file mode 100644 index e1f4f9f794eb..000000000000 --- a/core/java/android/net/TestNetworkInterface.aidl +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -/** @hide */ -parcelable TestNetworkInterface; diff --git a/core/java/android/net/TestNetworkInterface.java b/core/java/android/net/TestNetworkInterface.java deleted file mode 100644 index 4449ff80180b..000000000000 --- a/core/java/android/net/TestNetworkInterface.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.net; - -import android.annotation.NonNull; -import android.annotation.SystemApi; -import android.os.Parcel; -import android.os.ParcelFileDescriptor; -import android.os.Parcelable; - -/** - * This class is used to return the interface name and fd of the test interface - * - * @hide - */ -@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) -public final class TestNetworkInterface implements Parcelable { - @NonNull - private final ParcelFileDescriptor mFileDescriptor; - @NonNull - private final String mInterfaceName; - - @Override - public int describeContents() { - return (mFileDescriptor != null) ? Parcelable.CONTENTS_FILE_DESCRIPTOR : 0; - } - - @Override - public void writeToParcel(@NonNull Parcel out, int flags) { - out.writeParcelable(mFileDescriptor, PARCELABLE_WRITE_RETURN_VALUE); - out.writeString(mInterfaceName); - } - - public TestNetworkInterface(@NonNull ParcelFileDescriptor pfd, @NonNull String intf) { - mFileDescriptor = pfd; - mInterfaceName = intf; - } - - private TestNetworkInterface(@NonNull Parcel in) { - mFileDescriptor = in.readParcelable(ParcelFileDescriptor.class.getClassLoader()); - mInterfaceName = in.readString(); - } - - @NonNull - public ParcelFileDescriptor getFileDescriptor() { - return mFileDescriptor; - } - - @NonNull - public String getInterfaceName() { - return mInterfaceName; - } - - @NonNull - public static final Parcelable.Creator CREATOR = - new Parcelable.Creator() { - public TestNetworkInterface createFromParcel(Parcel in) { - return new TestNetworkInterface(in); - } - - public TestNetworkInterface[] newArray(int size) { - return new TestNetworkInterface[size]; - } - }; -} diff --git a/core/java/android/net/TestNetworkManager.java b/core/java/android/net/TestNetworkManager.java deleted file mode 100644 index 4e894143bf91..000000000000 --- a/core/java/android/net/TestNetworkManager.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.net; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.SystemApi; -import android.os.IBinder; -import android.os.RemoteException; - -import com.android.internal.util.Preconditions; - -import java.util.Arrays; -import java.util.Collection; - -/** - * Class that allows creation and management of per-app, test-only networks - * - * @hide - */ -@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) -public class TestNetworkManager { - /** - * Prefix for tun interfaces created by this class. - * @hide - */ - public static final String TEST_TUN_PREFIX = "testtun"; - - /** - * Prefix for tap interfaces created by this class. - * @hide - */ - public static final String TEST_TAP_PREFIX = "testtap"; - - @NonNull private static final String TAG = TestNetworkManager.class.getSimpleName(); - - @NonNull private final ITestNetworkManager mService; - - /** @hide */ - public TestNetworkManager(@NonNull ITestNetworkManager service) { - mService = Preconditions.checkNotNull(service, "missing ITestNetworkManager"); - } - - /** - * Teardown the capability-limited, testing-only network for a given interface - * - * @param network The test network that should be torn down - * @hide - */ - @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) - public void teardownTestNetwork(@NonNull Network network) { - try { - mService.teardownTestNetwork(network.netId); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - private void setupTestNetwork( - @NonNull String iface, - @Nullable LinkProperties lp, - boolean isMetered, - @NonNull int[] administratorUids, - @NonNull IBinder binder) { - try { - mService.setupTestNetwork(iface, lp, isMetered, administratorUids, binder); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Sets up a capability-limited, testing-only network for a given interface - * - * @param lp The LinkProperties for the TestNetworkService to use for this test network. Note - * that the interface name and link addresses will be overwritten, and the passed-in values - * discarded. - * @param isMetered Whether or not the network should be considered metered. - * @param binder A binder object guarding the lifecycle of this test network. - * @hide - */ - public void setupTestNetwork( - @NonNull LinkProperties lp, boolean isMetered, @NonNull IBinder binder) { - Preconditions.checkNotNull(lp, "Invalid LinkProperties"); - setupTestNetwork(lp.getInterfaceName(), lp, isMetered, new int[0], binder); - } - - /** - * Sets up a capability-limited, testing-only network for a given interface - * - * @param iface the name of the interface to be used for the Network LinkProperties. - * @param binder A binder object guarding the lifecycle of this test network. - * @hide - */ - @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) - public void setupTestNetwork(@NonNull String iface, @NonNull IBinder binder) { - setupTestNetwork(iface, null, true, new int[0], binder); - } - - /** - * Sets up a capability-limited, testing-only network for a given interface with the given - * administrator UIDs. - * - * @param iface the name of the interface to be used for the Network LinkProperties. - * @param administratorUids The administrator UIDs to be used for the test-only network - * @param binder A binder object guarding the lifecycle of this test network. - * @hide - */ - public void setupTestNetwork( - @NonNull String iface, @NonNull int[] administratorUids, @NonNull IBinder binder) { - setupTestNetwork(iface, null, true, administratorUids, binder); - } - - /** - * Create a tun interface for testing purposes - * - * @param linkAddrs an array of LinkAddresses to assign to the TUN interface - * @return A ParcelFileDescriptor of the underlying TUN interface. Close this to tear down the - * TUN interface. - * @deprecated Use {@link #createTunInterface(Collection)} instead. - * @hide - */ - @Deprecated - @NonNull - public TestNetworkInterface createTunInterface(@NonNull LinkAddress[] linkAddrs) { - return createTunInterface(Arrays.asList(linkAddrs)); - } - - /** - * Create a tun interface for testing purposes - * - * @param linkAddrs an array of LinkAddresses to assign to the TUN interface - * @return A ParcelFileDescriptor of the underlying TUN interface. Close this to tear down the - * TUN interface. - * @hide - */ - @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) - @NonNull - public TestNetworkInterface createTunInterface(@NonNull Collection linkAddrs) { - try { - final LinkAddress[] arr = new LinkAddress[linkAddrs.size()]; - return mService.createTunInterface(linkAddrs.toArray(arr)); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Create a tap interface for testing purposes - * - * @return A ParcelFileDescriptor of the underlying TAP interface. Close this to tear down the - * TAP interface. - * @hide - */ - @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) - @NonNull - public TestNetworkInterface createTapInterface() { - try { - return mService.createTapInterface(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - -} diff --git a/core/java/android/net/TransportInfo.java b/core/java/android/net/TransportInfo.java deleted file mode 100644 index aa4bbb051179..000000000000 --- a/core/java/android/net/TransportInfo.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import android.annotation.NonNull; -import android.annotation.SystemApi; - -/** - * A container for transport-specific capabilities which is returned by - * {@link NetworkCapabilities#getTransportInfo()}. Specific networks - * may provide concrete implementations of this interface. - * @see android.net.wifi.aware.WifiAwareNetworkInfo - * @see android.net.wifi.WifiInfo - */ -public interface TransportInfo { - - /** - * Create a copy of a {@link TransportInfo} that will preserve location sensitive fields that - * were set based on the permissions of the process that originally received it. - * - *

By default {@link TransportInfo} does not preserve such fields during parceling, as - * they should not be shared outside of the process that receives them without appropriate - * checks. - * - * @param parcelLocationSensitiveFields Whether the location sensitive fields should be kept - * when parceling - * @return Copy of this instance. - * @hide - */ - @SystemApi - @NonNull - default TransportInfo makeCopy(boolean parcelLocationSensitiveFields) { - return this; - } - - /** - * Returns whether this TransportInfo type has location sensitive fields or not (helps - * to determine whether to perform a location permission check or not before sending to - * apps). - * - * @return {@code true} if this instance contains location sensitive info, {@code false} - * otherwise. - * @hide - */ - @SystemApi - default boolean hasLocationSensitiveFields() { - return false; - } -} diff --git a/core/java/android/net/UidRange.aidl b/core/java/android/net/UidRange.aidl deleted file mode 100644 index f70fc8e2fefd..000000000000 --- a/core/java/android/net/UidRange.aidl +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -/** - * An inclusive range of UIDs. - * - * {@hide} - */ -parcelable UidRange; \ No newline at end of file diff --git a/core/java/android/net/VpnManager.java b/core/java/android/net/VpnManager.java deleted file mode 100644 index c87b8279c4d6..000000000000 --- a/core/java/android/net/VpnManager.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import static com.android.internal.util.Preconditions.checkNotNull; - -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.app.Activity; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.res.Resources; -import android.os.RemoteException; - -import com.android.internal.net.VpnProfile; - -import java.io.IOException; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.security.GeneralSecurityException; - -/** - * This class provides an interface for apps to manage platform VPN profiles - * - *

Apps can use this API to provide profiles with which the platform can set up a VPN without - * further app intermediation. When a VPN profile is present and the app is selected as an always-on - * VPN, the platform will directly trigger the negotiation of the VPN without starting or waking the - * app (unlike VpnService). - * - *

VPN apps using supported protocols should preferentially use this API over the {@link - * VpnService} API for ease-of-development and reduced maintainance burden. This also give the user - * the guarantee that VPN network traffic is not subjected to on-device packet interception. - * - * @see Ikev2VpnProfile - */ -public class VpnManager { - /** Type representing a lack of VPN @hide */ - public static final int TYPE_VPN_NONE = -1; - /** VPN service type code @hide */ - public static final int TYPE_VPN_SERVICE = 1; - /** Platform VPN type code @hide */ - public static final int TYPE_VPN_PLATFORM = 2; - - /** @hide */ - @IntDef(value = {TYPE_VPN_NONE, TYPE_VPN_SERVICE, TYPE_VPN_PLATFORM}) - @Retention(RetentionPolicy.SOURCE) - public @interface VpnType {} - - @NonNull private final Context mContext; - @NonNull private final IConnectivityManager mService; - - private static Intent getIntentForConfirmation() { - final Intent intent = new Intent(); - final ComponentName componentName = ComponentName.unflattenFromString( - Resources.getSystem().getString( - com.android.internal.R.string.config_platformVpnConfirmDialogComponent)); - intent.setComponent(componentName); - return intent; - } - - /** - * Create an instance of the VpnManager with the given context. - * - *

Internal only. Applications are expected to obtain an instance of the VpnManager via the - * {@link Context.getSystemService()} method call. - * - * @hide - */ - public VpnManager(@NonNull Context ctx, @NonNull IConnectivityManager service) { - mContext = checkNotNull(ctx, "missing Context"); - mService = checkNotNull(service, "missing IConnectivityManager"); - } - - /** - * Install a VpnProfile configuration keyed on the calling app's package name. - * - *

This method returns {@code null} if user consent has already been granted, or an {@link - * Intent} to a system activity. If an intent is returned, the application should launch the - * activity using {@link Activity#startActivityForResult} to request user consent. The activity - * may pop up a dialog to require user action, and the result will come back via its {@link - * Activity#onActivityResult}. If the result is {@link Activity#RESULT_OK}, the user has - * consented, and the VPN profile can be started. - * - * @param profile the VpnProfile provided by this package. Will override any previous VpnProfile - * stored for this package. - * @return an Intent requesting user consent to start the VPN, or null if consent is not - * required based on privileges or previous user consent. - */ - @Nullable - public Intent provisionVpnProfile(@NonNull PlatformVpnProfile profile) { - final VpnProfile internalProfile; - - try { - internalProfile = profile.toVpnProfile(); - } catch (GeneralSecurityException | IOException e) { - // Conversion to VpnProfile failed; this is an invalid profile. Both of these exceptions - // indicate a failure to convert a PrivateKey or X509Certificate to a Base64 encoded - // string as required by the VpnProfile. - throw new IllegalArgumentException("Failed to serialize PlatformVpnProfile", e); - } - - try { - // Profile can never be null; it either gets set, or an exception is thrown. - if (mService.provisionVpnProfile(internalProfile, mContext.getOpPackageName())) { - return null; - } - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - return getIntentForConfirmation(); - } - - /** - * Delete the VPN profile configuration that was provisioned by the calling app - * - * @throws SecurityException if this would violate user settings - */ - public void deleteProvisionedVpnProfile() { - try { - mService.deleteVpnProfile(mContext.getOpPackageName()); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Request the startup of a previously provisioned VPN. - * - * @throws SecurityException exception if user or device settings prevent this VPN from being - * setup, or if user consent has not been granted - */ - public void startProvisionedVpnProfile() { - try { - mService.startVpnProfile(mContext.getOpPackageName()); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** Tear down the VPN provided by the calling app (if any) */ - public void stopProvisionedVpnProfile() { - try { - mService.stopVpnProfile(mContext.getOpPackageName()); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } -} diff --git a/core/java/android/net/VpnService.java b/core/java/android/net/VpnService.java deleted file mode 100644 index 8e90a119fe21..000000000000 --- a/core/java/android/net/VpnService.java +++ /dev/null @@ -1,903 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import static android.system.OsConstants.AF_INET; -import static android.system.OsConstants.AF_INET6; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.RequiresPermission; -import android.annotation.SystemApi; -import android.app.Activity; -import android.app.PendingIntent; -import android.app.Service; -import android.app.admin.DevicePolicyManager; -import android.compat.annotation.UnsupportedAppUsage; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.pm.IPackageManager; -import android.content.pm.PackageManager; -import android.os.Binder; -import android.os.IBinder; -import android.os.Parcel; -import android.os.ParcelFileDescriptor; -import android.os.RemoteException; -import android.os.ServiceManager; -import android.os.UserHandle; - -import com.android.internal.net.VpnConfig; - -import java.net.DatagramSocket; -import java.net.Inet4Address; -import java.net.Inet6Address; -import java.net.InetAddress; -import java.net.Socket; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; - -/** - * VpnService is a base class for applications to extend and build their - * own VPN solutions. In general, it creates a virtual network interface, - * configures addresses and routing rules, and returns a file descriptor - * to the application. Each read from the descriptor retrieves an outgoing - * packet which was routed to the interface. Each write to the descriptor - * injects an incoming packet just like it was received from the interface. - * The interface is running on Internet Protocol (IP), so packets are - * always started with IP headers. The application then completes a VPN - * connection by processing and exchanging packets with the remote server - * over a tunnel. - * - *

Letting applications intercept packets raises huge security concerns. - * A VPN application can easily break the network. Besides, two of them may - * conflict with each other. The system takes several actions to address - * these issues. Here are some key points: - *

    - *
  • User action is required the first time an application creates a VPN - * connection.
  • - *
  • There can be only one VPN connection running at the same time. The - * existing interface is deactivated when a new one is created.
  • - *
  • A system-managed notification is shown during the lifetime of a - * VPN connection.
  • - *
  • A system-managed dialog gives the information of the current VPN - * connection. It also provides a button to disconnect.
  • - *
  • The network is restored automatically when the file descriptor is - * closed. It also covers the cases when a VPN application is crashed - * or killed by the system.
  • - *
- * - *

There are two primary methods in this class: {@link #prepare} and - * {@link Builder#establish}. The former deals with user action and stops - * the VPN connection created by another application. The latter creates - * a VPN interface using the parameters supplied to the {@link Builder}. - * An application must call {@link #prepare} to grant the right to use - * other methods in this class, and the right can be revoked at any time. - * Here are the general steps to create a VPN connection: - *

    - *
  1. When the user presses the button to connect, call {@link #prepare} - * and launch the returned intent, if non-null.
  2. - *
  3. When the application becomes prepared, start the service.
  4. - *
  5. Create a tunnel to the remote server and negotiate the network - * parameters for the VPN connection.
  6. - *
  7. Supply those parameters to a {@link Builder} and create a VPN - * interface by calling {@link Builder#establish}.
  8. - *
  9. Process and exchange packets between the tunnel and the returned - * file descriptor.
  10. - *
  11. When {@link #onRevoke} is invoked, close the file descriptor and - * shut down the tunnel gracefully.
  12. - *
- * - *

Services extending this class need to be declared with an appropriate - * permission and intent filter. Their access must be secured by - * {@link android.Manifest.permission#BIND_VPN_SERVICE} permission, and - * their intent filter must match {@link #SERVICE_INTERFACE} action. Here - * is an example of declaring a VPN service in {@code AndroidManifest.xml}: - *

- * <service android:name=".ExampleVpnService"
- *         android:permission="android.permission.BIND_VPN_SERVICE">
- *     <intent-filter>
- *         <action android:name="android.net.VpnService"/>
- *     </intent-filter>
- * </service>
- * - *

The Android system starts a VPN in the background by calling - * {@link android.content.Context#startService startService()}. In Android 8.0 - * (API level 26) and higher, the system places VPN apps on the temporary - * allowlist for a short period so the app can start in the background. The VPN - * app must promote itself to the foreground after it's launched or the system - * will shut down the app. - * - *

Developer's guide

- * - *

To learn more about developing VPN apps, read the - * VPN developer's guide. - * - * @see Builder - */ -public class VpnService extends Service { - - /** - * The action must be matched by the intent filter of this service. It also - * needs to require {@link android.Manifest.permission#BIND_VPN_SERVICE} - * permission so that other applications cannot abuse it. - */ - public static final String SERVICE_INTERFACE = VpnConfig.SERVICE_INTERFACE; - - /** - * Key for boolean meta-data field indicating whether this VpnService supports always-on mode. - * - *

For a VPN app targeting {@link android.os.Build.VERSION_CODES#N API 24} or above, Android - * provides users with the ability to set it as always-on, so that VPN connection is - * persisted after device reboot and app upgrade. Always-on VPN can also be enabled by device - * owner and profile owner apps through - * {@link DevicePolicyManager#setAlwaysOnVpnPackage}. - * - *

VPN apps not supporting this feature should opt out by adding this meta-data field to the - * {@code VpnService} component of {@code AndroidManifest.xml}. In case there is more than one - * {@code VpnService} component defined in {@code AndroidManifest.xml}, opting out any one of - * them will opt out the entire app. For example, - *

 {@code
-     * 
-     *     
-     *         
-     *     
-     *     
-     * 
-     * } 
- * - *

This meta-data field defaults to {@code true} if absent. It will only have effect on - * {@link android.os.Build.VERSION_CODES#O_MR1} or higher. - */ - public static final String SERVICE_META_DATA_SUPPORTS_ALWAYS_ON = - "android.net.VpnService.SUPPORTS_ALWAYS_ON"; - - /** - * Use IConnectivityManager since those methods are hidden and not - * available in ConnectivityManager. - */ - private static IConnectivityManager getService() { - return IConnectivityManager.Stub.asInterface( - ServiceManager.getService(Context.CONNECTIVITY_SERVICE)); - } - - /** - * Prepare to establish a VPN connection. This method returns {@code null} - * if the VPN application is already prepared or if the user has previously - * consented to the VPN application. Otherwise, it returns an - * {@link Intent} to a system activity. The application should launch the - * activity using {@link Activity#startActivityForResult} to get itself - * prepared. The activity may pop up a dialog to require user action, and - * the result will come back via its {@link Activity#onActivityResult}. - * If the result is {@link Activity#RESULT_OK}, the application becomes - * prepared and is granted to use other methods in this class. - * - *

Only one application can be granted at the same time. The right - * is revoked when another application is granted. The application - * losing the right will be notified via its {@link #onRevoke}. Unless - * it becomes prepared again, subsequent calls to other methods in this - * class will fail. - * - *

The user may disable the VPN at any time while it is activated, in - * which case this method will return an intent the next time it is - * executed to obtain the user's consent again. - * - * @see #onRevoke - */ - public static Intent prepare(Context context) { - try { - if (getService().prepareVpn(context.getPackageName(), null, context.getUserId())) { - return null; - } - } catch (RemoteException e) { - // ignore - } - return VpnConfig.getIntentForConfirmation(); - } - - /** - * Version of {@link #prepare(Context)} which does not require user consent. - * - *

Requires {@link android.Manifest.permission#CONTROL_VPN} and should generally not be - * used. Only acceptable in situations where user consent has been obtained through other means. - * - *

Once this is run, future preparations may be done with the standard prepare method as this - * will authorize the package to prepare the VPN without consent in the future. - * - * @hide - */ - @SystemApi - @RequiresPermission(android.Manifest.permission.CONTROL_VPN) - public static void prepareAndAuthorize(Context context) { - IConnectivityManager cm = getService(); - String packageName = context.getPackageName(); - try { - // Only prepare if we're not already prepared. - int userId = context.getUserId(); - if (!cm.prepareVpn(packageName, null, userId)) { - cm.prepareVpn(null, packageName, userId); - } - cm.setVpnPackageAuthorization(packageName, userId, VpnManager.TYPE_VPN_SERVICE); - } catch (RemoteException e) { - // ignore - } - } - - /** - * Protect a socket from VPN connections. After protecting, data sent - * through this socket will go directly to the underlying network, - * so its traffic will not be forwarded through the VPN. - * This method is useful if some connections need to be kept - * outside of VPN. For example, a VPN tunnel should protect itself if its - * destination is covered by VPN routes. Otherwise its outgoing packets - * will be sent back to the VPN interface and cause an infinite loop. This - * method will fail if the application is not prepared or is revoked. - * - *

The socket is NOT closed by this method. - * - * @return {@code true} on success. - */ - public boolean protect(int socket) { - return NetworkUtils.protectFromVpn(socket); - } - - /** - * Convenience method to protect a {@link Socket} from VPN connections. - * - * @return {@code true} on success. - * @see #protect(int) - */ - public boolean protect(Socket socket) { - return protect(socket.getFileDescriptor$().getInt$()); - } - - /** - * Convenience method to protect a {@link DatagramSocket} from VPN - * connections. - * - * @return {@code true} on success. - * @see #protect(int) - */ - public boolean protect(DatagramSocket socket) { - return protect(socket.getFileDescriptor$().getInt$()); - } - - /** - * Adds a network address to the VPN interface. - * - * Both IPv4 and IPv6 addresses are supported. The VPN must already be established. Fails if the - * address is already in use or cannot be assigned to the interface for any other reason. - * - * Adding an address implicitly allows traffic from that address family (i.e., IPv4 or IPv6) to - * be routed over the VPN. @see Builder#allowFamily - * - * @throws IllegalArgumentException if the address is invalid. - * - * @param address The IP address (IPv4 or IPv6) to assign to the VPN interface. - * @param prefixLength The prefix length of the address. - * - * @return {@code true} on success. - * @see Builder#addAddress - * - * @hide - */ - public boolean addAddress(InetAddress address, int prefixLength) { - check(address, prefixLength); - try { - return getService().addVpnAddress(address.getHostAddress(), prefixLength); - } catch (RemoteException e) { - throw new IllegalStateException(e); - } - } - - /** - * Removes a network address from the VPN interface. - * - * Both IPv4 and IPv6 addresses are supported. The VPN must already be established. Fails if the - * address is not assigned to the VPN interface, or if it is the only address assigned (thus - * cannot be removed), or if the address cannot be removed for any other reason. - * - * After removing an address, if there are no addresses, routes or DNS servers of a particular - * address family (i.e., IPv4 or IPv6) configured on the VPN, that DOES NOT block that - * family from being routed. In other words, once an address family has been allowed, it stays - * allowed for the rest of the VPN's session. @see Builder#allowFamily - * - * @throws IllegalArgumentException if the address is invalid. - * - * @param address The IP address (IPv4 or IPv6) to assign to the VPN interface. - * @param prefixLength The prefix length of the address. - * - * @return {@code true} on success. - * - * @hide - */ - public boolean removeAddress(InetAddress address, int prefixLength) { - check(address, prefixLength); - try { - return getService().removeVpnAddress(address.getHostAddress(), prefixLength); - } catch (RemoteException e) { - throw new IllegalStateException(e); - } - } - - /** - * Sets the underlying networks used by the VPN for its upstream connections. - * - *

Used by the system to know the actual networks that carry traffic for apps affected by - * this VPN in order to present this information to the user (e.g., via status bar icons). - * - *

This method only needs to be called if the VPN has explicitly bound its underlying - * communications channels — such as the socket(s) passed to {@link #protect(int)} — - * to a {@code Network} using APIs such as {@link Network#bindSocket(Socket)} or - * {@link Network#bindSocket(DatagramSocket)}. The VPN should call this method every time - * the set of {@code Network}s it is using changes. - * - *

{@code networks} is one of the following: - *

    - *
  • a non-empty array: an array of one or more {@link Network}s, in - * decreasing preference order. For example, if this VPN uses both wifi and mobile (cellular) - * networks to carry app traffic, but prefers or uses wifi more than mobile, wifi should appear - * first in the array.
  • - *
  • an empty array: a zero-element array, meaning that the VPN has no - * underlying network connection, and thus, app traffic will not be sent or received.
  • - *
  • null: (default) signifies that the VPN uses whatever is the system's - * default network. I.e., it doesn't use the {@code bindSocket} or {@code bindDatagramSocket} - * APIs mentioned above to send traffic over specific channels.
  • - *
- * - *

This call will succeed only if the VPN is currently established. For setting this value - * when the VPN has not yet been established, see {@link Builder#setUnderlyingNetworks}. - * - * @param networks An array of networks the VPN uses to tunnel traffic to/from its servers. - * - * @return {@code true} on success. - */ - public boolean setUnderlyingNetworks(Network[] networks) { - try { - return getService().setUnderlyingNetworksForVpn(networks); - } catch (RemoteException e) { - throw new IllegalStateException(e); - } - } - - /** - * Returns whether the service is running in always-on VPN mode. In this mode the system ensures - * that the service is always running by restarting it when necessary, e.g. after reboot. - * - * @see DevicePolicyManager#setAlwaysOnVpnPackage(ComponentName, String, boolean, Set) - */ - public final boolean isAlwaysOn() { - try { - return getService().isCallerCurrentAlwaysOnVpnApp(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Returns whether the service is running in always-on VPN lockdown mode. In this mode the - * system ensures that the service is always running and that the apps aren't allowed to bypass - * the VPN. - * - * @see DevicePolicyManager#setAlwaysOnVpnPackage(ComponentName, String, boolean, Set) - */ - public final boolean isLockdownEnabled() { - try { - return getService().isCallerCurrentAlwaysOnVpnLockdownApp(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Return the communication interface to the service. This method returns - * {@code null} on {@link Intent}s other than {@link #SERVICE_INTERFACE} - * action. Applications overriding this method must identify the intent - * and return the corresponding interface accordingly. - * - * @see Service#onBind - */ - @Override - public IBinder onBind(Intent intent) { - if (intent != null && SERVICE_INTERFACE.equals(intent.getAction())) { - return new Callback(); - } - return null; - } - - /** - * Invoked when the application is revoked. At this moment, the VPN - * interface is already deactivated by the system. The application should - * close the file descriptor and shut down gracefully. The default - * implementation of this method is calling {@link Service#stopSelf()}. - * - *

Calls to this method may not happen on the main thread - * of the process. - * - * @see #prepare - */ - public void onRevoke() { - stopSelf(); - } - - /** - * Use raw Binder instead of AIDL since now there is only one usage. - */ - private class Callback extends Binder { - @Override - protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) { - if (code == IBinder.LAST_CALL_TRANSACTION) { - onRevoke(); - return true; - } - return false; - } - } - - /** - * Private method to validate address and prefixLength. - */ - private static void check(InetAddress address, int prefixLength) { - if (address.isLoopbackAddress()) { - throw new IllegalArgumentException("Bad address"); - } - if (address instanceof Inet4Address) { - if (prefixLength < 0 || prefixLength > 32) { - throw new IllegalArgumentException("Bad prefixLength"); - } - } else if (address instanceof Inet6Address) { - if (prefixLength < 0 || prefixLength > 128) { - throw new IllegalArgumentException("Bad prefixLength"); - } - } else { - throw new IllegalArgumentException("Unsupported family"); - } - } - - /** - * Helper class to create a VPN interface. This class should be always - * used within the scope of the outer {@link VpnService}. - * - * @see VpnService - */ - public class Builder { - - private final VpnConfig mConfig = new VpnConfig(); - @UnsupportedAppUsage - private final List mAddresses = new ArrayList(); - @UnsupportedAppUsage - private final List mRoutes = new ArrayList(); - - public Builder() { - mConfig.user = VpnService.this.getClass().getName(); - } - - /** - * Set the name of this session. It will be displayed in - * system-managed dialogs and notifications. This is recommended - * not required. - */ - @NonNull - public Builder setSession(@NonNull String session) { - mConfig.session = session; - return this; - } - - /** - * Set the {@link PendingIntent} to an activity for users to - * configure the VPN connection. If it is not set, the button - * to configure will not be shown in system-managed dialogs. - */ - @NonNull - public Builder setConfigureIntent(@NonNull PendingIntent intent) { - mConfig.configureIntent = intent; - return this; - } - - /** - * Set the maximum transmission unit (MTU) of the VPN interface. If - * it is not set, the default value in the operating system will be - * used. - * - * @throws IllegalArgumentException if the value is not positive. - */ - @NonNull - public Builder setMtu(int mtu) { - if (mtu <= 0) { - throw new IllegalArgumentException("Bad mtu"); - } - mConfig.mtu = mtu; - return this; - } - - /** - * Sets an HTTP proxy for the VPN network. This proxy is only a recommendation - * and it is possible that some apps will ignore it. - */ - @NonNull - public Builder setHttpProxy(@NonNull ProxyInfo proxyInfo) { - mConfig.proxyInfo = proxyInfo; - return this; - } - - /** - * Add a network address to the VPN interface. Both IPv4 and IPv6 - * addresses are supported. At least one address must be set before - * calling {@link #establish}. - * - * Adding an address implicitly allows traffic from that address family - * (i.e., IPv4 or IPv6) to be routed over the VPN. @see #allowFamily - * - * @throws IllegalArgumentException if the address is invalid. - */ - @NonNull - public Builder addAddress(@NonNull InetAddress address, int prefixLength) { - check(address, prefixLength); - - if (address.isAnyLocalAddress()) { - throw new IllegalArgumentException("Bad address"); - } - mAddresses.add(new LinkAddress(address, prefixLength)); - mConfig.updateAllowedFamilies(address); - return this; - } - - /** - * Convenience method to add a network address to the VPN interface - * using a numeric address string. See {@link InetAddress} for the - * definitions of numeric address formats. - * - * Adding an address implicitly allows traffic from that address family - * (i.e., IPv4 or IPv6) to be routed over the VPN. @see #allowFamily - * - * @throws IllegalArgumentException if the address is invalid. - * @see #addAddress(InetAddress, int) - */ - @NonNull - public Builder addAddress(@NonNull String address, int prefixLength) { - return addAddress(InetAddress.parseNumericAddress(address), prefixLength); - } - - /** - * Add a network route to the VPN interface. Both IPv4 and IPv6 - * routes are supported. - * - * Adding a route implicitly allows traffic from that address family - * (i.e., IPv4 or IPv6) to be routed over the VPN. @see #allowFamily - * - * @throws IllegalArgumentException if the route is invalid. - */ - @NonNull - public Builder addRoute(@NonNull InetAddress address, int prefixLength) { - check(address, prefixLength); - - int offset = prefixLength / 8; - byte[] bytes = address.getAddress(); - if (offset < bytes.length) { - for (bytes[offset] <<= prefixLength % 8; offset < bytes.length; ++offset) { - if (bytes[offset] != 0) { - throw new IllegalArgumentException("Bad address"); - } - } - } - mRoutes.add(new RouteInfo(new IpPrefix(address, prefixLength), null)); - mConfig.updateAllowedFamilies(address); - return this; - } - - /** - * Convenience method to add a network route to the VPN interface - * using a numeric address string. See {@link InetAddress} for the - * definitions of numeric address formats. - * - * Adding a route implicitly allows traffic from that address family - * (i.e., IPv4 or IPv6) to be routed over the VPN. @see #allowFamily - * - * @throws IllegalArgumentException if the route is invalid. - * @see #addRoute(InetAddress, int) - */ - @NonNull - public Builder addRoute(@NonNull String address, int prefixLength) { - return addRoute(InetAddress.parseNumericAddress(address), prefixLength); - } - - /** - * Add a DNS server to the VPN connection. Both IPv4 and IPv6 - * addresses are supported. If none is set, the DNS servers of - * the default network will be used. - * - * Adding a server implicitly allows traffic from that address family - * (i.e., IPv4 or IPv6) to be routed over the VPN. @see #allowFamily - * - * @throws IllegalArgumentException if the address is invalid. - */ - @NonNull - public Builder addDnsServer(@NonNull InetAddress address) { - if (address.isLoopbackAddress() || address.isAnyLocalAddress()) { - throw new IllegalArgumentException("Bad address"); - } - if (mConfig.dnsServers == null) { - mConfig.dnsServers = new ArrayList(); - } - mConfig.dnsServers.add(address.getHostAddress()); - return this; - } - - /** - * Convenience method to add a DNS server to the VPN connection - * using a numeric address string. See {@link InetAddress} for the - * definitions of numeric address formats. - * - * Adding a server implicitly allows traffic from that address family - * (i.e., IPv4 or IPv6) to be routed over the VPN. @see #allowFamily - * - * @throws IllegalArgumentException if the address is invalid. - * @see #addDnsServer(InetAddress) - */ - @NonNull - public Builder addDnsServer(@NonNull String address) { - return addDnsServer(InetAddress.parseNumericAddress(address)); - } - - /** - * Add a search domain to the DNS resolver. - */ - @NonNull - public Builder addSearchDomain(@NonNull String domain) { - if (mConfig.searchDomains == null) { - mConfig.searchDomains = new ArrayList(); - } - mConfig.searchDomains.add(domain); - return this; - } - - /** - * Allows traffic from the specified address family. - * - * By default, if no address, route or DNS server of a specific family (IPv4 or IPv6) is - * added to this VPN, then all outgoing traffic of that family is blocked. If any address, - * route or DNS server is added, that family is allowed. - * - * This method allows an address family to be unblocked even without adding an address, - * route or DNS server of that family. Traffic of that family will then typically - * fall-through to the underlying network if it's supported. - * - * {@code family} must be either {@code AF_INET} (for IPv4) or {@code AF_INET6} (for IPv6). - * {@link IllegalArgumentException} is thrown if it's neither. - * - * @param family The address family ({@code AF_INET} or {@code AF_INET6}) to allow. - * - * @return this {@link Builder} object to facilitate chaining of method calls. - */ - @NonNull - public Builder allowFamily(int family) { - if (family == AF_INET) { - mConfig.allowIPv4 = true; - } else if (family == AF_INET6) { - mConfig.allowIPv6 = true; - } else { - throw new IllegalArgumentException(family + " is neither " + AF_INET + " nor " + - AF_INET6); - } - return this; - } - - private void verifyApp(String packageName) throws PackageManager.NameNotFoundException { - IPackageManager pm = IPackageManager.Stub.asInterface( - ServiceManager.getService("package")); - try { - pm.getApplicationInfo(packageName, 0, UserHandle.getCallingUserId()); - } catch (RemoteException e) { - throw new IllegalStateException(e); - } - } - - /** - * Adds an application that's allowed to access the VPN connection. - * - * If this method is called at least once, only applications added through this method (and - * no others) are allowed access. Else (if this method is never called), all applications - * are allowed by default. If some applications are added, other, un-added applications - * will use networking as if the VPN wasn't running. - * - * A {@link Builder} may have only a set of allowed applications OR a set of disallowed - * ones, but not both. Calling this method after {@link #addDisallowedApplication} has - * already been called, or vice versa, will throw an {@link UnsupportedOperationException}. - * - * {@code packageName} must be the canonical name of a currently installed application. - * {@link PackageManager.NameNotFoundException} is thrown if there's no such application. - * - * @throws PackageManager.NameNotFoundException If the application isn't installed. - * - * @param packageName The full name (e.g.: "com.google.apps.contacts") of an application. - * - * @return this {@link Builder} object to facilitate chaining method calls. - */ - @NonNull - public Builder addAllowedApplication(@NonNull String packageName) - throws PackageManager.NameNotFoundException { - if (mConfig.disallowedApplications != null) { - throw new UnsupportedOperationException("addDisallowedApplication already called"); - } - verifyApp(packageName); - if (mConfig.allowedApplications == null) { - mConfig.allowedApplications = new ArrayList(); - } - mConfig.allowedApplications.add(packageName); - return this; - } - - /** - * Adds an application that's denied access to the VPN connection. - * - * By default, all applications are allowed access, except for those denied through this - * method. Denied applications will use networking as if the VPN wasn't running. - * - * A {@link Builder} may have only a set of allowed applications OR a set of disallowed - * ones, but not both. Calling this method after {@link #addAllowedApplication} has already - * been called, or vice versa, will throw an {@link UnsupportedOperationException}. - * - * {@code packageName} must be the canonical name of a currently installed application. - * {@link PackageManager.NameNotFoundException} is thrown if there's no such application. - * - * @throws PackageManager.NameNotFoundException If the application isn't installed. - * - * @param packageName The full name (e.g.: "com.google.apps.contacts") of an application. - * - * @return this {@link Builder} object to facilitate chaining method calls. - */ - @NonNull - public Builder addDisallowedApplication(@NonNull String packageName) - throws PackageManager.NameNotFoundException { - if (mConfig.allowedApplications != null) { - throw new UnsupportedOperationException("addAllowedApplication already called"); - } - verifyApp(packageName); - if (mConfig.disallowedApplications == null) { - mConfig.disallowedApplications = new ArrayList(); - } - mConfig.disallowedApplications.add(packageName); - return this; - } - - /** - * Allows all apps to bypass this VPN connection. - * - * By default, all traffic from apps is forwarded through the VPN interface and it is not - * possible for apps to side-step the VPN. If this method is called, apps may use methods - * such as {@link ConnectivityManager#bindProcessToNetwork} to instead send/receive - * directly over the underlying network or any other network they have permissions for. - * - * @return this {@link Builder} object to facilitate chaining of method calls. - */ - @NonNull - public Builder allowBypass() { - mConfig.allowBypass = true; - return this; - } - - /** - * Sets the VPN interface's file descriptor to be in blocking/non-blocking mode. - * - * By default, the file descriptor returned by {@link #establish} is non-blocking. - * - * @param blocking True to put the descriptor into blocking mode; false for non-blocking. - * - * @return this {@link Builder} object to facilitate chaining method calls. - */ - @NonNull - public Builder setBlocking(boolean blocking) { - mConfig.blocking = blocking; - return this; - } - - /** - * Sets the underlying networks used by the VPN for its upstream connections. - * - * @see VpnService#setUnderlyingNetworks - * - * @param networks An array of networks the VPN uses to tunnel traffic to/from its servers. - * - * @return this {@link Builder} object to facilitate chaining method calls. - */ - @NonNull - public Builder setUnderlyingNetworks(@Nullable Network[] networks) { - mConfig.underlyingNetworks = networks != null ? networks.clone() : null; - return this; - } - - /** - * Marks the VPN network as metered. A VPN network is classified as metered when the user is - * sensitive to heavy data usage due to monetary costs and/or data limitations. In such - * cases, you should set this to {@code true} so that apps on the system can avoid doing - * large data transfers. Otherwise, set this to {@code false}. Doing so would cause VPN - * network to inherit its meteredness from its underlying networks. - * - *

VPN apps targeting {@link android.os.Build.VERSION_CODES#Q} or above will be - * considered metered by default. - * - * @param isMetered {@code true} if VPN network should be treated as metered regardless of - * underlying network meteredness - * @return this {@link Builder} object to facilitate chaining method calls - * @see #setUnderlyingNetworks(Network[]) - * @see ConnectivityManager#isActiveNetworkMetered() - */ - @NonNull - public Builder setMetered(boolean isMetered) { - mConfig.isMetered = isMetered; - return this; - } - - /** - * Create a VPN interface using the parameters supplied to this - * builder. The interface works on IP packets, and a file descriptor - * is returned for the application to access them. Each read - * retrieves an outgoing packet which was routed to the interface. - * Each write injects an incoming packet just like it was received - * from the interface. The file descriptor is put into non-blocking - * mode by default to avoid blocking Java threads. To use the file - * descriptor completely in native space, see - * {@link ParcelFileDescriptor#detachFd()}. The application MUST - * close the file descriptor when the VPN connection is terminated. - * The VPN interface will be removed and the network will be - * restored by the system automatically. - * - *

To avoid conflicts, there can be only one active VPN interface - * at the same time. Usually network parameters are never changed - * during the lifetime of a VPN connection. It is also common for an - * application to create a new file descriptor after closing the - * previous one. However, it is rare but not impossible to have two - * interfaces while performing a seamless handover. In this case, the - * old interface will be deactivated when the new one is created - * successfully. Both file descriptors are valid but now outgoing - * packets will be routed to the new interface. Therefore, after - * draining the old file descriptor, the application MUST close it - * and start using the new file descriptor. If the new interface - * cannot be created, the existing interface and its file descriptor - * remain untouched. - * - *

An exception will be thrown if the interface cannot be created - * for any reason. However, this method returns {@code null} if the - * application is not prepared or is revoked. This helps solve - * possible race conditions between other VPN applications. - * - * @return {@link ParcelFileDescriptor} of the VPN interface, or - * {@code null} if the application is not prepared. - * @throws IllegalArgumentException if a parameter is not accepted - * by the operating system. - * @throws IllegalStateException if a parameter cannot be applied - * by the operating system. - * @throws SecurityException if the service is not properly declared - * in {@code AndroidManifest.xml}. - * @see VpnService - */ - @Nullable - public ParcelFileDescriptor establish() { - mConfig.addresses = mAddresses; - mConfig.routes = mRoutes; - - try { - return getService().establishVpn(mConfig); - } catch (RemoteException e) { - throw new IllegalStateException(e); - } - } - } -} diff --git a/core/java/android/net/apf/ApfCapabilities.aidl b/core/java/android/net/apf/ApfCapabilities.aidl deleted file mode 100644 index 7c4d4c2da4bc..000000000000 --- a/core/java/android/net/apf/ApfCapabilities.aidl +++ /dev/null @@ -1,20 +0,0 @@ -/* -** -** Copyright (C) 2019 The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -package android.net.apf; - -@JavaOnlyStableParcelable parcelable ApfCapabilities; \ No newline at end of file diff --git a/core/java/android/net/apf/ApfCapabilities.java b/core/java/android/net/apf/ApfCapabilities.java deleted file mode 100644 index bf5b26e278f9..000000000000 --- a/core/java/android/net/apf/ApfCapabilities.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net.apf; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.SystemApi; -import android.content.res.Resources; -import android.os.Parcel; -import android.os.Parcelable; - -import com.android.internal.R; - -/** - * APF program support capabilities. APF stands for Android Packet Filtering and it is a flexible - * way to drop unwanted network packets to save power. - * - * See documentation at hardware/google/apf/apf.h - * - * This class is immutable. - * @hide - */ -@SystemApi -public final class ApfCapabilities implements Parcelable { - /** - * Version of APF instruction set supported for packet filtering. 0 indicates no support for - * packet filtering using APF programs. - */ - public final int apfVersionSupported; - - /** - * Maximum size of APF program allowed. - */ - public final int maximumApfProgramSize; - - /** - * Format of packets passed to APF filter. Should be one of ARPHRD_* - */ - public final int apfPacketFormat; - - public ApfCapabilities( - int apfVersionSupported, int maximumApfProgramSize, int apfPacketFormat) { - this.apfVersionSupported = apfVersionSupported; - this.maximumApfProgramSize = maximumApfProgramSize; - this.apfPacketFormat = apfPacketFormat; - } - - private ApfCapabilities(Parcel in) { - apfVersionSupported = in.readInt(); - maximumApfProgramSize = in.readInt(); - apfPacketFormat = in.readInt(); - } - - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(apfVersionSupported); - dest.writeInt(maximumApfProgramSize); - dest.writeInt(apfPacketFormat); - } - - public static final Creator CREATOR = new Creator() { - @Override - public ApfCapabilities createFromParcel(Parcel in) { - return new ApfCapabilities(in); - } - - @Override - public ApfCapabilities[] newArray(int size) { - return new ApfCapabilities[size]; - } - }; - - @NonNull - @Override - public String toString() { - return String.format("%s{version: %d, maxSize: %d, format: %d}", getClass().getSimpleName(), - apfVersionSupported, maximumApfProgramSize, apfPacketFormat); - } - - @Override - public boolean equals(@Nullable Object obj) { - if (!(obj instanceof ApfCapabilities)) return false; - final ApfCapabilities other = (ApfCapabilities) obj; - return apfVersionSupported == other.apfVersionSupported - && maximumApfProgramSize == other.maximumApfProgramSize - && apfPacketFormat == other.apfPacketFormat; - } - - /** - * Determines whether the APF interpreter advertises support for the data buffer access opcodes - * LDDW (LoaD Data Word) and STDW (STore Data Word). Full LDDW (LoaD Data Word) and - * STDW (STore Data Word) support is present from APFv4 on. - * - * @return {@code true} if the IWifiStaIface#readApfPacketFilterData is supported. - */ - public boolean hasDataAccess() { - return apfVersionSupported >= 4; - } - - /** - * @return Whether the APF Filter in the device should filter out IEEE 802.3 Frames. - */ - public static boolean getApfDrop8023Frames() { - return Resources.getSystem().getBoolean(R.bool.config_apfDrop802_3Frames); - } - - /** - * @return An array of denylisted EtherType, packets with EtherTypes within it will be dropped. - */ - public static @NonNull int[] getApfEtherTypeBlackList() { - return Resources.getSystem().getIntArray(R.array.config_apfEthTypeBlackList); - } -} diff --git a/core/java/android/net/util/DnsUtils.java b/core/java/android/net/util/DnsUtils.java deleted file mode 100644 index 7908353eeda2..000000000000 --- a/core/java/android/net/util/DnsUtils.java +++ /dev/null @@ -1,379 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net.util; - -import static android.system.OsConstants.AF_INET; -import static android.system.OsConstants.AF_INET6; -import static android.system.OsConstants.IPPROTO_UDP; -import static android.system.OsConstants.SOCK_DGRAM; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.net.InetAddresses; -import android.net.Network; -import android.system.ErrnoException; -import android.system.Os; -import android.util.Log; - -import com.android.internal.util.BitUtils; - -import libcore.io.IoUtils; - -import java.io.FileDescriptor; -import java.io.IOException; -import java.net.Inet4Address; -import java.net.Inet6Address; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.SocketAddress; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; - -/** - * @hide - */ -public class DnsUtils { - private static final String TAG = "DnsUtils"; - private static final int CHAR_BIT = 8; - public static final int IPV6_ADDR_SCOPE_NODELOCAL = 0x01; - public static final int IPV6_ADDR_SCOPE_LINKLOCAL = 0x02; - public static final int IPV6_ADDR_SCOPE_SITELOCAL = 0x05; - public static final int IPV6_ADDR_SCOPE_GLOBAL = 0x0e; - private static final Comparator sRfc6724Comparator = new Rfc6724Comparator(); - - /** - * Comparator to sort SortableAddress in Rfc6724 style. - */ - public static class Rfc6724Comparator implements Comparator { - // This function matches the behaviour of _rfc6724_compare in the native resolver. - @Override - public int compare(SortableAddress span1, SortableAddress span2) { - // Rule 1: Avoid unusable destinations. - if (span1.hasSrcAddr != span2.hasSrcAddr) { - return span2.hasSrcAddr - span1.hasSrcAddr; - } - - // Rule 2: Prefer matching scope. - if (span1.scopeMatch != span2.scopeMatch) { - return span2.scopeMatch - span1.scopeMatch; - } - - // TODO: Implement rule 3: Avoid deprecated addresses. - // TODO: Implement rule 4: Prefer home addresses. - - // Rule 5: Prefer matching label. - if (span1.labelMatch != span2.labelMatch) { - return span2.labelMatch - span1.labelMatch; - } - - // Rule 6: Prefer higher precedence. - if (span1.precedence != span2.precedence) { - return span2.precedence - span1.precedence; - } - - // TODO: Implement rule 7: Prefer native transport. - - // Rule 8: Prefer smaller scope. - if (span1.scope != span2.scope) { - return span1.scope - span2.scope; - } - - // Rule 9: Use longest matching prefix. IPv6 only. - if (span1.prefixMatchLen != span2.prefixMatchLen) { - return span2.prefixMatchLen - span1.prefixMatchLen; - } - - // Rule 10: Leave the order unchanged. Collections.sort is a stable sort. - return 0; - } - } - - /** - * Class used to sort with RFC 6724 - */ - public static class SortableAddress { - public final int label; - public final int labelMatch; - public final int scope; - public final int scopeMatch; - public final int precedence; - public final int prefixMatchLen; - public final int hasSrcAddr; - public final InetAddress address; - - public SortableAddress(@NonNull InetAddress addr, @Nullable InetAddress srcAddr) { - address = addr; - hasSrcAddr = (srcAddr != null) ? 1 : 0; - label = findLabel(addr); - scope = findScope(addr); - precedence = findPrecedence(addr); - labelMatch = ((srcAddr != null) && (label == findLabel(srcAddr))) ? 1 : 0; - scopeMatch = ((srcAddr != null) && (scope == findScope(srcAddr))) ? 1 : 0; - if (isIpv6Address(addr) && isIpv6Address(srcAddr)) { - prefixMatchLen = compareIpv6PrefixMatchLen(srcAddr, addr); - } else { - prefixMatchLen = 0; - } - } - } - - /** - * Sort the given address list in RFC6724 order. - * Will leave the list unchanged if an error occurs. - * - * This function matches the behaviour of _rfc6724_sort in the native resolver. - */ - public static @NonNull List rfc6724Sort(@Nullable Network network, - @NonNull List answers) { - final ArrayList sortableAnswerList = new ArrayList<>(); - for (InetAddress addr : answers) { - sortableAnswerList.add(new SortableAddress(addr, findSrcAddress(network, addr))); - } - - Collections.sort(sortableAnswerList, sRfc6724Comparator); - - final List sortedAnswers = new ArrayList<>(); - for (SortableAddress ans : sortableAnswerList) { - sortedAnswers.add(ans.address); - } - - return sortedAnswers; - } - - private static @Nullable InetAddress findSrcAddress(@Nullable Network network, - @NonNull InetAddress addr) { - final int domain; - if (isIpv4Address(addr)) { - domain = AF_INET; - } else if (isIpv6Address(addr)) { - domain = AF_INET6; - } else { - return null; - } - final FileDescriptor socket; - try { - socket = Os.socket(domain, SOCK_DGRAM, IPPROTO_UDP); - } catch (ErrnoException e) { - Log.e(TAG, "findSrcAddress:" + e.toString()); - return null; - } - try { - if (network != null) network.bindSocket(socket); - Os.connect(socket, new InetSocketAddress(addr, 0)); - return ((InetSocketAddress) Os.getsockname(socket)).getAddress(); - } catch (IOException | ErrnoException e) { - return null; - } finally { - IoUtils.closeQuietly(socket); - } - } - - /** - * Get the label for a given IPv4/IPv6 address. - * RFC 6724, section 2.1. - * - * Note that Java will return an IPv4-mapped address as an IPv4 address. - */ - private static int findLabel(@NonNull InetAddress addr) { - if (isIpv4Address(addr)) { - return 4; - } else if (isIpv6Address(addr)) { - if (addr.isLoopbackAddress()) { - return 0; - } else if (isIpv6Address6To4(addr)) { - return 2; - } else if (isIpv6AddressTeredo(addr)) { - return 5; - } else if (isIpv6AddressULA(addr)) { - return 13; - } else if (((Inet6Address) addr).isIPv4CompatibleAddress()) { - return 3; - } else if (addr.isSiteLocalAddress()) { - return 11; - } else if (isIpv6Address6Bone(addr)) { - return 12; - } else { - // All other IPv6 addresses, including global unicast addresses. - return 1; - } - } else { - // This should never happen. - return 1; - } - } - - private static boolean isIpv6Address(@Nullable InetAddress addr) { - return addr instanceof Inet6Address; - } - - private static boolean isIpv4Address(@Nullable InetAddress addr) { - return addr instanceof Inet4Address; - } - - private static boolean isIpv6Address6To4(@NonNull InetAddress addr) { - if (!isIpv6Address(addr)) return false; - final byte[] byteAddr = addr.getAddress(); - return byteAddr[0] == 0x20 && byteAddr[1] == 0x02; - } - - private static boolean isIpv6AddressTeredo(@NonNull InetAddress addr) { - if (!isIpv6Address(addr)) return false; - final byte[] byteAddr = addr.getAddress(); - return byteAddr[0] == 0x20 && byteAddr[1] == 0x01 && byteAddr[2] == 0x00 - && byteAddr[3] == 0x00; - } - - private static boolean isIpv6AddressULA(@NonNull InetAddress addr) { - return isIpv6Address(addr) && (addr.getAddress()[0] & 0xfe) == 0xfc; - } - - private static boolean isIpv6Address6Bone(@NonNull InetAddress addr) { - if (!isIpv6Address(addr)) return false; - final byte[] byteAddr = addr.getAddress(); - return byteAddr[0] == 0x3f && byteAddr[1] == (byte) 0xfe; - } - - private static int getIpv6MulticastScope(@NonNull InetAddress addr) { - return !isIpv6Address(addr) ? 0 : (addr.getAddress()[1] & 0x0f); - } - - private static int findScope(@NonNull InetAddress addr) { - if (isIpv6Address(addr)) { - if (addr.isMulticastAddress()) { - return getIpv6MulticastScope(addr); - } else if (addr.isLoopbackAddress() || addr.isLinkLocalAddress()) { - /** - * RFC 4291 section 2.5.3 says loopback is to be treated as having - * link-local scope. - */ - return IPV6_ADDR_SCOPE_LINKLOCAL; - } else if (addr.isSiteLocalAddress()) { - return IPV6_ADDR_SCOPE_SITELOCAL; - } else { - return IPV6_ADDR_SCOPE_GLOBAL; - } - } else if (isIpv4Address(addr)) { - if (addr.isLoopbackAddress() || addr.isLinkLocalAddress()) { - return IPV6_ADDR_SCOPE_LINKLOCAL; - } else { - /** - * RFC 6724 section 3.2. Other IPv4 addresses, including private addresses - * and shared addresses (100.64.0.0/10), are assigned global scope. - */ - return IPV6_ADDR_SCOPE_GLOBAL; - } - } else { - /** - * This should never happen. - * Return a scope with low priority as a last resort. - */ - return IPV6_ADDR_SCOPE_NODELOCAL; - } - } - - /** - * Get the precedence for a given IPv4/IPv6 address. - * RFC 6724, section 2.1. - * - * Note that Java will return an IPv4-mapped address as an IPv4 address. - */ - private static int findPrecedence(@NonNull InetAddress addr) { - if (isIpv4Address(addr)) { - return 35; - } else if (isIpv6Address(addr)) { - if (addr.isLoopbackAddress()) { - return 50; - } else if (isIpv6Address6To4(addr)) { - return 30; - } else if (isIpv6AddressTeredo(addr)) { - return 5; - } else if (isIpv6AddressULA(addr)) { - return 3; - } else if (((Inet6Address) addr).isIPv4CompatibleAddress() || addr.isSiteLocalAddress() - || isIpv6Address6Bone(addr)) { - return 1; - } else { - // All other IPv6 addresses, including global unicast addresses. - return 40; - } - } else { - return 1; - } - } - - /** - * Find number of matching initial bits between the two addresses. - */ - private static int compareIpv6PrefixMatchLen(@NonNull InetAddress srcAddr, - @NonNull InetAddress dstAddr) { - final byte[] srcByte = srcAddr.getAddress(); - final byte[] dstByte = dstAddr.getAddress(); - - // This should never happen. - if (srcByte.length != dstByte.length) return 0; - - for (int i = 0; i < dstByte.length; ++i) { - if (srcByte[i] == dstByte[i]) { - continue; - } - int x = BitUtils.uint8(srcByte[i]) ^ BitUtils.uint8(dstByte[i]); - return i * CHAR_BIT + (Integer.numberOfLeadingZeros(x) - 24); // Java ints are 32 bits - } - return dstByte.length * CHAR_BIT; - } - - /** - * Check if given network has Ipv4 capability - * This function matches the behaviour of have_ipv4 in the native resolver. - */ - public static boolean haveIpv4(@Nullable Network network) { - final SocketAddress addrIpv4 = - new InetSocketAddress(InetAddresses.parseNumericAddress("8.8.8.8"), 0); - return checkConnectivity(network, AF_INET, addrIpv4); - } - - /** - * Check if given network has Ipv6 capability - * This function matches the behaviour of have_ipv6 in the native resolver. - */ - public static boolean haveIpv6(@Nullable Network network) { - final SocketAddress addrIpv6 = - new InetSocketAddress(InetAddresses.parseNumericAddress("2000::"), 0); - return checkConnectivity(network, AF_INET6, addrIpv6); - } - - private static boolean checkConnectivity(@Nullable Network network, - int domain, @NonNull SocketAddress addr) { - final FileDescriptor socket; - try { - socket = Os.socket(domain, SOCK_DGRAM, IPPROTO_UDP); - } catch (ErrnoException e) { - return false; - } - try { - if (network != null) network.bindSocket(socket); - Os.connect(socket, addr); - } catch (IOException | ErrnoException e) { - return false; - } finally { - IoUtils.closeQuietly(socket); - } - return true; - } -} diff --git a/core/java/android/net/util/KeepaliveUtils.java b/core/java/android/net/util/KeepaliveUtils.java deleted file mode 100644 index bfc4563fbf8f..000000000000 --- a/core/java/android/net/util/KeepaliveUtils.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net.util; - -import android.annotation.NonNull; -import android.content.Context; -import android.content.res.Resources; -import android.net.NetworkCapabilities; -import android.text.TextUtils; -import android.util.AndroidRuntimeException; - -import com.android.internal.R; - -/** - * Collection of utilities for socket keepalive offload. - * - * @hide - */ -public final class KeepaliveUtils { - - public static final String TAG = "KeepaliveUtils"; - - public static class KeepaliveDeviceConfigurationException extends AndroidRuntimeException { - public KeepaliveDeviceConfigurationException(final String msg) { - super(msg); - } - } - - /** - * Read supported keepalive count for each transport type from overlay resource. This should be - * used to create a local variable store of resource customization, and use it as the input for - * {@link getSupportedKeepalivesForNetworkCapabilities}. - * - * @param context The context to read resource from. - * @return An array of supported keepalive count for each transport type. - */ - @NonNull - public static int[] getSupportedKeepalives(@NonNull Context context) { - String[] res = null; - try { - res = context.getResources().getStringArray( - R.array.config_networkSupportedKeepaliveCount); - } catch (Resources.NotFoundException unused) { - } - if (res == null) throw new KeepaliveDeviceConfigurationException("invalid resource"); - - final int[] ret = new int[NetworkCapabilities.MAX_TRANSPORT + 1]; - for (final String row : res) { - if (TextUtils.isEmpty(row)) { - throw new KeepaliveDeviceConfigurationException("Empty string"); - } - final String[] arr = row.split(","); - if (arr.length != 2) { - throw new KeepaliveDeviceConfigurationException("Invalid parameter length"); - } - - int transport; - int supported; - try { - transport = Integer.parseInt(arr[0]); - supported = Integer.parseInt(arr[1]); - } catch (NumberFormatException e) { - throw new KeepaliveDeviceConfigurationException("Invalid number format"); - } - - if (!NetworkCapabilities.isValidTransport(transport)) { - throw new KeepaliveDeviceConfigurationException("Invalid transport " + transport); - } - - if (supported < 0) { - throw new KeepaliveDeviceConfigurationException( - "Invalid supported count " + supported + " for " - + NetworkCapabilities.transportNameOf(transport)); - } - ret[transport] = supported; - } - return ret; - } - - /** - * Get supported keepalive count for the given {@link NetworkCapabilities}. - * - * @param supportedKeepalives An array of supported keepalive count for each transport type. - * @param nc The {@link NetworkCapabilities} of the network the socket keepalive is on. - * - * @return Supported keepalive count for the given {@link NetworkCapabilities}. - */ - public static int getSupportedKeepalivesForNetworkCapabilities( - @NonNull int[] supportedKeepalives, @NonNull NetworkCapabilities nc) { - final int[] transports = nc.getTransportTypes(); - if (transports.length == 0) return 0; - int supportedCount = supportedKeepalives[transports[0]]; - // Iterate through transports and return minimum supported value. - for (final int transport : transports) { - if (supportedCount > supportedKeepalives[transport]) { - supportedCount = supportedKeepalives[transport]; - } - } - return supportedCount; - } -} diff --git a/core/java/android/net/util/MultinetworkPolicyTracker.java b/core/java/android/net/util/MultinetworkPolicyTracker.java deleted file mode 100644 index 85e3fa3048ed..000000000000 --- a/core/java/android/net/util/MultinetworkPolicyTracker.java +++ /dev/null @@ -1,217 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net.util; - -import static android.provider.Settings.Global.NETWORK_AVOID_BAD_WIFI; -import static android.provider.Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE; - -import android.annotation.NonNull; -import android.content.BroadcastReceiver; -import android.content.ContentResolver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.res.Resources; -import android.database.ContentObserver; -import android.net.Uri; -import android.os.Handler; -import android.provider.Settings; -import android.telephony.PhoneStateListener; -import android.telephony.SubscriptionManager; -import android.telephony.TelephonyManager; -import android.util.Log; - -import com.android.internal.R; -import com.android.internal.annotations.VisibleForTesting; - -import java.util.Arrays; -import java.util.List; - -/** - * A class to encapsulate management of the "Smart Networking" capability of - * avoiding bad Wi-Fi when, for example upstream connectivity is lost or - * certain critical link failures occur. - * - * This enables the device to switch to another form of connectivity, like - * mobile, if it's available and working. - * - * The Runnable |avoidBadWifiCallback|, if given, is posted to the supplied - * Handler' whenever the computed "avoid bad wifi" value changes. - * - * Disabling this reverts the device to a level of networking sophistication - * circa 2012-13 by disabling disparate code paths each of which contribute to - * maintaining continuous, working Internet connectivity. - * - * @hide - */ -public class MultinetworkPolicyTracker { - private static String TAG = MultinetworkPolicyTracker.class.getSimpleName(); - - private final Context mContext; - private final Handler mHandler; - private final Runnable mAvoidBadWifiCallback; - private final List mSettingsUris; - private final ContentResolver mResolver; - private final SettingObserver mSettingObserver; - private final BroadcastReceiver mBroadcastReceiver; - - private volatile boolean mAvoidBadWifi = true; - private volatile int mMeteredMultipathPreference; - private int mActiveSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; - - public MultinetworkPolicyTracker(Context ctx, Handler handler) { - this(ctx, handler, null); - } - - public MultinetworkPolicyTracker(Context ctx, Handler handler, Runnable avoidBadWifiCallback) { - mContext = ctx; - mHandler = handler; - mAvoidBadWifiCallback = avoidBadWifiCallback; - mSettingsUris = Arrays.asList( - Settings.Global.getUriFor(NETWORK_AVOID_BAD_WIFI), - Settings.Global.getUriFor(NETWORK_METERED_MULTIPATH_PREFERENCE)); - mResolver = mContext.getContentResolver(); - mSettingObserver = new SettingObserver(); - mBroadcastReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - reevaluateInternal(); - } - }; - - ctx.getSystemService(TelephonyManager.class).listen( - new PhoneStateListener(handler.getLooper()) { - @Override - public void onActiveDataSubscriptionIdChanged(int subId) { - mActiveSubId = subId; - reevaluateInternal(); - } - }, PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE); - - updateAvoidBadWifi(); - updateMeteredMultipathPreference(); - } - - public void start() { - for (Uri uri : mSettingsUris) { - mResolver.registerContentObserver(uri, false, mSettingObserver); - } - - final IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); - mContext.registerReceiverForAllUsers(mBroadcastReceiver, intentFilter, - null /* broadcastPermission */, mHandler); - - reevaluate(); - } - - public void shutdown() { - mResolver.unregisterContentObserver(mSettingObserver); - - mContext.unregisterReceiver(mBroadcastReceiver); - } - - public boolean getAvoidBadWifi() { - return mAvoidBadWifi; - } - - // TODO: move this to MultipathPolicyTracker. - public int getMeteredMultipathPreference() { - return mMeteredMultipathPreference; - } - - /** - * Whether the device or carrier configuration disables avoiding bad wifi by default. - */ - public boolean configRestrictsAvoidBadWifi() { - return (getResourcesForActiveSubId().getInteger(R.integer.config_networkAvoidBadWifi) == 0); - } - - @NonNull - private Resources getResourcesForActiveSubId() { - return SubscriptionManager.getResourcesForSubId(mContext, mActiveSubId); - } - - /** - * Whether we should display a notification when wifi becomes unvalidated. - */ - public boolean shouldNotifyWifiUnvalidated() { - return configRestrictsAvoidBadWifi() && getAvoidBadWifiSetting() == null; - } - - public String getAvoidBadWifiSetting() { - return Settings.Global.getString(mResolver, NETWORK_AVOID_BAD_WIFI); - } - - @VisibleForTesting - public void reevaluate() { - mHandler.post(this::reevaluateInternal); - } - - /** - * Reevaluate the settings. Must be called on the handler thread. - */ - private void reevaluateInternal() { - if (updateAvoidBadWifi() && mAvoidBadWifiCallback != null) { - mAvoidBadWifiCallback.run(); - } - updateMeteredMultipathPreference(); - } - - public boolean updateAvoidBadWifi() { - final boolean settingAvoidBadWifi = "1".equals(getAvoidBadWifiSetting()); - final boolean prev = mAvoidBadWifi; - mAvoidBadWifi = settingAvoidBadWifi || !configRestrictsAvoidBadWifi(); - return mAvoidBadWifi != prev; - } - - /** - * The default (device and carrier-dependent) value for metered multipath preference. - */ - public int configMeteredMultipathPreference() { - return mContext.getResources().getInteger( - R.integer.config_networkMeteredMultipathPreference); - } - - public void updateMeteredMultipathPreference() { - String setting = Settings.Global.getString(mResolver, NETWORK_METERED_MULTIPATH_PREFERENCE); - try { - mMeteredMultipathPreference = Integer.parseInt(setting); - } catch (NumberFormatException e) { - mMeteredMultipathPreference = configMeteredMultipathPreference(); - } - } - - private class SettingObserver extends ContentObserver { - public SettingObserver() { - super(null); - } - - @Override - public void onChange(boolean selfChange) { - Log.wtf(TAG, "Should never be reached."); - } - - @Override - public void onChange(boolean selfChange, Uri uri) { - if (!mSettingsUris.contains(uri)) { - Log.wtf(TAG, "Unexpected settings observation: " + uri); - } - reevaluate(); - } - } -} diff --git a/core/java/android/net/util/SocketUtils.java b/core/java/android/net/util/SocketUtils.java deleted file mode 100644 index e64060f1b220..000000000000 --- a/core/java/android/net/util/SocketUtils.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net.util; - -import static android.system.OsConstants.SOL_SOCKET; -import static android.system.OsConstants.SO_BINDTODEVICE; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.SystemApi; -import android.net.NetworkUtils; -import android.system.ErrnoException; -import android.system.NetlinkSocketAddress; -import android.system.Os; -import android.system.PacketSocketAddress; - -import libcore.io.IoBridge; - -import java.io.FileDescriptor; -import java.io.IOException; -import java.net.SocketAddress; - -/** - * Collection of utilities to interact with raw sockets. - * @hide - */ -@SystemApi -public final class SocketUtils { - /** - * Create a raw datagram socket that is bound to an interface. - * - *

Data sent through the socket will go directly to the underlying network, ignoring VPNs. - */ - public static void bindSocketToInterface(@NonNull FileDescriptor socket, @NonNull String iface) - throws ErrnoException { - // SO_BINDTODEVICE actually takes a string. This works because the first member - // of struct ifreq is a NULL-terminated interface name. - // TODO: add a setsockoptString() - Os.setsockoptIfreq(socket, SOL_SOCKET, SO_BINDTODEVICE, iface); - NetworkUtils.protectFromVpn(socket); - } - - /** - * Make a socket address to communicate with netlink. - */ - @NonNull - public static SocketAddress makeNetlinkSocketAddress(int portId, int groupsMask) { - return new NetlinkSocketAddress(portId, groupsMask); - } - - /** - * Make socket address that packet sockets can bind to. - * - * @param protocol the layer 2 protocol of the packets to receive. One of the {@code ETH_P_*} - * constants in {@link android.system.OsConstants}. - * @param ifIndex the interface index on which packets will be received. - */ - @NonNull - public static SocketAddress makePacketSocketAddress(int protocol, int ifIndex) { - return new PacketSocketAddress( - protocol /* sll_protocol */, - ifIndex /* sll_ifindex */, - null /* sll_addr */); - } - - /** - * Make a socket address that packet socket can send packets to. - * @deprecated Use {@link #makePacketSocketAddress(int, int, byte[])} instead. - * - * @param ifIndex the interface index on which packets will be sent. - * @param hwAddr the hardware address to which packets will be sent. - */ - @Deprecated - @NonNull - public static SocketAddress makePacketSocketAddress(int ifIndex, @NonNull byte[] hwAddr) { - return new PacketSocketAddress( - 0 /* sll_protocol */, - ifIndex /* sll_ifindex */, - hwAddr /* sll_addr */); - } - - /** - * Make a socket address that a packet socket can send packets to. - * - * @param protocol the layer 2 protocol of the packets to send. One of the {@code ETH_P_*} - * constants in {@link android.system.OsConstants}. - * @param ifIndex the interface index on which packets will be sent. - * @param hwAddr the hardware address to which packets will be sent. - */ - @NonNull - public static SocketAddress makePacketSocketAddress(int protocol, int ifIndex, - @NonNull byte[] hwAddr) { - return new PacketSocketAddress( - protocol /* sll_protocol */, - ifIndex /* sll_ifindex */, - hwAddr /* sll_addr */); - } - - /** - * @see IoBridge#closeAndSignalBlockedThreads(FileDescriptor) - */ - public static void closeSocket(@Nullable FileDescriptor fd) throws IOException { - IoBridge.closeAndSignalBlockedThreads(fd); - } - - private SocketUtils() {} -} diff --git a/packages/Connectivity/framework/src/android/net/CaptivePortal.java b/packages/Connectivity/framework/src/android/net/CaptivePortal.java new file mode 100644 index 000000000000..269bbf20c8b1 --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/CaptivePortal.java @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed urnder the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.net; + +import android.annotation.NonNull; +import android.annotation.RequiresPermission; +import android.annotation.SystemApi; +import android.os.IBinder; +import android.os.Parcel; +import android.os.Parcelable; +import android.os.RemoteException; + +/** + * A class allowing apps handling the {@link ConnectivityManager#ACTION_CAPTIVE_PORTAL_SIGN_IN} + * activity to indicate to the system different outcomes of captive portal sign in. This class is + * passed as an extra named {@link ConnectivityManager#EXTRA_CAPTIVE_PORTAL} with the + * {@code ACTION_CAPTIVE_PORTAL_SIGN_IN} activity. + */ +public class CaptivePortal implements Parcelable { + /** + * Response code from the captive portal application, indicating that the portal was dismissed + * and the network should be re-validated. + * @see ICaptivePortal#appResponse(int) + * @see android.net.INetworkMonitor#notifyCaptivePortalAppFinished(int) + * @hide + */ + @SystemApi + public static final int APP_RETURN_DISMISSED = 0; + /** + * Response code from the captive portal application, indicating that the user did not login and + * does not want to use the captive portal network. + * @see ICaptivePortal#appResponse(int) + * @see android.net.INetworkMonitor#notifyCaptivePortalAppFinished(int) + * @hide + */ + @SystemApi + public static final int APP_RETURN_UNWANTED = 1; + /** + * Response code from the captive portal application, indicating that the user does not wish to + * login but wants to use the captive portal network as-is. + * @see ICaptivePortal#appResponse(int) + * @see android.net.INetworkMonitor#notifyCaptivePortalAppFinished(int) + * @hide + */ + @SystemApi + public static final int APP_RETURN_WANTED_AS_IS = 2; + /** Event offset of request codes from captive portal application. */ + private static final int APP_REQUEST_BASE = 100; + /** + * Request code from the captive portal application, indicating that the network condition may + * have changed and the network should be re-validated. + * @see ICaptivePortal#appRequest(int) + * @see android.net.INetworkMonitor#forceReevaluation(int) + * @hide + */ + @SystemApi + public static final int APP_REQUEST_REEVALUATION_REQUIRED = APP_REQUEST_BASE + 0; + + private final IBinder mBinder; + + /** @hide */ + public CaptivePortal(@NonNull IBinder binder) { + mBinder = binder; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeStrongBinder(mBinder); + } + + public static final @android.annotation.NonNull Parcelable.Creator CREATOR + = new Parcelable.Creator() { + @Override + public CaptivePortal createFromParcel(Parcel in) { + return new CaptivePortal(in.readStrongBinder()); + } + + @Override + public CaptivePortal[] newArray(int size) { + return new CaptivePortal[size]; + } + }; + + /** + * Indicate to the system that the captive portal has been + * dismissed. In response the framework will re-evaluate the network's + * connectivity and might take further action thereafter. + */ + public void reportCaptivePortalDismissed() { + try { + ICaptivePortal.Stub.asInterface(mBinder).appResponse(APP_RETURN_DISMISSED); + } catch (RemoteException e) { + } + } + + /** + * Indicate to the system that the user does not want to pursue signing in to the + * captive portal and the system should continue to prefer other networks + * without captive portals for use as the default active data network. The + * system will not retest the network for a captive portal so as to avoid + * disturbing the user with further sign in to network notifications. + */ + public void ignoreNetwork() { + try { + ICaptivePortal.Stub.asInterface(mBinder).appResponse(APP_RETURN_UNWANTED); + } catch (RemoteException e) { + } + } + + /** + * Indicate to the system the user wants to use this network as is, even though + * the captive portal is still in place. The system will treat the network + * as if it did not have a captive portal when selecting the network to use + * as the default active data network. This may result in this network + * becoming the default active data network, which could disrupt network + * connectivity for apps because the captive portal is still in place. + * @hide + */ + @SystemApi + public void useNetwork() { + try { + ICaptivePortal.Stub.asInterface(mBinder).appResponse(APP_RETURN_WANTED_AS_IS); + } catch (RemoteException e) { + } + } + + /** + * Request that the system reevaluates the captive portal status. + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.NETWORK_STACK) + public void reevaluateNetwork() { + try { + ICaptivePortal.Stub.asInterface(mBinder).appRequest(APP_REQUEST_REEVALUATION_REQUIRED); + } catch (RemoteException e) { + } + } + + /** + * Log a captive portal login event. + * @param eventId one of the CAPTIVE_PORTAL_LOGIN_* constants in metrics_constants.proto. + * @param packageName captive portal application package name. + * @hide + */ + @SystemApi + public void logEvent(int eventId, @NonNull String packageName) { + try { + ICaptivePortal.Stub.asInterface(mBinder).logEvent(eventId, packageName); + } catch (RemoteException e) { + } + } +} diff --git a/packages/Connectivity/framework/src/android/net/CaptivePortalData.aidl b/packages/Connectivity/framework/src/android/net/CaptivePortalData.aidl new file mode 100644 index 000000000000..1d57ee759136 --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/CaptivePortalData.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +@JavaOnlyStableParcelable parcelable CaptivePortalData; diff --git a/packages/Connectivity/framework/src/android/net/CaptivePortalData.java b/packages/Connectivity/framework/src/android/net/CaptivePortalData.java new file mode 100644 index 000000000000..18467fad8ec4 --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/CaptivePortalData.java @@ -0,0 +1,305 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.Objects; + +/** + * Metadata sent by captive portals, see https://www.ietf.org/id/draft-ietf-capport-api-03.txt. + * @hide + */ +@SystemApi +public final class CaptivePortalData implements Parcelable { + private final long mRefreshTimeMillis; + @Nullable + private final Uri mUserPortalUrl; + @Nullable + private final Uri mVenueInfoUrl; + private final boolean mIsSessionExtendable; + private final long mByteLimit; + private final long mExpiryTimeMillis; + private final boolean mCaptive; + private final String mVenueFriendlyName; + + private CaptivePortalData(long refreshTimeMillis, Uri userPortalUrl, Uri venueInfoUrl, + boolean isSessionExtendable, long byteLimit, long expiryTimeMillis, boolean captive, + String venueFriendlyName) { + mRefreshTimeMillis = refreshTimeMillis; + mUserPortalUrl = userPortalUrl; + mVenueInfoUrl = venueInfoUrl; + mIsSessionExtendable = isSessionExtendable; + mByteLimit = byteLimit; + mExpiryTimeMillis = expiryTimeMillis; + mCaptive = captive; + mVenueFriendlyName = venueFriendlyName; + } + + private CaptivePortalData(Parcel p) { + this(p.readLong(), p.readParcelable(null), p.readParcelable(null), p.readBoolean(), + p.readLong(), p.readLong(), p.readBoolean(), p.readString()); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeLong(mRefreshTimeMillis); + dest.writeParcelable(mUserPortalUrl, 0); + dest.writeParcelable(mVenueInfoUrl, 0); + dest.writeBoolean(mIsSessionExtendable); + dest.writeLong(mByteLimit); + dest.writeLong(mExpiryTimeMillis); + dest.writeBoolean(mCaptive); + dest.writeString(mVenueFriendlyName); + } + + /** + * A builder to create new {@link CaptivePortalData}. + */ + public static class Builder { + private long mRefreshTime; + private Uri mUserPortalUrl; + private Uri mVenueInfoUrl; + private boolean mIsSessionExtendable; + private long mBytesRemaining = -1; + private long mExpiryTime = -1; + private boolean mCaptive; + private String mVenueFriendlyName; + + /** + * Create an empty builder. + */ + public Builder() {} + + /** + * Create a builder copying all data from existing {@link CaptivePortalData}. + */ + public Builder(@Nullable CaptivePortalData data) { + if (data == null) return; + setRefreshTime(data.mRefreshTimeMillis) + .setUserPortalUrl(data.mUserPortalUrl) + .setVenueInfoUrl(data.mVenueInfoUrl) + .setSessionExtendable(data.mIsSessionExtendable) + .setBytesRemaining(data.mByteLimit) + .setExpiryTime(data.mExpiryTimeMillis) + .setCaptive(data.mCaptive) + .setVenueFriendlyName(data.mVenueFriendlyName); + } + + /** + * Set the time at which data was last refreshed, as per {@link System#currentTimeMillis()}. + */ + @NonNull + public Builder setRefreshTime(long refreshTime) { + mRefreshTime = refreshTime; + return this; + } + + /** + * Set the URL to be used for users to login to the portal, if captive. + */ + @NonNull + public Builder setUserPortalUrl(@Nullable Uri userPortalUrl) { + mUserPortalUrl = userPortalUrl; + return this; + } + + /** + * Set the URL that can be used by users to view information about the network venue. + */ + @NonNull + public Builder setVenueInfoUrl(@Nullable Uri venueInfoUrl) { + mVenueInfoUrl = venueInfoUrl; + return this; + } + + /** + * Set whether the portal supports extending a user session on the portal URL page. + */ + @NonNull + public Builder setSessionExtendable(boolean sessionExtendable) { + mIsSessionExtendable = sessionExtendable; + return this; + } + + /** + * Set the number of bytes remaining on the network before the portal closes. + */ + @NonNull + public Builder setBytesRemaining(long bytesRemaining) { + mBytesRemaining = bytesRemaining; + return this; + } + + /** + * Set the time at the session will expire, as per {@link System#currentTimeMillis()}. + */ + @NonNull + public Builder setExpiryTime(long expiryTime) { + mExpiryTime = expiryTime; + return this; + } + + /** + * Set whether the network is captive (portal closed). + */ + @NonNull + public Builder setCaptive(boolean captive) { + mCaptive = captive; + return this; + } + + /** + * Set the venue friendly name. + */ + @NonNull + public Builder setVenueFriendlyName(@Nullable String venueFriendlyName) { + mVenueFriendlyName = venueFriendlyName; + return this; + } + + /** + * Create a new {@link CaptivePortalData}. + */ + @NonNull + public CaptivePortalData build() { + return new CaptivePortalData(mRefreshTime, mUserPortalUrl, mVenueInfoUrl, + mIsSessionExtendable, mBytesRemaining, mExpiryTime, mCaptive, + mVenueFriendlyName); + } + } + + /** + * Get the time at which data was last refreshed, as per {@link System#currentTimeMillis()}. + */ + public long getRefreshTimeMillis() { + return mRefreshTimeMillis; + } + + /** + * Get the URL to be used for users to login to the portal, or extend their session if + * {@link #isSessionExtendable()} is true. + */ + @Nullable + public Uri getUserPortalUrl() { + return mUserPortalUrl; + } + + /** + * Get the URL that can be used by users to view information about the network venue. + */ + @Nullable + public Uri getVenueInfoUrl() { + return mVenueInfoUrl; + } + + /** + * Indicates whether the user portal URL can be used to extend sessions, when the user is logged + * in and the session has a time or byte limit. + */ + public boolean isSessionExtendable() { + return mIsSessionExtendable; + } + + /** + * Get the remaining bytes on the captive portal session, at the time {@link CaptivePortalData} + * was refreshed. This may be different from the limit currently enforced by the portal. + * @return The byte limit, or -1 if not set. + */ + public long getByteLimit() { + return mByteLimit; + } + + /** + * Get the time at the session will expire, as per {@link System#currentTimeMillis()}. + * @return The expiry time, or -1 if unset. + */ + public long getExpiryTimeMillis() { + return mExpiryTimeMillis; + } + + /** + * Get whether the network is captive (portal closed). + */ + public boolean isCaptive() { + return mCaptive; + } + + /** + * Get the venue friendly name + */ + @Nullable + public String getVenueFriendlyName() { + return mVenueFriendlyName; + } + + @NonNull + public static final Creator CREATOR = new Creator() { + @Override + public CaptivePortalData createFromParcel(Parcel source) { + return new CaptivePortalData(source); + } + + @Override + public CaptivePortalData[] newArray(int size) { + return new CaptivePortalData[size]; + } + }; + + @Override + public int hashCode() { + return Objects.hash(mRefreshTimeMillis, mUserPortalUrl, mVenueInfoUrl, + mIsSessionExtendable, mByteLimit, mExpiryTimeMillis, mCaptive, mVenueFriendlyName); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof CaptivePortalData)) return false; + final CaptivePortalData other = (CaptivePortalData) obj; + return mRefreshTimeMillis == other.mRefreshTimeMillis + && Objects.equals(mUserPortalUrl, other.mUserPortalUrl) + && Objects.equals(mVenueInfoUrl, other.mVenueInfoUrl) + && mIsSessionExtendable == other.mIsSessionExtendable + && mByteLimit == other.mByteLimit + && mExpiryTimeMillis == other.mExpiryTimeMillis + && mCaptive == other.mCaptive + && Objects.equals(mVenueFriendlyName, other.mVenueFriendlyName); + } + + @Override + public String toString() { + return "CaptivePortalData {" + + "refreshTime: " + mRefreshTimeMillis + + ", userPortalUrl: " + mUserPortalUrl + + ", venueInfoUrl: " + mVenueInfoUrl + + ", isSessionExtendable: " + mIsSessionExtendable + + ", byteLimit: " + mByteLimit + + ", expiryTime: " + mExpiryTimeMillis + + ", captive: " + mCaptive + + ", venueFriendlyName: " + mVenueFriendlyName + + "}"; + } +} diff --git a/packages/Connectivity/framework/src/android/net/ConnectionInfo.aidl b/packages/Connectivity/framework/src/android/net/ConnectionInfo.aidl new file mode 100644 index 000000000000..07faf8bbbed8 --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/ConnectionInfo.aidl @@ -0,0 +1,20 @@ +/* +** +** Copyright (C) 2018 The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +package android.net; + +parcelable ConnectionInfo; diff --git a/packages/Connectivity/framework/src/android/net/ConnectionInfo.java b/packages/Connectivity/framework/src/android/net/ConnectionInfo.java new file mode 100644 index 000000000000..4514a8484d96 --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/ConnectionInfo.java @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.os.Parcel; +import android.os.Parcelable; + +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.UnknownHostException; + +/** + * Describe a network connection including local and remote address/port of a connection and the + * transport protocol. + * + * @hide + */ +public final class ConnectionInfo implements Parcelable { + public final int protocol; + public final InetSocketAddress local; + public final InetSocketAddress remote; + + @Override + public int describeContents() { + return 0; + } + + public ConnectionInfo(int protocol, InetSocketAddress local, InetSocketAddress remote) { + this.protocol = protocol; + this.local = local; + this.remote = remote; + } + + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeInt(protocol); + out.writeByteArray(local.getAddress().getAddress()); + out.writeInt(local.getPort()); + out.writeByteArray(remote.getAddress().getAddress()); + out.writeInt(remote.getPort()); + } + + public static final @android.annotation.NonNull Creator CREATOR = new Creator() { + public ConnectionInfo createFromParcel(Parcel in) { + int protocol = in.readInt(); + InetAddress localAddress; + try { + localAddress = InetAddress.getByAddress(in.createByteArray()); + } catch (UnknownHostException e) { + throw new IllegalArgumentException("Invalid InetAddress"); + } + int localPort = in.readInt(); + InetAddress remoteAddress; + try { + remoteAddress = InetAddress.getByAddress(in.createByteArray()); + } catch (UnknownHostException e) { + throw new IllegalArgumentException("Invalid InetAddress"); + } + int remotePort = in.readInt(); + InetSocketAddress local = new InetSocketAddress(localAddress, localPort); + InetSocketAddress remote = new InetSocketAddress(remoteAddress, remotePort); + return new ConnectionInfo(protocol, local, remote); + } + + public ConnectionInfo[] newArray(int size) { + return new ConnectionInfo[size]; + } + }; +} diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityDiagnosticsManager.aidl b/packages/Connectivity/framework/src/android/net/ConnectivityDiagnosticsManager.aidl new file mode 100644 index 000000000000..82ba0ca113c5 --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/ConnectivityDiagnosticsManager.aidl @@ -0,0 +1,21 @@ +/** + * + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +parcelable ConnectivityDiagnosticsManager.ConnectivityReport; +parcelable ConnectivityDiagnosticsManager.DataStallReport; \ No newline at end of file diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityDiagnosticsManager.java b/packages/Connectivity/framework/src/android/net/ConnectivityDiagnosticsManager.java new file mode 100644 index 000000000000..523449497345 --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/ConnectivityDiagnosticsManager.java @@ -0,0 +1,777 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.StringDef; +import android.content.Context; +import android.os.Binder; +import android.os.Parcel; +import android.os.Parcelable; +import android.os.PersistableBundle; +import android.os.RemoteException; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.Preconditions; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executor; + +/** + * Class that provides utilities for collecting network connectivity diagnostics information. + * Connectivity information is made available through triggerable diagnostics tools and by listening + * to System validations. Some diagnostics information may be permissions-restricted. + * + *

ConnectivityDiagnosticsManager is intended for use by applications offering network + * connectivity on a user device. These tools will provide several mechanisms for these applications + * to be alerted to network conditions as well as diagnose potential network issues themselves. + * + *

The primary responsibilities of this class are to: + * + *

    + *
  • Allow permissioned applications to register and unregister callbacks for network event + * notifications + *
  • Invoke callbacks for network event notifications, including: + *
      + *
    • Network validations + *
    • Data stalls + *
    • Connectivity reports from applications + *
    + *
+ */ +public class ConnectivityDiagnosticsManager { + /** @hide */ + @VisibleForTesting + public static final Map + sCallbacks = new ConcurrentHashMap<>(); + + private final Context mContext; + private final IConnectivityManager mService; + + /** @hide */ + public ConnectivityDiagnosticsManager(Context context, IConnectivityManager service) { + mContext = Preconditions.checkNotNull(context, "missing context"); + mService = Preconditions.checkNotNull(service, "missing IConnectivityManager"); + } + + /** @hide */ + @VisibleForTesting + public static boolean persistableBundleEquals( + @Nullable PersistableBundle a, @Nullable PersistableBundle b) { + if (a == b) return true; + if (a == null || b == null) return false; + if (!Objects.equals(a.keySet(), b.keySet())) return false; + for (String key : a.keySet()) { + if (!Objects.equals(a.get(key), b.get(key))) return false; + } + return true; + } + + /** Class that includes connectivity information for a specific Network at a specific time. */ + public static final class ConnectivityReport implements Parcelable { + /** + * The overall status of the network is that it is invalid; it neither provides + * connectivity nor has been exempted from validation. + */ + public static final int NETWORK_VALIDATION_RESULT_INVALID = 0; + + /** + * The overall status of the network is that it is valid, this may be because it provides + * full Internet access (all probes succeeded), or because other properties of the network + * caused probes not to be run. + */ + // TODO: link to INetworkMonitor.NETWORK_VALIDATION_RESULT_VALID + public static final int NETWORK_VALIDATION_RESULT_VALID = 1; + + /** + * The overall status of the network is that it provides partial connectivity; some + * probed services succeeded but others failed. + */ + // TODO: link to INetworkMonitor.NETWORK_VALIDATION_RESULT_PARTIAL; + public static final int NETWORK_VALIDATION_RESULT_PARTIALLY_VALID = 2; + + /** + * Due to the properties of the network, validation was not performed. + */ + public static final int NETWORK_VALIDATION_RESULT_SKIPPED = 3; + + /** @hide */ + @IntDef( + prefix = {"NETWORK_VALIDATION_RESULT_"}, + value = { + NETWORK_VALIDATION_RESULT_INVALID, + NETWORK_VALIDATION_RESULT_VALID, + NETWORK_VALIDATION_RESULT_PARTIALLY_VALID, + NETWORK_VALIDATION_RESULT_SKIPPED + }) + @Retention(RetentionPolicy.SOURCE) + public @interface NetworkValidationResult {} + + /** + * The overall validation result for the Network being reported on. + * + *

The possible values for this key are: + * {@link #NETWORK_VALIDATION_RESULT_INVALID}, + * {@link #NETWORK_VALIDATION_RESULT_VALID}, + * {@link #NETWORK_VALIDATION_RESULT_PARTIALLY_VALID}, + * {@link #NETWORK_VALIDATION_RESULT_SKIPPED}. + * + * @see android.net.NetworkCapabilities#NET_CAPABILITY_VALIDATED + */ + @NetworkValidationResult + public static final String KEY_NETWORK_VALIDATION_RESULT = "networkValidationResult"; + + /** DNS probe. */ + // TODO: link to INetworkMonitor.NETWORK_VALIDATION_PROBE_DNS + public static final int NETWORK_PROBE_DNS = 0x04; + + /** HTTP probe. */ + // TODO: link to INetworkMonitor.NETWORK_VALIDATION_PROBE_HTTP + public static final int NETWORK_PROBE_HTTP = 0x08; + + /** HTTPS probe. */ + // TODO: link to INetworkMonitor.NETWORK_VALIDATION_PROBE_HTTPS; + public static final int NETWORK_PROBE_HTTPS = 0x10; + + /** Captive portal fallback probe. */ + // TODO: link to INetworkMonitor.NETWORK_VALIDATION_FALLBACK + public static final int NETWORK_PROBE_FALLBACK = 0x20; + + /** Private DNS (DNS over TLS) probd. */ + // TODO: link to INetworkMonitor.NETWORK_VALIDATION_PROBE_PRIVDNS + public static final int NETWORK_PROBE_PRIVATE_DNS = 0x40; + + /** @hide */ + @IntDef( + prefix = {"NETWORK_PROBE_"}, + value = { + NETWORK_PROBE_DNS, + NETWORK_PROBE_HTTP, + NETWORK_PROBE_HTTPS, + NETWORK_PROBE_FALLBACK, + NETWORK_PROBE_PRIVATE_DNS + }) + @Retention(RetentionPolicy.SOURCE) + public @interface NetworkProbe {} + + /** + * A bitmask of network validation probes that succeeded. + * + *

The possible bits values reported by this key are: + * {@link #NETWORK_PROBE_DNS}, + * {@link #NETWORK_PROBE_HTTP}, + * {@link #NETWORK_PROBE_HTTPS}, + * {@link #NETWORK_PROBE_FALLBACK}, + * {@link #NETWORK_PROBE_PRIVATE_DNS}. + */ + @NetworkProbe + public static final String KEY_NETWORK_PROBES_SUCCEEDED_BITMASK = + "networkProbesSucceeded"; + + /** + * A bitmask of network validation probes that were attempted. + * + *

These probes may have failed or may be incomplete at the time of this report. + * + *

The possible bits values reported by this key are: + * {@link #NETWORK_PROBE_DNS}, + * {@link #NETWORK_PROBE_HTTP}, + * {@link #NETWORK_PROBE_HTTPS}, + * {@link #NETWORK_PROBE_FALLBACK}, + * {@link #NETWORK_PROBE_PRIVATE_DNS}. + */ + @NetworkProbe + public static final String KEY_NETWORK_PROBES_ATTEMPTED_BITMASK = + "networkProbesAttempted"; + + /** @hide */ + @StringDef(prefix = {"KEY_"}, value = { + KEY_NETWORK_VALIDATION_RESULT, KEY_NETWORK_PROBES_SUCCEEDED_BITMASK, + KEY_NETWORK_PROBES_ATTEMPTED_BITMASK}) + @Retention(RetentionPolicy.SOURCE) + public @interface ConnectivityReportBundleKeys {} + + /** The Network for which this ConnectivityReport applied */ + @NonNull private final Network mNetwork; + + /** + * The timestamp for the report. The timestamp is taken from {@link + * System#currentTimeMillis}. + */ + private final long mReportTimestamp; + + /** LinkProperties available on the Network at the reported timestamp */ + @NonNull private final LinkProperties mLinkProperties; + + /** NetworkCapabilities available on the Network at the reported timestamp */ + @NonNull private final NetworkCapabilities mNetworkCapabilities; + + /** PersistableBundle that may contain additional info about the report */ + @NonNull private final PersistableBundle mAdditionalInfo; + + /** + * Constructor for ConnectivityReport. + * + *

Apps should obtain instances through {@link + * ConnectivityDiagnosticsCallback#onConnectivityReportAvailable} instead of instantiating + * their own instances (unless for testing purposes). + * + * @param network The Network for which this ConnectivityReport applies + * @param reportTimestamp The timestamp for the report + * @param linkProperties The LinkProperties available on network at reportTimestamp + * @param networkCapabilities The NetworkCapabilities available on network at + * reportTimestamp + * @param additionalInfo A PersistableBundle that may contain additional info about the + * report + */ + public ConnectivityReport( + @NonNull Network network, + long reportTimestamp, + @NonNull LinkProperties linkProperties, + @NonNull NetworkCapabilities networkCapabilities, + @NonNull PersistableBundle additionalInfo) { + mNetwork = network; + mReportTimestamp = reportTimestamp; + mLinkProperties = new LinkProperties(linkProperties); + mNetworkCapabilities = new NetworkCapabilities(networkCapabilities); + mAdditionalInfo = additionalInfo; + } + + /** + * Returns the Network for this ConnectivityReport. + * + * @return The Network for which this ConnectivityReport applied + */ + @NonNull + public Network getNetwork() { + return mNetwork; + } + + /** + * Returns the epoch timestamp (milliseconds) for when this report was taken. + * + * @return The timestamp for the report. Taken from {@link System#currentTimeMillis}. + */ + public long getReportTimestamp() { + return mReportTimestamp; + } + + /** + * Returns the LinkProperties available when this report was taken. + * + * @return LinkProperties available on the Network at the reported timestamp + */ + @NonNull + public LinkProperties getLinkProperties() { + return new LinkProperties(mLinkProperties); + } + + /** + * Returns the NetworkCapabilities when this report was taken. + * + * @return NetworkCapabilities available on the Network at the reported timestamp + */ + @NonNull + public NetworkCapabilities getNetworkCapabilities() { + return new NetworkCapabilities(mNetworkCapabilities); + } + + /** + * Returns a PersistableBundle with additional info for this report. + * + * @return PersistableBundle that may contain additional info about the report + */ + @NonNull + public PersistableBundle getAdditionalInfo() { + return new PersistableBundle(mAdditionalInfo); + } + + @Override + public boolean equals(@Nullable Object o) { + if (this == o) return true; + if (!(o instanceof ConnectivityReport)) return false; + final ConnectivityReport that = (ConnectivityReport) o; + + // PersistableBundle is optimized to avoid unparcelling data unless fields are + // referenced. Because of this, use {@link ConnectivityDiagnosticsManager#equals} over + // {@link PersistableBundle#kindofEquals}. + return mReportTimestamp == that.mReportTimestamp + && mNetwork.equals(that.mNetwork) + && mLinkProperties.equals(that.mLinkProperties) + && mNetworkCapabilities.equals(that.mNetworkCapabilities) + && persistableBundleEquals(mAdditionalInfo, that.mAdditionalInfo); + } + + @Override + public int hashCode() { + return Objects.hash( + mNetwork, + mReportTimestamp, + mLinkProperties, + mNetworkCapabilities, + mAdditionalInfo); + } + + /** {@inheritDoc} */ + @Override + public int describeContents() { + return 0; + } + + /** {@inheritDoc} */ + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeParcelable(mNetwork, flags); + dest.writeLong(mReportTimestamp); + dest.writeParcelable(mLinkProperties, flags); + dest.writeParcelable(mNetworkCapabilities, flags); + dest.writeParcelable(mAdditionalInfo, flags); + } + + /** Implement the Parcelable interface */ + public static final @NonNull Creator CREATOR = + new Creator() { + public ConnectivityReport createFromParcel(Parcel in) { + return new ConnectivityReport( + in.readParcelable(null), + in.readLong(), + in.readParcelable(null), + in.readParcelable(null), + in.readParcelable(null)); + } + + public ConnectivityReport[] newArray(int size) { + return new ConnectivityReport[size]; + } + }; + } + + /** Class that includes information for a suspected data stall on a specific Network */ + public static final class DataStallReport implements Parcelable { + /** + * Indicates that the Data Stall was detected using DNS events. + */ + public static final int DETECTION_METHOD_DNS_EVENTS = 1; + + /** + * Indicates that the Data Stall was detected using TCP metrics. + */ + public static final int DETECTION_METHOD_TCP_METRICS = 2; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef( + prefix = {"DETECTION_METHOD_"}, + value = {DETECTION_METHOD_DNS_EVENTS, DETECTION_METHOD_TCP_METRICS}) + public @interface DetectionMethod {} + + /** + * This key represents the period in milliseconds over which other included TCP metrics + * were measured. + * + *

This key will be included if the data stall detection method is + * {@link #DETECTION_METHOD_TCP_METRICS}. + * + *

This value is an int. + */ + public static final String KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS = + "tcpMetricsCollectionPeriodMillis"; + + /** + * This key represents the fail rate of TCP packets when the suspected data stall was + * detected. + * + *

This key will be included if the data stall detection method is + * {@link #DETECTION_METHOD_TCP_METRICS}. + * + *

This value is an int percentage between 0 and 100. + */ + public static final String KEY_TCP_PACKET_FAIL_RATE = "tcpPacketFailRate"; + + /** + * This key represents the consecutive number of DNS timeouts that have occurred. + * + *

The consecutive count will be reset any time a DNS response is received. + * + *

This key will be included if the data stall detection method is + * {@link #DETECTION_METHOD_DNS_EVENTS}. + * + *

This value is an int. + */ + public static final String KEY_DNS_CONSECUTIVE_TIMEOUTS = "dnsConsecutiveTimeouts"; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @StringDef(prefix = {"KEY_"}, value = { + KEY_TCP_PACKET_FAIL_RATE, + KEY_DNS_CONSECUTIVE_TIMEOUTS + }) + public @interface DataStallReportBundleKeys {} + + /** The Network for which this DataStallReport applied */ + @NonNull private final Network mNetwork; + + /** + * The timestamp for the report. The timestamp is taken from {@link + * System#currentTimeMillis}. + */ + private long mReportTimestamp; + + /** A bitmask of the detection methods used to identify the suspected data stall */ + @DetectionMethod private final int mDetectionMethod; + + /** LinkProperties available on the Network at the reported timestamp */ + @NonNull private final LinkProperties mLinkProperties; + + /** NetworkCapabilities available on the Network at the reported timestamp */ + @NonNull private final NetworkCapabilities mNetworkCapabilities; + + /** PersistableBundle that may contain additional information on the suspected data stall */ + @NonNull private final PersistableBundle mStallDetails; + + /** + * Constructor for DataStallReport. + * + *

Apps should obtain instances through {@link + * ConnectivityDiagnosticsCallback#onDataStallSuspected} instead of instantiating their own + * instances (unless for testing purposes). + * + * @param network The Network for which this DataStallReport applies + * @param reportTimestamp The timestamp for the report + * @param detectionMethod The detection method used to identify this data stall + * @param linkProperties The LinkProperties available on network at reportTimestamp + * @param networkCapabilities The NetworkCapabilities available on network at + * reportTimestamp + * @param stallDetails A PersistableBundle that may contain additional info about the report + */ + public DataStallReport( + @NonNull Network network, + long reportTimestamp, + @DetectionMethod int detectionMethod, + @NonNull LinkProperties linkProperties, + @NonNull NetworkCapabilities networkCapabilities, + @NonNull PersistableBundle stallDetails) { + mNetwork = network; + mReportTimestamp = reportTimestamp; + mDetectionMethod = detectionMethod; + mLinkProperties = new LinkProperties(linkProperties); + mNetworkCapabilities = new NetworkCapabilities(networkCapabilities); + mStallDetails = stallDetails; + } + + /** + * Returns the Network for this DataStallReport. + * + * @return The Network for which this DataStallReport applied + */ + @NonNull + public Network getNetwork() { + return mNetwork; + } + + /** + * Returns the epoch timestamp (milliseconds) for when this report was taken. + * + * @return The timestamp for the report. Taken from {@link System#currentTimeMillis}. + */ + public long getReportTimestamp() { + return mReportTimestamp; + } + + /** + * Returns the bitmask of detection methods used to identify this suspected data stall. + * + * @return The bitmask of detection methods used to identify the suspected data stall + */ + public int getDetectionMethod() { + return mDetectionMethod; + } + + /** + * Returns the LinkProperties available when this report was taken. + * + * @return LinkProperties available on the Network at the reported timestamp + */ + @NonNull + public LinkProperties getLinkProperties() { + return new LinkProperties(mLinkProperties); + } + + /** + * Returns the NetworkCapabilities when this report was taken. + * + * @return NetworkCapabilities available on the Network at the reported timestamp + */ + @NonNull + public NetworkCapabilities getNetworkCapabilities() { + return new NetworkCapabilities(mNetworkCapabilities); + } + + /** + * Returns a PersistableBundle with additional info for this report. + * + *

Gets a bundle with details about the suspected data stall including information + * specific to the monitoring method that detected the data stall. + * + * @return PersistableBundle that may contain additional information on the suspected data + * stall + */ + @NonNull + public PersistableBundle getStallDetails() { + return new PersistableBundle(mStallDetails); + } + + @Override + public boolean equals(@Nullable Object o) { + if (this == o) return true; + if (!(o instanceof DataStallReport)) return false; + final DataStallReport that = (DataStallReport) o; + + // PersistableBundle is optimized to avoid unparcelling data unless fields are + // referenced. Because of this, use {@link ConnectivityDiagnosticsManager#equals} over + // {@link PersistableBundle#kindofEquals}. + return mReportTimestamp == that.mReportTimestamp + && mDetectionMethod == that.mDetectionMethod + && mNetwork.equals(that.mNetwork) + && mLinkProperties.equals(that.mLinkProperties) + && mNetworkCapabilities.equals(that.mNetworkCapabilities) + && persistableBundleEquals(mStallDetails, that.mStallDetails); + } + + @Override + public int hashCode() { + return Objects.hash( + mNetwork, + mReportTimestamp, + mDetectionMethod, + mLinkProperties, + mNetworkCapabilities, + mStallDetails); + } + + /** {@inheritDoc} */ + @Override + public int describeContents() { + return 0; + } + + /** {@inheritDoc} */ + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeParcelable(mNetwork, flags); + dest.writeLong(mReportTimestamp); + dest.writeInt(mDetectionMethod); + dest.writeParcelable(mLinkProperties, flags); + dest.writeParcelable(mNetworkCapabilities, flags); + dest.writeParcelable(mStallDetails, flags); + } + + /** Implement the Parcelable interface */ + public static final @NonNull Creator CREATOR = + new Creator() { + public DataStallReport createFromParcel(Parcel in) { + return new DataStallReport( + in.readParcelable(null), + in.readLong(), + in.readInt(), + in.readParcelable(null), + in.readParcelable(null), + in.readParcelable(null)); + } + + public DataStallReport[] newArray(int size) { + return new DataStallReport[size]; + } + }; + } + + /** @hide */ + @VisibleForTesting + public static class ConnectivityDiagnosticsBinder + extends IConnectivityDiagnosticsCallback.Stub { + @NonNull private final ConnectivityDiagnosticsCallback mCb; + @NonNull private final Executor mExecutor; + + /** @hide */ + @VisibleForTesting + public ConnectivityDiagnosticsBinder( + @NonNull ConnectivityDiagnosticsCallback cb, @NonNull Executor executor) { + this.mCb = cb; + this.mExecutor = executor; + } + + /** @hide */ + @VisibleForTesting + public void onConnectivityReportAvailable(@NonNull ConnectivityReport report) { + final long token = Binder.clearCallingIdentity(); + try { + mExecutor.execute(() -> { + mCb.onConnectivityReportAvailable(report); + }); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + /** @hide */ + @VisibleForTesting + public void onDataStallSuspected(@NonNull DataStallReport report) { + final long token = Binder.clearCallingIdentity(); + try { + mExecutor.execute(() -> { + mCb.onDataStallSuspected(report); + }); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + /** @hide */ + @VisibleForTesting + public void onNetworkConnectivityReported( + @NonNull Network network, boolean hasConnectivity) { + final long token = Binder.clearCallingIdentity(); + try { + mExecutor.execute(() -> { + mCb.onNetworkConnectivityReported(network, hasConnectivity); + }); + } finally { + Binder.restoreCallingIdentity(token); + } + } + } + + /** + * Abstract base class for Connectivity Diagnostics callbacks. Used for notifications about + * network connectivity events. Must be extended by applications wanting notifications. + */ + public abstract static class ConnectivityDiagnosticsCallback { + /** + * Called when the platform completes a data connectivity check. This will also be invoked + * immediately upon registration for each network matching the request with the latest + * report, if a report has already been generated for that network. + * + *

The Network specified in the ConnectivityReport may not be active any more when this + * method is invoked. + * + * @param report The ConnectivityReport containing information about a connectivity check + */ + public void onConnectivityReportAvailable(@NonNull ConnectivityReport report) {} + + /** + * Called when the platform suspects a data stall on some Network. + * + *

The Network specified in the DataStallReport may not be active any more when this + * method is invoked. + * + * @param report The DataStallReport containing information about the suspected data stall + */ + public void onDataStallSuspected(@NonNull DataStallReport report) {} + + /** + * Called when any app reports connectivity to the System. + * + * @param network The Network for which connectivity has been reported + * @param hasConnectivity The connectivity reported to the System + */ + public void onNetworkConnectivityReported( + @NonNull Network network, boolean hasConnectivity) {} + } + + /** + * Registers a ConnectivityDiagnosticsCallback with the System. + * + *

Only apps that offer network connectivity to the user should be registering callbacks. + * These are the only apps whose callbacks will be invoked by the system. Apps considered to + * meet these conditions include: + * + *

    + *
  • Carrier apps with active subscriptions + *
  • Active VPNs + *
  • WiFi Suggesters + *
+ * + *

Callbacks registered by apps not meeting the above criteria will not be invoked. + * + *

If a registering app loses its relevant permissions, any callbacks it registered will + * silently stop receiving callbacks. + * + *

Each register() call MUST use a ConnectivityDiagnosticsCallback instance that is + * not currently registered. If a ConnectivityDiagnosticsCallback instance is registered with + * multiple NetworkRequests, an IllegalArgumentException will be thrown. + * + *

To avoid performance issues due to apps leaking callbacks, the system will limit the + * number of outstanding requests to 100 per app (identified by their UID), shared with + * callbacks in {@link ConnectivityManager}. Registering a callback with this method will count + * toward this limit. If this limit is exceeded, an exception will be thrown. To avoid hitting + * this issue and to conserve resources, make sure to unregister the callbacks with + * {@link #unregisterConnectivityDiagnosticsCallback}. + * + * @param request The NetworkRequest that will be used to match with Networks for which + * callbacks will be fired + * @param e The Executor to be used for running the callback method invocations + * @param callback The ConnectivityDiagnosticsCallback that the caller wants registered with the + * System + * @throws IllegalArgumentException if the same callback instance is registered with multiple + * NetworkRequests + * @throws RuntimeException if the app already has too many callbacks registered. + */ + public void registerConnectivityDiagnosticsCallback( + @NonNull NetworkRequest request, + @NonNull Executor e, + @NonNull ConnectivityDiagnosticsCallback callback) { + final ConnectivityDiagnosticsBinder binder = new ConnectivityDiagnosticsBinder(callback, e); + if (sCallbacks.putIfAbsent(callback, binder) != null) { + throw new IllegalArgumentException("Callback is currently registered"); + } + + try { + mService.registerConnectivityDiagnosticsCallback( + binder, request, mContext.getOpPackageName()); + } catch (RemoteException exception) { + exception.rethrowFromSystemServer(); + } + } + + /** + * Unregisters a ConnectivityDiagnosticsCallback with the System. + * + *

If the given callback is not currently registered with the System, this operation will be + * a no-op. + * + * @param callback The ConnectivityDiagnosticsCallback to be unregistered from the System. + */ + public void unregisterConnectivityDiagnosticsCallback( + @NonNull ConnectivityDiagnosticsCallback callback) { + // unconditionally removing from sCallbacks prevents race conditions here, since remove() is + // atomic. + final ConnectivityDiagnosticsBinder binder = sCallbacks.remove(callback); + if (binder == null) return; + + try { + mService.unregisterConnectivityDiagnosticsCallback(binder); + } catch (RemoteException exception) { + exception.rethrowFromSystemServer(); + } + } +} diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java new file mode 100644 index 000000000000..7f07bba668a3 --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java @@ -0,0 +1,5058 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.net; + +import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; +import static android.net.IpSecManager.INVALID_RESOURCE_ID; +import static android.net.NetworkRequest.Type.BACKGROUND_REQUEST; +import static android.net.NetworkRequest.Type.LISTEN; +import static android.net.NetworkRequest.Type.REQUEST; +import static android.net.NetworkRequest.Type.TRACK_DEFAULT; +import static android.net.QosCallback.QosCallbackRegistrationException; + +import android.annotation.CallbackExecutor; +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.RequiresPermission; +import android.annotation.SdkConstant; +import android.annotation.SdkConstant.SdkConstantType; +import android.annotation.SuppressLint; +import android.annotation.SystemApi; +import android.annotation.SystemService; +import android.app.PendingIntent; +import android.compat.annotation.UnsupportedAppUsage; +import android.content.Context; +import android.content.Intent; +import android.net.IpSecManager.UdpEncapsulationSocket; +import android.net.SocketKeepalive.Callback; +import android.net.TetheringManager.StartTetheringCallback; +import android.net.TetheringManager.TetheringEventCallback; +import android.net.TetheringManager.TetheringRequest; +import android.os.Binder; +import android.os.Build; +import android.os.Build.VERSION_CODES; +import android.os.Bundle; +import android.os.Handler; +import android.os.IBinder; +import android.os.INetworkActivityListener; +import android.os.INetworkManagementService; +import android.os.Looper; +import android.os.Message; +import android.os.Messenger; +import android.os.ParcelFileDescriptor; +import android.os.PersistableBundle; +import android.os.Process; +import android.os.RemoteException; +import android.os.ResultReceiver; +import android.os.ServiceManager; +import android.os.ServiceSpecificException; +import android.provider.Settings; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; +import android.util.ArrayMap; +import android.util.Log; +import android.util.Range; +import android.util.SparseIntArray; + +import com.android.connectivity.aidl.INetworkAgent; +import com.android.internal.annotations.GuardedBy; +import com.android.internal.util.Preconditions; +import com.android.internal.util.Protocol; + +import libcore.net.event.NetworkEventDispatcher; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.RejectedExecutionException; + +/** + * Class that answers queries about the state of network connectivity. It also + * notifies applications when network connectivity changes. + *

+ * The primary responsibilities of this class are to: + *

    + *
  1. Monitor network connections (Wi-Fi, GPRS, UMTS, etc.)
  2. + *
  3. Send broadcast intents when network connectivity changes
  4. + *
  5. Attempt to "fail over" to another network when connectivity to a network + * is lost
  6. + *
  7. Provide an API that allows applications to query the coarse-grained or fine-grained + * state of the available networks
  8. + *
  9. Provide an API that allows applications to request and select networks for their data + * traffic
  10. + *
+ */ +@SystemService(Context.CONNECTIVITY_SERVICE) +public class ConnectivityManager { + private static final String TAG = "ConnectivityManager"; + private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + + /** + * A change in network connectivity has occurred. A default connection has either + * been established or lost. The NetworkInfo for the affected network is + * sent as an extra; it should be consulted to see what kind of + * connectivity event occurred. + *

+ * Apps targeting Android 7.0 (API level 24) and higher do not receive this + * broadcast if they declare the broadcast receiver in their manifest. Apps + * will still receive broadcasts if they register their + * {@link android.content.BroadcastReceiver} with + * {@link android.content.Context#registerReceiver Context.registerReceiver()} + * and that context is still valid. + *

+ * If this is a connection that was the result of failing over from a + * disconnected network, then the FAILOVER_CONNECTION boolean extra is + * set to true. + *

+ * For a loss of connectivity, if the connectivity manager is attempting + * to connect (or has already connected) to another network, the + * NetworkInfo for the new network is also passed as an extra. This lets + * any receivers of the broadcast know that they should not necessarily + * tell the user that no data traffic will be possible. Instead, the + * receiver should expect another broadcast soon, indicating either that + * the failover attempt succeeded (and so there is still overall data + * connectivity), or that the failover attempt failed, meaning that all + * connectivity has been lost. + *

+ * For a disconnect event, the boolean extra EXTRA_NO_CONNECTIVITY + * is set to {@code true} if there are no connected networks at all. + * + * @deprecated apps should use the more versatile {@link #requestNetwork}, + * {@link #registerNetworkCallback} or {@link #registerDefaultNetworkCallback} + * functions instead for faster and more detailed updates about the network + * changes they care about. + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + @Deprecated + public static final String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE"; + + /** + * The device has connected to a network that has presented a captive + * portal, which is blocking Internet connectivity. The user was presented + * with a notification that network sign in is required, + * and the user invoked the notification's action indicating they + * desire to sign in to the network. Apps handling this activity should + * facilitate signing in to the network. This action includes a + * {@link Network} typed extra called {@link #EXTRA_NETWORK} that represents + * the network presenting the captive portal; all communication with the + * captive portal must be done using this {@code Network} object. + *

+ * This activity includes a {@link CaptivePortal} extra named + * {@link #EXTRA_CAPTIVE_PORTAL} that can be used to indicate different + * outcomes of the captive portal sign in to the system: + *

    + *
  • When the app handling this action believes the user has signed in to + * the network and the captive portal has been dismissed, the app should + * call {@link CaptivePortal#reportCaptivePortalDismissed} so the system can + * reevaluate the network. If reevaluation finds the network no longer + * subject to a captive portal, the network may become the default active + * data network.
  • + *
  • When the app handling this action believes the user explicitly wants + * to ignore the captive portal and the network, the app should call + * {@link CaptivePortal#ignoreNetwork}.
  • + *
+ */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_CAPTIVE_PORTAL_SIGN_IN = "android.net.conn.CAPTIVE_PORTAL"; + + /** + * The lookup key for a {@link NetworkInfo} object. Retrieve with + * {@link android.content.Intent#getParcelableExtra(String)}. + * + * @deprecated The {@link NetworkInfo} object is deprecated, as many of its properties + * can't accurately represent modern network characteristics. + * Please obtain information about networks from the {@link NetworkCapabilities} + * or {@link LinkProperties} objects instead. + */ + @Deprecated + public static final String EXTRA_NETWORK_INFO = "networkInfo"; + + /** + * Network type which triggered a {@link #CONNECTIVITY_ACTION} broadcast. + * + * @see android.content.Intent#getIntExtra(String, int) + * @deprecated The network type is not rich enough to represent the characteristics + * of modern networks. Please use {@link NetworkCapabilities} instead, + * in particular the transports. + */ + @Deprecated + public static final String EXTRA_NETWORK_TYPE = "networkType"; + + /** + * The lookup key for a boolean that indicates whether a connect event + * is for a network to which the connectivity manager was failing over + * following a disconnect on another network. + * Retrieve it with {@link android.content.Intent#getBooleanExtra(String,boolean)}. + * + * @deprecated See {@link NetworkInfo}. + */ + @Deprecated + public static final String EXTRA_IS_FAILOVER = "isFailover"; + /** + * The lookup key for a {@link NetworkInfo} object. This is supplied when + * there is another network that it may be possible to connect to. Retrieve with + * {@link android.content.Intent#getParcelableExtra(String)}. + * + * @deprecated See {@link NetworkInfo}. + */ + @Deprecated + public static final String EXTRA_OTHER_NETWORK_INFO = "otherNetwork"; + /** + * The lookup key for a boolean that indicates whether there is a + * complete lack of connectivity, i.e., no network is available. + * Retrieve it with {@link android.content.Intent#getBooleanExtra(String,boolean)}. + */ + public static final String EXTRA_NO_CONNECTIVITY = "noConnectivity"; + /** + * The lookup key for a string that indicates why an attempt to connect + * to a network failed. The string has no particular structure. It is + * intended to be used in notifications presented to users. Retrieve + * it with {@link android.content.Intent#getStringExtra(String)}. + */ + public static final String EXTRA_REASON = "reason"; + /** + * The lookup key for a string that provides optionally supplied + * extra information about the network state. The information + * may be passed up from the lower networking layers, and its + * meaning may be specific to a particular network type. Retrieve + * it with {@link android.content.Intent#getStringExtra(String)}. + * + * @deprecated See {@link NetworkInfo#getExtraInfo()}. + */ + @Deprecated + public static final String EXTRA_EXTRA_INFO = "extraInfo"; + /** + * The lookup key for an int that provides information about + * our connection to the internet at large. 0 indicates no connection, + * 100 indicates a great connection. Retrieve it with + * {@link android.content.Intent#getIntExtra(String, int)}. + * {@hide} + */ + public static final String EXTRA_INET_CONDITION = "inetCondition"; + /** + * The lookup key for a {@link CaptivePortal} object included with the + * {@link #ACTION_CAPTIVE_PORTAL_SIGN_IN} intent. The {@code CaptivePortal} + * object can be used to either indicate to the system that the captive + * portal has been dismissed or that the user does not want to pursue + * signing in to captive portal. Retrieve it with + * {@link android.content.Intent#getParcelableExtra(String)}. + */ + public static final String EXTRA_CAPTIVE_PORTAL = "android.net.extra.CAPTIVE_PORTAL"; + + /** + * Key for passing a URL to the captive portal login activity. + */ + public static final String EXTRA_CAPTIVE_PORTAL_URL = "android.net.extra.CAPTIVE_PORTAL_URL"; + + /** + * Key for passing a {@link android.net.captiveportal.CaptivePortalProbeSpec} to the captive + * portal login activity. + * {@hide} + */ + @SystemApi + public static final String EXTRA_CAPTIVE_PORTAL_PROBE_SPEC = + "android.net.extra.CAPTIVE_PORTAL_PROBE_SPEC"; + + /** + * Key for passing a user agent string to the captive portal login activity. + * {@hide} + */ + @SystemApi + public static final String EXTRA_CAPTIVE_PORTAL_USER_AGENT = + "android.net.extra.CAPTIVE_PORTAL_USER_AGENT"; + + /** + * Broadcast action to indicate the change of data activity status + * (idle or active) on a network in a recent period. + * The network becomes active when data transmission is started, or + * idle if there is no data transmission for a period of time. + * {@hide} + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_DATA_ACTIVITY_CHANGE = + "android.net.conn.DATA_ACTIVITY_CHANGE"; + /** + * The lookup key for an enum that indicates the network device type on which this data activity + * change happens. + * {@hide} + */ + public static final String EXTRA_DEVICE_TYPE = "deviceType"; + /** + * The lookup key for a boolean that indicates the device is active or not. {@code true} means + * it is actively sending or receiving data and {@code false} means it is idle. + * {@hide} + */ + public static final String EXTRA_IS_ACTIVE = "isActive"; + /** + * The lookup key for a long that contains the timestamp (nanos) of the radio state change. + * {@hide} + */ + public static final String EXTRA_REALTIME_NS = "tsNanos"; + + /** + * Broadcast Action: The setting for background data usage has changed + * values. Use {@link #getBackgroundDataSetting()} to get the current value. + *

+ * If an application uses the network in the background, it should listen + * for this broadcast and stop using the background data if the value is + * {@code false}. + *

+ * + * @deprecated As of {@link VERSION_CODES#ICE_CREAM_SANDWICH}, availability + * of background data depends on several combined factors, and + * this broadcast is no longer sent. Instead, when background + * data is unavailable, {@link #getActiveNetworkInfo()} will now + * appear disconnected. During first boot after a platform + * upgrade, this broadcast will be sent once if + * {@link #getBackgroundDataSetting()} was {@code false} before + * the upgrade. + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + @Deprecated + public static final String ACTION_BACKGROUND_DATA_SETTING_CHANGED = + "android.net.conn.BACKGROUND_DATA_SETTING_CHANGED"; + + /** + * Broadcast Action: The network connection may not be good + * uses {@code ConnectivityManager.EXTRA_INET_CONDITION} and + * {@code ConnectivityManager.EXTRA_NETWORK_INFO} to specify + * the network and it's condition. + * @hide + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + @UnsupportedAppUsage + public static final String INET_CONDITION_ACTION = + "android.net.conn.INET_CONDITION_ACTION"; + + /** + * Broadcast Action: A tetherable connection has come or gone. + * Uses {@code ConnectivityManager.EXTRA_AVAILABLE_TETHER}, + * {@code ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY}, + * {@code ConnectivityManager.EXTRA_ACTIVE_TETHER}, and + * {@code ConnectivityManager.EXTRA_ERRORED_TETHER} to indicate + * the current state of tethering. Each include a list of + * interface names in that state (may be empty). + * @hide + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + public static final String ACTION_TETHER_STATE_CHANGED = + TetheringManager.ACTION_TETHER_STATE_CHANGED; + + /** + * @hide + * gives a String[] listing all the interfaces configured for + * tethering and currently available for tethering. + */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + public static final String EXTRA_AVAILABLE_TETHER = TetheringManager.EXTRA_AVAILABLE_TETHER; + + /** + * @hide + * gives a String[] listing all the interfaces currently in local-only + * mode (ie, has DHCPv4+IPv6-ULA support and no packet forwarding) + */ + public static final String EXTRA_ACTIVE_LOCAL_ONLY = TetheringManager.EXTRA_ACTIVE_LOCAL_ONLY; + + /** + * @hide + * gives a String[] listing all the interfaces currently tethered + * (ie, has DHCPv4 support and packets potentially forwarded/NATed) + */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + public static final String EXTRA_ACTIVE_TETHER = TetheringManager.EXTRA_ACTIVE_TETHER; + + /** + * @hide + * gives a String[] listing all the interfaces we tried to tether and + * failed. Use {@link #getLastTetherError} to find the error code + * for any interfaces listed here. + */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + public static final String EXTRA_ERRORED_TETHER = TetheringManager.EXTRA_ERRORED_TETHER; + + /** + * Broadcast Action: The captive portal tracker has finished its test. + * Sent only while running Setup Wizard, in lieu of showing a user + * notification. + * @hide + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_CAPTIVE_PORTAL_TEST_COMPLETED = + "android.net.conn.CAPTIVE_PORTAL_TEST_COMPLETED"; + /** + * The lookup key for a boolean that indicates whether a captive portal was detected. + * Retrieve it with {@link android.content.Intent#getBooleanExtra(String,boolean)}. + * @hide + */ + public static final String EXTRA_IS_CAPTIVE_PORTAL = "captivePortal"; + + /** + * Action used to display a dialog that asks the user whether to connect to a network that is + * not validated. This intent is used to start the dialog in settings via startActivity. + * + * @hide + */ + public static final String ACTION_PROMPT_UNVALIDATED = "android.net.conn.PROMPT_UNVALIDATED"; + + /** + * Action used to display a dialog that asks the user whether to avoid a network that is no + * longer validated. This intent is used to start the dialog in settings via startActivity. + * + * @hide + */ + public static final String ACTION_PROMPT_LOST_VALIDATION = + "android.net.conn.PROMPT_LOST_VALIDATION"; + + /** + * Action used to display a dialog that asks the user whether to stay connected to a network + * that has not validated. This intent is used to start the dialog in settings via + * startActivity. + * + * @hide + */ + public static final String ACTION_PROMPT_PARTIAL_CONNECTIVITY = + "android.net.conn.PROMPT_PARTIAL_CONNECTIVITY"; + + /** + * Invalid tethering type. + * @see #startTethering(int, boolean, OnStartTetheringCallback) + * @hide + */ + public static final int TETHERING_INVALID = TetheringManager.TETHERING_INVALID; + + /** + * Wifi tethering type. + * @see #startTethering(int, boolean, OnStartTetheringCallback) + * @hide + */ + @SystemApi + public static final int TETHERING_WIFI = TetheringManager.TETHERING_WIFI; + + /** + * USB tethering type. + * @see #startTethering(int, boolean, OnStartTetheringCallback) + * @hide + */ + @SystemApi + public static final int TETHERING_USB = TetheringManager.TETHERING_USB; + + /** + * Bluetooth tethering type. + * @see #startTethering(int, boolean, OnStartTetheringCallback) + * @hide + */ + @SystemApi + public static final int TETHERING_BLUETOOTH = TetheringManager.TETHERING_BLUETOOTH; + + /** + * Wifi P2p tethering type. + * Wifi P2p tethering is set through events automatically, and don't + * need to start from #startTethering(int, boolean, OnStartTetheringCallback). + * @hide + */ + public static final int TETHERING_WIFI_P2P = TetheringManager.TETHERING_WIFI_P2P; + + /** + * Extra used for communicating with the TetherService. Includes the type of tethering to + * enable if any. + * @hide + */ + public static final String EXTRA_ADD_TETHER_TYPE = TetheringConstants.EXTRA_ADD_TETHER_TYPE; + + /** + * Extra used for communicating with the TetherService. Includes the type of tethering for + * which to cancel provisioning. + * @hide + */ + public static final String EXTRA_REM_TETHER_TYPE = TetheringConstants.EXTRA_REM_TETHER_TYPE; + + /** + * Extra used for communicating with the TetherService. True to schedule a recheck of tether + * provisioning. + * @hide + */ + public static final String EXTRA_SET_ALARM = TetheringConstants.EXTRA_SET_ALARM; + + /** + * Tells the TetherService to run a provision check now. + * @hide + */ + public static final String EXTRA_RUN_PROVISION = TetheringConstants.EXTRA_RUN_PROVISION; + + /** + * Extra used for communicating with the TetherService. Contains the {@link ResultReceiver} + * which will receive provisioning results. Can be left empty. + * @hide + */ + public static final String EXTRA_PROVISION_CALLBACK = + TetheringConstants.EXTRA_PROVISION_CALLBACK; + + /** + * The absence of a connection type. + * @hide + */ + @SystemApi + public static final int TYPE_NONE = -1; + + /** + * A Mobile data connection. Devices may support more than one. + * + * @deprecated Applications should instead use {@link NetworkCapabilities#hasTransport} or + * {@link #requestNetwork(NetworkRequest, NetworkCallback)} to request an + * appropriate network. {@see NetworkCapabilities} for supported transports. + */ + @Deprecated + public static final int TYPE_MOBILE = 0; + + /** + * A WIFI data connection. Devices may support more than one. + * + * @deprecated Applications should instead use {@link NetworkCapabilities#hasTransport} or + * {@link #requestNetwork(NetworkRequest, NetworkCallback)} to request an + * appropriate network. {@see NetworkCapabilities} for supported transports. + */ + @Deprecated + public static final int TYPE_WIFI = 1; + + /** + * An MMS-specific Mobile data connection. This network type may use the + * same network interface as {@link #TYPE_MOBILE} or it may use a different + * one. This is used by applications needing to talk to the carrier's + * Multimedia Messaging Service servers. + * + * @deprecated Applications should instead use {@link NetworkCapabilities#hasCapability} or + * {@link #requestNetwork(NetworkRequest, NetworkCallback)} to request a network that + * provides the {@link NetworkCapabilities#NET_CAPABILITY_MMS} capability. + */ + @Deprecated + public static final int TYPE_MOBILE_MMS = 2; + + /** + * A SUPL-specific Mobile data connection. This network type may use the + * same network interface as {@link #TYPE_MOBILE} or it may use a different + * one. This is used by applications needing to talk to the carrier's + * Secure User Plane Location servers for help locating the device. + * + * @deprecated Applications should instead use {@link NetworkCapabilities#hasCapability} or + * {@link #requestNetwork(NetworkRequest, NetworkCallback)} to request a network that + * provides the {@link NetworkCapabilities#NET_CAPABILITY_SUPL} capability. + */ + @Deprecated + public static final int TYPE_MOBILE_SUPL = 3; + + /** + * A DUN-specific Mobile data connection. This network type may use the + * same network interface as {@link #TYPE_MOBILE} or it may use a different + * one. This is sometimes by the system when setting up an upstream connection + * for tethering so that the carrier is aware of DUN traffic. + * + * @deprecated Applications should instead use {@link NetworkCapabilities#hasCapability} or + * {@link #requestNetwork(NetworkRequest, NetworkCallback)} to request a network that + * provides the {@link NetworkCapabilities#NET_CAPABILITY_DUN} capability. + */ + @Deprecated + public static final int TYPE_MOBILE_DUN = 4; + + /** + * A High Priority Mobile data connection. This network type uses the + * same network interface as {@link #TYPE_MOBILE} but the routing setup + * is different. + * + * @deprecated Applications should instead use {@link NetworkCapabilities#hasTransport} or + * {@link #requestNetwork(NetworkRequest, NetworkCallback)} to request an + * appropriate network. {@see NetworkCapabilities} for supported transports. + */ + @Deprecated + public static final int TYPE_MOBILE_HIPRI = 5; + + /** + * A WiMAX data connection. + * + * @deprecated Applications should instead use {@link NetworkCapabilities#hasTransport} or + * {@link #requestNetwork(NetworkRequest, NetworkCallback)} to request an + * appropriate network. {@see NetworkCapabilities} for supported transports. + */ + @Deprecated + public static final int TYPE_WIMAX = 6; + + /** + * A Bluetooth data connection. + * + * @deprecated Applications should instead use {@link NetworkCapabilities#hasTransport} or + * {@link #requestNetwork(NetworkRequest, NetworkCallback)} to request an + * appropriate network. {@see NetworkCapabilities} for supported transports. + */ + @Deprecated + public static final int TYPE_BLUETOOTH = 7; + + /** + * Fake data connection. This should not be used on shipping devices. + * @deprecated This is not used any more. + */ + @Deprecated + public static final int TYPE_DUMMY = 8; + + /** + * An Ethernet data connection. + * + * @deprecated Applications should instead use {@link NetworkCapabilities#hasTransport} or + * {@link #requestNetwork(NetworkRequest, NetworkCallback)} to request an + * appropriate network. {@see NetworkCapabilities} for supported transports. + */ + @Deprecated + public static final int TYPE_ETHERNET = 9; + + /** + * Over the air Administration. + * @deprecated Use {@link NetworkCapabilities} instead. + * {@hide} + */ + @Deprecated + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562) + public static final int TYPE_MOBILE_FOTA = 10; + + /** + * IP Multimedia Subsystem. + * @deprecated Use {@link NetworkCapabilities#NET_CAPABILITY_IMS} instead. + * {@hide} + */ + @Deprecated + @UnsupportedAppUsage + public static final int TYPE_MOBILE_IMS = 11; + + /** + * Carrier Branded Services. + * @deprecated Use {@link NetworkCapabilities#NET_CAPABILITY_CBS} instead. + * {@hide} + */ + @Deprecated + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562) + public static final int TYPE_MOBILE_CBS = 12; + + /** + * A Wi-Fi p2p connection. Only requesting processes will have access to + * the peers connected. + * @deprecated Use {@link NetworkCapabilities#NET_CAPABILITY_WIFI_P2P} instead. + * {@hide} + */ + @Deprecated + @SystemApi + public static final int TYPE_WIFI_P2P = 13; + + /** + * The network to use for initially attaching to the network + * @deprecated Use {@link NetworkCapabilities#NET_CAPABILITY_IA} instead. + * {@hide} + */ + @Deprecated + @UnsupportedAppUsage + public static final int TYPE_MOBILE_IA = 14; + + /** + * Emergency PDN connection for emergency services. This + * may include IMS and MMS in emergency situations. + * @deprecated Use {@link NetworkCapabilities#NET_CAPABILITY_EIMS} instead. + * {@hide} + */ + @Deprecated + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562) + public static final int TYPE_MOBILE_EMERGENCY = 15; + + /** + * The network that uses proxy to achieve connectivity. + * @deprecated Use {@link NetworkCapabilities} instead. + * {@hide} + */ + @Deprecated + @SystemApi + public static final int TYPE_PROXY = 16; + + /** + * A virtual network using one or more native bearers. + * It may or may not be providing security services. + * @deprecated Applications should use {@link NetworkCapabilities#TRANSPORT_VPN} instead. + */ + @Deprecated + public static final int TYPE_VPN = 17; + + /** + * A network that is exclusively meant to be used for testing + * + * @deprecated Use {@link NetworkCapabilities} instead. + * @hide + */ + @Deprecated + public static final int TYPE_TEST = 18; // TODO: Remove this once NetworkTypes are unused. + + /** + * @deprecated Use {@link NetworkCapabilities} instead. + * @hide + */ + @Deprecated + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = { "TYPE_" }, value = { + TYPE_NONE, + TYPE_MOBILE, + TYPE_WIFI, + TYPE_MOBILE_MMS, + TYPE_MOBILE_SUPL, + TYPE_MOBILE_DUN, + TYPE_MOBILE_HIPRI, + TYPE_WIMAX, + TYPE_BLUETOOTH, + TYPE_DUMMY, + TYPE_ETHERNET, + TYPE_MOBILE_FOTA, + TYPE_MOBILE_IMS, + TYPE_MOBILE_CBS, + TYPE_WIFI_P2P, + TYPE_MOBILE_IA, + TYPE_MOBILE_EMERGENCY, + TYPE_PROXY, + TYPE_VPN, + TYPE_TEST + }) + public @interface LegacyNetworkType {} + + // Deprecated constants for return values of startUsingNetworkFeature. They used to live + // in com.android.internal.telephony.PhoneConstants until they were made inaccessible. + private static final int DEPRECATED_PHONE_CONSTANT_APN_ALREADY_ACTIVE = 0; + private static final int DEPRECATED_PHONE_CONSTANT_APN_REQUEST_STARTED = 1; + private static final int DEPRECATED_PHONE_CONSTANT_APN_REQUEST_FAILED = 3; + + /** {@hide} */ + public static final int MAX_RADIO_TYPE = TYPE_TEST; + + /** {@hide} */ + public static final int MAX_NETWORK_TYPE = TYPE_TEST; + + private static final int MIN_NETWORK_TYPE = TYPE_MOBILE; + + /** + * If you want to set the default network preference,you can directly + * change the networkAttributes array in framework's config.xml. + * + * @deprecated Since we support so many more networks now, the single + * network default network preference can't really express + * the hierarchy. Instead, the default is defined by the + * networkAttributes in config.xml. You can determine + * the current value by calling {@link #getNetworkPreference()} + * from an App. + */ + @Deprecated + public static final int DEFAULT_NETWORK_PREFERENCE = TYPE_WIFI; + + /** + * @hide + */ + public static final int REQUEST_ID_UNSET = 0; + + /** + * Static unique request used as a tombstone for NetworkCallbacks that have been unregistered. + * This allows to distinguish when unregistering NetworkCallbacks those that were never + * registered from those that were already unregistered. + * @hide + */ + private static final NetworkRequest ALREADY_UNREGISTERED = + new NetworkRequest.Builder().clearCapabilities().build(); + + /** + * A NetID indicating no Network is selected. + * Keep in sync with bionic/libc/dns/include/resolv_netid.h + * @hide + */ + public static final int NETID_UNSET = 0; + + /** + * Private DNS Mode values. + * + * The "private_dns_mode" global setting stores a String value which is + * expected to be one of the following. + */ + + /** + * @hide + */ + public static final String PRIVATE_DNS_MODE_OFF = "off"; + /** + * @hide + */ + public static final String PRIVATE_DNS_MODE_OPPORTUNISTIC = "opportunistic"; + /** + * @hide + */ + public static final String PRIVATE_DNS_MODE_PROVIDER_HOSTNAME = "hostname"; + /** + * The default Private DNS mode. + * + * This may change from release to release or may become dependent upon + * the capabilities of the underlying platform. + * + * @hide + */ + public static final String PRIVATE_DNS_DEFAULT_MODE_FALLBACK = PRIVATE_DNS_MODE_OPPORTUNISTIC; + + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562) + private final IConnectivityManager mService; + /** + * A kludge to facilitate static access where a Context pointer isn't available, like in the + * case of the static set/getProcessDefaultNetwork methods and from the Network class. + * TODO: Remove this after deprecating the static methods in favor of non-static methods or + * methods that take a Context argument. + */ + private static ConnectivityManager sInstance; + + private final Context mContext; + + private INetworkManagementService mNMService; + private INetworkPolicyManager mNPManager; + private final TetheringManager mTetheringManager; + + /** + * Tests if a given integer represents a valid network type. + * @param networkType the type to be tested + * @return a boolean. {@code true} if the type is valid, else {@code false} + * @deprecated All APIs accepting a network type are deprecated. There should be no need to + * validate a network type. + */ + @Deprecated + public static boolean isNetworkTypeValid(int networkType) { + return MIN_NETWORK_TYPE <= networkType && networkType <= MAX_NETWORK_TYPE; + } + + /** + * Returns a non-localized string representing a given network type. + * ONLY used for debugging output. + * @param type the type needing naming + * @return a String for the given type, or a string version of the type ("87") + * if no name is known. + * @deprecated Types are deprecated. Use {@link NetworkCapabilities} instead. + * {@hide} + */ + @Deprecated + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + public static String getNetworkTypeName(int type) { + switch (type) { + case TYPE_NONE: + return "NONE"; + case TYPE_MOBILE: + return "MOBILE"; + case TYPE_WIFI: + return "WIFI"; + case TYPE_MOBILE_MMS: + return "MOBILE_MMS"; + case TYPE_MOBILE_SUPL: + return "MOBILE_SUPL"; + case TYPE_MOBILE_DUN: + return "MOBILE_DUN"; + case TYPE_MOBILE_HIPRI: + return "MOBILE_HIPRI"; + case TYPE_WIMAX: + return "WIMAX"; + case TYPE_BLUETOOTH: + return "BLUETOOTH"; + case TYPE_DUMMY: + return "DUMMY"; + case TYPE_ETHERNET: + return "ETHERNET"; + case TYPE_MOBILE_FOTA: + return "MOBILE_FOTA"; + case TYPE_MOBILE_IMS: + return "MOBILE_IMS"; + case TYPE_MOBILE_CBS: + return "MOBILE_CBS"; + case TYPE_WIFI_P2P: + return "WIFI_P2P"; + case TYPE_MOBILE_IA: + return "MOBILE_IA"; + case TYPE_MOBILE_EMERGENCY: + return "MOBILE_EMERGENCY"; + case TYPE_PROXY: + return "PROXY"; + case TYPE_VPN: + return "VPN"; + default: + return Integer.toString(type); + } + } + + /** + * @hide + * TODO: Expose for SystemServer when becomes a module. + */ + public void systemReady() { + try { + mService.systemReady(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Checks if a given type uses the cellular data connection. + * This should be replaced in the future by a network property. + * @param networkType the type to check + * @return a boolean - {@code true} if uses cellular network, else {@code false} + * @deprecated Types are deprecated. Use {@link NetworkCapabilities} instead. + * {@hide} + */ + @Deprecated + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562) + public static boolean isNetworkTypeMobile(int networkType) { + switch (networkType) { + case TYPE_MOBILE: + case TYPE_MOBILE_MMS: + case TYPE_MOBILE_SUPL: + case TYPE_MOBILE_DUN: + case TYPE_MOBILE_HIPRI: + case TYPE_MOBILE_FOTA: + case TYPE_MOBILE_IMS: + case TYPE_MOBILE_CBS: + case TYPE_MOBILE_IA: + case TYPE_MOBILE_EMERGENCY: + return true; + default: + return false; + } + } + + /** + * Checks if the given network type is backed by a Wi-Fi radio. + * + * @deprecated Types are deprecated. Use {@link NetworkCapabilities} instead. + * @hide + */ + @Deprecated + public static boolean isNetworkTypeWifi(int networkType) { + switch (networkType) { + case TYPE_WIFI: + case TYPE_WIFI_P2P: + return true; + default: + return false; + } + } + + /** + * Specifies the preferred network type. When the device has more + * than one type available the preferred network type will be used. + * + * @param preference the network type to prefer over all others. It is + * unspecified what happens to the old preferred network in the + * overall ordering. + * @deprecated Functionality has been removed as it no longer makes sense, + * with many more than two networks - we'd need an array to express + * preference. Instead we use dynamic network properties of + * the networks to describe their precedence. + */ + @Deprecated + public void setNetworkPreference(int preference) { + } + + /** + * Retrieves the current preferred network type. + * + * @return an integer representing the preferred network type + * + * @deprecated Functionality has been removed as it no longer makes sense, + * with many more than two networks - we'd need an array to express + * preference. Instead we use dynamic network properties of + * the networks to describe their precedence. + */ + @Deprecated + @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + public int getNetworkPreference() { + return TYPE_NONE; + } + + /** + * Returns details about the currently active default data network. When + * connected, this network is the default route for outgoing connections. + * You should always check {@link NetworkInfo#isConnected()} before initiating + * network traffic. This may return {@code null} when there is no default + * network. + * Note that if the default network is a VPN, this method will return the + * NetworkInfo for one of its underlying networks instead, or null if the + * VPN agent did not specify any. Apps interested in learning about VPNs + * should use {@link #getNetworkInfo(android.net.Network)} instead. + * + * @return a {@link NetworkInfo} object for the current default network + * or {@code null} if no default network is currently active + * @deprecated See {@link NetworkInfo}. + */ + @Deprecated + @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + @Nullable + public NetworkInfo getActiveNetworkInfo() { + try { + return mService.getActiveNetworkInfo(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Returns a {@link Network} object corresponding to the currently active + * default data network. In the event that the current active default data + * network disconnects, the returned {@code Network} object will no longer + * be usable. This will return {@code null} when there is no default + * network. + * + * @return a {@link Network} object for the current default network or + * {@code null} if no default network is currently active + */ + @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + @Nullable + public Network getActiveNetwork() { + try { + return mService.getActiveNetwork(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Returns a {@link Network} object corresponding to the currently active + * default data network for a specific UID. In the event that the default data + * network disconnects, the returned {@code Network} object will no longer + * be usable. This will return {@code null} when there is no default + * network for the UID. + * + * @return a {@link Network} object for the current default network for the + * given UID or {@code null} if no default network is currently active + * + * @hide + */ + @RequiresPermission(android.Manifest.permission.NETWORK_STACK) + @Nullable + public Network getActiveNetworkForUid(int uid) { + return getActiveNetworkForUid(uid, false); + } + + /** {@hide} */ + public Network getActiveNetworkForUid(int uid, boolean ignoreBlocked) { + try { + return mService.getActiveNetworkForUid(uid, ignoreBlocked); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Checks if a VPN app supports always-on mode. + * + * In order to support the always-on feature, an app has to + *

    + *
  • target {@link VERSION_CODES#N API 24} or above, and + *
  • not opt out through the {@link VpnService#SERVICE_META_DATA_SUPPORTS_ALWAYS_ON} + * meta-data field. + *
+ * + * @param userId The identifier of the user for whom the VPN app is installed. + * @param vpnPackage The canonical package name of the VPN app. + * @return {@code true} if and only if the VPN app exists and supports always-on mode. + * @hide + */ + public boolean isAlwaysOnVpnPackageSupportedForUser(int userId, @Nullable String vpnPackage) { + try { + return mService.isAlwaysOnVpnPackageSupported(userId, vpnPackage); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Configures an always-on VPN connection through a specific application. + * This connection is automatically granted and persisted after a reboot. + * + *

The designated package should declare a {@link VpnService} in its + * manifest guarded by {@link android.Manifest.permission.BIND_VPN_SERVICE}, + * otherwise the call will fail. + * + * @param userId The identifier of the user to set an always-on VPN for. + * @param vpnPackage The package name for an installed VPN app on the device, or {@code null} + * to remove an existing always-on VPN configuration. + * @param lockdownEnabled {@code true} to disallow networking when the VPN is not connected or + * {@code false} otherwise. + * @param lockdownAllowlist The list of packages that are allowed to access network directly + * when VPN is in lockdown mode but is not running. Non-existent packages are ignored so + * this method must be called when a package that should be allowed is installed or + * uninstalled. + * @return {@code true} if the package is set as always-on VPN controller; + * {@code false} otherwise. + * @hide + */ + @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN) + public boolean setAlwaysOnVpnPackageForUser(int userId, @Nullable String vpnPackage, + boolean lockdownEnabled, @Nullable List lockdownAllowlist) { + try { + return mService.setAlwaysOnVpnPackage( + userId, vpnPackage, lockdownEnabled, lockdownAllowlist); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Returns the package name of the currently set always-on VPN application. + * If there is no always-on VPN set, or the VPN is provided by the system instead + * of by an app, {@code null} will be returned. + * + * @return Package name of VPN controller responsible for always-on VPN, + * or {@code null} if none is set. + * @hide + */ + @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN) + public String getAlwaysOnVpnPackageForUser(int userId) { + try { + return mService.getAlwaysOnVpnPackage(userId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * @return whether always-on VPN is in lockdown mode. + * + * @hide + **/ + @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN) + public boolean isVpnLockdownEnabled(int userId) { + try { + return mService.isVpnLockdownEnabled(userId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + + } + + /** + * @return the list of packages that are allowed to access network when always-on VPN is in + * lockdown mode but not connected. Returns {@code null} when VPN lockdown is not active. + * + * @hide + **/ + @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN) + public List getVpnLockdownWhitelist(int userId) { + try { + return mService.getVpnLockdownWhitelist(userId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Adds or removes a requirement for given UID ranges to use the VPN. + * + * If set to {@code true}, informs the system that the UIDs in the specified ranges must not + * have any connectivity except if a VPN is connected and applies to the UIDs, or if the UIDs + * otherwise have permission to bypass the VPN (e.g., because they have the + * {@link android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS} permission, or when + * using a socket protected by a method such as {@link VpnService#protect(DatagramSocket)}. If + * set to {@code false}, a previously-added restriction is removed. + *

+ * Each of the UID ranges specified by this method is added and removed as is, and no processing + * is performed on the ranges to de-duplicate, merge, split, or intersect them. In order to + * remove a previously-added range, the exact range must be removed as is. + *

+ * The changes are applied asynchronously and may not have been applied by the time the method + * returns. Apps will be notified about any changes that apply to them via + * {@link NetworkCallback#onBlockedStatusChanged} callbacks called after the changes take + * effect. + *

+ * This method should be called only by the VPN code. + * + * @param ranges the UID ranges to restrict + * @param requireVpn whether the specified UID ranges must use a VPN + * + * TODO: expose as @SystemApi. + * @hide + */ + @RequiresPermission(anyOf = { + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, + android.Manifest.permission.NETWORK_STACK}) + public void setRequireVpnForUids(boolean requireVpn, + @NonNull Collection> ranges) { + Objects.requireNonNull(ranges); + // The Range class is not parcelable. Convert to UidRange, which is what is used internally. + // This method is not necessarily expected to be used outside the system server, so + // parceling may not be necessary, but it could be used out-of-process, e.g., by the network + // stack process, or by tests. + UidRange[] rangesArray = new UidRange[ranges.size()]; + int index = 0; + for (Range range : ranges) { + rangesArray[index++] = new UidRange(range.getLower(), range.getUpper()); + } + try { + mService.setRequireVpnForUids(requireVpn, rangesArray); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Returns details about the currently active default data network + * for a given uid. This is for internal use only to avoid spying + * other apps. + * + * @return a {@link NetworkInfo} object for the current default network + * for the given uid or {@code null} if no default network is + * available for the specified uid. + * + * {@hide} + */ + @RequiresPermission(android.Manifest.permission.NETWORK_STACK) + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + public NetworkInfo getActiveNetworkInfoForUid(int uid) { + return getActiveNetworkInfoForUid(uid, false); + } + + /** {@hide} */ + public NetworkInfo getActiveNetworkInfoForUid(int uid, boolean ignoreBlocked) { + try { + return mService.getActiveNetworkInfoForUid(uid, ignoreBlocked); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Returns connection status information about a particular + * network type. + * + * @param networkType integer specifying which networkType in + * which you're interested. + * @return a {@link NetworkInfo} object for the requested + * network type or {@code null} if the type is not + * supported by the device. If {@code networkType} is + * TYPE_VPN and a VPN is active for the calling app, + * then this method will try to return one of the + * underlying networks for the VPN or null if the + * VPN agent didn't specify any. + * + * @deprecated This method does not support multiple connected networks + * of the same type. Use {@link #getAllNetworks} and + * {@link #getNetworkInfo(android.net.Network)} instead. + */ + @Deprecated + @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + @Nullable + public NetworkInfo getNetworkInfo(int networkType) { + try { + return mService.getNetworkInfo(networkType); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Returns connection status information about a particular + * Network. + * + * @param network {@link Network} specifying which network + * in which you're interested. + * @return a {@link NetworkInfo} object for the requested + * network or {@code null} if the {@code Network} + * is not valid. + * @deprecated See {@link NetworkInfo}. + */ + @Deprecated + @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + @Nullable + public NetworkInfo getNetworkInfo(@Nullable Network network) { + return getNetworkInfoForUid(network, Process.myUid(), false); + } + + /** {@hide} */ + public NetworkInfo getNetworkInfoForUid(Network network, int uid, boolean ignoreBlocked) { + try { + return mService.getNetworkInfoForUid(network, uid, ignoreBlocked); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Returns connection status information about all network + * types supported by the device. + * + * @return an array of {@link NetworkInfo} objects. Check each + * {@link NetworkInfo#getType} for which type each applies. + * + * @deprecated This method does not support multiple connected networks + * of the same type. Use {@link #getAllNetworks} and + * {@link #getNetworkInfo(android.net.Network)} instead. + */ + @Deprecated + @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + @NonNull + public NetworkInfo[] getAllNetworkInfo() { + try { + return mService.getAllNetworkInfo(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Returns the {@link Network} object currently serving a given type, or + * null if the given type is not connected. + * + * @hide + * @deprecated This method does not support multiple connected networks + * of the same type. Use {@link #getAllNetworks} and + * {@link #getNetworkInfo(android.net.Network)} instead. + */ + @Deprecated + @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + @UnsupportedAppUsage + public Network getNetworkForType(int networkType) { + try { + return mService.getNetworkForType(networkType); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Returns an array of all {@link Network} currently tracked by the + * framework. + * + * @return an array of {@link Network} objects. + */ + @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + @NonNull + public Network[] getAllNetworks() { + try { + return mService.getAllNetworks(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Returns an array of {@link android.net.NetworkCapabilities} objects, representing + * the Networks that applications run by the given user will use by default. + * @hide + */ + @UnsupportedAppUsage + public NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser(int userId) { + try { + return mService.getDefaultNetworkCapabilitiesForUser( + userId, mContext.getOpPackageName()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Returns the IP information for the current default network. + * + * @return a {@link LinkProperties} object describing the IP info + * for the current default network, or {@code null} if there + * is no current default network. + * + * {@hide} + * @deprecated please use {@link #getLinkProperties(Network)} on the return + * value of {@link #getActiveNetwork()} instead. In particular, + * this method will return non-null LinkProperties even if the + * app is blocked by policy from using this network. + */ + @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 109783091) + public LinkProperties getActiveLinkProperties() { + try { + return mService.getActiveLinkProperties(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Returns the IP information for a given network type. + * + * @param networkType the network type of interest. + * @return a {@link LinkProperties} object describing the IP info + * for the given networkType, or {@code null} if there is + * no current default network. + * + * {@hide} + * @deprecated This method does not support multiple connected networks + * of the same type. Use {@link #getAllNetworks}, + * {@link #getNetworkInfo(android.net.Network)}, and + * {@link #getLinkProperties(android.net.Network)} instead. + */ + @Deprecated + @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562) + public LinkProperties getLinkProperties(int networkType) { + try { + return mService.getLinkPropertiesForType(networkType); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Get the {@link LinkProperties} for the given {@link Network}. This + * will return {@code null} if the network is unknown. + * + * @param network The {@link Network} object identifying the network in question. + * @return The {@link LinkProperties} for the network, or {@code null}. + */ + @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + @Nullable + public LinkProperties getLinkProperties(@Nullable Network network) { + try { + return mService.getLinkProperties(network); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Get the {@link android.net.NetworkCapabilities} for the given {@link Network}. This + * will return {@code null} if the network is unknown. + * + * @param network The {@link Network} object identifying the network in question. + * @return The {@link android.net.NetworkCapabilities} for the network, or {@code null}. + */ + @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + @Nullable + public NetworkCapabilities getNetworkCapabilities(@Nullable Network network) { + try { + return mService.getNetworkCapabilities(network, mContext.getOpPackageName()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Gets a URL that can be used for resolving whether a captive portal is present. + * 1. This URL should respond with a 204 response to a GET request to indicate no captive + * portal is present. + * 2. This URL must be HTTP as redirect responses are used to find captive portal + * sign-in pages. Captive portals cannot respond to HTTPS requests with redirects. + * + * The system network validation may be using different strategies to detect captive portals, + * so this method does not necessarily return a URL used by the system. It only returns a URL + * that may be relevant for other components trying to detect captive portals. + * + * @hide + * @deprecated This API returns URL which is not guaranteed to be one of the URLs used by the + * system. + */ + @Deprecated + @SystemApi + @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) + public String getCaptivePortalServerUrl() { + try { + return mService.getCaptivePortalServerUrl(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Tells the underlying networking system that the caller wants to + * begin using the named feature. The interpretation of {@code feature} + * is completely up to each networking implementation. + * + *

This method requires the caller to hold either the + * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission + * or the ability to modify system settings as determined by + * {@link android.provider.Settings.System#canWrite}.

+ * + * @param networkType specifies which network the request pertains to + * @param feature the name of the feature to be used + * @return an integer value representing the outcome of the request. + * The interpretation of this value is specific to each networking + * implementation+feature combination, except that the value {@code -1} + * always indicates failure. + * + * @deprecated Deprecated in favor of the cleaner + * {@link #requestNetwork(NetworkRequest, NetworkCallback)} API. + * In {@link VERSION_CODES#M}, and above, this method is unsupported and will + * throw {@code UnsupportedOperationException} if called. + * @removed + */ + @Deprecated + public int startUsingNetworkFeature(int networkType, String feature) { + checkLegacyRoutingApiAccess(); + NetworkCapabilities netCap = networkCapabilitiesForFeature(networkType, feature); + if (netCap == null) { + Log.d(TAG, "Can't satisfy startUsingNetworkFeature for " + networkType + ", " + + feature); + return DEPRECATED_PHONE_CONSTANT_APN_REQUEST_FAILED; + } + + NetworkRequest request = null; + synchronized (sLegacyRequests) { + LegacyRequest l = sLegacyRequests.get(netCap); + if (l != null) { + Log.d(TAG, "renewing startUsingNetworkFeature request " + l.networkRequest); + renewRequestLocked(l); + if (l.currentNetwork != null) { + return DEPRECATED_PHONE_CONSTANT_APN_ALREADY_ACTIVE; + } else { + return DEPRECATED_PHONE_CONSTANT_APN_REQUEST_STARTED; + } + } + + request = requestNetworkForFeatureLocked(netCap); + } + if (request != null) { + Log.d(TAG, "starting startUsingNetworkFeature for request " + request); + return DEPRECATED_PHONE_CONSTANT_APN_REQUEST_STARTED; + } else { + Log.d(TAG, " request Failed"); + return DEPRECATED_PHONE_CONSTANT_APN_REQUEST_FAILED; + } + } + + /** + * Tells the underlying networking system that the caller is finished + * using the named feature. The interpretation of {@code feature} + * is completely up to each networking implementation. + * + *

This method requires the caller to hold either the + * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission + * or the ability to modify system settings as determined by + * {@link android.provider.Settings.System#canWrite}.

+ * + * @param networkType specifies which network the request pertains to + * @param feature the name of the feature that is no longer needed + * @return an integer value representing the outcome of the request. + * The interpretation of this value is specific to each networking + * implementation+feature combination, except that the value {@code -1} + * always indicates failure. + * + * @deprecated Deprecated in favor of the cleaner + * {@link #unregisterNetworkCallback(NetworkCallback)} API. + * In {@link VERSION_CODES#M}, and above, this method is unsupported and will + * throw {@code UnsupportedOperationException} if called. + * @removed + */ + @Deprecated + public int stopUsingNetworkFeature(int networkType, String feature) { + checkLegacyRoutingApiAccess(); + NetworkCapabilities netCap = networkCapabilitiesForFeature(networkType, feature); + if (netCap == null) { + Log.d(TAG, "Can't satisfy stopUsingNetworkFeature for " + networkType + ", " + + feature); + return -1; + } + + if (removeRequestForFeature(netCap)) { + Log.d(TAG, "stopUsingNetworkFeature for " + networkType + ", " + feature); + } + return 1; + } + + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + private NetworkCapabilities networkCapabilitiesForFeature(int networkType, String feature) { + if (networkType == TYPE_MOBILE) { + switch (feature) { + case "enableCBS": + return networkCapabilitiesForType(TYPE_MOBILE_CBS); + case "enableDUN": + case "enableDUNAlways": + return networkCapabilitiesForType(TYPE_MOBILE_DUN); + case "enableFOTA": + return networkCapabilitiesForType(TYPE_MOBILE_FOTA); + case "enableHIPRI": + return networkCapabilitiesForType(TYPE_MOBILE_HIPRI); + case "enableIMS": + return networkCapabilitiesForType(TYPE_MOBILE_IMS); + case "enableMMS": + return networkCapabilitiesForType(TYPE_MOBILE_MMS); + case "enableSUPL": + return networkCapabilitiesForType(TYPE_MOBILE_SUPL); + default: + return null; + } + } else if (networkType == TYPE_WIFI && "p2p".equals(feature)) { + return networkCapabilitiesForType(TYPE_WIFI_P2P); + } + return null; + } + + private int legacyTypeForNetworkCapabilities(NetworkCapabilities netCap) { + if (netCap == null) return TYPE_NONE; + if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_CBS)) { + return TYPE_MOBILE_CBS; + } + if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_IMS)) { + return TYPE_MOBILE_IMS; + } + if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_FOTA)) { + return TYPE_MOBILE_FOTA; + } + if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_DUN)) { + return TYPE_MOBILE_DUN; + } + if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_SUPL)) { + return TYPE_MOBILE_SUPL; + } + if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS)) { + return TYPE_MOBILE_MMS; + } + if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) { + return TYPE_MOBILE_HIPRI; + } + if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_WIFI_P2P)) { + return TYPE_WIFI_P2P; + } + return TYPE_NONE; + } + + private static class LegacyRequest { + NetworkCapabilities networkCapabilities; + NetworkRequest networkRequest; + int expireSequenceNumber; + Network currentNetwork; + int delay = -1; + + private void clearDnsBinding() { + if (currentNetwork != null) { + currentNetwork = null; + setProcessDefaultNetworkForHostResolution(null); + } + } + + NetworkCallback networkCallback = new NetworkCallback() { + @Override + public void onAvailable(Network network) { + currentNetwork = network; + Log.d(TAG, "startUsingNetworkFeature got Network:" + network); + setProcessDefaultNetworkForHostResolution(network); + } + @Override + public void onLost(Network network) { + if (network.equals(currentNetwork)) clearDnsBinding(); + Log.d(TAG, "startUsingNetworkFeature lost Network:" + network); + } + }; + } + + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + private static final HashMap sLegacyRequests = + new HashMap<>(); + + private NetworkRequest findRequestForFeature(NetworkCapabilities netCap) { + synchronized (sLegacyRequests) { + LegacyRequest l = sLegacyRequests.get(netCap); + if (l != null) return l.networkRequest; + } + return null; + } + + private void renewRequestLocked(LegacyRequest l) { + l.expireSequenceNumber++; + Log.d(TAG, "renewing request to seqNum " + l.expireSequenceNumber); + sendExpireMsgForFeature(l.networkCapabilities, l.expireSequenceNumber, l.delay); + } + + private void expireRequest(NetworkCapabilities netCap, int sequenceNum) { + int ourSeqNum = -1; + synchronized (sLegacyRequests) { + LegacyRequest l = sLegacyRequests.get(netCap); + if (l == null) return; + ourSeqNum = l.expireSequenceNumber; + if (l.expireSequenceNumber == sequenceNum) removeRequestForFeature(netCap); + } + Log.d(TAG, "expireRequest with " + ourSeqNum + ", " + sequenceNum); + } + + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + private NetworkRequest requestNetworkForFeatureLocked(NetworkCapabilities netCap) { + int delay = -1; + int type = legacyTypeForNetworkCapabilities(netCap); + try { + delay = mService.getRestoreDefaultNetworkDelay(type); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + LegacyRequest l = new LegacyRequest(); + l.networkCapabilities = netCap; + l.delay = delay; + l.expireSequenceNumber = 0; + l.networkRequest = sendRequestForNetwork( + netCap, l.networkCallback, 0, REQUEST, type, getDefaultHandler()); + if (l.networkRequest == null) return null; + sLegacyRequests.put(netCap, l); + sendExpireMsgForFeature(netCap, l.expireSequenceNumber, delay); + return l.networkRequest; + } + + private void sendExpireMsgForFeature(NetworkCapabilities netCap, int seqNum, int delay) { + if (delay >= 0) { + Log.d(TAG, "sending expire msg with seqNum " + seqNum + " and delay " + delay); + CallbackHandler handler = getDefaultHandler(); + Message msg = handler.obtainMessage(EXPIRE_LEGACY_REQUEST, seqNum, 0, netCap); + handler.sendMessageDelayed(msg, delay); + } + } + + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + private boolean removeRequestForFeature(NetworkCapabilities netCap) { + final LegacyRequest l; + synchronized (sLegacyRequests) { + l = sLegacyRequests.remove(netCap); + } + if (l == null) return false; + unregisterNetworkCallback(l.networkCallback); + l.clearDnsBinding(); + return true; + } + + private static final SparseIntArray sLegacyTypeToTransport = new SparseIntArray(); + static { + sLegacyTypeToTransport.put(TYPE_MOBILE, NetworkCapabilities.TRANSPORT_CELLULAR); + sLegacyTypeToTransport.put(TYPE_MOBILE_CBS, NetworkCapabilities.TRANSPORT_CELLULAR); + sLegacyTypeToTransport.put(TYPE_MOBILE_DUN, NetworkCapabilities.TRANSPORT_CELLULAR); + sLegacyTypeToTransport.put(TYPE_MOBILE_FOTA, NetworkCapabilities.TRANSPORT_CELLULAR); + sLegacyTypeToTransport.put(TYPE_MOBILE_HIPRI, NetworkCapabilities.TRANSPORT_CELLULAR); + sLegacyTypeToTransport.put(TYPE_MOBILE_IMS, NetworkCapabilities.TRANSPORT_CELLULAR); + sLegacyTypeToTransport.put(TYPE_MOBILE_MMS, NetworkCapabilities.TRANSPORT_CELLULAR); + sLegacyTypeToTransport.put(TYPE_MOBILE_SUPL, NetworkCapabilities.TRANSPORT_CELLULAR); + sLegacyTypeToTransport.put(TYPE_WIFI, NetworkCapabilities.TRANSPORT_WIFI); + sLegacyTypeToTransport.put(TYPE_WIFI_P2P, NetworkCapabilities.TRANSPORT_WIFI); + sLegacyTypeToTransport.put(TYPE_BLUETOOTH, NetworkCapabilities.TRANSPORT_BLUETOOTH); + sLegacyTypeToTransport.put(TYPE_ETHERNET, NetworkCapabilities.TRANSPORT_ETHERNET); + } + + private static final SparseIntArray sLegacyTypeToCapability = new SparseIntArray(); + static { + sLegacyTypeToCapability.put(TYPE_MOBILE_CBS, NetworkCapabilities.NET_CAPABILITY_CBS); + sLegacyTypeToCapability.put(TYPE_MOBILE_DUN, NetworkCapabilities.NET_CAPABILITY_DUN); + sLegacyTypeToCapability.put(TYPE_MOBILE_FOTA, NetworkCapabilities.NET_CAPABILITY_FOTA); + sLegacyTypeToCapability.put(TYPE_MOBILE_IMS, NetworkCapabilities.NET_CAPABILITY_IMS); + sLegacyTypeToCapability.put(TYPE_MOBILE_MMS, NetworkCapabilities.NET_CAPABILITY_MMS); + sLegacyTypeToCapability.put(TYPE_MOBILE_SUPL, NetworkCapabilities.NET_CAPABILITY_SUPL); + sLegacyTypeToCapability.put(TYPE_WIFI_P2P, NetworkCapabilities.NET_CAPABILITY_WIFI_P2P); + } + + /** + * Given a legacy type (TYPE_WIFI, ...) returns a NetworkCapabilities + * instance suitable for registering a request or callback. Throws an + * IllegalArgumentException if no mapping from the legacy type to + * NetworkCapabilities is known. + * + * @deprecated Types are deprecated. Use {@link NetworkCallback} or {@link NetworkRequest} + * to find the network instead. + * @hide + */ + public static NetworkCapabilities networkCapabilitiesForType(int type) { + final NetworkCapabilities nc = new NetworkCapabilities(); + + // Map from type to transports. + final int NOT_FOUND = -1; + final int transport = sLegacyTypeToTransport.get(type, NOT_FOUND); + Preconditions.checkArgument(transport != NOT_FOUND, "unknown legacy type: " + type); + nc.addTransportType(transport); + + // Map from type to capabilities. + nc.addCapability(sLegacyTypeToCapability.get( + type, NetworkCapabilities.NET_CAPABILITY_INTERNET)); + nc.maybeMarkCapabilitiesRestricted(); + return nc; + } + + /** @hide */ + public static class PacketKeepaliveCallback { + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + public PacketKeepaliveCallback() { + } + /** The requested keepalive was successfully started. */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + public void onStarted() {} + /** The keepalive was successfully stopped. */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + public void onStopped() {} + /** An error occurred. */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + public void onError(int error) {} + } + + /** + * Allows applications to request that the system periodically send specific packets on their + * behalf, using hardware offload to save battery power. + * + * To request that the system send keepalives, call one of the methods that return a + * {@link ConnectivityManager.PacketKeepalive} object, such as {@link #startNattKeepalive}, + * passing in a non-null callback. If the callback is successfully started, the callback's + * {@code onStarted} method will be called. If an error occurs, {@code onError} will be called, + * specifying one of the {@code ERROR_*} constants in this class. + * + * To stop an existing keepalive, call {@link PacketKeepalive#stop}. The system will call + * {@link PacketKeepaliveCallback#onStopped} if the operation was successful or + * {@link PacketKeepaliveCallback#onError} if an error occurred. + * + * @deprecated Use {@link SocketKeepalive} instead. + * + * @hide + */ + public class PacketKeepalive { + + private static final String TAG = "PacketKeepalive"; + + /** @hide */ + public static final int SUCCESS = 0; + + /** @hide */ + public static final int NO_KEEPALIVE = -1; + + /** @hide */ + public static final int BINDER_DIED = -10; + + /** The specified {@code Network} is not connected. */ + public static final int ERROR_INVALID_NETWORK = -20; + /** The specified IP addresses are invalid. For example, the specified source IP address is + * not configured on the specified {@code Network}. */ + public static final int ERROR_INVALID_IP_ADDRESS = -21; + /** The requested port is invalid. */ + public static final int ERROR_INVALID_PORT = -22; + /** The packet length is invalid (e.g., too long). */ + public static final int ERROR_INVALID_LENGTH = -23; + /** The packet transmission interval is invalid (e.g., too short). */ + public static final int ERROR_INVALID_INTERVAL = -24; + + /** The hardware does not support this request. */ + public static final int ERROR_HARDWARE_UNSUPPORTED = -30; + /** The hardware returned an error. */ + public static final int ERROR_HARDWARE_ERROR = -31; + + /** The NAT-T destination port for IPsec */ + public static final int NATT_PORT = 4500; + + /** The minimum interval in seconds between keepalive packet transmissions */ + public static final int MIN_INTERVAL = 10; + + private final Network mNetwork; + private final ISocketKeepaliveCallback mCallback; + private final ExecutorService mExecutor; + + private volatile Integer mSlot; + + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + public void stop() { + try { + mExecutor.execute(() -> { + try { + if (mSlot != null) { + mService.stopKeepalive(mNetwork, mSlot); + } + } catch (RemoteException e) { + Log.e(TAG, "Error stopping packet keepalive: ", e); + throw e.rethrowFromSystemServer(); + } + }); + } catch (RejectedExecutionException e) { + // The internal executor has already stopped due to previous event. + } + } + + private PacketKeepalive(Network network, PacketKeepaliveCallback callback) { + Preconditions.checkNotNull(network, "network cannot be null"); + Preconditions.checkNotNull(callback, "callback cannot be null"); + mNetwork = network; + mExecutor = Executors.newSingleThreadExecutor(); + mCallback = new ISocketKeepaliveCallback.Stub() { + @Override + public void onStarted(int slot) { + final long token = Binder.clearCallingIdentity(); + try { + mExecutor.execute(() -> { + mSlot = slot; + callback.onStarted(); + }); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + @Override + public void onStopped() { + final long token = Binder.clearCallingIdentity(); + try { + mExecutor.execute(() -> { + mSlot = null; + callback.onStopped(); + }); + } finally { + Binder.restoreCallingIdentity(token); + } + mExecutor.shutdown(); + } + + @Override + public void onError(int error) { + final long token = Binder.clearCallingIdentity(); + try { + mExecutor.execute(() -> { + mSlot = null; + callback.onError(error); + }); + } finally { + Binder.restoreCallingIdentity(token); + } + mExecutor.shutdown(); + } + + @Override + public void onDataReceived() { + // PacketKeepalive is only used for Nat-T keepalive and as such does not invoke + // this callback when data is received. + } + }; + } + } + + /** + * Starts an IPsec NAT-T keepalive packet with the specified parameters. + * + * @deprecated Use {@link #createSocketKeepalive} instead. + * + * @hide + */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + public PacketKeepalive startNattKeepalive( + Network network, int intervalSeconds, PacketKeepaliveCallback callback, + InetAddress srcAddr, int srcPort, InetAddress dstAddr) { + final PacketKeepalive k = new PacketKeepalive(network, callback); + try { + mService.startNattKeepalive(network, intervalSeconds, k.mCallback, + srcAddr.getHostAddress(), srcPort, dstAddr.getHostAddress()); + } catch (RemoteException e) { + Log.e(TAG, "Error starting packet keepalive: ", e); + throw e.rethrowFromSystemServer(); + } + return k; + } + + // Construct an invalid fd. + private ParcelFileDescriptor createInvalidFd() { + final int invalidFd = -1; + return ParcelFileDescriptor.adoptFd(invalidFd); + } + + /** + * Request that keepalives be started on a IPsec NAT-T socket. + * + * @param network The {@link Network} the socket is on. + * @param socket The socket that needs to be kept alive. + * @param source The source address of the {@link UdpEncapsulationSocket}. + * @param destination The destination address of the {@link UdpEncapsulationSocket}. + * @param executor The executor on which callback will be invoked. The provided {@link Executor} + * must run callback sequentially, otherwise the order of callbacks cannot be + * guaranteed. + * @param callback A {@link SocketKeepalive.Callback}. Used for notifications about keepalive + * changes. Must be extended by applications that use this API. + * + * @return A {@link SocketKeepalive} object that can be used to control the keepalive on the + * given socket. + **/ + public @NonNull SocketKeepalive createSocketKeepalive(@NonNull Network network, + @NonNull UdpEncapsulationSocket socket, + @NonNull InetAddress source, + @NonNull InetAddress destination, + @NonNull @CallbackExecutor Executor executor, + @NonNull Callback callback) { + ParcelFileDescriptor dup; + try { + // Dup is needed here as the pfd inside the socket is owned by the IpSecService, + // which cannot be obtained by the app process. + dup = ParcelFileDescriptor.dup(socket.getFileDescriptor()); + } catch (IOException ignored) { + // Construct an invalid fd, so that if the user later calls start(), it will fail with + // ERROR_INVALID_SOCKET. + dup = createInvalidFd(); + } + return new NattSocketKeepalive(mService, network, dup, socket.getResourceId(), source, + destination, executor, callback); + } + + /** + * Request that keepalives be started on a IPsec NAT-T socket file descriptor. Directly called + * by system apps which don't use IpSecService to create {@link UdpEncapsulationSocket}. + * + * @param network The {@link Network} the socket is on. + * @param pfd The {@link ParcelFileDescriptor} that needs to be kept alive. The provided + * {@link ParcelFileDescriptor} must be bound to a port and the keepalives will be sent + * from that port. + * @param source The source address of the {@link UdpEncapsulationSocket}. + * @param destination The destination address of the {@link UdpEncapsulationSocket}. The + * keepalive packets will always be sent to port 4500 of the given {@code destination}. + * @param executor The executor on which callback will be invoked. The provided {@link Executor} + * must run callback sequentially, otherwise the order of callbacks cannot be + * guaranteed. + * @param callback A {@link SocketKeepalive.Callback}. Used for notifications about keepalive + * changes. Must be extended by applications that use this API. + * + * @return A {@link SocketKeepalive} object that can be used to control the keepalive on the + * given socket. + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD) + public @NonNull SocketKeepalive createNattKeepalive(@NonNull Network network, + @NonNull ParcelFileDescriptor pfd, + @NonNull InetAddress source, + @NonNull InetAddress destination, + @NonNull @CallbackExecutor Executor executor, + @NonNull Callback callback) { + ParcelFileDescriptor dup; + try { + // TODO: Consider remove unnecessary dup. + dup = pfd.dup(); + } catch (IOException ignored) { + // Construct an invalid fd, so that if the user later calls start(), it will fail with + // ERROR_INVALID_SOCKET. + dup = createInvalidFd(); + } + return new NattSocketKeepalive(mService, network, dup, + INVALID_RESOURCE_ID /* Unused */, source, destination, executor, callback); + } + + /** + * Request that keepalives be started on a TCP socket. + * The socket must be established. + * + * @param network The {@link Network} the socket is on. + * @param socket The socket that needs to be kept alive. + * @param executor The executor on which callback will be invoked. This implementation assumes + * the provided {@link Executor} runs the callbacks in sequence with no + * concurrency. Failing this, no guarantee of correctness can be made. It is + * the responsibility of the caller to ensure the executor provides this + * guarantee. A simple way of creating such an executor is with the standard + * tool {@code Executors.newSingleThreadExecutor}. + * @param callback A {@link SocketKeepalive.Callback}. Used for notifications about keepalive + * changes. Must be extended by applications that use this API. + * + * @return A {@link SocketKeepalive} object that can be used to control the keepalive on the + * given socket. + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD) + public @NonNull SocketKeepalive createSocketKeepalive(@NonNull Network network, + @NonNull Socket socket, + @NonNull Executor executor, + @NonNull Callback callback) { + ParcelFileDescriptor dup; + try { + dup = ParcelFileDescriptor.fromSocket(socket); + } catch (UncheckedIOException ignored) { + // Construct an invalid fd, so that if the user later calls start(), it will fail with + // ERROR_INVALID_SOCKET. + dup = createInvalidFd(); + } + return new TcpSocketKeepalive(mService, network, dup, executor, callback); + } + + /** + * Ensure that a network route exists to deliver traffic to the specified + * host via the specified network interface. An attempt to add a route that + * already exists is ignored, but treated as successful. + * + *

This method requires the caller to hold either the + * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission + * or the ability to modify system settings as determined by + * {@link android.provider.Settings.System#canWrite}.

+ * + * @param networkType the type of the network over which traffic to the specified + * host is to be routed + * @param hostAddress the IP address of the host to which the route is desired + * @return {@code true} on success, {@code false} on failure + * + * @deprecated Deprecated in favor of the + * {@link #requestNetwork(NetworkRequest, NetworkCallback)}, + * {@link #bindProcessToNetwork} and {@link Network#getSocketFactory} API. + * In {@link VERSION_CODES#M}, and above, this method is unsupported and will + * throw {@code UnsupportedOperationException} if called. + * @removed + */ + @Deprecated + public boolean requestRouteToHost(int networkType, int hostAddress) { + return requestRouteToHostAddress(networkType, NetworkUtils.intToInetAddress(hostAddress)); + } + + /** + * Ensure that a network route exists to deliver traffic to the specified + * host via the specified network interface. An attempt to add a route that + * already exists is ignored, but treated as successful. + * + *

This method requires the caller to hold either the + * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission + * or the ability to modify system settings as determined by + * {@link android.provider.Settings.System#canWrite}.

+ * + * @param networkType the type of the network over which traffic to the specified + * host is to be routed + * @param hostAddress the IP address of the host to which the route is desired + * @return {@code true} on success, {@code false} on failure + * @hide + * @deprecated Deprecated in favor of the {@link #requestNetwork} and + * {@link #bindProcessToNetwork} API. + */ + @Deprecated + @UnsupportedAppUsage + public boolean requestRouteToHostAddress(int networkType, InetAddress hostAddress) { + checkLegacyRoutingApiAccess(); + try { + return mService.requestRouteToHostAddress(networkType, hostAddress.getAddress(), + mContext.getOpPackageName(), getAttributionTag()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * @return the context's attribution tag + */ + // TODO: Remove method and replace with direct call once R code is pushed to AOSP + private @Nullable String getAttributionTag() { + return null; + } + + /** + * Returns the value of the setting for background data usage. If false, + * applications should not use the network if the application is not in the + * foreground. Developers should respect this setting, and check the value + * of this before performing any background data operations. + *

+ * All applications that have background services that use the network + * should listen to {@link #ACTION_BACKGROUND_DATA_SETTING_CHANGED}. + *

+ * @deprecated As of {@link VERSION_CODES#ICE_CREAM_SANDWICH}, availability of + * background data depends on several combined factors, and this method will + * always return {@code true}. Instead, when background data is unavailable, + * {@link #getActiveNetworkInfo()} will now appear disconnected. + * + * @return Whether background data usage is allowed. + */ + @Deprecated + public boolean getBackgroundDataSetting() { + // assume that background data is allowed; final authority is + // NetworkInfo which may be blocked. + return true; + } + + /** + * Sets the value of the setting for background data usage. + * + * @param allowBackgroundData Whether an application should use data while + * it is in the background. + * + * @attr ref android.Manifest.permission#CHANGE_BACKGROUND_DATA_SETTING + * @see #getBackgroundDataSetting() + * @hide + */ + @Deprecated + @UnsupportedAppUsage + public void setBackgroundDataSetting(boolean allowBackgroundData) { + // ignored + } + + /** + * @hide + * @deprecated Talk to TelephonyManager directly + */ + @Deprecated + @UnsupportedAppUsage + public boolean getMobileDataEnabled() { + TelephonyManager tm = mContext.getSystemService(TelephonyManager.class); + if (tm != null) { + int subId = SubscriptionManager.getDefaultDataSubscriptionId(); + Log.d("ConnectivityManager", "getMobileDataEnabled()+ subId=" + subId); + boolean retVal = tm.createForSubscriptionId(subId).isDataEnabled(); + Log.d("ConnectivityManager", "getMobileDataEnabled()- subId=" + subId + + " retVal=" + retVal); + return retVal; + } + Log.d("ConnectivityManager", "getMobileDataEnabled()- remote exception retVal=false"); + return false; + } + + /** + * Callback for use with {@link ConnectivityManager#addDefaultNetworkActiveListener} + * to find out when the system default network has gone in to a high power state. + */ + public interface OnNetworkActiveListener { + /** + * Called on the main thread of the process to report that the current data network + * has become active, and it is now a good time to perform any pending network + * operations. Note that this listener only tells you when the network becomes + * active; if at any other time you want to know whether it is active (and thus okay + * to initiate network traffic), you can retrieve its instantaneous state with + * {@link ConnectivityManager#isDefaultNetworkActive}. + */ + void onNetworkActive(); + } + + private INetworkManagementService getNetworkManagementService() { + synchronized (this) { + if (mNMService != null) { + return mNMService; + } + IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); + mNMService = INetworkManagementService.Stub.asInterface(b); + return mNMService; + } + } + + private final ArrayMap + mNetworkActivityListeners = new ArrayMap<>(); + + /** + * Start listening to reports when the system's default data network is active, meaning it is + * a good time to perform network traffic. Use {@link #isDefaultNetworkActive()} + * to determine the current state of the system's default network after registering the + * listener. + *

+ * If the process default network has been set with + * {@link ConnectivityManager#bindProcessToNetwork} this function will not + * reflect the process's default, but the system default. + * + * @param l The listener to be told when the network is active. + */ + public void addDefaultNetworkActiveListener(final OnNetworkActiveListener l) { + INetworkActivityListener rl = new INetworkActivityListener.Stub() { + @Override + public void onNetworkActive() throws RemoteException { + l.onNetworkActive(); + } + }; + + try { + getNetworkManagementService().registerNetworkActivityListener(rl); + mNetworkActivityListeners.put(l, rl); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Remove network active listener previously registered with + * {@link #addDefaultNetworkActiveListener}. + * + * @param l Previously registered listener. + */ + public void removeDefaultNetworkActiveListener(@NonNull OnNetworkActiveListener l) { + INetworkActivityListener rl = mNetworkActivityListeners.get(l); + Preconditions.checkArgument(rl != null, "Listener was not registered."); + try { + getNetworkManagementService().unregisterNetworkActivityListener(rl); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Return whether the data network is currently active. An active network means that + * it is currently in a high power state for performing data transmission. On some + * types of networks, it may be expensive to move and stay in such a state, so it is + * more power efficient to batch network traffic together when the radio is already in + * this state. This method tells you whether right now is currently a good time to + * initiate network traffic, as the network is already active. + */ + public boolean isDefaultNetworkActive() { + try { + return getNetworkManagementService().isNetworkActive(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * {@hide} + */ + public ConnectivityManager(Context context, IConnectivityManager service) { + mContext = Preconditions.checkNotNull(context, "missing context"); + mService = Preconditions.checkNotNull(service, "missing IConnectivityManager"); + mTetheringManager = (TetheringManager) mContext.getSystemService(Context.TETHERING_SERVICE); + sInstance = this; + } + + /** {@hide} */ + @UnsupportedAppUsage + public static ConnectivityManager from(Context context) { + return (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + } + + /** @hide */ + public NetworkRequest getDefaultRequest() { + try { + // This is not racy as the default request is final in ConnectivityService. + return mService.getDefaultRequest(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /* TODO: These permissions checks don't belong in client-side code. Move them to + * services.jar, possibly in com.android.server.net. */ + + /** {@hide} */ + public static final void enforceChangePermission(Context context, + String callingPkg, String callingAttributionTag) { + int uid = Binder.getCallingUid(); + checkAndNoteChangeNetworkStateOperation(context, uid, callingPkg, + callingAttributionTag, true /* throwException */); + } + + /** + * Check if the package is a allowed to change the network state. This also accounts that such + * an access happened. + * + * @return {@code true} iff the package is allowed to change the network state. + */ + // TODO: Remove method and replace with direct call once R code is pushed to AOSP + private static boolean checkAndNoteChangeNetworkStateOperation(@NonNull Context context, + int uid, @NonNull String callingPackage, @Nullable String callingAttributionTag, + boolean throwException) { + return Settings.checkAndNoteChangeNetworkStateOperation(context, uid, callingPackage, + throwException); + } + + /** + * Check if the package is a allowed to write settings. This also accounts that such an access + * happened. + * + * @return {@code true} iff the package is allowed to write settings. + */ + // TODO: Remove method and replace with direct call once R code is pushed to AOSP + private static boolean checkAndNoteWriteSettingsOperation(@NonNull Context context, int uid, + @NonNull String callingPackage, @Nullable String callingAttributionTag, + boolean throwException) { + return Settings.checkAndNoteWriteSettingsOperation(context, uid, callingPackage, + throwException); + } + + /** + * @deprecated - use getSystemService. This is a kludge to support static access in certain + * situations where a Context pointer is unavailable. + * @hide + */ + @Deprecated + static ConnectivityManager getInstanceOrNull() { + return sInstance; + } + + /** + * @deprecated - use getSystemService. This is a kludge to support static access in certain + * situations where a Context pointer is unavailable. + * @hide + */ + @Deprecated + @UnsupportedAppUsage + private static ConnectivityManager getInstance() { + if (getInstanceOrNull() == null) { + throw new IllegalStateException("No ConnectivityManager yet constructed"); + } + return getInstanceOrNull(); + } + + /** + * Get the set of tetherable, available interfaces. This list is limited by + * device configuration and current interface existence. + * + * @return an array of 0 or more Strings of tetherable interface names. + * + * @deprecated Use {@link TetheringEventCallback#onTetherableInterfacesChanged(List)} instead. + * {@hide} + */ + @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + @UnsupportedAppUsage + @Deprecated + public String[] getTetherableIfaces() { + return mTetheringManager.getTetherableIfaces(); + } + + /** + * Get the set of tethered interfaces. + * + * @return an array of 0 or more String of currently tethered interface names. + * + * @deprecated Use {@link TetheringEventCallback#onTetherableInterfacesChanged(List)} instead. + * {@hide} + */ + @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + @UnsupportedAppUsage + @Deprecated + public String[] getTetheredIfaces() { + return mTetheringManager.getTetheredIfaces(); + } + + /** + * Get the set of interface names which attempted to tether but + * failed. Re-attempting to tether may cause them to reset to the Tethered + * state. Alternatively, causing the interface to be destroyed and recreated + * may cause them to reset to the available state. + * {@link ConnectivityManager#getLastTetherError} can be used to get more + * information on the cause of the errors. + * + * @return an array of 0 or more String indicating the interface names + * which failed to tether. + * + * @deprecated Use {@link TetheringEventCallback#onError(String, int)} instead. + * {@hide} + */ + @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + @UnsupportedAppUsage + @Deprecated + public String[] getTetheringErroredIfaces() { + return mTetheringManager.getTetheringErroredIfaces(); + } + + /** + * Get the set of tethered dhcp ranges. + * + * @deprecated This method is not supported. + * TODO: remove this function when all of clients are removed. + * {@hide} + */ + @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) + @Deprecated + public String[] getTetheredDhcpRanges() { + throw new UnsupportedOperationException("getTetheredDhcpRanges is not supported"); + } + + /** + * Attempt to tether the named interface. This will setup a dhcp server + * on the interface, forward and NAT IP packets and forward DNS requests + * to the best active upstream network interface. Note that if no upstream + * IP network interface is available, dhcp will still run and traffic will be + * allowed between the tethered devices and this device, though upstream net + * access will of course fail until an upstream network interface becomes + * active. + * + *

This method requires the caller to hold either the + * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission + * or the ability to modify system settings as determined by + * {@link android.provider.Settings.System#canWrite}.

+ * + *

WARNING: New clients should not use this function. The only usages should be in PanService + * and WifiStateMachine which need direct access. All other clients should use + * {@link #startTethering} and {@link #stopTethering} which encapsulate proper provisioning + * logic.

+ * + * @param iface the interface name to tether. + * @return error a {@code TETHER_ERROR} value indicating success or failure type + * @deprecated Use {@link TetheringManager#startTethering} instead + * + * {@hide} + */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @Deprecated + public int tether(String iface) { + return mTetheringManager.tether(iface); + } + + /** + * Stop tethering the named interface. + * + *

This method requires the caller to hold either the + * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission + * or the ability to modify system settings as determined by + * {@link android.provider.Settings.System#canWrite}.

+ * + *

WARNING: New clients should not use this function. The only usages should be in PanService + * and WifiStateMachine which need direct access. All other clients should use + * {@link #startTethering} and {@link #stopTethering} which encapsulate proper provisioning + * logic.

+ * + * @param iface the interface name to untether. + * @return error a {@code TETHER_ERROR} value indicating success or failure type + * + * {@hide} + */ + @UnsupportedAppUsage + @Deprecated + public int untether(String iface) { + return mTetheringManager.untether(iface); + } + + /** + * Check if the device allows for tethering. It may be disabled via + * {@code ro.tether.denied} system property, Settings.TETHER_SUPPORTED or + * due to device configuration. + * + *

If this app does not have permission to use this API, it will always + * return false rather than throw an exception.

+ * + *

If the device has a hotspot provisioning app, the caller is required to hold the + * {@link android.Manifest.permission.TETHER_PRIVILEGED} permission.

+ * + *

Otherwise, this method requires the caller to hold the ability to modify system + * settings as determined by {@link android.provider.Settings.System#canWrite}.

+ * + * @return a boolean - {@code true} indicating Tethering is supported. + * + * @deprecated Use {@link TetheringEventCallback#onTetheringSupported(boolean)} instead. + * {@hide} + */ + @SystemApi + @RequiresPermission(anyOf = {android.Manifest.permission.TETHER_PRIVILEGED, + android.Manifest.permission.WRITE_SETTINGS}) + public boolean isTetheringSupported() { + return mTetheringManager.isTetheringSupported(); + } + + /** + * Callback for use with {@link #startTethering} to find out whether tethering succeeded. + * + * @deprecated Use {@link TetheringManager.StartTetheringCallback} instead. + * @hide + */ + @SystemApi + @Deprecated + public static abstract class OnStartTetheringCallback { + /** + * Called when tethering has been successfully started. + */ + public void onTetheringStarted() {} + + /** + * Called when starting tethering failed. + */ + public void onTetheringFailed() {} + } + + /** + * Convenient overload for + * {@link #startTethering(int, boolean, OnStartTetheringCallback, Handler)} which passes a null + * handler to run on the current thread's {@link Looper}. + * + * @deprecated Use {@link TetheringManager#startTethering} instead. + * @hide + */ + @SystemApi + @Deprecated + @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) + public void startTethering(int type, boolean showProvisioningUi, + final OnStartTetheringCallback callback) { + startTethering(type, showProvisioningUi, callback, null); + } + + /** + * Runs tether provisioning for the given type if needed and then starts tethering if + * the check succeeds. If no carrier provisioning is required for tethering, tethering is + * enabled immediately. If provisioning fails, tethering will not be enabled. It also + * schedules tether provisioning re-checks if appropriate. + * + * @param type The type of tethering to start. Must be one of + * {@link ConnectivityManager.TETHERING_WIFI}, + * {@link ConnectivityManager.TETHERING_USB}, or + * {@link ConnectivityManager.TETHERING_BLUETOOTH}. + * @param showProvisioningUi a boolean indicating to show the provisioning app UI if there + * is one. This should be true the first time this function is called and also any time + * the user can see this UI. It gives users information from their carrier about the + * check failing and how they can sign up for tethering if possible. + * @param callback an {@link OnStartTetheringCallback} which will be called to notify the caller + * of the result of trying to tether. + * @param handler {@link Handler} to specify the thread upon which the callback will be invoked. + * + * @deprecated Use {@link TetheringManager#startTethering} instead. + * @hide + */ + @SystemApi + @Deprecated + @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) + public void startTethering(int type, boolean showProvisioningUi, + final OnStartTetheringCallback callback, Handler handler) { + Preconditions.checkNotNull(callback, "OnStartTetheringCallback cannot be null."); + + final Executor executor = new Executor() { + @Override + public void execute(Runnable command) { + if (handler == null) { + command.run(); + } else { + handler.post(command); + } + } + }; + + final StartTetheringCallback tetheringCallback = new StartTetheringCallback() { + @Override + public void onTetheringStarted() { + callback.onTetheringStarted(); + } + + @Override + public void onTetheringFailed(final int error) { + callback.onTetheringFailed(); + } + }; + + final TetheringRequest request = new TetheringRequest.Builder(type) + .setShouldShowEntitlementUi(showProvisioningUi).build(); + + mTetheringManager.startTethering(request, executor, tetheringCallback); + } + + /** + * Stops tethering for the given type. Also cancels any provisioning rechecks for that type if + * applicable. + * + * @param type The type of tethering to stop. Must be one of + * {@link ConnectivityManager.TETHERING_WIFI}, + * {@link ConnectivityManager.TETHERING_USB}, or + * {@link ConnectivityManager.TETHERING_BLUETOOTH}. + * + * @deprecated Use {@link TetheringManager#stopTethering} instead. + * @hide + */ + @SystemApi + @Deprecated + @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) + public void stopTethering(int type) { + mTetheringManager.stopTethering(type); + } + + /** + * Callback for use with {@link registerTetheringEventCallback} to find out tethering + * upstream status. + * + * @deprecated Use {@link TetheringManager#OnTetheringEventCallback} instead. + * @hide + */ + @SystemApi + @Deprecated + public abstract static class OnTetheringEventCallback { + + /** + * Called when tethering upstream changed. This can be called multiple times and can be + * called any time. + * + * @param network the {@link Network} of tethering upstream. Null means tethering doesn't + * have any upstream. + */ + public void onUpstreamChanged(@Nullable Network network) {} + } + + @GuardedBy("mTetheringEventCallbacks") + private final ArrayMap + mTetheringEventCallbacks = new ArrayMap<>(); + + /** + * Start listening to tethering change events. Any new added callback will receive the last + * tethering status right away. If callback is registered when tethering has no upstream or + * disabled, {@link OnTetheringEventCallback#onUpstreamChanged} will immediately be called + * with a null argument. The same callback object cannot be registered twice. + * + * @param executor the executor on which callback will be invoked. + * @param callback the callback to be called when tethering has change events. + * + * @deprecated Use {@link TetheringManager#registerTetheringEventCallback} instead. + * @hide + */ + @SystemApi + @Deprecated + @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) + public void registerTetheringEventCallback( + @NonNull @CallbackExecutor Executor executor, + @NonNull final OnTetheringEventCallback callback) { + Preconditions.checkNotNull(callback, "OnTetheringEventCallback cannot be null."); + + final TetheringEventCallback tetherCallback = + new TetheringEventCallback() { + @Override + public void onUpstreamChanged(@Nullable Network network) { + callback.onUpstreamChanged(network); + } + }; + + synchronized (mTetheringEventCallbacks) { + mTetheringEventCallbacks.put(callback, tetherCallback); + mTetheringManager.registerTetheringEventCallback(executor, tetherCallback); + } + } + + /** + * Remove tethering event callback previously registered with + * {@link #registerTetheringEventCallback}. + * + * @param callback previously registered callback. + * + * @deprecated Use {@link TetheringManager#unregisterTetheringEventCallback} instead. + * @hide + */ + @SystemApi + @Deprecated + @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) + public void unregisterTetheringEventCallback( + @NonNull final OnTetheringEventCallback callback) { + Objects.requireNonNull(callback, "The callback must be non-null"); + synchronized (mTetheringEventCallbacks) { + final TetheringEventCallback tetherCallback = + mTetheringEventCallbacks.remove(callback); + mTetheringManager.unregisterTetheringEventCallback(tetherCallback); + } + } + + + /** + * Get the list of regular expressions that define any tetherable + * USB network interfaces. If USB tethering is not supported by the + * device, this list should be empty. + * + * @return an array of 0 or more regular expression Strings defining + * what interfaces are considered tetherable usb interfaces. + * + * @deprecated Use {@link TetheringEventCallback#onTetherableInterfaceRegexpsChanged} instead. + * {@hide} + */ + @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + @UnsupportedAppUsage + @Deprecated + public String[] getTetherableUsbRegexs() { + return mTetheringManager.getTetherableUsbRegexs(); + } + + /** + * Get the list of regular expressions that define any tetherable + * Wifi network interfaces. If Wifi tethering is not supported by the + * device, this list should be empty. + * + * @return an array of 0 or more regular expression Strings defining + * what interfaces are considered tetherable wifi interfaces. + * + * @deprecated Use {@link TetheringEventCallback#onTetherableInterfaceRegexpsChanged} instead. + * {@hide} + */ + @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + @UnsupportedAppUsage + @Deprecated + public String[] getTetherableWifiRegexs() { + return mTetheringManager.getTetherableWifiRegexs(); + } + + /** + * Get the list of regular expressions that define any tetherable + * Bluetooth network interfaces. If Bluetooth tethering is not supported by the + * device, this list should be empty. + * + * @return an array of 0 or more regular expression Strings defining + * what interfaces are considered tetherable bluetooth interfaces. + * + * @deprecated Use {@link TetheringEventCallback#onTetherableInterfaceRegexpsChanged( + *TetheringManager.TetheringInterfaceRegexps)} instead. + * {@hide} + */ + @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + @UnsupportedAppUsage + @Deprecated + public String[] getTetherableBluetoothRegexs() { + return mTetheringManager.getTetherableBluetoothRegexs(); + } + + /** + * Attempt to both alter the mode of USB and Tethering of USB. A + * utility method to deal with some of the complexity of USB - will + * attempt to switch to Rndis and subsequently tether the resulting + * interface on {@code true} or turn off tethering and switch off + * Rndis on {@code false}. + * + *

This method requires the caller to hold either the + * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission + * or the ability to modify system settings as determined by + * {@link android.provider.Settings.System#canWrite}.

+ * + * @param enable a boolean - {@code true} to enable tethering + * @return error a {@code TETHER_ERROR} value indicating success or failure type + * @deprecated Use {@link TetheringManager#startTethering} instead + * + * {@hide} + */ + @UnsupportedAppUsage + @Deprecated + public int setUsbTethering(boolean enable) { + return mTetheringManager.setUsbTethering(enable); + } + + /** + * @deprecated Use {@link TetheringManager#TETHER_ERROR_NO_ERROR}. + * {@hide} + */ + @SystemApi + @Deprecated + public static final int TETHER_ERROR_NO_ERROR = TetheringManager.TETHER_ERROR_NO_ERROR; + /** + * @deprecated Use {@link TetheringManager#TETHER_ERROR_UNKNOWN_IFACE}. + * {@hide} + */ + @Deprecated + public static final int TETHER_ERROR_UNKNOWN_IFACE = + TetheringManager.TETHER_ERROR_UNKNOWN_IFACE; + /** + * @deprecated Use {@link TetheringManager#TETHER_ERROR_SERVICE_UNAVAIL}. + * {@hide} + */ + @Deprecated + public static final int TETHER_ERROR_SERVICE_UNAVAIL = + TetheringManager.TETHER_ERROR_SERVICE_UNAVAIL; + /** + * @deprecated Use {@link TetheringManager#TETHER_ERROR_UNSUPPORTED}. + * {@hide} + */ + @Deprecated + public static final int TETHER_ERROR_UNSUPPORTED = TetheringManager.TETHER_ERROR_UNSUPPORTED; + /** + * @deprecated Use {@link TetheringManager#TETHER_ERROR_UNAVAIL_IFACE}. + * {@hide} + */ + @Deprecated + public static final int TETHER_ERROR_UNAVAIL_IFACE = + TetheringManager.TETHER_ERROR_UNAVAIL_IFACE; + /** + * @deprecated Use {@link TetheringManager#TETHER_ERROR_INTERNAL_ERROR}. + * {@hide} + */ + @Deprecated + public static final int TETHER_ERROR_MASTER_ERROR = + TetheringManager.TETHER_ERROR_INTERNAL_ERROR; + /** + * @deprecated Use {@link TetheringManager#TETHER_ERROR_TETHER_IFACE_ERROR}. + * {@hide} + */ + @Deprecated + public static final int TETHER_ERROR_TETHER_IFACE_ERROR = + TetheringManager.TETHER_ERROR_TETHER_IFACE_ERROR; + /** + * @deprecated Use {@link TetheringManager#TETHER_ERROR_UNTETHER_IFACE_ERROR}. + * {@hide} + */ + @Deprecated + public static final int TETHER_ERROR_UNTETHER_IFACE_ERROR = + TetheringManager.TETHER_ERROR_UNTETHER_IFACE_ERROR; + /** + * @deprecated Use {@link TetheringManager#TETHER_ERROR_ENABLE_FORWARDING_ERROR}. + * {@hide} + */ + @Deprecated + public static final int TETHER_ERROR_ENABLE_NAT_ERROR = + TetheringManager.TETHER_ERROR_ENABLE_FORWARDING_ERROR; + /** + * @deprecated Use {@link TetheringManager#TETHER_ERROR_DISABLE_FORWARDING_ERROR}. + * {@hide} + */ + @Deprecated + public static final int TETHER_ERROR_DISABLE_NAT_ERROR = + TetheringManager.TETHER_ERROR_DISABLE_FORWARDING_ERROR; + /** + * @deprecated Use {@link TetheringManager#TETHER_ERROR_IFACE_CFG_ERROR}. + * {@hide} + */ + @Deprecated + public static final int TETHER_ERROR_IFACE_CFG_ERROR = + TetheringManager.TETHER_ERROR_IFACE_CFG_ERROR; + /** + * @deprecated Use {@link TetheringManager#TETHER_ERROR_PROVISIONING_FAILED}. + * {@hide} + */ + @SystemApi + @Deprecated + public static final int TETHER_ERROR_PROVISION_FAILED = + TetheringManager.TETHER_ERROR_PROVISIONING_FAILED; + /** + * @deprecated Use {@link TetheringManager#TETHER_ERROR_DHCPSERVER_ERROR}. + * {@hide} + */ + @Deprecated + public static final int TETHER_ERROR_DHCPSERVER_ERROR = + TetheringManager.TETHER_ERROR_DHCPSERVER_ERROR; + /** + * @deprecated Use {@link TetheringManager#TETHER_ERROR_ENTITLEMENT_UNKNOWN}. + * {@hide} + */ + @SystemApi + @Deprecated + public static final int TETHER_ERROR_ENTITLEMENT_UNKONWN = + TetheringManager.TETHER_ERROR_ENTITLEMENT_UNKNOWN; + + /** + * Get a more detailed error code after a Tethering or Untethering + * request asynchronously failed. + * + * @param iface The name of the interface of interest + * @return error The error code of the last error tethering or untethering the named + * interface + * + * @deprecated Use {@link TetheringEventCallback#onError(String, int)} instead. + * {@hide} + */ + @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @Deprecated + public int getLastTetherError(String iface) { + int error = mTetheringManager.getLastTetherError(iface); + if (error == TetheringManager.TETHER_ERROR_UNKNOWN_TYPE) { + // TETHER_ERROR_UNKNOWN_TYPE was introduced with TetheringManager and has never been + // returned by ConnectivityManager. Convert it to the legacy TETHER_ERROR_UNKNOWN_IFACE + // instead. + error = TetheringManager.TETHER_ERROR_UNKNOWN_IFACE; + } + return error; + } + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(value = { + TETHER_ERROR_NO_ERROR, + TETHER_ERROR_PROVISION_FAILED, + TETHER_ERROR_ENTITLEMENT_UNKONWN, + }) + public @interface EntitlementResultCode { + } + + /** + * Callback for use with {@link #getLatestTetheringEntitlementResult} to find out whether + * entitlement succeeded. + * + * @deprecated Use {@link TetheringManager#OnTetheringEntitlementResultListener} instead. + * @hide + */ + @SystemApi + @Deprecated + public interface OnTetheringEntitlementResultListener { + /** + * Called to notify entitlement result. + * + * @param resultCode an int value of entitlement result. It may be one of + * {@link #TETHER_ERROR_NO_ERROR}, + * {@link #TETHER_ERROR_PROVISION_FAILED}, or + * {@link #TETHER_ERROR_ENTITLEMENT_UNKONWN}. + */ + void onTetheringEntitlementResult(@EntitlementResultCode int resultCode); + } + + /** + * Get the last value of the entitlement check on this downstream. If the cached value is + * {@link #TETHER_ERROR_NO_ERROR} or showEntitlementUi argument is false, it just return the + * cached value. Otherwise, a UI-based entitlement check would be performed. It is not + * guaranteed that the UI-based entitlement check will complete in any specific time period + * and may in fact never complete. Any successful entitlement check the platform performs for + * any reason will update the cached value. + * + * @param type the downstream type of tethering. Must be one of + * {@link #TETHERING_WIFI}, + * {@link #TETHERING_USB}, or + * {@link #TETHERING_BLUETOOTH}. + * @param showEntitlementUi a boolean indicating whether to run UI-based entitlement check. + * @param executor the executor on which callback will be invoked. + * @param listener an {@link OnTetheringEntitlementResultListener} which will be called to + * notify the caller of the result of entitlement check. The listener may be called zero + * or one time. + * @deprecated Use {@link TetheringManager#requestLatestTetheringEntitlementResult} instead. + * {@hide} + */ + @SystemApi + @Deprecated + @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) + public void getLatestTetheringEntitlementResult(int type, boolean showEntitlementUi, + @NonNull @CallbackExecutor Executor executor, + @NonNull final OnTetheringEntitlementResultListener listener) { + Preconditions.checkNotNull(listener, "TetheringEntitlementResultListener cannot be null."); + ResultReceiver wrappedListener = new ResultReceiver(null) { + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + Binder.withCleanCallingIdentity(() -> + executor.execute(() -> { + listener.onTetheringEntitlementResult(resultCode); + })); + } + }; + + mTetheringManager.requestLatestTetheringEntitlementResult(type, wrappedListener, + showEntitlementUi); + } + + /** + * Report network connectivity status. This is currently used only + * to alter status bar UI. + *

This method requires the caller to hold the permission + * {@link android.Manifest.permission#STATUS_BAR}. + * + * @param networkType The type of network you want to report on + * @param percentage The quality of the connection 0 is bad, 100 is good + * @deprecated Types are deprecated. Use {@link #reportNetworkConnectivity} instead. + * {@hide} + */ + public void reportInetCondition(int networkType, int percentage) { + printStackTrace(); + try { + mService.reportInetCondition(networkType, percentage); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Report a problem network to the framework. This provides a hint to the system + * that there might be connectivity problems on this network and may cause + * the framework to re-evaluate network connectivity and/or switch to another + * network. + * + * @param network The {@link Network} the application was attempting to use + * or {@code null} to indicate the current default network. + * @deprecated Use {@link #reportNetworkConnectivity} which allows reporting both + * working and non-working connectivity. + */ + @Deprecated + public void reportBadNetwork(@Nullable Network network) { + printStackTrace(); + try { + // One of these will be ignored because it matches system's current state. + // The other will trigger the necessary reevaluation. + mService.reportNetworkConnectivity(network, true); + mService.reportNetworkConnectivity(network, false); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Report to the framework whether a network has working connectivity. + * This provides a hint to the system that a particular network is providing + * working connectivity or not. In response the framework may re-evaluate + * the network's connectivity and might take further action thereafter. + * + * @param network The {@link Network} the application was attempting to use + * or {@code null} to indicate the current default network. + * @param hasConnectivity {@code true} if the application was able to successfully access the + * Internet using {@code network} or {@code false} if not. + */ + public void reportNetworkConnectivity(@Nullable Network network, boolean hasConnectivity) { + printStackTrace(); + try { + mService.reportNetworkConnectivity(network, hasConnectivity); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Set a network-independent global http proxy. This is not normally what you want + * for typical HTTP proxies - they are general network dependent. However if you're + * doing something unusual like general internal filtering this may be useful. On + * a private network where the proxy is not accessible, you may break HTTP using this. + * + * @param p A {@link ProxyInfo} object defining the new global + * HTTP proxy. A {@code null} value will clear the global HTTP proxy. + * @hide + */ + @RequiresPermission(android.Manifest.permission.NETWORK_STACK) + public void setGlobalProxy(ProxyInfo p) { + try { + mService.setGlobalProxy(p); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Retrieve any network-independent global HTTP proxy. + * + * @return {@link ProxyInfo} for the current global HTTP proxy or {@code null} + * if no global HTTP proxy is set. + * @hide + */ + public ProxyInfo getGlobalProxy() { + try { + return mService.getGlobalProxy(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Retrieve the global HTTP proxy, or if no global HTTP proxy is set, a + * network-specific HTTP proxy. If {@code network} is null, the + * network-specific proxy returned is the proxy of the default active + * network. + * + * @return {@link ProxyInfo} for the current global HTTP proxy, or if no + * global HTTP proxy is set, {@code ProxyInfo} for {@code network}, + * or when {@code network} is {@code null}, + * the {@code ProxyInfo} for the default active network. Returns + * {@code null} when no proxy applies or the caller doesn't have + * permission to use {@code network}. + * @hide + */ + public ProxyInfo getProxyForNetwork(Network network) { + try { + return mService.getProxyForNetwork(network); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Get the current default HTTP proxy settings. If a global proxy is set it will be returned, + * otherwise if this process is bound to a {@link Network} using + * {@link #bindProcessToNetwork} then that {@code Network}'s proxy is returned, otherwise + * the default network's proxy is returned. + * + * @return the {@link ProxyInfo} for the current HTTP proxy, or {@code null} if no + * HTTP proxy is active. + */ + @Nullable + public ProxyInfo getDefaultProxy() { + return getProxyForNetwork(getBoundNetworkForProcess()); + } + + /** + * Returns true if the hardware supports the given network type + * else it returns false. This doesn't indicate we have coverage + * or are authorized onto a network, just whether or not the + * hardware supports it. For example a GSM phone without a SIM + * should still return {@code true} for mobile data, but a wifi only + * tablet would return {@code false}. + * + * @param networkType The network type we'd like to check + * @return {@code true} if supported, else {@code false} + * @deprecated Types are deprecated. Use {@link NetworkCapabilities} instead. + * @hide + */ + @Deprecated + @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562) + public boolean isNetworkSupported(int networkType) { + try { + return mService.isNetworkSupported(networkType); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Returns if the currently active data network is metered. A network is + * classified as metered when the user is sensitive to heavy data usage on + * that connection due to monetary costs, data limitations or + * battery/performance issues. You should check this before doing large + * data transfers, and warn the user or delay the operation until another + * network is available. + * + * @return {@code true} if large transfers should be avoided, otherwise + * {@code false}. + */ + @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + public boolean isActiveNetworkMetered() { + try { + return mService.isActiveNetworkMetered(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * If the LockdownVpn mechanism is enabled, updates the vpn + * with a reload of its profile. + * + * @return a boolean with {@code} indicating success + * + *

This method can only be called by the system UID + * {@hide} + */ + public boolean updateLockdownVpn() { + try { + return mService.updateLockdownVpn(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Set sign in error notification to visible or invisible + * + * @hide + * @deprecated Doesn't properly deal with multiple connected networks of the same type. + */ + @Deprecated + public void setProvisioningNotificationVisible(boolean visible, int networkType, + String action) { + try { + mService.setProvisioningNotificationVisible(visible, networkType, action); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Set the value for enabling/disabling airplane mode + * + * @param enable whether to enable airplane mode or not + * + * @hide + */ + @RequiresPermission(anyOf = { + android.Manifest.permission.NETWORK_AIRPLANE_MODE, + android.Manifest.permission.NETWORK_SETTINGS, + android.Manifest.permission.NETWORK_SETUP_WIZARD, + android.Manifest.permission.NETWORK_STACK}) + @SystemApi + public void setAirplaneMode(boolean enable) { + try { + mService.setAirplaneMode(enable); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** {@hide} - returns the factory serial number */ + @UnsupportedAppUsage + @RequiresPermission(anyOf = { + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, + android.Manifest.permission.NETWORK_FACTORY}) + public int registerNetworkFactory(Messenger messenger, String name) { + try { + return mService.registerNetworkFactory(messenger, name); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** {@hide} */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) + @RequiresPermission(anyOf = { + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, + android.Manifest.permission.NETWORK_FACTORY}) + public void unregisterNetworkFactory(Messenger messenger) { + try { + mService.unregisterNetworkFactory(messenger); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Registers the specified {@link NetworkProvider}. + * Each listener must only be registered once. The listener can be unregistered with + * {@link #unregisterNetworkProvider}. + * + * @param provider the provider to register + * @return the ID of the provider. This ID must be used by the provider when registering + * {@link android.net.NetworkAgent}s. + * @hide + */ + @SystemApi + @RequiresPermission(anyOf = { + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, + android.Manifest.permission.NETWORK_FACTORY}) + public int registerNetworkProvider(@NonNull NetworkProvider provider) { + if (provider.getProviderId() != NetworkProvider.ID_NONE) { + throw new IllegalStateException("NetworkProviders can only be registered once"); + } + + try { + int providerId = mService.registerNetworkProvider(provider.getMessenger(), + provider.getName()); + provider.setProviderId(providerId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + return provider.getProviderId(); + } + + /** + * Unregisters the specified NetworkProvider. + * + * @param provider the provider to unregister + * @hide + */ + @SystemApi + @RequiresPermission(anyOf = { + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, + android.Manifest.permission.NETWORK_FACTORY}) + public void unregisterNetworkProvider(@NonNull NetworkProvider provider) { + try { + mService.unregisterNetworkProvider(provider.getMessenger()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + provider.setProviderId(NetworkProvider.ID_NONE); + } + + + /** @hide exposed via the NetworkProvider class. */ + @RequiresPermission(anyOf = { + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, + android.Manifest.permission.NETWORK_FACTORY}) + public void declareNetworkRequestUnfulfillable(@NonNull NetworkRequest request) { + try { + mService.declareNetworkRequestUnfulfillable(request); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + // TODO : remove this method. It is a stopgap measure to help sheperding a number + // of dependent changes that would conflict throughout the automerger graph. Having this + // temporarily helps with the process of going through with all these dependent changes across + // the entire tree. + /** + * @hide + * Register a NetworkAgent with ConnectivityService. + * @return Network corresponding to NetworkAgent. + */ + @RequiresPermission(anyOf = { + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, + android.Manifest.permission.NETWORK_FACTORY}) + public Network registerNetworkAgent(INetworkAgent na, NetworkInfo ni, LinkProperties lp, + NetworkCapabilities nc, int score, NetworkAgentConfig config) { + return registerNetworkAgent(na, ni, lp, nc, score, config, NetworkProvider.ID_NONE); + } + + /** + * @hide + * Register a NetworkAgent with ConnectivityService. + * @return Network corresponding to NetworkAgent. + */ + @RequiresPermission(anyOf = { + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, + android.Manifest.permission.NETWORK_FACTORY}) + public Network registerNetworkAgent(INetworkAgent na, NetworkInfo ni, LinkProperties lp, + NetworkCapabilities nc, int score, NetworkAgentConfig config, int providerId) { + try { + return mService.registerNetworkAgent(na, ni, lp, nc, score, config, providerId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Base class for {@code NetworkRequest} callbacks. Used for notifications about network + * changes. Should be extended by applications wanting notifications. + * + * A {@code NetworkCallback} is registered by calling + * {@link #requestNetwork(NetworkRequest, NetworkCallback)}, + * {@link #registerNetworkCallback(NetworkRequest, NetworkCallback)}, + * or {@link #registerDefaultNetworkCallback(NetworkCallback)}. A {@code NetworkCallback} is + * unregistered by calling {@link #unregisterNetworkCallback(NetworkCallback)}. + * A {@code NetworkCallback} should be registered at most once at any time. + * A {@code NetworkCallback} that has been unregistered can be registered again. + */ + public static class NetworkCallback { + /** + * Called when the framework connects to a new network to evaluate whether it satisfies this + * request. If evaluation succeeds, this callback may be followed by an {@link #onAvailable} + * callback. There is no guarantee that this new network will satisfy any requests, or that + * the network will stay connected for longer than the time necessary to evaluate it. + *

+ * Most applications should not act on this callback, and should instead use + * {@link #onAvailable}. This callback is intended for use by applications that can assist + * the framework in properly evaluating the network — for example, an application that + * can automatically log in to a captive portal without user intervention. + * + * @param network The {@link Network} of the network that is being evaluated. + * + * @hide + */ + public void onPreCheck(@NonNull Network network) {} + + /** + * Called when the framework connects and has declared a new network ready for use. + * This callback may be called more than once if the {@link Network} that is + * satisfying the request changes. + * + * @param network The {@link Network} of the satisfying network. + * @param networkCapabilities The {@link NetworkCapabilities} of the satisfying network. + * @param linkProperties The {@link LinkProperties} of the satisfying network. + * @param blocked Whether access to the {@link Network} is blocked due to system policy. + * @hide + */ + public void onAvailable(@NonNull Network network, + @NonNull NetworkCapabilities networkCapabilities, + @NonNull LinkProperties linkProperties, boolean blocked) { + // Internally only this method is called when a new network is available, and + // it calls the callback in the same way and order that older versions used + // to call so as not to change the behavior. + onAvailable(network); + if (!networkCapabilities.hasCapability( + NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED)) { + onNetworkSuspended(network); + } + onCapabilitiesChanged(network, networkCapabilities); + onLinkPropertiesChanged(network, linkProperties); + onBlockedStatusChanged(network, blocked); + } + + /** + * Called when the framework connects and has declared a new network ready for use. + * + *

For callbacks registered with {@link #registerNetworkCallback}, multiple networks may + * be available at the same time, and onAvailable will be called for each of these as they + * appear. + * + *

For callbacks registered with {@link #requestNetwork} and + * {@link #registerDefaultNetworkCallback}, this means the network passed as an argument + * is the new best network for this request and is now tracked by this callback ; this + * callback will no longer receive method calls about other networks that may have been + * passed to this method previously. The previously-best network may have disconnected, or + * it may still be around and the newly-best network may simply be better. + * + *

Starting with {@link android.os.Build.VERSION_CODES#O}, this will always immediately + * be followed by a call to {@link #onCapabilitiesChanged(Network, NetworkCapabilities)} + * then by a call to {@link #onLinkPropertiesChanged(Network, LinkProperties)}, and a call + * to {@link #onBlockedStatusChanged(Network, boolean)}. + * + *

Do NOT call {@link #getNetworkCapabilities(Network)} or + * {@link #getLinkProperties(Network)} or other synchronous ConnectivityManager methods in + * this callback as this is prone to race conditions (there is no guarantee the objects + * returned by these methods will be current). Instead, wait for a call to + * {@link #onCapabilitiesChanged(Network, NetworkCapabilities)} and + * {@link #onLinkPropertiesChanged(Network, LinkProperties)} whose arguments are guaranteed + * to be well-ordered with respect to other callbacks. + * + * @param network The {@link Network} of the satisfying network. + */ + public void onAvailable(@NonNull Network network) {} + + /** + * Called when the network is about to be lost, typically because there are no outstanding + * requests left for it. This may be paired with a {@link NetworkCallback#onAvailable} call + * with the new replacement network for graceful handover. This method is not guaranteed + * to be called before {@link NetworkCallback#onLost} is called, for example in case a + * network is suddenly disconnected. + * + *

Do NOT call {@link #getNetworkCapabilities(Network)} or + * {@link #getLinkProperties(Network)} or other synchronous ConnectivityManager methods in + * this callback as this is prone to race conditions ; calling these methods while in a + * callback may return an outdated or even a null object. + * + * @param network The {@link Network} that is about to be lost. + * @param maxMsToLive The time in milliseconds the system intends to keep the network + * connected for graceful handover; note that the network may still + * suffer a hard loss at any time. + */ + public void onLosing(@NonNull Network network, int maxMsToLive) {} + + /** + * Called when a network disconnects or otherwise no longer satisfies this request or + * callback. + * + *

If the callback was registered with requestNetwork() or + * registerDefaultNetworkCallback(), it will only be invoked against the last network + * returned by onAvailable() when that network is lost and no other network satisfies + * the criteria of the request. + * + *

If the callback was registered with registerNetworkCallback() it will be called for + * each network which no longer satisfies the criteria of the callback. + * + *

Do NOT call {@link #getNetworkCapabilities(Network)} or + * {@link #getLinkProperties(Network)} or other synchronous ConnectivityManager methods in + * this callback as this is prone to race conditions ; calling these methods while in a + * callback may return an outdated or even a null object. + * + * @param network The {@link Network} lost. + */ + public void onLost(@NonNull Network network) {} + + /** + * Called if no network is found within the timeout time specified in + * {@link #requestNetwork(NetworkRequest, NetworkCallback, int)} call or if the + * requested network request cannot be fulfilled (whether or not a timeout was + * specified). When this callback is invoked the associated + * {@link NetworkRequest} will have already been removed and released, as if + * {@link #unregisterNetworkCallback(NetworkCallback)} had been called. + */ + public void onUnavailable() {} + + /** + * Called when the network corresponding to this request changes capabilities but still + * satisfies the requested criteria. + * + *

Starting with {@link android.os.Build.VERSION_CODES#O} this method is guaranteed + * to be called immediately after {@link #onAvailable}. + * + *

Do NOT call {@link #getLinkProperties(Network)} or other synchronous + * ConnectivityManager methods in this callback as this is prone to race conditions : + * calling these methods while in a callback may return an outdated or even a null object. + * + * @param network The {@link Network} whose capabilities have changed. + * @param networkCapabilities The new {@link android.net.NetworkCapabilities} for this + * network. + */ + public void onCapabilitiesChanged(@NonNull Network network, + @NonNull NetworkCapabilities networkCapabilities) {} + + /** + * Called when the network corresponding to this request changes {@link LinkProperties}. + * + *

Starting with {@link android.os.Build.VERSION_CODES#O} this method is guaranteed + * to be called immediately after {@link #onAvailable}. + * + *

Do NOT call {@link #getNetworkCapabilities(Network)} or other synchronous + * ConnectivityManager methods in this callback as this is prone to race conditions : + * calling these methods while in a callback may return an outdated or even a null object. + * + * @param network The {@link Network} whose link properties have changed. + * @param linkProperties The new {@link LinkProperties} for this network. + */ + public void onLinkPropertiesChanged(@NonNull Network network, + @NonNull LinkProperties linkProperties) {} + + /** + * Called when the network the framework connected to for this request suspends data + * transmission temporarily. + * + *

This generally means that while the TCP connections are still live temporarily + * network data fails to transfer. To give a specific example, this is used on cellular + * networks to mask temporary outages when driving through a tunnel, etc. In general this + * means read operations on sockets on this network will block once the buffers are + * drained, and write operations will block once the buffers are full. + * + *

Do NOT call {@link #getNetworkCapabilities(Network)} or + * {@link #getLinkProperties(Network)} or other synchronous ConnectivityManager methods in + * this callback as this is prone to race conditions (there is no guarantee the objects + * returned by these methods will be current). + * + * @hide + */ + public void onNetworkSuspended(@NonNull Network network) {} + + /** + * Called when the network the framework connected to for this request + * returns from a {@link NetworkInfo.State#SUSPENDED} state. This should always be + * preceded by a matching {@link NetworkCallback#onNetworkSuspended} call. + + *

Do NOT call {@link #getNetworkCapabilities(Network)} or + * {@link #getLinkProperties(Network)} or other synchronous ConnectivityManager methods in + * this callback as this is prone to race conditions : calling these methods while in a + * callback may return an outdated or even a null object. + * + * @hide + */ + public void onNetworkResumed(@NonNull Network network) {} + + /** + * Called when access to the specified network is blocked or unblocked. + * + *

Do NOT call {@link #getNetworkCapabilities(Network)} or + * {@link #getLinkProperties(Network)} or other synchronous ConnectivityManager methods in + * this callback as this is prone to race conditions : calling these methods while in a + * callback may return an outdated or even a null object. + * + * @param network The {@link Network} whose blocked status has changed. + * @param blocked The blocked status of this {@link Network}. + */ + public void onBlockedStatusChanged(@NonNull Network network, boolean blocked) {} + + private NetworkRequest networkRequest; + } + + /** + * Constant error codes used by ConnectivityService to communicate about failures and errors + * across a Binder boundary. + * @hide + */ + public interface Errors { + int TOO_MANY_REQUESTS = 1; + } + + /** @hide */ + public static class TooManyRequestsException extends RuntimeException {} + + private static RuntimeException convertServiceException(ServiceSpecificException e) { + switch (e.errorCode) { + case Errors.TOO_MANY_REQUESTS: + return new TooManyRequestsException(); + default: + Log.w(TAG, "Unknown service error code " + e.errorCode); + return new RuntimeException(e); + } + } + + private static final int BASE = Protocol.BASE_CONNECTIVITY_MANAGER; + /** @hide */ + public static final int CALLBACK_PRECHECK = BASE + 1; + /** @hide */ + public static final int CALLBACK_AVAILABLE = BASE + 2; + /** @hide arg1 = TTL */ + public static final int CALLBACK_LOSING = BASE + 3; + /** @hide */ + public static final int CALLBACK_LOST = BASE + 4; + /** @hide */ + public static final int CALLBACK_UNAVAIL = BASE + 5; + /** @hide */ + public static final int CALLBACK_CAP_CHANGED = BASE + 6; + /** @hide */ + public static final int CALLBACK_IP_CHANGED = BASE + 7; + /** @hide obj = NetworkCapabilities, arg1 = seq number */ + private static final int EXPIRE_LEGACY_REQUEST = BASE + 8; + /** @hide */ + public static final int CALLBACK_SUSPENDED = BASE + 9; + /** @hide */ + public static final int CALLBACK_RESUMED = BASE + 10; + /** @hide */ + public static final int CALLBACK_BLK_CHANGED = BASE + 11; + + /** @hide */ + public static String getCallbackName(int whichCallback) { + switch (whichCallback) { + case CALLBACK_PRECHECK: return "CALLBACK_PRECHECK"; + case CALLBACK_AVAILABLE: return "CALLBACK_AVAILABLE"; + case CALLBACK_LOSING: return "CALLBACK_LOSING"; + case CALLBACK_LOST: return "CALLBACK_LOST"; + case CALLBACK_UNAVAIL: return "CALLBACK_UNAVAIL"; + case CALLBACK_CAP_CHANGED: return "CALLBACK_CAP_CHANGED"; + case CALLBACK_IP_CHANGED: return "CALLBACK_IP_CHANGED"; + case EXPIRE_LEGACY_REQUEST: return "EXPIRE_LEGACY_REQUEST"; + case CALLBACK_SUSPENDED: return "CALLBACK_SUSPENDED"; + case CALLBACK_RESUMED: return "CALLBACK_RESUMED"; + case CALLBACK_BLK_CHANGED: return "CALLBACK_BLK_CHANGED"; + default: + return Integer.toString(whichCallback); + } + } + + private class CallbackHandler extends Handler { + private static final String TAG = "ConnectivityManager.CallbackHandler"; + private static final boolean DBG = false; + + CallbackHandler(Looper looper) { + super(looper); + } + + CallbackHandler(Handler handler) { + this(Preconditions.checkNotNull(handler, "Handler cannot be null.").getLooper()); + } + + @Override + public void handleMessage(Message message) { + if (message.what == EXPIRE_LEGACY_REQUEST) { + expireRequest((NetworkCapabilities) message.obj, message.arg1); + return; + } + + final NetworkRequest request = getObject(message, NetworkRequest.class); + final Network network = getObject(message, Network.class); + final NetworkCallback callback; + synchronized (sCallbacks) { + callback = sCallbacks.get(request); + if (callback == null) { + Log.w(TAG, + "callback not found for " + getCallbackName(message.what) + " message"); + return; + } + if (message.what == CALLBACK_UNAVAIL) { + sCallbacks.remove(request); + callback.networkRequest = ALREADY_UNREGISTERED; + } + } + if (DBG) { + Log.d(TAG, getCallbackName(message.what) + " for network " + network); + } + + switch (message.what) { + case CALLBACK_PRECHECK: { + callback.onPreCheck(network); + break; + } + case CALLBACK_AVAILABLE: { + NetworkCapabilities cap = getObject(message, NetworkCapabilities.class); + LinkProperties lp = getObject(message, LinkProperties.class); + callback.onAvailable(network, cap, lp, message.arg1 != 0); + break; + } + case CALLBACK_LOSING: { + callback.onLosing(network, message.arg1); + break; + } + case CALLBACK_LOST: { + callback.onLost(network); + break; + } + case CALLBACK_UNAVAIL: { + callback.onUnavailable(); + break; + } + case CALLBACK_CAP_CHANGED: { + NetworkCapabilities cap = getObject(message, NetworkCapabilities.class); + callback.onCapabilitiesChanged(network, cap); + break; + } + case CALLBACK_IP_CHANGED: { + LinkProperties lp = getObject(message, LinkProperties.class); + callback.onLinkPropertiesChanged(network, lp); + break; + } + case CALLBACK_SUSPENDED: { + callback.onNetworkSuspended(network); + break; + } + case CALLBACK_RESUMED: { + callback.onNetworkResumed(network); + break; + } + case CALLBACK_BLK_CHANGED: { + boolean blocked = message.arg1 != 0; + callback.onBlockedStatusChanged(network, blocked); + } + } + } + + private T getObject(Message msg, Class c) { + return (T) msg.getData().getParcelable(c.getSimpleName()); + } + } + + private CallbackHandler getDefaultHandler() { + synchronized (sCallbacks) { + if (sCallbackHandler == null) { + sCallbackHandler = new CallbackHandler(ConnectivityThread.getInstanceLooper()); + } + return sCallbackHandler; + } + } + + private static final HashMap sCallbacks = new HashMap<>(); + private static CallbackHandler sCallbackHandler; + + private NetworkRequest sendRequestForNetwork(NetworkCapabilities need, NetworkCallback callback, + int timeoutMs, NetworkRequest.Type reqType, int legacyType, CallbackHandler handler) { + printStackTrace(); + checkCallbackNotNull(callback); + Preconditions.checkArgument( + reqType == TRACK_DEFAULT || need != null, "null NetworkCapabilities"); + final NetworkRequest request; + final String callingPackageName = mContext.getOpPackageName(); + try { + synchronized(sCallbacks) { + if (callback.networkRequest != null + && callback.networkRequest != ALREADY_UNREGISTERED) { + // TODO: throw exception instead and enforce 1:1 mapping of callbacks + // and requests (http://b/20701525). + Log.e(TAG, "NetworkCallback was already registered"); + } + Messenger messenger = new Messenger(handler); + Binder binder = new Binder(); + if (reqType == LISTEN) { + request = mService.listenForNetwork( + need, messenger, binder, callingPackageName); + } else { + request = mService.requestNetwork( + need, reqType.ordinal(), messenger, timeoutMs, binder, legacyType, + callingPackageName, getAttributionTag()); + } + if (request != null) { + sCallbacks.put(request, callback); + } + callback.networkRequest = request; + } + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } catch (ServiceSpecificException e) { + throw convertServiceException(e); + } + return request; + } + + /** + * Helper function to request a network with a particular legacy type. + * + * This API is only for use in internal system code that requests networks with legacy type and + * relies on CONNECTIVITY_ACTION broadcasts instead of NetworkCallbacks. New caller should use + * {@link #requestNetwork(NetworkRequest, NetworkCallback, Handler)} instead. + * + * @param request {@link NetworkRequest} describing this request. + * @param timeoutMs The time in milliseconds to attempt looking for a suitable network + * before {@link NetworkCallback#onUnavailable()} is called. The timeout must + * be a positive value (i.e. >0). + * @param legacyType to specify the network type(#TYPE_*). + * @param handler {@link Handler} to specify the thread upon which the callback will be invoked. + * @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note + * the callback must not be shared - it uniquely specifies this request. + * + * @hide + */ + @SystemApi + @RequiresPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) + public void requestNetwork(@NonNull NetworkRequest request, + int timeoutMs, int legacyType, @NonNull Handler handler, + @NonNull NetworkCallback networkCallback) { + if (legacyType == TYPE_NONE) { + throw new IllegalArgumentException("TYPE_NONE is meaningless legacy type"); + } + CallbackHandler cbHandler = new CallbackHandler(handler); + NetworkCapabilities nc = request.networkCapabilities; + sendRequestForNetwork(nc, networkCallback, timeoutMs, REQUEST, legacyType, cbHandler); + } + + /** + * Request a network to satisfy a set of {@link android.net.NetworkCapabilities}. + * + *

This method will attempt to find the best network that matches the passed + * {@link NetworkRequest}, and to bring up one that does if none currently satisfies the + * criteria. The platform will evaluate which network is the best at its own discretion. + * Throughput, latency, cost per byte, policy, user preference and other considerations + * may be factored in the decision of what is considered the best network. + * + *

As long as this request is outstanding, the platform will try to maintain the best network + * matching this request, while always attempting to match the request to a better network if + * possible. If a better match is found, the platform will switch this request to the now-best + * network and inform the app of the newly best network by invoking + * {@link NetworkCallback#onAvailable(Network)} on the provided callback. Note that the platform + * will not try to maintain any other network than the best one currently matching the request: + * a network not matching any network request may be disconnected at any time. + * + *

For example, an application could use this method to obtain a connected cellular network + * even if the device currently has a data connection over Ethernet. This may cause the cellular + * radio to consume additional power. Or, an application could inform the system that it wants + * a network supporting sending MMSes and have the system let it know about the currently best + * MMS-supporting network through the provided {@link NetworkCallback}. + * + *

The status of the request can be followed by listening to the various callbacks described + * in {@link NetworkCallback}. The {@link Network} object passed to the callback methods can be + * used to direct traffic to the network (although accessing some networks may be subject to + * holding specific permissions). Callers will learn about the specific characteristics of the + * network through + * {@link NetworkCallback#onCapabilitiesChanged(Network, NetworkCapabilities)} and + * {@link NetworkCallback#onLinkPropertiesChanged(Network, LinkProperties)}. The methods of the + * provided {@link NetworkCallback} will only be invoked due to changes in the best network + * matching the request at any given time; therefore when a better network matching the request + * becomes available, the {@link NetworkCallback#onAvailable(Network)} method is called + * with the new network after which no further updates are given about the previously-best + * network, unless it becomes the best again at some later time. All callbacks are invoked + * in order on the same thread, which by default is a thread created by the framework running + * in the app. + * {@see #requestNetwork(NetworkRequest, NetworkCallback, Handler)} to change where the + * callbacks are invoked. + * + *

This{@link NetworkRequest} will live until released via + * {@link #unregisterNetworkCallback(NetworkCallback)} or the calling application exits, at + * which point the system may let go of the network at any time. + * + *

A version of this method which takes a timeout is + * {@link #requestNetwork(NetworkRequest, NetworkCallback, int)}, that an app can use to only + * wait for a limited amount of time for the network to become unavailable. + * + *

It is presently unsupported to request a network with mutable + * {@link NetworkCapabilities} such as + * {@link NetworkCapabilities#NET_CAPABILITY_VALIDATED} or + * {@link NetworkCapabilities#NET_CAPABILITY_CAPTIVE_PORTAL} + * as these {@code NetworkCapabilities} represent states that a particular + * network may never attain, and whether a network will attain these states + * is unknown prior to bringing up the network so the framework does not + * know how to go about satisfying a request with these capabilities. + * + *

This method requires the caller to hold either the + * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission + * or the ability to modify system settings as determined by + * {@link android.provider.Settings.System#canWrite}.

+ * + *

To avoid performance issues due to apps leaking callbacks, the system will limit the + * number of outstanding requests to 100 per app (identified by their UID), shared with + * all variants of this method, of {@link #registerNetworkCallback} as well as + * {@link ConnectivityDiagnosticsManager#registerConnectivityDiagnosticsCallback}. + * Requesting a network with this method will count toward this limit. If this limit is + * exceeded, an exception will be thrown. To avoid hitting this issue and to conserve resources, + * make sure to unregister the callbacks with + * {@link #unregisterNetworkCallback(NetworkCallback)}. + * + * @param request {@link NetworkRequest} describing this request. + * @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note + * the callback must not be shared - it uniquely specifies this request. + * The callback is invoked on the default internal Handler. + * @throws IllegalArgumentException if {@code request} contains invalid network capabilities. + * @throws SecurityException if missing the appropriate permissions. + * @throws RuntimeException if the app already has too many callbacks registered. + */ + public void requestNetwork(@NonNull NetworkRequest request, + @NonNull NetworkCallback networkCallback) { + requestNetwork(request, networkCallback, getDefaultHandler()); + } + + /** + * Request a network to satisfy a set of {@link android.net.NetworkCapabilities}. + * + * This method behaves identically to {@link #requestNetwork(NetworkRequest, NetworkCallback)} + * but runs all the callbacks on the passed Handler. + * + *

This method has the same permission requirements as + * {@link #requestNetwork(NetworkRequest, NetworkCallback)}, is subject to the same limitations, + * and throws the same exceptions in the same conditions. + * + * @param request {@link NetworkRequest} describing this request. + * @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note + * the callback must not be shared - it uniquely specifies this request. + * @param handler {@link Handler} to specify the thread upon which the callback will be invoked. + */ + public void requestNetwork(@NonNull NetworkRequest request, + @NonNull NetworkCallback networkCallback, @NonNull Handler handler) { + CallbackHandler cbHandler = new CallbackHandler(handler); + NetworkCapabilities nc = request.networkCapabilities; + sendRequestForNetwork(nc, networkCallback, 0, REQUEST, TYPE_NONE, cbHandler); + } + + /** + * Request a network to satisfy a set of {@link android.net.NetworkCapabilities}, limited + * by a timeout. + * + * This function behaves identically to the non-timed-out version + * {@link #requestNetwork(NetworkRequest, NetworkCallback)}, but if a suitable network + * is not found within the given time (in milliseconds) the + * {@link NetworkCallback#onUnavailable()} callback is called. The request can still be + * released normally by calling {@link #unregisterNetworkCallback(NetworkCallback)} but does + * not have to be released if timed-out (it is automatically released). Unregistering a + * request that timed out is not an error. + * + *

Do not use this method to poll for the existence of specific networks (e.g. with a small + * timeout) - {@link #registerNetworkCallback(NetworkRequest, NetworkCallback)} is provided + * for that purpose. Calling this method will attempt to bring up the requested network. + * + *

This method has the same permission requirements as + * {@link #requestNetwork(NetworkRequest, NetworkCallback)}, is subject to the same limitations, + * and throws the same exceptions in the same conditions. + * + * @param request {@link NetworkRequest} describing this request. + * @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note + * the callback must not be shared - it uniquely specifies this request. + * @param timeoutMs The time in milliseconds to attempt looking for a suitable network + * before {@link NetworkCallback#onUnavailable()} is called. The timeout must + * be a positive value (i.e. >0). + */ + public void requestNetwork(@NonNull NetworkRequest request, + @NonNull NetworkCallback networkCallback, int timeoutMs) { + checkTimeout(timeoutMs); + NetworkCapabilities nc = request.networkCapabilities; + sendRequestForNetwork(nc, networkCallback, timeoutMs, REQUEST, TYPE_NONE, + getDefaultHandler()); + } + + /** + * Request a network to satisfy a set of {@link android.net.NetworkCapabilities}, limited + * by a timeout. + * + * This method behaves identically to + * {@link #requestNetwork(NetworkRequest, NetworkCallback, int)} but runs all the callbacks + * on the passed Handler. + * + *

This method has the same permission requirements as + * {@link #requestNetwork(NetworkRequest, NetworkCallback)}, is subject to the same limitations, + * and throws the same exceptions in the same conditions. + * + * @param request {@link NetworkRequest} describing this request. + * @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note + * the callback must not be shared - it uniquely specifies this request. + * @param handler {@link Handler} to specify the thread upon which the callback will be invoked. + * @param timeoutMs The time in milliseconds to attempt looking for a suitable network + * before {@link NetworkCallback#onUnavailable} is called. + */ + public void requestNetwork(@NonNull NetworkRequest request, + @NonNull NetworkCallback networkCallback, @NonNull Handler handler, int timeoutMs) { + checkTimeout(timeoutMs); + CallbackHandler cbHandler = new CallbackHandler(handler); + NetworkCapabilities nc = request.networkCapabilities; + sendRequestForNetwork(nc, networkCallback, timeoutMs, REQUEST, TYPE_NONE, cbHandler); + } + + /** + * The lookup key for a {@link Network} object included with the intent after + * successfully finding a network for the applications request. Retrieve it with + * {@link android.content.Intent#getParcelableExtra(String)}. + *

+ * Note that if you intend to invoke {@link Network#openConnection(java.net.URL)} + * then you must get a ConnectivityManager instance before doing so. + */ + public static final String EXTRA_NETWORK = "android.net.extra.NETWORK"; + + /** + * The lookup key for a {@link NetworkRequest} object included with the intent after + * successfully finding a network for the applications request. Retrieve it with + * {@link android.content.Intent#getParcelableExtra(String)}. + */ + public static final String EXTRA_NETWORK_REQUEST = "android.net.extra.NETWORK_REQUEST"; + + + /** + * Request a network to satisfy a set of {@link android.net.NetworkCapabilities}. + * + * This function behaves identically to the version that takes a NetworkCallback, but instead + * of {@link NetworkCallback} a {@link PendingIntent} is used. This means + * the request may outlive the calling application and get called back when a suitable + * network is found. + *

+ * The operation is an Intent broadcast that goes to a broadcast receiver that + * you registered with {@link Context#registerReceiver} or through the + * <receiver> tag in an AndroidManifest.xml file + *

+ * The operation Intent is delivered with two extras, a {@link Network} typed + * extra called {@link #EXTRA_NETWORK} and a {@link NetworkRequest} + * typed extra called {@link #EXTRA_NETWORK_REQUEST} containing + * the original requests parameters. It is important to create a new, + * {@link NetworkCallback} based request before completing the processing of the + * Intent to reserve the network or it will be released shortly after the Intent + * is processed. + *

+ * If there is already a request for this Intent registered (with the equality of + * two Intents defined by {@link Intent#filterEquals}), then it will be removed and + * replaced by this one, effectively releasing the previous {@link NetworkRequest}. + *

+ * The request may be released normally by calling + * {@link #releaseNetworkRequest(android.app.PendingIntent)}. + *

It is presently unsupported to request a network with either + * {@link NetworkCapabilities#NET_CAPABILITY_VALIDATED} or + * {@link NetworkCapabilities#NET_CAPABILITY_CAPTIVE_PORTAL} + * as these {@code NetworkCapabilities} represent states that a particular + * network may never attain, and whether a network will attain these states + * is unknown prior to bringing up the network so the framework does not + * know how to go about satisfying a request with these capabilities. + * + *

To avoid performance issues due to apps leaking callbacks, the system will limit the + * number of outstanding requests to 100 per app (identified by their UID), shared with + * all variants of this method, of {@link #registerNetworkCallback} as well as + * {@link ConnectivityDiagnosticsManager#registerConnectivityDiagnosticsCallback}. + * Requesting a network with this method will count toward this limit. If this limit is + * exceeded, an exception will be thrown. To avoid hitting this issue and to conserve resources, + * make sure to unregister the callbacks with {@link #unregisterNetworkCallback(PendingIntent)} + * or {@link #releaseNetworkRequest(PendingIntent)}. + * + *

This method requires the caller to hold either the + * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission + * or the ability to modify system settings as determined by + * {@link android.provider.Settings.System#canWrite}.

+ * + * @param request {@link NetworkRequest} describing this request. + * @param operation Action to perform when the network is available (corresponds + * to the {@link NetworkCallback#onAvailable} call. Typically + * comes from {@link PendingIntent#getBroadcast}. Cannot be null. + * @throws IllegalArgumentException if {@code request} contains invalid network capabilities. + * @throws SecurityException if missing the appropriate permissions. + * @throws RuntimeException if the app already has too many callbacks registered. + */ + public void requestNetwork(@NonNull NetworkRequest request, + @NonNull PendingIntent operation) { + printStackTrace(); + checkPendingIntentNotNull(operation); + try { + mService.pendingRequestForNetwork( + request.networkCapabilities, operation, mContext.getOpPackageName(), + getAttributionTag()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } catch (ServiceSpecificException e) { + throw convertServiceException(e); + } + } + + /** + * Removes a request made via {@link #requestNetwork(NetworkRequest, android.app.PendingIntent)} + *

+ * This method has the same behavior as + * {@link #unregisterNetworkCallback(android.app.PendingIntent)} with respect to + * releasing network resources and disconnecting. + * + * @param operation A PendingIntent equal (as defined by {@link Intent#filterEquals}) to the + * PendingIntent passed to + * {@link #requestNetwork(NetworkRequest, android.app.PendingIntent)} with the + * corresponding NetworkRequest you'd like to remove. Cannot be null. + */ + public void releaseNetworkRequest(@NonNull PendingIntent operation) { + printStackTrace(); + checkPendingIntentNotNull(operation); + try { + mService.releasePendingNetworkRequest(operation); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + private static void checkPendingIntentNotNull(PendingIntent intent) { + Preconditions.checkNotNull(intent, "PendingIntent cannot be null."); + } + + private static void checkCallbackNotNull(NetworkCallback callback) { + Preconditions.checkNotNull(callback, "null NetworkCallback"); + } + + private static void checkTimeout(int timeoutMs) { + Preconditions.checkArgumentPositive(timeoutMs, "timeoutMs must be strictly positive."); + } + + /** + * Registers to receive notifications about all networks which satisfy the given + * {@link NetworkRequest}. The callbacks will continue to be called until + * either the application exits or {@link #unregisterNetworkCallback(NetworkCallback)} is + * called. + * + *

To avoid performance issues due to apps leaking callbacks, the system will limit the + * number of outstanding requests to 100 per app (identified by their UID), shared with + * all variants of this method, of {@link #requestNetwork} as well as + * {@link ConnectivityDiagnosticsManager#registerConnectivityDiagnosticsCallback}. + * Requesting a network with this method will count toward this limit. If this limit is + * exceeded, an exception will be thrown. To avoid hitting this issue and to conserve resources, + * make sure to unregister the callbacks with + * {@link #unregisterNetworkCallback(NetworkCallback)}. + * + * @param request {@link NetworkRequest} describing this request. + * @param networkCallback The {@link NetworkCallback} that the system will call as suitable + * networks change state. + * The callback is invoked on the default internal Handler. + * @throws RuntimeException if the app already has too many callbacks registered. + */ + @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + public void registerNetworkCallback(@NonNull NetworkRequest request, + @NonNull NetworkCallback networkCallback) { + registerNetworkCallback(request, networkCallback, getDefaultHandler()); + } + + /** + * Registers to receive notifications about all networks which satisfy the given + * {@link NetworkRequest}. The callbacks will continue to be called until + * either the application exits or {@link #unregisterNetworkCallback(NetworkCallback)} is + * called. + * + *

To avoid performance issues due to apps leaking callbacks, the system will limit the + * number of outstanding requests to 100 per app (identified by their UID), shared with + * all variants of this method, of {@link #requestNetwork} as well as + * {@link ConnectivityDiagnosticsManager#registerConnectivityDiagnosticsCallback}. + * Requesting a network with this method will count toward this limit. If this limit is + * exceeded, an exception will be thrown. To avoid hitting this issue and to conserve resources, + * make sure to unregister the callbacks with + * {@link #unregisterNetworkCallback(NetworkCallback)}. + * + * + * @param request {@link NetworkRequest} describing this request. + * @param networkCallback The {@link NetworkCallback} that the system will call as suitable + * networks change state. + * @param handler {@link Handler} to specify the thread upon which the callback will be invoked. + * @throws RuntimeException if the app already has too many callbacks registered. + */ + @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + public void registerNetworkCallback(@NonNull NetworkRequest request, + @NonNull NetworkCallback networkCallback, @NonNull Handler handler) { + CallbackHandler cbHandler = new CallbackHandler(handler); + NetworkCapabilities nc = request.networkCapabilities; + sendRequestForNetwork(nc, networkCallback, 0, LISTEN, TYPE_NONE, cbHandler); + } + + /** + * Registers a PendingIntent to be sent when a network is available which satisfies the given + * {@link NetworkRequest}. + * + * This function behaves identically to the version that takes a NetworkCallback, but instead + * of {@link NetworkCallback} a {@link PendingIntent} is used. This means + * the request may outlive the calling application and get called back when a suitable + * network is found. + *

+ * The operation is an Intent broadcast that goes to a broadcast receiver that + * you registered with {@link Context#registerReceiver} or through the + * <receiver> tag in an AndroidManifest.xml file + *

+ * The operation Intent is delivered with two extras, a {@link Network} typed + * extra called {@link #EXTRA_NETWORK} and a {@link NetworkRequest} + * typed extra called {@link #EXTRA_NETWORK_REQUEST} containing + * the original requests parameters. + *

+ * If there is already a request for this Intent registered (with the equality of + * two Intents defined by {@link Intent#filterEquals}), then it will be removed and + * replaced by this one, effectively releasing the previous {@link NetworkRequest}. + *

+ * The request may be released normally by calling + * {@link #unregisterNetworkCallback(android.app.PendingIntent)}. + * + *

To avoid performance issues due to apps leaking callbacks, the system will limit the + * number of outstanding requests to 100 per app (identified by their UID), shared with + * all variants of this method, of {@link #requestNetwork} as well as + * {@link ConnectivityDiagnosticsManager#registerConnectivityDiagnosticsCallback}. + * Requesting a network with this method will count toward this limit. If this limit is + * exceeded, an exception will be thrown. To avoid hitting this issue and to conserve resources, + * make sure to unregister the callbacks with {@link #unregisterNetworkCallback(PendingIntent)} + * or {@link #releaseNetworkRequest(PendingIntent)}. + * + * @param request {@link NetworkRequest} describing this request. + * @param operation Action to perform when the network is available (corresponds + * to the {@link NetworkCallback#onAvailable} call. Typically + * comes from {@link PendingIntent#getBroadcast}. Cannot be null. + * @throws RuntimeException if the app already has too many callbacks registered. + */ + @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + public void registerNetworkCallback(@NonNull NetworkRequest request, + @NonNull PendingIntent operation) { + printStackTrace(); + checkPendingIntentNotNull(operation); + try { + mService.pendingListenForNetwork( + request.networkCapabilities, operation, mContext.getOpPackageName()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } catch (ServiceSpecificException e) { + throw convertServiceException(e); + } + } + + /** + * Registers to receive notifications about changes in the system default network. The callbacks + * will continue to be called until either the application exits or + * {@link #unregisterNetworkCallback(NetworkCallback)} is called. + * + *

To avoid performance issues due to apps leaking callbacks, the system will limit the + * number of outstanding requests to 100 per app (identified by their UID), shared with + * all variants of this method, of {@link #requestNetwork} as well as + * {@link ConnectivityDiagnosticsManager#registerConnectivityDiagnosticsCallback}. + * Requesting a network with this method will count toward this limit. If this limit is + * exceeded, an exception will be thrown. To avoid hitting this issue and to conserve resources, + * make sure to unregister the callbacks with + * {@link #unregisterNetworkCallback(NetworkCallback)}. + * + * @param networkCallback The {@link NetworkCallback} that the system will call as the + * system default network changes. + * The callback is invoked on the default internal Handler. + * @throws RuntimeException if the app already has too many callbacks registered. + */ + @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + public void registerDefaultNetworkCallback(@NonNull NetworkCallback networkCallback) { + registerDefaultNetworkCallback(networkCallback, getDefaultHandler()); + } + + /** + * Registers to receive notifications about changes in the system default network. The callbacks + * will continue to be called until either the application exits or + * {@link #unregisterNetworkCallback(NetworkCallback)} is called. + * + *

To avoid performance issues due to apps leaking callbacks, the system will limit the + * number of outstanding requests to 100 per app (identified by their UID), shared with + * all variants of this method, of {@link #requestNetwork} as well as + * {@link ConnectivityDiagnosticsManager#registerConnectivityDiagnosticsCallback}. + * Requesting a network with this method will count toward this limit. If this limit is + * exceeded, an exception will be thrown. To avoid hitting this issue and to conserve resources, + * make sure to unregister the callbacks with + * {@link #unregisterNetworkCallback(NetworkCallback)}. + * + * @param networkCallback The {@link NetworkCallback} that the system will call as the + * system default network changes. + * @param handler {@link Handler} to specify the thread upon which the callback will be invoked. + * @throws RuntimeException if the app already has too many callbacks registered. + */ + @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + public void registerDefaultNetworkCallback(@NonNull NetworkCallback networkCallback, + @NonNull Handler handler) { + // This works because if the NetworkCapabilities are null, + // ConnectivityService takes them from the default request. + // + // Since the capabilities are exactly the same as the default request's + // capabilities, this request is guaranteed, at all times, to be + // satisfied by the same network, if any, that satisfies the default + // request, i.e., the system default network. + CallbackHandler cbHandler = new CallbackHandler(handler); + sendRequestForNetwork(null /* NetworkCapabilities need */, networkCallback, 0, + TRACK_DEFAULT, TYPE_NONE, cbHandler); + } + + /** + * Requests bandwidth update for a given {@link Network} and returns whether the update request + * is accepted by ConnectivityService. Once accepted, ConnectivityService will poll underlying + * network connection for updated bandwidth information. The caller will be notified via + * {@link ConnectivityManager.NetworkCallback} if there is an update. Notice that this + * method assumes that the caller has previously called + * {@link #registerNetworkCallback(NetworkRequest, NetworkCallback)} to listen for network + * changes. + * + * @param network {@link Network} specifying which network you're interested. + * @return {@code true} on success, {@code false} if the {@link Network} is no longer valid. + */ + public boolean requestBandwidthUpdate(@NonNull Network network) { + try { + return mService.requestBandwidthUpdate(network); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Unregisters a {@code NetworkCallback} and possibly releases networks originating from + * {@link #requestNetwork(NetworkRequest, NetworkCallback)} and + * {@link #registerNetworkCallback(NetworkRequest, NetworkCallback)} calls. + * If the given {@code NetworkCallback} had previously been used with + * {@code #requestNetwork}, any networks that had been connected to only to satisfy that request + * will be disconnected. + * + * Notifications that would have triggered that {@code NetworkCallback} will immediately stop + * triggering it as soon as this call returns. + * + * @param networkCallback The {@link NetworkCallback} used when making the request. + */ + public void unregisterNetworkCallback(@NonNull NetworkCallback networkCallback) { + printStackTrace(); + checkCallbackNotNull(networkCallback); + final List reqs = new ArrayList<>(); + // Find all requests associated to this callback and stop callback triggers immediately. + // Callback is reusable immediately. http://b/20701525, http://b/35921499. + synchronized (sCallbacks) { + Preconditions.checkArgument(networkCallback.networkRequest != null, + "NetworkCallback was not registered"); + if (networkCallback.networkRequest == ALREADY_UNREGISTERED) { + Log.d(TAG, "NetworkCallback was already unregistered"); + return; + } + for (Map.Entry e : sCallbacks.entrySet()) { + if (e.getValue() == networkCallback) { + reqs.add(e.getKey()); + } + } + // TODO: throw exception if callback was registered more than once (http://b/20701525). + for (NetworkRequest r : reqs) { + try { + mService.releaseNetworkRequest(r); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + // Only remove mapping if rpc was successful. + sCallbacks.remove(r); + } + networkCallback.networkRequest = ALREADY_UNREGISTERED; + } + } + + /** + * Unregisters a callback previously registered via + * {@link #registerNetworkCallback(NetworkRequest, android.app.PendingIntent)}. + * + * @param operation A PendingIntent equal (as defined by {@link Intent#filterEquals}) to the + * PendingIntent passed to + * {@link #registerNetworkCallback(NetworkRequest, android.app.PendingIntent)}. + * Cannot be null. + */ + public void unregisterNetworkCallback(@NonNull PendingIntent operation) { + releaseNetworkRequest(operation); + } + + /** + * Informs the system whether it should switch to {@code network} regardless of whether it is + * validated or not. If {@code accept} is true, and the network was explicitly selected by the + * user (e.g., by selecting a Wi-Fi network in the Settings app), then the network will become + * the system default network regardless of any other network that's currently connected. If + * {@code always} is true, then the choice is remembered, so that the next time the user + * connects to this network, the system will switch to it. + * + * @param network The network to accept. + * @param accept Whether to accept the network even if unvalidated. + * @param always Whether to remember this choice in the future. + * + * @hide + */ + @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) + public void setAcceptUnvalidated(Network network, boolean accept, boolean always) { + try { + mService.setAcceptUnvalidated(network, accept, always); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Informs the system whether it should consider the network as validated even if it only has + * partial connectivity. If {@code accept} is true, then the network will be considered as + * validated even if connectivity is only partial. If {@code always} is true, then the choice + * is remembered, so that the next time the user connects to this network, the system will + * switch to it. + * + * @param network The network to accept. + * @param accept Whether to consider the network as validated even if it has partial + * connectivity. + * @param always Whether to remember this choice in the future. + * + * @hide + */ + @RequiresPermission(android.Manifest.permission.NETWORK_STACK) + public void setAcceptPartialConnectivity(Network network, boolean accept, boolean always) { + try { + mService.setAcceptPartialConnectivity(network, accept, always); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Informs the system to penalize {@code network}'s score when it becomes unvalidated. This is + * only meaningful if the system is configured not to penalize such networks, e.g., if the + * {@code config_networkAvoidBadWifi} configuration variable is set to 0 and the {@code + * NETWORK_AVOID_BAD_WIFI setting is unset}. + * + * @param network The network to accept. + * + * @hide + */ + @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) + public void setAvoidUnvalidated(Network network) { + try { + mService.setAvoidUnvalidated(network); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Requests that the system open the captive portal app on the specified network. + * + * @param network The network to log into. + * + * @hide + */ + @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) + public void startCaptivePortalApp(Network network) { + try { + mService.startCaptivePortalApp(network); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Requests that the system open the captive portal app with the specified extras. + * + *

This endpoint is exclusively for use by the NetworkStack and is protected by the + * corresponding permission. + * @param network Network on which the captive portal was detected. + * @param appExtras Extras to include in the app start intent. + * @hide + */ + @SystemApi + @RequiresPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) + public void startCaptivePortalApp(@NonNull Network network, @NonNull Bundle appExtras) { + try { + mService.startCaptivePortalAppInternal(network, appExtras); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Determine whether the device is configured to avoid bad wifi. + * @hide + */ + @SystemApi + @RequiresPermission(anyOf = { + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, + android.Manifest.permission.NETWORK_STACK}) + public boolean shouldAvoidBadWifi() { + try { + return mService.shouldAvoidBadWifi(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * It is acceptable to briefly use multipath data to provide seamless connectivity for + * time-sensitive user-facing operations when the system default network is temporarily + * unresponsive. The amount of data should be limited (less than one megabyte for every call to + * this method), and the operation should be infrequent to ensure that data usage is limited. + * + * An example of such an operation might be a time-sensitive foreground activity, such as a + * voice command, that the user is performing while walking out of range of a Wi-Fi network. + */ + public static final int MULTIPATH_PREFERENCE_HANDOVER = 1 << 0; + + /** + * It is acceptable to use small amounts of multipath data on an ongoing basis to provide + * a backup channel for traffic that is primarily going over another network. + * + * An example might be maintaining backup connections to peers or servers for the purpose of + * fast fallback if the default network is temporarily unresponsive or disconnects. The traffic + * on backup paths should be negligible compared to the traffic on the main path. + */ + public static final int MULTIPATH_PREFERENCE_RELIABILITY = 1 << 1; + + /** + * It is acceptable to use metered data to improve network latency and performance. + */ + public static final int MULTIPATH_PREFERENCE_PERFORMANCE = 1 << 2; + + /** + * Return value to use for unmetered networks. On such networks we currently set all the flags + * to true. + * @hide + */ + public static final int MULTIPATH_PREFERENCE_UNMETERED = + MULTIPATH_PREFERENCE_HANDOVER | + MULTIPATH_PREFERENCE_RELIABILITY | + MULTIPATH_PREFERENCE_PERFORMANCE; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(flag = true, value = { + MULTIPATH_PREFERENCE_HANDOVER, + MULTIPATH_PREFERENCE_RELIABILITY, + MULTIPATH_PREFERENCE_PERFORMANCE, + }) + public @interface MultipathPreference { + } + + /** + * Provides a hint to the calling application on whether it is desirable to use the + * multinetwork APIs (e.g., {@link Network#openConnection}, {@link Network#bindSocket}, etc.) + * for multipath data transfer on this network when it is not the system default network. + * Applications desiring to use multipath network protocols should call this method before + * each such operation. + * + * @param network The network on which the application desires to use multipath data. + * If {@code null}, this method will return the a preference that will generally + * apply to metered networks. + * @return a bitwise OR of zero or more of the {@code MULTIPATH_PREFERENCE_*} constants. + */ + @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + public @MultipathPreference int getMultipathPreference(@Nullable Network network) { + try { + return mService.getMultipathPreference(network); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Resets all connectivity manager settings back to factory defaults. + * @hide + */ + @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) + public void factoryReset() { + try { + mService.factoryReset(); + mTetheringManager.stopAllTethering(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Binds the current process to {@code network}. All Sockets created in the future + * (and not explicitly bound via a bound SocketFactory from + * {@link Network#getSocketFactory() Network.getSocketFactory()}) will be bound to + * {@code network}. All host name resolutions will be limited to {@code network} as well. + * Note that if {@code network} ever disconnects, all Sockets created in this way will cease to + * work and all host name resolutions will fail. This is by design so an application doesn't + * accidentally use Sockets it thinks are still bound to a particular {@link Network}. + * To clear binding pass {@code null} for {@code network}. Using individually bound + * Sockets created by Network.getSocketFactory().createSocket() and + * performing network-specific host name resolutions via + * {@link Network#getAllByName Network.getAllByName} is preferred to calling + * {@code bindProcessToNetwork}. + * + * @param network The {@link Network} to bind the current process to, or {@code null} to clear + * the current binding. + * @return {@code true} on success, {@code false} if the {@link Network} is no longer valid. + */ + public boolean bindProcessToNetwork(@Nullable Network network) { + // Forcing callers to call through non-static function ensures ConnectivityManager + // instantiated. + return setProcessDefaultNetwork(network); + } + + /** + * Binds the current process to {@code network}. All Sockets created in the future + * (and not explicitly bound via a bound SocketFactory from + * {@link Network#getSocketFactory() Network.getSocketFactory()}) will be bound to + * {@code network}. All host name resolutions will be limited to {@code network} as well. + * Note that if {@code network} ever disconnects, all Sockets created in this way will cease to + * work and all host name resolutions will fail. This is by design so an application doesn't + * accidentally use Sockets it thinks are still bound to a particular {@link Network}. + * To clear binding pass {@code null} for {@code network}. Using individually bound + * Sockets created by Network.getSocketFactory().createSocket() and + * performing network-specific host name resolutions via + * {@link Network#getAllByName Network.getAllByName} is preferred to calling + * {@code setProcessDefaultNetwork}. + * + * @param network The {@link Network} to bind the current process to, or {@code null} to clear + * the current binding. + * @return {@code true} on success, {@code false} if the {@link Network} is no longer valid. + * @deprecated This function can throw {@link IllegalStateException}. Use + * {@link #bindProcessToNetwork} instead. {@code bindProcessToNetwork} + * is a direct replacement. + */ + @Deprecated + public static boolean setProcessDefaultNetwork(@Nullable Network network) { + int netId = (network == null) ? NETID_UNSET : network.netId; + boolean isSameNetId = (netId == NetworkUtils.getBoundNetworkForProcess()); + + if (netId != NETID_UNSET) { + netId = network.getNetIdForResolv(); + } + + if (!NetworkUtils.bindProcessToNetwork(netId)) { + return false; + } + + if (!isSameNetId) { + // Set HTTP proxy system properties to match network. + // TODO: Deprecate this static method and replace it with a non-static version. + try { + Proxy.setHttpProxySystemProperty(getInstance().getDefaultProxy()); + } catch (SecurityException e) { + // The process doesn't have ACCESS_NETWORK_STATE, so we can't fetch the proxy. + Log.e(TAG, "Can't set proxy properties", e); + } + // Must flush DNS cache as new network may have different DNS resolutions. + InetAddress.clearDnsCache(); + // Must flush socket pool as idle sockets will be bound to previous network and may + // cause subsequent fetches to be performed on old network. + NetworkEventDispatcher.getInstance().onNetworkConfigurationChanged(); + } + + return true; + } + + /** + * Returns the {@link Network} currently bound to this process via + * {@link #bindProcessToNetwork}, or {@code null} if no {@link Network} is explicitly bound. + * + * @return {@code Network} to which this process is bound, or {@code null}. + */ + @Nullable + public Network getBoundNetworkForProcess() { + // Forcing callers to call thru non-static function ensures ConnectivityManager + // instantiated. + return getProcessDefaultNetwork(); + } + + /** + * Returns the {@link Network} currently bound to this process via + * {@link #bindProcessToNetwork}, or {@code null} if no {@link Network} is explicitly bound. + * + * @return {@code Network} to which this process is bound, or {@code null}. + * @deprecated Using this function can lead to other functions throwing + * {@link IllegalStateException}. Use {@link #getBoundNetworkForProcess} instead. + * {@code getBoundNetworkForProcess} is a direct replacement. + */ + @Deprecated + @Nullable + public static Network getProcessDefaultNetwork() { + int netId = NetworkUtils.getBoundNetworkForProcess(); + if (netId == NETID_UNSET) return null; + return new Network(netId); + } + + private void unsupportedStartingFrom(int version) { + if (Process.myUid() == Process.SYSTEM_UID) { + // The getApplicationInfo() call we make below is not supported in system context. Let + // the call through here, and rely on the fact that ConnectivityService will refuse to + // allow the system to use these APIs anyway. + return; + } + + if (mContext.getApplicationInfo().targetSdkVersion >= version) { + throw new UnsupportedOperationException( + "This method is not supported in target SDK version " + version + " and above"); + } + } + + // Checks whether the calling app can use the legacy routing API (startUsingNetworkFeature, + // stopUsingNetworkFeature, requestRouteToHost), and if not throw UnsupportedOperationException. + // TODO: convert the existing system users (Tethering, GnssLocationProvider) to the new APIs and + // remove these exemptions. Note that this check is not secure, and apps can still access these + // functions by accessing ConnectivityService directly. However, it should be clear that doing + // so is unsupported and may break in the future. http://b/22728205 + private void checkLegacyRoutingApiAccess() { + unsupportedStartingFrom(VERSION_CODES.M); + } + + /** + * Binds host resolutions performed by this process to {@code network}. + * {@link #bindProcessToNetwork} takes precedence over this setting. + * + * @param network The {@link Network} to bind host resolutions from the current process to, or + * {@code null} to clear the current binding. + * @return {@code true} on success, {@code false} if the {@link Network} is no longer valid. + * @hide + * @deprecated This is strictly for legacy usage to support {@link #startUsingNetworkFeature}. + */ + @Deprecated + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + public static boolean setProcessDefaultNetworkForHostResolution(Network network) { + return NetworkUtils.bindProcessToNetworkForHostResolution( + (network == null) ? NETID_UNSET : network.getNetIdForResolv()); + } + + /** + * Device is not restricting metered network activity while application is running on + * background. + */ + public static final int RESTRICT_BACKGROUND_STATUS_DISABLED = 1; + + /** + * Device is restricting metered network activity while application is running on background, + * but application is allowed to bypass it. + *

+ * In this state, application should take action to mitigate metered network access. + * For example, a music streaming application should switch to a low-bandwidth bitrate. + */ + public static final int RESTRICT_BACKGROUND_STATUS_WHITELISTED = 2; + + /** + * Device is restricting metered network activity while application is running on background. + *

+ * In this state, application should not try to use the network while running on background, + * because it would be denied. + */ + public static final int RESTRICT_BACKGROUND_STATUS_ENABLED = 3; + + /** + * A change in the background metered network activity restriction has occurred. + *

+ * Applications should call {@link #getRestrictBackgroundStatus()} to check if the restriction + * applies to them. + *

+ * This is only sent to registered receivers, not manifest receivers. + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_RESTRICT_BACKGROUND_CHANGED = + "android.net.conn.RESTRICT_BACKGROUND_CHANGED"; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(flag = false, value = { + RESTRICT_BACKGROUND_STATUS_DISABLED, + RESTRICT_BACKGROUND_STATUS_WHITELISTED, + RESTRICT_BACKGROUND_STATUS_ENABLED, + }) + public @interface RestrictBackgroundStatus { + } + + private INetworkPolicyManager getNetworkPolicyManager() { + synchronized (this) { + if (mNPManager != null) { + return mNPManager; + } + mNPManager = INetworkPolicyManager.Stub.asInterface(ServiceManager + .getService(Context.NETWORK_POLICY_SERVICE)); + return mNPManager; + } + } + + /** + * Determines if the calling application is subject to metered network restrictions while + * running on background. + * + * @return {@link #RESTRICT_BACKGROUND_STATUS_DISABLED}, + * {@link #RESTRICT_BACKGROUND_STATUS_ENABLED}, + * or {@link #RESTRICT_BACKGROUND_STATUS_WHITELISTED} + */ + public @RestrictBackgroundStatus int getRestrictBackgroundStatus() { + try { + return getNetworkPolicyManager().getRestrictBackgroundByCaller(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * The network watchlist is a list of domains and IP addresses that are associated with + * potentially harmful apps. This method returns the SHA-256 of the watchlist config file + * currently used by the system for validation purposes. + * + * @return Hash of network watchlist config file. Null if config does not exist. + */ + @Nullable + public byte[] getNetworkWatchlistConfigHash() { + try { + return mService.getNetworkWatchlistConfigHash(); + } catch (RemoteException e) { + Log.e(TAG, "Unable to get watchlist config hash"); + throw e.rethrowFromSystemServer(); + } + } + + /** + * Returns the {@code uid} of the owner of a network connection. + * + * @param protocol The protocol of the connection. Only {@code IPPROTO_TCP} and {@code + * IPPROTO_UDP} currently supported. + * @param local The local {@link InetSocketAddress} of a connection. + * @param remote The remote {@link InetSocketAddress} of a connection. + * @return {@code uid} if the connection is found and the app has permission to observe it + * (e.g., if it is associated with the calling VPN app's VpnService tunnel) or {@link + * android.os.Process#INVALID_UID} if the connection is not found. + * @throws {@link SecurityException} if the caller is not the active VpnService for the current + * user. + * @throws {@link IllegalArgumentException} if an unsupported protocol is requested. + */ + public int getConnectionOwnerUid( + int protocol, @NonNull InetSocketAddress local, @NonNull InetSocketAddress remote) { + ConnectionInfo connectionInfo = new ConnectionInfo(protocol, local, remote); + try { + return mService.getConnectionOwnerUid(connectionInfo); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + private void printStackTrace() { + if (DEBUG) { + final StackTraceElement[] callStack = Thread.currentThread().getStackTrace(); + final StringBuffer sb = new StringBuffer(); + for (int i = 3; i < callStack.length; i++) { + final String stackTrace = callStack[i].toString(); + if (stackTrace == null || stackTrace.contains("android.os")) { + break; + } + sb.append(" [").append(stackTrace).append("]"); + } + Log.d(TAG, "StackLog:" + sb.toString()); + } + } + + /** + * Simulates a Data Stall for the specified Network. + * + *

This method should only be used for tests. + * + *

The caller must be the owner of the specified Network. + * + * @param detectionMethod The detection method used to identify the Data Stall. + * @param timestampMillis The timestamp at which the stall 'occurred', in milliseconds. + * @param network The Network for which a Data Stall is being simluated. + * @param extras The PersistableBundle of extras included in the Data Stall notification. + * @throws SecurityException if the caller is not the owner of the given network. + * @hide + */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_TEST_NETWORKS, + android.Manifest.permission.NETWORK_STACK}) + public void simulateDataStall(int detectionMethod, long timestampMillis, + @NonNull Network network, @NonNull PersistableBundle extras) { + try { + mService.simulateDataStall(detectionMethod, timestampMillis, network, extras); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } + + private void setOemNetworkPreference(@NonNull OemNetworkPreferences preference) { + Log.d(TAG, "setOemNetworkPreference called with preference: " + + preference.toString()); + } + + @NonNull + private final List mQosCallbackConnections = new ArrayList<>(); + + /** + * Registers a {@link QosSocketInfo} with an associated {@link QosCallback}. The callback will + * receive available QoS events related to the {@link Network} and local ip + port + * specified within socketInfo. + *

+ * The same {@link QosCallback} must be unregistered before being registered a second time, + * otherwise {@link QosCallbackRegistrationException} is thrown. + *

+ * This API does not, in itself, require any permission if called with a network that is not + * restricted. However, the underlying implementation currently only supports the IMS network, + * which is always restricted. That means non-preinstalled callers can't possibly find this API + * useful, because they'd never be called back on networks that they would have access to. + * + * @throws SecurityException if {@link QosSocketInfo#getNetwork()} is restricted and the app is + * missing CONNECTIVITY_USE_RESTRICTED_NETWORKS permission. + * @throws QosCallback.QosCallbackRegistrationException if qosCallback is already registered. + * @throws RuntimeException if the app already has too many callbacks registered. + * + * Exceptions after the time of registration is passed through + * {@link QosCallback#onError(QosCallbackException)}. see: {@link QosCallbackException}. + * + * @param socketInfo the socket information used to match QoS events + * @param callback receives qos events that satisfy socketInfo + * @param executor The executor on which the callback will be invoked. The provided + * {@link Executor} must run callback sequentially, otherwise the order of + * callbacks cannot be guaranteed. + * + * @hide + */ + @SystemApi + public void registerQosCallback(@NonNull final QosSocketInfo socketInfo, + @NonNull final QosCallback callback, + @CallbackExecutor @NonNull final Executor executor) { + Objects.requireNonNull(socketInfo, "socketInfo must be non-null"); + Objects.requireNonNull(callback, "callback must be non-null"); + Objects.requireNonNull(executor, "executor must be non-null"); + + try { + synchronized (mQosCallbackConnections) { + if (getQosCallbackConnection(callback) == null) { + final QosCallbackConnection connection = + new QosCallbackConnection(this, callback, executor); + mQosCallbackConnections.add(connection); + mService.registerQosSocketCallback(socketInfo, connection); + } else { + Log.e(TAG, "registerQosCallback: Callback already registered"); + throw new QosCallbackRegistrationException(); + } + } + } catch (final RemoteException e) { + Log.e(TAG, "registerQosCallback: Error while registering ", e); + + // The same unregister method method is called for consistency even though nothing + // will be sent to the ConnectivityService since the callback was never successfully + // registered. + unregisterQosCallback(callback); + e.rethrowFromSystemServer(); + } catch (final ServiceSpecificException e) { + Log.e(TAG, "registerQosCallback: Error while registering ", e); + unregisterQosCallback(callback); + throw convertServiceException(e); + } + } + + /** + * Unregisters the given {@link QosCallback}. The {@link QosCallback} will no longer receive + * events once unregistered and can be registered a second time. + *

+ * If the {@link QosCallback} does not have an active registration, it is a no-op. + * + * @param callback the callback being unregistered + * + * @hide + */ + @SystemApi + public void unregisterQosCallback(@NonNull final QosCallback callback) { + Objects.requireNonNull(callback, "The callback must be non-null"); + try { + synchronized (mQosCallbackConnections) { + final QosCallbackConnection connection = getQosCallbackConnection(callback); + if (connection != null) { + connection.stopReceivingMessages(); + mService.unregisterQosCallback(connection); + mQosCallbackConnections.remove(connection); + } else { + Log.d(TAG, "unregisterQosCallback: Callback not registered"); + } + } + } catch (final RemoteException e) { + Log.e(TAG, "unregisterQosCallback: Error while unregistering ", e); + e.rethrowFromSystemServer(); + } + } + + /** + * Gets the connection related to the callback. + * + * @param callback the callback to look up + * @return the related connection + */ + @Nullable + private QosCallbackConnection getQosCallbackConnection(final QosCallback callback) { + for (final QosCallbackConnection connection : mQosCallbackConnections) { + // Checking by reference here is intentional + if (connection.getCallback() == callback) { + return connection; + } + } + return null; + } + + /** + * Request a network to satisfy a set of {@link android.net.NetworkCapabilities}, but + * does not cause any networks to retain the NET_CAPABILITY_FOREGROUND capability. This can + * be used to request that the system provide a network without causing the network to be + * in the foreground. + * + *

This method will attempt to find the best network that matches the passed + * {@link NetworkRequest}, and to bring up one that does if none currently satisfies the + * criteria. The platform will evaluate which network is the best at its own discretion. + * Throughput, latency, cost per byte, policy, user preference and other considerations + * may be factored in the decision of what is considered the best network. + * + *

As long as this request is outstanding, the platform will try to maintain the best network + * matching this request, while always attempting to match the request to a better network if + * possible. If a better match is found, the platform will switch this request to the now-best + * network and inform the app of the newly best network by invoking + * {@link NetworkCallback#onAvailable(Network)} on the provided callback. Note that the platform + * will not try to maintain any other network than the best one currently matching the request: + * a network not matching any network request may be disconnected at any time. + * + *

For example, an application could use this method to obtain a connected cellular network + * even if the device currently has a data connection over Ethernet. This may cause the cellular + * radio to consume additional power. Or, an application could inform the system that it wants + * a network supporting sending MMSes and have the system let it know about the currently best + * MMS-supporting network through the provided {@link NetworkCallback}. + * + *

The status of the request can be followed by listening to the various callbacks described + * in {@link NetworkCallback}. The {@link Network} object passed to the callback methods can be + * used to direct traffic to the network (although accessing some networks may be subject to + * holding specific permissions). Callers will learn about the specific characteristics of the + * network through + * {@link NetworkCallback#onCapabilitiesChanged(Network, NetworkCapabilities)} and + * {@link NetworkCallback#onLinkPropertiesChanged(Network, LinkProperties)}. The methods of the + * provided {@link NetworkCallback} will only be invoked due to changes in the best network + * matching the request at any given time; therefore when a better network matching the request + * becomes available, the {@link NetworkCallback#onAvailable(Network)} method is called + * with the new network after which no further updates are given about the previously-best + * network, unless it becomes the best again at some later time. All callbacks are invoked + * in order on the same thread, which by default is a thread created by the framework running + * in the app. + * + *

This{@link NetworkRequest} will live until released via + * {@link #unregisterNetworkCallback(NetworkCallback)} or the calling application exits, at + * which point the system may let go of the network at any time. + * + *

It is presently unsupported to request a network with mutable + * {@link NetworkCapabilities} such as + * {@link NetworkCapabilities#NET_CAPABILITY_VALIDATED} or + * {@link NetworkCapabilities#NET_CAPABILITY_CAPTIVE_PORTAL} + * as these {@code NetworkCapabilities} represent states that a particular + * network may never attain, and whether a network will attain these states + * is unknown prior to bringing up the network so the framework does not + * know how to go about satisfying a request with these capabilities. + * + *

To avoid performance issues due to apps leaking callbacks, the system will limit the + * number of outstanding requests to 100 per app (identified by their UID), shared with + * all variants of this method, of {@link #registerNetworkCallback} as well as + * {@link ConnectivityDiagnosticsManager#registerConnectivityDiagnosticsCallback}. + * Requesting a network with this method will count toward this limit. If this limit is + * exceeded, an exception will be thrown. To avoid hitting this issue and to conserve resources, + * make sure to unregister the callbacks with + * {@link #unregisterNetworkCallback(NetworkCallback)}. + * + * @param request {@link NetworkRequest} describing this request. + * @param handler {@link Handler} to specify the thread upon which the callback will be invoked. + * If null, the callback is invoked on the default internal Handler. + * @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note + * the callback must not be shared - it uniquely specifies this request. + * @throws IllegalArgumentException if {@code request} contains invalid network capabilities. + * @throws SecurityException if missing the appropriate permissions. + * @throws RuntimeException if the app already has too many callbacks registered. + * + * @hide + */ + @SystemApi(client = MODULE_LIBRARIES) + @SuppressLint("ExecutorRegistration") + @RequiresPermission(anyOf = { + android.Manifest.permission.NETWORK_SETTINGS, + android.Manifest.permission.NETWORK_STACK, + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK + }) + public void requestBackgroundNetwork(@NonNull NetworkRequest request, + @Nullable Handler handler, @NonNull NetworkCallback networkCallback) { + final NetworkCapabilities nc = request.networkCapabilities; + sendRequestForNetwork(nc, networkCallback, 0, BACKGROUND_REQUEST, + TYPE_NONE, handler == null ? getDefaultHandler() : new CallbackHandler(handler)); + } +} diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityMetricsEvent.aidl b/packages/Connectivity/framework/src/android/net/ConnectivityMetricsEvent.aidl new file mode 100644 index 000000000000..1c541dc4c8cc --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/ConnectivityMetricsEvent.aidl @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +/** {@hide} */ +parcelable ConnectivityMetricsEvent; diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityThread.java b/packages/Connectivity/framework/src/android/net/ConnectivityThread.java new file mode 100644 index 000000000000..0b218e738b77 --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/ConnectivityThread.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.os.HandlerThread; +import android.os.Looper; + +/** + * Shared singleton connectivity thread for the system. This is a thread for + * connectivity operations such as AsyncChannel connections to system services. + * Various connectivity manager objects can use this singleton as a common + * resource for their handlers instead of creating separate threads of their own. + * @hide + */ +public final class ConnectivityThread extends HandlerThread { + + // A class implementing the lazy holder idiom: the unique static instance + // of ConnectivityThread is instantiated in a thread-safe way (guaranteed by + // the language specs) the first time that Singleton is referenced in get() + // or getInstanceLooper(). + private static class Singleton { + private static final ConnectivityThread INSTANCE = createInstance(); + } + + private ConnectivityThread() { + super("ConnectivityThread"); + } + + private static ConnectivityThread createInstance() { + ConnectivityThread t = new ConnectivityThread(); + t.start(); + return t; + } + + public static ConnectivityThread get() { + return Singleton.INSTANCE; + } + + public static Looper getInstanceLooper() { + return Singleton.INSTANCE.getLooper(); + } +} diff --git a/packages/Connectivity/framework/src/android/net/DhcpInfo.aidl b/packages/Connectivity/framework/src/android/net/DhcpInfo.aidl new file mode 100644 index 000000000000..29cd21fe7652 --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/DhcpInfo.aidl @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2008, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +parcelable DhcpInfo; diff --git a/packages/Connectivity/framework/src/android/net/DhcpInfo.java b/packages/Connectivity/framework/src/android/net/DhcpInfo.java new file mode 100644 index 000000000000..912df67a0b45 --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/DhcpInfo.java @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * A simple object for retrieving the results of a DHCP request. + */ +public class DhcpInfo implements Parcelable { + public int ipAddress; + public int gateway; + public int netmask; + public int dns1; + public int dns2; + public int serverAddress; + + public int leaseDuration; + + public DhcpInfo() { + super(); + } + + /** copy constructor {@hide} */ + public DhcpInfo(DhcpInfo source) { + if (source != null) { + ipAddress = source.ipAddress; + gateway = source.gateway; + netmask = source.netmask; + dns1 = source.dns1; + dns2 = source.dns2; + serverAddress = source.serverAddress; + leaseDuration = source.leaseDuration; + } + } + + public String toString() { + StringBuffer str = new StringBuffer(); + + str.append("ipaddr "); putAddress(str, ipAddress); + str.append(" gateway "); putAddress(str, gateway); + str.append(" netmask "); putAddress(str, netmask); + str.append(" dns1 "); putAddress(str, dns1); + str.append(" dns2 "); putAddress(str, dns2); + str.append(" DHCP server "); putAddress(str, serverAddress); + str.append(" lease ").append(leaseDuration).append(" seconds"); + + return str.toString(); + } + + private static void putAddress(StringBuffer buf, int addr) { + buf.append(NetworkUtils.intToInetAddress(addr).getHostAddress()); + } + + /** Implement the Parcelable interface */ + public int describeContents() { + return 0; + } + + /** Implement the Parcelable interface */ + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(ipAddress); + dest.writeInt(gateway); + dest.writeInt(netmask); + dest.writeInt(dns1); + dest.writeInt(dns2); + dest.writeInt(serverAddress); + dest.writeInt(leaseDuration); + } + + /** Implement the Parcelable interface */ + public static final @android.annotation.NonNull Creator CREATOR = + new Creator() { + public DhcpInfo createFromParcel(Parcel in) { + DhcpInfo info = new DhcpInfo(); + info.ipAddress = in.readInt(); + info.gateway = in.readInt(); + info.netmask = in.readInt(); + info.dns1 = in.readInt(); + info.dns2 = in.readInt(); + info.serverAddress = in.readInt(); + info.leaseDuration = in.readInt(); + return info; + } + + public DhcpInfo[] newArray(int size) { + return new DhcpInfo[size]; + } + }; +} diff --git a/packages/Connectivity/framework/src/android/net/DnsResolver.java b/packages/Connectivity/framework/src/android/net/DnsResolver.java new file mode 100644 index 000000000000..3f7660f5709a --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/DnsResolver.java @@ -0,0 +1,577 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import static android.net.NetworkUtils.getDnsNetwork; +import static android.net.NetworkUtils.resNetworkCancel; +import static android.net.NetworkUtils.resNetworkQuery; +import static android.net.NetworkUtils.resNetworkResult; +import static android.net.NetworkUtils.resNetworkSend; +import static android.net.util.DnsUtils.haveIpv4; +import static android.net.util.DnsUtils.haveIpv6; +import static android.net.util.DnsUtils.rfc6724Sort; +import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_ERROR; +import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT; +import static android.system.OsConstants.ENONET; + +import android.annotation.CallbackExecutor; +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.os.CancellationSignal; +import android.os.Looper; +import android.os.MessageQueue; +import android.system.ErrnoException; +import android.util.Log; + +import com.android.net.module.util.DnsPacket; + +import java.io.FileDescriptor; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Executor; + +/** + * Dns resolver class for asynchronous dns querying + * + * Note that if a client sends a query with more than 1 record in the question section but + * the remote dns server does not support this, it may not respond at all, leading to a timeout. + * + */ +public final class DnsResolver { + private static final String TAG = "DnsResolver"; + private static final int FD_EVENTS = EVENT_INPUT | EVENT_ERROR; + private static final int MAXPACKET = 8 * 1024; + private static final int SLEEP_TIME_MS = 2; + + @IntDef(prefix = { "CLASS_" }, value = { + CLASS_IN + }) + @Retention(RetentionPolicy.SOURCE) + @interface QueryClass {} + public static final int CLASS_IN = 1; + + @IntDef(prefix = { "TYPE_" }, value = { + TYPE_A, + TYPE_AAAA + }) + @Retention(RetentionPolicy.SOURCE) + @interface QueryType {} + public static final int TYPE_A = 1; + public static final int TYPE_AAAA = 28; + + @IntDef(prefix = { "FLAG_" }, value = { + FLAG_EMPTY, + FLAG_NO_RETRY, + FLAG_NO_CACHE_STORE, + FLAG_NO_CACHE_LOOKUP + }) + @Retention(RetentionPolicy.SOURCE) + @interface QueryFlag {} + public static final int FLAG_EMPTY = 0; + public static final int FLAG_NO_RETRY = 1 << 0; + public static final int FLAG_NO_CACHE_STORE = 1 << 1; + public static final int FLAG_NO_CACHE_LOOKUP = 1 << 2; + + @IntDef(prefix = { "ERROR_" }, value = { + ERROR_PARSE, + ERROR_SYSTEM + }) + @Retention(RetentionPolicy.SOURCE) + @interface DnsError {} + /** + * Indicates that there was an error parsing the response the query. + * The cause of this error is available via getCause() and is a {@link ParseException}. + */ + public static final int ERROR_PARSE = 0; + /** + * Indicates that there was an error sending the query. + * The cause of this error is available via getCause() and is an ErrnoException. + */ + public static final int ERROR_SYSTEM = 1; + + private static final int NETID_UNSET = 0; + + private static final DnsResolver sInstance = new DnsResolver(); + + /** + * Get instance for DnsResolver + */ + public static @NonNull DnsResolver getInstance() { + return sInstance; + } + + private DnsResolver() {} + + /** + * Base interface for answer callbacks + * + * @param The type of the answer + */ + public interface Callback { + /** + * Success response to + * {@link android.net.DnsResolver#query query()} or + * {@link android.net.DnsResolver#rawQuery rawQuery()}. + * + * Invoked when the answer to a query was successfully parsed. + * + * @param answer answer to the query. + * @param rcode The response code in the DNS response. + * + * {@see android.net.DnsResolver#query query()} + */ + void onAnswer(@NonNull T answer, int rcode); + /** + * Error response to + * {@link android.net.DnsResolver#query query()} or + * {@link android.net.DnsResolver#rawQuery rawQuery()}. + * + * Invoked when there is no valid answer to + * {@link android.net.DnsResolver#query query()} + * {@link android.net.DnsResolver#rawQuery rawQuery()}. + * + * @param error a {@link DnsException} object with additional + * detail regarding the failure + */ + void onError(@NonNull DnsException error); + } + + /** + * Class to represent DNS error + */ + public static class DnsException extends Exception { + /** + * DNS error code as one of the ERROR_* constants + */ + @DnsError public final int code; + + DnsException(@DnsError int code, @Nullable Throwable cause) { + super(cause); + this.code = code; + } + } + + /** + * Send a raw DNS query. + * The answer will be provided asynchronously through the provided {@link Callback}. + * + * @param network {@link Network} specifying which network to query on. + * {@code null} for query on default network. + * @param query blob message to query + * @param flags flags as a combination of the FLAGS_* constants + * @param executor The {@link Executor} that the callback should be executed on. + * @param cancellationSignal used by the caller to signal if the query should be + * cancelled. May be {@code null}. + * @param callback a {@link Callback} which will be called to notify the caller + * of the result of dns query. + */ + public void rawQuery(@Nullable Network network, @NonNull byte[] query, @QueryFlag int flags, + @NonNull @CallbackExecutor Executor executor, + @Nullable CancellationSignal cancellationSignal, + @NonNull Callback callback) { + if (cancellationSignal != null && cancellationSignal.isCanceled()) { + return; + } + final Object lock = new Object(); + final FileDescriptor queryfd; + try { + queryfd = resNetworkSend((network != null) + ? network.getNetIdForResolv() : NETID_UNSET, query, query.length, flags); + } catch (ErrnoException e) { + executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e))); + return; + } + + synchronized (lock) { + registerFDListener(executor, queryfd, callback, cancellationSignal, lock); + if (cancellationSignal == null) return; + addCancellationSignal(cancellationSignal, queryfd, lock); + } + } + + /** + * Send a DNS query with the specified name, class and query type. + * The answer will be provided asynchronously through the provided {@link Callback}. + * + * @param network {@link Network} specifying which network to query on. + * {@code null} for query on default network. + * @param domain domain name to query + * @param nsClass dns class as one of the CLASS_* constants + * @param nsType dns resource record (RR) type as one of the TYPE_* constants + * @param flags flags as a combination of the FLAGS_* constants + * @param executor The {@link Executor} that the callback should be executed on. + * @param cancellationSignal used by the caller to signal if the query should be + * cancelled. May be {@code null}. + * @param callback a {@link Callback} which will be called to notify the caller + * of the result of dns query. + */ + public void rawQuery(@Nullable Network network, @NonNull String domain, + @QueryClass int nsClass, @QueryType int nsType, @QueryFlag int flags, + @NonNull @CallbackExecutor Executor executor, + @Nullable CancellationSignal cancellationSignal, + @NonNull Callback callback) { + if (cancellationSignal != null && cancellationSignal.isCanceled()) { + return; + } + final Object lock = new Object(); + final FileDescriptor queryfd; + try { + queryfd = resNetworkQuery((network != null) + ? network.getNetIdForResolv() : NETID_UNSET, domain, nsClass, nsType, flags); + } catch (ErrnoException e) { + executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e))); + return; + } + synchronized (lock) { + registerFDListener(executor, queryfd, callback, cancellationSignal, lock); + if (cancellationSignal == null) return; + addCancellationSignal(cancellationSignal, queryfd, lock); + } + } + + private class InetAddressAnswerAccumulator implements Callback { + private final List mAllAnswers; + private final Network mNetwork; + private int mRcode; + private DnsException mDnsException; + private final Callback> mUserCallback; + private final int mTargetAnswerCount; + private int mReceivedAnswerCount = 0; + + InetAddressAnswerAccumulator(@NonNull Network network, int size, + @NonNull Callback> callback) { + mNetwork = network; + mTargetAnswerCount = size; + mAllAnswers = new ArrayList<>(); + mUserCallback = callback; + } + + private boolean maybeReportError() { + if (mRcode != 0) { + mUserCallback.onAnswer(mAllAnswers, mRcode); + return true; + } + if (mDnsException != null) { + mUserCallback.onError(mDnsException); + return true; + } + return false; + } + + private void maybeReportAnswer() { + if (++mReceivedAnswerCount != mTargetAnswerCount) return; + if (mAllAnswers.isEmpty() && maybeReportError()) return; + mUserCallback.onAnswer(rfc6724Sort(mNetwork, mAllAnswers), mRcode); + } + + @Override + public void onAnswer(@NonNull byte[] answer, int rcode) { + // If at least one query succeeded, return an rcode of 0. + // Otherwise, arbitrarily return the first rcode received. + if (mReceivedAnswerCount == 0 || rcode == 0) { + mRcode = rcode; + } + try { + mAllAnswers.addAll(new DnsAddressAnswer(answer).getAddresses()); + } catch (DnsPacket.ParseException e) { + // Convert the com.android.net.module.util.DnsPacket.ParseException to an + // android.net.ParseException. This is the type that was used in Q and is implied + // by the public documentation of ERROR_PARSE. + // + // DnsPacket cannot throw android.net.ParseException directly because it's @hide. + ParseException pe = new ParseException(e.reason, e.getCause()); + pe.setStackTrace(e.getStackTrace()); + mDnsException = new DnsException(ERROR_PARSE, pe); + } + maybeReportAnswer(); + } + + @Override + public void onError(@NonNull DnsException error) { + mDnsException = error; + maybeReportAnswer(); + } + } + + /** + * Send a DNS query with the specified name on a network with both IPv4 and IPv6, + * get back a set of InetAddresses with rfc6724 sorting style asynchronously. + * + * This method will examine the connection ability on given network, and query IPv4 + * and IPv6 if connection is available. + * + * If at least one query succeeded with valid answer, rcode will be 0 + * + * The answer will be provided asynchronously through the provided {@link Callback}. + * + * @param network {@link Network} specifying which network to query on. + * {@code null} for query on default network. + * @param domain domain name to query + * @param flags flags as a combination of the FLAGS_* constants + * @param executor The {@link Executor} that the callback should be executed on. + * @param cancellationSignal used by the caller to signal if the query should be + * cancelled. May be {@code null}. + * @param callback a {@link Callback} which will be called to notify the + * caller of the result of dns query. + */ + public void query(@Nullable Network network, @NonNull String domain, @QueryFlag int flags, + @NonNull @CallbackExecutor Executor executor, + @Nullable CancellationSignal cancellationSignal, + @NonNull Callback> callback) { + if (cancellationSignal != null && cancellationSignal.isCanceled()) { + return; + } + final Object lock = new Object(); + final Network queryNetwork; + try { + queryNetwork = (network != null) ? network : getDnsNetwork(); + } catch (ErrnoException e) { + executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e))); + return; + } + final boolean queryIpv6 = haveIpv6(queryNetwork); + final boolean queryIpv4 = haveIpv4(queryNetwork); + + // This can only happen if queryIpv4 and queryIpv6 are both false. + // This almost certainly means that queryNetwork does not exist or no longer exists. + if (!queryIpv6 && !queryIpv4) { + executor.execute(() -> callback.onError( + new DnsException(ERROR_SYSTEM, new ErrnoException("resNetworkQuery", ENONET)))); + return; + } + + final FileDescriptor v4fd; + final FileDescriptor v6fd; + + int queryCount = 0; + + if (queryIpv6) { + try { + v6fd = resNetworkQuery(queryNetwork.getNetIdForResolv(), domain, CLASS_IN, + TYPE_AAAA, flags); + } catch (ErrnoException e) { + executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e))); + return; + } + queryCount++; + } else v6fd = null; + + // Avoiding gateways drop packets if queries are sent too close together + try { + Thread.sleep(SLEEP_TIME_MS); + } catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + } + + if (queryIpv4) { + try { + v4fd = resNetworkQuery(queryNetwork.getNetIdForResolv(), domain, CLASS_IN, TYPE_A, + flags); + } catch (ErrnoException e) { + if (queryIpv6) resNetworkCancel(v6fd); // Closes fd, marks it invalid. + executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e))); + return; + } + queryCount++; + } else v4fd = null; + + final InetAddressAnswerAccumulator accumulator = + new InetAddressAnswerAccumulator(queryNetwork, queryCount, callback); + + synchronized (lock) { + if (queryIpv6) { + registerFDListener(executor, v6fd, accumulator, cancellationSignal, lock); + } + if (queryIpv4) { + registerFDListener(executor, v4fd, accumulator, cancellationSignal, lock); + } + if (cancellationSignal == null) return; + cancellationSignal.setOnCancelListener(() -> { + synchronized (lock) { + if (queryIpv4) cancelQuery(v4fd); + if (queryIpv6) cancelQuery(v6fd); + } + }); + } + } + + /** + * Send a DNS query with the specified name and query type, get back a set of + * InetAddresses with rfc6724 sorting style asynchronously. + * + * The answer will be provided asynchronously through the provided {@link Callback}. + * + * @param network {@link Network} specifying which network to query on. + * {@code null} for query on default network. + * @param domain domain name to query + * @param nsType dns resource record (RR) type as one of the TYPE_* constants + * @param flags flags as a combination of the FLAGS_* constants + * @param executor The {@link Executor} that the callback should be executed on. + * @param cancellationSignal used by the caller to signal if the query should be + * cancelled. May be {@code null}. + * @param callback a {@link Callback} which will be called to notify the caller + * of the result of dns query. + */ + public void query(@Nullable Network network, @NonNull String domain, + @QueryType int nsType, @QueryFlag int flags, + @NonNull @CallbackExecutor Executor executor, + @Nullable CancellationSignal cancellationSignal, + @NonNull Callback> callback) { + if (cancellationSignal != null && cancellationSignal.isCanceled()) { + return; + } + final Object lock = new Object(); + final FileDescriptor queryfd; + final Network queryNetwork; + try { + queryNetwork = (network != null) ? network : getDnsNetwork(); + queryfd = resNetworkQuery(queryNetwork.getNetIdForResolv(), domain, CLASS_IN, nsType, + flags); + } catch (ErrnoException e) { + executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e))); + return; + } + final InetAddressAnswerAccumulator accumulator = + new InetAddressAnswerAccumulator(queryNetwork, 1, callback); + synchronized (lock) { + registerFDListener(executor, queryfd, accumulator, cancellationSignal, lock); + if (cancellationSignal == null) return; + addCancellationSignal(cancellationSignal, queryfd, lock); + } + } + + /** + * Class to retrieve DNS response + * + * @hide + */ + public static final class DnsResponse { + public final @NonNull byte[] answerbuf; + public final int rcode; + public DnsResponse(@NonNull byte[] answerbuf, int rcode) { + this.answerbuf = answerbuf; + this.rcode = rcode; + } + } + + private void registerFDListener(@NonNull Executor executor, + @NonNull FileDescriptor queryfd, @NonNull Callback answerCallback, + @Nullable CancellationSignal cancellationSignal, @NonNull Object lock) { + final MessageQueue mainThreadMessageQueue = Looper.getMainLooper().getQueue(); + mainThreadMessageQueue.addOnFileDescriptorEventListener( + queryfd, + FD_EVENTS, + (fd, events) -> { + // b/134310704 + // Unregister fd event listener before resNetworkResult is called to prevent + // race condition caused by fd reused. + // For example when querying v4 and v6, it's possible that the first query ends + // and the fd is closed before the second request starts, which might return + // the same fd for the second request. By that time, the looper must have + // unregistered the fd, otherwise another event listener can't be registered. + mainThreadMessageQueue.removeOnFileDescriptorEventListener(fd); + + executor.execute(() -> { + DnsResponse resp = null; + ErrnoException exception = null; + synchronized (lock) { + if (cancellationSignal != null && cancellationSignal.isCanceled()) { + return; + } + try { + resp = resNetworkResult(fd); // Closes fd, marks it invalid. + } catch (ErrnoException e) { + Log.e(TAG, "resNetworkResult:" + e.toString()); + exception = e; + } + } + if (exception != null) { + answerCallback.onError(new DnsException(ERROR_SYSTEM, exception)); + return; + } + answerCallback.onAnswer(resp.answerbuf, resp.rcode); + }); + + // The file descriptor has already been unregistered, so it does not really + // matter what is returned here. In spirit 0 (meaning "unregister this FD") + // is still the closest to what the looper needs to do. When returning 0, + // Looper knows to ignore the fd if it has already been unregistered. + return 0; + }); + } + + private void cancelQuery(@NonNull FileDescriptor queryfd) { + if (!queryfd.valid()) return; + Looper.getMainLooper().getQueue().removeOnFileDescriptorEventListener(queryfd); + resNetworkCancel(queryfd); // Closes fd, marks it invalid. + } + + private void addCancellationSignal(@NonNull CancellationSignal cancellationSignal, + @NonNull FileDescriptor queryfd, @NonNull Object lock) { + cancellationSignal.setOnCancelListener(() -> { + synchronized (lock) { + cancelQuery(queryfd); + } + }); + } + + private static class DnsAddressAnswer extends DnsPacket { + private static final String TAG = "DnsResolver.DnsAddressAnswer"; + private static final boolean DBG = false; + + private final int mQueryType; + + DnsAddressAnswer(@NonNull byte[] data) throws ParseException { + super(data); + if ((mHeader.flags & (1 << 15)) == 0) { + throw new ParseException("Not an answer packet"); + } + if (mHeader.getRecordCount(QDSECTION) == 0) { + throw new ParseException("No question found"); + } + // Expect only one question in question section. + mQueryType = mRecords[QDSECTION].get(0).nsType; + } + + public @NonNull List getAddresses() { + final List results = new ArrayList(); + if (mHeader.getRecordCount(ANSECTION) == 0) return results; + + for (final DnsRecord ansSec : mRecords[ANSECTION]) { + // Only support A and AAAA, also ignore answers if query type != answer type. + int nsType = ansSec.nsType; + if (nsType != mQueryType || (nsType != TYPE_A && nsType != TYPE_AAAA)) { + continue; + } + try { + results.add(InetAddress.getByAddress(ansSec.getRR())); + } catch (UnknownHostException e) { + if (DBG) { + Log.w(TAG, "rr to address fail"); + } + } + } + return results; + } + } + +} diff --git a/packages/Connectivity/framework/src/android/net/ICaptivePortal.aidl b/packages/Connectivity/framework/src/android/net/ICaptivePortal.aidl new file mode 100644 index 000000000000..fe21905c7002 --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/ICaptivePortal.aidl @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2015, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +/** + * Interface to inform NetworkMonitor of decisions of app handling captive portal. + * @hide + */ +oneway interface ICaptivePortal { + void appRequest(int request); + void appResponse(int response); + void logEvent(int eventId, String packageName); +} diff --git a/packages/Connectivity/framework/src/android/net/IConnectivityDiagnosticsCallback.aidl b/packages/Connectivity/framework/src/android/net/IConnectivityDiagnosticsCallback.aidl new file mode 100644 index 000000000000..82b64a928000 --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/IConnectivityDiagnosticsCallback.aidl @@ -0,0 +1,28 @@ +/** + * + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.net.ConnectivityDiagnosticsManager; +import android.net.Network; + +/** @hide */ +oneway interface IConnectivityDiagnosticsCallback { + void onConnectivityReportAvailable(in ConnectivityDiagnosticsManager.ConnectivityReport report); + void onDataStallSuspected(in ConnectivityDiagnosticsManager.DataStallReport report); + void onNetworkConnectivityReported(in Network n, boolean hasConnectivity); +} \ No newline at end of file diff --git a/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl b/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl new file mode 100644 index 000000000000..1b4d2e413943 --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl @@ -0,0 +1,246 @@ +/** + * Copyright (c) 2008, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.app.PendingIntent; +import android.net.ConnectionInfo; +import android.net.ConnectivityDiagnosticsManager; +import android.net.IConnectivityDiagnosticsCallback; +import android.net.IQosCallback; +import android.net.ISocketKeepaliveCallback; +import android.net.LinkProperties; +import android.net.Network; +import android.net.NetworkAgentConfig; +import android.net.NetworkCapabilities; +import android.net.NetworkInfo; +import android.net.NetworkRequest; +import android.net.NetworkState; +import android.net.ProxyInfo; +import android.net.UidRange; +import android.net.QosSocketInfo; +import android.os.Bundle; +import android.os.IBinder; +import android.os.INetworkActivityListener; +import android.os.Messenger; +import android.os.ParcelFileDescriptor; +import android.os.PersistableBundle; +import android.os.ResultReceiver; + +import com.android.connectivity.aidl.INetworkAgent; +import com.android.internal.net.LegacyVpnInfo; +import com.android.internal.net.VpnConfig; +import com.android.internal.net.VpnProfile; + +/** + * Interface that answers queries about, and allows changing, the + * state of network connectivity. + */ +/** {@hide} */ +interface IConnectivityManager +{ + Network getActiveNetwork(); + Network getActiveNetworkForUid(int uid, boolean ignoreBlocked); + @UnsupportedAppUsage + NetworkInfo getActiveNetworkInfo(); + NetworkInfo getActiveNetworkInfoForUid(int uid, boolean ignoreBlocked); + @UnsupportedAppUsage(maxTargetSdk = 28) + NetworkInfo getNetworkInfo(int networkType); + NetworkInfo getNetworkInfoForUid(in Network network, int uid, boolean ignoreBlocked); + @UnsupportedAppUsage + NetworkInfo[] getAllNetworkInfo(); + Network getNetworkForType(int networkType); + Network[] getAllNetworks(); + NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser( + int userId, String callingPackageName); + + boolean isNetworkSupported(int networkType); + + @UnsupportedAppUsage + LinkProperties getActiveLinkProperties(); + LinkProperties getLinkPropertiesForType(int networkType); + LinkProperties getLinkProperties(in Network network); + + NetworkCapabilities getNetworkCapabilities(in Network network, String callingPackageName); + + @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553) + NetworkState[] getAllNetworkState(); + + boolean isActiveNetworkMetered(); + + boolean requestRouteToHostAddress(int networkType, in byte[] hostAddress, + String callingPackageName, String callingAttributionTag); + + @UnsupportedAppUsage(maxTargetSdk = 29, + publicAlternatives = "Use {@code TetheringManager#getLastTetherError} as alternative") + int getLastTetherError(String iface); + + @UnsupportedAppUsage(maxTargetSdk = 29, + publicAlternatives = "Use {@code TetheringManager#getTetherableIfaces} as alternative") + String[] getTetherableIfaces(); + + @UnsupportedAppUsage(maxTargetSdk = 29, + publicAlternatives = "Use {@code TetheringManager#getTetheredIfaces} as alternative") + String[] getTetheredIfaces(); + + @UnsupportedAppUsage(maxTargetSdk = 29, + publicAlternatives = "Use {@code TetheringManager#getTetheringErroredIfaces} " + + "as Alternative") + String[] getTetheringErroredIfaces(); + + @UnsupportedAppUsage(maxTargetSdk = 29, + publicAlternatives = "Use {@code TetheringManager#getTetherableUsbRegexs} as alternative") + String[] getTetherableUsbRegexs(); + + @UnsupportedAppUsage(maxTargetSdk = 29, + publicAlternatives = "Use {@code TetheringManager#getTetherableWifiRegexs} as alternative") + String[] getTetherableWifiRegexs(); + + @UnsupportedAppUsage(maxTargetSdk = 28) + void reportInetCondition(int networkType, int percentage); + + void reportNetworkConnectivity(in Network network, boolean hasConnectivity); + + ProxyInfo getGlobalProxy(); + + void setGlobalProxy(in ProxyInfo p); + + ProxyInfo getProxyForNetwork(in Network nework); + + boolean prepareVpn(String oldPackage, String newPackage, int userId); + + void setVpnPackageAuthorization(String packageName, int userId, int vpnType); + + ParcelFileDescriptor establishVpn(in VpnConfig config); + + boolean provisionVpnProfile(in VpnProfile profile, String packageName); + + void deleteVpnProfile(String packageName); + + void startVpnProfile(String packageName); + + void stopVpnProfile(String packageName); + + VpnConfig getVpnConfig(int userId); + + @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553) + void startLegacyVpn(in VpnProfile profile); + + LegacyVpnInfo getLegacyVpnInfo(int userId); + + boolean updateLockdownVpn(); + boolean isAlwaysOnVpnPackageSupported(int userId, String packageName); + boolean setAlwaysOnVpnPackage(int userId, String packageName, boolean lockdown, + in List lockdownWhitelist); + String getAlwaysOnVpnPackage(int userId); + boolean isVpnLockdownEnabled(int userId); + List getVpnLockdownWhitelist(int userId); + void setRequireVpnForUids(boolean requireVpn, in UidRange[] ranges); + + void setProvisioningNotificationVisible(boolean visible, int networkType, in String action); + + void setAirplaneMode(boolean enable); + + boolean requestBandwidthUpdate(in Network network); + + int registerNetworkFactory(in Messenger messenger, in String name); + void unregisterNetworkFactory(in Messenger messenger); + + int registerNetworkProvider(in Messenger messenger, in String name); + void unregisterNetworkProvider(in Messenger messenger); + + void declareNetworkRequestUnfulfillable(in NetworkRequest request); + + Network registerNetworkAgent(in INetworkAgent na, in NetworkInfo ni, in LinkProperties lp, + in NetworkCapabilities nc, int score, in NetworkAgentConfig config, + in int factorySerialNumber); + + NetworkRequest requestNetwork(in NetworkCapabilities networkCapabilities, int reqType, + in Messenger messenger, int timeoutSec, in IBinder binder, int legacy, + String callingPackageName, String callingAttributionTag); + + NetworkRequest pendingRequestForNetwork(in NetworkCapabilities networkCapabilities, + in PendingIntent operation, String callingPackageName, String callingAttributionTag); + + void releasePendingNetworkRequest(in PendingIntent operation); + + NetworkRequest listenForNetwork(in NetworkCapabilities networkCapabilities, + in Messenger messenger, in IBinder binder, String callingPackageName); + + void pendingListenForNetwork(in NetworkCapabilities networkCapabilities, + in PendingIntent operation, String callingPackageName); + + void releaseNetworkRequest(in NetworkRequest networkRequest); + + void setAcceptUnvalidated(in Network network, boolean accept, boolean always); + void setAcceptPartialConnectivity(in Network network, boolean accept, boolean always); + void setAvoidUnvalidated(in Network network); + void startCaptivePortalApp(in Network network); + void startCaptivePortalAppInternal(in Network network, in Bundle appExtras); + + boolean shouldAvoidBadWifi(); + int getMultipathPreference(in Network Network); + + NetworkRequest getDefaultRequest(); + + int getRestoreDefaultNetworkDelay(int networkType); + + boolean addVpnAddress(String address, int prefixLength); + boolean removeVpnAddress(String address, int prefixLength); + boolean setUnderlyingNetworksForVpn(in Network[] networks); + + void factoryReset(); + + void startNattKeepalive(in Network network, int intervalSeconds, + in ISocketKeepaliveCallback cb, String srcAddr, int srcPort, String dstAddr); + + void startNattKeepaliveWithFd(in Network network, in ParcelFileDescriptor pfd, int resourceId, + int intervalSeconds, in ISocketKeepaliveCallback cb, String srcAddr, + String dstAddr); + + void startTcpKeepalive(in Network network, in ParcelFileDescriptor pfd, int intervalSeconds, + in ISocketKeepaliveCallback cb); + + void stopKeepalive(in Network network, int slot); + + String getCaptivePortalServerUrl(); + + byte[] getNetworkWatchlistConfigHash(); + + int getConnectionOwnerUid(in ConnectionInfo connectionInfo); + boolean isCallerCurrentAlwaysOnVpnApp(); + boolean isCallerCurrentAlwaysOnVpnLockdownApp(); + + void registerConnectivityDiagnosticsCallback(in IConnectivityDiagnosticsCallback callback, + in NetworkRequest request, String callingPackageName); + void unregisterConnectivityDiagnosticsCallback(in IConnectivityDiagnosticsCallback callback); + + IBinder startOrGetTestNetworkService(); + + void simulateDataStall(int detectionMethod, long timestampMillis, in Network network, + in PersistableBundle extras); + + void systemReady(); + + void registerNetworkActivityListener(in INetworkActivityListener l); + + void unregisterNetworkActivityListener(in INetworkActivityListener l); + + boolean isDefaultNetworkActive(); + + void registerQosSocketCallback(in QosSocketInfo socketInfo, in IQosCallback callback); + void unregisterQosCallback(in IQosCallback callback); +} diff --git a/packages/Connectivity/framework/src/android/net/ISocketKeepaliveCallback.aidl b/packages/Connectivity/framework/src/android/net/ISocketKeepaliveCallback.aidl new file mode 100644 index 000000000000..020fbcacbfef --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/ISocketKeepaliveCallback.aidl @@ -0,0 +1,34 @@ +/** + * Copyright (c) 2019, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +/** + * Callback to provide status changes of keepalive offload. + * + * @hide + */ +oneway interface ISocketKeepaliveCallback +{ + /** The keepalive was successfully started. */ + void onStarted(int slot); + /** The keepalive was successfully stopped. */ + void onStopped(); + /** The keepalive was stopped because of an error. */ + void onError(int error); + /** The keepalive on a TCP socket was stopped because the socket received data. */ + void onDataReceived(); +} diff --git a/packages/Connectivity/framework/src/android/net/ITestNetworkManager.aidl b/packages/Connectivity/framework/src/android/net/ITestNetworkManager.aidl new file mode 100644 index 000000000000..2a863adde581 --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/ITestNetworkManager.aidl @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2018, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.net.LinkAddress; +import android.net.LinkProperties; +import android.net.TestNetworkInterface; +import android.os.IBinder; +import android.os.ParcelFileDescriptor; + +/** + * Interface that allows for creation and management of test-only networks. + * + * @hide + */ +interface ITestNetworkManager +{ + TestNetworkInterface createTunInterface(in LinkAddress[] linkAddrs); + TestNetworkInterface createTapInterface(); + + void setupTestNetwork(in String iface, in LinkProperties lp, in boolean isMetered, + in int[] administratorUids, in IBinder binder); + + void teardownTestNetwork(int netId); +} diff --git a/packages/Connectivity/framework/src/android/net/InetAddresses.java b/packages/Connectivity/framework/src/android/net/InetAddresses.java new file mode 100644 index 000000000000..01b795e456fa --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/InetAddresses.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.annotation.NonNull; + +import libcore.net.InetAddressUtils; + +import java.net.InetAddress; + +/** + * Utility methods for {@link InetAddress} implementations. + */ +public class InetAddresses { + + private InetAddresses() {} + + /** + * Checks to see if the {@code address} is a numeric address (such as {@code "192.0.2.1"} or + * {@code "2001:db8::1:2"}). + * + *

A numeric address is either an IPv4 address containing exactly 4 decimal numbers or an + * IPv6 numeric address. IPv4 addresses that consist of either hexadecimal or octal digits or + * do not have exactly 4 numbers are not treated as numeric. + * + *

This method will never do a DNS lookup. + * + * @param address the address to parse. + * @return true if the supplied address is numeric, false otherwise. + */ + public static boolean isNumericAddress(@NonNull String address) { + return InetAddressUtils.isNumericAddress(address); + } + + /** + * Returns an InetAddress corresponding to the given numeric address (such + * as {@code "192.168.0.1"} or {@code "2001:4860:800d::68"}). + * + *

See {@link #isNumericAddress(String)} (String)} for a definition as to what constitutes a + * numeric address. + * + *

This method will never do a DNS lookup. + * + * @param address the address to parse, must be numeric. + * @return an {@link InetAddress} instance corresponding to the address. + * @throws IllegalArgumentException if {@code address} is not a numeric address. + */ + public static @NonNull InetAddress parseNumericAddress(@NonNull String address) { + return InetAddressUtils.parseNumericAddress(address); + } +} diff --git a/packages/Connectivity/framework/src/android/net/InterfaceConfiguration.aidl b/packages/Connectivity/framework/src/android/net/InterfaceConfiguration.aidl new file mode 100644 index 000000000000..8aa5e3452853 --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/InterfaceConfiguration.aidl @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2008, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +parcelable InterfaceConfiguration; diff --git a/packages/Connectivity/framework/src/android/net/InvalidPacketException.java b/packages/Connectivity/framework/src/android/net/InvalidPacketException.java new file mode 100644 index 000000000000..1873d778c0f2 --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/InvalidPacketException.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.annotation.IntDef; +import android.annotation.SystemApi; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Thrown when a packet is invalid. + * @hide + */ +@SystemApi +public final class InvalidPacketException extends Exception { + private final int mError; + + // Must match SocketKeepalive#ERROR_INVALID_IP_ADDRESS. + /** Invalid IP address. */ + public static final int ERROR_INVALID_IP_ADDRESS = -21; + + // Must match SocketKeepalive#ERROR_INVALID_PORT. + /** Invalid port number. */ + public static final int ERROR_INVALID_PORT = -22; + + // Must match SocketKeepalive#ERROR_INVALID_LENGTH. + /** Invalid packet length. */ + public static final int ERROR_INVALID_LENGTH = -23; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = { "ERROR_" }, value = { + ERROR_INVALID_IP_ADDRESS, + ERROR_INVALID_PORT, + ERROR_INVALID_LENGTH + }) + public @interface ErrorCode {} + + /** + * This packet is invalid. + * See the error code for details. + */ + public InvalidPacketException(@ErrorCode final int error) { + this.mError = error; + } + + /** Get error code. */ + public int getError() { + return mError; + } +} diff --git a/packages/Connectivity/framework/src/android/net/IpConfiguration.aidl b/packages/Connectivity/framework/src/android/net/IpConfiguration.aidl new file mode 100644 index 000000000000..7a30f0e79cad --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/IpConfiguration.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +parcelable IpConfiguration; diff --git a/packages/Connectivity/framework/src/android/net/IpConfiguration.java b/packages/Connectivity/framework/src/android/net/IpConfiguration.java new file mode 100644 index 000000000000..0b205642b321 --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/IpConfiguration.java @@ -0,0 +1,223 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SuppressLint; +import android.annotation.SystemApi; +import android.compat.annotation.UnsupportedAppUsage; +import android.os.Build; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.Objects; + +/** + * A class representing a configured network. + * @hide + */ +@SystemApi +public final class IpConfiguration implements Parcelable { + private static final String TAG = "IpConfiguration"; + + // This enum has been used by apps through reflection for many releases. + // Therefore they can't just be removed. Duplicating these constants to + // give an alternate SystemApi is a worse option than exposing them. + @SuppressLint("Enum") + public enum IpAssignment { + /* Use statically configured IP settings. Configuration can be accessed + * with staticIpConfiguration */ + STATIC, + /* Use dynamically configured IP settings */ + DHCP, + /* no IP details are assigned, this is used to indicate + * that any existing IP settings should be retained */ + UNASSIGNED + } + + /** @hide */ + public IpAssignment ipAssignment; + + /** @hide */ + public StaticIpConfiguration staticIpConfiguration; + + // This enum has been used by apps through reflection for many releases. + // Therefore they can't just be removed. Duplicating these constants to + // give an alternate SystemApi is a worse option than exposing them. + @SuppressLint("Enum") + public enum ProxySettings { + /* No proxy is to be used. Any existing proxy settings + * should be cleared. */ + NONE, + /* Use statically configured proxy. Configuration can be accessed + * with httpProxy. */ + STATIC, + /* no proxy details are assigned, this is used to indicate + * that any existing proxy settings should be retained */ + UNASSIGNED, + /* Use a Pac based proxy. + */ + PAC + } + + /** @hide */ + public ProxySettings proxySettings; + + /** @hide */ + @UnsupportedAppUsage + public ProxyInfo httpProxy; + + private void init(IpAssignment ipAssignment, + ProxySettings proxySettings, + StaticIpConfiguration staticIpConfiguration, + ProxyInfo httpProxy) { + this.ipAssignment = ipAssignment; + this.proxySettings = proxySettings; + this.staticIpConfiguration = (staticIpConfiguration == null) ? + null : new StaticIpConfiguration(staticIpConfiguration); + this.httpProxy = (httpProxy == null) ? + null : new ProxyInfo(httpProxy); + } + + public IpConfiguration() { + init(IpAssignment.UNASSIGNED, ProxySettings.UNASSIGNED, null, null); + } + + /** @hide */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + public IpConfiguration(IpAssignment ipAssignment, + ProxySettings proxySettings, + StaticIpConfiguration staticIpConfiguration, + ProxyInfo httpProxy) { + init(ipAssignment, proxySettings, staticIpConfiguration, httpProxy); + } + + public IpConfiguration(@NonNull IpConfiguration source) { + this(); + if (source != null) { + init(source.ipAssignment, source.proxySettings, + source.staticIpConfiguration, source.httpProxy); + } + } + + public @NonNull IpAssignment getIpAssignment() { + return ipAssignment; + } + + public void setIpAssignment(@NonNull IpAssignment ipAssignment) { + this.ipAssignment = ipAssignment; + } + + public @Nullable StaticIpConfiguration getStaticIpConfiguration() { + return staticIpConfiguration; + } + + public void setStaticIpConfiguration(@Nullable StaticIpConfiguration staticIpConfiguration) { + this.staticIpConfiguration = staticIpConfiguration; + } + + public @NonNull ProxySettings getProxySettings() { + return proxySettings; + } + + public void setProxySettings(@NonNull ProxySettings proxySettings) { + this.proxySettings = proxySettings; + } + + public @Nullable ProxyInfo getHttpProxy() { + return httpProxy; + } + + public void setHttpProxy(@Nullable ProxyInfo httpProxy) { + this.httpProxy = httpProxy; + } + + @Override + public String toString() { + StringBuilder sbuf = new StringBuilder(); + sbuf.append("IP assignment: " + ipAssignment.toString()); + sbuf.append("\n"); + if (staticIpConfiguration != null) { + sbuf.append("Static configuration: " + staticIpConfiguration.toString()); + sbuf.append("\n"); + } + sbuf.append("Proxy settings: " + proxySettings.toString()); + sbuf.append("\n"); + if (httpProxy != null) { + sbuf.append("HTTP proxy: " + httpProxy.toString()); + sbuf.append("\n"); + } + + return sbuf.toString(); + } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + + if (!(o instanceof IpConfiguration)) { + return false; + } + + IpConfiguration other = (IpConfiguration) o; + return this.ipAssignment == other.ipAssignment && + this.proxySettings == other.proxySettings && + Objects.equals(this.staticIpConfiguration, other.staticIpConfiguration) && + Objects.equals(this.httpProxy, other.httpProxy); + } + + @Override + public int hashCode() { + return 13 + (staticIpConfiguration != null ? staticIpConfiguration.hashCode() : 0) + + 17 * ipAssignment.ordinal() + + 47 * proxySettings.ordinal() + + 83 * httpProxy.hashCode(); + } + + /** Implement the Parcelable interface */ + public int describeContents() { + return 0; + } + + /** Implement the Parcelable interface */ + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeString(ipAssignment.name()); + dest.writeString(proxySettings.name()); + dest.writeParcelable(staticIpConfiguration, flags); + dest.writeParcelable(httpProxy, flags); + } + + /** Implement the Parcelable interface */ + public static final @NonNull Creator CREATOR = + new Creator() { + public IpConfiguration createFromParcel(Parcel in) { + IpConfiguration config = new IpConfiguration(); + config.ipAssignment = IpAssignment.valueOf(in.readString()); + config.proxySettings = ProxySettings.valueOf(in.readString()); + config.staticIpConfiguration = in.readParcelable(null); + config.httpProxy = in.readParcelable(null); + return config; + } + + public IpConfiguration[] newArray(int size) { + return new IpConfiguration[size]; + } + }; +} diff --git a/packages/Connectivity/framework/src/android/net/IpPrefix.aidl b/packages/Connectivity/framework/src/android/net/IpPrefix.aidl new file mode 100644 index 000000000000..0d70f2a1ed2c --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/IpPrefix.aidl @@ -0,0 +1,22 @@ +/** + * + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +// @JavaOnlyStableParcelable only affects the parcelable when built as stable aidl (aidl_interface +// build rule). IpPrefix is also used in cpp but only as non-stable aidl. +@JavaOnlyStableParcelable parcelable IpPrefix cpp_header "binder/IpPrefix.h"; diff --git a/packages/Connectivity/framework/src/android/net/IpPrefix.java b/packages/Connectivity/framework/src/android/net/IpPrefix.java new file mode 100644 index 000000000000..e7c801475c4d --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/IpPrefix.java @@ -0,0 +1,300 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.annotation.IntRange; +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.os.Parcel; +import android.os.Parcelable; +import android.util.Pair; + +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Arrays; +import java.util.Comparator; + +/** + * This class represents an IP prefix, i.e., a contiguous block of IP addresses aligned on a + * power of two boundary (also known as an "IP subnet"). A prefix is specified by two pieces of + * information: + * + *

    + *
  • A starting IP address (IPv4 or IPv6). This is the first IP address of the prefix. + *
  • A prefix length. This specifies the length of the prefix by specifing the number of bits + * in the IP address, starting from the most significant bit in network byte order, that + * are constant for all addresses in the prefix. + *
+ * + * For example, the prefix 192.0.2.0/24 covers the 256 IPv4 addresses from + * 192.0.2.0 to 192.0.2.255, inclusive, and the prefix + * 2001:db8:1:2 covers the 2^64 IPv6 addresses from 2001:db8:1:2:: to + * 2001:db8:1:2:ffff:ffff:ffff:ffff, inclusive. + * + * Objects of this class are immutable. + */ +public final class IpPrefix implements Parcelable { + private final byte[] address; // network byte order + private final int prefixLength; + + private void checkAndMaskAddressAndPrefixLength() { + if (address.length != 4 && address.length != 16) { + throw new IllegalArgumentException( + "IpPrefix has " + address.length + " bytes which is neither 4 nor 16"); + } + NetworkUtils.maskRawAddress(address, prefixLength); + } + + /** + * Constructs a new {@code IpPrefix} from a byte array containing an IPv4 or IPv6 address in + * network byte order and a prefix length. Silently truncates the address to the prefix length, + * so for example {@code 192.0.2.1/24} is silently converted to {@code 192.0.2.0/24}. + * + * @param address the IP address. Must be non-null and exactly 4 or 16 bytes long. + * @param prefixLength the prefix length. Must be >= 0 and <= (32 or 128) (IPv4 or IPv6). + * + * @hide + */ + public IpPrefix(@NonNull byte[] address, @IntRange(from = 0, to = 128) int prefixLength) { + this.address = address.clone(); + this.prefixLength = prefixLength; + checkAndMaskAddressAndPrefixLength(); + } + + /** + * Constructs a new {@code IpPrefix} from an IPv4 or IPv6 address and a prefix length. Silently + * truncates the address to the prefix length, so for example {@code 192.0.2.1/24} is silently + * converted to {@code 192.0.2.0/24}. + * + * @param address the IP address. Must be non-null. + * @param prefixLength the prefix length. Must be >= 0 and <= (32 or 128) (IPv4 or IPv6). + * @hide + */ + @SystemApi + public IpPrefix(@NonNull InetAddress address, @IntRange(from = 0, to = 128) int prefixLength) { + // We don't reuse the (byte[], int) constructor because it calls clone() on the byte array, + // which is unnecessary because getAddress() already returns a clone. + this.address = address.getAddress(); + this.prefixLength = prefixLength; + checkAndMaskAddressAndPrefixLength(); + } + + /** + * Constructs a new IpPrefix from a string such as "192.0.2.1/24" or "2001:db8::1/64". + * Silently truncates the address to the prefix length, so for example {@code 192.0.2.1/24} + * is silently converted to {@code 192.0.2.0/24}. + * + * @param prefix the prefix to parse + * + * @hide + */ + @SystemApi + public IpPrefix(@NonNull String prefix) { + // We don't reuse the (InetAddress, int) constructor because "error: call to this must be + // first statement in constructor". We could factor out setting the member variables to an + // init() method, but if we did, then we'd have to make the members non-final, or "error: + // cannot assign a value to final variable address". So we just duplicate the code here. + Pair ipAndMask = NetworkUtils.parseIpAndMask(prefix); + this.address = ipAndMask.first.getAddress(); + this.prefixLength = ipAndMask.second; + checkAndMaskAddressAndPrefixLength(); + } + + /** + * Compares this {@code IpPrefix} object against the specified object in {@code obj}. Two + * objects are equal if they have the same startAddress and prefixLength. + * + * @param obj the object to be tested for equality. + * @return {@code true} if both objects are equal, {@code false} otherwise. + */ + @Override + public boolean equals(Object obj) { + if (!(obj instanceof IpPrefix)) { + return false; + } + IpPrefix that = (IpPrefix) obj; + return Arrays.equals(this.address, that.address) && this.prefixLength == that.prefixLength; + } + + /** + * Gets the hashcode of the represented IP prefix. + * + * @return the appropriate hashcode value. + */ + @Override + public int hashCode() { + return Arrays.hashCode(address) + 11 * prefixLength; + } + + /** + * Returns a copy of the first IP address in the prefix. Modifying the returned object does not + * change this object's contents. + * + * @return the address in the form of a byte array. + */ + public @NonNull InetAddress getAddress() { + try { + return InetAddress.getByAddress(address); + } catch (UnknownHostException e) { + // Cannot happen. InetAddress.getByAddress can only throw an exception if the byte + // array is the wrong length, but we check that in the constructor. + throw new IllegalArgumentException("Address is invalid"); + } + } + + /** + * Returns a copy of the IP address bytes in network order (the highest order byte is the zeroth + * element). Modifying the returned array does not change this object's contents. + * + * @return the address in the form of a byte array. + */ + public @NonNull byte[] getRawAddress() { + return address.clone(); + } + + /** + * Returns the prefix length of this {@code IpPrefix}. + * + * @return the prefix length. + */ + @IntRange(from = 0, to = 128) + public int getPrefixLength() { + return prefixLength; + } + + /** + * Determines whether the prefix contains the specified address. + * + * @param address An {@link InetAddress} to test. + * @return {@code true} if the prefix covers the given address. {@code false} otherwise. + */ + public boolean contains(@NonNull InetAddress address) { + byte[] addrBytes = address.getAddress(); + if (addrBytes == null || addrBytes.length != this.address.length) { + return false; + } + NetworkUtils.maskRawAddress(addrBytes, prefixLength); + return Arrays.equals(this.address, addrBytes); + } + + /** + * Returns whether the specified prefix is entirely contained in this prefix. + * + * Note this is mathematical inclusion, so a prefix is always contained within itself. + * @param otherPrefix the prefix to test + * @hide + */ + public boolean containsPrefix(@NonNull IpPrefix otherPrefix) { + if (otherPrefix.getPrefixLength() < prefixLength) return false; + final byte[] otherAddress = otherPrefix.getRawAddress(); + NetworkUtils.maskRawAddress(otherAddress, prefixLength); + return Arrays.equals(otherAddress, address); + } + + /** + * @hide + */ + public boolean isIPv6() { + return getAddress() instanceof Inet6Address; + } + + /** + * @hide + */ + public boolean isIPv4() { + return getAddress() instanceof Inet4Address; + } + + /** + * Returns a string representation of this {@code IpPrefix}. + * + * @return a string such as {@code "192.0.2.0/24"} or {@code "2001:db8:1:2::/64"}. + */ + public String toString() { + try { + return InetAddress.getByAddress(address).getHostAddress() + "/" + prefixLength; + } catch(UnknownHostException e) { + // Cosmic rays? + throw new IllegalStateException("IpPrefix with invalid address! Shouldn't happen.", e); + } + } + + /** + * Implement the Parcelable interface. + */ + public int describeContents() { + return 0; + } + + /** + * Implement the Parcelable interface. + */ + public void writeToParcel(Parcel dest, int flags) { + dest.writeByteArray(address); + dest.writeInt(prefixLength); + } + + /** + * Returns a comparator ordering IpPrefixes by length, shorter to longer. + * Contents of the address will break ties. + * @hide + */ + public static Comparator lengthComparator() { + return new Comparator() { + @Override + public int compare(IpPrefix prefix1, IpPrefix prefix2) { + if (prefix1.isIPv4()) { + if (prefix2.isIPv6()) return -1; + } else { + if (prefix2.isIPv4()) return 1; + } + final int p1len = prefix1.getPrefixLength(); + final int p2len = prefix2.getPrefixLength(); + if (p1len < p2len) return -1; + if (p2len < p1len) return 1; + final byte[] a1 = prefix1.address; + final byte[] a2 = prefix2.address; + final int len = a1.length < a2.length ? a1.length : a2.length; + for (int i = 0; i < len; ++i) { + if (a1[i] < a2[i]) return -1; + if (a1[i] > a2[i]) return 1; + } + if (a2.length < len) return 1; + if (a1.length < len) return -1; + return 0; + } + }; + } + + /** + * Implement the Parcelable interface. + */ + public static final @android.annotation.NonNull Creator CREATOR = + new Creator() { + public IpPrefix createFromParcel(Parcel in) { + byte[] address = in.createByteArray(); + int prefixLength = in.readInt(); + return new IpPrefix(address, prefixLength); + } + + public IpPrefix[] newArray(int size) { + return new IpPrefix[size]; + } + }; +} diff --git a/packages/Connectivity/framework/src/android/net/KeepalivePacketData.aidl b/packages/Connectivity/framework/src/android/net/KeepalivePacketData.aidl new file mode 100644 index 000000000000..d456b53fd188 --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/KeepalivePacketData.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +parcelable KeepalivePacketData; diff --git a/packages/Connectivity/framework/src/android/net/KeepalivePacketData.java b/packages/Connectivity/framework/src/android/net/KeepalivePacketData.java new file mode 100644 index 000000000000..5877f1f4e269 --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/KeepalivePacketData.java @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import static android.net.InvalidPacketException.ERROR_INVALID_IP_ADDRESS; +import static android.net.InvalidPacketException.ERROR_INVALID_PORT; + +import android.annotation.IntRange; +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.util.Log; + +import com.android.net.module.util.IpUtils; + +import java.net.InetAddress; + +/** + * Represents the actual packets that are sent by the + * {@link android.net.SocketKeepalive} API. + * @hide + */ +@SystemApi +public class KeepalivePacketData { + private static final String TAG = "KeepalivePacketData"; + + /** Source IP address */ + @NonNull + private final InetAddress mSrcAddress; + + /** Destination IP address */ + @NonNull + private final InetAddress mDstAddress; + + /** Source port */ + private final int mSrcPort; + + /** Destination port */ + private final int mDstPort; + + /** Packet data. A raw byte string of packet data, not including the link-layer header. */ + private final byte[] mPacket; + + // Note: If you add new fields, please modify the parcelling code in the child classes. + + + // This should only be constructed via static factory methods, such as + // nattKeepalivePacket. + /** + * A holding class for data necessary to build a keepalive packet. + */ + protected KeepalivePacketData(@NonNull InetAddress srcAddress, + @IntRange(from = 0, to = 65535) int srcPort, @NonNull InetAddress dstAddress, + @IntRange(from = 0, to = 65535) int dstPort, + @NonNull byte[] data) throws InvalidPacketException { + this.mSrcAddress = srcAddress; + this.mDstAddress = dstAddress; + this.mSrcPort = srcPort; + this.mDstPort = dstPort; + this.mPacket = data; + + // Check we have two IP addresses of the same family. + if (srcAddress == null || dstAddress == null || !srcAddress.getClass().getName() + .equals(dstAddress.getClass().getName())) { + Log.e(TAG, "Invalid or mismatched InetAddresses in KeepalivePacketData"); + throw new InvalidPacketException(ERROR_INVALID_IP_ADDRESS); + } + + // Check the ports. + if (!IpUtils.isValidUdpOrTcpPort(srcPort) || !IpUtils.isValidUdpOrTcpPort(dstPort)) { + Log.e(TAG, "Invalid ports in KeepalivePacketData"); + throw new InvalidPacketException(ERROR_INVALID_PORT); + } + } + + /** Get source IP address. */ + @NonNull + public InetAddress getSrcAddress() { + return mSrcAddress; + } + + /** Get destination IP address. */ + @NonNull + public InetAddress getDstAddress() { + return mDstAddress; + } + + /** Get source port number. */ + public int getSrcPort() { + return mSrcPort; + } + + /** Get destination port number. */ + public int getDstPort() { + return mDstPort; + } + + /** + * Returns a byte array of the given packet data. + */ + @NonNull + public byte[] getPacket() { + return mPacket.clone(); + } + +} diff --git a/packages/Connectivity/framework/src/android/net/LinkAddress.aidl b/packages/Connectivity/framework/src/android/net/LinkAddress.aidl new file mode 100644 index 000000000000..9c804db08d61 --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/LinkAddress.aidl @@ -0,0 +1,21 @@ +/** + * + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +@JavaOnlyStableParcelable parcelable LinkAddress; + diff --git a/packages/Connectivity/framework/src/android/net/LinkAddress.java b/packages/Connectivity/framework/src/android/net/LinkAddress.java new file mode 100644 index 000000000000..44d25a1ab0af --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/LinkAddress.java @@ -0,0 +1,549 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import static android.system.OsConstants.IFA_F_DADFAILED; +import static android.system.OsConstants.IFA_F_DEPRECATED; +import static android.system.OsConstants.IFA_F_OPTIMISTIC; +import static android.system.OsConstants.IFA_F_PERMANENT; +import static android.system.OsConstants.IFA_F_TENTATIVE; +import static android.system.OsConstants.RT_SCOPE_HOST; +import static android.system.OsConstants.RT_SCOPE_LINK; +import static android.system.OsConstants.RT_SCOPE_SITE; +import static android.system.OsConstants.RT_SCOPE_UNIVERSE; + +import android.annotation.IntRange; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.compat.annotation.UnsupportedAppUsage; +import android.os.Build; +import android.os.Parcel; +import android.os.Parcelable; +import android.os.SystemClock; +import android.util.Pair; + +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.InterfaceAddress; +import java.net.UnknownHostException; +import java.util.Objects; + +/** + * Identifies an IP address on a network link. + * + * A {@code LinkAddress} consists of: + *
    + *
  • An IP address and prefix length (e.g., {@code 2001:db8::1/64} or {@code 192.0.2.1/24}). + * The address must be unicast, as multicast addresses cannot be assigned to interfaces. + *
  • Address flags: A bitmask of {@code OsConstants.IFA_F_*} values representing properties + * of the address (e.g., {@code android.system.OsConstants.IFA_F_OPTIMISTIC}). + *
  • Address scope: One of the {@code OsConstants.IFA_F_*} values; defines the scope in which + * the address is unique (e.g., + * {@code android.system.OsConstants.RT_SCOPE_LINK} or + * {@code android.system.OsConstants.RT_SCOPE_UNIVERSE}). + *
+ */ +public class LinkAddress implements Parcelable { + + /** + * Indicates the deprecation or expiration time is unknown + * @hide + */ + @SystemApi + public static final long LIFETIME_UNKNOWN = -1; + + /** + * Indicates this address is permanent. + * @hide + */ + @SystemApi + public static final long LIFETIME_PERMANENT = Long.MAX_VALUE; + + /** + * IPv4 or IPv6 address. + */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) + private InetAddress address; + + /** + * Prefix length. + */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) + private int prefixLength; + + /** + * Address flags. A bitmask of {@code IFA_F_*} values. Note that {@link #getFlags()} may not + * return these exact values. For example, it may set or clear the {@code IFA_F_DEPRECATED} + * flag depending on the current preferred lifetime. + */ + private int flags; + + /** + * Address scope. One of the RT_SCOPE_* constants. + */ + private int scope; + + /** + * The time, as reported by {@link SystemClock#elapsedRealtime}, when this LinkAddress will be + * or was deprecated. At the time existing connections can still use this address until it + * expires, but new connections should use the new address. {@link #LIFETIME_UNKNOWN} indicates + * this information is not available. {@link #LIFETIME_PERMANENT} indicates this + * {@link LinkAddress} will never be deprecated. + */ + private long deprecationTime; + + /** + * The time, as reported by {@link SystemClock#elapsedRealtime}, when this {@link LinkAddress} + * will expire and be removed from the interface. {@link #LIFETIME_UNKNOWN} indicates this + * information is not available. {@link #LIFETIME_PERMANENT} indicates this {@link LinkAddress} + * will never expire. + */ + private long expirationTime; + + /** + * Utility function to determines the scope of a unicast address. Per RFC 4291 section 2.5 and + * RFC 6724 section 3.2. + * @hide + */ + private static int scopeForUnicastAddress(InetAddress addr) { + if (addr.isAnyLocalAddress()) { + return RT_SCOPE_HOST; + } + + if (addr.isLoopbackAddress() || addr.isLinkLocalAddress()) { + return RT_SCOPE_LINK; + } + + // isSiteLocalAddress() returns true for private IPv4 addresses, but RFC 6724 section 3.2 + // says that they are assigned global scope. + if (!(addr instanceof Inet4Address) && addr.isSiteLocalAddress()) { + return RT_SCOPE_SITE; + } + + return RT_SCOPE_UNIVERSE; + } + + /** + * Utility function to check if |address| is a Unique Local IPv6 Unicast Address + * (a.k.a. "ULA"; RFC 4193). + * + * Per RFC 4193 section 8, fc00::/7 identifies these addresses. + */ + private boolean isIpv6ULA() { + if (isIpv6()) { + byte[] bytes = address.getAddress(); + return ((bytes[0] & (byte)0xfe) == (byte)0xfc); + } + return false; + } + + /** + * @return true if the address is IPv6. + * @hide + */ + @SystemApi + public boolean isIpv6() { + return address instanceof Inet6Address; + } + + /** + * For backward compatibility. + * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely + * just yet. + * @return true if the address is IPv6. + * @hide + */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) + public boolean isIPv6() { + return isIpv6(); + } + + /** + * @return true if the address is IPv4 or is a mapped IPv4 address. + * @hide + */ + @SystemApi + public boolean isIpv4() { + return address instanceof Inet4Address; + } + + /** + * Utility function for the constructors. + */ + private void init(InetAddress address, int prefixLength, int flags, int scope, + long deprecationTime, long expirationTime) { + if (address == null || + address.isMulticastAddress() || + prefixLength < 0 || + (address instanceof Inet4Address && prefixLength > 32) || + (prefixLength > 128)) { + throw new IllegalArgumentException("Bad LinkAddress params " + address + + "/" + prefixLength); + } + + // deprecation time and expiration time must be both provided, or neither. + if ((deprecationTime == LIFETIME_UNKNOWN) != (expirationTime == LIFETIME_UNKNOWN)) { + throw new IllegalArgumentException( + "Must not specify only one of deprecation time and expiration time"); + } + + // deprecation time needs to be a positive value. + if (deprecationTime != LIFETIME_UNKNOWN && deprecationTime < 0) { + throw new IllegalArgumentException("invalid deprecation time " + deprecationTime); + } + + // expiration time needs to be a positive value. + if (expirationTime != LIFETIME_UNKNOWN && expirationTime < 0) { + throw new IllegalArgumentException("invalid expiration time " + expirationTime); + } + + // expiration time can't be earlier than deprecation time + if (deprecationTime != LIFETIME_UNKNOWN && expirationTime != LIFETIME_UNKNOWN + && expirationTime < deprecationTime) { + throw new IllegalArgumentException("expiration earlier than deprecation (" + + deprecationTime + ", " + expirationTime + ")"); + } + + this.address = address; + this.prefixLength = prefixLength; + this.flags = flags; + this.scope = scope; + this.deprecationTime = deprecationTime; + this.expirationTime = expirationTime; + } + + /** + * Constructs a new {@code LinkAddress} from an {@code InetAddress} and prefix length, with + * the specified flags and scope. Flags and scope are not checked for validity. + * + * @param address The IP address. + * @param prefixLength The prefix length. Must be >= 0 and <= (32 or 128) (IPv4 or IPv6). + * @param flags A bitmask of {@code IFA_F_*} values representing properties of the address. + * @param scope An integer defining the scope in which the address is unique (e.g., + * {@link OsConstants#RT_SCOPE_LINK} or {@link OsConstants#RT_SCOPE_SITE}). + * @hide + */ + @SystemApi + public LinkAddress(@NonNull InetAddress address, @IntRange(from = 0, to = 128) int prefixLength, + int flags, int scope) { + init(address, prefixLength, flags, scope, LIFETIME_UNKNOWN, LIFETIME_UNKNOWN); + } + + /** + * Constructs a new {@code LinkAddress} from an {@code InetAddress}, prefix length, with + * the specified flags, scope, deprecation time, and expiration time. Flags and scope are not + * checked for validity. The value of the {@code IFA_F_DEPRECATED} and {@code IFA_F_PERMANENT} + * flag will be adjusted based on the passed-in lifetimes. + * + * @param address The IP address. + * @param prefixLength The prefix length. Must be >= 0 and <= (32 or 128) (IPv4 or IPv6). + * @param flags A bitmask of {@code IFA_F_*} values representing properties of the address. + * @param scope An integer defining the scope in which the address is unique (e.g., + * {@link OsConstants#RT_SCOPE_LINK} or {@link OsConstants#RT_SCOPE_SITE}). + * @param deprecationTime The time, as reported by {@link SystemClock#elapsedRealtime}, when + * this {@link LinkAddress} will be or was deprecated. At the time + * existing connections can still use this address until it expires, but + * new connections should use the new address. {@link #LIFETIME_UNKNOWN} + * indicates this information is not available. + * {@link #LIFETIME_PERMANENT} indicates this {@link LinkAddress} will + * never be deprecated. + * @param expirationTime The time, as reported by {@link SystemClock#elapsedRealtime}, when this + * {@link LinkAddress} will expire and be removed from the interface. + * {@link #LIFETIME_UNKNOWN} indicates this information is not available. + * {@link #LIFETIME_PERMANENT} indicates this {@link LinkAddress} will + * never expire. + * @hide + */ + @SystemApi + public LinkAddress(@NonNull InetAddress address, @IntRange(from = 0, to = 128) int prefixLength, + int flags, int scope, long deprecationTime, long expirationTime) { + init(address, prefixLength, flags, scope, deprecationTime, expirationTime); + } + + /** + * Constructs a new {@code LinkAddress} from an {@code InetAddress} and a prefix length. + * The flags are set to zero and the scope is determined from the address. + * @param address The IP address. + * @param prefixLength The prefix length. Must be >= 0 and <= (32 or 128) (IPv4 or IPv6). + * @hide + */ + @SystemApi + public LinkAddress(@NonNull InetAddress address, + @IntRange(from = 0, to = 128) int prefixLength) { + this(address, prefixLength, 0, 0); + this.scope = scopeForUnicastAddress(address); + } + + /** + * Constructs a new {@code LinkAddress} from an {@code InterfaceAddress}. + * The flags are set to zero and the scope is determined from the address. + * @param interfaceAddress The interface address. + * @hide + */ + public LinkAddress(@NonNull InterfaceAddress interfaceAddress) { + this(interfaceAddress.getAddress(), + interfaceAddress.getNetworkPrefixLength()); + } + + /** + * Constructs a new {@code LinkAddress} from a string such as "192.0.2.5/24" or + * "2001:db8::1/64". The flags are set to zero and the scope is determined from the address. + * @param address The string to parse. + * @hide + */ + @SystemApi + public LinkAddress(@NonNull String address) { + this(address, 0, 0); + this.scope = scopeForUnicastAddress(this.address); + } + + /** + * Constructs a new {@code LinkAddress} from a string such as "192.0.2.5/24" or + * "2001:db8::1/64", with the specified flags and scope. + * @param address The string to parse. + * @param flags The address flags. + * @param scope The address scope. + * @hide + */ + @SystemApi + public LinkAddress(@NonNull String address, int flags, int scope) { + // This may throw an IllegalArgumentException; catching it is the caller's responsibility. + // TODO: consider rejecting mapped IPv4 addresses such as "::ffff:192.0.2.5/24". + Pair ipAndMask = NetworkUtils.parseIpAndMask(address); + init(ipAndMask.first, ipAndMask.second, flags, scope, LIFETIME_UNKNOWN, LIFETIME_UNKNOWN); + } + + /** + * Returns a string representation of this address, such as "192.0.2.1/24" or "2001:db8::1/64". + * The string representation does not contain the flags and scope, just the address and prefix + * length. + */ + @Override + public String toString() { + return address.getHostAddress() + "/" + prefixLength; + } + + /** + * Compares this {@code LinkAddress} instance against {@code obj}. Two addresses are equal if + * their address, prefix length, flags and scope are equal. Thus, for example, two addresses + * that have the same address and prefix length are not equal if one of them is deprecated and + * the other is not. + * + * @param obj the object to be tested for equality. + * @return {@code true} if both objects are equal, {@code false} otherwise. + */ + @Override + public boolean equals(Object obj) { + if (!(obj instanceof LinkAddress)) { + return false; + } + LinkAddress linkAddress = (LinkAddress) obj; + return this.address.equals(linkAddress.address) + && this.prefixLength == linkAddress.prefixLength + && this.flags == linkAddress.flags + && this.scope == linkAddress.scope + && this.deprecationTime == linkAddress.deprecationTime + && this.expirationTime == linkAddress.expirationTime; + } + + /** + * Returns a hashcode for this address. + */ + @Override + public int hashCode() { + return Objects.hash(address, prefixLength, flags, scope, deprecationTime, expirationTime); + } + + /** + * Determines whether this {@code LinkAddress} and the provided {@code LinkAddress} + * represent the same address. Two {@code LinkAddresses} represent the same address + * if they have the same IP address and prefix length, even if their properties are + * different. + * + * @param other the {@code LinkAddress} to compare to. + * @return {@code true} if both objects have the same address and prefix length, {@code false} + * otherwise. + * @hide + */ + @SystemApi + public boolean isSameAddressAs(@Nullable LinkAddress other) { + if (other == null) { + return false; + } + return address.equals(other.address) && prefixLength == other.prefixLength; + } + + /** + * Returns the {@link InetAddress} of this {@code LinkAddress}. + */ + public InetAddress getAddress() { + return address; + } + + /** + * Returns the prefix length of this {@code LinkAddress}. + */ + @IntRange(from = 0, to = 128) + public int getPrefixLength() { + return prefixLength; + } + + /** + * Returns the prefix length of this {@code LinkAddress}. + * TODO: Delete all callers and remove in favour of getPrefixLength(). + * @hide + */ + @UnsupportedAppUsage + @IntRange(from = 0, to = 128) + public int getNetworkPrefixLength() { + return getPrefixLength(); + } + + /** + * Returns the flags of this {@code LinkAddress}. + */ + public int getFlags() { + int flags = this.flags; + if (deprecationTime != LIFETIME_UNKNOWN) { + if (SystemClock.elapsedRealtime() >= deprecationTime) { + flags |= IFA_F_DEPRECATED; + } else { + // If deprecation time is in the future, or permanent. + flags &= ~IFA_F_DEPRECATED; + } + } + + if (expirationTime == LIFETIME_PERMANENT) { + flags |= IFA_F_PERMANENT; + } else if (expirationTime != LIFETIME_UNKNOWN) { + // If we know this address expired or will expire in the future, then this address + // should not be permanent. + flags &= ~IFA_F_PERMANENT; + } + + // Do no touch the original flags. Return the adjusted flags here. + return flags; + } + + /** + * Returns the scope of this {@code LinkAddress}. + */ + public int getScope() { + return scope; + } + + /** + * Get the deprecation time, as reported by {@link SystemClock#elapsedRealtime}, when this + * {@link LinkAddress} will be or was deprecated. At the time existing connections can still use + * this address until it expires, but new connections should use the new address. + * + * @return The deprecation time in milliseconds. {@link #LIFETIME_UNKNOWN} indicates this + * information is not available. {@link #LIFETIME_PERMANENT} indicates this {@link LinkAddress} + * will never be deprecated. + * + * @hide + */ + @SystemApi + public long getDeprecationTime() { + return deprecationTime; + } + + /** + * Get the expiration time, as reported by {@link SystemClock#elapsedRealtime}, when this + * {@link LinkAddress} will expire and be removed from the interface. + * + * @return The expiration time in milliseconds. {@link #LIFETIME_UNKNOWN} indicates this + * information is not available. {@link #LIFETIME_PERMANENT} indicates this {@link LinkAddress} + * will never expire. + * + * @hide + */ + @SystemApi + public long getExpirationTime() { + return expirationTime; + } + + /** + * Returns true if this {@code LinkAddress} is global scope and preferred (i.e., not currently + * deprecated). + * + * @hide + */ + @SystemApi + public boolean isGlobalPreferred() { + /** + * Note that addresses flagged as IFA_F_OPTIMISTIC are + * simultaneously flagged as IFA_F_TENTATIVE (when the tentative + * state has cleared either DAD has succeeded or failed, and both + * flags are cleared regardless). + */ + int flags = getFlags(); + return (scope == RT_SCOPE_UNIVERSE + && !isIpv6ULA() + && (flags & (IFA_F_DADFAILED | IFA_F_DEPRECATED)) == 0L + && ((flags & IFA_F_TENTATIVE) == 0L || (flags & IFA_F_OPTIMISTIC) != 0L)); + } + + /** + * Implement the Parcelable interface. + */ + public int describeContents() { + return 0; + } + + /** + * Implement the Parcelable interface. + */ + public void writeToParcel(Parcel dest, int flags) { + dest.writeByteArray(address.getAddress()); + dest.writeInt(prefixLength); + dest.writeInt(this.flags); + dest.writeInt(scope); + dest.writeLong(deprecationTime); + dest.writeLong(expirationTime); + } + + /** + * Implement the Parcelable interface. + */ + public static final @android.annotation.NonNull Creator CREATOR = + new Creator() { + public LinkAddress createFromParcel(Parcel in) { + InetAddress address = null; + try { + address = InetAddress.getByAddress(in.createByteArray()); + } catch (UnknownHostException e) { + // Nothing we can do here. When we call the constructor, we'll throw an + // IllegalArgumentException, because a LinkAddress can't have a null + // InetAddress. + } + int prefixLength = in.readInt(); + int flags = in.readInt(); + int scope = in.readInt(); + long deprecationTime = in.readLong(); + long expirationTime = in.readLong(); + return new LinkAddress(address, prefixLength, flags, scope, deprecationTime, + expirationTime); + } + + public LinkAddress[] newArray(int size) { + return new LinkAddress[size]; + } + }; +} diff --git a/packages/Connectivity/framework/src/android/net/LinkProperties.aidl b/packages/Connectivity/framework/src/android/net/LinkProperties.aidl new file mode 100644 index 000000000000..a8b3c7b0392f --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/LinkProperties.aidl @@ -0,0 +1,20 @@ +/* +** +** Copyright (C) 2010 The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +package android.net; + +@JavaOnlyStableParcelable parcelable LinkProperties; diff --git a/packages/Connectivity/framework/src/android/net/LinkProperties.java b/packages/Connectivity/framework/src/android/net/LinkProperties.java new file mode 100644 index 000000000000..486e2d74dd05 --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/LinkProperties.java @@ -0,0 +1,1823 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.compat.annotation.UnsupportedAppUsage; +import android.os.Build; +import android.os.Parcel; +import android.os.Parcelable; +import android.text.TextUtils; + +import com.android.net.module.util.LinkPropertiesUtils; + +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Hashtable; +import java.util.List; +import java.util.Objects; +import java.util.StringJoiner; + +/** + * Describes the properties of a network link. + * + * A link represents a connection to a network. + * It may have multiple addresses and multiple gateways, + * multiple dns servers but only one http proxy and one + * network interface. + * + * Note that this is just a holder of data. Modifying it + * does not affect live networks. + * + */ +public final class LinkProperties implements Parcelable { + // The interface described by the network link. + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) + private String mIfaceName; + private final ArrayList mLinkAddresses = new ArrayList<>(); + private final ArrayList mDnses = new ArrayList<>(); + // PCSCF addresses are addresses of SIP proxies that only exist for the IMS core service. + private final ArrayList mPcscfs = new ArrayList(); + private final ArrayList mValidatedPrivateDnses = new ArrayList<>(); + private boolean mUsePrivateDns; + private String mPrivateDnsServerName; + private String mDomains; + private ArrayList mRoutes = new ArrayList<>(); + private Inet4Address mDhcpServerAddress; + private ProxyInfo mHttpProxy; + private int mMtu; + // in the format "rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max" + private String mTcpBufferSizes; + private IpPrefix mNat64Prefix; + private boolean mWakeOnLanSupported; + private Uri mCaptivePortalApiUrl; + private CaptivePortalData mCaptivePortalData; + + /** + * Indicates whether parceling should preserve fields that are set based on permissions of + * the process receiving the {@link LinkProperties}. + */ + private final transient boolean mParcelSensitiveFields; + + private static final int MIN_MTU = 68; + + private static final int MIN_MTU_V6 = 1280; + + private static final int MAX_MTU = 10000; + + private static final int INET6_ADDR_LENGTH = 16; + + // Stores the properties of links that are "stacked" above this link. + // Indexed by interface name to allow modification and to prevent duplicates being added. + private Hashtable mStackedLinks = new Hashtable<>(); + + /** + * @hide + */ + @UnsupportedAppUsage(implicitMember = + "values()[Landroid/net/LinkProperties$ProvisioningChange;") + public enum ProvisioningChange { + @UnsupportedAppUsage + STILL_NOT_PROVISIONED, + @UnsupportedAppUsage + LOST_PROVISIONING, + @UnsupportedAppUsage + GAINED_PROVISIONING, + @UnsupportedAppUsage + STILL_PROVISIONED, + } + + /** + * Compare the provisioning states of two LinkProperties instances. + * + * @hide + */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + public static ProvisioningChange compareProvisioning( + LinkProperties before, LinkProperties after) { + if (before.isProvisioned() && after.isProvisioned()) { + // On dual-stack networks, DHCPv4 renewals can occasionally fail. + // When this happens, IPv6-reachable services continue to function + // normally but IPv4-only services (naturally) fail. + // + // When an application using an IPv4-only service reports a bad + // network condition to the framework, attempts to re-validate + // the network succeed (since we support IPv6-only networks) and + // nothing is changed. + // + // For users, this is confusing and unexpected behaviour, and is + // not necessarily easy to diagnose. Therefore, we treat changing + // from a dual-stack network to an IPv6-only network equivalent to + // a total loss of provisioning. + // + // For one such example of this, see b/18867306. + // + // Additionally, losing IPv6 provisioning can result in TCP + // connections getting stuck until timeouts fire and other + // baffling failures. Therefore, loss of either IPv4 or IPv6 on a + // previously dual-stack network is deemed a lost of provisioning. + if ((before.isIpv4Provisioned() && !after.isIpv4Provisioned()) + || (before.isIpv6Provisioned() && !after.isIpv6Provisioned())) { + return ProvisioningChange.LOST_PROVISIONING; + } + return ProvisioningChange.STILL_PROVISIONED; + } else if (before.isProvisioned() && !after.isProvisioned()) { + return ProvisioningChange.LOST_PROVISIONING; + } else if (!before.isProvisioned() && after.isProvisioned()) { + return ProvisioningChange.GAINED_PROVISIONING; + } else { // !before.isProvisioned() && !after.isProvisioned() + return ProvisioningChange.STILL_NOT_PROVISIONED; + } + } + + /** + * Constructs a new {@code LinkProperties} with default values. + */ + public LinkProperties() { + mParcelSensitiveFields = false; + } + + /** + * @hide + */ + @SystemApi + public LinkProperties(@Nullable LinkProperties source) { + this(source, false /* parcelSensitiveFields */); + } + + /** + * Create a copy of a {@link LinkProperties} that may preserve fields that were set + * based on the permissions of the process that originally received it. + * + *

By default {@link LinkProperties} does not preserve such fields during parceling, as + * they should not be shared outside of the process that receives them without appropriate + * checks. + * @param parcelSensitiveFields Whether the sensitive fields should be kept when parceling + * @hide + */ + @SystemApi + public LinkProperties(@Nullable LinkProperties source, boolean parcelSensitiveFields) { + mParcelSensitiveFields = parcelSensitiveFields; + if (source == null) return; + mIfaceName = source.mIfaceName; + mLinkAddresses.addAll(source.mLinkAddresses); + mDnses.addAll(source.mDnses); + mValidatedPrivateDnses.addAll(source.mValidatedPrivateDnses); + mUsePrivateDns = source.mUsePrivateDns; + mPrivateDnsServerName = source.mPrivateDnsServerName; + mPcscfs.addAll(source.mPcscfs); + mDomains = source.mDomains; + mRoutes.addAll(source.mRoutes); + mHttpProxy = (source.mHttpProxy == null) ? null : new ProxyInfo(source.mHttpProxy); + for (LinkProperties l: source.mStackedLinks.values()) { + addStackedLink(l); + } + setMtu(source.mMtu); + setDhcpServerAddress(source.getDhcpServerAddress()); + mTcpBufferSizes = source.mTcpBufferSizes; + mNat64Prefix = source.mNat64Prefix; + mWakeOnLanSupported = source.mWakeOnLanSupported; + mCaptivePortalApiUrl = source.mCaptivePortalApiUrl; + mCaptivePortalData = source.mCaptivePortalData; + } + + /** + * Sets the interface name for this link. All {@link RouteInfo} already set for this + * will have their interface changed to match this new value. + * + * @param iface The name of the network interface used for this link. + */ + public void setInterfaceName(@Nullable String iface) { + mIfaceName = iface; + ArrayList newRoutes = new ArrayList<>(mRoutes.size()); + for (RouteInfo route : mRoutes) { + newRoutes.add(routeWithInterface(route)); + } + mRoutes = newRoutes; + } + + /** + * Gets the interface name for this link. May be {@code null} if not set. + * + * @return The interface name set for this link or {@code null}. + */ + public @Nullable String getInterfaceName() { + return mIfaceName; + } + + /** + * @hide + */ + @SystemApi + public @NonNull List getAllInterfaceNames() { + List interfaceNames = new ArrayList<>(mStackedLinks.size() + 1); + if (mIfaceName != null) interfaceNames.add(mIfaceName); + for (LinkProperties stacked: mStackedLinks.values()) { + interfaceNames.addAll(stacked.getAllInterfaceNames()); + } + return interfaceNames; + } + + /** + * Returns all the addresses on this link. We often think of a link having a single address, + * however, particularly with Ipv6 several addresses are typical. Note that the + * {@code LinkProperties} actually contains {@link LinkAddress} objects which also include + * prefix lengths for each address. This is a simplified utility alternative to + * {@link LinkProperties#getLinkAddresses}. + * + * @return An unmodifiable {@link List} of {@link InetAddress} for this link. + * @hide + */ + @SystemApi + public @NonNull List getAddresses() { + final List addresses = new ArrayList<>(); + for (LinkAddress linkAddress : mLinkAddresses) { + addresses.add(linkAddress.getAddress()); + } + return Collections.unmodifiableList(addresses); + } + + /** + * Returns all the addresses on this link and all the links stacked above it. + * @hide + */ + @UnsupportedAppUsage + public @NonNull List getAllAddresses() { + List addresses = new ArrayList<>(); + for (LinkAddress linkAddress : mLinkAddresses) { + addresses.add(linkAddress.getAddress()); + } + for (LinkProperties stacked: mStackedLinks.values()) { + addresses.addAll(stacked.getAllAddresses()); + } + return addresses; + } + + private int findLinkAddressIndex(LinkAddress address) { + for (int i = 0; i < mLinkAddresses.size(); i++) { + if (mLinkAddresses.get(i).isSameAddressAs(address)) { + return i; + } + } + return -1; + } + + /** + * Adds a {@link LinkAddress} to this {@code LinkProperties} if a {@link LinkAddress} of the + * same address/prefix does not already exist. If it does exist it is replaced. + * @param address The {@code LinkAddress} to add. + * @return true if {@code address} was added or updated, false otherwise. + * @hide + */ + @SystemApi + public boolean addLinkAddress(@NonNull LinkAddress address) { + if (address == null) { + return false; + } + int i = findLinkAddressIndex(address); + if (i < 0) { + // Address was not present. Add it. + mLinkAddresses.add(address); + return true; + } else if (mLinkAddresses.get(i).equals(address)) { + // Address was present and has same properties. Do nothing. + return false; + } else { + // Address was present and has different properties. Update it. + mLinkAddresses.set(i, address); + return true; + } + } + + /** + * Removes a {@link LinkAddress} from this {@code LinkProperties}. Specifically, matches + * and {@link LinkAddress} with the same address and prefix. + * + * @param toRemove A {@link LinkAddress} specifying the address to remove. + * @return true if the address was removed, false if it did not exist. + * @hide + */ + @SystemApi + public boolean removeLinkAddress(@NonNull LinkAddress toRemove) { + int i = findLinkAddressIndex(toRemove); + if (i >= 0) { + mLinkAddresses.remove(i); + return true; + } + return false; + } + + /** + * Returns all the {@link LinkAddress} on this link. Typically a link will have + * one IPv4 address and one or more IPv6 addresses. + * + * @return An unmodifiable {@link List} of {@link LinkAddress} for this link. + */ + public @NonNull List getLinkAddresses() { + return Collections.unmodifiableList(mLinkAddresses); + } + + /** + * Returns all the addresses on this link and all the links stacked above it. + * @hide + */ + @SystemApi + public @NonNull List getAllLinkAddresses() { + List addresses = new ArrayList<>(mLinkAddresses); + for (LinkProperties stacked: mStackedLinks.values()) { + addresses.addAll(stacked.getAllLinkAddresses()); + } + return addresses; + } + + /** + * Replaces the {@link LinkAddress} in this {@code LinkProperties} with + * the given {@link Collection} of {@link LinkAddress}. + * + * @param addresses The {@link Collection} of {@link LinkAddress} to set in this + * object. + */ + public void setLinkAddresses(@NonNull Collection addresses) { + mLinkAddresses.clear(); + for (LinkAddress address: addresses) { + addLinkAddress(address); + } + } + + /** + * Adds the given {@link InetAddress} to the list of DNS servers, if not present. + * + * @param dnsServer The {@link InetAddress} to add to the list of DNS servers. + * @return true if the DNS server was added, false if it was already present. + * @hide + */ + @SystemApi + public boolean addDnsServer(@NonNull InetAddress dnsServer) { + if (dnsServer != null && !mDnses.contains(dnsServer)) { + mDnses.add(dnsServer); + return true; + } + return false; + } + + /** + * Removes the given {@link InetAddress} from the list of DNS servers. + * + * @param dnsServer The {@link InetAddress} to remove from the list of DNS servers. + * @return true if the DNS server was removed, false if it did not exist. + * @hide + */ + @SystemApi + public boolean removeDnsServer(@NonNull InetAddress dnsServer) { + return mDnses.remove(dnsServer); + } + + /** + * Replaces the DNS servers in this {@code LinkProperties} with + * the given {@link Collection} of {@link InetAddress} objects. + * + * @param dnsServers The {@link Collection} of DNS servers to set in this object. + */ + public void setDnsServers(@NonNull Collection dnsServers) { + mDnses.clear(); + for (InetAddress dnsServer: dnsServers) { + addDnsServer(dnsServer); + } + } + + /** + * Returns all the {@link InetAddress} for DNS servers on this link. + * + * @return An unmodifiable {@link List} of {@link InetAddress} for DNS servers on + * this link. + */ + public @NonNull List getDnsServers() { + return Collections.unmodifiableList(mDnses); + } + + /** + * Set whether private DNS is currently in use on this network. + * + * @param usePrivateDns The private DNS state. + * @hide + */ + @SystemApi + public void setUsePrivateDns(boolean usePrivateDns) { + mUsePrivateDns = usePrivateDns; + } + + /** + * Returns whether private DNS is currently in use on this network. When + * private DNS is in use, applications must not send unencrypted DNS + * queries as doing so could reveal private user information. Furthermore, + * if private DNS is in use and {@link #getPrivateDnsServerName} is not + * {@code null}, DNS queries must be sent to the specified DNS server. + * + * @return {@code true} if private DNS is in use, {@code false} otherwise. + */ + public boolean isPrivateDnsActive() { + return mUsePrivateDns; + } + + /** + * Set the name of the private DNS server to which private DNS queries + * should be sent when in strict mode. This value should be {@code null} + * when private DNS is off or in opportunistic mode. + * + * @param privateDnsServerName The private DNS server name. + * @hide + */ + @SystemApi + public void setPrivateDnsServerName(@Nullable String privateDnsServerName) { + mPrivateDnsServerName = privateDnsServerName; + } + + /** + * Set DHCP server address. + * + * @param serverAddress the server address to set. + */ + public void setDhcpServerAddress(@Nullable Inet4Address serverAddress) { + mDhcpServerAddress = serverAddress; + } + + /** + * Get DHCP server address + * + * @return The current DHCP server address. + */ + public @Nullable Inet4Address getDhcpServerAddress() { + return mDhcpServerAddress; + } + + /** + * Returns the private DNS server name that is in use. If not {@code null}, + * private DNS is in strict mode. In this mode, applications should ensure + * that all DNS queries are encrypted and sent to this hostname and that + * queries are only sent if the hostname's certificate is valid. If + * {@code null} and {@link #isPrivateDnsActive} is {@code true}, private + * DNS is in opportunistic mode, and applications should ensure that DNS + * queries are encrypted and sent to a DNS server returned by + * {@link #getDnsServers}. System DNS will handle each of these cases + * correctly, but applications implementing their own DNS lookups must make + * sure to follow these requirements. + * + * @return The private DNS server name. + */ + public @Nullable String getPrivateDnsServerName() { + return mPrivateDnsServerName; + } + + /** + * Adds the given {@link InetAddress} to the list of validated private DNS servers, + * if not present. This is distinct from the server name in that these are actually + * resolved addresses. + * + * @param dnsServer The {@link InetAddress} to add to the list of validated private DNS servers. + * @return true if the DNS server was added, false if it was already present. + * @hide + */ + public boolean addValidatedPrivateDnsServer(@NonNull InetAddress dnsServer) { + if (dnsServer != null && !mValidatedPrivateDnses.contains(dnsServer)) { + mValidatedPrivateDnses.add(dnsServer); + return true; + } + return false; + } + + /** + * Removes the given {@link InetAddress} from the list of validated private DNS servers. + * + * @param dnsServer The {@link InetAddress} to remove from the list of validated private DNS + * servers. + * @return true if the DNS server was removed, false if it did not exist. + * @hide + */ + public boolean removeValidatedPrivateDnsServer(@NonNull InetAddress dnsServer) { + return mValidatedPrivateDnses.remove(dnsServer); + } + + /** + * Replaces the validated private DNS servers in this {@code LinkProperties} with + * the given {@link Collection} of {@link InetAddress} objects. + * + * @param dnsServers The {@link Collection} of validated private DNS servers to set in this + * object. + * @hide + */ + @SystemApi + public void setValidatedPrivateDnsServers(@NonNull Collection dnsServers) { + mValidatedPrivateDnses.clear(); + for (InetAddress dnsServer: dnsServers) { + addValidatedPrivateDnsServer(dnsServer); + } + } + + /** + * Returns all the {@link InetAddress} for validated private DNS servers on this link. + * These are resolved from the private DNS server name. + * + * @return An unmodifiable {@link List} of {@link InetAddress} for validated private + * DNS servers on this link. + * @hide + */ + @SystemApi + public @NonNull List getValidatedPrivateDnsServers() { + return Collections.unmodifiableList(mValidatedPrivateDnses); + } + + /** + * Adds the given {@link InetAddress} to the list of PCSCF servers, if not present. + * + * @param pcscfServer The {@link InetAddress} to add to the list of PCSCF servers. + * @return true if the PCSCF server was added, false otherwise. + * @hide + */ + @SystemApi + public boolean addPcscfServer(@NonNull InetAddress pcscfServer) { + if (pcscfServer != null && !mPcscfs.contains(pcscfServer)) { + mPcscfs.add(pcscfServer); + return true; + } + return false; + } + + /** + * Removes the given {@link InetAddress} from the list of PCSCF servers. + * + * @param pcscfServer The {@link InetAddress} to remove from the list of PCSCF servers. + * @return true if the PCSCF server was removed, false otherwise. + * @hide + */ + public boolean removePcscfServer(@NonNull InetAddress pcscfServer) { + return mPcscfs.remove(pcscfServer); + } + + /** + * Replaces the PCSCF servers in this {@code LinkProperties} with + * the given {@link Collection} of {@link InetAddress} objects. + * + * @param pcscfServers The {@link Collection} of PCSCF servers to set in this object. + * @hide + */ + @SystemApi + public void setPcscfServers(@NonNull Collection pcscfServers) { + mPcscfs.clear(); + for (InetAddress pcscfServer: pcscfServers) { + addPcscfServer(pcscfServer); + } + } + + /** + * Returns all the {@link InetAddress} for PCSCF servers on this link. + * + * @return An unmodifiable {@link List} of {@link InetAddress} for PCSCF servers on + * this link. + * @hide + */ + @SystemApi + public @NonNull List getPcscfServers() { + return Collections.unmodifiableList(mPcscfs); + } + + /** + * Sets the DNS domain search path used on this link. + * + * @param domains A {@link String} listing in priority order the comma separated + * domains to search when resolving host names on this link. + */ + public void setDomains(@Nullable String domains) { + mDomains = domains; + } + + /** + * Get the DNS domains search path set for this link. May be {@code null} if not set. + * + * @return A {@link String} containing the comma separated domains to search when resolving host + * names on this link or {@code null}. + */ + public @Nullable String getDomains() { + return mDomains; + } + + /** + * Sets the Maximum Transmission Unit size to use on this link. This should not be used + * unless the system default (1500) is incorrect. Values less than 68 or greater than + * 10000 will be ignored. + * + * @param mtu The MTU to use for this link. + */ + public void setMtu(int mtu) { + mMtu = mtu; + } + + /** + * Gets any non-default MTU size set for this link. Note that if the default is being used + * this will return 0. + * + * @return The mtu value set for this link. + */ + public int getMtu() { + return mMtu; + } + + /** + * Sets the tcp buffers sizes to be used when this link is the system default. + * Should be of the form "rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max". + * + * @param tcpBufferSizes The tcp buffers sizes to use. + * + * @hide + */ + @SystemApi + public void setTcpBufferSizes(@Nullable String tcpBufferSizes) { + mTcpBufferSizes = tcpBufferSizes; + } + + /** + * Gets the tcp buffer sizes. May be {@code null} if not set. + * + * @return the tcp buffer sizes to use when this link is the system default or {@code null}. + * + * @hide + */ + @SystemApi + public @Nullable String getTcpBufferSizes() { + return mTcpBufferSizes; + } + + private RouteInfo routeWithInterface(RouteInfo route) { + return new RouteInfo( + route.getDestination(), + route.getGateway(), + mIfaceName, + route.getType(), + route.getMtu()); + } + + private int findRouteIndexByRouteKey(RouteInfo route) { + for (int i = 0; i < mRoutes.size(); i++) { + if (mRoutes.get(i).getRouteKey().equals(route.getRouteKey())) { + return i; + } + } + return -1; + } + + /** + * Adds a {@link RouteInfo} to this {@code LinkProperties}, if a {@link RouteInfo} + * with the same {@link RouteInfo.RouteKey} with different properties + * (e.g., different MTU), it will be updated. If the {@link RouteInfo} had an + * interface name set and that differs from the interface set for this + * {@code LinkProperties} an {@link IllegalArgumentException} will be thrown. + * The proper course is to add either un-named or properly named {@link RouteInfo}. + * + * @param route A {@link RouteInfo} to add to this object. + * @return {@code true} was added or updated, false otherwise. + */ + public boolean addRoute(@NonNull RouteInfo route) { + String routeIface = route.getInterface(); + if (routeIface != null && !routeIface.equals(mIfaceName)) { + throw new IllegalArgumentException( + "Route added with non-matching interface: " + routeIface + + " vs. " + mIfaceName); + } + route = routeWithInterface(route); + + int i = findRouteIndexByRouteKey(route); + if (i == -1) { + // Route was not present. Add it. + mRoutes.add(route); + return true; + } else if (mRoutes.get(i).equals(route)) { + // Route was present and has same properties. Do nothing. + return false; + } else { + // Route was present and has different properties. Update it. + mRoutes.set(i, route); + return true; + } + } + + /** + * Removes a {@link RouteInfo} from this {@code LinkProperties}, if present. The route must + * specify an interface and the interface must match the interface of this + * {@code LinkProperties}, or it will not be removed. + * + * @param route A {@link RouteInfo} specifying the route to remove. + * @return {@code true} if the route was removed, {@code false} if it was not present. + * + * @hide + */ + @SystemApi + public boolean removeRoute(@NonNull RouteInfo route) { + return Objects.equals(mIfaceName, route.getInterface()) && mRoutes.remove(route); + } + + /** + * Returns all the {@link RouteInfo} set on this link. + * + * @return An unmodifiable {@link List} of {@link RouteInfo} for this link. + */ + public @NonNull List getRoutes() { + return Collections.unmodifiableList(mRoutes); + } + + /** + * Make sure this LinkProperties instance contains routes that cover the local subnet + * of its link addresses. Add any route that is missing. + * @hide + */ + public void ensureDirectlyConnectedRoutes() { + for (LinkAddress addr : mLinkAddresses) { + addRoute(new RouteInfo(addr, null, mIfaceName)); + } + } + + /** + * Returns all the routes on this link and all the links stacked above it. + * @hide + */ + @SystemApi + public @NonNull List getAllRoutes() { + List routes = new ArrayList<>(mRoutes); + for (LinkProperties stacked: mStackedLinks.values()) { + routes.addAll(stacked.getAllRoutes()); + } + return routes; + } + + /** + * Sets the recommended {@link ProxyInfo} to use on this link, or {@code null} for none. + * Note that Http Proxies are only a hint - the system recommends their use, but it does + * not enforce it and applications may ignore them. + * + * @param proxy A {@link ProxyInfo} defining the HTTP Proxy to use on this link. + */ + public void setHttpProxy(@Nullable ProxyInfo proxy) { + mHttpProxy = proxy; + } + + /** + * Gets the recommended {@link ProxyInfo} (or {@code null}) set on this link. + * + * @return The {@link ProxyInfo} set on this link or {@code null}. + */ + public @Nullable ProxyInfo getHttpProxy() { + return mHttpProxy; + } + + /** + * Returns the NAT64 prefix in use on this link, if any. + * + * @return the NAT64 prefix or {@code null}. + */ + public @Nullable IpPrefix getNat64Prefix() { + return mNat64Prefix; + } + + /** + * Sets the NAT64 prefix in use on this link. + * + * Currently, only 96-bit prefixes (i.e., where the 32-bit IPv4 address is at the end of the + * 128-bit IPv6 address) are supported or {@code null} for no prefix. + * + * @param prefix the NAT64 prefix. + */ + public void setNat64Prefix(@Nullable IpPrefix prefix) { + if (prefix != null && prefix.getPrefixLength() != 96) { + throw new IllegalArgumentException("Only 96-bit prefixes are supported: " + prefix); + } + mNat64Prefix = prefix; // IpPrefix objects are immutable. + } + + /** + * Adds a stacked link. + * + * If there is already a stacked link with the same interface name as link, + * that link is replaced with link. Otherwise, link is added to the list + * of stacked links. + * + * @param link The link to add. + * @return true if the link was stacked, false otherwise. + * @hide + */ + @UnsupportedAppUsage + public boolean addStackedLink(@NonNull LinkProperties link) { + if (link.getInterfaceName() != null) { + mStackedLinks.put(link.getInterfaceName(), link); + return true; + } + return false; + } + + /** + * Removes a stacked link. + * + * If there is a stacked link with the given interface name, it is + * removed. Otherwise, nothing changes. + * + * @param iface The interface name of the link to remove. + * @return true if the link was removed, false otherwise. + * @hide + */ + public boolean removeStackedLink(@NonNull String iface) { + LinkProperties removed = mStackedLinks.remove(iface); + return removed != null; + } + + /** + * Returns all the links stacked on top of this link. + * @hide + */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + public @NonNull List getStackedLinks() { + if (mStackedLinks.isEmpty()) { + return Collections.emptyList(); + } + final List stacked = new ArrayList<>(); + for (LinkProperties link : mStackedLinks.values()) { + stacked.add(new LinkProperties(link)); + } + return Collections.unmodifiableList(stacked); + } + + /** + * Clears this object to its initial state. + */ + public void clear() { + if (mParcelSensitiveFields) { + throw new UnsupportedOperationException( + "Cannot clear LinkProperties when parcelSensitiveFields is set"); + } + + mIfaceName = null; + mLinkAddresses.clear(); + mDnses.clear(); + mUsePrivateDns = false; + mPrivateDnsServerName = null; + mPcscfs.clear(); + mDomains = null; + mRoutes.clear(); + mHttpProxy = null; + mStackedLinks.clear(); + mMtu = 0; + mDhcpServerAddress = null; + mTcpBufferSizes = null; + mNat64Prefix = null; + mWakeOnLanSupported = false; + mCaptivePortalApiUrl = null; + mCaptivePortalData = null; + } + + /** + * Implement the Parcelable interface + */ + public int describeContents() { + return 0; + } + + @Override + public String toString() { + // Space as a separator, so no need for spaces at start/end of the individual fragments. + final StringJoiner resultJoiner = new StringJoiner(" ", "{", "}"); + + if (mIfaceName != null) { + resultJoiner.add("InterfaceName:"); + resultJoiner.add(mIfaceName); + } + + resultJoiner.add("LinkAddresses: ["); + if (!mLinkAddresses.isEmpty()) { + resultJoiner.add(TextUtils.join(",", mLinkAddresses)); + } + resultJoiner.add("]"); + + resultJoiner.add("DnsAddresses: ["); + if (!mDnses.isEmpty()) { + resultJoiner.add(TextUtils.join(",", mDnses)); + } + resultJoiner.add("]"); + + if (mUsePrivateDns) { + resultJoiner.add("UsePrivateDns: true"); + } + + if (mPrivateDnsServerName != null) { + resultJoiner.add("PrivateDnsServerName:"); + resultJoiner.add(mPrivateDnsServerName); + } + + if (!mPcscfs.isEmpty()) { + resultJoiner.add("PcscfAddresses: ["); + resultJoiner.add(TextUtils.join(",", mPcscfs)); + resultJoiner.add("]"); + } + + if (!mValidatedPrivateDnses.isEmpty()) { + final StringJoiner validatedPrivateDnsesJoiner = + new StringJoiner(",", "ValidatedPrivateDnsAddresses: [", "]"); + for (final InetAddress addr : mValidatedPrivateDnses) { + validatedPrivateDnsesJoiner.add(addr.getHostAddress()); + } + resultJoiner.add(validatedPrivateDnsesJoiner.toString()); + } + + resultJoiner.add("Domains:"); + resultJoiner.add(mDomains); + + resultJoiner.add("MTU:"); + resultJoiner.add(Integer.toString(mMtu)); + + if (mWakeOnLanSupported) { + resultJoiner.add("WakeOnLanSupported: true"); + } + + if (mDhcpServerAddress != null) { + resultJoiner.add("ServerAddress:"); + resultJoiner.add(mDhcpServerAddress.toString()); + } + + if (mCaptivePortalApiUrl != null) { + resultJoiner.add("CaptivePortalApiUrl: " + mCaptivePortalApiUrl); + } + + if (mCaptivePortalData != null) { + resultJoiner.add("CaptivePortalData: " + mCaptivePortalData); + } + + if (mTcpBufferSizes != null) { + resultJoiner.add("TcpBufferSizes:"); + resultJoiner.add(mTcpBufferSizes); + } + + resultJoiner.add("Routes: ["); + if (!mRoutes.isEmpty()) { + resultJoiner.add(TextUtils.join(",", mRoutes)); + } + resultJoiner.add("]"); + + if (mHttpProxy != null) { + resultJoiner.add("HttpProxy:"); + resultJoiner.add(mHttpProxy.toString()); + } + + if (mNat64Prefix != null) { + resultJoiner.add("Nat64Prefix:"); + resultJoiner.add(mNat64Prefix.toString()); + } + + final Collection stackedLinksValues = mStackedLinks.values(); + if (!stackedLinksValues.isEmpty()) { + final StringJoiner stackedLinksJoiner = new StringJoiner(",", "Stacked: [", "]"); + for (final LinkProperties lp : stackedLinksValues) { + stackedLinksJoiner.add("[ " + lp + " ]"); + } + resultJoiner.add(stackedLinksJoiner.toString()); + } + + return resultJoiner.toString(); + } + + /** + * Returns true if this link has an IPv4 address. + * + * @return {@code true} if there is an IPv4 address, {@code false} otherwise. + * @hide + */ + @SystemApi + public boolean hasIpv4Address() { + for (LinkAddress address : mLinkAddresses) { + if (address.getAddress() instanceof Inet4Address) { + return true; + } + } + return false; + } + + /** + * For backward compatibility. + * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely + * just yet. + * @return {@code true} if there is an IPv4 address, {@code false} otherwise. + * @hide + */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) + public boolean hasIPv4Address() { + return hasIpv4Address(); + } + + /** + * Returns true if this link or any of its stacked interfaces has an IPv4 address. + * + * @return {@code true} if there is an IPv4 address, {@code false} otherwise. + */ + private boolean hasIpv4AddressOnInterface(String iface) { + // mIfaceName can be null. + return (Objects.equals(iface, mIfaceName) && hasIpv4Address()) + || (iface != null && mStackedLinks.containsKey(iface) + && mStackedLinks.get(iface).hasIpv4Address()); + } + + /** + * Returns true if this link has a global preferred IPv6 address. + * + * @return {@code true} if there is a global preferred IPv6 address, {@code false} otherwise. + * @hide + */ + @SystemApi + public boolean hasGlobalIpv6Address() { + for (LinkAddress address : mLinkAddresses) { + if (address.getAddress() instanceof Inet6Address && address.isGlobalPreferred()) { + return true; + } + } + return false; + } + + /** + * Returns true if this link has an IPv4 unreachable default route. + * + * @return {@code true} if there is an IPv4 unreachable default route, {@code false} otherwise. + * @hide + */ + public boolean hasIpv4UnreachableDefaultRoute() { + for (RouteInfo r : mRoutes) { + if (r.isIPv4UnreachableDefault()) { + return true; + } + } + return false; + } + + /** + * For backward compatibility. + * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely + * just yet. + * @return {@code true} if there is a global preferred IPv6 address, {@code false} otherwise. + * @hide + */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) + public boolean hasGlobalIPv6Address() { + return hasGlobalIpv6Address(); + } + + /** + * Returns true if this link has an IPv4 default route. + * + * @return {@code true} if there is an IPv4 default route, {@code false} otherwise. + * @hide + */ + @SystemApi + public boolean hasIpv4DefaultRoute() { + for (RouteInfo r : mRoutes) { + if (r.isIPv4Default()) { + return true; + } + } + return false; + } + + /** + * Returns true if this link has an IPv6 unreachable default route. + * + * @return {@code true} if there is an IPv6 unreachable default route, {@code false} otherwise. + * @hide + */ + public boolean hasIpv6UnreachableDefaultRoute() { + for (RouteInfo r : mRoutes) { + if (r.isIPv6UnreachableDefault()) { + return true; + } + } + return false; + } + + /** + * For backward compatibility. + * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely + * just yet. + * @return {@code true} if there is an IPv4 default route, {@code false} otherwise. + * @hide + */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) + public boolean hasIPv4DefaultRoute() { + return hasIpv4DefaultRoute(); + } + + /** + * Returns true if this link has an IPv6 default route. + * + * @return {@code true} if there is an IPv6 default route, {@code false} otherwise. + * @hide + */ + @SystemApi + public boolean hasIpv6DefaultRoute() { + for (RouteInfo r : mRoutes) { + if (r.isIPv6Default()) { + return true; + } + } + return false; + } + + /** + * For backward compatibility. + * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely + * just yet. + * @return {@code true} if there is an IPv6 default route, {@code false} otherwise. + * @hide + */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) + public boolean hasIPv6DefaultRoute() { + return hasIpv6DefaultRoute(); + } + + /** + * Returns true if this link has an IPv4 DNS server. + * + * @return {@code true} if there is an IPv4 DNS server, {@code false} otherwise. + * @hide + */ + @SystemApi + public boolean hasIpv4DnsServer() { + for (InetAddress ia : mDnses) { + if (ia instanceof Inet4Address) { + return true; + } + } + return false; + } + + /** + * For backward compatibility. + * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely + * just yet. + * @return {@code true} if there is an IPv4 DNS server, {@code false} otherwise. + * @hide + */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) + public boolean hasIPv4DnsServer() { + return hasIpv4DnsServer(); + } + + /** + * Returns true if this link has an IPv6 DNS server. + * + * @return {@code true} if there is an IPv6 DNS server, {@code false} otherwise. + * @hide + */ + @SystemApi + public boolean hasIpv6DnsServer() { + for (InetAddress ia : mDnses) { + if (ia instanceof Inet6Address) { + return true; + } + } + return false; + } + + /** + * For backward compatibility. + * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely + * just yet. + * @return {@code true} if there is an IPv6 DNS server, {@code false} otherwise. + * @hide + */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) + public boolean hasIPv6DnsServer() { + return hasIpv6DnsServer(); + } + + /** + * Returns true if this link has an IPv4 PCSCF server. + * + * @return {@code true} if there is an IPv4 PCSCF server, {@code false} otherwise. + * @hide + */ + public boolean hasIpv4PcscfServer() { + for (InetAddress ia : mPcscfs) { + if (ia instanceof Inet4Address) { + return true; + } + } + return false; + } + + /** + * Returns true if this link has an IPv6 PCSCF server. + * + * @return {@code true} if there is an IPv6 PCSCF server, {@code false} otherwise. + * @hide + */ + public boolean hasIpv6PcscfServer() { + for (InetAddress ia : mPcscfs) { + if (ia instanceof Inet6Address) { + return true; + } + } + return false; + } + + /** + * Returns true if this link is provisioned for global IPv4 connectivity. + * This requires an IP address, default route, and DNS server. + * + * @return {@code true} if the link is provisioned, {@code false} otherwise. + * @hide + */ + @SystemApi + public boolean isIpv4Provisioned() { + return (hasIpv4Address() + && hasIpv4DefaultRoute() + && hasIpv4DnsServer()); + } + + /** + * Returns true if this link is provisioned for global IPv6 connectivity. + * This requires an IP address, default route, and DNS server. + * + * @return {@code true} if the link is provisioned, {@code false} otherwise. + * @hide + */ + @SystemApi + public boolean isIpv6Provisioned() { + return (hasGlobalIpv6Address() + && hasIpv6DefaultRoute() + && hasIpv6DnsServer()); + } + + /** + * For backward compatibility. + * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely + * just yet. + * @return {@code true} if the link is provisioned, {@code false} otherwise. + * @hide + */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) + public boolean isIPv6Provisioned() { + return isIpv6Provisioned(); + } + + + /** + * Returns true if this link is provisioned for global connectivity, + * for at least one Internet Protocol family. + * + * @return {@code true} if the link is provisioned, {@code false} otherwise. + * @hide + */ + @SystemApi + public boolean isProvisioned() { + return (isIpv4Provisioned() || isIpv6Provisioned()); + } + + /** + * Evaluate whether the {@link InetAddress} is considered reachable. + * + * @return {@code true} if the given {@link InetAddress} is considered reachable, + * {@code false} otherwise. + * @hide + */ + @SystemApi + public boolean isReachable(@NonNull InetAddress ip) { + final List allRoutes = getAllRoutes(); + // If we don't have a route to this IP address, it's not reachable. + final RouteInfo bestRoute = RouteInfo.selectBestRoute(allRoutes, ip); + if (bestRoute == null) { + return false; + } + + // TODO: better source address evaluation for destination addresses. + + if (ip instanceof Inet4Address) { + // For IPv4, it suffices for now to simply have any address. + return hasIpv4AddressOnInterface(bestRoute.getInterface()); + } else if (ip instanceof Inet6Address) { + if (ip.isLinkLocalAddress()) { + // For now, just make sure link-local destinations have + // scopedIds set, since transmits will generally fail otherwise. + // TODO: verify it matches the ifindex of one of the interfaces. + return (((Inet6Address)ip).getScopeId() != 0); + } else { + // For non-link-local destinations check that either the best route + // is directly connected or that some global preferred address exists. + // TODO: reconsider all cases (disconnected ULA networks, ...). + return (!bestRoute.hasGateway() || hasGlobalIpv6Address()); + } + } + + return false; + } + + /** + * Compares this {@code LinkProperties} interface name against the target + * + * @param target LinkProperties to compare. + * @return {@code true} if both are identical, {@code false} otherwise. + * @hide + */ + @UnsupportedAppUsage + public boolean isIdenticalInterfaceName(@NonNull LinkProperties target) { + return LinkPropertiesUtils.isIdenticalInterfaceName(target, this); + } + + /** + * Compares this {@code LinkProperties} DHCP server address against the target + * + * @param target LinkProperties to compare. + * @return {@code true} if both are identical, {@code false} otherwise. + * @hide + */ + public boolean isIdenticalDhcpServerAddress(@NonNull LinkProperties target) { + return Objects.equals(mDhcpServerAddress, target.mDhcpServerAddress); + } + + /** + * Compares this {@code LinkProperties} interface addresses against the target + * + * @param target LinkProperties to compare. + * @return {@code true} if both are identical, {@code false} otherwise. + * @hide + */ + @UnsupportedAppUsage + public boolean isIdenticalAddresses(@NonNull LinkProperties target) { + return LinkPropertiesUtils.isIdenticalAddresses(target, this); + } + + /** + * Compares this {@code LinkProperties} DNS addresses against the target + * + * @param target LinkProperties to compare. + * @return {@code true} if both are identical, {@code false} otherwise. + * @hide + */ + @UnsupportedAppUsage + public boolean isIdenticalDnses(@NonNull LinkProperties target) { + return LinkPropertiesUtils.isIdenticalDnses(target, this); + } + + /** + * Compares this {@code LinkProperties} private DNS settings against the + * target. + * + * @param target LinkProperties to compare. + * @return {@code true} if both are identical, {@code false} otherwise. + * @hide + */ + public boolean isIdenticalPrivateDns(@NonNull LinkProperties target) { + return (isPrivateDnsActive() == target.isPrivateDnsActive() + && TextUtils.equals(getPrivateDnsServerName(), + target.getPrivateDnsServerName())); + } + + /** + * Compares this {@code LinkProperties} validated private DNS addresses against + * the target + * + * @param target LinkProperties to compare. + * @return {@code true} if both are identical, {@code false} otherwise. + * @hide + */ + public boolean isIdenticalValidatedPrivateDnses(@NonNull LinkProperties target) { + Collection targetDnses = target.getValidatedPrivateDnsServers(); + return (mValidatedPrivateDnses.size() == targetDnses.size()) + ? mValidatedPrivateDnses.containsAll(targetDnses) : false; + } + + /** + * Compares this {@code LinkProperties} PCSCF addresses against the target + * + * @param target LinkProperties to compare. + * @return {@code true} if both are identical, {@code false} otherwise. + * @hide + */ + public boolean isIdenticalPcscfs(@NonNull LinkProperties target) { + Collection targetPcscfs = target.getPcscfServers(); + return (mPcscfs.size() == targetPcscfs.size()) ? + mPcscfs.containsAll(targetPcscfs) : false; + } + + /** + * Compares this {@code LinkProperties} Routes against the target + * + * @param target LinkProperties to compare. + * @return {@code true} if both are identical, {@code false} otherwise. + * @hide + */ + @UnsupportedAppUsage + public boolean isIdenticalRoutes(@NonNull LinkProperties target) { + return LinkPropertiesUtils.isIdenticalRoutes(target, this); + } + + /** + * Compares this {@code LinkProperties} HttpProxy against the target + * + * @param target LinkProperties to compare. + * @return {@code true} if both are identical, {@code false} otherwise. + * @hide + */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) + public boolean isIdenticalHttpProxy(@NonNull LinkProperties target) { + return LinkPropertiesUtils.isIdenticalHttpProxy(target, this); + } + + /** + * Compares this {@code LinkProperties} stacked links against the target + * + * @param target LinkProperties to compare. + * @return {@code true} if both are identical, {@code false} otherwise. + * @hide + */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + public boolean isIdenticalStackedLinks(@NonNull LinkProperties target) { + if (!mStackedLinks.keySet().equals(target.mStackedLinks.keySet())) { + return false; + } + for (LinkProperties stacked : mStackedLinks.values()) { + // Hashtable values can never be null. + String iface = stacked.getInterfaceName(); + if (!stacked.equals(target.mStackedLinks.get(iface))) { + return false; + } + } + return true; + } + + /** + * Compares this {@code LinkProperties} MTU against the target + * + * @param target LinkProperties to compare. + * @return {@code true} if both are identical, {@code false} otherwise. + * @hide + */ + public boolean isIdenticalMtu(@NonNull LinkProperties target) { + return getMtu() == target.getMtu(); + } + + /** + * Compares this {@code LinkProperties} Tcp buffer sizes against the target. + * + * @param target LinkProperties to compare. + * @return {@code true} if both are identical, {@code false} otherwise. + * @hide + */ + public boolean isIdenticalTcpBufferSizes(@NonNull LinkProperties target) { + return Objects.equals(mTcpBufferSizes, target.mTcpBufferSizes); + } + + /** + * Compares this {@code LinkProperties} NAT64 prefix against the target. + * + * @param target LinkProperties to compare. + * @return {@code true} if both are identical, {@code false} otherwise. + * @hide + */ + public boolean isIdenticalNat64Prefix(@NonNull LinkProperties target) { + return Objects.equals(mNat64Prefix, target.mNat64Prefix); + } + + /** + * Compares this {@code LinkProperties} WakeOnLan supported against the target. + * + * @param target LinkProperties to compare. + * @return {@code true} if both are identical, {@code false} otherwise. + * @hide + */ + public boolean isIdenticalWakeOnLan(LinkProperties target) { + return isWakeOnLanSupported() == target.isWakeOnLanSupported(); + } + + /** + * Compares this {@code LinkProperties}'s CaptivePortalApiUrl against the target. + * + * @param target LinkProperties to compare. + * @return {@code true} if both are identical, {@code false} otherwise. + * @hide + */ + public boolean isIdenticalCaptivePortalApiUrl(LinkProperties target) { + return Objects.equals(mCaptivePortalApiUrl, target.mCaptivePortalApiUrl); + } + + /** + * Compares this {@code LinkProperties}'s CaptivePortalData against the target. + * + * @param target LinkProperties to compare. + * @return {@code true} if both are identical, {@code false} otherwise. + * @hide + */ + public boolean isIdenticalCaptivePortalData(LinkProperties target) { + return Objects.equals(mCaptivePortalData, target.mCaptivePortalData); + } + + /** + * Set whether the network interface supports WakeOnLAN + * + * @param supported WakeOnLAN supported value + * + * @hide + */ + public void setWakeOnLanSupported(boolean supported) { + mWakeOnLanSupported = supported; + } + + /** + * Returns whether the network interface supports WakeOnLAN + * + * @return {@code true} if interface supports WakeOnLAN, {@code false} otherwise. + */ + public boolean isWakeOnLanSupported() { + return mWakeOnLanSupported; + } + + /** + * Set the URL of the captive portal API endpoint to get more information about the network. + * @hide + */ + @SystemApi + public void setCaptivePortalApiUrl(@Nullable Uri url) { + mCaptivePortalApiUrl = url; + } + + /** + * Get the URL of the captive portal API endpoint to get more information about the network. + * + *

This is null unless the application has + * {@link android.Manifest.permission.NETWORK_SETTINGS} or + * {@link NetworkStack#PERMISSION_MAINLINE_NETWORK_STACK} permissions, and the network provided + * the URL. + * @hide + */ + @SystemApi + @Nullable + public Uri getCaptivePortalApiUrl() { + return mCaptivePortalApiUrl; + } + + /** + * Set the CaptivePortalData obtained from the captive portal API (RFC7710bis). + * @hide + */ + @SystemApi + public void setCaptivePortalData(@Nullable CaptivePortalData data) { + mCaptivePortalData = data; + } + + /** + * Get the CaptivePortalData obtained from the captive portal API (RFC7710bis). + * + *

This is null unless the application has + * {@link android.Manifest.permission.NETWORK_SETTINGS} or + * {@link NetworkStack#PERMISSION_MAINLINE_NETWORK_STACK} permissions. + * @hide + */ + @SystemApi + @Nullable + public CaptivePortalData getCaptivePortalData() { + return mCaptivePortalData; + } + + /** + * Compares this {@code LinkProperties} instance against the target + * LinkProperties in {@code obj}. Two LinkPropertieses are equal if + * all their fields are equal in values. + * + * For collection fields, such as mDnses, containsAll() is used to check + * if two collections contains the same elements, independent of order. + * There are two thoughts regarding containsAll() + * 1. Duplicated elements. eg, (A, B, B) and (A, A, B) are equal. + * 2. Worst case performance is O(n^2). + * + * @param obj the object to be tested for equality. + * @return {@code true} if both objects are equal, {@code false} otherwise. + */ + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + + if (!(obj instanceof LinkProperties)) return false; + + LinkProperties target = (LinkProperties) obj; + /* + * This method does not check that stacked interfaces are equal, because + * stacked interfaces are not so much a property of the link as a + * description of connections between links. + */ + return isIdenticalInterfaceName(target) + && isIdenticalAddresses(target) + && isIdenticalDhcpServerAddress(target) + && isIdenticalDnses(target) + && isIdenticalPrivateDns(target) + && isIdenticalValidatedPrivateDnses(target) + && isIdenticalPcscfs(target) + && isIdenticalRoutes(target) + && isIdenticalHttpProxy(target) + && isIdenticalStackedLinks(target) + && isIdenticalMtu(target) + && isIdenticalTcpBufferSizes(target) + && isIdenticalNat64Prefix(target) + && isIdenticalWakeOnLan(target) + && isIdenticalCaptivePortalApiUrl(target) + && isIdenticalCaptivePortalData(target); + } + + /** + * Generate hashcode based on significant fields + * + * Equal objects must produce the same hash code, while unequal objects + * may have the same hash codes. + */ + @Override + public int hashCode() { + return ((null == mIfaceName) ? 0 : mIfaceName.hashCode() + + mLinkAddresses.size() * 31 + + mDnses.size() * 37 + + mValidatedPrivateDnses.size() * 61 + + ((null == mDomains) ? 0 : mDomains.hashCode()) + + mRoutes.size() * 41 + + ((null == mHttpProxy) ? 0 : mHttpProxy.hashCode()) + + mStackedLinks.hashCode() * 47) + + mMtu * 51 + + ((null == mTcpBufferSizes) ? 0 : mTcpBufferSizes.hashCode()) + + (mUsePrivateDns ? 57 : 0) + + ((null == mDhcpServerAddress) ? 0 : mDhcpServerAddress.hashCode()) + + mPcscfs.size() * 67 + + ((null == mPrivateDnsServerName) ? 0 : mPrivateDnsServerName.hashCode()) + + Objects.hash(mNat64Prefix) + + (mWakeOnLanSupported ? 71 : 0) + + Objects.hash(mCaptivePortalApiUrl, mCaptivePortalData); + } + + /** + * Implement the Parcelable interface. + */ + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(getInterfaceName()); + dest.writeInt(mLinkAddresses.size()); + for (LinkAddress linkAddress : mLinkAddresses) { + dest.writeParcelable(linkAddress, flags); + } + + writeAddresses(dest, mDnses); + writeAddresses(dest, mValidatedPrivateDnses); + dest.writeBoolean(mUsePrivateDns); + dest.writeString(mPrivateDnsServerName); + writeAddresses(dest, mPcscfs); + dest.writeString(mDomains); + writeAddress(dest, mDhcpServerAddress); + dest.writeInt(mMtu); + dest.writeString(mTcpBufferSizes); + dest.writeInt(mRoutes.size()); + for (RouteInfo route : mRoutes) { + dest.writeParcelable(route, flags); + } + + if (mHttpProxy != null) { + dest.writeByte((byte)1); + dest.writeParcelable(mHttpProxy, flags); + } else { + dest.writeByte((byte)0); + } + dest.writeParcelable(mNat64Prefix, 0); + + ArrayList stackedLinks = new ArrayList<>(mStackedLinks.values()); + dest.writeList(stackedLinks); + + dest.writeBoolean(mWakeOnLanSupported); + dest.writeParcelable(mParcelSensitiveFields ? mCaptivePortalApiUrl : null, 0); + dest.writeParcelable(mParcelSensitiveFields ? mCaptivePortalData : null, 0); + } + + private static void writeAddresses(@NonNull Parcel dest, @NonNull List list) { + dest.writeInt(list.size()); + for (InetAddress d : list) { + writeAddress(dest, d); + } + } + + private static void writeAddress(@NonNull Parcel dest, @Nullable InetAddress addr) { + byte[] addressBytes = (addr == null ? null : addr.getAddress()); + dest.writeByteArray(addressBytes); + if (addr instanceof Inet6Address) { + final Inet6Address v6Addr = (Inet6Address) addr; + final boolean hasScopeId = v6Addr.getScopeId() != 0; + dest.writeBoolean(hasScopeId); + if (hasScopeId) dest.writeInt(v6Addr.getScopeId()); + } + } + + @Nullable + private static InetAddress readAddress(@NonNull Parcel p) throws UnknownHostException { + final byte[] addr = p.createByteArray(); + if (addr == null) return null; + + if (addr.length == INET6_ADDR_LENGTH) { + final boolean hasScopeId = p.readBoolean(); + final int scopeId = hasScopeId ? p.readInt() : 0; + return Inet6Address.getByAddress(null /* host */, addr, scopeId); + } + + return InetAddress.getByAddress(addr); + } + + /** + * Implement the Parcelable interface. + */ + public static final @android.annotation.NonNull Creator CREATOR = + new Creator() { + public LinkProperties createFromParcel(Parcel in) { + LinkProperties netProp = new LinkProperties(); + + String iface = in.readString(); + if (iface != null) { + netProp.setInterfaceName(iface); + } + int addressCount = in.readInt(); + for (int i = 0; i < addressCount; i++) { + netProp.addLinkAddress(in.readParcelable(null)); + } + addressCount = in.readInt(); + for (int i = 0; i < addressCount; i++) { + try { + netProp.addDnsServer(readAddress(in)); + } catch (UnknownHostException e) { } + } + addressCount = in.readInt(); + for (int i = 0; i < addressCount; i++) { + try { + netProp.addValidatedPrivateDnsServer(readAddress(in)); + } catch (UnknownHostException e) { } + } + netProp.setUsePrivateDns(in.readBoolean()); + netProp.setPrivateDnsServerName(in.readString()); + addressCount = in.readInt(); + for (int i = 0; i < addressCount; i++) { + try { + netProp.addPcscfServer(readAddress(in)); + } catch (UnknownHostException e) { } + } + netProp.setDomains(in.readString()); + try { + netProp.setDhcpServerAddress((Inet4Address) InetAddress + .getByAddress(in.createByteArray())); + } catch (UnknownHostException e) { } + netProp.setMtu(in.readInt()); + netProp.setTcpBufferSizes(in.readString()); + addressCount = in.readInt(); + for (int i = 0; i < addressCount; i++) { + netProp.addRoute(in.readParcelable(null)); + } + if (in.readByte() == 1) { + netProp.setHttpProxy(in.readParcelable(null)); + } + netProp.setNat64Prefix(in.readParcelable(null)); + ArrayList stackedLinks = new ArrayList(); + in.readList(stackedLinks, LinkProperties.class.getClassLoader()); + for (LinkProperties stackedLink: stackedLinks) { + netProp.addStackedLink(stackedLink); + } + netProp.setWakeOnLanSupported(in.readBoolean()); + + netProp.setCaptivePortalApiUrl(in.readParcelable(null)); + netProp.setCaptivePortalData(in.readParcelable(null)); + return netProp; + } + + public LinkProperties[] newArray(int size) { + return new LinkProperties[size]; + } + }; + + /** + * Check the valid MTU range based on IPv4 or IPv6. + * @hide + */ + public static boolean isValidMtu(int mtu, boolean ipv6) { + if (ipv6) { + return mtu >= MIN_MTU_V6 && mtu <= MAX_MTU; + } else { + return mtu >= MIN_MTU && mtu <= MAX_MTU; + } + } +} diff --git a/packages/Connectivity/framework/src/android/net/MacAddress.aidl b/packages/Connectivity/framework/src/android/net/MacAddress.aidl new file mode 100644 index 000000000000..48a18a7ac821 --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/MacAddress.aidl @@ -0,0 +1,20 @@ +/** + * + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +@JavaOnlyStableParcelable parcelable MacAddress; diff --git a/packages/Connectivity/framework/src/android/net/MacAddress.java b/packages/Connectivity/framework/src/android/net/MacAddress.java new file mode 100644 index 000000000000..c7116b41e80a --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/MacAddress.java @@ -0,0 +1,400 @@ +/* + * Copyright 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.compat.annotation.UnsupportedAppUsage; +import android.net.wifi.WifiInfo; +import android.os.Build; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.util.Preconditions; +import com.android.net.module.util.MacAddressUtils; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.net.Inet6Address; +import java.net.UnknownHostException; +import java.security.SecureRandom; +import java.util.Arrays; + +/** + * Representation of a MAC address. + * + * This class only supports 48 bits long addresses and does not support 64 bits long addresses. + * Instances of this class are immutable. This class provides implementations of hashCode() + * and equals() that make it suitable for use as keys in standard implementations of + * {@link java.util.Map}. + */ +public final class MacAddress implements Parcelable { + + private static final int ETHER_ADDR_LEN = 6; + private static final byte[] ETHER_ADDR_BROADCAST = addr(0xff, 0xff, 0xff, 0xff, 0xff, 0xff); + + /** + * The MacAddress representing the unique broadcast MAC address. + */ + public static final MacAddress BROADCAST_ADDRESS = MacAddress.fromBytes(ETHER_ADDR_BROADCAST); + + /** + * The MacAddress zero MAC address. + * + *

Not publicly exposed or treated specially since the OUI 00:00:00 is registered. + * @hide + */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + public static final MacAddress ALL_ZEROS_ADDRESS = new MacAddress(0); + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = { "TYPE_" }, value = { + TYPE_UNKNOWN, + TYPE_UNICAST, + TYPE_MULTICAST, + TYPE_BROADCAST, + }) + public @interface MacAddressType { } + + /** @hide Indicates a MAC address of unknown type. */ + public static final int TYPE_UNKNOWN = 0; + /** Indicates a MAC address is a unicast address. */ + public static final int TYPE_UNICAST = 1; + /** Indicates a MAC address is a multicast address. */ + public static final int TYPE_MULTICAST = 2; + /** Indicates a MAC address is the broadcast address. */ + public static final int TYPE_BROADCAST = 3; + + private static final long VALID_LONG_MASK = (1L << 48) - 1; + private static final long LOCALLY_ASSIGNED_MASK = MacAddress.fromString("2:0:0:0:0:0").mAddr; + private static final long MULTICAST_MASK = MacAddress.fromString("1:0:0:0:0:0").mAddr; + private static final long OUI_MASK = MacAddress.fromString("ff:ff:ff:0:0:0").mAddr; + private static final long NIC_MASK = MacAddress.fromString("0:0:0:ff:ff:ff").mAddr; + private static final MacAddress BASE_GOOGLE_MAC = MacAddress.fromString("da:a1:19:0:0:0"); + /** Default wifi MAC address used for a special purpose **/ + private static final MacAddress DEFAULT_MAC_ADDRESS = + MacAddress.fromString(WifiInfo.DEFAULT_MAC_ADDRESS); + + // Internal representation of the MAC address as a single 8 byte long. + // The encoding scheme sets the two most significant bytes to 0. The 6 bytes of the + // MAC address are encoded in the 6 least significant bytes of the long, where the first + // byte of the array is mapped to the 3rd highest logical byte of the long, the second + // byte of the array is mapped to the 4th highest logical byte of the long, and so on. + private final long mAddr; + + private MacAddress(long addr) { + mAddr = (VALID_LONG_MASK & addr); + } + + /** + * Returns the type of this address. + * + * @return the int constant representing the MAC address type of this MacAddress. + */ + public @MacAddressType int getAddressType() { + if (equals(BROADCAST_ADDRESS)) { + return TYPE_BROADCAST; + } + if ((mAddr & MULTICAST_MASK) != 0) { + return TYPE_MULTICAST; + } + return TYPE_UNICAST; + } + + /** + * @return true if this MacAddress is a locally assigned address. + */ + public boolean isLocallyAssigned() { + return (mAddr & LOCALLY_ASSIGNED_MASK) != 0; + } + + /** + * Convert this MacAddress to a byte array. + * + * The returned array is in network order. For example, if this MacAddress is 1:2:3:4:5:6, + * the returned array is [1, 2, 3, 4, 5, 6]. + * + * @return a byte array representation of this MacAddress. + */ + public @NonNull byte[] toByteArray() { + return byteAddrFromLongAddr(mAddr); + } + + /** + * Returns a human-readable representation of this MacAddress. + * The exact format is implementation-dependent and should not be assumed to have any + * particular format. + */ + @Override + public @NonNull String toString() { + return stringAddrFromLongAddr(mAddr); + } + + /** + * @return a String representation of the OUI part of this MacAddress made of 3 hexadecimal + * numbers in [0,ff] joined by ':' characters. + */ + public @NonNull String toOuiString() { + return String.format( + "%02x:%02x:%02x", (mAddr >> 40) & 0xff, (mAddr >> 32) & 0xff, (mAddr >> 24) & 0xff); + } + + @Override + public int hashCode() { + return (int) ((mAddr >> 32) ^ mAddr); + } + + @Override + public boolean equals(Object o) { + return (o instanceof MacAddress) && ((MacAddress) o).mAddr == mAddr; + } + + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeLong(mAddr); + } + + @Override + public int describeContents() { + return 0; + } + + public static final @android.annotation.NonNull Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public MacAddress createFromParcel(Parcel in) { + return new MacAddress(in.readLong()); + } + + public MacAddress[] newArray(int size) { + return new MacAddress[size]; + } + }; + + /** + * Returns true if the given byte array is an valid MAC address. + * A valid byte array representation for a MacAddress is a non-null array of length 6. + * + * @param addr a byte array. + * @return true if the given byte array is not null and has the length of a MAC address. + * + * @hide + */ + public static boolean isMacAddress(byte[] addr) { + return MacAddressUtils.isMacAddress(addr); + } + + /** + * Returns the MAC address type of the MAC address represented by the given byte array, + * or null if the given byte array does not represent a MAC address. + * A valid byte array representation for a MacAddress is a non-null array of length 6. + * + * @param addr a byte array representing a MAC address. + * @return the int constant representing the MAC address type of the MAC address represented + * by the given byte array, or type UNKNOWN if the byte array is not a valid MAC address. + * + * @hide + */ + public static int macAddressType(byte[] addr) { + if (!isMacAddress(addr)) { + return TYPE_UNKNOWN; + } + return MacAddress.fromBytes(addr).getAddressType(); + } + + /** + * Converts a String representation of a MAC address to a byte array representation. + * A valid String representation for a MacAddress is a series of 6 values in the + * range [0,ff] printed in hexadecimal and joined by ':' characters. + * + * @param addr a String representation of a MAC address. + * @return the byte representation of the MAC address. + * @throws IllegalArgumentException if the given String is not a valid representation. + * + * @hide + */ + public static @NonNull byte[] byteAddrFromStringAddr(String addr) { + Preconditions.checkNotNull(addr); + String[] parts = addr.split(":"); + if (parts.length != ETHER_ADDR_LEN) { + throw new IllegalArgumentException(addr + " was not a valid MAC address"); + } + byte[] bytes = new byte[ETHER_ADDR_LEN]; + for (int i = 0; i < ETHER_ADDR_LEN; i++) { + int x = Integer.valueOf(parts[i], 16); + if (x < 0 || 0xff < x) { + throw new IllegalArgumentException(addr + "was not a valid MAC address"); + } + bytes[i] = (byte) x; + } + return bytes; + } + + /** + * Converts a byte array representation of a MAC address to a String representation made + * of 6 hexadecimal numbers in [0,ff] joined by ':' characters. + * A valid byte array representation for a MacAddress is a non-null array of length 6. + * + * @param addr a byte array representation of a MAC address. + * @return the String representation of the MAC address. + * @throws IllegalArgumentException if the given byte array is not a valid representation. + * + * @hide + */ + public static @NonNull String stringAddrFromByteAddr(byte[] addr) { + if (!isMacAddress(addr)) { + return null; + } + return String.format("%02x:%02x:%02x:%02x:%02x:%02x", + addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); + } + + private static byte[] byteAddrFromLongAddr(long addr) { + return MacAddressUtils.byteAddrFromLongAddr(addr); + } + + private static long longAddrFromByteAddr(byte[] addr) { + return MacAddressUtils.longAddrFromByteAddr(addr); + } + + // Internal conversion function equivalent to longAddrFromByteAddr(byteAddrFromStringAddr(addr)) + // that avoids the allocation of an intermediary byte[]. + private static long longAddrFromStringAddr(String addr) { + Preconditions.checkNotNull(addr); + String[] parts = addr.split(":"); + if (parts.length != ETHER_ADDR_LEN) { + throw new IllegalArgumentException(addr + " was not a valid MAC address"); + } + long longAddr = 0; + for (int i = 0; i < parts.length; i++) { + int x = Integer.valueOf(parts[i], 16); + if (x < 0 || 0xff < x) { + throw new IllegalArgumentException(addr + "was not a valid MAC address"); + } + longAddr = x + (longAddr << 8); + } + return longAddr; + } + + // Internal conversion function equivalent to stringAddrFromByteAddr(byteAddrFromLongAddr(addr)) + // that avoids the allocation of an intermediary byte[]. + private static @NonNull String stringAddrFromLongAddr(long addr) { + return String.format("%02x:%02x:%02x:%02x:%02x:%02x", + (addr >> 40) & 0xff, + (addr >> 32) & 0xff, + (addr >> 24) & 0xff, + (addr >> 16) & 0xff, + (addr >> 8) & 0xff, + addr & 0xff); + } + + /** + * Creates a MacAddress from the given String representation. A valid String representation + * for a MacAddress is a series of 6 values in the range [0,ff] printed in hexadecimal + * and joined by ':' characters. + * + * @param addr a String representation of a MAC address. + * @return the MacAddress corresponding to the given String representation. + * @throws IllegalArgumentException if the given String is not a valid representation. + */ + public static @NonNull MacAddress fromString(@NonNull String addr) { + return new MacAddress(longAddrFromStringAddr(addr)); + } + + /** + * Creates a MacAddress from the given byte array representation. + * A valid byte array representation for a MacAddress is a non-null array of length 6. + * + * @param addr a byte array representation of a MAC address. + * @return the MacAddress corresponding to the given byte array representation. + * @throws IllegalArgumentException if the given byte array is not a valid representation. + */ + public static @NonNull MacAddress fromBytes(@NonNull byte[] addr) { + return new MacAddress(longAddrFromByteAddr(addr)); + } + + /** + * Returns a generated MAC address whose 24 least significant bits constituting the + * NIC part of the address are randomly selected and has Google OUI base. + * + * The locally assigned bit is always set to 1. The multicast bit is always set to 0. + * + * @return a random locally assigned, unicast MacAddress with Google OUI. + * + * @hide + */ + public static @NonNull MacAddress createRandomUnicastAddressWithGoogleBase() { + return MacAddressUtils.createRandomUnicastAddress(BASE_GOOGLE_MAC, new SecureRandom()); + } + + // Convenience function for working around the lack of byte literals. + private static byte[] addr(int... in) { + if (in.length != ETHER_ADDR_LEN) { + throw new IllegalArgumentException(Arrays.toString(in) + + " was not an array with length equal to " + ETHER_ADDR_LEN); + } + byte[] out = new byte[ETHER_ADDR_LEN]; + for (int i = 0; i < ETHER_ADDR_LEN; i++) { + out[i] = (byte) in[i]; + } + return out; + } + + /** + * Checks if this MAC Address matches the provided range. + * + * @param baseAddress MacAddress representing the base address to compare with. + * @param mask MacAddress representing the mask to use during comparison. + * @return true if this MAC Address matches the given range. + * + */ + public boolean matches(@NonNull MacAddress baseAddress, @NonNull MacAddress mask) { + Preconditions.checkNotNull(baseAddress); + Preconditions.checkNotNull(mask); + return (mAddr & mask.mAddr) == (baseAddress.mAddr & mask.mAddr); + } + + /** + * Create a link-local Inet6Address from the MAC address. The EUI-48 MAC address is converted + * to an EUI-64 MAC address per RFC 4291. The resulting EUI-64 is used to construct a link-local + * IPv6 address per RFC 4862. + * + * @return A link-local Inet6Address constructed from the MAC address. + */ + public @Nullable Inet6Address getLinkLocalIpv6FromEui48Mac() { + byte[] macEui48Bytes = toByteArray(); + byte[] addr = new byte[16]; + + addr[0] = (byte) 0xfe; + addr[1] = (byte) 0x80; + addr[8] = (byte) (macEui48Bytes[0] ^ (byte) 0x02); // flip the link-local bit + addr[9] = macEui48Bytes[1]; + addr[10] = macEui48Bytes[2]; + addr[11] = (byte) 0xff; + addr[12] = (byte) 0xfe; + addr[13] = macEui48Bytes[3]; + addr[14] = macEui48Bytes[4]; + addr[15] = macEui48Bytes[5]; + + try { + return Inet6Address.getByAddress(null, addr, 0); + } catch (UnknownHostException e) { + return null; + } + } +} diff --git a/packages/Connectivity/framework/src/android/net/NattKeepalivePacketData.java b/packages/Connectivity/framework/src/android/net/NattKeepalivePacketData.java new file mode 100644 index 000000000000..c4f8fc281f25 --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/NattKeepalivePacketData.java @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import static android.net.InvalidPacketException.ERROR_INVALID_IP_ADDRESS; +import static android.net.InvalidPacketException.ERROR_INVALID_PORT; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.os.Parcel; +import android.os.Parcelable; +import android.system.OsConstants; + +import com.android.net.module.util.IpUtils; + +import java.net.Inet4Address; +import java.net.InetAddress; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.Objects; + +/** @hide */ +@SystemApi +public final class NattKeepalivePacketData extends KeepalivePacketData implements Parcelable { + private static final int IPV4_HEADER_LENGTH = 20; + private static final int UDP_HEADER_LENGTH = 8; + + // This should only be constructed via static factory methods, such as + // nattKeepalivePacket + public NattKeepalivePacketData(@NonNull InetAddress srcAddress, int srcPort, + @NonNull InetAddress dstAddress, int dstPort, @NonNull byte[] data) throws + InvalidPacketException { + super(srcAddress, srcPort, dstAddress, dstPort, data); + } + + /** + * Factory method to create Nat-T keepalive packet structure. + * @hide + */ + public static NattKeepalivePacketData nattKeepalivePacket( + InetAddress srcAddress, int srcPort, InetAddress dstAddress, int dstPort) + throws InvalidPacketException { + + if (!(srcAddress instanceof Inet4Address) || !(dstAddress instanceof Inet4Address)) { + throw new InvalidPacketException(ERROR_INVALID_IP_ADDRESS); + } + + if (dstPort != NattSocketKeepalive.NATT_PORT) { + throw new InvalidPacketException(ERROR_INVALID_PORT); + } + + int length = IPV4_HEADER_LENGTH + UDP_HEADER_LENGTH + 1; + ByteBuffer buf = ByteBuffer.allocate(length); + buf.order(ByteOrder.BIG_ENDIAN); + buf.putShort((short) 0x4500); // IP version and TOS + buf.putShort((short) length); + buf.putInt(0); // ID, flags, offset + buf.put((byte) 64); // TTL + buf.put((byte) OsConstants.IPPROTO_UDP); + int ipChecksumOffset = buf.position(); + buf.putShort((short) 0); // IP checksum + buf.put(srcAddress.getAddress()); + buf.put(dstAddress.getAddress()); + buf.putShort((short) srcPort); + buf.putShort((short) dstPort); + buf.putShort((short) (length - 20)); // UDP length + int udpChecksumOffset = buf.position(); + buf.putShort((short) 0); // UDP checksum + buf.put((byte) 0xff); // NAT-T keepalive + buf.putShort(ipChecksumOffset, IpUtils.ipChecksum(buf, 0)); + buf.putShort(udpChecksumOffset, IpUtils.udpChecksum(buf, 0, IPV4_HEADER_LENGTH)); + + return new NattKeepalivePacketData(srcAddress, srcPort, dstAddress, dstPort, buf.array()); + } + + /** Parcelable Implementation */ + public int describeContents() { + return 0; + } + + /** Write to parcel */ + public void writeToParcel(@NonNull Parcel out, int flags) { + out.writeString(getSrcAddress().getHostAddress()); + out.writeString(getDstAddress().getHostAddress()); + out.writeInt(getSrcPort()); + out.writeInt(getDstPort()); + } + + /** Parcelable Creator */ + public static final @NonNull Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public NattKeepalivePacketData createFromParcel(Parcel in) { + final InetAddress srcAddress = + InetAddresses.parseNumericAddress(in.readString()); + final InetAddress dstAddress = + InetAddresses.parseNumericAddress(in.readString()); + final int srcPort = in.readInt(); + final int dstPort = in.readInt(); + try { + return NattKeepalivePacketData.nattKeepalivePacket(srcAddress, srcPort, + dstAddress, dstPort); + } catch (InvalidPacketException e) { + throw new IllegalArgumentException( + "Invalid NAT-T keepalive data: " + e.getError()); + } + } + + public NattKeepalivePacketData[] newArray(int size) { + return new NattKeepalivePacketData[size]; + } + }; + + @Override + public boolean equals(@Nullable final Object o) { + if (!(o instanceof NattKeepalivePacketData)) return false; + final NattKeepalivePacketData other = (NattKeepalivePacketData) o; + final InetAddress srcAddress = getSrcAddress(); + final InetAddress dstAddress = getDstAddress(); + return srcAddress.equals(other.getSrcAddress()) + && dstAddress.equals(other.getDstAddress()) + && getSrcPort() == other.getSrcPort() + && getDstPort() == other.getDstPort(); + } + + @Override + public int hashCode() { + return Objects.hash(getSrcAddress(), getDstAddress(), getSrcPort(), getDstPort()); + } +} diff --git a/packages/Connectivity/framework/src/android/net/NattSocketKeepalive.java b/packages/Connectivity/framework/src/android/net/NattSocketKeepalive.java new file mode 100644 index 000000000000..a15d165e65e7 --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/NattSocketKeepalive.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.annotation.NonNull; +import android.os.ParcelFileDescriptor; +import android.os.RemoteException; +import android.util.Log; + +import java.net.InetAddress; +import java.util.concurrent.Executor; + +/** @hide */ +public final class NattSocketKeepalive extends SocketKeepalive { + /** The NAT-T destination port for IPsec */ + public static final int NATT_PORT = 4500; + + @NonNull private final InetAddress mSource; + @NonNull private final InetAddress mDestination; + private final int mResourceId; + + NattSocketKeepalive(@NonNull IConnectivityManager service, + @NonNull Network network, + @NonNull ParcelFileDescriptor pfd, + int resourceId, + @NonNull InetAddress source, + @NonNull InetAddress destination, + @NonNull Executor executor, + @NonNull Callback callback) { + super(service, network, pfd, executor, callback); + mSource = source; + mDestination = destination; + mResourceId = resourceId; + } + + @Override + void startImpl(int intervalSec) { + mExecutor.execute(() -> { + try { + mService.startNattKeepaliveWithFd(mNetwork, mPfd, mResourceId, + intervalSec, mCallback, + mSource.getHostAddress(), mDestination.getHostAddress()); + } catch (RemoteException e) { + Log.e(TAG, "Error starting socket keepalive: ", e); + throw e.rethrowFromSystemServer(); + } + }); + } + + @Override + void stopImpl() { + mExecutor.execute(() -> { + try { + if (mSlot != null) { + mService.stopKeepalive(mNetwork, mSlot); + } + } catch (RemoteException e) { + Log.e(TAG, "Error stopping socket keepalive: ", e); + throw e.rethrowFromSystemServer(); + } + }); + } +} diff --git a/packages/Connectivity/framework/src/android/net/Network.aidl b/packages/Connectivity/framework/src/android/net/Network.aidl new file mode 100644 index 000000000000..05622025bf33 --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/Network.aidl @@ -0,0 +1,20 @@ +/* +** +** Copyright (C) 2014 The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +package android.net; + +@JavaOnlyStableParcelable parcelable Network; diff --git a/packages/Connectivity/framework/src/android/net/Network.java b/packages/Connectivity/framework/src/android/net/Network.java new file mode 100644 index 000000000000..b07bd68a0f50 --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/Network.java @@ -0,0 +1,535 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.compat.annotation.UnsupportedAppUsage; +import android.os.Build; +import android.os.Parcel; +import android.os.ParcelFileDescriptor; +import android.os.Parcelable; +import android.system.ErrnoException; +import android.system.Os; +import android.system.OsConstants; +import android.util.proto.ProtoOutputStream; + +import com.android.internal.annotations.GuardedBy; +import com.android.okhttp.internalandroidapi.Dns; +import com.android.okhttp.internalandroidapi.HttpURLConnectionFactory; + +import libcore.io.IoUtils; + +import java.io.FileDescriptor; +import java.io.IOException; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.MalformedURLException; +import java.net.Socket; +import java.net.SocketAddress; +import java.net.SocketException; +import java.net.URL; +import java.net.URLConnection; +import java.net.UnknownHostException; +import java.util.Arrays; +import java.util.concurrent.TimeUnit; + +import javax.net.SocketFactory; + +/** + * Identifies a {@code Network}. This is supplied to applications via + * {@link ConnectivityManager.NetworkCallback} in response to the active + * {@link ConnectivityManager#requestNetwork} or passive + * {@link ConnectivityManager#registerNetworkCallback} calls. + * It is used to direct traffic to the given {@code Network}, either on a {@link Socket} basis + * through a targeted {@link SocketFactory} or process-wide via + * {@link ConnectivityManager#bindProcessToNetwork}. + */ +public class Network implements Parcelable { + + /** + * The unique id of the network. + * @hide + */ + @UnsupportedAppUsage + public final int netId; + + // Objects used to perform per-network operations such as getSocketFactory + // and openConnection, and a lock to protect access to them. + private volatile NetworkBoundSocketFactory mNetworkBoundSocketFactory = null; + // mUrlConnectionFactory is initialized lazily when it is first needed. + @GuardedBy("mLock") + private HttpURLConnectionFactory mUrlConnectionFactory; + private final Object mLock = new Object(); + + // Default connection pool values. These are evaluated at startup, just + // like the OkHttp code. Also like the OkHttp code, we will throw parse + // exceptions at class loading time if the properties are set but are not + // valid integers. + private static final boolean httpKeepAlive = + Boolean.parseBoolean(System.getProperty("http.keepAlive", "true")); + private static final int httpMaxConnections = + httpKeepAlive ? Integer.parseInt(System.getProperty("http.maxConnections", "5")) : 0; + private static final long httpKeepAliveDurationMs = + Long.parseLong(System.getProperty("http.keepAliveDuration", "300000")); // 5 minutes. + // Value used to obfuscate network handle longs. + // The HANDLE_MAGIC value MUST be kept in sync with the corresponding + // value in the native/android/net.c NDK implementation. + private static final long HANDLE_MAGIC = 0xcafed00dL; + private static final int HANDLE_MAGIC_SIZE = 32; + + // A boolean to control how getAllByName()/getByName() behaves in the face + // of Private DNS. + // + // When true, these calls will request that DNS resolution bypass any + // Private DNS that might otherwise apply. Use of this feature is restricted + // and permission checks are made by netd (attempts to bypass Private DNS + // without appropriate permission are silently turned into vanilla DNS + // requests). This only affects DNS queries made using this network object. + // + // It it not parceled to receivers because (a) it can be set or cleared at + // anytime and (b) receivers should be explicit about attempts to bypass + // Private DNS so that the intent of the code is easily determined and + // code search audits are possible. + private final transient boolean mPrivateDnsBypass; + + /** + * @hide + */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + public Network(int netId) { + this(netId, false); + } + + /** + * @hide + */ + public Network(int netId, boolean privateDnsBypass) { + this.netId = netId; + this.mPrivateDnsBypass = privateDnsBypass; + } + + /** + * @hide + */ + @SystemApi + public Network(@NonNull Network that) { + this(that.netId, that.mPrivateDnsBypass); + } + + /** + * Operates the same as {@code InetAddress.getAllByName} except that host + * resolution is done on this network. + * + * @param host the hostname or literal IP string to be resolved. + * @return the array of addresses associated with the specified host. + * @throws UnknownHostException if the address lookup fails. + */ + public InetAddress[] getAllByName(String host) throws UnknownHostException { + return InetAddress.getAllByNameOnNet(host, getNetIdForResolv()); + } + + /** + * Operates the same as {@code InetAddress.getByName} except that host + * resolution is done on this network. + * + * @param host the hostname to be resolved to an address or {@code null}. + * @return the {@code InetAddress} instance representing the host. + * @throws UnknownHostException + * if the address lookup fails. + */ + public InetAddress getByName(String host) throws UnknownHostException { + return InetAddress.getByNameOnNet(host, getNetIdForResolv()); + } + + /** + * Obtain a Network object for which Private DNS is to be bypassed when attempting + * to use {@link #getAllByName(String)}/{@link #getByName(String)} methods on the given + * instance for hostname resolution. + * + * @hide + */ + @SystemApi + public @NonNull Network getPrivateDnsBypassingCopy() { + return new Network(netId, true); + } + + /** + * Get the unique id of the network. + * + * @hide + */ + @SystemApi + public int getNetId() { + return netId; + } + + /** + * Returns a netid marked with the Private DNS bypass flag. + * + * This flag must be kept in sync with the NETID_USE_LOCAL_NAMESERVERS flag + * in system/netd/include/NetdClient.h. + * + * @hide + */ + public int getNetIdForResolv() { + return mPrivateDnsBypass + ? (int) (0x80000000L | (long) netId) // Non-portable DNS resolution flag. + : netId; + } + + /** + * A {@code SocketFactory} that produces {@code Socket}'s bound to this network. + */ + private class NetworkBoundSocketFactory extends SocketFactory { + private Socket connectToHost(String host, int port, SocketAddress localAddress) + throws IOException { + // Lookup addresses only on this Network. + InetAddress[] hostAddresses = getAllByName(host); + // Try all addresses. + for (int i = 0; i < hostAddresses.length; i++) { + try { + Socket socket = createSocket(); + boolean failed = true; + try { + if (localAddress != null) socket.bind(localAddress); + socket.connect(new InetSocketAddress(hostAddresses[i], port)); + failed = false; + return socket; + } finally { + if (failed) IoUtils.closeQuietly(socket); + } + } catch (IOException e) { + if (i == (hostAddresses.length - 1)) throw e; + } + } + throw new UnknownHostException(host); + } + + @Override + public Socket createSocket(String host, int port, InetAddress localHost, int localPort) + throws IOException { + return connectToHost(host, port, new InetSocketAddress(localHost, localPort)); + } + + @Override + public Socket createSocket(InetAddress address, int port, InetAddress localAddress, + int localPort) throws IOException { + Socket socket = createSocket(); + boolean failed = true; + try { + socket.bind(new InetSocketAddress(localAddress, localPort)); + socket.connect(new InetSocketAddress(address, port)); + failed = false; + } finally { + if (failed) IoUtils.closeQuietly(socket); + } + return socket; + } + + @Override + public Socket createSocket(InetAddress host, int port) throws IOException { + Socket socket = createSocket(); + boolean failed = true; + try { + socket.connect(new InetSocketAddress(host, port)); + failed = false; + } finally { + if (failed) IoUtils.closeQuietly(socket); + } + return socket; + } + + @Override + public Socket createSocket(String host, int port) throws IOException { + return connectToHost(host, port, null); + } + + @Override + public Socket createSocket() throws IOException { + Socket socket = new Socket(); + boolean failed = true; + try { + bindSocket(socket); + failed = false; + } finally { + if (failed) IoUtils.closeQuietly(socket); + } + return socket; + } + } + + /** + * Returns a {@link SocketFactory} bound to this network. Any {@link Socket} created by + * this factory will have its traffic sent over this {@code Network}. Note that if this + * {@code Network} ever disconnects, this factory and any {@link Socket} it produced in the + * past or future will cease to work. + * + * @return a {@link SocketFactory} which produces {@link Socket} instances bound to this + * {@code Network}. + */ + public SocketFactory getSocketFactory() { + if (mNetworkBoundSocketFactory == null) { + synchronized (mLock) { + if (mNetworkBoundSocketFactory == null) { + mNetworkBoundSocketFactory = new NetworkBoundSocketFactory(); + } + } + } + return mNetworkBoundSocketFactory; + } + + private static HttpURLConnectionFactory createUrlConnectionFactory(Dns dnsLookup) { + // Set configuration on the HttpURLConnectionFactory that will be good for all + // connections created by this Network. Configuration that might vary is left + // until openConnection() and passed as arguments. + HttpURLConnectionFactory urlConnectionFactory = new HttpURLConnectionFactory(); + urlConnectionFactory.setDns(dnsLookup); // Let traffic go via dnsLookup + // A private connection pool just for this Network. + urlConnectionFactory.setNewConnectionPool(httpMaxConnections, + httpKeepAliveDurationMs, TimeUnit.MILLISECONDS); + return urlConnectionFactory; + } + + /** + * Opens the specified {@link URL} on this {@code Network}, such that all traffic will be sent + * on this Network. The URL protocol must be {@code HTTP} or {@code HTTPS}. + * + * @return a {@code URLConnection} to the resource referred to by this URL. + * @throws MalformedURLException if the URL protocol is not HTTP or HTTPS. + * @throws IOException if an error occurs while opening the connection. + * @see java.net.URL#openConnection() + */ + public URLConnection openConnection(URL url) throws IOException { + final ConnectivityManager cm = ConnectivityManager.getInstanceOrNull(); + if (cm == null) { + throw new IOException("No ConnectivityManager yet constructed, please construct one"); + } + // TODO: Should this be optimized to avoid fetching the global proxy for every request? + final ProxyInfo proxyInfo = cm.getProxyForNetwork(this); + final java.net.Proxy proxy; + if (proxyInfo != null) { + proxy = proxyInfo.makeProxy(); + } else { + proxy = java.net.Proxy.NO_PROXY; + } + return openConnection(url, proxy); + } + + /** + * Opens the specified {@link URL} on this {@code Network}, such that all traffic will be sent + * on this Network. The URL protocol must be {@code HTTP} or {@code HTTPS}. + * + * @param proxy the proxy through which the connection will be established. + * @return a {@code URLConnection} to the resource referred to by this URL. + * @throws MalformedURLException if the URL protocol is not HTTP or HTTPS. + * @throws IllegalArgumentException if the argument proxy is null. + * @throws IOException if an error occurs while opening the connection. + * @see java.net.URL#openConnection() + */ + public URLConnection openConnection(URL url, java.net.Proxy proxy) throws IOException { + if (proxy == null) throw new IllegalArgumentException("proxy is null"); + // TODO: This creates a connection pool and host resolver for + // every Network object, instead of one for every NetId. This is + // suboptimal, because an app could potentially have more than one + // Network object for the same NetId, causing increased memory footprint + // and performance penalties due to lack of connection reuse (connection + // setup time, congestion window growth time, etc.). + // + // Instead, investigate only having one connection pool and host resolver + // for every NetId, perhaps by using a static HashMap of NetIds to + // connection pools and host resolvers. The tricky part is deciding when + // to remove a map entry; a WeakHashMap shouldn't be used because whether + // a Network is referenced doesn't correlate with whether a new Network + // will be instantiated in the near future with the same NetID. A good + // solution would involve purging empty (or when all connections are timed + // out) ConnectionPools. + final HttpURLConnectionFactory urlConnectionFactory; + synchronized (mLock) { + if (mUrlConnectionFactory == null) { + Dns dnsLookup = hostname -> Arrays.asList(getAllByName(hostname)); + mUrlConnectionFactory = createUrlConnectionFactory(dnsLookup); + } + urlConnectionFactory = mUrlConnectionFactory; + } + SocketFactory socketFactory = getSocketFactory(); + return urlConnectionFactory.openConnection(url, socketFactory, proxy); + } + + /** + * Binds the specified {@link DatagramSocket} to this {@code Network}. All data traffic on the + * socket will be sent on this {@code Network}, irrespective of any process-wide network binding + * set by {@link ConnectivityManager#bindProcessToNetwork}. The socket must not be + * connected. + */ + public void bindSocket(DatagramSocket socket) throws IOException { + // Query a property of the underlying socket to ensure that the socket's file descriptor + // exists, is available to bind to a network and is not closed. + socket.getReuseAddress(); + final ParcelFileDescriptor pfd = ParcelFileDescriptor.fromDatagramSocket(socket); + bindSocket(pfd.getFileDescriptor()); + // ParcelFileDescriptor.fromSocket() creates a dup of the original fd. The original and the + // dup share the underlying socket in the kernel. The socket is never truly closed until the + // last fd pointing to the socket being closed. So close the dup one after binding the + // socket to control the lifetime of the dup fd. + pfd.close(); + } + + /** + * Binds the specified {@link Socket} to this {@code Network}. All data traffic on the socket + * will be sent on this {@code Network}, irrespective of any process-wide network binding set by + * {@link ConnectivityManager#bindProcessToNetwork}. The socket must not be connected. + */ + public void bindSocket(Socket socket) throws IOException { + // Query a property of the underlying socket to ensure that the socket's file descriptor + // exists, is available to bind to a network and is not closed. + socket.getReuseAddress(); + final ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket); + bindSocket(pfd.getFileDescriptor()); + // ParcelFileDescriptor.fromSocket() creates a dup of the original fd. The original and the + // dup share the underlying socket in the kernel. The socket is never truly closed until the + // last fd pointing to the socket being closed. So close the dup one after binding the + // socket to control the lifetime of the dup fd. + pfd.close(); + } + + /** + * Binds the specified {@link FileDescriptor} to this {@code Network}. All data traffic on the + * socket represented by this file descriptor will be sent on this {@code Network}, + * irrespective of any process-wide network binding set by + * {@link ConnectivityManager#bindProcessToNetwork}. The socket must not be connected. + */ + public void bindSocket(FileDescriptor fd) throws IOException { + try { + final SocketAddress peer = Os.getpeername(fd); + final InetAddress inetPeer = ((InetSocketAddress) peer).getAddress(); + if (!inetPeer.isAnyLocalAddress()) { + // Apparently, the kernel doesn't update a connected UDP socket's + // routing upon mark changes. + throw new SocketException("Socket is connected"); + } + } catch (ErrnoException e) { + // getpeername() failed. + if (e.errno != OsConstants.ENOTCONN) { + throw e.rethrowAsSocketException(); + } + } catch (ClassCastException e) { + // Wasn't an InetSocketAddress. + throw new SocketException("Only AF_INET/AF_INET6 sockets supported"); + } + + final int err = NetworkUtils.bindSocketToNetwork(fd, netId); + if (err != 0) { + // bindSocketToNetwork returns negative errno. + throw new ErrnoException("Binding socket to network " + netId, -err) + .rethrowAsSocketException(); + } + } + + /** + * Returns a {@link Network} object given a handle returned from {@link #getNetworkHandle}. + * + * @param networkHandle a handle returned from {@link #getNetworkHandle}. + * @return A {@link Network} object derived from {@code networkHandle}. + */ + public static Network fromNetworkHandle(long networkHandle) { + if (networkHandle == 0) { + throw new IllegalArgumentException( + "Network.fromNetworkHandle refusing to instantiate NETID_UNSET Network."); + } + if ((networkHandle & ((1L << HANDLE_MAGIC_SIZE) - 1)) != HANDLE_MAGIC + || networkHandle < 0) { + throw new IllegalArgumentException( + "Value passed to fromNetworkHandle() is not a network handle."); + } + return new Network((int) (networkHandle >> HANDLE_MAGIC_SIZE)); + } + + /** + * Returns a handle representing this {@code Network}, for use with the NDK API. + */ + public long getNetworkHandle() { + // The network handle is explicitly not the same as the netId. + // + // The netId is an implementation detail which might be changed in the + // future, or which alone (i.e. in the absence of some additional + // context) might not be sufficient to fully identify a Network. + // + // As such, the intention is to prevent accidental misuse of the API + // that might result if a developer assumed that handles and netIds + // were identical and passing a netId to a call expecting a handle + // "just worked". Such accidental misuse, if widely deployed, might + // prevent future changes to the semantics of the netId field or + // inhibit the expansion of state required for Network objects. + // + // This extra layer of indirection might be seen as paranoia, and might + // never end up being necessary, but the added complexity is trivial. + // At some future date it may be desirable to realign the handle with + // Multiple Provisioning Domains API recommendations, as made by the + // IETF mif working group. + if (netId == 0) { + return 0L; // make this zero condition obvious for debugging + } + return (((long) netId) << HANDLE_MAGIC_SIZE) | HANDLE_MAGIC; + } + + // implement the Parcelable interface + public int describeContents() { + return 0; + } + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(netId); + } + + public static final @android.annotation.NonNull Creator CREATOR = + new Creator() { + public Network createFromParcel(Parcel in) { + int netId = in.readInt(); + + return new Network(netId); + } + + public Network[] newArray(int size) { + return new Network[size]; + } + }; + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof Network)) return false; + Network other = (Network)obj; + return this.netId == other.netId; + } + + @Override + public int hashCode() { + return netId * 11; + } + + @Override + public String toString() { + return Integer.toString(netId); + } + + /** @hide */ + public void dumpDebug(ProtoOutputStream proto, long fieldId) { + final long token = proto.start(fieldId); + proto.write(NetworkProto.NET_ID, netId); + proto.end(token); + } +} diff --git a/packages/Connectivity/framework/src/android/net/NetworkAgent.java b/packages/Connectivity/framework/src/android/net/NetworkAgent.java new file mode 100644 index 000000000000..d22d82d1f4d0 --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/NetworkAgent.java @@ -0,0 +1,1185 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.annotation.IntDef; +import android.annotation.IntRange; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.compat.annotation.UnsupportedAppUsage; +import android.content.Context; +import android.os.Build; +import android.os.Bundle; +import android.os.ConditionVariable; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.os.RemoteException; +import android.telephony.data.EpsBearerQosSessionAttributes; +import android.util.Log; + +import com.android.connectivity.aidl.INetworkAgent; +import com.android.connectivity.aidl.INetworkAgentRegistry; +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.Protocol; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * A utility class for handling for communicating between bearer-specific + * code and ConnectivityService. + * + * An agent manages the life cycle of a network. A network starts its + * life cycle when {@link register} is called on NetworkAgent. The network + * is then connecting. When full L3 connectivity has been established, + * the agent should call {@link markConnected} to inform the system that + * this network is ready to use. When the network disconnects its life + * ends and the agent should call {@link unregister}, at which point the + * system will clean up and free resources. + * Any reconnection becomes a new logical network, so after a network + * is disconnected the agent cannot be used any more. Network providers + * should create a new NetworkAgent instance to handle new connections. + * + * A bearer may have more than one NetworkAgent if it can simultaneously + * support separate networks (IMS / Internet / MMS Apns on cellular, or + * perhaps connections with different SSID or P2P for Wi-Fi). + * + * This class supports methods to start and stop sending keepalive packets. + * Keepalive packets are typically sent at periodic intervals over a network + * with NAT when there is no other traffic to avoid the network forcefully + * closing the connection. NetworkAgents that manage technologies that + * have hardware support for keepalive should implement the related + * methods to save battery life. NetworkAgent that cannot get support + * without waking up the CPU should not, as this would be prohibitive in + * terms of battery - these agents should simply not override the related + * methods, which results in the implementation returning + * {@link SocketKeepalive.ERROR_UNSUPPORTED} as appropriate. + * + * Keepalive packets need to be sent at relatively frequent intervals + * (a few seconds to a few minutes). As the contents of keepalive packets + * depend on the current network status, hardware needs to be configured + * to send them and has a limited amount of memory to do so. The HAL + * formalizes this as slots that an implementation can configure to send + * the correct packets. Devices typically have a small number of slots + * per radio technology, and the specific number of slots for each + * technology is specified in configuration files. + * {@see SocketKeepalive} for details. + * + * @hide + */ +@SystemApi +public abstract class NetworkAgent { + /** + * The {@link Network} corresponding to this object. + */ + @Nullable + private volatile Network mNetwork; + + @Nullable + private volatile INetworkAgentRegistry mRegistry; + + private interface RegistryAction { + void execute(@NonNull INetworkAgentRegistry registry) throws RemoteException; + } + + private final Handler mHandler; + private final String LOG_TAG; + private static final boolean DBG = true; + private static final boolean VDBG = false; + private final ArrayList mPreConnectedQueue = new ArrayList<>(); + private volatile long mLastBwRefreshTime = 0; + private static final long BW_REFRESH_MIN_WIN_MS = 500; + private boolean mBandwidthUpdateScheduled = false; + private AtomicBoolean mBandwidthUpdatePending = new AtomicBoolean(false); + @NonNull + private NetworkInfo mNetworkInfo; + @NonNull + private final Object mRegisterLock = new Object(); + + /** + * The ID of the {@link NetworkProvider} that created this object, or + * {@link NetworkProvider#ID_NONE} if unknown. + * @hide + */ + public final int providerId; + + private static final int BASE = Protocol.BASE_NETWORK_AGENT; + + /** + * Sent by ConnectivityService to the NetworkAgent to inform it of + * suspected connectivity problems on its network. The NetworkAgent + * should take steps to verify and correct connectivity. + * @hide + */ + public static final int CMD_SUSPECT_BAD = BASE; + + /** + * Sent by the NetworkAgent (note the EVENT vs CMD prefix) to + * ConnectivityService to pass the current NetworkInfo (connection state). + * Sent when the NetworkInfo changes, mainly due to change of state. + * obj = NetworkInfo + * @hide + */ + public static final int EVENT_NETWORK_INFO_CHANGED = BASE + 1; + + /** + * Sent by the NetworkAgent to ConnectivityService to pass the current + * NetworkCapabilties. + * obj = NetworkCapabilities + * @hide + */ + public static final int EVENT_NETWORK_CAPABILITIES_CHANGED = BASE + 2; + + /** + * Sent by the NetworkAgent to ConnectivityService to pass the current + * NetworkProperties. + * obj = NetworkProperties + * @hide + */ + public static final int EVENT_NETWORK_PROPERTIES_CHANGED = BASE + 3; + + /** + * Centralize the place where base network score, and network score scaling, will be + * stored, so as we can consistently compare apple and oranges, or wifi, ethernet and LTE + * @hide + */ + public static final int WIFI_BASE_SCORE = 60; + + /** + * Sent by the NetworkAgent to ConnectivityService to pass the current + * network score. + * arg1 = network score int + * @hide + */ + public static final int EVENT_NETWORK_SCORE_CHANGED = BASE + 4; + + /** + * Sent by the NetworkAgent to ConnectivityService to pass the current + * list of underlying networks. + * obj = array of Network objects + * @hide + */ + public static final int EVENT_UNDERLYING_NETWORKS_CHANGED = BASE + 5; + + /** + * Sent by ConnectivityService to the NetworkAgent to inform the agent of the + * networks status - whether we could use the network or could not, due to + * either a bad network configuration (no internet link) or captive portal. + * + * arg1 = either {@code VALID_NETWORK} or {@code INVALID_NETWORK} + * obj = Bundle containing map from {@code REDIRECT_URL_KEY} to {@code String} + * representing URL that Internet probe was redirect to, if it was redirected, + * or mapping to {@code null} otherwise. + * @hide + */ + public static final int CMD_REPORT_NETWORK_STATUS = BASE + 7; + + + /** + * Network validation suceeded. + * Corresponds to {@link NetworkCapabilities.NET_CAPABILITY_VALIDATED}. + */ + public static final int VALIDATION_STATUS_VALID = 1; + + /** + * Network validation was attempted and failed. This may be received more than once as + * subsequent validation attempts are made. + */ + public static final int VALIDATION_STATUS_NOT_VALID = 2; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = { "VALIDATION_STATUS_" }, value = { + VALIDATION_STATUS_VALID, + VALIDATION_STATUS_NOT_VALID + }) + public @interface ValidationStatus {} + + // TODO: remove. + /** @hide */ + public static final int VALID_NETWORK = 1; + /** @hide */ + public static final int INVALID_NETWORK = 2; + + /** + * The key for the redirect URL in the Bundle argument of {@code CMD_REPORT_NETWORK_STATUS}. + * @hide + */ + public static final String REDIRECT_URL_KEY = "redirect URL"; + + /** + * Sent by the NetworkAgent to ConnectivityService to indicate this network was + * explicitly selected. This should be sent before the NetworkInfo is marked + * CONNECTED so it can be given special treatment at that time. + * + * obj = boolean indicating whether to use this network even if unvalidated + * @hide + */ + public static final int EVENT_SET_EXPLICITLY_SELECTED = BASE + 8; + + /** + * Sent by ConnectivityService to the NetworkAgent to inform the agent of + * whether the network should in the future be used even if not validated. + * This decision is made by the user, but it is the network transport's + * responsibility to remember it. + * + * arg1 = 1 if true, 0 if false + * @hide + */ + public static final int CMD_SAVE_ACCEPT_UNVALIDATED = BASE + 9; + + /** + * Sent by ConnectivityService to the NetworkAgent to inform the agent to pull + * the underlying network connection for updated bandwidth information. + * @hide + */ + public static final int CMD_REQUEST_BANDWIDTH_UPDATE = BASE + 10; + + /** + * Sent by ConnectivityService to the NetworkAgent to request that the specified packet be sent + * periodically on the given interval. + * + * arg1 = the hardware slot number of the keepalive to start + * arg2 = interval in seconds + * obj = KeepalivePacketData object describing the data to be sent + * + * Also used internally by ConnectivityService / KeepaliveTracker, with different semantics. + * @hide + */ + public static final int CMD_START_SOCKET_KEEPALIVE = BASE + 11; + + /** + * Requests that the specified keepalive packet be stopped. + * + * arg1 = hardware slot number of the keepalive to stop. + * + * Also used internally by ConnectivityService / KeepaliveTracker, with different semantics. + * @hide + */ + public static final int CMD_STOP_SOCKET_KEEPALIVE = BASE + 12; + + /** + * Sent by the NetworkAgent to ConnectivityService to provide status on a socket keepalive + * request. This may either be the reply to a CMD_START_SOCKET_KEEPALIVE, or an asynchronous + * error notification. + * + * This is also sent by KeepaliveTracker to the app's {@link SocketKeepalive}, + * so that the app's {@link SocketKeepalive.Callback} methods can be called. + * + * arg1 = hardware slot number of the keepalive + * arg2 = error code + * @hide + */ + public static final int EVENT_SOCKET_KEEPALIVE = BASE + 13; + + /** + * Sent by ConnectivityService to inform this network transport of signal strength thresholds + * that when crossed should trigger a system wakeup and a NetworkCapabilities update. + * + * obj = int[] describing signal strength thresholds. + * @hide + */ + public static final int CMD_SET_SIGNAL_STRENGTH_THRESHOLDS = BASE + 14; + + /** + * Sent by ConnectivityService to the NeworkAgent to inform the agent to avoid + * automatically reconnecting to this network (e.g. via autojoin). Happens + * when user selects "No" option on the "Stay connected?" dialog box. + * @hide + */ + public static final int CMD_PREVENT_AUTOMATIC_RECONNECT = BASE + 15; + + /** + * Sent by the KeepaliveTracker to NetworkAgent to add a packet filter. + * + * For TCP keepalive offloads, keepalive packets are sent by the firmware. However, because the + * remote site will send ACK packets in response to the keepalive packets, the firmware also + * needs to be configured to properly filter the ACKs to prevent the system from waking up. + * This does not happen with UDP, so this message is TCP-specific. + * arg1 = hardware slot number of the keepalive to filter for. + * obj = the keepalive packet to send repeatedly. + * @hide + */ + public static final int CMD_ADD_KEEPALIVE_PACKET_FILTER = BASE + 16; + + /** + * Sent by the KeepaliveTracker to NetworkAgent to remove a packet filter. See + * {@link #CMD_ADD_KEEPALIVE_PACKET_FILTER}. + * arg1 = hardware slot number of the keepalive packet filter to remove. + * @hide + */ + public static final int CMD_REMOVE_KEEPALIVE_PACKET_FILTER = BASE + 17; + + /** + * Sent by ConnectivityService to the NetworkAgent to complete the bidirectional connection. + * obj = INetworkAgentRegistry + */ + private static final int EVENT_AGENT_CONNECTED = BASE + 18; + + /** + * Sent by ConnectivityService to the NetworkAgent to inform the agent that it was disconnected. + */ + private static final int EVENT_AGENT_DISCONNECTED = BASE + 19; + + /** + * Sent by QosCallbackTracker to {@link NetworkAgent} to register a new filter with + * callback. + * + * arg1 = QoS agent callback ID + * obj = {@link QosFilter} + * @hide + */ + public static final int CMD_REGISTER_QOS_CALLBACK = BASE + 20; + + /** + * Sent by QosCallbackTracker to {@link NetworkAgent} to unregister a callback. + * + * arg1 = QoS agent callback ID + * @hide + */ + public static final int CMD_UNREGISTER_QOS_CALLBACK = BASE + 21; + + private static NetworkInfo getLegacyNetworkInfo(final NetworkAgentConfig config) { + // The subtype can be changed with (TODO) setLegacySubtype, but it starts + // with 0 (TelephonyManager.NETWORK_TYPE_UNKNOWN) and an empty description. + final NetworkInfo ni = new NetworkInfo(config.legacyType, 0, config.legacyTypeName, ""); + ni.setIsAvailable(true); + ni.setDetailedState(NetworkInfo.DetailedState.CONNECTING, null /* reason */, + config.getLegacyExtraInfo()); + return ni; + } + + /** + * Create a new network agent. + * @param context a {@link Context} to get system services from. + * @param looper the {@link Looper} on which to invoke the callbacks. + * @param logTag the tag for logs + * @param nc the initial {@link NetworkCapabilities} of this network. Update with + * sendNetworkCapabilities. + * @param lp the initial {@link LinkProperties} of this network. Update with sendLinkProperties. + * @param score the initial score of this network. Update with sendNetworkScore. + * @param config an immutable {@link NetworkAgentConfig} for this agent. + * @param provider the {@link NetworkProvider} managing this agent. + */ + public NetworkAgent(@NonNull Context context, @NonNull Looper looper, @NonNull String logTag, + @NonNull NetworkCapabilities nc, @NonNull LinkProperties lp, int score, + @NonNull NetworkAgentConfig config, @Nullable NetworkProvider provider) { + this(looper, context, logTag, nc, lp, score, config, + provider == null ? NetworkProvider.ID_NONE : provider.getProviderId(), + getLegacyNetworkInfo(config)); + } + + private static class InitialConfiguration { + public final Context context; + public final NetworkCapabilities capabilities; + public final LinkProperties properties; + public final int score; + public final NetworkAgentConfig config; + public final NetworkInfo info; + InitialConfiguration(@NonNull Context context, @NonNull NetworkCapabilities capabilities, + @NonNull LinkProperties properties, int score, @NonNull NetworkAgentConfig config, + @NonNull NetworkInfo info) { + this.context = context; + this.capabilities = capabilities; + this.properties = properties; + this.score = score; + this.config = config; + this.info = info; + } + } + private volatile InitialConfiguration mInitialConfiguration; + + private NetworkAgent(@NonNull Looper looper, @NonNull Context context, @NonNull String logTag, + @NonNull NetworkCapabilities nc, @NonNull LinkProperties lp, int score, + @NonNull NetworkAgentConfig config, int providerId, @NonNull NetworkInfo ni) { + mHandler = new NetworkAgentHandler(looper); + LOG_TAG = logTag; + mNetworkInfo = new NetworkInfo(ni); + this.providerId = providerId; + if (ni == null || nc == null || lp == null) { + throw new IllegalArgumentException(); + } + + mInitialConfiguration = new InitialConfiguration(context, + new NetworkCapabilities(nc, /* parcelLocationSensitiveFields */ true), + new LinkProperties(lp), score, config, ni); + } + + private class NetworkAgentHandler extends Handler { + NetworkAgentHandler(Looper looper) { + super(looper); + } + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case EVENT_AGENT_CONNECTED: { + if (mRegistry != null) { + log("Received new connection while already connected!"); + } else { + if (VDBG) log("NetworkAgent fully connected"); + synchronized (mPreConnectedQueue) { + final INetworkAgentRegistry registry = (INetworkAgentRegistry) msg.obj; + mRegistry = registry; + for (RegistryAction a : mPreConnectedQueue) { + try { + a.execute(registry); + } catch (RemoteException e) { + Log.wtf(LOG_TAG, "Communication error with registry", e); + // Fall through + } + } + mPreConnectedQueue.clear(); + } + } + break; + } + case EVENT_AGENT_DISCONNECTED: { + if (DBG) log("NetworkAgent channel lost"); + // let the client know CS is done with us. + onNetworkUnwanted(); + synchronized (mPreConnectedQueue) { + mRegistry = null; + } + break; + } + case CMD_SUSPECT_BAD: { + log("Unhandled Message " + msg); + break; + } + case CMD_REQUEST_BANDWIDTH_UPDATE: { + long currentTimeMs = System.currentTimeMillis(); + if (VDBG) { + log("CMD_REQUEST_BANDWIDTH_UPDATE request received."); + } + if (currentTimeMs >= (mLastBwRefreshTime + BW_REFRESH_MIN_WIN_MS)) { + mBandwidthUpdateScheduled = false; + if (!mBandwidthUpdatePending.getAndSet(true)) { + onBandwidthUpdateRequested(); + } + } else { + // deliver the request at a later time rather than discard it completely. + if (!mBandwidthUpdateScheduled) { + long waitTime = mLastBwRefreshTime + BW_REFRESH_MIN_WIN_MS + - currentTimeMs + 1; + mBandwidthUpdateScheduled = sendEmptyMessageDelayed( + CMD_REQUEST_BANDWIDTH_UPDATE, waitTime); + } + } + break; + } + case CMD_REPORT_NETWORK_STATUS: { + String redirectUrl = ((Bundle) msg.obj).getString(REDIRECT_URL_KEY); + if (VDBG) { + log("CMD_REPORT_NETWORK_STATUS(" + + (msg.arg1 == VALID_NETWORK ? "VALID, " : "INVALID, ") + + redirectUrl); + } + Uri uri = null; + try { + if (null != redirectUrl) { + uri = Uri.parse(redirectUrl); + } + } catch (Exception e) { + Log.wtf(LOG_TAG, "Surprising URI : " + redirectUrl, e); + } + onValidationStatus(msg.arg1 /* status */, uri); + break; + } + case CMD_SAVE_ACCEPT_UNVALIDATED: { + onSaveAcceptUnvalidated(msg.arg1 != 0); + break; + } + case CMD_START_SOCKET_KEEPALIVE: { + onStartSocketKeepalive(msg.arg1 /* slot */, + Duration.ofSeconds(msg.arg2) /* interval */, + (KeepalivePacketData) msg.obj /* packet */); + break; + } + case CMD_STOP_SOCKET_KEEPALIVE: { + onStopSocketKeepalive(msg.arg1 /* slot */); + break; + } + + case CMD_SET_SIGNAL_STRENGTH_THRESHOLDS: { + onSignalStrengthThresholdsUpdated((int[]) msg.obj); + break; + } + case CMD_PREVENT_AUTOMATIC_RECONNECT: { + onAutomaticReconnectDisabled(); + break; + } + case CMD_ADD_KEEPALIVE_PACKET_FILTER: { + onAddKeepalivePacketFilter(msg.arg1 /* slot */, + (KeepalivePacketData) msg.obj /* packet */); + break; + } + case CMD_REMOVE_KEEPALIVE_PACKET_FILTER: { + onRemoveKeepalivePacketFilter(msg.arg1 /* slot */); + break; + } + case CMD_REGISTER_QOS_CALLBACK: { + onQosCallbackRegistered( + msg.arg1 /* QoS callback id */, + (QosFilter) msg.obj /* QoS filter */); + break; + } + case CMD_UNREGISTER_QOS_CALLBACK: { + onQosCallbackUnregistered( + msg.arg1 /* QoS callback id */); + break; + } + } + } + } + + /** + * Register this network agent with ConnectivityService. + * + * This method can only be called once per network agent. + * + * @return the Network associated with this network agent (which can also be obtained later + * by calling getNetwork() on this agent). + * @throws IllegalStateException thrown by the system server if this network agent is + * already registered. + */ + @NonNull + public Network register() { + if (VDBG) log("Registering NetworkAgent"); + synchronized (mRegisterLock) { + if (mNetwork != null) { + throw new IllegalStateException("Agent already registered"); + } + final ConnectivityManager cm = (ConnectivityManager) mInitialConfiguration.context + .getSystemService(Context.CONNECTIVITY_SERVICE); + mNetwork = cm.registerNetworkAgent(new NetworkAgentBinder(mHandler), + new NetworkInfo(mInitialConfiguration.info), + mInitialConfiguration.properties, mInitialConfiguration.capabilities, + mInitialConfiguration.score, mInitialConfiguration.config, providerId); + mInitialConfiguration = null; // All this memory can now be GC'd + } + return mNetwork; + } + + private static class NetworkAgentBinder extends INetworkAgent.Stub { + private static final String LOG_TAG = NetworkAgentBinder.class.getSimpleName(); + + private final Handler mHandler; + + private NetworkAgentBinder(Handler handler) { + mHandler = handler; + } + + @Override + public void onRegistered(@NonNull INetworkAgentRegistry registry) { + mHandler.sendMessage(mHandler.obtainMessage(EVENT_AGENT_CONNECTED, registry)); + } + + @Override + public void onDisconnected() { + mHandler.sendMessage(mHandler.obtainMessage(EVENT_AGENT_DISCONNECTED)); + } + + @Override + public void onBandwidthUpdateRequested() { + mHandler.sendMessage(mHandler.obtainMessage(CMD_REQUEST_BANDWIDTH_UPDATE)); + } + + @Override + public void onValidationStatusChanged( + int validationStatus, @Nullable String captivePortalUrl) { + // TODO: consider using a parcelable as argument when the interface is structured + Bundle redirectUrlBundle = new Bundle(); + redirectUrlBundle.putString(NetworkAgent.REDIRECT_URL_KEY, captivePortalUrl); + mHandler.sendMessage(mHandler.obtainMessage(CMD_REPORT_NETWORK_STATUS, + validationStatus, 0, redirectUrlBundle)); + } + + @Override + public void onSaveAcceptUnvalidated(boolean acceptUnvalidated) { + mHandler.sendMessage(mHandler.obtainMessage(CMD_SAVE_ACCEPT_UNVALIDATED, + acceptUnvalidated ? 1 : 0, 0)); + } + + @Override + public void onStartNattSocketKeepalive(int slot, int intervalDurationMs, + @NonNull NattKeepalivePacketData packetData) { + mHandler.sendMessage(mHandler.obtainMessage(CMD_START_SOCKET_KEEPALIVE, + slot, intervalDurationMs, packetData)); + } + + @Override + public void onStartTcpSocketKeepalive(int slot, int intervalDurationMs, + @NonNull TcpKeepalivePacketData packetData) { + mHandler.sendMessage(mHandler.obtainMessage(CMD_START_SOCKET_KEEPALIVE, + slot, intervalDurationMs, packetData)); + } + + @Override + public void onStopSocketKeepalive(int slot) { + mHandler.sendMessage(mHandler.obtainMessage(CMD_STOP_SOCKET_KEEPALIVE, slot, 0)); + } + + @Override + public void onSignalStrengthThresholdsUpdated(@NonNull int[] thresholds) { + mHandler.sendMessage(mHandler.obtainMessage( + CMD_SET_SIGNAL_STRENGTH_THRESHOLDS, thresholds)); + } + + @Override + public void onPreventAutomaticReconnect() { + mHandler.sendMessage(mHandler.obtainMessage(CMD_PREVENT_AUTOMATIC_RECONNECT)); + } + + @Override + public void onAddNattKeepalivePacketFilter(int slot, + @NonNull NattKeepalivePacketData packetData) { + mHandler.sendMessage(mHandler.obtainMessage(CMD_ADD_KEEPALIVE_PACKET_FILTER, + slot, 0, packetData)); + } + + @Override + public void onAddTcpKeepalivePacketFilter(int slot, + @NonNull TcpKeepalivePacketData packetData) { + mHandler.sendMessage(mHandler.obtainMessage(CMD_ADD_KEEPALIVE_PACKET_FILTER, + slot, 0, packetData)); + } + + @Override + public void onRemoveKeepalivePacketFilter(int slot) { + mHandler.sendMessage(mHandler.obtainMessage(CMD_REMOVE_KEEPALIVE_PACKET_FILTER, + slot, 0)); + } + + @Override + public void onQosFilterCallbackRegistered(final int qosCallbackId, + final QosFilterParcelable qosFilterParcelable) { + if (qosFilterParcelable.getQosFilter() != null) { + mHandler.sendMessage( + mHandler.obtainMessage(CMD_REGISTER_QOS_CALLBACK, qosCallbackId, 0, + qosFilterParcelable.getQosFilter())); + return; + } + + Log.wtf(LOG_TAG, "onQosFilterCallbackRegistered: qos filter is null."); + } + + @Override + public void onQosCallbackUnregistered(final int qosCallbackId) { + mHandler.sendMessage(mHandler.obtainMessage( + CMD_UNREGISTER_QOS_CALLBACK, qosCallbackId, 0, null)); + } + } + + /** + * Register this network agent with a testing harness. + * + * The returned Messenger sends messages to the Handler. This allows a test to send + * this object {@code CMD_*} messages as if they came from ConnectivityService, which + * is useful for testing the behavior. + * + * @hide + */ + public INetworkAgent registerForTest(final Network network) { + log("Registering NetworkAgent for test"); + synchronized (mRegisterLock) { + mNetwork = network; + mInitialConfiguration = null; + } + return new NetworkAgentBinder(mHandler); + } + + /** + * Waits for the handler to be idle. + * This is useful for testing, and has smaller scope than an accessor to mHandler. + * TODO : move the implementation in common library with the tests + * @hide + */ + @VisibleForTesting + public boolean waitForIdle(final long timeoutMs) { + final ConditionVariable cv = new ConditionVariable(false); + mHandler.post(cv::open); + return cv.block(timeoutMs); + } + + /** + * @return The Network associated with this agent, or null if it's not registered yet. + */ + @Nullable + public Network getNetwork() { + return mNetwork; + } + + private void queueOrSendMessage(@NonNull RegistryAction action) { + synchronized (mPreConnectedQueue) { + if (mRegistry != null) { + try { + action.execute(mRegistry); + } catch (RemoteException e) { + Log.wtf(LOG_TAG, "Error executing registry action", e); + // Fall through: the channel is asynchronous and does not report errors back + } + } else { + mPreConnectedQueue.add(action); + } + } + } + + /** + * Must be called by the agent when the network's {@link LinkProperties} change. + * @param linkProperties the new LinkProperties. + */ + public final void sendLinkProperties(@NonNull LinkProperties linkProperties) { + Objects.requireNonNull(linkProperties); + final LinkProperties lp = new LinkProperties(linkProperties); + queueOrSendMessage(reg -> reg.sendLinkProperties(lp)); + } + + /** + * Must be called by the agent when the network's underlying networks change. + * + *

{@code networks} is one of the following: + *

    + *
  • a non-empty array: an array of one or more {@link Network}s, in + * decreasing preference order. For example, if this VPN uses both wifi and mobile (cellular) + * networks to carry app traffic, but prefers or uses wifi more than mobile, wifi should appear + * first in the array.
  • + *
  • an empty array: a zero-element array, meaning that the VPN has no + * underlying network connection, and thus, app traffic will not be sent or received.
  • + *
  • null: (default) signifies that the VPN uses whatever is the system's + * default network. I.e., it doesn't use the {@code bindSocket} or {@code bindDatagramSocket} + * APIs mentioned above to send traffic over specific channels.
  • + *
+ * + * @param underlyingNetworks the new list of underlying networks. + * @see {@link VpnService.Builder#setUnderlyingNetworks(Network[])} + */ + public final void setUnderlyingNetworks(@Nullable List underlyingNetworks) { + final ArrayList underlyingArray = (underlyingNetworks != null) + ? new ArrayList<>(underlyingNetworks) : null; + queueOrSendMessage(reg -> reg.sendUnderlyingNetworks(underlyingArray)); + } + + /** + * Inform ConnectivityService that this agent has now connected. + * Call {@link #unregister} to disconnect. + */ + public void markConnected() { + mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null /* reason */, + mNetworkInfo.getExtraInfo()); + queueOrSendNetworkInfo(mNetworkInfo); + } + + /** + * Unregister this network agent. + * + * This signals the network has disconnected and ends its lifecycle. After this is called, + * the network is torn down and this agent can no longer be used. + */ + public void unregister() { + // When unregistering an agent nobody should use the extrainfo (or reason) any more. + mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, null /* reason */, + null /* extraInfo */); + queueOrSendNetworkInfo(mNetworkInfo); + } + + /** + * Change the legacy subtype of this network agent. + * + * This is only for backward compatibility and should not be used by non-legacy network agents, + * or agents that did not use to set a subtype. As such, only TYPE_MOBILE type agents can use + * this and others will be thrown an exception if they try. + * + * @deprecated this is for backward compatibility only. + * @param legacySubtype the legacy subtype. + * @hide + */ + @Deprecated + public void setLegacySubtype(final int legacySubtype, @NonNull final String legacySubtypeName) { + mNetworkInfo.setSubtype(legacySubtype, legacySubtypeName); + queueOrSendNetworkInfo(mNetworkInfo); + } + + /** + * Set the ExtraInfo of this network agent. + * + * This sets the ExtraInfo field inside the NetworkInfo returned by legacy public API and the + * broadcasts about the corresponding Network. + * This is only for backward compatibility and should not be used by non-legacy network agents, + * who will be thrown an exception if they try. The extra info should only be : + *
    + *
  • For cellular agents, the APN name.
  • + *
  • For ethernet agents, the interface name.
  • + *
+ * + * @deprecated this is for backward compatibility only. + * @param extraInfo the ExtraInfo. + * @hide + */ + @Deprecated + public void setLegacyExtraInfo(@Nullable final String extraInfo) { + mNetworkInfo.setExtraInfo(extraInfo); + queueOrSendNetworkInfo(mNetworkInfo); + } + + /** + * Must be called by the agent when it has a new NetworkInfo object. + * @hide TODO: expose something better. + */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) + public final void sendNetworkInfo(NetworkInfo networkInfo) { + queueOrSendNetworkInfo(new NetworkInfo(networkInfo)); + } + + private void queueOrSendNetworkInfo(NetworkInfo networkInfo) { + queueOrSendMessage(reg -> reg.sendNetworkInfo(networkInfo)); + } + + /** + * Must be called by the agent when the network's {@link NetworkCapabilities} change. + * @param networkCapabilities the new NetworkCapabilities. + */ + public final void sendNetworkCapabilities(@NonNull NetworkCapabilities networkCapabilities) { + Objects.requireNonNull(networkCapabilities); + mBandwidthUpdatePending.set(false); + mLastBwRefreshTime = System.currentTimeMillis(); + final NetworkCapabilities nc = + new NetworkCapabilities(networkCapabilities, + /* parcelLocationSensitiveFields */ true); + queueOrSendMessage(reg -> reg.sendNetworkCapabilities(nc)); + } + + /** + * Must be called by the agent to update the score of this network. + * + * @param score the new score, between 0 and 99. + */ + public final void sendNetworkScore(@IntRange(from = 0, to = 99) int score) { + if (score < 0) { + throw new IllegalArgumentException("Score must be >= 0"); + } + queueOrSendMessage(reg -> reg.sendScore(score)); + } + + /** + * Must be called by the agent to indicate this network was manually selected by the user. + * This should be called before the NetworkInfo is marked CONNECTED so that this + * Network can be given special treatment at that time. If {@code acceptUnvalidated} is + * {@code true}, then the system will switch to this network. If it is {@code false} and the + * network cannot be validated, the system will ask the user whether to switch to this network. + * If the user confirms and selects "don't ask again", then the system will call + * {@link #saveAcceptUnvalidated} to persist the user's choice. Thus, if the transport ever + * calls this method with {@code acceptUnvalidated} set to {@code false}, it must also implement + * {@link #saveAcceptUnvalidated} to respect the user's choice. + * @hide should move to NetworkAgentConfig. + */ + public void explicitlySelected(boolean acceptUnvalidated) { + explicitlySelected(true /* explicitlySelected */, acceptUnvalidated); + } + + /** + * Must be called by the agent to indicate whether the network was manually selected by the + * user. This should be called before the network becomes connected, so it can be given + * special treatment when it does. + * + * If {@code explicitlySelected} is {@code true}, and {@code acceptUnvalidated} is {@code true}, + * then the system will switch to this network. If {@code explicitlySelected} is {@code true} + * and {@code acceptUnvalidated} is {@code false}, and the network cannot be validated, the + * system will ask the user whether to switch to this network. If the user confirms and selects + * "don't ask again", then the system will call {@link #saveAcceptUnvalidated} to persist the + * user's choice. Thus, if the transport ever calls this method with {@code explicitlySelected} + * set to {@code true} and {@code acceptUnvalidated} set to {@code false}, it must also + * implement {@link #saveAcceptUnvalidated} to respect the user's choice. + * + * If {@code explicitlySelected} is {@code false} and {@code acceptUnvalidated} is + * {@code true}, the system will interpret this as the user having accepted partial connectivity + * on this network. Thus, the system will switch to the network and consider it validated even + * if it only provides partial connectivity, but the network is not otherwise treated specially. + * @hide should move to NetworkAgentConfig. + */ + public void explicitlySelected(boolean explicitlySelected, boolean acceptUnvalidated) { + queueOrSendMessage(reg -> reg.sendExplicitlySelected( + explicitlySelected, acceptUnvalidated)); + } + + /** + * Called when ConnectivityService has indicated they no longer want this network. + * The parent factory should (previously) have received indication of the change + * as well, either canceling NetworkRequests or altering their score such that this + * network won't be immediately requested again. + */ + public void onNetworkUnwanted() { + unwanted(); + } + /** @hide TODO delete once subclasses have moved to onNetworkUnwanted. */ + protected void unwanted() { + } + + /** + * Called when ConnectivityService request a bandwidth update. The parent factory + * shall try to overwrite this method and produce a bandwidth update if capable. + * @hide + */ + public void onBandwidthUpdateRequested() { + pollLceData(); + } + /** @hide TODO delete once subclasses have moved to onBandwidthUpdateRequested. */ + protected void pollLceData() { + } + + /** + * Called when the system determines the usefulness of this network. + * + * The system attempts to validate Internet connectivity on networks that provide the + * {@link NetworkCapabilities#NET_CAPABILITY_INTERNET} capability. + * + * Currently there are two possible values: + * {@code VALIDATION_STATUS_VALID} if Internet connectivity was validated, + * {@code VALIDATION_STATUS_NOT_VALID} if Internet connectivity was not validated. + * + * This is guaranteed to be called again when the network status changes, but the system + * may also call this multiple times even if the status does not change. + * + * @param status one of {@code VALIDATION_STATUS_VALID} or {@code VALIDATION_STATUS_NOT_VALID}. + * @param redirectUri If Internet connectivity is being redirected (e.g., on a captive portal), + * this is the destination the probes are being redirected to, otherwise {@code null}. + */ + public void onValidationStatus(@ValidationStatus int status, @Nullable Uri redirectUri) { + networkStatus(status, null == redirectUri ? "" : redirectUri.toString()); + } + /** @hide TODO delete once subclasses have moved to onValidationStatus */ + protected void networkStatus(int status, String redirectUrl) { + } + + + /** + * Called when the user asks to remember the choice to use this network even if unvalidated. + * The transport is responsible for remembering the choice, and the next time the user connects + * to the network, should explicitlySelected with {@code acceptUnvalidated} set to {@code true}. + * This method will only be called if {@link #explicitlySelected} was called with + * {@code acceptUnvalidated} set to {@code false}. + * @param accept whether the user wants to use the network even if unvalidated. + */ + public void onSaveAcceptUnvalidated(boolean accept) { + saveAcceptUnvalidated(accept); + } + /** @hide TODO delete once subclasses have moved to onSaveAcceptUnvalidated */ + protected void saveAcceptUnvalidated(boolean accept) { + } + + /** + * Requests that the network hardware send the specified packet at the specified interval. + * + * @param slot the hardware slot on which to start the keepalive. + * @param interval the interval between packets, between 10 and 3600. Note that this API + * does not support sub-second precision and will round off the request. + * @param packet the packet to send. + */ + // seconds is from SocketKeepalive.MIN_INTERVAL_SEC to MAX_INTERVAL_SEC, but these should + // not be exposed as constants because they may change in the future (API guideline 4.8) + // and should have getters if exposed at all. Getters can't be used in the annotation, + // so the values unfortunately need to be copied. + public void onStartSocketKeepalive(int slot, @NonNull Duration interval, + @NonNull KeepalivePacketData packet) { + final long intervalSeconds = interval.getSeconds(); + if (intervalSeconds < SocketKeepalive.MIN_INTERVAL_SEC + || intervalSeconds > SocketKeepalive.MAX_INTERVAL_SEC) { + throw new IllegalArgumentException("Interval needs to be comprised between " + + SocketKeepalive.MIN_INTERVAL_SEC + " and " + SocketKeepalive.MAX_INTERVAL_SEC + + " but was " + intervalSeconds); + } + final Message msg = mHandler.obtainMessage(CMD_START_SOCKET_KEEPALIVE, slot, + (int) intervalSeconds, packet); + startSocketKeepalive(msg); + msg.recycle(); + } + /** @hide TODO delete once subclasses have moved to onStartSocketKeepalive */ + protected void startSocketKeepalive(Message msg) { + onSocketKeepaliveEvent(msg.arg1, SocketKeepalive.ERROR_UNSUPPORTED); + } + + /** + * Requests that the network hardware stop a previously-started keepalive. + * + * @param slot the hardware slot on which to stop the keepalive. + */ + public void onStopSocketKeepalive(int slot) { + Message msg = mHandler.obtainMessage(CMD_STOP_SOCKET_KEEPALIVE, slot, 0, null); + stopSocketKeepalive(msg); + msg.recycle(); + } + /** @hide TODO delete once subclasses have moved to onStopSocketKeepalive */ + protected void stopSocketKeepalive(Message msg) { + onSocketKeepaliveEvent(msg.arg1, SocketKeepalive.ERROR_UNSUPPORTED); + } + + /** + * Must be called by the agent when a socket keepalive event occurs. + * + * @param slot the hardware slot on which the event occurred. + * @param event the event that occurred, as one of the SocketKeepalive.ERROR_* + * or SocketKeepalive.SUCCESS constants. + */ + public final void sendSocketKeepaliveEvent(int slot, + @SocketKeepalive.KeepaliveEvent int event) { + queueOrSendMessage(reg -> reg.sendSocketKeepaliveEvent(slot, event)); + } + /** @hide TODO delete once callers have moved to sendSocketKeepaliveEvent */ + public void onSocketKeepaliveEvent(int slot, int reason) { + sendSocketKeepaliveEvent(slot, reason); + } + + /** + * Called by ConnectivityService to add specific packet filter to network hardware to block + * replies (e.g., TCP ACKs) matching the sent keepalive packets. Implementations that support + * this feature must override this method. + * + * @param slot the hardware slot on which the keepalive should be sent. + * @param packet the packet that is being sent. + */ + public void onAddKeepalivePacketFilter(int slot, @NonNull KeepalivePacketData packet) { + Message msg = mHandler.obtainMessage(CMD_ADD_KEEPALIVE_PACKET_FILTER, slot, 0, packet); + addKeepalivePacketFilter(msg); + msg.recycle(); + } + /** @hide TODO delete once subclasses have moved to onAddKeepalivePacketFilter */ + protected void addKeepalivePacketFilter(Message msg) { + } + + /** + * Called by ConnectivityService to remove a packet filter installed with + * {@link #addKeepalivePacketFilter(Message)}. Implementations that support this feature + * must override this method. + * + * @param slot the hardware slot on which the keepalive is being sent. + */ + public void onRemoveKeepalivePacketFilter(int slot) { + Message msg = mHandler.obtainMessage(CMD_REMOVE_KEEPALIVE_PACKET_FILTER, slot, 0, null); + removeKeepalivePacketFilter(msg); + msg.recycle(); + } + /** @hide TODO delete once subclasses have moved to onRemoveKeepalivePacketFilter */ + protected void removeKeepalivePacketFilter(Message msg) { + } + + /** + * Called by ConnectivityService to inform this network agent of signal strength thresholds + * that when crossed should trigger a system wakeup and a NetworkCapabilities update. + * + * When the system updates the list of thresholds that should wake up the CPU for a + * given agent it will call this method on the agent. The agent that implement this + * should implement it in hardware so as to ensure the CPU will be woken up on breach. + * Agents are expected to react to a breach by sending an updated NetworkCapabilities + * object with the appropriate signal strength to sendNetworkCapabilities. + * + * The specific units are bearer-dependent. See details on the units and requests in + * {@link NetworkCapabilities.Builder#setSignalStrength}. + * + * @param thresholds the array of thresholds that should trigger wakeups. + */ + public void onSignalStrengthThresholdsUpdated(@NonNull int[] thresholds) { + setSignalStrengthThresholds(thresholds); + } + /** @hide TODO delete once subclasses have moved to onSetSignalStrengthThresholds */ + protected void setSignalStrengthThresholds(int[] thresholds) { + } + + /** + * Called when the user asks to not stay connected to this network because it was found to not + * provide Internet access. Usually followed by call to {@code unwanted}. The transport is + * responsible for making sure the device does not automatically reconnect to the same network + * after the {@code unwanted} call. + */ + public void onAutomaticReconnectDisabled() { + preventAutomaticReconnect(); + } + /** @hide TODO delete once subclasses have moved to onAutomaticReconnectDisabled */ + protected void preventAutomaticReconnect() { + } + + /** + * Called when a qos callback is registered with a filter. + * @param qosCallbackId the id for the callback registered + * @param filter the filter being registered + */ + public void onQosCallbackRegistered(final int qosCallbackId, final @NonNull QosFilter filter) { + } + + /** + * Called when a qos callback is registered with a filter. + *

+ * Any QoS events that are sent with the same callback id after this method is called + * are a no-op. + * + * @param qosCallbackId the id for the callback being unregistered + */ + public void onQosCallbackUnregistered(final int qosCallbackId) { + } + + + /** + * Sends the attributes of Eps Bearer Qos Session back to the Application + * + * @param qosCallbackId the callback id that the session belongs to + * @param sessionId the unique session id across all Eps Bearer Qos Sessions + * @param attributes the attributes of the Eps Qos Session + */ + public final void sendQosSessionAvailable(final int qosCallbackId, final int sessionId, + @NonNull final EpsBearerQosSessionAttributes attributes) { + Objects.requireNonNull(attributes, "The attributes must be non-null"); + queueOrSendMessage(ra -> ra.sendEpsQosSessionAvailable(qosCallbackId, + new QosSession(sessionId, QosSession.TYPE_EPS_BEARER), + attributes)); + } + + /** + * Sends event that the Eps Qos Session was lost. + * + * @param qosCallbackId the callback id that the session belongs to + * @param sessionId the unique session id across all Eps Bearer Qos Sessions + */ + public final void sendQosSessionLost(final int qosCallbackId, final int sessionId) { + queueOrSendMessage(ra -> ra.sendQosSessionLost(qosCallbackId, + new QosSession(sessionId, QosSession.TYPE_EPS_BEARER))); + } + + /** + * Sends the exception type back to the application. + * + * The NetworkAgent should not send anymore messages with this id. + * + * @param qosCallbackId the callback id this exception belongs to + * @param exceptionType the type of exception + */ + public final void sendQosCallbackError(final int qosCallbackId, + @QosCallbackException.ExceptionType final int exceptionType) { + queueOrSendMessage(ra -> ra.sendQosCallbackError(qosCallbackId, exceptionType)); + } + + + /** @hide */ + protected void log(final String s) { + Log.d(LOG_TAG, "NetworkAgent: " + s); + } +} diff --git a/packages/Connectivity/framework/src/android/net/NetworkAgentConfig.aidl b/packages/Connectivity/framework/src/android/net/NetworkAgentConfig.aidl new file mode 100644 index 000000000000..cb70bdd31260 --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/NetworkAgentConfig.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +parcelable NetworkAgentConfig; diff --git a/packages/Connectivity/framework/src/android/net/NetworkAgentConfig.java b/packages/Connectivity/framework/src/android/net/NetworkAgentConfig.java new file mode 100644 index 000000000000..664c2650ff0c --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/NetworkAgentConfig.java @@ -0,0 +1,440 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.Objects; + +/** + * Allows a network transport to provide the system with policy and configuration information about + * a particular network when registering a {@link NetworkAgent}. This information cannot change once the agent is registered. + * + * @hide + */ +@SystemApi +public final class NetworkAgentConfig implements Parcelable { + + /** + * If the {@link Network} is a VPN, whether apps are allowed to bypass the + * VPN. This is set by a {@link VpnService} and used by + * {@link ConnectivityManager} when creating a VPN. + * + * @hide + */ + public boolean allowBypass; + + /** + * Set if the network was manually/explicitly connected to by the user either from settings + * or a 3rd party app. For example, turning on cell data is not explicit but tapping on a wifi + * ap in the wifi settings to trigger a connection is explicit. A 3rd party app asking to + * connect to a particular access point is also explicit, though this may change in the future + * as we want apps to use the multinetwork apis. + * + * @hide + */ + public boolean explicitlySelected; + + /** + * @return whether this network was explicitly selected by the user. + */ + public boolean isExplicitlySelected() { + return explicitlySelected; + } + + /** + * Set if the user desires to use this network even if it is unvalidated. This field has meaning + * only if {@link explicitlySelected} is true. If it is, this field must also be set to the + * appropriate value based on previous user choice. + * + * TODO : rename this field to match its accessor + * @hide + */ + public boolean acceptUnvalidated; + + /** + * @return whether the system should accept this network even if it doesn't validate. + */ + public boolean isUnvalidatedConnectivityAcceptable() { + return acceptUnvalidated; + } + + /** + * Whether the user explicitly set that this network should be validated even if presence of + * only partial internet connectivity. + * + * TODO : rename this field to match its accessor + * @hide + */ + public boolean acceptPartialConnectivity; + + /** + * @return whether the system should validate this network even if it only offers partial + * Internet connectivity. + */ + public boolean isPartialConnectivityAcceptable() { + return acceptPartialConnectivity; + } + + /** + * Set to avoid surfacing the "Sign in to network" notification. + * if carrier receivers/apps are registered to handle the carrier-specific provisioning + * procedure, a carrier specific provisioning notification will be placed. + * only one notification should be displayed. This field is set based on + * which notification should be used for provisioning. + * + * @hide + */ + public boolean provisioningNotificationDisabled; + + /** + * + * @return whether the sign in to network notification is enabled by this configuration. + * @hide + */ + public boolean isProvisioningNotificationEnabled() { + return !provisioningNotificationDisabled; + } + + /** + * For mobile networks, this is the subscriber ID (such as IMSI). + * + * @hide + */ + public String subscriberId; + + /** + * @return the subscriber ID, or null if none. + * @hide + */ + @SystemApi(client = MODULE_LIBRARIES) + @Nullable + public String getSubscriberId() { + return subscriberId; + } + + /** + * Set to skip 464xlat. This means the device will treat the network as IPv6-only and + * will not attempt to detect a NAT64 via RFC 7050 DNS lookups. + * + * @hide + */ + public boolean skip464xlat; + + /** + * @return whether NAT64 prefix detection is enabled. + * @hide + */ + public boolean isNat64DetectionEnabled() { + return !skip464xlat; + } + + /** + * The legacy type of this network agent, or TYPE_NONE if unset. + * @hide + */ + public int legacyType = ConnectivityManager.TYPE_NONE; + + /** + * @return the legacy type + */ + @ConnectivityManager.LegacyNetworkType + public int getLegacyType() { + return legacyType; + } + + /** + * Set to true if the PRIVATE_DNS_BROKEN notification has shown for this network. + * Reset this bit when private DNS mode is changed from strict mode to opportunistic/off mode. + * + * This is not parceled, because it would not make sense. + * + * @hide + */ + public transient boolean hasShownBroken; + + /** + * The name of the legacy network type. It's a free-form string used in logging. + * @hide + */ + @NonNull + public String legacyTypeName = ""; + + /** + * @return the name of the legacy network type. It's a free-form string used in logging. + */ + @NonNull + public String getLegacyTypeName() { + return legacyTypeName; + } + + /** + * The legacy extra info of the agent. The extra info should only be : + *

    + *
  • For cellular agents, the APN name.
  • + *
  • For ethernet agents, the interface name.
  • + *
+ * @hide + */ + @NonNull + private String mLegacyExtraInfo = ""; + + /** + * The legacy extra info of the agent. + * @hide + */ + @NonNull + public String getLegacyExtraInfo() { + return mLegacyExtraInfo; + } + + /** @hide */ + public NetworkAgentConfig() { + } + + /** @hide */ + public NetworkAgentConfig(@Nullable NetworkAgentConfig nac) { + if (nac != null) { + allowBypass = nac.allowBypass; + explicitlySelected = nac.explicitlySelected; + acceptUnvalidated = nac.acceptUnvalidated; + acceptPartialConnectivity = nac.acceptPartialConnectivity; + subscriberId = nac.subscriberId; + provisioningNotificationDisabled = nac.provisioningNotificationDisabled; + skip464xlat = nac.skip464xlat; + legacyType = nac.legacyType; + legacyTypeName = nac.legacyTypeName; + mLegacyExtraInfo = nac.mLegacyExtraInfo; + } + } + + /** + * Builder class to facilitate constructing {@link NetworkAgentConfig} objects. + */ + public static final class Builder { + private final NetworkAgentConfig mConfig = new NetworkAgentConfig(); + + /** + * Sets whether the network was explicitly selected by the user. + * + * @return this builder, to facilitate chaining. + */ + @NonNull + public Builder setExplicitlySelected(final boolean explicitlySelected) { + mConfig.explicitlySelected = explicitlySelected; + return this; + } + + /** + * Sets whether the system should validate this network even if it is found not to offer + * Internet connectivity. + * + * @return this builder, to facilitate chaining. + */ + @NonNull + public Builder setUnvalidatedConnectivityAcceptable( + final boolean unvalidatedConnectivityAcceptable) { + mConfig.acceptUnvalidated = unvalidatedConnectivityAcceptable; + return this; + } + + /** + * Sets whether the system should validate this network even if it is found to only offer + * partial Internet connectivity. + * + * @return this builder, to facilitate chaining. + */ + @NonNull + public Builder setPartialConnectivityAcceptable( + final boolean partialConnectivityAcceptable) { + mConfig.acceptPartialConnectivity = partialConnectivityAcceptable; + return this; + } + + /** + * Sets the subscriber ID for this network. + * + * @return this builder, to facilitate chaining. + * @hide + */ + @NonNull + @SystemApi(client = MODULE_LIBRARIES) + public Builder setSubscriberId(@Nullable String subscriberId) { + mConfig.subscriberId = subscriberId; + return this; + } + + /** + * Disables active detection of NAT64 (e.g., via RFC 7050 DNS lookups). Used to save power + * and reduce idle traffic on networks that are known to be IPv6-only without a NAT64. + * + * @return this builder, to facilitate chaining. + * @hide + */ + @NonNull + public Builder disableNat64Detection() { + mConfig.skip464xlat = true; + return this; + } + + /** + * Disables the "Sign in to network" notification. Used if the network transport will + * perform its own carrier-specific provisioning procedure. + * + * @return this builder, to facilitate chaining. + * @hide + */ + @NonNull + public Builder disableProvisioningNotification() { + mConfig.provisioningNotificationDisabled = true; + return this; + } + + /** + * Sets the legacy type for this network. + * + * @param legacyType the type + * @return this builder, to facilitate chaining. + */ + @NonNull + public Builder setLegacyType(int legacyType) { + mConfig.legacyType = legacyType; + return this; + } + + /** + * Sets the name of the legacy type of the agent. It's a free-form string used in logging. + * @param legacyTypeName the name + * @return this builder, to facilitate chaining. + */ + @NonNull + public Builder setLegacyTypeName(@NonNull String legacyTypeName) { + mConfig.legacyTypeName = legacyTypeName; + return this; + } + + /** + * Sets the legacy extra info of the agent. + * @param legacyExtraInfo the legacy extra info. + * @return this builder, to facilitate chaining. + * @hide + */ + @NonNull + public Builder setLegacyExtraInfo(@NonNull String legacyExtraInfo) { + mConfig.mLegacyExtraInfo = legacyExtraInfo; + return this; + } + + /** + * Returns the constructed {@link NetworkAgentConfig} object. + */ + @NonNull + public NetworkAgentConfig build() { + return mConfig; + } + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + final NetworkAgentConfig that = (NetworkAgentConfig) o; + return allowBypass == that.allowBypass + && explicitlySelected == that.explicitlySelected + && acceptUnvalidated == that.acceptUnvalidated + && acceptPartialConnectivity == that.acceptPartialConnectivity + && provisioningNotificationDisabled == that.provisioningNotificationDisabled + && skip464xlat == that.skip464xlat + && legacyType == that.legacyType + && Objects.equals(subscriberId, that.subscriberId) + && Objects.equals(legacyTypeName, that.legacyTypeName) + && Objects.equals(mLegacyExtraInfo, that.mLegacyExtraInfo); + } + + @Override + public int hashCode() { + return Objects.hash(allowBypass, explicitlySelected, acceptUnvalidated, + acceptPartialConnectivity, provisioningNotificationDisabled, subscriberId, + skip464xlat, legacyType, legacyTypeName, mLegacyExtraInfo); + } + + @Override + public String toString() { + return "NetworkAgentConfig {" + + " allowBypass = " + allowBypass + + ", explicitlySelected = " + explicitlySelected + + ", acceptUnvalidated = " + acceptUnvalidated + + ", acceptPartialConnectivity = " + acceptPartialConnectivity + + ", provisioningNotificationDisabled = " + provisioningNotificationDisabled + + ", subscriberId = '" + subscriberId + '\'' + + ", skip464xlat = " + skip464xlat + + ", legacyType = " + legacyType + + ", hasShownBroken = " + hasShownBroken + + ", legacyTypeName = '" + legacyTypeName + '\'' + + ", legacyExtraInfo = '" + mLegacyExtraInfo + '\'' + + "}"; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel out, int flags) { + out.writeInt(allowBypass ? 1 : 0); + out.writeInt(explicitlySelected ? 1 : 0); + out.writeInt(acceptUnvalidated ? 1 : 0); + out.writeInt(acceptPartialConnectivity ? 1 : 0); + out.writeString(subscriberId); + out.writeInt(provisioningNotificationDisabled ? 1 : 0); + out.writeInt(skip464xlat ? 1 : 0); + out.writeInt(legacyType); + out.writeString(legacyTypeName); + out.writeString(mLegacyExtraInfo); + } + + public static final @NonNull Creator CREATOR = + new Creator() { + @Override + public NetworkAgentConfig createFromParcel(Parcel in) { + NetworkAgentConfig networkAgentConfig = new NetworkAgentConfig(); + networkAgentConfig.allowBypass = in.readInt() != 0; + networkAgentConfig.explicitlySelected = in.readInt() != 0; + networkAgentConfig.acceptUnvalidated = in.readInt() != 0; + networkAgentConfig.acceptPartialConnectivity = in.readInt() != 0; + networkAgentConfig.subscriberId = in.readString(); + networkAgentConfig.provisioningNotificationDisabled = in.readInt() != 0; + networkAgentConfig.skip464xlat = in.readInt() != 0; + networkAgentConfig.legacyType = in.readInt(); + networkAgentConfig.legacyTypeName = in.readString(); + networkAgentConfig.mLegacyExtraInfo = in.readString(); + return networkAgentConfig; + } + + @Override + public NetworkAgentConfig[] newArray(int size) { + return new NetworkAgentConfig[size]; + } + }; +} diff --git a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.aidl b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.aidl new file mode 100644 index 000000000000..01d328605de4 --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.aidl @@ -0,0 +1,21 @@ +/* +** +** Copyright (C) 2014 The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +package android.net; + +@JavaOnlyStableParcelable parcelable NetworkCapabilities; + diff --git a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java new file mode 100644 index 000000000000..3843b9ab93c2 --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java @@ -0,0 +1,2517 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.RequiresPermission; +import android.annotation.SystemApi; +import android.compat.annotation.UnsupportedAppUsage; +import android.net.ConnectivityManager.NetworkCallback; +import android.os.Build; +import android.os.Parcel; +import android.os.Parcelable; +import android.os.Process; +import android.text.TextUtils; +import android.util.ArraySet; +import android.util.proto.ProtoOutputStream; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.ArrayUtils; +import com.android.internal.util.BitUtils; +import com.android.internal.util.Preconditions; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Arrays; +import java.util.Objects; +import java.util.Set; +import java.util.StringJoiner; + +/** + * Representation of the capabilities of an active network. Instances are + * typically obtained through + * {@link NetworkCallback#onCapabilitiesChanged(Network, NetworkCapabilities)} + * or {@link ConnectivityManager#getNetworkCapabilities(Network)}. + *

+ * This replaces the old {@link ConnectivityManager#TYPE_MOBILE} method of + * network selection. Rather than indicate a need for Wi-Fi because an + * application needs high bandwidth and risk obsolescence when a new, fast + * network appears (like LTE), the application should specify it needs high + * bandwidth. Similarly if an application needs an unmetered network for a bulk + * transfer it can specify that rather than assuming all cellular based + * connections are metered and all Wi-Fi based connections are not. + */ +public final class NetworkCapabilities implements Parcelable { + private static final String TAG = "NetworkCapabilities"; + + // Set to true when private DNS is broken. + private boolean mPrivateDnsBroken; + + /** + * Uid of the app making the request. + */ + private int mRequestorUid; + + /** + * Package name of the app making the request. + */ + private String mRequestorPackageName; + + /** + * Indicates whether parceling should preserve fields that are set based on permissions of + * the process receiving the {@link NetworkCapabilities}. + */ + private final boolean mParcelLocationSensitiveFields; + + public NetworkCapabilities() { + mParcelLocationSensitiveFields = false; + clearAll(); + mNetworkCapabilities = DEFAULT_CAPABILITIES; + } + + public NetworkCapabilities(NetworkCapabilities nc) { + this(nc, false /* parcelLocationSensitiveFields */); + } + + /** + * Make a copy of NetworkCapabilities. + * + * @param nc Original NetworkCapabilities + * @param parcelLocationSensitiveFields Whether to parcel location sensitive data or not. + * @hide + */ + @SystemApi + public NetworkCapabilities( + @Nullable NetworkCapabilities nc, boolean parcelLocationSensitiveFields) { + mParcelLocationSensitiveFields = parcelLocationSensitiveFields; + if (nc != null) { + set(nc); + } + } + + /** + * Completely clears the contents of this object, removing even the capabilities that are set + * by default when the object is constructed. + * @hide + */ + public void clearAll() { + // Ensures that the internal copies maintained by the connectivity stack does not set + // this bit. + if (mParcelLocationSensitiveFields) { + throw new UnsupportedOperationException( + "Cannot clear NetworkCapabilities when parcelLocationSensitiveFields is set"); + } + mNetworkCapabilities = mTransportTypes = mUnwantedNetworkCapabilities = 0; + mLinkUpBandwidthKbps = mLinkDownBandwidthKbps = LINK_BANDWIDTH_UNSPECIFIED; + mNetworkSpecifier = null; + mTransportInfo = null; + mSignalStrength = SIGNAL_STRENGTH_UNSPECIFIED; + mUids = null; + mAdministratorUids = new int[0]; + mOwnerUid = Process.INVALID_UID; + mSSID = null; + mPrivateDnsBroken = false; + mRequestorUid = Process.INVALID_UID; + mRequestorPackageName = null; + } + + /** + * Set all contents of this object to the contents of a NetworkCapabilities. + * + * @param nc Original NetworkCapabilities + * @hide + */ + public void set(@NonNull NetworkCapabilities nc) { + mNetworkCapabilities = nc.mNetworkCapabilities; + mTransportTypes = nc.mTransportTypes; + mLinkUpBandwidthKbps = nc.mLinkUpBandwidthKbps; + mLinkDownBandwidthKbps = nc.mLinkDownBandwidthKbps; + mNetworkSpecifier = nc.mNetworkSpecifier; + if (nc.getTransportInfo() != null) { + setTransportInfo(nc.getTransportInfo().makeCopy(mParcelLocationSensitiveFields)); + } else { + setTransportInfo(null); + } + mSignalStrength = nc.mSignalStrength; + setUids(nc.mUids); // Will make the defensive copy + setAdministratorUids(nc.getAdministratorUids()); + mOwnerUid = nc.mOwnerUid; + mUnwantedNetworkCapabilities = nc.mUnwantedNetworkCapabilities; + mSSID = nc.mSSID; + mPrivateDnsBroken = nc.mPrivateDnsBroken; + mRequestorUid = nc.mRequestorUid; + mRequestorPackageName = nc.mRequestorPackageName; + } + + /** + * Represents the network's capabilities. If any are specified they will be satisfied + * by any Network that matches all of them. + */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + private long mNetworkCapabilities; + + /** + * If any capabilities specified here they must not exist in the matching Network. + */ + private long mUnwantedNetworkCapabilities; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = { "NET_CAPABILITY_" }, value = { + NET_CAPABILITY_MMS, + NET_CAPABILITY_SUPL, + NET_CAPABILITY_DUN, + NET_CAPABILITY_FOTA, + NET_CAPABILITY_IMS, + NET_CAPABILITY_CBS, + NET_CAPABILITY_WIFI_P2P, + NET_CAPABILITY_IA, + NET_CAPABILITY_RCS, + NET_CAPABILITY_XCAP, + NET_CAPABILITY_EIMS, + NET_CAPABILITY_NOT_METERED, + NET_CAPABILITY_INTERNET, + NET_CAPABILITY_NOT_RESTRICTED, + NET_CAPABILITY_TRUSTED, + NET_CAPABILITY_NOT_VPN, + NET_CAPABILITY_VALIDATED, + NET_CAPABILITY_CAPTIVE_PORTAL, + NET_CAPABILITY_NOT_ROAMING, + NET_CAPABILITY_FOREGROUND, + NET_CAPABILITY_NOT_CONGESTED, + NET_CAPABILITY_NOT_SUSPENDED, + NET_CAPABILITY_OEM_PAID, + NET_CAPABILITY_MCX, + NET_CAPABILITY_PARTIAL_CONNECTIVITY, + NET_CAPABILITY_TEMPORARILY_NOT_METERED, + NET_CAPABILITY_OEM_PRIVATE, + NET_CAPABILITY_VEHICLE_INTERNAL, + NET_CAPABILITY_NOT_VCN_MANAGED, + }) + public @interface NetCapability { } + + /** + * Indicates this is a network that has the ability to reach the + * carrier's MMSC for sending and receiving MMS messages. + */ + public static final int NET_CAPABILITY_MMS = 0; + + /** + * Indicates this is a network that has the ability to reach the carrier's + * SUPL server, used to retrieve GPS information. + */ + public static final int NET_CAPABILITY_SUPL = 1; + + /** + * Indicates this is a network that has the ability to reach the carrier's + * DUN or tethering gateway. + */ + public static final int NET_CAPABILITY_DUN = 2; + + /** + * Indicates this is a network that has the ability to reach the carrier's + * FOTA portal, used for over the air updates. + */ + public static final int NET_CAPABILITY_FOTA = 3; + + /** + * Indicates this is a network that has the ability to reach the carrier's + * IMS servers, used for network registration and signaling. + */ + public static final int NET_CAPABILITY_IMS = 4; + + /** + * Indicates this is a network that has the ability to reach the carrier's + * CBS servers, used for carrier specific services. + */ + public static final int NET_CAPABILITY_CBS = 5; + + /** + * Indicates this is a network that has the ability to reach a Wi-Fi direct + * peer. + */ + public static final int NET_CAPABILITY_WIFI_P2P = 6; + + /** + * Indicates this is a network that has the ability to reach a carrier's + * Initial Attach servers. + */ + public static final int NET_CAPABILITY_IA = 7; + + /** + * Indicates this is a network that has the ability to reach a carrier's + * RCS servers, used for Rich Communication Services. + */ + public static final int NET_CAPABILITY_RCS = 8; + + /** + * Indicates this is a network that has the ability to reach a carrier's + * XCAP servers, used for configuration and control. + */ + public static final int NET_CAPABILITY_XCAP = 9; + + /** + * Indicates this is a network that has the ability to reach a carrier's + * Emergency IMS servers or other services, used for network signaling + * during emergency calls. + */ + public static final int NET_CAPABILITY_EIMS = 10; + + /** + * Indicates that this network is unmetered. + */ + public static final int NET_CAPABILITY_NOT_METERED = 11; + + /** + * Indicates that this network should be able to reach the internet. + */ + public static final int NET_CAPABILITY_INTERNET = 12; + + /** + * Indicates that this network is available for general use. If this is not set + * applications should not attempt to communicate on this network. Note that this + * is simply informative and not enforcement - enforcement is handled via other means. + * Set by default. + */ + public static final int NET_CAPABILITY_NOT_RESTRICTED = 13; + + /** + * Indicates that the user has indicated implicit trust of this network. This + * generally means it's a sim-selected carrier, a plugged in ethernet, a paired + * BT device or a wifi the user asked to connect to. Untrusted networks + * are probably limited to unknown wifi AP. Set by default. + */ + public static final int NET_CAPABILITY_TRUSTED = 14; + + /** + * Indicates that this network is not a VPN. This capability is set by default and should be + * explicitly cleared for VPN networks. + */ + public static final int NET_CAPABILITY_NOT_VPN = 15; + + /** + * Indicates that connectivity on this network was successfully validated. For example, for a + * network with NET_CAPABILITY_INTERNET, it means that Internet connectivity was successfully + * detected. + */ + public static final int NET_CAPABILITY_VALIDATED = 16; + + /** + * Indicates that this network was found to have a captive portal in place last time it was + * probed. + */ + public static final int NET_CAPABILITY_CAPTIVE_PORTAL = 17; + + /** + * Indicates that this network is not roaming. + */ + public static final int NET_CAPABILITY_NOT_ROAMING = 18; + + /** + * Indicates that this network is available for use by apps, and not a network that is being + * kept up in the background to facilitate fast network switching. + */ + public static final int NET_CAPABILITY_FOREGROUND = 19; + + /** + * Indicates that this network is not congested. + *

+ * When a network is congested, applications should defer network traffic + * that can be done at a later time, such as uploading analytics. + */ + public static final int NET_CAPABILITY_NOT_CONGESTED = 20; + + /** + * Indicates that this network is not currently suspended. + *

+ * When a network is suspended, the network's IP addresses and any connections + * established on the network remain valid, but the network is temporarily unable + * to transfer data. This can happen, for example, if a cellular network experiences + * a temporary loss of signal, such as when driving through a tunnel, etc. + * A network with this capability is not suspended, so is expected to be able to + * transfer data. + */ + public static final int NET_CAPABILITY_NOT_SUSPENDED = 21; + + /** + * Indicates that traffic that goes through this network is paid by oem. For example, + * this network can be used by system apps to upload telemetry data. + * @hide + */ + @SystemApi + public static final int NET_CAPABILITY_OEM_PAID = 22; + + /** + * Indicates this is a network that has the ability to reach a carrier's Mission Critical + * servers. + */ + public static final int NET_CAPABILITY_MCX = 23; + + /** + * Indicates that this network was tested to only provide partial connectivity. + * @hide + */ + @SystemApi + public static final int NET_CAPABILITY_PARTIAL_CONNECTIVITY = 24; + + /** + * Indicates that this network is temporarily unmetered. + *

+ * This capability will be set for networks that are generally metered, but are currently + * unmetered, e.g., because the user is in a particular area. This capability can be changed at + * any time. When it is removed, applications are responsible for stopping any data transfer + * that should not occur on a metered network. + * Note that most apps should use {@link #NET_CAPABILITY_NOT_METERED} instead. For more + * information, see https://developer.android.com/about/versions/11/features/5g#meteredness. + */ + public static final int NET_CAPABILITY_TEMPORARILY_NOT_METERED = 25; + + /** + * Indicates that this network is private to the OEM and meant only for OEM use. + * @hide + */ + @SystemApi + public static final int NET_CAPABILITY_OEM_PRIVATE = 26; + + /** + * Indicates this is an internal vehicle network, meant to communicate with other + * automotive systems. + * + * @hide + */ + @SystemApi + public static final int NET_CAPABILITY_VEHICLE_INTERNAL = 27; + + /** + * Indicates that this network is not managed by a Virtual Carrier Network (VCN). + * + * TODO(b/177299683): Add additional clarifying javadoc. + * @hide + */ + public static final int NET_CAPABILITY_NOT_VCN_MANAGED = 28; + + private static final int MIN_NET_CAPABILITY = NET_CAPABILITY_MMS; + private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_NOT_VCN_MANAGED; + + /** + * Network capabilities that are expected to be mutable, i.e., can change while a particular + * network is connected. + */ + private static final long MUTABLE_CAPABILITIES = + // TRUSTED can change when user explicitly connects to an untrusted network in Settings. + // http://b/18206275 + (1 << NET_CAPABILITY_TRUSTED) + | (1 << NET_CAPABILITY_VALIDATED) + | (1 << NET_CAPABILITY_CAPTIVE_PORTAL) + | (1 << NET_CAPABILITY_NOT_ROAMING) + | (1 << NET_CAPABILITY_FOREGROUND) + | (1 << NET_CAPABILITY_NOT_CONGESTED) + | (1 << NET_CAPABILITY_NOT_SUSPENDED) + | (1 << NET_CAPABILITY_PARTIAL_CONNECTIVITY) + | (1 << NET_CAPABILITY_TEMPORARILY_NOT_METERED) + | (1 << NET_CAPABILITY_NOT_VCN_MANAGED); + + /** + * Network capabilities that are not allowed in NetworkRequests. This exists because the + * NetworkFactory / NetworkAgent model does not deal well with the situation where a + * capability's presence cannot be known in advance. If such a capability is requested, then we + * can get into a cycle where the NetworkFactory endlessly churns out NetworkAgents that then + * get immediately torn down because they do not have the requested capability. + */ + // Note that as a historical exception, the TRUSTED and NOT_VCN_MANAGED capabilities + // are mutable but requestable. Factories are responsible for not getting + // in an infinite loop about these. + private static final long NON_REQUESTABLE_CAPABILITIES = + MUTABLE_CAPABILITIES + & ~(1 << NET_CAPABILITY_TRUSTED) + & ~(1 << NET_CAPABILITY_NOT_VCN_MANAGED); + + /** + * Capabilities that are set by default when the object is constructed. + */ + private static final long DEFAULT_CAPABILITIES = + (1 << NET_CAPABILITY_NOT_RESTRICTED) + | (1 << NET_CAPABILITY_TRUSTED) + | (1 << NET_CAPABILITY_NOT_VPN); + + /** + * Capabilities that suggest that a network is restricted. + * {@see #maybeMarkCapabilitiesRestricted}, {@see #FORCE_RESTRICTED_CAPABILITIES} + */ + @VisibleForTesting + /* package */ static final long RESTRICTED_CAPABILITIES = + (1 << NET_CAPABILITY_CBS) + | (1 << NET_CAPABILITY_DUN) + | (1 << NET_CAPABILITY_EIMS) + | (1 << NET_CAPABILITY_FOTA) + | (1 << NET_CAPABILITY_IA) + | (1 << NET_CAPABILITY_IMS) + | (1 << NET_CAPABILITY_MCX) + | (1 << NET_CAPABILITY_RCS) + | (1 << NET_CAPABILITY_VEHICLE_INTERNAL) + | (1 << NET_CAPABILITY_XCAP); + + /** + * Capabilities that force network to be restricted. + * {@see #maybeMarkCapabilitiesRestricted}. + */ + private static final long FORCE_RESTRICTED_CAPABILITIES = + (1 << NET_CAPABILITY_OEM_PAID) + | (1 << NET_CAPABILITY_OEM_PRIVATE); + + /** + * Capabilities that suggest that a network is unrestricted. + * {@see #maybeMarkCapabilitiesRestricted}. + */ + @VisibleForTesting + /* package */ static final long UNRESTRICTED_CAPABILITIES = + (1 << NET_CAPABILITY_INTERNET) + | (1 << NET_CAPABILITY_MMS) + | (1 << NET_CAPABILITY_SUPL) + | (1 << NET_CAPABILITY_WIFI_P2P); + + /** + * Capabilities that are managed by ConnectivityService. + */ + private static final long CONNECTIVITY_MANAGED_CAPABILITIES = + (1 << NET_CAPABILITY_VALIDATED) + | (1 << NET_CAPABILITY_CAPTIVE_PORTAL) + | (1 << NET_CAPABILITY_FOREGROUND) + | (1 << NET_CAPABILITY_PARTIAL_CONNECTIVITY); + + /** + * Capabilities that are allowed for test networks. This list must be set so that it is safe + * for an unprivileged user to create a network with these capabilities via shell. As such, + * it must never contain capabilities that are generally useful to the system, such as + * INTERNET, IMS, SUPL, etc. + */ + private static final long TEST_NETWORKS_ALLOWED_CAPABILITIES = + (1 << NET_CAPABILITY_NOT_METERED) + | (1 << NET_CAPABILITY_TEMPORARILY_NOT_METERED) + | (1 << NET_CAPABILITY_NOT_RESTRICTED) + | (1 << NET_CAPABILITY_NOT_VPN) + | (1 << NET_CAPABILITY_NOT_ROAMING) + | (1 << NET_CAPABILITY_NOT_CONGESTED) + | (1 << NET_CAPABILITY_NOT_SUSPENDED) + | (1 << NET_CAPABILITY_NOT_VCN_MANAGED); + + /** + * Adds the given capability to this {@code NetworkCapability} instance. + * Note that when searching for a network to satisfy a request, all capabilities + * requested must be satisfied. + * + * @param capability the capability to be added. + * @return This NetworkCapabilities instance, to facilitate chaining. + * @hide + */ + public @NonNull NetworkCapabilities addCapability(@NetCapability int capability) { + // If the given capability was previously added to the list of unwanted capabilities + // then the capability will also be removed from the list of unwanted capabilities. + // TODO: Consider adding unwanted capabilities to the public API and mention this + // in the documentation. + checkValidCapability(capability); + mNetworkCapabilities |= 1 << capability; + mUnwantedNetworkCapabilities &= ~(1 << capability); // remove from unwanted capability list + return this; + } + + /** + * Adds the given capability to the list of unwanted capabilities of this + * {@code NetworkCapability} instance. Note that when searching for a network to + * satisfy a request, the network must not contain any capability from unwanted capability + * list. + *

+ * If the capability was previously added to the list of required capabilities (for + * example, it was there by default or added using {@link #addCapability(int)} method), then + * it will be removed from the list of required capabilities as well. + * + * @see #addCapability(int) + * @hide + */ + public void addUnwantedCapability(@NetCapability int capability) { + checkValidCapability(capability); + mUnwantedNetworkCapabilities |= 1 << capability; + mNetworkCapabilities &= ~(1 << capability); // remove from requested capabilities + } + + /** + * Removes (if found) the given capability from this {@code NetworkCapability} instance. + * + * @param capability the capability to be removed. + * @return This NetworkCapabilities instance, to facilitate chaining. + * @hide + */ + public @NonNull NetworkCapabilities removeCapability(@NetCapability int capability) { + // Note that this method removes capabilities that were added via addCapability(int), + // addUnwantedCapability(int) or setCapabilities(int[], int[]). + checkValidCapability(capability); + final long mask = ~(1 << capability); + mNetworkCapabilities &= mask; + mUnwantedNetworkCapabilities &= mask; + return this; + } + + /** + * Sets (or clears) the given capability on this {@link NetworkCapabilities} + * instance. + * @hide + */ + public @NonNull NetworkCapabilities setCapability(@NetCapability int capability, + boolean value) { + if (value) { + addCapability(capability); + } else { + removeCapability(capability); + } + return this; + } + + /** + * Gets all the capabilities set on this {@code NetworkCapability} instance. + * + * @return an array of capability values for this instance. + * @hide + */ + @UnsupportedAppUsage + public @NetCapability int[] getCapabilities() { + return BitUtils.unpackBits(mNetworkCapabilities); + } + + /** + * Gets all the unwanted capabilities set on this {@code NetworkCapability} instance. + * + * @return an array of unwanted capability values for this instance. + * @hide + */ + public @NetCapability int[] getUnwantedCapabilities() { + return BitUtils.unpackBits(mUnwantedNetworkCapabilities); + } + + + /** + * Sets all the capabilities set on this {@code NetworkCapability} instance. + * This overwrites any existing capabilities. + * + * @hide + */ + public void setCapabilities(@NetCapability int[] capabilities, + @NetCapability int[] unwantedCapabilities) { + mNetworkCapabilities = BitUtils.packBits(capabilities); + mUnwantedNetworkCapabilities = BitUtils.packBits(unwantedCapabilities); + } + + /** + * @deprecated use {@link #setCapabilities(int[], int[])} + * @hide + */ + @Deprecated + public void setCapabilities(@NetCapability int[] capabilities) { + setCapabilities(capabilities, new int[] {}); + } + + /** + * Tests for the presence of a capability on this instance. + * + * @param capability the capabilities to be tested for. + * @return {@code true} if set on this instance. + */ + public boolean hasCapability(@NetCapability int capability) { + return isValidCapability(capability) + && ((mNetworkCapabilities & (1 << capability)) != 0); + } + + /** @hide */ + public boolean hasUnwantedCapability(@NetCapability int capability) { + return isValidCapability(capability) + && ((mUnwantedNetworkCapabilities & (1 << capability)) != 0); + } + + /** + * Check if this NetworkCapabilities has system managed capabilities or not. + * @hide + */ + public boolean hasConnectivityManagedCapability() { + return ((mNetworkCapabilities & CONNECTIVITY_MANAGED_CAPABILITIES) != 0); + } + + /** Note this method may result in having the same capability in wanted and unwanted lists. */ + private void combineNetCapabilities(@NonNull NetworkCapabilities nc) { + this.mNetworkCapabilities |= nc.mNetworkCapabilities; + this.mUnwantedNetworkCapabilities |= nc.mUnwantedNetworkCapabilities; + } + + /** + * Convenience function that returns a human-readable description of the first mutable + * capability we find. Used to present an error message to apps that request mutable + * capabilities. + * + * @hide + */ + public @Nullable String describeFirstNonRequestableCapability() { + final long nonRequestable = (mNetworkCapabilities | mUnwantedNetworkCapabilities) + & NON_REQUESTABLE_CAPABILITIES; + + if (nonRequestable != 0) { + return capabilityNameOf(BitUtils.unpackBits(nonRequestable)[0]); + } + if (mLinkUpBandwidthKbps != 0 || mLinkDownBandwidthKbps != 0) return "link bandwidth"; + if (hasSignalStrength()) return "signalStrength"; + if (isPrivateDnsBroken()) { + return "privateDnsBroken"; + } + return null; + } + + private boolean satisfiedByNetCapabilities(@NonNull NetworkCapabilities nc, + boolean onlyImmutable) { + long requestedCapabilities = mNetworkCapabilities; + long requestedUnwantedCapabilities = mUnwantedNetworkCapabilities; + long providedCapabilities = nc.mNetworkCapabilities; + + if (onlyImmutable) { + requestedCapabilities &= ~MUTABLE_CAPABILITIES; + requestedUnwantedCapabilities &= ~MUTABLE_CAPABILITIES; + } + return ((providedCapabilities & requestedCapabilities) == requestedCapabilities) + && ((requestedUnwantedCapabilities & providedCapabilities) == 0); + } + + /** @hide */ + public boolean equalsNetCapabilities(@NonNull NetworkCapabilities nc) { + return (nc.mNetworkCapabilities == this.mNetworkCapabilities) + && (nc.mUnwantedNetworkCapabilities == this.mUnwantedNetworkCapabilities); + } + + private boolean equalsNetCapabilitiesRequestable(@NonNull NetworkCapabilities that) { + return ((this.mNetworkCapabilities & ~NON_REQUESTABLE_CAPABILITIES) == + (that.mNetworkCapabilities & ~NON_REQUESTABLE_CAPABILITIES)) + && ((this.mUnwantedNetworkCapabilities & ~NON_REQUESTABLE_CAPABILITIES) == + (that.mUnwantedNetworkCapabilities & ~NON_REQUESTABLE_CAPABILITIES)); + } + + /** + * Deduces that all the capabilities it provides are typically provided by restricted networks + * or not. + * + * @return {@code true} if the network should be restricted. + * @hide + */ + public boolean deduceRestrictedCapability() { + // Check if we have any capability that forces the network to be restricted. + final boolean forceRestrictedCapability = + (mNetworkCapabilities & FORCE_RESTRICTED_CAPABILITIES) != 0; + + // Verify there aren't any unrestricted capabilities. If there are we say + // the whole thing is unrestricted unless it is forced to be restricted. + final boolean hasUnrestrictedCapabilities = + (mNetworkCapabilities & UNRESTRICTED_CAPABILITIES) != 0; + + // Must have at least some restricted capabilities. + final boolean hasRestrictedCapabilities = + (mNetworkCapabilities & RESTRICTED_CAPABILITIES) != 0; + + return forceRestrictedCapability + || (hasRestrictedCapabilities && !hasUnrestrictedCapabilities); + } + + /** + * Removes the NET_CAPABILITY_NOT_RESTRICTED capability if deducing the network is restricted. + * + * @hide + */ + public void maybeMarkCapabilitiesRestricted() { + if (deduceRestrictedCapability()) { + removeCapability(NET_CAPABILITY_NOT_RESTRICTED); + } + } + + /** + * Test networks have strong restrictions on what capabilities they can have. Enforce these + * restrictions. + * @hide + */ + public void restrictCapabilitesForTestNetwork(int creatorUid) { + final long originalCapabilities = mNetworkCapabilities; + final long originalTransportTypes = mTransportTypes; + final NetworkSpecifier originalSpecifier = mNetworkSpecifier; + final int originalSignalStrength = mSignalStrength; + final int originalOwnerUid = getOwnerUid(); + final int[] originalAdministratorUids = getAdministratorUids(); + clearAll(); + mTransportTypes = (originalTransportTypes & TEST_NETWORKS_ALLOWED_TRANSPORTS) + | (1 << TRANSPORT_TEST); + mNetworkCapabilities = originalCapabilities & TEST_NETWORKS_ALLOWED_CAPABILITIES; + mNetworkSpecifier = originalSpecifier; + mSignalStrength = originalSignalStrength; + + // Only retain the owner and administrator UIDs if they match the app registering the remote + // caller that registered the network. + if (originalOwnerUid == creatorUid) { + setOwnerUid(creatorUid); + } + if (ArrayUtils.contains(originalAdministratorUids, creatorUid)) { + setAdministratorUids(new int[] {creatorUid}); + } + // There is no need to clear the UIDs, they have already been cleared by clearAll() above. + } + + /** + * Representing the transport type. Apps should generally not care about transport. A + * request for a fast internet connection could be satisfied by a number of different + * transports. If any are specified here it will be satisfied a Network that matches + * any of them. If a caller doesn't care about the transport it should not specify any. + */ + private long mTransportTypes; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = { "TRANSPORT_" }, value = { + TRANSPORT_CELLULAR, + TRANSPORT_WIFI, + TRANSPORT_BLUETOOTH, + TRANSPORT_ETHERNET, + TRANSPORT_VPN, + TRANSPORT_WIFI_AWARE, + TRANSPORT_LOWPAN, + TRANSPORT_TEST, + }) + public @interface Transport { } + + /** + * Indicates this network uses a Cellular transport. + */ + public static final int TRANSPORT_CELLULAR = 0; + + /** + * Indicates this network uses a Wi-Fi transport. + */ + public static final int TRANSPORT_WIFI = 1; + + /** + * Indicates this network uses a Bluetooth transport. + */ + public static final int TRANSPORT_BLUETOOTH = 2; + + /** + * Indicates this network uses an Ethernet transport. + */ + public static final int TRANSPORT_ETHERNET = 3; + + /** + * Indicates this network uses a VPN transport. + */ + public static final int TRANSPORT_VPN = 4; + + /** + * Indicates this network uses a Wi-Fi Aware transport. + */ + public static final int TRANSPORT_WIFI_AWARE = 5; + + /** + * Indicates this network uses a LoWPAN transport. + */ + public static final int TRANSPORT_LOWPAN = 6; + + /** + * Indicates this network uses a Test-only virtual interface as a transport. + * + * @hide + */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + public static final int TRANSPORT_TEST = 7; + + /** @hide */ + public static final int MIN_TRANSPORT = TRANSPORT_CELLULAR; + /** @hide */ + public static final int MAX_TRANSPORT = TRANSPORT_TEST; + + /** @hide */ + public static boolean isValidTransport(@Transport int transportType) { + return (MIN_TRANSPORT <= transportType) && (transportType <= MAX_TRANSPORT); + } + + private static final String[] TRANSPORT_NAMES = { + "CELLULAR", + "WIFI", + "BLUETOOTH", + "ETHERNET", + "VPN", + "WIFI_AWARE", + "LOWPAN", + "TEST" + }; + + /** + * Allowed transports on a test network, in addition to TRANSPORT_TEST. + */ + private static final int TEST_NETWORKS_ALLOWED_TRANSPORTS = 1 << TRANSPORT_TEST + // Test ethernet networks can be created with EthernetManager#setIncludeTestInterfaces + | 1 << TRANSPORT_ETHERNET + // Test VPN networks can be created but their UID ranges must be empty. + | 1 << TRANSPORT_VPN; + + /** + * Adds the given transport type to this {@code NetworkCapability} instance. + * Multiple transports may be applied. Note that when searching + * for a network to satisfy a request, any listed in the request will satisfy the request. + * For example {@code TRANSPORT_WIFI} and {@code TRANSPORT_ETHERNET} added to a + * {@code NetworkCapabilities} would cause either a Wi-Fi network or an Ethernet network + * to be selected. This is logically different than + * {@code NetworkCapabilities.NET_CAPABILITY_*} listed above. + * + * @param transportType the transport type to be added. + * @return This NetworkCapabilities instance, to facilitate chaining. + * @hide + */ + public @NonNull NetworkCapabilities addTransportType(@Transport int transportType) { + checkValidTransportType(transportType); + mTransportTypes |= 1 << transportType; + setNetworkSpecifier(mNetworkSpecifier); // used for exception checking + return this; + } + + /** + * Removes (if found) the given transport from this {@code NetworkCapability} instance. + * + * @param transportType the transport type to be removed. + * @return This NetworkCapabilities instance, to facilitate chaining. + * @hide + */ + public @NonNull NetworkCapabilities removeTransportType(@Transport int transportType) { + checkValidTransportType(transportType); + mTransportTypes &= ~(1 << transportType); + setNetworkSpecifier(mNetworkSpecifier); // used for exception checking + return this; + } + + /** + * Sets (or clears) the given transport on this {@link NetworkCapabilities} + * instance. + * + * @hide + */ + public @NonNull NetworkCapabilities setTransportType(@Transport int transportType, + boolean value) { + if (value) { + addTransportType(transportType); + } else { + removeTransportType(transportType); + } + return this; + } + + /** + * Gets all the transports set on this {@code NetworkCapability} instance. + * + * @return an array of transport type values for this instance. + * @hide + */ + @SystemApi + @NonNull public @Transport int[] getTransportTypes() { + return BitUtils.unpackBits(mTransportTypes); + } + + /** + * Sets all the transports set on this {@code NetworkCapability} instance. + * This overwrites any existing transports. + * + * @hide + */ + public void setTransportTypes(@Transport int[] transportTypes) { + mTransportTypes = BitUtils.packBits(transportTypes); + } + + /** + * Tests for the presence of a transport on this instance. + * + * @param transportType the transport type to be tested for. + * @return {@code true} if set on this instance. + */ + public boolean hasTransport(@Transport int transportType) { + return isValidTransport(transportType) && ((mTransportTypes & (1 << transportType)) != 0); + } + + private void combineTransportTypes(NetworkCapabilities nc) { + this.mTransportTypes |= nc.mTransportTypes; + } + + private boolean satisfiedByTransportTypes(NetworkCapabilities nc) { + return ((this.mTransportTypes == 0) + || ((this.mTransportTypes & nc.mTransportTypes) != 0)); + } + + /** @hide */ + public boolean equalsTransportTypes(NetworkCapabilities nc) { + return (nc.mTransportTypes == this.mTransportTypes); + } + + /** + * UID of the app that owns this network, or Process#INVALID_UID if none/unknown. + * + *

This field keeps track of the UID of the app that created this network and is in charge of + * its lifecycle. This could be the UID of apps such as the Wifi network suggestor, the running + * VPN, or Carrier Service app managing a cellular data connection. + * + *

For NetworkCapability instances being sent from ConnectivityService, this value MUST be + * reset to Process.INVALID_UID unless all the following conditions are met: + * + *

The caller is the network owner, AND one of the following sets of requirements is met: + * + *

    + *
  1. The described Network is a VPN + *
+ * + *

OR: + * + *

    + *
  1. The calling app is the network owner + *
  2. The calling app has the ACCESS_FINE_LOCATION permission granted + *
  3. The user's location toggle is on + *
+ * + * This is because the owner UID is location-sensitive. The apps that request a network could + * know where the device is if they can tell for sure the system has connected to the network + * they requested. + * + *

This is populated by the network agents and for the NetworkCapabilities instance sent by + * an app to the System Server, the value MUST be reset to Process.INVALID_UID by the system + * server. + */ + private int mOwnerUid = Process.INVALID_UID; + + /** + * Set the UID of the owner app. + * @hide + */ + public @NonNull NetworkCapabilities setOwnerUid(final int uid) { + mOwnerUid = uid; + return this; + } + + /** + * Retrieves the UID of the app that owns this network. + * + *

For user privacy reasons, this field will only be populated if the following conditions + * are met: + * + *

The caller is the network owner, AND one of the following sets of requirements is met: + * + *

    + *
  1. The described Network is a VPN + *
+ * + *

OR: + * + *

    + *
  1. The calling app is the network owner + *
  2. The calling app has the ACCESS_FINE_LOCATION permission granted + *
  3. The user's location toggle is on + *
+ * + * Instances of NetworkCapabilities sent to apps without the appropriate permissions will have + * this field cleared out. + */ + public int getOwnerUid() { + return mOwnerUid; + } + + private boolean equalsOwnerUid(@NonNull final NetworkCapabilities nc) { + return mOwnerUid == nc.mOwnerUid; + } + + /** + * UIDs of packages that are administrators of this network, or empty if none. + * + *

This field tracks the UIDs of packages that have permission to manage this network. + * + *

Network owners will also be listed as administrators. + * + *

For NetworkCapability instances being sent from the System Server, this value MUST be + * empty unless the destination is 1) the System Server, or 2) Telephony. In either case, the + * receiving entity must have the ACCESS_FINE_LOCATION permission and target R+. + * + *

When received from an app in a NetworkRequest this is always cleared out by the system + * server. This field is never used for matching NetworkRequests to NetworkAgents. + */ + @NonNull private int[] mAdministratorUids = new int[0]; + + /** + * Sets the int[] of UIDs that are administrators of this network. + * + *

UIDs included in administratorUids gain administrator privileges over this Network. + * Examples of UIDs that should be included in administratorUids are: + * + *

    + *
  • Carrier apps with privileges for the relevant subscription + *
  • Active VPN apps + *
  • Other application groups with a particular Network-related role + *
+ * + *

In general, user-supplied networks (such as WiFi networks) do not have an administrator. + * + *

An app is granted owner privileges over Networks that it supplies. The owner UID MUST + * always be included in administratorUids. + * + *

The administrator UIDs are set by network agents. + * + * @param administratorUids the UIDs to be set as administrators of this Network. + * @throws IllegalArgumentException if duplicate UIDs are contained in administratorUids + * @see #mAdministratorUids + * @hide + */ + @NonNull + public NetworkCapabilities setAdministratorUids(@NonNull final int[] administratorUids) { + mAdministratorUids = Arrays.copyOf(administratorUids, administratorUids.length); + Arrays.sort(mAdministratorUids); + for (int i = 0; i < mAdministratorUids.length - 1; i++) { + if (mAdministratorUids[i] >= mAdministratorUids[i + 1]) { + throw new IllegalArgumentException("All administrator UIDs must be unique"); + } + } + return this; + } + + /** + * Retrieves the UIDs that are administrators of this Network. + * + *

This is only populated in NetworkCapabilities objects that come from network agents for + * networks that are managed by specific apps on the system, such as carrier privileged apps or + * wifi suggestion apps. This will include the network owner. + * + * @return the int[] of UIDs that are administrators of this Network + * @see #mAdministratorUids + * @hide + */ + @NonNull + @SystemApi + public int[] getAdministratorUids() { + return Arrays.copyOf(mAdministratorUids, mAdministratorUids.length); + } + + /** + * Tests if the set of administrator UIDs of this network is the same as that of the passed one. + * + *

The administrator UIDs must be in sorted order. + * + *

nc is assumed non-null. Else, NPE. + * + * @hide + */ + @VisibleForTesting(visibility = PRIVATE) + public boolean equalsAdministratorUids(@NonNull final NetworkCapabilities nc) { + return Arrays.equals(mAdministratorUids, nc.mAdministratorUids); + } + + /** + * Combine the administrator UIDs of the capabilities. + * + *

This is only legal if either of the administrators lists are empty, or if they are equal. + * Combining administrator UIDs is only possible for combining non-overlapping sets of UIDs. + * + *

If both administrator lists are non-empty but not equal, they conflict with each other. In + * this case, it would not make sense to add them together. + */ + private void combineAdministratorUids(@NonNull final NetworkCapabilities nc) { + if (nc.mAdministratorUids.length == 0) return; + if (mAdministratorUids.length == 0) { + mAdministratorUids = Arrays.copyOf(nc.mAdministratorUids, nc.mAdministratorUids.length); + return; + } + if (!equalsAdministratorUids(nc)) { + throw new IllegalStateException("Can't combine two different administrator UID lists"); + } + } + + /** + * Value indicating that link bandwidth is unspecified. + * @hide + */ + public static final int LINK_BANDWIDTH_UNSPECIFIED = 0; + + /** + * Passive link bandwidth. This is a rough guide of the expected peak bandwidth + * for the first hop on the given transport. It is not measured, but may take into account + * link parameters (Radio technology, allocated channels, etc). + */ + private int mLinkUpBandwidthKbps = LINK_BANDWIDTH_UNSPECIFIED; + private int mLinkDownBandwidthKbps = LINK_BANDWIDTH_UNSPECIFIED; + + /** + * Sets the upstream bandwidth for this network in Kbps. This always only refers to + * the estimated first hop transport bandwidth. + *

+ * {@see Builder#setLinkUpstreamBandwidthKbps} + * + * @param upKbps the estimated first hop upstream (device to network) bandwidth. + * @hide + */ + public @NonNull NetworkCapabilities setLinkUpstreamBandwidthKbps(int upKbps) { + mLinkUpBandwidthKbps = upKbps; + return this; + } + + /** + * Retrieves the upstream bandwidth for this network in Kbps. This always only refers to + * the estimated first hop transport bandwidth. + * + * @return The estimated first hop upstream (device to network) bandwidth. + */ + public int getLinkUpstreamBandwidthKbps() { + return mLinkUpBandwidthKbps; + } + + /** + * Sets the downstream bandwidth for this network in Kbps. This always only refers to + * the estimated first hop transport bandwidth. + *

+ * {@see Builder#setLinkUpstreamBandwidthKbps} + * + * @param downKbps the estimated first hop downstream (network to device) bandwidth. + * @hide + */ + public @NonNull NetworkCapabilities setLinkDownstreamBandwidthKbps(int downKbps) { + mLinkDownBandwidthKbps = downKbps; + return this; + } + + /** + * Retrieves the downstream bandwidth for this network in Kbps. This always only refers to + * the estimated first hop transport bandwidth. + * + * @return The estimated first hop downstream (network to device) bandwidth. + */ + public int getLinkDownstreamBandwidthKbps() { + return mLinkDownBandwidthKbps; + } + + private void combineLinkBandwidths(NetworkCapabilities nc) { + this.mLinkUpBandwidthKbps = + Math.max(this.mLinkUpBandwidthKbps, nc.mLinkUpBandwidthKbps); + this.mLinkDownBandwidthKbps = + Math.max(this.mLinkDownBandwidthKbps, nc.mLinkDownBandwidthKbps); + } + private boolean satisfiedByLinkBandwidths(NetworkCapabilities nc) { + return !(this.mLinkUpBandwidthKbps > nc.mLinkUpBandwidthKbps + || this.mLinkDownBandwidthKbps > nc.mLinkDownBandwidthKbps); + } + private boolean equalsLinkBandwidths(NetworkCapabilities nc) { + return (this.mLinkUpBandwidthKbps == nc.mLinkUpBandwidthKbps + && this.mLinkDownBandwidthKbps == nc.mLinkDownBandwidthKbps); + } + /** @hide */ + public static int minBandwidth(int a, int b) { + if (a == LINK_BANDWIDTH_UNSPECIFIED) { + return b; + } else if (b == LINK_BANDWIDTH_UNSPECIFIED) { + return a; + } else { + return Math.min(a, b); + } + } + /** @hide */ + public static int maxBandwidth(int a, int b) { + return Math.max(a, b); + } + + private NetworkSpecifier mNetworkSpecifier = null; + private TransportInfo mTransportInfo = null; + + /** + * Sets the optional bearer specific network specifier. + * This has no meaning if a single transport is also not specified, so calling + * this without a single transport set will generate an exception, as will + * subsequently adding or removing transports after this is set. + *

+ * + * @param networkSpecifier A concrete, parcelable framework class that extends + * NetworkSpecifier. + * @return This NetworkCapabilities instance, to facilitate chaining. + * @hide + */ + public @NonNull NetworkCapabilities setNetworkSpecifier( + @NonNull NetworkSpecifier networkSpecifier) { + if (networkSpecifier != null && Long.bitCount(mTransportTypes) != 1) { + throw new IllegalStateException("Must have a single transport specified to use " + + "setNetworkSpecifier"); + } + + mNetworkSpecifier = networkSpecifier; + + return this; + } + + /** + * Sets the optional transport specific information. + * + * @param transportInfo A concrete, parcelable framework class that extends + * {@link TransportInfo}. + * @return This NetworkCapabilities instance, to facilitate chaining. + * @hide + */ + public @NonNull NetworkCapabilities setTransportInfo(@NonNull TransportInfo transportInfo) { + mTransportInfo = transportInfo; + return this; + } + + /** + * Gets the optional bearer specific network specifier. May be {@code null} if not set. + * + * @return The optional {@link NetworkSpecifier} specifying the bearer specific network + * specifier or {@code null}. + */ + public @Nullable NetworkSpecifier getNetworkSpecifier() { + return mNetworkSpecifier; + } + + /** + * Returns a transport-specific information container. The application may cast this + * container to a concrete sub-class based on its knowledge of the network request. The + * application should be able to deal with a {@code null} return value or an invalid case, + * e.g. use {@code instanceof} operator to verify expected type. + * + * @return A concrete implementation of the {@link TransportInfo} class or null if not + * available for the network. + */ + @Nullable public TransportInfo getTransportInfo() { + return mTransportInfo; + } + + private void combineSpecifiers(NetworkCapabilities nc) { + if (mNetworkSpecifier != null && !mNetworkSpecifier.equals(nc.mNetworkSpecifier)) { + throw new IllegalStateException("Can't combine two networkSpecifiers"); + } + setNetworkSpecifier(nc.mNetworkSpecifier); + } + + private boolean satisfiedBySpecifier(NetworkCapabilities nc) { + return mNetworkSpecifier == null || mNetworkSpecifier.canBeSatisfiedBy(nc.mNetworkSpecifier) + || nc.mNetworkSpecifier instanceof MatchAllNetworkSpecifier; + } + + private boolean equalsSpecifier(NetworkCapabilities nc) { + return Objects.equals(mNetworkSpecifier, nc.mNetworkSpecifier); + } + + private void combineTransportInfos(NetworkCapabilities nc) { + if (mTransportInfo != null && !mTransportInfo.equals(nc.mTransportInfo)) { + throw new IllegalStateException("Can't combine two TransportInfos"); + } + setTransportInfo(nc.mTransportInfo); + } + + private boolean equalsTransportInfo(NetworkCapabilities nc) { + return Objects.equals(mTransportInfo, nc.mTransportInfo); + } + + /** + * Magic value that indicates no signal strength provided. A request specifying this value is + * always satisfied. + */ + public static final int SIGNAL_STRENGTH_UNSPECIFIED = Integer.MIN_VALUE; + + /** + * Signal strength. This is a signed integer, and higher values indicate better signal. + * The exact units are bearer-dependent. For example, Wi-Fi uses RSSI. + */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) + private int mSignalStrength = SIGNAL_STRENGTH_UNSPECIFIED; + + /** + * Sets the signal strength. This is a signed integer, with higher values indicating a stronger + * signal. The exact units are bearer-dependent. For example, Wi-Fi uses the same RSSI units + * reported by wifi code. + *

+ * Note that when used to register a network callback, this specifies the minimum acceptable + * signal strength. When received as the state of an existing network it specifies the current + * value. A value of code SIGNAL_STRENGTH_UNSPECIFIED} means no value when received and has no + * effect when requesting a callback. + * + * @param signalStrength the bearer-specific signal strength. + * @hide + */ + public @NonNull NetworkCapabilities setSignalStrength(int signalStrength) { + mSignalStrength = signalStrength; + return this; + } + + /** + * Returns {@code true} if this object specifies a signal strength. + * + * @hide + */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + public boolean hasSignalStrength() { + return mSignalStrength > SIGNAL_STRENGTH_UNSPECIFIED; + } + + /** + * Retrieves the signal strength. + * + * @return The bearer-specific signal strength. + */ + public int getSignalStrength() { + return mSignalStrength; + } + + private void combineSignalStrength(NetworkCapabilities nc) { + this.mSignalStrength = Math.max(this.mSignalStrength, nc.mSignalStrength); + } + + private boolean satisfiedBySignalStrength(NetworkCapabilities nc) { + return this.mSignalStrength <= nc.mSignalStrength; + } + + private boolean equalsSignalStrength(NetworkCapabilities nc) { + return this.mSignalStrength == nc.mSignalStrength; + } + + /** + * List of UIDs this network applies to. No restriction if null. + *

+ * For networks, mUids represent the list of network this applies to, and null means this + * network applies to all UIDs. + * For requests, mUids is the list of UIDs this network MUST apply to to match ; ALL UIDs + * must be included in a network so that they match. As an exception to the general rule, + * a null mUids field for requests mean "no requirements" rather than what the general rule + * would suggest ("must apply to all UIDs") : this is because this has shown to be what users + * of this API expect in practice. A network that must match all UIDs can still be + * expressed with a set ranging the entire set of possible UIDs. + *

+ * mUids is typically (and at this time, only) used by VPN. This network is only available to + * the UIDs in this list, and it is their default network. Apps in this list that wish to + * bypass the VPN can do so iff the VPN app allows them to or if they are privileged. If this + * member is null, then the network is not restricted by app UID. If it's an empty list, then + * it means nobody can use it. + * As a special exception, the app managing this network (as identified by its UID stored in + * mOwnerUid) can always see this network. This is embodied by a special check in + * satisfiedByUids. That still does not mean the network necessarily applies + * to the app that manages it as determined by #appliesToUid. + *

+ * Please note that in principle a single app can be associated with multiple UIDs because + * each app will have a different UID when it's run as a different (macro-)user. A single + * macro user can only have a single active VPN app at any given time however. + *

+ * Also please be aware this class does not try to enforce any normalization on this. Callers + * can only alter the UIDs by setting them wholesale : this class does not provide any utility + * to add or remove individual UIDs or ranges. If callers have any normalization needs on + * their own (like requiring sortedness or no overlap) they need to enforce it + * themselves. Some of the internal methods also assume this is normalized as in no adjacent + * or overlapping ranges are present. + * + * @hide + */ + private ArraySet mUids = null; + + /** + * Convenience method to set the UIDs this network applies to to a single UID. + * @hide + */ + public @NonNull NetworkCapabilities setSingleUid(int uid) { + final ArraySet identity = new ArraySet<>(1); + identity.add(new UidRange(uid, uid)); + setUids(identity); + return this; + } + + /** + * Set the list of UIDs this network applies to. + * This makes a copy of the set so that callers can't modify it after the call. + * @hide + */ + public @NonNull NetworkCapabilities setUids(Set uids) { + if (null == uids) { + mUids = null; + } else { + mUids = new ArraySet<>(uids); + } + return this; + } + + /** + * Get the list of UIDs this network applies to. + * This returns a copy of the set so that callers can't modify the original object. + * @hide + */ + public @Nullable Set getUids() { + return null == mUids ? null : new ArraySet<>(mUids); + } + + /** + * Test whether this network applies to this UID. + * @hide + */ + public boolean appliesToUid(int uid) { + if (null == mUids) return true; + for (UidRange range : mUids) { + if (range.contains(uid)) { + return true; + } + } + return false; + } + + /** + * Tests if the set of UIDs that this network applies to is the same as the passed network. + *

+ * This test only checks whether equal range objects are in both sets. It will + * return false if the ranges are not exactly the same, even if the covered UIDs + * are for an equivalent result. + *

+ * Note that this method is not very optimized, which is fine as long as it's not used very + * often. + *

+ * nc is assumed nonnull. + * + * @hide + */ + @VisibleForTesting + public boolean equalsUids(@NonNull NetworkCapabilities nc) { + Set comparedUids = nc.mUids; + if (null == comparedUids) return null == mUids; + if (null == mUids) return false; + // Make a copy so it can be mutated to check that all ranges in mUids + // also are in uids. + final Set uids = new ArraySet<>(mUids); + for (UidRange range : comparedUids) { + if (!uids.contains(range)) { + return false; + } + uids.remove(range); + } + return uids.isEmpty(); + } + + /** + * Test whether the passed NetworkCapabilities satisfies the UIDs this capabilities require. + * + * This method is called on the NetworkCapabilities embedded in a request with the + * capabilities of an available network. It checks whether all the UIDs from this listen + * (representing the UIDs that must have access to the network) are satisfied by the UIDs + * in the passed nc (representing the UIDs that this network is available to). + *

+ * As a special exception, the UID that created the passed network (as represented by its + * mOwnerUid field) always satisfies a NetworkRequest requiring it (of LISTEN + * or REQUEST types alike), even if the network does not apply to it. That is so a VPN app + * can see its own network when it listens for it. + *

+ * nc is assumed nonnull. Else, NPE. + * @see #appliesToUid + * @hide + */ + public boolean satisfiedByUids(@NonNull NetworkCapabilities nc) { + if (null == nc.mUids || null == mUids) return true; // The network satisfies everything. + for (UidRange requiredRange : mUids) { + if (requiredRange.contains(nc.mOwnerUid)) return true; + if (!nc.appliesToUidRange(requiredRange)) { + return false; + } + } + return true; + } + + /** + * Returns whether this network applies to the passed ranges. + * This assumes that to apply, the passed range has to be entirely contained + * within one of the ranges this network applies to. If the ranges are not normalized, + * this method may return false even though all required UIDs are covered because no + * single range contained them all. + * @hide + */ + @VisibleForTesting + public boolean appliesToUidRange(@Nullable UidRange requiredRange) { + if (null == mUids) return true; + for (UidRange uidRange : mUids) { + if (uidRange.containsRange(requiredRange)) { + return true; + } + } + return false; + } + + /** + * Combine the UIDs this network currently applies to with the UIDs the passed + * NetworkCapabilities apply to. + * nc is assumed nonnull. + */ + private void combineUids(@NonNull NetworkCapabilities nc) { + if (null == nc.mUids || null == mUids) { + mUids = null; + return; + } + mUids.addAll(nc.mUids); + } + + + /** + * The SSID of the network, or null if not applicable or unknown. + *

+ * This is filled in by wifi code. + * @hide + */ + private String mSSID; + + /** + * Sets the SSID of this network. + * @hide + */ + public @NonNull NetworkCapabilities setSSID(@Nullable String ssid) { + mSSID = ssid; + return this; + } + + /** + * Gets the SSID of this network, or null if none or unknown. + * @hide + */ + @SystemApi + public @Nullable String getSsid() { + return mSSID; + } + + /** + * Tests if the SSID of this network is the same as the SSID of the passed network. + * @hide + */ + public boolean equalsSSID(@NonNull NetworkCapabilities nc) { + return Objects.equals(mSSID, nc.mSSID); + } + + /** + * Check if the SSID requirements of this object are matched by the passed object. + * @hide + */ + public boolean satisfiedBySSID(@NonNull NetworkCapabilities nc) { + return mSSID == null || mSSID.equals(nc.mSSID); + } + + /** + * Combine SSIDs of the capabilities. + *

+ * This is only legal if either the SSID of this object is null, or both SSIDs are + * equal. + * @hide + */ + private void combineSSIDs(@NonNull NetworkCapabilities nc) { + if (mSSID != null && !mSSID.equals(nc.mSSID)) { + throw new IllegalStateException("Can't combine two SSIDs"); + } + setSSID(nc.mSSID); + } + + /** + * Combine a set of Capabilities to this one. Useful for coming up with the complete set. + *

+ * Note that this method may break an invariant of having a particular capability in either + * wanted or unwanted lists but never in both. Requests that have the same capability in + * both lists will never be satisfied. + * @hide + */ + public void combineCapabilities(@NonNull NetworkCapabilities nc) { + combineNetCapabilities(nc); + combineTransportTypes(nc); + combineLinkBandwidths(nc); + combineSpecifiers(nc); + combineTransportInfos(nc); + combineSignalStrength(nc); + combineUids(nc); + combineSSIDs(nc); + combineRequestor(nc); + combineAdministratorUids(nc); + } + + /** + * Check if our requirements are satisfied by the given {@code NetworkCapabilities}. + * + * @param nc the {@code NetworkCapabilities} that may or may not satisfy our requirements. + * @param onlyImmutable if {@code true}, do not consider mutable requirements such as link + * bandwidth, signal strength, or validation / captive portal status. + * + * @hide + */ + private boolean satisfiedByNetworkCapabilities(NetworkCapabilities nc, boolean onlyImmutable) { + return (nc != null + && satisfiedByNetCapabilities(nc, onlyImmutable) + && satisfiedByTransportTypes(nc) + && (onlyImmutable || satisfiedByLinkBandwidths(nc)) + && satisfiedBySpecifier(nc) + && (onlyImmutable || satisfiedBySignalStrength(nc)) + && (onlyImmutable || satisfiedByUids(nc)) + && (onlyImmutable || satisfiedBySSID(nc))) + && (onlyImmutable || satisfiedByRequestor(nc)); + } + + /** + * Check if our requirements are satisfied by the given {@code NetworkCapabilities}. + * + * @param nc the {@code NetworkCapabilities} that may or may not satisfy our requirements. + * + * @hide + */ + @SystemApi + public boolean satisfiedByNetworkCapabilities(@Nullable NetworkCapabilities nc) { + return satisfiedByNetworkCapabilities(nc, false); + } + + /** + * Check if our immutable requirements are satisfied by the given {@code NetworkCapabilities}. + * + * @param nc the {@code NetworkCapabilities} that may or may not satisfy our requirements. + * + * @hide + */ + public boolean satisfiedByImmutableNetworkCapabilities(@Nullable NetworkCapabilities nc) { + return satisfiedByNetworkCapabilities(nc, true); + } + + /** + * Checks that our immutable capabilities are the same as those of the given + * {@code NetworkCapabilities} and return a String describing any difference. + * The returned String is empty if there is no difference. + * + * @hide + */ + public String describeImmutableDifferences(@Nullable NetworkCapabilities that) { + if (that == null) { + return "other NetworkCapabilities was null"; + } + + StringJoiner joiner = new StringJoiner(", "); + + // Ignore NOT_METERED being added or removed as it is effectively dynamic. http://b/63326103 + // TODO: properly support NOT_METERED as a mutable and requestable capability. + final long mask = ~MUTABLE_CAPABILITIES & ~(1 << NET_CAPABILITY_NOT_METERED); + long oldImmutableCapabilities = this.mNetworkCapabilities & mask; + long newImmutableCapabilities = that.mNetworkCapabilities & mask; + if (oldImmutableCapabilities != newImmutableCapabilities) { + String before = capabilityNamesOf(BitUtils.unpackBits(oldImmutableCapabilities)); + String after = capabilityNamesOf(BitUtils.unpackBits(newImmutableCapabilities)); + joiner.add(String.format("immutable capabilities changed: %s -> %s", before, after)); + } + + if (!equalsSpecifier(that)) { + NetworkSpecifier before = this.getNetworkSpecifier(); + NetworkSpecifier after = that.getNetworkSpecifier(); + joiner.add(String.format("specifier changed: %s -> %s", before, after)); + } + + if (!equalsTransportTypes(that)) { + String before = transportNamesOf(this.getTransportTypes()); + String after = transportNamesOf(that.getTransportTypes()); + joiner.add(String.format("transports changed: %s -> %s", before, after)); + } + + return joiner.toString(); + } + + /** + * Checks that our requestable capabilities are the same as those of the given + * {@code NetworkCapabilities}. + * + * @hide + */ + public boolean equalRequestableCapabilities(@Nullable NetworkCapabilities nc) { + if (nc == null) return false; + return (equalsNetCapabilitiesRequestable(nc) + && equalsTransportTypes(nc) + && equalsSpecifier(nc)); + } + + @Override + public boolean equals(@Nullable Object obj) { + if (obj == null || (obj instanceof NetworkCapabilities == false)) return false; + NetworkCapabilities that = (NetworkCapabilities) obj; + return equalsNetCapabilities(that) + && equalsTransportTypes(that) + && equalsLinkBandwidths(that) + && equalsSignalStrength(that) + && equalsSpecifier(that) + && equalsTransportInfo(that) + && equalsUids(that) + && equalsSSID(that) + && equalsOwnerUid(that) + && equalsPrivateDnsBroken(that) + && equalsRequestor(that) + && equalsAdministratorUids(that); + } + + @Override + public int hashCode() { + return (int) (mNetworkCapabilities & 0xFFFFFFFF) + + ((int) (mNetworkCapabilities >> 32) * 3) + + ((int) (mUnwantedNetworkCapabilities & 0xFFFFFFFF) * 5) + + ((int) (mUnwantedNetworkCapabilities >> 32) * 7) + + ((int) (mTransportTypes & 0xFFFFFFFF) * 11) + + ((int) (mTransportTypes >> 32) * 13) + + mLinkUpBandwidthKbps * 17 + + mLinkDownBandwidthKbps * 19 + + Objects.hashCode(mNetworkSpecifier) * 23 + + mSignalStrength * 29 + + mOwnerUid * 31 + + Objects.hashCode(mUids) * 37 + + Objects.hashCode(mSSID) * 41 + + Objects.hashCode(mTransportInfo) * 43 + + Objects.hashCode(mPrivateDnsBroken) * 47 + + Objects.hashCode(mRequestorUid) * 53 + + Objects.hashCode(mRequestorPackageName) * 59 + + Arrays.hashCode(mAdministratorUids) * 61; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeLong(mNetworkCapabilities); + dest.writeLong(mUnwantedNetworkCapabilities); + dest.writeLong(mTransportTypes); + dest.writeInt(mLinkUpBandwidthKbps); + dest.writeInt(mLinkDownBandwidthKbps); + dest.writeParcelable((Parcelable) mNetworkSpecifier, flags); + dest.writeParcelable((Parcelable) mTransportInfo, flags); + dest.writeInt(mSignalStrength); + dest.writeArraySet(mUids); + dest.writeString(mSSID); + dest.writeBoolean(mPrivateDnsBroken); + dest.writeIntArray(getAdministratorUids()); + dest.writeInt(mOwnerUid); + dest.writeInt(mRequestorUid); + dest.writeString(mRequestorPackageName); + } + + public static final @android.annotation.NonNull Creator CREATOR = + new Creator() { + @Override + public NetworkCapabilities createFromParcel(Parcel in) { + NetworkCapabilities netCap = new NetworkCapabilities(); + + netCap.mNetworkCapabilities = in.readLong(); + netCap.mUnwantedNetworkCapabilities = in.readLong(); + netCap.mTransportTypes = in.readLong(); + netCap.mLinkUpBandwidthKbps = in.readInt(); + netCap.mLinkDownBandwidthKbps = in.readInt(); + netCap.mNetworkSpecifier = in.readParcelable(null); + netCap.mTransportInfo = in.readParcelable(null); + netCap.mSignalStrength = in.readInt(); + netCap.mUids = (ArraySet) in.readArraySet( + null /* ClassLoader, null for default */); + netCap.mSSID = in.readString(); + netCap.mPrivateDnsBroken = in.readBoolean(); + netCap.setAdministratorUids(in.createIntArray()); + netCap.mOwnerUid = in.readInt(); + netCap.mRequestorUid = in.readInt(); + netCap.mRequestorPackageName = in.readString(); + return netCap; + } + @Override + public NetworkCapabilities[] newArray(int size) { + return new NetworkCapabilities[size]; + } + }; + + @Override + public @NonNull String toString() { + final StringBuilder sb = new StringBuilder("["); + if (0 != mTransportTypes) { + sb.append(" Transports: "); + appendStringRepresentationOfBitMaskToStringBuilder(sb, mTransportTypes, + NetworkCapabilities::transportNameOf, "|"); + } + if (0 != mNetworkCapabilities) { + sb.append(" Capabilities: "); + appendStringRepresentationOfBitMaskToStringBuilder(sb, mNetworkCapabilities, + NetworkCapabilities::capabilityNameOf, "&"); + } + if (0 != mUnwantedNetworkCapabilities) { + sb.append(" Unwanted: "); + appendStringRepresentationOfBitMaskToStringBuilder(sb, mUnwantedNetworkCapabilities, + NetworkCapabilities::capabilityNameOf, "&"); + } + if (mLinkUpBandwidthKbps > 0) { + sb.append(" LinkUpBandwidth>=").append(mLinkUpBandwidthKbps).append("Kbps"); + } + if (mLinkDownBandwidthKbps > 0) { + sb.append(" LinkDnBandwidth>=").append(mLinkDownBandwidthKbps).append("Kbps"); + } + if (mNetworkSpecifier != null) { + sb.append(" Specifier: <").append(mNetworkSpecifier).append(">"); + } + if (mTransportInfo != null) { + sb.append(" TransportInfo: <").append(mTransportInfo).append(">"); + } + if (hasSignalStrength()) { + sb.append(" SignalStrength: ").append(mSignalStrength); + } + + if (null != mUids) { + if ((1 == mUids.size()) && (mUids.valueAt(0).count() == 1)) { + sb.append(" Uid: ").append(mUids.valueAt(0).start); + } else { + sb.append(" Uids: <").append(mUids).append(">"); + } + } + if (mOwnerUid != Process.INVALID_UID) { + sb.append(" OwnerUid: ").append(mOwnerUid); + } + + if (!ArrayUtils.isEmpty(mAdministratorUids)) { + sb.append(" AdminUids: ").append(Arrays.toString(mAdministratorUids)); + } + + if (mRequestorUid != Process.INVALID_UID) { + sb.append(" RequestorUid: ").append(mRequestorUid); + } + + if (mRequestorPackageName != null) { + sb.append(" RequestorPkg: ").append(mRequestorPackageName); + } + + if (null != mSSID) { + sb.append(" SSID: ").append(mSSID); + } + + + if (mPrivateDnsBroken) { + sb.append(" PrivateDnsBroken"); + } + + sb.append("]"); + return sb.toString(); + } + + + private interface NameOf { + String nameOf(int value); + } + + /** + * @hide + */ + public static void appendStringRepresentationOfBitMaskToStringBuilder(@NonNull StringBuilder sb, + long bitMask, @NonNull NameOf nameFetcher, @NonNull String separator) { + int bitPos = 0; + boolean firstElementAdded = false; + while (bitMask != 0) { + if ((bitMask & 1) != 0) { + if (firstElementAdded) { + sb.append(separator); + } else { + firstElementAdded = true; + } + sb.append(nameFetcher.nameOf(bitPos)); + } + bitMask >>= 1; + ++bitPos; + } + } + + /** @hide */ + public void dumpDebug(@NonNull ProtoOutputStream proto, long fieldId) { + final long token = proto.start(fieldId); + + for (int transport : getTransportTypes()) { + proto.write(NetworkCapabilitiesProto.TRANSPORTS, transport); + } + + for (int capability : getCapabilities()) { + proto.write(NetworkCapabilitiesProto.CAPABILITIES, capability); + } + + proto.write(NetworkCapabilitiesProto.LINK_UP_BANDWIDTH_KBPS, mLinkUpBandwidthKbps); + proto.write(NetworkCapabilitiesProto.LINK_DOWN_BANDWIDTH_KBPS, mLinkDownBandwidthKbps); + + if (mNetworkSpecifier != null) { + proto.write(NetworkCapabilitiesProto.NETWORK_SPECIFIER, mNetworkSpecifier.toString()); + } + if (mTransportInfo != null) { + // TODO b/120653863: write transport-specific info to proto? + } + + proto.write(NetworkCapabilitiesProto.CAN_REPORT_SIGNAL_STRENGTH, hasSignalStrength()); + proto.write(NetworkCapabilitiesProto.SIGNAL_STRENGTH, mSignalStrength); + + proto.end(token); + } + + /** + * @hide + */ + public static @NonNull String capabilityNamesOf(@Nullable @NetCapability int[] capabilities) { + StringJoiner joiner = new StringJoiner("|"); + if (capabilities != null) { + for (int c : capabilities) { + joiner.add(capabilityNameOf(c)); + } + } + return joiner.toString(); + } + + /** + * @hide + */ + public static @NonNull String capabilityNameOf(@NetCapability int capability) { + switch (capability) { + case NET_CAPABILITY_MMS: return "MMS"; + case NET_CAPABILITY_SUPL: return "SUPL"; + case NET_CAPABILITY_DUN: return "DUN"; + case NET_CAPABILITY_FOTA: return "FOTA"; + case NET_CAPABILITY_IMS: return "IMS"; + case NET_CAPABILITY_CBS: return "CBS"; + case NET_CAPABILITY_WIFI_P2P: return "WIFI_P2P"; + case NET_CAPABILITY_IA: return "IA"; + case NET_CAPABILITY_RCS: return "RCS"; + case NET_CAPABILITY_XCAP: return "XCAP"; + case NET_CAPABILITY_EIMS: return "EIMS"; + case NET_CAPABILITY_NOT_METERED: return "NOT_METERED"; + case NET_CAPABILITY_INTERNET: return "INTERNET"; + case NET_CAPABILITY_NOT_RESTRICTED: return "NOT_RESTRICTED"; + case NET_CAPABILITY_TRUSTED: return "TRUSTED"; + case NET_CAPABILITY_NOT_VPN: return "NOT_VPN"; + case NET_CAPABILITY_VALIDATED: return "VALIDATED"; + case NET_CAPABILITY_CAPTIVE_PORTAL: return "CAPTIVE_PORTAL"; + case NET_CAPABILITY_NOT_ROAMING: return "NOT_ROAMING"; + case NET_CAPABILITY_FOREGROUND: return "FOREGROUND"; + case NET_CAPABILITY_NOT_CONGESTED: return "NOT_CONGESTED"; + case NET_CAPABILITY_NOT_SUSPENDED: return "NOT_SUSPENDED"; + case NET_CAPABILITY_OEM_PAID: return "OEM_PAID"; + case NET_CAPABILITY_MCX: return "MCX"; + case NET_CAPABILITY_PARTIAL_CONNECTIVITY: return "PARTIAL_CONNECTIVITY"; + case NET_CAPABILITY_TEMPORARILY_NOT_METERED: return "TEMPORARILY_NOT_METERED"; + case NET_CAPABILITY_OEM_PRIVATE: return "OEM_PRIVATE"; + case NET_CAPABILITY_VEHICLE_INTERNAL: return "NET_CAPABILITY_VEHICLE_INTERNAL"; + case NET_CAPABILITY_NOT_VCN_MANAGED: return "NOT_VCN_MANAGED"; + default: return Integer.toString(capability); + } + } + + /** + * @hide + */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + public static @NonNull String transportNamesOf(@Nullable @Transport int[] types) { + StringJoiner joiner = new StringJoiner("|"); + if (types != null) { + for (int t : types) { + joiner.add(transportNameOf(t)); + } + } + return joiner.toString(); + } + + /** + * @hide + */ + public static @NonNull String transportNameOf(@Transport int transport) { + if (!isValidTransport(transport)) { + return "UNKNOWN"; + } + return TRANSPORT_NAMES[transport]; + } + + private static void checkValidTransportType(@Transport int transport) { + Preconditions.checkArgument( + isValidTransport(transport), "Invalid TransportType " + transport); + } + + private static boolean isValidCapability(@NetworkCapabilities.NetCapability int capability) { + return capability >= MIN_NET_CAPABILITY && capability <= MAX_NET_CAPABILITY; + } + + private static void checkValidCapability(@NetworkCapabilities.NetCapability int capability) { + Preconditions.checkArgument(isValidCapability(capability), + "NetworkCapability " + capability + "out of range"); + } + + /** + * Check if this {@code NetworkCapability} instance is metered. + * + * @return {@code true} if {@code NET_CAPABILITY_NOT_METERED} is not set on this instance. + * @hide + */ + public boolean isMetered() { + return !hasCapability(NET_CAPABILITY_NOT_METERED); + } + + /** + * Check if private dns is broken. + * + * @return {@code true} if {@code mPrivateDnsBroken} is set when private DNS is broken. + * @hide + */ + public boolean isPrivateDnsBroken() { + return mPrivateDnsBroken; + } + + /** + * Set mPrivateDnsBroken to true when private dns is broken. + * + * @param broken the status of private DNS to be set. + * @hide + */ + public void setPrivateDnsBroken(boolean broken) { + mPrivateDnsBroken = broken; + } + + private boolean equalsPrivateDnsBroken(NetworkCapabilities nc) { + return mPrivateDnsBroken == nc.mPrivateDnsBroken; + } + + /** + * Set the UID of the app making the request. + * + * For instances of NetworkCapabilities representing a request, sets the + * UID of the app making the request. For a network created by the system, + * sets the UID of the only app whose requests can match this network. + * This can be set to {@link Process#INVALID_UID} if there is no such app, + * or if this instance of NetworkCapabilities is about to be sent to a + * party that should not learn about this. + * + * @param uid UID of the app. + * @hide + */ + public @NonNull NetworkCapabilities setRequestorUid(int uid) { + mRequestorUid = uid; + return this; + } + + /** + * Returns the UID of the app making the request. + * + * For a NetworkRequest being made by an app, contains the app's UID. For a network + * created by the system, contains the UID of the only app whose requests can match + * this network, or {@link Process#INVALID_UID} if none or if the + * caller does not have permission to learn about this. + * + * @return the uid of the app making the request. + * @hide + */ + public int getRequestorUid() { + return mRequestorUid; + } + + /** + * Set the package name of the app making the request. + * + * For instances of NetworkCapabilities representing a request, sets the + * package name of the app making the request. For a network created by the system, + * sets the package name of the only app whose requests can match this network. + * This can be set to null if there is no such app, or if this instance of + * NetworkCapabilities is about to be sent to a party that should not learn about this. + * + * @param packageName package name of the app. + * @hide + */ + public @NonNull NetworkCapabilities setRequestorPackageName(@NonNull String packageName) { + mRequestorPackageName = packageName; + return this; + } + + /** + * Returns the package name of the app making the request. + * + * For a NetworkRequest being made by an app, contains the app's package name. For a + * network created by the system, contains the package name of the only app whose + * requests can match this network, or null if none or if the caller does not have + * permission to learn about this. + * + * @return the package name of the app making the request. + * @hide + */ + @Nullable + public String getRequestorPackageName() { + return mRequestorPackageName; + } + + /** + * Set the uid and package name of the app causing this network to exist. + * + * {@see #setRequestorUid} and {@link #setRequestorPackageName} + * + * @param uid UID of the app. + * @param packageName package name of the app. + * @hide + */ + public @NonNull NetworkCapabilities setRequestorUidAndPackageName( + int uid, @NonNull String packageName) { + return setRequestorUid(uid).setRequestorPackageName(packageName); + } + + /** + * Test whether the passed NetworkCapabilities satisfies the requestor restrictions of this + * capabilities. + * + * This method is called on the NetworkCapabilities embedded in a request with the + * capabilities of an available network. If the available network, sets a specific + * requestor (by uid and optionally package name), then this will only match a request from the + * same app. If either of the capabilities have an unset uid or package name, then it matches + * everything. + *

+ * nc is assumed nonnull. Else, NPE. + */ + private boolean satisfiedByRequestor(NetworkCapabilities nc) { + // No uid set, matches everything. + if (mRequestorUid == Process.INVALID_UID || nc.mRequestorUid == Process.INVALID_UID) { + return true; + } + // uids don't match. + if (mRequestorUid != nc.mRequestorUid) return false; + // No package names set, matches everything + if (null == nc.mRequestorPackageName || null == mRequestorPackageName) return true; + // check for package name match. + return TextUtils.equals(mRequestorPackageName, nc.mRequestorPackageName); + } + + /** + * Combine requestor info of the capabilities. + *

+ * This is only legal if either the requestor info of this object is reset, or both info are + * equal. + * nc is assumed nonnull. + */ + private void combineRequestor(@NonNull NetworkCapabilities nc) { + if (mRequestorUid != Process.INVALID_UID && mRequestorUid != nc.mOwnerUid) { + throw new IllegalStateException("Can't combine two uids"); + } + if (mRequestorPackageName != null + && !mRequestorPackageName.equals(nc.mRequestorPackageName)) { + throw new IllegalStateException("Can't combine two package names"); + } + setRequestorUid(nc.mRequestorUid); + setRequestorPackageName(nc.mRequestorPackageName); + } + + private boolean equalsRequestor(NetworkCapabilities nc) { + return mRequestorUid == nc.mRequestorUid + && TextUtils.equals(mRequestorPackageName, nc.mRequestorPackageName); + } + + /** + * Builder class for NetworkCapabilities. + * + * This class is mainly for for {@link NetworkAgent} instances to use. Many fields in + * the built class require holding a signature permission to use - mostly + * {@link android.Manifest.permission.NETWORK_FACTORY}, but refer to the specific + * description of each setter. As this class lives entirely in app space it does not + * enforce these restrictions itself but the system server clears out the relevant + * fields when receiving a NetworkCapabilities object from a caller without the + * appropriate permission. + * + * Apps don't use this builder directly. Instead, they use {@link NetworkRequest} via + * its builder object. + * + * @hide + */ + @SystemApi + public static final class Builder { + private final NetworkCapabilities mCaps; + + /** + * Creates a new Builder to construct NetworkCapabilities objects. + */ + public Builder() { + mCaps = new NetworkCapabilities(); + } + + /** + * Creates a new Builder of NetworkCapabilities from an existing instance. + */ + public Builder(@NonNull final NetworkCapabilities nc) { + Objects.requireNonNull(nc); + mCaps = new NetworkCapabilities(nc); + } + + /** + * Adds the given transport type. + * + * Multiple transports may be added. Note that when searching for a network to satisfy a + * request, satisfying any of the transports listed in the request will satisfy the request. + * For example {@code TRANSPORT_WIFI} and {@code TRANSPORT_ETHERNET} added to a + * {@code NetworkCapabilities} would cause either a Wi-Fi network or an Ethernet network + * to be selected. This is logically different than + * {@code NetworkCapabilities.NET_CAPABILITY_*}. + * + * @param transportType the transport type to be added or removed. + * @return this builder + */ + @NonNull + public Builder addTransportType(@Transport int transportType) { + checkValidTransportType(transportType); + mCaps.addTransportType(transportType); + return this; + } + + /** + * Removes the given transport type. + * + * {@see #addTransportType}. + * + * @param transportType the transport type to be added or removed. + * @return this builder + */ + @NonNull + public Builder removeTransportType(@Transport int transportType) { + checkValidTransportType(transportType); + mCaps.removeTransportType(transportType); + return this; + } + + /** + * Adds the given capability. + * + * @param capability the capability + * @return this builder + */ + @NonNull + public Builder addCapability(@NetCapability final int capability) { + mCaps.setCapability(capability, true); + return this; + } + + /** + * Removes the given capability. + * + * @param capability the capability + * @return this builder + */ + @NonNull + public Builder removeCapability(@NetCapability final int capability) { + mCaps.setCapability(capability, false); + return this; + } + + /** + * Sets the owner UID. + * + * The default value is {@link Process#INVALID_UID}. Pass this value to reset. + * + * Note: for security the system will clear out this field when received from a + * non-privileged source. + * + * @param ownerUid the owner UID + * @return this builder + */ + @NonNull + @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) + public Builder setOwnerUid(final int ownerUid) { + mCaps.setOwnerUid(ownerUid); + return this; + } + + /** + * Sets the list of UIDs that are administrators of this network. + * + *

UIDs included in administratorUids gain administrator privileges over this + * Network. Examples of UIDs that should be included in administratorUids are: + *

    + *
  • Carrier apps with privileges for the relevant subscription + *
  • Active VPN apps + *
  • Other application groups with a particular Network-related role + *
+ * + *

In general, user-supplied networks (such as WiFi networks) do not have + * administrators. + * + *

An app is granted owner privileges over Networks that it supplies. The owner + * UID MUST always be included in administratorUids. + * + * The default value is the empty array. Pass an empty array to reset. + * + * Note: for security the system will clear out this field when received from a + * non-privileged source, such as an app using reflection to call this or + * mutate the member in the built object. + * + * @param administratorUids the UIDs to be set as administrators of this Network. + * @return this builder + */ + @NonNull + @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) + public Builder setAdministratorUids(@NonNull final int[] administratorUids) { + Objects.requireNonNull(administratorUids); + mCaps.setAdministratorUids(administratorUids); + return this; + } + + /** + * Sets the upstream bandwidth of the link. + * + * Sets the upstream bandwidth for this network in Kbps. This always only refers to + * the estimated first hop transport bandwidth. + *

+ * Note that when used to request a network, this specifies the minimum acceptable. + * When received as the state of an existing network this specifies the typical + * first hop bandwidth expected. This is never measured, but rather is inferred + * from technology type and other link parameters. It could be used to differentiate + * between very slow 1xRTT cellular links and other faster networks or even between + * 802.11b vs 802.11AC wifi technologies. It should not be used to differentiate between + * fast backhauls and slow backhauls. + * + * @param upKbps the estimated first hop upstream (device to network) bandwidth. + * @return this builder + */ + @NonNull + public Builder setLinkUpstreamBandwidthKbps(final int upKbps) { + mCaps.setLinkUpstreamBandwidthKbps(upKbps); + return this; + } + + /** + * Sets the downstream bandwidth for this network in Kbps. This always only refers to + * the estimated first hop transport bandwidth. + *

+ * Note that when used to request a network, this specifies the minimum acceptable. + * When received as the state of an existing network this specifies the typical + * first hop bandwidth expected. This is never measured, but rather is inferred + * from technology type and other link parameters. It could be used to differentiate + * between very slow 1xRTT cellular links and other faster networks or even between + * 802.11b vs 802.11AC wifi technologies. It should not be used to differentiate between + * fast backhauls and slow backhauls. + * + * @param downKbps the estimated first hop downstream (network to device) bandwidth. + * @return this builder + */ + @NonNull + public Builder setLinkDownstreamBandwidthKbps(final int downKbps) { + mCaps.setLinkDownstreamBandwidthKbps(downKbps); + return this; + } + + /** + * Sets the optional bearer specific network specifier. + * This has no meaning if a single transport is also not specified, so calling + * this without a single transport set will generate an exception, as will + * subsequently adding or removing transports after this is set. + *

+ * + * @param specifier a concrete, parcelable framework class that extends NetworkSpecifier, + * or null to clear it. + * @return this builder + */ + @NonNull + public Builder setNetworkSpecifier(@Nullable final NetworkSpecifier specifier) { + mCaps.setNetworkSpecifier(specifier); + return this; + } + + /** + * Sets the optional transport specific information. + * + * @param info A concrete, parcelable framework class that extends {@link TransportInfo}, + * or null to clear it. + * @return this builder + */ + @NonNull + public Builder setTransportInfo(@Nullable final TransportInfo info) { + mCaps.setTransportInfo(info); + return this; + } + + /** + * Sets the signal strength. This is a signed integer, with higher values indicating a + * stronger signal. The exact units are bearer-dependent. For example, Wi-Fi uses the + * same RSSI units reported by wifi code. + *

+ * Note that when used to register a network callback, this specifies the minimum + * acceptable signal strength. When received as the state of an existing network it + * specifies the current value. A value of code SIGNAL_STRENGTH_UNSPECIFIED} means + * no value when received and has no effect when requesting a callback. + * + * Note: for security the system will throw if it receives a NetworkRequest where + * the underlying NetworkCapabilities has this member set from a source that does + * not hold the {@link android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP} + * permission. Apps with this permission can use this indirectly through + * {@link android.net.NetworkRequest}. + * + * @param signalStrength the bearer-specific signal strength. + * @return this builder + */ + @NonNull + @RequiresPermission(android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP) + public Builder setSignalStrength(final int signalStrength) { + mCaps.setSignalStrength(signalStrength); + return this; + } + + /** + * Sets the SSID of this network. + * + * Note: for security the system will clear out this field when received from a + * non-privileged source, like an app using reflection to set this. + * + * @param ssid the SSID, or null to clear it. + * @return this builder + */ + @NonNull + @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) + public Builder setSsid(@Nullable final String ssid) { + mCaps.setSSID(ssid); + return this; + } + + /** + * Set the uid of the app causing this network to exist. + * + * Note: for security the system will clear out this field when received from a + * non-privileged source. + * + * @param uid UID of the app. + * @return this builder + */ + @NonNull + @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) + public Builder setRequestorUid(final int uid) { + mCaps.setRequestorUid(uid); + return this; + } + + /** + * Set the package name of the app causing this network to exist. + * + * Note: for security the system will clear out this field when received from a + * non-privileged source. + * + * @param packageName package name of the app, or null to clear it. + * @return this builder + */ + @NonNull + @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) + public Builder setRequestorPackageName(@Nullable final String packageName) { + mCaps.setRequestorPackageName(packageName); + return this; + } + + /** + * Builds the instance of the capabilities. + * + * @return the built instance of NetworkCapabilities. + */ + @NonNull + public NetworkCapabilities build() { + if (mCaps.getOwnerUid() != Process.INVALID_UID) { + if (!ArrayUtils.contains(mCaps.getAdministratorUids(), mCaps.getOwnerUid())) { + throw new IllegalStateException("The owner UID must be included in " + + " administrator UIDs."); + } + } + return new NetworkCapabilities(mCaps); + } + } +} diff --git a/packages/Connectivity/framework/src/android/net/NetworkConfig.java b/packages/Connectivity/framework/src/android/net/NetworkConfig.java new file mode 100644 index 000000000000..32a2cda00370 --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/NetworkConfig.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import java.util.Locale; + +/** + * Describes the buildtime configuration of a network. + * Holds settings read from resources. + * @hide + */ +public class NetworkConfig { + /** + * Human readable string + */ + public String name; + + /** + * Type from ConnectivityManager + */ + public int type; + + /** + * the radio number from radio attributes config + */ + public int radio; + + /** + * higher number == higher priority when turning off connections + */ + public int priority; + + /** + * indicates the boot time dependencyMet setting + */ + public boolean dependencyMet; + + /** + * indicates the default restoral timer in seconds + * if the network is used as a special network feature + * -1 indicates no restoration of default + */ + public int restoreTime; + + /** + * input string from config.xml resource. Uses the form: + * [Connection name],[ConnectivityManager connection type], + * [associated radio-type],[priority],[dependencyMet] + */ + public NetworkConfig(String init) { + String fragments[] = init.split(","); + name = fragments[0].trim().toLowerCase(Locale.ROOT); + type = Integer.parseInt(fragments[1]); + radio = Integer.parseInt(fragments[2]); + priority = Integer.parseInt(fragments[3]); + restoreTime = Integer.parseInt(fragments[4]); + dependencyMet = Boolean.parseBoolean(fragments[5]); + } + + /** + * Indicates if this network is supposed to be default-routable + */ + public boolean isDefault() { + return (type == radio); + } +} diff --git a/packages/Connectivity/framework/src/android/net/NetworkInfo.aidl b/packages/Connectivity/framework/src/android/net/NetworkInfo.aidl new file mode 100644 index 000000000000..f50187302966 --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/NetworkInfo.aidl @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2007, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +parcelable NetworkInfo; diff --git a/packages/Connectivity/framework/src/android/net/NetworkInfo.java b/packages/Connectivity/framework/src/android/net/NetworkInfo.java new file mode 100644 index 000000000000..d752901e2eb0 --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/NetworkInfo.java @@ -0,0 +1,626 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.compat.annotation.UnsupportedAppUsage; +import android.os.Parcel; +import android.os.Parcelable; +import android.telephony.Annotation.NetworkType; +import android.text.TextUtils; + +import com.android.internal.annotations.VisibleForTesting; + +import java.util.EnumMap; + +/** + * Describes the status of a network interface. + *

Use {@link ConnectivityManager#getActiveNetworkInfo()} to get an instance that represents + * the current network connection. + * + * @deprecated Callers should instead use the {@link ConnectivityManager.NetworkCallback} API to + * learn about connectivity changes, or switch to use + * {@link ConnectivityManager#getNetworkCapabilities} or + * {@link ConnectivityManager#getLinkProperties} to get information synchronously. Keep + * in mind that while callbacks are guaranteed to be called for every event in order, + * synchronous calls have no such constraints, and as such it is unadvisable to use the + * synchronous methods inside the callbacks as they will often not offer a view of + * networking that is consistent (that is: they may return a past or a future state with + * respect to the event being processed by the callback). Instead, callers are advised + * to only use the arguments of the callbacks, possibly memorizing the specific bits of + * information they need to keep from one callback to another. + */ +@Deprecated +public class NetworkInfo implements Parcelable { + + /** + * Coarse-grained network state. This is probably what most applications should + * use, rather than {@link android.net.NetworkInfo.DetailedState DetailedState}. + * The mapping between the two is as follows: + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Detailed stateCoarse-grained state
IDLEDISCONNECTED
SCANNINGDISCONNECTED
CONNECTINGCONNECTING
AUTHENTICATINGCONNECTING
OBTAINING_IPADDRCONNECTING
VERIFYING_POOR_LINKCONNECTING
CAPTIVE_PORTAL_CHECKCONNECTING
CONNECTEDCONNECTED
SUSPENDEDSUSPENDED
DISCONNECTINGDISCONNECTING
DISCONNECTEDDISCONNECTED
FAILEDDISCONNECTED
BLOCKEDDISCONNECTED
+ * + * @deprecated See {@link NetworkInfo}. + */ + @Deprecated + public enum State { + CONNECTING, CONNECTED, SUSPENDED, DISCONNECTING, DISCONNECTED, UNKNOWN + } + + /** + * The fine-grained state of a network connection. This level of detail + * is probably of interest to few applications. Most should use + * {@link android.net.NetworkInfo.State State} instead. + * + * @deprecated See {@link NetworkInfo}. + */ + @Deprecated + public enum DetailedState { + /** Ready to start data connection setup. */ + IDLE, + /** Searching for an available access point. */ + SCANNING, + /** Currently setting up data connection. */ + CONNECTING, + /** Network link established, performing authentication. */ + AUTHENTICATING, + /** Awaiting response from DHCP server in order to assign IP address information. */ + OBTAINING_IPADDR, + /** IP traffic should be available. */ + CONNECTED, + /** IP traffic is suspended */ + SUSPENDED, + /** Currently tearing down data connection. */ + DISCONNECTING, + /** IP traffic not available. */ + DISCONNECTED, + /** Attempt to connect failed. */ + FAILED, + /** Access to this network is blocked. */ + BLOCKED, + /** Link has poor connectivity. */ + VERIFYING_POOR_LINK, + /** Checking if network is a captive portal */ + CAPTIVE_PORTAL_CHECK + } + + /** + * This is the map described in the Javadoc comment above. The positions + * of the elements of the array must correspond to the ordinal values + * of DetailedState. + */ + private static final EnumMap stateMap = + new EnumMap(DetailedState.class); + + static { + stateMap.put(DetailedState.IDLE, State.DISCONNECTED); + stateMap.put(DetailedState.SCANNING, State.DISCONNECTED); + stateMap.put(DetailedState.CONNECTING, State.CONNECTING); + stateMap.put(DetailedState.AUTHENTICATING, State.CONNECTING); + stateMap.put(DetailedState.OBTAINING_IPADDR, State.CONNECTING); + stateMap.put(DetailedState.VERIFYING_POOR_LINK, State.CONNECTING); + stateMap.put(DetailedState.CAPTIVE_PORTAL_CHECK, State.CONNECTING); + stateMap.put(DetailedState.CONNECTED, State.CONNECTED); + stateMap.put(DetailedState.SUSPENDED, State.SUSPENDED); + stateMap.put(DetailedState.DISCONNECTING, State.DISCONNECTING); + stateMap.put(DetailedState.DISCONNECTED, State.DISCONNECTED); + stateMap.put(DetailedState.FAILED, State.DISCONNECTED); + stateMap.put(DetailedState.BLOCKED, State.DISCONNECTED); + } + + private int mNetworkType; + private int mSubtype; + private String mTypeName; + private String mSubtypeName; + @NonNull + private State mState; + @NonNull + private DetailedState mDetailedState; + private String mReason; + private String mExtraInfo; + private boolean mIsFailover; + private boolean mIsAvailable; + private boolean mIsRoaming; + + /** + * Create a new instance of NetworkInfo. + * + * This may be useful for apps to write unit tests. + * + * @param type the legacy type of the network, as one of the ConnectivityManager.TYPE_* + * constants. + * @param subtype the subtype if applicable, as one of the TelephonyManager.NETWORK_TYPE_* + * constants. + * @param typeName a human-readable string for the network type, or an empty string or null. + * @param subtypeName a human-readable string for the subtype, or an empty string or null. + */ + public NetworkInfo(int type, @NetworkType int subtype, + @Nullable String typeName, @Nullable String subtypeName) { + if (!ConnectivityManager.isNetworkTypeValid(type) + && type != ConnectivityManager.TYPE_NONE) { + throw new IllegalArgumentException("Invalid network type: " + type); + } + mNetworkType = type; + mSubtype = subtype; + mTypeName = typeName; + mSubtypeName = subtypeName; + setDetailedState(DetailedState.IDLE, null, null); + mState = State.UNKNOWN; + } + + /** {@hide} */ + @UnsupportedAppUsage + public NetworkInfo(NetworkInfo source) { + if (source != null) { + synchronized (source) { + mNetworkType = source.mNetworkType; + mSubtype = source.mSubtype; + mTypeName = source.mTypeName; + mSubtypeName = source.mSubtypeName; + mState = source.mState; + mDetailedState = source.mDetailedState; + mReason = source.mReason; + mExtraInfo = source.mExtraInfo; + mIsFailover = source.mIsFailover; + mIsAvailable = source.mIsAvailable; + mIsRoaming = source.mIsRoaming; + } + } + } + + /** + * Reports the type of network to which the + * info in this {@code NetworkInfo} pertains. + * @return one of {@link ConnectivityManager#TYPE_MOBILE}, {@link + * ConnectivityManager#TYPE_WIFI}, {@link ConnectivityManager#TYPE_WIMAX}, {@link + * ConnectivityManager#TYPE_ETHERNET}, {@link ConnectivityManager#TYPE_BLUETOOTH}, or other + * types defined by {@link ConnectivityManager}. + * @deprecated Callers should switch to checking {@link NetworkCapabilities#hasTransport} + * instead with one of the NetworkCapabilities#TRANSPORT_* constants : + * {@link #getType} and {@link #getTypeName} cannot account for networks using + * multiple transports. Note that generally apps should not care about transport; + * {@link NetworkCapabilities#NET_CAPABILITY_NOT_METERED} and + * {@link NetworkCapabilities#getLinkDownstreamBandwidthKbps} are calls that + * apps concerned with meteredness or bandwidth should be looking at, as they + * offer this information with much better accuracy. + */ + @Deprecated + public int getType() { + synchronized (this) { + return mNetworkType; + } + } + + /** + * @deprecated Use {@link NetworkCapabilities} instead + * @hide + */ + @Deprecated + public void setType(int type) { + synchronized (this) { + mNetworkType = type; + } + } + + /** + * Return a network-type-specific integer describing the subtype + * of the network. + * @return the network subtype + * @deprecated Use {@link android.telephony.TelephonyManager#getDataNetworkType} instead. + */ + @Deprecated + public int getSubtype() { + synchronized (this) { + return mSubtype; + } + } + + /** + * @hide + */ + @UnsupportedAppUsage + public void setSubtype(int subtype, String subtypeName) { + synchronized (this) { + mSubtype = subtype; + mSubtypeName = subtypeName; + } + } + + /** + * Return a human-readable name describe the type of the network, + * for example "WIFI" or "MOBILE". + * @return the name of the network type + * @deprecated Callers should switch to checking {@link NetworkCapabilities#hasTransport} + * instead with one of the NetworkCapabilities#TRANSPORT_* constants : + * {@link #getType} and {@link #getTypeName} cannot account for networks using + * multiple transports. Note that generally apps should not care about transport; + * {@link NetworkCapabilities#NET_CAPABILITY_NOT_METERED} and + * {@link NetworkCapabilities#getLinkDownstreamBandwidthKbps} are calls that + * apps concerned with meteredness or bandwidth should be looking at, as they + * offer this information with much better accuracy. + */ + @Deprecated + public String getTypeName() { + synchronized (this) { + return mTypeName; + } + } + + /** + * Return a human-readable name describing the subtype of the network. + * @return the name of the network subtype + * @deprecated Use {@link android.telephony.TelephonyManager#getDataNetworkType} instead. + */ + @Deprecated + public String getSubtypeName() { + synchronized (this) { + return mSubtypeName; + } + } + + /** + * Indicates whether network connectivity exists or is in the process + * of being established. This is good for applications that need to + * do anything related to the network other than read or write data. + * For the latter, call {@link #isConnected()} instead, which guarantees + * that the network is fully usable. + * @return {@code true} if network connectivity exists or is in the process + * of being established, {@code false} otherwise. + * @deprecated Apps should instead use the + * {@link android.net.ConnectivityManager.NetworkCallback} API to + * learn about connectivity changes. + * {@link ConnectivityManager#registerDefaultNetworkCallback} and + * {@link ConnectivityManager#registerNetworkCallback}. These will + * give a more accurate picture of the connectivity state of + * the device and let apps react more easily and quickly to changes. + */ + @Deprecated + public boolean isConnectedOrConnecting() { + synchronized (this) { + return mState == State.CONNECTED || mState == State.CONNECTING; + } + } + + /** + * Indicates whether network connectivity exists and it is possible to establish + * connections and pass data. + *

Always call this before attempting to perform data transactions. + * @return {@code true} if network connectivity exists, {@code false} otherwise. + * @deprecated Apps should instead use the + * {@link android.net.ConnectivityManager.NetworkCallback} API to + * learn about connectivity changes. See + * {@link ConnectivityManager#registerDefaultNetworkCallback} and + * {@link ConnectivityManager#registerNetworkCallback}. These will + * give a more accurate picture of the connectivity state of + * the device and let apps react more easily and quickly to changes. + */ + @Deprecated + public boolean isConnected() { + synchronized (this) { + return mState == State.CONNECTED; + } + } + + /** + * Indicates whether network connectivity is possible. A network is unavailable + * when a persistent or semi-persistent condition prevents the possibility + * of connecting to that network. Examples include + *

    + *
  • The device is out of the coverage area for any network of this type.
  • + *
  • The device is on a network other than the home network (i.e., roaming), and + * data roaming has been disabled.
  • + *
  • The device's radio is turned off, e.g., because airplane mode is enabled.
  • + *
+ * Since Android L, this always returns {@code true}, because the system only + * returns info for available networks. + * @return {@code true} if the network is available, {@code false} otherwise + * @deprecated Apps should instead use the + * {@link android.net.ConnectivityManager.NetworkCallback} API to + * learn about connectivity changes. + * {@link ConnectivityManager#registerDefaultNetworkCallback} and + * {@link ConnectivityManager#registerNetworkCallback}. These will + * give a more accurate picture of the connectivity state of + * the device and let apps react more easily and quickly to changes. + */ + @Deprecated + public boolean isAvailable() { + synchronized (this) { + return mIsAvailable; + } + } + + /** + * Sets if the network is available, ie, if the connectivity is possible. + * @param isAvailable the new availability value. + * @deprecated Use {@link NetworkCapabilities} instead + * + * @hide + */ + @Deprecated + @UnsupportedAppUsage + public void setIsAvailable(boolean isAvailable) { + synchronized (this) { + mIsAvailable = isAvailable; + } + } + + /** + * Indicates whether the current attempt to connect to the network + * resulted from the ConnectivityManager trying to fail over to this + * network following a disconnect from another network. + * @return {@code true} if this is a failover attempt, {@code false} + * otherwise. + * @deprecated This field is not populated in recent Android releases, + * and does not make a lot of sense in a multi-network world. + */ + @Deprecated + public boolean isFailover() { + synchronized (this) { + return mIsFailover; + } + } + + /** + * Set the failover boolean. + * @param isFailover {@code true} to mark the current connection attempt + * as a failover. + * @deprecated This hasn't been set in any recent Android release. + * @hide + */ + @Deprecated + @UnsupportedAppUsage + public void setFailover(boolean isFailover) { + synchronized (this) { + mIsFailover = isFailover; + } + } + + /** + * Indicates whether the device is currently roaming on this network. When + * {@code true}, it suggests that use of data on this network may incur + * extra costs. + * + * @return {@code true} if roaming is in effect, {@code false} otherwise. + * @deprecated Callers should switch to checking + * {@link NetworkCapabilities#NET_CAPABILITY_NOT_ROAMING} + * instead, since that handles more complex situations, such as + * VPNs. + */ + @Deprecated + public boolean isRoaming() { + synchronized (this) { + return mIsRoaming; + } + } + + /** + * @deprecated Use {@link NetworkCapabilities#NET_CAPABILITY_NOT_ROAMING} instead. + * {@hide} + */ + @VisibleForTesting + @Deprecated + @UnsupportedAppUsage + public void setRoaming(boolean isRoaming) { + synchronized (this) { + mIsRoaming = isRoaming; + } + } + + /** + * Reports the current coarse-grained state of the network. + * @return the coarse-grained state + * @deprecated Apps should instead use the + * {@link android.net.ConnectivityManager.NetworkCallback} API to + * learn about connectivity changes. + * {@link ConnectivityManager#registerDefaultNetworkCallback} and + * {@link ConnectivityManager#registerNetworkCallback}. These will + * give a more accurate picture of the connectivity state of + * the device and let apps react more easily and quickly to changes. + */ + @Deprecated + public State getState() { + synchronized (this) { + return mState; + } + } + + /** + * Reports the current fine-grained state of the network. + * @return the fine-grained state + * @deprecated Apps should instead use the + * {@link android.net.ConnectivityManager.NetworkCallback} API to + * learn about connectivity changes. See + * {@link ConnectivityManager#registerDefaultNetworkCallback} and + * {@link ConnectivityManager#registerNetworkCallback}. These will + * give a more accurate picture of the connectivity state of + * the device and let apps react more easily and quickly to changes. + */ + @Deprecated + public @NonNull DetailedState getDetailedState() { + synchronized (this) { + return mDetailedState; + } + } + + /** + * Sets the fine-grained state of the network. + * + * This is only useful for testing. + * + * @param detailedState the {@link DetailedState}. + * @param reason a {@code String} indicating the reason for the state change, + * if one was supplied. May be {@code null}. + * @param extraInfo an optional {@code String} providing addditional network state + * information passed up from the lower networking layers. + * @deprecated Use {@link NetworkCapabilities} instead. + */ + @Deprecated + public void setDetailedState(@NonNull DetailedState detailedState, @Nullable String reason, + @Nullable String extraInfo) { + synchronized (this) { + this.mDetailedState = detailedState; + this.mState = stateMap.get(detailedState); + this.mReason = reason; + this.mExtraInfo = extraInfo; + } + } + + /** + * Set the extraInfo field. + * @param extraInfo an optional {@code String} providing addditional network state + * information passed up from the lower networking layers. + * @deprecated See {@link NetworkInfo#getExtraInfo}. + * @hide + */ + @Deprecated + public void setExtraInfo(String extraInfo) { + synchronized (this) { + this.mExtraInfo = extraInfo; + } + } + + /** + * Report the reason an attempt to establish connectivity failed, + * if one is available. + * @return the reason for failure, or null if not available + * @deprecated This method does not have a consistent contract that could make it useful + * to callers. + */ + public String getReason() { + synchronized (this) { + return mReason; + } + } + + /** + * Report the extra information about the network state, if any was + * provided by the lower networking layers. + * @return the extra information, or null if not available + * @deprecated Use other services e.g. WifiManager to get additional information passed up from + * the lower networking layers. + */ + @Deprecated + public String getExtraInfo() { + synchronized (this) { + return mExtraInfo; + } + } + + @Override + public String toString() { + synchronized (this) { + final StringBuilder builder = new StringBuilder("["); + builder.append("type: ").append(getTypeName()).append("[").append(getSubtypeName()). + append("], state: ").append(mState).append("/").append(mDetailedState). + append(", reason: ").append(mReason == null ? "(unspecified)" : mReason). + append(", extra: ").append(mExtraInfo == null ? "(none)" : mExtraInfo). + append(", failover: ").append(mIsFailover). + append(", available: ").append(mIsAvailable). + append(", roaming: ").append(mIsRoaming). + append("]"); + return builder.toString(); + } + } + + /** + * Returns a brief summary string suitable for debugging. + * @hide + */ + public String toShortString() { + synchronized (this) { + final StringBuilder builder = new StringBuilder(); + builder.append(getTypeName()); + + final String subtype = getSubtypeName(); + if (!TextUtils.isEmpty(subtype)) { + builder.append("[").append(subtype).append("]"); + } + + builder.append(" "); + builder.append(mDetailedState); + if (mIsRoaming) { + builder.append(" ROAMING"); + } + if (mExtraInfo != null) { + builder.append(" extra: ").append(mExtraInfo); + } + return builder.toString(); + } + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + synchronized (this) { + dest.writeInt(mNetworkType); + dest.writeInt(mSubtype); + dest.writeString(mTypeName); + dest.writeString(mSubtypeName); + dest.writeString(mState.name()); + dest.writeString(mDetailedState.name()); + dest.writeInt(mIsFailover ? 1 : 0); + dest.writeInt(mIsAvailable ? 1 : 0); + dest.writeInt(mIsRoaming ? 1 : 0); + dest.writeString(mReason); + dest.writeString(mExtraInfo); + } + } + + public static final @android.annotation.NonNull Creator CREATOR = new Creator() { + @Override + public NetworkInfo createFromParcel(Parcel in) { + int netType = in.readInt(); + int subtype = in.readInt(); + String typeName = in.readString(); + String subtypeName = in.readString(); + NetworkInfo netInfo = new NetworkInfo(netType, subtype, typeName, subtypeName); + netInfo.mState = State.valueOf(in.readString()); + netInfo.mDetailedState = DetailedState.valueOf(in.readString()); + netInfo.mIsFailover = in.readInt() != 0; + netInfo.mIsAvailable = in.readInt() != 0; + netInfo.mIsRoaming = in.readInt() != 0; + netInfo.mReason = in.readString(); + netInfo.mExtraInfo = in.readString(); + return netInfo; + } + + @Override + public NetworkInfo[] newArray(int size) { + return new NetworkInfo[size]; + } + }; +} diff --git a/packages/Connectivity/framework/src/android/net/NetworkProvider.java b/packages/Connectivity/framework/src/android/net/NetworkProvider.java new file mode 100644 index 000000000000..14cb51c85d06 --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/NetworkProvider.java @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.annotation.IntRange; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.RequiresPermission; +import android.annotation.SystemApi; +import android.content.Context; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.os.Messenger; +import android.util.Log; + +/** + * Base class for network providers such as telephony or Wi-Fi. NetworkProviders connect the device + * to networks and makes them available to the core network stack by creating + * {@link NetworkAgent}s. The networks can then provide connectivity to apps and can be interacted + * with via networking APIs such as {@link ConnectivityManager}. + * + * Subclasses should implement {@link #onNetworkRequested} and {@link #onNetworkRequestWithdrawn} + * to receive {@link NetworkRequest}s sent by the system and by apps. A network that is not the + * best (highest-scoring) network for any request is generally not used by the system, and torn + * down. + * + * @hide + */ +@SystemApi +public class NetworkProvider { + /** + * {@code providerId} value that indicates the absence of a provider. It is the providerId of + * any NetworkProvider that is not currently registered, and of any NetworkRequest that is not + * currently being satisfied by a network. + */ + public static final int ID_NONE = -1; + + /** + * The first providerId value that will be allocated. + * @hide only used by ConnectivityService. + */ + public static final int FIRST_PROVIDER_ID = 1; + + /** @hide only used by ConnectivityService */ + public static final int CMD_REQUEST_NETWORK = 1; + /** @hide only used by ConnectivityService */ + public static final int CMD_CANCEL_REQUEST = 2; + + private final Messenger mMessenger; + private final String mName; + private final Context mContext; + + private int mProviderId = ID_NONE; + + /** + * Constructs a new NetworkProvider. + * + * @param looper the Looper on which to run {@link #onNetworkRequested} and + * {@link #onNetworkRequestWithdrawn}. + * @param name the name of the listener, used only for debugging. + * + * @hide + */ + @SystemApi + public NetworkProvider(@NonNull Context context, @NonNull Looper looper, @NonNull String name) { + Handler handler = new Handler(looper) { + @Override + public void handleMessage(Message m) { + switch (m.what) { + case CMD_REQUEST_NETWORK: + onNetworkRequested((NetworkRequest) m.obj, m.arg1, m.arg2); + break; + case CMD_CANCEL_REQUEST: + onNetworkRequestWithdrawn((NetworkRequest) m.obj); + break; + default: + Log.e(mName, "Unhandled message: " + m.what); + } + } + }; + mContext = context; + mMessenger = new Messenger(handler); + mName = name; + } + + // TODO: consider adding a register() method so ConnectivityManager does not need to call this. + /** @hide */ + public @Nullable Messenger getMessenger() { + return mMessenger; + } + + /** @hide */ + public @NonNull String getName() { + return mName; + } + + /** + * Returns the ID of this provider. This is known only once the provider is registered via + * {@link ConnectivityManager#registerNetworkProvider()}, otherwise the ID is {@link #ID_NONE}. + * This ID must be used when registering any {@link NetworkAgent}s. + */ + public int getProviderId() { + return mProviderId; + } + + /** @hide */ + public void setProviderId(int providerId) { + mProviderId = providerId; + } + + /** + * Called when a NetworkRequest is received. The request may be a new request or an existing + * request with a different score. + * + * @param request the NetworkRequest being received + * @param score the score of the network currently satisfying the request, or 0 if none. + * @param providerId the ID of the provider that created the network currently satisfying this + * request, or {@link #ID_NONE} if none. + * + * @hide + */ + @SystemApi + public void onNetworkRequested(@NonNull NetworkRequest request, + @IntRange(from = 0, to = 99) int score, int providerId) {} + + /** + * Called when a NetworkRequest is withdrawn. + * @hide + */ + @SystemApi + public void onNetworkRequestWithdrawn(@NonNull NetworkRequest request) {} + + /** + * Asserts that no provider will ever be able to satisfy the specified request. The provider + * must only call this method if it knows that it is the only provider on the system capable of + * satisfying this request, and that the request cannot be satisfied. The application filing the + * request will receive an {@link NetworkCallback#onUnavailable()} callback. + * + * @param request the request that permanently cannot be fulfilled + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) + public void declareNetworkRequestUnfulfillable(@NonNull NetworkRequest request) { + ConnectivityManager.from(mContext).declareNetworkRequestUnfulfillable(request); + } +} diff --git a/packages/Connectivity/framework/src/android/net/NetworkRequest.aidl b/packages/Connectivity/framework/src/android/net/NetworkRequest.aidl new file mode 100644 index 000000000000..508defc6b497 --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/NetworkRequest.aidl @@ -0,0 +1,20 @@ +/** + * Copyright (c) 2014, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +parcelable NetworkRequest; + diff --git a/packages/Connectivity/framework/src/android/net/NetworkRequest.java b/packages/Connectivity/framework/src/android/net/NetworkRequest.java new file mode 100644 index 000000000000..04011fc6816e --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/NetworkRequest.java @@ -0,0 +1,582 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.RequiresPermission; +import android.annotation.SystemApi; +import android.compat.annotation.UnsupportedAppUsage; +import android.net.NetworkCapabilities.NetCapability; +import android.net.NetworkCapabilities.Transport; +import android.os.Build; +import android.os.Parcel; +import android.os.Parcelable; +import android.os.Process; +import android.text.TextUtils; +import android.util.proto.ProtoOutputStream; + +import java.util.Objects; +import java.util.Set; + +/** + * Defines a request for a network, made through {@link NetworkRequest.Builder} and used + * to request a network via {@link ConnectivityManager#requestNetwork} or listen for changes + * via {@link ConnectivityManager#registerNetworkCallback}. + */ +public class NetworkRequest implements Parcelable { + /** + * The first requestId value that will be allocated. + * @hide only used by ConnectivityService. + */ + public static final int FIRST_REQUEST_ID = 1; + + /** + * The requestId value that represents the absence of a request. + * @hide only used by ConnectivityService. + */ + public static final int REQUEST_ID_NONE = -1; + + /** + * The {@link NetworkCapabilities} that define this request. + * @hide + */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + public final @NonNull NetworkCapabilities networkCapabilities; + + /** + * Identifies the request. NetworkRequests should only be constructed by + * the Framework and given out to applications as tokens to be used to identify + * the request. + * @hide + */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + public final int requestId; + + /** + * Set for legacy requests and the default. Set to TYPE_NONE for none. + * Causes CONNECTIVITY_ACTION broadcasts to be sent. + * @hide + */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) + public final int legacyType; + + /** + * A NetworkRequest as used by the system can be one of the following types: + * + * - LISTEN, for which the framework will issue callbacks about any + * and all networks that match the specified NetworkCapabilities, + * + * - REQUEST, capable of causing a specific network to be created + * first (e.g. a telephony DUN request), the framework will issue + * callbacks about the single, highest scoring current network + * (if any) that matches the specified NetworkCapabilities, or + * + * - TRACK_DEFAULT, a hybrid of the two designed such that the + * framework will issue callbacks for the single, highest scoring + * current network (if any) that matches the capabilities of the + * default Internet request (mDefaultRequest), but which cannot cause + * the framework to either create or retain the existence of any + * specific network. Note that from the point of view of the request + * matching code, TRACK_DEFAULT is identical to REQUEST: its special + * behaviour is not due to different semantics, but to the fact that + * the system will only ever create a TRACK_DEFAULT with capabilities + * that are identical to the default request's capabilities, thus + * causing it to share fate in every way with the default request. + * + * - BACKGROUND_REQUEST, like REQUEST but does not cause any networks + * to retain the NET_CAPABILITY_FOREGROUND capability. A network with + * no foreground requests is in the background. A network that has + * one or more background requests and loses its last foreground + * request to a higher-scoring network will not go into the + * background immediately, but will linger and go into the background + * after the linger timeout. + * + * - The value NONE is used only by applications. When an application + * creates a NetworkRequest, it does not have a type; the type is set + * by the system depending on the method used to file the request + * (requestNetwork, registerNetworkCallback, etc.). + * + * @hide + */ + public static enum Type { + NONE, + LISTEN, + TRACK_DEFAULT, + REQUEST, + BACKGROUND_REQUEST, + }; + + /** + * The type of the request. This is only used by the system and is always NONE elsewhere. + * + * @hide + */ + public final Type type; + + /** + * @hide + */ + public NetworkRequest(NetworkCapabilities nc, int legacyType, int rId, Type type) { + if (nc == null) { + throw new NullPointerException(); + } + requestId = rId; + networkCapabilities = nc; + this.legacyType = legacyType; + this.type = type; + } + + /** + * @hide + */ + public NetworkRequest(NetworkRequest that) { + networkCapabilities = new NetworkCapabilities(that.networkCapabilities); + requestId = that.requestId; + this.legacyType = that.legacyType; + this.type = that.type; + } + + /** + * Builder used to create {@link NetworkRequest} objects. Specify the Network features + * needed in terms of {@link NetworkCapabilities} features + */ + public static class Builder { + private final NetworkCapabilities mNetworkCapabilities; + + /** + * Default constructor for Builder. + */ + public Builder() { + // By default, restrict this request to networks available to this app. + // Apps can rescind this restriction, but ConnectivityService will enforce + // it for apps that do not have the NETWORK_SETTINGS permission. + mNetworkCapabilities = new NetworkCapabilities(); + mNetworkCapabilities.setSingleUid(Process.myUid()); + } + + /** + * Build {@link NetworkRequest} give the current set of capabilities. + */ + public NetworkRequest build() { + // Make a copy of mNetworkCapabilities so we don't inadvertently remove NOT_RESTRICTED + // when later an unrestricted capability could be added to mNetworkCapabilities, in + // which case NOT_RESTRICTED should be returned to mNetworkCapabilities, which + // maybeMarkCapabilitiesRestricted() doesn't add back. + final NetworkCapabilities nc = new NetworkCapabilities(mNetworkCapabilities); + nc.maybeMarkCapabilitiesRestricted(); + return new NetworkRequest(nc, ConnectivityManager.TYPE_NONE, + ConnectivityManager.REQUEST_ID_UNSET, Type.NONE); + } + + /** + * Add the given capability requirement to this builder. These represent + * the requested network's required capabilities. Note that when searching + * for a network to satisfy a request, all capabilities requested must be + * satisfied. + * + * @param capability The capability to add. + * @return The builder to facilitate chaining + * {@code builder.addCapability(...).addCapability();}. + */ + public Builder addCapability(@NetworkCapabilities.NetCapability int capability) { + mNetworkCapabilities.addCapability(capability); + return this; + } + + /** + * Removes (if found) the given capability from this builder instance. + * + * @param capability The capability to remove. + * @return The builder to facilitate chaining. + */ + public Builder removeCapability(@NetworkCapabilities.NetCapability int capability) { + mNetworkCapabilities.removeCapability(capability); + return this; + } + + /** + * Set the {@code NetworkCapabilities} for this builder instance, + * overriding any capabilities that had been previously set. + * + * @param nc The superseding {@code NetworkCapabilities} instance. + * @return The builder to facilitate chaining. + * @hide + */ + public Builder setCapabilities(NetworkCapabilities nc) { + mNetworkCapabilities.set(nc); + return this; + } + + /** + * Set the watched UIDs for this request. This will be reset and wiped out unless + * the calling app holds the CHANGE_NETWORK_STATE permission. + * + * @param uids The watched UIDs as a set of UidRanges, or null for everything. + * @return The builder to facilitate chaining. + * @hide + */ + public Builder setUids(Set uids) { + mNetworkCapabilities.setUids(uids); + return this; + } + + /** + * Add a capability that must not exist in the requested network. + *

+ * If the capability was previously added to the list of required capabilities (for + * example, it was there by default or added using {@link #addCapability(int)} method), then + * it will be removed from the list of required capabilities as well. + * + * @see #addCapability(int) + * + * @param capability The capability to add to unwanted capability list. + * @return The builder to facilitate chaining. + * + * @hide + */ + public Builder addUnwantedCapability(@NetworkCapabilities.NetCapability int capability) { + mNetworkCapabilities.addUnwantedCapability(capability); + return this; + } + + /** + * Completely clears all the {@code NetworkCapabilities} from this builder instance, + * removing even the capabilities that are set by default when the object is constructed. + * + * @return The builder to facilitate chaining. + */ + @NonNull + public Builder clearCapabilities() { + mNetworkCapabilities.clearAll(); + return this; + } + + /** + * Adds the given transport requirement to this builder. These represent + * the set of allowed transports for the request. Only networks using one + * of these transports will satisfy the request. If no particular transports + * are required, none should be specified here. + * + * @param transportType The transport type to add. + * @return The builder to facilitate chaining. + */ + public Builder addTransportType(@NetworkCapabilities.Transport int transportType) { + mNetworkCapabilities.addTransportType(transportType); + return this; + } + + /** + * Removes (if found) the given transport from this builder instance. + * + * @param transportType The transport type to remove. + * @return The builder to facilitate chaining. + */ + public Builder removeTransportType(@NetworkCapabilities.Transport int transportType) { + mNetworkCapabilities.removeTransportType(transportType); + return this; + } + + /** + * @hide + */ + public Builder setLinkUpstreamBandwidthKbps(int upKbps) { + mNetworkCapabilities.setLinkUpstreamBandwidthKbps(upKbps); + return this; + } + /** + * @hide + */ + public Builder setLinkDownstreamBandwidthKbps(int downKbps) { + mNetworkCapabilities.setLinkDownstreamBandwidthKbps(downKbps); + return this; + } + + /** + * Sets the optional bearer specific network specifier. + * This has no meaning if a single transport is also not specified, so calling + * this without a single transport set will generate an exception, as will + * subsequently adding or removing transports after this is set. + *

+ * If the {@code networkSpecifier} is provided, it shall be interpreted as follows: + *
    + *
  • If the specifier can be parsed as an integer, it will be treated as a + * {@link android.net TelephonyNetworkSpecifier}, and the provided integer will be + * interpreted as a SubscriptionId. + *
  • If the value is an ethernet interface name, it will be treated as such. + *
  • For all other cases, the behavior is undefined. + *
+ * + * @param networkSpecifier A {@code String} of either a SubscriptionId in cellular + * network request or an ethernet interface name in ethernet + * network request. + * + * @deprecated Use {@link #setNetworkSpecifier(NetworkSpecifier)} instead. + */ + @Deprecated + public Builder setNetworkSpecifier(String networkSpecifier) { + try { + int subId = Integer.parseInt(networkSpecifier); + return setNetworkSpecifier(new TelephonyNetworkSpecifier.Builder() + .setSubscriptionId(subId).build()); + } catch (NumberFormatException nfe) { + // A StringNetworkSpecifier does not accept null or empty ("") strings. When network + // specifiers were strings a null string and an empty string were considered + // equivalent. Hence no meaning is attached to a null or empty ("") string. + return setNetworkSpecifier(TextUtils.isEmpty(networkSpecifier) ? null + : new StringNetworkSpecifier(networkSpecifier)); + } + } + + /** + * Sets the optional bearer specific network specifier. + * This has no meaning if a single transport is also not specified, so calling + * this without a single transport set will generate an exception, as will + * subsequently adding or removing transports after this is set. + *

+ * + * @param networkSpecifier A concrete, parcelable framework class that extends + * NetworkSpecifier. + */ + public Builder setNetworkSpecifier(NetworkSpecifier networkSpecifier) { + if (networkSpecifier instanceof MatchAllNetworkSpecifier) { + throw new IllegalArgumentException("A MatchAllNetworkSpecifier is not permitted"); + } + mNetworkCapabilities.setNetworkSpecifier(networkSpecifier); + return this; + } + + /** + * Sets the signal strength. This is a signed integer, with higher values indicating a + * stronger signal. The exact units are bearer-dependent. For example, Wi-Fi uses the same + * RSSI units reported by WifiManager. + *

+ * Note that when used to register a network callback, this specifies the minimum acceptable + * signal strength. When received as the state of an existing network it specifies the + * current value. A value of {@code SIGNAL_STRENGTH_UNSPECIFIED} means no value when + * received and has no effect when requesting a callback. + * + *

This method requires the caller to hold the + * {@link android.Manifest.permission#NETWORK_SIGNAL_STRENGTH_WAKEUP} permission + * + * @param signalStrength the bearer-specific signal strength. + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP) + public @NonNull Builder setSignalStrength(int signalStrength) { + mNetworkCapabilities.setSignalStrength(signalStrength); + return this; + } + } + + // implement the Parcelable interface + public int describeContents() { + return 0; + } + public void writeToParcel(Parcel dest, int flags) { + networkCapabilities.writeToParcel(dest, flags); + dest.writeInt(legacyType); + dest.writeInt(requestId); + dest.writeString(type.name()); + } + + public static final @android.annotation.NonNull Creator CREATOR = + new Creator() { + public NetworkRequest createFromParcel(Parcel in) { + NetworkCapabilities nc = NetworkCapabilities.CREATOR.createFromParcel(in); + int legacyType = in.readInt(); + int requestId = in.readInt(); + Type type = Type.valueOf(in.readString()); // IllegalArgumentException if invalid. + NetworkRequest result = new NetworkRequest(nc, legacyType, requestId, type); + return result; + } + public NetworkRequest[] newArray(int size) { + return new NetworkRequest[size]; + } + }; + + /** + * Returns true iff. this NetworkRequest is of type LISTEN. + * + * @hide + */ + public boolean isListen() { + return type == Type.LISTEN; + } + + /** + * Returns true iff. the contained NetworkRequest is one that: + * + * - should be associated with at most one satisfying network + * at a time; + * + * - should cause a network to be kept up, but not necessarily in + * the foreground, if it is the best network which can satisfy the + * NetworkRequest. + * + * For full detail of how isRequest() is used for pairing Networks with + * NetworkRequests read rematchNetworkAndRequests(). + * + * @hide + */ + public boolean isRequest() { + return isForegroundRequest() || isBackgroundRequest(); + } + + /** + * Returns true iff. the contained NetworkRequest is one that: + * + * - should be associated with at most one satisfying network + * at a time; + * + * - should cause a network to be kept up and in the foreground if + * it is the best network which can satisfy the NetworkRequest. + * + * For full detail of how isRequest() is used for pairing Networks with + * NetworkRequests read rematchNetworkAndRequests(). + * + * @hide + */ + public boolean isForegroundRequest() { + return type == Type.TRACK_DEFAULT || type == Type.REQUEST; + } + + /** + * Returns true iff. this NetworkRequest is of type BACKGROUND_REQUEST. + * + * @hide + */ + public boolean isBackgroundRequest() { + return type == Type.BACKGROUND_REQUEST; + } + + /** + * @see Builder#addCapability(int) + */ + public boolean hasCapability(@NetCapability int capability) { + return networkCapabilities.hasCapability(capability); + } + + /** + * @see Builder#addUnwantedCapability(int) + * + * @hide + */ + public boolean hasUnwantedCapability(@NetCapability int capability) { + return networkCapabilities.hasUnwantedCapability(capability); + } + + /** + * Returns true if and only if the capabilities requested in this NetworkRequest are satisfied + * by the provided {@link NetworkCapabilities}. + * + * @param nc Capabilities that should satisfy this NetworkRequest. null capabilities do not + * satisfy any request. + */ + public boolean canBeSatisfiedBy(@Nullable NetworkCapabilities nc) { + return networkCapabilities.satisfiedByNetworkCapabilities(nc); + } + + /** + * @see Builder#addTransportType(int) + */ + public boolean hasTransport(@Transport int transportType) { + return networkCapabilities.hasTransport(transportType); + } + + /** + * @see Builder#setNetworkSpecifier(NetworkSpecifier) + */ + @Nullable + public NetworkSpecifier getNetworkSpecifier() { + return networkCapabilities.getNetworkSpecifier(); + } + + /** + * @return the uid of the app making the request. + * + * Note: This could return {@link Process#INVALID_UID} if the {@link NetworkRequest} object was + * not obtained from {@link ConnectivityManager}. + * @hide + */ + @SystemApi + public int getRequestorUid() { + return networkCapabilities.getRequestorUid(); + } + + /** + * @return the package name of the app making the request. + * + * Note: This could return {@code null} if the {@link NetworkRequest} object was not obtained + * from {@link ConnectivityManager}. + * @hide + */ + @SystemApi + @Nullable + public String getRequestorPackageName() { + return networkCapabilities.getRequestorPackageName(); + } + + public String toString() { + return "NetworkRequest [ " + type + " id=" + requestId + + (legacyType != ConnectivityManager.TYPE_NONE ? ", legacyType=" + legacyType : "") + + ", " + networkCapabilities.toString() + " ]"; + } + + private int typeToProtoEnum(Type t) { + switch (t) { + case NONE: + return NetworkRequestProto.TYPE_NONE; + case LISTEN: + return NetworkRequestProto.TYPE_LISTEN; + case TRACK_DEFAULT: + return NetworkRequestProto.TYPE_TRACK_DEFAULT; + case REQUEST: + return NetworkRequestProto.TYPE_REQUEST; + case BACKGROUND_REQUEST: + return NetworkRequestProto.TYPE_BACKGROUND_REQUEST; + default: + return NetworkRequestProto.TYPE_UNKNOWN; + } + } + + /** @hide */ + public void dumpDebug(ProtoOutputStream proto, long fieldId) { + final long token = proto.start(fieldId); + + proto.write(NetworkRequestProto.TYPE, typeToProtoEnum(type)); + proto.write(NetworkRequestProto.REQUEST_ID, requestId); + proto.write(NetworkRequestProto.LEGACY_TYPE, legacyType); + networkCapabilities.dumpDebug(proto, NetworkRequestProto.NETWORK_CAPABILITIES); + + proto.end(token); + } + + public boolean equals(Object obj) { + if (obj instanceof NetworkRequest == false) return false; + NetworkRequest that = (NetworkRequest)obj; + return (that.legacyType == this.legacyType && + that.requestId == this.requestId && + that.type == this.type && + Objects.equals(that.networkCapabilities, this.networkCapabilities)); + } + + public int hashCode() { + return Objects.hash(requestId, legacyType, networkCapabilities, type); + } +} diff --git a/packages/Connectivity/framework/src/android/net/NetworkUtils.java b/packages/Connectivity/framework/src/android/net/NetworkUtils.java new file mode 100644 index 000000000000..8be4af7b1396 --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/NetworkUtils.java @@ -0,0 +1,425 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.compat.annotation.UnsupportedAppUsage; +import android.os.Build; +import android.system.ErrnoException; +import android.util.Log; +import android.util.Pair; + +import com.android.net.module.util.Inet4AddressUtils; + +import java.io.FileDescriptor; +import java.math.BigInteger; +import java.net.Inet4Address; +import java.net.InetAddress; +import java.net.SocketException; +import java.net.UnknownHostException; +import java.util.Locale; +import java.util.TreeSet; + +/** + * Native methods for managing network interfaces. + * + * {@hide} + */ +public class NetworkUtils { + + private static final String TAG = "NetworkUtils"; + + /** + * Attaches a socket filter that drops all of incoming packets. + * @param fd the socket's {@link FileDescriptor}. + */ + public static native void attachDropAllBPFFilter(FileDescriptor fd) throws SocketException; + + /** + * Detaches a socket filter. + * @param fd the socket's {@link FileDescriptor}. + */ + public static native void detachBPFFilter(FileDescriptor fd) throws SocketException; + + /** + * Binds the current process to the network designated by {@code netId}. All sockets created + * in the future (and not explicitly bound via a bound {@link SocketFactory} (see + * {@link Network#getSocketFactory}) will be bound to this network. Note that if this + * {@code Network} ever disconnects all sockets created in this way will cease to work. This + * is by design so an application doesn't accidentally use sockets it thinks are still bound to + * a particular {@code Network}. Passing NETID_UNSET clears the binding. + */ + public native static boolean bindProcessToNetwork(int netId); + + /** + * Return the netId last passed to {@link #bindProcessToNetwork}, or NETID_UNSET if + * {@link #unbindProcessToNetwork} has been called since {@link #bindProcessToNetwork}. + */ + public native static int getBoundNetworkForProcess(); + + /** + * Binds host resolutions performed by this process to the network designated by {@code netId}. + * {@link #bindProcessToNetwork} takes precedence over this setting. Passing NETID_UNSET clears + * the binding. + * + * @deprecated This is strictly for legacy usage to support startUsingNetworkFeature(). + */ + @Deprecated + public native static boolean bindProcessToNetworkForHostResolution(int netId); + + /** + * Explicitly binds {@code fd} to the network designated by {@code netId}. This + * overrides any binding via {@link #bindProcessToNetwork}. + * @return 0 on success or negative errno on failure. + */ + public static native int bindSocketToNetwork(FileDescriptor fd, int netId); + + /** + * Protect {@code fd} from VPN connections. After protecting, data sent through + * this socket will go directly to the underlying network, so its traffic will not be + * forwarded through the VPN. + */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + public static native boolean protectFromVpn(FileDescriptor fd); + + /** + * Protect {@code socketfd} from VPN connections. After protecting, data sent through + * this socket will go directly to the underlying network, so its traffic will not be + * forwarded through the VPN. + */ + public native static boolean protectFromVpn(int socketfd); + + /** + * Determine if {@code uid} can access network designated by {@code netId}. + * @return {@code true} if {@code uid} can access network, {@code false} otherwise. + */ + public native static boolean queryUserAccess(int uid, int netId); + + /** + * DNS resolver series jni method. + * Issue the query {@code msg} on the network designated by {@code netId}. + * {@code flags} is an additional config to control actual querying behavior. + * @return a file descriptor to watch for read events + */ + public static native FileDescriptor resNetworkSend( + int netId, byte[] msg, int msglen, int flags) throws ErrnoException; + + /** + * DNS resolver series jni method. + * Look up the {@code nsClass} {@code nsType} Resource Record (RR) associated + * with Domain Name {@code dname} on the network designated by {@code netId}. + * {@code flags} is an additional config to control actual querying behavior. + * @return a file descriptor to watch for read events + */ + public static native FileDescriptor resNetworkQuery( + int netId, String dname, int nsClass, int nsType, int flags) throws ErrnoException; + + /** + * DNS resolver series jni method. + * Read a result for the query associated with the {@code fd}. + * @return DnsResponse containing blob answer and rcode + */ + public static native DnsResolver.DnsResponse resNetworkResult(FileDescriptor fd) + throws ErrnoException; + + /** + * DNS resolver series jni method. + * Attempts to cancel the in-progress query associated with the {@code fd}. + */ + public static native void resNetworkCancel(FileDescriptor fd); + + /** + * DNS resolver series jni method. + * Attempts to get network which resolver will use if no network is explicitly selected. + */ + public static native Network getDnsNetwork() throws ErrnoException; + + /** + * Get the tcp repair window associated with the {@code fd}. + * + * @param fd the tcp socket's {@link FileDescriptor}. + * @return a {@link TcpRepairWindow} object indicates tcp window size. + */ + public static native TcpRepairWindow getTcpRepairWindow(FileDescriptor fd) + throws ErrnoException; + + /** + * @see Inet4AddressUtils#intToInet4AddressHTL(int) + * @deprecated Use either {@link Inet4AddressUtils#intToInet4AddressHTH(int)} + * or {@link Inet4AddressUtils#intToInet4AddressHTL(int)} + */ + @Deprecated + @UnsupportedAppUsage + public static InetAddress intToInetAddress(int hostAddress) { + return Inet4AddressUtils.intToInet4AddressHTL(hostAddress); + } + + /** + * @see Inet4AddressUtils#inet4AddressToIntHTL(Inet4Address) + * @deprecated Use either {@link Inet4AddressUtils#inet4AddressToIntHTH(Inet4Address)} + * or {@link Inet4AddressUtils#inet4AddressToIntHTL(Inet4Address)} + */ + @Deprecated + public static int inetAddressToInt(Inet4Address inetAddr) + throws IllegalArgumentException { + return Inet4AddressUtils.inet4AddressToIntHTL(inetAddr); + } + + /** + * @see Inet4AddressUtils#prefixLengthToV4NetmaskIntHTL(int) + * @deprecated Use either {@link Inet4AddressUtils#prefixLengthToV4NetmaskIntHTH(int)} + * or {@link Inet4AddressUtils#prefixLengthToV4NetmaskIntHTL(int)} + */ + @Deprecated + @UnsupportedAppUsage + public static int prefixLengthToNetmaskInt(int prefixLength) + throws IllegalArgumentException { + return Inet4AddressUtils.prefixLengthToV4NetmaskIntHTL(prefixLength); + } + + /** + * Convert a IPv4 netmask integer to a prefix length + * @param netmask as an integer (0xff000000 for a /8 subnet) + * @return the network prefix length + */ + public static int netmaskIntToPrefixLength(int netmask) { + return Integer.bitCount(netmask); + } + + /** + * Convert an IPv4 netmask to a prefix length, checking that the netmask is contiguous. + * @param netmask as a {@code Inet4Address}. + * @return the network prefix length + * @throws IllegalArgumentException the specified netmask was not contiguous. + * @hide + * @deprecated use {@link Inet4AddressUtils#netmaskToPrefixLength(Inet4Address)} + */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @Deprecated + public static int netmaskToPrefixLength(Inet4Address netmask) { + // This is only here because some apps seem to be using it (@UnsupportedAppUsage). + return Inet4AddressUtils.netmaskToPrefixLength(netmask); + } + + + /** + * Create an InetAddress from a string where the string must be a standard + * representation of a V4 or V6 address. Avoids doing a DNS lookup on failure + * but it will throw an IllegalArgumentException in that case. + * @param addrString + * @return the InetAddress + * @hide + * @deprecated Use {@link InetAddresses#parseNumericAddress(String)}, if possible. + */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) + @Deprecated + public static InetAddress numericToInetAddress(String addrString) + throws IllegalArgumentException { + return InetAddress.parseNumericAddress(addrString); + } + + /** + * Masks a raw IP address byte array with the specified prefix length. + */ + public static void maskRawAddress(byte[] array, int prefixLength) { + if (prefixLength < 0 || prefixLength > array.length * 8) { + throw new RuntimeException("IP address with " + array.length + + " bytes has invalid prefix length " + prefixLength); + } + + int offset = prefixLength / 8; + int remainder = prefixLength % 8; + byte mask = (byte)(0xFF << (8 - remainder)); + + if (offset < array.length) array[offset] = (byte)(array[offset] & mask); + + offset++; + + for (; offset < array.length; offset++) { + array[offset] = 0; + } + } + + /** + * Get InetAddress masked with prefixLength. Will never return null. + * @param address the IP address to mask with + * @param prefixLength the prefixLength used to mask the IP + */ + public static InetAddress getNetworkPart(InetAddress address, int prefixLength) { + byte[] array = address.getAddress(); + maskRawAddress(array, prefixLength); + + InetAddress netPart = null; + try { + netPart = InetAddress.getByAddress(array); + } catch (UnknownHostException e) { + throw new RuntimeException("getNetworkPart error - " + e.toString()); + } + return netPart; + } + + /** + * Returns the implicit netmask of an IPv4 address, as was the custom before 1993. + */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + public static int getImplicitNetmask(Inet4Address address) { + // Only here because it seems to be used by apps + return Inet4AddressUtils.getImplicitNetmask(address); + } + + /** + * Utility method to parse strings such as "192.0.2.5/24" or "2001:db8::cafe:d00d/64". + * @hide + */ + public static Pair parseIpAndMask(String ipAndMaskString) { + InetAddress address = null; + int prefixLength = -1; + try { + String[] pieces = ipAndMaskString.split("/", 2); + prefixLength = Integer.parseInt(pieces[1]); + address = InetAddress.parseNumericAddress(pieces[0]); + } catch (NullPointerException e) { // Null string. + } catch (ArrayIndexOutOfBoundsException e) { // No prefix length. + } catch (NumberFormatException e) { // Non-numeric prefix. + } catch (IllegalArgumentException e) { // Invalid IP address. + } + + if (address == null || prefixLength == -1) { + throw new IllegalArgumentException("Invalid IP address and mask " + ipAndMaskString); + } + + return new Pair(address, prefixLength); + } + + /** + * Convert a 32 char hex string into a Inet6Address. + * throws a runtime exception if the string isn't 32 chars, isn't hex or can't be + * made into an Inet6Address + * @param addrHexString a 32 character hex string representing an IPv6 addr + * @return addr an InetAddress representation for the string + */ + public static InetAddress hexToInet6Address(String addrHexString) + throws IllegalArgumentException { + try { + return numericToInetAddress(String.format(Locale.US, "%s:%s:%s:%s:%s:%s:%s:%s", + addrHexString.substring(0,4), addrHexString.substring(4,8), + addrHexString.substring(8,12), addrHexString.substring(12,16), + addrHexString.substring(16,20), addrHexString.substring(20,24), + addrHexString.substring(24,28), addrHexString.substring(28,32))); + } catch (Exception e) { + Log.e("NetworkUtils", "error in hexToInet6Address(" + addrHexString + "): " + e); + throw new IllegalArgumentException(e); + } + } + + /** + * Trim leading zeros from IPv4 address strings + * Our base libraries will interpret that as octel.. + * Must leave non v4 addresses and host names alone. + * For example, 192.168.000.010 -> 192.168.0.10 + * TODO - fix base libraries and remove this function + * @param addr a string representing an ip addr + * @return a string propertly trimmed + */ + @UnsupportedAppUsage + public static String trimV4AddrZeros(String addr) { + if (addr == null) return null; + String[] octets = addr.split("\\."); + if (octets.length != 4) return addr; + StringBuilder builder = new StringBuilder(16); + String result = null; + for (int i = 0; i < 4; i++) { + try { + if (octets[i].length() > 3) return addr; + builder.append(Integer.parseInt(octets[i])); + } catch (NumberFormatException e) { + return addr; + } + if (i < 3) builder.append('.'); + } + result = builder.toString(); + return result; + } + + /** + * Returns a prefix set without overlaps. + * + * This expects the src set to be sorted from shorter to longer. Results are undefined + * failing this condition. The returned prefix set is sorted in the same order as the + * passed set, with the same comparator. + */ + private static TreeSet deduplicatePrefixSet(final TreeSet src) { + final TreeSet dst = new TreeSet<>(src.comparator()); + // Prefixes match addresses that share their upper part up to their length, therefore + // the only kind of possible overlap in two prefixes is strict inclusion of the longer + // (more restrictive) in the shorter (including equivalence if they have the same + // length). + // Because prefixes in the src set are sorted from shorter to longer, deduplicating + // is done by simply iterating in order, and not adding any longer prefix that is + // already covered by a shorter one. + newPrefixes: + for (IpPrefix newPrefix : src) { + for (IpPrefix existingPrefix : dst) { + if (existingPrefix.containsPrefix(newPrefix)) { + continue newPrefixes; + } + } + dst.add(newPrefix); + } + return dst; + } + + /** + * Returns how many IPv4 addresses match any of the prefixes in the passed ordered set. + * + * Obviously this returns an integral value between 0 and 2**32. + * The behavior is undefined if any of the prefixes is not an IPv4 prefix or if the + * set is not ordered smallest prefix to longer prefix. + * + * @param prefixes the set of prefixes, ordered by length + */ + public static long routedIPv4AddressCount(final TreeSet prefixes) { + long routedIPCount = 0; + for (final IpPrefix prefix : deduplicatePrefixSet(prefixes)) { + if (!prefix.isIPv4()) { + Log.wtf(TAG, "Non-IPv4 prefix in routedIPv4AddressCount"); + } + int rank = 32 - prefix.getPrefixLength(); + routedIPCount += 1L << rank; + } + return routedIPCount; + } + + /** + * Returns how many IPv6 addresses match any of the prefixes in the passed ordered set. + * + * This returns a BigInteger between 0 and 2**128. + * The behavior is undefined if any of the prefixes is not an IPv6 prefix or if the + * set is not ordered smallest prefix to longer prefix. + */ + public static BigInteger routedIPv6AddressCount(final TreeSet prefixes) { + BigInteger routedIPCount = BigInteger.ZERO; + for (final IpPrefix prefix : deduplicatePrefixSet(prefixes)) { + if (!prefix.isIPv6()) { + Log.wtf(TAG, "Non-IPv6 prefix in routedIPv6AddressCount"); + } + int rank = 128 - prefix.getPrefixLength(); + routedIPCount = routedIPCount.add(BigInteger.ONE.shiftLeft(rank)); + } + return routedIPCount; + } + +} diff --git a/packages/Connectivity/framework/src/android/net/PacProxySelector.java b/packages/Connectivity/framework/src/android/net/PacProxySelector.java new file mode 100644 index 000000000000..326943a27d4e --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/PacProxySelector.java @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.os.ServiceManager; +import android.util.Log; + +import com.android.net.IProxyService; + +import com.google.android.collect.Lists; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.MalformedURLException; +import java.net.Proxy; +import java.net.Proxy.Type; +import java.net.ProxySelector; +import java.net.SocketAddress; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.List; + +/** + * @hide + */ +public class PacProxySelector extends ProxySelector { + private static final String TAG = "PacProxySelector"; + public static final String PROXY_SERVICE = "com.android.net.IProxyService"; + private static final String SOCKS = "SOCKS "; + private static final String PROXY = "PROXY "; + + private IProxyService mProxyService; + private final List mDefaultList; + + public PacProxySelector() { + mProxyService = IProxyService.Stub.asInterface( + ServiceManager.getService(PROXY_SERVICE)); + if (mProxyService == null) { + // Added because of b10267814 where mako is restarting. + Log.e(TAG, "PacProxyInstaller: no proxy service"); + } + mDefaultList = Lists.newArrayList(java.net.Proxy.NO_PROXY); + } + + @Override + public List select(URI uri) { + if (mProxyService == null) { + mProxyService = IProxyService.Stub.asInterface( + ServiceManager.getService(PROXY_SERVICE)); + } + if (mProxyService == null) { + Log.e(TAG, "select: no proxy service return NO_PROXY"); + return Lists.newArrayList(java.net.Proxy.NO_PROXY); + } + String response = null; + String urlString; + try { + // Strip path and username/password from URI so it's not visible to PAC script. The + // path often contains credentials the app does not want exposed to a potentially + // malicious PAC script. + if (!"http".equalsIgnoreCase(uri.getScheme())) { + uri = new URI(uri.getScheme(), null, uri.getHost(), uri.getPort(), "/", null, null); + } + urlString = uri.toURL().toString(); + } catch (URISyntaxException e) { + urlString = uri.getHost(); + } catch (MalformedURLException e) { + urlString = uri.getHost(); + } + try { + response = mProxyService.resolvePacFile(uri.getHost(), urlString); + } catch (Exception e) { + Log.e(TAG, "Error resolving PAC File", e); + } + if (response == null) { + return mDefaultList; + } + + return parseResponse(response); + } + + private static List parseResponse(String response) { + String[] split = response.split(";"); + List ret = Lists.newArrayList(); + for (String s : split) { + String trimmed = s.trim(); + if (trimmed.equals("DIRECT")) { + ret.add(java.net.Proxy.NO_PROXY); + } else if (trimmed.startsWith(PROXY)) { + Proxy proxy = proxyFromHostPort(Type.HTTP, trimmed.substring(PROXY.length())); + if (proxy != null) { + ret.add(proxy); + } + } else if (trimmed.startsWith(SOCKS)) { + Proxy proxy = proxyFromHostPort(Type.SOCKS, trimmed.substring(SOCKS.length())); + if (proxy != null) { + ret.add(proxy); + } + } + } + if (ret.size() == 0) { + ret.add(java.net.Proxy.NO_PROXY); + } + return ret; + } + + private static Proxy proxyFromHostPort(Proxy.Type type, String hostPortString) { + try { + String[] hostPort = hostPortString.split(":"); + String host = hostPort[0]; + int port = Integer.parseInt(hostPort[1]); + return new Proxy(type, InetSocketAddress.createUnresolved(host, port)); + } catch (NumberFormatException|ArrayIndexOutOfBoundsException e) { + Log.d(TAG, "Unable to parse proxy " + hostPortString + " " + e); + return null; + } + } + + @Override + public void connectFailed(URI uri, SocketAddress address, IOException failure) { + + } + +} diff --git a/packages/Connectivity/framework/src/android/net/Proxy.java b/packages/Connectivity/framework/src/android/net/Proxy.java new file mode 100644 index 000000000000..03b07e080add --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/Proxy.java @@ -0,0 +1,294 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.annotation.SdkConstant; +import android.annotation.SdkConstant.SdkConstantType; +import android.compat.annotation.UnsupportedAppUsage; +import android.content.Context; +import android.os.Build; +import android.text.TextUtils; +import android.util.Log; + +import com.android.net.module.util.ProxyUtils; + +import java.net.InetSocketAddress; +import java.net.ProxySelector; +import java.net.URI; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * A convenience class for accessing the user and default proxy + * settings. + */ +public final class Proxy { + + private static final String TAG = "Proxy"; + + private static final ProxySelector sDefaultProxySelector; + + /** + * Used to notify an app that's caching the proxy that either the default + * connection has changed or any connection's proxy has changed. The new + * proxy should be queried using {@link ConnectivityManager#getDefaultProxy()}. + * + *

This is a protected intent that can only be sent by the system + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String PROXY_CHANGE_ACTION = "android.intent.action.PROXY_CHANGE"; + /** + * Intent extra included with {@link #PROXY_CHANGE_ACTION} intents. + * It describes the new proxy being used (as a {@link ProxyInfo} object). + * @deprecated Because {@code PROXY_CHANGE_ACTION} is sent whenever the proxy + * for any network on the system changes, applications should always use + * {@link ConnectivityManager#getDefaultProxy()} or + * {@link ConnectivityManager#getLinkProperties(Network)}.{@link LinkProperties#getHttpProxy()} + * to get the proxy for the Network(s) they are using. + */ + @Deprecated + public static final String EXTRA_PROXY_INFO = "android.intent.extra.PROXY_INFO"; + + /** @hide */ + public static final int PROXY_VALID = 0; + /** @hide */ + public static final int PROXY_HOSTNAME_EMPTY = 1; + /** @hide */ + public static final int PROXY_HOSTNAME_INVALID = 2; + /** @hide */ + public static final int PROXY_PORT_EMPTY = 3; + /** @hide */ + public static final int PROXY_PORT_INVALID = 4; + /** @hide */ + public static final int PROXY_EXCLLIST_INVALID = 5; + + private static ConnectivityManager sConnectivityManager = null; + + // Hostname / IP REGEX validation + // Matches blank input, ips, and domain names + private static final String NAME_IP_REGEX = + "[a-zA-Z0-9]+(\\-[a-zA-Z0-9]+)*(\\.[a-zA-Z0-9]+(\\-[a-zA-Z0-9]+)*)*"; + + private static final String HOSTNAME_REGEXP = "^$|^" + NAME_IP_REGEX + "$"; + + private static final Pattern HOSTNAME_PATTERN; + + private static final String EXCL_REGEX = + "[a-zA-Z0-9*]+(\\-[a-zA-Z0-9*]+)*(\\.[a-zA-Z0-9*]+(\\-[a-zA-Z0-9*]+)*)*"; + + private static final String EXCLLIST_REGEXP = "^$|^" + EXCL_REGEX + "(," + EXCL_REGEX + ")*$"; + + private static final Pattern EXCLLIST_PATTERN; + + static { + HOSTNAME_PATTERN = Pattern.compile(HOSTNAME_REGEXP); + EXCLLIST_PATTERN = Pattern.compile(EXCLLIST_REGEXP); + sDefaultProxySelector = ProxySelector.getDefault(); + } + + /** + * Return the proxy object to be used for the URL given as parameter. + * @param ctx A Context used to get the settings for the proxy host. + * @param url A URL to be accessed. Used to evaluate exclusion list. + * @return Proxy (java.net) object containing the host name. If the + * user did not set a hostname it returns the default host. + * A null value means that no host is to be used. + * {@hide} + */ + @UnsupportedAppUsage + public static final java.net.Proxy getProxy(Context ctx, String url) { + String host = ""; + if ((url != null) && !isLocalHost(host)) { + URI uri = URI.create(url); + ProxySelector proxySelector = ProxySelector.getDefault(); + + List proxyList = proxySelector.select(uri); + + if (proxyList.size() > 0) { + return proxyList.get(0); + } + } + return java.net.Proxy.NO_PROXY; + } + + + /** + * Return the proxy host set by the user. + * @param ctx A Context used to get the settings for the proxy host. + * @return String containing the host name. If the user did not set a host + * name it returns the default host. A null value means that no + * host is to be used. + * @deprecated Use standard java vm proxy values to find the host, port + * and exclusion list. This call ignores the exclusion list. + */ + @Deprecated + public static final String getHost(Context ctx) { + java.net.Proxy proxy = getProxy(ctx, null); + if (proxy == java.net.Proxy.NO_PROXY) return null; + try { + return ((InetSocketAddress)(proxy.address())).getHostName(); + } catch (Exception e) { + return null; + } + } + + /** + * Return the proxy port set by the user. + * @param ctx A Context used to get the settings for the proxy port. + * @return The port number to use or -1 if no proxy is to be used. + * @deprecated Use standard java vm proxy values to find the host, port + * and exclusion list. This call ignores the exclusion list. + */ + @Deprecated + public static final int getPort(Context ctx) { + java.net.Proxy proxy = getProxy(ctx, null); + if (proxy == java.net.Proxy.NO_PROXY) return -1; + try { + return ((InetSocketAddress)(proxy.address())).getPort(); + } catch (Exception e) { + return -1; + } + } + + /** + * Return the default proxy host specified by the carrier. + * @return String containing the host name or null if there is no proxy for + * this carrier. + * @deprecated Use standard java vm proxy values to find the host, port and + * exclusion list. This call ignores the exclusion list and no + * longer reports only mobile-data apn-based proxy values. + */ + @Deprecated + public static final String getDefaultHost() { + String host = System.getProperty("http.proxyHost"); + if (TextUtils.isEmpty(host)) return null; + return host; + } + + /** + * Return the default proxy port specified by the carrier. + * @return The port number to be used with the proxy host or -1 if there is + * no proxy for this carrier. + * @deprecated Use standard java vm proxy values to find the host, port and + * exclusion list. This call ignores the exclusion list and no + * longer reports only mobile-data apn-based proxy values. + */ + @Deprecated + public static final int getDefaultPort() { + if (getDefaultHost() == null) return -1; + try { + return Integer.parseInt(System.getProperty("http.proxyPort")); + } catch (NumberFormatException e) { + return -1; + } + } + + private static final boolean isLocalHost(String host) { + if (host == null) { + return false; + } + try { + if (host != null) { + if (host.equalsIgnoreCase("localhost")) { + return true; + } + if (InetAddresses.parseNumericAddress(host).isLoopbackAddress()) { + return true; + } + } + } catch (IllegalArgumentException iex) { + } + return false; + } + + /** + * Validate syntax of hostname, port and exclusion list entries + * {@hide} + */ + public static int validate(String hostname, String port, String exclList) { + Matcher match = HOSTNAME_PATTERN.matcher(hostname); + Matcher listMatch = EXCLLIST_PATTERN.matcher(exclList); + + if (!match.matches()) return PROXY_HOSTNAME_INVALID; + + if (!listMatch.matches()) return PROXY_EXCLLIST_INVALID; + + if (hostname.length() > 0 && port.length() == 0) return PROXY_PORT_EMPTY; + + if (port.length() > 0) { + if (hostname.length() == 0) return PROXY_HOSTNAME_EMPTY; + int portVal = -1; + try { + portVal = Integer.parseInt(port); + } catch (NumberFormatException ex) { + return PROXY_PORT_INVALID; + } + if (portVal <= 0 || portVal > 0xFFFF) return PROXY_PORT_INVALID; + } + return PROXY_VALID; + } + + /** @hide */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + public static final void setHttpProxySystemProperty(ProxyInfo p) { + String host = null; + String port = null; + String exclList = null; + Uri pacFileUrl = Uri.EMPTY; + if (p != null) { + host = p.getHost(); + port = Integer.toString(p.getPort()); + exclList = ProxyUtils.exclusionListAsString(p.getExclusionList()); + pacFileUrl = p.getPacFileUrl(); + } + setHttpProxySystemProperty(host, port, exclList, pacFileUrl); + } + + /** @hide */ + public static final void setHttpProxySystemProperty(String host, String port, String exclList, + Uri pacFileUrl) { + if (exclList != null) exclList = exclList.replace(",", "|"); + if (false) Log.d(TAG, "setHttpProxySystemProperty :"+host+":"+port+" - "+exclList); + if (host != null) { + System.setProperty("http.proxyHost", host); + System.setProperty("https.proxyHost", host); + } else { + System.clearProperty("http.proxyHost"); + System.clearProperty("https.proxyHost"); + } + if (port != null) { + System.setProperty("http.proxyPort", port); + System.setProperty("https.proxyPort", port); + } else { + System.clearProperty("http.proxyPort"); + System.clearProperty("https.proxyPort"); + } + if (exclList != null) { + System.setProperty("http.nonProxyHosts", exclList); + System.setProperty("https.nonProxyHosts", exclList); + } else { + System.clearProperty("http.nonProxyHosts"); + System.clearProperty("https.nonProxyHosts"); + } + if (!Uri.EMPTY.equals(pacFileUrl)) { + ProxySelector.setDefault(new PacProxySelector()); + } else { + ProxySelector.setDefault(sDefaultProxySelector); + } + } +} diff --git a/packages/Connectivity/framework/src/android/net/ProxyInfo.aidl b/packages/Connectivity/framework/src/android/net/ProxyInfo.aidl new file mode 100644 index 000000000000..a5d0c120e747 --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/ProxyInfo.aidl @@ -0,0 +1,21 @@ +/* +** +** Copyright (C) 2010 The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +package android.net; + +@JavaOnlyStableParcelable parcelable ProxyInfo; + diff --git a/packages/Connectivity/framework/src/android/net/ProxyInfo.java b/packages/Connectivity/framework/src/android/net/ProxyInfo.java new file mode 100644 index 000000000000..c9bca2876b0a --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/ProxyInfo.java @@ -0,0 +1,367 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.compat.annotation.UnsupportedAppUsage; +import android.os.Parcel; +import android.os.Parcelable; +import android.text.TextUtils; + +import java.net.InetSocketAddress; +import java.net.URLConnection; +import java.util.List; +import java.util.Locale; + +/** + * Describes a proxy configuration. + * + * Proxy configurations are already integrated within the {@code java.net} and + * Apache HTTP stack. So {@link URLConnection} and Apache's {@code HttpClient} will use + * them automatically. + * + * Other HTTP stacks will need to obtain the proxy info from + * {@link Proxy#PROXY_CHANGE_ACTION} broadcast as the extra {@link Proxy#EXTRA_PROXY_INFO}. + */ +public class ProxyInfo implements Parcelable { + + private final String mHost; + private final int mPort; + private final String mExclusionList; + private final String[] mParsedExclusionList; + private final Uri mPacFileUrl; + + /** + *@hide + */ + public static final String LOCAL_EXCL_LIST = ""; + /** + *@hide + */ + public static final int LOCAL_PORT = -1; + /** + *@hide + */ + public static final String LOCAL_HOST = "localhost"; + + /** + * Constructs a {@link ProxyInfo} object that points at a Direct proxy + * on the specified host and port. + */ + public static ProxyInfo buildDirectProxy(String host, int port) { + return new ProxyInfo(host, port, null); + } + + /** + * Constructs a {@link ProxyInfo} object that points at a Direct proxy + * on the specified host and port. + * + * The proxy will not be used to access any host in exclusion list, exclList. + * + * @param exclList Hosts to exclude using the proxy on connections for. These + * hosts can use wildcards such as *.example.com. + */ + public static ProxyInfo buildDirectProxy(String host, int port, List exclList) { + String[] array = exclList.toArray(new String[exclList.size()]); + return new ProxyInfo(host, port, TextUtils.join(",", array), array); + } + + /** + * Construct a {@link ProxyInfo} that will download and run the PAC script + * at the specified URL. + */ + public static ProxyInfo buildPacProxy(Uri pacUri) { + return new ProxyInfo(pacUri); + } + + /** + * Construct a {@link ProxyInfo} object that will download and run the PAC script at the + * specified URL and port. + */ + @NonNull + public static ProxyInfo buildPacProxy(@NonNull Uri pacUrl, int port) { + return new ProxyInfo(pacUrl, port); + } + + /** + * Create a ProxyProperties that points at a HTTP Proxy. + * @hide + */ + @UnsupportedAppUsage + public ProxyInfo(String host, int port, String exclList) { + mHost = host; + mPort = port; + mExclusionList = exclList; + mParsedExclusionList = parseExclusionList(mExclusionList); + mPacFileUrl = Uri.EMPTY; + } + + /** + * Create a ProxyProperties that points at a PAC URL. + * @hide + */ + public ProxyInfo(@NonNull Uri pacFileUrl) { + mHost = LOCAL_HOST; + mPort = LOCAL_PORT; + mExclusionList = LOCAL_EXCL_LIST; + mParsedExclusionList = parseExclusionList(mExclusionList); + if (pacFileUrl == null) { + throw new NullPointerException(); + } + mPacFileUrl = pacFileUrl; + } + + /** + * Only used in PacProxyInstaller after Local Proxy is bound. + * @hide + */ + public ProxyInfo(@NonNull Uri pacFileUrl, int localProxyPort) { + mHost = LOCAL_HOST; + mPort = localProxyPort; + mExclusionList = LOCAL_EXCL_LIST; + mParsedExclusionList = parseExclusionList(mExclusionList); + if (pacFileUrl == null) { + throw new NullPointerException(); + } + mPacFileUrl = pacFileUrl; + } + + private static String[] parseExclusionList(String exclusionList) { + if (exclusionList == null) { + return new String[0]; + } else { + return exclusionList.toLowerCase(Locale.ROOT).split(","); + } + } + + private ProxyInfo(String host, int port, String exclList, String[] parsedExclList) { + mHost = host; + mPort = port; + mExclusionList = exclList; + mParsedExclusionList = parsedExclList; + mPacFileUrl = Uri.EMPTY; + } + + /** + * A copy constructor to hold proxy properties. + */ + public ProxyInfo(@Nullable ProxyInfo source) { + if (source != null) { + mHost = source.getHost(); + mPort = source.getPort(); + mPacFileUrl = source.mPacFileUrl; + mExclusionList = source.getExclusionListAsString(); + mParsedExclusionList = source.mParsedExclusionList; + } else { + mHost = null; + mPort = 0; + mExclusionList = null; + mParsedExclusionList = null; + mPacFileUrl = Uri.EMPTY; + } + } + + /** + * @hide + */ + public InetSocketAddress getSocketAddress() { + InetSocketAddress inetSocketAddress = null; + try { + inetSocketAddress = new InetSocketAddress(mHost, mPort); + } catch (IllegalArgumentException e) { } + return inetSocketAddress; + } + + /** + * Returns the URL of the current PAC script or null if there is + * no PAC script. + */ + public Uri getPacFileUrl() { + return mPacFileUrl; + } + + /** + * When configured to use a Direct Proxy this returns the host + * of the proxy. + */ + public String getHost() { + return mHost; + } + + /** + * When configured to use a Direct Proxy this returns the port + * of the proxy + */ + public int getPort() { + return mPort; + } + + /** + * When configured to use a Direct Proxy this returns the list + * of hosts for which the proxy is ignored. + */ + public String[] getExclusionList() { + return mParsedExclusionList; + } + + /** + * comma separated + * @hide + */ + @Nullable + public String getExclusionListAsString() { + return mExclusionList; + } + + /** + * Return true if the pattern of proxy is valid, otherwise return false. + */ + public boolean isValid() { + if (!Uri.EMPTY.equals(mPacFileUrl)) return true; + return Proxy.PROXY_VALID == Proxy.validate(mHost == null ? "" : mHost, + mPort == 0 ? "" : Integer.toString(mPort), + mExclusionList == null ? "" : mExclusionList); + } + + /** + * @hide + */ + public java.net.Proxy makeProxy() { + java.net.Proxy proxy = java.net.Proxy.NO_PROXY; + if (mHost != null) { + try { + InetSocketAddress inetSocketAddress = new InetSocketAddress(mHost, mPort); + proxy = new java.net.Proxy(java.net.Proxy.Type.HTTP, inetSocketAddress); + } catch (IllegalArgumentException e) { + } + } + return proxy; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + if (!Uri.EMPTY.equals(mPacFileUrl)) { + sb.append("PAC Script: "); + sb.append(mPacFileUrl); + } + if (mHost != null) { + sb.append("["); + sb.append(mHost); + sb.append("] "); + sb.append(Integer.toString(mPort)); + if (mExclusionList != null) { + sb.append(" xl=").append(mExclusionList); + } + } else { + sb.append("[ProxyProperties.mHost == null]"); + } + return sb.toString(); + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof ProxyInfo)) return false; + ProxyInfo p = (ProxyInfo)o; + // If PAC URL is present in either then they must be equal. + // Other parameters will only be for fall back. + if (!Uri.EMPTY.equals(mPacFileUrl)) { + return mPacFileUrl.equals(p.getPacFileUrl()) && mPort == p.mPort; + } + if (!Uri.EMPTY.equals(p.mPacFileUrl)) { + return false; + } + if (mExclusionList != null && !mExclusionList.equals(p.getExclusionListAsString())) { + return false; + } + if (mHost != null && p.getHost() != null && mHost.equals(p.getHost()) == false) { + return false; + } + if (mHost != null && p.mHost == null) return false; + if (mHost == null && p.mHost != null) return false; + if (mPort != p.mPort) return false; + return true; + } + + /** + * Implement the Parcelable interface + * @hide + */ + public int describeContents() { + return 0; + } + + @Override + /* + * generate hashcode based on significant fields + */ + public int hashCode() { + return ((null == mHost) ? 0 : mHost.hashCode()) + + ((null == mExclusionList) ? 0 : mExclusionList.hashCode()) + + mPort; + } + + /** + * Implement the Parcelable interface. + * @hide + */ + public void writeToParcel(Parcel dest, int flags) { + if (!Uri.EMPTY.equals(mPacFileUrl)) { + dest.writeByte((byte)1); + mPacFileUrl.writeToParcel(dest, 0); + dest.writeInt(mPort); + return; + } else { + dest.writeByte((byte)0); + } + if (mHost != null) { + dest.writeByte((byte)1); + dest.writeString(mHost); + dest.writeInt(mPort); + } else { + dest.writeByte((byte)0); + } + dest.writeString(mExclusionList); + dest.writeStringArray(mParsedExclusionList); + } + + public static final @android.annotation.NonNull Creator CREATOR = + new Creator() { + public ProxyInfo createFromParcel(Parcel in) { + String host = null; + int port = 0; + if (in.readByte() != 0) { + Uri url = Uri.CREATOR.createFromParcel(in); + int localPort = in.readInt(); + return new ProxyInfo(url, localPort); + } + if (in.readByte() != 0) { + host = in.readString(); + port = in.readInt(); + } + String exclList = in.readString(); + String[] parsedExclList = in.createStringArray(); + ProxyInfo proxyProperties = new ProxyInfo(host, port, exclList, parsedExclList); + return proxyProperties; + } + + public ProxyInfo[] newArray(int size) { + return new ProxyInfo[size]; + } + }; +} diff --git a/packages/Connectivity/framework/src/android/net/RouteInfo.aidl b/packages/Connectivity/framework/src/android/net/RouteInfo.aidl new file mode 100644 index 000000000000..7af9fdaef342 --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/RouteInfo.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +@JavaOnlyStableParcelable parcelable RouteInfo; diff --git a/packages/Connectivity/framework/src/android/net/RouteInfo.java b/packages/Connectivity/framework/src/android/net/RouteInfo.java new file mode 100644 index 000000000000..94f849f006f3 --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/RouteInfo.java @@ -0,0 +1,658 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.compat.annotation.UnsupportedAppUsage; +import android.os.Build; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.net.module.util.NetUtils; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Collection; +import java.util.Objects; + +/** + * Represents a network route. + *

+ * This is used both to describe static network configuration and live network + * configuration information. + * + * A route contains three pieces of information: + *

    + *
  • a destination {@link IpPrefix} specifying the network destinations covered by this route. + * If this is {@code null} it indicates a default route of the address family (IPv4 or IPv6) + * implied by the gateway IP address. + *
  • a gateway {@link InetAddress} indicating the next hop to use. If this is {@code null} it + * indicates a directly-connected route. + *
  • an interface (which may be unspecified). + *
+ * Either the destination or the gateway may be {@code null}, but not both. If the + * destination and gateway are both specified, they must be of the same address family + * (IPv4 or IPv6). + */ +public final class RouteInfo implements Parcelable { + /** @hide */ + @IntDef(value = { + RTN_UNICAST, + RTN_UNREACHABLE, + RTN_THROW, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface RouteType {} + + /** + * The IP destination address for this route. + */ + @NonNull + private final IpPrefix mDestination; + + /** + * The gateway address for this route. + */ + @UnsupportedAppUsage + @Nullable + private final InetAddress mGateway; + + /** + * The interface for this route. + */ + @Nullable + private final String mInterface; + + + /** Unicast route. @hide */ + @SystemApi + public static final int RTN_UNICAST = 1; + + /** Unreachable route. @hide */ + @SystemApi + public static final int RTN_UNREACHABLE = 7; + + /** Throw route. @hide */ + @SystemApi + public static final int RTN_THROW = 9; + + /** + * The type of this route; one of the RTN_xxx constants above. + */ + private final int mType; + + /** + * The maximum transmission unit size for this route. + */ + private final int mMtu; + + // Derived data members. + // TODO: remove these. + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) + private final boolean mIsHost; + private final boolean mHasGateway; + + /** + * Constructs a RouteInfo object. + * + * If destination is null, then gateway must be specified and the + * constructed route is either the IPv4 default route 0.0.0.0 + * if the gateway is an instance of {@link Inet4Address}, or the IPv6 default + * route ::/0 if gateway is an instance of + * {@link Inet6Address}. + *

+ * destination and gateway may not both be null. + * + * @param destination the destination prefix + * @param gateway the IP address to route packets through + * @param iface the interface name to send packets on + * @param type the type of this route + * + * @hide + */ + @SystemApi + public RouteInfo(@Nullable IpPrefix destination, @Nullable InetAddress gateway, + @Nullable String iface, @RouteType int type) { + this(destination, gateway, iface, type, 0); + } + + /** + * Constructs a RouteInfo object. + * + * If destination is null, then gateway must be specified and the + * constructed route is either the IPv4 default route 0.0.0.0 + * if the gateway is an instance of {@link Inet4Address}, or the IPv6 default + * route ::/0 if gateway is an instance of + * {@link Inet6Address}. + *

+ * destination and gateway may not both be null. + * + * @param destination the destination prefix + * @param gateway the IP address to route packets through + * @param iface the interface name to send packets on + * @param type the type of this route + * @param mtu the maximum transmission unit size for this route + * + * @hide + */ + @SystemApi + public RouteInfo(@Nullable IpPrefix destination, @Nullable InetAddress gateway, + @Nullable String iface, @RouteType int type, int mtu) { + switch (type) { + case RTN_UNICAST: + case RTN_UNREACHABLE: + case RTN_THROW: + // TODO: It would be nice to ensure that route types that don't have nexthops or + // interfaces, such as unreachable or throw, can't be created if an interface or + // a gateway is specified. This is a bit too complicated to do at the moment + // because: + // + // - LinkProperties sets the interface on routes added to it, and modifies the + // interfaces of all the routes when its interface name changes. + // - Even when the gateway is null, we store a non-null gateway here. + // + // For now, we just rely on the code that sets routes to do things properly. + break; + default: + throw new IllegalArgumentException("Unknown route type " + type); + } + + if (destination == null) { + if (gateway != null) { + if (gateway instanceof Inet4Address) { + destination = new IpPrefix(Inet4Address.ANY, 0); + } else { + destination = new IpPrefix(Inet6Address.ANY, 0); + } + } else { + // no destination, no gateway. invalid. + throw new IllegalArgumentException("Invalid arguments passed in: " + gateway + "," + + destination); + } + } + // TODO: set mGateway to null if there is no gateway. This is more correct, saves space, and + // matches the documented behaviour. Before we can do this we need to fix all callers (e.g., + // ConnectivityService) to stop doing things like r.getGateway().equals(), ... . + if (gateway == null) { + if (destination.getAddress() instanceof Inet4Address) { + gateway = Inet4Address.ANY; + } else { + gateway = Inet6Address.ANY; + } + } + mHasGateway = (!gateway.isAnyLocalAddress()); + + if ((destination.getAddress() instanceof Inet4Address + && !(gateway instanceof Inet4Address)) + || (destination.getAddress() instanceof Inet6Address + && !(gateway instanceof Inet6Address))) { + throw new IllegalArgumentException("address family mismatch in RouteInfo constructor"); + } + mDestination = destination; // IpPrefix objects are immutable. + mGateway = gateway; // InetAddress objects are immutable. + mInterface = iface; // Strings are immutable. + mType = type; + mIsHost = isHost(); + mMtu = mtu; + } + + /** + * Constructs a {@code RouteInfo} object. + * + * If destination is null, then gateway must be specified and the + * constructed route is either the IPv4 default route 0.0.0.0 + * if the gateway is an instance of {@link Inet4Address}, or the IPv6 default + * route ::/0 if gateway is an instance of {@link Inet6Address}. + *

+ * Destination and gateway may not both be null. + * + * @param destination the destination address and prefix in an {@link IpPrefix} + * @param gateway the {@link InetAddress} to route packets through + * @param iface the interface name to send packets on + * + * @hide + */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + public RouteInfo(@Nullable IpPrefix destination, @Nullable InetAddress gateway, + @Nullable String iface) { + this(destination, gateway, iface, RTN_UNICAST); + } + + /** + * @hide + */ + @UnsupportedAppUsage + public RouteInfo(@Nullable LinkAddress destination, @Nullable InetAddress gateway, + @Nullable String iface) { + this(destination == null ? null : + new IpPrefix(destination.getAddress(), destination.getPrefixLength()), + gateway, iface); + } + + /** + * Constructs a {@code RouteInfo} object. + * + * If destination is null, then gateway must be specified and the + * constructed route is either the IPv4 default route 0.0.0.0 + * if the gateway is an instance of {@link Inet4Address}, or the IPv6 default + * route ::/0 if gateway is an instance of {@link Inet6Address}. + *

+ * Destination and gateway may not both be null. + * + * @param destination the destination address and prefix in an {@link IpPrefix} + * @param gateway the {@link InetAddress} to route packets through + * + * @hide + */ + public RouteInfo(@Nullable IpPrefix destination, @Nullable InetAddress gateway) { + this(destination, gateway, null); + } + + /** + * @hide + * + * TODO: Remove this. + */ + @UnsupportedAppUsage + public RouteInfo(@Nullable LinkAddress destination, @Nullable InetAddress gateway) { + this(destination, gateway, null); + } + + /** + * Constructs a default {@code RouteInfo} object. + * + * @param gateway the {@link InetAddress} to route packets through + * + * @hide + */ + @UnsupportedAppUsage + public RouteInfo(@NonNull InetAddress gateway) { + this((IpPrefix) null, gateway, null); + } + + /** + * Constructs a {@code RouteInfo} object representing a direct connected subnet. + * + * @param destination the {@link IpPrefix} describing the address and prefix + * length of the subnet. + * + * @hide + */ + public RouteInfo(@NonNull IpPrefix destination) { + this(destination, null, null); + } + + /** + * @hide + */ + public RouteInfo(@NonNull LinkAddress destination) { + this(destination, null, null); + } + + /** + * @hide + */ + public RouteInfo(@NonNull IpPrefix destination, @RouteType int type) { + this(destination, null, null, type); + } + + /** + * @hide + */ + public static RouteInfo makeHostRoute(@NonNull InetAddress host, @Nullable String iface) { + return makeHostRoute(host, null, iface); + } + + /** + * @hide + */ + public static RouteInfo makeHostRoute(@Nullable InetAddress host, @Nullable InetAddress gateway, + @Nullable String iface) { + if (host == null) return null; + + if (host instanceof Inet4Address) { + return new RouteInfo(new IpPrefix(host, 32), gateway, iface); + } else { + return new RouteInfo(new IpPrefix(host, 128), gateway, iface); + } + } + + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) + private boolean isHost() { + return (mDestination.getAddress() instanceof Inet4Address && + mDestination.getPrefixLength() == 32) || + (mDestination.getAddress() instanceof Inet6Address && + mDestination.getPrefixLength() == 128); + } + + /** + * Retrieves the destination address and prefix length in the form of an {@link IpPrefix}. + * + * @return {@link IpPrefix} specifying the destination. This is never {@code null}. + */ + @NonNull + public IpPrefix getDestination() { + return mDestination; + } + + /** + * TODO: Convert callers to use IpPrefix and then remove. + * @hide + */ + @NonNull + public LinkAddress getDestinationLinkAddress() { + return new LinkAddress(mDestination.getAddress(), mDestination.getPrefixLength()); + } + + /** + * Retrieves the gateway or next hop {@link InetAddress} for this route. + * + * @return {@link InetAddress} specifying the gateway or next hop. This may be + * {@code null} for a directly-connected route." + */ + @Nullable + public InetAddress getGateway() { + return mGateway; + } + + /** + * Retrieves the interface used for this route if specified, else {@code null}. + * + * @return The name of the interface used for this route. + */ + @Nullable + public String getInterface() { + return mInterface; + } + + /** + * Retrieves the type of this route. + * + * @return The type of this route; one of the {@code RTN_xxx} constants defined in this class. + * + * @hide + */ + @SystemApi + @RouteType + public int getType() { + return mType; + } + + /** + * Retrieves the MTU size for this route. + * + * @return The MTU size, or 0 if it has not been set. + * @hide + */ + @SystemApi + public int getMtu() { + return mMtu; + } + + /** + * Indicates if this route is a default route (ie, has no destination specified). + * + * @return {@code true} if the destination has a prefix length of 0. + */ + public boolean isDefaultRoute() { + return mType == RTN_UNICAST && mDestination.getPrefixLength() == 0; + } + + /** + * Indicates if this route is an unreachable default route. + * + * @return {@code true} if it's an unreachable route with prefix length of 0. + * @hide + */ + private boolean isUnreachableDefaultRoute() { + return mType == RTN_UNREACHABLE && mDestination.getPrefixLength() == 0; + } + + /** + * Indicates if this route is an IPv4 default route. + * @hide + */ + public boolean isIPv4Default() { + return isDefaultRoute() && mDestination.getAddress() instanceof Inet4Address; + } + + /** + * Indicates if this route is an IPv4 unreachable default route. + * @hide + */ + public boolean isIPv4UnreachableDefault() { + return isUnreachableDefaultRoute() && mDestination.getAddress() instanceof Inet4Address; + } + + /** + * Indicates if this route is an IPv6 default route. + * @hide + */ + public boolean isIPv6Default() { + return isDefaultRoute() && mDestination.getAddress() instanceof Inet6Address; + } + + /** + * Indicates if this route is an IPv6 unreachable default route. + * @hide + */ + public boolean isIPv6UnreachableDefault() { + return isUnreachableDefaultRoute() && mDestination.getAddress() instanceof Inet6Address; + } + + /** + * Indicates if this route is a host route (ie, matches only a single host address). + * + * @return {@code true} if the destination has a prefix length of 32 or 128 for IPv4 or IPv6, + * respectively. + * @hide + */ + public boolean isHostRoute() { + return mIsHost; + } + + /** + * Indicates if this route has a next hop ({@code true}) or is directly-connected + * ({@code false}). + * + * @return {@code true} if a gateway is specified + */ + public boolean hasGateway() { + return mHasGateway; + } + + /** + * Determines whether the destination and prefix of this route includes the specified + * address. + * + * @param destination A {@link InetAddress} to test to see if it would match this route. + * @return {@code true} if the destination and prefix length cover the given address. + */ + public boolean matches(InetAddress destination) { + return mDestination.contains(destination); + } + + /** + * Find the route from a Collection of routes that best matches a given address. + * May return null if no routes are applicable. + * @param routes a Collection of RouteInfos to chose from + * @param dest the InetAddress your trying to get to + * @return the RouteInfo from the Collection that best fits the given address + * + * @hide + */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @Nullable + public static RouteInfo selectBestRoute(Collection routes, InetAddress dest) { + return NetUtils.selectBestRoute(routes, dest); + } + + /** + * Returns a human-readable description of this object. + */ + public String toString() { + String val = ""; + if (mDestination != null) val = mDestination.toString(); + if (mType == RTN_UNREACHABLE) { + val += " unreachable"; + } else if (mType == RTN_THROW) { + val += " throw"; + } else { + val += " ->"; + if (mGateway != null) val += " " + mGateway.getHostAddress(); + if (mInterface != null) val += " " + mInterface; + if (mType != RTN_UNICAST) { + val += " unknown type " + mType; + } + } + val += " mtu " + mMtu; + return val; + } + + /** + * Compares this RouteInfo object against the specified object and indicates if they are equal. + * @return {@code true} if the objects are equal, {@code false} otherwise. + */ + public boolean equals(Object obj) { + if (this == obj) return true; + + if (!(obj instanceof RouteInfo)) return false; + + RouteInfo target = (RouteInfo) obj; + + return Objects.equals(mDestination, target.getDestination()) && + Objects.equals(mGateway, target.getGateway()) && + Objects.equals(mInterface, target.getInterface()) && + mType == target.getType() && mMtu == target.getMtu(); + } + + /** + * A helper class that contains the destination, the gateway and the interface in a + * {@code RouteInfo}, used by {@link ConnectivityService#updateRoutes} or + * {@link LinkProperties#addRoute} to calculate the list to be updated. + * {@code RouteInfo} objects with different interfaces are treated as different routes because + * *usually* on Android different interfaces use different routing tables, and moving a route + * to a new routing table never constitutes an update, but is always a remove and an add. + * + * @hide + */ + public static class RouteKey { + @NonNull private final IpPrefix mDestination; + @Nullable private final InetAddress mGateway; + @Nullable private final String mInterface; + + RouteKey(@NonNull IpPrefix destination, @Nullable InetAddress gateway, + @Nullable String iface) { + mDestination = destination; + mGateway = gateway; + mInterface = iface; + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof RouteKey)) { + return false; + } + RouteKey p = (RouteKey) o; + // No need to do anything special for scoped addresses. Inet6Address#equals does not + // consider the scope ID, but the netd route IPCs (e.g., INetd#networkAddRouteParcel) + // and the kernel ignore scoped addresses both in the prefix and in the nexthop and only + // look at RTA_OIF. + return Objects.equals(p.mDestination, mDestination) + && Objects.equals(p.mGateway, mGateway) + && Objects.equals(p.mInterface, mInterface); + } + + @Override + public int hashCode() { + return Objects.hash(mDestination, mGateway, mInterface); + } + } + + /** + * Get {@code RouteKey} of this {@code RouteInfo}. + * @return a {@code RouteKey} object. + * + * @hide + */ + @NonNull + public RouteKey getRouteKey() { + return new RouteKey(mDestination, mGateway, mInterface); + } + + /** + * Returns a hashcode for this RouteInfo object. + */ + public int hashCode() { + return (mDestination.hashCode() * 41) + + (mGateway == null ? 0 :mGateway.hashCode() * 47) + + (mInterface == null ? 0 :mInterface.hashCode() * 67) + + (mType * 71) + (mMtu * 89); + } + + /** + * Implement the Parcelable interface + */ + public int describeContents() { + return 0; + } + + /** + * Implement the Parcelable interface + */ + public void writeToParcel(Parcel dest, int flags) { + dest.writeParcelable(mDestination, flags); + byte[] gatewayBytes = (mGateway == null) ? null : mGateway.getAddress(); + dest.writeByteArray(gatewayBytes); + dest.writeString(mInterface); + dest.writeInt(mType); + dest.writeInt(mMtu); + } + + /** + * Implement the Parcelable interface. + */ + public static final @android.annotation.NonNull Creator CREATOR = + new Creator() { + public RouteInfo createFromParcel(Parcel in) { + IpPrefix dest = in.readParcelable(null); + + InetAddress gateway = null; + byte[] addr = in.createByteArray(); + try { + gateway = InetAddress.getByAddress(addr); + } catch (UnknownHostException e) {} + + String iface = in.readString(); + int type = in.readInt(); + int mtu = in.readInt(); + + return new RouteInfo(dest, gateway, iface, type, mtu); + } + + public RouteInfo[] newArray(int size) { + return new RouteInfo[size]; + } + }; +} diff --git a/packages/Connectivity/framework/src/android/net/SocketKeepalive.java b/packages/Connectivity/framework/src/android/net/SocketKeepalive.java new file mode 100644 index 000000000000..d007a9520cb5 --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/SocketKeepalive.java @@ -0,0 +1,301 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.annotation.IntDef; +import android.annotation.IntRange; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.os.Binder; +import android.os.ParcelFileDescriptor; +import android.os.RemoteException; + +import java.io.IOException; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.concurrent.Executor; + +/** + * Allows applications to request that the system periodically send specific packets on their + * behalf, using hardware offload to save battery power. + * + * To request that the system send keepalives, call one of the methods that return a + * {@link SocketKeepalive} object, such as {@link ConnectivityManager#createSocketKeepalive}, + * passing in a non-null callback. If the {@link SocketKeepalive} is successfully + * started, the callback's {@code onStarted} method will be called. If an error occurs, + * {@code onError} will be called, specifying one of the {@code ERROR_*} constants in this + * class. + * + * To stop an existing keepalive, call {@link SocketKeepalive#stop}. The system will call + * {@link SocketKeepalive.Callback#onStopped} if the operation was successful or + * {@link SocketKeepalive.Callback#onError} if an error occurred. + * + * For cellular, the device MUST support at least 1 keepalive slot. + * + * For WiFi, the device SHOULD support keepalive offload. If it does not, it MUST reply with + * {@link SocketKeepalive.Callback#onError} with {@code ERROR_UNSUPPORTED} to any keepalive offload + * request. If it does, it MUST support at least 3 concurrent keepalive slots. + */ +public abstract class SocketKeepalive implements AutoCloseable { + static final String TAG = "SocketKeepalive"; + + /** + * No errors. + * @hide + */ + @SystemApi + public static final int SUCCESS = 0; + + /** @hide */ + public static final int NO_KEEPALIVE = -1; + + /** @hide */ + public static final int DATA_RECEIVED = -2; + + /** @hide */ + public static final int BINDER_DIED = -10; + + /** The specified {@code Network} is not connected. */ + public static final int ERROR_INVALID_NETWORK = -20; + /** The specified IP addresses are invalid. For example, the specified source IP address is + * not configured on the specified {@code Network}. */ + public static final int ERROR_INVALID_IP_ADDRESS = -21; + /** The requested port is invalid. */ + public static final int ERROR_INVALID_PORT = -22; + /** The packet length is invalid (e.g., too long). */ + public static final int ERROR_INVALID_LENGTH = -23; + /** The packet transmission interval is invalid (e.g., too short). */ + public static final int ERROR_INVALID_INTERVAL = -24; + /** The target socket is invalid. */ + public static final int ERROR_INVALID_SOCKET = -25; + /** The target socket is not idle. */ + public static final int ERROR_SOCKET_NOT_IDLE = -26; + /** + * The stop reason is uninitialized. This should only be internally used as initial state + * of stop reason, instead of propagating to application. + * @hide + */ + public static final int ERROR_STOP_REASON_UNINITIALIZED = -27; + + /** The device does not support this request. */ + public static final int ERROR_UNSUPPORTED = -30; + /** @hide TODO: delete when telephony code has been updated. */ + public static final int ERROR_HARDWARE_UNSUPPORTED = ERROR_UNSUPPORTED; + /** The hardware returned an error. */ + public static final int ERROR_HARDWARE_ERROR = -31; + /** The limitation of resource is reached. */ + public static final int ERROR_INSUFFICIENT_RESOURCES = -32; + + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = { "ERROR_" }, value = { + ERROR_INVALID_NETWORK, + ERROR_INVALID_IP_ADDRESS, + ERROR_INVALID_PORT, + ERROR_INVALID_LENGTH, + ERROR_INVALID_INTERVAL, + ERROR_INVALID_SOCKET, + ERROR_SOCKET_NOT_IDLE + }) + public @interface ErrorCode {} + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(value = { + SUCCESS, + ERROR_INVALID_LENGTH, + ERROR_UNSUPPORTED, + ERROR_INSUFFICIENT_RESOURCES, + ERROR_HARDWARE_UNSUPPORTED + }) + public @interface KeepaliveEvent {} + + /** + * The minimum interval in seconds between keepalive packet transmissions. + * + * @hide + **/ + public static final int MIN_INTERVAL_SEC = 10; + + /** + * The maximum interval in seconds between keepalive packet transmissions. + * + * @hide + **/ + public static final int MAX_INTERVAL_SEC = 3600; + + /** + * An exception that embarks an error code. + * @hide + */ + public static class ErrorCodeException extends Exception { + public final int error; + public ErrorCodeException(final int error, final Throwable e) { + super(e); + this.error = error; + } + public ErrorCodeException(final int error) { + this.error = error; + } + } + + /** + * This socket is invalid. + * See the error code for details, and the optional cause. + * @hide + */ + public static class InvalidSocketException extends ErrorCodeException { + public InvalidSocketException(final int error, final Throwable e) { + super(error, e); + } + public InvalidSocketException(final int error) { + super(error); + } + } + + @NonNull final IConnectivityManager mService; + @NonNull final Network mNetwork; + @NonNull final ParcelFileDescriptor mPfd; + @NonNull final Executor mExecutor; + @NonNull final ISocketKeepaliveCallback mCallback; + // TODO: remove slot since mCallback could be used to identify which keepalive to stop. + @Nullable Integer mSlot; + + SocketKeepalive(@NonNull IConnectivityManager service, @NonNull Network network, + @NonNull ParcelFileDescriptor pfd, + @NonNull Executor executor, @NonNull Callback callback) { + mService = service; + mNetwork = network; + mPfd = pfd; + mExecutor = executor; + mCallback = new ISocketKeepaliveCallback.Stub() { + @Override + public void onStarted(int slot) { + final long token = Binder.clearCallingIdentity(); + try { + mExecutor.execute(() -> { + mSlot = slot; + callback.onStarted(); + }); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + @Override + public void onStopped() { + final long token = Binder.clearCallingIdentity(); + try { + executor.execute(() -> { + mSlot = null; + callback.onStopped(); + }); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + @Override + public void onError(int error) { + final long token = Binder.clearCallingIdentity(); + try { + executor.execute(() -> { + mSlot = null; + callback.onError(error); + }); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + @Override + public void onDataReceived() { + final long token = Binder.clearCallingIdentity(); + try { + executor.execute(() -> { + mSlot = null; + callback.onDataReceived(); + }); + } finally { + Binder.restoreCallingIdentity(token); + } + } + }; + } + + /** + * Request that keepalive be started with the given {@code intervalSec}. See + * {@link SocketKeepalive}. If the remote binder dies, or the binder call throws an exception + * when invoking start or stop of the {@link SocketKeepalive}, a {@link RemoteException} will be + * thrown into the {@code executor}. This is typically not important to catch because the remote + * party is the system, so if it is not in shape to communicate through binder the system is + * probably going down anyway. If the caller cares regardless, it can use a custom + * {@link Executor} to catch the {@link RemoteException}. + * + * @param intervalSec The target interval in seconds between keepalive packet transmissions. + * The interval should be between 10 seconds and 3600 seconds, otherwise + * {@link #ERROR_INVALID_INTERVAL} will be returned. + */ + public final void start(@IntRange(from = MIN_INTERVAL_SEC, to = MAX_INTERVAL_SEC) + int intervalSec) { + startImpl(intervalSec); + } + + abstract void startImpl(int intervalSec); + + /** + * Requests that keepalive be stopped. The application must wait for {@link Callback#onStopped} + * before using the object. See {@link SocketKeepalive}. + */ + public final void stop() { + stopImpl(); + } + + abstract void stopImpl(); + + /** + * Deactivate this {@link SocketKeepalive} and free allocated resources. The instance won't be + * usable again if {@code close()} is called. + */ + @Override + public final void close() { + stop(); + try { + mPfd.close(); + } catch (IOException e) { + // Nothing much can be done. + } + } + + /** + * The callback which app can use to learn the status changes of {@link SocketKeepalive}. See + * {@link SocketKeepalive}. + */ + public static class Callback { + /** The requested keepalive was successfully started. */ + public void onStarted() {} + /** The keepalive was successfully stopped. */ + public void onStopped() {} + /** An error occurred. */ + public void onError(@ErrorCode int error) {} + /** The keepalive on a TCP socket was stopped because the socket received data. This is + * never called for UDP sockets. */ + public void onDataReceived() {} + } +} diff --git a/packages/Connectivity/framework/src/android/net/StaticIpConfiguration.aidl b/packages/Connectivity/framework/src/android/net/StaticIpConfiguration.aidl new file mode 100644 index 000000000000..8aac701fe7e1 --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/StaticIpConfiguration.aidl @@ -0,0 +1,20 @@ +/* +** +** Copyright (C) 2019 The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +package android.net; + +@JavaOnlyStableParcelable parcelable StaticIpConfiguration; \ No newline at end of file diff --git a/packages/Connectivity/framework/src/android/net/StaticIpConfiguration.java b/packages/Connectivity/framework/src/android/net/StaticIpConfiguration.java new file mode 100644 index 000000000000..ce545974f5cb --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/StaticIpConfiguration.java @@ -0,0 +1,332 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.compat.annotation.UnsupportedAppUsage; +import android.os.Build; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.util.Preconditions; +import com.android.net.module.util.InetAddressUtils; + +import java.net.InetAddress; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + * Class that describes static IP configuration. + * + *

This class is different from {@link LinkProperties} because it represents + * configuration intent. The general contract is that if we can represent + * a configuration here, then we should be able to configure it on a network. + * The intent is that it closely match the UI we have for configuring networks. + * + *

In contrast, {@link LinkProperties} represents current state. It is much more + * expressive. For example, it supports multiple IP addresses, multiple routes, + * stacked interfaces, and so on. Because LinkProperties is so expressive, + * using it to represent configuration intent as well as current state causes + * problems. For example, we could unknowingly save a configuration that we are + * not in fact capable of applying, or we could save a configuration that the + * UI cannot display, which has the potential for malicious code to hide + * hostile or unexpected configuration from the user. + * + * @hide + */ +@SystemApi +public final class StaticIpConfiguration implements Parcelable { + /** @hide */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @Nullable + public LinkAddress ipAddress; + /** @hide */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @Nullable + public InetAddress gateway; + /** @hide */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @NonNull + public final ArrayList dnsServers; + /** @hide */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @Nullable + public String domains; + + public StaticIpConfiguration() { + dnsServers = new ArrayList<>(); + } + + public StaticIpConfiguration(@Nullable StaticIpConfiguration source) { + this(); + if (source != null) { + // All of these except dnsServers are immutable, so no need to make copies. + ipAddress = source.ipAddress; + gateway = source.gateway; + dnsServers.addAll(source.dnsServers); + domains = source.domains; + } + } + + public void clear() { + ipAddress = null; + gateway = null; + dnsServers.clear(); + domains = null; + } + + /** + * Get the static IP address included in the configuration. + */ + public @Nullable LinkAddress getIpAddress() { + return ipAddress; + } + + /** + * Get the gateway included in the configuration. + */ + public @Nullable InetAddress getGateway() { + return gateway; + } + + /** + * Get the DNS servers included in the configuration. + */ + public @NonNull List getDnsServers() { + return dnsServers; + } + + /** + * Get a {@link String} containing the comma separated domains to search when resolving host + * names on this link, in priority order. + */ + public @Nullable String getDomains() { + return domains; + } + + /** + * Helper class to build a new instance of {@link StaticIpConfiguration}. + */ + public static final class Builder { + private LinkAddress mIpAddress; + private InetAddress mGateway; + private Iterable mDnsServers; + private String mDomains; + + /** + * Set the IP address to be included in the configuration; null by default. + * @return The {@link Builder} for chaining. + */ + public @NonNull Builder setIpAddress(@Nullable LinkAddress ipAddress) { + mIpAddress = ipAddress; + return this; + } + + /** + * Set the address of the gateway to be included in the configuration; null by default. + * @return The {@link Builder} for chaining. + */ + public @NonNull Builder setGateway(@Nullable InetAddress gateway) { + mGateway = gateway; + return this; + } + + /** + * Set the addresses of the DNS servers included in the configuration; empty by default. + * @return The {@link Builder} for chaining. + */ + public @NonNull Builder setDnsServers(@NonNull Iterable dnsServers) { + Preconditions.checkNotNull(dnsServers); + mDnsServers = dnsServers; + return this; + } + + /** + * Sets the DNS domain search path to be used on the link; null by default. + * @param newDomains A {@link String} containing the comma separated domains to search when + * resolving host names on this link, in priority order. + * @return The {@link Builder} for chaining. + */ + public @NonNull Builder setDomains(@Nullable String newDomains) { + mDomains = newDomains; + return this; + } + + /** + * Create a {@link StaticIpConfiguration} from the parameters in this {@link Builder}. + * @return The newly created StaticIpConfiguration. + */ + public @NonNull StaticIpConfiguration build() { + final StaticIpConfiguration config = new StaticIpConfiguration(); + config.ipAddress = mIpAddress; + config.gateway = mGateway; + if (mDnsServers != null) { + for (InetAddress server : mDnsServers) { + config.dnsServers.add(server); + } + } + config.domains = mDomains; + return config; + } + } + + /** + * Add a DNS server to this configuration. + */ + public void addDnsServer(@NonNull InetAddress server) { + dnsServers.add(server); + } + + /** + * Returns the network routes specified by this object. Will typically include a + * directly-connected route for the IP address's local subnet and a default route. + * @param iface Interface to include in the routes. + */ + public @NonNull List getRoutes(@Nullable String iface) { + List routes = new ArrayList(3); + if (ipAddress != null) { + RouteInfo connectedRoute = new RouteInfo(ipAddress, null, iface); + routes.add(connectedRoute); + // If the default gateway is not covered by the directly-connected route, also add a + // host route to the gateway as well. This configuration is arguably invalid, but it + // used to work in K and earlier, and other OSes appear to accept it. + if (gateway != null && !connectedRoute.matches(gateway)) { + routes.add(RouteInfo.makeHostRoute(gateway, iface)); + } + } + if (gateway != null) { + routes.add(new RouteInfo((IpPrefix) null, gateway, iface)); + } + return routes; + } + + /** + * Returns a LinkProperties object expressing the data in this object. Note that the information + * contained in the LinkProperties will not be a complete picture of the link's configuration, + * because any configuration information that is obtained dynamically by the network (e.g., + * IPv6 configuration) will not be included. + * @hide + */ + public @NonNull LinkProperties toLinkProperties(String iface) { + LinkProperties lp = new LinkProperties(); + lp.setInterfaceName(iface); + if (ipAddress != null) { + lp.addLinkAddress(ipAddress); + } + for (RouteInfo route : getRoutes(iface)) { + lp.addRoute(route); + } + for (InetAddress dns : dnsServers) { + lp.addDnsServer(dns); + } + lp.setDomains(domains); + return lp; + } + + @NonNull + @Override + public String toString() { + StringBuffer str = new StringBuffer(); + + str.append("IP address "); + if (ipAddress != null ) str.append(ipAddress).append(" "); + + str.append("Gateway "); + if (gateway != null) str.append(gateway.getHostAddress()).append(" "); + + str.append(" DNS servers: ["); + for (InetAddress dnsServer : dnsServers) { + str.append(" ").append(dnsServer.getHostAddress()); + } + + str.append(" ] Domains "); + if (domains != null) str.append(domains); + return str.toString(); + } + + @Override + public int hashCode() { + int result = 13; + result = 47 * result + (ipAddress == null ? 0 : ipAddress.hashCode()); + result = 47 * result + (gateway == null ? 0 : gateway.hashCode()); + result = 47 * result + (domains == null ? 0 : domains.hashCode()); + result = 47 * result + dnsServers.hashCode(); + return result; + } + + @Override + public boolean equals(@Nullable Object obj) { + if (this == obj) return true; + + if (!(obj instanceof StaticIpConfiguration)) return false; + + StaticIpConfiguration other = (StaticIpConfiguration) obj; + + return other != null && + Objects.equals(ipAddress, other.ipAddress) && + Objects.equals(gateway, other.gateway) && + dnsServers.equals(other.dnsServers) && + Objects.equals(domains, other.domains); + } + + /** Implement the Parcelable interface */ + public static final @android.annotation.NonNull Creator CREATOR = + new Creator() { + public StaticIpConfiguration createFromParcel(Parcel in) { + return readFromParcel(in); + } + + public StaticIpConfiguration[] newArray(int size) { + return new StaticIpConfiguration[size]; + } + }; + + /** Implement the Parcelable interface */ + @Override + public int describeContents() { + return 0; + } + + /** Implement the Parcelable interface */ + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeParcelable(ipAddress, flags); + InetAddressUtils.parcelInetAddress(dest, gateway, flags); + dest.writeInt(dnsServers.size()); + for (InetAddress dnsServer : dnsServers) { + InetAddressUtils.parcelInetAddress(dest, dnsServer, flags); + } + dest.writeString(domains); + } + + /** @hide */ + public static StaticIpConfiguration readFromParcel(Parcel in) { + final StaticIpConfiguration s = new StaticIpConfiguration(); + s.ipAddress = in.readParcelable(null); + s.gateway = InetAddressUtils.unparcelInetAddress(in); + s.dnsServers.clear(); + int size = in.readInt(); + for (int i = 0; i < size; i++) { + s.dnsServers.add(InetAddressUtils.unparcelInetAddress(in)); + } + s.domains = in.readString(); + return s; + } +} diff --git a/packages/Connectivity/framework/src/android/net/TcpKeepalivePacketData.java b/packages/Connectivity/framework/src/android/net/TcpKeepalivePacketData.java new file mode 100644 index 000000000000..ddb3a6a72fb4 --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/TcpKeepalivePacketData.java @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.net; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.os.Parcel; +import android.os.Parcelable; + +import java.net.InetAddress; +import java.util.Objects; + +/** + * Represents the actual tcp keep alive packets which will be used for hardware offload. + * @hide + */ +@SystemApi +public final class TcpKeepalivePacketData extends KeepalivePacketData implements Parcelable { + private static final String TAG = "TcpKeepalivePacketData"; + + /** TCP sequence number. */ + public final int tcpSeq; + + /** TCP ACK number. */ + public final int tcpAck; + + /** TCP RCV window. */ + public final int tcpWindow; + + /** TCP RCV window scale. */ + public final int tcpWindowScale; + + /** IP TOS. */ + public final int ipTos; + + /** IP TTL. */ + public final int ipTtl; + + public TcpKeepalivePacketData(@NonNull final InetAddress srcAddress, int srcPort, + @NonNull final InetAddress dstAddress, int dstPort, @NonNull final byte[] data, + int tcpSeq, int tcpAck, int tcpWindow, int tcpWindowScale, int ipTos, int ipTtl) + throws InvalidPacketException { + super(srcAddress, srcPort, dstAddress, dstPort, data); + this.tcpSeq = tcpSeq; + this.tcpAck = tcpAck; + this.tcpWindow = tcpWindow; + this.tcpWindowScale = tcpWindowScale; + this.ipTos = ipTos; + this.ipTtl = ipTtl; + } + + @Override + public boolean equals(@Nullable final Object o) { + if (!(o instanceof TcpKeepalivePacketData)) return false; + final TcpKeepalivePacketData other = (TcpKeepalivePacketData) o; + final InetAddress srcAddress = getSrcAddress(); + final InetAddress dstAddress = getDstAddress(); + return srcAddress.equals(other.getSrcAddress()) + && dstAddress.equals(other.getDstAddress()) + && getSrcPort() == other.getSrcPort() + && getDstPort() == other.getDstPort() + && this.tcpAck == other.tcpAck + && this.tcpSeq == other.tcpSeq + && this.tcpWindow == other.tcpWindow + && this.tcpWindowScale == other.tcpWindowScale + && this.ipTos == other.ipTos + && this.ipTtl == other.ipTtl; + } + + @Override + public int hashCode() { + return Objects.hash(getSrcAddress(), getDstAddress(), getSrcPort(), getDstPort(), + tcpAck, tcpSeq, tcpWindow, tcpWindowScale, ipTos, ipTtl); + } + + /** + * Parcelable Implementation. + * Note that this object implements parcelable (and needs to keep doing this as it inherits + * from a class that does), but should usually be parceled as a stable parcelable using + * the toStableParcelable() and fromStableParcelable() methods. + */ + @Override + public int describeContents() { + return 0; + } + + /** Write to parcel. */ + @Override + public void writeToParcel(@NonNull Parcel out, int flags) { + out.writeString(getSrcAddress().getHostAddress()); + out.writeString(getDstAddress().getHostAddress()); + out.writeInt(getSrcPort()); + out.writeInt(getDstPort()); + out.writeByteArray(getPacket()); + out.writeInt(tcpSeq); + out.writeInt(tcpAck); + out.writeInt(tcpWindow); + out.writeInt(tcpWindowScale); + out.writeInt(ipTos); + out.writeInt(ipTtl); + } + + private static TcpKeepalivePacketData readFromParcel(Parcel in) throws InvalidPacketException { + InetAddress srcAddress = InetAddresses.parseNumericAddress(in.readString()); + InetAddress dstAddress = InetAddresses.parseNumericAddress(in.readString()); + int srcPort = in.readInt(); + int dstPort = in.readInt(); + byte[] packet = in.createByteArray(); + int tcpSeq = in.readInt(); + int tcpAck = in.readInt(); + int tcpWnd = in.readInt(); + int tcpWndScale = in.readInt(); + int ipTos = in.readInt(); + int ipTtl = in.readInt(); + return new TcpKeepalivePacketData(srcAddress, srcPort, dstAddress, dstPort, packet, tcpSeq, + tcpAck, tcpWnd, tcpWndScale, ipTos, ipTtl); + } + + /** Parcelable Creator. */ + public static final @NonNull Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public TcpKeepalivePacketData createFromParcel(Parcel in) { + try { + return readFromParcel(in); + } catch (InvalidPacketException e) { + throw new IllegalArgumentException( + "Invalid TCP keepalive data: " + e.getError()); + } + } + + public TcpKeepalivePacketData[] newArray(int size) { + return new TcpKeepalivePacketData[size]; + } + }; + + @Override + public String toString() { + return "saddr: " + getSrcAddress() + + " daddr: " + getDstAddress() + + " sport: " + getSrcPort() + + " dport: " + getDstPort() + + " seq: " + tcpSeq + + " ack: " + tcpAck + + " window: " + tcpWindow + + " windowScale: " + tcpWindowScale + + " tos: " + ipTos + + " ttl: " + ipTtl; + } +} diff --git a/packages/Connectivity/framework/src/android/net/TcpRepairWindow.java b/packages/Connectivity/framework/src/android/net/TcpRepairWindow.java new file mode 100644 index 000000000000..f062fa9034ea --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/TcpRepairWindow.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.annotation.SystemApi; + +/** + * Corresponds to C's {@code struct tcp_repair_window} from + * include/uapi/linux/tcp.h + * + * @hide + */ +@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) +public final class TcpRepairWindow { + public final int sndWl1; + public final int sndWnd; + public final int maxWindow; + public final int rcvWnd; + public final int rcvWup; + public final int rcvWndScale; + + /** + * Constructs an instance with the given field values. + */ + public TcpRepairWindow(final int sndWl1, final int sndWnd, final int maxWindow, + final int rcvWnd, final int rcvWup, final int rcvWndScale) { + this.sndWl1 = sndWl1; + this.sndWnd = sndWnd; + this.maxWindow = maxWindow; + this.rcvWnd = rcvWnd; + this.rcvWup = rcvWup; + this.rcvWndScale = rcvWndScale; + } +} diff --git a/packages/Connectivity/framework/src/android/net/TcpSocketKeepalive.java b/packages/Connectivity/framework/src/android/net/TcpSocketKeepalive.java new file mode 100644 index 000000000000..d89814d49bd0 --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/TcpSocketKeepalive.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.annotation.NonNull; +import android.os.ParcelFileDescriptor; +import android.os.RemoteException; +import android.util.Log; + +import java.util.concurrent.Executor; + +/** @hide */ +final class TcpSocketKeepalive extends SocketKeepalive { + + TcpSocketKeepalive(@NonNull IConnectivityManager service, + @NonNull Network network, + @NonNull ParcelFileDescriptor pfd, + @NonNull Executor executor, + @NonNull Callback callback) { + super(service, network, pfd, executor, callback); + } + + /** + * Starts keepalives. {@code mSocket} must be a connected TCP socket. + * + * - The application must not write to or read from the socket after calling this method, until + * onDataReceived, onStopped, or onError are called. If it does, the keepalive will fail + * with {@link #ERROR_SOCKET_NOT_IDLE}, or {@code #ERROR_INVALID_SOCKET} if the socket + * experienced an error (as in poll(2) returned POLLERR or POLLHUP); if this happens, the data + * received from the socket may be invalid, and the socket can't be recovered. + * - If the socket has data in the send or receive buffer, then this call will fail with + * {@link #ERROR_SOCKET_NOT_IDLE} and can be retried after the data has been processed. + * An app could ensure this by using an application-layer protocol to receive acknowledgement + * that indicates all data has been delivered to server, e.g. HTTP 200 OK. + * Then the app could go into keepalive mode after reading all remaining data within the + * acknowledgement. + */ + @Override + void startImpl(int intervalSec) { + mExecutor.execute(() -> { + try { + mService.startTcpKeepalive(mNetwork, mPfd, intervalSec, mCallback); + } catch (RemoteException e) { + Log.e(TAG, "Error starting packet keepalive: ", e); + throw e.rethrowFromSystemServer(); + } + }); + } + + @Override + void stopImpl() { + mExecutor.execute(() -> { + try { + if (mSlot != null) { + mService.stopKeepalive(mNetwork, mSlot); + } + } catch (RemoteException e) { + Log.e(TAG, "Error stopping packet keepalive: ", e); + throw e.rethrowFromSystemServer(); + } + }); + } +} diff --git a/packages/Connectivity/framework/src/android/net/TestNetworkInterface.aidl b/packages/Connectivity/framework/src/android/net/TestNetworkInterface.aidl new file mode 100644 index 000000000000..e1f4f9f794eb --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/TestNetworkInterface.aidl @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +/** @hide */ +parcelable TestNetworkInterface; diff --git a/packages/Connectivity/framework/src/android/net/TestNetworkInterface.java b/packages/Connectivity/framework/src/android/net/TestNetworkInterface.java new file mode 100644 index 000000000000..4449ff80180b --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/TestNetworkInterface.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.net; + +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.os.Parcel; +import android.os.ParcelFileDescriptor; +import android.os.Parcelable; + +/** + * This class is used to return the interface name and fd of the test interface + * + * @hide + */ +@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) +public final class TestNetworkInterface implements Parcelable { + @NonNull + private final ParcelFileDescriptor mFileDescriptor; + @NonNull + private final String mInterfaceName; + + @Override + public int describeContents() { + return (mFileDescriptor != null) ? Parcelable.CONTENTS_FILE_DESCRIPTOR : 0; + } + + @Override + public void writeToParcel(@NonNull Parcel out, int flags) { + out.writeParcelable(mFileDescriptor, PARCELABLE_WRITE_RETURN_VALUE); + out.writeString(mInterfaceName); + } + + public TestNetworkInterface(@NonNull ParcelFileDescriptor pfd, @NonNull String intf) { + mFileDescriptor = pfd; + mInterfaceName = intf; + } + + private TestNetworkInterface(@NonNull Parcel in) { + mFileDescriptor = in.readParcelable(ParcelFileDescriptor.class.getClassLoader()); + mInterfaceName = in.readString(); + } + + @NonNull + public ParcelFileDescriptor getFileDescriptor() { + return mFileDescriptor; + } + + @NonNull + public String getInterfaceName() { + return mInterfaceName; + } + + @NonNull + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public TestNetworkInterface createFromParcel(Parcel in) { + return new TestNetworkInterface(in); + } + + public TestNetworkInterface[] newArray(int size) { + return new TestNetworkInterface[size]; + } + }; +} diff --git a/packages/Connectivity/framework/src/android/net/TestNetworkManager.java b/packages/Connectivity/framework/src/android/net/TestNetworkManager.java new file mode 100644 index 000000000000..4e894143bf91 --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/TestNetworkManager.java @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.net; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.os.IBinder; +import android.os.RemoteException; + +import com.android.internal.util.Preconditions; + +import java.util.Arrays; +import java.util.Collection; + +/** + * Class that allows creation and management of per-app, test-only networks + * + * @hide + */ +@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) +public class TestNetworkManager { + /** + * Prefix for tun interfaces created by this class. + * @hide + */ + public static final String TEST_TUN_PREFIX = "testtun"; + + /** + * Prefix for tap interfaces created by this class. + * @hide + */ + public static final String TEST_TAP_PREFIX = "testtap"; + + @NonNull private static final String TAG = TestNetworkManager.class.getSimpleName(); + + @NonNull private final ITestNetworkManager mService; + + /** @hide */ + public TestNetworkManager(@NonNull ITestNetworkManager service) { + mService = Preconditions.checkNotNull(service, "missing ITestNetworkManager"); + } + + /** + * Teardown the capability-limited, testing-only network for a given interface + * + * @param network The test network that should be torn down + * @hide + */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + public void teardownTestNetwork(@NonNull Network network) { + try { + mService.teardownTestNetwork(network.netId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + private void setupTestNetwork( + @NonNull String iface, + @Nullable LinkProperties lp, + boolean isMetered, + @NonNull int[] administratorUids, + @NonNull IBinder binder) { + try { + mService.setupTestNetwork(iface, lp, isMetered, administratorUids, binder); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Sets up a capability-limited, testing-only network for a given interface + * + * @param lp The LinkProperties for the TestNetworkService to use for this test network. Note + * that the interface name and link addresses will be overwritten, and the passed-in values + * discarded. + * @param isMetered Whether or not the network should be considered metered. + * @param binder A binder object guarding the lifecycle of this test network. + * @hide + */ + public void setupTestNetwork( + @NonNull LinkProperties lp, boolean isMetered, @NonNull IBinder binder) { + Preconditions.checkNotNull(lp, "Invalid LinkProperties"); + setupTestNetwork(lp.getInterfaceName(), lp, isMetered, new int[0], binder); + } + + /** + * Sets up a capability-limited, testing-only network for a given interface + * + * @param iface the name of the interface to be used for the Network LinkProperties. + * @param binder A binder object guarding the lifecycle of this test network. + * @hide + */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + public void setupTestNetwork(@NonNull String iface, @NonNull IBinder binder) { + setupTestNetwork(iface, null, true, new int[0], binder); + } + + /** + * Sets up a capability-limited, testing-only network for a given interface with the given + * administrator UIDs. + * + * @param iface the name of the interface to be used for the Network LinkProperties. + * @param administratorUids The administrator UIDs to be used for the test-only network + * @param binder A binder object guarding the lifecycle of this test network. + * @hide + */ + public void setupTestNetwork( + @NonNull String iface, @NonNull int[] administratorUids, @NonNull IBinder binder) { + setupTestNetwork(iface, null, true, administratorUids, binder); + } + + /** + * Create a tun interface for testing purposes + * + * @param linkAddrs an array of LinkAddresses to assign to the TUN interface + * @return A ParcelFileDescriptor of the underlying TUN interface. Close this to tear down the + * TUN interface. + * @deprecated Use {@link #createTunInterface(Collection)} instead. + * @hide + */ + @Deprecated + @NonNull + public TestNetworkInterface createTunInterface(@NonNull LinkAddress[] linkAddrs) { + return createTunInterface(Arrays.asList(linkAddrs)); + } + + /** + * Create a tun interface for testing purposes + * + * @param linkAddrs an array of LinkAddresses to assign to the TUN interface + * @return A ParcelFileDescriptor of the underlying TUN interface. Close this to tear down the + * TUN interface. + * @hide + */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + @NonNull + public TestNetworkInterface createTunInterface(@NonNull Collection linkAddrs) { + try { + final LinkAddress[] arr = new LinkAddress[linkAddrs.size()]; + return mService.createTunInterface(linkAddrs.toArray(arr)); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Create a tap interface for testing purposes + * + * @return A ParcelFileDescriptor of the underlying TAP interface. Close this to tear down the + * TAP interface. + * @hide + */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + @NonNull + public TestNetworkInterface createTapInterface() { + try { + return mService.createTapInterface(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + +} diff --git a/packages/Connectivity/framework/src/android/net/TransportInfo.java b/packages/Connectivity/framework/src/android/net/TransportInfo.java new file mode 100644 index 000000000000..aa4bbb051179 --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/TransportInfo.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.annotation.NonNull; +import android.annotation.SystemApi; + +/** + * A container for transport-specific capabilities which is returned by + * {@link NetworkCapabilities#getTransportInfo()}. Specific networks + * may provide concrete implementations of this interface. + * @see android.net.wifi.aware.WifiAwareNetworkInfo + * @see android.net.wifi.WifiInfo + */ +public interface TransportInfo { + + /** + * Create a copy of a {@link TransportInfo} that will preserve location sensitive fields that + * were set based on the permissions of the process that originally received it. + * + *

By default {@link TransportInfo} does not preserve such fields during parceling, as + * they should not be shared outside of the process that receives them without appropriate + * checks. + * + * @param parcelLocationSensitiveFields Whether the location sensitive fields should be kept + * when parceling + * @return Copy of this instance. + * @hide + */ + @SystemApi + @NonNull + default TransportInfo makeCopy(boolean parcelLocationSensitiveFields) { + return this; + } + + /** + * Returns whether this TransportInfo type has location sensitive fields or not (helps + * to determine whether to perform a location permission check or not before sending to + * apps). + * + * @return {@code true} if this instance contains location sensitive info, {@code false} + * otherwise. + * @hide + */ + @SystemApi + default boolean hasLocationSensitiveFields() { + return false; + } +} diff --git a/packages/Connectivity/framework/src/android/net/UidRange.aidl b/packages/Connectivity/framework/src/android/net/UidRange.aidl new file mode 100644 index 000000000000..f70fc8e2fefd --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/UidRange.aidl @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +/** + * An inclusive range of UIDs. + * + * {@hide} + */ +parcelable UidRange; \ No newline at end of file diff --git a/packages/Connectivity/framework/src/android/net/VpnManager.java b/packages/Connectivity/framework/src/android/net/VpnManager.java new file mode 100644 index 000000000000..c87b8279c4d6 --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/VpnManager.java @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import static com.android.internal.util.Preconditions.checkNotNull; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.Activity; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.res.Resources; +import android.os.RemoteException; + +import com.android.internal.net.VpnProfile; + +import java.io.IOException; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.security.GeneralSecurityException; + +/** + * This class provides an interface for apps to manage platform VPN profiles + * + *

Apps can use this API to provide profiles with which the platform can set up a VPN without + * further app intermediation. When a VPN profile is present and the app is selected as an always-on + * VPN, the platform will directly trigger the negotiation of the VPN without starting or waking the + * app (unlike VpnService). + * + *

VPN apps using supported protocols should preferentially use this API over the {@link + * VpnService} API for ease-of-development and reduced maintainance burden. This also give the user + * the guarantee that VPN network traffic is not subjected to on-device packet interception. + * + * @see Ikev2VpnProfile + */ +public class VpnManager { + /** Type representing a lack of VPN @hide */ + public static final int TYPE_VPN_NONE = -1; + /** VPN service type code @hide */ + public static final int TYPE_VPN_SERVICE = 1; + /** Platform VPN type code @hide */ + public static final int TYPE_VPN_PLATFORM = 2; + + /** @hide */ + @IntDef(value = {TYPE_VPN_NONE, TYPE_VPN_SERVICE, TYPE_VPN_PLATFORM}) + @Retention(RetentionPolicy.SOURCE) + public @interface VpnType {} + + @NonNull private final Context mContext; + @NonNull private final IConnectivityManager mService; + + private static Intent getIntentForConfirmation() { + final Intent intent = new Intent(); + final ComponentName componentName = ComponentName.unflattenFromString( + Resources.getSystem().getString( + com.android.internal.R.string.config_platformVpnConfirmDialogComponent)); + intent.setComponent(componentName); + return intent; + } + + /** + * Create an instance of the VpnManager with the given context. + * + *

Internal only. Applications are expected to obtain an instance of the VpnManager via the + * {@link Context.getSystemService()} method call. + * + * @hide + */ + public VpnManager(@NonNull Context ctx, @NonNull IConnectivityManager service) { + mContext = checkNotNull(ctx, "missing Context"); + mService = checkNotNull(service, "missing IConnectivityManager"); + } + + /** + * Install a VpnProfile configuration keyed on the calling app's package name. + * + *

This method returns {@code null} if user consent has already been granted, or an {@link + * Intent} to a system activity. If an intent is returned, the application should launch the + * activity using {@link Activity#startActivityForResult} to request user consent. The activity + * may pop up a dialog to require user action, and the result will come back via its {@link + * Activity#onActivityResult}. If the result is {@link Activity#RESULT_OK}, the user has + * consented, and the VPN profile can be started. + * + * @param profile the VpnProfile provided by this package. Will override any previous VpnProfile + * stored for this package. + * @return an Intent requesting user consent to start the VPN, or null if consent is not + * required based on privileges or previous user consent. + */ + @Nullable + public Intent provisionVpnProfile(@NonNull PlatformVpnProfile profile) { + final VpnProfile internalProfile; + + try { + internalProfile = profile.toVpnProfile(); + } catch (GeneralSecurityException | IOException e) { + // Conversion to VpnProfile failed; this is an invalid profile. Both of these exceptions + // indicate a failure to convert a PrivateKey or X509Certificate to a Base64 encoded + // string as required by the VpnProfile. + throw new IllegalArgumentException("Failed to serialize PlatformVpnProfile", e); + } + + try { + // Profile can never be null; it either gets set, or an exception is thrown. + if (mService.provisionVpnProfile(internalProfile, mContext.getOpPackageName())) { + return null; + } + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + return getIntentForConfirmation(); + } + + /** + * Delete the VPN profile configuration that was provisioned by the calling app + * + * @throws SecurityException if this would violate user settings + */ + public void deleteProvisionedVpnProfile() { + try { + mService.deleteVpnProfile(mContext.getOpPackageName()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Request the startup of a previously provisioned VPN. + * + * @throws SecurityException exception if user or device settings prevent this VPN from being + * setup, or if user consent has not been granted + */ + public void startProvisionedVpnProfile() { + try { + mService.startVpnProfile(mContext.getOpPackageName()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** Tear down the VPN provided by the calling app (if any) */ + public void stopProvisionedVpnProfile() { + try { + mService.stopVpnProfile(mContext.getOpPackageName()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } +} diff --git a/packages/Connectivity/framework/src/android/net/VpnService.java b/packages/Connectivity/framework/src/android/net/VpnService.java new file mode 100644 index 000000000000..8e90a119fe21 --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/VpnService.java @@ -0,0 +1,903 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import static android.system.OsConstants.AF_INET; +import static android.system.OsConstants.AF_INET6; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.RequiresPermission; +import android.annotation.SystemApi; +import android.app.Activity; +import android.app.PendingIntent; +import android.app.Service; +import android.app.admin.DevicePolicyManager; +import android.compat.annotation.UnsupportedAppUsage; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.IPackageManager; +import android.content.pm.PackageManager; +import android.os.Binder; +import android.os.IBinder; +import android.os.Parcel; +import android.os.ParcelFileDescriptor; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.os.UserHandle; + +import com.android.internal.net.VpnConfig; + +import java.net.DatagramSocket; +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.Socket; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +/** + * VpnService is a base class for applications to extend and build their + * own VPN solutions. In general, it creates a virtual network interface, + * configures addresses and routing rules, and returns a file descriptor + * to the application. Each read from the descriptor retrieves an outgoing + * packet which was routed to the interface. Each write to the descriptor + * injects an incoming packet just like it was received from the interface. + * The interface is running on Internet Protocol (IP), so packets are + * always started with IP headers. The application then completes a VPN + * connection by processing and exchanging packets with the remote server + * over a tunnel. + * + *

Letting applications intercept packets raises huge security concerns. + * A VPN application can easily break the network. Besides, two of them may + * conflict with each other. The system takes several actions to address + * these issues. Here are some key points: + *

    + *
  • User action is required the first time an application creates a VPN + * connection.
  • + *
  • There can be only one VPN connection running at the same time. The + * existing interface is deactivated when a new one is created.
  • + *
  • A system-managed notification is shown during the lifetime of a + * VPN connection.
  • + *
  • A system-managed dialog gives the information of the current VPN + * connection. It also provides a button to disconnect.
  • + *
  • The network is restored automatically when the file descriptor is + * closed. It also covers the cases when a VPN application is crashed + * or killed by the system.
  • + *
+ * + *

There are two primary methods in this class: {@link #prepare} and + * {@link Builder#establish}. The former deals with user action and stops + * the VPN connection created by another application. The latter creates + * a VPN interface using the parameters supplied to the {@link Builder}. + * An application must call {@link #prepare} to grant the right to use + * other methods in this class, and the right can be revoked at any time. + * Here are the general steps to create a VPN connection: + *

    + *
  1. When the user presses the button to connect, call {@link #prepare} + * and launch the returned intent, if non-null.
  2. + *
  3. When the application becomes prepared, start the service.
  4. + *
  5. Create a tunnel to the remote server and negotiate the network + * parameters for the VPN connection.
  6. + *
  7. Supply those parameters to a {@link Builder} and create a VPN + * interface by calling {@link Builder#establish}.
  8. + *
  9. Process and exchange packets between the tunnel and the returned + * file descriptor.
  10. + *
  11. When {@link #onRevoke} is invoked, close the file descriptor and + * shut down the tunnel gracefully.
  12. + *
+ * + *

Services extending this class need to be declared with an appropriate + * permission and intent filter. Their access must be secured by + * {@link android.Manifest.permission#BIND_VPN_SERVICE} permission, and + * their intent filter must match {@link #SERVICE_INTERFACE} action. Here + * is an example of declaring a VPN service in {@code AndroidManifest.xml}: + *

+ * <service android:name=".ExampleVpnService"
+ *         android:permission="android.permission.BIND_VPN_SERVICE">
+ *     <intent-filter>
+ *         <action android:name="android.net.VpnService"/>
+ *     </intent-filter>
+ * </service>
+ * + *

The Android system starts a VPN in the background by calling + * {@link android.content.Context#startService startService()}. In Android 8.0 + * (API level 26) and higher, the system places VPN apps on the temporary + * allowlist for a short period so the app can start in the background. The VPN + * app must promote itself to the foreground after it's launched or the system + * will shut down the app. + * + *

Developer's guide

+ * + *

To learn more about developing VPN apps, read the + * VPN developer's guide. + * + * @see Builder + */ +public class VpnService extends Service { + + /** + * The action must be matched by the intent filter of this service. It also + * needs to require {@link android.Manifest.permission#BIND_VPN_SERVICE} + * permission so that other applications cannot abuse it. + */ + public static final String SERVICE_INTERFACE = VpnConfig.SERVICE_INTERFACE; + + /** + * Key for boolean meta-data field indicating whether this VpnService supports always-on mode. + * + *

For a VPN app targeting {@link android.os.Build.VERSION_CODES#N API 24} or above, Android + * provides users with the ability to set it as always-on, so that VPN connection is + * persisted after device reboot and app upgrade. Always-on VPN can also be enabled by device + * owner and profile owner apps through + * {@link DevicePolicyManager#setAlwaysOnVpnPackage}. + * + *

VPN apps not supporting this feature should opt out by adding this meta-data field to the + * {@code VpnService} component of {@code AndroidManifest.xml}. In case there is more than one + * {@code VpnService} component defined in {@code AndroidManifest.xml}, opting out any one of + * them will opt out the entire app. For example, + *

 {@code
+     * 
+     *     
+     *         
+     *     
+     *     
+     * 
+     * } 
+ * + *

This meta-data field defaults to {@code true} if absent. It will only have effect on + * {@link android.os.Build.VERSION_CODES#O_MR1} or higher. + */ + public static final String SERVICE_META_DATA_SUPPORTS_ALWAYS_ON = + "android.net.VpnService.SUPPORTS_ALWAYS_ON"; + + /** + * Use IConnectivityManager since those methods are hidden and not + * available in ConnectivityManager. + */ + private static IConnectivityManager getService() { + return IConnectivityManager.Stub.asInterface( + ServiceManager.getService(Context.CONNECTIVITY_SERVICE)); + } + + /** + * Prepare to establish a VPN connection. This method returns {@code null} + * if the VPN application is already prepared or if the user has previously + * consented to the VPN application. Otherwise, it returns an + * {@link Intent} to a system activity. The application should launch the + * activity using {@link Activity#startActivityForResult} to get itself + * prepared. The activity may pop up a dialog to require user action, and + * the result will come back via its {@link Activity#onActivityResult}. + * If the result is {@link Activity#RESULT_OK}, the application becomes + * prepared and is granted to use other methods in this class. + * + *

Only one application can be granted at the same time. The right + * is revoked when another application is granted. The application + * losing the right will be notified via its {@link #onRevoke}. Unless + * it becomes prepared again, subsequent calls to other methods in this + * class will fail. + * + *

The user may disable the VPN at any time while it is activated, in + * which case this method will return an intent the next time it is + * executed to obtain the user's consent again. + * + * @see #onRevoke + */ + public static Intent prepare(Context context) { + try { + if (getService().prepareVpn(context.getPackageName(), null, context.getUserId())) { + return null; + } + } catch (RemoteException e) { + // ignore + } + return VpnConfig.getIntentForConfirmation(); + } + + /** + * Version of {@link #prepare(Context)} which does not require user consent. + * + *

Requires {@link android.Manifest.permission#CONTROL_VPN} and should generally not be + * used. Only acceptable in situations where user consent has been obtained through other means. + * + *

Once this is run, future preparations may be done with the standard prepare method as this + * will authorize the package to prepare the VPN without consent in the future. + * + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.CONTROL_VPN) + public static void prepareAndAuthorize(Context context) { + IConnectivityManager cm = getService(); + String packageName = context.getPackageName(); + try { + // Only prepare if we're not already prepared. + int userId = context.getUserId(); + if (!cm.prepareVpn(packageName, null, userId)) { + cm.prepareVpn(null, packageName, userId); + } + cm.setVpnPackageAuthorization(packageName, userId, VpnManager.TYPE_VPN_SERVICE); + } catch (RemoteException e) { + // ignore + } + } + + /** + * Protect a socket from VPN connections. After protecting, data sent + * through this socket will go directly to the underlying network, + * so its traffic will not be forwarded through the VPN. + * This method is useful if some connections need to be kept + * outside of VPN. For example, a VPN tunnel should protect itself if its + * destination is covered by VPN routes. Otherwise its outgoing packets + * will be sent back to the VPN interface and cause an infinite loop. This + * method will fail if the application is not prepared or is revoked. + * + *

The socket is NOT closed by this method. + * + * @return {@code true} on success. + */ + public boolean protect(int socket) { + return NetworkUtils.protectFromVpn(socket); + } + + /** + * Convenience method to protect a {@link Socket} from VPN connections. + * + * @return {@code true} on success. + * @see #protect(int) + */ + public boolean protect(Socket socket) { + return protect(socket.getFileDescriptor$().getInt$()); + } + + /** + * Convenience method to protect a {@link DatagramSocket} from VPN + * connections. + * + * @return {@code true} on success. + * @see #protect(int) + */ + public boolean protect(DatagramSocket socket) { + return protect(socket.getFileDescriptor$().getInt$()); + } + + /** + * Adds a network address to the VPN interface. + * + * Both IPv4 and IPv6 addresses are supported. The VPN must already be established. Fails if the + * address is already in use or cannot be assigned to the interface for any other reason. + * + * Adding an address implicitly allows traffic from that address family (i.e., IPv4 or IPv6) to + * be routed over the VPN. @see Builder#allowFamily + * + * @throws IllegalArgumentException if the address is invalid. + * + * @param address The IP address (IPv4 or IPv6) to assign to the VPN interface. + * @param prefixLength The prefix length of the address. + * + * @return {@code true} on success. + * @see Builder#addAddress + * + * @hide + */ + public boolean addAddress(InetAddress address, int prefixLength) { + check(address, prefixLength); + try { + return getService().addVpnAddress(address.getHostAddress(), prefixLength); + } catch (RemoteException e) { + throw new IllegalStateException(e); + } + } + + /** + * Removes a network address from the VPN interface. + * + * Both IPv4 and IPv6 addresses are supported. The VPN must already be established. Fails if the + * address is not assigned to the VPN interface, or if it is the only address assigned (thus + * cannot be removed), or if the address cannot be removed for any other reason. + * + * After removing an address, if there are no addresses, routes or DNS servers of a particular + * address family (i.e., IPv4 or IPv6) configured on the VPN, that DOES NOT block that + * family from being routed. In other words, once an address family has been allowed, it stays + * allowed for the rest of the VPN's session. @see Builder#allowFamily + * + * @throws IllegalArgumentException if the address is invalid. + * + * @param address The IP address (IPv4 or IPv6) to assign to the VPN interface. + * @param prefixLength The prefix length of the address. + * + * @return {@code true} on success. + * + * @hide + */ + public boolean removeAddress(InetAddress address, int prefixLength) { + check(address, prefixLength); + try { + return getService().removeVpnAddress(address.getHostAddress(), prefixLength); + } catch (RemoteException e) { + throw new IllegalStateException(e); + } + } + + /** + * Sets the underlying networks used by the VPN for its upstream connections. + * + *

Used by the system to know the actual networks that carry traffic for apps affected by + * this VPN in order to present this information to the user (e.g., via status bar icons). + * + *

This method only needs to be called if the VPN has explicitly bound its underlying + * communications channels — such as the socket(s) passed to {@link #protect(int)} — + * to a {@code Network} using APIs such as {@link Network#bindSocket(Socket)} or + * {@link Network#bindSocket(DatagramSocket)}. The VPN should call this method every time + * the set of {@code Network}s it is using changes. + * + *

{@code networks} is one of the following: + *

    + *
  • a non-empty array: an array of one or more {@link Network}s, in + * decreasing preference order. For example, if this VPN uses both wifi and mobile (cellular) + * networks to carry app traffic, but prefers or uses wifi more than mobile, wifi should appear + * first in the array.
  • + *
  • an empty array: a zero-element array, meaning that the VPN has no + * underlying network connection, and thus, app traffic will not be sent or received.
  • + *
  • null: (default) signifies that the VPN uses whatever is the system's + * default network. I.e., it doesn't use the {@code bindSocket} or {@code bindDatagramSocket} + * APIs mentioned above to send traffic over specific channels.
  • + *
+ * + *

This call will succeed only if the VPN is currently established. For setting this value + * when the VPN has not yet been established, see {@link Builder#setUnderlyingNetworks}. + * + * @param networks An array of networks the VPN uses to tunnel traffic to/from its servers. + * + * @return {@code true} on success. + */ + public boolean setUnderlyingNetworks(Network[] networks) { + try { + return getService().setUnderlyingNetworksForVpn(networks); + } catch (RemoteException e) { + throw new IllegalStateException(e); + } + } + + /** + * Returns whether the service is running in always-on VPN mode. In this mode the system ensures + * that the service is always running by restarting it when necessary, e.g. after reboot. + * + * @see DevicePolicyManager#setAlwaysOnVpnPackage(ComponentName, String, boolean, Set) + */ + public final boolean isAlwaysOn() { + try { + return getService().isCallerCurrentAlwaysOnVpnApp(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Returns whether the service is running in always-on VPN lockdown mode. In this mode the + * system ensures that the service is always running and that the apps aren't allowed to bypass + * the VPN. + * + * @see DevicePolicyManager#setAlwaysOnVpnPackage(ComponentName, String, boolean, Set) + */ + public final boolean isLockdownEnabled() { + try { + return getService().isCallerCurrentAlwaysOnVpnLockdownApp(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Return the communication interface to the service. This method returns + * {@code null} on {@link Intent}s other than {@link #SERVICE_INTERFACE} + * action. Applications overriding this method must identify the intent + * and return the corresponding interface accordingly. + * + * @see Service#onBind + */ + @Override + public IBinder onBind(Intent intent) { + if (intent != null && SERVICE_INTERFACE.equals(intent.getAction())) { + return new Callback(); + } + return null; + } + + /** + * Invoked when the application is revoked. At this moment, the VPN + * interface is already deactivated by the system. The application should + * close the file descriptor and shut down gracefully. The default + * implementation of this method is calling {@link Service#stopSelf()}. + * + *

Calls to this method may not happen on the main thread + * of the process. + * + * @see #prepare + */ + public void onRevoke() { + stopSelf(); + } + + /** + * Use raw Binder instead of AIDL since now there is only one usage. + */ + private class Callback extends Binder { + @Override + protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) { + if (code == IBinder.LAST_CALL_TRANSACTION) { + onRevoke(); + return true; + } + return false; + } + } + + /** + * Private method to validate address and prefixLength. + */ + private static void check(InetAddress address, int prefixLength) { + if (address.isLoopbackAddress()) { + throw new IllegalArgumentException("Bad address"); + } + if (address instanceof Inet4Address) { + if (prefixLength < 0 || prefixLength > 32) { + throw new IllegalArgumentException("Bad prefixLength"); + } + } else if (address instanceof Inet6Address) { + if (prefixLength < 0 || prefixLength > 128) { + throw new IllegalArgumentException("Bad prefixLength"); + } + } else { + throw new IllegalArgumentException("Unsupported family"); + } + } + + /** + * Helper class to create a VPN interface. This class should be always + * used within the scope of the outer {@link VpnService}. + * + * @see VpnService + */ + public class Builder { + + private final VpnConfig mConfig = new VpnConfig(); + @UnsupportedAppUsage + private final List mAddresses = new ArrayList(); + @UnsupportedAppUsage + private final List mRoutes = new ArrayList(); + + public Builder() { + mConfig.user = VpnService.this.getClass().getName(); + } + + /** + * Set the name of this session. It will be displayed in + * system-managed dialogs and notifications. This is recommended + * not required. + */ + @NonNull + public Builder setSession(@NonNull String session) { + mConfig.session = session; + return this; + } + + /** + * Set the {@link PendingIntent} to an activity for users to + * configure the VPN connection. If it is not set, the button + * to configure will not be shown in system-managed dialogs. + */ + @NonNull + public Builder setConfigureIntent(@NonNull PendingIntent intent) { + mConfig.configureIntent = intent; + return this; + } + + /** + * Set the maximum transmission unit (MTU) of the VPN interface. If + * it is not set, the default value in the operating system will be + * used. + * + * @throws IllegalArgumentException if the value is not positive. + */ + @NonNull + public Builder setMtu(int mtu) { + if (mtu <= 0) { + throw new IllegalArgumentException("Bad mtu"); + } + mConfig.mtu = mtu; + return this; + } + + /** + * Sets an HTTP proxy for the VPN network. This proxy is only a recommendation + * and it is possible that some apps will ignore it. + */ + @NonNull + public Builder setHttpProxy(@NonNull ProxyInfo proxyInfo) { + mConfig.proxyInfo = proxyInfo; + return this; + } + + /** + * Add a network address to the VPN interface. Both IPv4 and IPv6 + * addresses are supported. At least one address must be set before + * calling {@link #establish}. + * + * Adding an address implicitly allows traffic from that address family + * (i.e., IPv4 or IPv6) to be routed over the VPN. @see #allowFamily + * + * @throws IllegalArgumentException if the address is invalid. + */ + @NonNull + public Builder addAddress(@NonNull InetAddress address, int prefixLength) { + check(address, prefixLength); + + if (address.isAnyLocalAddress()) { + throw new IllegalArgumentException("Bad address"); + } + mAddresses.add(new LinkAddress(address, prefixLength)); + mConfig.updateAllowedFamilies(address); + return this; + } + + /** + * Convenience method to add a network address to the VPN interface + * using a numeric address string. See {@link InetAddress} for the + * definitions of numeric address formats. + * + * Adding an address implicitly allows traffic from that address family + * (i.e., IPv4 or IPv6) to be routed over the VPN. @see #allowFamily + * + * @throws IllegalArgumentException if the address is invalid. + * @see #addAddress(InetAddress, int) + */ + @NonNull + public Builder addAddress(@NonNull String address, int prefixLength) { + return addAddress(InetAddress.parseNumericAddress(address), prefixLength); + } + + /** + * Add a network route to the VPN interface. Both IPv4 and IPv6 + * routes are supported. + * + * Adding a route implicitly allows traffic from that address family + * (i.e., IPv4 or IPv6) to be routed over the VPN. @see #allowFamily + * + * @throws IllegalArgumentException if the route is invalid. + */ + @NonNull + public Builder addRoute(@NonNull InetAddress address, int prefixLength) { + check(address, prefixLength); + + int offset = prefixLength / 8; + byte[] bytes = address.getAddress(); + if (offset < bytes.length) { + for (bytes[offset] <<= prefixLength % 8; offset < bytes.length; ++offset) { + if (bytes[offset] != 0) { + throw new IllegalArgumentException("Bad address"); + } + } + } + mRoutes.add(new RouteInfo(new IpPrefix(address, prefixLength), null)); + mConfig.updateAllowedFamilies(address); + return this; + } + + /** + * Convenience method to add a network route to the VPN interface + * using a numeric address string. See {@link InetAddress} for the + * definitions of numeric address formats. + * + * Adding a route implicitly allows traffic from that address family + * (i.e., IPv4 or IPv6) to be routed over the VPN. @see #allowFamily + * + * @throws IllegalArgumentException if the route is invalid. + * @see #addRoute(InetAddress, int) + */ + @NonNull + public Builder addRoute(@NonNull String address, int prefixLength) { + return addRoute(InetAddress.parseNumericAddress(address), prefixLength); + } + + /** + * Add a DNS server to the VPN connection. Both IPv4 and IPv6 + * addresses are supported. If none is set, the DNS servers of + * the default network will be used. + * + * Adding a server implicitly allows traffic from that address family + * (i.e., IPv4 or IPv6) to be routed over the VPN. @see #allowFamily + * + * @throws IllegalArgumentException if the address is invalid. + */ + @NonNull + public Builder addDnsServer(@NonNull InetAddress address) { + if (address.isLoopbackAddress() || address.isAnyLocalAddress()) { + throw new IllegalArgumentException("Bad address"); + } + if (mConfig.dnsServers == null) { + mConfig.dnsServers = new ArrayList(); + } + mConfig.dnsServers.add(address.getHostAddress()); + return this; + } + + /** + * Convenience method to add a DNS server to the VPN connection + * using a numeric address string. See {@link InetAddress} for the + * definitions of numeric address formats. + * + * Adding a server implicitly allows traffic from that address family + * (i.e., IPv4 or IPv6) to be routed over the VPN. @see #allowFamily + * + * @throws IllegalArgumentException if the address is invalid. + * @see #addDnsServer(InetAddress) + */ + @NonNull + public Builder addDnsServer(@NonNull String address) { + return addDnsServer(InetAddress.parseNumericAddress(address)); + } + + /** + * Add a search domain to the DNS resolver. + */ + @NonNull + public Builder addSearchDomain(@NonNull String domain) { + if (mConfig.searchDomains == null) { + mConfig.searchDomains = new ArrayList(); + } + mConfig.searchDomains.add(domain); + return this; + } + + /** + * Allows traffic from the specified address family. + * + * By default, if no address, route or DNS server of a specific family (IPv4 or IPv6) is + * added to this VPN, then all outgoing traffic of that family is blocked. If any address, + * route or DNS server is added, that family is allowed. + * + * This method allows an address family to be unblocked even without adding an address, + * route or DNS server of that family. Traffic of that family will then typically + * fall-through to the underlying network if it's supported. + * + * {@code family} must be either {@code AF_INET} (for IPv4) or {@code AF_INET6} (for IPv6). + * {@link IllegalArgumentException} is thrown if it's neither. + * + * @param family The address family ({@code AF_INET} or {@code AF_INET6}) to allow. + * + * @return this {@link Builder} object to facilitate chaining of method calls. + */ + @NonNull + public Builder allowFamily(int family) { + if (family == AF_INET) { + mConfig.allowIPv4 = true; + } else if (family == AF_INET6) { + mConfig.allowIPv6 = true; + } else { + throw new IllegalArgumentException(family + " is neither " + AF_INET + " nor " + + AF_INET6); + } + return this; + } + + private void verifyApp(String packageName) throws PackageManager.NameNotFoundException { + IPackageManager pm = IPackageManager.Stub.asInterface( + ServiceManager.getService("package")); + try { + pm.getApplicationInfo(packageName, 0, UserHandle.getCallingUserId()); + } catch (RemoteException e) { + throw new IllegalStateException(e); + } + } + + /** + * Adds an application that's allowed to access the VPN connection. + * + * If this method is called at least once, only applications added through this method (and + * no others) are allowed access. Else (if this method is never called), all applications + * are allowed by default. If some applications are added, other, un-added applications + * will use networking as if the VPN wasn't running. + * + * A {@link Builder} may have only a set of allowed applications OR a set of disallowed + * ones, but not both. Calling this method after {@link #addDisallowedApplication} has + * already been called, or vice versa, will throw an {@link UnsupportedOperationException}. + * + * {@code packageName} must be the canonical name of a currently installed application. + * {@link PackageManager.NameNotFoundException} is thrown if there's no such application. + * + * @throws PackageManager.NameNotFoundException If the application isn't installed. + * + * @param packageName The full name (e.g.: "com.google.apps.contacts") of an application. + * + * @return this {@link Builder} object to facilitate chaining method calls. + */ + @NonNull + public Builder addAllowedApplication(@NonNull String packageName) + throws PackageManager.NameNotFoundException { + if (mConfig.disallowedApplications != null) { + throw new UnsupportedOperationException("addDisallowedApplication already called"); + } + verifyApp(packageName); + if (mConfig.allowedApplications == null) { + mConfig.allowedApplications = new ArrayList(); + } + mConfig.allowedApplications.add(packageName); + return this; + } + + /** + * Adds an application that's denied access to the VPN connection. + * + * By default, all applications are allowed access, except for those denied through this + * method. Denied applications will use networking as if the VPN wasn't running. + * + * A {@link Builder} may have only a set of allowed applications OR a set of disallowed + * ones, but not both. Calling this method after {@link #addAllowedApplication} has already + * been called, or vice versa, will throw an {@link UnsupportedOperationException}. + * + * {@code packageName} must be the canonical name of a currently installed application. + * {@link PackageManager.NameNotFoundException} is thrown if there's no such application. + * + * @throws PackageManager.NameNotFoundException If the application isn't installed. + * + * @param packageName The full name (e.g.: "com.google.apps.contacts") of an application. + * + * @return this {@link Builder} object to facilitate chaining method calls. + */ + @NonNull + public Builder addDisallowedApplication(@NonNull String packageName) + throws PackageManager.NameNotFoundException { + if (mConfig.allowedApplications != null) { + throw new UnsupportedOperationException("addAllowedApplication already called"); + } + verifyApp(packageName); + if (mConfig.disallowedApplications == null) { + mConfig.disallowedApplications = new ArrayList(); + } + mConfig.disallowedApplications.add(packageName); + return this; + } + + /** + * Allows all apps to bypass this VPN connection. + * + * By default, all traffic from apps is forwarded through the VPN interface and it is not + * possible for apps to side-step the VPN. If this method is called, apps may use methods + * such as {@link ConnectivityManager#bindProcessToNetwork} to instead send/receive + * directly over the underlying network or any other network they have permissions for. + * + * @return this {@link Builder} object to facilitate chaining of method calls. + */ + @NonNull + public Builder allowBypass() { + mConfig.allowBypass = true; + return this; + } + + /** + * Sets the VPN interface's file descriptor to be in blocking/non-blocking mode. + * + * By default, the file descriptor returned by {@link #establish} is non-blocking. + * + * @param blocking True to put the descriptor into blocking mode; false for non-blocking. + * + * @return this {@link Builder} object to facilitate chaining method calls. + */ + @NonNull + public Builder setBlocking(boolean blocking) { + mConfig.blocking = blocking; + return this; + } + + /** + * Sets the underlying networks used by the VPN for its upstream connections. + * + * @see VpnService#setUnderlyingNetworks + * + * @param networks An array of networks the VPN uses to tunnel traffic to/from its servers. + * + * @return this {@link Builder} object to facilitate chaining method calls. + */ + @NonNull + public Builder setUnderlyingNetworks(@Nullable Network[] networks) { + mConfig.underlyingNetworks = networks != null ? networks.clone() : null; + return this; + } + + /** + * Marks the VPN network as metered. A VPN network is classified as metered when the user is + * sensitive to heavy data usage due to monetary costs and/or data limitations. In such + * cases, you should set this to {@code true} so that apps on the system can avoid doing + * large data transfers. Otherwise, set this to {@code false}. Doing so would cause VPN + * network to inherit its meteredness from its underlying networks. + * + *

VPN apps targeting {@link android.os.Build.VERSION_CODES#Q} or above will be + * considered metered by default. + * + * @param isMetered {@code true} if VPN network should be treated as metered regardless of + * underlying network meteredness + * @return this {@link Builder} object to facilitate chaining method calls + * @see #setUnderlyingNetworks(Network[]) + * @see ConnectivityManager#isActiveNetworkMetered() + */ + @NonNull + public Builder setMetered(boolean isMetered) { + mConfig.isMetered = isMetered; + return this; + } + + /** + * Create a VPN interface using the parameters supplied to this + * builder. The interface works on IP packets, and a file descriptor + * is returned for the application to access them. Each read + * retrieves an outgoing packet which was routed to the interface. + * Each write injects an incoming packet just like it was received + * from the interface. The file descriptor is put into non-blocking + * mode by default to avoid blocking Java threads. To use the file + * descriptor completely in native space, see + * {@link ParcelFileDescriptor#detachFd()}. The application MUST + * close the file descriptor when the VPN connection is terminated. + * The VPN interface will be removed and the network will be + * restored by the system automatically. + * + *

To avoid conflicts, there can be only one active VPN interface + * at the same time. Usually network parameters are never changed + * during the lifetime of a VPN connection. It is also common for an + * application to create a new file descriptor after closing the + * previous one. However, it is rare but not impossible to have two + * interfaces while performing a seamless handover. In this case, the + * old interface will be deactivated when the new one is created + * successfully. Both file descriptors are valid but now outgoing + * packets will be routed to the new interface. Therefore, after + * draining the old file descriptor, the application MUST close it + * and start using the new file descriptor. If the new interface + * cannot be created, the existing interface and its file descriptor + * remain untouched. + * + *

An exception will be thrown if the interface cannot be created + * for any reason. However, this method returns {@code null} if the + * application is not prepared or is revoked. This helps solve + * possible race conditions between other VPN applications. + * + * @return {@link ParcelFileDescriptor} of the VPN interface, or + * {@code null} if the application is not prepared. + * @throws IllegalArgumentException if a parameter is not accepted + * by the operating system. + * @throws IllegalStateException if a parameter cannot be applied + * by the operating system. + * @throws SecurityException if the service is not properly declared + * in {@code AndroidManifest.xml}. + * @see VpnService + */ + @Nullable + public ParcelFileDescriptor establish() { + mConfig.addresses = mAddresses; + mConfig.routes = mRoutes; + + try { + return getService().establishVpn(mConfig); + } catch (RemoteException e) { + throw new IllegalStateException(e); + } + } + } +} diff --git a/packages/Connectivity/framework/src/android/net/apf/ApfCapabilities.aidl b/packages/Connectivity/framework/src/android/net/apf/ApfCapabilities.aidl new file mode 100644 index 000000000000..7c4d4c2da4bc --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/apf/ApfCapabilities.aidl @@ -0,0 +1,20 @@ +/* +** +** Copyright (C) 2019 The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +package android.net.apf; + +@JavaOnlyStableParcelable parcelable ApfCapabilities; \ No newline at end of file diff --git a/packages/Connectivity/framework/src/android/net/apf/ApfCapabilities.java b/packages/Connectivity/framework/src/android/net/apf/ApfCapabilities.java new file mode 100644 index 000000000000..bf5b26e278f9 --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/apf/ApfCapabilities.java @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.apf; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.content.res.Resources; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.R; + +/** + * APF program support capabilities. APF stands for Android Packet Filtering and it is a flexible + * way to drop unwanted network packets to save power. + * + * See documentation at hardware/google/apf/apf.h + * + * This class is immutable. + * @hide + */ +@SystemApi +public final class ApfCapabilities implements Parcelable { + /** + * Version of APF instruction set supported for packet filtering. 0 indicates no support for + * packet filtering using APF programs. + */ + public final int apfVersionSupported; + + /** + * Maximum size of APF program allowed. + */ + public final int maximumApfProgramSize; + + /** + * Format of packets passed to APF filter. Should be one of ARPHRD_* + */ + public final int apfPacketFormat; + + public ApfCapabilities( + int apfVersionSupported, int maximumApfProgramSize, int apfPacketFormat) { + this.apfVersionSupported = apfVersionSupported; + this.maximumApfProgramSize = maximumApfProgramSize; + this.apfPacketFormat = apfPacketFormat; + } + + private ApfCapabilities(Parcel in) { + apfVersionSupported = in.readInt(); + maximumApfProgramSize = in.readInt(); + apfPacketFormat = in.readInt(); + } + + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(apfVersionSupported); + dest.writeInt(maximumApfProgramSize); + dest.writeInt(apfPacketFormat); + } + + public static final Creator CREATOR = new Creator() { + @Override + public ApfCapabilities createFromParcel(Parcel in) { + return new ApfCapabilities(in); + } + + @Override + public ApfCapabilities[] newArray(int size) { + return new ApfCapabilities[size]; + } + }; + + @NonNull + @Override + public String toString() { + return String.format("%s{version: %d, maxSize: %d, format: %d}", getClass().getSimpleName(), + apfVersionSupported, maximumApfProgramSize, apfPacketFormat); + } + + @Override + public boolean equals(@Nullable Object obj) { + if (!(obj instanceof ApfCapabilities)) return false; + final ApfCapabilities other = (ApfCapabilities) obj; + return apfVersionSupported == other.apfVersionSupported + && maximumApfProgramSize == other.maximumApfProgramSize + && apfPacketFormat == other.apfPacketFormat; + } + + /** + * Determines whether the APF interpreter advertises support for the data buffer access opcodes + * LDDW (LoaD Data Word) and STDW (STore Data Word). Full LDDW (LoaD Data Word) and + * STDW (STore Data Word) support is present from APFv4 on. + * + * @return {@code true} if the IWifiStaIface#readApfPacketFilterData is supported. + */ + public boolean hasDataAccess() { + return apfVersionSupported >= 4; + } + + /** + * @return Whether the APF Filter in the device should filter out IEEE 802.3 Frames. + */ + public static boolean getApfDrop8023Frames() { + return Resources.getSystem().getBoolean(R.bool.config_apfDrop802_3Frames); + } + + /** + * @return An array of denylisted EtherType, packets with EtherTypes within it will be dropped. + */ + public static @NonNull int[] getApfEtherTypeBlackList() { + return Resources.getSystem().getIntArray(R.array.config_apfEthTypeBlackList); + } +} diff --git a/packages/Connectivity/framework/src/android/net/util/DnsUtils.java b/packages/Connectivity/framework/src/android/net/util/DnsUtils.java new file mode 100644 index 000000000000..7908353eeda2 --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/util/DnsUtils.java @@ -0,0 +1,379 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.util; + +import static android.system.OsConstants.AF_INET; +import static android.system.OsConstants.AF_INET6; +import static android.system.OsConstants.IPPROTO_UDP; +import static android.system.OsConstants.SOCK_DGRAM; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.InetAddresses; +import android.net.Network; +import android.system.ErrnoException; +import android.system.Os; +import android.util.Log; + +import com.android.internal.util.BitUtils; + +import libcore.io.IoUtils; + +import java.io.FileDescriptor; +import java.io.IOException; +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +/** + * @hide + */ +public class DnsUtils { + private static final String TAG = "DnsUtils"; + private static final int CHAR_BIT = 8; + public static final int IPV6_ADDR_SCOPE_NODELOCAL = 0x01; + public static final int IPV6_ADDR_SCOPE_LINKLOCAL = 0x02; + public static final int IPV6_ADDR_SCOPE_SITELOCAL = 0x05; + public static final int IPV6_ADDR_SCOPE_GLOBAL = 0x0e; + private static final Comparator sRfc6724Comparator = new Rfc6724Comparator(); + + /** + * Comparator to sort SortableAddress in Rfc6724 style. + */ + public static class Rfc6724Comparator implements Comparator { + // This function matches the behaviour of _rfc6724_compare in the native resolver. + @Override + public int compare(SortableAddress span1, SortableAddress span2) { + // Rule 1: Avoid unusable destinations. + if (span1.hasSrcAddr != span2.hasSrcAddr) { + return span2.hasSrcAddr - span1.hasSrcAddr; + } + + // Rule 2: Prefer matching scope. + if (span1.scopeMatch != span2.scopeMatch) { + return span2.scopeMatch - span1.scopeMatch; + } + + // TODO: Implement rule 3: Avoid deprecated addresses. + // TODO: Implement rule 4: Prefer home addresses. + + // Rule 5: Prefer matching label. + if (span1.labelMatch != span2.labelMatch) { + return span2.labelMatch - span1.labelMatch; + } + + // Rule 6: Prefer higher precedence. + if (span1.precedence != span2.precedence) { + return span2.precedence - span1.precedence; + } + + // TODO: Implement rule 7: Prefer native transport. + + // Rule 8: Prefer smaller scope. + if (span1.scope != span2.scope) { + return span1.scope - span2.scope; + } + + // Rule 9: Use longest matching prefix. IPv6 only. + if (span1.prefixMatchLen != span2.prefixMatchLen) { + return span2.prefixMatchLen - span1.prefixMatchLen; + } + + // Rule 10: Leave the order unchanged. Collections.sort is a stable sort. + return 0; + } + } + + /** + * Class used to sort with RFC 6724 + */ + public static class SortableAddress { + public final int label; + public final int labelMatch; + public final int scope; + public final int scopeMatch; + public final int precedence; + public final int prefixMatchLen; + public final int hasSrcAddr; + public final InetAddress address; + + public SortableAddress(@NonNull InetAddress addr, @Nullable InetAddress srcAddr) { + address = addr; + hasSrcAddr = (srcAddr != null) ? 1 : 0; + label = findLabel(addr); + scope = findScope(addr); + precedence = findPrecedence(addr); + labelMatch = ((srcAddr != null) && (label == findLabel(srcAddr))) ? 1 : 0; + scopeMatch = ((srcAddr != null) && (scope == findScope(srcAddr))) ? 1 : 0; + if (isIpv6Address(addr) && isIpv6Address(srcAddr)) { + prefixMatchLen = compareIpv6PrefixMatchLen(srcAddr, addr); + } else { + prefixMatchLen = 0; + } + } + } + + /** + * Sort the given address list in RFC6724 order. + * Will leave the list unchanged if an error occurs. + * + * This function matches the behaviour of _rfc6724_sort in the native resolver. + */ + public static @NonNull List rfc6724Sort(@Nullable Network network, + @NonNull List answers) { + final ArrayList sortableAnswerList = new ArrayList<>(); + for (InetAddress addr : answers) { + sortableAnswerList.add(new SortableAddress(addr, findSrcAddress(network, addr))); + } + + Collections.sort(sortableAnswerList, sRfc6724Comparator); + + final List sortedAnswers = new ArrayList<>(); + for (SortableAddress ans : sortableAnswerList) { + sortedAnswers.add(ans.address); + } + + return sortedAnswers; + } + + private static @Nullable InetAddress findSrcAddress(@Nullable Network network, + @NonNull InetAddress addr) { + final int domain; + if (isIpv4Address(addr)) { + domain = AF_INET; + } else if (isIpv6Address(addr)) { + domain = AF_INET6; + } else { + return null; + } + final FileDescriptor socket; + try { + socket = Os.socket(domain, SOCK_DGRAM, IPPROTO_UDP); + } catch (ErrnoException e) { + Log.e(TAG, "findSrcAddress:" + e.toString()); + return null; + } + try { + if (network != null) network.bindSocket(socket); + Os.connect(socket, new InetSocketAddress(addr, 0)); + return ((InetSocketAddress) Os.getsockname(socket)).getAddress(); + } catch (IOException | ErrnoException e) { + return null; + } finally { + IoUtils.closeQuietly(socket); + } + } + + /** + * Get the label for a given IPv4/IPv6 address. + * RFC 6724, section 2.1. + * + * Note that Java will return an IPv4-mapped address as an IPv4 address. + */ + private static int findLabel(@NonNull InetAddress addr) { + if (isIpv4Address(addr)) { + return 4; + } else if (isIpv6Address(addr)) { + if (addr.isLoopbackAddress()) { + return 0; + } else if (isIpv6Address6To4(addr)) { + return 2; + } else if (isIpv6AddressTeredo(addr)) { + return 5; + } else if (isIpv6AddressULA(addr)) { + return 13; + } else if (((Inet6Address) addr).isIPv4CompatibleAddress()) { + return 3; + } else if (addr.isSiteLocalAddress()) { + return 11; + } else if (isIpv6Address6Bone(addr)) { + return 12; + } else { + // All other IPv6 addresses, including global unicast addresses. + return 1; + } + } else { + // This should never happen. + return 1; + } + } + + private static boolean isIpv6Address(@Nullable InetAddress addr) { + return addr instanceof Inet6Address; + } + + private static boolean isIpv4Address(@Nullable InetAddress addr) { + return addr instanceof Inet4Address; + } + + private static boolean isIpv6Address6To4(@NonNull InetAddress addr) { + if (!isIpv6Address(addr)) return false; + final byte[] byteAddr = addr.getAddress(); + return byteAddr[0] == 0x20 && byteAddr[1] == 0x02; + } + + private static boolean isIpv6AddressTeredo(@NonNull InetAddress addr) { + if (!isIpv6Address(addr)) return false; + final byte[] byteAddr = addr.getAddress(); + return byteAddr[0] == 0x20 && byteAddr[1] == 0x01 && byteAddr[2] == 0x00 + && byteAddr[3] == 0x00; + } + + private static boolean isIpv6AddressULA(@NonNull InetAddress addr) { + return isIpv6Address(addr) && (addr.getAddress()[0] & 0xfe) == 0xfc; + } + + private static boolean isIpv6Address6Bone(@NonNull InetAddress addr) { + if (!isIpv6Address(addr)) return false; + final byte[] byteAddr = addr.getAddress(); + return byteAddr[0] == 0x3f && byteAddr[1] == (byte) 0xfe; + } + + private static int getIpv6MulticastScope(@NonNull InetAddress addr) { + return !isIpv6Address(addr) ? 0 : (addr.getAddress()[1] & 0x0f); + } + + private static int findScope(@NonNull InetAddress addr) { + if (isIpv6Address(addr)) { + if (addr.isMulticastAddress()) { + return getIpv6MulticastScope(addr); + } else if (addr.isLoopbackAddress() || addr.isLinkLocalAddress()) { + /** + * RFC 4291 section 2.5.3 says loopback is to be treated as having + * link-local scope. + */ + return IPV6_ADDR_SCOPE_LINKLOCAL; + } else if (addr.isSiteLocalAddress()) { + return IPV6_ADDR_SCOPE_SITELOCAL; + } else { + return IPV6_ADDR_SCOPE_GLOBAL; + } + } else if (isIpv4Address(addr)) { + if (addr.isLoopbackAddress() || addr.isLinkLocalAddress()) { + return IPV6_ADDR_SCOPE_LINKLOCAL; + } else { + /** + * RFC 6724 section 3.2. Other IPv4 addresses, including private addresses + * and shared addresses (100.64.0.0/10), are assigned global scope. + */ + return IPV6_ADDR_SCOPE_GLOBAL; + } + } else { + /** + * This should never happen. + * Return a scope with low priority as a last resort. + */ + return IPV6_ADDR_SCOPE_NODELOCAL; + } + } + + /** + * Get the precedence for a given IPv4/IPv6 address. + * RFC 6724, section 2.1. + * + * Note that Java will return an IPv4-mapped address as an IPv4 address. + */ + private static int findPrecedence(@NonNull InetAddress addr) { + if (isIpv4Address(addr)) { + return 35; + } else if (isIpv6Address(addr)) { + if (addr.isLoopbackAddress()) { + return 50; + } else if (isIpv6Address6To4(addr)) { + return 30; + } else if (isIpv6AddressTeredo(addr)) { + return 5; + } else if (isIpv6AddressULA(addr)) { + return 3; + } else if (((Inet6Address) addr).isIPv4CompatibleAddress() || addr.isSiteLocalAddress() + || isIpv6Address6Bone(addr)) { + return 1; + } else { + // All other IPv6 addresses, including global unicast addresses. + return 40; + } + } else { + return 1; + } + } + + /** + * Find number of matching initial bits between the two addresses. + */ + private static int compareIpv6PrefixMatchLen(@NonNull InetAddress srcAddr, + @NonNull InetAddress dstAddr) { + final byte[] srcByte = srcAddr.getAddress(); + final byte[] dstByte = dstAddr.getAddress(); + + // This should never happen. + if (srcByte.length != dstByte.length) return 0; + + for (int i = 0; i < dstByte.length; ++i) { + if (srcByte[i] == dstByte[i]) { + continue; + } + int x = BitUtils.uint8(srcByte[i]) ^ BitUtils.uint8(dstByte[i]); + return i * CHAR_BIT + (Integer.numberOfLeadingZeros(x) - 24); // Java ints are 32 bits + } + return dstByte.length * CHAR_BIT; + } + + /** + * Check if given network has Ipv4 capability + * This function matches the behaviour of have_ipv4 in the native resolver. + */ + public static boolean haveIpv4(@Nullable Network network) { + final SocketAddress addrIpv4 = + new InetSocketAddress(InetAddresses.parseNumericAddress("8.8.8.8"), 0); + return checkConnectivity(network, AF_INET, addrIpv4); + } + + /** + * Check if given network has Ipv6 capability + * This function matches the behaviour of have_ipv6 in the native resolver. + */ + public static boolean haveIpv6(@Nullable Network network) { + final SocketAddress addrIpv6 = + new InetSocketAddress(InetAddresses.parseNumericAddress("2000::"), 0); + return checkConnectivity(network, AF_INET6, addrIpv6); + } + + private static boolean checkConnectivity(@Nullable Network network, + int domain, @NonNull SocketAddress addr) { + final FileDescriptor socket; + try { + socket = Os.socket(domain, SOCK_DGRAM, IPPROTO_UDP); + } catch (ErrnoException e) { + return false; + } + try { + if (network != null) network.bindSocket(socket); + Os.connect(socket, addr); + } catch (IOException | ErrnoException e) { + return false; + } finally { + IoUtils.closeQuietly(socket); + } + return true; + } +} diff --git a/packages/Connectivity/framework/src/android/net/util/KeepaliveUtils.java b/packages/Connectivity/framework/src/android/net/util/KeepaliveUtils.java new file mode 100644 index 000000000000..bfc4563fbf8f --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/util/KeepaliveUtils.java @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.util; + +import android.annotation.NonNull; +import android.content.Context; +import android.content.res.Resources; +import android.net.NetworkCapabilities; +import android.text.TextUtils; +import android.util.AndroidRuntimeException; + +import com.android.internal.R; + +/** + * Collection of utilities for socket keepalive offload. + * + * @hide + */ +public final class KeepaliveUtils { + + public static final String TAG = "KeepaliveUtils"; + + public static class KeepaliveDeviceConfigurationException extends AndroidRuntimeException { + public KeepaliveDeviceConfigurationException(final String msg) { + super(msg); + } + } + + /** + * Read supported keepalive count for each transport type from overlay resource. This should be + * used to create a local variable store of resource customization, and use it as the input for + * {@link getSupportedKeepalivesForNetworkCapabilities}. + * + * @param context The context to read resource from. + * @return An array of supported keepalive count for each transport type. + */ + @NonNull + public static int[] getSupportedKeepalives(@NonNull Context context) { + String[] res = null; + try { + res = context.getResources().getStringArray( + R.array.config_networkSupportedKeepaliveCount); + } catch (Resources.NotFoundException unused) { + } + if (res == null) throw new KeepaliveDeviceConfigurationException("invalid resource"); + + final int[] ret = new int[NetworkCapabilities.MAX_TRANSPORT + 1]; + for (final String row : res) { + if (TextUtils.isEmpty(row)) { + throw new KeepaliveDeviceConfigurationException("Empty string"); + } + final String[] arr = row.split(","); + if (arr.length != 2) { + throw new KeepaliveDeviceConfigurationException("Invalid parameter length"); + } + + int transport; + int supported; + try { + transport = Integer.parseInt(arr[0]); + supported = Integer.parseInt(arr[1]); + } catch (NumberFormatException e) { + throw new KeepaliveDeviceConfigurationException("Invalid number format"); + } + + if (!NetworkCapabilities.isValidTransport(transport)) { + throw new KeepaliveDeviceConfigurationException("Invalid transport " + transport); + } + + if (supported < 0) { + throw new KeepaliveDeviceConfigurationException( + "Invalid supported count " + supported + " for " + + NetworkCapabilities.transportNameOf(transport)); + } + ret[transport] = supported; + } + return ret; + } + + /** + * Get supported keepalive count for the given {@link NetworkCapabilities}. + * + * @param supportedKeepalives An array of supported keepalive count for each transport type. + * @param nc The {@link NetworkCapabilities} of the network the socket keepalive is on. + * + * @return Supported keepalive count for the given {@link NetworkCapabilities}. + */ + public static int getSupportedKeepalivesForNetworkCapabilities( + @NonNull int[] supportedKeepalives, @NonNull NetworkCapabilities nc) { + final int[] transports = nc.getTransportTypes(); + if (transports.length == 0) return 0; + int supportedCount = supportedKeepalives[transports[0]]; + // Iterate through transports and return minimum supported value. + for (final int transport : transports) { + if (supportedCount > supportedKeepalives[transport]) { + supportedCount = supportedKeepalives[transport]; + } + } + return supportedCount; + } +} diff --git a/packages/Connectivity/framework/src/android/net/util/MultinetworkPolicyTracker.java b/packages/Connectivity/framework/src/android/net/util/MultinetworkPolicyTracker.java new file mode 100644 index 000000000000..85e3fa3048ed --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/util/MultinetworkPolicyTracker.java @@ -0,0 +1,217 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.util; + +import static android.provider.Settings.Global.NETWORK_AVOID_BAD_WIFI; +import static android.provider.Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE; + +import android.annotation.NonNull; +import android.content.BroadcastReceiver; +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.res.Resources; +import android.database.ContentObserver; +import android.net.Uri; +import android.os.Handler; +import android.provider.Settings; +import android.telephony.PhoneStateListener; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; +import android.util.Log; + +import com.android.internal.R; +import com.android.internal.annotations.VisibleForTesting; + +import java.util.Arrays; +import java.util.List; + +/** + * A class to encapsulate management of the "Smart Networking" capability of + * avoiding bad Wi-Fi when, for example upstream connectivity is lost or + * certain critical link failures occur. + * + * This enables the device to switch to another form of connectivity, like + * mobile, if it's available and working. + * + * The Runnable |avoidBadWifiCallback|, if given, is posted to the supplied + * Handler' whenever the computed "avoid bad wifi" value changes. + * + * Disabling this reverts the device to a level of networking sophistication + * circa 2012-13 by disabling disparate code paths each of which contribute to + * maintaining continuous, working Internet connectivity. + * + * @hide + */ +public class MultinetworkPolicyTracker { + private static String TAG = MultinetworkPolicyTracker.class.getSimpleName(); + + private final Context mContext; + private final Handler mHandler; + private final Runnable mAvoidBadWifiCallback; + private final List mSettingsUris; + private final ContentResolver mResolver; + private final SettingObserver mSettingObserver; + private final BroadcastReceiver mBroadcastReceiver; + + private volatile boolean mAvoidBadWifi = true; + private volatile int mMeteredMultipathPreference; + private int mActiveSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; + + public MultinetworkPolicyTracker(Context ctx, Handler handler) { + this(ctx, handler, null); + } + + public MultinetworkPolicyTracker(Context ctx, Handler handler, Runnable avoidBadWifiCallback) { + mContext = ctx; + mHandler = handler; + mAvoidBadWifiCallback = avoidBadWifiCallback; + mSettingsUris = Arrays.asList( + Settings.Global.getUriFor(NETWORK_AVOID_BAD_WIFI), + Settings.Global.getUriFor(NETWORK_METERED_MULTIPATH_PREFERENCE)); + mResolver = mContext.getContentResolver(); + mSettingObserver = new SettingObserver(); + mBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + reevaluateInternal(); + } + }; + + ctx.getSystemService(TelephonyManager.class).listen( + new PhoneStateListener(handler.getLooper()) { + @Override + public void onActiveDataSubscriptionIdChanged(int subId) { + mActiveSubId = subId; + reevaluateInternal(); + } + }, PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE); + + updateAvoidBadWifi(); + updateMeteredMultipathPreference(); + } + + public void start() { + for (Uri uri : mSettingsUris) { + mResolver.registerContentObserver(uri, false, mSettingObserver); + } + + final IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); + mContext.registerReceiverForAllUsers(mBroadcastReceiver, intentFilter, + null /* broadcastPermission */, mHandler); + + reevaluate(); + } + + public void shutdown() { + mResolver.unregisterContentObserver(mSettingObserver); + + mContext.unregisterReceiver(mBroadcastReceiver); + } + + public boolean getAvoidBadWifi() { + return mAvoidBadWifi; + } + + // TODO: move this to MultipathPolicyTracker. + public int getMeteredMultipathPreference() { + return mMeteredMultipathPreference; + } + + /** + * Whether the device or carrier configuration disables avoiding bad wifi by default. + */ + public boolean configRestrictsAvoidBadWifi() { + return (getResourcesForActiveSubId().getInteger(R.integer.config_networkAvoidBadWifi) == 0); + } + + @NonNull + private Resources getResourcesForActiveSubId() { + return SubscriptionManager.getResourcesForSubId(mContext, mActiveSubId); + } + + /** + * Whether we should display a notification when wifi becomes unvalidated. + */ + public boolean shouldNotifyWifiUnvalidated() { + return configRestrictsAvoidBadWifi() && getAvoidBadWifiSetting() == null; + } + + public String getAvoidBadWifiSetting() { + return Settings.Global.getString(mResolver, NETWORK_AVOID_BAD_WIFI); + } + + @VisibleForTesting + public void reevaluate() { + mHandler.post(this::reevaluateInternal); + } + + /** + * Reevaluate the settings. Must be called on the handler thread. + */ + private void reevaluateInternal() { + if (updateAvoidBadWifi() && mAvoidBadWifiCallback != null) { + mAvoidBadWifiCallback.run(); + } + updateMeteredMultipathPreference(); + } + + public boolean updateAvoidBadWifi() { + final boolean settingAvoidBadWifi = "1".equals(getAvoidBadWifiSetting()); + final boolean prev = mAvoidBadWifi; + mAvoidBadWifi = settingAvoidBadWifi || !configRestrictsAvoidBadWifi(); + return mAvoidBadWifi != prev; + } + + /** + * The default (device and carrier-dependent) value for metered multipath preference. + */ + public int configMeteredMultipathPreference() { + return mContext.getResources().getInteger( + R.integer.config_networkMeteredMultipathPreference); + } + + public void updateMeteredMultipathPreference() { + String setting = Settings.Global.getString(mResolver, NETWORK_METERED_MULTIPATH_PREFERENCE); + try { + mMeteredMultipathPreference = Integer.parseInt(setting); + } catch (NumberFormatException e) { + mMeteredMultipathPreference = configMeteredMultipathPreference(); + } + } + + private class SettingObserver extends ContentObserver { + public SettingObserver() { + super(null); + } + + @Override + public void onChange(boolean selfChange) { + Log.wtf(TAG, "Should never be reached."); + } + + @Override + public void onChange(boolean selfChange, Uri uri) { + if (!mSettingsUris.contains(uri)) { + Log.wtf(TAG, "Unexpected settings observation: " + uri); + } + reevaluate(); + } + } +} diff --git a/packages/Connectivity/framework/src/android/net/util/SocketUtils.java b/packages/Connectivity/framework/src/android/net/util/SocketUtils.java new file mode 100644 index 000000000000..e64060f1b220 --- /dev/null +++ b/packages/Connectivity/framework/src/android/net/util/SocketUtils.java @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.util; + +import static android.system.OsConstants.SOL_SOCKET; +import static android.system.OsConstants.SO_BINDTODEVICE; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.net.NetworkUtils; +import android.system.ErrnoException; +import android.system.NetlinkSocketAddress; +import android.system.Os; +import android.system.PacketSocketAddress; + +import libcore.io.IoBridge; + +import java.io.FileDescriptor; +import java.io.IOException; +import java.net.SocketAddress; + +/** + * Collection of utilities to interact with raw sockets. + * @hide + */ +@SystemApi +public final class SocketUtils { + /** + * Create a raw datagram socket that is bound to an interface. + * + *

Data sent through the socket will go directly to the underlying network, ignoring VPNs. + */ + public static void bindSocketToInterface(@NonNull FileDescriptor socket, @NonNull String iface) + throws ErrnoException { + // SO_BINDTODEVICE actually takes a string. This works because the first member + // of struct ifreq is a NULL-terminated interface name. + // TODO: add a setsockoptString() + Os.setsockoptIfreq(socket, SOL_SOCKET, SO_BINDTODEVICE, iface); + NetworkUtils.protectFromVpn(socket); + } + + /** + * Make a socket address to communicate with netlink. + */ + @NonNull + public static SocketAddress makeNetlinkSocketAddress(int portId, int groupsMask) { + return new NetlinkSocketAddress(portId, groupsMask); + } + + /** + * Make socket address that packet sockets can bind to. + * + * @param protocol the layer 2 protocol of the packets to receive. One of the {@code ETH_P_*} + * constants in {@link android.system.OsConstants}. + * @param ifIndex the interface index on which packets will be received. + */ + @NonNull + public static SocketAddress makePacketSocketAddress(int protocol, int ifIndex) { + return new PacketSocketAddress( + protocol /* sll_protocol */, + ifIndex /* sll_ifindex */, + null /* sll_addr */); + } + + /** + * Make a socket address that packet socket can send packets to. + * @deprecated Use {@link #makePacketSocketAddress(int, int, byte[])} instead. + * + * @param ifIndex the interface index on which packets will be sent. + * @param hwAddr the hardware address to which packets will be sent. + */ + @Deprecated + @NonNull + public static SocketAddress makePacketSocketAddress(int ifIndex, @NonNull byte[] hwAddr) { + return new PacketSocketAddress( + 0 /* sll_protocol */, + ifIndex /* sll_ifindex */, + hwAddr /* sll_addr */); + } + + /** + * Make a socket address that a packet socket can send packets to. + * + * @param protocol the layer 2 protocol of the packets to send. One of the {@code ETH_P_*} + * constants in {@link android.system.OsConstants}. + * @param ifIndex the interface index on which packets will be sent. + * @param hwAddr the hardware address to which packets will be sent. + */ + @NonNull + public static SocketAddress makePacketSocketAddress(int protocol, int ifIndex, + @NonNull byte[] hwAddr) { + return new PacketSocketAddress( + protocol /* sll_protocol */, + ifIndex /* sll_ifindex */, + hwAddr /* sll_addr */); + } + + /** + * @see IoBridge#closeAndSignalBlockedThreads(FileDescriptor) + */ + public static void closeSocket(@Nullable FileDescriptor fd) throws IOException { + IoBridge.closeAndSignalBlockedThreads(fd); + } + + private SocketUtils() {} +} -- cgit v1.2.3-59-g8ed1b