Merge "Register localOnly softapCallback for local only hotspot"
This commit is contained in:
@@ -172,6 +172,9 @@ public class PrivateAddressCoordinator {
|
|||||||
return new LinkAddress(LEGACY_WIFI_P2P_IFACE_ADDRESS);
|
return new LinkAddress(LEGACY_WIFI_P2P_IFACE_ADDRESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This ensures that tethering isn't started on 2 different interfaces with the same type.
|
||||||
|
// Once tethering could support multiple interface with the same type,
|
||||||
|
// TetheringSoftApCallback would need to handle it among others.
|
||||||
final LinkAddress cachedAddress = mCachedAddresses.get(ipServer.interfaceType());
|
final LinkAddress cachedAddress = mCachedAddresses.get(ipServer.interfaceType());
|
||||||
if (useLastAddress && cachedAddress != null
|
if (useLastAddress && cachedAddress != null
|
||||||
&& !isConflictWithUpstream(asIpPrefix(cachedAddress))) {
|
&& !isConflictWithUpstream(asIpPrefix(cachedAddress))) {
|
||||||
|
|||||||
@@ -448,8 +448,22 @@ public class Tethering {
|
|||||||
mStateReceiver, noUpstreamFilter, PERMISSION_MAINLINE_NETWORK_STACK, mHandler);
|
mStateReceiver, noUpstreamFilter, PERMISSION_MAINLINE_NETWORK_STACK, mHandler);
|
||||||
|
|
||||||
final WifiManager wifiManager = getWifiManager();
|
final WifiManager wifiManager = getWifiManager();
|
||||||
|
TetheringSoftApCallback softApCallback = new TetheringSoftApCallback();
|
||||||
if (wifiManager != null) {
|
if (wifiManager != null) {
|
||||||
wifiManager.registerSoftApCallback(mExecutor, new TetheringSoftApCallback());
|
wifiManager.registerSoftApCallback(mExecutor, softApCallback);
|
||||||
|
}
|
||||||
|
if (SdkLevel.isAtLeastT() && wifiManager != null) {
|
||||||
|
try {
|
||||||
|
// Although WifiManager#registerLocalOnlyHotspotSoftApCallback document that it need
|
||||||
|
// NEARBY_WIFI_DEVICES permission, but actually a caller who have NETWORK_STACK
|
||||||
|
// or MAINLINE_NETWORK_STACK permission would also able to use this API.
|
||||||
|
wifiManager.registerLocalOnlyHotspotSoftApCallback(mExecutor, softApCallback);
|
||||||
|
} catch (UnsupportedOperationException e) {
|
||||||
|
// Since wifi module development in internal branch,
|
||||||
|
// #registerLocalOnlyHotspotSoftApCallback currently doesn't supported in AOSP
|
||||||
|
// before AOSP switch to Android T + 1.
|
||||||
|
Log.wtf(TAG, "registerLocalOnlyHotspotSoftApCallback API is not supported");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
startTrackDefaultNetwork();
|
startTrackDefaultNetwork();
|
||||||
@@ -545,6 +559,13 @@ public class Tethering {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Called by wifi when the number of soft AP clients changed.
|
// Called by wifi when the number of soft AP clients changed.
|
||||||
|
// Currently multiple softAp would not behave well in PrivateAddressCoordinator
|
||||||
|
// (where it gets the address from cache), it ensure tethering only support one ipServer for
|
||||||
|
// TETHERING_WIFI. Once tethering support multiple softAp enabled simultaneously,
|
||||||
|
// onConnectedClientsChanged should also be updated to support tracking different softAp's
|
||||||
|
// clients individually.
|
||||||
|
// TODO: Add wtf log and have check to reject request duplicated type with different
|
||||||
|
// interface.
|
||||||
@Override
|
@Override
|
||||||
public void onConnectedClientsChanged(final List<WifiClient> clients) {
|
public void onConnectedClientsChanged(final List<WifiClient> clients) {
|
||||||
updateConnectedClients(clients);
|
updateConnectedClients(clients);
|
||||||
|
|||||||
@@ -195,6 +195,7 @@ import com.android.networkstack.apishim.common.BluetoothPanShim.TetheredInterfac
|
|||||||
import com.android.networkstack.apishim.common.UnsupportedApiLevelException;
|
import com.android.networkstack.apishim.common.UnsupportedApiLevelException;
|
||||||
import com.android.networkstack.tethering.TestConnectivityManager.TestNetworkAgent;
|
import com.android.networkstack.tethering.TestConnectivityManager.TestNetworkAgent;
|
||||||
import com.android.networkstack.tethering.metrics.TetheringMetrics;
|
import com.android.networkstack.tethering.metrics.TetheringMetrics;
|
||||||
|
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
|
||||||
import com.android.testutils.MiscAsserts;
|
import com.android.testutils.MiscAsserts;
|
||||||
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
@@ -301,6 +302,7 @@ public class TetheringTest {
|
|||||||
private OffloadController mOffloadCtrl;
|
private OffloadController mOffloadCtrl;
|
||||||
private PrivateAddressCoordinator mPrivateAddressCoordinator;
|
private PrivateAddressCoordinator mPrivateAddressCoordinator;
|
||||||
private SoftApCallback mSoftApCallback;
|
private SoftApCallback mSoftApCallback;
|
||||||
|
private SoftApCallback mLocalOnlyHotspotCallback;
|
||||||
private UpstreamNetworkMonitor mUpstreamNetworkMonitor;
|
private UpstreamNetworkMonitor mUpstreamNetworkMonitor;
|
||||||
private TetheredInterfaceCallbackShim mTetheredInterfaceCallbackShim;
|
private TetheredInterfaceCallbackShim mTetheredInterfaceCallbackShim;
|
||||||
|
|
||||||
@@ -671,6 +673,14 @@ public class TetheringTest {
|
|||||||
verify(mWifiManager).registerSoftApCallback(any(), softApCallbackCaptor.capture());
|
verify(mWifiManager).registerSoftApCallback(any(), softApCallbackCaptor.capture());
|
||||||
mSoftApCallback = softApCallbackCaptor.getValue();
|
mSoftApCallback = softApCallbackCaptor.getValue();
|
||||||
|
|
||||||
|
if (isAtLeastT()) {
|
||||||
|
final ArgumentCaptor<SoftApCallback> localOnlyCallbackCaptor =
|
||||||
|
ArgumentCaptor.forClass(SoftApCallback.class);
|
||||||
|
verify(mWifiManager).registerLocalOnlyHotspotSoftApCallback(any(),
|
||||||
|
localOnlyCallbackCaptor.capture());
|
||||||
|
mLocalOnlyHotspotCallback = localOnlyCallbackCaptor.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI)).thenReturn(true);
|
when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI)).thenReturn(true);
|
||||||
when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI_DIRECT)).thenReturn(true);
|
when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI_DIRECT)).thenReturn(true);
|
||||||
}
|
}
|
||||||
@@ -2537,12 +2547,11 @@ public class TetheringTest {
|
|||||||
eventCallbacks = dhcpEventCbsCaptor.getValue();
|
eventCallbacks = dhcpEventCbsCaptor.getValue();
|
||||||
// Update lease for local only tethering.
|
// Update lease for local only tethering.
|
||||||
final MacAddress testMac1 = MacAddress.fromString("11:11:11:11:11:11");
|
final MacAddress testMac1 = MacAddress.fromString("11:11:11:11:11:11");
|
||||||
final ArrayList<DhcpLeaseParcelable> p2pLeases = new ArrayList<>();
|
final DhcpLeaseParcelable p2pLease = createDhcpLeaseParcelable("clientId1", testMac1,
|
||||||
p2pLeases.add(createDhcpLeaseParcelable("clientId1", testMac1, "192.168.50.24", 24,
|
"192.168.50.24", 24, Long.MAX_VALUE, "test1");
|
||||||
Long.MAX_VALUE, "test1"));
|
final List<TetheredClient> p2pClients = notifyDhcpLeasesChanged(TETHERING_WIFI_P2P,
|
||||||
notifyDhcpLeasesChanged(p2pLeases, eventCallbacks);
|
eventCallbacks, p2pLease);
|
||||||
final List<TetheredClient> clients = toTetheredClients(p2pLeases, TETHERING_WIFI_P2P);
|
callback.expectTetheredClientChanged(p2pClients);
|
||||||
callback.expectTetheredClientChanged(clients);
|
|
||||||
reset(mDhcpServer);
|
reset(mDhcpServer);
|
||||||
|
|
||||||
// Run wifi tethering.
|
// Run wifi tethering.
|
||||||
@@ -2552,25 +2561,20 @@ public class TetheringTest {
|
|||||||
any(), dhcpEventCbsCaptor.capture());
|
any(), dhcpEventCbsCaptor.capture());
|
||||||
eventCallbacks = dhcpEventCbsCaptor.getValue();
|
eventCallbacks = dhcpEventCbsCaptor.getValue();
|
||||||
// Update mac address from softAp callback before getting dhcp lease.
|
// Update mac address from softAp callback before getting dhcp lease.
|
||||||
final ArrayList<WifiClient> wifiClients = new ArrayList<>();
|
|
||||||
final MacAddress testMac2 = MacAddress.fromString("22:22:22:22:22:22");
|
final MacAddress testMac2 = MacAddress.fromString("22:22:22:22:22:22");
|
||||||
final WifiClient testClient = mock(WifiClient.class);
|
final TetheredClient noAddrClient = notifyConnectedWifiClientsChanged(testMac2,
|
||||||
when(testClient.getMacAddress()).thenReturn(testMac2);
|
false /* isLocalOnly */);
|
||||||
wifiClients.add(testClient);
|
final List<TetheredClient> p2pAndNoAddrClients = new ArrayList<>(p2pClients);
|
||||||
mSoftApCallback.onConnectedClientsChanged(wifiClients);
|
p2pAndNoAddrClients.add(noAddrClient);
|
||||||
final TetheredClient noAddrClient = new TetheredClient(testMac2,
|
callback.expectTetheredClientChanged(p2pAndNoAddrClients);
|
||||||
Collections.emptyList() /* addresses */, TETHERING_WIFI);
|
|
||||||
clients.add(noAddrClient);
|
|
||||||
callback.expectTetheredClientChanged(clients);
|
|
||||||
|
|
||||||
// Update dhcp lease for wifi tethering.
|
// Update dhcp lease for wifi tethering.
|
||||||
clients.remove(noAddrClient);
|
final DhcpLeaseParcelable wifiLease = createDhcpLeaseParcelable("clientId2", testMac2,
|
||||||
final ArrayList<DhcpLeaseParcelable> wifiLeases = new ArrayList<>();
|
"192.168.43.24", 24, Long.MAX_VALUE, "test2");
|
||||||
wifiLeases.add(createDhcpLeaseParcelable("clientId2", testMac2, "192.168.43.24", 24,
|
final List<TetheredClient> p2pAndWifiClients = new ArrayList<>(p2pClients);
|
||||||
Long.MAX_VALUE, "test2"));
|
p2pAndWifiClients.addAll(notifyDhcpLeasesChanged(TETHERING_WIFI,
|
||||||
notifyDhcpLeasesChanged(wifiLeases, eventCallbacks);
|
eventCallbacks, wifiLease));
|
||||||
clients.addAll(toTetheredClients(wifiLeases, TETHERING_WIFI));
|
callback.expectTetheredClientChanged(p2pAndWifiClients);
|
||||||
callback.expectTetheredClientChanged(clients);
|
|
||||||
|
|
||||||
// Test onStarted callback that register second callback when tethering is running.
|
// Test onStarted callback that register second callback when tethering is running.
|
||||||
TestTetheringEventCallback callback2 = new TestTetheringEventCallback();
|
TestTetheringEventCallback callback2 = new TestTetheringEventCallback();
|
||||||
@@ -2578,18 +2582,74 @@ public class TetheringTest {
|
|||||||
mTethering.registerTetheringEventCallback(callback2);
|
mTethering.registerTetheringEventCallback(callback2);
|
||||||
mLooper.dispatchAll();
|
mLooper.dispatchAll();
|
||||||
});
|
});
|
||||||
callback2.expectTetheredClientChanged(clients);
|
callback2.expectTetheredClientChanged(p2pAndWifiClients);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void notifyDhcpLeasesChanged(List<DhcpLeaseParcelable> leaseParcelables,
|
@Test
|
||||||
IDhcpEventCallbacks callback) throws Exception {
|
@IgnoreUpTo(Build.VERSION_CODES.S_V2)
|
||||||
callback.onLeasesChanged(leaseParcelables);
|
public void testUpdateConnectedClientsForLocalOnlyHotspot() throws Exception {
|
||||||
|
TestTetheringEventCallback callback = new TestTetheringEventCallback();
|
||||||
|
runAsShell(NETWORK_SETTINGS, () -> {
|
||||||
|
mTethering.registerTetheringEventCallback(callback);
|
||||||
|
mLooper.dispatchAll();
|
||||||
|
});
|
||||||
|
callback.expectTetheredClientChanged(Collections.emptyList());
|
||||||
|
|
||||||
|
// Run local only hotspot.
|
||||||
|
mTethering.interfaceStatusChanged(TEST_WLAN_IFNAME, true);
|
||||||
|
sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_LOCAL_ONLY);
|
||||||
|
|
||||||
|
final ArgumentCaptor<IDhcpEventCallbacks> dhcpEventCbsCaptor =
|
||||||
|
ArgumentCaptor.forClass(IDhcpEventCallbacks.class);
|
||||||
|
verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS)).startWithCallbacks(
|
||||||
|
any(), dhcpEventCbsCaptor.capture());
|
||||||
|
final IDhcpEventCallbacks eventCallbacks = dhcpEventCbsCaptor.getValue();
|
||||||
|
// Update mac address from softAp callback before getting dhcp lease.
|
||||||
|
final MacAddress testMac = MacAddress.fromString("22:22:22:22:22:22");
|
||||||
|
final TetheredClient noAddrClient = notifyConnectedWifiClientsChanged(testMac,
|
||||||
|
true /* isLocalOnly */);
|
||||||
|
final List<TetheredClient> noAddrLocalOnlyClients = new ArrayList<>();
|
||||||
|
noAddrLocalOnlyClients.add(noAddrClient);
|
||||||
|
callback.expectTetheredClientChanged(noAddrLocalOnlyClients);
|
||||||
|
|
||||||
|
// Update dhcp lease for local only hotspot.
|
||||||
|
final DhcpLeaseParcelable wifiLease = createDhcpLeaseParcelable("clientId", testMac,
|
||||||
|
"192.168.43.24", 24, Long.MAX_VALUE, "test");
|
||||||
|
final List<TetheredClient> localOnlyClients = notifyDhcpLeasesChanged(TETHERING_WIFI,
|
||||||
|
eventCallbacks, wifiLease);
|
||||||
|
callback.expectTetheredClientChanged(localOnlyClients);
|
||||||
|
|
||||||
|
// Client disconnect from local only hotspot.
|
||||||
|
mLocalOnlyHotspotCallback.onConnectedClientsChanged(Collections.emptyList());
|
||||||
|
callback.expectTetheredClientChanged(Collections.emptyList());
|
||||||
|
}
|
||||||
|
|
||||||
|
private TetheredClient notifyConnectedWifiClientsChanged(final MacAddress mac,
|
||||||
|
boolean isLocalOnly) throws Exception {
|
||||||
|
final ArrayList<WifiClient> wifiClients = new ArrayList<>();
|
||||||
|
final WifiClient testClient = mock(WifiClient.class);
|
||||||
|
when(testClient.getMacAddress()).thenReturn(mac);
|
||||||
|
wifiClients.add(testClient);
|
||||||
|
if (isLocalOnly) {
|
||||||
|
mLocalOnlyHotspotCallback.onConnectedClientsChanged(wifiClients);
|
||||||
|
} else {
|
||||||
|
mSoftApCallback.onConnectedClientsChanged(wifiClients);
|
||||||
|
}
|
||||||
|
return new TetheredClient(mac, Collections.emptyList() /* addresses */, TETHERING_WIFI);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<TetheredClient> notifyDhcpLeasesChanged(int type, IDhcpEventCallbacks callback,
|
||||||
|
DhcpLeaseParcelable... leases) throws Exception {
|
||||||
|
final List<DhcpLeaseParcelable> dhcpLeases = Arrays.asList(leases);
|
||||||
|
callback.onLeasesChanged(dhcpLeases);
|
||||||
mLooper.dispatchAll();
|
mLooper.dispatchAll();
|
||||||
|
|
||||||
|
return toTetheredClients(dhcpLeases, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<TetheredClient> toTetheredClients(List<DhcpLeaseParcelable> leaseParcelables,
|
private List<TetheredClient> toTetheredClients(List<DhcpLeaseParcelable> leaseParcelables,
|
||||||
int type) throws Exception {
|
int type) throws Exception {
|
||||||
final ArrayList<TetheredClient> leases = new ArrayList<>();
|
final ArrayList<TetheredClient> clients = new ArrayList<>();
|
||||||
for (DhcpLeaseParcelable lease : leaseParcelables) {
|
for (DhcpLeaseParcelable lease : leaseParcelables) {
|
||||||
final LinkAddress address = new LinkAddress(
|
final LinkAddress address = new LinkAddress(
|
||||||
intToInet4AddressHTH(lease.netAddr), lease.prefixLength,
|
intToInet4AddressHTH(lease.netAddr), lease.prefixLength,
|
||||||
@@ -2599,13 +2659,13 @@ public class TetheringTest {
|
|||||||
final MacAddress macAddress = MacAddress.fromBytes(lease.hwAddr);
|
final MacAddress macAddress = MacAddress.fromBytes(lease.hwAddr);
|
||||||
|
|
||||||
final AddressInfo addressInfo = new TetheredClient.AddressInfo(address, lease.hostname);
|
final AddressInfo addressInfo = new TetheredClient.AddressInfo(address, lease.hostname);
|
||||||
leases.add(new TetheredClient(
|
clients.add(new TetheredClient(
|
||||||
macAddress,
|
macAddress,
|
||||||
Collections.singletonList(addressInfo),
|
Collections.singletonList(addressInfo),
|
||||||
type));
|
type));
|
||||||
}
|
}
|
||||||
|
|
||||||
return leases;
|
return clients;
|
||||||
}
|
}
|
||||||
|
|
||||||
private DhcpLeaseParcelable createDhcpLeaseParcelable(final String clientId,
|
private DhcpLeaseParcelable createDhcpLeaseParcelable(final String clientId,
|
||||||
|
|||||||
Reference in New Issue
Block a user