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