Merge "Fix test flake in MdnsDiscoveryManagerTests" into main
diff --git a/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
index f123dca..0ac97f0 100644
--- a/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
+++ b/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
@@ -333,6 +333,11 @@
public static final int TETHER_ERROR_UNKNOWN_REQUEST = 17;
@FlaggedApi(Flags.FLAG_TETHERING_WITH_SOFT_AP_CONFIG)
public static final int TETHER_ERROR_DUPLICATE_REQUEST = 18;
+ /**
+ * Never used outside Tethering.java.
+ * @hide
+ */
+ public static final int TETHER_ERROR_BLUETOOTH_SERVICE_PENDING = 19;
/** @hide */
@Retention(RetentionPolicy.SOURCE)
diff --git a/Tethering/src/com/android/networkstack/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java
index 1249e85..b50831d 100644
--- a/Tethering/src/com/android/networkstack/tethering/Tethering.java
+++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java
@@ -43,6 +43,7 @@
import static android.net.TetheringManager.TETHERING_WIFI;
import static android.net.TetheringManager.TETHERING_WIFI_P2P;
import static android.net.TetheringManager.TETHERING_WIGIG;
+import static android.net.TetheringManager.TETHER_ERROR_BLUETOOTH_SERVICE_PENDING;
import static android.net.TetheringManager.TETHER_ERROR_INTERNAL_ERROR;
import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR;
import static android.net.TetheringManager.TETHER_ERROR_SERVICE_UNAVAIL;
@@ -132,7 +133,6 @@
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
-import android.util.Pair;
import android.util.SparseArray;
import androidx.annotation.NonNull;
@@ -292,7 +292,7 @@
private SettingsObserver mSettingsObserver;
private BluetoothPan mBluetoothPan;
private PanServiceListener mBluetoothPanListener;
- private ArrayList<Pair<Boolean, IIntResultListener>> mPendingPanRequests;
+ private final ArrayList<IIntResultListener> mPendingPanRequestListeners;
// AIDL doesn't support Set<Integer>. Maintain a int bitmap here. When the bitmap is passed to
// TetheringManager, TetheringManager would convert it to a set of Integer types.
// mSupportedTypeBitmap should always be updated inside tethering internal thread but it may be
@@ -312,7 +312,7 @@
// This is intended to ensrure that if something calls startTethering(bluetooth) just after
// bluetooth is enabled. Before onServiceConnected is called, store the calls into this
// list and handle them as soon as onServiceConnected is called.
- mPendingPanRequests = new ArrayList<>();
+ mPendingPanRequestListeners = new ArrayList<>();
mTetherStates = new ArrayMap<>();
mConnectedClientsTracker = new ConnectedClientsTracker();
@@ -708,8 +708,7 @@
// If tethering is already enabled with a different request,
// disable before re-enabling.
if (unfinishedRequest != null && !unfinishedRequest.equalsIgnoreUidPackage(request)) {
- enableTetheringInternal(type, false /* disabled */,
- unfinishedRequest.getInterfaceName(), null);
+ enableTetheringInternal(false /* disabled */, unfinishedRequest, null);
mEntitlementMgr.stopProvisioningIfNeeded(type);
}
mPendingTetheringRequests.put(type, request);
@@ -720,7 +719,7 @@
mEntitlementMgr.startProvisioningIfNeeded(type,
request.getShouldShowEntitlementUi());
}
- enableTetheringInternal(type, true /* enabled */, request.getInterfaceName(), listener);
+ enableTetheringInternal(true /* enabled */, request, listener);
mTetheringMetrics.createBuilder(type, callerPkg);
});
}
@@ -767,7 +766,10 @@
void stopTetheringInternal(int type) {
mPendingTetheringRequests.remove(type);
- enableTetheringInternal(type, false /* disabled */, null, null);
+ // Using a placeholder here is ok since none of the disable APIs use the request for
+ // anything. We simply need the tethering type to know which link layer to poke for removal.
+ // TODO: Remove the placeholder here and loop through each pending/serving request.
+ enableTetheringInternal(false /* disabled */, createPlaceholderRequest(type), null);
mEntitlementMgr.stopProvisioningIfNeeded(type);
}
@@ -775,9 +777,10 @@
* Enables or disables tethering for the given type. If provisioning is required, it will
* schedule provisioning rechecks for the specified interface.
*/
- private void enableTetheringInternal(int type, boolean enable,
- String iface, final IIntResultListener listener) {
- int result = TETHER_ERROR_NO_ERROR;
+ private void enableTetheringInternal(boolean enable, @NonNull final TetheringRequest request,
+ final IIntResultListener listener) {
+ final int type = request.getTetheringType();
+ final int result;
switch (type) {
case TETHERING_WIFI:
result = setWifiTethering(enable);
@@ -786,7 +789,7 @@
result = setUsbTethering(enable);
break;
case TETHERING_BLUETOOTH:
- setBluetoothTethering(enable, listener);
+ result = setBluetoothTethering(enable, listener);
break;
case TETHERING_NCM:
result = setNcmTethering(enable);
@@ -795,17 +798,17 @@
result = setEthernetTethering(enable);
break;
case TETHERING_VIRTUAL:
- result = setVirtualMachineTethering(enable, iface);
+ result = setVirtualMachineTethering(enable, request);
break;
default:
Log.w(TAG, "Invalid tether type.");
result = TETHER_ERROR_UNKNOWN_TYPE;
}
- // The result of Bluetooth tethering will be sent by #setBluetoothTethering.
- if (type != TETHERING_BLUETOOTH) {
- sendTetherResult(listener, result, type);
- }
+ // The result of Bluetooth tethering will be sent after the pan service connects.
+ if (result == TETHER_ERROR_BLUETOOTH_SERVICE_PENDING) return;
+
+ sendTetherResult(listener, result, type);
}
private void sendTetherResult(final IIntResultListener listener, final int result,
@@ -844,13 +847,12 @@
return TETHER_ERROR_INTERNAL_ERROR;
}
- private void setBluetoothTethering(final boolean enable, final IIntResultListener listener) {
+ private int setBluetoothTethering(final boolean enable, final IIntResultListener listener) {
final BluetoothAdapter adapter = mDeps.getBluetoothAdapter();
if (adapter == null || !adapter.isEnabled()) {
Log.w(TAG, "Tried to enable bluetooth tethering with null or disabled adapter. null: "
+ (adapter == null));
- sendTetherResult(listener, TETHER_ERROR_SERVICE_UNAVAIL, TETHERING_BLUETOOTH);
- return;
+ return TETHER_ERROR_SERVICE_UNAVAIL;
}
if (mBluetoothPanListener != null && mBluetoothPanListener.isConnected()) {
@@ -858,16 +860,21 @@
// When bluetooth tethering is enabled, any time a PAN client pairs with this
// host, bluetooth will bring up a bt-pan interface and notify tethering to
// enable IP serving.
- setBluetoothTetheringSettings(mBluetoothPan, enable, listener);
- return;
+ return setBluetoothTetheringSettings(mBluetoothPan, enable);
}
- // The reference of IIntResultListener should only exist when application want to start
- // tethering but tethering is not bound to pan service yet. Even if the calling process
- // dies, the referenice of IIntResultListener would still keep in mPendingPanRequests. Once
- // tethering bound to pan service (onServiceConnected) or bluetooth just crash
- // (onServiceDisconnected), all the references from mPendingPanRequests would be cleared.
- mPendingPanRequests.add(new Pair(enable, listener));
+ if (!enable) {
+ // The service is not connected. If disabling tethering, there's no point starting
+ // the service just to stop tethering since tethering is not started. Just remove
+ // any pending requests to enable tethering, and notify them that they have failed.
+ for (IIntResultListener pendingListener : mPendingPanRequestListeners) {
+ sendTetherResult(pendingListener, TETHER_ERROR_SERVICE_UNAVAIL,
+ TETHERING_BLUETOOTH);
+ }
+ mPendingPanRequestListeners.clear();
+ return TETHER_ERROR_NO_ERROR;
+ }
+ mPendingPanRequestListeners.add(listener);
// Bluetooth tethering is not a popular feature. To avoid bind to bluetooth pan service all
// the time but user never use bluetooth tethering. mBluetoothPanListener is created first
@@ -877,6 +884,7 @@
mBluetoothPanListener = new PanServiceListener();
adapter.getProfileProxy(mContext, mBluetoothPanListener, BluetoothProfile.PAN);
}
+ return TETHER_ERROR_BLUETOOTH_SERVICE_PENDING;
}
private class PanServiceListener implements ServiceListener {
@@ -893,10 +901,12 @@
mBluetoothPan = (BluetoothPan) proxy;
mIsConnected = true;
- for (Pair<Boolean, IIntResultListener> request : mPendingPanRequests) {
- setBluetoothTetheringSettings(mBluetoothPan, request.first, request.second);
+ for (IIntResultListener pendingListener : mPendingPanRequestListeners) {
+ final int result = setBluetoothTetheringSettings(mBluetoothPan,
+ true /* enable */);
+ sendTetherResult(pendingListener, result, TETHERING_BLUETOOTH);
}
- mPendingPanRequests.clear();
+ mPendingPanRequestListeners.clear();
});
}
@@ -907,11 +917,11 @@
// reachable before next onServiceConnected.
mIsConnected = false;
- for (Pair<Boolean, IIntResultListener> request : mPendingPanRequests) {
- sendTetherResult(request.second, TETHER_ERROR_SERVICE_UNAVAIL,
+ for (IIntResultListener pendingListener : mPendingPanRequestListeners) {
+ sendTetherResult(pendingListener, TETHER_ERROR_SERVICE_UNAVAIL,
TETHERING_BLUETOOTH);
}
- mPendingPanRequests.clear();
+ mPendingPanRequestListeners.clear();
mBluetoothIfaceRequest = null;
mBluetoothCallback = null;
maybeDisableBluetoothIpServing();
@@ -923,8 +933,8 @@
}
}
- private void setBluetoothTetheringSettings(@NonNull final BluetoothPan bluetoothPan,
- final boolean enable, final IIntResultListener listener) {
+ private int setBluetoothTetheringSettings(@NonNull final BluetoothPan bluetoothPan,
+ final boolean enable) {
if (SdkLevel.isAtLeastT()) {
changeBluetoothTetheringSettings(bluetoothPan, enable);
} else {
@@ -933,9 +943,8 @@
// Enabling bluetooth tethering settings can silently fail. Send internal error if the
// result is not expected.
- final int result = bluetoothPan.isTetheringOn() == enable
+ return bluetoothPan.isTetheringOn() == enable
? TETHER_ERROR_NO_ERROR : TETHER_ERROR_INTERNAL_ERROR;
- sendTetherResult(listener, result, TETHERING_BLUETOOTH);
}
private void changeBluetoothTetheringSettingsPreT(@NonNull final BluetoothPan bluetoothPan,
@@ -1054,14 +1063,15 @@
}
}
- private int setVirtualMachineTethering(final boolean enable, String iface) {
+ private int setVirtualMachineTethering(final boolean enable,
+ @NonNull final TetheringRequest request) {
+ final String iface = request.getInterfaceName();
if (enable) {
if (TextUtils.isEmpty(iface)) {
mConfiguredVirtualIface = "avf_tap_fixed";
} else {
mConfiguredVirtualIface = iface;
}
- final TetheringRequest request = getOrCreatePendingTetheringRequest(TETHERING_VIRTUAL);
enableIpServing(request, mConfiguredVirtualIface);
} else if (mConfiguredVirtualIface != null) {
ensureIpServerStopped(mConfiguredVirtualIface);
@@ -1094,6 +1104,19 @@
}
/**
+ * Create a placeholder request. This is used in case we try to find a pending request but there
+ * is none (e.g. stopTethering removed a pending request), or for cases where we only have the
+ * tethering type (e.g. stopTethering(int)).
+ */
+ @NonNull
+ private TetheringRequest createPlaceholderRequest(int type) {
+ final TetheringRequest request = new TetheringRequest.Builder(type).build();
+ request.getParcel().requestType = TetheringRequest.REQUEST_TYPE_LEGACY;
+ request.getParcel().connectivityScope = CONNECTIVITY_SCOPE_GLOBAL;
+ return request;
+ }
+
+ /**
* Gets the TetheringRequest that #startTethering was called with but is waiting for the link
* layer event to indicate the interface is available to tether.
* Note: There are edge cases where the pending request is absent and we must temporarily
@@ -1109,9 +1132,7 @@
Log.w(TAG, "No pending TetheringRequest for type " + type + " found, creating a placeholder"
+ " request");
- TetheringRequest placeholder = new TetheringRequest.Builder(type).build();
- placeholder.getParcel().requestType = REQUEST_TYPE_PLACEHOLDER;
- return placeholder;
+ return createPlaceholderRequest(type);
}
private void handleLegacyTether(String iface, final IIntResultListener listener) {
@@ -1730,27 +1751,7 @@
break;
case IFACE_IP_MODE_LOCAL_ONLY:
type = maybeInferWifiTetheringType(ifname);
- // BUG: this request is incorrect - instead of LOHS, it will reflect whatever
- // request (if any) is being processed for TETHERING_WIFI. However, this is the
- // historical behaviour. It mostly works because a) most of the time there is no
- // such request b) tetherinternal doesn't look at the connectivity scope of the
- // request, it takes the scope from requestedState.
- request = getPendingTetheringRequest(type);
- if (request == null) {
- request = createImplicitLocalOnlyTetheringRequest(TETHERING_WIFI);
- } else {
- // If we've taken this request from the pending requests, then force the
- // connectivity scope to local so we start IpServer in local-only mode (this
- // matches historical behavior). This should be OK since the connectivity scope
- // is only used to start IpServer in the correct mode.
- // TODO: This will break fuzzy-matching logic for start/stop tethering in the
- // future. Figure out how to reconcile that with this forced scope.
- // Possibly ignore the connectivity scope for wifi if both requests are
- // explicit, since explicit Wifi requests may only have
- // CONNECTIVITY_SCOPE_GLOBAL. Or possibly, don't add any edge case and
- // treat it as a different request entirely.
- request.getParcel().connectivityScope = CONNECTIVITY_SCOPE_LOCAL;
- }
+ request = createImplicitLocalOnlyTetheringRequest(type);
break;
default:
mLog.e("Cannot enable IP serving in unknown WiFi mode: " + wifiIpMode);
@@ -2427,9 +2428,14 @@
break;
}
case EVENT_REQUEST_CHANGE_DOWNSTREAM: {
- final int tetheringType = message.arg1;
+ final int type = message.arg1;
final Boolean enabled = (Boolean) message.obj;
- enableTetheringInternal(tetheringType, enabled, null, null);
+ // Using a placeholder here is ok since we just need to the type of
+ // tethering to poke the link layer. When the link layer comes up, we won't
+ // have a pending request to use, but this matches the historical behavior.
+ // TODO: Get the TetheringRequest from IpServer and make sure to put it in
+ // the pending list too.
+ enableTetheringInternal(enabled, createPlaceholderRequest(type), null);
break;
}
default:
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
index f7a44f1..e1c2db9 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
@@ -93,7 +93,6 @@
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.notNull;
@@ -2787,6 +2786,10 @@
public void assertHasResult() {
if (!mHasResult) fail("No callback result");
}
+
+ public void assertDoesNotHaveResult() {
+ if (mHasResult) fail("Has callback result");
+ }
}
@Test
@@ -3395,10 +3398,9 @@
}
@Test
+ @IgnoreUpTo(Build.VERSION_CODES.S_V2)
public void testBluetoothTethering() throws Exception {
initTetheringOnTestThread();
- // Switch to @IgnoreUpTo(Build.VERSION_CODES.S_V2) when it is available for AOSP.
- assumeTrue(isAtLeastT());
final ResultListener result = new ResultListener(TETHER_ERROR_NO_ERROR);
mockBluetoothSettings(true /* bluetoothOn */, true /* tetheringOn */);
@@ -3432,10 +3434,9 @@
}
@Test
+ @IgnoreAfter(Build.VERSION_CODES.S_V2)
public void testBluetoothTetheringBeforeT() throws Exception {
initTetheringOnTestThread();
- // Switch to @IgnoreAfter(Build.VERSION_CODES.S_V2) when it is available for AOSP.
- assumeFalse(isAtLeastT());
final ResultListener result = new ResultListener(TETHER_ERROR_NO_ERROR);
mockBluetoothSettings(true /* bluetoothOn */, true /* tetheringOn */);
@@ -3515,6 +3516,23 @@
verifyNetdCommandForBtTearDown();
}
+ @Test
+ public void testPendingPanEnableRequestFailedUponDisableRequest() throws Exception {
+ initTetheringOnTestThread();
+
+ mockBluetoothSettings(true /* bluetoothOn */, true /* tetheringOn */);
+ final ResultListener failedEnable = new ResultListener(TETHER_ERROR_SERVICE_UNAVAIL);
+ mTethering.startTethering(createTetheringRequest(TETHERING_BLUETOOTH),
+ TEST_CALLER_PKG, failedEnable);
+ mLooper.dispatchAll();
+ failedEnable.assertDoesNotHaveResult();
+
+ // Stop tethering before the pan service connects. This should fail the enable request.
+ mTethering.stopTethering(TETHERING_BLUETOOTH);
+ mLooper.dispatchAll();
+ failedEnable.assertHasResult();
+ }
+
private void mockBluetoothSettings(boolean bluetoothOn, boolean tetheringOn) {
when(mBluetoothAdapter.isEnabled()).thenReturn(bluetoothOn);
when(mBluetoothPan.isTetheringOn()).thenReturn(tetheringOn);
diff --git a/bpf/headers/include/bpf/KernelUtils.h b/bpf/headers/include/bpf/KernelUtils.h
index 68bc607..a36085a 100644
--- a/bpf/headers/include/bpf/KernelUtils.h
+++ b/bpf/headers/include/bpf/KernelUtils.h
@@ -55,12 +55,12 @@
isKernelVersion(4, 9) || // minimum for Android S & T
isKernelVersion(4, 14) || // minimum for Android U
isKernelVersion(4, 19) || // minimum for Android V
- isKernelVersion(5, 4) || // first supported in Android R, min for W
+ isKernelVersion(5, 4) || // first supported in Android R, min for 25Q2
isKernelVersion(5, 10) || // first supported in Android S
isKernelVersion(5, 15) || // first supported in Android T
isKernelVersion(6, 1) || // first supported in Android U
isKernelVersion(6, 6) || // first supported in Android V
- isKernelVersion(6, 12); // first supported in Android W
+ isKernelVersion(6, 12); // first supported in Android 25Q2
}
// Figure out the bitness of userspace.
diff --git a/bpf/headers/include/bpf_map_def.h b/bpf/headers/include/bpf_map_def.h
index d67da48..e95ca5f 100644
--- a/bpf/headers/include/bpf_map_def.h
+++ b/bpf/headers/include/bpf_map_def.h
@@ -106,8 +106,12 @@
// Here sizeof & __alignof__ are consistent, but _Alignof is not: compile for 'aosp_cf_x86_phone'
_Static_assert(sizeof(unsigned long long) == 8, "sizeof unsigned long long != 8");
_Static_assert(__alignof__(unsigned long long) == 8, "__alignof__ unsigned long long != 8");
-// BPF wants 8, but 32-bit x86 wants 4
-//_Static_assert(_Alignof(unsigned long long) == 8, "_Alignof unsigned long long != 8");
+// BPF & everyone else wants 8, but 32-bit x86 wants 4
+#if defined(__i386__)
+_Static_assert(_Alignof(unsigned long long) == 4, "x86-32 _Alignof unsigned long long != 4");
+#else
+_Static_assert(_Alignof(unsigned long long) == 8, "_Alignof unsigned long long != 8");
+#endif
// for maps:
diff --git a/bpf/loader/NetBpfLoad.cpp b/bpf/loader/NetBpfLoad.cpp
index 04d7492..c67be66 100644
--- a/bpf/loader/NetBpfLoad.cpp
+++ b/bpf/loader/NetBpfLoad.cpp
@@ -823,14 +823,14 @@
"tmp_map_" + objName + "_" + mapNames[i];
ret = bpfFdPin(fd, createLoc.c_str());
if (ret) {
- int err = errno;
+ const int err = errno;
ALOGE("create %s -> %d [%d:%s]", createLoc.c_str(), ret, err, strerror(err));
return -err;
}
ret = renameat2(AT_FDCWD, createLoc.c_str(),
AT_FDCWD, mapPinLoc.c_str(), RENAME_NOREPLACE);
if (ret) {
- int err = errno;
+ const int err = errno;
ALOGE("rename %s %s -> %d [%d:%s]", createLoc.c_str(), mapPinLoc.c_str(), ret,
err, strerror(err));
return -err;
@@ -838,32 +838,34 @@
} else {
ret = bpfFdPin(fd, mapPinLoc.c_str());
if (ret) {
- int err = errno;
+ const int err = errno;
ALOGE("pin %s -> %d [%d:%s]", mapPinLoc.c_str(), ret, err, strerror(err));
return -err;
}
}
ret = chmod(mapPinLoc.c_str(), md[i].mode);
if (ret) {
- int err = errno;
+ const int err = errno;
ALOGE("chmod(%s, 0%o) = %d [%d:%s]", mapPinLoc.c_str(), md[i].mode, ret, err,
strerror(err));
return -err;
}
ret = chown(mapPinLoc.c_str(), (uid_t)md[i].uid, (gid_t)md[i].gid);
if (ret) {
- int err = errno;
+ const int err = errno;
ALOGE("chown(%s, %u, %u) = %d [%d:%s]", mapPinLoc.c_str(), md[i].uid, md[i].gid,
ret, err, strerror(err));
return -err;
}
}
- int mapId = bpfGetFdMapId(fd);
- if (mapId == -1) {
- if (isAtLeastKernelVersion(4, 14, 0))
- ALOGE("bpfGetFdMapId failed, ret: %d [%d]", mapId, errno);
- } else {
+ if (isAtLeastKernelVersion(4, 14, 0)) {
+ int mapId = bpfGetFdMapId(fd);
+ if (mapId == -1) {
+ const int err = errno;
+ ALOGE("bpfGetFdMapId failed, errno: %d", err);
+ return -err;
+ }
ALOGI("map %s id %d", mapPinLoc.c_str(), mapId);
}
@@ -1006,7 +1008,7 @@
if (access(progPinLoc.c_str(), F_OK) == 0) {
fd.reset(retrieveProgram(progPinLoc.c_str()));
ALOGD("New bpf prog load reusing prog %s, ret: %d (%s)", progPinLoc.c_str(), fd.get(),
- (!fd.ok() ? std::strerror(errno) : "no error"));
+ !fd.ok() ? std::strerror(errno) : "ok");
reuse = true;
} else {
static char log_buf[1 << 20]; // 1 MiB logging buffer
@@ -1037,7 +1039,7 @@
ALOGD("BPF_PROG_LOAD call for %s (%s) returned '%s' fd: %d (%s)", elfPath,
cs[i].name.c_str(), log_oneline ? log_buf : "{multiline}",
- fd.get(), (!fd.ok() ? std::strerror(errno) : "ok"));
+ fd.get(), !fd.ok() ? std::strerror(errno) : "ok");
if (!fd.ok()) {
// kernel NULL terminates log_buf, so this checks for non-empty string
@@ -1066,14 +1068,14 @@
"tmp_prog_" + objName + '_' + string(name);
ret = bpfFdPin(fd, createLoc.c_str());
if (ret) {
- int err = errno;
+ const int err = errno;
ALOGE("create %s -> %d [%d:%s]", createLoc.c_str(), ret, err, strerror(err));
return -err;
}
ret = renameat2(AT_FDCWD, createLoc.c_str(),
AT_FDCWD, progPinLoc.c_str(), RENAME_NOREPLACE);
if (ret) {
- int err = errno;
+ const int err = errno;
ALOGE("rename %s %s -> %d [%d:%s]", createLoc.c_str(), progPinLoc.c_str(), ret,
err, strerror(err));
return -err;
@@ -1081,19 +1083,19 @@
} else {
ret = bpfFdPin(fd, progPinLoc.c_str());
if (ret) {
- int err = errno;
+ const int err = errno;
ALOGE("create %s -> %d [%d:%s]", progPinLoc.c_str(), ret, err, strerror(err));
return -err;
}
}
if (chmod(progPinLoc.c_str(), 0440)) {
- int err = errno;
+ const int err = errno;
ALOGE("chmod %s 0440 -> [%d:%s]", progPinLoc.c_str(), err, strerror(err));
return -err;
}
if (chown(progPinLoc.c_str(), (uid_t)cs[i].prog_def->uid,
(gid_t)cs[i].prog_def->gid)) {
- int err = errno;
+ const int err = errno;
ALOGE("chown %s %d %d -> [%d:%s]", progPinLoc.c_str(), cs[i].prog_def->uid,
cs[i].prog_def->gid, err, strerror(err));
return -err;
@@ -1490,6 +1492,11 @@
if (!isTV()) return 1;
}
+ if (isKernel32Bit() && isAtLeast25Q2) {
+ ALOGE("Android 25Q2 requires 64 bit kernel.");
+ return 1;
+ }
+
// 6.6 is highest version supported by Android V, so this is effectively W+ (sdk=36+)
if (isKernel32Bit() && isAtLeastKernelVersion(6, 7, 0)) {
ALOGE("Android platform with 32 bit kernel version >= 6.7.0 is unsupported");
diff --git a/bpf/netd/BpfHandler.cpp b/bpf/netd/BpfHandler.cpp
index 6af7228..125f26b 100644
--- a/bpf/netd/BpfHandler.cpp
+++ b/bpf/netd/BpfHandler.cpp
@@ -318,7 +318,6 @@
RETURN_IF_NOT_OK(mUidPermissionMap.init(UID_PERMISSION_MAP_PATH));
// initialized last so mCookieTagMap.isValid() implies everything else is valid too
RETURN_IF_NOT_OK(mCookieTagMap.init(COOKIE_TAG_MAP_PATH));
- ALOGI("%s successfully", __func__);
return netdutils::status::ok;
}
diff --git a/common/flags.aconfig b/common/flags.aconfig
index 5f279fa..51b4fc0 100644
--- a/common/flags.aconfig
+++ b/common/flags.aconfig
@@ -171,6 +171,6 @@
is_exported: true
namespace: "android_core_networking"
description: "Flag for controlling access to the local network behind a new runtime permission. Requires ConnectivityCompatChanges.RESTRICT_LOCAL_NETWORK to enable feature."
- bug: "365139289"
+ bug: "388774939"
is_fixed_read_only: true
}
diff --git a/framework/Android.bp b/framework/Android.bp
index a1c6a15..d6ee759 100644
--- a/framework/Android.bp
+++ b/framework/Android.bp
@@ -160,7 +160,10 @@
java_defaults {
name: "CronetJavaDefaults",
srcs: [":httpclient_api_sources"],
- static_libs: ["com.android.net.http.flags-aconfig-java"],
+ static_libs: [
+ "com.android.net.http.flags-aconfig-java",
+ "modules-utils-expresslog",
+ ],
libs: [
"androidx.annotation_annotation",
],
diff --git a/networksecurity/service/src/com/android/server/net/ct/DataStore.java b/networksecurity/service/src/com/android/server/net/ct/DataStore.java
index 8180316..1f99efa 100644
--- a/networksecurity/service/src/com/android/server/net/ct/DataStore.java
+++ b/networksecurity/service/src/com/android/server/net/ct/DataStore.java
@@ -44,8 +44,9 @@
}
try (InputStream in = new FileInputStream(mPropertyFile)) {
load(in);
- } catch (IOException e) {
+ } catch (IOException | IllegalArgumentException e) {
Log.e(TAG, "Error loading property store", e);
+ delete();
}
}
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsAdvertiser.java b/service-t/src/com/android/server/connectivity/mdns/MdnsAdvertiser.java
index 54f7ca3..c3306bd 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsAdvertiser.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsAdvertiser.java
@@ -1007,6 +1007,19 @@
});
}
+ private List<String> getOffloadSubtype(@NonNull NsdServiceInfo nsdServiceInfo) {
+ // Workaround: Google Cast doesn't announce subtypes per DNS-SD/mDNS spec.
+ // Thus, subtypes aren't offloaded; only "_googlecast._tcp" is.
+ // Subtype responses occur when hardware offload is off.
+ // This solution works because Google Cast doesn't follow the intended usage of subtypes in
+ // the spec, as it always discovers for both the subtype+base type, and only uses the mDNS
+ // subtype as an optimization.
+ if (nsdServiceInfo.getServiceType().equals("_googlecast._tcp")) {
+ return new ArrayList<>();
+ }
+ return new ArrayList<>(nsdServiceInfo.getSubtypes());
+ }
+
private OffloadServiceInfoWrapper createOffloadService(int serviceId,
@NonNull Registration registration, byte[] rawOffloadPacket) {
final NsdServiceInfo nsdServiceInfo = registration.getServiceInfo();
@@ -1017,7 +1030,7 @@
final OffloadServiceInfo offloadServiceInfo = new OffloadServiceInfo(
new OffloadServiceInfo.Key(nsdServiceInfo.getServiceName(),
nsdServiceInfo.getServiceType()),
- new ArrayList<>(nsdServiceInfo.getSubtypes()),
+ getOffloadSubtype(nsdServiceInfo),
String.join(".", mDeviceHostName),
rawOffloadPacket,
priority,
diff --git a/service/ServiceConnectivityResources/res/raw/ct_public_keys.pem b/service/ServiceConnectivityResources/res/raw/ct_public_keys.pem
new file mode 100644
index 0000000..80dccbe
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/raw/ct_public_keys.pem
@@ -0,0 +1,42 @@
+-----BEGIN PUBLIC KEY-----
+MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAnmb1lacOnP5H1bwb06mG
+fEUeC9PZRwNQskSs9KaWrpfrSkLKuHXkVCbgeagbUR/Sh1OeIhyJRSS0PLCO0JjC
+UpGhYMrIGRgEET4IrP9f8aMFqxxxBUEanI+OxAhIJlP9tiWfGdKAASYcxg/DyXXz
+bqSXBEFJqBLqmnfHcLB/NhO1ejV6AiU1NMrT+iWSrJG8b6mq/LlAqWvidK8oPBsW
+87M4pPLpUoA54ultjx2wEzJ9dBy6jtnKZ/dz4DkDhYug5izRDcYtEfzQBoum0etV
+s4EoogW1AMeqW5G+L4HjPNgp3gNGZ/2RaBy7gp8Br+byYu2wHwdQIBQjS310yaKc
+nuNFOd+Q0DrzvHKB7yYzzdwo+hNocPpkvOzSw74jd09kDZQ+S2peCJ5NPU7VKT6/
+tkvc3tYA9pAu4/T+BGqRft4FjgeNANfSIX/WhWDzzVWymTUGFUvt+D0fF3Cw+XSa
+b8uTgRZ1Ma/FvSGgXHVoG9E4QAFFG4I9mmRqsnzA+8fqSNAfieL5OWecq4PU+pMa
+uNVJ9hbvmW2yXuMgEg6K9kFLdxggRn+OcxowgXJJh79L0r7RN1d8kuHelDhOzcte
+dUTtLNOb/1PA0d/I2IVJwc9xSQZXurqqT/Z+c01B3/R0BgGDkIT/yZ5iHPoZFYPD
+U8UdQzUK0KXgGkc8P5pJW8kCAwEAAQ==
+-----END PUBLIC KEY-----
+-----BEGIN PUBLIC KEY-----
+MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAn1ssK1m56VVurVJ/fNKe
++aXDnytBy/hWY48ZT+ZC0S29llfjkaCBlmkngoI2hgwz9BI6pHwUINS15pT1sznw
+kHoEaNKr8sANHTQ0PYlDuk5iQSjnaGz7XmqbZ3c92BQrmLG/kwX2c17YNJI2qCk3
+MaBJBeS5YErR3xcucT9M7qtNWWIT9O0sLV1lDUZVCYedWBSnNz1/mAiLhttWmU5u
+GKl/5LmjWP/piNjh8whx0abJUGeGS2HH0JAOb0pjBV6UQvj3tO+gTiNDhdrE4CKh
+Qn8SKNjW/BY320f0A5t581Q0++cQUAisRgBQos0Pkvg5vb6wgII+pJq0SnZoYFfH
+oycuR4q3eOCgJmpEAPC0MhNpIDUQS6p3QabD9ID+21ymiQa/Zf8Mv2xMM6ZItKxX
+77vSKvBbimTGmB2IU+Zi484PKI5QwxBUCHVSmNpvHyXyjhBmpqik9Op26QYYT10b
+ADnJY1L/Q+i44nI4pfwgIncqAWuLnxg/XggJDWj48Un9SMNoyN7gzQX75M7rh7/t
+F6QtKvJreP0pP2UoVSgZKjXnL9tqeZbOdZU1kBHi1HOhlUKTfq5dn2fVUeYkE769
+clFF7Y1FiI259IPhTKiOIfARJ4BL4Sn8D9c9vpxDYPFl5bCJbspmFpwfzTMDnGVS
+/IlY6Putpv2/lD1B7aQGt1sCAwEAAQ==
+-----END PUBLIC KEY-----
+-----BEGIN PUBLIC KEY-----
+MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAwMPNecDhLDamK9Rs8W5V
+c0LWZPbk9FNP+budBoFMX46dWyJ75O5e8xY9UhJSBFl8+Itm/rWO/h2zZ6qE3Cq8
+1LYbOg+x+rLnYOcAvD2O7EU73A3RD/vqoUDDVK3cwKMq3ry7CYu+NJW7TRIKV7Ct
+BMCBrvpmC1WlZ/jxSV0Soapza4/H+UV0hHYh/Wn3EWObGWYdI3yxwZ81AyU1QCR/
+oaO0PQPXqvo3gPBINnK3Qr0aLtYc4YCfTXe6i4g3DeAlkpqNLZtC2hyqiRB4Dg47
+zDzYECGofRAu8w9d8uI+eccacXfvI9zEcL7FAl5AzBKmMFOfBNTr08V7+aROWfGO
+7imWsj2MQ6RG17zqJak5QX/1bqDxwhG0KolB86mPZu0WeKz1B3iP5qAUlDNBHLDV
+pQIez0mrMsVsimVguuLYHMpIgijphA9WhijCJW2x7c6aocB6IpnMIV1sqnUQTwLG
+t32AMrckxqFmaKGj/8I9M+Xj+Cy4fIa5YSOdb/tlaYZSfjH5ch41xucQ2HWFyZ/9
+hkTFodvF5ajCQ5maHeIjDkS/Bc/s9CB+/fbSkstDsPMRp/ExyQcEYjKTG5o9Ewyo
++KGGXS2dSS10Ibl0Zx/S/0ZuZx8ZAxMOIIPpugdkWqHU9thh71dR8zM4KMkEfB8C
+sWLGB1yMuztn9nRUcpiEZTECAwEAAQ==
+-----END PUBLIC KEY-----
diff --git a/service/src/com/android/server/BpfNetMaps.java b/service/src/com/android/server/BpfNetMaps.java
index c743573..4fae73a 100644
--- a/service/src/com/android/server/BpfNetMaps.java
+++ b/service/src/com/android/server/BpfNetMaps.java
@@ -464,7 +464,7 @@
ToDo : Remove this method when SdkLevel.isAtLeastB() is fixed, aosp is at sdk level 36 or use
NetworkStackUtils.isAtLeast25Q2 when it is moved to a static lib.
*/
- private static boolean isAtLeast25Q2() {
+ public static boolean isAtLeast25Q2() {
return SdkLevel.isAtLeastB() || (SdkLevel.isAtLeastV()
&& "Baklava".equals(Build.VERSION.CODENAME));
}
diff --git a/service/src/com/android/server/connectivity/NetworkAgentInfo.java b/service/src/com/android/server/connectivity/NetworkAgentInfo.java
index 2686e4a..e762a8e 100644
--- a/service/src/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/service/src/com/android/server/connectivity/NetworkAgentInfo.java
@@ -1128,6 +1128,7 @@
int delta = add ? +1 : -1;
switch (request.type) {
case REQUEST:
+ case RESERVATION:
mNumRequestNetworkRequests += delta;
break;
diff --git a/service/src/com/android/server/connectivity/PermissionMonitor.java b/service/src/com/android/server/connectivity/PermissionMonitor.java
index 0d388e8..737e27a 100755
--- a/service/src/com/android/server/connectivity/PermissionMonitor.java
+++ b/service/src/com/android/server/connectivity/PermissionMonitor.java
@@ -282,7 +282,8 @@
mContext = context;
mBpfNetMaps = bpfNetMaps;
mThread = thread;
- if (Flags.restrictLocalNetwork()) {
+ if (BpfNetMaps.isAtLeast25Q2()) {
+ // Local net restrictions is supported as a developer opt-in starting in Android B.
// This listener should finish registration by the time the system has completed
// boot setup such that any changes to runtime permissions for local network
// restrictions can only occur after this registration has completed.
@@ -1330,7 +1331,8 @@
// Flags.restrictLocalNetwork() is used to offer the feature to devices, but it will
// only be enforced when develoeprs choose to enable it.
// TODO(b/394567896): Update compat change checks
- if (CompatChanges.isChangeEnabled(RESTRICT_LOCAL_NETWORK, uid)) {
+ if (CompatChanges.isChangeEnabled(RESTRICT_LOCAL_NETWORK, uid)
+ && BpfNetMaps.isAtLeast25Q2()) {
// TODO(b/388803658): Update network permissions and record change
}
}
diff --git a/staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java b/staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java
index 0d96fc4..2420e7a 100644
--- a/staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java
+++ b/staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java
@@ -497,4 +497,33 @@
return false;
}
}
+
+ /**
+ * Sends a netlink request to set MTU for given interface
+ *
+ * @param interfaceName The name of the network interface to query.
+ * @param mtu MTU value to set for the interface.
+ * @return true if the request finished successfully, otherwise false.
+ */
+ public static boolean setInterfaceMtu(@NonNull String interfaceName, int mtu) {
+ if (mtu < 68) {
+ Log.e(TAG, "Invalid mtu: " + mtu + ", mtu should be greater than 68 referring RFC791");
+ return false;
+ }
+ final RtNetlinkLinkMessage ntMsg =
+ RtNetlinkLinkMessage.createSetMtuMessage(interfaceName, /*seqNo*/ 0, mtu);
+ if (ntMsg == null) {
+ Log.e(TAG, "Failed to create message to set MTU to " + mtu
+ + "for interface " + interfaceName);
+ return false;
+ }
+ final byte[] msg = ntMsg.pack(ByteOrder.nativeOrder());
+ try {
+ NetlinkUtils.sendOneShotKernelMessage(NETLINK_ROUTE, msg);
+ return true;
+ } catch (ErrnoException e) {
+ Log.e(TAG, "Failed to set MTU to " + mtu + " for: " + interfaceName, e);
+ return false;
+ }
+ }
}
diff --git a/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkLinkMessage.java b/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkLinkMessage.java
index f17a7ec..c19a124 100644
--- a/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkLinkMessage.java
+++ b/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkLinkMessage.java
@@ -364,6 +364,37 @@
DEFAULT_MTU, /*hardwareAddress*/ null, /*interfaceName*/ null);
}
+ /**
+ * Creates an {@link RtNetlinkLinkMessage} instance that can be used to set the MTU of a
+ * network interface.
+ *
+ * @param interfaceName The name of the network interface to query.
+ * @param sequenceNumber The sequence number for the Netlink message.
+ * @param mtu MTU value to set for the interface.
+ * @return An `RtNetlinkLinkMessage` instance representing the request to query the interface.
+ */
+ @Nullable
+ public static RtNetlinkLinkMessage createSetMtuMessage(@NonNull String interfaceName,
+ int sequenceNumber, int mtu) {
+ return createSetMtuMessage(
+ interfaceName, sequenceNumber, mtu, new OsAccess());
+ }
+
+ @VisibleForTesting
+ @Nullable
+ protected static RtNetlinkLinkMessage createSetMtuMessage(@NonNull String interfaceName,
+ int sequenceNumber, int mtu, @NonNull OsAccess osAccess) {
+ final int interfaceIndex = osAccess.if_nametoindex(interfaceName);
+ if (interfaceIndex == OsAccess.INVALID_INTERFACE_INDEX) {
+ return null;
+ }
+ return RtNetlinkLinkMessage.build(
+ new StructNlMsgHdr(/*payloadLen*/ 0, RTM_NEWLINK, NLM_F_REQUEST_ACK , sequenceNumber),
+ new StructIfinfoMsg((short) AF_UNSPEC, /*type*/ 0, interfaceIndex,
+ /*flags*/ 0, /*change*/ 0),
+ mtu, /*hardwareAddress*/ null, /*interfaceName*/ null);
+ }
+
@Override
public String toString() {
return "RtNetlinkLinkMessage{ "
diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkLinkMessageTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkLinkMessageTest.java
index b29fc73..13710b1 100644
--- a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkLinkMessageTest.java
+++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkLinkMessageTest.java
@@ -328,6 +328,28 @@
}
@Test
+ public void testCreateSetInterfaceMtuMessage() {
+ final String expectedHexBytes =
+ "280000001000050068240000000000000000000008000000" // struct nlmsghdr
+ + "000000000000000008000400DC050000"; // struct ifinfomsg
+ final String interfaceName = "wlan0";
+ final int interfaceIndex = 8;
+ final int sequenceNumber = 0x2468;
+ final int mtu = 1500;
+
+ when(mOsAccess.if_nametoindex(interfaceName)).thenReturn(interfaceIndex);
+
+ final RtNetlinkLinkMessage msg = RtNetlinkLinkMessage.createSetMtuMessage(
+ interfaceName,
+ sequenceNumber,
+ mtu,
+ mOsAccess);
+ assertNotNull(msg);
+ final byte[] bytes = msg.pack(ByteOrder.LITTLE_ENDIAN); // For testing.
+ assertEquals(expectedHexBytes, HexDump.toHexString(bytes));
+ }
+
+ @Test
public void testToString() {
final ByteBuffer byteBuffer = toByteBuffer(RTM_NEWLINK_HEX);
byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing.
diff --git a/tests/cts/net/src/android/net/cts/ApfIntegrationTest.kt b/tests/cts/net/src/android/net/cts/ApfIntegrationTest.kt
index 9379697..ee2e7db 100644
--- a/tests/cts/net/src/android/net/cts/ApfIntegrationTest.kt
+++ b/tests/cts/net/src/android/net/cts/ApfIntegrationTest.kt
@@ -52,8 +52,8 @@
import android.os.Handler
import android.os.HandlerThread
import android.os.PowerManager
-import android.os.UserManager
import android.os.SystemProperties
+import android.os.UserManager
import android.platform.test.annotations.AppModeFull
import android.provider.DeviceConfig
import android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsAdvertiserTest.kt b/tests/unit/java/com/android/server/connectivity/mdns/MdnsAdvertiserTest.kt
index ba62114..e6e6ecc 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsAdvertiserTest.kt
+++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsAdvertiserTest.kt
@@ -92,6 +92,13 @@
network = TEST_NETWORK_1
}
+private val GOOGLECAST_SERVICE = NsdServiceInfo("TestServiceName", "_googlecast._tcp").apply {
+ subtypes = setOf(TEST_SUBTYPE)
+ port = 12345
+ hostAddresses = listOf(TEST_ADDR)
+ network = TEST_NETWORK_1
+}
+
private val SERVICE_1_SUBTYPE = NsdServiceInfo("TestServiceName", "_advertisertest._tcp").apply {
subtypes = setOf(TEST_SUBTYPE)
port = 12345
@@ -143,6 +150,15 @@
OffloadEngine.OFFLOAD_TYPE_REPLY.toLong()
)
+private val OFFLOAD_SERVICE_INFO_GOOGLECAST = OffloadServiceInfo(
+ OffloadServiceInfo.Key("TestServiceName", "_googlecast._tcp"),
+ listOf(),
+ "Android_test.local",
+ TEST_OFFLOAD_PACKET1,
+ Int.MAX_VALUE,
+ OffloadEngine.OFFLOAD_TYPE_REPLY.toLong()
+)
+
private val OFFLOAD_SERVICEINFO_NO_SUBTYPE = OffloadServiceInfo(
OffloadServiceInfo.Key("TestServiceName", "_advertisertest._tcp"),
listOf(),
@@ -189,11 +205,25 @@
fun setUp() {
thread.start()
doReturn(TEST_HOSTNAME).`when`(mockDeps).generateHostname(anyBoolean())
- doReturn(mockInterfaceAdvertiser1).`when`(mockDeps).makeAdvertiser(eq(mockSocket1),
- any(), any(), any(), any(), any(), any(), any()
+ doReturn(mockInterfaceAdvertiser1).`when`(mockDeps).makeAdvertiser(
+ eq(mockSocket1),
+ any(),
+ any(),
+ any(),
+ any(),
+ any(),
+ any(),
+ any()
)
- doReturn(mockInterfaceAdvertiser2).`when`(mockDeps).makeAdvertiser(eq(mockSocket2),
- any(), any(), any(), any(), any(), any(), any()
+ doReturn(mockInterfaceAdvertiser2).`when`(mockDeps).makeAdvertiser(
+ eq(mockSocket2),
+ any(),
+ any(),
+ any(),
+ any(),
+ any(),
+ any(),
+ any()
)
doReturn(true).`when`(mockInterfaceAdvertiser1).isProbing(anyInt())
doReturn(true).`when`(mockInterfaceAdvertiser2).isProbing(anyInt())
@@ -202,16 +232,21 @@
doReturn(TEST_INTERFACE1).`when`(mockInterfaceAdvertiser1).socketInterfaceName
doReturn(TEST_INTERFACE2).`when`(mockInterfaceAdvertiser2).socketInterfaceName
doReturn(TEST_OFFLOAD_PACKET1).`when`(mockInterfaceAdvertiser1).getRawOffloadPayload(
- SERVICE_ID_1)
+ SERVICE_ID_1
+ )
doReturn(TEST_OFFLOAD_PACKET1).`when`(mockInterfaceAdvertiser1).getRawOffloadPayload(
- SERVICE_ID_2)
+ SERVICE_ID_2
+ )
doReturn(TEST_OFFLOAD_PACKET1).`when`(mockInterfaceAdvertiser1).getRawOffloadPayload(
- SERVICE_ID_3)
+ SERVICE_ID_3
+ )
doReturn(TEST_OFFLOAD_PACKET1).`when`(mockInterfaceAdvertiser2).getRawOffloadPayload(
- SERVICE_ID_1)
+ SERVICE_ID_1
+ )
doReturn(resources).`when`(context).getResources()
doReturn(SERVICES_PRIORITY_LIST).`when`(resources).getStringArray(
- R.array.config_nsdOffloadServicesPriority)
+ R.array.config_nsdOffloadServicesPriority
+ )
ConnectivityResources.setResourcesContextForTest(context)
}
@@ -232,8 +267,12 @@
fun testAddService_OneNetwork() {
val advertiser =
MdnsAdvertiser(thread.looper, socketProvider, cb, mockDeps, sharedlog, flags, context)
- postSync { advertiser.addOrUpdateService(SERVICE_ID_1, SERVICE_1,
- DEFAULT_ADVERTISING_OPTION, TEST_CLIENT_UID_1) }
+ postSync { advertiser.addOrUpdateService(
+ SERVICE_ID_1,
+ SERVICE_1,
+ DEFAULT_ADVERTISING_OPTION,
+ TEST_CLIENT_UID_1
+ ) }
val socketCbCaptor = ArgumentCaptor.forClass(SocketCallback::class.java)
verify(socketProvider).requestSocket(eq(TEST_NETWORK_1), socketCbCaptor.capture())
@@ -255,7 +294,9 @@
doReturn(false).`when`(mockInterfaceAdvertiser1).isProbing(SERVICE_ID_1)
postSync { intAdvCbCaptor.value.onServiceProbingSucceeded(
- mockInterfaceAdvertiser1, SERVICE_ID_1) }
+ mockInterfaceAdvertiser1,
+ SERVICE_ID_1
+ ) }
verify(cb).onRegisterServiceSucceeded(eq(SERVICE_ID_1), argThat { it.matches(SERVICE_1) })
verify(cb).onOffloadStartOrUpdate(eq(TEST_INTERFACE1), eq(OFFLOAD_SERVICEINFO_NO_SUBTYPE))
@@ -296,12 +337,18 @@
fun testAddService_AllNetworksWithSubType() {
val advertiser =
MdnsAdvertiser(thread.looper, socketProvider, cb, mockDeps, sharedlog, flags, context)
- postSync { advertiser.addOrUpdateService(SERVICE_ID_1, ALL_NETWORKS_SERVICE_SUBTYPE,
- DEFAULT_ADVERTISING_OPTION, TEST_CLIENT_UID_1) }
+ postSync { advertiser.addOrUpdateService(
+ SERVICE_ID_1,
+ ALL_NETWORKS_SERVICE_SUBTYPE,
+ DEFAULT_ADVERTISING_OPTION,
+ TEST_CLIENT_UID_1
+ ) }
val socketCbCaptor = ArgumentCaptor.forClass(SocketCallback::class.java)
- verify(socketProvider).requestSocket(eq(ALL_NETWORKS_SERVICE_SUBTYPE.network),
- socketCbCaptor.capture())
+ verify(socketProvider).requestSocket(
+ eq(ALL_NETWORKS_SERVICE_SUBTYPE.network),
+ socketCbCaptor.capture()
+ )
val socketCb = socketCbCaptor.value
postSync { socketCb.onSocketCreated(TEST_SOCKETKEY_1, mockSocket1, listOf(TEST_LINKADDR)) }
@@ -309,30 +356,56 @@
val intAdvCbCaptor1 = ArgumentCaptor.forClass(MdnsInterfaceAdvertiser.Callback::class.java)
val intAdvCbCaptor2 = ArgumentCaptor.forClass(MdnsInterfaceAdvertiser.Callback::class.java)
- verify(mockDeps).makeAdvertiser(eq(mockSocket1), eq(listOf(TEST_LINKADDR)),
- eq(thread.looper), any(), intAdvCbCaptor1.capture(), eq(TEST_HOSTNAME), any(), any()
+ verify(mockDeps).makeAdvertiser(
+ eq(mockSocket1),
+ eq(listOf(TEST_LINKADDR)),
+ eq(thread.looper),
+ any(),
+ intAdvCbCaptor1.capture(),
+ eq(TEST_HOSTNAME),
+ any(),
+ any()
)
- verify(mockDeps).makeAdvertiser(eq(mockSocket2), eq(listOf(TEST_LINKADDR)),
- eq(thread.looper), any(), intAdvCbCaptor2.capture(), eq(TEST_HOSTNAME), any(), any()
+ verify(mockDeps).makeAdvertiser(
+ eq(mockSocket2),
+ eq(listOf(TEST_LINKADDR)),
+ eq(thread.looper),
+ any(),
+ intAdvCbCaptor2.capture(),
+ eq(TEST_HOSTNAME),
+ any(),
+ any()
)
verify(mockInterfaceAdvertiser1).addService(
- anyInt(), eq(ALL_NETWORKS_SERVICE_SUBTYPE), any())
+ anyInt(),
+ eq(ALL_NETWORKS_SERVICE_SUBTYPE),
+ any()
+ )
verify(mockInterfaceAdvertiser2).addService(
- anyInt(), eq(ALL_NETWORKS_SERVICE_SUBTYPE), any())
+ anyInt(),
+ eq(ALL_NETWORKS_SERVICE_SUBTYPE),
+ any()
+ )
doReturn(false).`when`(mockInterfaceAdvertiser1).isProbing(SERVICE_ID_1)
postSync { intAdvCbCaptor1.value.onServiceProbingSucceeded(
- mockInterfaceAdvertiser1, SERVICE_ID_1) }
+ mockInterfaceAdvertiser1,
+ SERVICE_ID_1
+ ) }
verify(cb).onOffloadStartOrUpdate(eq(TEST_INTERFACE1), eq(OFFLOAD_SERVICEINFO))
// Need both advertisers to finish probing and call onRegisterServiceSucceeded
verify(cb, never()).onRegisterServiceSucceeded(anyInt(), any())
doReturn(false).`when`(mockInterfaceAdvertiser2).isProbing(SERVICE_ID_1)
postSync { intAdvCbCaptor2.value.onServiceProbingSucceeded(
- mockInterfaceAdvertiser2, SERVICE_ID_1) }
+ mockInterfaceAdvertiser2,
+ SERVICE_ID_1
+ ) }
verify(cb).onOffloadStartOrUpdate(eq(TEST_INTERFACE2), eq(OFFLOAD_SERVICEINFO))
- verify(cb).onRegisterServiceSucceeded(eq(SERVICE_ID_1),
- argThat { it.matches(ALL_NETWORKS_SERVICE_SUBTYPE) })
+ verify(cb).onRegisterServiceSucceeded(
+ eq(SERVICE_ID_1),
+ argThat { it.matches(ALL_NETWORKS_SERVICE_SUBTYPE) }
+ )
// Services are conflicted.
postSync {
@@ -378,19 +451,30 @@
val advertiser =
MdnsAdvertiser(thread.looper, socketProvider, cb, mockDeps, sharedlog, flags, context)
postSync {
- advertiser.addOrUpdateService(SERVICE_ID_1, SERVICE_1, DEFAULT_ADVERTISING_OPTION,
- TEST_CLIENT_UID_1)
- advertiser.addOrUpdateService(SERVICE_ID_2,
+ advertiser.addOrUpdateService(
+ SERVICE_ID_1,
+ SERVICE_1,
+ DEFAULT_ADVERTISING_OPTION,
+ TEST_CLIENT_UID_1
+ )
+ advertiser.addOrUpdateService(
+ SERVICE_ID_2,
NsdServiceInfo("TestService2", "_PRIORITYTEST._udp").apply {
port = 12345
hostAddresses = listOf(TEST_ADDR)
- }, DEFAULT_ADVERTISING_OPTION, TEST_CLIENT_UID_1)
+ },
+ DEFAULT_ADVERTISING_OPTION,
+ TEST_CLIENT_UID_1
+ )
advertiser.addOrUpdateService(
SERVICE_ID_3,
NsdServiceInfo("TestService3", "_notprioritized._tcp").apply {
port = 12345
hostAddresses = listOf(TEST_ADDR)
- }, DEFAULT_ADVERTISING_OPTION, TEST_CLIENT_UID_1)
+ },
+ DEFAULT_ADVERTISING_OPTION,
+ TEST_CLIENT_UID_1
+ )
}
val socketCbCaptor = ArgumentCaptor.forClass(SocketCallback::class.java)
@@ -400,8 +484,15 @@
postSync { socketCb.onSocketCreated(TEST_SOCKETKEY_1, mockSocket1, listOf(TEST_LINKADDR)) }
val intAdvCbCaptor1 = ArgumentCaptor.forClass(MdnsInterfaceAdvertiser.Callback::class.java)
- verify(mockDeps).makeAdvertiser(eq(mockSocket1), eq(listOf(TEST_LINKADDR)),
- eq(thread.looper), any(), intAdvCbCaptor1.capture(), eq(TEST_HOSTNAME), any(), any()
+ verify(mockDeps).makeAdvertiser(
+ eq(mockSocket1),
+ eq(listOf(TEST_LINKADDR)),
+ eq(thread.looper),
+ any(),
+ intAdvCbCaptor1.capture(),
+ eq(TEST_HOSTNAME),
+ any(),
+ any()
)
doReturn(false).`when`(mockInterfaceAdvertiser1).isProbing(SERVICE_ID_1)
@@ -433,30 +524,88 @@
}
@Test
+ fun testAddService_NoSubtypeForGoogleCastOffload() {
+ val advertiser =
+ MdnsAdvertiser(thread.looper, socketProvider, cb, mockDeps, sharedlog, flags, context)
+ postSync {
+ advertiser.addOrUpdateService(
+ SERVICE_ID_1,
+ GOOGLECAST_SERVICE,
+ DEFAULT_ADVERTISING_OPTION,
+ TEST_CLIENT_UID_1
+ )
+ }
+ val socketCbCaptor = ArgumentCaptor.forClass(SocketCallback::class.java)
+ verify(socketProvider).requestSocket(eq(SERVICE_1.network), socketCbCaptor.capture())
+
+ val socketCb = socketCbCaptor.value
+ postSync { socketCb.onSocketCreated(TEST_SOCKETKEY_1, mockSocket1, listOf(TEST_LINKADDR)) }
+
+ val intAdvCbCaptor1 = ArgumentCaptor.forClass(MdnsInterfaceAdvertiser.Callback::class.java)
+ verify(mockDeps).makeAdvertiser(
+ eq(mockSocket1),
+ eq(listOf(TEST_LINKADDR)),
+ eq(thread.looper),
+ any(),
+ intAdvCbCaptor1.capture(),
+ eq(TEST_HOSTNAME),
+ any(),
+ any()
+ )
+
+ doReturn(false).`when`(mockInterfaceAdvertiser1).isProbing(SERVICE_ID_1)
+ postSync {
+ intAdvCbCaptor1.value.onServiceProbingSucceeded(mockInterfaceAdvertiser1, SERVICE_ID_1)
+ }
+
+ verify(cb).onOffloadStartOrUpdate(eq(TEST_INTERFACE1), eq(OFFLOAD_SERVICE_INFO_GOOGLECAST))
+ }
+
+ @Test
fun testAddService_Conflicts() {
val advertiser =
MdnsAdvertiser(thread.looper, socketProvider, cb, mockDeps, sharedlog, flags, context)
- postSync { advertiser.addOrUpdateService(SERVICE_ID_1, SERVICE_1,
- DEFAULT_ADVERTISING_OPTION, TEST_CLIENT_UID_1) }
+ postSync { advertiser.addOrUpdateService(
+ SERVICE_ID_1,
+ SERVICE_1,
+ DEFAULT_ADVERTISING_OPTION,
+ TEST_CLIENT_UID_1
+ ) }
val oneNetSocketCbCaptor = ArgumentCaptor.forClass(SocketCallback::class.java)
verify(socketProvider).requestSocket(eq(TEST_NETWORK_1), oneNetSocketCbCaptor.capture())
val oneNetSocketCb = oneNetSocketCbCaptor.value
// Register a service with the same name on all networks (name conflict)
- postSync { advertiser.addOrUpdateService(SERVICE_ID_2, ALL_NETWORKS_SERVICE,
- DEFAULT_ADVERTISING_OPTION, TEST_CLIENT_UID_1) }
+ postSync { advertiser.addOrUpdateService(
+ SERVICE_ID_2,
+ ALL_NETWORKS_SERVICE,
+ DEFAULT_ADVERTISING_OPTION,
+ TEST_CLIENT_UID_1
+ ) }
val allNetSocketCbCaptor = ArgumentCaptor.forClass(SocketCallback::class.java)
verify(socketProvider).requestSocket(eq(null), allNetSocketCbCaptor.capture())
val allNetSocketCb = allNetSocketCbCaptor.value
- postSync { advertiser.addOrUpdateService(LONG_SERVICE_ID_1, LONG_SERVICE_1,
- DEFAULT_ADVERTISING_OPTION, TEST_CLIENT_UID_1) }
- postSync { advertiser.addOrUpdateService(LONG_SERVICE_ID_2, LONG_ALL_NETWORKS_SERVICE,
- DEFAULT_ADVERTISING_OPTION, TEST_CLIENT_UID_1) }
+ postSync { advertiser.addOrUpdateService(
+ LONG_SERVICE_ID_1,
+ LONG_SERVICE_1,
+ DEFAULT_ADVERTISING_OPTION,
+ TEST_CLIENT_UID_1
+ ) }
+ postSync { advertiser.addOrUpdateService(
+ LONG_SERVICE_ID_2,
+ LONG_ALL_NETWORKS_SERVICE,
+ DEFAULT_ADVERTISING_OPTION,
+ TEST_CLIENT_UID_1
+ ) }
- postSync { advertiser.addOrUpdateService(CASE_INSENSITIVE_TEST_SERVICE_ID,
- ALL_NETWORKS_SERVICE_2, DEFAULT_ADVERTISING_OPTION, TEST_CLIENT_UID_1) }
+ postSync { advertiser.addOrUpdateService(
+ CASE_INSENSITIVE_TEST_SERVICE_ID,
+ ALL_NETWORKS_SERVICE_2,
+ DEFAULT_ADVERTISING_OPTION,
+ TEST_CLIENT_UID_1
+ ) }
// Callbacks for matching network and all networks both get the socket
postSync {
@@ -465,7 +614,9 @@
}
val expectedRenamed = NsdServiceInfo(
- "${ALL_NETWORKS_SERVICE.serviceName} (2)", ALL_NETWORKS_SERVICE.serviceType).apply {
+ "${ALL_NETWORKS_SERVICE.serviceName} (2)",
+ ALL_NETWORKS_SERVICE.serviceType
+ ).apply {
port = ALL_NETWORKS_SERVICE.port
hostAddresses = ALL_NETWORKS_SERVICE.hostAddresses
network = ALL_NETWORKS_SERVICE.network
@@ -473,14 +624,16 @@
val expectedLongRenamed = NsdServiceInfo(
"${LONG_ALL_NETWORKS_SERVICE.serviceName.dropLast(4)} (2)",
- LONG_ALL_NETWORKS_SERVICE.serviceType).apply {
+ LONG_ALL_NETWORKS_SERVICE.serviceType
+ ).apply {
port = LONG_ALL_NETWORKS_SERVICE.port
hostAddresses = LONG_ALL_NETWORKS_SERVICE.hostAddresses
network = LONG_ALL_NETWORKS_SERVICE.network
}
val expectedCaseInsensitiveRenamed = NsdServiceInfo(
- "${ALL_NETWORKS_SERVICE_2.serviceName} (3)", ALL_NETWORKS_SERVICE_2.serviceType
+ "${ALL_NETWORKS_SERVICE_2.serviceName} (3)",
+ ALL_NETWORKS_SERVICE_2.serviceType
).apply {
port = ALL_NETWORKS_SERVICE_2.port
hostAddresses = ALL_NETWORKS_SERVICE_2.hostAddresses
@@ -488,30 +641,58 @@
}
val intAdvCbCaptor = ArgumentCaptor.forClass(MdnsInterfaceAdvertiser.Callback::class.java)
- verify(mockDeps).makeAdvertiser(eq(mockSocket1), eq(listOf(TEST_LINKADDR)),
- eq(thread.looper), any(), intAdvCbCaptor.capture(), eq(TEST_HOSTNAME), any(), any()
+ verify(mockDeps).makeAdvertiser(
+ eq(mockSocket1),
+ eq(listOf(TEST_LINKADDR)),
+ eq(thread.looper),
+ any(),
+ intAdvCbCaptor.capture(),
+ eq(TEST_HOSTNAME),
+ any(),
+ any()
)
- verify(mockInterfaceAdvertiser1).addService(eq(SERVICE_ID_1),
- argThat { it.matches(SERVICE_1) }, any())
- verify(mockInterfaceAdvertiser1).addService(eq(SERVICE_ID_2),
- argThat { it.matches(expectedRenamed) }, any())
- verify(mockInterfaceAdvertiser1).addService(eq(LONG_SERVICE_ID_1),
- argThat { it.matches(LONG_SERVICE_1) }, any())
- verify(mockInterfaceAdvertiser1).addService(eq(LONG_SERVICE_ID_2),
- argThat { it.matches(expectedLongRenamed) }, any())
- verify(mockInterfaceAdvertiser1).addService(eq(CASE_INSENSITIVE_TEST_SERVICE_ID),
- argThat { it.matches(expectedCaseInsensitiveRenamed) }, any())
+ verify(mockInterfaceAdvertiser1).addService(
+ eq(SERVICE_ID_1),
+ argThat { it.matches(SERVICE_1) },
+ any()
+ )
+ verify(mockInterfaceAdvertiser1).addService(
+ eq(SERVICE_ID_2),
+ argThat { it.matches(expectedRenamed) },
+ any()
+ )
+ verify(mockInterfaceAdvertiser1).addService(
+ eq(LONG_SERVICE_ID_1),
+ argThat { it.matches(LONG_SERVICE_1) },
+ any()
+ )
+ verify(mockInterfaceAdvertiser1).addService(
+ eq(LONG_SERVICE_ID_2),
+ argThat { it.matches(expectedLongRenamed) },
+ any()
+ )
+ verify(mockInterfaceAdvertiser1).addService(
+ eq(CASE_INSENSITIVE_TEST_SERVICE_ID),
+ argThat { it.matches(expectedCaseInsensitiveRenamed) },
+ any()
+ )
doReturn(false).`when`(mockInterfaceAdvertiser1).isProbing(SERVICE_ID_1)
postSync { intAdvCbCaptor.value.onServiceProbingSucceeded(
- mockInterfaceAdvertiser1, SERVICE_ID_1) }
+ mockInterfaceAdvertiser1,
+ SERVICE_ID_1
+ ) }
verify(cb).onRegisterServiceSucceeded(eq(SERVICE_ID_1), argThat { it.matches(SERVICE_1) })
doReturn(false).`when`(mockInterfaceAdvertiser1).isProbing(SERVICE_ID_2)
postSync { intAdvCbCaptor.value.onServiceProbingSucceeded(
- mockInterfaceAdvertiser1, SERVICE_ID_2) }
- verify(cb).onRegisterServiceSucceeded(eq(SERVICE_ID_2),
- argThat { it.matches(expectedRenamed) })
+ mockInterfaceAdvertiser1,
+ SERVICE_ID_2
+ ) }
+ verify(cb).onRegisterServiceSucceeded(
+ eq(SERVICE_ID_2),
+ argThat { it.matches(expectedRenamed) }
+ )
postSync { oneNetSocketCb.onInterfaceDestroyed(TEST_SOCKETKEY_1, mockSocket1) }
postSync { allNetSocketCb.onInterfaceDestroyed(TEST_SOCKETKEY_1, mockSocket1) }
@@ -523,10 +704,21 @@
@Test
fun testAddOrUpdateService_Updates() {
val advertiser =
- MdnsAdvertiser(thread.looper, socketProvider, cb, mockDeps, sharedlog, flags,
- context)
- postSync { advertiser.addOrUpdateService(SERVICE_ID_1, ALL_NETWORKS_SERVICE,
- DEFAULT_ADVERTISING_OPTION, TEST_CLIENT_UID_1) }
+ MdnsAdvertiser(
+ thread.looper,
+ socketProvider,
+ cb,
+ mockDeps,
+ sharedlog,
+ flags,
+ context
+ )
+ postSync { advertiser.addOrUpdateService(
+ SERVICE_ID_1,
+ ALL_NETWORKS_SERVICE,
+ DEFAULT_ADVERTISING_OPTION,
+ TEST_CLIENT_UID_1
+ ) }
val socketCbCaptor = ArgumentCaptor.forClass(SocketCallback::class.java)
verify(socketProvider).requestSocket(eq(null), socketCbCaptor.capture())
@@ -534,41 +726,70 @@
val socketCb = socketCbCaptor.value
postSync { socketCb.onSocketCreated(TEST_SOCKETKEY_1, mockSocket1, listOf(TEST_LINKADDR)) }
- verify(mockInterfaceAdvertiser1).addService(eq(SERVICE_ID_1),
- argThat { it.matches(ALL_NETWORKS_SERVICE) }, any())
+ verify(mockInterfaceAdvertiser1).addService(
+ eq(SERVICE_ID_1),
+ argThat { it.matches(ALL_NETWORKS_SERVICE) },
+ any()
+ )
val updateOptions = MdnsAdvertisingOptions.newBuilder().setIsOnlyUpdate(true).build()
// Update with serviceId that is not registered yet should fail
- postSync { advertiser.addOrUpdateService(SERVICE_ID_2, ALL_NETWORKS_SERVICE_SUBTYPE,
- updateOptions, TEST_CLIENT_UID_1) }
+ postSync { advertiser.addOrUpdateService(
+ SERVICE_ID_2,
+ ALL_NETWORKS_SERVICE_SUBTYPE,
+ updateOptions,
+ TEST_CLIENT_UID_1
+ ) }
verify(cb).onRegisterServiceFailed(SERVICE_ID_2, NsdManager.FAILURE_INTERNAL_ERROR)
// Update service with different NsdServiceInfo should fail
- postSync { advertiser.addOrUpdateService(SERVICE_ID_1, SERVICE_1_SUBTYPE, updateOptions,
- TEST_CLIENT_UID_1) }
+ postSync { advertiser.addOrUpdateService(
+ SERVICE_ID_1,
+ SERVICE_1_SUBTYPE,
+ updateOptions,
+ TEST_CLIENT_UID_1
+ ) }
verify(cb).onRegisterServiceFailed(SERVICE_ID_1, NsdManager.FAILURE_INTERNAL_ERROR)
// Update service with same NsdServiceInfo but different subType should succeed
- postSync { advertiser.addOrUpdateService(SERVICE_ID_1, ALL_NETWORKS_SERVICE_SUBTYPE,
- updateOptions, TEST_CLIENT_UID_1) }
+ postSync { advertiser.addOrUpdateService(
+ SERVICE_ID_1,
+ ALL_NETWORKS_SERVICE_SUBTYPE,
+ updateOptions,
+ TEST_CLIENT_UID_1
+ ) }
verify(mockInterfaceAdvertiser1).updateService(eq(SERVICE_ID_1), eq(setOf(TEST_SUBTYPE)))
// Newly created MdnsInterfaceAdvertiser will get addService() call.
postSync { socketCb.onSocketCreated(TEST_SOCKETKEY_2, mockSocket2, listOf(TEST_LINKADDR2)) }
- verify(mockInterfaceAdvertiser2).addService(eq(SERVICE_ID_1),
- argThat { it.matches(ALL_NETWORKS_SERVICE_SUBTYPE) }, any())
+ verify(mockInterfaceAdvertiser2).addService(
+ eq(SERVICE_ID_1),
+ argThat { it.matches(ALL_NETWORKS_SERVICE_SUBTYPE) },
+ any()
+ )
}
@Test
fun testAddOrUpdateService_customTtl_registeredSuccess() {
val advertiser = MdnsAdvertiser(
- thread.looper, socketProvider, cb, mockDeps, sharedlog, flags, context)
+ thread.looper,
+ socketProvider,
+ cb,
+ mockDeps,
+ sharedlog,
+ flags,
+ context
+ )
val updateOptions =
MdnsAdvertisingOptions.newBuilder().setTtl(Duration.ofSeconds(30)).build()
- postSync { advertiser.addOrUpdateService(SERVICE_ID_1, ALL_NETWORKS_SERVICE,
- updateOptions, TEST_CLIENT_UID_1) }
+ postSync { advertiser.addOrUpdateService(
+ SERVICE_ID_1,
+ ALL_NETWORKS_SERVICE,
+ updateOptions,
+ TEST_CLIENT_UID_1
+ ) }
val socketCbCaptor = ArgumentCaptor.forClass(SocketCallback::class.java)
verify(socketProvider).requestSocket(eq(null), socketCbCaptor.capture())
@@ -582,8 +803,12 @@
val advertiser =
MdnsAdvertiser(thread.looper, socketProvider, cb, mockDeps, sharedlog, flags, context)
verify(mockDeps, times(1)).generateHostname(anyBoolean())
- postSync { advertiser.addOrUpdateService(SERVICE_ID_1, SERVICE_1,
- DEFAULT_ADVERTISING_OPTION, TEST_CLIENT_UID_1) }
+ postSync { advertiser.addOrUpdateService(
+ SERVICE_ID_1,
+ SERVICE_1,
+ DEFAULT_ADVERTISING_OPTION,
+ TEST_CLIENT_UID_1
+ ) }
postSync { advertiser.removeService(SERVICE_ID_1) }
verify(mockDeps, times(2)).generateHostname(anyBoolean())
}
@@ -593,8 +818,12 @@
val flags = MdnsFeatureFlags.newBuilder().setIsShortHostnamesEnabled(shortHostname).build()
val advertiser =
MdnsAdvertiser(thread.looper, socketProvider, cb, mockDeps, sharedlog, flags, context)
- postSync { advertiser.addOrUpdateService(SERVICE_ID_1, SERVICE_1,
- DEFAULT_ADVERTISING_OPTION, TEST_CLIENT_UID_1) }
+ postSync { advertiser.addOrUpdateService(
+ SERVICE_ID_1,
+ SERVICE_1,
+ DEFAULT_ADVERTISING_OPTION,
+ TEST_CLIENT_UID_1
+ ) }
val socketCbCaptor = ArgumentCaptor.forClass(SocketCallback::class.java)
verify(socketProvider).requestSocket(eq(TEST_NETWORK_1), socketCbCaptor.capture())
@@ -621,8 +850,10 @@
val hostname = doHostnameGenerationTest(shortHostname = true)
// Short hostnames are [8 uppercase letters or digits].local
assertEquals(2, hostname.size)
- assertTrue(Regex("Android_[A-Z0-9]{8}").matches(hostname[0]),
- "Unexpected hostname: ${hostname.contentToString()}")
+ assertTrue(
+ Regex("Android_[A-Z0-9]{8}").matches(hostname[0]),
+ "Unexpected hostname: ${hostname.contentToString()}"
+ )
assertEquals("local", hostname[1])
}
@@ -631,8 +862,10 @@
val hostname = doHostnameGenerationTest(shortHostname = false)
// Long hostnames are Android_[32 lowercase hex characters].local
assertEquals(2, hostname.size)
- assertTrue(Regex("Android_[a-f0-9]{32}").matches(hostname[0]),
- "Unexpected hostname: ${hostname.contentToString()}")
+ assertTrue(
+ Regex("Android_[a-f0-9]{32}").matches(hostname[0]),
+ "Unexpected hostname: ${hostname.contentToString()}"
+ )
assertEquals("local", hostname[1])
}