Support LocalNetworkAgent for Tethering
The feature will be gradually enabled via flag rollout. Sample ip rule output: 0: from all lookup local 10000: from all fwmark 0xc0000/0xd0000 lookup legacy_system 11000: from all iif lo oif dummy0 uidrange 0-0 lookup dummy0 11000: from all iif lo oif rmnet1 uidrange 0-0 lookup rmnet1 11000: from all iif lo oif wlan0 uidrange 0-0 lookup wlan0 16000: from all fwmark 0x10063/0x1ffff iif lo lookup local_network 16000: from all fwmark 0x10064/0x1ffff iif lo lookup rmnet1 16000: from all fwmark 0x10066/0x1ffff iif lo lookup wlan0 16000: from all fwmark 0x10063/0x1ffff iif lo lookup wlan0 17000: from all iif lo oif dummy0 lookup dummy0 17000: from all iif lo oif rmnet1 lookup rmnet1 17000: from all iif lo oif wlan0 lookup wlan0 18000: from all fwmark 0x0/0x10000 lookup legacy_system 19000: from all fwmark 0x0/0x10000 lookup legacy_network 20000: from all fwmark 0x0/0x10000 lookup local_network 20000: from all fwmark 0x0/0x10000 lookup wlan0 21000: from all iif wlan0 lookup rmnet1 23000: from all fwmark 0x64/0x1ffff iif lo lookup rmnet1 23000: from all fwmark 0x66/0x1ffff iif lo lookup wlan0 31000: from all fwmark 0x0/0xffff iif lo lookup rmnet1 32000: from all unreachable Test: adb shell device_config put tethering tethering_local_network_agent 1 Test: atest TetheringTests:android.net.ip.IpServerTest TetheringManagerTest Bug: 349487600 Change-Id: Iaa88dde645da917149fec0d44fff796c551bcc7e
This commit is contained in:
parent
f3ae766e8e
commit
d55bd89bd6
5 changed files with 206 additions and 18 deletions
|
|
@ -31,6 +31,7 @@ import static android.net.TetheringManager.TETHER_ERROR_ENABLE_FORWARDING_ERROR;
|
|||
import static android.net.TetheringManager.TETHER_ERROR_IFACE_CFG_ERROR;
|
||||
import static android.net.TetheringManager.TETHER_ERROR_INTERNAL_ERROR;
|
||||
import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR;
|
||||
import static android.net.TetheringManager.TETHER_ERROR_SERVICE_UNAVAIL;
|
||||
import static android.net.TetheringManager.TETHER_ERROR_TETHER_IFACE_ERROR;
|
||||
import static android.net.TetheringManager.TETHER_ERROR_UNTETHER_IFACE_ERROR;
|
||||
import static android.net.TetheringManager.TetheringRequest.checkStaticAddressConfiguration;
|
||||
|
|
@ -40,19 +41,25 @@ import static android.system.OsConstants.RT_SCOPE_UNIVERSE;
|
|||
|
||||
import static com.android.net.module.util.Inet4AddressUtils.intToInet4AddressHTH;
|
||||
import static com.android.net.module.util.NetworkStackConstants.RFC7421_PREFIX_LENGTH;
|
||||
import static com.android.networkstack.tethering.TetheringConfiguration.TETHERING_LOCAL_NETWORK_AGENT;
|
||||
import static com.android.networkstack.tethering.TetheringConfiguration.USE_SYNC_SM;
|
||||
import static com.android.networkstack.tethering.util.PrefixUtils.asIpPrefix;
|
||||
import static com.android.networkstack.tethering.util.TetheringMessageBase.BASE_IPSERVER;
|
||||
import static com.android.networkstack.tethering.util.TetheringUtils.getTransportTypeForTetherableType;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.net.INetd;
|
||||
import android.net.INetworkStackStatusCallback;
|
||||
import android.net.IpPrefix;
|
||||
import android.net.LinkAddress;
|
||||
import android.net.LinkProperties;
|
||||
import android.net.MacAddress;
|
||||
import android.net.NetworkAgent;
|
||||
import android.net.RouteInfo;
|
||||
import android.net.TetheredClient;
|
||||
import android.net.TetheringManager.TetheringRequest;
|
||||
import android.net.connectivity.ConnectivityInternalApiUtil;
|
||||
import android.net.dhcp.DhcpLeaseParcelable;
|
||||
import android.net.dhcp.DhcpServerCallbacks;
|
||||
import android.net.dhcp.DhcpServingParamsParcel;
|
||||
|
|
@ -60,7 +67,9 @@ import android.net.dhcp.DhcpServingParamsParcelExt;
|
|||
import android.net.dhcp.IDhcpEventCallbacks;
|
||||
import android.net.dhcp.IDhcpServer;
|
||||
import android.net.ip.RouterAdvertisementDaemon.RaParams;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceSpecificException;
|
||||
|
|
@ -70,11 +79,13 @@ import android.util.SparseArray;
|
|||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.util.MessageUtils;
|
||||
import com.android.internal.util.State;
|
||||
import com.android.modules.utils.build.SdkLevel;
|
||||
import com.android.net.module.util.DeviceConfigUtils;
|
||||
import com.android.net.module.util.IIpv4PrefixRequest;
|
||||
import com.android.net.module.util.InterfaceParams;
|
||||
import com.android.net.module.util.NetdUtils;
|
||||
|
|
@ -204,6 +215,23 @@ public class IpServer extends StateMachineShim {
|
|||
/** Create a DhcpServer instance to be used by IpServer. */
|
||||
public abstract void makeDhcpServer(String ifName, DhcpServingParamsParcel params,
|
||||
DhcpServerCallbacks cb);
|
||||
|
||||
/**
|
||||
* @see DeviceConfigUtils#isTetheringFeatureEnabled
|
||||
*/
|
||||
public boolean isFeatureEnabled(Context context, String name) {
|
||||
return DeviceConfigUtils.isTetheringFeatureEnabled(context, name);
|
||||
}
|
||||
|
||||
/** Create a NetworkAgent instance to be used by IpServer. */
|
||||
@RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
|
||||
@SuppressLint("NewApi")
|
||||
public NetworkAgent makeNetworkAgent(
|
||||
@NonNull Context context, @NonNull Looper looper, @NonNull String logTag,
|
||||
int interfaceType, @NonNull LinkProperties lp) {
|
||||
return ConnectivityInternalApiUtil.buildTetheringNetworkAgent(
|
||||
context, looper, logTag, getTransportTypeForTetherableType(interfaceType), lp);
|
||||
}
|
||||
}
|
||||
|
||||
// request from the user that it wants to tether
|
||||
|
|
@ -304,16 +332,28 @@ public class IpServer extends StateMachineShim {
|
|||
|
||||
private final TetheringMetrics mTetheringMetrics;
|
||||
private final Handler mHandler;
|
||||
private final Context mContext;
|
||||
|
||||
private final boolean mSupportLocalAgent;
|
||||
|
||||
// This will be null if the TetheredState is not entered or feature not supported.
|
||||
// This will be only accessed from the IpServer handler thread.
|
||||
private NetworkAgent mTetheringAgent;
|
||||
|
||||
private static boolean everRegistered(@NonNull NetworkAgent agent) {
|
||||
return agent.getNetwork() != null;
|
||||
}
|
||||
|
||||
// TODO: Add a dependency object to pass the data members or variables from the tethering
|
||||
// object. It helps to reduce the arguments of the constructor.
|
||||
public IpServer(
|
||||
String ifaceName, Handler handler, int interfaceType, SharedLog log,
|
||||
INetd netd, @NonNull BpfCoordinator bpfCoordinator,
|
||||
String ifaceName, @NonNull Context context, Handler handler, int interfaceType,
|
||||
SharedLog log, INetd netd, @NonNull BpfCoordinator bpfCoordinator,
|
||||
RoutingCoordinatorManager routingCoordinatorManager, Callback callback,
|
||||
TetheringConfiguration config,
|
||||
TetheringMetrics tetheringMetrics, Dependencies deps) {
|
||||
super(ifaceName, USE_SYNC_SM ? null : handler.getLooper());
|
||||
mContext = Objects.requireNonNull(context);
|
||||
mHandler = handler;
|
||||
mLog = log.forSubComponent(ifaceName);
|
||||
mNetd = netd;
|
||||
|
|
@ -339,6 +379,10 @@ public class IpServer extends StateMachineShim {
|
|||
mLastError = TETHER_ERROR_NO_ERROR;
|
||||
mServingMode = STATE_AVAILABLE;
|
||||
|
||||
// Tethering network agent is supported on V+, and will be rolled out gradually.
|
||||
mSupportLocalAgent = SdkLevel.isAtLeastV()
|
||||
&& mDeps.isFeatureEnabled(mContext, TETHERING_LOCAL_NETWORK_AGENT);
|
||||
|
||||
mInitialState = new InitialState();
|
||||
mLocalHotspotState = new LocalHotspotState();
|
||||
mTetheredState = new TetheredState();
|
||||
|
|
@ -787,6 +831,7 @@ public class IpServer extends StateMachineShim {
|
|||
//
|
||||
// TODO: Evaluate using a data structure than is more directly suited to
|
||||
// communicating only the relevant information.
|
||||
@SuppressLint("NewApi")
|
||||
private void updateUpstreamIPv6LinkProperties(LinkProperties v6only, int ttlAdjustment) {
|
||||
if (mRaDaemon == null) return;
|
||||
|
||||
|
|
@ -847,8 +892,7 @@ public class IpServer extends StateMachineShim {
|
|||
}
|
||||
|
||||
private void removeRoutesFromNetwork(int netId, @NonNull final List<RouteInfo> toBeRemoved) {
|
||||
final int removalFailures = NetdUtils.removeRoutesFromNetwork(
|
||||
mNetd, netId, toBeRemoved);
|
||||
final int removalFailures = NetdUtils.removeRoutesFromNetwork(mNetd, netId, toBeRemoved);
|
||||
if (removalFailures > 0) {
|
||||
mLog.e("Failed to remove " + removalFailures
|
||||
+ " IPv6 routes from network " + netId + ".");
|
||||
|
|
@ -900,7 +944,9 @@ public class IpServer extends StateMachineShim {
|
|||
if (!deprecatedPrefixes.isEmpty()) {
|
||||
final List<RouteInfo> routesToBeRemoved =
|
||||
getLocalRoutesFor(mIfaceName, deprecatedPrefixes);
|
||||
removeRoutesFromNetwork(LOCAL_NET_ID, routesToBeRemoved);
|
||||
if (mTetheringAgent == null) {
|
||||
removeRoutesFromNetwork(LOCAL_NET_ID, routesToBeRemoved);
|
||||
}
|
||||
for (RouteInfo route : routesToBeRemoved) mLinkProperties.removeRoute(route);
|
||||
}
|
||||
|
||||
|
|
@ -914,7 +960,9 @@ public class IpServer extends StateMachineShim {
|
|||
if (!addedPrefixes.isEmpty()) {
|
||||
final List<RouteInfo> routesToBeAdded =
|
||||
getLocalRoutesFor(mIfaceName, addedPrefixes);
|
||||
addRoutesToNetwork(LOCAL_NET_ID, routesToBeAdded);
|
||||
if (mTetheringAgent == null) {
|
||||
addRoutesToNetwork(LOCAL_NET_ID, routesToBeAdded);
|
||||
}
|
||||
for (RouteInfo route : routesToBeAdded) mLinkProperties.addRoute(route);
|
||||
}
|
||||
}
|
||||
|
|
@ -1112,7 +1160,26 @@ public class IpServer extends StateMachineShim {
|
|||
return CONNECTIVITY_SCOPE_LOCAL;
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
private void startServingInterface() {
|
||||
// TODO: Enable Network Agent for Wifi P2P Group Owner mode when Network Agent
|
||||
// for Group Client mode is supported.
|
||||
if (mSupportLocalAgent && getScope() == CONNECTIVITY_SCOPE_GLOBAL) {
|
||||
try {
|
||||
mTetheringAgent = mDeps.makeNetworkAgent(mContext, Looper.myLooper(), TAG,
|
||||
mInterfaceType, mLinkProperties);
|
||||
// Entering CONNECTING state, the ConnectivityService will create the
|
||||
// native network.
|
||||
mTetheringAgent.register();
|
||||
} catch (RuntimeException e) {
|
||||
mLog.e("Error Creating Local Network", e);
|
||||
// If an exception occurs during the creation or registration of the
|
||||
// NetworkAgent, it typically indicates a problem with the system services.
|
||||
mLastError = TETHER_ERROR_SERVICE_UNAVAIL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!startIPv4(getScope())) {
|
||||
mLastError = TETHER_ERROR_IFACE_CFG_ERROR;
|
||||
return;
|
||||
|
|
@ -1122,14 +1189,16 @@ public class IpServer extends StateMachineShim {
|
|||
// Enable IPv6, disable accepting RA, etc. See TetherController::tetherInterface()
|
||||
// for more detail.
|
||||
mNetd.tetherInterfaceAdd(mIfaceName);
|
||||
NetdUtils.networkAddInterface(mNetd, LOCAL_NET_ID, mIfaceName,
|
||||
20 /* maxAttempts */, 50 /* pollingIntervalMs */);
|
||||
// Activate a route to dest and IPv6 link local.
|
||||
NetdUtils.modifyRoute(mNetd, NetdUtils.ModifyOperation.ADD, LOCAL_NET_ID,
|
||||
new RouteInfo(asIpPrefix(mIpv4Address), null, mIfaceName, RTN_UNICAST));
|
||||
NetdUtils.modifyRoute(mNetd, NetdUtils.ModifyOperation.ADD, LOCAL_NET_ID,
|
||||
new RouteInfo(new IpPrefix("fe80::/64"), null, mIfaceName,
|
||||
RTN_UNICAST));
|
||||
if (mTetheringAgent == null) {
|
||||
NetdUtils.networkAddInterface(mNetd, LOCAL_NET_ID, mIfaceName,
|
||||
20 /* maxAttempts */, 50 /* pollingIntervalMs */);
|
||||
// Activate a route to dest and IPv6 link local.
|
||||
NetdUtils.modifyRoute(mNetd, NetdUtils.ModifyOperation.ADD, LOCAL_NET_ID,
|
||||
new RouteInfo(asIpPrefix(mIpv4Address), null, mIfaceName, RTN_UNICAST));
|
||||
NetdUtils.modifyRoute(mNetd, NetdUtils.ModifyOperation.ADD, LOCAL_NET_ID,
|
||||
new RouteInfo(new IpPrefix("fe80::/64"), null, mIfaceName,
|
||||
RTN_UNICAST));
|
||||
}
|
||||
} catch (RemoteException | ServiceSpecificException | IllegalStateException e) {
|
||||
mLog.e("Error Tethering", e);
|
||||
mLastError = TETHER_ERROR_TETHER_IFACE_ERROR;
|
||||
|
|
@ -1141,9 +1210,17 @@ public class IpServer extends StateMachineShim {
|
|||
// TODO: Make this a fatal error once Bluetooth IPv6 is sorted.
|
||||
return;
|
||||
}
|
||||
|
||||
if (mTetheringAgent != null && everRegistered(mTetheringAgent)) {
|
||||
mTetheringAgent.sendLinkProperties(mLinkProperties);
|
||||
// Mark it connected to notify the applications for
|
||||
// the network availability.
|
||||
mTetheringAgent.markConnected();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressLint("NewApi")
|
||||
public void exit() {
|
||||
// Note that at this point, we're leaving the tethered state. We can fail any
|
||||
// of these operations, but it doesn't really change that we have to try them
|
||||
|
|
@ -1155,7 +1232,9 @@ public class IpServer extends StateMachineShim {
|
|||
try {
|
||||
mNetd.tetherInterfaceRemove(mIfaceName);
|
||||
} finally {
|
||||
mNetd.networkRemoveInterface(LOCAL_NET_ID, mIfaceName);
|
||||
if (mTetheringAgent == null) {
|
||||
mNetd.networkRemoveInterface(LOCAL_NET_ID, mIfaceName);
|
||||
}
|
||||
}
|
||||
} catch (RemoteException | ServiceSpecificException e) {
|
||||
mLastError = TETHER_ERROR_UNTETHER_IFACE_ERROR;
|
||||
|
|
@ -1165,6 +1244,11 @@ public class IpServer extends StateMachineShim {
|
|||
stopIPv4();
|
||||
mBpfCoordinator.removeIpServer(IpServer.this);
|
||||
|
||||
if (mTetheringAgent != null && everRegistered(mTetheringAgent)) {
|
||||
mTetheringAgent.unregister();
|
||||
mTetheringAgent = null;
|
||||
}
|
||||
|
||||
resetLinkProperties();
|
||||
|
||||
mTetheringMetrics.updateErrorCode(mInterfaceType, mLastError);
|
||||
|
|
@ -1184,6 +1268,12 @@ public class IpServer extends StateMachineShim {
|
|||
break;
|
||||
case CMD_IPV6_TETHER_UPDATE:
|
||||
updateUpstreamIPv6LinkProperties((LinkProperties) message.obj, message.arg1);
|
||||
// Sends update to the NetworkAgent.
|
||||
// TODO: Refactor the callers of sendLinkProperties()
|
||||
// and move these code into sendLinkProperties().
|
||||
if (mTetheringAgent != null && everRegistered(mTetheringAgent)) {
|
||||
mTetheringAgent.sendLinkProperties(mLinkProperties);
|
||||
}
|
||||
sendLinkProperties();
|
||||
break;
|
||||
case CMD_IP_FORWARDING_ENABLE_ERROR:
|
||||
|
|
@ -1236,13 +1326,17 @@ public class IpServer extends StateMachineShim {
|
|||
// Remove deprecated routes from downstream network.
|
||||
final List<RouteInfo> routesToBeRemoved =
|
||||
List.of(getDirectConnectedRoute(deprecatedLinkAddress));
|
||||
removeRoutesFromNetwork(LOCAL_NET_ID, routesToBeRemoved);
|
||||
if (mTetheringAgent == null) {
|
||||
removeRoutesFromNetwork(LOCAL_NET_ID, routesToBeRemoved);
|
||||
}
|
||||
for (RouteInfo route : routesToBeRemoved) mLinkProperties.removeRoute(route);
|
||||
mLinkProperties.removeLinkAddress(deprecatedLinkAddress);
|
||||
|
||||
// Add new routes to downstream network.
|
||||
final List<RouteInfo> routesToBeAdded = List.of(getDirectConnectedRoute(mIpv4Address));
|
||||
addRoutesToNetwork(LOCAL_NET_ID, routesToBeAdded);
|
||||
if (mTetheringAgent == null) {
|
||||
addRoutesToNetwork(LOCAL_NET_ID, routesToBeAdded);
|
||||
}
|
||||
for (RouteInfo route : routesToBeAdded) mLinkProperties.addRoute(route);
|
||||
mLinkProperties.addLinkAddress(mIpv4Address);
|
||||
|
||||
|
|
@ -1255,6 +1349,10 @@ public class IpServer extends StateMachineShim {
|
|||
mLog.e("Failed to update local DNS caching server");
|
||||
return;
|
||||
}
|
||||
// Sends update to the NetworkAgent.
|
||||
if (mTetheringAgent != null && everRegistered(mTetheringAgent)) {
|
||||
mTetheringAgent.sendLinkProperties(mLinkProperties);
|
||||
}
|
||||
sendLinkProperties();
|
||||
|
||||
// Notify DHCP server that new prefix/route has been applied on IpServer.
|
||||
|
|
|
|||
|
|
@ -3105,7 +3105,7 @@ public class Tethering {
|
|||
|
||||
mLog.i("adding IpServer for: " + iface);
|
||||
final TetherState tetherState = new TetherState(
|
||||
new IpServer(iface, mHandler, interfaceType, mLog, mNetd, mBpfCoordinator,
|
||||
new IpServer(iface, mContext, mHandler, interfaceType, mLog, mNetd, mBpfCoordinator,
|
||||
mRoutingCoordinator, new ControlCallback(), mConfig, mTetheringMetrics,
|
||||
mDeps.makeIpServerDependencies()), isNcm);
|
||||
mTetherStates.put(iface, tetherState);
|
||||
|
|
|
|||
|
|
@ -148,6 +148,12 @@ public class TetheringConfiguration {
|
|||
*/
|
||||
public static final String TETHER_ACTIVE_SESSIONS_METRICS = "tether_active_sessions_metrics";
|
||||
|
||||
/**
|
||||
* A feature flag to control whether the tethering local network agent should be enabled.
|
||||
* Disabled by default.
|
||||
*/
|
||||
public static final String TETHERING_LOCAL_NETWORK_AGENT = "tethering_local_network_agent";
|
||||
|
||||
public final String[] tetherableUsbRegexs;
|
||||
public final String[] tetherableWifiRegexs;
|
||||
public final String[] tetherableWigigRegexs;
|
||||
|
|
|
|||
|
|
@ -15,8 +15,20 @@
|
|||
*/
|
||||
package com.android.networkstack.tethering.util;
|
||||
|
||||
import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH;
|
||||
import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
|
||||
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
|
||||
import static android.net.NetworkCapabilities.TRANSPORT_USB;
|
||||
import static android.net.TetheringManager.CONNECTIVITY_SCOPE_GLOBAL;
|
||||
import static android.net.TetheringManager.CONNECTIVITY_SCOPE_LOCAL;
|
||||
import static android.net.TetheringManager.TETHERING_BLUETOOTH;
|
||||
import static android.net.TetheringManager.TETHERING_ETHERNET;
|
||||
import static android.net.TetheringManager.TETHERING_NCM;
|
||||
import static android.net.TetheringManager.TETHERING_USB;
|
||||
import static android.net.TetheringManager.TETHERING_VIRTUAL;
|
||||
import static android.net.TetheringManager.TETHERING_WIFI;
|
||||
import static android.net.TetheringManager.TETHERING_WIFI_P2P;
|
||||
import static android.net.TetheringManager.TETHERING_WIGIG;
|
||||
|
||||
import android.net.TetherStatsParcel;
|
||||
import android.net.TetheringManager.TetheringRequest;
|
||||
|
|
@ -207,4 +219,30 @@ public class TetheringUtils {
|
|||
request.getParcel().connectivityScope = CONNECTIVITY_SCOPE_GLOBAL;
|
||||
return request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the transport type for the given interface type.
|
||||
*
|
||||
* @param interfaceType The interface type.
|
||||
* @return The transport type.
|
||||
* @throws IllegalArgumentException if the interface type is invalid.
|
||||
*/
|
||||
public static int getTransportTypeForTetherableType(int interfaceType) {
|
||||
switch (interfaceType) {
|
||||
case TETHERING_WIFI:
|
||||
case TETHERING_WIGIG:
|
||||
case TETHERING_WIFI_P2P:
|
||||
return TRANSPORT_WIFI;
|
||||
case TETHERING_USB:
|
||||
case TETHERING_NCM:
|
||||
return TRANSPORT_USB;
|
||||
case TETHERING_BLUETOOTH:
|
||||
return TRANSPORT_BLUETOOTH;
|
||||
case TETHERING_ETHERNET:
|
||||
case TETHERING_VIRTUAL: // For virtual machines.
|
||||
return TRANSPORT_ETHERNET;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid interface type: " + interfaceType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,11 +16,25 @@
|
|||
|
||||
package android.net.connectivity;
|
||||
|
||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED;
|
||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
|
||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
|
||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.LinkProperties;
|
||||
import android.net.LocalNetworkConfig;
|
||||
import android.net.NetworkAgent;
|
||||
import android.net.NetworkAgentConfig;
|
||||
import android.net.NetworkCapabilities;
|
||||
import android.net.NetworkScore;
|
||||
import android.os.Build;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.RequiresApi;
|
||||
|
||||
/**
|
||||
|
|
@ -57,4 +71,36 @@ public class ConnectivityInternalApiUtil {
|
|||
final ConnectivityManager cm = ctx.getSystemService(ConnectivityManager.class);
|
||||
return cm.getRoutingCoordinatorService();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a NetworkAgent instance to be used by Tethering.
|
||||
* @param ctx the context
|
||||
* @return an instance of the {@code NetworkAgent}
|
||||
*/
|
||||
// TODO: Expose LocalNetworkConfig related APIs and delete this method. This method is
|
||||
// only here because on R Tethering is installed and not Connectivity, requiring all
|
||||
// shared classes to be public API. LocalNetworkConfig is not public yet, but it will
|
||||
// only be used by Tethering on V+ so it's fine.
|
||||
@SuppressLint("WrongConstant")
|
||||
@NonNull
|
||||
public static NetworkAgent buildTetheringNetworkAgent(@NonNull Context ctx,
|
||||
@NonNull Looper looper, @NonNull String logTag, int transportType,
|
||||
@NonNull LinkProperties lp) {
|
||||
final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder()
|
||||
.addCapability(NET_CAPABILITY_NOT_METERED)
|
||||
.addCapability(NET_CAPABILITY_NOT_ROAMING)
|
||||
.addCapability(NET_CAPABILITY_NOT_CONGESTED)
|
||||
.addCapability(NET_CAPABILITY_NOT_SUSPENDED)
|
||||
.addTransportType(transportType);
|
||||
// TODO: Change to use the constant definition. Flags.netCapabilityLocalNetwork() was not
|
||||
// fully rolled out but the service will still process this capability, set it anyway.
|
||||
builder.addCapability(36 /* NET_CAPABILITY_LOCAL_NETWORK */);
|
||||
final NetworkCapabilities caps = builder.build();
|
||||
final NetworkAgentConfig nac = new NetworkAgentConfig.Builder().build();
|
||||
return new NetworkAgent(ctx, looper, logTag, caps, lp,
|
||||
new LocalNetworkConfig.Builder().build(), new NetworkScore.Builder()
|
||||
.setKeepConnectedReason(NetworkScore.KEEP_CONNECTED_LOCAL_NETWORK)
|
||||
.build(), nac, null /* provider */) {
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue