[automerger skipped] Merge changes I7065d081,Ic7c3a331,Ia432057b am: 2458be40f4 am: 172d2ce499 am: 06c8108318 -s ours
am skip reason: Change-Id I7065d081c11bc606d691f76ac8b499dd075d6504 with SHA-1 2781c80d28 is in history
Change-Id: Ifa5a0b23acc51bc01d480046a4354376083ff84a
diff --git a/Tethering/Android.bp b/Tethering/Android.bp
index 1315ed0..cf2b1f0 100644
--- a/Tethering/Android.bp
+++ b/Tethering/Android.bp
@@ -16,7 +16,7 @@
java_defaults {
name: "TetheringAndroidLibraryDefaults",
- platform_apis: true,
+ sdk_version: "system_current",
srcs: [
"src/**/*.java",
":framework-tethering-shared-srcs",
@@ -29,6 +29,7 @@
"netlink-client",
"networkstack-aidl-interfaces-unstable-java",
"android.hardware.tetheroffload.control-V1.0-java",
+ "net-utils-framework-common",
],
libs: [
"framework-tethering",
@@ -80,7 +81,7 @@
// Common defaults for compiling the actual APK.
java_defaults {
name: "TetheringAppDefaults",
- platform_apis: true,
+ sdk_version: "system_current",
privileged: true,
// Build system doesn't track transitive dependeicies for jni_libs, list all the dependencies
// explicitly.
diff --git a/Tethering/apex/manifest.json b/Tethering/apex/manifest.json
index b64de4f..538ffb3 100644
--- a/Tethering/apex/manifest.json
+++ b/Tethering/apex/manifest.json
@@ -1,4 +1,4 @@
{
"name": "com.android.tethering",
- "version": 290000000
+ "version": 300000000
}
diff --git a/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
index 8dacecc..79c6930 100644
--- a/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
+++ b/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
@@ -130,6 +130,12 @@
*/
public static final int TETHERING_WIFI_P2P = 3;
+ /**
+ * Ncm local tethering type.
+ * @see #startTethering(TetheringRequest, Executor, StartTetheringCallback)
+ */
+ public static final int TETHERING_NCM = 4;
+
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;
diff --git a/Tethering/res/values/config.xml b/Tethering/res/values/config.xml
index 6fa1f77..c489cbc 100644
--- a/Tethering/res/values/config.xml
+++ b/Tethering/res/values/config.xml
@@ -29,6 +29,12 @@
</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.*" -->
<string-array translatable="false" name="config_tether_wifi_regexs">
@@ -38,8 +44,9 @@
<!-- List of regexpressions describing the interface (if any) that represent tetherable
Wifi P2P interfaces. If the device doesn't want to support tethering over Wifi P2p this
- should be empty. An example would be "p2p-p2p.*" -->
+ should be empty. An example would be "p2p-p2p\\d-.*" -->
<string-array translatable="false" name="config_tether_wifi_p2p_regexs">
+ <item>"p2p-p2p\\d-.*"</item>
</string-array>
<!-- List of regexpressions describing the interface (if any) that represent tetherable
diff --git a/Tethering/res/values/overlayable.xml b/Tethering/res/values/overlayable.xml
index e089d9d..fe025c7 100644
--- a/Tethering/res/values/overlayable.xml
+++ b/Tethering/res/values/overlayable.xml
@@ -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"/>
diff --git a/Tethering/src/android/net/ip/IpServer.java b/Tethering/src/android/net/ip/IpServer.java
index 0491ad7..57cc4dd 100644
--- a/Tethering/src/android/net/ip/IpServer.java
+++ b/Tethering/src/android/net/ip/IpServer.java
@@ -416,7 +416,8 @@
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) {
diff --git a/Tethering/src/com/android/server/connectivity/tethering/Tethering.java b/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
index ce6a43f..02ba17e 100644
--- a/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
+++ b/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
@@ -19,6 +19,7 @@
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;
@@ -30,6 +31,7 @@
import static android.net.TetheringManager.EXTRA_ERRORED_TETHER;
import static android.net.TetheringManager.TETHERING_BLUETOOTH;
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;
@@ -408,6 +410,8 @@
return TETHERING_USB;
} else if (cfg.isBluetooth(iface)) {
return TETHERING_BLUETOOTH;
+ } else if (cfg.isNcm(iface)) {
+ return TETHERING_NCM;
}
return TETHERING_INVALID;
}
@@ -456,6 +460,10 @@
case TETHERING_BLUETOOTH:
setBluetoothTethering(enable, listener);
break;
+ case TETHERING_NCM:
+ result = setNcmTethering(enable);
+ sendTetherResult(listener, result);
+ break;
default:
Log.w(TAG, "Invalid tether type.");
sendTetherResult(listener, TETHER_ERROR_UNKNOWN_IFACE);
@@ -479,7 +487,7 @@
mLog.e("setWifiTethering: failed to get WifiManager!");
return TETHER_ERROR_SERVICE_UNAVAIL;
}
- if ((enable && mgr.startSoftAp(null /* use existing wifi config */))
+ if ((enable && mgr.startTetheredHotspot(null /* use existing softap config */))
|| (!enable && mgr.stopSoftAp())) {
mWifiTetherRequested = enable;
return TETHER_ERROR_NO_ERROR;
@@ -805,6 +813,7 @@
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 +841,8 @@
} 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 +1144,16 @@
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>();
diff --git a/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java b/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java
index 068c346..7e9e26f 100644
--- a/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java
+++ b/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java
@@ -83,6 +83,7 @@
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 @@
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 @@
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 @@
dumpStringArray(pw, "tetherableWifiRegexs", tetherableWifiRegexs);
dumpStringArray(pw, "tetherableWifiP2pRegexs", tetherableWifiP2pRegexs);
dumpStringArray(pw, "tetherableBluetoothRegexs", tetherableBluetoothRegexs);
+ dumpStringArray(pw, "tetherableNcmRegexs", tetherableNcmRegexs);
pw.print("isDunRequired: ");
pw.println(isDunRequired);
diff --git a/Tethering/src/com/android/server/connectivity/tethering/TetheringInterfaceUtils.java b/Tethering/src/com/android/server/connectivity/tethering/TetheringInterfaceUtils.java
index d5cdd8a..4dd6830 100644
--- a/Tethering/src/com/android/server/connectivity/tethering/TetheringInterfaceUtils.java
+++ b/Tethering/src/com/android/server/connectivity/tethering/TetheringInterfaceUtils.java
@@ -22,6 +22,8 @@
import android.net.RouteInfo;
import android.net.util.InterfaceSet;
+import com.android.net.module.util.NetUtils;
+
import java.net.InetAddress;
import java.net.UnknownHostException;
@@ -85,7 +87,7 @@
private static String getInterfaceForDestination(LinkProperties lp, InetAddress dst) {
final RouteInfo ri = (lp != null)
- ? RouteInfo.selectBestRoute(lp.getAllRoutes(), dst)
+ ? NetUtils.selectBestRoute(lp.getAllRoutes(), dst)
: null;
return (ri != null) ? ri.getInterface() : null;
}
diff --git a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java b/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java
index e6a5521..4710287 100644
--- a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java
+++ b/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java
@@ -18,6 +18,7 @@
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.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;
@@ -97,7 +99,7 @@
import android.net.util.InterfaceParams;
import android.net.util.NetworkConstants;
import android.net.util.SharedLog;
-import android.net.wifi.WifiConfiguration;
+import android.net.wifi.SoftApConfiguration;
import android.net.wifi.WifiManager;
import android.net.wifi.p2p.WifiP2pGroup;
import android.net.wifi.p2p.WifiP2pInfo;
@@ -151,6 +153,7 @@
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 @@
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 @@
.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 @@
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 @@
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 @@
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 @@
private void runUsbTethering(UpstreamNetworkState upstreamState) {
prepareUsbTethering(upstreamState);
- sendUsbBroadcast(true, true, true);
+ sendUsbBroadcast(true, true, true, TETHERING_USB);
mLooper.dispatchAll();
}
@@ -814,6 +836,29 @@
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);
@@ -827,12 +872,12 @@
// TODO: Test with and without interfaceStatusChanged().
@Test
public void failingWifiTetheringLegacyApBroadcast() throws Exception {
- when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
+ when(mWifiManager.startTetheredHotspot(any(SoftApConfiguration.class))).thenReturn(true);
// Emulate pressing the WiFi tethering button.
mTethering.startTethering(createTetheringRquestParcel(TETHERING_WIFI), null);
mLooper.dispatchAll();
- verify(mWifiManager, times(1)).startSoftAp(null);
+ verify(mWifiManager, times(1)).startTetheredHotspot(null);
verifyNoMoreInteractions(mWifiManager);
verifyNoMoreInteractions(mNetd);
@@ -854,12 +899,12 @@
// TODO: Test with and without interfaceStatusChanged().
@Test
public void workingWifiTetheringEnrichedApBroadcast() throws Exception {
- when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
+ when(mWifiManager.startTetheredHotspot(any(SoftApConfiguration.class))).thenReturn(true);
// Emulate pressing the WiFi tethering button.
mTethering.startTethering(createTetheringRquestParcel(TETHERING_WIFI), null);
mLooper.dispatchAll();
- verify(mWifiManager, times(1)).startSoftAp(null);
+ verify(mWifiManager, times(1)).startTetheredHotspot(null);
verifyNoMoreInteractions(mWifiManager);
verifyNoMoreInteractions(mNetd);
@@ -930,13 +975,13 @@
// TODO: Test with and without interfaceStatusChanged().
@Test
public void failureEnablingIpForwarding() throws Exception {
- when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
+ when(mWifiManager.startTetheredHotspot(any(SoftApConfiguration.class))).thenReturn(true);
doThrow(new RemoteException()).when(mNetd).ipfwdEnableForwarding(TETHERING_NAME);
// Emulate pressing the WiFi tethering button.
mTethering.startTethering(createTetheringRquestParcel(TETHERING_WIFI), null);
mLooper.dispatchAll();
- verify(mWifiManager, times(1)).startSoftAp(null);
+ verify(mWifiManager, times(1)).startTetheredHotspot(null);
verifyNoMoreInteractions(mWifiManager);
verifyNoMoreInteractions(mNetd);
@@ -1193,7 +1238,7 @@
when(mUpstreamNetworkMonitor.getCurrentPreferredUpstream()).thenReturn(upstreamState);
when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any()))
.thenReturn(upstreamState);
- when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
+ when(mWifiManager.startTetheredHotspot(any(SoftApConfiguration.class))).thenReturn(true);
mTethering.interfaceStatusChanged(TEST_WLAN_IFNAME, true);
mLooper.dispatchAll();
tetherState = callback.pollTetherStatesChanged();