Merge changes I34842acd,Icc6c4d6b
am: fb3dccd961
Change-Id: I38f5452905216ebf9e0b28311d34ad0667243274
This commit is contained in:
@@ -1577,6 +1577,7 @@ package android.content {
|
||||
field public static final String BUGREPORT_SERVICE = "bugreport";
|
||||
field public static final String CONTENT_SUGGESTIONS_SERVICE = "content_suggestions";
|
||||
field public static final String CONTEXTHUB_SERVICE = "contexthub";
|
||||
field public static final String ETHERNET_SERVICE = "ethernet";
|
||||
field public static final String EUICC_CARD_SERVICE = "euicc_card";
|
||||
field public static final String HDMI_CONTROL_SERVICE = "hdmi_control";
|
||||
field public static final String NETD_SERVICE = "netd";
|
||||
@@ -3285,10 +3286,12 @@ package android.hardware.usb {
|
||||
method @RequiresPermission(android.Manifest.permission.MANAGE_USB) public void setCurrentFunctions(long);
|
||||
field @RequiresPermission(android.Manifest.permission.MANAGE_USB) public static final String ACTION_USB_PORT_CHANGED = "android.hardware.usb.action.USB_PORT_CHANGED";
|
||||
field public static final String ACTION_USB_STATE = "android.hardware.usb.action.USB_STATE";
|
||||
field public static final long FUNCTION_NCM = 1024L; // 0x400L
|
||||
field public static final long FUNCTION_NONE = 0L; // 0x0L
|
||||
field public static final long FUNCTION_RNDIS = 32L; // 0x20L
|
||||
field public static final String USB_CONFIGURED = "configured";
|
||||
field public static final String USB_CONNECTED = "connected";
|
||||
field public static final String USB_FUNCTION_NCM = "ncm";
|
||||
field public static final String USB_FUNCTION_RNDIS = "rndis";
|
||||
}
|
||||
|
||||
@@ -4380,6 +4383,19 @@ package android.net {
|
||||
method @Deprecated public void onUpstreamChanged(@Nullable android.net.Network);
|
||||
}
|
||||
|
||||
public class EthernetManager {
|
||||
method @NonNull public android.net.EthernetManager.TetheredInterfaceRequest requestTetheredInterface(@NonNull android.net.EthernetManager.TetheredInterfaceCallback);
|
||||
}
|
||||
|
||||
public static interface EthernetManager.TetheredInterfaceCallback {
|
||||
method public void onAvailable(@NonNull String);
|
||||
method public void onUnavailable();
|
||||
}
|
||||
|
||||
public static class EthernetManager.TetheredInterfaceRequest {
|
||||
method public void release();
|
||||
}
|
||||
|
||||
public class InvalidPacketException extends java.lang.Exception {
|
||||
ctor public InvalidPacketException(int);
|
||||
field public static final int ERROR_INVALID_IP_ADDRESS = -21; // 0xffffffeb
|
||||
@@ -4753,7 +4769,9 @@ package android.net {
|
||||
field public static final String EXTRA_AVAILABLE_TETHER = "availableArray";
|
||||
field public static final String EXTRA_ERRORED_TETHER = "erroredArray";
|
||||
field public static final int TETHERING_BLUETOOTH = 2; // 0x2
|
||||
field public static final int TETHERING_ETHERNET = 5; // 0x5
|
||||
field public static final int TETHERING_INVALID = -1; // 0xffffffff
|
||||
field public static final int TETHERING_NCM = 4; // 0x4
|
||||
field public static final int TETHERING_USB = 1; // 0x1
|
||||
field public static final int TETHERING_WIFI = 0; // 0x0
|
||||
field public static final int TETHERING_WIFI_P2P = 3; // 0x3
|
||||
|
||||
@@ -653,6 +653,7 @@ package android.content {
|
||||
method public void setContentCaptureOptions(@Nullable android.content.ContentCaptureOptions);
|
||||
field public static final String BUGREPORT_SERVICE = "bugreport";
|
||||
field public static final String CONTENT_CAPTURE_MANAGER_SERVICE = "content_capture";
|
||||
field public static final String ETHERNET_SERVICE = "ethernet";
|
||||
field public static final String NETWORK_STACK_SERVICE = "network_stack";
|
||||
field public static final String PERMISSION_SERVICE = "permission";
|
||||
field public static final String ROLLBACK_SERVICE = "rollback";
|
||||
@@ -1392,6 +1393,19 @@ package android.net {
|
||||
field public static final String EXTRA_CAPTIVE_PORTAL_USER_AGENT = "android.net.extra.CAPTIVE_PORTAL_USER_AGENT";
|
||||
}
|
||||
|
||||
public class EthernetManager {
|
||||
method @NonNull public android.net.EthernetManager.TetheredInterfaceRequest requestTetheredInterface(@NonNull android.net.EthernetManager.TetheredInterfaceCallback);
|
||||
}
|
||||
|
||||
public static interface EthernetManager.TetheredInterfaceCallback {
|
||||
method public void onAvailable(@NonNull String);
|
||||
method public void onUnavailable();
|
||||
}
|
||||
|
||||
public static class EthernetManager.TetheredInterfaceRequest {
|
||||
method public void release();
|
||||
}
|
||||
|
||||
public final class IpPrefix implements android.os.Parcelable {
|
||||
ctor public IpPrefix(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int);
|
||||
ctor public IpPrefix(@NonNull String);
|
||||
@@ -1540,7 +1554,9 @@ package android.net {
|
||||
field public static final String EXTRA_AVAILABLE_TETHER = "availableArray";
|
||||
field public static final String EXTRA_ERRORED_TETHER = "erroredArray";
|
||||
field public static final int TETHERING_BLUETOOTH = 2; // 0x2
|
||||
field public static final int TETHERING_ETHERNET = 5; // 0x5
|
||||
field public static final int TETHERING_INVALID = -1; // 0xffffffff
|
||||
field public static final int TETHERING_NCM = 4; // 0x4
|
||||
field public static final int TETHERING_USB = 1; // 0x1
|
||||
field public static final int TETHERING_WIFI = 0; // 0x0
|
||||
field public static final int TETHERING_WIFI_P2P = 3; // 0x3
|
||||
|
||||
@@ -4022,16 +4022,16 @@ public abstract class Context {
|
||||
public static final String LOWPAN_SERVICE = "lowpan";
|
||||
|
||||
/**
|
||||
* Use with {@link #getSystemService(String)} to retrieve a {@link
|
||||
* android.net.EthernetManager} for handling management of
|
||||
* Ethernet access.
|
||||
* Use with {@link #getSystemService(String)} to retrieve a {@link android.net.EthernetManager}
|
||||
* for handling management of Ethernet access.
|
||||
*
|
||||
* @see #getSystemService(String)
|
||||
* @see android.net.EthernetManager
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@UnsupportedAppUsage
|
||||
@SystemApi
|
||||
@TestApi
|
||||
public static final String ETHERNET_SERVICE = "ethernet";
|
||||
|
||||
/**
|
||||
|
||||
@@ -261,6 +261,15 @@ public class UsbManager {
|
||||
*/
|
||||
public static final String USB_FUNCTION_ACCESSORY = "accessory";
|
||||
|
||||
/**
|
||||
* Name of the NCM USB function.
|
||||
* Used in extras for the {@link #ACTION_USB_STATE} broadcast
|
||||
*
|
||||
* {@hide}
|
||||
*/
|
||||
@SystemApi
|
||||
public static final String USB_FUNCTION_NCM = "ncm";
|
||||
|
||||
/**
|
||||
* Name of extra for {@link #ACTION_USB_PORT_CHANGED}
|
||||
* containing the {@link UsbPort} object for the port.
|
||||
@@ -367,8 +376,15 @@ public class UsbManager {
|
||||
*/
|
||||
public static final long FUNCTION_ADB = GadgetFunction.ADB;
|
||||
|
||||
/**
|
||||
* Code for the ncm source usb function.
|
||||
* {@hide}
|
||||
*/
|
||||
@SystemApi
|
||||
public static final long FUNCTION_NCM = 1 << 10;
|
||||
|
||||
private static final long SETTABLE_FUNCTIONS = FUNCTION_MTP | FUNCTION_PTP | FUNCTION_RNDIS
|
||||
| FUNCTION_MIDI;
|
||||
| FUNCTION_MIDI | FUNCTION_NCM;
|
||||
|
||||
private static final Map<String, Long> FUNCTION_NAME_TO_CODE = new HashMap<>();
|
||||
|
||||
@@ -380,6 +396,7 @@ public class UsbManager {
|
||||
FUNCTION_NAME_TO_CODE.put(UsbManager.USB_FUNCTION_ACCESSORY, FUNCTION_ACCESSORY);
|
||||
FUNCTION_NAME_TO_CODE.put(UsbManager.USB_FUNCTION_AUDIO_SOURCE, FUNCTION_AUDIO_SOURCE);
|
||||
FUNCTION_NAME_TO_CODE.put(UsbManager.USB_FUNCTION_ADB, FUNCTION_ADB);
|
||||
FUNCTION_NAME_TO_CODE.put(UsbManager.USB_FUNCTION_NCM, FUNCTION_NCM);
|
||||
}
|
||||
|
||||
private final Context mContext;
|
||||
@@ -935,6 +952,9 @@ public class UsbManager {
|
||||
if ((functions & FUNCTION_AUDIO_SOURCE) != 0) {
|
||||
joiner.add(UsbManager.USB_FUNCTION_AUDIO_SOURCE);
|
||||
}
|
||||
if ((functions & FUNCTION_NCM) != 0) {
|
||||
joiner.add(UsbManager.USB_FUNCTION_NCM);
|
||||
}
|
||||
if ((functions & FUNCTION_ADB) != 0) {
|
||||
joiner.add(UsbManager.USB_FUNCTION_ADB);
|
||||
}
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
package android.net;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.SystemApi;
|
||||
import android.annotation.SystemService;
|
||||
import android.annotation.TestApi;
|
||||
import android.compat.annotation.UnsupportedAppUsage;
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
@@ -32,6 +34,8 @@ import java.util.Objects;
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
@TestApi
|
||||
@SystemService(Context.ETHERNET_SERVICE)
|
||||
public class EthernetManager {
|
||||
private static final String TAG = "EthernetManager";
|
||||
@@ -62,12 +66,14 @@ public class EthernetManager {
|
||||
|
||||
/**
|
||||
* A listener interface to receive notification on changes in Ethernet.
|
||||
* @hide
|
||||
*/
|
||||
public interface Listener {
|
||||
/**
|
||||
* Called when Ethernet port's availability is changed.
|
||||
* @param iface Ethernet interface name
|
||||
* @param isAvailable {@code true} if Ethernet port exists.
|
||||
* @hide
|
||||
*/
|
||||
@UnsupportedAppUsage
|
||||
void onAvailabilityChanged(String iface, boolean isAvailable);
|
||||
@@ -78,6 +84,7 @@ public class EthernetManager {
|
||||
* Applications will almost always want to use
|
||||
* {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve
|
||||
* the standard {@link android.content.Context#ETHERNET_SERVICE Context.ETHERNET_SERVICE}.
|
||||
* @hide
|
||||
*/
|
||||
public EthernetManager(Context context, IEthernetManager service) {
|
||||
mContext = context;
|
||||
@@ -87,6 +94,7 @@ public class EthernetManager {
|
||||
/**
|
||||
* Get Ethernet configuration.
|
||||
* @return the Ethernet Configuration, contained in {@link IpConfiguration}.
|
||||
* @hide
|
||||
*/
|
||||
@UnsupportedAppUsage
|
||||
public IpConfiguration getConfiguration(String iface) {
|
||||
@@ -99,6 +107,7 @@ public class EthernetManager {
|
||||
|
||||
/**
|
||||
* Set Ethernet configuration.
|
||||
* @hide
|
||||
*/
|
||||
@UnsupportedAppUsage
|
||||
public void setConfiguration(String iface, IpConfiguration config) {
|
||||
@@ -111,6 +120,7 @@ public class EthernetManager {
|
||||
|
||||
/**
|
||||
* Indicates whether the system currently has one or more Ethernet interfaces.
|
||||
* @hide
|
||||
*/
|
||||
@UnsupportedAppUsage
|
||||
public boolean isAvailable() {
|
||||
@@ -121,6 +131,7 @@ public class EthernetManager {
|
||||
* Indicates whether the system has given interface.
|
||||
*
|
||||
* @param iface Ethernet interface name
|
||||
* @hide
|
||||
*/
|
||||
@UnsupportedAppUsage
|
||||
public boolean isAvailable(String iface) {
|
||||
@@ -135,6 +146,7 @@ public class EthernetManager {
|
||||
* Adds a listener.
|
||||
* @param listener A {@link Listener} to add.
|
||||
* @throws IllegalArgumentException If the listener is null.
|
||||
* @hide
|
||||
*/
|
||||
@UnsupportedAppUsage
|
||||
public void addListener(Listener listener) {
|
||||
@@ -153,6 +165,7 @@ public class EthernetManager {
|
||||
|
||||
/**
|
||||
* Returns an array of available Ethernet interface names.
|
||||
* @hide
|
||||
*/
|
||||
@UnsupportedAppUsage
|
||||
public String[] getAvailableInterfaces() {
|
||||
@@ -167,6 +180,7 @@ public class EthernetManager {
|
||||
* Removes a listener.
|
||||
* @param listener A {@link Listener} to remove.
|
||||
* @throws IllegalArgumentException If the listener is null.
|
||||
* @hide
|
||||
*/
|
||||
@UnsupportedAppUsage
|
||||
public void removeListener(Listener listener) {
|
||||
|
||||
@@ -130,6 +130,18 @@ public class TetheringManager {
|
||||
*/
|
||||
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_UNKNOWN_IFACE = 1;
|
||||
public static final int TETHER_ERROR_SERVICE_UNAVAIL = 2;
|
||||
|
||||
@@ -28,6 +28,12 @@
|
||||
<item>"rndis\\d"</item>
|
||||
</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
|
||||
Wifi interfaces. If the device doesn't want to support tethering over Wifi this
|
||||
should be empty. An example would be "softap.*" -->
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
<overlayable name="TetheringConfig">
|
||||
<policy type="product|system|vendor">
|
||||
<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_p2p_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 String WIFI_P2P_IFACE_ADDR = "192.168.49.1";
|
||||
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
|
||||
private static final String BLUETOOTH_IFACE_ADDR = "192.168.44.1";
|
||||
@@ -416,7 +418,8 @@ public class IpServer extends StateMachine {
|
||||
final Inet4Address srvAddr;
|
||||
int prefixLen = 0;
|
||||
try {
|
||||
if (mInterfaceType == TetheringManager.TETHERING_USB) {
|
||||
if (mInterfaceType == TetheringManager.TETHERING_USB
|
||||
|| mInterfaceType == TetheringManager.TETHERING_NCM) {
|
||||
srvAddr = (Inet4Address) parseNumericAddress(USB_NEAR_IFACE_ADDR);
|
||||
prefixLen = USB_PREFIX_LENGTH;
|
||||
} else if (mInterfaceType == TetheringManager.TETHERING_WIFI) {
|
||||
@@ -425,6 +428,10 @@ public class IpServer extends StateMachine {
|
||||
} else if (mInterfaceType == TetheringManager.TETHERING_WIFI_P2P) {
|
||||
srvAddr = (Inet4Address) parseNumericAddress(WIFI_P2P_IFACE_ADDR);
|
||||
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 {
|
||||
// BT configures the interface elsewhere: only start DHCP.
|
||||
// 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.hardware.usb.UsbManager.USB_CONFIGURED;
|
||||
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.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED;
|
||||
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_ERRORED_TETHER;
|
||||
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_NCM;
|
||||
import static android.net.TetheringManager.TETHERING_USB;
|
||||
import static android.net.TetheringManager.TETHERING_WIFI;
|
||||
import static android.net.TetheringManager.TETHERING_WIFI_P2P;
|
||||
@@ -66,6 +69,7 @@ import android.content.IntentFilter;
|
||||
import android.content.res.Resources;
|
||||
import android.hardware.usb.UsbManager;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.EthernetManager;
|
||||
import android.net.IIntResultListener;
|
||||
import android.net.INetd;
|
||||
import android.net.ITetheringEventCallback;
|
||||
@@ -110,6 +114,7 @@ import android.util.SparseArray;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.util.IndentingPrintWriter;
|
||||
import com.android.internal.util.MessageUtils;
|
||||
@@ -212,6 +217,13 @@ public class Tethering {
|
||||
private boolean mDataSaverEnabled = false;
|
||||
private String mWifiP2pTetherInterface = null;
|
||||
|
||||
@GuardedBy("mPublicSync")
|
||||
private EthernetManager.TetheredInterfaceRequest mEthernetIfaceRequest;
|
||||
@GuardedBy("mPublicSync")
|
||||
private String mConfiguredEthernetIface;
|
||||
@GuardedBy("mPublicSync")
|
||||
private EthernetCallback mEthernetCallback;
|
||||
|
||||
public Tethering(TetheringDependencies deps) {
|
||||
mLog.mark("Tethering.constructed");
|
||||
mDeps = deps;
|
||||
@@ -408,6 +420,8 @@ public class Tethering {
|
||||
return TETHERING_USB;
|
||||
} else if (cfg.isBluetooth(iface)) {
|
||||
return TETHERING_BLUETOOTH;
|
||||
} else if (cfg.isNcm(iface)) {
|
||||
return TETHERING_NCM;
|
||||
}
|
||||
return TETHERING_INVALID;
|
||||
}
|
||||
@@ -456,6 +470,14 @@ public class Tethering {
|
||||
case TETHERING_BLUETOOTH:
|
||||
setBluetoothTethering(enable, listener);
|
||||
break;
|
||||
case TETHERING_NCM:
|
||||
result = setNcmTethering(enable);
|
||||
sendTetherResult(listener, result);
|
||||
break;
|
||||
case TETHERING_ETHERNET:
|
||||
result = setEthernetTethering(enable);
|
||||
sendTetherResult(listener, result);
|
||||
break;
|
||||
default:
|
||||
Log.w(TAG, "Invalid tether type.");
|
||||
sendTetherResult(listener, TETHER_ERROR_UNKNOWN_IFACE);
|
||||
@@ -532,6 +554,57 @@ public class Tethering {
|
||||
}, 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) {
|
||||
return tether(iface, IpServer.STATE_TETHERED);
|
||||
}
|
||||
@@ -582,6 +655,7 @@ public class Tethering {
|
||||
stopTethering(TETHERING_WIFI_P2P);
|
||||
stopTethering(TETHERING_USB);
|
||||
stopTethering(TETHERING_BLUETOOTH);
|
||||
stopTethering(TETHERING_ETHERNET);
|
||||
}
|
||||
|
||||
int getLastTetherError(String iface) {
|
||||
@@ -805,6 +879,7 @@ public class Tethering {
|
||||
final boolean usbConnected = intent.getBooleanExtra(USB_CONNECTED, false);
|
||||
final boolean usbConfigured = intent.getBooleanExtra(USB_CONFIGURED, 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",
|
||||
usbConnected, usbConfigured, rndisEnabled));
|
||||
@@ -832,6 +907,8 @@ public class Tethering {
|
||||
} else if (usbConfigured && rndisEnabled) {
|
||||
// Tether if rndis is enabled and usb is configured.
|
||||
tetherMatchingInterfaces(IpServer.STATE_TETHERED, TETHERING_USB);
|
||||
} else if (usbConnected && ncmEnabled) {
|
||||
tetherMatchingInterfaces(IpServer.STATE_LOCAL_ONLY, TETHERING_NCM);
|
||||
}
|
||||
mRndisEnabled = usbConfigured && rndisEnabled;
|
||||
}
|
||||
@@ -1133,6 +1210,16 @@ public class Tethering {
|
||||
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.
|
||||
String[] getTetheredIfaces() {
|
||||
ArrayList<String> list = new ArrayList<String>();
|
||||
|
||||
@@ -83,6 +83,7 @@ public class TetheringConfiguration {
|
||||
public final String[] tetherableWifiRegexs;
|
||||
public final String[] tetherableWifiP2pRegexs;
|
||||
public final String[] tetherableBluetoothRegexs;
|
||||
public final String[] tetherableNcmRegexs;
|
||||
public final boolean isDunRequired;
|
||||
public final boolean chooseUpstreamAutomatically;
|
||||
public final Collection<Integer> preferredUpstreamIfaceTypes;
|
||||
@@ -103,6 +104,7 @@ public class TetheringConfiguration {
|
||||
Resources res = getResources(ctx, activeDataSubId);
|
||||
|
||||
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
|
||||
// us an interface name. Careful consideration needs to be given to
|
||||
// implications for Settings and for provisioning checks.
|
||||
@@ -156,6 +158,11 @@ public class TetheringConfiguration {
|
||||
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.*/
|
||||
public boolean hasMobileHotspotProvisionApp() {
|
||||
return !TextUtils.isEmpty(provisioningAppNoUi);
|
||||
@@ -170,6 +177,7 @@ public class TetheringConfiguration {
|
||||
dumpStringArray(pw, "tetherableWifiRegexs", tetherableWifiRegexs);
|
||||
dumpStringArray(pw, "tetherableWifiP2pRegexs", tetherableWifiP2pRegexs);
|
||||
dumpStringArray(pw, "tetherableBluetoothRegexs", tetherableBluetoothRegexs);
|
||||
dumpStringArray(pw, "tetherableNcmRegexs", tetherableNcmRegexs);
|
||||
|
||||
pw.print("isDunRequired: ");
|
||||
pw.println(isDunRequired);
|
||||
|
||||
@@ -19,6 +19,7 @@ android_test {
|
||||
certificate: "platform",
|
||||
srcs: [
|
||||
"src/**/*.java",
|
||||
"src/**/*.kt",
|
||||
],
|
||||
test_suites: [
|
||||
"device-tests",
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.android.networkstack.tethering.tests.unit">
|
||||
|
||||
<uses-permission android:name="android.permission.TETHER_PRIVILEGED"/>
|
||||
|
||||
<application android:debuggable="true">
|
||||
<uses-library android:name="android.test.runner" />
|
||||
</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_CONNECTED;
|
||||
import static android.hardware.usb.UsbManager.USB_FUNCTION_NCM;
|
||||
import static android.hardware.usb.UsbManager.USB_FUNCTION_RNDIS;
|
||||
import static android.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED;
|
||||
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_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_WIFI;
|
||||
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_WLAN_IFNAME = "test_wlan0";
|
||||
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 int DHCPSERVER_START_TIMEOUT_MS = 1000;
|
||||
@@ -252,9 +255,11 @@ public class TetheringTest {
|
||||
ifName.equals(TEST_USB_IFNAME)
|
||||
|| ifName.equals(TEST_WLAN_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[] {
|
||||
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,
|
||||
MacAddress.ALL_ZEROS_ADDRESS);
|
||||
}
|
||||
@@ -428,13 +433,16 @@ public class TetheringTest {
|
||||
.thenReturn(new String[]{ "test_p2p-p2p\\d-.*" });
|
||||
when(mResources.getStringArray(R.array.config_tether_bluetooth_regexs))
|
||||
.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.getBoolean(R.bool.config_tether_upstream_automatic)).thenReturn(false);
|
||||
when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn(
|
||||
false);
|
||||
when(mNetd.interfaceGetList())
|
||||
.thenReturn(new String[] {
|
||||
TEST_MOBILE_IFNAME, TEST_WLAN_IFNAME, TEST_USB_IFNAME, TEST_P2P_IFNAME});
|
||||
TEST_MOBILE_IFNAME, TEST_WLAN_IFNAME, TEST_USB_IFNAME, TEST_P2P_IFNAME,
|
||||
TEST_NCM_IFNAME});
|
||||
when(mResources.getString(R.string.config_wifi_tether_enable)).thenReturn("");
|
||||
mInterfaceConfiguration = new InterfaceConfigurationParcel();
|
||||
mInterfaceConfiguration.flags = new String[0];
|
||||
@@ -524,11 +532,16 @@ public class TetheringTest {
|
||||
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);
|
||||
intent.putExtra(USB_CONNECTED, connected);
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -578,6 +591,15 @@ public class TetheringTest {
|
||||
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) {
|
||||
when(mUpstreamNetworkMonitor.getCurrentPreferredUpstream()).thenReturn(upstreamState);
|
||||
when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any()))
|
||||
@@ -600,7 +622,7 @@ public class TetheringTest {
|
||||
verifyNoMoreInteractions(mNetd);
|
||||
|
||||
// Pretend we then receive USB configured broadcast.
|
||||
sendUsbBroadcast(true, true, true);
|
||||
sendUsbBroadcast(true, true, true, TETHERING_USB);
|
||||
mLooper.dispatchAll();
|
||||
// Now we should see the start of tethering mechanics (in this case:
|
||||
// tetherMatchingInterfaces() which starts by fetching all interfaces).
|
||||
@@ -691,7 +713,7 @@ public class TetheringTest {
|
||||
|
||||
private void runUsbTethering(UpstreamNetworkState upstreamState) {
|
||||
prepareUsbTethering(upstreamState);
|
||||
sendUsbBroadcast(true, true, true);
|
||||
sendUsbBroadcast(true, true, true, TETHERING_USB);
|
||||
mLooper.dispatchAll();
|
||||
}
|
||||
|
||||
@@ -814,6 +836,29 @@ public class TetheringTest {
|
||||
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
|
||||
public void workingLocalOnlyHotspotEnrichedApBroadcastWithIfaceChanged() throws Exception {
|
||||
workingLocalOnlyHotspotEnrichedApBroadcast(true);
|
||||
|
||||
Reference in New Issue
Block a user