Merge "Register localOnly softapCallback for local only hotspot" am: 46c86bbf82
Original change: https://android-review.googlesource.com/c/platform/packages/modules/Connectivity/+/1930828 Change-Id: Idedc261b6b08a84bd21c9bf19ac480730279913d Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -172,6 +172,9 @@ public class PrivateAddressCoordinator {
|
||||
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());
|
||||
if (useLastAddress && cachedAddress != null
|
||||
&& !isConflictWithUpstream(asIpPrefix(cachedAddress))) {
|
||||
|
||||
@@ -448,8 +448,22 @@ public class Tethering {
|
||||
mStateReceiver, noUpstreamFilter, PERMISSION_MAINLINE_NETWORK_STACK, mHandler);
|
||||
|
||||
final WifiManager wifiManager = getWifiManager();
|
||||
TetheringSoftApCallback softApCallback = new TetheringSoftApCallback();
|
||||
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();
|
||||
@@ -545,6 +559,13 @@ public class Tethering {
|
||||
}
|
||||
|
||||
// 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
|
||||
public void onConnectedClientsChanged(final List<WifiClient> 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.tethering.TestConnectivityManager.TestNetworkAgent;
|
||||
import com.android.networkstack.tethering.metrics.TetheringMetrics;
|
||||
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
|
||||
import com.android.testutils.MiscAsserts;
|
||||
|
||||
import org.junit.After;
|
||||
@@ -301,6 +302,7 @@ public class TetheringTest {
|
||||
private OffloadController mOffloadCtrl;
|
||||
private PrivateAddressCoordinator mPrivateAddressCoordinator;
|
||||
private SoftApCallback mSoftApCallback;
|
||||
private SoftApCallback mLocalOnlyHotspotCallback;
|
||||
private UpstreamNetworkMonitor mUpstreamNetworkMonitor;
|
||||
private TetheredInterfaceCallbackShim mTetheredInterfaceCallbackShim;
|
||||
|
||||
@@ -671,6 +673,14 @@ public class TetheringTest {
|
||||
verify(mWifiManager).registerSoftApCallback(any(), softApCallbackCaptor.capture());
|
||||
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_DIRECT)).thenReturn(true);
|
||||
}
|
||||
@@ -2537,12 +2547,11 @@ public class TetheringTest {
|
||||
eventCallbacks = dhcpEventCbsCaptor.getValue();
|
||||
// Update lease for local only tethering.
|
||||
final MacAddress testMac1 = MacAddress.fromString("11:11:11:11:11:11");
|
||||
final ArrayList<DhcpLeaseParcelable> p2pLeases = new ArrayList<>();
|
||||
p2pLeases.add(createDhcpLeaseParcelable("clientId1", testMac1, "192.168.50.24", 24,
|
||||
Long.MAX_VALUE, "test1"));
|
||||
notifyDhcpLeasesChanged(p2pLeases, eventCallbacks);
|
||||
final List<TetheredClient> clients = toTetheredClients(p2pLeases, TETHERING_WIFI_P2P);
|
||||
callback.expectTetheredClientChanged(clients);
|
||||
final DhcpLeaseParcelable p2pLease = createDhcpLeaseParcelable("clientId1", testMac1,
|
||||
"192.168.50.24", 24, Long.MAX_VALUE, "test1");
|
||||
final List<TetheredClient> p2pClients = notifyDhcpLeasesChanged(TETHERING_WIFI_P2P,
|
||||
eventCallbacks, p2pLease);
|
||||
callback.expectTetheredClientChanged(p2pClients);
|
||||
reset(mDhcpServer);
|
||||
|
||||
// Run wifi tethering.
|
||||
@@ -2552,25 +2561,20 @@ public class TetheringTest {
|
||||
any(), dhcpEventCbsCaptor.capture());
|
||||
eventCallbacks = dhcpEventCbsCaptor.getValue();
|
||||
// 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 WifiClient testClient = mock(WifiClient.class);
|
||||
when(testClient.getMacAddress()).thenReturn(testMac2);
|
||||
wifiClients.add(testClient);
|
||||
mSoftApCallback.onConnectedClientsChanged(wifiClients);
|
||||
final TetheredClient noAddrClient = new TetheredClient(testMac2,
|
||||
Collections.emptyList() /* addresses */, TETHERING_WIFI);
|
||||
clients.add(noAddrClient);
|
||||
callback.expectTetheredClientChanged(clients);
|
||||
final TetheredClient noAddrClient = notifyConnectedWifiClientsChanged(testMac2,
|
||||
false /* isLocalOnly */);
|
||||
final List<TetheredClient> p2pAndNoAddrClients = new ArrayList<>(p2pClients);
|
||||
p2pAndNoAddrClients.add(noAddrClient);
|
||||
callback.expectTetheredClientChanged(p2pAndNoAddrClients);
|
||||
|
||||
// Update dhcp lease for wifi tethering.
|
||||
clients.remove(noAddrClient);
|
||||
final ArrayList<DhcpLeaseParcelable> wifiLeases = new ArrayList<>();
|
||||
wifiLeases.add(createDhcpLeaseParcelable("clientId2", testMac2, "192.168.43.24", 24,
|
||||
Long.MAX_VALUE, "test2"));
|
||||
notifyDhcpLeasesChanged(wifiLeases, eventCallbacks);
|
||||
clients.addAll(toTetheredClients(wifiLeases, TETHERING_WIFI));
|
||||
callback.expectTetheredClientChanged(clients);
|
||||
final DhcpLeaseParcelable wifiLease = createDhcpLeaseParcelable("clientId2", testMac2,
|
||||
"192.168.43.24", 24, Long.MAX_VALUE, "test2");
|
||||
final List<TetheredClient> p2pAndWifiClients = new ArrayList<>(p2pClients);
|
||||
p2pAndWifiClients.addAll(notifyDhcpLeasesChanged(TETHERING_WIFI,
|
||||
eventCallbacks, wifiLease));
|
||||
callback.expectTetheredClientChanged(p2pAndWifiClients);
|
||||
|
||||
// Test onStarted callback that register second callback when tethering is running.
|
||||
TestTetheringEventCallback callback2 = new TestTetheringEventCallback();
|
||||
@@ -2578,18 +2582,74 @@ public class TetheringTest {
|
||||
mTethering.registerTetheringEventCallback(callback2);
|
||||
mLooper.dispatchAll();
|
||||
});
|
||||
callback2.expectTetheredClientChanged(clients);
|
||||
callback2.expectTetheredClientChanged(p2pAndWifiClients);
|
||||
}
|
||||
|
||||
private void notifyDhcpLeasesChanged(List<DhcpLeaseParcelable> leaseParcelables,
|
||||
IDhcpEventCallbacks callback) throws Exception {
|
||||
callback.onLeasesChanged(leaseParcelables);
|
||||
@Test
|
||||
@IgnoreUpTo(Build.VERSION_CODES.S_V2)
|
||||
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();
|
||||
|
||||
return toTetheredClients(dhcpLeases, type);
|
||||
}
|
||||
|
||||
private List<TetheredClient> toTetheredClients(List<DhcpLeaseParcelable> leaseParcelables,
|
||||
int type) throws Exception {
|
||||
final ArrayList<TetheredClient> leases = new ArrayList<>();
|
||||
final ArrayList<TetheredClient> clients = new ArrayList<>();
|
||||
for (DhcpLeaseParcelable lease : leaseParcelables) {
|
||||
final LinkAddress address = new LinkAddress(
|
||||
intToInet4AddressHTH(lease.netAddr), lease.prefixLength,
|
||||
@@ -2599,13 +2659,13 @@ public class TetheringTest {
|
||||
final MacAddress macAddress = MacAddress.fromBytes(lease.hwAddr);
|
||||
|
||||
final AddressInfo addressInfo = new TetheredClient.AddressInfo(address, lease.hostname);
|
||||
leases.add(new TetheredClient(
|
||||
clients.add(new TetheredClient(
|
||||
macAddress,
|
||||
Collections.singletonList(addressInfo),
|
||||
type));
|
||||
}
|
||||
|
||||
return leases;
|
||||
return clients;
|
||||
}
|
||||
|
||||
private DhcpLeaseParcelable createDhcpLeaseParcelable(final String clientId,
|
||||
|
||||
Reference in New Issue
Block a user