Merge changes I270ff43c,Ifc7eee24 am: cec294d1b4
Original change: https://android-review.googlesource.com/c/platform/packages/modules/Connectivity/+/1730548 Change-Id: I435e69ba3fc71cf56a7bf8cc54b394831615fa57
This commit is contained in:
@@ -193,4 +193,8 @@
|
||||
state. -->
|
||||
<!-- Config for showing upstream roaming notification. -->
|
||||
<bool name="config_upstream_roaming_notification">false</bool>
|
||||
|
||||
<!-- Which USB function should be enabled when TETHERING_USB is requested. 0: RNDIS, 1: NCM.
|
||||
-->
|
||||
<integer translatable="false" name="config_tether_usb_functions">0</integer>
|
||||
</resources>
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
<item type="array" name="config_tether_wifi_p2p_regexs"/>
|
||||
<item type="array" name="config_tether_bluetooth_regexs"/>
|
||||
<item type="array" name="config_tether_dhcp_range"/>
|
||||
<item type="integer" name="config_tether_usb_functions"/>
|
||||
<!-- Use the BPF offload for tethering when the kernel has support. True by default.
|
||||
If the device doesn't want to support tether BPF offload, this should be false.
|
||||
Note that this setting could be overridden by device config.
|
||||
|
||||
@@ -64,6 +64,7 @@ import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED;
|
||||
import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED;
|
||||
import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
|
||||
|
||||
import static com.android.networkstack.tethering.TetheringConfiguration.TETHER_FORCE_USB_FUNCTIONS;
|
||||
import static com.android.networkstack.tethering.TetheringNotificationUpdater.DOWNSTREAM_NONE;
|
||||
import static com.android.networkstack.tethering.UpstreamNetworkMonitor.isCellular;
|
||||
|
||||
@@ -77,6 +78,7 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.database.ContentObserver;
|
||||
import android.hardware.usb.UsbManager;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.EthernetManager;
|
||||
@@ -248,6 +250,7 @@ public class Tethering {
|
||||
private InterfaceSet mCurrentUpstreamIfaceSet;
|
||||
|
||||
private boolean mRndisEnabled; // track the RNDIS function enabled state
|
||||
private boolean mNcmEnabled; // track the NCM function enabled state
|
||||
// True iff. WiFi tethering should be started when soft AP is ready.
|
||||
private boolean mWifiTetherRequested;
|
||||
private Network mTetherUpstream;
|
||||
@@ -259,6 +262,7 @@ public class Tethering {
|
||||
private EthernetManager.TetheredInterfaceRequest mEthernetIfaceRequest;
|
||||
private String mConfiguredEthernetIface;
|
||||
private EthernetCallback mEthernetCallback;
|
||||
private SettingsObserver mSettingsObserver;
|
||||
|
||||
public Tethering(TetheringDependencies deps) {
|
||||
mLog.mark("Tethering.constructed");
|
||||
@@ -310,6 +314,10 @@ public class Tethering {
|
||||
mEntitlementMgr.reevaluateSimCardProvisioning(mConfig);
|
||||
});
|
||||
|
||||
mSettingsObserver = new SettingsObserver(mHandler);
|
||||
mContext.getContentResolver().registerContentObserver(
|
||||
Settings.Global.getUriFor(TETHER_FORCE_USB_FUNCTIONS), false, mSettingsObserver);
|
||||
|
||||
mStateReceiver = new StateReceiver();
|
||||
|
||||
mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
|
||||
@@ -359,6 +367,28 @@ public class Tethering {
|
||||
startStateMachineUpdaters();
|
||||
}
|
||||
|
||||
private class SettingsObserver extends ContentObserver {
|
||||
SettingsObserver(Handler handler) {
|
||||
super(handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChange(boolean selfChange) {
|
||||
mLog.i("OBSERVED Settings change");
|
||||
final boolean isUsingNcm = mConfig.isUsingNcm();
|
||||
updateConfiguration();
|
||||
if (isUsingNcm != mConfig.isUsingNcm()) {
|
||||
stopTetheringInternal(TETHERING_USB);
|
||||
stopTetheringInternal(TETHERING_NCM);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
ContentObserver getSettingsObserverForTest() {
|
||||
return mSettingsObserver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start to register callbacks.
|
||||
* Call this function when tethering is ready to handle callback events.
|
||||
@@ -490,24 +520,35 @@ public class Tethering {
|
||||
}
|
||||
}
|
||||
|
||||
// This method needs to exist because TETHERING_BLUETOOTH and TETHERING_WIGIG can't use
|
||||
// enableIpServing.
|
||||
private void startOrStopIpServer(final String iface, boolean enabled) {
|
||||
// TODO: do not listen to USB interface state changes. USB tethering is driven only by
|
||||
// USB_ACTION broadcasts.
|
||||
|
||||
if (enabled) {
|
||||
ensureIpServerStarted(iface);
|
||||
} else {
|
||||
ensureIpServerStopped(iface);
|
||||
}
|
||||
}
|
||||
|
||||
void interfaceStatusChanged(String iface, boolean up) {
|
||||
// Never called directly: only called from interfaceLinkStateChanged.
|
||||
// See NetlinkHandler.cpp: notifyInterfaceChanged.
|
||||
if (VDBG) Log.d(TAG, "interfaceStatusChanged " + iface + ", " + up);
|
||||
if (up) {
|
||||
maybeTrackNewInterface(iface);
|
||||
} else {
|
||||
if (ifaceNameToType(iface) == TETHERING_BLUETOOTH
|
||||
|| ifaceNameToType(iface) == TETHERING_WIGIG) {
|
||||
stopTrackingInterface(iface);
|
||||
} else {
|
||||
// Ignore usb0 down after enabling RNDIS.
|
||||
|
||||
final int type = ifaceNameToType(iface);
|
||||
if (!up && type != TETHERING_BLUETOOTH && type != TETHERING_WIGIG) {
|
||||
// Ignore usb interface down after enabling RNDIS.
|
||||
// We will handle disconnect in interfaceRemoved.
|
||||
// Similarly, ignore interface down for WiFi. We monitor WiFi AP status
|
||||
// through the WifiManager.WIFI_AP_STATE_CHANGED_ACTION intent.
|
||||
if (VDBG) Log.d(TAG, "ignore interface down for " + iface);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
startOrStopIpServer(iface, up);
|
||||
}
|
||||
|
||||
void interfaceLinkStateChanged(String iface, boolean up) {
|
||||
@@ -535,12 +576,12 @@ public class Tethering {
|
||||
|
||||
void interfaceAdded(String iface) {
|
||||
if (VDBG) Log.d(TAG, "interfaceAdded " + iface);
|
||||
maybeTrackNewInterface(iface);
|
||||
startOrStopIpServer(iface, true /* enabled */);
|
||||
}
|
||||
|
||||
void interfaceRemoved(String iface) {
|
||||
if (VDBG) Log.d(TAG, "interfaceRemoved " + iface);
|
||||
stopTrackingInterface(iface);
|
||||
startOrStopIpServer(iface, false /* enabled */);
|
||||
}
|
||||
|
||||
void startTethering(final TetheringRequestParcel request, final IIntResultListener listener) {
|
||||
@@ -568,11 +609,14 @@ public class Tethering {
|
||||
|
||||
void stopTethering(int type) {
|
||||
mHandler.post(() -> {
|
||||
stopTetheringInternal(type);
|
||||
});
|
||||
}
|
||||
void stopTetheringInternal(int type) {
|
||||
mActiveTetheringRequests.remove(type);
|
||||
|
||||
enableTetheringInternal(type, false /* disabled */, null);
|
||||
mEntitlementMgr.stopProvisioningIfNeeded(type);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -701,7 +745,7 @@ public class Tethering {
|
||||
|
||||
private void stopEthernetTethering() {
|
||||
if (mConfiguredEthernetIface != null) {
|
||||
stopTrackingInterface(mConfiguredEthernetIface);
|
||||
ensureIpServerStopped(mConfiguredEthernetIface);
|
||||
mConfiguredEthernetIface = null;
|
||||
}
|
||||
if (mEthernetCallback != null) {
|
||||
@@ -718,8 +762,7 @@ public class Tethering {
|
||||
// Ethernet callback arrived after Ethernet tethering stopped. Ignore.
|
||||
return;
|
||||
}
|
||||
maybeTrackNewInterface(iface, TETHERING_ETHERNET);
|
||||
changeInterfaceState(iface, getRequestedState(TETHERING_ETHERNET));
|
||||
enableIpServing(TETHERING_ETHERNET, iface, getRequestedState(TETHERING_ETHERNET));
|
||||
mConfiguredEthernetIface = iface;
|
||||
}
|
||||
|
||||
@@ -851,6 +894,13 @@ public class Tethering {
|
||||
: IpServer.STATE_TETHERED;
|
||||
}
|
||||
|
||||
private int getRequestedUsbType(boolean forNcmFunction) {
|
||||
// TETHERING_NCM is only used if the device does not use NCM for regular USB tethering.
|
||||
if (forNcmFunction && !mConfig.isUsingNcm()) return TETHERING_NCM;
|
||||
|
||||
return TETHERING_USB;
|
||||
}
|
||||
|
||||
// TODO: Figure out how to update for local hotspot mode interfaces.
|
||||
private void sendTetherStateChangedBroadcast() {
|
||||
if (!isTetheringSupported()) return;
|
||||
@@ -877,12 +927,14 @@ public class Tethering {
|
||||
} else if (tetherState.lastState == IpServer.STATE_LOCAL_ONLY) {
|
||||
localOnly.add(tetheringIface);
|
||||
} else if (tetherState.lastState == IpServer.STATE_TETHERED) {
|
||||
if (cfg.isUsb(iface)) {
|
||||
downstreamTypesMask |= (1 << TETHERING_USB);
|
||||
} else if (cfg.isWifi(iface)) {
|
||||
downstreamTypesMask |= (1 << TETHERING_WIFI);
|
||||
} else if (cfg.isBluetooth(iface)) {
|
||||
downstreamTypesMask |= (1 << TETHERING_BLUETOOTH);
|
||||
switch (type) {
|
||||
case TETHERING_USB:
|
||||
case TETHERING_WIFI:
|
||||
case TETHERING_BLUETOOTH:
|
||||
downstreamTypesMask |= (1 << type);
|
||||
break;
|
||||
default:
|
||||
// Do nothing.
|
||||
}
|
||||
tethered.add(tetheringIface);
|
||||
}
|
||||
@@ -987,8 +1039,8 @@ public class Tethering {
|
||||
final boolean rndisEnabled = intent.getBooleanExtra(USB_FUNCTION_RNDIS, false);
|
||||
final boolean ncmEnabled = intent.getBooleanExtra(USB_FUNCTION_NCM, false);
|
||||
|
||||
mLog.log(String.format("USB bcast connected:%s configured:%s rndis:%s",
|
||||
usbConnected, usbConfigured, rndisEnabled));
|
||||
mLog.log(String.format("USB bcast connected:%s configured:%s rndis:%s ncm:%s",
|
||||
usbConnected, usbConfigured, rndisEnabled, ncmEnabled));
|
||||
|
||||
// There are three types of ACTION_USB_STATE:
|
||||
//
|
||||
@@ -1005,19 +1057,18 @@ public class Tethering {
|
||||
// functions are ready to use.
|
||||
//
|
||||
// For more explanation, see b/62552150 .
|
||||
if (!usbConnected && mRndisEnabled) {
|
||||
if (!usbConnected && (mRndisEnabled || mNcmEnabled)) {
|
||||
// Turn off tethering if it was enabled and there is a disconnect.
|
||||
tetherMatchingInterfaces(IpServer.STATE_AVAILABLE, TETHERING_USB);
|
||||
disableUsbIpServing(TETHERING_USB);
|
||||
mEntitlementMgr.stopProvisioningIfNeeded(TETHERING_USB);
|
||||
} else if (usbConfigured && rndisEnabled) {
|
||||
// Tether if rndis is enabled and usb is configured.
|
||||
final int state = getRequestedState(TETHERING_USB);
|
||||
tetherMatchingInterfaces(state, TETHERING_USB);
|
||||
} else if (usbConnected && ncmEnabled) {
|
||||
final int state = getRequestedState(TETHERING_NCM);
|
||||
tetherMatchingInterfaces(state, TETHERING_NCM);
|
||||
enableUsbIpServing(false /* isNcm */);
|
||||
} else if (usbConfigured && ncmEnabled) {
|
||||
enableUsbIpServing(true /* isNcm */);
|
||||
}
|
||||
mRndisEnabled = usbConfigured && rndisEnabled;
|
||||
mNcmEnabled = usbConfigured && ncmEnabled;
|
||||
}
|
||||
|
||||
private void handleWifiApAction(Intent intent) {
|
||||
@@ -1164,6 +1215,11 @@ public class Tethering {
|
||||
}
|
||||
}
|
||||
|
||||
private void enableIpServing(int tetheringType, String ifname, int ipServingMode) {
|
||||
ensureIpServerStarted(ifname, tetheringType);
|
||||
changeInterfaceState(ifname, ipServingMode);
|
||||
}
|
||||
|
||||
private void disableWifiIpServingCommon(int tetheringType, String ifname, int apState) {
|
||||
mLog.log("Canceling WiFi tethering request -"
|
||||
+ " type=" + tetheringType
|
||||
@@ -1224,7 +1280,7 @@ public class Tethering {
|
||||
}
|
||||
|
||||
if (!TextUtils.isEmpty(ifname)) {
|
||||
maybeTrackNewInterface(ifname);
|
||||
ensureIpServerStarted(ifname);
|
||||
changeInterfaceState(ifname, ipServingMode);
|
||||
} else {
|
||||
mLog.e(String.format(
|
||||
@@ -1239,18 +1295,17 @@ public class Tethering {
|
||||
// - handles both enabling and disabling serving states
|
||||
// - only tethers the first matching interface in listInterfaces()
|
||||
// order of a given type
|
||||
private void tetherMatchingInterfaces(int requestedState, int interfaceType) {
|
||||
if (VDBG) {
|
||||
Log.d(TAG, "tetherMatchingInterfaces(" + requestedState + ", " + interfaceType + ")");
|
||||
}
|
||||
|
||||
private void enableUsbIpServing(boolean isNcm) {
|
||||
final int interfaceType = getRequestedUsbType(isNcm);
|
||||
final int requestedState = getRequestedState(interfaceType);
|
||||
String[] ifaces = null;
|
||||
try {
|
||||
ifaces = mNetd.interfaceGetList();
|
||||
} catch (RemoteException | ServiceSpecificException e) {
|
||||
Log.e(TAG, "Error listing Interfaces", e);
|
||||
mLog.e("Cannot enableUsbIpServing due to error listing Interfaces" + e);
|
||||
return;
|
||||
}
|
||||
|
||||
String chosenIface = null;
|
||||
if (ifaces != null) {
|
||||
for (String iface : ifaces) {
|
||||
@@ -1260,6 +1315,7 @@ public class Tethering {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (chosenIface == null) {
|
||||
Log.e(TAG, "could not find iface of type " + interfaceType);
|
||||
return;
|
||||
@@ -1268,6 +1324,33 @@ public class Tethering {
|
||||
changeInterfaceState(chosenIface, requestedState);
|
||||
}
|
||||
|
||||
private void disableUsbIpServing(int interfaceType) {
|
||||
String[] ifaces = null;
|
||||
try {
|
||||
ifaces = mNetd.interfaceGetList();
|
||||
} catch (RemoteException | ServiceSpecificException e) {
|
||||
mLog.e("Cannot disableUsbIpServing due to error listing Interfaces" + e);
|
||||
return;
|
||||
}
|
||||
|
||||
String chosenIface = null;
|
||||
if (ifaces != null) {
|
||||
for (String iface : ifaces) {
|
||||
if (ifaceNameToType(iface) == interfaceType) {
|
||||
chosenIface = iface;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (chosenIface == null) {
|
||||
Log.e(TAG, "could not find iface of type " + interfaceType);
|
||||
return;
|
||||
}
|
||||
|
||||
changeInterfaceState(chosenIface, IpServer.STATE_AVAILABLE);
|
||||
}
|
||||
|
||||
private void changeInterfaceState(String ifname, int requestedState) {
|
||||
final int result;
|
||||
switch (requestedState) {
|
||||
@@ -1320,13 +1403,21 @@ public class Tethering {
|
||||
mLog.e("setUsbTethering: failed to get UsbManager!");
|
||||
return TETHER_ERROR_SERVICE_UNAVAIL;
|
||||
}
|
||||
usbManager.setCurrentFunctions(enable ? UsbManager.FUNCTION_RNDIS
|
||||
: UsbManager.FUNCTION_NONE);
|
||||
|
||||
final long usbFunction = mConfig.isUsingNcm()
|
||||
? UsbManager.FUNCTION_NCM : UsbManager.FUNCTION_RNDIS;
|
||||
usbManager.setCurrentFunctions(enable ? usbFunction : UsbManager.FUNCTION_NONE);
|
||||
|
||||
return TETHER_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
private int setNcmTethering(boolean enable) {
|
||||
if (VDBG) Log.d(TAG, "setNcmTethering(" + enable + ")");
|
||||
|
||||
// If TETHERING_USB is forced to use ncm function, TETHERING_NCM would no longer be
|
||||
// available.
|
||||
if (mConfig.isUsingNcm()) return TETHER_ERROR_SERVICE_UNAVAIL;
|
||||
|
||||
UsbManager usbManager = (UsbManager) mContext.getSystemService(Context.USB_SERVICE);
|
||||
usbManager.setCurrentFunctions(enable ? UsbManager.FUNCTION_NCM : UsbManager.FUNCTION_NONE);
|
||||
return TETHER_ERROR_NO_ERROR;
|
||||
@@ -2437,7 +2528,7 @@ public class Tethering {
|
||||
mTetherMainSM.sendMessage(which, state, 0, newLp);
|
||||
}
|
||||
|
||||
private void maybeTrackNewInterface(final String iface) {
|
||||
private void ensureIpServerStarted(final String iface) {
|
||||
// If we don't care about this type of interface, ignore.
|
||||
final int interfaceType = ifaceNameToType(iface);
|
||||
if (interfaceType == TETHERING_INVALID) {
|
||||
@@ -2457,17 +2548,17 @@ public class Tethering {
|
||||
return;
|
||||
}
|
||||
|
||||
maybeTrackNewInterface(iface, interfaceType);
|
||||
ensureIpServerStarted(iface, interfaceType);
|
||||
}
|
||||
|
||||
private void maybeTrackNewInterface(final String iface, int interfaceType) {
|
||||
private void ensureIpServerStarted(final String iface, int interfaceType) {
|
||||
// If we have already started a TISM for this interface, skip.
|
||||
if (mTetherStates.containsKey(iface)) {
|
||||
mLog.log("active iface (" + iface + ") reported as added, ignoring");
|
||||
return;
|
||||
}
|
||||
|
||||
mLog.log("adding TetheringInterfaceStateMachine for: " + iface);
|
||||
mLog.log("adding IpServer for: " + iface);
|
||||
final TetherState tetherState = new TetherState(
|
||||
new IpServer(iface, mLooper, interfaceType, mLog, mNetd, mBpfCoordinator,
|
||||
makeControlCallback(), mConfig.enableLegacyDhcpServer,
|
||||
@@ -2477,14 +2568,12 @@ public class Tethering {
|
||||
tetherState.ipServer.start();
|
||||
}
|
||||
|
||||
private void stopTrackingInterface(final String iface) {
|
||||
private void ensureIpServerStopped(final String iface) {
|
||||
final TetherState tetherState = mTetherStates.get(iface);
|
||||
if (tetherState == null) {
|
||||
mLog.log("attempting to remove unknown iface (" + iface + "), ignoring");
|
||||
return;
|
||||
}
|
||||
if (tetherState == null) return;
|
||||
|
||||
tetherState.ipServer.stop();
|
||||
mLog.log("removing TetheringInterfaceStateMachine for: " + iface);
|
||||
mLog.log("removing IpServer for: " + iface);
|
||||
mTetherStates.remove(iface);
|
||||
}
|
||||
|
||||
|
||||
@@ -23,11 +23,13 @@ import static android.net.ConnectivityManager.TYPE_MOBILE_DUN;
|
||||
import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI;
|
||||
import static android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.net.TetheringConfigurationParcel;
|
||||
import android.net.util.SharedLog;
|
||||
import android.provider.DeviceConfig;
|
||||
import android.provider.Settings;
|
||||
import android.telephony.SubscriptionManager;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.text.TextUtils;
|
||||
@@ -75,6 +77,12 @@ public class TetheringConfiguration {
|
||||
|
||||
private static final String[] DEFAULT_IPV4_DNS = {"8.8.4.4", "8.8.8.8"};
|
||||
|
||||
@VisibleForTesting
|
||||
public static final int TETHER_USB_RNDIS_FUNCTION = 0;
|
||||
|
||||
@VisibleForTesting
|
||||
public static final int TETHER_USB_NCM_FUNCTION = 1;
|
||||
|
||||
/**
|
||||
* Override enabling BPF offload configuration for tethering.
|
||||
*/
|
||||
@@ -104,13 +112,20 @@ public class TetheringConfiguration {
|
||||
* via resource overlays, and later noticed issues. To that end, it overrides
|
||||
* config_tether_upstream_automatic when set to true.
|
||||
*
|
||||
* This flag is enabled if !=0 and less than the module APK version: see
|
||||
* This flag is enabled if !=0 and less than the module APEX version: see
|
||||
* {@link DeviceConfigUtils#isFeatureEnabled}. It is also ignored after R, as later devices
|
||||
* should just set config_tether_upstream_automatic to true instead.
|
||||
*/
|
||||
public static final String TETHER_FORCE_UPSTREAM_AUTOMATIC_VERSION =
|
||||
"tether_force_upstream_automatic_version";
|
||||
|
||||
/**
|
||||
* Settings key to foce choosing usb functions for usb tethering.
|
||||
*
|
||||
* TODO: Remove this hard code string and make Settings#TETHER_FORCE_USB_FUNCTIONS as API.
|
||||
*/
|
||||
public static final String TETHER_FORCE_USB_FUNCTIONS =
|
||||
"tether_force_usb_functions";
|
||||
/**
|
||||
* Default value that used to periodic polls tether offload stats from tethering offload HAL
|
||||
* to make the data warnings work.
|
||||
@@ -143,12 +158,17 @@ public class TetheringConfiguration {
|
||||
private final boolean mEnableWifiP2pDedicatedIp;
|
||||
|
||||
private final boolean mEnableSelectAllPrefixRange;
|
||||
private final int mUsbTetheringFunction;
|
||||
protected final ContentResolver mContentResolver;
|
||||
|
||||
public TetheringConfiguration(Context ctx, SharedLog log, int id) {
|
||||
final SharedLog configLog = log.forSubComponent("config");
|
||||
|
||||
activeDataSubId = id;
|
||||
Resources res = getResources(ctx, activeDataSubId);
|
||||
mContentResolver = ctx.getContentResolver();
|
||||
|
||||
mUsbTetheringFunction = getUsbTetheringFunction(res);
|
||||
|
||||
tetherableUsbRegexs = getResourceStringArray(res, R.array.config_tether_usb_regexs);
|
||||
tetherableNcmRegexs = getResourceStringArray(res, R.array.config_tether_ncm_regexs);
|
||||
@@ -200,6 +220,11 @@ public class TetheringConfiguration {
|
||||
configLog.log(toString());
|
||||
}
|
||||
|
||||
/** Check whether using ncm for usb tethering */
|
||||
public boolean isUsingNcm() {
|
||||
return mUsbTetheringFunction == TETHER_USB_NCM_FUNCTION;
|
||||
}
|
||||
|
||||
/** Check whether input interface belong to usb.*/
|
||||
public boolean isUsb(String iface) {
|
||||
return matchesDownstreamRegexs(iface, tetherableUsbRegexs);
|
||||
@@ -285,6 +310,9 @@ public class TetheringConfiguration {
|
||||
|
||||
pw.print("mEnableSelectAllPrefixRange: ");
|
||||
pw.println(mEnableSelectAllPrefixRange);
|
||||
|
||||
pw.print("mUsbTetheringFunction: ");
|
||||
pw.println(isUsingNcm() ? "NCM" : "RNDIS");
|
||||
}
|
||||
|
||||
/** Returns the string representation of this object.*/
|
||||
@@ -350,6 +378,26 @@ public class TetheringConfiguration {
|
||||
return mEnableSelectAllPrefixRange;
|
||||
}
|
||||
|
||||
private int getUsbTetheringFunction(Resources res) {
|
||||
final int valueFromRes = getResourceInteger(res, R.integer.config_tether_usb_functions,
|
||||
TETHER_USB_RNDIS_FUNCTION /* defaultValue */);
|
||||
return getSettingsIntValue(TETHER_FORCE_USB_FUNCTIONS, valueFromRes);
|
||||
}
|
||||
|
||||
private int getSettingsIntValue(final String name, final int defaultValue) {
|
||||
final String value = getSettingsValue(name);
|
||||
try {
|
||||
return value != null ? Integer.parseInt(value) : defaultValue;
|
||||
} catch (NumberFormatException e) {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
protected String getSettingsValue(final String name) {
|
||||
return Settings.Global.getString(mContentResolver, name);
|
||||
}
|
||||
|
||||
private static Collection<Integer> getUpstreamIfaceTypes(Resources res, boolean dunRequired) {
|
||||
final int[] ifaceTypes = res.getIntArray(R.array.config_tether_upstream_types);
|
||||
final ArrayList<Integer> upstreamIfaceTypes = new ArrayList<>(ifaceTypes.length);
|
||||
|
||||
@@ -226,7 +226,7 @@ public final class EntitlementManagerTest {
|
||||
mEnMgr = new WrappedEntitlementManager(mMockContext, new Handler(mLooper.getLooper()), mLog,
|
||||
mPermissionChangeCallback);
|
||||
mEnMgr.setOnUiEntitlementFailedListener(mEntitlementFailedListener);
|
||||
mConfig = new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
|
||||
mConfig = new FakeTetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
|
||||
mEnMgr.setTetheringConfigurationFetcher(() -> {
|
||||
return mConfig;
|
||||
});
|
||||
@@ -251,7 +251,7 @@ public final class EntitlementManagerTest {
|
||||
when(mCarrierConfigManager.getConfigForSubId(anyInt())).thenReturn(mCarrierConfig);
|
||||
mCarrierConfig.putBoolean(CarrierConfigManager.KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL, true);
|
||||
mCarrierConfig.putBoolean(CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL, true);
|
||||
mConfig = new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
|
||||
mConfig = new FakeTetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -265,7 +265,7 @@ public final class EntitlementManagerTest {
|
||||
setupForRequiredProvisioning();
|
||||
when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE))
|
||||
.thenReturn(null);
|
||||
mConfig = new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
|
||||
mConfig = new FakeTetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
|
||||
// Couldn't get the CarrierConfigManager, but still had a declared provisioning app.
|
||||
// Therefore provisioning still be required.
|
||||
assertTrue(mEnMgr.isTetherProvisioningRequired(mConfig));
|
||||
@@ -275,7 +275,7 @@ public final class EntitlementManagerTest {
|
||||
public void toleratesCarrierConfigMissing() {
|
||||
setupForRequiredProvisioning();
|
||||
when(mCarrierConfigManager.getConfig()).thenReturn(null);
|
||||
mConfig = new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
|
||||
mConfig = new FakeTetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
|
||||
// We still have a provisioning app configured, so still require provisioning.
|
||||
assertTrue(mEnMgr.isTetherProvisioningRequired(mConfig));
|
||||
}
|
||||
@@ -293,11 +293,11 @@ public final class EntitlementManagerTest {
|
||||
setupForRequiredProvisioning();
|
||||
when(mResources.getStringArray(R.array.config_mobile_hotspot_provision_app))
|
||||
.thenReturn(null);
|
||||
mConfig = new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
|
||||
mConfig = new FakeTetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
|
||||
assertFalse(mEnMgr.isTetherProvisioningRequired(mConfig));
|
||||
when(mResources.getStringArray(R.array.config_mobile_hotspot_provision_app))
|
||||
.thenReturn(new String[] {"malformedApp"});
|
||||
mConfig = new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
|
||||
mConfig = new FakeTetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
|
||||
assertFalse(mEnMgr.isTetherProvisioningRequired(mConfig));
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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 com.android.networkstack.tethering;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.net.util.SharedLog;
|
||||
|
||||
/** FakeTetheringConfiguration is used to override static method for testing. */
|
||||
public class FakeTetheringConfiguration extends TetheringConfiguration {
|
||||
FakeTetheringConfiguration(Context ctx, SharedLog log, int id) {
|
||||
super(ctx, log, id);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getDeviceConfigProperty(final String name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isFeatureEnabled(Context ctx, String featureVersionFlag) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Resources getResourcesForSubIdWrapper(Context ctx, int subId) {
|
||||
return ctx.getResources();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getSettingsValue(final String name) {
|
||||
if (mContentResolver == null) return null;
|
||||
|
||||
return super.getSettingsValue(name);
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,9 @@ import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
|
||||
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
|
||||
import static com.android.networkstack.tethering.TetheringConfiguration.TETHER_FORCE_USB_FUNCTIONS;
|
||||
import static com.android.networkstack.tethering.TetheringConfiguration.TETHER_USB_NCM_FUNCTION;
|
||||
import static com.android.networkstack.tethering.TetheringConfiguration.TETHER_USB_RNDIS_FUNCTION;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
@@ -35,6 +38,7 @@ import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.ModuleInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
@@ -42,12 +46,15 @@ import android.content.res.Resources;
|
||||
import android.net.util.SharedLog;
|
||||
import android.os.Build;
|
||||
import android.provider.DeviceConfig;
|
||||
import android.provider.Settings;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.test.mock.MockContentResolver;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.internal.util.test.BroadcastInterceptingContext;
|
||||
import com.android.internal.util.test.FakeSettingsProvider;
|
||||
import com.android.net.module.util.DeviceConfigUtils;
|
||||
import com.android.testutils.DevSdkIgnoreRule;
|
||||
import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter;
|
||||
@@ -78,6 +85,7 @@ public class TetheringConfigurationTest {
|
||||
private static final String TEST_PACKAGE_NAME = "com.android.tethering.test";
|
||||
private static final String APEX_NAME = "com.android.tethering";
|
||||
private static final long TEST_PACKAGE_VERSION = 1234L;
|
||||
@Mock private ApplicationInfo mApplicationInfo;
|
||||
@Mock private Context mContext;
|
||||
@Mock private TelephonyManager mTelephonyManager;
|
||||
@Mock private Resources mResources;
|
||||
@@ -88,6 +96,7 @@ public class TetheringConfigurationTest {
|
||||
private boolean mHasTelephonyManager;
|
||||
private boolean mEnableLegacyDhcpServer;
|
||||
private MockitoSession mMockingSession;
|
||||
private MockContentResolver mContentResolver;
|
||||
|
||||
private class MockTetheringConfiguration extends TetheringConfiguration {
|
||||
MockTetheringConfiguration(Context ctx, SharedLog log, int id) {
|
||||
@@ -105,6 +114,11 @@ public class TetheringConfigurationTest {
|
||||
super(base);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApplicationInfo getApplicationInfo() {
|
||||
return mApplicationInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Resources getResources() {
|
||||
return mResources;
|
||||
@@ -153,7 +167,8 @@ public class TetheringConfigurationTest {
|
||||
new String[0]);
|
||||
when(mResources.getInteger(R.integer.config_tether_offload_poll_interval)).thenReturn(
|
||||
TetheringConfiguration.DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS);
|
||||
when(mResources.getStringArray(R.array.config_tether_usb_regexs)).thenReturn(new String[0]);
|
||||
when(mResources.getStringArray(R.array.config_tether_usb_regexs))
|
||||
.thenReturn(new String[]{ "test_usb\\d" });
|
||||
when(mResources.getStringArray(R.array.config_tether_wifi_regexs))
|
||||
.thenReturn(new String[]{ "test_wlan\\d" });
|
||||
when(mResources.getStringArray(R.array.config_tether_bluetooth_regexs)).thenReturn(
|
||||
@@ -171,12 +186,20 @@ public class TetheringConfigurationTest {
|
||||
mHasTelephonyManager = true;
|
||||
mMockContext = new MockContext(mContext);
|
||||
mEnableLegacyDhcpServer = false;
|
||||
|
||||
mContentResolver = new MockContentResolver(mMockContext);
|
||||
mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
|
||||
when(mContext.getContentResolver()).thenReturn(mContentResolver);
|
||||
// Call {@link #clearSettingsProvider()} before and after using FakeSettingsProvider.
|
||||
FakeSettingsProvider.clearSettingsProvider();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
mMockingSession.finishMocking();
|
||||
DeviceConfigUtils.resetPackageVersionCacheForTest();
|
||||
// Call {@link #clearSettingsProvider()} before and after using FakeSettingsProvider.
|
||||
FakeSettingsProvider.clearSettingsProvider();
|
||||
}
|
||||
|
||||
private TetheringConfiguration getTetheringConfiguration(int... legacyTetherUpstreamTypes) {
|
||||
@@ -539,4 +562,42 @@ public class TetheringConfigurationTest {
|
||||
assertEquals(value, new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID)
|
||||
.chooseUpstreamAutomatically);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUsbTetheringFunctions() throws Exception {
|
||||
// Test default value. If both resource and settings is not configured, usingNcm is false.
|
||||
assertIsUsingNcm(false /* usingNcm */);
|
||||
|
||||
when(mResources.getInteger(R.integer.config_tether_usb_functions)).thenReturn(
|
||||
TETHER_USB_NCM_FUNCTION);
|
||||
assertIsUsingNcm(true /* usingNcm */);
|
||||
|
||||
when(mResources.getInteger(R.integer.config_tether_usb_functions)).thenReturn(
|
||||
TETHER_USB_RNDIS_FUNCTION);
|
||||
assertIsUsingNcm(false /* usingNcm */);
|
||||
|
||||
setTetherForceUsbFunctions(TETHER_USB_RNDIS_FUNCTION);
|
||||
assertIsUsingNcm(false /* usingNcm */);
|
||||
|
||||
setTetherForceUsbFunctions(TETHER_USB_NCM_FUNCTION);
|
||||
assertIsUsingNcm(true /* usingNcm */);
|
||||
|
||||
// Test throws NumberFormatException.
|
||||
setTetherForceUsbFunctions("WrongNumberFormat");
|
||||
assertIsUsingNcm(false /* usingNcm */);
|
||||
}
|
||||
|
||||
private void assertIsUsingNcm(boolean expected) {
|
||||
final TetheringConfiguration cfg =
|
||||
new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
|
||||
assertEquals(expected, cfg.isUsingNcm());
|
||||
}
|
||||
|
||||
private void setTetherForceUsbFunctions(final String value) {
|
||||
Settings.Global.putString(mContentResolver, TETHER_FORCE_USB_FUNCTIONS, value);
|
||||
}
|
||||
|
||||
private void setTetherForceUsbFunctions(final int value) {
|
||||
setTetherForceUsbFunctions(Integer.toString(value));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ import static android.net.TetheringManager.TETHERING_WIFI;
|
||||
import static android.net.TetheringManager.TETHERING_WIFI_P2P;
|
||||
import static android.net.TetheringManager.TETHER_ERROR_IFACE_CFG_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_UNKNOWN_IFACE;
|
||||
import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_FAILED;
|
||||
import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STARTED;
|
||||
@@ -65,6 +66,9 @@ import static com.android.net.module.util.Inet4AddressUtils.intToInet4AddressHTH
|
||||
import static com.android.networkstack.tethering.TestConnectivityManager.BROADCAST_FIRST;
|
||||
import static com.android.networkstack.tethering.TestConnectivityManager.CALLBACKS_FIRST;
|
||||
import static com.android.networkstack.tethering.Tethering.UserRestrictionActionListener;
|
||||
import static com.android.networkstack.tethering.TetheringConfiguration.TETHER_FORCE_USB_FUNCTIONS;
|
||||
import static com.android.networkstack.tethering.TetheringConfiguration.TETHER_USB_NCM_FUNCTION;
|
||||
import static com.android.networkstack.tethering.TetheringConfiguration.TETHER_USB_RNDIS_FUNCTION;
|
||||
import static com.android.networkstack.tethering.TetheringNotificationUpdater.DOWNSTREAM_NONE;
|
||||
import static com.android.networkstack.tethering.UpstreamNetworkMonitor.EVENT_ON_CAPABILITIES;
|
||||
import static com.android.testutils.TestPermissionUtil.runAsShell;
|
||||
@@ -106,6 +110,7 @@ import android.content.IntentFilter;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Resources;
|
||||
import android.database.ContentObserver;
|
||||
import android.hardware.usb.UsbManager;
|
||||
import android.net.ConnectivityManager.NetworkCallback;
|
||||
import android.net.EthernetManager;
|
||||
@@ -178,7 +183,6 @@ import com.android.networkstack.tethering.TestConnectivityManager.TestNetworkAge
|
||||
import com.android.testutils.MiscAsserts;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
@@ -207,7 +211,7 @@ public class TetheringTest {
|
||||
private static final String TEST_MOBILE_IFNAME = "test_rmnet_data0";
|
||||
private static final String TEST_DUN_IFNAME = "test_dun0";
|
||||
private static final String TEST_XLAT_MOBILE_IFNAME = "v4-test_rmnet_data0";
|
||||
private static final String TEST_USB_IFNAME = "test_rndis0";
|
||||
private static final String TEST_RNDIS_IFNAME = "test_rndis0";
|
||||
private static final String TEST_WIFI_IFNAME = "test_wlan0";
|
||||
private static final String TEST_WLAN_IFNAME = "test_wlan1";
|
||||
private static final String TEST_P2P_IFNAME = "test_p2p-p2p0-0";
|
||||
@@ -217,6 +221,11 @@ public class TetheringTest {
|
||||
private static final String TETHERING_NAME = "Tethering";
|
||||
private static final String[] PROVISIONING_APP_NAME = {"some", "app"};
|
||||
private static final String PROVISIONING_NO_UI_APP_NAME = "no_ui_app";
|
||||
private static final String TEST_RNDIS_REGEX = "test_rndis\\d";
|
||||
private static final String TEST_NCM_REGEX = "test_ncm\\d";
|
||||
private static final String TEST_WIFI_REGEX = "test_wlan\\d";
|
||||
private static final String TEST_P2P_REGEX = "test_p2p-p2p\\d-.*";
|
||||
private static final String TEST_BT_REGEX = "test_pan\\d";
|
||||
|
||||
private static final int CELLULAR_NETID = 100;
|
||||
private static final int WIFI_NETID = 101;
|
||||
@@ -339,7 +348,7 @@ public class TetheringTest {
|
||||
@Override
|
||||
public InterfaceParams getInterfaceParams(String ifName) {
|
||||
assertTrue("Non-mocked interface " + ifName,
|
||||
ifName.equals(TEST_USB_IFNAME)
|
||||
ifName.equals(TEST_RNDIS_IFNAME)
|
||||
|| ifName.equals(TEST_WLAN_IFNAME)
|
||||
|| ifName.equals(TEST_WIFI_IFNAME)
|
||||
|| ifName.equals(TEST_MOBILE_IFNAME)
|
||||
@@ -349,7 +358,7 @@ public class TetheringTest {
|
||||
|| ifName.equals(TEST_ETH_IFNAME)
|
||||
|| ifName.equals(TEST_BT_IFNAME));
|
||||
final String[] ifaces = new String[] {
|
||||
TEST_USB_IFNAME, TEST_WLAN_IFNAME, TEST_WIFI_IFNAME, TEST_MOBILE_IFNAME,
|
||||
TEST_RNDIS_IFNAME, TEST_WLAN_IFNAME, TEST_WIFI_IFNAME, TEST_MOBILE_IFNAME,
|
||||
TEST_DUN_IFNAME, TEST_P2P_IFNAME, TEST_NCM_IFNAME, TEST_ETH_IFNAME};
|
||||
return new InterfaceParams(ifName, ArrayUtils.indexOf(ifaces, ifName) + IFINDEX_OFFSET,
|
||||
MacAddress.ALL_ZEROS_ADDRESS);
|
||||
@@ -373,28 +382,6 @@ public class TetheringTest {
|
||||
}
|
||||
}
|
||||
|
||||
// MyTetheringConfiguration is used to override static method for testing.
|
||||
private class MyTetheringConfiguration extends TetheringConfiguration {
|
||||
MyTetheringConfiguration(Context ctx, SharedLog log, int id) {
|
||||
super(ctx, log, id);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getDeviceConfigProperty(final String name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isFeatureEnabled(Context ctx, String featureVersionFlag) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Resources getResourcesForSubIdWrapper(Context ctx, int subId) {
|
||||
return mResources;
|
||||
}
|
||||
}
|
||||
|
||||
public class MockTetheringDependencies extends TetheringDependencies {
|
||||
StateMachine mUpstreamNetworkMonitorSM;
|
||||
ArrayList<IpServer> mIpv6CoordinatorNotifyList;
|
||||
@@ -456,7 +443,7 @@ public class TetheringTest {
|
||||
@Override
|
||||
public TetheringConfiguration generateTetheringConfiguration(Context ctx, SharedLog log,
|
||||
int subId) {
|
||||
mConfig = spy(new MyTetheringConfiguration(ctx, log, subId));
|
||||
mConfig = spy(new FakeTetheringConfiguration(ctx, log, subId));
|
||||
return mConfig;
|
||||
}
|
||||
|
||||
@@ -585,18 +572,13 @@ public class TetheringTest {
|
||||
new Network(DUN_NETID));
|
||||
}
|
||||
|
||||
// See FakeSettingsProvider#clearSettingsProvider() that this needs to be called before and
|
||||
// after use.
|
||||
// See FakeSettingsProvider#clearSettingsProvider() that this also needs to be called before
|
||||
// use.
|
||||
@BeforeClass
|
||||
public static void setupOnce() {
|
||||
FakeSettingsProvider.clearSettingsProvider();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void tearDownOnce() {
|
||||
FakeSettingsProvider.clearSettingsProvider();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
@@ -606,7 +588,7 @@ public class TetheringTest {
|
||||
false);
|
||||
when(mNetd.interfaceGetList())
|
||||
.thenReturn(new String[] {
|
||||
TEST_MOBILE_IFNAME, TEST_WLAN_IFNAME, TEST_USB_IFNAME, TEST_P2P_IFNAME,
|
||||
TEST_MOBILE_IFNAME, TEST_WLAN_IFNAME, TEST_RNDIS_IFNAME, TEST_P2P_IFNAME,
|
||||
TEST_NCM_IFNAME, TEST_ETH_IFNAME, TEST_BT_IFNAME});
|
||||
when(mResources.getString(R.string.config_wifi_tether_enable)).thenReturn("");
|
||||
mInterfaceConfiguration = new InterfaceConfigurationParcel();
|
||||
@@ -659,17 +641,19 @@ public class TetheringTest {
|
||||
supported ? 1 : 0);
|
||||
when(mUserManager.hasUserRestriction(
|
||||
UserManager.DISALLOW_CONFIG_TETHERING)).thenReturn(!supported);
|
||||
when(mResources.getInteger(R.integer.config_tether_usb_functions)).thenReturn(
|
||||
TetheringConfiguration.TETHER_USB_RNDIS_FUNCTION);
|
||||
// Setup tetherable configuration.
|
||||
when(mResources.getStringArray(R.array.config_tether_usb_regexs))
|
||||
.thenReturn(new String[] { "test_rndis\\d" });
|
||||
.thenReturn(new String[] { TEST_RNDIS_REGEX});
|
||||
when(mResources.getStringArray(R.array.config_tether_wifi_regexs))
|
||||
.thenReturn(new String[] { "test_wlan\\d" });
|
||||
.thenReturn(new String[] { TEST_WIFI_REGEX });
|
||||
when(mResources.getStringArray(R.array.config_tether_wifi_p2p_regexs))
|
||||
.thenReturn(new String[] { "test_p2p-p2p\\d-.*" });
|
||||
.thenReturn(new String[] { TEST_P2P_REGEX });
|
||||
when(mResources.getStringArray(R.array.config_tether_bluetooth_regexs))
|
||||
.thenReturn(new String[] { "test_pan\\d" });
|
||||
.thenReturn(new String[] { TEST_BT_REGEX });
|
||||
when(mResources.getStringArray(R.array.config_tether_ncm_regexs))
|
||||
.thenReturn(new String[] { "test_ncm\\d" });
|
||||
.thenReturn(new String[] { TEST_NCM_REGEX });
|
||||
when(mResources.getIntArray(R.array.config_tether_upstream_types)).thenReturn(
|
||||
new int[] { TYPE_WIFI, TYPE_MOBILE_DUN });
|
||||
when(mResources.getBoolean(R.bool.config_tether_upstream_automatic)).thenReturn(true);
|
||||
@@ -705,6 +689,7 @@ public class TetheringTest {
|
||||
@After
|
||||
public void tearDown() {
|
||||
mServiceContext.unregisterReceiver(mBroadcastReceiver);
|
||||
FakeSettingsProvider.clearSettingsProvider();
|
||||
}
|
||||
|
||||
private void sendWifiApStateChanged(int state) {
|
||||
@@ -750,16 +735,18 @@ public class TetheringTest {
|
||||
mLooper.dispatchAll();
|
||||
}
|
||||
|
||||
private void sendUsbBroadcast(boolean connected, boolean configured, boolean function,
|
||||
int type) {
|
||||
private boolean tetherUsbFunctionMatches(int function, int enabledType) {
|
||||
return function == enabledType;
|
||||
}
|
||||
|
||||
private void sendUsbBroadcast(boolean connected, boolean configured, int function) {
|
||||
final Intent intent = new Intent(UsbManager.ACTION_USB_STATE);
|
||||
intent.putExtra(USB_CONNECTED, connected);
|
||||
intent.putExtra(USB_CONFIGURED, configured);
|
||||
if (type == TETHERING_USB) {
|
||||
intent.putExtra(USB_FUNCTION_RNDIS, function);
|
||||
} else {
|
||||
intent.putExtra(USB_FUNCTION_NCM, function);
|
||||
}
|
||||
intent.putExtra(USB_FUNCTION_RNDIS,
|
||||
tetherUsbFunctionMatches(TETHER_USB_RNDIS_FUNCTION, function));
|
||||
intent.putExtra(USB_FUNCTION_NCM,
|
||||
tetherUsbFunctionMatches(TETHER_USB_NCM_FUNCTION, function));
|
||||
mServiceContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
|
||||
mLooper.dispatchAll();
|
||||
}
|
||||
@@ -834,11 +821,18 @@ public class TetheringTest {
|
||||
final TetheringRequestParcel request = createTetheringRequestParcel(TETHERING_USB);
|
||||
mTethering.startTethering(request, null);
|
||||
mLooper.dispatchAll();
|
||||
verify(mUsbManager, times(1)).setCurrentFunctions(UsbManager.FUNCTION_RNDIS);
|
||||
|
||||
assertEquals(1, mTethering.getActiveTetheringRequests().size());
|
||||
assertEquals(request, mTethering.getActiveTetheringRequests().get(TETHERING_USB));
|
||||
|
||||
mTethering.interfaceStatusChanged(TEST_USB_IFNAME, true);
|
||||
if (mTethering.getTetheringConfiguration().isUsingNcm()) {
|
||||
verify(mUsbManager).setCurrentFunctions(UsbManager.FUNCTION_NCM);
|
||||
mTethering.interfaceStatusChanged(TEST_NCM_IFNAME, true);
|
||||
} else {
|
||||
verify(mUsbManager).setCurrentFunctions(UsbManager.FUNCTION_RNDIS);
|
||||
mTethering.interfaceStatusChanged(TEST_RNDIS_IFNAME, true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -851,7 +845,7 @@ public class TetheringTest {
|
||||
verifyNoMoreInteractions(mNetd);
|
||||
|
||||
// Pretend we then receive USB configured broadcast.
|
||||
sendUsbBroadcast(true, true, true, TETHERING_USB);
|
||||
sendUsbBroadcast(true, true, TETHER_USB_RNDIS_FUNCTION);
|
||||
// Now we should see the start of tethering mechanics (in this case:
|
||||
// tetherMatchingInterfaces() which starts by fetching all interfaces).
|
||||
verify(mNetd, times(1)).interfaceGetList();
|
||||
@@ -923,16 +917,13 @@ public class TetheringTest {
|
||||
*/
|
||||
private void sendIPv6TetherUpdates(UpstreamNetworkState upstreamState) {
|
||||
// IPv6TetheringCoordinator must have been notified of downstream
|
||||
verify(mIPv6TetheringCoordinator, times(1)).addActiveDownstream(
|
||||
argThat(sm -> sm.linkProperties().getInterfaceName().equals(TEST_USB_IFNAME)),
|
||||
eq(IpServer.STATE_TETHERED));
|
||||
|
||||
for (IpServer ipSrv : mTetheringDependencies.mIpv6CoordinatorNotifyList) {
|
||||
UpstreamNetworkState ipv6OnlyState = buildMobileUpstreamState(false, true, false);
|
||||
ipSrv.sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, 0, 0,
|
||||
upstreamState.linkProperties.isIpv6Provisioned()
|
||||
? ipv6OnlyState.linkProperties
|
||||
: null);
|
||||
break;
|
||||
}
|
||||
mLooper.dispatchAll();
|
||||
}
|
||||
@@ -940,7 +931,18 @@ public class TetheringTest {
|
||||
private void runUsbTethering(UpstreamNetworkState upstreamState) {
|
||||
initTetheringUpstream(upstreamState);
|
||||
prepareUsbTethering();
|
||||
sendUsbBroadcast(true, true, true, TETHERING_USB);
|
||||
if (mTethering.getTetheringConfiguration().isUsingNcm()) {
|
||||
sendUsbBroadcast(true, true, TETHER_USB_NCM_FUNCTION);
|
||||
verify(mIPv6TetheringCoordinator).addActiveDownstream(
|
||||
argThat(sm -> sm.linkProperties().getInterfaceName().equals(TEST_NCM_IFNAME)),
|
||||
eq(IpServer.STATE_TETHERED));
|
||||
} else {
|
||||
sendUsbBroadcast(true, true, TETHER_USB_RNDIS_FUNCTION);
|
||||
verify(mIPv6TetheringCoordinator).addActiveDownstream(
|
||||
argThat(sm -> sm.linkProperties().getInterfaceName().equals(TEST_RNDIS_IFNAME)),
|
||||
eq(IpServer.STATE_TETHERED));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void assertSetIfaceToDadProxy(final int numOfCalls, final String ifaceName) {
|
||||
@@ -956,8 +958,8 @@ public class TetheringTest {
|
||||
UpstreamNetworkState upstreamState = buildMobileIPv4UpstreamState();
|
||||
runUsbTethering(upstreamState);
|
||||
|
||||
verify(mNetd, times(1)).tetherAddForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
|
||||
verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
|
||||
verify(mNetd, times(1)).tetherAddForward(TEST_RNDIS_IFNAME, TEST_MOBILE_IFNAME);
|
||||
verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_RNDIS_IFNAME, TEST_MOBILE_IFNAME);
|
||||
|
||||
sendIPv6TetherUpdates(upstreamState);
|
||||
assertSetIfaceToDadProxy(0 /* numOfCalls */, "" /* ifaceName */);
|
||||
@@ -983,8 +985,8 @@ public class TetheringTest {
|
||||
UpstreamNetworkState upstreamState = buildMobileIPv6UpstreamState();
|
||||
runUsbTethering(upstreamState);
|
||||
|
||||
verify(mNetd, times(1)).tetherAddForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
|
||||
verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
|
||||
verify(mNetd, times(1)).tetherAddForward(TEST_RNDIS_IFNAME, TEST_MOBILE_IFNAME);
|
||||
verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_RNDIS_IFNAME, TEST_MOBILE_IFNAME);
|
||||
|
||||
sendIPv6TetherUpdates(upstreamState);
|
||||
// TODO: add interfaceParams to compare in verify.
|
||||
@@ -998,8 +1000,8 @@ public class TetheringTest {
|
||||
UpstreamNetworkState upstreamState = buildMobileDualStackUpstreamState();
|
||||
runUsbTethering(upstreamState);
|
||||
|
||||
verify(mNetd, times(1)).tetherAddForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
|
||||
verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
|
||||
verify(mNetd, times(1)).tetherAddForward(TEST_RNDIS_IFNAME, TEST_MOBILE_IFNAME);
|
||||
verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_RNDIS_IFNAME, TEST_MOBILE_IFNAME);
|
||||
verify(mRouterAdvertisementDaemon, times(1)).start();
|
||||
verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).startWithCallbacks(
|
||||
any(), any());
|
||||
@@ -1015,12 +1017,13 @@ public class TetheringTest {
|
||||
UpstreamNetworkState upstreamState = buildMobile464xlatUpstreamState();
|
||||
runUsbTethering(upstreamState);
|
||||
|
||||
verify(mNetd, times(1)).tetherAddForward(TEST_USB_IFNAME, TEST_XLAT_MOBILE_IFNAME);
|
||||
verify(mNetd, times(1)).tetherAddForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
|
||||
verify(mNetd, times(1)).tetherAddForward(TEST_RNDIS_IFNAME, TEST_XLAT_MOBILE_IFNAME);
|
||||
verify(mNetd, times(1)).tetherAddForward(TEST_RNDIS_IFNAME, TEST_MOBILE_IFNAME);
|
||||
verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).startWithCallbacks(
|
||||
any(), any());
|
||||
verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_XLAT_MOBILE_IFNAME);
|
||||
verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
|
||||
verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_RNDIS_IFNAME,
|
||||
TEST_XLAT_MOBILE_IFNAME);
|
||||
verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_RNDIS_IFNAME, TEST_MOBILE_IFNAME);
|
||||
|
||||
sendIPv6TetherUpdates(upstreamState);
|
||||
assertSetIfaceToDadProxy(1 /* numOfCalls */, TEST_MOBILE_IFNAME /* ifaceName */);
|
||||
@@ -1030,14 +1033,20 @@ public class TetheringTest {
|
||||
|
||||
@Test
|
||||
public void workingMobileUsbTethering_v6Then464xlat() throws Exception {
|
||||
when(mResources.getInteger(R.integer.config_tether_usb_functions)).thenReturn(
|
||||
TetheringConfiguration.TETHER_USB_NCM_FUNCTION);
|
||||
when(mResources.getStringArray(R.array.config_tether_usb_regexs))
|
||||
.thenReturn(new String[] {TEST_NCM_REGEX});
|
||||
sendConfigurationChanged();
|
||||
|
||||
// Setup IPv6
|
||||
UpstreamNetworkState upstreamState = buildMobileIPv6UpstreamState();
|
||||
runUsbTethering(upstreamState);
|
||||
|
||||
verify(mNetd, times(1)).tetherAddForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
|
||||
verify(mNetd, times(1)).tetherAddForward(TEST_NCM_IFNAME, TEST_MOBILE_IFNAME);
|
||||
verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).startWithCallbacks(
|
||||
any(), any());
|
||||
verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
|
||||
verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_NCM_IFNAME, TEST_MOBILE_IFNAME);
|
||||
|
||||
// Then 464xlat comes up
|
||||
upstreamState = buildMobile464xlatUpstreamState();
|
||||
@@ -1052,11 +1061,12 @@ public class TetheringTest {
|
||||
mLooper.dispatchAll();
|
||||
|
||||
// Forwarding is added for 464xlat
|
||||
verify(mNetd, times(1)).tetherAddForward(TEST_USB_IFNAME, TEST_XLAT_MOBILE_IFNAME);
|
||||
verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_XLAT_MOBILE_IFNAME);
|
||||
verify(mNetd, times(1)).tetherAddForward(TEST_NCM_IFNAME, TEST_XLAT_MOBILE_IFNAME);
|
||||
verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_NCM_IFNAME,
|
||||
TEST_XLAT_MOBILE_IFNAME);
|
||||
// Forwarding was not re-added for v6 (still times(1))
|
||||
verify(mNetd, times(1)).tetherAddForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
|
||||
verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
|
||||
verify(mNetd, times(1)).tetherAddForward(TEST_NCM_IFNAME, TEST_MOBILE_IFNAME);
|
||||
verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_NCM_IFNAME, TEST_MOBILE_IFNAME);
|
||||
// DHCP not restarted on downstream (still times(1))
|
||||
verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).startWithCallbacks(
|
||||
any(), any());
|
||||
@@ -1093,7 +1103,7 @@ public class TetheringTest {
|
||||
|
||||
// Start USB tethering with no current upstream.
|
||||
prepareUsbTethering();
|
||||
sendUsbBroadcast(true, true, true, TETHERING_USB);
|
||||
sendUsbBroadcast(true, true, TETHER_USB_RNDIS_FUNCTION);
|
||||
inOrder.verify(mUpstreamNetworkMonitor).startObserveAllNetworks();
|
||||
inOrder.verify(mUpstreamNetworkMonitor).setTryCell(true);
|
||||
|
||||
@@ -1308,7 +1318,7 @@ public class TetheringTest {
|
||||
|
||||
// Start USB tethering with no current upstream.
|
||||
prepareUsbTethering();
|
||||
sendUsbBroadcast(true, true, true, TETHERING_USB);
|
||||
sendUsbBroadcast(true, true, TETHER_USB_RNDIS_FUNCTION);
|
||||
inOrder.verify(mUpstreamNetworkMonitor).startObserveAllNetworks();
|
||||
inOrder.verify(mUpstreamNetworkMonitor).setTryCell(true);
|
||||
ArgumentCaptor<NetworkCallback> captor = ArgumentCaptor.forClass(NetworkCallback.class);
|
||||
@@ -1342,7 +1352,7 @@ public class TetheringTest {
|
||||
|
||||
private void runNcmTethering() {
|
||||
prepareNcmTethering();
|
||||
sendUsbBroadcast(true, true, true, TETHERING_NCM);
|
||||
sendUsbBroadcast(true, true, TETHER_USB_NCM_FUNCTION);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1622,7 +1632,7 @@ public class TetheringTest {
|
||||
// Start usb tethering and check that usb interface is tethered.
|
||||
final UpstreamNetworkState upstreamState = buildMobileIPv4UpstreamState();
|
||||
runUsbTethering(upstreamState);
|
||||
assertContains(Arrays.asList(mTethering.getTetheredIfaces()), TEST_USB_IFNAME);
|
||||
assertContains(Arrays.asList(mTethering.getTetheredIfaces()), TEST_RNDIS_IFNAME);
|
||||
assertTrue(mTethering.isTetheringActive());
|
||||
assertEquals(0, mTethering.getActiveTetheringRequests().size());
|
||||
|
||||
@@ -1862,7 +1872,7 @@ public class TetheringTest {
|
||||
callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_FAILED);
|
||||
runStopUSBTethering();
|
||||
callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED);
|
||||
reset(mUsbManager);
|
||||
reset(mUsbManager, mIPv6TetheringCoordinator);
|
||||
// 2. Offload fail if no OffloadControl.
|
||||
initOffloadConfiguration(true /* offloadConfig */, false /* offloadControl */,
|
||||
0 /* defaultDisabled */);
|
||||
@@ -1870,7 +1880,7 @@ public class TetheringTest {
|
||||
callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_FAILED);
|
||||
runStopUSBTethering();
|
||||
callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED);
|
||||
reset(mUsbManager);
|
||||
reset(mUsbManager, mIPv6TetheringCoordinator);
|
||||
// 3. Offload fail if disabled by settings.
|
||||
initOffloadConfiguration(true /* offloadConfig */, true /* offloadControl */,
|
||||
1 /* defaultDisabled */);
|
||||
@@ -1883,8 +1893,10 @@ public class TetheringTest {
|
||||
private void runStopUSBTethering() {
|
||||
mTethering.stopTethering(TETHERING_USB);
|
||||
mLooper.dispatchAll();
|
||||
mTethering.interfaceRemoved(TEST_USB_IFNAME);
|
||||
mTethering.interfaceRemoved(TEST_RNDIS_IFNAME);
|
||||
sendUsbBroadcast(true, true, -1 /* function */);
|
||||
mLooper.dispatchAll();
|
||||
verify(mUsbManager).setCurrentFunctions(UsbManager.FUNCTION_NONE);
|
||||
}
|
||||
|
||||
private void initOffloadConfiguration(final boolean offloadConfig,
|
||||
@@ -2059,29 +2071,29 @@ public class TetheringTest {
|
||||
// Start Tethering.
|
||||
final UpstreamNetworkState upstreamState = buildMobileIPv4UpstreamState();
|
||||
runUsbTethering(upstreamState);
|
||||
assertContains(Arrays.asList(mTethering.getTetheredIfaces()), TEST_USB_IFNAME);
|
||||
assertContains(Arrays.asList(mTethering.getTetheredIfaces()), TEST_RNDIS_IFNAME);
|
||||
// Data saver is ON.
|
||||
setDataSaverEnabled(true);
|
||||
// Verify that tethering should be disabled.
|
||||
verify(mUsbManager, times(1)).setCurrentFunctions(UsbManager.FUNCTION_NONE);
|
||||
mTethering.interfaceRemoved(TEST_USB_IFNAME);
|
||||
mTethering.interfaceRemoved(TEST_RNDIS_IFNAME);
|
||||
mLooper.dispatchAll();
|
||||
assertEquals(mTethering.getTetheredIfaces(), new String[0]);
|
||||
reset(mUsbManager);
|
||||
reset(mUsbManager, mIPv6TetheringCoordinator);
|
||||
|
||||
runUsbTethering(upstreamState);
|
||||
// Verify that user can start tethering again without turning OFF data saver.
|
||||
assertContains(Arrays.asList(mTethering.getTetheredIfaces()), TEST_USB_IFNAME);
|
||||
assertContains(Arrays.asList(mTethering.getTetheredIfaces()), TEST_RNDIS_IFNAME);
|
||||
|
||||
// If data saver is keep ON with change event, tethering should not be OFF this time.
|
||||
setDataSaverEnabled(true);
|
||||
verify(mUsbManager, times(0)).setCurrentFunctions(UsbManager.FUNCTION_NONE);
|
||||
assertContains(Arrays.asList(mTethering.getTetheredIfaces()), TEST_USB_IFNAME);
|
||||
assertContains(Arrays.asList(mTethering.getTetheredIfaces()), TEST_RNDIS_IFNAME);
|
||||
|
||||
// If data saver is turned OFF, it should not change tethering.
|
||||
setDataSaverEnabled(false);
|
||||
verify(mUsbManager, times(0)).setCurrentFunctions(UsbManager.FUNCTION_NONE);
|
||||
assertContains(Arrays.asList(mTethering.getTetheredIfaces()), TEST_USB_IFNAME);
|
||||
assertContains(Arrays.asList(mTethering.getTetheredIfaces()), TEST_RNDIS_IFNAME);
|
||||
}
|
||||
|
||||
private static <T> void assertContains(Collection<T> collection, T element) {
|
||||
@@ -2141,8 +2153,8 @@ public class TetheringTest {
|
||||
verify(mUsbManager, times(1)).setCurrentFunctions(UsbManager.FUNCTION_RNDIS);
|
||||
|
||||
// Expect that when USB comes up, the DHCP server is configured with the requested address.
|
||||
mTethering.interfaceStatusChanged(TEST_USB_IFNAME, true);
|
||||
sendUsbBroadcast(true, true, true, TETHERING_USB);
|
||||
mTethering.interfaceStatusChanged(TEST_RNDIS_IFNAME, true);
|
||||
sendUsbBroadcast(true, true, TETHER_USB_RNDIS_FUNCTION);
|
||||
verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).startWithCallbacks(
|
||||
any(), any());
|
||||
verify(mNetd).interfaceSetCfg(argThat(cfg -> serverAddr.equals(cfg.ipv4Addr)));
|
||||
@@ -2150,6 +2162,12 @@ public class TetheringTest {
|
||||
|
||||
@Test
|
||||
public void testRequestStaticIp() throws Exception {
|
||||
when(mResources.getInteger(R.integer.config_tether_usb_functions)).thenReturn(
|
||||
TetheringConfiguration.TETHER_USB_NCM_FUNCTION);
|
||||
when(mResources.getStringArray(R.array.config_tether_usb_regexs))
|
||||
.thenReturn(new String[] {TEST_NCM_REGEX});
|
||||
sendConfigurationChanged();
|
||||
|
||||
final LinkAddress serverLinkAddr = new LinkAddress("192.168.0.123/24");
|
||||
final LinkAddress clientLinkAddr = new LinkAddress("192.168.0.42/24");
|
||||
final String serverAddr = "192.168.0.123";
|
||||
@@ -2159,9 +2177,9 @@ public class TetheringTest {
|
||||
mTethering.startTethering(createTetheringRequestParcel(TETHERING_USB,
|
||||
serverLinkAddr, clientLinkAddr, false, CONNECTIVITY_SCOPE_GLOBAL), null);
|
||||
mLooper.dispatchAll();
|
||||
verify(mUsbManager, times(1)).setCurrentFunctions(UsbManager.FUNCTION_RNDIS);
|
||||
mTethering.interfaceStatusChanged(TEST_USB_IFNAME, true);
|
||||
sendUsbBroadcast(true, true, true, TETHERING_USB);
|
||||
verify(mUsbManager, times(1)).setCurrentFunctions(UsbManager.FUNCTION_NCM);
|
||||
mTethering.interfaceStatusChanged(TEST_NCM_IFNAME, true);
|
||||
sendUsbBroadcast(true, true, TETHER_USB_NCM_FUNCTION);
|
||||
verify(mNetd).interfaceSetCfg(argThat(cfg -> serverAddr.equals(cfg.ipv4Addr)));
|
||||
verify(mIpServerDependencies, times(1)).makeDhcpServer(any(), dhcpParamsCaptor.capture(),
|
||||
any());
|
||||
@@ -2328,7 +2346,7 @@ public class TetheringTest {
|
||||
wifiNetwork, TEST_WIFI_IFNAME, TRANSPORT_WIFI);
|
||||
// verify turn off usb tethering
|
||||
verify(mUsbManager).setCurrentFunctions(UsbManager.FUNCTION_NONE);
|
||||
mTethering.interfaceRemoved(TEST_USB_IFNAME);
|
||||
mTethering.interfaceRemoved(TEST_RNDIS_IFNAME);
|
||||
mLooper.dispatchAll();
|
||||
// verify restart usb tethering
|
||||
verify(mUsbManager).setCurrentFunctions(UsbManager.FUNCTION_RNDIS);
|
||||
@@ -2369,7 +2387,7 @@ public class TetheringTest {
|
||||
verify(mUsbManager).setCurrentFunctions(UsbManager.FUNCTION_NONE);
|
||||
// verify turn off ethernet tethering
|
||||
verify(mockRequest).release();
|
||||
mTethering.interfaceRemoved(TEST_USB_IFNAME);
|
||||
mTethering.interfaceRemoved(TEST_RNDIS_IFNAME);
|
||||
ethCallback.onUnavailable();
|
||||
mLooper.dispatchAll();
|
||||
// verify restart usb tethering
|
||||
@@ -2382,14 +2400,15 @@ public class TetheringTest {
|
||||
reset(mUsbManager, mEm);
|
||||
when(mNetd.interfaceGetList())
|
||||
.thenReturn(new String[] {
|
||||
TEST_MOBILE_IFNAME, TEST_WLAN_IFNAME, TEST_USB_IFNAME, TEST_P2P_IFNAME,
|
||||
TEST_MOBILE_IFNAME, TEST_WLAN_IFNAME, TEST_RNDIS_IFNAME, TEST_P2P_IFNAME,
|
||||
TEST_NCM_IFNAME, TEST_ETH_IFNAME});
|
||||
|
||||
mTethering.interfaceStatusChanged(TEST_USB_IFNAME, true);
|
||||
sendUsbBroadcast(true, true, true, TETHERING_USB);
|
||||
assertContains(Arrays.asList(mTethering.getTetherableIfacesForTest()), TEST_USB_IFNAME);
|
||||
mTethering.interfaceStatusChanged(TEST_RNDIS_IFNAME, true);
|
||||
sendUsbBroadcast(true, true, TETHER_USB_RNDIS_FUNCTION);
|
||||
assertContains(Arrays.asList(mTethering.getTetherableIfacesForTest()), TEST_RNDIS_IFNAME);
|
||||
assertContains(Arrays.asList(mTethering.getTetherableIfacesForTest()), TEST_ETH_IFNAME);
|
||||
assertEquals(TETHER_ERROR_IFACE_CFG_ERROR, mTethering.getLastErrorForTest(TEST_USB_IFNAME));
|
||||
assertEquals(TETHER_ERROR_IFACE_CFG_ERROR, mTethering.getLastErrorForTest(
|
||||
TEST_RNDIS_IFNAME));
|
||||
assertEquals(TETHER_ERROR_IFACE_CFG_ERROR, mTethering.getLastErrorForTest(TEST_ETH_IFNAME));
|
||||
}
|
||||
|
||||
@@ -2580,6 +2599,46 @@ public class TetheringTest {
|
||||
reset(mBluetoothAdapter, mBluetoothPan);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUsbTetheringWithNcmFunction() throws Exception {
|
||||
when(mResources.getInteger(R.integer.config_tether_usb_functions)).thenReturn(
|
||||
TetheringConfiguration.TETHER_USB_NCM_FUNCTION);
|
||||
when(mResources.getStringArray(R.array.config_tether_usb_regexs))
|
||||
.thenReturn(new String[] {TEST_NCM_REGEX});
|
||||
sendConfigurationChanged();
|
||||
|
||||
// If TETHERING_USB is forced to use ncm function, TETHERING_NCM would no longer be
|
||||
// available.
|
||||
final ResultListener ncmResult = new ResultListener(TETHER_ERROR_SERVICE_UNAVAIL);
|
||||
mTethering.startTethering(createTetheringRequestParcel(TETHERING_NCM), ncmResult);
|
||||
mLooper.dispatchAll();
|
||||
ncmResult.assertHasResult();
|
||||
|
||||
final UpstreamNetworkState upstreamState = buildMobileDualStackUpstreamState();
|
||||
runUsbTethering(upstreamState);
|
||||
|
||||
verify(mNetd).interfaceGetList();
|
||||
verify(mNetd).tetherAddForward(TEST_NCM_IFNAME, TEST_MOBILE_IFNAME);
|
||||
verify(mNetd).ipfwdAddInterfaceForward(TEST_NCM_IFNAME, TEST_MOBILE_IFNAME);
|
||||
|
||||
verify(mRouterAdvertisementDaemon).start();
|
||||
verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS)).startWithCallbacks(
|
||||
any(), any());
|
||||
sendIPv6TetherUpdates(upstreamState);
|
||||
assertSetIfaceToDadProxy(1 /* numOfCalls */, TEST_MOBILE_IFNAME /* ifaceName */);
|
||||
verify(mRouterAdvertisementDaemon).buildNewRa(any(), notNull());
|
||||
verify(mNetd).tetherApplyDnsInterfaces();
|
||||
|
||||
Settings.Global.putInt(mContentResolver, TETHER_FORCE_USB_FUNCTIONS,
|
||||
TETHER_USB_RNDIS_FUNCTION);
|
||||
final ContentObserver observer = mTethering.getSettingsObserverForTest();
|
||||
observer.onChange(false /* selfChange */);
|
||||
mLooper.dispatchAll();
|
||||
// stop TETHERING_USB and TETHERING_NCM
|
||||
verify(mUsbManager, times(2)).setCurrentFunctions(UsbManager.FUNCTION_NONE);
|
||||
mTethering.interfaceRemoved(TEST_NCM_IFNAME);
|
||||
sendUsbBroadcast(true, true, -1 /* function */);
|
||||
}
|
||||
// TODO: Test that a request for hotspot mode doesn't interfere with an
|
||||
// already operating tethering mode interface.
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user