Merge "Start tethered hotspot with TetheringRequest" into main am: 8594562526 am: 6ae0b1e92c
Original change: https://android-review.googlesource.com/c/platform/packages/modules/Connectivity/+/3161517 Change-Id: I9635420400de643767d4446cf6e04295381ddee1 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
commit
cc039d78ab
4 changed files with 324 additions and 48 deletions
|
|
@ -340,6 +340,11 @@ public class TetheringManager {
|
|||
* @hide
|
||||
*/
|
||||
public static final int TETHER_ERROR_BLUETOOTH_SERVICE_PENDING = 19;
|
||||
/**
|
||||
* Never used outside Tethering.java.
|
||||
* @hide
|
||||
*/
|
||||
public static final int TETHER_ERROR_SOFT_AP_CALLBACK_PENDING = 20;
|
||||
|
||||
/** @hide */
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
|
|
|
|||
|
|
@ -240,6 +240,11 @@ public class RequestTracker {
|
|||
mServingRequests.entrySet().removeIf(e -> e.getValue().getTetheringType() == type);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
List<TetheringRequest> getServingTetheringRequests() {
|
||||
return new ArrayList<>(mServingRequests.values());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an existing (pending or serving) request that fuzzy matches the given request.
|
||||
* Optionally specify matchUid to only return requests with the same uid.
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ import static android.net.TetheringManager.TETHER_ERROR_DUPLICATE_REQUEST;
|
|||
import static android.net.TetheringManager.TETHER_ERROR_INTERNAL_ERROR;
|
||||
import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR;
|
||||
import static android.net.TetheringManager.TETHER_ERROR_SERVICE_UNAVAIL;
|
||||
import static android.net.TetheringManager.TETHER_ERROR_SOFT_AP_CALLBACK_PENDING;
|
||||
import static android.net.TetheringManager.TETHER_ERROR_UNAVAIL_IFACE;
|
||||
import static android.net.TetheringManager.TETHER_ERROR_UNKNOWN_IFACE;
|
||||
import static android.net.TetheringManager.TETHER_ERROR_UNKNOWN_REQUEST;
|
||||
|
|
@ -114,6 +115,7 @@ import android.net.TetheringInterface;
|
|||
import android.net.TetheringManager.TetheringRequest;
|
||||
import android.net.Uri;
|
||||
import android.net.ip.IpServer;
|
||||
import android.net.wifi.SoftApState;
|
||||
import android.net.wifi.WifiClient;
|
||||
import android.net.wifi.WifiManager;
|
||||
import android.net.wifi.p2p.WifiP2pGroup;
|
||||
|
|
@ -775,7 +777,7 @@ public class Tethering {
|
|||
final int result;
|
||||
switch (type) {
|
||||
case TETHERING_WIFI:
|
||||
result = setWifiTethering(enable);
|
||||
result = setWifiTethering(enable, request, listener);
|
||||
break;
|
||||
case TETHERING_USB:
|
||||
result = setUsbTethering(enable);
|
||||
|
|
@ -800,6 +802,9 @@ public class Tethering {
|
|||
// The result of Bluetooth tethering will be sent after the pan service connects.
|
||||
if (result == TETHER_ERROR_BLUETOOTH_SERVICE_PENDING) return;
|
||||
|
||||
// The result of Wifi tethering will be sent after the SoftApCallback result.
|
||||
if (result == TETHER_ERROR_SOFT_AP_CALLBACK_PENDING) return;
|
||||
|
||||
sendTetherResultAndRemoveOnError(request, listener, result);
|
||||
}
|
||||
|
||||
|
|
@ -824,7 +829,8 @@ public class Tethering {
|
|||
}
|
||||
}
|
||||
|
||||
private int setWifiTethering(final boolean enable) {
|
||||
private int setWifiTethering(final boolean enable, TetheringRequest request,
|
||||
IIntResultListener listener) {
|
||||
final long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
final WifiManager mgr = getWifiManager();
|
||||
|
|
@ -832,8 +838,34 @@ public class Tethering {
|
|||
mLog.e("setWifiTethering: failed to get WifiManager!");
|
||||
return TETHER_ERROR_SERVICE_UNAVAIL;
|
||||
}
|
||||
if ((enable && mgr.startTetheredHotspot(null /* use existing softap config */))
|
||||
|| (!enable && mgr.stopSoftAp())) {
|
||||
final boolean success;
|
||||
if (enable) {
|
||||
if (isTetheringWithSoftApConfigEnabled()) {
|
||||
// Notes:
|
||||
// - A call to startTetheredHotspot can only succeed if the SoftAp is idle. If
|
||||
// the SoftAp is running or is being disabled, the call will fail.
|
||||
// - If a call to startTetheredHotspot fails, the callback is immediately called
|
||||
// with WIFI_AP_STATE_FAILED and a null interface.
|
||||
// - If a call to startTetheredHotspot succeeds, the passed-in callback is the
|
||||
// only callback that will receive future WIFI_AP_STATE_ENABLED and
|
||||
// WIFI_AP_STATE_DISABLED events in the future, until another call to
|
||||
// startTetheredHotspot succeeds, at which point the old callback will stop
|
||||
// receiving any events.
|
||||
// - Wifi may decide to restart the hotspot at any time (such as for a CC
|
||||
// change), and if it does so, it will send WIFI_AP_STATE_DISABLED and then
|
||||
// either WIFI_AP_STATE_ENABLED or (if restarting fails) WIFI_AP_STATE_FAILED.
|
||||
mgr.startTetheredHotspot(request, mExecutor,
|
||||
new StartTetheringSoftApCallback(listener));
|
||||
// Result isn't used since we get the real result via
|
||||
// StartTetheringSoftApCallback.
|
||||
return TETHER_ERROR_SOFT_AP_CALLBACK_PENDING;
|
||||
}
|
||||
success = mgr.startTetheredHotspot(null);
|
||||
} else {
|
||||
success = mgr.stopSoftAp();
|
||||
}
|
||||
|
||||
if (success) {
|
||||
return TETHER_ERROR_NO_ERROR;
|
||||
}
|
||||
} finally {
|
||||
|
|
@ -1458,6 +1490,9 @@ public class Tethering {
|
|||
final String ifname = intent.getStringExtra(EXTRA_WIFI_AP_INTERFACE_NAME);
|
||||
final int ipmode = intent.getIntExtra(EXTRA_WIFI_AP_MODE, IFACE_IP_MODE_UNSPECIFIED);
|
||||
|
||||
// In B+, Tethered AP is handled by StartTetheringSoftApCallback.
|
||||
if (isTetheringWithSoftApConfigEnabled() && ipmode == IFACE_IP_MODE_TETHERED) return;
|
||||
|
||||
switch (curState) {
|
||||
case WifiManager.WIFI_AP_STATE_ENABLING:
|
||||
// We can see this state on the way to both enabled and failure states.
|
||||
|
|
@ -1538,11 +1573,63 @@ public class Tethering {
|
|||
}
|
||||
}
|
||||
|
||||
class StartTetheringSoftApCallback implements SoftApCallback {
|
||||
|
||||
@Nullable
|
||||
IIntResultListener mPendingListener;
|
||||
|
||||
StartTetheringSoftApCallback(IIntResultListener pendingListener) {
|
||||
mPendingListener = pendingListener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStateChanged(SoftApState softApState) {
|
||||
final int state = softApState.getState();
|
||||
final String iface = softApState.getIface();
|
||||
final TetheringRequest request = softApState.getTetheringRequest();
|
||||
switch (softApState.getState()) {
|
||||
case WifiManager.WIFI_AP_STATE_ENABLED:
|
||||
enableIpServing(request, iface);
|
||||
// If stopTethering has already been called, IP serving will still be started,
|
||||
// but as soon as the wifi code processes the stop, WIFI_AP_STATE_DISABLED will
|
||||
// be sent and tethering will be stopped again.
|
||||
sendTetherResultAndRemoveOnError(request, mPendingListener,
|
||||
TETHER_ERROR_NO_ERROR);
|
||||
mPendingListener = null;
|
||||
break;
|
||||
case WifiManager.WIFI_AP_STATE_FAILED:
|
||||
// TODO: if a call to startTethering happens just after a call to stopTethering,
|
||||
// the start will fail because hotspot is still being disabled. This likely
|
||||
// cannot be fixed in tethering code but must be fixed in WiFi.
|
||||
sendTetherResultAndRemoveOnError(request, mPendingListener,
|
||||
TETHER_ERROR_INTERNAL_ERROR);
|
||||
mPendingListener = null;
|
||||
break;
|
||||
case WifiManager.WIFI_AP_STATE_DISABLED:
|
||||
// TODO(b/403164072): SoftAP may restart due to CC change, in which we'll get
|
||||
// DISABLED -> ENABLED (or FAILED). Before the transition back to ENABLED is
|
||||
// complete, it is possible that a new Wifi request is accepted since there's no
|
||||
// active request to fuzzy-match it, which will unexpectedly cause Wifi to
|
||||
// overwrite this SoftApCallback. This should be fixed in Wifi to disallow any
|
||||
// new calls to startTetheredHotspot while SoftAP is restarting.
|
||||
disableWifiIpServing(iface, state);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
List<TetheringRequest> getPendingTetheringRequests() {
|
||||
return mRequestTracker.getPendingTetheringRequests();
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
List<TetheringRequest> getServingTetheringRequests() {
|
||||
return mRequestTracker.getServingTetheringRequests();
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
boolean isTetheringActive() {
|
||||
return getTetheredIfaces().length > 0;
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ import static android.net.wifi.WifiManager.IFACE_IP_MODE_LOCAL_ONLY;
|
|||
import static android.net.wifi.WifiManager.IFACE_IP_MODE_TETHERED;
|
||||
import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED;
|
||||
import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED;
|
||||
import static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED;
|
||||
import static android.system.OsConstants.RT_SCOPE_UNIVERSE;
|
||||
import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
|
||||
|
||||
|
|
@ -169,6 +170,7 @@ import android.net.ip.DadProxy;
|
|||
import android.net.ip.IpServer;
|
||||
import android.net.ip.RouterAdvertisementDaemon;
|
||||
import android.net.wifi.SoftApConfiguration;
|
||||
import android.net.wifi.SoftApState;
|
||||
import android.net.wifi.WifiClient;
|
||||
import android.net.wifi.WifiManager;
|
||||
import android.net.wifi.WifiManager.SoftApCallback;
|
||||
|
|
@ -241,6 +243,7 @@ import java.util.Collections;
|
|||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.Vector;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
|
|
@ -842,6 +845,38 @@ public class TetheringTest {
|
|||
mLooper.dispatchAll();
|
||||
}
|
||||
|
||||
private void sendStartTetheringSoftApCallback(int state, TetheringRequest request,
|
||||
String ifname) {
|
||||
ArgumentCaptor<SoftApCallback> callbackCaptor =
|
||||
ArgumentCaptor.forClass(SoftApCallback.class);
|
||||
verify(mWifiManager, atLeastOnce()).startTetheredHotspot(any(TetheringRequest.class),
|
||||
any(Executor.class), callbackCaptor.capture());
|
||||
SoftApState softApState = mock(SoftApState.class);
|
||||
when(softApState.getState()).thenReturn(state);
|
||||
when(softApState.getTetheringRequest()).thenReturn(request);
|
||||
when(softApState.getIface()).thenReturn(ifname);
|
||||
callbackCaptor.getValue().onStateChanged(softApState);
|
||||
mLooper.dispatchAll();
|
||||
}
|
||||
|
||||
private void verifyWifiTetheringRequested() {
|
||||
if (mTetheringDependencies.isTetheringWithSoftApConfigEnabled()) {
|
||||
verify(mWifiManager).startTetheredHotspot(any(), any(), any());
|
||||
} else {
|
||||
verify(mWifiManager).startTetheredHotspot(null);
|
||||
}
|
||||
verify(mWifiManager, never()).stopSoftAp();
|
||||
verifyNoMoreInteractions(mWifiManager);
|
||||
}
|
||||
|
||||
private void sendSoftApEvent(int state, TetheringRequest request, String ifname) {
|
||||
if (mTetheringDependencies.isTetheringWithSoftApConfigEnabled()) {
|
||||
sendStartTetheringSoftApCallback(state, request, ifname);
|
||||
} else {
|
||||
sendWifiApStateChanged(state, ifname, IFACE_IP_MODE_TETHERED);
|
||||
}
|
||||
}
|
||||
|
||||
private static final String[] P2P_RECEIVER_PERMISSIONS_FOR_BROADCAST = {
|
||||
android.Manifest.permission.ACCESS_FINE_LOCATION,
|
||||
android.Manifest.permission.ACCESS_WIFI_STATE
|
||||
|
|
@ -1964,11 +1999,9 @@ public class TetheringTest {
|
|||
initTetheringOnTestThread();
|
||||
|
||||
// Emulate pressing the WiFi tethering button.
|
||||
mTethering.startTethering(createTetheringRequest(TETHERING_WIFI), TEST_CALLER_PKG,
|
||||
null);
|
||||
mTethering.startTethering(createTetheringRequest(TETHERING_WIFI), TEST_CALLER_PKG, null);
|
||||
mLooper.dispatchAll();
|
||||
verify(mWifiManager, times(1)).startTetheredHotspot(null);
|
||||
verifyNoMoreInteractions(mWifiManager);
|
||||
verifyWifiTetheringRequested();
|
||||
verifyNoMoreInteractions(mNetd);
|
||||
|
||||
// Emulate externally-visible WifiManager effects, causing the
|
||||
|
|
@ -1997,14 +2030,15 @@ public class TetheringTest {
|
|||
// TODO: Test with and without interfaceStatusChanged().
|
||||
@Test
|
||||
public void workingWifiTetheringEnrichedApBroadcast() throws Exception {
|
||||
// B+ uses SoftApCallback instead of WIFI_AP_STATE_CHANGED for tethered hotspot.
|
||||
mTetheringWithSoftApConfigEnabled = false;
|
||||
initTetheringOnTestThread();
|
||||
|
||||
// Emulate pressing the WiFi tethering button.
|
||||
mTethering.startTethering(createTetheringRequest(TETHERING_WIFI), TEST_CALLER_PKG,
|
||||
null);
|
||||
mLooper.dispatchAll();
|
||||
verify(mWifiManager, times(1)).startTetheredHotspot(null);
|
||||
verifyNoMoreInteractions(mWifiManager);
|
||||
verifyWifiTetheringRequested();
|
||||
verifyNoMoreInteractions(mNetd);
|
||||
|
||||
// Emulate externally-visible WifiManager effects, causing the
|
||||
|
|
@ -2042,6 +2076,122 @@ public class TetheringTest {
|
|||
verifyStopHotpot();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startWifiTetheringWithSoftApConfigurationSuccess() throws Exception {
|
||||
assumeTrue(mTetheringDependencies.isTetheringWithSoftApConfigEnabled());
|
||||
initTetheringOnTestThread();
|
||||
|
||||
// Emulate pressing the WiFi tethering button.
|
||||
TetheringRequest request = new TetheringRequest.Builder(TETHERING_WIFI)
|
||||
.setSoftApConfiguration(new SoftApConfiguration.Builder()
|
||||
.setWifiSsid(WifiSsid.fromBytes("SSID".getBytes(StandardCharsets.UTF_8)))
|
||||
.build())
|
||||
.build();
|
||||
IIntResultListener startResultListener = mock(IIntResultListener.class);
|
||||
mTethering.startTethering(request, TEST_CALLER_PKG, startResultListener);
|
||||
mLooper.dispatchAll();
|
||||
verifyNoMoreInteractions(mNetd);
|
||||
verify(startResultListener, never()).onResult(anyInt());
|
||||
// Emulate Wifi iface enabled
|
||||
sendStartTetheringSoftApCallback(WIFI_AP_STATE_ENABLED, request, TEST_WLAN_IFNAME);
|
||||
|
||||
verifyStartHotspot();
|
||||
verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_ACTIVE_TETHER);
|
||||
verify(startResultListener).onResult(TETHER_ERROR_NO_ERROR);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startWifiTetheringWithSoftApConfigurationFailure() throws Exception {
|
||||
assumeTrue(mTetheringDependencies.isTetheringWithSoftApConfigEnabled());
|
||||
initTetheringOnTestThread();
|
||||
|
||||
// Emulate pressing the WiFi tethering button.
|
||||
TetheringRequest request = new TetheringRequest.Builder(TETHERING_WIFI)
|
||||
.setSoftApConfiguration(new SoftApConfiguration.Builder()
|
||||
.setWifiSsid(WifiSsid.fromBytes("SSID".getBytes(StandardCharsets.UTF_8)))
|
||||
.build())
|
||||
.build();
|
||||
IIntResultListener startResultListener = mock(IIntResultListener.class);
|
||||
mTethering.startTethering(request, TEST_CALLER_PKG, startResultListener);
|
||||
mLooper.dispatchAll();
|
||||
verify(startResultListener, never()).onResult(anyInt());
|
||||
// Emulate Wifi iface failure
|
||||
sendStartTetheringSoftApCallback(WIFI_AP_STATE_FAILED, request, TEST_WLAN_IFNAME);
|
||||
|
||||
verify(startResultListener).onResult(TETHER_ERROR_INTERNAL_ERROR);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startWifiTetheringWithSoftApConfigurationRestartAfterStarting() throws Exception {
|
||||
assumeTrue(mTetheringDependencies.isTetheringWithSoftApConfigEnabled());
|
||||
initTetheringOnTestThread();
|
||||
TestTetheringEventCallback callback = new TestTetheringEventCallback();
|
||||
SoftApConfiguration softApConfig = new SoftApConfiguration.Builder()
|
||||
.setWifiSsid(WifiSsid.fromBytes("SSID".getBytes(StandardCharsets.UTF_8)))
|
||||
.build();
|
||||
final TetheringInterface wifiIface = new TetheringInterface(
|
||||
TETHERING_WIFI, TEST_WLAN_IFNAME);
|
||||
final TetheringInterface wifiIfaceWithConfig = new TetheringInterface(
|
||||
TETHERING_WIFI, TEST_WLAN_IFNAME, softApConfig);
|
||||
|
||||
// 1. Register one callback before running any tethering.
|
||||
mTethering.registerTetheringEventCallback(callback);
|
||||
mLooper.dispatchAll();
|
||||
assertTetherStatesNotNullButEmpty(callback.pollTetherStatesChanged());
|
||||
// Emulate pressing the WiFi tethering button.
|
||||
TetheringRequest request = new TetheringRequest.Builder(TETHERING_WIFI)
|
||||
.setSoftApConfiguration(softApConfig)
|
||||
.build();
|
||||
IIntResultListener startResultListener = mock(IIntResultListener.class);
|
||||
mTethering.startTethering(request, TEST_CALLER_PKG, startResultListener);
|
||||
mLooper.dispatchAll();
|
||||
|
||||
// Wifi success
|
||||
sendStartTetheringSoftApCallback(WIFI_AP_STATE_ENABLED, request, TEST_WLAN_IFNAME);
|
||||
verifyStartHotspot();
|
||||
TetherStatesParcel tetherState = callback.pollTetherStatesChanged();
|
||||
assertArrayEquals(tetherState.availableList, new TetheringInterface[] {wifiIface});
|
||||
tetherState = callback.pollTetherStatesChanged();
|
||||
assertArrayEquals(tetherState.tetheredList, new TetheringInterface[] {wifiIfaceWithConfig});
|
||||
verify(startResultListener).onResult(TETHER_ERROR_NO_ERROR);
|
||||
|
||||
// Restart Wifi
|
||||
sendStartTetheringSoftApCallback(WIFI_AP_STATE_DISABLED, request, TEST_WLAN_IFNAME);
|
||||
sendStartTetheringSoftApCallback(WIFI_AP_STATE_ENABLED, request, TEST_WLAN_IFNAME);
|
||||
|
||||
// Verify we go from TETHERED -> AVAILABLE -> TETHERED with the same config.
|
||||
tetherState = callback.pollTetherStatesChanged();
|
||||
assertArrayEquals(tetherState.availableList, new TetheringInterface[] {wifiIface});
|
||||
tetherState = callback.pollTetherStatesChanged();
|
||||
assertArrayEquals(tetherState.tetheredList, new TetheringInterface[] {wifiIfaceWithConfig});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startWifiApBroadcastDoesNotStartIpServing() throws Exception {
|
||||
assumeTrue(mTetheringDependencies.isTetheringWithSoftApConfigEnabled());
|
||||
initTetheringOnTestThread();
|
||||
|
||||
// Call startTethering for wifi
|
||||
TetheringRequest request = new TetheringRequest.Builder(TETHERING_WIFI)
|
||||
.setSoftApConfiguration(new SoftApConfiguration.Builder()
|
||||
.setWifiSsid(WifiSsid.fromBytes("SSID".getBytes(StandardCharsets.UTF_8)))
|
||||
.build())
|
||||
.build();
|
||||
IIntResultListener startResultListener = mock(IIntResultListener.class);
|
||||
mTethering.startTethering(request, TEST_CALLER_PKG, startResultListener);
|
||||
mLooper.dispatchAll();
|
||||
|
||||
// WIFI_AP_STATE_CHANGED broadcast should be ignored since we should only be using
|
||||
// SoftApCallback for tethered AP.
|
||||
sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED);
|
||||
sendWifiApStateChanged(WIFI_AP_STATE_DISABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED);
|
||||
verify(mNetd, never()).tetherStartWithConfiguration(any());
|
||||
verify(mNotificationUpdater, never()).onDownstreamChanged(DOWNSTREAM_NONE);
|
||||
verify(mWifiManager, never()).updateInterfaceIpState(
|
||||
TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
|
||||
assertTrue(mTethering.getServingTetheringRequests().isEmpty());
|
||||
}
|
||||
|
||||
// TODO: Test with and without interfaceStatusChanged().
|
||||
@Test
|
||||
public void failureEnablingIpForwarding() throws Exception {
|
||||
|
|
@ -2049,11 +2199,10 @@ public class TetheringTest {
|
|||
doThrow(new RemoteException()).when(mNetd).ipfwdEnableForwarding(TETHERING_NAME);
|
||||
|
||||
// Emulate pressing the WiFi tethering button.
|
||||
mTethering.startTethering(createTetheringRequest(TETHERING_WIFI), TEST_CALLER_PKG,
|
||||
null);
|
||||
TetheringRequest request = createTetheringRequest(TETHERING_WIFI);
|
||||
mTethering.startTethering(request, TEST_CALLER_PKG, null);
|
||||
mLooper.dispatchAll();
|
||||
verify(mWifiManager, times(1)).startTetheredHotspot(null);
|
||||
verifyNoMoreInteractions(mWifiManager);
|
||||
verifyWifiTetheringRequested();
|
||||
verifyNoMoreInteractions(mNetd);
|
||||
verify(mTetheringMetrics).createBuilder(eq(TETHERING_WIFI), anyString());
|
||||
|
||||
|
|
@ -2061,7 +2210,7 @@ public class TetheringTest {
|
|||
// per-interface state machine to start up, and telling us that
|
||||
// tethering mode is to be started.
|
||||
mTethering.interfaceStatusChanged(TEST_WLAN_IFNAME, true);
|
||||
sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED);
|
||||
sendSoftApEvent(WIFI_AP_STATE_ENABLED, request, TEST_WLAN_IFNAME);
|
||||
|
||||
// We verify get/set called three times here: twice for setup and once during
|
||||
// teardown because all events happen over the course of the single
|
||||
|
|
@ -2390,7 +2539,8 @@ public class TetheringTest {
|
|||
UpstreamNetworkState upstreamState = buildMobileDualStackUpstreamState();
|
||||
initTetheringUpstream(upstreamState);
|
||||
|
||||
mTethering.startTethering(createTetheringRequest(TETHERING_WIFI), TEST_CALLER_PKG,
|
||||
TetheringRequest request = createTetheringRequest(TETHERING_WIFI);
|
||||
mTethering.startTethering(request, TEST_CALLER_PKG,
|
||||
null);
|
||||
mTethering.interfaceStatusChanged(TEST_WLAN_IFNAME, true);
|
||||
mLooper.dispatchAll();
|
||||
|
|
@ -2398,7 +2548,7 @@ public class TetheringTest {
|
|||
// Starting in B, ignore the interfaceStatusChanged
|
||||
callback.assertNoStateChangeCallback();
|
||||
}
|
||||
sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED);
|
||||
sendSoftApEvent(WIFI_AP_STATE_ENABLED, request, TEST_WLAN_IFNAME);
|
||||
mLooper.dispatchAll();
|
||||
tetherState = callback.pollTetherStatesChanged();
|
||||
assertArrayEquals(tetherState.availableList, new TetheringInterface[] {wifiIface});
|
||||
|
|
@ -2426,8 +2576,7 @@ public class TetheringTest {
|
|||
if (isAtLeastT()) {
|
||||
// After T, tethering doesn't support WIFI_AP_STATE_DISABLED with null interface name.
|
||||
callback2.assertNoStateChangeCallback();
|
||||
sendWifiApStateChanged(WIFI_AP_STATE_DISABLED, TEST_WLAN_IFNAME,
|
||||
IFACE_IP_MODE_TETHERED);
|
||||
sendSoftApEvent(WIFI_AP_STATE_DISABLED, request, TEST_WLAN_IFNAME);
|
||||
}
|
||||
tetherState = callback2.pollTetherStatesChanged();
|
||||
assertArrayEquals(tetherState.availableList, new TetheringInterface[] {wifiIface});
|
||||
|
|
@ -2500,7 +2649,8 @@ public class TetheringTest {
|
|||
mLooper.dispatchAll();
|
||||
// Netd "up" event should not trigger a state change callback in B+.
|
||||
callback.assertNoStateChangeCallback();
|
||||
sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED);
|
||||
sendStartTetheringSoftApCallback(WIFI_AP_STATE_ENABLED, tetheringRequest,
|
||||
TEST_WLAN_IFNAME);
|
||||
// Verify we see Available -> Tethered states
|
||||
assertArrayEquals(new TetheringInterface[] {wifiIfaceWithoutConfig},
|
||||
callback.pollTetherStatesChanged().availableList);
|
||||
|
|
@ -2520,8 +2670,8 @@ public class TetheringTest {
|
|||
// Disable wifi tethering
|
||||
mTethering.stopTethering(TETHERING_WIFI);
|
||||
mLooper.dispatchAll();
|
||||
sendWifiApStateChanged(WIFI_AP_STATE_DISABLED, TEST_WLAN_IFNAME,
|
||||
IFACE_IP_MODE_TETHERED);
|
||||
sendStartTetheringSoftApCallback(WIFI_AP_STATE_DISABLED, tetheringRequest,
|
||||
TEST_WLAN_IFNAME);
|
||||
assertArrayEquals(new TetheringInterface[] {wifiIfaceWithoutConfig},
|
||||
callback.pollTetherStatesChanged().availableList);
|
||||
assertArrayEquals(new TetheringInterface[] {wifiIfaceWithoutConfig},
|
||||
|
|
@ -2566,7 +2716,7 @@ public class TetheringTest {
|
|||
ResultListener successListener = new ResultListener(TETHER_ERROR_NO_ERROR);
|
||||
mTethering.startTethering(tetheringRequest, TEST_CALLER_PKG, successListener);
|
||||
mLooper.dispatchAll();
|
||||
successListener.assertHasResult();
|
||||
successListener.assertDoesNotHaveResult();
|
||||
|
||||
// Try starting wifi tethering with various fuzzy-matching requests and verify we get
|
||||
// TETHER_ERROR_DUPLICATE_REQUEST.
|
||||
|
|
@ -2581,8 +2731,7 @@ public class TetheringTest {
|
|||
ResultListener differentIpAddrListener = new ResultListener(TETHER_ERROR_DUPLICATE_REQUEST);
|
||||
mTethering.startTethering(differentIpAddr, TEST_CALLER_PKG, differentIpAddrListener);
|
||||
mLooper.dispatchAll();
|
||||
verify(mWifiManager, times(1)).startTetheredHotspot(any());
|
||||
verify(mWifiManager, never()).stopSoftAp();
|
||||
verifyWifiTetheringRequested();
|
||||
differentIpAddrListener.assertHasResult();
|
||||
|
||||
// Different UID
|
||||
|
|
@ -2593,13 +2742,13 @@ public class TetheringTest {
|
|||
mTethering.startTethering(differentUid, TEST_CALLER_PKG, differentUidListener);
|
||||
mLooper.dispatchAll();
|
||||
differentUidListener.assertHasResult();
|
||||
verify(mWifiManager, times(1)).startTetheredHotspot(any());
|
||||
verify(mWifiManager, never()).stopSoftAp();
|
||||
verifyWifiTetheringRequested();
|
||||
|
||||
// Mock the link layer event to start IP serving and verify we still get
|
||||
// TETHER_ERROR_DUPLICATE_REQUEST even though the request is no longer pending and is
|
||||
// already serving.
|
||||
sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED);
|
||||
// Mock the link layer event to start IP serving and verify
|
||||
// 1) The original request's result listener is called.
|
||||
// 2) We still get TETHER_ERROR_DUPLICATE_REQUEST for new requests.
|
||||
sendStartTetheringSoftApCallback(WIFI_AP_STATE_ENABLED, tetheringRequest, TEST_WLAN_IFNAME);
|
||||
successListener.assertHasResult();
|
||||
assertArrayEquals(new TetheringInterface[] {wifiIfaceWithoutConfig},
|
||||
callback.pollTetherStatesChanged().availableList);
|
||||
assertArrayEquals(new TetheringInterface[] {wifiIfaceWithConfig},
|
||||
|
|
@ -2613,7 +2762,7 @@ public class TetheringTest {
|
|||
mLooper.dispatchAll();
|
||||
differentIpAddrListener.assertHasResult();
|
||||
differentUidListener.assertHasResult();
|
||||
verify(mWifiManager, times(1)).startTetheredHotspot(any());
|
||||
verify(mWifiManager, times(1)).startTetheredHotspot(any(), any(), any());
|
||||
verify(mWifiManager, never()).stopSoftAp();
|
||||
}
|
||||
|
||||
|
|
@ -2630,8 +2779,8 @@ public class TetheringTest {
|
|||
ResultListener successListener = new ResultListener(TETHER_ERROR_NO_ERROR);
|
||||
mTethering.startTethering(tetheringRequest, TEST_CALLER_PKG, successListener);
|
||||
mLooper.dispatchAll();
|
||||
sendStartTetheringSoftApCallback(WIFI_AP_STATE_ENABLED, tetheringRequest, TEST_WLAN_IFNAME);
|
||||
successListener.assertHasResult();
|
||||
sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED);
|
||||
|
||||
// Starting wifi again will cause TETHER_ERROR_DUPLICATE_REQUEST
|
||||
ResultListener failureListener = new ResultListener(TETHER_ERROR_DUPLICATE_REQUEST);
|
||||
|
|
@ -2662,9 +2811,8 @@ public class TetheringTest {
|
|||
ResultListener successListener = new ResultListener(TETHER_ERROR_NO_ERROR);
|
||||
mTethering.startTethering(tetheringRequest, TEST_CALLER_PKG, successListener);
|
||||
mLooper.dispatchAll();
|
||||
sendStartTetheringSoftApCallback(WIFI_AP_STATE_ENABLED, tetheringRequest, TEST_WLAN_IFNAME);
|
||||
successListener.assertHasResult();
|
||||
sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED);
|
||||
|
||||
// Starting wifi again will cause TETHER_ERROR_DUPLICATE_REQUEST
|
||||
ResultListener failureListener = new ResultListener(TETHER_ERROR_DUPLICATE_REQUEST);
|
||||
mTethering.startTethering(tetheringRequest, TEST_CALLER_PKG, failureListener);
|
||||
|
|
@ -2672,12 +2820,15 @@ public class TetheringTest {
|
|||
failureListener.assertHasResult();
|
||||
|
||||
// Trigger wifi ap state change to tell IpServer it's unwanted.
|
||||
sendWifiApStateChanged(WIFI_AP_STATE_DISABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED);
|
||||
sendStartTetheringSoftApCallback(WIFI_AP_STATE_DISABLED, tetheringRequest,
|
||||
TEST_WLAN_IFNAME);
|
||||
|
||||
// We should be able to request the same Wifi again
|
||||
ResultListener successListener2 = new ResultListener(TETHER_ERROR_NO_ERROR);
|
||||
mTethering.startTethering(tetheringRequest, TEST_CALLER_PKG, successListener2);
|
||||
mLooper.dispatchAll();
|
||||
sendStartTetheringSoftApCallback(WIFI_AP_STATE_ENABLED, tetheringRequest,
|
||||
TEST_WLAN_IFNAME);
|
||||
successListener2.assertHasResult();
|
||||
}
|
||||
|
||||
|
|
@ -2697,14 +2848,15 @@ public class TetheringTest {
|
|||
ResultListener successListener = new ResultListener(TETHER_ERROR_NO_ERROR);
|
||||
mTethering.startTethering(tetheringRequest, TEST_CALLER_PKG, successListener);
|
||||
mLooper.dispatchAll();
|
||||
sendStartTetheringSoftApCallback(WIFI_AP_STATE_ENABLED, tetheringRequest, TEST_WLAN_IFNAME);
|
||||
successListener.assertHasResult();
|
||||
sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED);
|
||||
|
||||
// We should be able to request the same Wifi again since the DHCP server transitioned the
|
||||
// IpServer back to InitialState.
|
||||
ResultListener successListener2 = new ResultListener(TETHER_ERROR_NO_ERROR);
|
||||
mTethering.startTethering(tetheringRequest, TEST_CALLER_PKG, successListener2);
|
||||
mLooper.dispatchAll();
|
||||
sendStartTetheringSoftApCallback(WIFI_AP_STATE_ENABLED, tetheringRequest, TEST_WLAN_IFNAME);
|
||||
successListener2.assertHasResult();
|
||||
}
|
||||
|
||||
|
|
@ -2721,7 +2873,10 @@ public class TetheringTest {
|
|||
ResultListener successListener = new ResultListener(TETHER_ERROR_NO_ERROR);
|
||||
mTethering.startTethering(tetheringRequest, TEST_CALLER_PKG, successListener);
|
||||
mLooper.dispatchAll();
|
||||
successListener.assertHasResult();
|
||||
ArgumentCaptor<SoftApCallback> callbackCaptor =
|
||||
ArgumentCaptor.forClass(SoftApCallback.class);
|
||||
verify(mWifiManager, atLeastOnce()).startTetheredHotspot(any(TetheringRequest.class),
|
||||
any(Executor.class), callbackCaptor.capture());
|
||||
|
||||
// Starting wifi again will cause TETHER_ERROR_DUPLICATE_REQUEST
|
||||
ResultListener failureListener = new ResultListener(TETHER_ERROR_DUPLICATE_REQUEST);
|
||||
|
|
@ -2736,6 +2891,20 @@ public class TetheringTest {
|
|||
ResultListener successListener2 = new ResultListener(TETHER_ERROR_NO_ERROR);
|
||||
mTethering.startTethering(tetheringRequest, TEST_CALLER_PKG, successListener2);
|
||||
mLooper.dispatchAll();
|
||||
sendStartTetheringSoftApCallback(WIFI_AP_STATE_ENABLED, tetheringRequest, TEST_WLAN_IFNAME);
|
||||
successListener2.assertHasResult();
|
||||
|
||||
// Mock the first request going up and then down from the stop request.
|
||||
SoftApState softApState = mock(SoftApState.class);
|
||||
when(softApState.getState()).thenReturn(WIFI_AP_STATE_ENABLED);
|
||||
when(softApState.getTetheringRequest()).thenReturn(tetheringRequest);
|
||||
when(softApState.getIface()).thenReturn(TEST_WLAN_IFNAME);
|
||||
callbackCaptor.getValue().onStateChanged(softApState);
|
||||
mLooper.dispatchAll();
|
||||
successListener.assertHasResult();
|
||||
|
||||
// Mock the second request going up
|
||||
sendStartTetheringSoftApCallback(WIFI_AP_STATE_ENABLED, tetheringRequest, TEST_WLAN_IFNAME);
|
||||
successListener2.assertHasResult();
|
||||
}
|
||||
|
||||
|
|
@ -2752,8 +2921,8 @@ public class TetheringTest {
|
|||
ResultListener successListener = new ResultListener(TETHER_ERROR_NO_ERROR);
|
||||
mTethering.startTethering(tetheringRequest, TEST_CALLER_PKG, successListener);
|
||||
mLooper.dispatchAll();
|
||||
sendStartTetheringSoftApCallback(WIFI_AP_STATE_ENABLED, tetheringRequest, TEST_WLAN_IFNAME);
|
||||
successListener.assertHasResult();
|
||||
sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED);
|
||||
|
||||
// Starting wifi again will cause TETHER_ERROR_DUPLICATE_REQUEST
|
||||
ResultListener failureListener = new ResultListener(TETHER_ERROR_DUPLICATE_REQUEST);
|
||||
|
|
@ -2768,6 +2937,7 @@ public class TetheringTest {
|
|||
ResultListener successListener2 = new ResultListener(TETHER_ERROR_NO_ERROR);
|
||||
mTethering.startTethering(tetheringRequest, TEST_CALLER_PKG, successListener2);
|
||||
mLooper.dispatchAll();
|
||||
sendStartTetheringSoftApCallback(WIFI_AP_STATE_ENABLED, tetheringRequest, TEST_WLAN_IFNAME);
|
||||
successListener2.assertHasResult();
|
||||
}
|
||||
|
||||
|
|
@ -3216,7 +3386,7 @@ public class TetheringTest {
|
|||
serverLinkAddr, clientLinkAddr, false, CONNECTIVITY_SCOPE_GLOBAL, null),
|
||||
TEST_CALLER_PKG, null);
|
||||
mLooper.dispatchAll();
|
||||
verify(mWifiManager, times(1)).startTetheredHotspot(any());
|
||||
verifyWifiTetheringRequested();
|
||||
mTethering.interfaceStatusChanged(TEST_WLAN_IFNAME, true);
|
||||
|
||||
// Call legacyTether on the interface before the link layer event comes back.
|
||||
|
|
@ -3588,8 +3758,11 @@ public class TetheringTest {
|
|||
reset(mDhcpServer);
|
||||
|
||||
// Run wifi tethering.
|
||||
TetheringRequest request = createTetheringRequest(TETHERING_WIFI);
|
||||
mTethering.startTethering(request, TEST_CALLER_PKG, null);
|
||||
mLooper.dispatchAll();
|
||||
mTethering.interfaceStatusChanged(TEST_WLAN_IFNAME, true);
|
||||
sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED);
|
||||
sendSoftApEvent(WIFI_AP_STATE_ENABLED, request, TEST_WLAN_IFNAME);
|
||||
verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS)).startWithCallbacks(
|
||||
any(), dhcpEventCbsCaptor.capture());
|
||||
eventCallbacks = dhcpEventCbsCaptor.getValue();
|
||||
|
|
@ -3652,8 +3825,12 @@ public class TetheringTest {
|
|||
});
|
||||
callback.expectTetheredClientChanged(Collections.emptyList());
|
||||
|
||||
TetheringRequest request = createTetheringRequest(TETHERING_WIFI);
|
||||
mTethering.startTethering(request, TEST_CALLER_PKG, null);
|
||||
mLooper.dispatchAll();
|
||||
verifyWifiTetheringRequested();
|
||||
mTethering.interfaceStatusChanged(TEST_WLAN_IFNAME, true);
|
||||
sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED);
|
||||
sendSoftApEvent(WIFI_AP_STATE_ENABLED, request, TEST_WLAN_IFNAME);
|
||||
final ArgumentCaptor<IDhcpEventCallbacks> dhcpEventCbsCaptor =
|
||||
ArgumentCaptor.forClass(IDhcpEventCallbacks.class);
|
||||
verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS)).startWithCallbacks(
|
||||
|
|
@ -4184,8 +4361,11 @@ public class TetheringTest {
|
|||
@Test
|
||||
public void testIpv4AddressForSapAndLohsConcurrency() throws Exception {
|
||||
initTetheringOnTestThread();
|
||||
TetheringRequest request = createTetheringRequest(TETHERING_WIFI);
|
||||
mTethering.startTethering(request, TEST_CALLER_PKG, null);
|
||||
mLooper.dispatchAll();
|
||||
mTethering.interfaceStatusChanged(TEST_WLAN_IFNAME, true);
|
||||
sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED);
|
||||
sendSoftApEvent(WIFI_AP_STATE_ENABLED, request, TEST_WLAN_IFNAME);
|
||||
|
||||
ArgumentCaptor<InterfaceConfigurationParcel> ifaceConfigCaptor =
|
||||
ArgumentCaptor.forClass(InterfaceConfigurationParcel.class);
|
||||
|
|
@ -4234,14 +4414,13 @@ public class TetheringTest {
|
|||
assertEquals(TETHER_ERROR_NO_ERROR, mTethering.getLastErrorForTest(TEST_P2P_IFNAME));
|
||||
|
||||
// Emulate pressing the WiFi tethering button.
|
||||
mTethering.startTethering(createTetheringRequest(TETHERING_WIFI), TEST_CALLER_PKG,
|
||||
null);
|
||||
TetheringRequest request = createTetheringRequest(TETHERING_WIFI);
|
||||
mTethering.startTethering(request, TEST_CALLER_PKG, null);
|
||||
mLooper.dispatchAll();
|
||||
verify(mWifiManager).startTetheredHotspot(null);
|
||||
verifyNoMoreInteractions(mWifiManager);
|
||||
verifyWifiTetheringRequested();
|
||||
|
||||
mTethering.interfaceStatusChanged(TEST_WLAN_IFNAME, true);
|
||||
sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED);
|
||||
sendSoftApEvent(WIFI_AP_STATE_ENABLED, request, TEST_WLAN_IFNAME);
|
||||
|
||||
verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER);
|
||||
verify(mWifiManager).updateInterfaceIpState(
|
||||
|
|
|
|||
Loading…
Reference in a new issue