Merge changes I34842acd,Icc6c4d6b
* changes: Add support for Ethernet tethering Local Tethering with ncm interface
This commit is contained in:
@@ -130,6 +130,18 @@ public class TetheringManager {
|
|||||||
*/
|
*/
|
||||||
public static final int TETHERING_WIFI_P2P = 3;
|
public static final int TETHERING_WIFI_P2P = 3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ncm local tethering type.
|
||||||
|
* @see #startTethering(TetheringRequest, Executor, StartTetheringCallback)
|
||||||
|
*/
|
||||||
|
public static final int TETHERING_NCM = 4;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ethernet tethering type.
|
||||||
|
* @see #startTethering(TetheringRequest, Executor, StartTetheringCallback)
|
||||||
|
*/
|
||||||
|
public static final int TETHERING_ETHERNET = 5;
|
||||||
|
|
||||||
public static final int TETHER_ERROR_NO_ERROR = 0;
|
public static final int TETHER_ERROR_NO_ERROR = 0;
|
||||||
public static final int TETHER_ERROR_UNKNOWN_IFACE = 1;
|
public static final int TETHER_ERROR_UNKNOWN_IFACE = 1;
|
||||||
public static final int TETHER_ERROR_SERVICE_UNAVAIL = 2;
|
public static final int TETHER_ERROR_SERVICE_UNAVAIL = 2;
|
||||||
|
|||||||
@@ -28,6 +28,12 @@
|
|||||||
<item>"rndis\\d"</item>
|
<item>"rndis\\d"</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
|
<!-- List of regexpressions describing the interface (if any) that represent tetherable
|
||||||
|
NCM interfaces. If the device doesn't want to support tethering over NCM this should
|
||||||
|
be empty. -->
|
||||||
|
<string-array translatable="false" name="config_tether_ncm_regexs">
|
||||||
|
</string-array>
|
||||||
|
|
||||||
<!-- List of regexpressions describing the interface (if any) that represent tetherable
|
<!-- List of regexpressions describing the interface (if any) that represent tetherable
|
||||||
Wifi interfaces. If the device doesn't want to support tethering over Wifi this
|
Wifi interfaces. If the device doesn't want to support tethering over Wifi this
|
||||||
should be empty. An example would be "softap.*" -->
|
should be empty. An example would be "softap.*" -->
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
<overlayable name="TetheringConfig">
|
<overlayable name="TetheringConfig">
|
||||||
<policy type="product|system|vendor">
|
<policy type="product|system|vendor">
|
||||||
<item type="array" name="config_tether_usb_regexs"/>
|
<item type="array" name="config_tether_usb_regexs"/>
|
||||||
|
<item type="array" name="config_tether_ncm_regexs" />
|
||||||
<item type="array" name="config_tether_wifi_regexs"/>
|
<item type="array" name="config_tether_wifi_regexs"/>
|
||||||
<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"/>
|
||||||
|
|||||||
@@ -93,6 +93,8 @@ public class IpServer extends StateMachine {
|
|||||||
private static final int WIFI_HOST_IFACE_PREFIX_LENGTH = 24;
|
private static final int WIFI_HOST_IFACE_PREFIX_LENGTH = 24;
|
||||||
private static final String WIFI_P2P_IFACE_ADDR = "192.168.49.1";
|
private static final String WIFI_P2P_IFACE_ADDR = "192.168.49.1";
|
||||||
private static final int WIFI_P2P_IFACE_PREFIX_LENGTH = 24;
|
private static final int WIFI_P2P_IFACE_PREFIX_LENGTH = 24;
|
||||||
|
private static final String ETHERNET_IFACE_ADDR = "192.168.50.1";
|
||||||
|
private static final int ETHERNET_IFACE_PREFIX_LENGTH = 24;
|
||||||
|
|
||||||
// TODO: have PanService use some visible version of this constant
|
// TODO: have PanService use some visible version of this constant
|
||||||
private static final String BLUETOOTH_IFACE_ADDR = "192.168.44.1";
|
private static final String BLUETOOTH_IFACE_ADDR = "192.168.44.1";
|
||||||
@@ -416,7 +418,8 @@ public class IpServer extends StateMachine {
|
|||||||
final Inet4Address srvAddr;
|
final Inet4Address srvAddr;
|
||||||
int prefixLen = 0;
|
int prefixLen = 0;
|
||||||
try {
|
try {
|
||||||
if (mInterfaceType == TetheringManager.TETHERING_USB) {
|
if (mInterfaceType == TetheringManager.TETHERING_USB
|
||||||
|
|| mInterfaceType == TetheringManager.TETHERING_NCM) {
|
||||||
srvAddr = (Inet4Address) parseNumericAddress(USB_NEAR_IFACE_ADDR);
|
srvAddr = (Inet4Address) parseNumericAddress(USB_NEAR_IFACE_ADDR);
|
||||||
prefixLen = USB_PREFIX_LENGTH;
|
prefixLen = USB_PREFIX_LENGTH;
|
||||||
} else if (mInterfaceType == TetheringManager.TETHERING_WIFI) {
|
} else if (mInterfaceType == TetheringManager.TETHERING_WIFI) {
|
||||||
@@ -425,6 +428,10 @@ public class IpServer extends StateMachine {
|
|||||||
} else if (mInterfaceType == TetheringManager.TETHERING_WIFI_P2P) {
|
} else if (mInterfaceType == TetheringManager.TETHERING_WIFI_P2P) {
|
||||||
srvAddr = (Inet4Address) parseNumericAddress(WIFI_P2P_IFACE_ADDR);
|
srvAddr = (Inet4Address) parseNumericAddress(WIFI_P2P_IFACE_ADDR);
|
||||||
prefixLen = WIFI_P2P_IFACE_PREFIX_LENGTH;
|
prefixLen = WIFI_P2P_IFACE_PREFIX_LENGTH;
|
||||||
|
} else if (mInterfaceType == TetheringManager.TETHERING_ETHERNET) {
|
||||||
|
// TODO: randomize address for tethering too, similarly to wifi
|
||||||
|
srvAddr = (Inet4Address) parseNumericAddress(ETHERNET_IFACE_ADDR);
|
||||||
|
prefixLen = ETHERNET_IFACE_PREFIX_LENGTH;
|
||||||
} else {
|
} else {
|
||||||
// BT configures the interface elsewhere: only start DHCP.
|
// BT configures the interface elsewhere: only start DHCP.
|
||||||
// TODO: make all tethering types behave the same way, and delete the bluetooth
|
// TODO: make all tethering types behave the same way, and delete the bluetooth
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ package com.android.server.connectivity.tethering;
|
|||||||
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
|
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
|
||||||
import static android.hardware.usb.UsbManager.USB_CONFIGURED;
|
import static android.hardware.usb.UsbManager.USB_CONFIGURED;
|
||||||
import static android.hardware.usb.UsbManager.USB_CONNECTED;
|
import static android.hardware.usb.UsbManager.USB_CONNECTED;
|
||||||
|
import static android.hardware.usb.UsbManager.USB_FUNCTION_NCM;
|
||||||
import static android.hardware.usb.UsbManager.USB_FUNCTION_RNDIS;
|
import static android.hardware.usb.UsbManager.USB_FUNCTION_RNDIS;
|
||||||
import static android.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED;
|
import static android.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED;
|
||||||
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
|
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
|
||||||
@@ -29,7 +30,9 @@ import static android.net.TetheringManager.EXTRA_ACTIVE_TETHER;
|
|||||||
import static android.net.TetheringManager.EXTRA_AVAILABLE_TETHER;
|
import static android.net.TetheringManager.EXTRA_AVAILABLE_TETHER;
|
||||||
import static android.net.TetheringManager.EXTRA_ERRORED_TETHER;
|
import static android.net.TetheringManager.EXTRA_ERRORED_TETHER;
|
||||||
import static android.net.TetheringManager.TETHERING_BLUETOOTH;
|
import static android.net.TetheringManager.TETHERING_BLUETOOTH;
|
||||||
|
import static android.net.TetheringManager.TETHERING_ETHERNET;
|
||||||
import static android.net.TetheringManager.TETHERING_INVALID;
|
import static android.net.TetheringManager.TETHERING_INVALID;
|
||||||
|
import static android.net.TetheringManager.TETHERING_NCM;
|
||||||
import static android.net.TetheringManager.TETHERING_USB;
|
import static android.net.TetheringManager.TETHERING_USB;
|
||||||
import static android.net.TetheringManager.TETHERING_WIFI;
|
import static android.net.TetheringManager.TETHERING_WIFI;
|
||||||
import static android.net.TetheringManager.TETHERING_WIFI_P2P;
|
import static android.net.TetheringManager.TETHERING_WIFI_P2P;
|
||||||
@@ -66,6 +69,7 @@ import android.content.IntentFilter;
|
|||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
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.IIntResultListener;
|
import android.net.IIntResultListener;
|
||||||
import android.net.INetd;
|
import android.net.INetd;
|
||||||
import android.net.ITetheringEventCallback;
|
import android.net.ITetheringEventCallback;
|
||||||
@@ -110,6 +114,7 @@ import android.util.SparseArray;
|
|||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import com.android.internal.annotations.GuardedBy;
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
import com.android.internal.util.IndentingPrintWriter;
|
import com.android.internal.util.IndentingPrintWriter;
|
||||||
import com.android.internal.util.MessageUtils;
|
import com.android.internal.util.MessageUtils;
|
||||||
@@ -212,6 +217,13 @@ public class Tethering {
|
|||||||
private boolean mDataSaverEnabled = false;
|
private boolean mDataSaverEnabled = false;
|
||||||
private String mWifiP2pTetherInterface = null;
|
private String mWifiP2pTetherInterface = null;
|
||||||
|
|
||||||
|
@GuardedBy("mPublicSync")
|
||||||
|
private EthernetManager.TetheredInterfaceRequest mEthernetIfaceRequest;
|
||||||
|
@GuardedBy("mPublicSync")
|
||||||
|
private String mConfiguredEthernetIface;
|
||||||
|
@GuardedBy("mPublicSync")
|
||||||
|
private EthernetCallback mEthernetCallback;
|
||||||
|
|
||||||
public Tethering(TetheringDependencies deps) {
|
public Tethering(TetheringDependencies deps) {
|
||||||
mLog.mark("Tethering.constructed");
|
mLog.mark("Tethering.constructed");
|
||||||
mDeps = deps;
|
mDeps = deps;
|
||||||
@@ -408,6 +420,8 @@ public class Tethering {
|
|||||||
return TETHERING_USB;
|
return TETHERING_USB;
|
||||||
} else if (cfg.isBluetooth(iface)) {
|
} else if (cfg.isBluetooth(iface)) {
|
||||||
return TETHERING_BLUETOOTH;
|
return TETHERING_BLUETOOTH;
|
||||||
|
} else if (cfg.isNcm(iface)) {
|
||||||
|
return TETHERING_NCM;
|
||||||
}
|
}
|
||||||
return TETHERING_INVALID;
|
return TETHERING_INVALID;
|
||||||
}
|
}
|
||||||
@@ -456,6 +470,14 @@ public class Tethering {
|
|||||||
case TETHERING_BLUETOOTH:
|
case TETHERING_BLUETOOTH:
|
||||||
setBluetoothTethering(enable, listener);
|
setBluetoothTethering(enable, listener);
|
||||||
break;
|
break;
|
||||||
|
case TETHERING_NCM:
|
||||||
|
result = setNcmTethering(enable);
|
||||||
|
sendTetherResult(listener, result);
|
||||||
|
break;
|
||||||
|
case TETHERING_ETHERNET:
|
||||||
|
result = setEthernetTethering(enable);
|
||||||
|
sendTetherResult(listener, result);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
Log.w(TAG, "Invalid tether type.");
|
Log.w(TAG, "Invalid tether type.");
|
||||||
sendTetherResult(listener, TETHER_ERROR_UNKNOWN_IFACE);
|
sendTetherResult(listener, TETHER_ERROR_UNKNOWN_IFACE);
|
||||||
@@ -532,6 +554,57 @@ public class Tethering {
|
|||||||
}, BluetoothProfile.PAN);
|
}, BluetoothProfile.PAN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int setEthernetTethering(final boolean enable) {
|
||||||
|
final EthernetManager em = (EthernetManager) mContext.getSystemService(
|
||||||
|
Context.ETHERNET_SERVICE);
|
||||||
|
synchronized (mPublicSync) {
|
||||||
|
if (enable) {
|
||||||
|
mEthernetCallback = new EthernetCallback();
|
||||||
|
mEthernetIfaceRequest = em.requestTetheredInterface(mEthernetCallback);
|
||||||
|
} else {
|
||||||
|
if (mConfiguredEthernetIface != null) {
|
||||||
|
stopEthernetTetheringLocked();
|
||||||
|
mEthernetIfaceRequest.release();
|
||||||
|
}
|
||||||
|
mEthernetCallback = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return TETHER_ERROR_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void stopEthernetTetheringLocked() {
|
||||||
|
if (mConfiguredEthernetIface == null) return;
|
||||||
|
changeInterfaceState(mConfiguredEthernetIface, IpServer.STATE_AVAILABLE);
|
||||||
|
stopTrackingInterfaceLocked(mConfiguredEthernetIface);
|
||||||
|
mConfiguredEthernetIface = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class EthernetCallback implements EthernetManager.TetheredInterfaceCallback {
|
||||||
|
@Override
|
||||||
|
public void onAvailable(String iface) {
|
||||||
|
synchronized (mPublicSync) {
|
||||||
|
if (this != mEthernetCallback) {
|
||||||
|
// Ethernet callback arrived after Ethernet tethering stopped. Ignore.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
maybeTrackNewInterfaceLocked(iface, TETHERING_ETHERNET);
|
||||||
|
changeInterfaceState(iface, IpServer.STATE_TETHERED);
|
||||||
|
mConfiguredEthernetIface = iface;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onUnavailable() {
|
||||||
|
synchronized (mPublicSync) {
|
||||||
|
if (this != mEthernetCallback) {
|
||||||
|
// onAvailable called after stopping Ethernet tethering.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
stopEthernetTetheringLocked();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int tether(String iface) {
|
int tether(String iface) {
|
||||||
return tether(iface, IpServer.STATE_TETHERED);
|
return tether(iface, IpServer.STATE_TETHERED);
|
||||||
}
|
}
|
||||||
@@ -582,6 +655,7 @@ public class Tethering {
|
|||||||
stopTethering(TETHERING_WIFI_P2P);
|
stopTethering(TETHERING_WIFI_P2P);
|
||||||
stopTethering(TETHERING_USB);
|
stopTethering(TETHERING_USB);
|
||||||
stopTethering(TETHERING_BLUETOOTH);
|
stopTethering(TETHERING_BLUETOOTH);
|
||||||
|
stopTethering(TETHERING_ETHERNET);
|
||||||
}
|
}
|
||||||
|
|
||||||
int getLastTetherError(String iface) {
|
int getLastTetherError(String iface) {
|
||||||
@@ -805,6 +879,7 @@ public class Tethering {
|
|||||||
final boolean usbConnected = intent.getBooleanExtra(USB_CONNECTED, false);
|
final boolean usbConnected = intent.getBooleanExtra(USB_CONNECTED, false);
|
||||||
final boolean usbConfigured = intent.getBooleanExtra(USB_CONFIGURED, false);
|
final boolean usbConfigured = intent.getBooleanExtra(USB_CONFIGURED, false);
|
||||||
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);
|
||||||
|
|
||||||
mLog.log(String.format("USB bcast connected:%s configured:%s rndis:%s",
|
mLog.log(String.format("USB bcast connected:%s configured:%s rndis:%s",
|
||||||
usbConnected, usbConfigured, rndisEnabled));
|
usbConnected, usbConfigured, rndisEnabled));
|
||||||
@@ -832,6 +907,8 @@ public class Tethering {
|
|||||||
} 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.
|
||||||
tetherMatchingInterfaces(IpServer.STATE_TETHERED, TETHERING_USB);
|
tetherMatchingInterfaces(IpServer.STATE_TETHERED, TETHERING_USB);
|
||||||
|
} else if (usbConnected && ncmEnabled) {
|
||||||
|
tetherMatchingInterfaces(IpServer.STATE_LOCAL_ONLY, TETHERING_NCM);
|
||||||
}
|
}
|
||||||
mRndisEnabled = usbConfigured && rndisEnabled;
|
mRndisEnabled = usbConfigured && rndisEnabled;
|
||||||
}
|
}
|
||||||
@@ -1133,6 +1210,16 @@ public class Tethering {
|
|||||||
return TETHER_ERROR_NO_ERROR;
|
return TETHER_ERROR_NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int setNcmTethering(boolean enable) {
|
||||||
|
if (VDBG) Log.d(TAG, "setNcmTethering(" + enable + ")");
|
||||||
|
UsbManager usbManager = (UsbManager) mContext.getSystemService(Context.USB_SERVICE);
|
||||||
|
synchronized (mPublicSync) {
|
||||||
|
usbManager.setCurrentFunctions(enable ? UsbManager.FUNCTION_NCM
|
||||||
|
: UsbManager.FUNCTION_NONE);
|
||||||
|
}
|
||||||
|
return TETHER_ERROR_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO review API - figure out how to delete these entirely.
|
// TODO review API - figure out how to delete these entirely.
|
||||||
String[] getTetheredIfaces() {
|
String[] getTetheredIfaces() {
|
||||||
ArrayList<String> list = new ArrayList<String>();
|
ArrayList<String> list = new ArrayList<String>();
|
||||||
|
|||||||
@@ -83,6 +83,7 @@ public class TetheringConfiguration {
|
|||||||
public final String[] tetherableWifiRegexs;
|
public final String[] tetherableWifiRegexs;
|
||||||
public final String[] tetherableWifiP2pRegexs;
|
public final String[] tetherableWifiP2pRegexs;
|
||||||
public final String[] tetherableBluetoothRegexs;
|
public final String[] tetherableBluetoothRegexs;
|
||||||
|
public final String[] tetherableNcmRegexs;
|
||||||
public final boolean isDunRequired;
|
public final boolean isDunRequired;
|
||||||
public final boolean chooseUpstreamAutomatically;
|
public final boolean chooseUpstreamAutomatically;
|
||||||
public final Collection<Integer> preferredUpstreamIfaceTypes;
|
public final Collection<Integer> preferredUpstreamIfaceTypes;
|
||||||
@@ -103,6 +104,7 @@ public class TetheringConfiguration {
|
|||||||
Resources res = getResources(ctx, activeDataSubId);
|
Resources res = getResources(ctx, activeDataSubId);
|
||||||
|
|
||||||
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);
|
||||||
// TODO: Evaluate deleting this altogether now that Wi-Fi always passes
|
// TODO: Evaluate deleting this altogether now that Wi-Fi always passes
|
||||||
// us an interface name. Careful consideration needs to be given to
|
// us an interface name. Careful consideration needs to be given to
|
||||||
// implications for Settings and for provisioning checks.
|
// implications for Settings and for provisioning checks.
|
||||||
@@ -156,6 +158,11 @@ public class TetheringConfiguration {
|
|||||||
return matchesDownstreamRegexs(iface, tetherableBluetoothRegexs);
|
return matchesDownstreamRegexs(iface, tetherableBluetoothRegexs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Check if interface is ncm */
|
||||||
|
public boolean isNcm(String iface) {
|
||||||
|
return matchesDownstreamRegexs(iface, tetherableNcmRegexs);
|
||||||
|
}
|
||||||
|
|
||||||
/** Check whether no ui entitlement application is available.*/
|
/** Check whether no ui entitlement application is available.*/
|
||||||
public boolean hasMobileHotspotProvisionApp() {
|
public boolean hasMobileHotspotProvisionApp() {
|
||||||
return !TextUtils.isEmpty(provisioningAppNoUi);
|
return !TextUtils.isEmpty(provisioningAppNoUi);
|
||||||
@@ -170,6 +177,7 @@ public class TetheringConfiguration {
|
|||||||
dumpStringArray(pw, "tetherableWifiRegexs", tetherableWifiRegexs);
|
dumpStringArray(pw, "tetherableWifiRegexs", tetherableWifiRegexs);
|
||||||
dumpStringArray(pw, "tetherableWifiP2pRegexs", tetherableWifiP2pRegexs);
|
dumpStringArray(pw, "tetherableWifiP2pRegexs", tetherableWifiP2pRegexs);
|
||||||
dumpStringArray(pw, "tetherableBluetoothRegexs", tetherableBluetoothRegexs);
|
dumpStringArray(pw, "tetherableBluetoothRegexs", tetherableBluetoothRegexs);
|
||||||
|
dumpStringArray(pw, "tetherableNcmRegexs", tetherableNcmRegexs);
|
||||||
|
|
||||||
pw.print("isDunRequired: ");
|
pw.print("isDunRequired: ");
|
||||||
pw.println(isDunRequired);
|
pw.println(isDunRequired);
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ android_test {
|
|||||||
certificate: "platform",
|
certificate: "platform",
|
||||||
srcs: [
|
srcs: [
|
||||||
"src/**/*.java",
|
"src/**/*.java",
|
||||||
|
"src/**/*.kt",
|
||||||
],
|
],
|
||||||
test_suites: [
|
test_suites: [
|
||||||
"device-tests",
|
"device-tests",
|
||||||
|
|||||||
@@ -16,6 +16,8 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="com.android.networkstack.tethering.tests.unit">
|
package="com.android.networkstack.tethering.tests.unit">
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.TETHER_PRIVILEGED"/>
|
||||||
|
|
||||||
<application android:debuggable="true">
|
<application android:debuggable="true">
|
||||||
<uses-library android:name="android.test.runner" />
|
<uses-library android:name="android.test.runner" />
|
||||||
</application>
|
</application>
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package com.android.server.connectivity.tethering;
|
|||||||
|
|
||||||
import static android.hardware.usb.UsbManager.USB_CONFIGURED;
|
import static android.hardware.usb.UsbManager.USB_CONFIGURED;
|
||||||
import static android.hardware.usb.UsbManager.USB_CONNECTED;
|
import static android.hardware.usb.UsbManager.USB_CONNECTED;
|
||||||
|
import static android.hardware.usb.UsbManager.USB_FUNCTION_NCM;
|
||||||
import static android.hardware.usb.UsbManager.USB_FUNCTION_RNDIS;
|
import static android.hardware.usb.UsbManager.USB_FUNCTION_RNDIS;
|
||||||
import static android.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED;
|
import static android.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED;
|
||||||
import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED;
|
import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED;
|
||||||
@@ -27,6 +28,7 @@ import static android.net.TetheringManager.ACTION_TETHER_STATE_CHANGED;
|
|||||||
import static android.net.TetheringManager.EXTRA_ACTIVE_LOCAL_ONLY;
|
import static android.net.TetheringManager.EXTRA_ACTIVE_LOCAL_ONLY;
|
||||||
import static android.net.TetheringManager.EXTRA_ACTIVE_TETHER;
|
import static android.net.TetheringManager.EXTRA_ACTIVE_TETHER;
|
||||||
import static android.net.TetheringManager.EXTRA_AVAILABLE_TETHER;
|
import static android.net.TetheringManager.EXTRA_AVAILABLE_TETHER;
|
||||||
|
import static android.net.TetheringManager.TETHERING_NCM;
|
||||||
import static android.net.TetheringManager.TETHERING_USB;
|
import static android.net.TetheringManager.TETHERING_USB;
|
||||||
import static android.net.TetheringManager.TETHERING_WIFI;
|
import static android.net.TetheringManager.TETHERING_WIFI;
|
||||||
import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR;
|
import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR;
|
||||||
@@ -151,6 +153,7 @@ public class TetheringTest {
|
|||||||
private static final String TEST_USB_IFNAME = "test_rndis0";
|
private static final String TEST_USB_IFNAME = "test_rndis0";
|
||||||
private static final String TEST_WLAN_IFNAME = "test_wlan0";
|
private static final String TEST_WLAN_IFNAME = "test_wlan0";
|
||||||
private static final String TEST_P2P_IFNAME = "test_p2p-p2p0-0";
|
private static final String TEST_P2P_IFNAME = "test_p2p-p2p0-0";
|
||||||
|
private static final String TEST_NCM_IFNAME = "test_ncm0";
|
||||||
private static final String TETHERING_NAME = "Tethering";
|
private static final String TETHERING_NAME = "Tethering";
|
||||||
|
|
||||||
private static final int DHCPSERVER_START_TIMEOUT_MS = 1000;
|
private static final int DHCPSERVER_START_TIMEOUT_MS = 1000;
|
||||||
@@ -252,9 +255,11 @@ public class TetheringTest {
|
|||||||
ifName.equals(TEST_USB_IFNAME)
|
ifName.equals(TEST_USB_IFNAME)
|
||||||
|| ifName.equals(TEST_WLAN_IFNAME)
|
|| ifName.equals(TEST_WLAN_IFNAME)
|
||||||
|| ifName.equals(TEST_MOBILE_IFNAME)
|
|| ifName.equals(TEST_MOBILE_IFNAME)
|
||||||
|| ifName.equals(TEST_P2P_IFNAME));
|
|| ifName.equals(TEST_P2P_IFNAME)
|
||||||
|
|| ifName.equals(TEST_NCM_IFNAME));
|
||||||
final String[] ifaces = new String[] {
|
final String[] ifaces = new String[] {
|
||||||
TEST_USB_IFNAME, TEST_WLAN_IFNAME, TEST_MOBILE_IFNAME, TEST_P2P_IFNAME};
|
TEST_USB_IFNAME, TEST_WLAN_IFNAME, TEST_MOBILE_IFNAME, TEST_P2P_IFNAME,
|
||||||
|
TEST_NCM_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);
|
||||||
}
|
}
|
||||||
@@ -428,13 +433,16 @@ public class TetheringTest {
|
|||||||
.thenReturn(new String[]{ "test_p2p-p2p\\d-.*" });
|
.thenReturn(new String[]{ "test_p2p-p2p\\d-.*" });
|
||||||
when(mResources.getStringArray(R.array.config_tether_bluetooth_regexs))
|
when(mResources.getStringArray(R.array.config_tether_bluetooth_regexs))
|
||||||
.thenReturn(new String[0]);
|
.thenReturn(new String[0]);
|
||||||
|
when(mResources.getStringArray(R.array.config_tether_ncm_regexs))
|
||||||
|
.thenReturn(new String[] { "test_ncm\\d" });
|
||||||
when(mResources.getIntArray(R.array.config_tether_upstream_types)).thenReturn(new int[0]);
|
when(mResources.getIntArray(R.array.config_tether_upstream_types)).thenReturn(new int[0]);
|
||||||
when(mResources.getBoolean(R.bool.config_tether_upstream_automatic)).thenReturn(false);
|
when(mResources.getBoolean(R.bool.config_tether_upstream_automatic)).thenReturn(false);
|
||||||
when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn(
|
when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn(
|
||||||
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_USB_IFNAME, TEST_P2P_IFNAME,
|
||||||
|
TEST_NCM_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();
|
||||||
mInterfaceConfiguration.flags = new String[0];
|
mInterfaceConfiguration.flags = new String[0];
|
||||||
@@ -524,11 +532,16 @@ public class TetheringTest {
|
|||||||
P2P_RECEIVER_PERMISSIONS_FOR_BROADCAST);
|
P2P_RECEIVER_PERMISSIONS_FOR_BROADCAST);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendUsbBroadcast(boolean connected, boolean configured, boolean rndisFunction) {
|
private void sendUsbBroadcast(boolean connected, boolean configured, boolean function,
|
||||||
|
int type) {
|
||||||
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);
|
||||||
intent.putExtra(USB_FUNCTION_RNDIS, rndisFunction);
|
if (type == TETHERING_USB) {
|
||||||
|
intent.putExtra(USB_FUNCTION_RNDIS, function);
|
||||||
|
} else {
|
||||||
|
intent.putExtra(USB_FUNCTION_NCM, function);
|
||||||
|
}
|
||||||
mServiceContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
|
mServiceContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -578,6 +591,15 @@ public class TetheringTest {
|
|||||||
verifyNoMoreInteractions(mWifiManager);
|
verifyNoMoreInteractions(mWifiManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void prepareNcmTethering() {
|
||||||
|
// Emulate startTethering(TETHERING_NCM) called
|
||||||
|
mTethering.startTethering(createTetheringRquestParcel(TETHERING_NCM), null);
|
||||||
|
mLooper.dispatchAll();
|
||||||
|
verify(mUsbManager, times(1)).setCurrentFunctions(UsbManager.FUNCTION_NCM);
|
||||||
|
|
||||||
|
mTethering.interfaceStatusChanged(TEST_NCM_IFNAME, true);
|
||||||
|
}
|
||||||
|
|
||||||
private void prepareUsbTethering(UpstreamNetworkState upstreamState) {
|
private void prepareUsbTethering(UpstreamNetworkState upstreamState) {
|
||||||
when(mUpstreamNetworkMonitor.getCurrentPreferredUpstream()).thenReturn(upstreamState);
|
when(mUpstreamNetworkMonitor.getCurrentPreferredUpstream()).thenReturn(upstreamState);
|
||||||
when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any()))
|
when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any()))
|
||||||
@@ -600,7 +622,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);
|
sendUsbBroadcast(true, true, true, TETHERING_USB);
|
||||||
mLooper.dispatchAll();
|
mLooper.dispatchAll();
|
||||||
// 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).
|
||||||
@@ -691,7 +713,7 @@ public class TetheringTest {
|
|||||||
|
|
||||||
private void runUsbTethering(UpstreamNetworkState upstreamState) {
|
private void runUsbTethering(UpstreamNetworkState upstreamState) {
|
||||||
prepareUsbTethering(upstreamState);
|
prepareUsbTethering(upstreamState);
|
||||||
sendUsbBroadcast(true, true, true);
|
sendUsbBroadcast(true, true, true, TETHERING_USB);
|
||||||
mLooper.dispatchAll();
|
mLooper.dispatchAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -814,6 +836,29 @@ public class TetheringTest {
|
|||||||
verify(mUpstreamNetworkMonitor, times(1)).setCurrentUpstream(upstreamState.network);
|
verify(mUpstreamNetworkMonitor, times(1)).setCurrentUpstream(upstreamState.network);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void runNcmTethering() {
|
||||||
|
prepareNcmTethering();
|
||||||
|
sendUsbBroadcast(true, true, true, TETHERING_NCM);
|
||||||
|
mLooper.dispatchAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void workingNcmTethering() throws Exception {
|
||||||
|
runNcmTethering();
|
||||||
|
|
||||||
|
verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).start(any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void workingNcmTethering_LegacyDhcp() {
|
||||||
|
when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn(
|
||||||
|
true);
|
||||||
|
sendConfigurationChanged();
|
||||||
|
runNcmTethering();
|
||||||
|
|
||||||
|
verify(mIpServerDependencies, never()).makeDhcpServer(any(), any(), any());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void workingLocalOnlyHotspotEnrichedApBroadcastWithIfaceChanged() throws Exception {
|
public void workingLocalOnlyHotspotEnrichedApBroadcastWithIfaceChanged() throws Exception {
|
||||||
workingLocalOnlyHotspotEnrichedApBroadcast(true);
|
workingLocalOnlyHotspotEnrichedApBroadcast(true);
|
||||||
|
|||||||
Reference in New Issue
Block a user