Merge "Use new bluetooth API to enable/disable bt tethering after T"
This commit is contained in:
commit
ceeebae37e
5 changed files with 226 additions and 27 deletions
|
|
@ -614,10 +614,8 @@ public class IpServer extends StateMachine {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (mInterfaceType == TetheringManager.TETHERING_BLUETOOTH) {
|
||||
// BT configures the interface elsewhere: only start DHCP.
|
||||
// TODO: make all tethering types behave the same way, and delete the bluetooth
|
||||
// code that calls into NetworkManagementService directly.
|
||||
if (shouldNotConfigureBluetoothInterface()) {
|
||||
// Interface was already configured elsewhere, only start DHCP.
|
||||
return configureDhcp(enabled, mIpv4Address, null /* clientAddress */);
|
||||
}
|
||||
|
||||
|
|
@ -651,12 +649,15 @@ public class IpServer extends StateMachine {
|
|||
return configureDhcp(enabled, mIpv4Address, mStaticIpv4ClientAddr);
|
||||
}
|
||||
|
||||
private boolean shouldNotConfigureBluetoothInterface() {
|
||||
// Before T, bluetooth tethering configures the interface elsewhere.
|
||||
return (mInterfaceType == TetheringManager.TETHERING_BLUETOOTH) && !SdkLevel.isAtLeastT();
|
||||
}
|
||||
|
||||
private LinkAddress requestIpv4Address(final boolean useLastAddress) {
|
||||
if (mStaticIpv4ServerAddr != null) return mStaticIpv4ServerAddr;
|
||||
|
||||
if (mInterfaceType == TetheringManager.TETHERING_BLUETOOTH) {
|
||||
return new LinkAddress(BLUETOOTH_IFACE_ADDR);
|
||||
}
|
||||
if (shouldNotConfigureBluetoothInterface()) return new LinkAddress(BLUETOOTH_IFACE_ADDR);
|
||||
|
||||
return mPrivateAddressCoordinator.requestDownstreamAddress(this, useLastAddress);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -134,7 +134,12 @@ import com.android.internal.util.IndentingPrintWriter;
|
|||
import com.android.internal.util.MessageUtils;
|
||||
import com.android.internal.util.State;
|
||||
import com.android.internal.util.StateMachine;
|
||||
import com.android.modules.utils.build.SdkLevel;
|
||||
import com.android.net.module.util.BaseNetdUnsolicitedEventListener;
|
||||
import com.android.networkstack.apishim.common.BluetoothPanShim;
|
||||
import com.android.networkstack.apishim.common.BluetoothPanShim.TetheredInterfaceCallbackShim;
|
||||
import com.android.networkstack.apishim.common.BluetoothPanShim.TetheredInterfaceRequestShim;
|
||||
import com.android.networkstack.apishim.common.UnsupportedApiLevelException;
|
||||
import com.android.networkstack.tethering.util.InterfaceSet;
|
||||
import com.android.networkstack.tethering.util.PrefixUtils;
|
||||
import com.android.networkstack.tethering.util.TetheringUtils;
|
||||
|
|
@ -265,8 +270,11 @@ public class Tethering {
|
|||
private int mOffloadStatus = TETHER_HARDWARE_OFFLOAD_STOPPED;
|
||||
|
||||
private EthernetManager.TetheredInterfaceRequest mEthernetIfaceRequest;
|
||||
private TetheredInterfaceRequestShim mBluetoothIfaceRequest;
|
||||
private String mConfiguredEthernetIface;
|
||||
private String mConfiguredBluetoothIface;
|
||||
private EthernetCallback mEthernetCallback;
|
||||
private TetheredInterfaceCallbackShim mBluetoothCallback;
|
||||
private SettingsObserver mSettingsObserver;
|
||||
private BluetoothPan mBluetoothPan;
|
||||
private PanServiceListener mBluetoothPanListener;
|
||||
|
|
@ -533,14 +541,16 @@ public class Tethering {
|
|||
}
|
||||
}
|
||||
|
||||
// This method needs to exist because TETHERING_BLUETOOTH and TETHERING_WIGIG can't use
|
||||
// enableIpServing.
|
||||
// This method needs to exist because TETHERING_BLUETOOTH before Android T and TETHERING_WIGIG
|
||||
// can't use enableIpServing.
|
||||
private void processInterfaceStateChange(final String iface, boolean enabled) {
|
||||
// Do not listen to USB interface state changes or USB interface add/removes. USB tethering
|
||||
// is driven only by USB_ACTION broadcasts.
|
||||
final int type = ifaceNameToType(iface);
|
||||
if (type == TETHERING_USB || type == TETHERING_NCM) return;
|
||||
|
||||
if (type == TETHERING_BLUETOOTH && SdkLevel.isAtLeastT()) return;
|
||||
|
||||
if (enabled) {
|
||||
ensureIpServerStarted(iface);
|
||||
} else {
|
||||
|
|
@ -769,6 +779,9 @@ public class Tethering {
|
|||
TETHERING_BLUETOOTH);
|
||||
}
|
||||
mPendingPanRequests.clear();
|
||||
mBluetoothIfaceRequest = null;
|
||||
mBluetoothCallback = null;
|
||||
maybeDisableBluetoothIpServing();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -779,7 +792,11 @@ public class Tethering {
|
|||
|
||||
private void setBluetoothTetheringSettings(@NonNull final BluetoothPan bluetoothPan,
|
||||
final boolean enable, final IIntResultListener listener) {
|
||||
bluetoothPan.setBluetoothTethering(enable);
|
||||
if (SdkLevel.isAtLeastT()) {
|
||||
changeBluetoothTetheringSettings(bluetoothPan, enable);
|
||||
} else {
|
||||
changeBluetoothTetheringSettingsPreT(bluetoothPan, enable);
|
||||
}
|
||||
|
||||
// Enabling bluetooth tethering settings can silently fail. Send internal error if the
|
||||
// result is not expected.
|
||||
|
|
@ -788,6 +805,68 @@ public class Tethering {
|
|||
sendTetherResult(listener, result, TETHERING_BLUETOOTH);
|
||||
}
|
||||
|
||||
private void changeBluetoothTetheringSettingsPreT(@NonNull final BluetoothPan bluetoothPan,
|
||||
final boolean enable) {
|
||||
bluetoothPan.setBluetoothTethering(enable);
|
||||
}
|
||||
|
||||
private void changeBluetoothTetheringSettings(@NonNull final BluetoothPan bluetoothPan,
|
||||
final boolean enable) {
|
||||
final BluetoothPanShim panShim = mDeps.getBluetoothPanShim(bluetoothPan);
|
||||
if (enable) {
|
||||
if (mBluetoothIfaceRequest != null) {
|
||||
Log.d(TAG, "Bluetooth tethering settings already enabled");
|
||||
return;
|
||||
}
|
||||
|
||||
mBluetoothCallback = new BluetoothCallback();
|
||||
try {
|
||||
mBluetoothIfaceRequest = panShim.requestTetheredInterface(mExecutor,
|
||||
mBluetoothCallback);
|
||||
} catch (UnsupportedApiLevelException e) {
|
||||
Log.wtf(TAG, "Use unsupported API, " + e);
|
||||
}
|
||||
} else {
|
||||
if (mBluetoothIfaceRequest == null) {
|
||||
Log.d(TAG, "Bluetooth tethering settings already disabled");
|
||||
return;
|
||||
}
|
||||
|
||||
mBluetoothIfaceRequest.release();
|
||||
mBluetoothIfaceRequest = null;
|
||||
mBluetoothCallback = null;
|
||||
// If bluetooth request is released, tethering won't able to receive
|
||||
// onUnavailable callback, explicitly disable bluetooth IpServer manually.
|
||||
maybeDisableBluetoothIpServing();
|
||||
}
|
||||
}
|
||||
|
||||
// BluetoothCallback is only called after T. Before T, PanService would call tether/untether to
|
||||
// notify bluetooth interface status.
|
||||
private class BluetoothCallback implements TetheredInterfaceCallbackShim {
|
||||
@Override
|
||||
public void onAvailable(String iface) {
|
||||
if (this != mBluetoothCallback) return;
|
||||
|
||||
enableIpServing(TETHERING_BLUETOOTH, iface, getRequestedState(TETHERING_BLUETOOTH));
|
||||
mConfiguredBluetoothIface = iface;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUnavailable() {
|
||||
if (this != mBluetoothCallback) return;
|
||||
|
||||
maybeDisableBluetoothIpServing();
|
||||
}
|
||||
}
|
||||
|
||||
private void maybeDisableBluetoothIpServing() {
|
||||
if (mConfiguredBluetoothIface == null) return;
|
||||
|
||||
ensureIpServerStopped(mConfiguredBluetoothIface);
|
||||
mConfiguredBluetoothIface = null;
|
||||
}
|
||||
|
||||
private int setEthernetTethering(final boolean enable) {
|
||||
final EthernetManager em = (EthernetManager) mContext.getSystemService(
|
||||
Context.ETHERNET_SERVICE);
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ package com.android.networkstack.tethering;
|
|||
|
||||
import android.app.usage.NetworkStatsManager;
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothPan;
|
||||
import android.content.Context;
|
||||
import android.net.INetd;
|
||||
import android.net.ip.IpServer;
|
||||
|
|
@ -31,6 +32,8 @@ import android.text.TextUtils;
|
|||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.android.internal.util.StateMachine;
|
||||
import com.android.networkstack.apishim.BluetoothPanShimImpl;
|
||||
import com.android.networkstack.apishim.common.BluetoothPanShim;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
|
|
@ -158,4 +161,13 @@ public abstract class TetheringDependencies {
|
|||
TetheringConfiguration cfg) {
|
||||
return new PrivateAddressCoordinator(ctx, cfg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get BluetoothPanShim object to enable/disable bluetooth tethering.
|
||||
*
|
||||
* TODO: use BluetoothPan directly when mainline module is built with API 32.
|
||||
*/
|
||||
public BluetoothPanShim getBluetoothPanShim(BluetoothPan pan) {
|
||||
return BluetoothPanShimImpl.newInstance(pan);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package android.net.ip;
|
||||
|
||||
import static android.net.INetd.IF_STATE_DOWN;
|
||||
import static android.net.INetd.IF_STATE_UP;
|
||||
import static android.net.RouteInfo.RTN_UNICAST;
|
||||
import static android.net.TetheringManager.TETHERING_BLUETOOTH;
|
||||
|
|
@ -33,6 +34,7 @@ import static android.net.ip.IpServer.STATE_TETHERED;
|
|||
import static android.net.ip.IpServer.STATE_UNAVAILABLE;
|
||||
import static android.system.OsConstants.ETH_P_IPV6;
|
||||
|
||||
import static com.android.modules.utils.build.SdkLevel.isAtLeastT;
|
||||
import static com.android.net.module.util.Inet4AddressUtils.intToInet4AddressHTH;
|
||||
import static com.android.net.module.util.netlink.NetlinkConstants.RTM_DELNEIGH;
|
||||
import static com.android.net.module.util.netlink.NetlinkConstants.RTM_NEWNEIGH;
|
||||
|
|
@ -400,11 +402,16 @@ public class IpServerTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void canBeTethered() throws Exception {
|
||||
public void canBeTetheredAsBluetooth() throws Exception {
|
||||
initStateMachine(TETHERING_BLUETOOTH);
|
||||
|
||||
dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED);
|
||||
InOrder inOrder = inOrder(mCallback, mNetd);
|
||||
InOrder inOrder = inOrder(mCallback, mNetd, mAddressCoordinator);
|
||||
if (isAtLeastT()) {
|
||||
inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any(), eq(true));
|
||||
inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg ->
|
||||
IFACE_NAME.equals(cfg.ifName) && assertContainsFlag(cfg.flags, IF_STATE_UP)));
|
||||
}
|
||||
inOrder.verify(mNetd).tetherInterfaceAdd(IFACE_NAME);
|
||||
inOrder.verify(mNetd).networkAddInterface(INetd.LOCAL_NET_ID, IFACE_NAME);
|
||||
// One for ipv4 route, one for ipv6 link local route.
|
||||
|
|
@ -426,7 +433,13 @@ public class IpServerTest {
|
|||
inOrder.verify(mNetd).tetherApplyDnsInterfaces();
|
||||
inOrder.verify(mNetd).tetherInterfaceRemove(IFACE_NAME);
|
||||
inOrder.verify(mNetd).networkRemoveInterface(INetd.LOCAL_NET_ID, IFACE_NAME);
|
||||
inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg -> IFACE_NAME.equals(cfg.ifName)));
|
||||
// One is ipv4 address clear (set to 0.0.0.0), another is set interface down which only
|
||||
// happen after T. Before T, the interface configuration control in bluetooth side.
|
||||
if (isAtLeastT()) {
|
||||
inOrder.verify(mNetd).interfaceSetCfg(
|
||||
argThat(cfg -> assertContainsFlag(cfg.flags, IF_STATE_DOWN)));
|
||||
}
|
||||
inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg -> cfg.flags.length == 0));
|
||||
inOrder.verify(mAddressCoordinator).releaseDownstream(any());
|
||||
inOrder.verify(mCallback).updateInterfaceState(
|
||||
mIpServer, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR);
|
||||
|
|
@ -443,7 +456,7 @@ public class IpServerTest {
|
|||
InOrder inOrder = inOrder(mCallback, mNetd, mAddressCoordinator);
|
||||
inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any(), eq(true));
|
||||
inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg ->
|
||||
IFACE_NAME.equals(cfg.ifName) && assertContainsFlag(cfg.flags, IF_STATE_UP)));
|
||||
IFACE_NAME.equals(cfg.ifName) && assertContainsFlag(cfg.flags, IF_STATE_UP)));
|
||||
inOrder.verify(mNetd).tetherInterfaceAdd(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),
|
||||
|
|
@ -587,7 +600,8 @@ public class IpServerTest {
|
|||
inOrder.verify(mNetd).tetherApplyDnsInterfaces();
|
||||
inOrder.verify(mNetd).tetherInterfaceRemove(IFACE_NAME);
|
||||
inOrder.verify(mNetd).networkRemoveInterface(INetd.LOCAL_NET_ID, IFACE_NAME);
|
||||
inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg -> IFACE_NAME.equals(cfg.ifName)));
|
||||
inOrder.verify(mNetd, times(isAtLeastT() ? 2 : 1)).interfaceSetCfg(
|
||||
argThat(cfg -> IFACE_NAME.equals(cfg.ifName)));
|
||||
inOrder.verify(mAddressCoordinator).releaseDownstream(any());
|
||||
inOrder.verify(mBpfCoordinator).tetherOffloadClientClear(mIpServer);
|
||||
inOrder.verify(mBpfCoordinator).stopMonitoring(mIpServer);
|
||||
|
|
@ -683,7 +697,11 @@ public class IpServerTest {
|
|||
initTetheredStateMachine(TETHERING_BLUETOOTH, UPSTREAM_IFACE);
|
||||
dispatchTetherConnectionChanged(UPSTREAM_IFACE);
|
||||
|
||||
assertDhcpStarted(mBluetoothPrefix);
|
||||
if (isAtLeastT()) {
|
||||
assertDhcpStarted(PrefixUtils.asIpPrefix(mTestAddress));
|
||||
} else {
|
||||
assertDhcpStarted(mBluetoothPrefix);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -1371,7 +1389,6 @@ public class IpServerTest {
|
|||
for (String flag : flags) {
|
||||
if (flag.equals(match)) return true;
|
||||
}
|
||||
fail("Missing flag: " + match);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ import static android.system.OsConstants.RT_SCOPE_UNIVERSE;
|
|||
import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
|
||||
|
||||
import static com.android.modules.utils.build.SdkLevel.isAtLeastS;
|
||||
import static com.android.modules.utils.build.SdkLevel.isAtLeastT;
|
||||
import static com.android.net.module.util.Inet4AddressUtils.inet4AddressToIntHTH;
|
||||
import static com.android.net.module.util.Inet4AddressUtils.intToInet4AddressHTH;
|
||||
import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_1_0;
|
||||
|
|
@ -81,6 +82,8 @@ import static org.junit.Assert.assertEquals;
|
|||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.junit.Assume.assumeFalse;
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
import static org.mockito.ArgumentMatchers.argThat;
|
||||
import static org.mockito.ArgumentMatchers.notNull;
|
||||
import static org.mockito.Matchers.anyInt;
|
||||
|
|
@ -182,6 +185,10 @@ import com.android.internal.util.StateMachine;
|
|||
import com.android.internal.util.test.BroadcastInterceptingContext;
|
||||
import com.android.internal.util.test.FakeSettingsProvider;
|
||||
import com.android.net.module.util.CollectionUtils;
|
||||
import com.android.networkstack.apishim.common.BluetoothPanShim;
|
||||
import com.android.networkstack.apishim.common.BluetoothPanShim.TetheredInterfaceCallbackShim;
|
||||
import com.android.networkstack.apishim.common.BluetoothPanShim.TetheredInterfaceRequestShim;
|
||||
import com.android.networkstack.apishim.common.UnsupportedApiLevelException;
|
||||
import com.android.networkstack.tethering.TestConnectivityManager.TestNetworkAgent;
|
||||
import com.android.testutils.MiscAsserts;
|
||||
|
||||
|
|
@ -261,6 +268,8 @@ public class TetheringTest {
|
|||
@Mock private PackageManager mPackageManager;
|
||||
@Mock private BluetoothAdapter mBluetoothAdapter;
|
||||
@Mock private BluetoothPan mBluetoothPan;
|
||||
@Mock private BluetoothPanShim mBluetoothPanShim;
|
||||
@Mock private TetheredInterfaceRequestShim mTetheredInterfaceRequestShim;
|
||||
|
||||
private final MockIpServerDependencies mIpServerDependencies =
|
||||
spy(new MockIpServerDependencies());
|
||||
|
|
@ -285,6 +294,7 @@ public class TetheringTest {
|
|||
private PrivateAddressCoordinator mPrivateAddressCoordinator;
|
||||
private SoftApCallback mSoftApCallback;
|
||||
private UpstreamNetworkMonitor mUpstreamNetworkMonitor;
|
||||
private TetheredInterfaceCallbackShim mTetheredInterfaceCallbackShim;
|
||||
|
||||
private TestConnectivityManager mCm;
|
||||
|
||||
|
|
@ -483,13 +493,23 @@ public class TetheringTest {
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public PrivateAddressCoordinator getPrivateAddressCoordinator(Context ctx,
|
||||
TetheringConfiguration cfg) {
|
||||
mPrivateAddressCoordinator = super.getPrivateAddressCoordinator(ctx, cfg);
|
||||
return mPrivateAddressCoordinator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BluetoothPanShim getBluetoothPanShim(BluetoothPan pan) {
|
||||
try {
|
||||
when(mBluetoothPanShim.requestTetheredInterface(
|
||||
any(), any())).thenReturn(mTetheredInterfaceRequestShim);
|
||||
} catch (UnsupportedApiLevelException e) {
|
||||
fail("BluetoothPan#requestTetheredInterface is not supported");
|
||||
}
|
||||
return mBluetoothPanShim;
|
||||
}
|
||||
}
|
||||
|
||||
private static LinkProperties buildUpstreamLinkProperties(String interfaceName,
|
||||
|
|
@ -2557,6 +2577,44 @@ public class TetheringTest {
|
|||
|
||||
@Test
|
||||
public void testBluetoothTethering() throws Exception {
|
||||
// Switch to @IgnoreUpTo(Build.VERSION_CODES.S_V2) when it is available for AOSP.
|
||||
assumeTrue(isAtLeastT());
|
||||
|
||||
final ResultListener result = new ResultListener(TETHER_ERROR_NO_ERROR);
|
||||
mockBluetoothSettings(true /* bluetoothOn */, true /* tetheringOn */);
|
||||
mTethering.startTethering(createTetheringRequestParcel(TETHERING_BLUETOOTH), result);
|
||||
mLooper.dispatchAll();
|
||||
verifySetBluetoothTethering(true /* enable */, true /* bindToPanService */);
|
||||
result.assertHasResult();
|
||||
|
||||
mTetheredInterfaceCallbackShim.onAvailable(TEST_BT_IFNAME);
|
||||
mLooper.dispatchAll();
|
||||
verifyNetdCommandForBtSetup();
|
||||
|
||||
// If PAN disconnect, tethering should also be stopped.
|
||||
mTetheredInterfaceCallbackShim.onUnavailable();
|
||||
mLooper.dispatchAll();
|
||||
verifyNetdCommandForBtTearDown();
|
||||
|
||||
// Tethering could restart if PAN reconnect.
|
||||
mTetheredInterfaceCallbackShim.onAvailable(TEST_BT_IFNAME);
|
||||
mLooper.dispatchAll();
|
||||
verifyNetdCommandForBtSetup();
|
||||
|
||||
// Pretend that bluetooth tethering was disabled.
|
||||
mockBluetoothSettings(true /* bluetoothOn */, false /* tetheringOn */);
|
||||
mTethering.stopTethering(TETHERING_BLUETOOTH);
|
||||
mLooper.dispatchAll();
|
||||
verifySetBluetoothTethering(false /* enable */, false /* bindToPanService */);
|
||||
|
||||
verifyNetdCommandForBtTearDown();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBluetoothTetheringBeforeT() throws Exception {
|
||||
// Switch to @IgnoreAfter(Build.VERSION_CODES.S_V2) when it is available for AOSP.
|
||||
assumeFalse(isAtLeastT());
|
||||
|
||||
final ResultListener result = new ResultListener(TETHER_ERROR_NO_ERROR);
|
||||
mockBluetoothSettings(true /* bluetoothOn */, true /* tetheringOn */);
|
||||
mTethering.startTethering(createTetheringRequestParcel(TETHERING_BLUETOOTH), result);
|
||||
|
|
@ -2610,12 +2668,17 @@ public class TetheringTest {
|
|||
mTethering.interfaceAdded(TEST_BT_IFNAME);
|
||||
mLooper.dispatchAll();
|
||||
|
||||
mTethering.interfaceStatusChanged(TEST_BT_IFNAME, false);
|
||||
mTethering.interfaceStatusChanged(TEST_BT_IFNAME, true);
|
||||
final ResultListener tetherResult = new ResultListener(TETHER_ERROR_NO_ERROR);
|
||||
mTethering.tether(TEST_BT_IFNAME, IpServer.STATE_TETHERED, tetherResult);
|
||||
mLooper.dispatchAll();
|
||||
tetherResult.assertHasResult();
|
||||
if (isAtLeastT()) {
|
||||
mTetheredInterfaceCallbackShim.onAvailable(TEST_BT_IFNAME);
|
||||
mLooper.dispatchAll();
|
||||
} else {
|
||||
mTethering.interfaceStatusChanged(TEST_BT_IFNAME, false);
|
||||
mTethering.interfaceStatusChanged(TEST_BT_IFNAME, true);
|
||||
final ResultListener tetherResult = new ResultListener(TETHER_ERROR_NO_ERROR);
|
||||
mTethering.tether(TEST_BT_IFNAME, IpServer.STATE_TETHERED, tetherResult);
|
||||
mLooper.dispatchAll();
|
||||
tetherResult.assertHasResult();
|
||||
}
|
||||
|
||||
verifyNetdCommandForBtSetup();
|
||||
|
||||
|
|
@ -2632,6 +2695,10 @@ public class TetheringTest {
|
|||
}
|
||||
|
||||
private void verifyNetdCommandForBtSetup() throws Exception {
|
||||
if (isAtLeastT()) {
|
||||
verify(mNetd).interfaceSetCfg(argThat(cfg -> TEST_BT_IFNAME.equals(cfg.ifName)
|
||||
&& assertContainsFlag(cfg.flags, INetd.IF_STATE_UP)));
|
||||
}
|
||||
verify(mNetd).tetherInterfaceAdd(TEST_BT_IFNAME);
|
||||
verify(mNetd).networkAddInterface(INetd.LOCAL_NET_ID, TEST_BT_IFNAME);
|
||||
verify(mNetd, times(2)).networkAddRoute(eq(INetd.LOCAL_NET_ID), eq(TEST_BT_IFNAME),
|
||||
|
|
@ -2644,19 +2711,30 @@ public class TetheringTest {
|
|||
reset(mNetd);
|
||||
}
|
||||
|
||||
private boolean assertContainsFlag(String[] flags, String match) {
|
||||
for (String flag : flags) {
|
||||
if (flag.equals(match)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void verifyNetdCommandForBtTearDown() throws Exception {
|
||||
verify(mNetd).tetherApplyDnsInterfaces();
|
||||
verify(mNetd).tetherInterfaceRemove(TEST_BT_IFNAME);
|
||||
verify(mNetd).networkRemoveInterface(INetd.LOCAL_NET_ID, TEST_BT_IFNAME);
|
||||
verify(mNetd).interfaceSetCfg(any(InterfaceConfigurationParcel.class));
|
||||
// One is ipv4 address clear (set to 0.0.0.0), another is set interface down which only
|
||||
// happen after T. Before T, the interface configuration control in bluetooth side.
|
||||
verify(mNetd, times(isAtLeastT() ? 2 : 1)).interfaceSetCfg(
|
||||
any(InterfaceConfigurationParcel.class));
|
||||
verify(mNetd).tetherStop();
|
||||
verify(mNetd).ipfwdDisableForwarding(TETHERING_NAME);
|
||||
reset(mNetd);
|
||||
}
|
||||
|
||||
// If bindToPanService is true, this function would return ServiceListener which could notify
|
||||
// PanService is connected or disconnected.
|
||||
private ServiceListener verifySetBluetoothTethering(final boolean enable,
|
||||
final boolean bindToPanService) {
|
||||
final boolean bindToPanService) throws Exception {
|
||||
ServiceListener listener = null;
|
||||
verify(mBluetoothAdapter).isEnabled();
|
||||
if (bindToPanService) {
|
||||
|
|
@ -2671,7 +2749,19 @@ public class TetheringTest {
|
|||
verify(mBluetoothAdapter, never()).getProfileProxy(eq(mServiceContext), any(),
|
||||
anyInt());
|
||||
}
|
||||
verify(mBluetoothPan).setBluetoothTethering(enable);
|
||||
|
||||
if (isAtLeastT()) {
|
||||
if (enable) {
|
||||
final ArgumentCaptor<TetheredInterfaceCallbackShim> callbackCaptor =
|
||||
ArgumentCaptor.forClass(TetheredInterfaceCallbackShim.class);
|
||||
verify(mBluetoothPanShim).requestTetheredInterface(any(), callbackCaptor.capture());
|
||||
mTetheredInterfaceCallbackShim = callbackCaptor.getValue();
|
||||
} else {
|
||||
verify(mTetheredInterfaceRequestShim).release();
|
||||
}
|
||||
} else {
|
||||
verify(mBluetoothPan).setBluetoothTethering(enable);
|
||||
}
|
||||
verify(mBluetoothPan).isTetheringOn();
|
||||
verifyNoMoreInteractions(mBluetoothAdapter, mBluetoothPan);
|
||||
reset(mBluetoothAdapter, mBluetoothPan);
|
||||
|
|
|
|||
Loading…
Reference in a new issue