Merge "Add CtsTetheringTestLatestSdk into mainline-presubmit"
diff --git a/Cronet/tests/cts/Android.bp b/Cronet/tests/cts/Android.bp
index 44b3364..1e0adef 100644
--- a/Cronet/tests/cts/Android.bp
+++ b/Cronet/tests/cts/Android.bp
@@ -53,7 +53,9 @@
defaults: [
"cts_defaults",
],
+ enforce_default_target_sdk_version: true,
sdk_version: "test_current",
+ min_sdk_version: "30",
static_libs: ["CtsNetHttpTestsLib"],
// Tag this as a cts test artifact
test_suites: [
diff --git a/Cronet/tests/mts/Android.bp b/Cronet/tests/mts/Android.bp
index 93564e4..4e4251c 100644
--- a/Cronet/tests/mts/Android.bp
+++ b/Cronet/tests/mts/Android.bp
@@ -34,25 +34,13 @@
"--output $(out)",
}
+// Library to be used in coverage tests. cronet_java_tests can't be used directly because the common
+// tests need to inherit the NetHttpTests manifest.
android_library {
name: "NetHttpTestsLibPreJarJar",
- srcs: [":cronet_aml_javatests_sources"],
+ static_libs: ["cronet_java_tests"],
sdk_version: "module_current",
min_sdk_version: "30",
- static_libs: [
- "cronet_testserver_utils",
- "androidx.test.ext.junit",
- "androidx.test.rules",
- "junit",
- "truth",
- ],
- libs: [
- "android.test.base",
- "framework-connectivity-pre-jarjar",
- // android.net.TrafficStats apis
- "framework-connectivity-t",
- ],
- lint: { test: true }
}
android_test {
diff --git a/Cronet/tests/mts/jarjar_excludes.txt b/Cronet/tests/mts/jarjar_excludes.txt
index cf3a017..a3e86de 100644
--- a/Cronet/tests/mts/jarjar_excludes.txt
+++ b/Cronet/tests/mts/jarjar_excludes.txt
@@ -5,6 +5,8 @@
# cronet_tests.so is not jarjared and uses base classes. We can remove this when there's a
# separate java base target to depend on.
org\.chromium\.base\..+
+J\.cronet_tests_N(\$.+)?
+
# Do not jarjar the tests and its utils as they also do JNI with cronet_tests.so
org\.chromium\.net\..*Test.*(\$.+)?
org\.chromium\.net\.NativeTestServer(\$.+)?
diff --git a/Tethering/Android.bp b/Tethering/Android.bp
index b88ec7f..4478b1e 100644
--- a/Tethering/Android.bp
+++ b/Tethering/Android.bp
@@ -195,11 +195,7 @@
certificate: "networkstack",
manifest: "AndroidManifest.xml",
use_embedded_native_libs: true,
- // The network stack *must* be included to ensure security of the device
- required: [
- "NetworkStack",
- "privapp_allowlist_com.android.tethering",
- ],
+ privapp_allowlist: ":privapp_allowlist_com.android.tethering",
apex_available: ["com.android.tethering"],
lint: { strict_updatability_linting: true },
}
@@ -215,11 +211,7 @@
certificate: "networkstack",
manifest: "AndroidManifest.xml",
use_embedded_native_libs: true,
- // The network stack *must* be included to ensure security of the device
- required: [
- "NetworkStackNext",
- "privapp_allowlist_com.android.tethering",
- ],
+ privapp_allowlist: ":privapp_allowlist_com.android.tethering",
apex_available: ["com.android.tethering"],
lint: { strict_updatability_linting: true },
}
diff --git a/Tethering/apex/Android.bp b/Tethering/apex/Android.bp
index 4bfd1fb..cf9b359 100644
--- a/Tethering/apex/Android.bp
+++ b/Tethering/apex/Android.bp
@@ -112,10 +112,7 @@
"ServiceConnectivityResources",
"HalfSheetUX",
],
- prebuilts: [
- "current_sdkinfo",
- "privapp_allowlist_com.android.tethering",
- ],
+ prebuilts: ["current_sdkinfo"],
manifest: "manifest.json",
key: "com.android.tethering.key",
// Indicates that pre-installed version of this apex can be compressed.
diff --git a/Tethering/apex/permissions/Android.bp b/Tethering/apex/permissions/Android.bp
index ac9ec65..69c1aa2 100644
--- a/Tethering/apex/permissions/Android.bp
+++ b/Tethering/apex/permissions/Android.bp
@@ -19,10 +19,7 @@
default_visibility: ["//packages/modules/Connectivity/Tethering:__subpackages__"],
}
-prebuilt_etc {
+filegroup {
name: "privapp_allowlist_com.android.tethering",
- sub_dir: "permissions",
- filename: "permissions.xml",
- src: "permissions.xml",
- installable: false,
+ srcs: ["permissions.xml"],
}
\ No newline at end of file
diff --git a/Tethering/src/android/net/ip/IpServer.java b/Tethering/src/android/net/ip/IpServer.java
index 9d0f6b4..6affb62 100644
--- a/Tethering/src/android/net/ip/IpServer.java
+++ b/Tethering/src/android/net/ip/IpServer.java
@@ -17,6 +17,8 @@
package android.net.ip;
import static android.net.RouteInfo.RTN_UNICAST;
+import static android.net.TetheringManager.CONNECTIVITY_SCOPE_GLOBAL;
+import static android.net.TetheringManager.CONNECTIVITY_SCOPE_LOCAL;
import static android.net.TetheringManager.TETHER_ERROR_DHCPSERVER_ERROR;
import static android.net.TetheringManager.TETHER_ERROR_ENABLE_FORWARDING_ERROR;
import static android.net.TetheringManager.TETHER_ERROR_IFACE_CFG_ERROR;
@@ -405,8 +407,8 @@
/** Internals. */
- private boolean startIPv4() {
- return configureIPv4(true);
+ private boolean startIPv4(int scope) {
+ return configureIPv4(true, scope);
}
/**
@@ -616,7 +618,7 @@
}
private void stopIPv4() {
- configureIPv4(false);
+ configureIPv4(false /* enabled */, CONNECTIVITY_SCOPE_GLOBAL /* not used */);
// NOTE: All of configureIPv4() will be refactored out of existence
// into calls to InterfaceController, shared with startIPv4().
mInterfaceCtrl.clearIPv4Address();
@@ -627,11 +629,11 @@
mStaticIpv4ClientAddr = null;
}
- private boolean configureIPv4(boolean enabled) {
+ private boolean configureIPv4(boolean enabled, int scope) {
if (VDBG) Log.d(TAG, "configureIPv4(" + enabled + ")");
if (enabled) {
- mIpv4Address = requestIpv4Address(true /* useLastAddress */);
+ mIpv4Address = requestIpv4Address(scope, true /* useLastAddress */);
}
if (mIpv4Address == null) {
@@ -679,12 +681,12 @@
return (mInterfaceType == TetheringManager.TETHERING_BLUETOOTH) && !SdkLevel.isAtLeastT();
}
- private LinkAddress requestIpv4Address(final boolean useLastAddress) {
+ private LinkAddress requestIpv4Address(final int scope, final boolean useLastAddress) {
if (mStaticIpv4ServerAddr != null) return mStaticIpv4ServerAddr;
if (shouldNotConfigureBluetoothInterface()) return new LinkAddress(BLUETOOTH_IFACE_ADDR);
- return mPrivateAddressCoordinator.requestDownstreamAddress(this, useLastAddress);
+ return mPrivateAddressCoordinator.requestDownstreamAddress(this, scope, useLastAddress);
}
private boolean startIPv6() {
@@ -1133,8 +1135,16 @@
sendInterfaceState(mDesiredInterfaceState);
}
+ private int getScope() {
+ if (mDesiredInterfaceState == STATE_TETHERED) {
+ return CONNECTIVITY_SCOPE_GLOBAL;
+ }
+
+ return CONNECTIVITY_SCOPE_LOCAL;
+ }
+
private void startServingInterface() {
- if (!startIPv4()) {
+ if (!startIPv4(getScope())) {
mLastError = TETHER_ERROR_IFACE_CFG_ERROR;
return;
}
@@ -1222,7 +1232,7 @@
}
final LinkAddress deprecatedLinkAddress = mIpv4Address;
- mIpv4Address = requestIpv4Address(false);
+ mIpv4Address = requestIpv4Address(getScope(), false);
if (mIpv4Address == null) {
mLog.e("Fail to request a new downstream prefix");
return;
diff --git a/Tethering/src/com/android/networkstack/tethering/ConnectedClientsTracker.java b/Tethering/src/com/android/networkstack/tethering/ConnectedClientsTracker.java
index 8a96988..5b19c4e 100644
--- a/Tethering/src/com/android/networkstack/tethering/ConnectedClientsTracker.java
+++ b/Tethering/src/com/android/networkstack/tethering/ConnectedClientsTracker.java
@@ -29,6 +29,8 @@
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
+import com.android.modules.utils.build.SdkLevel;
+
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@@ -49,6 +51,8 @@
@NonNull
private List<WifiClient> mLastWifiClients = Collections.emptyList();
@NonNull
+ private List<WifiClient> mLastLocalOnlyClients = Collections.emptyList();
+ @NonNull
private List<TetheredClient> mLastTetheredClients = Collections.emptyList();
@VisibleForTesting
@@ -72,25 +76,44 @@
*
* <p>The new list can be obtained through {@link #getLastTetheredClients()}.
* @param ipServers The IpServers used to assign addresses to clients.
- * @param wifiClients The list of L2-connected WiFi clients. Null for no change since last
- * update.
+ * @param wifiClients The list of L2-connected WiFi clients that are connected to a global
+ * hotspot. Null for no change since last update.
+ * @param localOnlyClients The list of L2-connected WiFi clients that are connected to localOnly
+ * hotspot. Null for no change since last update.
* @return True if the list of clients changed since the last calculation.
*/
public boolean updateConnectedClients(
- Iterable<IpServer> ipServers, @Nullable List<WifiClient> wifiClients) {
+ Iterable<IpServer> ipServers, @Nullable List<WifiClient> wifiClients,
+ @Nullable List<WifiClient> localOnlyClients) {
final long now = mClock.elapsedRealtime();
- if (wifiClients != null) {
- mLastWifiClients = wifiClients;
- }
+ if (wifiClients != null) mLastWifiClients = wifiClients;
+ if (localOnlyClients != null) mLastLocalOnlyClients = localOnlyClients;
+
final Set<MacAddress> wifiClientMacs = getClientMacs(mLastWifiClients);
+ final Set<MacAddress> localOnlyClientMacs = getClientMacs(mLastLocalOnlyClients);
// Build the list of non-expired leases from all IpServers, grouped by mac address
final Map<MacAddress, TetheredClient> clientsMap = new HashMap<>();
for (IpServer server : ipServers) {
+ final Set<MacAddress> connectedClientMacs;
+ switch (server.servingMode()) {
+ case IpServer.STATE_TETHERED:
+ connectedClientMacs = wifiClientMacs;
+ break;
+ case IpServer.STATE_LOCAL_ONLY:
+ // Before T, SAP and LOHS both use wifiClientMacs because
+ // registerLocalOnlyHotspotSoftApCallback didn't exist.
+ connectedClientMacs = SdkLevel.isAtLeastT()
+ ? localOnlyClientMacs : wifiClientMacs;
+ break;
+ default:
+ continue;
+ }
+
for (TetheredClient client : server.getAllLeases()) {
if (client.getTetheringType() == TETHERING_WIFI
- && !wifiClientMacs.contains(client.getMacAddress())) {
+ && !connectedClientMacs.contains(client.getMacAddress())) {
// Skip leases of WiFi clients that are not (or no longer) L2-connected
continue;
}
@@ -104,11 +127,8 @@
// TODO: add IPv6 addresses from netlink
// Add connected WiFi clients that do not have any known address
- for (MacAddress client : wifiClientMacs) {
- if (clientsMap.containsKey(client)) continue;
- clientsMap.put(client, new TetheredClient(
- client, Collections.emptyList() /* addresses */, TETHERING_WIFI));
- }
+ addWifiClientsIfNoLeases(clientsMap, wifiClientMacs);
+ addWifiClientsIfNoLeases(clientsMap, localOnlyClientMacs);
final HashSet<TetheredClient> clients = new HashSet<>(clientsMap.values());
final boolean clientsChanged = clients.size() != mLastTetheredClients.size()
@@ -117,6 +137,15 @@
return clientsChanged;
}
+ private static void addWifiClientsIfNoLeases(
+ final Map<MacAddress, TetheredClient> clientsMap, final Set<MacAddress> clientMacs) {
+ for (MacAddress mac : clientMacs) {
+ if (clientsMap.containsKey(mac)) continue;
+ clientsMap.put(mac, new TetheredClient(
+ mac, Collections.emptyList() /* addresses */, TETHERING_WIFI));
+ }
+ }
+
private static void addLease(Map<MacAddress, TetheredClient> clientsMap, TetheredClient lease) {
final TetheredClient aggregateClient = clientsMap.getOrDefault(
lease.getMacAddress(), lease);
diff --git a/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java b/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java
index 41a10ae..6c0ca82 100644
--- a/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java
+++ b/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java
@@ -16,6 +16,8 @@
package com.android.networkstack.tethering;
import static android.net.NetworkCapabilities.TRANSPORT_VPN;
+import static android.net.TetheringManager.CONNECTIVITY_SCOPE_GLOBAL;
+import static android.net.TetheringManager.CONNECTIVITY_SCOPE_LOCAL;
import static android.net.TetheringManager.TETHERING_BLUETOOTH;
import static android.net.TetheringManager.TETHERING_WIFI_P2P;
@@ -34,7 +36,6 @@
import android.net.ip.IpServer;
import android.util.ArrayMap;
import android.util.ArraySet;
-import android.util.SparseArray;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -77,7 +78,7 @@
private final ConnectivityManager mConnectivityMgr;
private final TetheringConfiguration mConfig;
// keyed by downstream type(TetheringManager.TETHERING_*).
- private final SparseArray<LinkAddress> mCachedAddresses;
+ private final ArrayMap<AddressKey, LinkAddress> mCachedAddresses;
public PrivateAddressCoordinator(Context context, TetheringConfiguration config) {
mDownstreams = new ArraySet<>();
@@ -85,10 +86,12 @@
mConnectivityMgr = (ConnectivityManager) context.getSystemService(
Context.CONNECTIVITY_SERVICE);
mConfig = config;
- mCachedAddresses = new SparseArray<>();
+ mCachedAddresses = new ArrayMap<AddressKey, LinkAddress>();
// Reserved static addresses for bluetooth and wifi p2p.
- mCachedAddresses.put(TETHERING_BLUETOOTH, new LinkAddress(LEGACY_BLUETOOTH_IFACE_ADDRESS));
- mCachedAddresses.put(TETHERING_WIFI_P2P, new LinkAddress(LEGACY_WIFI_P2P_IFACE_ADDRESS));
+ mCachedAddresses.put(new AddressKey(TETHERING_BLUETOOTH, CONNECTIVITY_SCOPE_GLOBAL),
+ new LinkAddress(LEGACY_BLUETOOTH_IFACE_ADDRESS));
+ mCachedAddresses.put(new AddressKey(TETHERING_WIFI_P2P, CONNECTIVITY_SCOPE_LOCAL),
+ new LinkAddress(LEGACY_WIFI_P2P_IFACE_ADDRESS));
mTetheringPrefixes = new ArrayList<>(Arrays.asList(new IpPrefix("192.168.0.0/16"),
new IpPrefix("172.16.0.0/12"), new IpPrefix("10.0.0.0/8")));
@@ -166,16 +169,18 @@
* returns null if there is no available address.
*/
@Nullable
- public LinkAddress requestDownstreamAddress(final IpServer ipServer, boolean useLastAddress) {
+ public LinkAddress requestDownstreamAddress(final IpServer ipServer, final int scope,
+ boolean useLastAddress) {
if (mConfig.shouldEnableWifiP2pDedicatedIp()
&& ipServer.interfaceType() == TETHERING_WIFI_P2P) {
return new LinkAddress(LEGACY_WIFI_P2P_IFACE_ADDRESS);
}
+ final AddressKey addrKey = new AddressKey(ipServer.interfaceType(), scope);
// 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(addrKey);
if (useLastAddress && cachedAddress != null
&& !isConflictWithUpstream(asIpPrefix(cachedAddress))) {
mDownstreams.add(ipServer);
@@ -186,7 +191,7 @@
final LinkAddress newAddress = chooseDownstreamAddress(prefixRange);
if (newAddress != null) {
mDownstreams.add(ipServer);
- mCachedAddresses.put(ipServer.interfaceType(), newAddress);
+ mCachedAddresses.put(addrKey, newAddress);
return newAddress;
}
}
@@ -384,6 +389,34 @@
return asIpPrefix(address);
}
+ private static class AddressKey {
+ private final int mTetheringType;
+ private final int mScope;
+
+ private AddressKey(int type, int scope) {
+ mTetheringType = type;
+ mScope = scope;
+ }
+
+ @Override
+ public int hashCode() {
+ return (mTetheringType << 16) + mScope;
+ }
+
+ @Override
+ public boolean equals(@Nullable Object obj) {
+ if (!(obj instanceof AddressKey)) return false;
+ final AddressKey other = (AddressKey) obj;
+
+ return mTetheringType == other.mTetheringType && mScope == other.mScope;
+ }
+
+ @Override
+ public String toString() {
+ return "AddressKey(" + mTetheringType + ", " + mScope + ")";
+ }
+ }
+
void dump(final IndentingPrintWriter pw) {
pw.println("mTetheringPrefixes:");
pw.increaseIndent();
diff --git a/Tethering/src/com/android/networkstack/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java
index 4c5bf4e..e5f644e 100644
--- a/Tethering/src/com/android/networkstack/tethering/Tethering.java
+++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java
@@ -58,6 +58,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.IFACE_IP_MODE_UNSPECIFIED;
+import static android.net.wifi.WifiManager.SoftApCallback;
import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED;
import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED;
import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
@@ -479,15 +480,15 @@
mStateReceiver, noUpstreamFilter, PERMISSION_MAINLINE_NETWORK_STACK, mHandler);
final WifiManager wifiManager = getWifiManager();
- TetheringSoftApCallback softApCallback = new TetheringSoftApCallback();
if (wifiManager != null) {
- wifiManager.registerSoftApCallback(mExecutor, softApCallback);
- }
- if (SdkLevel.isAtLeastT() && wifiManager != null) {
- // 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);
+ wifiManager.registerSoftApCallback(mExecutor, new TetheringSoftApCallback());
+ if (SdkLevel.isAtLeastT()) {
+ // Although WifiManager#registerLocalOnlyHotspotSoftApCallback document that it need
+ // NEARBY_WIFI_DEVICES permission, but actually a caller who have NETWORK_STACK
+ // or MAINLINE_NETWORK_STACK permission can also use this API.
+ wifiManager.registerLocalOnlyHotspotSoftApCallback(mExecutor,
+ new LocalOnlyHotspotCallback());
+ }
}
startTrackDefaultNetwork();
@@ -573,26 +574,17 @@
}
}
- private class TetheringSoftApCallback implements WifiManager.SoftApCallback {
- // TODO: Remove onStateChanged override when this method has default on
- // WifiManager#SoftApCallback interface.
- // Wifi listener for state change of the soft AP
- @Override
- public void onStateChanged(final int state, final int failureReason) {
- // Nothing
- }
-
- // 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.
+ private class TetheringSoftApCallback implements SoftApCallback {
@Override
public void onConnectedClientsChanged(final List<WifiClient> clients) {
- updateConnectedClients(clients);
+ updateConnectedClients(clients, null);
+ }
+ }
+
+ private class LocalOnlyHotspotCallback implements SoftApCallback {
+ @Override
+ public void onConnectedClientsChanged(final List<WifiClient> clients) {
+ updateConnectedClients(null, clients);
}
}
@@ -1968,7 +1960,7 @@
mIPv6TetheringCoordinator.removeActiveDownstream(who);
mOffload.excludeDownstreamInterface(who.interfaceName());
mForwardedDownstreams.remove(who);
- updateConnectedClients(null /* wifiClients */);
+ maybeDhcpLeasesChanged();
// If this is a Wi-Fi interface, tell WifiManager of any errors
// or the inactive serving state.
@@ -2710,9 +2702,15 @@
if (e != null) throw e;
}
- private void updateConnectedClients(final List<WifiClient> wifiClients) {
+ private void maybeDhcpLeasesChanged() {
+ // null means wifi clients did not change.
+ updateConnectedClients(null, null);
+ }
+
+ private void updateConnectedClients(final List<WifiClient> wifiClients,
+ final List<WifiClient> localOnlyClients) {
if (mConnectedClientsTracker.updateConnectedClients(mTetherMainSM.getAllDownstreams(),
- wifiClients)) {
+ wifiClients, localOnlyClients)) {
reportTetherClientsChanged(mConnectedClientsTracker.getLastTetheredClients());
}
}
@@ -2731,7 +2729,7 @@
@Override
public void dhcpLeasesChanged() {
- updateConnectedClients(null /* wifiClients */);
+ maybeDhcpLeasesChanged();
}
@Override
diff --git a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
index f0d9057..46e50ef 100644
--- a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
+++ b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
@@ -19,6 +19,8 @@
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.CONNECTIVITY_SCOPE_GLOBAL;
+import static android.net.TetheringManager.CONNECTIVITY_SCOPE_LOCAL;
import static android.net.TetheringManager.TETHERING_BLUETOOTH;
import static android.net.TetheringManager.TETHERING_NCM;
import static android.net.TetheringManager.TETHERING_USB;
@@ -48,6 +50,7 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyBoolean;
@@ -271,8 +274,8 @@
dispatchTetherConnectionChanged(upstreamIface, lp, 0);
}
reset(mNetd, mCallback, mAddressCoordinator, mBpfCoordinator);
- when(mAddressCoordinator.requestDownstreamAddress(any(), anyBoolean())).thenReturn(
- mTestAddress);
+ when(mAddressCoordinator.requestDownstreamAddress(any(), anyInt(),
+ anyBoolean())).thenReturn(mTestAddress);
}
@SuppressWarnings("DoNotCall") // Ignore warning for synchronous to call to Thread.run()
@@ -293,8 +296,8 @@
@Before public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
when(mSharedLog.forSubComponent(anyString())).thenReturn(mSharedLog);
- when(mAddressCoordinator.requestDownstreamAddress(any(), anyBoolean())).thenReturn(
- mTestAddress);
+ when(mAddressCoordinator.requestDownstreamAddress(any(), anyInt(),
+ anyBoolean())).thenReturn(mTestAddress);
when(mTetherConfig.isBpfOffloadEnabled()).thenReturn(DEFAULT_USING_BPF_OFFLOAD);
when(mTetherConfig.useLegacyDhcpServer()).thenReturn(false /* default value */);
@@ -428,7 +431,8 @@
dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED);
InOrder inOrder = inOrder(mCallback, mNetd, mAddressCoordinator);
if (isAtLeastT()) {
- inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any(), eq(true));
+ inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any(),
+ eq(CONNECTIVITY_SCOPE_GLOBAL), eq(true));
inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg ->
IFACE_NAME.equals(cfg.ifName) && assertContainsFlag(cfg.flags, IF_STATE_UP)));
}
@@ -477,7 +481,8 @@
dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED);
InOrder inOrder = inOrder(mCallback, mNetd, mAddressCoordinator);
- inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any(), eq(true));
+ inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any(),
+ eq(CONNECTIVITY_SCOPE_GLOBAL), 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);
@@ -498,7 +503,8 @@
dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_LOCAL_ONLY);
InOrder inOrder = inOrder(mCallback, mNetd, mAddressCoordinator);
- inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any(), eq(true));
+ inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any(),
+ eq(CONNECTIVITY_SCOPE_LOCAL), eq(true));
inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg ->
IFACE_NAME.equals(cfg.ifName) && assertNotContainsFlag(cfg.flags, IF_STATE_UP)));
inOrder.verify(mNetd).tetherInterfaceAdd(IFACE_NAME);
@@ -766,7 +772,8 @@
final ArgumentCaptor<LinkProperties> lpCaptor =
ArgumentCaptor.forClass(LinkProperties.class);
InOrder inOrder = inOrder(mNetd, mCallback, mAddressCoordinator);
- inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any(), eq(true));
+ inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any(),
+ eq(CONNECTIVITY_SCOPE_LOCAL), eq(true));
inOrder.verify(mNetd).networkAddInterface(INetd.LOCAL_NET_ID, IFACE_NAME);
// One for ipv4 route, one for ipv6 link local route.
inOrder.verify(mNetd, times(2)).networkAddRoute(eq(INetd.LOCAL_NET_ID), eq(IFACE_NAME),
@@ -779,12 +786,13 @@
// Simulate the DHCP server receives DHCPDECLINE on MirrorLink and then signals
// onNewPrefixRequest callback.
final LinkAddress newAddress = new LinkAddress("192.168.100.125/24");
- when(mAddressCoordinator.requestDownstreamAddress(any(), anyBoolean())).thenReturn(
- newAddress);
+ when(mAddressCoordinator.requestDownstreamAddress(any(), anyInt(),
+ anyBoolean())).thenReturn(newAddress);
eventCallbacks.onNewPrefixRequest(new IpPrefix("192.168.42.0/24"));
mLooper.dispatchAll();
- inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any(), eq(false));
+ inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any(),
+ eq(CONNECTIVITY_SCOPE_LOCAL), eq(false));
inOrder.verify(mNetd).tetherApplyDnsInterfaces();
inOrder.verify(mCallback).updateLinkProperties(eq(mIpServer), lpCaptor.capture());
verifyNoMoreInteractions(mCallback);
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/ConnectedClientsTrackerTest.kt b/Tethering/tests/unit/src/com/android/networkstack/tethering/ConnectedClientsTrackerTest.kt
index d915354..2dd9f91 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/ConnectedClientsTrackerTest.kt
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/ConnectedClientsTrackerTest.kt
@@ -24,19 +24,25 @@
import android.net.TetheringManager.TETHERING_WIFI
import android.net.ip.IpServer
import android.net.wifi.WifiClient
+import android.os.Build
import androidx.test.filters.SmallTest
import androidx.test.runner.AndroidJUnit4
+import com.android.testutils.DevSdkIgnoreRule
+import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
+import kotlin.test.assertEquals
+import kotlin.test.assertFalse
+import kotlin.test.assertTrue
+import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito.doReturn
import org.mockito.Mockito.mock
-import kotlin.test.assertEquals
-import kotlin.test.assertFalse
-import kotlin.test.assertTrue
@RunWith(AndroidJUnit4::class)
@SmallTest
class ConnectedClientsTrackerTest {
+ @get:Rule
+ val ignoreRule = DevSdkIgnoreRule()
private val server1 = mock(IpServer::class.java)
private val server2 = mock(IpServer::class.java)
@@ -70,55 +76,122 @@
@Test
fun testUpdateConnectedClients() {
+ doReturn(IpServer.STATE_TETHERED).`when`(server1).servingMode()
+ doReturn(IpServer.STATE_TETHERED).`when`(server2).servingMode()
+ runUpdateConnectedClientsTest(isGlobal = true)
+ }
+
+ @Test @IgnoreUpTo(Build.VERSION_CODES.S_V2)
+ fun testUpdateConnectedClients_LocalOnly() {
+ doReturn(IpServer.STATE_LOCAL_ONLY).`when`(server1).servingMode()
+ doReturn(IpServer.STATE_LOCAL_ONLY).`when`(server2).servingMode()
+ runUpdateConnectedClientsTest(isGlobal = false)
+ }
+
+ fun runUpdateConnectedClientsTest(isGlobal: Boolean) {
doReturn(emptyList<TetheredClient>()).`when`(server1).allLeases
doReturn(emptyList<TetheredClient>()).`when`(server2).allLeases
val tracker = ConnectedClientsTracker(clock)
- assertFalse(tracker.updateConnectedClients(servers, null))
+ assertFalse(tracker.updateConnectedClients(servers, null, null))
// Obtain a lease for client 1
doReturn(listOf(client1)).`when`(server1).allLeases
- assertSameClients(listOf(client1), assertNewClients(tracker, servers, listOf(wifiClient1)))
+ if (isGlobal) {
+ assertSameClients(listOf(client1), assertNewClients(tracker, servers,
+ wifiClients = listOf(wifiClient1)))
+ } else {
+ assertSameClients(listOf(client1), assertNewClients(tracker, servers,
+ localOnlyClients = listOf(wifiClient1)))
+ }
// Client 2 L2-connected, no lease yet
val client2WithoutAddr = TetheredClient(client2Addr, emptyList(), TETHERING_WIFI)
- assertSameClients(listOf(client1, client2WithoutAddr),
- assertNewClients(tracker, servers, listOf(wifiClient1, wifiClient2)))
+ if (isGlobal) {
+ assertSameClients(listOf(client1, client2WithoutAddr), assertNewClients(
+ tracker, servers, wifiClients = listOf(wifiClient1, wifiClient2)))
+ } else {
+ assertSameClients(listOf(client1, client2WithoutAddr), assertNewClients(
+ tracker, servers, localOnlyClients = listOf(wifiClient1, wifiClient2)))
+ }
// Client 2 lease obtained
doReturn(listOf(client1, client2)).`when`(server1).allLeases
- assertSameClients(listOf(client1, client2), assertNewClients(tracker, servers, null))
+ assertSameClients(listOf(client1, client2), assertNewClients(tracker, servers))
// Client 3 lease obtained
doReturn(listOf(client3)).`when`(server2).allLeases
- assertSameClients(listOf(client1, client2, client3),
- assertNewClients(tracker, servers, null))
+ assertSameClients(listOf(client1, client2, client3), assertNewClients(tracker, servers))
- // Client 2 L2-disconnected
- assertSameClients(listOf(client1, client3),
- assertNewClients(tracker, servers, listOf(wifiClient1)))
-
- // Client 1 L2-disconnected
- assertSameClients(listOf(client3), assertNewClients(tracker, servers, emptyList()))
-
- // Client 1 comes back
- assertSameClients(listOf(client1, client3),
- assertNewClients(tracker, servers, listOf(wifiClient1)))
+ if (isGlobal) {
+ // Client 2 L2-disconnected
+ assertSameClients(listOf(client1, client3),
+ assertNewClients(tracker, servers, wifiClients = listOf(wifiClient1)))
+ // Client 1 L2-disconnected
+ assertSameClients(listOf(client3), assertNewClients(tracker, servers,
+ wifiClients = emptyList()))
+ // Client 1 comes back
+ assertSameClients(listOf(client1, client3),
+ assertNewClients(tracker, servers, wifiClients = listOf(wifiClient1)))
+ } else {
+ // Client 2 L2-disconnected
+ assertSameClients(listOf(client1, client3),
+ assertNewClients(tracker, servers, localOnlyClients = listOf(wifiClient1)))
+ // Client 1 L2-disconnected
+ assertSameClients(listOf(client3),
+ assertNewClients(tracker, servers, localOnlyClients = emptyList()))
+ // Client 1 comes back
+ assertSameClients(listOf(client1, client3),
+ assertNewClients(tracker, servers, localOnlyClients = listOf(wifiClient1)))
+ }
// Leases lost, client 1 still L2-connected
doReturn(emptyList<TetheredClient>()).`when`(server1).allLeases
doReturn(emptyList<TetheredClient>()).`when`(server2).allLeases
assertSameClients(listOf(TetheredClient(client1Addr, emptyList(), TETHERING_WIFI)),
- assertNewClients(tracker, servers, null))
+ assertNewClients(tracker, servers))
+ }
+
+ @Test @IgnoreUpTo(Build.VERSION_CODES.S_V2)
+ fun testLocalOnlyAndTetheredHotspotClients() {
+ val tracker = ConnectedClientsTracker(clock)
+ doReturn(IpServer.STATE_LOCAL_ONLY).`when`(server1).servingMode()
+ doReturn(IpServer.STATE_TETHERED).`when`(server2).servingMode()
+
+ // Client 1 connected to server1 (LOHS)
+ doReturn(listOf(client1)).`when`(server1).allLeases
+ doReturn(emptyList<TetheredClient>()).`when`(server2).allLeases
+ assertSameClients(listOf(client1), assertNewClients(tracker, servers,
+ localOnlyClients = listOf(wifiClient1)))
+
+ // Client 2 connected to server2 (wifi Tethering)
+ doReturn(listOf(client2)).`when`(server2).allLeases
+ assertSameClients(listOf(client1, client2), assertNewClients(tracker, servers,
+ listOf(wifiClient2), listOf(wifiClient1)))
+
+ // Client 2 L2-disconnected but lease doesn't expired yet
+ assertSameClients(listOf(client1), assertNewClients(tracker, servers,
+ wifiClients = emptyList()))
+
+ // Client 1 lease lost but still L2-connected
+ doReturn(emptyList<TetheredClient>()).`when`(server1).allLeases
+ val client1WithoutAddr = TetheredClient(client1Addr, emptyList(), TETHERING_WIFI)
+ assertSameClients(listOf(client1WithoutAddr), assertNewClients(tracker, servers))
+
+ // Client 1 L2-disconnected
+ assertSameClients(emptyList(), assertNewClients(tracker, servers,
+ localOnlyClients = emptyList()))
}
@Test
fun testUpdateConnectedClients_LeaseExpiration() {
+ doReturn(IpServer.STATE_TETHERED).`when`(server1).servingMode()
+ doReturn(IpServer.STATE_TETHERED).`when`(server2).servingMode()
val tracker = ConnectedClientsTracker(clock)
doReturn(listOf(client1, client2)).`when`(server1).allLeases
doReturn(listOf(client3)).`when`(server2).allLeases
assertSameClients(listOf(client1, client2, client3), assertNewClients(
- tracker, servers, listOf(wifiClient1, wifiClient2)))
+ tracker, servers, wifiClients = listOf(wifiClient1, wifiClient2)))
clock.time += 20
// Client 3 has no remaining lease: removed
@@ -131,15 +204,16 @@
// Only the "t + 30" address is left, the "t + 10" address expired
listOf(client2Exp30AddrInfo),
TETHERING_WIFI))
- assertSameClients(expectedClients, assertNewClients(tracker, servers, null))
+ assertSameClients(expectedClients, assertNewClients(tracker, servers))
}
private fun assertNewClients(
tracker: ConnectedClientsTracker,
ipServers: Iterable<IpServer>,
- wifiClients: List<WifiClient>?
+ wifiClients: List<WifiClient>? = null,
+ localOnlyClients: List<WifiClient>? = null
): List<TetheredClient> {
- assertTrue(tracker.updateConnectedClients(ipServers, wifiClients))
+ assertTrue(tracker.updateConnectedClients(ipServers, wifiClients, localOnlyClients))
return tracker.lastTetheredClients
}
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java
index 55d9852..91b092a 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java
@@ -19,6 +19,8 @@
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_VPN;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static android.net.TetheringManager.CONNECTIVITY_SCOPE_GLOBAL;
+import static android.net.TetheringManager.CONNECTIVITY_SCOPE_LOCAL;
import static android.net.TetheringManager.TETHERING_ETHERNET;
import static android.net.TetheringManager.TETHERING_USB;
import static android.net.TetheringManager.TETHERING_WIFI;
@@ -61,6 +63,7 @@
private static final String TEST_IFNAME = "test0";
@Mock private IpServer mHotspotIpServer;
+ @Mock private IpServer mLocalHotspotIpServer;
@Mock private IpServer mUsbIpServer;
@Mock private IpServer mEthernetIpServer;
@Mock private IpServer mWifiP2pIpServer;
@@ -90,6 +93,7 @@
when(mUsbIpServer.interfaceType()).thenReturn(TETHERING_USB);
when(mEthernetIpServer.interfaceType()).thenReturn(TETHERING_ETHERNET);
when(mHotspotIpServer.interfaceType()).thenReturn(TETHERING_WIFI);
+ when(mLocalHotspotIpServer.interfaceType()).thenReturn(TETHERING_WIFI);
when(mWifiP2pIpServer.interfaceType()).thenReturn(TETHERING_WIFI_P2P);
}
@@ -104,9 +108,10 @@
mPrivateAddressCoordinator = spy(new PrivateAddressCoordinator(mContext, mConfig));
}
- private LinkAddress requestDownstreamAddress(final IpServer ipServer, boolean useLastAddress) {
+ private LinkAddress requestDownstreamAddress(final IpServer ipServer, int scope,
+ boolean useLastAddress) {
final LinkAddress address = mPrivateAddressCoordinator.requestDownstreamAddress(
- ipServer, useLastAddress);
+ ipServer, scope, useLastAddress);
when(ipServer.getAddress()).thenReturn(address);
return address;
}
@@ -115,19 +120,19 @@
public void testRequestDownstreamAddressWithoutUsingLastAddress() throws Exception {
final IpPrefix bluetoothPrefix = asIpPrefix(mBluetoothAddress);
final LinkAddress address = requestDownstreamAddress(mHotspotIpServer,
- false /* useLastAddress */);
+ CONNECTIVITY_SCOPE_GLOBAL, false /* useLastAddress */);
final IpPrefix hotspotPrefix = asIpPrefix(address);
assertNotEquals(hotspotPrefix, bluetoothPrefix);
final LinkAddress newAddress = requestDownstreamAddress(mHotspotIpServer,
- false /* useLastAddress */);
+ CONNECTIVITY_SCOPE_GLOBAL, false /* useLastAddress */);
final IpPrefix testDupRequest = asIpPrefix(newAddress);
assertNotEquals(hotspotPrefix, testDupRequest);
assertNotEquals(bluetoothPrefix, testDupRequest);
mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer);
final LinkAddress usbAddress = requestDownstreamAddress(mUsbIpServer,
- false /* useLastAddress */);
+ CONNECTIVITY_SCOPE_GLOBAL, false /* useLastAddress */);
final IpPrefix usbPrefix = asIpPrefix(usbAddress);
assertNotEquals(usbPrefix, bluetoothPrefix);
assertNotEquals(usbPrefix, hotspotPrefix);
@@ -139,25 +144,28 @@
int fakeSubAddr = 0x2b00; // 43.0.
when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(fakeSubAddr);
LinkAddress actualAddress = requestDownstreamAddress(mHotspotIpServer,
- false /* useLastAddress */);
+ CONNECTIVITY_SCOPE_GLOBAL, false /* useLastAddress */);
assertEquals(new LinkAddress("192.168.43.2/24"), actualAddress);
mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer);
fakeSubAddr = 0x2d01; // 45.1.
when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(fakeSubAddr);
- actualAddress = requestDownstreamAddress(mHotspotIpServer, false /* useLastAddress */);
+ actualAddress = requestDownstreamAddress(mHotspotIpServer,
+ CONNECTIVITY_SCOPE_GLOBAL, false /* useLastAddress */);
assertEquals(new LinkAddress("192.168.45.2/24"), actualAddress);
mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer);
fakeSubAddr = 0x2eff; // 46.255.
when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(fakeSubAddr);
- actualAddress = requestDownstreamAddress(mHotspotIpServer, false /* useLastAddress */);
+ actualAddress = requestDownstreamAddress(mHotspotIpServer,
+ CONNECTIVITY_SCOPE_GLOBAL, false /* useLastAddress */);
assertEquals(new LinkAddress("192.168.46.254/24"), actualAddress);
mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer);
fakeSubAddr = 0x2f05; // 47.5.
when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(fakeSubAddr);
- actualAddress = requestDownstreamAddress(mHotspotIpServer, false /* useLastAddress */);
+ actualAddress = requestDownstreamAddress(mHotspotIpServer,
+ CONNECTIVITY_SCOPE_GLOBAL, false /* useLastAddress */);
assertEquals(new LinkAddress("192.168.47.5/24"), actualAddress);
mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer);
}
@@ -168,7 +176,7 @@
when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(
getSubAddress(mBluetoothAddress.getAddress().getAddress()));
final LinkAddress hotspotAddress = requestDownstreamAddress(mHotspotIpServer,
- false /* useLastAddress */);
+ CONNECTIVITY_SCOPE_GLOBAL, false /* useLastAddress */);
final IpPrefix hotspotPrefix = asIpPrefix(hotspotAddress);
assertNotEquals(asIpPrefix(mBluetoothAddress), hotspotPrefix);
mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer);
@@ -177,7 +185,7 @@
when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(
getSubAddress(hotspotAddress.getAddress().getAddress()));
final LinkAddress usbAddress = requestDownstreamAddress(mUsbIpServer,
- false /* useLastAddress */);
+ CONNECTIVITY_SCOPE_GLOBAL, false /* useLastAddress */);
final IpPrefix usbPrefix = asIpPrefix(usbAddress);
assertNotEquals(asIpPrefix(mBluetoothAddress), usbPrefix);
assertNotEquals(hotspotPrefix, usbPrefix);
@@ -187,7 +195,7 @@
when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(
getSubAddress(mLegacyWifiP2pAddress.getAddress().getAddress()));
final LinkAddress etherAddress = requestDownstreamAddress(mEthernetIpServer,
- false /* useLastAddress */);
+ CONNECTIVITY_SCOPE_GLOBAL, false /* useLastAddress */);
final IpPrefix etherPrefix = asIpPrefix(etherAddress);
assertNotEquals(asIpPrefix(mLegacyWifiP2pAddress), etherPrefix);
assertNotEquals(asIpPrefix(mBluetoothAddress), etherPrefix);
@@ -200,11 +208,11 @@
final int fakeHotspotSubAddr = 0x2b05; // 43.5
when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(fakeHotspotSubAddr);
final LinkAddress hotspotAddress = requestDownstreamAddress(mHotspotIpServer,
- true /* useLastAddress */);
+ CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */);
assertEquals("Wrong wifi prefix: ", new LinkAddress("192.168.43.5/24"), hotspotAddress);
final LinkAddress usbAddress = requestDownstreamAddress(mUsbIpServer,
- true /* useLastAddress */);
+ CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */);
assertEquals("Wrong wifi prefix: ", new LinkAddress("192.168.45.5/24"), usbAddress);
mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer);
@@ -214,10 +222,10 @@
when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(fakeHotspotSubAddr);
final LinkAddress newHotspotAddress = requestDownstreamAddress(mHotspotIpServer,
- true /* useLastAddress */);
+ CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */);
assertEquals(hotspotAddress, newHotspotAddress);
final LinkAddress newUsbAddress = requestDownstreamAddress(mUsbIpServer,
- true /* useLastAddress */);
+ CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */);
assertEquals(usbAddress, newUsbAddress);
final UpstreamNetworkState wifiUpstream = buildUpstreamNetworkState(mWifiNetwork,
@@ -257,7 +265,7 @@
when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(fakeHotspotSubAddr);
// - Enable hotspot with prefix 192.168.43.0/24
final LinkAddress hotspotAddr = requestDownstreamAddress(mHotspotIpServer,
- true /* useLastAddress */);
+ CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */);
final IpPrefix hotspotPrefix = asIpPrefix(hotspotAddr);
assertEquals("Wrong wifi prefix: ", predefinedPrefix, hotspotPrefix);
// - test mobile network with null NetworkCapabilities. Ideally this should not happen
@@ -311,21 +319,21 @@
// - Restart hotspot again and its prefix is different previous.
mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer);
final LinkAddress hotspotAddr2 = requestDownstreamAddress(mHotspotIpServer,
- true /* useLastAddress */);
+ CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */);
final IpPrefix hotspotPrefix2 = asIpPrefix(hotspotAddr2);
assertNotEquals(hotspotPrefix, hotspotPrefix2);
mPrivateAddressCoordinator.updateUpstreamPrefix(v4OnlyWifi);
verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT);
// - Usb tethering can be enabled and its prefix is different with conflict one.
final LinkAddress usbAddr = requestDownstreamAddress(mUsbIpServer,
- true /* useLastAddress */);
+ CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */);
final IpPrefix usbPrefix = asIpPrefix(usbAddr);
assertNotEquals(predefinedPrefix, usbPrefix);
assertNotEquals(hotspotPrefix2, usbPrefix);
// - Disable wifi upstream, then wifi's prefix can be selected again.
mPrivateAddressCoordinator.removeUpstreamPrefix(mWifiNetwork);
final LinkAddress ethAddr = requestDownstreamAddress(mEthernetIpServer,
- true /* useLastAddress */);
+ CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */);
final IpPrefix ethPrefix = asIpPrefix(ethAddr);
assertEquals(predefinedPrefix, ethPrefix);
}
@@ -335,7 +343,7 @@
final int randomAddress = 0x8605; // 134.5
when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(randomAddress);
final LinkAddress addr0 = requestDownstreamAddress(mHotspotIpServer,
- true /* useLastAddress */);
+ CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */);
// Check whether return address is prefix 192.168.0.0/16 + subAddress 0.0.134.5.
assertEquals("Wrong prefix: ", new LinkAddress("192.168.134.5/24"), addr0);
final UpstreamNetworkState wifiUpstream = buildUpstreamNetworkState(mWifiNetwork,
@@ -345,7 +353,7 @@
// Check whether return address is next prefix of 192.168.134.0/24.
final LinkAddress addr1 = requestDownstreamAddress(mHotspotIpServer,
- true /* useLastAddress */);
+ CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */);
assertEquals("Wrong prefix: ", new LinkAddress("192.168.135.5/24"), addr1);
final UpstreamNetworkState wifiUpstream2 = buildUpstreamNetworkState(mWifiNetwork,
new LinkAddress("192.168.149.16/19"), null,
@@ -355,7 +363,7 @@
// The conflict range is 128 ~ 159, so the address is 192.168.160.5/24.
final LinkAddress addr2 = requestDownstreamAddress(mHotspotIpServer,
- true /* useLastAddress */);
+ CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */);
assertEquals("Wrong prefix: ", new LinkAddress("192.168.160.5/24"), addr2);
final UpstreamNetworkState mobileUpstream = buildUpstreamNetworkState(mMobileNetwork,
new LinkAddress("192.168.129.53/18"), null,
@@ -370,7 +378,7 @@
// The conflict range are 128 ~ 159 and 159 ~ 191, so the address is 192.168.192.5/24.
final LinkAddress addr3 = requestDownstreamAddress(mHotspotIpServer,
- true /* useLastAddress */);
+ CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */);
assertEquals("Wrong prefix: ", new LinkAddress("192.168.192.5/24"), addr3);
final UpstreamNetworkState mobileUpstream3 = buildUpstreamNetworkState(mMobileNetwork3,
new LinkAddress("192.168.188.133/17"), null,
@@ -380,7 +388,7 @@
// Conflict range: 128 ~ 255. The next available address is 192.168.0.5 because
// 192.168.134/24 ~ 192.168.255.255/24 is not available.
final LinkAddress addr4 = requestDownstreamAddress(mHotspotIpServer,
- true /* useLastAddress */);
+ CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */);
assertEquals("Wrong prefix: ", new LinkAddress("192.168.0.5/24"), addr4);
final UpstreamNetworkState mobileUpstream4 = buildUpstreamNetworkState(mMobileNetwork4,
new LinkAddress("192.168.3.59/21"), null,
@@ -389,7 +397,7 @@
// Conflict ranges: 128 ~ 255 and 0 ~ 7, so the address is 192.168.8.5/24.
final LinkAddress addr5 = requestDownstreamAddress(mHotspotIpServer,
- true /* useLastAddress */);
+ CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */);
assertEquals("Wrong prefix: ", new LinkAddress("192.168.8.5/24"), addr5);
final UpstreamNetworkState mobileUpstream5 = buildUpstreamNetworkState(mMobileNetwork5,
new LinkAddress("192.168.68.43/21"), null,
@@ -399,7 +407,7 @@
// Update an upstream that does *not* conflict, check whether return the same address
// 192.168.5/24.
final LinkAddress addr6 = requestDownstreamAddress(mHotspotIpServer,
- true /* useLastAddress */);
+ CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */);
assertEquals("Wrong prefix: ", new LinkAddress("192.168.8.5/24"), addr6);
final UpstreamNetworkState mobileUpstream6 = buildUpstreamNetworkState(mMobileNetwork6,
new LinkAddress("192.168.10.97/21"), null,
@@ -408,7 +416,7 @@
// Conflict ranges: 0 ~ 15 and 128 ~ 255, so the address is 192.168.16.5/24.
final LinkAddress addr7 = requestDownstreamAddress(mHotspotIpServer,
- true /* useLastAddress */);
+ CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */);
assertEquals("Wrong prefix: ", new LinkAddress("192.168.16.5/24"), addr7);
final UpstreamNetworkState mobileUpstream7 = buildUpstreamNetworkState(mMobileNetwork6,
new LinkAddress("192.168.0.0/17"), null,
@@ -417,7 +425,7 @@
// Choose prefix from next range(172.16.0.0/12) when no available prefix in 192.168.0.0/16.
final LinkAddress addr8 = requestDownstreamAddress(mHotspotIpServer,
- true /* useLastAddress */);
+ CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */);
assertEquals("Wrong prefix: ", new LinkAddress("172.16.134.5/24"), addr8);
}
@@ -426,7 +434,7 @@
final int randomAddress = 0x1f2b2a; // 31.43.42
when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(randomAddress);
final LinkAddress classC1 = requestDownstreamAddress(mHotspotIpServer,
- true /* useLastAddress */);
+ CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */);
// Check whether return address is prefix 192.168.0.0/16 + subAddress 0.0.43.42.
assertEquals("Wrong prefix: ", new LinkAddress("192.168.43.42/24"), classC1);
final UpstreamNetworkState wifiUpstream = buildUpstreamNetworkState(mWifiNetwork,
@@ -437,7 +445,7 @@
// Check whether return address is next address of prefix 192.168.128.0/17.
final LinkAddress classC2 = requestDownstreamAddress(mHotspotIpServer,
- true /* useLastAddress */);
+ CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */);
assertEquals("Wrong prefix: ", new LinkAddress("192.168.128.42/24"), classC2);
final UpstreamNetworkState mobileUpstream = buildUpstreamNetworkState(mMobileNetwork,
new LinkAddress("192.1.2.3/8"), null,
@@ -447,7 +455,7 @@
// Check whether return address is under prefix 172.16.0.0/12.
final LinkAddress classB1 = requestDownstreamAddress(mHotspotIpServer,
- true /* useLastAddress */);
+ CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */);
assertEquals("Wrong prefix: ", new LinkAddress("172.31.43.42/24"), classB1);
final UpstreamNetworkState mobileUpstream2 = buildUpstreamNetworkState(mMobileNetwork2,
new LinkAddress("172.28.123.100/14"), null,
@@ -458,12 +466,12 @@
// 172.28.0.0 ~ 172.31.255.255 is not available.
// Check whether return address is next address of prefix 172.16.0.0/14.
final LinkAddress classB2 = requestDownstreamAddress(mHotspotIpServer,
- true /* useLastAddress */);
+ CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */);
assertEquals("Wrong prefix: ", new LinkAddress("172.16.0.42/24"), classB2);
// Check whether new downstream is next address of address 172.16.0.42/24.
final LinkAddress classB3 = requestDownstreamAddress(mUsbIpServer,
- true /* useLastAddress */);
+ CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */);
assertEquals("Wrong prefix: ", new LinkAddress("172.16.1.42/24"), classB3);
final UpstreamNetworkState mobileUpstream3 = buildUpstreamNetworkState(mMobileNetwork3,
new LinkAddress("172.16.0.1/24"), null,
@@ -474,7 +482,7 @@
// Check whether return address is next address of prefix 172.16.1.42/24.
final LinkAddress classB4 = requestDownstreamAddress(mHotspotIpServer,
- true /* useLastAddress */);
+ CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */);
assertEquals("Wrong prefix: ", new LinkAddress("172.16.2.42/24"), classB4);
final UpstreamNetworkState mobileUpstream4 = buildUpstreamNetworkState(mMobileNetwork4,
new LinkAddress("172.16.0.1/13"), null,
@@ -485,11 +493,11 @@
// Check whether return address is next address of prefix 172.16.0.1/13.
final LinkAddress classB5 = requestDownstreamAddress(mHotspotIpServer,
- true /* useLastAddress */);
+ CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */);
assertEquals("Wrong prefix: ", new LinkAddress("172.24.0.42/24"), classB5);
// Check whether return address is next address of prefix 172.24.0.42/24.
final LinkAddress classB6 = requestDownstreamAddress(mUsbIpServer,
- true /* useLastAddress */);
+ CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */);
assertEquals("Wrong prefix: ", new LinkAddress("172.24.1.42/24"), classB6);
final UpstreamNetworkState mobileUpstream5 = buildUpstreamNetworkState(mMobileNetwork5,
new LinkAddress("172.24.0.1/12"), null,
@@ -500,11 +508,11 @@
// Check whether return address is prefix 10.0.0.0/8 + subAddress 0.31.43.42.
final LinkAddress classA1 = requestDownstreamAddress(mHotspotIpServer,
- true /* useLastAddress */);
+ CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */);
assertEquals("Wrong prefix: ", new LinkAddress("10.31.43.42/24"), classA1);
// Check whether new downstream is next address of address 10.31.43.42/24.
final LinkAddress classA2 = requestDownstreamAddress(mUsbIpServer,
- true /* useLastAddress */);
+ CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */);
assertEquals("Wrong prefix: ", new LinkAddress("10.31.44.42/24"), classA2);
}
@@ -524,7 +532,7 @@
private void assertReseveredWifiP2pPrefix() throws Exception {
LinkAddress address = requestDownstreamAddress(mHotspotIpServer,
- true /* useLastAddress */);
+ CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */);
final IpPrefix hotspotPrefix = asIpPrefix(address);
final IpPrefix legacyWifiP2pPrefix = asIpPrefix(mLegacyWifiP2pAddress);
assertNotEquals(legacyWifiP2pPrefix, hotspotPrefix);
@@ -544,8 +552,23 @@
// If #shouldEnableWifiP2pDedicatedIp() is enabled, wifi P2P gets the configured address.
LinkAddress address = requestDownstreamAddress(mWifiP2pIpServer,
- true /* useLastAddress */);
+ CONNECTIVITY_SCOPE_LOCAL, true /* useLastAddress */);
assertEquals(mLegacyWifiP2pAddress, address);
mPrivateAddressCoordinator.releaseDownstream(mWifiP2pIpServer);
}
+
+ @Test
+ public void testEnableSapAndLohsConcurrently() throws Exception {
+ // 0x2b05 -> 43.5, 0x8605 -> 134.5
+ when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(0x2b05, 0x8605);
+
+ final LinkAddress hotspotAddress = requestDownstreamAddress(mHotspotIpServer,
+ CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */);
+ assertEquals("Wrong hotspot prefix: ", new LinkAddress("192.168.43.5/24"), hotspotAddress);
+
+ final LinkAddress localHotspotAddress = requestDownstreamAddress(mLocalHotspotIpServer,
+ CONNECTIVITY_SCOPE_LOCAL, true /* useLastAddress */);
+ assertEquals("Wrong local hotspot prefix: ", new LinkAddress("192.168.134.5/24"),
+ localHotspotAddress);
+ }
}
diff --git a/service-t/src/com/android/server/NsdService.java b/service-t/src/com/android/server/NsdService.java
index 29a03d1..c47c572 100644
--- a/service-t/src/com/android/server/NsdService.java
+++ b/service-t/src/com/android/server/NsdService.java
@@ -73,7 +73,6 @@
import com.android.server.connectivity.mdns.MdnsSearchOptions;
import com.android.server.connectivity.mdns.MdnsServiceBrowserListener;
import com.android.server.connectivity.mdns.MdnsServiceInfo;
-import com.android.server.connectivity.mdns.MdnsSocketClientBase;
import com.android.server.connectivity.mdns.MdnsSocketProvider;
import com.android.server.connectivity.mdns.util.MdnsUtils;
@@ -1394,8 +1393,7 @@
mMdnsSocketClient =
new MdnsMultinetworkSocketClient(handler.getLooper(), mMdnsSocketProvider);
mMdnsDiscoveryManager = deps.makeMdnsDiscoveryManager(new ExecutorProvider(),
- mMdnsSocketClient, LOGGER.forSubComponent("MdnsDiscoveryManager"),
- handler.getLooper());
+ mMdnsSocketClient, LOGGER.forSubComponent("MdnsDiscoveryManager"));
handler.post(() -> mMdnsSocketClient.setCallback(mMdnsDiscoveryManager));
mAdvertiser = deps.makeMdnsAdvertiser(handler.getLooper(), mMdnsSocketProvider,
new AdvertiserCallback(), LOGGER.forSubComponent("MdnsAdvertiser"));
@@ -1453,9 +1451,8 @@
*/
public MdnsDiscoveryManager makeMdnsDiscoveryManager(
@NonNull ExecutorProvider executorProvider,
- @NonNull MdnsSocketClientBase socketClient, @NonNull SharedLog sharedLog,
- @NonNull Looper looper) {
- return new MdnsDiscoveryManager(executorProvider, socketClient, sharedLog, looper);
+ @NonNull MdnsMultinetworkSocketClient socketClient, @NonNull SharedLog sharedLog) {
+ return new MdnsDiscoveryManager(executorProvider, socketClient, sharedLog);
}
/**
diff --git a/service-t/src/com/android/server/connectivity/mdns/EnqueueMdnsQueryCallable.java b/service-t/src/com/android/server/connectivity/mdns/EnqueueMdnsQueryCallable.java
index 9a67007..866ecba 100644
--- a/service-t/src/com/android/server/connectivity/mdns/EnqueueMdnsQueryCallable.java
+++ b/service-t/src/com/android/server/connectivity/mdns/EnqueueMdnsQueryCallable.java
@@ -211,7 +211,7 @@
| (expectUnicastResponse ? MdnsConstants.QCLASS_UNICAST : 0));
}
- private void sendPacketTo(MdnsSocketClientBase requestSender, InetSocketAddress address)
+ private void sendPacketTo(MdnsSocketClient requestSender, InetSocketAddress address)
throws IOException {
DatagramPacket packet = packetWriter.getPacket(address);
if (expectUnicastResponse) {
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsDiscoveryManager.java b/service-t/src/com/android/server/connectivity/mdns/MdnsDiscoveryManager.java
index 0154827..0f30f10 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsDiscoveryManager.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsDiscoveryManager.java
@@ -17,8 +17,6 @@
package com.android.server.connectivity.mdns;
import static com.android.server.connectivity.mdns.util.MdnsUtils.ensureRunningOnHandlerThread;
-import static com.android.server.connectivity.mdns.util.MdnsUtils.isNetworkMatched;
-import static com.android.server.connectivity.mdns.util.MdnsUtils.isRunningOnHandlerThread;
import android.Manifest.permission;
import android.annotation.NonNull;
@@ -26,7 +24,7 @@
import android.annotation.RequiresPermission;
import android.net.Network;
import android.os.Handler;
-import android.os.Looper;
+import android.os.HandlerThread;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Pair;
@@ -38,6 +36,7 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
/**
* This class keeps tracking the set of registered {@link MdnsServiceBrowserListener} instances, and
@@ -53,6 +52,7 @@
@NonNull private final PerNetworkServiceTypeClients perNetworkServiceTypeClients;
@NonNull private final Handler handler;
+ @Nullable private final HandlerThread handlerThread;
private static class PerNetworkServiceTypeClients {
private final ArrayMap<Pair<String, Network>, MdnsServiceTypeClient> clients =
@@ -86,15 +86,12 @@
return list;
}
- public List<MdnsServiceTypeClient> getByMatchingNetwork(@Nullable Network network) {
+ public List<MdnsServiceTypeClient> getByNetwork(@Nullable Network network) {
final List<MdnsServiceTypeClient> list = new ArrayList<>();
for (int i = 0; i < clients.size(); i++) {
final Pair<String, Network> perNetworkServiceType = clients.keyAt(i);
final Network serviceTypeNetwork = perNetworkServiceType.second;
- // The serviceTypeNetwork would be null if the MdnsSocketClient is being used. This
- // is also the case if the socket is for a tethering interface. In either of these
- // cases, the client is expected to process any responses.
- if (serviceTypeNetwork == null || isNetworkMatched(network, serviceTypeNetwork)) {
+ if (Objects.equals(network, serviceTypeNetwork)) {
list.add(clients.valueAt(i));
}
}
@@ -112,17 +109,23 @@
}
public MdnsDiscoveryManager(@NonNull ExecutorProvider executorProvider,
- @NonNull MdnsSocketClientBase socketClient, @NonNull SharedLog sharedLog,
- @NonNull Looper looper) {
+ @NonNull MdnsSocketClientBase socketClient, @NonNull SharedLog sharedLog) {
this.executorProvider = executorProvider;
this.socketClient = socketClient;
this.sharedLog = sharedLog;
- perNetworkServiceTypeClients = new PerNetworkServiceTypeClients();
- handler = new Handler(looper);
+ this.perNetworkServiceTypeClients = new PerNetworkServiceTypeClients();
+ if (socketClient.getLooper() != null) {
+ this.handlerThread = null;
+ this.handler = new Handler(socketClient.getLooper());
+ } else {
+ this.handlerThread = new HandlerThread(MdnsDiscoveryManager.class.getSimpleName());
+ this.handlerThread.start();
+ this.handler = new Handler(handlerThread.getLooper());
+ }
}
private void checkAndRunOnHandlerThread(@NonNull Runnable function) {
- if (isRunningOnHandlerThread(handler)) {
+ if (this.handlerThread == null) {
function.run();
} else {
handler.post(function);
@@ -130,6 +133,15 @@
}
/**
+ * Do the cleanup of the MdnsDiscoveryManager
+ */
+ public void shutDown() {
+ if (this.handlerThread != null) {
+ this.handlerThread.quitSafely();
+ }
+ }
+
+ /**
* Starts (or continue) to discovery mDNS services with given {@code serviceType}, and registers
* {@code listener} for receiving mDNS service discovery responses.
*
@@ -239,7 +251,7 @@
private void handleOnResponseReceived(@NonNull MdnsPacket packet, int interfaceIndex,
@Nullable Network network) {
for (MdnsServiceTypeClient serviceTypeClient
- : perNetworkServiceTypeClients.getByMatchingNetwork(network)) {
+ : perNetworkServiceTypeClients.getByNetwork(network)) {
serviceTypeClient.processResponse(packet, interfaceIndex, network);
}
}
@@ -254,7 +266,7 @@
private void handleOnFailedToParseMdnsResponse(int receivedPacketNumber, int errorCode,
@Nullable Network network) {
for (MdnsServiceTypeClient serviceTypeClient
- : perNetworkServiceTypeClients.getByMatchingNetwork(network)) {
+ : perNetworkServiceTypeClients.getByNetwork(network)) {
serviceTypeClient.onFailedToParseMdnsResponse(receivedPacketNumber, errorCode);
}
}
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsMultinetworkSocketClient.java b/service-t/src/com/android/server/connectivity/mdns/MdnsMultinetworkSocketClient.java
index 52c8622..d9bfb26 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsMultinetworkSocketClient.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsMultinetworkSocketClient.java
@@ -17,7 +17,6 @@
package com.android.server.connectivity.mdns;
import static com.android.server.connectivity.mdns.util.MdnsUtils.ensureRunningOnHandlerThread;
-import static com.android.server.connectivity.mdns.util.MdnsUtils.isNetworkMatched;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -34,6 +33,7 @@
import java.net.Inet6Address;
import java.net.InetSocketAddress;
import java.util.List;
+import java.util.Objects;
/**
* The {@link MdnsMultinetworkSocketClient} manages the multinetwork socket for mDns
@@ -205,6 +205,11 @@
mSocketProvider.unrequestSocket(callback);
}
+ @Override
+ public Looper getLooper() {
+ return mHandler.getLooper();
+ }
+
private void sendMdnsPacket(@NonNull DatagramPacket packet, @Nullable Network targetNetwork) {
final boolean isIpv6 = ((InetSocketAddress) packet.getSocketAddress()).getAddress()
instanceof Inet6Address;
@@ -216,7 +221,10 @@
final Network network = activeSockets.valueAt(i);
// Check ip capability and network before sending packet
if (((isIpv6 && socket.hasJoinedIpv6()) || (isIpv4 && socket.hasJoinedIpv4()))
- && isNetworkMatched(targetNetwork, network)) {
+ // Contrary to MdnsUtils.isNetworkMatched, only send packets targeting
+ // the null network to interfaces that have the null network (tethering
+ // downstream interfaces).
+ && Objects.equals(network, targetNetwork)) {
try {
socket.send(packet);
} catch (IOException e) {
@@ -248,12 +256,6 @@
}
}
- /** Sends a mDNS request packet that asks for multicast response. */
- @Override
- public void sendMulticastPacket(@NonNull DatagramPacket packet) {
- sendMulticastPacket(packet, null /* network */);
- }
-
/**
* Sends a mDNS request packet via given network that asks for multicast response. Null network
* means sending packet via all networks.
@@ -263,12 +265,6 @@
mHandler.post(() -> sendMdnsPacket(packet, network));
}
- /** Sends a mDNS request packet that asks for unicast response. */
- @Override
- public void sendUnicastPacket(@NonNull DatagramPacket packet) {
- sendUnicastPacket(packet, null /* network */);
- }
-
/**
* Sends a mDNS request packet via given network that asks for unicast response. Null network
* means sending packet via all networks.
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsServiceTypeClient.java b/service-t/src/com/android/server/connectivity/mdns/MdnsServiceTypeClient.java
index e56bd5b..c2c0db2 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsServiceTypeClient.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsServiceTypeClient.java
@@ -201,7 +201,7 @@
searchOptions.getSubtypes(),
searchOptions.isPassiveMode(),
++currentSessionId,
- searchOptions.getNetwork());
+ network);
if (hadReply) {
requestTaskFuture = scheduleNextRunLocked(taskConfig);
} else {
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsSocketClient.java b/service-t/src/com/android/server/connectivity/mdns/MdnsSocketClient.java
index 783b18a..1144d16 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsSocketClient.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsSocketClient.java
@@ -195,13 +195,11 @@
}
/** Sends a mDNS request packet that asks for multicast response. */
- @Override
public void sendMulticastPacket(@NonNull DatagramPacket packet) {
sendMdnsPacket(packet, multicastPacketQueue);
}
/** Sends a mDNS request packet that asks for unicast response. */
- @Override
public void sendUnicastPacket(DatagramPacket packet) {
if (useSeparateSocketForUnicast) {
sendMdnsPacket(packet, unicastPacketQueue);
@@ -210,6 +208,36 @@
}
}
+ @Override
+ public void sendMulticastPacket(@NonNull DatagramPacket packet, @Nullable Network network) {
+ if (network != null) {
+ throw new IllegalArgumentException("This socket client does not support sending to "
+ + "specific networks");
+ }
+ sendMulticastPacket(packet);
+ }
+
+ @Override
+ public void sendUnicastPacket(@NonNull DatagramPacket packet, @Nullable Network network) {
+ if (network != null) {
+ throw new IllegalArgumentException("This socket client does not support sending to "
+ + "specific networks");
+ }
+ sendUnicastPacket(packet);
+ }
+
+ @Override
+ public void notifyNetworkRequested(
+ @NonNull MdnsServiceBrowserListener listener,
+ @Nullable Network network,
+ @NonNull SocketCreationCallback socketCreationCallback) {
+ if (network != null) {
+ throw new IllegalArgumentException("This socket client does not support requesting "
+ + "specific networks");
+ }
+ socketCreationCallback.onSocketCreated(null);
+ }
+
private void sendMdnsPacket(DatagramPacket packet, Queue<DatagramPacket> packetQueueToUse) {
if (shouldStopSocketLoop && !MdnsConfigs.allowAddMdnsPacketAfterDiscoveryStops()) {
LOGGER.w("sendMdnsPacket() is called after discovery already stopped");
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsSocketClientBase.java b/service-t/src/com/android/server/connectivity/mdns/MdnsSocketClientBase.java
index c614cd3..deadc58 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsSocketClientBase.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsSocketClientBase.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.net.Network;
+import android.os.Looper;
import java.io.IOException;
import java.net.DatagramPacket;
@@ -38,39 +39,34 @@
/*** Set callback for receiving mDns response */
void setCallback(@Nullable Callback callback);
- /*** Sends a mDNS request packet that asks for multicast response. */
- void sendMulticastPacket(@NonNull DatagramPacket packet);
+ /**
+ * Send a mDNS request packet via given network that asks for multicast response.
+ *
+ * <p>The socket client may use a null network to identify some or all interfaces, in which case
+ * passing null sends the packet to these.
+ */
+ void sendMulticastPacket(@NonNull DatagramPacket packet, @Nullable Network network);
/**
- * Sends a mDNS request packet via given network that asks for multicast response. Null network
- * means sending packet via all networks.
+ * Send a mDNS request packet via given network that asks for unicast response.
+ *
+ * <p>The socket client may use a null network to identify some or all interfaces, in which case
+ * passing null sends the packet to these.
*/
- default void sendMulticastPacket(@NonNull DatagramPacket packet, @Nullable Network network) {
- throw new UnsupportedOperationException(
- "This socket client doesn't support per-network sending");
- }
-
- /*** Sends a mDNS request packet that asks for unicast response. */
- void sendUnicastPacket(@NonNull DatagramPacket packet);
-
- /**
- * Sends a mDNS request packet via given network that asks for unicast response. Null network
- * means sending packet via all networks.
- */
- default void sendUnicastPacket(@NonNull DatagramPacket packet, @Nullable Network network) {
- throw new UnsupportedOperationException(
- "This socket client doesn't support per-network sending");
- }
+ void sendUnicastPacket(@NonNull DatagramPacket packet, @Nullable Network network);
/*** Notify that the given network is requested for mdns discovery / resolution */
- default void notifyNetworkRequested(@NonNull MdnsServiceBrowserListener listener,
- @Nullable Network network, @NonNull SocketCreationCallback socketCreationCallback) {
- socketCreationCallback.onSocketCreated(network);
- }
+ void notifyNetworkRequested(@NonNull MdnsServiceBrowserListener listener,
+ @Nullable Network network, @NonNull SocketCreationCallback socketCreationCallback);
/*** Notify that the network is unrequested */
default void notifyNetworkUnrequested(@NonNull MdnsServiceBrowserListener listener) { }
+ /*** Gets looper that used by the socket client */
+ default Looper getLooper() {
+ return null;
+ }
+
/*** Callback for mdns response */
interface Callback {
/*** Receive a mdns response */
diff --git a/service/libconnectivity/Android.bp b/service/libconnectivity/Android.bp
index 391ceac..e063af7 100644
--- a/service/libconnectivity/Android.bp
+++ b/service/libconnectivity/Android.bp
@@ -27,6 +27,7 @@
min_sdk_version: "30",
static_libs: [
"connectivity_native_aidl_interface-V1-ndk",
+ "libmodules-utils-build",
],
export_include_dirs: ["include"],
cflags: [
diff --git a/service/libconnectivity/src/connectivity_native.cpp b/service/libconnectivity/src/connectivity_native.cpp
index a476498..f39bb0a 100644
--- a/service/libconnectivity/src/connectivity_native.cpp
+++ b/service/libconnectivity/src/connectivity_native.cpp
@@ -17,6 +17,7 @@
#include "connectivity_native.h"
#include <android/binder_manager.h>
+#include <android-modules-utils/sdk_level.h>
#include <aidl/android/net/connectivity/aidl/ConnectivityNative.h>
using aidl::android::net::connectivity::aidl::IConnectivityNative;
@@ -44,6 +45,7 @@
}
int AConnectivityNative_blockPortForBind(in_port_t port) {
+ if (!android::modules::sdklevel::IsAtLeastU()) return ENOSYS;
std::shared_ptr<IConnectivityNative> c = getBinder();
if (!c) {
return EAGAIN;
@@ -52,6 +54,7 @@
}
int AConnectivityNative_unblockPortForBind(in_port_t port) {
+ if (!android::modules::sdklevel::IsAtLeastU()) return ENOSYS;
std::shared_ptr<IConnectivityNative> c = getBinder();
if (!c) {
return EAGAIN;
@@ -60,6 +63,7 @@
}
int AConnectivityNative_unblockAllPortsForBind() {
+ if (!android::modules::sdklevel::IsAtLeastU()) return ENOSYS;
std::shared_ptr<IConnectivityNative> c = getBinder();
if (!c) {
return EAGAIN;
@@ -68,6 +72,7 @@
}
int AConnectivityNative_getPortsBlockedForBind(in_port_t *ports, size_t *count) {
+ if (!android::modules::sdklevel::IsAtLeastU()) return ENOSYS;
std::shared_ptr<IConnectivityNative> c = getBinder();
if (!c) {
return EAGAIN;
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index f579093..98ad861 100755
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -109,7 +109,6 @@
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.ActivityManager;
import android.app.ActivityManager.UidFrozenStateChangedCallback;
@@ -1279,6 +1278,18 @@
return Binder.getCallingUid();
}
+ public boolean isAtLeastS() {
+ return SdkLevel.isAtLeastS();
+ }
+
+ public boolean isAtLeastT() {
+ return SdkLevel.isAtLeastT();
+ }
+
+ public boolean isAtLeastU() {
+ return SdkLevel.isAtLeastU();
+ }
+
/**
* Get system properties to use in ConnectivityService.
*/
@@ -1391,7 +1402,7 @@
@Nullable
public CarrierPrivilegeAuthenticator makeCarrierPrivilegeAuthenticator(
@NonNull final Context context, @NonNull final TelephonyManager tm) {
- if (SdkLevel.isAtLeastT()) {
+ if (isAtLeastT()) {
return new CarrierPrivilegeAuthenticator(context, tm);
} else {
return null;
@@ -1499,6 +1510,14 @@
}
/**
+ * As above but with a UID.
+ * @see CompatChanges#isChangeEnabled(long, int)
+ */
+ public boolean isChangeEnabled(final long changeId, final int uid) {
+ return CompatChanges.isChangeEnabled(changeId, uid);
+ }
+
+ /**
* Call {@link InetDiagMessage#destroyLiveTcpSockets(Set, Set)}
*
* @param ranges target uid ranges
@@ -1711,7 +1730,7 @@
// Even if it could, running on S would at least require mocking out the BPF map,
// otherwise the unit tests will fail on pre-T devices where the seccomp filter blocks
// the bpf syscall. http://aosp/1907693
- if (SdkLevel.isAtLeastT()) {
+ if (mDeps.isAtLeastT()) {
mDscpPolicyTracker = new DscpPolicyTracker();
}
} catch (ErrnoException e) {
@@ -1721,13 +1740,13 @@
mIngressRateLimit = ConnectivitySettingsManager.getIngressRateLimitInBytesPerSecond(
mContext);
- if (SdkLevel.isAtLeastT()) {
+ if (mDeps.isAtLeastT()) {
mCdmps = new CompanionDeviceManagerProxyService(context);
} else {
mCdmps = null;
}
- if (SdkLevel.isAtLeastU()
+ if (mDeps.isAtLeastU()
&& mDeps.isFeatureEnabled(context, KEY_DESTROY_FROZEN_SOCKETS_VERSION)) {
final UidFrozenStateChangedCallback frozenStateChangedCallback =
new UidFrozenStateChangedCallback() {
@@ -3195,8 +3214,6 @@
sendStickyBroadcast(makeGeneralIntent(info, bcastType));
}
- // TODO(b/193460475): Remove when tooling supports SystemApi to public API.
- @SuppressLint("NewApi")
// TODO: Set the mini sdk to 31 and remove @TargetApi annotation when b/205923322 is addressed.
@TargetApi(Build.VERSION_CODES.S)
private void sendStickyBroadcast(Intent intent) {
@@ -3232,7 +3249,7 @@
private void applyMostRecentPolicyForConnectivityAction(BroadcastOptions options,
NetworkInfo info) {
// Delivery group policy APIs are only available on U+.
- if (!SdkLevel.isAtLeastU()) return;
+ if (!mDeps.isAtLeastU()) return;
final BroadcastOptionsShim optsShim = mDeps.makeBroadcastOptionsShim(options);
try {
@@ -3310,7 +3327,7 @@
}
// On T+ devices, register callback for statsd to pull NETWORK_BPF_MAP_INFO atom
- if (SdkLevel.isAtLeastT()) {
+ if (mDeps.isAtLeastT()) {
mBpfNetMaps.setPullAtomCallback(mContext);
}
// Wait PermissionMonitor to finish the permission update. Then MultipathPolicyTracker won't
@@ -4520,7 +4537,7 @@
@VisibleForTesting
boolean shouldIgnoreValidationFailureAfterRoam(NetworkAgentInfo nai) {
// T+ devices should use unregisterAfterReplacement.
- if (SdkLevel.isAtLeastT()) return false;
+ if (mDeps.isAtLeastT()) return false;
// If the network never roamed, return false. The check below is not sufficient if time
// since boot is less than blockTimeOut, though that's extremely unlikely to happen.
@@ -4659,7 +4676,7 @@
// for an unnecessarily long time.
destroyNativeNetwork(nai);
}
- if (!nai.isCreated() && !SdkLevel.isAtLeastT()) {
+ if (!nai.isCreated() && !mDeps.isAtLeastT()) {
// Backwards compatibility: send onNetworkDestroyed even if network was never created.
// This can never run if the code above runs because shouldDestroyNativeNetwork is
// false if the network was never created.
@@ -4743,7 +4760,7 @@
}
private void checkNrisConsistency(final NetworkRequestInfo nri) {
- if (SdkLevel.isAtLeastT()) {
+ if (mDeps.isAtLeastT()) {
for (final NetworkRequestInfo n : mNetworkRequests.values()) {
if (n.mBinder != null && n.mBinder == nri.mBinder) {
// Temporary help to debug b/194394697 ; TODO : remove this function when the
@@ -6333,7 +6350,7 @@
+ Arrays.toString(ranges) + "): netd command failed: " + e);
}
- if (SdkLevel.isAtLeastT()) {
+ if (mDeps.isAtLeastT()) {
mPermissionMonitor.updateVpnLockdownUidRanges(requireVpn, ranges);
}
@@ -7127,7 +7144,7 @@
@NonNull final NetworkCapabilities networkCapabilities) {
// This check is added to fix the linter error for "current min is 30", which is not going
// to happen because Connectivity service always run in S+.
- if (!SdkLevel.isAtLeastS()) {
+ if (!mDeps.isAtLeastS()) {
Log.wtf(TAG, "Connectivity service should always run in at least SDK S");
return;
}
@@ -8564,7 +8581,7 @@
// On T and above, allow rules are needed for all VPNs. Allow rule with null iface is a
// wildcard to allow apps to receive packets on all interfaces. This is required to accept
// incoming traffic in Lockdown mode by overriding the Lockdown blocking rule.
- return SdkLevel.isAtLeastT() && nai.isVPN() && lp != null && lp.getInterfaceName() != null;
+ return mDeps.isAtLeastT() && nai.isVPN() && lp != null && lp.getInterfaceName() != null;
}
private static UidRangeParcel[] toUidRangeStableParcels(final @NonNull Set<UidRange> ranges) {
@@ -8807,21 +8824,19 @@
// else not handled
}
- // TODO(b/193460475): Remove when tooling supports SystemApi to public API.
- @SuppressLint("NewApi")
private void sendIntent(PendingIntent pendingIntent, Intent intent) {
mPendingIntentWakeLock.acquire();
try {
if (DBG) log("Sending " + pendingIntent);
final BroadcastOptions options = BroadcastOptions.makeBasic();
- if (SdkLevel.isAtLeastT()) {
+ if (mDeps.isAtLeastT()) {
// Explicitly disallow the receiver from starting activities, to prevent apps from
// utilizing the PendingIntent as a backdoor to do this.
options.setPendingIntentBackgroundActivityLaunchAllowed(false);
}
pendingIntent.send(mContext, 0, intent, this /* onFinished */, null /* Handler */,
null /* requiredPermission */,
- SdkLevel.isAtLeastT() ? options.toBundle() : null);
+ mDeps.isAtLeastT() ? options.toBundle() : null);
} catch (PendingIntent.CanceledException e) {
if (DBG) log(pendingIntent + " was not sent, it had been canceled.");
mPendingIntentWakeLock.release();
@@ -9100,7 +9115,7 @@
private void updateProfileAllowedNetworks() {
// Netd command is not implemented before U.
- if (!SdkLevel.isAtLeastU()) return;
+ if (!mDeps.isAtLeastU()) return;
ensureRunningOnConnectivityServiceThread();
final ArrayList<NativeUidRangeConfig> configs = new ArrayList<>();
@@ -9836,7 +9851,7 @@
// in the absence of a satisfactory, scalable solution which follows an easy/standard
// process to check the interface version, just use an SDK check. NetworkStack will
// always be new enough when running on T+.
- if (SdkLevel.isAtLeastT()) {
+ if (mDeps.isAtLeastT()) {
networkAgent.networkMonitor().notifyNetworkConnected(params);
} else {
networkAgent.networkMonitor().notifyNetworkConnected(params.linkProperties,
@@ -11312,7 +11327,7 @@
if (um.isManagedProfile(profile.getIdentifier())) {
return true;
}
- if (SdkLevel.isAtLeastT() && dpm.getDeviceOwner() != null) return true;
+ if (mDeps.isAtLeastT() && dpm.getDeviceOwner() != null) return true;
return false;
}
@@ -11594,7 +11609,7 @@
private boolean canNetworkBeRateLimited(@NonNull final NetworkAgentInfo networkAgent) {
// Rate-limiting cannot run correctly before T because the BPF program is not loaded.
- if (!SdkLevel.isAtLeastT()) return false;
+ if (!mDeps.isAtLeastT()) return false;
final NetworkCapabilities agentCaps = networkAgent.networkCapabilities;
// Only test networks (they cannot hold NET_CAPABILITY_INTERNET) and networks that provide
@@ -12101,7 +12116,7 @@
throw new IllegalStateException(e);
}
- if (SdkLevel.isAtLeastU() && enable) {
+ if (mDeps.isAtLeastU() && enable) {
try {
closeSocketsForFirewallChainLocked(chain);
} catch (ErrnoException | SocketException | InterruptedIOException e) {
diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
index e434649..904e4bd 100755
--- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
@@ -167,6 +167,7 @@
import static com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
import static com.android.testutils.DevSdkIgnoreRuleKt.SC_V2;
import static com.android.testutils.FunctionalUtils.ignoreExceptions;
+import static com.android.testutils.HandlerUtils.visibleOnHandlerThread;
import static com.android.testutils.HandlerUtils.waitForIdleSerialExecutor;
import static com.android.testutils.MiscAsserts.assertContainsAll;
import static com.android.testutils.MiscAsserts.assertContainsExactly;
@@ -376,7 +377,6 @@
import com.android.internal.util.WakeupMessage;
import com.android.internal.util.test.BroadcastInterceptingContext;
import com.android.internal.util.test.FakeSettingsProvider;
-import com.android.modules.utils.build.SdkLevel;
import com.android.net.module.util.ArrayTrackRecord;
import com.android.net.module.util.CollectionUtils;
import com.android.net.module.util.LocationPermissionChecker;
@@ -869,7 +869,7 @@
@Override
public void sendStickyBroadcast(Intent intent, Bundle options) {
// Verify that delivery group policy APIs were used on U.
- if (SdkLevel.isAtLeastU() && CONNECTIVITY_ACTION.equals(intent.getAction())) {
+ if (mDeps.isAtLeastU() && CONNECTIVITY_ACTION.equals(intent.getAction())) {
final NetworkInfo ni = intent.getParcelableExtra(EXTRA_NETWORK_INFO,
NetworkInfo.class);
try {
@@ -1085,7 +1085,7 @@
}
private void onValidationRequested() throws Exception {
- if (SdkLevel.isAtLeastT()) {
+ if (mDeps.isAtLeastT()) {
verify(mNetworkMonitor).notifyNetworkConnectedParcel(any());
} else {
verify(mNetworkMonitor).notifyNetworkConnected(any(), any());
@@ -1932,6 +1932,7 @@
class ConnectivityServiceDependencies extends ConnectivityService.Dependencies {
final ConnectivityResources mConnRes;
+ final ArraySet<Pair<Long, Integer>> mEnabledChangeIds = new ArraySet<>();
ConnectivityServiceDependencies(final Context mockResContext) {
mConnRes = new ConnectivityResources(mockResContext);
@@ -1997,7 +1998,7 @@
@Override
public CarrierPrivilegeAuthenticator makeCarrierPrivilegeAuthenticator(
@NonNull final Context context, @NonNull final TelephonyManager tm) {
- return SdkLevel.isAtLeastT() ? mCarrierPrivilegeAuthenticator : null;
+ return mDeps.isAtLeastT() ? mCarrierPrivilegeAuthenticator : null;
}
@Override
@@ -2096,6 +2097,61 @@
}
}
+ public void setChangeIdEnabled(final boolean enabled, final long changeId, final int uid) {
+ final Pair<Long, Integer> data = new Pair<>(changeId, uid);
+ // mEnabledChangeIds is read on the handler thread and maybe the test thread, so
+ // make sure both threads see it before continuing.
+ visibleOnHandlerThread(mCsHandlerThread.getThreadHandler(), () -> {
+ if (enabled) {
+ mEnabledChangeIds.add(data);
+ } else {
+ mEnabledChangeIds.remove(data);
+ }
+ });
+ }
+
+ @Override
+ public boolean isChangeEnabled(final long changeId, final int uid) {
+ return mEnabledChangeIds.contains(new Pair<>(changeId, uid));
+ }
+
+ // In AOSP, build version codes are all over the place (e.g. at the time of this writing
+ // U == V). Define custom ones.
+ private static final int VERSION_UNMOCKED = -1;
+ private static final int VERSION_R = 1;
+ private static final int VERSION_S = 2;
+ private static final int VERSION_T = 3;
+ private static final int VERSION_U = 4;
+ private static final int VERSION_V = 5;
+ private static final int VERSION_MAX = VERSION_V;
+ private int mSdkLevel = VERSION_UNMOCKED;
+
+ private void setBuildSdk(final int sdkLevel) {
+ if (sdkLevel > VERSION_MAX) {
+ throw new IllegalArgumentException("setBuildSdk must not be called with"
+ + " Build.VERSION constants but Dependencies.VERSION_* constants");
+ }
+ visibleOnHandlerThread(mCsHandlerThread.getThreadHandler(), () -> mSdkLevel = sdkLevel);
+ }
+
+ @Override
+ public boolean isAtLeastS() {
+ return mSdkLevel == VERSION_UNMOCKED ? super.isAtLeastS()
+ : mSdkLevel >= VERSION_S;
+ }
+
+ @Override
+ public boolean isAtLeastT() {
+ return mSdkLevel == VERSION_UNMOCKED ? super.isAtLeastT()
+ : mSdkLevel >= VERSION_T;
+ }
+
+ @Override
+ public boolean isAtLeastU() {
+ return mSdkLevel == VERSION_UNMOCKED ? super.isAtLeastU()
+ : mSdkLevel >= VERSION_U;
+ }
+
@Override
public BpfNetMaps getBpfNetMaps(Context context, INetd netd) {
return mBpfNetMaps;
@@ -5933,7 +5989,7 @@
doReturn(0).when(mResources).getInteger(R.integer.config_activelyPreferBadWifi);
mPolicyTracker.reevaluate();
waitForIdle();
- if (SdkLevel.isAtLeastU()) {
+ if (mDeps.isAtLeastU()) {
// U+ ignore the setting and always actively prefers bad wifi
assertTrue(mService.mNetworkRanker.getConfiguration().activelyPreferBadWifi());
} else {
@@ -6103,7 +6159,7 @@
@Test
public void testPreferBadWifi_doNotAvoid_doNotPrefer() throws Exception {
// Starting with U this mode is no longer supported and can't actually be tested
- assumeFalse(SdkLevel.isAtLeastU());
+ assumeFalse(mDeps.isAtLeastU());
doTestPreferBadWifi(false /* avoidBadWifi */, false /* preferBadWifi */,
timeout -> timeout < 14_000);
}
@@ -9772,7 +9828,7 @@
final Set<Integer> excludedUids = new ArraySet<Integer>();
excludedUids.add(VPN_UID);
- if (SdkLevel.isAtLeastT()) {
+ if (mDeps.isAtLeastT()) {
// On T onwards, the corresponding SDK sandbox UID should also be excluded
excludedUids.add(toSdkSandboxUid(VPN_UID));
}
@@ -9820,7 +9876,7 @@
vpnDefaultCallbackAsUid.assertNoCallback();
excludedUids.add(uid);
- if (SdkLevel.isAtLeastT()) {
+ if (mDeps.isAtLeastT()) {
// On T onwards, the corresponding SDK sandbox UID should also be excluded
excludedUids.add(toSdkSandboxUid(uid));
}
@@ -10554,7 +10610,7 @@
private void verifyClatdStart(@Nullable InOrder inOrder, @NonNull String iface, int netId,
@NonNull String nat64Prefix) throws Exception {
- if (SdkLevel.isAtLeastT()) {
+ if (mDeps.isAtLeastT()) {
verifyWithOrder(inOrder, mClatCoordinator)
.clatStart(eq(iface), eq(netId), eq(new IpPrefix(nat64Prefix)));
} else {
@@ -10564,7 +10620,7 @@
private void verifyNeverClatdStart(@Nullable InOrder inOrder, @NonNull String iface)
throws Exception {
- if (SdkLevel.isAtLeastT()) {
+ if (mDeps.isAtLeastT()) {
verifyNeverWithOrder(inOrder, mClatCoordinator).clatStart(eq(iface), anyInt(), any());
} else {
verifyNeverWithOrder(inOrder, mMockNetd).clatdStart(eq(iface), anyString());
@@ -10573,7 +10629,7 @@
private void verifyClatdStop(@Nullable InOrder inOrder, @NonNull String iface)
throws Exception {
- if (SdkLevel.isAtLeastT()) {
+ if (mDeps.isAtLeastT()) {
verifyWithOrder(inOrder, mClatCoordinator).clatStop();
} else {
verifyWithOrder(inOrder, mMockNetd).clatdStop(eq(iface));
@@ -10582,7 +10638,7 @@
private void verifyNeverClatdStop(@Nullable InOrder inOrder, @NonNull String iface)
throws Exception {
- if (SdkLevel.isAtLeastT()) {
+ if (mDeps.isAtLeastT()) {
verifyNeverWithOrder(inOrder, mClatCoordinator).clatStop();
} else {
verifyNeverWithOrder(inOrder, mMockNetd).clatdStop(eq(iface));
@@ -10775,7 +10831,7 @@
networkCallback.assertNoCallback();
verify(mMockNetd, times(1)).networkRemoveInterface(cellNetId, CLAT_MOBILE_IFNAME);
- if (SdkLevel.isAtLeastU()) {
+ if (mDeps.isAtLeastU()) {
verifyWakeupModifyInterface(CLAT_MOBILE_IFNAME, false);
}
@@ -10815,7 +10871,7 @@
assertRoutesAdded(cellNetId, stackedDefault);
verify(mMockNetd, times(1)).networkAddInterface(cellNetId, CLAT_MOBILE_IFNAME);
- if (SdkLevel.isAtLeastU()) {
+ if (mDeps.isAtLeastU()) {
verifyWakeupModifyInterface(CLAT_MOBILE_IFNAME, true);
}
@@ -10834,7 +10890,7 @@
verify(mMockNetd, times(1)).networkRemoveInterface(cellNetId, CLAT_MOBILE_IFNAME);
verify(mMockNetd, times(1)).interfaceGetCfg(CLAT_MOBILE_IFNAME);
- if (SdkLevel.isAtLeastU()) {
+ if (mDeps.isAtLeastU()) {
verifyWakeupModifyInterface(CLAT_MOBILE_IFNAME, false);
}
@@ -10845,13 +10901,13 @@
verify(mMockNetd, times(1)).idletimerRemoveInterface(eq(MOBILE_IFNAME), anyInt(),
eq(Integer.toString(TRANSPORT_CELLULAR)));
verify(mMockNetd).networkDestroy(cellNetId);
- if (SdkLevel.isAtLeastU()) {
+ if (mDeps.isAtLeastU()) {
verify(mMockNetd).setNetworkAllowlist(any());
} else {
verify(mMockNetd, never()).setNetworkAllowlist(any());
}
- if (SdkLevel.isAtLeastU()) {
+ if (mDeps.isAtLeastU()) {
verifyWakeupModifyInterface(MOBILE_IFNAME, false);
}
@@ -10885,7 +10941,7 @@
// assertRoutesAdded sees all calls since last mMockNetd reset, so expect IPv6 routes again.
assertRoutesAdded(cellNetId, ipv6Subnet, ipv6Default, stackedDefault);
- if (SdkLevel.isAtLeastU()) {
+ if (mDeps.isAtLeastU()) {
verifyWakeupModifyInterface(MOBILE_IFNAME, true);
}
@@ -10898,20 +10954,20 @@
networkCallback.assertNoCallback();
verifyClatdStop(null /* inOrder */, MOBILE_IFNAME);
- if (SdkLevel.isAtLeastU()) {
+ if (mDeps.isAtLeastU()) {
verifyWakeupModifyInterface(CLAT_MOBILE_IFNAME, false);
}
verify(mMockNetd).idletimerRemoveInterface(eq(MOBILE_IFNAME), anyInt(),
eq(Integer.toString(TRANSPORT_CELLULAR)));
verify(mMockNetd).networkDestroy(cellNetId);
- if (SdkLevel.isAtLeastU()) {
+ if (mDeps.isAtLeastU()) {
verify(mMockNetd).setNetworkAllowlist(any());
} else {
verify(mMockNetd, never()).setNetworkAllowlist(any());
}
- if (SdkLevel.isAtLeastU()) {
+ if (mDeps.isAtLeastU()) {
verifyWakeupModifyInterface(MOBILE_IFNAME, false);
}
@@ -11352,7 +11408,7 @@
mMockVpn.establish(lp, uid, vpnRange);
assertVpnUidRangesUpdated(true, vpnRange, uid);
- if (SdkLevel.isAtLeastT()) {
+ if (mDeps.isAtLeastT()) {
// On T and above, VPN should have rules for null interface. Null Interface is a
// wildcard and this accepts traffic from all the interfaces.
// There are two expected invocations, one during the VPN initial
@@ -12341,7 +12397,7 @@
@Test
public void testUnderlyingNetworksWillBeSetInNetworkAgentInfoConstructor() throws Exception {
- assumeTrue(SdkLevel.isAtLeastT());
+ assumeTrue(mDeps.isAtLeastT());
final Network network1 = new Network(100);
final Network network2 = new Network(101);
final List<Network> underlyingNetworks = new ArrayList<>();
@@ -16234,7 +16290,7 @@
mCellAgent.getNetwork().netId,
toUidRangeStableParcels(allowedRanges),
0 /* subPriority */);
- if (SdkLevel.isAtLeastU()) {
+ if (mDeps.isAtLeastU()) {
inOrder.verify(mMockNetd).setNetworkAllowlist(new NativeUidRangeConfig[]{config1User});
} else {
inOrder.verify(mMockNetd, never()).setNetworkAllowlist(any());
@@ -16252,7 +16308,7 @@
mCellAgent.getNetwork().netId,
toUidRangeStableParcels(allowedRanges),
0 /* subPriority */);
- if (SdkLevel.isAtLeastU()) {
+ if (mDeps.isAtLeastU()) {
inOrder.verify(mMockNetd).setNetworkAllowlist(new NativeUidRangeConfig[]{config2Users});
} else {
inOrder.verify(mMockNetd, never()).setNetworkAllowlist(any());
@@ -16283,7 +16339,7 @@
mCellAgent.getNetwork().netId,
allowAllUidRangesParcel,
0 /* subPriority */);
- if (SdkLevel.isAtLeastU()) {
+ if (mDeps.isAtLeastU()) {
inOrder.verify(mMockNetd).setNetworkAllowlist(
new NativeUidRangeConfig[]{cellAllAllowedConfig});
} else {
@@ -16302,7 +16358,7 @@
// making the order of the list undeterministic. Thus, verify this in order insensitive way.
final ArgumentCaptor<NativeUidRangeConfig[]> configsCaptor = ArgumentCaptor.forClass(
NativeUidRangeConfig[].class);
- if (SdkLevel.isAtLeastU()) {
+ if (mDeps.isAtLeastU()) {
inOrder.verify(mMockNetd).setNetworkAllowlist(configsCaptor.capture());
assertContainsAll(List.of(configsCaptor.getValue()),
List.of(cellAllAllowedConfig, enterpriseAllAllowedConfig));
@@ -16336,7 +16392,7 @@
mCellAgent.getNetwork().netId,
excludeAppRangesParcel,
0 /* subPriority */);
- if (SdkLevel.isAtLeastU()) {
+ if (mDeps.isAtLeastU()) {
inOrder.verify(mMockNetd).setNetworkAllowlist(configsCaptor.capture());
assertContainsAll(List.of(configsCaptor.getValue()),
List.of(cellExcludeAppConfig, enterpriseAllAllowedConfig));
@@ -16348,7 +16404,7 @@
mCm.setProfileNetworkPreference(testHandle, PROFILE_NETWORK_PREFERENCE_ENTERPRISE,
r -> r.run(), listener);
listener.expectOnComplete();
- if (SdkLevel.isAtLeastU()) {
+ if (mDeps.isAtLeastU()) {
inOrder.verify(mMockNetd).setNetworkAllowlist(configsCaptor.capture());
assertContainsAll(List.of(configsCaptor.getValue()),
List.of(cellAllAllowedConfig, enterpriseAllAllowedConfig));
@@ -16360,7 +16416,7 @@
// disconnects.
enterpriseAgent.disconnect();
waitForIdle();
- if (SdkLevel.isAtLeastU()) {
+ if (mDeps.isAtLeastU()) {
inOrder.verify(mMockNetd).setNetworkAllowlist(
new NativeUidRangeConfig[]{cellAllAllowedConfig});
} else {
@@ -16385,7 +16441,7 @@
List.of(prefBuilder.build()),
r -> r.run(), listener);
listener.expectOnComplete();
- if (SdkLevel.isAtLeastU()) {
+ if (mDeps.isAtLeastU()) {
inOrder.verify(mMockNetd).setNetworkAllowlist(new NativeUidRangeConfig[]{});
} else {
inOrder.verify(mMockNetd, never()).setNetworkAllowlist(any());
@@ -16413,7 +16469,7 @@
mCellAgent.getNetwork().netId,
excludeAppRangesParcel,
0 /* subPriority */);
- if (SdkLevel.isAtLeastU()) {
+ if (mDeps.isAtLeastU()) {
inOrder.verify(mMockNetd).setNetworkAllowlist(
new NativeUidRangeConfig[]{cellExcludeAppConfig});
} else {
@@ -16437,7 +16493,7 @@
// making the order of the list undeterministic. Thus, verify this in order insensitive way.
final ArgumentCaptor<NativeUidRangeConfig[]> configsCaptor = ArgumentCaptor.forClass(
NativeUidRangeConfig[].class);
- if (SdkLevel.isAtLeastU()) {
+ if (mDeps.isAtLeastU()) {
inOrder.verify(mMockNetd).setNetworkAllowlist(configsCaptor.capture());
assertContainsAll(List.of(configsCaptor.getValue()),
List.of(enterpriseAllAllowedConfig, cellExcludeAppConfig));
@@ -16448,7 +16504,7 @@
// Verify issuing with cellular set only when enterprise network disconnects.
enterpriseAgent.disconnect();
waitForIdle();
- if (SdkLevel.isAtLeastU()) {
+ if (mDeps.isAtLeastU()) {
inOrder.verify(mMockNetd).setNetworkAllowlist(
new NativeUidRangeConfig[]{cellExcludeAppConfig});
} else {
@@ -16457,7 +16513,7 @@
mCellAgent.disconnect();
waitForIdle();
- if (SdkLevel.isAtLeastU()) {
+ if (mDeps.isAtLeastU()) {
inOrder.verify(mMockNetd).setNetworkAllowlist(new NativeUidRangeConfig[]{});
} else {
inOrder.verify(mMockNetd, never()).setNetworkAllowlist(any());
@@ -16513,7 +16569,7 @@
profileNetworkPreferenceBuilder.setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE);
profileNetworkPreferenceBuilder.setPreferenceEnterpriseId(NET_ENTERPRISE_ID_1);
final TestOnCompleteListener listener = new TestOnCompleteListener();
- if (SdkLevel.isAtLeastT()) {
+ if (mDeps.isAtLeastT()) {
mCm.setProfileNetworkPreferences(testHandle,
List.of(profileNetworkPreferenceBuilder.build()),
r -> r.run(), listener);
@@ -16621,7 +16677,7 @@
agent.getNetwork().getNetId(),
intToUidRangeStableParcels(uids),
preferenceOrder);
- if (SdkLevel.isAtLeastT()) {
+ if (mDeps.isAtLeastT()) {
inOrder.verify(mMockNetd, times(1)).networkAddUidRangesParcel(uids200Parcel);
}
@@ -16629,7 +16685,7 @@
uids.add(400);
nc.setAllowedUids(uids);
agent.setNetworkCapabilities(nc, true /* sendToConnectivityService */);
- if (SdkLevel.isAtLeastT()) {
+ if (mDeps.isAtLeastT()) {
cb.expectCaps(agent, c -> c.getAllowedUids().equals(uids));
} else {
cb.assertNoCallback();
@@ -16640,13 +16696,13 @@
agent.getNetwork().getNetId(),
intToUidRangeStableParcels(uids),
preferenceOrder);
- if (SdkLevel.isAtLeastT()) {
+ if (mDeps.isAtLeastT()) {
inOrder.verify(mMockNetd, times(1)).networkAddUidRangesParcel(uids300400Parcel);
}
nc.setAllowedUids(uids);
agent.setNetworkCapabilities(nc, true /* sendToConnectivityService */);
- if (SdkLevel.isAtLeastT()) {
+ if (mDeps.isAtLeastT()) {
cb.expectCaps(agent, c -> c.getAllowedUids().equals(uids));
inOrder.verify(mMockNetd, times(1)).networkRemoveUidRangesParcel(uids200Parcel);
} else {
@@ -16657,7 +16713,7 @@
uids.add(600);
nc.setAllowedUids(uids);
agent.setNetworkCapabilities(nc, true /* sendToConnectivityService */);
- if (SdkLevel.isAtLeastT()) {
+ if (mDeps.isAtLeastT()) {
cb.expectCaps(agent, c -> c.getAllowedUids().equals(uids));
} else {
cb.assertNoCallback();
@@ -16666,7 +16722,7 @@
agent.getNetwork().getNetId(),
intToUidRangeStableParcels(uids),
preferenceOrder);
- if (SdkLevel.isAtLeastT()) {
+ if (mDeps.isAtLeastT()) {
inOrder.verify(mMockNetd, times(1)).networkAddUidRangesParcel(uids600Parcel);
inOrder.verify(mMockNetd, times(1)).networkRemoveUidRangesParcel(uids300400Parcel);
}
@@ -16674,7 +16730,7 @@
uids.clear();
nc.setAllowedUids(uids);
agent.setNetworkCapabilities(nc, true /* sendToConnectivityService */);
- if (SdkLevel.isAtLeastT()) {
+ if (mDeps.isAtLeastT()) {
cb.expectCaps(agent, c -> c.getAllowedUids().isEmpty());
inOrder.verify(mMockNetd, times(1)).networkRemoveUidRangesParcel(uids600Parcel);
} else {
@@ -16727,7 +16783,7 @@
// Cell gets to set the service UID as access UID
ncb.setAllowedUids(serviceUidSet);
mEthernetAgent.setNetworkCapabilities(ncb.build(), true /* sendToCS */);
- if (SdkLevel.isAtLeastT() && hasAutomotiveFeature) {
+ if (mDeps.isAtLeastT() && hasAutomotiveFeature) {
cb.expectCaps(mEthernetAgent, c -> c.getAllowedUids().equals(serviceUidSet));
} else {
// S and no automotive feature must ignore access UIDs.
@@ -16780,7 +16836,7 @@
cb.expectAvailableThenValidatedCallbacks(mCellAgent);
ncb.setAllowedUids(serviceUidSet);
mCellAgent.setNetworkCapabilities(ncb.build(), true /* sendToCS */);
- if (SdkLevel.isAtLeastT()) {
+ if (mDeps.isAtLeastT()) {
cb.expectCaps(mCellAgent, c -> c.getAllowedUids().equals(serviceUidSet));
} else {
// S must ignore access UIDs.
@@ -16790,7 +16846,7 @@
// ...but not to some other UID. Rejection sets UIDs to the empty set
ncb.setAllowedUids(nonServiceUidSet);
mCellAgent.setNetworkCapabilities(ncb.build(), true /* sendToCS */);
- if (SdkLevel.isAtLeastT()) {
+ if (mDeps.isAtLeastT()) {
cb.expectCaps(mCellAgent, c -> c.getAllowedUids().isEmpty());
} else {
// S must ignore access UIDs.
@@ -17712,14 +17768,14 @@
@Test
public void testIgnoreValidationAfterRoamEnabled() throws Exception {
- final boolean enabled = !SdkLevel.isAtLeastT();
+ final boolean enabled = !mDeps.isAtLeastT();
doTestIgnoreValidationAfterRoam(5_000, enabled);
}
@Test
public void testShouldIgnoreValidationFailureAfterRoam() {
// Always disabled on T+.
- assumeFalse(SdkLevel.isAtLeastT());
+ assumeFalse(mDeps.isAtLeastT());
NetworkAgentInfo nai = fakeWifiNai(new NetworkCapabilities());
@@ -17973,7 +18029,7 @@
mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp);
mCellAgent.connect(false /* validated */);
- if (SdkLevel.isAtLeastU()) {
+ if (mDeps.isAtLeastU()) {
final String expectedPrefix = makeNflogPrefix(MOBILE_IFNAME,
mCellAgent.getNetwork().getNetworkHandle());
verify(mMockNetd).wakeupAddInterface(MOBILE_IFNAME, expectedPrefix, PACKET_WAKEUP_MARK,
diff --git a/tests/unit/java/com/android/server/NsdServiceTest.java b/tests/unit/java/com/android/server/NsdServiceTest.java
index 955be12..1997215 100644
--- a/tests/unit/java/com/android/server/NsdServiceTest.java
+++ b/tests/unit/java/com/android/server/NsdServiceTest.java
@@ -179,7 +179,7 @@
anyInt(), anyString(), anyString(), anyString(), anyInt());
doReturn(false).when(mDeps).isMdnsDiscoveryManagerEnabled(any(Context.class));
doReturn(mDiscoveryManager).when(mDeps)
- .makeMdnsDiscoveryManager(any(), any(), any(), any());
+ .makeMdnsDiscoveryManager(any(), any(), any());
doReturn(mSocketProvider).when(mDeps).makeMdnsSocketProvider(any(), any(), any());
doReturn(mAdvertiser).when(mDeps).makeMdnsAdvertiser(any(), any(), any(), any());
mService = makeService();
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsDiscoveryManagerTests.java b/tests/unit/java/com/android/server/connectivity/mdns/MdnsDiscoveryManagerTests.java
index 89776e2..aeaca06 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsDiscoveryManagerTests.java
+++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsDiscoveryManagerTests.java
@@ -18,6 +18,9 @@
import static com.android.testutils.DevSdkIgnoreRuleKt.SC_V2;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
@@ -62,21 +65,24 @@
private static final String SERVICE_TYPE_2 = "_test._tcp.local";
private static final Network NETWORK_1 = Mockito.mock(Network.class);
private static final Network NETWORK_2 = Mockito.mock(Network.class);
- private static final Pair<String, Network> PER_NETWORK_SERVICE_TYPE_1 =
+ private static final Pair<String, Network> PER_NETWORK_SERVICE_TYPE_1_NULL_NETWORK =
Pair.create(SERVICE_TYPE_1, null);
- private static final Pair<String, Network> PER_NETWORK_SERVICE_TYPE_1_1 =
+ private static final Pair<String, Network> PER_NETWORK_SERVICE_TYPE_1_NETWORK_1 =
Pair.create(SERVICE_TYPE_1, NETWORK_1);
- private static final Pair<String, Network> PER_NETWORK_SERVICE_TYPE_2 =
+ private static final Pair<String, Network> PER_NETWORK_SERVICE_TYPE_2_NULL_NETWORK =
Pair.create(SERVICE_TYPE_2, null);
- private static final Pair<String, Network> PER_NETWORK_SERVICE_TYPE_2_2 =
+ private static final Pair<String, Network> PER_NETWORK_SERVICE_TYPE_2_NETWORK_1 =
+ Pair.create(SERVICE_TYPE_2, NETWORK_1);
+ private static final Pair<String, Network> PER_NETWORK_SERVICE_TYPE_2_NETWORK_2 =
Pair.create(SERVICE_TYPE_2, NETWORK_2);
@Mock private ExecutorProvider executorProvider;
@Mock private MdnsSocketClientBase socketClient;
- @Mock private MdnsServiceTypeClient mockServiceTypeClientOne;
- @Mock private MdnsServiceTypeClient mockServiceTypeClientOne1;
- @Mock private MdnsServiceTypeClient mockServiceTypeClientTwo;
- @Mock private MdnsServiceTypeClient mockServiceTypeClientTwo2;
+ @Mock private MdnsServiceTypeClient mockServiceTypeClientType1NullNetwork;
+ @Mock private MdnsServiceTypeClient mockServiceTypeClientType1Network1;
+ @Mock private MdnsServiceTypeClient mockServiceTypeClientType2NullNetwork;
+ @Mock private MdnsServiceTypeClient mockServiceTypeClientType2Network1;
+ @Mock private MdnsServiceTypeClient mockServiceTypeClientType2Network2;
@Mock MdnsServiceBrowserListener mockListenerOne;
@Mock MdnsServiceBrowserListener mockListenerTwo;
@@ -92,21 +98,28 @@
thread = new HandlerThread("MdnsDiscoveryManagerTests");
thread.start();
handler = new Handler(thread.getLooper());
- discoveryManager = new MdnsDiscoveryManager(executorProvider, socketClient, sharedLog,
- thread.getLooper()) {
+ doReturn(thread.getLooper()).when(socketClient).getLooper();
+ discoveryManager = new MdnsDiscoveryManager(executorProvider, socketClient,
+ sharedLog) {
@Override
MdnsServiceTypeClient createServiceTypeClient(@NonNull String serviceType,
@Nullable Network network) {
final Pair<String, Network> perNetworkServiceType =
Pair.create(serviceType, network);
- if (perNetworkServiceType.equals(PER_NETWORK_SERVICE_TYPE_1)) {
- return mockServiceTypeClientOne;
- } else if (perNetworkServiceType.equals(PER_NETWORK_SERVICE_TYPE_1_1)) {
- return mockServiceTypeClientOne1;
- } else if (perNetworkServiceType.equals(PER_NETWORK_SERVICE_TYPE_2)) {
- return mockServiceTypeClientTwo;
- } else if (perNetworkServiceType.equals(PER_NETWORK_SERVICE_TYPE_2_2)) {
- return mockServiceTypeClientTwo2;
+ if (perNetworkServiceType.equals(PER_NETWORK_SERVICE_TYPE_1_NULL_NETWORK)) {
+ return mockServiceTypeClientType1NullNetwork;
+ } else if (perNetworkServiceType.equals(
+ PER_NETWORK_SERVICE_TYPE_1_NETWORK_1)) {
+ return mockServiceTypeClientType1Network1;
+ } else if (perNetworkServiceType.equals(
+ PER_NETWORK_SERVICE_TYPE_2_NULL_NETWORK)) {
+ return mockServiceTypeClientType2NullNetwork;
+ } else if (perNetworkServiceType.equals(
+ PER_NETWORK_SERVICE_TYPE_2_NETWORK_1)) {
+ return mockServiceTypeClientType2Network1;
+ } else if (perNetworkServiceType.equals(
+ PER_NETWORK_SERVICE_TYPE_2_NETWORK_2)) {
+ return mockServiceTypeClientType2Network2;
}
return null;
}
@@ -143,11 +156,12 @@
final SocketCreationCallback callback = expectSocketCreationCallback(
SERVICE_TYPE_1, mockListenerOne, options);
runOnHandler(() -> callback.onSocketCreated(null /* network */));
- verify(mockServiceTypeClientOne).startSendAndReceive(mockListenerOne, options);
+ verify(mockServiceTypeClientType1NullNetwork).startSendAndReceive(mockListenerOne, options);
- when(mockServiceTypeClientOne.stopSendAndReceive(mockListenerOne)).thenReturn(true);
+ when(mockServiceTypeClientType1NullNetwork.stopSendAndReceive(mockListenerOne))
+ .thenReturn(true);
runOnHandler(() -> discoveryManager.unregisterListener(SERVICE_TYPE_1, mockListenerOne));
- verify(mockServiceTypeClientOne).stopSendAndReceive(mockListenerOne);
+ verify(mockServiceTypeClientType1NullNetwork).stopSendAndReceive(mockListenerOne);
verify(socketClient).stopDiscovery();
}
@@ -158,16 +172,16 @@
final SocketCreationCallback callback = expectSocketCreationCallback(
SERVICE_TYPE_1, mockListenerOne, options);
runOnHandler(() -> callback.onSocketCreated(null /* network */));
- verify(mockServiceTypeClientOne).startSendAndReceive(mockListenerOne, options);
+ verify(mockServiceTypeClientType1NullNetwork).startSendAndReceive(mockListenerOne, options);
runOnHandler(() -> callback.onSocketCreated(NETWORK_1));
- verify(mockServiceTypeClientOne1).startSendAndReceive(mockListenerOne, options);
+ verify(mockServiceTypeClientType1Network1).startSendAndReceive(mockListenerOne, options);
final SocketCreationCallback callback2 = expectSocketCreationCallback(
SERVICE_TYPE_2, mockListenerTwo, options);
runOnHandler(() -> callback2.onSocketCreated(null /* network */));
- verify(mockServiceTypeClientTwo).startSendAndReceive(mockListenerTwo, options);
+ verify(mockServiceTypeClientType2NullNetwork).startSendAndReceive(mockListenerTwo, options);
runOnHandler(() -> callback2.onSocketCreated(NETWORK_2));
- verify(mockServiceTypeClientTwo2).startSendAndReceive(mockListenerTwo, options);
+ verify(mockServiceTypeClientType2Network2).startSendAndReceive(mockListenerTwo, options);
}
@Test
@@ -177,103 +191,106 @@
final SocketCreationCallback callback = expectSocketCreationCallback(
SERVICE_TYPE_1, mockListenerOne, options1);
runOnHandler(() -> callback.onSocketCreated(null /* network */));
- verify(mockServiceTypeClientOne).startSendAndReceive(mockListenerOne, options1);
+ verify(mockServiceTypeClientType1NullNetwork).startSendAndReceive(
+ mockListenerOne, options1);
runOnHandler(() -> callback.onSocketCreated(NETWORK_1));
- verify(mockServiceTypeClientOne1).startSendAndReceive(mockListenerOne, options1);
+ verify(mockServiceTypeClientType1Network1).startSendAndReceive(mockListenerOne, options1);
final MdnsSearchOptions options2 =
MdnsSearchOptions.newBuilder().setNetwork(NETWORK_2).build();
final SocketCreationCallback callback2 = expectSocketCreationCallback(
SERVICE_TYPE_2, mockListenerTwo, options2);
runOnHandler(() -> callback2.onSocketCreated(NETWORK_2));
- verify(mockServiceTypeClientTwo2).startSendAndReceive(mockListenerTwo, options2);
+ verify(mockServiceTypeClientType2Network2).startSendAndReceive(mockListenerTwo, options2);
final MdnsPacket responseForServiceTypeOne = createMdnsPacket(SERVICE_TYPE_1);
final int ifIndex = 1;
runOnHandler(() -> discoveryManager.onResponseReceived(
responseForServiceTypeOne, ifIndex, null /* network */));
- verify(mockServiceTypeClientOne).processResponse(responseForServiceTypeOne, ifIndex,
- null /* network */);
- verify(mockServiceTypeClientOne1).processResponse(responseForServiceTypeOne, ifIndex,
- null /* network */);
- verify(mockServiceTypeClientTwo2).processResponse(responseForServiceTypeOne, ifIndex,
- null /* network */);
+ // Packets for network null are only processed by the ServiceTypeClient for network null
+ verify(mockServiceTypeClientType1NullNetwork).processResponse(responseForServiceTypeOne,
+ ifIndex, null /* network */);
+ verify(mockServiceTypeClientType1Network1, never()).processResponse(any(), anyInt(), any());
+ verify(mockServiceTypeClientType2Network2, never()).processResponse(any(), anyInt(), any());
final MdnsPacket responseForServiceTypeTwo = createMdnsPacket(SERVICE_TYPE_2);
runOnHandler(() -> discoveryManager.onResponseReceived(
responseForServiceTypeTwo, ifIndex, NETWORK_1));
- verify(mockServiceTypeClientOne).processResponse(responseForServiceTypeTwo, ifIndex,
- NETWORK_1);
- verify(mockServiceTypeClientOne1).processResponse(responseForServiceTypeTwo, ifIndex,
- NETWORK_1);
- verify(mockServiceTypeClientTwo2, never()).processResponse(responseForServiceTypeTwo,
+ verify(mockServiceTypeClientType1NullNetwork, never()).processResponse(any(), anyInt(),
+ eq(NETWORK_1));
+ verify(mockServiceTypeClientType1Network1).processResponse(responseForServiceTypeTwo,
ifIndex, NETWORK_1);
+ verify(mockServiceTypeClientType2Network2, never()).processResponse(any(), anyInt(),
+ eq(NETWORK_1));
final MdnsPacket responseForSubtype =
createMdnsPacket("subtype._sub._googlecast._tcp.local");
runOnHandler(() -> discoveryManager.onResponseReceived(
responseForSubtype, ifIndex, NETWORK_2));
- verify(mockServiceTypeClientOne).processResponse(responseForSubtype, ifIndex, NETWORK_2);
- verify(mockServiceTypeClientOne1, never()).processResponse(
+ verify(mockServiceTypeClientType1NullNetwork, never()).processResponse(
+ any(), anyInt(), eq(NETWORK_2));
+ verify(mockServiceTypeClientType1Network1, never()).processResponse(
+ any(), anyInt(), eq(NETWORK_2));
+ verify(mockServiceTypeClientType2Network2).processResponse(
responseForSubtype, ifIndex, NETWORK_2);
- verify(mockServiceTypeClientTwo2).processResponse(responseForSubtype, ifIndex, NETWORK_2);
}
@Test
public void testSocketCreatedAndDestroyed() throws IOException {
// Create a ServiceTypeClient for SERVICE_TYPE_1 and NETWORK_1
- final MdnsSearchOptions options1 =
+ final MdnsSearchOptions network1Options =
MdnsSearchOptions.newBuilder().setNetwork(NETWORK_1).build();
final SocketCreationCallback callback = expectSocketCreationCallback(
- SERVICE_TYPE_1, mockListenerOne, options1);
+ SERVICE_TYPE_1, mockListenerOne, network1Options);
runOnHandler(() -> callback.onSocketCreated(NETWORK_1));
- verify(mockServiceTypeClientOne1).startSendAndReceive(mockListenerOne, options1);
+ verify(mockServiceTypeClientType1Network1).startSendAndReceive(
+ mockListenerOne, network1Options);
- // Create a ServiceTypeClient for SERVICE_TYPE_2 and NETWORK_2
- final MdnsSearchOptions options2 =
- MdnsSearchOptions.newBuilder().setNetwork(NETWORK_2).build();
+ // Create a ServiceTypeClient for SERVICE_TYPE_2 and NETWORK_1
final SocketCreationCallback callback2 = expectSocketCreationCallback(
- SERVICE_TYPE_2, mockListenerTwo, options2);
- runOnHandler(() -> callback2.onSocketCreated(NETWORK_2));
- verify(mockServiceTypeClientTwo2).startSendAndReceive(mockListenerTwo, options2);
+ SERVICE_TYPE_2, mockListenerTwo, network1Options);
+ runOnHandler(() -> callback2.onSocketCreated(NETWORK_1));
+ verify(mockServiceTypeClientType2Network1).startSendAndReceive(
+ mockListenerTwo, network1Options);
// Receive a response, it should be processed on both clients.
final MdnsPacket response = createMdnsPacket(SERVICE_TYPE_1);
final int ifIndex = 1;
runOnHandler(() -> discoveryManager.onResponseReceived(
- response, ifIndex, null /* network */));
- verify(mockServiceTypeClientOne1).processResponse(response, ifIndex, null /* network */);
- verify(mockServiceTypeClientTwo2).processResponse(response, ifIndex, null /* network */);
+ response, ifIndex, NETWORK_1));
+ verify(mockServiceTypeClientType1Network1).processResponse(response, ifIndex, NETWORK_1);
+ verify(mockServiceTypeClientType2Network1).processResponse(response, ifIndex, NETWORK_1);
- // The client for NETWORK_1 receives the callback that the NETWORK_1 has been destroyed,
+ // The first callback receives a notification that the network has been destroyed,
// mockServiceTypeClientOne1 should send service removed notifications and remove from the
// list of clients.
runOnHandler(() -> callback.onAllSocketsDestroyed(NETWORK_1));
- verify(mockServiceTypeClientOne1).notifySocketDestroyed();
+ verify(mockServiceTypeClientType1Network1).notifySocketDestroyed();
- // Receive a response again, it should be processed only on mockServiceTypeClientTwo2.
- // Because the mockServiceTypeClientOne1 is removed from the list of clients, it is no
- // longer able to process responses.
+ // Receive a response again, it should be processed only on
+ // mockServiceTypeClientType2Network1. Because the mockServiceTypeClientType1Network1 is
+ // removed from the list of clients, it is no longer able to process responses.
runOnHandler(() -> discoveryManager.onResponseReceived(
- response, ifIndex, null /* network */));
- verify(mockServiceTypeClientOne1, times(1))
- .processResponse(response, ifIndex, null /* network */);
- verify(mockServiceTypeClientTwo2, times(2))
- .processResponse(response, ifIndex, null /* network */);
+ response, ifIndex, NETWORK_1));
+ // Still times(1) as a response was received once previously
+ verify(mockServiceTypeClientType1Network1, times(1))
+ .processResponse(response, ifIndex, NETWORK_1);
+ verify(mockServiceTypeClientType2Network1, times(2))
+ .processResponse(response, ifIndex, NETWORK_1);
- // The client for NETWORK_2 receives the callback that the NETWORK_1 has been destroyed,
+ // The client for NETWORK_1 receives the callback that the NETWORK_2 has been destroyed,
// mockServiceTypeClientTwo2 shouldn't send any notifications.
- runOnHandler(() -> callback2.onAllSocketsDestroyed(NETWORK_1));
- verify(mockServiceTypeClientTwo2, never()).notifySocketDestroyed();
+ runOnHandler(() -> callback2.onAllSocketsDestroyed(NETWORK_2));
+ verify(mockServiceTypeClientType2Network1, never()).notifySocketDestroyed();
- // Receive a response again, mockServiceTypeClientTwo2 is still in the list of clients, it's
- // still able to process responses.
+ // Receive a response again, mockServiceTypeClientType2Network1 is still in the list of
+ // clients, it's still able to process responses.
runOnHandler(() -> discoveryManager.onResponseReceived(
- response, ifIndex, null /* network */));
- verify(mockServiceTypeClientOne1, times(1))
- .processResponse(response, ifIndex, null /* network */);
- verify(mockServiceTypeClientTwo2, times(3))
- .processResponse(response, ifIndex, null /* network */);
+ response, ifIndex, NETWORK_1));
+ verify(mockServiceTypeClientType1Network1, times(1))
+ .processResponse(response, ifIndex, NETWORK_1);
+ verify(mockServiceTypeClientType2Network1, times(3))
+ .processResponse(response, ifIndex, NETWORK_1);
}
private MdnsPacket createMdnsPacket(String serviceType) {
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsMultinetworkSocketClientTest.java b/tests/unit/java/com/android/server/connectivity/mdns/MdnsMultinetworkSocketClientTest.java
index c6137c6..87ba5d7 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsMultinetworkSocketClientTest.java
+++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsMultinetworkSocketClientTest.java
@@ -38,6 +38,7 @@
import android.os.HandlerThread;
import com.android.net.module.util.HexDump;
+import com.android.server.connectivity.mdns.MdnsSocketClientBase.SocketCreationCallback;
import com.android.testutils.DevSdkIgnoreRule;
import com.android.testutils.DevSdkIgnoreRunner;
import com.android.testutils.HandlerUtils;
@@ -66,7 +67,7 @@
@Mock private MdnsInterfaceSocket mSocket;
@Mock private MdnsServiceBrowserListener mListener;
@Mock private MdnsSocketClientBase.Callback mCallback;
- @Mock private MdnsSocketClientBase.SocketCreationCallback mSocketCreationCallback;
+ @Mock private SocketCreationCallback mSocketCreationCallback;
private MdnsMultinetworkSocketClient mSocketClient;
private Handler mHandler;
@@ -113,22 +114,36 @@
InetAddresses.parseNumericAddress("192.0.2.1"), 0 /* port */);
final DatagramPacket ipv6Packet = new DatagramPacket(BUFFER, 0 /* offset */, BUFFER.length,
InetAddresses.parseNumericAddress("2001:db8::"), 0 /* port */);
- doReturn(true).when(mSocket).hasJoinedIpv4();
- doReturn(true).when(mSocket).hasJoinedIpv6();
- doReturn(createEmptyNetworkInterface()).when(mSocket).getInterface();
+
+ final MdnsInterfaceSocket tetherIfaceSock1 = mock(MdnsInterfaceSocket.class);
+ final MdnsInterfaceSocket tetherIfaceSock2 = mock(MdnsInterfaceSocket.class);
+ for (MdnsInterfaceSocket socket : List.of(mSocket, tetherIfaceSock1, tetherIfaceSock2)) {
+ doReturn(true).when(socket).hasJoinedIpv4();
+ doReturn(true).when(socket).hasJoinedIpv6();
+ doReturn(createEmptyNetworkInterface()).when(socket).getInterface();
+ }
+
// Notify socket created
callback.onSocketCreated(mNetwork, mSocket, List.of());
verify(mSocketCreationCallback).onSocketCreated(mNetwork);
+ callback.onSocketCreated(null, tetherIfaceSock1, List.of());
+ verify(mSocketCreationCallback).onSocketCreated(null);
+ callback.onSocketCreated(null, tetherIfaceSock2, List.of());
+ verify(mSocketCreationCallback, times(2)).onSocketCreated(null);
// Send packet to IPv4 with target network and verify sending has been called.
mSocketClient.sendMulticastPacket(ipv4Packet, mNetwork);
HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
verify(mSocket).send(ipv4Packet);
+ verify(tetherIfaceSock1, never()).send(any());
+ verify(tetherIfaceSock2, never()).send(any());
// Send packet to IPv6 without target network and verify sending has been called.
- mSocketClient.sendMulticastPacket(ipv6Packet);
+ mSocketClient.sendMulticastPacket(ipv6Packet, null);
HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
- verify(mSocket).send(ipv6Packet);
+ verify(mSocket, never()).send(ipv6Packet);
+ verify(tetherIfaceSock1).send(ipv6Packet);
+ verify(tetherIfaceSock2).send(ipv6Packet);
}
@Test
@@ -181,61 +196,86 @@
@Test
public void testSocketRemovedAfterNetworkUnrequested() throws IOException {
- // Request a socket
- final SocketCallback callback = expectSocketCallback(mListener, mNetwork);
+ // Request sockets on all networks
+ final SocketCallback callback = expectSocketCallback(mListener, null);
final DatagramPacket ipv4Packet = new DatagramPacket(BUFFER, 0 /* offset */, BUFFER.length,
InetAddresses.parseNumericAddress("192.0.2.1"), 0 /* port */);
+
+ // Notify 3 socket created, including 2 tethered interfaces (null network)
+ final MdnsInterfaceSocket socket2 = mock(MdnsInterfaceSocket.class);
+ final MdnsInterfaceSocket socket3 = mock(MdnsInterfaceSocket.class);
doReturn(true).when(mSocket).hasJoinedIpv4();
doReturn(true).when(mSocket).hasJoinedIpv6();
- doReturn(createEmptyNetworkInterface()).when(mSocket).getInterface();
- // Notify socket created
- callback.onSocketCreated(mNetwork, mSocket, List.of());
- verify(mSocketCreationCallback).onSocketCreated(mNetwork);
-
- // Send IPv4 packet and verify sending has been called.
- mSocketClient.sendMulticastPacket(ipv4Packet);
- HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
- verify(mSocket).send(ipv4Packet);
-
- // Request another socket with null network
- final MdnsServiceBrowserListener listener2 = mock(MdnsServiceBrowserListener.class);
- final Network network2 = mock(Network.class);
- final MdnsInterfaceSocket socket2 = mock(MdnsInterfaceSocket.class);
- final SocketCallback callback2 = expectSocketCallback(listener2, null);
doReturn(true).when(socket2).hasJoinedIpv4();
doReturn(true).when(socket2).hasJoinedIpv6();
+ doReturn(true).when(socket3).hasJoinedIpv4();
+ doReturn(true).when(socket3).hasJoinedIpv6();
+ doReturn(createEmptyNetworkInterface()).when(mSocket).getInterface();
doReturn(createEmptyNetworkInterface()).when(socket2).getInterface();
- // Notify socket created for two networks.
- callback2.onSocketCreated(mNetwork, mSocket, List.of());
- callback2.onSocketCreated(network2, socket2, List.of());
- verify(mSocketCreationCallback, times(2)).onSocketCreated(mNetwork);
- verify(mSocketCreationCallback).onSocketCreated(network2);
+ doReturn(createEmptyNetworkInterface()).when(socket3).getInterface();
- // Send IPv4 packet and verify sending to two sockets.
- mSocketClient.sendMulticastPacket(ipv4Packet);
+ callback.onSocketCreated(mNetwork, mSocket, List.of());
+ callback.onSocketCreated(null, socket2, List.of());
+ callback.onSocketCreated(null, socket3, List.of());
+ verify(mSocketCreationCallback).onSocketCreated(mNetwork);
+ verify(mSocketCreationCallback, times(2)).onSocketCreated(null);
+
+ // Send IPv4 packet on the non-null Network and verify sending has been called.
+ mSocketClient.sendMulticastPacket(ipv4Packet, mNetwork);
HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
- verify(mSocket, times(2)).send(ipv4Packet);
- verify(socket2).send(ipv4Packet);
+ verify(mSocket).send(ipv4Packet);
+ verify(socket2, never()).send(any());
+ verify(socket3, never()).send(any());
- // Unrequest another socket
+ // Request another socket with null network, get the same interfaces
+ final SocketCreationCallback socketCreationCb2 = mock(SocketCreationCallback.class);
+ final MdnsServiceBrowserListener listener2 = mock(MdnsServiceBrowserListener.class);
+
+ // requestSocket is called a second time
+ final ArgumentCaptor<SocketCallback> callback2Captor =
+ ArgumentCaptor.forClass(SocketCallback.class);
+ mHandler.post(() -> mSocketClient.notifyNetworkRequested(
+ listener2, null, socketCreationCb2));
+ HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
+ verify(mProvider, times(2)).requestSocket(eq(null), callback2Captor.capture());
+ final SocketCallback callback2 = callback2Captor.getAllValues().get(1);
+
+ // Notify socket created for all networks.
+ callback2.onSocketCreated(mNetwork, mSocket, List.of());
+ callback2.onSocketCreated(null, socket2, List.of());
+ callback2.onSocketCreated(null, socket3, List.of());
+ verify(socketCreationCb2).onSocketCreated(mNetwork);
+ verify(socketCreationCb2, times(2)).onSocketCreated(null);
+
+ // Send IPv4 packet to null network and verify sending to the 2 tethered interface sockets.
+ mSocketClient.sendMulticastPacket(ipv4Packet, null);
+ HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
+ // ipv4Packet still sent only once on mSocket: times(1) matches the packet sent earlier on
+ // mNetwork
+ verify(mSocket, times(1)).send(ipv4Packet);
+ verify(socket2).send(ipv4Packet);
+ verify(socket3).send(ipv4Packet);
+
+ // Unregister the second request
mHandler.post(() -> mSocketClient.notifyNetworkUnrequested(listener2));
verify(mProvider, timeout(DEFAULT_TIMEOUT)).unrequestSocket(callback2);
- // Send IPv4 packet again and verify only sending via mSocket
- mSocketClient.sendMulticastPacket(ipv4Packet);
+ // Send IPv4 packet again and verify it's still sent a second time
+ mSocketClient.sendMulticastPacket(ipv4Packet, null);
HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
- verify(mSocket, times(3)).send(ipv4Packet);
- verify(socket2).send(ipv4Packet);
+ verify(socket2, times(2)).send(ipv4Packet);
+ verify(socket3, times(2)).send(ipv4Packet);
- // Unrequest remaining socket
+ // Unrequest remaining sockets
mHandler.post(() -> mSocketClient.notifyNetworkUnrequested(mListener));
verify(mProvider, timeout(DEFAULT_TIMEOUT)).unrequestSocket(callback);
// Send IPv4 packet and verify no more sending.
- mSocketClient.sendMulticastPacket(ipv4Packet);
+ mSocketClient.sendMulticastPacket(ipv4Packet, null);
HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
- verify(mSocket, times(3)).send(ipv4Packet);
- verify(socket2).send(ipv4Packet);
+ verify(mSocket, times(1)).send(ipv4Packet);
+ verify(socket2, times(2)).send(ipv4Packet);
+ verify(socket3, times(2)).send(ipv4Packet);
}
@Test
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsServiceTypeClientTests.java b/tests/unit/java/com/android/server/connectivity/mdns/MdnsServiceTypeClientTests.java
index 42d296b..f15e8ff 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsServiceTypeClientTests.java
+++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsServiceTypeClientTests.java
@@ -952,7 +952,7 @@
currentThreadExecutor.getAndClearLastScheduledRunnable().run();
// Send twice for IPv4 and IPv6
inOrder.verify(mockSocketClient, times(2)).sendUnicastPacket(srvTxtQueryCaptor.capture(),
- eq(null) /* network */);
+ eq(mockNetwork));
final MdnsPacket srvTxtQueryPacket = MdnsPacket.parse(
new MdnsPacketReader(srvTxtQueryCaptor.getValue()));
@@ -987,7 +987,7 @@
ArgumentCaptor.forClass(DatagramPacket.class);
currentThreadExecutor.getAndClearLastScheduledRunnable().run();
inOrder.verify(mockSocketClient, times(2)).sendMulticastPacket(addressQueryCaptor.capture(),
- eq(null) /* network */);
+ eq(mockNetwork));
final MdnsPacket addressQueryPacket = MdnsPacket.parse(
new MdnsPacketReader(addressQueryCaptor.getValue()));
@@ -1255,17 +1255,17 @@
currentThreadExecutor.getAndClearLastScheduledRunnable().run();
if (expectsUnicastResponse) {
verify(mockSocketClient).sendUnicastPacket(
- expectedIPv4Packets[index], null /* network */);
+ expectedIPv4Packets[index], mockNetwork);
if (multipleSocketDiscovery) {
verify(mockSocketClient).sendUnicastPacket(
- expectedIPv6Packets[index], null /* network */);
+ expectedIPv6Packets[index], mockNetwork);
}
} else {
verify(mockSocketClient).sendMulticastPacket(
- expectedIPv4Packets[index], null /* network */);
+ expectedIPv4Packets[index], mockNetwork);
if (multipleSocketDiscovery) {
verify(mockSocketClient).sendMulticastPacket(
- expectedIPv6Packets[index], null /* network */);
+ expectedIPv6Packets[index], mockNetwork);
}
}
}