p2p: revise tethering handler for shared group interface support

When leaving a group, all information are erased and no group interface
is passed to tethering service.
For separate group interface, tethering could be stopped
on p2p group interface removed. For shared group interface,
i.e. management interface and group interface share one
interface, ex. p2p0, tethering has no chance to be stopped since management
interface won't be removed after leaving a group.

Bug: 141382930
Test: atest FrameworksNetTests
Test: atest FrameworksWifiTests
Test: atest TetheringTests
Change-Id: Ib611018b67c76ff79c7e6658136721090feb145b
This commit is contained in:
Jimmy Chen
2019-12-03 11:37:09 +08:00
parent 81369f59d2
commit ea902f6f2a
4 changed files with 52 additions and 24 deletions

View File

@@ -441,7 +441,8 @@ public class IpServer extends StateMachine {
} }
final Boolean setIfaceUp; final Boolean setIfaceUp;
if (mInterfaceType == TetheringManager.TETHERING_WIFI) { if (mInterfaceType == TetheringManager.TETHERING_WIFI
|| mInterfaceType == TetheringManager.TETHERING_WIFI_P2P) {
// The WiFi stack has ownership of the interface up/down state. // The WiFi stack has ownership of the interface up/down state.
// It is unclear whether the Bluetooth or USB stacks will manage their own // It is unclear whether the Bluetooth or USB stacks will manage their own
// state. // state.

View File

@@ -207,6 +207,7 @@ public class Tethering {
private Network mTetherUpstream; private Network mTetherUpstream;
private TetherStatesParcel mTetherStatesParcel; private TetherStatesParcel mTetherStatesParcel;
private boolean mDataSaverEnabled = false; private boolean mDataSaverEnabled = false;
private String mWifiP2pTetherInterface = null;
public Tethering(TetheringDependencies deps) { public Tethering(TetheringDependencies deps) {
mLog.mark("Tethering.constructed"); mLog.mark("Tethering.constructed");
@@ -852,6 +853,11 @@ public class Tethering {
} }
} }
private boolean isGroupOwner(WifiP2pGroup group) {
return group != null && group.isGroupOwner()
&& !TextUtils.isEmpty(group.getInterface());
}
private void handleWifiP2pAction(Intent intent) { private void handleWifiP2pAction(Intent intent) {
if (mConfig.isWifiP2pLegacyTetheringMode()) return; if (mConfig.isWifiP2pLegacyTetheringMode()) return;
@@ -864,24 +870,31 @@ public class Tethering {
Log.d(TAG, "WifiP2pAction: P2pInfo: " + p2pInfo + " Group: " + group); 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) { synchronized (Tethering.this.mPublicSync) {
// Enter below only if this device is Group Owner with a valid interface. // if no group is formed, bring it down if needed.
if (p2pInfo.groupFormed) { if (p2pInfo == null || !p2pInfo.groupFormed) {
TetherState tetherState = mTetherStates.get(group.getInterface()); disableWifiP2pIpServingLockedIfNeeded(mWifiP2pTetherInterface);
if (tetherState == null mWifiP2pTetherInterface = null;
|| (tetherState.lastState != IpServer.STATE_TETHERED return;
&& tetherState.lastState != IpServer.STATE_LOCAL_ONLY)) {
enableWifiIpServingLocked(group.getInterface(), IFACE_IP_MODE_LOCAL_ONLY);
}
} else {
disableWifiP2pIpServingLocked(group.getInterface());
} }
// If there is a group but the device is not the owner, bail out.
if (!isGroupOwner(group)) return;
// If already serving from the correct interface, nothing to do.
if (group.getInterface().equals(mWifiP2pTetherInterface)) return;
// If already serving from another interface, turn it down first.
if (!TextUtils.isEmpty(mWifiP2pTetherInterface)) {
mLog.w("P2P tethered interface " + mWifiP2pTetherInterface
+ "is different from current interface "
+ group.getInterface() + ", re-tether it");
disableWifiP2pIpServingLockedIfNeeded(mWifiP2pTetherInterface);
}
// Finally bring up serving on the new interface
mWifiP2pTetherInterface = group.getInterface();
enableWifiIpServingLocked(mWifiP2pTetherInterface, IFACE_IP_MODE_LOCAL_ONLY);
} }
} }
@@ -979,7 +992,9 @@ public class Tethering {
disableWifiIpServingLockedCommon(TETHERING_WIFI, ifname, apState); disableWifiIpServingLockedCommon(TETHERING_WIFI, ifname, apState);
} }
private void disableWifiP2pIpServingLocked(String ifname) { private void disableWifiP2pIpServingLockedIfNeeded(String ifname) {
if (TextUtils.isEmpty(ifname)) return;
disableWifiIpServingLockedCommon(TETHERING_WIFI_P2P, ifname, /* dummy */ 0); disableWifiIpServingLockedCommon(TETHERING_WIFI_P2P, ifname, /* dummy */ 0);
} }

View File

@@ -273,7 +273,7 @@ public class IpServerTest {
dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_LOCAL_ONLY); dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_LOCAL_ONLY);
InOrder inOrder = inOrder(mCallback, mNetd); InOrder inOrder = inOrder(mCallback, mNetd);
inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg -> inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg ->
IFACE_NAME.equals(cfg.ifName) && assertContainsFlag(cfg.flags, IF_STATE_UP))); IFACE_NAME.equals(cfg.ifName) && assertNotContainsFlag(cfg.flags, IF_STATE_UP)));
inOrder.verify(mNetd).tetherInterfaceAdd(IFACE_NAME); inOrder.verify(mNetd).tetherInterfaceAdd(IFACE_NAME);
inOrder.verify(mNetd).networkAddInterface(INetd.LOCAL_NET_ID, IFACE_NAME); inOrder.verify(mNetd).networkAddInterface(INetd.LOCAL_NET_ID, IFACE_NAME);
inOrder.verify(mNetd, times(2)).networkAddRoute(eq(INetd.LOCAL_NET_ID), eq(IFACE_NAME), inOrder.verify(mNetd, times(2)).networkAddRoute(eq(INetd.LOCAL_NET_ID), eq(IFACE_NAME),
@@ -547,4 +547,14 @@ public class IpServerTest {
fail("Missing flag: " + match); fail("Missing flag: " + match);
return false; return false;
} }
private boolean assertNotContainsFlag(String[] flags, String match) {
for (String flag : flags) {
if (flag.equals(match)) {
fail("Unexpected flag: " + match);
return false;
}
}
return true;
}
} }

View File

@@ -493,13 +493,15 @@ public class TetheringTest {
private void sendWifiP2pConnectionChanged( private void sendWifiP2pConnectionChanged(
boolean isGroupFormed, boolean isGroupOwner, String ifname) { boolean isGroupFormed, boolean isGroupOwner, String ifname) {
WifiP2pGroup group = null;
WifiP2pInfo p2pInfo = new WifiP2pInfo(); WifiP2pInfo p2pInfo = new WifiP2pInfo();
p2pInfo.groupFormed = isGroupFormed; p2pInfo.groupFormed = isGroupFormed;
p2pInfo.isGroupOwner = isGroupOwner; if (isGroupFormed) {
p2pInfo.isGroupOwner = isGroupOwner;
WifiP2pGroup group = mock(WifiP2pGroup.class); group = mock(WifiP2pGroup.class);
when(group.isGroupOwner()).thenReturn(isGroupOwner); when(group.isGroupOwner()).thenReturn(isGroupOwner);
when(group.getInterface()).thenReturn(ifname); when(group.getInterface()).thenReturn(ifname);
}
final Intent intent = mock(Intent.class); final Intent intent = mock(Intent.class);
when(intent.getAction()).thenReturn(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION); when(intent.getAction()).thenReturn(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);