Merge "p2p: mirgrate p2p into tethering modes"
am: 8a9a9adaeb
Change-Id: Ib8f43d77a5f57965fa217e6e92eb9773e7914b54
This commit is contained in:
@@ -472,6 +472,14 @@ public class ConnectivityManager {
|
||||
@SystemApi
|
||||
public static final int TETHERING_BLUETOOTH = 2;
|
||||
|
||||
/**
|
||||
* Wifi P2p tethering type.
|
||||
* Wifi P2p tethering is set through events automatically, and don't
|
||||
* need to start from #startTethering(int, boolean, OnStartTetheringCallback).
|
||||
* @hide
|
||||
*/
|
||||
public static final int TETHERING_WIFI_P2P = 3;
|
||||
|
||||
/**
|
||||
* Extra used for communicating with the TetherService. Includes the type of tethering to
|
||||
* enable if any.
|
||||
|
||||
@@ -386,6 +386,12 @@
|
||||
<string-array translatable="false" name="config_tether_wifi_regexs">
|
||||
</string-array>
|
||||
|
||||
<!-- 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.*" -->
|
||||
<string-array translatable="false" name="config_tether_wifi_p2p_regexs">
|
||||
</string-array>
|
||||
|
||||
<!-- List of regexpressions describing the interface (if any) that represent tetherable
|
||||
WiMAX interfaces. If the device doesn't want to support tethering over Wifi this
|
||||
should be empty. An example would be "softap.*" -->
|
||||
|
||||
@@ -1915,6 +1915,7 @@
|
||||
<java-symbol type="bool" name="config_tether_upstream_automatic" />
|
||||
<java-symbol type="array" name="config_tether_usb_regexs" />
|
||||
<java-symbol type="array" name="config_tether_wifi_regexs" />
|
||||
<java-symbol type="array" name="config_tether_wifi_p2p_regexs" />
|
||||
<java-symbol type="array" name="config_usbHostBlacklist" />
|
||||
<java-symbol type="array" name="config_serialPorts" />
|
||||
<java-symbol type="array" name="radioAttributes" />
|
||||
|
||||
@@ -30,6 +30,7 @@ import static android.net.ConnectivityManager.TETHERING_BLUETOOTH;
|
||||
import static android.net.ConnectivityManager.TETHERING_INVALID;
|
||||
import static android.net.ConnectivityManager.TETHERING_USB;
|
||||
import static android.net.ConnectivityManager.TETHERING_WIFI;
|
||||
import static android.net.ConnectivityManager.TETHERING_WIFI_P2P;
|
||||
import static android.net.ConnectivityManager.TETHER_ERROR_MASTER_ERROR;
|
||||
import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR;
|
||||
import static android.net.ConnectivityManager.TETHER_ERROR_SERVICE_UNAVAIL;
|
||||
@@ -77,6 +78,9 @@ import android.net.util.PrefixUtils;
|
||||
import android.net.util.SharedLog;
|
||||
import android.net.util.VersionedBroadcastListener;
|
||||
import android.net.wifi.WifiManager;
|
||||
import android.net.wifi.p2p.WifiP2pGroup;
|
||||
import android.net.wifi.p2p.WifiP2pInfo;
|
||||
import android.net.wifi.p2p.WifiP2pManager;
|
||||
import android.os.Binder;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
@@ -290,6 +294,7 @@ public class Tethering extends BaseNetworkObserver {
|
||||
filter.addAction(CONNECTIVITY_ACTION);
|
||||
filter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
|
||||
filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
|
||||
filter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
|
||||
mContext.registerReceiver(mStateReceiver, filter, null, handler);
|
||||
|
||||
filter = new IntentFilter();
|
||||
@@ -354,6 +359,8 @@ public class Tethering extends BaseNetworkObserver {
|
||||
|
||||
if (cfg.isWifi(iface)) {
|
||||
return TETHERING_WIFI;
|
||||
} else if (cfg.isWifiP2p(iface)) {
|
||||
return TETHERING_WIFI_P2P;
|
||||
} else if (cfg.isUsb(iface)) {
|
||||
return TETHERING_USB;
|
||||
} else if (cfg.isBluetooth(iface)) {
|
||||
@@ -527,6 +534,7 @@ public class Tethering extends BaseNetworkObserver {
|
||||
|
||||
public void untetherAll() {
|
||||
stopTethering(TETHERING_WIFI);
|
||||
stopTethering(TETHERING_WIFI_P2P);
|
||||
stopTethering(TETHERING_USB);
|
||||
stopTethering(TETHERING_BLUETOOTH);
|
||||
}
|
||||
@@ -713,6 +721,8 @@ public class Tethering extends BaseNetworkObserver {
|
||||
handleConnectivityAction(intent);
|
||||
} else if (action.equals(WifiManager.WIFI_AP_STATE_CHANGED_ACTION)) {
|
||||
handleWifiApAction(intent);
|
||||
} else if (action.equals(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION)) {
|
||||
handleWifiP2pAction(intent);
|
||||
} else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
|
||||
mLog.log("OBSERVED configuration changed");
|
||||
updateConfiguration();
|
||||
@@ -789,6 +799,39 @@ public class Tethering extends BaseNetworkObserver {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleWifiP2pAction(Intent intent) {
|
||||
if (mConfig.isWifiP2pLegacyTetheringMode()) return;
|
||||
|
||||
final WifiP2pInfo p2pInfo =
|
||||
(WifiP2pInfo) intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO);
|
||||
final WifiP2pGroup group =
|
||||
(WifiP2pGroup) intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_GROUP);
|
||||
|
||||
if (VDBG) {
|
||||
Log.d(TAG, "WifiP2pAction: P2pInfo: " + p2pInfo + " Group: " + group);
|
||||
}
|
||||
|
||||
if (p2pInfo == null) return;
|
||||
// When a p2p group is disconnected, p2pInfo would be cleared.
|
||||
// group is still valid for detecting whether this device is group owner.
|
||||
if (group == null || !group.isGroupOwner()
|
||||
|| TextUtils.isEmpty(group.getInterface())) return;
|
||||
|
||||
synchronized (Tethering.this.mPublicSync) {
|
||||
// Enter below only if this device is Group Owner with a valid interface.
|
||||
if (p2pInfo.groupFormed) {
|
||||
TetherState tetherState = mTetherStates.get(group.getInterface());
|
||||
if (tetherState == null
|
||||
|| (tetherState.lastState != IpServer.STATE_TETHERED
|
||||
&& tetherState.lastState != IpServer.STATE_LOCAL_ONLY)) {
|
||||
enableWifiIpServingLocked(group.getInterface(), IFACE_IP_MODE_LOCAL_ONLY);
|
||||
}
|
||||
} else {
|
||||
disableWifiP2pIpServingLocked(group.getInterface());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@@ -823,14 +866,11 @@ public class Tethering extends BaseNetworkObserver {
|
||||
}
|
||||
}
|
||||
|
||||
private void disableWifiIpServingLocked(String ifname, int apState) {
|
||||
mLog.log("Canceling WiFi tethering request - AP_STATE=" + apState);
|
||||
|
||||
// Regardless of whether we requested this transition, the AP has gone
|
||||
// down. Don't try to tether again unless we're requested to do so.
|
||||
// TODO: Remove this altogether, once Wi-Fi reliably gives us an
|
||||
// interface name with every broadcast.
|
||||
mWifiTetherRequested = false;
|
||||
private void disableWifiIpServingLockedCommon(int tetheringType, String ifname, int apState) {
|
||||
mLog.log("Canceling WiFi tethering request -"
|
||||
+ " type=" + tetheringType
|
||||
+ " interface=" + ifname
|
||||
+ " state=" + apState);
|
||||
|
||||
if (!TextUtils.isEmpty(ifname)) {
|
||||
final TetherState ts = mTetherStates.get(ifname);
|
||||
@@ -842,7 +882,7 @@ public class Tethering extends BaseNetworkObserver {
|
||||
|
||||
for (int i = 0; i < mTetherStates.size(); i++) {
|
||||
final IpServer ipServer = mTetherStates.valueAt(i).ipServer;
|
||||
if (ipServer.interfaceType() == TETHERING_WIFI) {
|
||||
if (ipServer.interfaceType() == tetheringType) {
|
||||
ipServer.unwanted();
|
||||
return;
|
||||
}
|
||||
@@ -853,6 +893,20 @@ public class Tethering extends BaseNetworkObserver {
|
||||
: "specified interface: " + ifname));
|
||||
}
|
||||
|
||||
private void disableWifiIpServingLocked(String ifname, int apState) {
|
||||
// Regardless of whether we requested this transition, the AP has gone
|
||||
// down. Don't try to tether again unless we're requested to do so.
|
||||
// TODO: Remove this altogether, once Wi-Fi reliably gives us an
|
||||
// interface name with every broadcast.
|
||||
mWifiTetherRequested = false;
|
||||
|
||||
disableWifiIpServingLockedCommon(TETHERING_WIFI, ifname, apState);
|
||||
}
|
||||
|
||||
private void disableWifiP2pIpServingLocked(String ifname) {
|
||||
disableWifiIpServingLockedCommon(TETHERING_WIFI_P2P, ifname, /* dummy */ 0);
|
||||
}
|
||||
|
||||
private void enableWifiIpServingLocked(String ifname, int wifiIpMode) {
|
||||
// Map wifiIpMode values to IpServer.Callback serving states, inferring
|
||||
// from mWifiTetherRequested as a final "best guess".
|
||||
@@ -870,7 +924,7 @@ public class Tethering extends BaseNetworkObserver {
|
||||
}
|
||||
|
||||
if (!TextUtils.isEmpty(ifname)) {
|
||||
maybeTrackNewInterfaceLocked(ifname, TETHERING_WIFI);
|
||||
maybeTrackNewInterfaceLocked(ifname);
|
||||
changeInterfaceState(ifname, ipServingMode);
|
||||
} else {
|
||||
mLog.e(String.format(
|
||||
|
||||
@@ -28,6 +28,7 @@ import static com.android.internal.R.array.config_tether_bluetooth_regexs;
|
||||
import static com.android.internal.R.array.config_tether_dhcp_range;
|
||||
import static com.android.internal.R.array.config_tether_upstream_types;
|
||||
import static com.android.internal.R.array.config_tether_usb_regexs;
|
||||
import static com.android.internal.R.array.config_tether_wifi_p2p_regexs;
|
||||
import static com.android.internal.R.array.config_tether_wifi_regexs;
|
||||
import static com.android.internal.R.bool.config_tether_upstream_automatic;
|
||||
import static com.android.internal.R.integer.config_mobile_hotspot_provision_check_period;
|
||||
@@ -85,6 +86,7 @@ public class TetheringConfiguration {
|
||||
|
||||
public final String[] tetherableUsbRegexs;
|
||||
public final String[] tetherableWifiRegexs;
|
||||
public final String[] tetherableWifiP2pRegexs;
|
||||
public final String[] tetherableBluetoothRegexs;
|
||||
public final boolean isDunRequired;
|
||||
public final boolean chooseUpstreamAutomatically;
|
||||
@@ -110,6 +112,7 @@ public class TetheringConfiguration {
|
||||
// us an interface name. Careful consideration needs to be given to
|
||||
// implications for Settings and for provisioning checks.
|
||||
tetherableWifiRegexs = getResourceStringArray(res, config_tether_wifi_regexs);
|
||||
tetherableWifiP2pRegexs = getResourceStringArray(res, config_tether_wifi_p2p_regexs);
|
||||
tetherableBluetoothRegexs = getResourceStringArray(res, config_tether_bluetooth_regexs);
|
||||
|
||||
isDunRequired = checkDunRequired(ctx, subId);
|
||||
@@ -138,6 +141,15 @@ public class TetheringConfiguration {
|
||||
return matchesDownstreamRegexs(iface, tetherableWifiRegexs);
|
||||
}
|
||||
|
||||
/** Check whether this interface is Wifi P2P interface. */
|
||||
public boolean isWifiP2p(String iface) {
|
||||
return matchesDownstreamRegexs(iface, tetherableWifiP2pRegexs);
|
||||
}
|
||||
|
||||
public boolean isWifiP2pLegacyTetheringMode() {
|
||||
return (tetherableWifiP2pRegexs == null || tetherableWifiP2pRegexs.length == 0);
|
||||
}
|
||||
|
||||
public boolean isBluetooth(String iface) {
|
||||
return matchesDownstreamRegexs(iface, tetherableBluetoothRegexs);
|
||||
}
|
||||
@@ -152,6 +164,7 @@ public class TetheringConfiguration {
|
||||
|
||||
dumpStringArray(pw, "tetherableUsbRegexs", tetherableUsbRegexs);
|
||||
dumpStringArray(pw, "tetherableWifiRegexs", tetherableWifiRegexs);
|
||||
dumpStringArray(pw, "tetherableWifiP2pRegexs", tetherableWifiP2pRegexs);
|
||||
dumpStringArray(pw, "tetherableBluetoothRegexs", tetherableBluetoothRegexs);
|
||||
|
||||
pw.print("isDunRequired: ");
|
||||
@@ -178,6 +191,7 @@ public class TetheringConfiguration {
|
||||
sj.add(String.format("subId:%d", subId));
|
||||
sj.add(String.format("tetherableUsbRegexs:%s", makeString(tetherableUsbRegexs)));
|
||||
sj.add(String.format("tetherableWifiRegexs:%s", makeString(tetherableWifiRegexs)));
|
||||
sj.add(String.format("tetherableWifiP2pRegexs:%s", makeString(tetherableWifiP2pRegexs)));
|
||||
sj.add(String.format("tetherableBluetoothRegexs:%s",
|
||||
makeString(tetherableBluetoothRegexs)));
|
||||
sj.add(String.format("isDunRequired:%s", isDunRequired));
|
||||
|
||||
@@ -93,6 +93,8 @@ public class IpServer extends StateMachine {
|
||||
private static final int USB_PREFIX_LENGTH = 24;
|
||||
private static final String WIFI_HOST_IFACE_ADDR = "192.168.43.1";
|
||||
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;
|
||||
|
||||
// TODO: have PanService use some visible version of this constant
|
||||
private static final String BLUETOOTH_IFACE_ADDR = "192.168.44.1";
|
||||
@@ -403,6 +405,9 @@ public class IpServer extends StateMachine {
|
||||
} else if (mInterfaceType == ConnectivityManager.TETHERING_WIFI) {
|
||||
ipAsString = getRandomWifiIPv4Address();
|
||||
prefixLen = WIFI_HOST_IFACE_PREFIX_LENGTH;
|
||||
} else if (mInterfaceType == ConnectivityManager.TETHERING_WIFI_P2P) {
|
||||
ipAsString = WIFI_P2P_IFACE_ADDR;
|
||||
prefixLen = WIFI_P2P_IFACE_PREFIX_LENGTH;
|
||||
} else {
|
||||
// BT configures the interface elsewhere: only start DHCP.
|
||||
final Inet4Address srvAddr = (Inet4Address) numericToInetAddress(BLUETOOTH_IFACE_ADDR);
|
||||
|
||||
@@ -19,11 +19,13 @@ package android.net.ip;
|
||||
import static android.net.ConnectivityManager.TETHERING_BLUETOOTH;
|
||||
import static android.net.ConnectivityManager.TETHERING_USB;
|
||||
import static android.net.ConnectivityManager.TETHERING_WIFI;
|
||||
import static android.net.ConnectivityManager.TETHERING_WIFI_P2P;
|
||||
import static android.net.ConnectivityManager.TETHER_ERROR_ENABLE_NAT_ERROR;
|
||||
import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR;
|
||||
import static android.net.ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR;
|
||||
import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS;
|
||||
import static android.net.ip.IpServer.STATE_AVAILABLE;
|
||||
import static android.net.ip.IpServer.STATE_LOCAL_ONLY;
|
||||
import static android.net.ip.IpServer.STATE_TETHERED;
|
||||
import static android.net.ip.IpServer.STATE_UNAVAILABLE;
|
||||
import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTH;
|
||||
@@ -255,6 +257,23 @@ public class IpServerTest {
|
||||
verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canBeTetheredAsWifiP2p() throws Exception {
|
||||
initStateMachine(TETHERING_WIFI_P2P);
|
||||
|
||||
dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_LOCAL_ONLY);
|
||||
InOrder inOrder = inOrder(mCallback, mNMService);
|
||||
inOrder.verify(mNMService).getInterfaceConfig(IFACE_NAME);
|
||||
inOrder.verify(mNMService).setInterfaceConfig(IFACE_NAME, mInterfaceConfiguration);
|
||||
inOrder.verify(mNMService).tetherInterface(IFACE_NAME);
|
||||
inOrder.verify(mCallback).updateInterfaceState(
|
||||
mIpServer, STATE_LOCAL_ONLY, TETHER_ERROR_NO_ERROR);
|
||||
inOrder.verify(mCallback).updateLinkProperties(
|
||||
eq(mIpServer), mLinkPropertiesCaptor.capture());
|
||||
assertIPv4AddressAndDirectlyConnectedRoute(mLinkPropertiesCaptor.getValue());
|
||||
verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void handlesFirstUpstreamChange() throws Exception {
|
||||
initTetheredStateMachine(TETHERING_BLUETOOTH, null);
|
||||
@@ -418,6 +437,14 @@ public class IpServerTest {
|
||||
assertDhcpStarted(new IpPrefix("192.168.44.0/24"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startsDhcpServerOnWifiP2p() throws Exception {
|
||||
initTetheredStateMachine(TETHERING_WIFI_P2P, UPSTREAM_IFACE);
|
||||
dispatchTetherConnectionChanged(UPSTREAM_IFACE);
|
||||
|
||||
assertDhcpStarted(new IpPrefix("192.168.49.0/24"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doesNotStartDhcpServerIfDisabled() throws Exception {
|
||||
initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, true /* usingLegacyDhcp */);
|
||||
|
||||
@@ -25,8 +25,10 @@ import static android.net.ConnectivityManager.EXTRA_ACTIVE_TETHER;
|
||||
import static android.net.ConnectivityManager.EXTRA_AVAILABLE_TETHER;
|
||||
import static android.net.ConnectivityManager.TETHERING_USB;
|
||||
import static android.net.ConnectivityManager.TETHERING_WIFI;
|
||||
import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR;
|
||||
import static android.net.ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
|
||||
import static android.net.ConnectivityManager.TYPE_MOBILE;
|
||||
import static android.net.ConnectivityManager.TYPE_WIFI_P2P;
|
||||
import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS;
|
||||
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME;
|
||||
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE;
|
||||
@@ -90,6 +92,9 @@ import android.net.util.NetworkConstants;
|
||||
import android.net.util.SharedLog;
|
||||
import android.net.wifi.WifiConfiguration;
|
||||
import android.net.wifi.WifiManager;
|
||||
import android.net.wifi.p2p.WifiP2pGroup;
|
||||
import android.net.wifi.p2p.WifiP2pInfo;
|
||||
import android.net.wifi.p2p.WifiP2pManager;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.INetworkManagementService;
|
||||
@@ -140,6 +145,7 @@ public class TetheringTest {
|
||||
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_WLAN_IFNAME = "test_wlan0";
|
||||
private static final String TEST_P2P_IFNAME = "test_p2p-p2p0-0";
|
||||
|
||||
private static final int DHCPSERVER_START_TIMEOUT_MS = 1000;
|
||||
|
||||
@@ -216,9 +222,10 @@ public class TetheringTest {
|
||||
assertTrue("Non-mocked interface " + ifName,
|
||||
ifName.equals(TEST_USB_IFNAME)
|
||||
|| ifName.equals(TEST_WLAN_IFNAME)
|
||||
|| ifName.equals(TEST_MOBILE_IFNAME));
|
||||
|| ifName.equals(TEST_MOBILE_IFNAME)
|
||||
|| ifName.equals(TEST_P2P_IFNAME));
|
||||
final String[] ifaces = new String[] {
|
||||
TEST_USB_IFNAME, TEST_WLAN_IFNAME, TEST_MOBILE_IFNAME };
|
||||
TEST_USB_IFNAME, TEST_WLAN_IFNAME, TEST_MOBILE_IFNAME, TEST_P2P_IFNAME};
|
||||
return new InterfaceParams(ifName, ArrayUtils.indexOf(ifaces, ifName) + IFINDEX_OFFSET,
|
||||
MacAddress.ALL_ZEROS_ADDRESS);
|
||||
}
|
||||
@@ -361,6 +368,8 @@ public class TetheringTest {
|
||||
.thenReturn(new String[] { "test_rndis\\d" });
|
||||
when(mResources.getStringArray(com.android.internal.R.array.config_tether_wifi_regexs))
|
||||
.thenReturn(new String[]{ "test_wlan\\d" });
|
||||
when(mResources.getStringArray(com.android.internal.R.array.config_tether_wifi_p2p_regexs))
|
||||
.thenReturn(new String[]{ "test_p2p-p2p\\d-.*" });
|
||||
when(mResources.getStringArray(com.android.internal.R.array.config_tether_bluetooth_regexs))
|
||||
.thenReturn(new String[0]);
|
||||
when(mResources.getIntArray(com.android.internal.R.array.config_tether_upstream_types))
|
||||
@@ -369,7 +378,7 @@ public class TetheringTest {
|
||||
.thenReturn(false);
|
||||
when(mNMService.listInterfaces())
|
||||
.thenReturn(new String[] {
|
||||
TEST_MOBILE_IFNAME, TEST_WLAN_IFNAME, TEST_USB_IFNAME});
|
||||
TEST_MOBILE_IFNAME, TEST_WLAN_IFNAME, TEST_USB_IFNAME, TEST_P2P_IFNAME});
|
||||
when(mNMService.getInterfaceConfig(anyString()))
|
||||
.thenReturn(new InterfaceConfiguration());
|
||||
when(mRouterAdvertisementDaemon.start())
|
||||
@@ -423,6 +432,31 @@ public class TetheringTest {
|
||||
mServiceContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
|
||||
}
|
||||
|
||||
private static final String[] P2P_RECEIVER_PERMISSIONS_FOR_BROADCAST = {
|
||||
android.Manifest.permission.ACCESS_FINE_LOCATION,
|
||||
android.Manifest.permission.ACCESS_WIFI_STATE
|
||||
};
|
||||
|
||||
private void sendWifiP2pConnectionChanged(
|
||||
boolean isGroupFormed, boolean isGroupOwner, String ifname) {
|
||||
WifiP2pInfo p2pInfo = new WifiP2pInfo();
|
||||
p2pInfo.groupFormed = isGroupFormed;
|
||||
p2pInfo.isGroupOwner = isGroupOwner;
|
||||
|
||||
NetworkInfo networkInfo = new NetworkInfo(TYPE_WIFI_P2P, 0, null, null);
|
||||
|
||||
WifiP2pGroup group = new WifiP2pGroup();
|
||||
group.setIsGroupOwner(isGroupOwner);
|
||||
group.setInterface(ifname);
|
||||
|
||||
final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
|
||||
intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO, p2pInfo);
|
||||
intent.putExtra(WifiP2pManager.EXTRA_NETWORK_INFO, networkInfo);
|
||||
intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_GROUP, group);
|
||||
mServiceContext.sendBroadcastAsUserMultiplePermissions(intent, UserHandle.ALL,
|
||||
P2P_RECEIVER_PERMISSIONS_FOR_BROADCAST);
|
||||
}
|
||||
|
||||
private void sendUsbBroadcast(boolean connected, boolean configured, boolean rndisFunction) {
|
||||
final Intent intent = new Intent(UsbManager.ACTION_USB_STATE);
|
||||
intent.putExtra(USB_CONNECTED, connected);
|
||||
@@ -436,11 +470,11 @@ public class TetheringTest {
|
||||
mServiceContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
|
||||
}
|
||||
|
||||
private void verifyInterfaceServingModeStarted() throws Exception {
|
||||
verify(mNMService, times(1)).getInterfaceConfig(TEST_WLAN_IFNAME);
|
||||
private void verifyInterfaceServingModeStarted(String ifname) throws Exception {
|
||||
verify(mNMService, times(1)).getInterfaceConfig(ifname);
|
||||
verify(mNMService, times(1))
|
||||
.setInterfaceConfig(eq(TEST_WLAN_IFNAME), any(InterfaceConfiguration.class));
|
||||
verify(mNMService, times(1)).tetherInterface(TEST_WLAN_IFNAME);
|
||||
.setInterfaceConfig(eq(ifname), any(InterfaceConfiguration.class));
|
||||
verify(mNMService, times(1)).tetherInterface(ifname);
|
||||
}
|
||||
|
||||
private void verifyTetheringBroadcast(String ifname, String whichExtra) {
|
||||
@@ -530,7 +564,7 @@ public class TetheringTest {
|
||||
sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_LOCAL_ONLY);
|
||||
mLooper.dispatchAll();
|
||||
|
||||
verifyInterfaceServingModeStarted();
|
||||
verifyInterfaceServingModeStarted(TEST_WLAN_IFNAME);
|
||||
verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER);
|
||||
verify(mNMService, times(1)).setIpForwardingEnabled(true);
|
||||
verify(mNMService, times(1)).startTethering(any(String[].class));
|
||||
@@ -542,8 +576,9 @@ public class TetheringTest {
|
||||
verifyNoMoreInteractions(mWifiManager);
|
||||
verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_ACTIVE_LOCAL_ONLY);
|
||||
verify(mUpstreamNetworkMonitor, times(1)).startObserveAllNetworks();
|
||||
// TODO: Figure out why this isn't exactly once, for sendTetherStateChangedBroadcast().
|
||||
assertTrue(1 <= mTetheringDependencies.isTetheringSupportedCalls);
|
||||
// This will be called twice, one is on entering IpServer.STATE_AVAILABLE,
|
||||
// and another one is on IpServer.STATE_TETHERED/IpServer.STATE_LOCAL_ONLY.
|
||||
assertEquals(2, mTetheringDependencies.isTetheringSupportedCalls);
|
||||
|
||||
// Emulate externally-visible WifiManager effects, when hotspot mode
|
||||
// is being torn down.
|
||||
@@ -552,9 +587,9 @@ public class TetheringTest {
|
||||
mLooper.dispatchAll();
|
||||
|
||||
verify(mNMService, times(1)).untetherInterface(TEST_WLAN_IFNAME);
|
||||
// TODO: Why is {g,s}etInterfaceConfig() called more than once?
|
||||
verify(mNMService, atLeastOnce()).getInterfaceConfig(TEST_WLAN_IFNAME);
|
||||
verify(mNMService, atLeastOnce())
|
||||
// {g,s}etInterfaceConfig() called twice for enabling and disabling IPv4.
|
||||
verify(mNMService, times(2)).getInterfaceConfig(TEST_WLAN_IFNAME);
|
||||
verify(mNMService, times(2))
|
||||
.setInterfaceConfig(eq(TEST_WLAN_IFNAME), any(InterfaceConfiguration.class));
|
||||
verify(mNMService, times(1)).stopTethering();
|
||||
verify(mNMService, times(1)).setIpForwardingEnabled(false);
|
||||
@@ -770,7 +805,7 @@ public class TetheringTest {
|
||||
sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED);
|
||||
mLooper.dispatchAll();
|
||||
|
||||
verifyInterfaceServingModeStarted();
|
||||
verifyInterfaceServingModeStarted(TEST_WLAN_IFNAME);
|
||||
verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER);
|
||||
verify(mNMService, times(1)).setIpForwardingEnabled(true);
|
||||
verify(mNMService, times(1)).startTethering(any(String[].class));
|
||||
@@ -785,8 +820,9 @@ public class TetheringTest {
|
||||
// In tethering mode, in the default configuration, an explicit request
|
||||
// for a mobile network is also made.
|
||||
verify(mUpstreamNetworkMonitor, times(1)).registerMobileNetworkRequest();
|
||||
// TODO: Figure out why this isn't exactly once, for sendTetherStateChangedBroadcast().
|
||||
assertTrue(1 <= mTetheringDependencies.isTetheringSupportedCalls);
|
||||
// This will be called twice, one is on entering IpServer.STATE_AVAILABLE,
|
||||
// and another one is on IpServer.STATE_TETHERED/IpServer.STATE_LOCAL_ONLY.
|
||||
assertEquals(2, mTetheringDependencies.isTetheringSupportedCalls);
|
||||
|
||||
/////
|
||||
// We do not currently emulate any upstream being found.
|
||||
@@ -809,7 +845,7 @@ public class TetheringTest {
|
||||
mLooper.dispatchAll();
|
||||
|
||||
verify(mNMService, times(1)).untetherInterface(TEST_WLAN_IFNAME);
|
||||
// TODO: Why is {g,s}etInterfaceConfig() called more than once?
|
||||
// {g,s}etInterfaceConfig() called twice for enabling and disabling IPv4.
|
||||
verify(mNMService, atLeastOnce()).getInterfaceConfig(TEST_WLAN_IFNAME);
|
||||
verify(mNMService, atLeastOnce())
|
||||
.setInterfaceConfig(eq(TEST_WLAN_IFNAME), any(InterfaceConfiguration.class));
|
||||
@@ -857,8 +893,9 @@ public class TetheringTest {
|
||||
TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
|
||||
verify(mWifiManager).updateInterfaceIpState(
|
||||
TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_TETHERED);
|
||||
// TODO: Figure out why this isn't exactly once, for sendTetherStateChangedBroadcast().
|
||||
assertTrue(1 <= mTetheringDependencies.isTetheringSupportedCalls);
|
||||
// There are 3 state change event:
|
||||
// AVAILABLE -> STATE_TETHERED -> STATE_AVAILABLE.
|
||||
assertEquals(3, mTetheringDependencies.isTetheringSupportedCalls);
|
||||
verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER);
|
||||
// This is called, but will throw.
|
||||
verify(mNMService, times(1)).setIpForwardingEnabled(true);
|
||||
@@ -1031,6 +1068,133 @@ public class TetheringTest {
|
||||
assertEquals(fakeSubId, newConfig.subId);
|
||||
}
|
||||
|
||||
private void workingWifiP2pGroupOwner(
|
||||
boolean emulateInterfaceStatusChanged) throws Exception {
|
||||
if (emulateInterfaceStatusChanged) {
|
||||
mTethering.interfaceStatusChanged(TEST_P2P_IFNAME, true);
|
||||
}
|
||||
sendWifiP2pConnectionChanged(true, true, TEST_P2P_IFNAME);
|
||||
mLooper.dispatchAll();
|
||||
|
||||
verifyInterfaceServingModeStarted(TEST_P2P_IFNAME);
|
||||
verifyTetheringBroadcast(TEST_P2P_IFNAME, EXTRA_AVAILABLE_TETHER);
|
||||
verify(mNMService, times(1)).setIpForwardingEnabled(true);
|
||||
verify(mNMService, times(1)).startTethering(any(String[].class));
|
||||
verifyNoMoreInteractions(mNMService);
|
||||
verifyTetheringBroadcast(TEST_P2P_IFNAME, EXTRA_ACTIVE_LOCAL_ONLY);
|
||||
verify(mUpstreamNetworkMonitor, times(1)).startObserveAllNetworks();
|
||||
// This will be called twice, one is on entering IpServer.STATE_AVAILABLE,
|
||||
// and another one is on IpServer.STATE_TETHERED/IpServer.STATE_LOCAL_ONLY.
|
||||
assertEquals(2, mTetheringDependencies.isTetheringSupportedCalls);
|
||||
|
||||
assertEquals(TETHER_ERROR_NO_ERROR, mTethering.getLastTetherError(TEST_P2P_IFNAME));
|
||||
|
||||
// Emulate externally-visible WifiP2pManager effects, when wifi p2p group
|
||||
// is being removed.
|
||||
sendWifiP2pConnectionChanged(false, true, TEST_P2P_IFNAME);
|
||||
mTethering.interfaceRemoved(TEST_P2P_IFNAME);
|
||||
mLooper.dispatchAll();
|
||||
|
||||
verify(mNMService, times(1)).untetherInterface(TEST_P2P_IFNAME);
|
||||
// {g,s}etInterfaceConfig() called twice for enabling and disabling IPv4.
|
||||
verify(mNMService, times(2)).getInterfaceConfig(TEST_P2P_IFNAME);
|
||||
verify(mNMService, times(2))
|
||||
.setInterfaceConfig(eq(TEST_P2P_IFNAME), any(InterfaceConfiguration.class));
|
||||
verify(mNMService, times(1)).stopTethering();
|
||||
verify(mNMService, times(1)).setIpForwardingEnabled(false);
|
||||
verify(mUpstreamNetworkMonitor, never()).getCurrentPreferredUpstream();
|
||||
verify(mUpstreamNetworkMonitor, never()).selectPreferredUpstreamType(any());
|
||||
verifyNoMoreInteractions(mNMService);
|
||||
// Asking for the last error after the per-interface state machine
|
||||
// has been reaped yields an unknown interface error.
|
||||
assertEquals(TETHER_ERROR_UNKNOWN_IFACE, mTethering.getLastTetherError(TEST_P2P_IFNAME));
|
||||
}
|
||||
|
||||
private void workingWifiP2pGroupClient(
|
||||
boolean emulateInterfaceStatusChanged) throws Exception {
|
||||
if (emulateInterfaceStatusChanged) {
|
||||
mTethering.interfaceStatusChanged(TEST_P2P_IFNAME, true);
|
||||
}
|
||||
sendWifiP2pConnectionChanged(true, false, TEST_P2P_IFNAME);
|
||||
mLooper.dispatchAll();
|
||||
|
||||
verify(mNMService, never()).getInterfaceConfig(TEST_P2P_IFNAME);
|
||||
verify(mNMService, never())
|
||||
.setInterfaceConfig(eq(TEST_P2P_IFNAME), any(InterfaceConfiguration.class));
|
||||
verify(mNMService, never()).tetherInterface(TEST_P2P_IFNAME);
|
||||
verify(mNMService, never()).setIpForwardingEnabled(true);
|
||||
verify(mNMService, never()).startTethering(any(String[].class));
|
||||
|
||||
// Emulate externally-visible WifiP2pManager effects, when wifi p2p group
|
||||
// is being removed.
|
||||
sendWifiP2pConnectionChanged(false, false, TEST_P2P_IFNAME);
|
||||
mTethering.interfaceRemoved(TEST_P2P_IFNAME);
|
||||
mLooper.dispatchAll();
|
||||
|
||||
verify(mNMService, never()).untetherInterface(TEST_P2P_IFNAME);
|
||||
verify(mNMService, never()).getInterfaceConfig(TEST_P2P_IFNAME);
|
||||
verify(mNMService, never())
|
||||
.setInterfaceConfig(eq(TEST_P2P_IFNAME), any(InterfaceConfiguration.class));
|
||||
verify(mNMService, never()).stopTethering();
|
||||
verify(mNMService, never()).setIpForwardingEnabled(false);
|
||||
verifyNoMoreInteractions(mNMService);
|
||||
// Asking for the last error after the per-interface state machine
|
||||
// has been reaped yields an unknown interface error.
|
||||
assertEquals(TETHER_ERROR_UNKNOWN_IFACE, mTethering.getLastTetherError(TEST_P2P_IFNAME));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void workingWifiP2pGroupOwnerWithIfaceChanged() throws Exception {
|
||||
workingWifiP2pGroupOwner(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void workingWifiP2pGroupOwnerSansIfaceChanged() throws Exception {
|
||||
workingWifiP2pGroupOwner(false);
|
||||
}
|
||||
|
||||
private void workingWifiP2pGroupOwnerLegacyMode(
|
||||
boolean emulateInterfaceStatusChanged) throws Exception {
|
||||
// change to legacy mode and update tethering information by chaning SIM
|
||||
when(mResources.getStringArray(com.android.internal.R.array.config_tether_wifi_p2p_regexs))
|
||||
.thenReturn(new String[]{});
|
||||
final int fakeSubId = 1234;
|
||||
mPhoneStateListener.onActiveDataSubscriptionIdChanged(fakeSubId);
|
||||
|
||||
if (emulateInterfaceStatusChanged) {
|
||||
mTethering.interfaceStatusChanged(TEST_P2P_IFNAME, true);
|
||||
}
|
||||
sendWifiP2pConnectionChanged(true, true, TEST_P2P_IFNAME);
|
||||
mLooper.dispatchAll();
|
||||
|
||||
verify(mNMService, never()).getInterfaceConfig(TEST_P2P_IFNAME);
|
||||
verify(mNMService, never())
|
||||
.setInterfaceConfig(eq(TEST_P2P_IFNAME), any(InterfaceConfiguration.class));
|
||||
verify(mNMService, never()).tetherInterface(TEST_P2P_IFNAME);
|
||||
verify(mNMService, never()).setIpForwardingEnabled(true);
|
||||
verify(mNMService, never()).startTethering(any(String[].class));
|
||||
assertEquals(TETHER_ERROR_UNKNOWN_IFACE, mTethering.getLastTetherError(TEST_P2P_IFNAME));
|
||||
}
|
||||
@Test
|
||||
public void workingWifiP2pGroupOwnerLegacyModeWithIfaceChanged() throws Exception {
|
||||
workingWifiP2pGroupOwnerLegacyMode(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void workingWifiP2pGroupOwnerLegacyModeSansIfaceChanged() throws Exception {
|
||||
workingWifiP2pGroupOwnerLegacyMode(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void workingWifiP2pGroupClientWithIfaceChanged() throws Exception {
|
||||
workingWifiP2pGroupClient(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void workingWifiP2pGroupClientSansIfaceChanged() throws Exception {
|
||||
workingWifiP2pGroupClient(false);
|
||||
}
|
||||
|
||||
// TODO: Test that a request for hotspot mode doesn't interfere with an
|
||||
// already operating tethering mode interface.
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user