Merge "[Thread] ignore all meshcop CTS tests before it's made stable" into main
diff --git a/bpf/headers/include/bpf/BpfUtils.h b/bpf/headers/include/bpf/BpfUtils.h
index 9e8b2c7..ed08e1a 100644
--- a/bpf/headers/include/bpf/BpfUtils.h
+++ b/bpf/headers/include/bpf/BpfUtils.h
@@ -26,6 +26,7 @@
#include <sys/socket.h>
#include <sys/utsname.h>
+#include <android-base/properties.h>
#include <log/log.h>
#include "KernelUtils.h"
@@ -33,6 +34,16 @@
namespace android {
namespace bpf {
+const bool unreleased = (base::GetProperty("ro.build.version.codename", "REL") != "REL");
+const int api_level = unreleased ? 10000 : android_get_device_api_level();
+const bool isAtLeastR = (api_level >= 30);
+const bool isAtLeastS = (api_level >= 31);
+// Sv2 is 32
+const bool isAtLeastT = (api_level >= 33);
+const bool isAtLeastU = (api_level >= 34);
+const bool isAtLeastV = (api_level >= 35);
+const bool isAtLeast25Q2 = (api_level >= 36);
+
// See kernel's net/core/sock_diag.c __sock_gen_cookie()
// the implementation of which guarantees 0 will never be returned,
// primarily because 0 is used to mean not yet initialized,
diff --git a/bpf/loader/NetBpfLoad.cpp b/bpf/loader/NetBpfLoad.cpp
index 40d1281..9486e75 100644
--- a/bpf/loader/NetBpfLoad.cpp
+++ b/bpf/loader/NetBpfLoad.cpp
@@ -1414,37 +1414,6 @@
static int doLoad(char** argv, char * const envp[]) {
const bool runningAsRoot = !getuid(); // true iff U QPR3 or V+
- // Any released device will have codename REL instead of a 'real' codename.
- // For safety: default to 'REL' so we default to unreleased=false on failure.
- const bool unreleased = (GetProperty("ro.build.version.codename", "REL") != "REL");
-
- // goog/main device_api_level is bumped *way* before aosp/main api level
- // (the latter only gets bumped during the push of goog/main to aosp/main)
- //
- // Since we develop in AOSP, we want it to behave as if it was bumped too.
- //
- // Note that AOSP doesn't really have a good api level (for example during
- // early V dev cycle, it would have *all* of T, some but not all of U, and some V).
- // One could argue that for our purposes AOSP api level should be infinite or 10000.
- //
- // This could also cause api to be increased in goog/main or other branches,
- // but I can't imagine a case where this would be a problem: the problem
- // is rather a too low api level, rather than some ill defined high value.
- // For example as I write this aosp is 34/U, and goog is 35/V,
- // we want to treat both goog & aosp as 35/V, but it's harmless if we
- // treat goog as 36 because that value isn't yet defined to mean anything,
- // and we thus never compare against it.
- //
- // Also note that 'android_get_device_api_level()' is what the
- // //system/core/init/apex_init_util.cpp
- // apex init .XXrc parsing code uses for XX filtering, and that code
- // (now) similarly uses __ANDROID_API_FUTURE__ for non 'REL' codenames.
- const int api_level = unreleased ? __ANDROID_API_FUTURE__ : android_get_device_api_level();
- const bool isAtLeastT = (api_level >= __ANDROID_API_T__);
- const bool isAtLeastU = (api_level >= __ANDROID_API_U__);
- const bool isAtLeastV = (api_level >= __ANDROID_API_V__);
- const bool isAtLeast25Q2 = (api_level > __ANDROID_API_V__); // TODO: fix >
-
const int first_api_level = GetIntProperty("ro.board.first_api_level", api_level);
// last in U QPR2 beta1
@@ -1591,7 +1560,7 @@
if (isArm() && (isTV() || isWear())) {
// exempt Arm TV or Wear devices (arm32 ABI is far less problematic than x86-32)
ALOGW("[Arm TV/Wear] 32-bit userspace unsupported on 6.2+ kernels.");
- } else if (first_api_level <= __ANDROID_API_T__ && isArm()) {
+ } else if (first_api_level <= 33 /*T*/ && isArm()) {
// also exempt Arm devices upgrading with major kernel rev from T-
// might possibly be better for them to run with a newer kernel...
ALOGW("[Arm KernelUpRev] 32-bit userspace unsupported on 6.2+ kernels.");
diff --git a/bpf/netd/BpfHandler.cpp b/bpf/netd/BpfHandler.cpp
index 125f26b..e3e508b 100644
--- a/bpf/netd/BpfHandler.cpp
+++ b/bpf/netd/BpfHandler.cpp
@@ -22,7 +22,6 @@
#include <inttypes.h>
#include <android-base/unique_fd.h>
-#include <android-modules-utils/sdk_level.h>
#include <bpf/WaitForProgsLoaded.h>
#include <log/log.h>
#include <netdutils/UidConstants.h>
@@ -37,6 +36,10 @@
using base::WaitForProperty;
using bpf::getSocketCookie;
using bpf::isAtLeastKernelVersion;
+using bpf::isAtLeastT;
+using bpf::isAtLeastU;
+using bpf::isAtLeastV;
+using bpf::isAtLeast25Q2;
using bpf::queryProgram;
using bpf::retrieveProgram;
using netdutils::Status;
@@ -72,18 +75,11 @@
return netdutils::status::ok;
}
-// Checks if the device is running on release version of Android 25Q2 or newer.
-static bool isAtLeast25Q2() {
- return android_get_device_api_level() >= 36 ||
- (android_get_device_api_level() == 35 &&
- modules::sdklevel::detail::IsAtLeastPreReleaseCodename("Baklava"));
-}
-
static Status initPrograms(const char* cg2_path) {
if (!cg2_path) return Status("cg2_path is NULL");
// This code was mainlined in T, so this should be trivially satisfied.
- if (!modules::sdklevel::IsAtLeastT()) return Status("S- platform is unsupported");
+ if (!isAtLeastT) return Status("S- platform is unsupported");
// S requires eBPF support which was only added in 4.9, so this should be satisfied.
if (!isAtLeastKernelVersion(4, 9, 0)) {
@@ -91,22 +87,22 @@
}
// U bumps the kernel requirement up to 4.14
- if (modules::sdklevel::IsAtLeastU() && !isAtLeastKernelVersion(4, 14, 0)) {
+ if (isAtLeastU && !isAtLeastKernelVersion(4, 14, 0)) {
return Status("U+ platform with kernel version < 4.14.0 is unsupported");
}
// U mandates this mount point (though it should also be the case on T)
- if (modules::sdklevel::IsAtLeastU() && !!strcmp(cg2_path, "/sys/fs/cgroup")) {
+ if (isAtLeastU && !!strcmp(cg2_path, "/sys/fs/cgroup")) {
return Status("U+ platform with cg2_path != /sys/fs/cgroup is unsupported");
}
// V bumps the kernel requirement up to 4.19
- if (modules::sdklevel::IsAtLeastV() && !isAtLeastKernelVersion(4, 19, 0)) {
+ if (isAtLeastV && !isAtLeastKernelVersion(4, 19, 0)) {
return Status("V+ platform with kernel version < 4.19.0 is unsupported");
}
// 25Q2 bumps the kernel requirement up to 5.4
- if (isAtLeast25Q2() && !isAtLeastKernelVersion(5, 4, 0)) {
+ if (isAtLeast25Q2 && !isAtLeastKernelVersion(5, 4, 0)) {
return Status("25Q2+ platform with kernel version < 5.4.0 is unsupported");
}
@@ -135,7 +131,7 @@
cg_fd, BPF_CGROUP_INET_SOCK_RELEASE));
}
- if (modules::sdklevel::IsAtLeastV()) {
+ if (isAtLeastV) {
// V requires 4.19+, so technically this 2nd 'if' is not required, but it
// doesn't hurt us to try to support AOSP forks that try to support older kernels.
if (isAtLeastKernelVersion(4, 19, 0)) {
@@ -180,7 +176,7 @@
if (queryProgram(cg_fd, BPF_CGROUP_INET_SOCK_RELEASE) <= 0) abort();
}
- if (modules::sdklevel::IsAtLeastV()) {
+ if (isAtLeastV) {
// V requires 4.19+, so technically this 2nd 'if' is not required, but it
// doesn't hurt us to try to support AOSP forks that try to support older kernels.
if (isAtLeastKernelVersion(4, 19, 0)) {
@@ -266,14 +262,13 @@
// ...unless someone changed 'exec_start bpfloader' to 'start bpfloader'
// in the rc file.
//
- // TODO: should be: if (!modules::sdklevel::IsAtLeastW())
- if (android_get_device_api_level() <= __ANDROID_API_V__) waitForBpf();
+ if (!isAtLeast25Q2) waitForBpf();
RETURN_IF_NOT_OK(initPrograms(cg2_path));
RETURN_IF_NOT_OK(initMaps());
- if (android_get_device_api_level() > __ANDROID_API_V__) {
- // make sure netd can create & write maps. sepolicy is V+, but enough to enforce on 25Q2+
+ if (isAtLeast25Q2) {
+ // Make sure netd can create & write maps. sepolicy is V+, but enough to enforce on 25Q2+
int key = 1;
int value = 123;
unique_fd map(bpf::createMap(BPF_MAP_TYPE_ARRAY, sizeof(key), sizeof(value), 2, 0));
diff --git a/bpf/tests/mts/bpf_existence_test.cpp b/bpf/tests/mts/bpf_existence_test.cpp
index 0ecda3d..75fb8e9 100644
--- a/bpf/tests/mts/bpf_existence_test.cpp
+++ b/bpf/tests/mts/bpf_existence_test.cpp
@@ -31,6 +31,12 @@
using std::string;
using android::bpf::isAtLeastKernelVersion;
+using android::bpf::isAtLeastR;
+using android::bpf::isAtLeastS;
+using android::bpf::isAtLeastT;
+using android::bpf::isAtLeastU;
+using android::bpf::isAtLeastV;
+using android::bpf::isAtLeast25Q2;
#define PLATFORM "/sys/fs/bpf/"
#define TETHERING "/sys/fs/bpf/tethering/"
@@ -42,16 +48,6 @@
class BpfExistenceTest : public ::testing::Test {
};
-const bool unreleased = (android::base::GetProperty("ro.build.version.codename", "REL") != "REL");
-const int api_level = unreleased ? 10000 : android_get_device_api_level();
-const bool isAtLeastR = (api_level >= 30);
-const bool isAtLeastS = (api_level >= 31);
-// Sv2 is 32
-const bool isAtLeastT = (api_level >= 33);
-const bool isAtLeastU = (api_level >= 34);
-const bool isAtLeastV = (api_level >= 35);
-const bool isAtLeast25Q2 = (api_level >= 36);
-
// Part of Android R platform (for 4.9+), but mainlined in S
static const set<string> PLATFORM_ONLY_IN_R = {
PLATFORM "map_offload_tether_ingress_map",
diff --git a/framework/src/android/net/L2capNetworkSpecifier.java b/framework/src/android/net/L2capNetworkSpecifier.java
index cfc9ed9..93f9352 100644
--- a/framework/src/android/net/L2capNetworkSpecifier.java
+++ b/framework/src/android/net/L2capNetworkSpecifier.java
@@ -170,6 +170,51 @@
return mPsm;
}
+ /**
+ * Checks whether the given L2capNetworkSpecifier is valid as part of a server network
+ * reservation request.
+ *
+ * @hide
+ */
+ public boolean isValidServerReservationSpecifier() {
+ // The ROLE_SERVER offer can be satisfied by a ROLE_ANY request.
+ if (mRole != ROLE_SERVER) return false;
+
+ // HEADER_COMPRESSION_ANY is never valid in a request.
+ if (mHeaderCompression == HEADER_COMPRESSION_ANY) return false;
+
+ // Remote address must be null for ROLE_SERVER requests.
+ if (mRemoteAddress != null) return false;
+
+ // reservation must allocate a PSM, so only PSM_ANY can be passed.
+ if (mPsm != PSM_ANY) return false;
+
+ return true;
+ }
+
+ /**
+ * Checks whether the given L2capNetworkSpecifier is valid as part of a client network request.
+ *
+ * @hide
+ */
+ public boolean isValidClientRequestSpecifier() {
+ // The ROLE_CLIENT offer can be satisfied by a ROLE_ANY request.
+ if (mRole != ROLE_CLIENT) return false;
+
+ // HEADER_COMPRESSION_ANY is never valid in a request.
+ if (mHeaderCompression == HEADER_COMPRESSION_ANY) return false;
+
+ // Remote address must not be null for ROLE_CLIENT requests.
+ if (mRemoteAddress == null) return false;
+
+ // Client network requests require a PSM to be specified.
+ // Ensure the PSM is within the valid range of dynamic BLE L2CAP values.
+ if (mPsm < 0x80) return false;
+ if (mPsm > 0xFF) return false;
+
+ return true;
+ }
+
/** A builder class for L2capNetworkSpecifier. */
public static final class Builder {
@Role
diff --git a/framework/src/android/net/NetworkAgentConfig.java b/framework/src/android/net/NetworkAgentConfig.java
index deaa734..da12a0a 100644
--- a/framework/src/android/net/NetworkAgentConfig.java
+++ b/framework/src/android/net/NetworkAgentConfig.java
@@ -272,27 +272,6 @@
return mVpnRequiresValidation;
}
- /**
- * Whether the native network creation should be skipped.
- *
- * If set, the native network and routes should be maintained by the caller.
- *
- * @hide
- */
- private boolean mSkipNativeNetworkCreation = false;
-
-
- /**
- * @return Whether the native network creation should be skipped.
- * @hide
- */
- // TODO: Expose API when ready.
- // @FlaggedApi(Flags.FLAG_TETHERING_NETWORK_AGENT)
- // @SystemApi(client = MODULE_LIBRARIES) when ready.
- public boolean shouldSkipNativeNetworkCreation() {
- return mSkipNativeNetworkCreation;
- }
-
/** @hide */
public NetworkAgentConfig() {
}
@@ -314,7 +293,6 @@
mLegacyExtraInfo = nac.mLegacyExtraInfo;
excludeLocalRouteVpn = nac.excludeLocalRouteVpn;
mVpnRequiresValidation = nac.mVpnRequiresValidation;
- mSkipNativeNetworkCreation = nac.mSkipNativeNetworkCreation;
}
}
@@ -506,26 +484,6 @@
}
/**
- * Sets the native network creation should be skipped.
- *
- * @return this builder, to facilitate chaining.
- * @hide
- */
- @NonNull
- // TODO: Expose API when ready.
- // @FlaggedApi(Flags.FLAG_TETHERING_NETWORK_AGENT)
- // @SystemApi(client = MODULE_LIBRARIES) when ready.
- public Builder setSkipNativeNetworkCreation(boolean skipNativeNetworkCreation) {
- if (!SdkLevel.isAtLeastV()) {
- // Local agents are supported starting on U on TVs and on V on everything else.
- // Thus, only support this flag on V+.
- throw new UnsupportedOperationException("Method is not supported");
- }
- mConfig.mSkipNativeNetworkCreation = skipNativeNetworkCreation;
- return this;
- }
-
- /**
* Returns the constructed {@link NetworkAgentConfig} object.
*/
@NonNull
@@ -552,8 +510,7 @@
&& Objects.equals(legacySubTypeName, that.legacySubTypeName)
&& Objects.equals(mLegacyExtraInfo, that.mLegacyExtraInfo)
&& excludeLocalRouteVpn == that.excludeLocalRouteVpn
- && mVpnRequiresValidation == that.mVpnRequiresValidation
- && mSkipNativeNetworkCreation == that.mSkipNativeNetworkCreation;
+ && mVpnRequiresValidation == that.mVpnRequiresValidation;
}
@Override
@@ -561,8 +518,7 @@
return Objects.hash(allowBypass, explicitlySelected, acceptUnvalidated,
acceptPartialConnectivity, provisioningNotificationDisabled, subscriberId,
skip464xlat, legacyType, legacySubType, legacyTypeName, legacySubTypeName,
- mLegacyExtraInfo, excludeLocalRouteVpn, mVpnRequiresValidation,
- mSkipNativeNetworkCreation);
+ mLegacyExtraInfo, excludeLocalRouteVpn, mVpnRequiresValidation);
}
@Override
@@ -583,7 +539,6 @@
+ ", legacyExtraInfo = '" + mLegacyExtraInfo + '\''
+ ", excludeLocalRouteVpn = '" + excludeLocalRouteVpn + '\''
+ ", vpnRequiresValidation = '" + mVpnRequiresValidation + '\''
- + ", skipNativeNetworkCreation = '" + mSkipNativeNetworkCreation + '\''
+ "}";
}
@@ -608,35 +563,33 @@
out.writeString(mLegacyExtraInfo);
out.writeInt(excludeLocalRouteVpn ? 1 : 0);
out.writeInt(mVpnRequiresValidation ? 1 : 0);
- out.writeInt(mSkipNativeNetworkCreation ? 1 : 0);
}
public static final @NonNull Creator<NetworkAgentConfig> CREATOR =
new Creator<NetworkAgentConfig>() {
- @Override
- public NetworkAgentConfig createFromParcel(Parcel in) {
- NetworkAgentConfig networkAgentConfig = new NetworkAgentConfig();
- networkAgentConfig.allowBypass = in.readInt() != 0;
- networkAgentConfig.explicitlySelected = in.readInt() != 0;
- networkAgentConfig.acceptUnvalidated = in.readInt() != 0;
- networkAgentConfig.acceptPartialConnectivity = in.readInt() != 0;
- networkAgentConfig.subscriberId = in.readString();
- networkAgentConfig.provisioningNotificationDisabled = in.readInt() != 0;
- networkAgentConfig.skip464xlat = in.readInt() != 0;
- networkAgentConfig.legacyType = in.readInt();
- networkAgentConfig.legacyTypeName = in.readString();
- networkAgentConfig.legacySubType = in.readInt();
- networkAgentConfig.legacySubTypeName = in.readString();
- networkAgentConfig.mLegacyExtraInfo = in.readString();
- networkAgentConfig.excludeLocalRouteVpn = in.readInt() != 0;
- networkAgentConfig.mVpnRequiresValidation = in.readInt() != 0;
- networkAgentConfig.mSkipNativeNetworkCreation = in.readInt() != 0;
- return networkAgentConfig;
- }
+ @Override
+ public NetworkAgentConfig createFromParcel(Parcel in) {
+ NetworkAgentConfig networkAgentConfig = new NetworkAgentConfig();
+ networkAgentConfig.allowBypass = in.readInt() != 0;
+ networkAgentConfig.explicitlySelected = in.readInt() != 0;
+ networkAgentConfig.acceptUnvalidated = in.readInt() != 0;
+ networkAgentConfig.acceptPartialConnectivity = in.readInt() != 0;
+ networkAgentConfig.subscriberId = in.readString();
+ networkAgentConfig.provisioningNotificationDisabled = in.readInt() != 0;
+ networkAgentConfig.skip464xlat = in.readInt() != 0;
+ networkAgentConfig.legacyType = in.readInt();
+ networkAgentConfig.legacyTypeName = in.readString();
+ networkAgentConfig.legacySubType = in.readInt();
+ networkAgentConfig.legacySubTypeName = in.readString();
+ networkAgentConfig.mLegacyExtraInfo = in.readString();
+ networkAgentConfig.excludeLocalRouteVpn = in.readInt() != 0;
+ networkAgentConfig.mVpnRequiresValidation = in.readInt() != 0;
+ return networkAgentConfig;
+ }
- @Override
- public NetworkAgentConfig[] newArray(int size) {
- return new NetworkAgentConfig[size];
- }
- };
+ @Override
+ public NetworkAgentConfig[] newArray(int size) {
+ return new NetworkAgentConfig[size];
+ }
+ };
}
diff --git a/framework/src/android/net/TestNetworkManager.java b/framework/src/android/net/TestNetworkManager.java
index 416c6de..cbc7a4f 100644
--- a/framework/src/android/net/TestNetworkManager.java
+++ b/framework/src/android/net/TestNetworkManager.java
@@ -23,8 +23,10 @@
import android.os.IBinder;
import android.os.RemoteException;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.List;
import java.util.Objects;
/**
@@ -196,45 +198,6 @@
}
/**
- * Create a tap interface for testing purposes
- *
- * @param linkAddrs an array of LinkAddresses to assign to the TAP interface
- * @return A TestNetworkInterface representing the underlying TAP interface. Close the contained
- * ParcelFileDescriptor to tear down the TAP interface.
- * @hide
- */
- @RequiresPermission(Manifest.permission.MANAGE_TEST_NETWORKS)
- @NonNull
- public TestNetworkInterface createTapInterface(@NonNull LinkAddress[] linkAddrs) {
- try {
- return mService.createInterface(TAP, CARRIER_UP, BRING_UP, USE_IPV6_PROV_DELAY,
- linkAddrs, null /* iface */);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Create a tap interface for testing purposes
- *
- * @param bringUp whether to bring up the interface before returning it.
- *
- * @return A ParcelFileDescriptor of the underlying TAP interface. Close this to tear down the
- * TAP interface.
- * @hide
- */
- @RequiresPermission(Manifest.permission.MANAGE_TEST_NETWORKS)
- @NonNull
- public TestNetworkInterface createTapInterface(boolean bringUp) {
- try {
- return mService.createInterface(TAP, CARRIER_UP, bringUp, USE_IPV6_PROV_DELAY,
- NO_ADDRS, null /* iface */);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
* Create a tap interface with a given interface name for testing purposes
*
* @param bringUp whether to bring up the interface before returning it.
@@ -258,26 +221,6 @@
}
/**
- * Create a tap interface with or without carrier for testing purposes.
- *
- * Note: setting carrierUp = false is not supported until kernel version 6.0.
- *
- * @param carrierUp whether the created interface has a carrier or not.
- * @param bringUp whether to bring up the interface before returning it.
- * @hide
- */
- @RequiresPermission(Manifest.permission.MANAGE_TEST_NETWORKS)
- @NonNull
- public TestNetworkInterface createTapInterface(boolean carrierUp, boolean bringUp) {
- try {
- return mService.createInterface(TAP, carrierUp, bringUp, USE_IPV6_PROV_DELAY, NO_ADDRS,
- null /* iface */);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
* Create a tap interface for testing purposes.
*
* Note: setting carrierUp = false is not supported until kernel version 6.0.
@@ -300,27 +243,6 @@
}
/**
- * Create a tap interface for testing purposes.
- *
- * @param disableIpv6ProvisioningDelay whether to disable DAD and RS delay.
- * @param linkAddrs an array of LinkAddresses to assign to the TAP interface
- * @return A TestNetworkInterface representing the underlying TAP interface. Close the contained
- * ParcelFileDescriptor to tear down the TAP interface.
- * @hide
- */
- @RequiresPermission(Manifest.permission.MANAGE_TEST_NETWORKS)
- @NonNull
- public TestNetworkInterface createTapInterface(boolean disableIpv6ProvisioningDelay,
- @NonNull LinkAddress[] linkAddrs) {
- try {
- return mService.createInterface(TAP, CARRIER_UP, BRING_UP, disableIpv6ProvisioningDelay,
- linkAddrs, null /* iface */);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
* Enable / disable carrier on TestNetworkInterface
*
* Note: TUNSETCARRIER is not supported until kernel version 5.0.
@@ -337,4 +259,110 @@
throw e.rethrowFromSystemServer();
}
}
+
+ /**
+ * Represents a request to create a tun/tap interface for testing.
+ *
+ * @hide
+ */
+ public static class TestInterfaceRequest {
+ public final boolean isTun;
+ public final boolean hasCarrier;
+ public final boolean bringUp;
+ public final boolean disableIpv6ProvDelay;
+ @Nullable public final String ifname;
+ public final LinkAddress[] linkAddresses;
+
+ private TestInterfaceRequest(boolean isTun, boolean hasCarrier, boolean bringUp,
+ boolean disableProvDelay, @Nullable String ifname, LinkAddress[] linkAddresses) {
+ this.isTun = isTun;
+ this.hasCarrier = hasCarrier;
+ this.bringUp = bringUp;
+ this.disableIpv6ProvDelay = disableProvDelay;
+ this.ifname = ifname;
+ this.linkAddresses = linkAddresses;
+ }
+
+ /**
+ * Builder class for TestInterfaceRequest
+ *
+ * Defaults to a tap interface with carrier that has been brought up.
+ */
+ public static class Builder {
+ private boolean mIsTun = false;
+ private boolean mHasCarrier = true;
+ private boolean mBringUp = true;
+ private boolean mDisableIpv6ProvDelay = false;
+ @Nullable private String mIfname;
+ private List<LinkAddress> mLinkAddresses = new ArrayList<>();
+
+ /** Create tun interface. */
+ public Builder setTun() {
+ mIsTun = true;
+ return this;
+ }
+
+ /** Create tap interface. */
+ public Builder setTap() {
+ mIsTun = false;
+ return this;
+ }
+
+ /** Configure whether the interface has carrier. */
+ public Builder setHasCarrier(boolean hasCarrier) {
+ mHasCarrier = hasCarrier;
+ return this;
+ }
+
+ /** Configure whether the interface should be brought up. */
+ public Builder setBringUp(boolean bringUp) {
+ mBringUp = bringUp;
+ return this;
+ }
+
+ /** Disable DAD and RS delay. */
+ public Builder setDisableIpv6ProvisioningDelay(boolean disableProvDelay) {
+ mDisableIpv6ProvDelay = disableProvDelay;
+ return this;
+ }
+
+ /** Set the interface name. */
+ public Builder setInterfaceName(@Nullable String ifname) {
+ mIfname = ifname;
+ return this;
+ }
+
+ /** The addresses to configure on the interface. */
+ public Builder addLinkAddress(LinkAddress la) {
+ mLinkAddresses.add(la);
+ return this;
+ }
+
+ /** Build TestInterfaceRequest */
+ public TestInterfaceRequest build() {
+ return new TestInterfaceRequest(mIsTun, mHasCarrier, mBringUp,
+ mDisableIpv6ProvDelay, mIfname, mLinkAddresses.toArray(new LinkAddress[0]));
+ }
+ }
+ }
+
+ /**
+ * Create a TestNetworkInterface (tun or tap) for testing purposes.
+ *
+ * @param request The request describing the interface to create.
+ * @return A TestNetworkInterface representing the underlying tun/tap interface. Close the
+ * contained ParcelFileDescriptor to tear down the tun/tap interface.
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.MANAGE_TEST_NETWORKS)
+ @NonNull
+ public TestNetworkInterface createTestInterface(@NonNull TestInterfaceRequest request) {
+ try {
+ // TODO: Make TestInterfaceRequest parcelable and pass it instead.
+ return mService.createInterface(request.isTun, request.hasCarrier, request.bringUp,
+ request.disableIpv6ProvDelay, request.linkAddresses, request.ifname);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsSocketProvider.java b/service-t/src/com/android/server/connectivity/mdns/MdnsSocketProvider.java
index 1212e29..d91bd11 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsSocketProvider.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsSocketProvider.java
@@ -564,7 +564,6 @@
// Never try mDNS on cellular, or on interfaces with incompatible flags
if (CollectionUtils.contains(transports, TRANSPORT_CELLULAR)
|| iface.isLoopback()
- || iface.isPointToPoint()
|| iface.isVirtual()
|| !iface.isUp()) {
return false;
diff --git a/service/ServiceConnectivityResources/OWNERS b/service/ServiceConnectivityResources/OWNERS
index df41ff2..c3c08ee 100644
--- a/service/ServiceConnectivityResources/OWNERS
+++ b/service/ServiceConnectivityResources/OWNERS
@@ -1,2 +1,3 @@
+per-file res/raw/ct_public_keys.pem = file:platform/packages/modules/Connectivity:main:/networksecurity/OWNERS
per-file res/values/config_thread.xml = file:platform/packages/modules/Connectivity:main:/thread/OWNERS
per-file res/values/overlayable.xml = file:platform/packages/modules/Connectivity:main:/thread/OWNERS
diff --git a/service/src/com/android/server/BpfNetMaps.java b/service/src/com/android/server/BpfNetMaps.java
index 7c0c223..36c0cf9 100644
--- a/service/src/com/android/server/BpfNetMaps.java
+++ b/service/src/com/android/server/BpfNetMaps.java
@@ -906,7 +906,12 @@
final InetAddress address, final int protocol, final int remotePort,
final boolean isAllowed) {
throwIfPre25Q2("addLocalNetAccess is not available on pre-B devices");
- final int ifIndex = mDeps.getIfIndex(iface);
+ final int ifIndex;
+ if (iface == null) {
+ ifIndex = 0;
+ } else {
+ ifIndex = mDeps.getIfIndex(iface);
+ }
if (ifIndex == 0) {
Log.e(TAG, "Failed to get if index, skip addLocalNetAccess for " + address
+ "(" + iface + ")");
@@ -935,7 +940,12 @@
public void removeLocalNetAccess(final int lpmBitlen, final String iface,
final InetAddress address, final int protocol, final int remotePort) {
throwIfPre25Q2("removeLocalNetAccess is not available on pre-B devices");
- final int ifIndex = mDeps.getIfIndex(iface);
+ final int ifIndex;
+ if (iface == null) {
+ ifIndex = 0;
+ } else {
+ ifIndex = mDeps.getIfIndex(iface);
+ }
if (ifIndex == 0) {
Log.e(TAG, "Failed to get if index, skip removeLocalNetAccess for " + address
+ "(" + iface + ")");
@@ -966,7 +976,12 @@
public boolean getLocalNetAccess(final int lpmBitlen, final String iface,
final InetAddress address, final int protocol, final int remotePort) {
throwIfPre25Q2("getLocalNetAccess is not available on pre-B devices");
- final int ifIndex = mDeps.getIfIndex(iface);
+ final int ifIndex;
+ if (iface == null) {
+ ifIndex = 0;
+ } else {
+ ifIndex = mDeps.getIfIndex(iface);
+ }
if (ifIndex == 0) {
Log.e(TAG, "Failed to get if index, returning default from getLocalNetAccess for "
+ address + "(" + iface + ")");
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index 6dbb1d8..adf593e 100644
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -1913,11 +1913,12 @@
&& mDeps.isFeatureEnabled(context, REQUEST_RESTRICTED_WIFI);
mBackgroundFirewallChainEnabled = mDeps.isAtLeastV() && mDeps.isFeatureNotChickenedOut(
context, ConnectivityFlags.BACKGROUND_FIREWALL_CHAIN);
- mUseDeclaredMethodsForCallbacksEnabled = mDeps.isFeatureEnabled(context,
- ConnectivityFlags.USE_DECLARED_METHODS_FOR_CALLBACKS);
+ mUseDeclaredMethodsForCallbacksEnabled =
+ mDeps.isFeatureNotChickenedOut(context,
+ ConnectivityFlags.USE_DECLARED_METHODS_FOR_CALLBACKS);
// registerUidFrozenStateChangedCallback is only available on U+
mQueueCallbacksForFrozenApps = mDeps.isAtLeastU()
- && mDeps.isFeatureEnabled(context, QUEUE_CALLBACKS_FOR_FROZEN_APPS);
+ && mDeps.isFeatureNotChickenedOut(context, QUEUE_CALLBACKS_FOR_FROZEN_APPS);
mCarrierPrivilegeAuthenticator = mDeps.makeCarrierPrivilegeAuthenticator(
mContext, mTelephonyManager, mRequestRestrictedWifiEnabled,
this::handleUidCarrierPrivilegesLost, mHandler);
diff --git a/service/src/com/android/server/L2capNetworkProvider.java b/service/src/com/android/server/L2capNetworkProvider.java
index 814a068..0352ad5 100644
--- a/service/src/com/android/server/L2capNetworkProvider.java
+++ b/service/src/com/android/server/L2capNetworkProvider.java
@@ -18,7 +18,6 @@
import static android.content.pm.PackageManager.FEATURE_BLUETOOTH_LE;
import static android.net.L2capNetworkSpecifier.HEADER_COMPRESSION_ANY;
-import static android.net.L2capNetworkSpecifier.PSM_ANY;
import static android.net.L2capNetworkSpecifier.ROLE_CLIENT;
import static android.net.L2capNetworkSpecifier.ROLE_SERVER;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_BANDWIDTH_CONSTRAINED;
@@ -61,6 +60,7 @@
import com.android.net.module.util.HandlerUtils;
import com.android.net.module.util.ServiceConnectivityJni;
import com.android.server.net.L2capNetwork;
+import com.android.server.net.L2capNetwork.L2capIpClient;
import com.android.server.net.L2capPacketForwarder;
import java.io.IOException;
@@ -126,23 +126,6 @@
CAPABILITIES = caps;
}
- // TODO: consider moving this into L2capNetworkSpecifier as #isValidServerReservation().
- private boolean isValidL2capServerSpecifier(L2capNetworkSpecifier l2capSpec) {
- // The ROLE_SERVER offer can be satisfied by a ROLE_ANY request.
- if (l2capSpec.getRole() != ROLE_SERVER) return false;
-
- // HEADER_COMPRESSION_ANY is never valid in a request.
- if (l2capSpec.getHeaderCompression() == HEADER_COMPRESSION_ANY) return false;
-
- // remoteAddr must be null for ROLE_SERVER requests.
- if (l2capSpec.getRemoteAddress() != null) return false;
-
- // reservation must allocate a PSM, so only PSM_ANY can be passed.
- if (l2capSpec.getPsm() != PSM_ANY) return false;
-
- return true;
- }
-
@Override
public void onNetworkNeeded(NetworkRequest request) {
// The NetworkSpecifier is guaranteed to be either null or an L2capNetworkSpecifier, so
@@ -150,7 +133,7 @@
final L2capNetworkSpecifier specifier =
(L2capNetworkSpecifier) request.getNetworkSpecifier();
if (specifier == null) return;
- if (!isValidL2capServerSpecifier(specifier)) {
+ if (!specifier.isValidServerReservationSpecifier()) {
Log.i(TAG, "Ignoring invalid reservation request: " + request);
return;
}
@@ -270,7 +253,6 @@
private class AcceptThread extends Thread {
private static final int TIMEOUT_MS = 500;
private final BluetoothServerSocket mServerSocket;
- private volatile boolean mIsRunning = true;
public AcceptThread(BluetoothServerSocket serverSocket) {
super("L2capNetworkProvider-AcceptThread");
@@ -294,16 +276,17 @@
@Override
public void run() {
- while (mIsRunning) {
+ while (true) {
final BluetoothSocket connectedSocket;
try {
connectedSocket = mServerSocket.accept();
} catch (IOException e) {
- // BluetoothServerSocket was closed().
- if (!mIsRunning) return;
-
- // Else, BluetoothServerSocket encountered exception.
- Log.e(TAG, "BluetoothServerSocket#accept failed", e);
+ // Note calling BluetoothServerSocket#close() also triggers an IOException
+ // which is indistinguishable from any other exceptional behavior.
+ // postDestroyAndUnregisterReservedOffer() is always safe to call as it
+ // first checks whether the offer still exists; so if the
+ // BluetoothServerSocket was closed (i.e. on tearDown()) this is a noop.
+ Log.w(TAG, "BluetoothServerSocket closed or #accept failed", e);
postDestroyAndUnregisterReservedOffer();
return; // stop running immediately on error
}
@@ -313,7 +296,6 @@
public void tearDown() {
HandlerUtils.ensureRunningOnHandlerThread(mHandler);
- mIsRunning = false;
try {
// BluetoothServerSocket.close() is thread-safe.
mServerSocket.close();
@@ -434,7 +416,6 @@
private class ConnectThread extends Thread {
private final L2capNetworkSpecifier mSpecifier;
private final BluetoothSocket mSocket;
- private volatile boolean mIsAborted = false;
public ConnectThread(L2capNetworkSpecifier specifier, BluetoothSocket socket) {
super("L2capNetworkProvider-ConnectThread");
@@ -451,11 +432,12 @@
if (!success) closeBluetoothSocket(mSocket);
});
} catch (IOException e) {
- Log.e(TAG, "Failed to connect", e);
- if (mIsAborted) return;
-
+ Log.w(TAG, "BluetoothSocket was closed or #connect failed", e);
+ // It is safe to call BluetoothSocket#close() multiple times.
closeBluetoothSocket(mSocket);
mHandler.post(() -> {
+ // Note that if the Socket was closed, this call is a noop as the
+ // ClientNetworkRequest has already been removed.
declareAllNetworkRequestsUnfulfillable(mSpecifier);
});
}
@@ -463,7 +445,6 @@
public void abort() {
HandlerUtils.ensureRunningOnHandlerThread(mHandler);
- mIsAborted = true;
// Closing the BluetoothSocket is the only way to unblock connect() because it calls
// shutdown on the underlying (connected) SOCK_SEQPACKET.
// It is safe to call BluetoothSocket#close() multiple times.
@@ -510,24 +491,6 @@
return true;
}
- private boolean isValidL2capClientSpecifier(L2capNetworkSpecifier l2capSpec) {
- // The ROLE_CLIENT offer can be satisfied by a ROLE_ANY request.
- if (l2capSpec.getRole() != ROLE_CLIENT) return false;
-
- // HEADER_COMPRESSION_ANY is never valid in a request.
- if (l2capSpec.getHeaderCompression() == HEADER_COMPRESSION_ANY) return false;
-
- // remoteAddr must not be null for ROLE_CLIENT requests.
- if (l2capSpec.getRemoteAddress() == null) return false;
-
- // Client network requests require a PSM to be specified.
- // Ensure the PSM is within the valid range of dynamic BLE L2CAP values.
- if (l2capSpec.getPsm() < 0x80) return false;
- if (l2capSpec.getPsm() > 0xFF) return false;
-
- return true;
- }
-
@Override
public void onNetworkNeeded(NetworkRequest request) {
// The NetworkSpecifier is guaranteed to be either null or an L2capNetworkSpecifier, so
@@ -535,7 +498,7 @@
final L2capNetworkSpecifier requestSpecifier =
(L2capNetworkSpecifier) request.getNetworkSpecifier();
if (requestSpecifier == null) return;
- if (!isValidL2capClientSpecifier(requestSpecifier)) {
+ if (!requestSpecifier.isValidClientRequestSpecifier()) {
Log.i(TAG, "Ignoring invalid client request: " + request);
return;
}
@@ -680,6 +643,11 @@
L2capPacketForwarder.ICallback cb) {
return new L2capPacketForwarder(handler, tunFd, socket, compressHeaders, cb);
}
+
+ /** Create an L2capIpClient */
+ public L2capIpClient createL2capIpClient(String logTag, Context context, String ifname) {
+ return new L2capIpClient(logTag, context, ifname);
+ }
}
public L2capNetworkProvider(Context context) {
diff --git a/service/src/com/android/server/net/L2capNetwork.java b/service/src/com/android/server/net/L2capNetwork.java
index c7417f9..ca155db 100644
--- a/service/src/com/android/server/net/L2capNetwork.java
+++ b/service/src/com/android/server/net/L2capNetwork.java
@@ -52,7 +52,7 @@
*
* Note that the IpClient does not need to be stopped.
*/
- private static class L2capIpClient extends IpClientCallbacks {
+ public static class L2capIpClient extends IpClientCallbacks {
private final String mLogTag;
private final ConditionVariable mOnIpClientCreatedCv = new ConditionVariable(false);
private final ConditionVariable mOnProvisioningSuccessCv = new ConditionVariable(false);
@@ -61,7 +61,7 @@
@Nullable
private volatile LinkProperties mLinkProperties;
- L2capIpClient(String logTag, Context context, String ifname) {
+ public L2capIpClient(String logTag, Context context, String ifname) {
mLogTag = logTag;
IpClientUtil.makeIpClient(context, ifname, this);
}
@@ -157,7 +157,7 @@
// LinkProperties) or fails (and returns null).
// Note that since L2capNetwork is using IPv6 link-local provisioning the most likely
// (only?) failure mode is due to the interface disappearing.
- final LinkProperties lp = new L2capIpClient(logTag, context, ifname).start();
+ final LinkProperties lp = deps.createL2capIpClient(logTag, context, ifname).start();
if (lp == null) return null;
return new L2capNetwork(
diff --git a/service/src/com/android/server/net/L2capPacketForwarder.java b/service/src/com/android/server/net/L2capPacketForwarder.java
index 737cb9c..8420d60 100644
--- a/service/src/com/android/server/net/L2capPacketForwarder.java
+++ b/service/src/com/android/server/net/L2capPacketForwarder.java
@@ -109,10 +109,10 @@
public int read(byte[] bytes, int off, int len) throws IOException {
// Note: EINTR is handled internally and automatically triggers a retry loop.
int bytesRead = mInputStream.read(bytes, off, len);
- if (bytesRead > MTU) {
+ if (bytesRead < 0 || bytesRead > MTU) {
// Don't try to recover, just trigger network teardown. This might indicate a bug in
// the Bluetooth stack.
- throw new IOException("Packet exceeds MTU");
+ throw new IOException("Packet exceeds MTU or reached EOF. Read: " + bytesRead);
}
return bytesRead;
}
diff --git a/staticlibs/device/com/android/net/module/util/netlink/InetDiagMessage.java b/staticlibs/device/com/android/net/module/util/netlink/InetDiagMessage.java
index fecaa09..c9a89ec 100644
--- a/staticlibs/device/com/android/net/module/util/netlink/InetDiagMessage.java
+++ b/staticlibs/device/com/android/net/module/util/netlink/InetDiagMessage.java
@@ -309,16 +309,18 @@
}
private static void sendNetlinkDestroyRequest(FileDescriptor fd, int proto,
- InetDiagMessage diagMsg) throws InterruptedIOException, ErrnoException {
+ StructInetDiagSockId id, short family, int state)
+ throws InterruptedIOException, ErrnoException {
+ // TODO: Investigate if it's fine to always set 0 to state and remove state from the arg
final byte[] destroyMsg = InetDiagMessage.inetDiagReqV2(
proto,
- diagMsg.inetDiagMsg.id,
- diagMsg.inetDiagMsg.idiag_family,
+ id,
+ family,
SOCK_DESTROY,
(short) (StructNlMsgHdr.NLM_F_REQUEST | StructNlMsgHdr.NLM_F_ACK),
0 /* pad */,
0 /* idiagExt */,
- 1 << diagMsg.inetDiagMsg.idiag_state
+ state
);
NetlinkUtils.sendMessage(fd, destroyMsg, 0, destroyMsg.length, IO_TIMEOUT_MS);
NetlinkUtils.receiveNetlinkAck(fd);
@@ -343,7 +345,8 @@
Consumer<InetDiagMessage> handleNlDumpMsg = (diagMsg) -> {
if (filter.test(diagMsg)) {
try {
- sendNetlinkDestroyRequest(destroyFd, proto, diagMsg);
+ sendNetlinkDestroyRequest(destroyFd, proto, diagMsg.inetDiagMsg.id,
+ diagMsg.inetDiagMsg.idiag_family, 1 << diagMsg.inetDiagMsg.idiag_state);
destroyedSockets.getAndIncrement();
} catch (InterruptedIOException | ErrnoException e) {
if (!(e instanceof ErrnoException
@@ -484,6 +487,30 @@
Log.d(TAG, "Destroyed live tcp sockets for uids=" + ownerUids + " in " + durationMs + "ms");
}
+ /**
+ * Close the udp socket which can be uniquely identified with the cookie and other information.
+ */
+ public static void destroyUdpSocket(final InetSocketAddress src, final InetSocketAddress dst,
+ final int ifIndex, final long cookie)
+ throws ErrnoException, SocketException, InterruptedIOException {
+ FileDescriptor fd = null;
+
+ try {
+ fd = NetlinkUtils.createNetLinkInetDiagSocket();
+ connectToKernel(fd);
+ final int family = (src.getAddress() instanceof Inet6Address) ? AF_INET6 : AF_INET;
+ final StructInetDiagSockId id = new StructInetDiagSockId(
+ src,
+ dst,
+ ifIndex,
+ cookie
+ );
+ sendNetlinkDestroyRequest(fd, IPPROTO_UDP, id, (short) family, 0 /* state */);
+ } finally {
+ closeSocketQuietly(fd);
+ }
+ }
+
@Override
public String toString() {
return "InetDiagMessage{ "
diff --git a/staticlibs/testutils/devicetests/com/android/testutils/PollingUtils.kt b/staticlibs/testutils/devicetests/com/android/testutils/PollingUtils.kt
new file mode 100644
index 0000000..a6e7ead
--- /dev/null
+++ b/staticlibs/testutils/devicetests/com/android/testutils/PollingUtils.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.testutils
+
+private const val POLLING_INTERVAL_MS: Int = 100
+
+/** Calls condition() until it returns true or timeout occurs. */
+fun pollingCheck(timeout_ms: Long, condition: () -> Boolean): Boolean {
+ var polling_time = 0
+ do {
+ Thread.sleep(POLLING_INTERVAL_MS.toLong())
+ polling_time += POLLING_INTERVAL_MS
+ if (condition()) return true
+ } while (polling_time < timeout_ms)
+ return false
+}
diff --git a/tests/common/java/android/net/NetworkAgentConfigTest.kt b/tests/common/java/android/net/NetworkAgentConfigTest.kt
index fe869f8..d640a73 100644
--- a/tests/common/java/android/net/NetworkAgentConfigTest.kt
+++ b/tests/common/java/android/net/NetworkAgentConfigTest.kt
@@ -20,7 +20,6 @@
import androidx.test.runner.AndroidJUnit4
import com.android.modules.utils.build.SdkLevel.isAtLeastS
import com.android.modules.utils.build.SdkLevel.isAtLeastT
-import com.android.modules.utils.build.SdkLevel.isAtLeastV
import com.android.testutils.ConnectivityModuleTest
import com.android.testutils.assertParcelingIsLossless
import org.junit.Assert.assertEquals
@@ -48,9 +47,6 @@
setLocalRoutesExcludedForVpn(true)
setVpnRequiresValidation(true)
}
- if (isAtLeastV()) {
- setSkipNativeNetworkCreation(true)
- }
}.build()
assertParcelingIsLossless(config)
}
@@ -75,9 +71,6 @@
setLocalRoutesExcludedForVpn(true)
setVpnRequiresValidation(true)
}
- if (isAtLeastV()) {
- setSkipNativeNetworkCreation(true)
- }
}.build()
assertTrue(config.isExplicitlySelected())
@@ -86,9 +79,6 @@
assertFalse(config.isPartialConnectivityAcceptable())
assertTrue(config.isUnvalidatedConnectivityAcceptable())
assertEquals("TEST_NETWORK", config.getLegacyTypeName())
- if (isAtLeastV()) {
- assertTrue(config.shouldSkipNativeNetworkCreation())
- }
if (isAtLeastT()) {
assertTrue(config.areLocalRoutesExcludedForVpn())
assertTrue(config.isVpnValidationRequired())
diff --git a/tests/cts/net/src/android/net/cts/ApfIntegrationTest.kt b/tests/cts/net/src/android/net/cts/ApfIntegrationTest.kt
index 8e790ca..2a372ce 100644
--- a/tests/cts/net/src/android/net/cts/ApfIntegrationTest.kt
+++ b/tests/cts/net/src/android/net/cts/ApfIntegrationTest.kt
@@ -19,8 +19,6 @@
package android.net.cts
-import android.Manifest.permission.WRITE_ALLOWLISTED_DEVICE_CONFIG
-import android.Manifest.permission.WRITE_DEVICE_CONFIG
import android.content.pm.PackageManager.FEATURE_AUTOMOTIVE
import android.content.pm.PackageManager.FEATURE_LEANBACK
import android.content.pm.PackageManager.FEATURE_WIFI
@@ -55,8 +53,6 @@
import android.os.SystemProperties
import android.os.UserManager
import android.platform.test.annotations.AppModeFull
-import android.provider.DeviceConfig
-import android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY
import android.system.Os
import android.system.OsConstants
import android.system.OsConstants.AF_INET6
@@ -90,7 +86,7 @@
import com.android.testutils.RecorderCallback.CallbackEntry.LinkPropertiesChanged
import com.android.testutils.SkipPresubmit
import com.android.testutils.TestableNetworkCallback
-import com.android.testutils.runAsShell
+import com.android.testutils.pollingCheck
import com.android.testutils.waitForIdle
import com.google.common.truth.Expect
import com.google.common.truth.Truth.assertThat
@@ -116,8 +112,6 @@
private const val TAG = "ApfIntegrationTest"
private const val TIMEOUT_MS = 2000L
-private const val APF_NEW_RA_FILTER_VERSION = "apf_new_ra_filter_version"
-private const val POLLING_INTERVAL_MS: Int = 100
private const val RCV_BUFFER_SIZE = 1480
private const val PING_HEADER_LENGTH = 8
@@ -135,16 +129,6 @@
private val powerManager = context.getSystemService(PowerManager::class.java)!!
private val wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG)
- fun pollingCheck(condition: () -> Boolean, timeout_ms: Int): Boolean {
- var polling_time = 0
- do {
- Thread.sleep(POLLING_INTERVAL_MS.toLong())
- polling_time += POLLING_INTERVAL_MS
- if (condition()) return true
- } while (polling_time < timeout_ms)
- return false
- }
-
fun turnScreenOff() {
if (!wakeLock.isHeld()) wakeLock.acquire()
runShellCommandOrThrow("input keyevent KEYCODE_SLEEP")
@@ -166,7 +150,9 @@
// This is a workaround for b/366037029.
Thread.sleep(2000L)
} else {
- val result = pollingCheck({ powerManager.isInteractive() }, timeout_ms = 2000)
+ val result = pollingCheck(timeout_ms = 2000) {
+ powerManager.isInteractive()
+ }
assertThat(result).isEqualTo(interactive)
}
}
@@ -192,16 +178,6 @@
Thread.sleep(1000)
// TODO: check that there is no active wifi network. Otherwise, ApfFilter has already been
// created.
- // APF adb cmds are only implemented in ApfFilter.java. Enable experiment to prevent
- // LegacyApfFilter.java from being used.
- runAsShell(WRITE_DEVICE_CONFIG, WRITE_ALLOWLISTED_DEVICE_CONFIG) {
- DeviceConfig.setProperty(
- NAMESPACE_CONNECTIVITY,
- APF_NEW_RA_FILTER_VERSION,
- "1", // value => force enabled
- false // makeDefault
- )
- }
}
@AfterClass
@@ -591,6 +567,13 @@
val program = gen.generate()
assertThat(program.size).isLessThan(counterRegion)
+ val randomProgram = ByteArray(1) { 0 } +
+ ByteArray(counterRegion - 1).also { Random.nextBytes(it) }
+ // There are known firmware bugs where they calculate the number of non-zero bytes within
+ // the program to determine the program length. Modify the test to first install a longer
+ // program before installing a program that do the program length check. This should help us
+ // catch these types of firmware bugs in CTS. (b/395545572)
+ installAndVerifyProgram(randomProgram)
installAndVerifyProgram(program)
// Trigger the program by sending a ping and waiting on the reply.
diff --git a/tests/cts/net/src/android/net/cts/DscpPolicyTest.kt b/tests/cts/net/src/android/net/cts/DscpPolicyTest.kt
index 1de4cf9..ceccf0b 100644
--- a/tests/cts/net/src/android/net/cts/DscpPolicyTest.kt
+++ b/tests/cts/net/src/android/net/cts/DscpPolicyTest.kt
@@ -44,6 +44,7 @@
import android.net.RouteInfo
import android.net.TestNetworkInterface
import android.net.TestNetworkManager
+import android.net.TestNetworkManager.TestInterfaceRequest
import android.net.cts.util.CtsNetUtils.TestNetworkCallback
import android.os.HandlerThread
import android.os.SystemClock
@@ -164,7 +165,11 @@
// Only statically configure the IPv4 address; for IPv6, use the SLAAC generated
// address.
- iface = tnm.createTapInterface(arrayOf(LinkAddress(LOCAL_IPV4_ADDRESS, IP4_PREFIX_LEN)))
+ val req = TestInterfaceRequest.Builder()
+ .setTap()
+ .addLinkAddress(LinkAddress(LOCAL_IPV4_ADDRESS, IP4_PREFIX_LEN))
+ .build()
+ iface = tnm.createTestInterface(req)
assertNotNull(iface)
}
diff --git a/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt b/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt
index 06f2075..9f32132 100644
--- a/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt
+++ b/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt
@@ -51,6 +51,7 @@
import android.net.StaticIpConfiguration
import android.net.TestNetworkInterface
import android.net.TestNetworkManager
+import android.net.TestNetworkManager.TestInterfaceRequest
import android.net.cts.EthernetManagerTest.EthernetStateListener.CallbackEntry.EthernetStateChanged
import android.net.cts.EthernetManagerTest.EthernetStateListener.CallbackEntry.InterfaceStateChanged
import android.os.Build
@@ -169,7 +170,12 @@
// false, it is subsequently disabled. This means that the interface may briefly get
// link. With IPv6 provisioning delays (RS delay and DAD) disabled, this can cause
// tests that expect no network to come up when hasCarrier is false to become flaky.
- tnm.createTapInterface(hasCarrier, false /* bringUp */)
+ val req = TestInterfaceRequest.Builder()
+ .setTap()
+ .setHasCarrier(hasCarrier)
+ .setBringUp(false)
+ .build()
+ tnm.createTestInterface(req)
}
val mtu = tapInterface.mtu
packetReader = PollPacketReader(
diff --git a/tests/cts/net/src/android/net/cts/NetworkReservationTest.kt b/tests/cts/net/src/android/net/cts/NetworkReservationTest.kt
index a9af34f..f43b927 100644
--- a/tests/cts/net/src/android/net/cts/NetworkReservationTest.kt
+++ b/tests/cts/net/src/android/net/cts/NetworkReservationTest.kt
@@ -19,6 +19,8 @@
import android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS
import android.Manifest.permission.MANAGE_TEST_NETWORKS
import android.Manifest.permission.NETWORK_SETTINGS
+import android.bluetooth.BluetoothManager
+import android.content.pm.PackageManager.FEATURE_BLUETOOTH_LE
import android.net.ConnectivityManager
import android.net.L2capNetworkSpecifier
import android.net.L2capNetworkSpecifier.HEADER_COMPRESSION_6LOWPAN
@@ -41,6 +43,7 @@
import android.os.HandlerThread
import android.platform.test.annotations.AppModeFull
import androidx.test.platform.app.InstrumentationRegistry
+import com.android.compatibility.common.util.SystemUtil.runShellCommandOrThrow
import com.android.testutils.ConnectivityModuleTest
import com.android.testutils.DevSdkIgnoreRule
import com.android.testutils.DevSdkIgnoreRunner
@@ -48,12 +51,15 @@
import com.android.testutils.RecorderCallback.CallbackEntry.Unavailable
import com.android.testutils.TestableNetworkCallback
import com.android.testutils.TestableNetworkOfferCallback
+import com.android.testutils.pollingCheck
import com.android.testutils.runAsShell
import kotlin.test.assertContains
import kotlin.test.assertEquals
+import kotlin.test.assertNotNull
import kotlin.test.assertNull
import kotlin.test.assertTrue
import org.junit.After
+import org.junit.Assume.assumeTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -93,6 +99,8 @@
private val provider = NetworkProvider(context, handlerThread.looper, TAG)
private val registeredCallbacks = ArrayList<TestableNetworkCallback>()
+ private val bm = context.getSystemService(BluetoothManager::class.java)!!
+ private var disableBluetoothInTearDown = false
@Before
fun setUp() {
@@ -101,6 +109,34 @@
}
}
+ private fun enableBluetooth() {
+ val adapter = bm.adapter
+ assertNotNull(adapter)
+ if (adapter.isEnabled()) return
+
+ runShellCommandOrThrow("svc bluetooth enable")
+ val bluetoothEnabled = pollingCheck(TIMEOUT_MS) {
+ adapter.isEnabled()
+ }
+ assertTrue(bluetoothEnabled)
+ // Only disable Bluetooth in tear down when it hasn't already been enabled.
+ disableBluetoothInTearDown = true
+ }
+
+ private fun disableBluetooth() {
+ // adapter can't actually be null here, because this function does not run unless
+ // disableBluetoothInTearDown is true. Just in case, refrain from throwing an exception in
+ // tearDown.
+ val adapter = bm.adapter
+ if (adapter == null) return
+
+ runShellCommandOrThrow("svc bluetooth disable")
+ // Wait for #isEnabled() to return false; ignore failures.
+ pollingCheck(TIMEOUT_MS) {
+ !adapter.isEnabled()
+ }
+ }
+
@After
fun tearDown() {
registeredCallbacks.forEach { cm.unregisterNetworkCallback(it) }
@@ -110,6 +146,10 @@
}
handlerThread.quitSafely()
handlerThread.join()
+
+ if (disableBluetoothInTearDown) {
+ disableBluetooth()
+ }
}
fun NetworkCapabilities.copyWithReservationId(resId: Int) = NetworkCapabilities(this).also {
@@ -158,6 +198,9 @@
@Test
fun testReserveL2capNetwork() {
+ assumeTrue(context.packageManager.hasSystemFeature(FEATURE_BLUETOOTH_LE))
+ enableBluetooth()
+
val l2capReservationSpecifier = L2capNetworkSpecifier.Builder()
.setRole(ROLE_SERVER)
.setHeaderCompression(HEADER_COMPRESSION_6LOWPAN)
diff --git a/tests/unit/java/com/android/server/BpfNetMapsTest.java b/tests/unit/java/com/android/server/BpfNetMapsTest.java
index fd92672..caf1765 100644
--- a/tests/unit/java/com/android/server/BpfNetMapsTest.java
+++ b/tests/unit/java/com/android/server/BpfNetMapsTest.java
@@ -266,6 +266,18 @@
@Test
@IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM)
+ public void testAddLocalNetAccessWithNullInterfaceAfterV() throws Exception {
+ assertTrue(mLocalNetAccessMap.isEmpty());
+
+ mBpfNetMaps.addLocalNetAccess(160, null,
+ Inet4Address.getByName("196.68.0.0"), 0, 0, true);
+
+ // As we tried to add null interface, it would be skipped and map should be empty.
+ assertTrue(mLocalNetAccessMap.isEmpty());
+ }
+
+ @Test
+ @IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM)
public void testAddLocalNetAccessAfterVWithIncorrectInterface() throws Exception {
assertTrue(mLocalNetAccessMap.isEmpty());
@@ -303,6 +315,13 @@
}
@Test
+ @IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM)
+ public void testGetLocalNetAccessWithNullInterfaceAfterV() throws Exception {
+ assertTrue(mBpfNetMaps.getLocalNetAccess(160, null,
+ Inet4Address.getByName("100.68.0.0"), 0, 0));
+ }
+
+ @Test
@IgnoreAfter(Build.VERSION_CODES.VANILLA_ICE_CREAM)
public void testRemoveLocalNetAccessBeforeV() {
assertThrows(UnsupportedOperationException.class, () ->
@@ -350,6 +369,25 @@
}
@Test
+ @IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM)
+ public void testRemoveLocalNetAccessAfterVWithNullInterface() throws Exception {
+ assertTrue(mLocalNetAccessMap.isEmpty());
+
+ mBpfNetMaps.addLocalNetAccess(160, TEST_IF_NAME,
+ Inet4Address.getByName("196.68.0.0"), 0, 0, true);
+
+ assertNotNull(mLocalNetAccessMap.getValue(new LocalNetAccessKey(160, TEST_IF_INDEX,
+ Inet4Address.getByName("196.68.0.0"), 0, 0)));
+ assertNull(mLocalNetAccessMap.getValue(new LocalNetAccessKey(160, TEST_IF_INDEX,
+ Inet4Address.getByName("100.68.0.0"), 0, 0)));
+
+ mBpfNetMaps.removeLocalNetAccess(160, null,
+ Inet4Address.getByName("196.68.0.0"), 0, 0);
+ assertNotNull(mLocalNetAccessMap.getValue(new LocalNetAccessKey(160, TEST_IF_INDEX,
+ Inet4Address.getByName("196.68.0.0"), 0, 0)));
+ }
+
+ @Test
@IgnoreAfter(Build.VERSION_CODES.VANILLA_ICE_CREAM)
public void testAddUidToLocalNetBlockMapBeforeV() {
assertThrows(UnsupportedOperationException.class, () ->
diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
index b7aa387..19a41d8 100755
--- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
@@ -154,7 +154,6 @@
import static android.net.Proxy.PROXY_CHANGE_ACTION;
import static android.net.RouteInfo.RTN_UNREACHABLE;
import static android.net.connectivity.ConnectivityCompatChanges.NETWORK_BLOCKED_WITHOUT_INTERNET_PERMISSION;
-import static android.net.connectivity.ConnectivityCompatChanges.RESTRICT_LOCAL_NETWORK;
import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.PREFIX_OPERATION_ADDED;
import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.PREFIX_OPERATION_REMOVED;
import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_FAILURE;
@@ -164,10 +163,7 @@
import static android.telephony.DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH;
import static android.telephony.DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
-import static com.android.server.ConnectivityService.ALLOW_SATALLITE_NETWORK_FALLBACK;
import static com.android.net.module.util.DeviceConfigUtils.TETHERING_MODULE_NAME;
-import static com.android.server.ConnectivityService.ALLOW_SYSUI_CONNECTIVITY_REPORTS;
-import static com.android.server.ConnectivityService.KEY_DESTROY_FROZEN_SOCKETS_VERSION;
import static com.android.server.ConnectivityService.MAX_NETWORK_REQUESTS_PER_SYSTEM_UID;
import static com.android.server.ConnectivityService.PREFERENCE_ORDER_MOBILE_DATA_PREFERERRED;
import static com.android.server.ConnectivityService.PREFERENCE_ORDER_OEM;
@@ -178,9 +174,6 @@
import static com.android.server.ConnectivityServiceTestUtils.transportToLegacyType;
import static com.android.server.NetworkAgentWrapper.CallbackType.OnQosCallbackRegister;
import static com.android.server.NetworkAgentWrapper.CallbackType.OnQosCallbackUnregister;
-import static com.android.server.connectivity.ConnectivityFlags.BACKGROUND_FIREWALL_CHAIN;
-import static com.android.server.connectivity.ConnectivityFlags.DELAY_DESTROY_SOCKETS;
-import static com.android.server.connectivity.ConnectivityFlags.INGRESS_TO_VPN_ADDRESS_FILTERING;
import static com.android.testutils.Cleanup.testAndCleanup;
import static com.android.testutils.ConcurrentUtils.await;
import static com.android.testutils.ConcurrentUtils.durationOf;
@@ -258,7 +251,6 @@
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.admin.DevicePolicyManager;
-import android.app.compat.CompatChanges;
import android.app.usage.NetworkStatsManager;
import android.compat.testing.PlatformCompatChangeRule;
import android.content.BroadcastReceiver;
@@ -2187,28 +2179,30 @@
case ConnectivityFlags.REQUEST_RESTRICTED_WIFI:
case ConnectivityFlags.USE_DECLARED_METHODS_FOR_CALLBACKS:
case ConnectivityFlags.QUEUE_CALLBACKS_FOR_FROZEN_APPS:
- case KEY_DESTROY_FROZEN_SOCKETS_VERSION:
+ case ConnectivityFlags.BACKGROUND_FIREWALL_CHAIN:
+ case ConnectivityService.KEY_DESTROY_FROZEN_SOCKETS_VERSION:
return true;
default:
- return super.isFeatureEnabled(context, name);
+ // This is a unit test and must never depend on actual device flag values.
+ throw new UnsupportedOperationException("Unknown flag " + name
+ + ", update this test");
}
}
@Override
public boolean isFeatureNotChickenedOut(Context context, String name) {
switch (name) {
- case ALLOW_SYSUI_CONNECTIVITY_REPORTS:
- return true;
- case ALLOW_SATALLITE_NETWORK_FALLBACK:
- return true;
- case INGRESS_TO_VPN_ADDRESS_FILTERING:
- return true;
- case BACKGROUND_FIREWALL_CHAIN:
- return true;
- case DELAY_DESTROY_SOCKETS:
+ case ConnectivityService.ALLOW_SYSUI_CONNECTIVITY_REPORTS:
+ case ConnectivityService.ALLOW_SATALLITE_NETWORK_FALLBACK:
+ case ConnectivityFlags.INGRESS_TO_VPN_ADDRESS_FILTERING:
+ case ConnectivityFlags.BACKGROUND_FIREWALL_CHAIN:
+ case ConnectivityFlags.DELAY_DESTROY_SOCKETS:
+ case ConnectivityFlags.USE_DECLARED_METHODS_FOR_CALLBACKS:
+ case ConnectivityFlags.QUEUE_CALLBACKS_FOR_FROZEN_APPS:
return true;
default:
- return super.isFeatureNotChickenedOut(context, name);
+ throw new UnsupportedOperationException("Unknown flag " + name
+ + ", update this test");
}
}
@@ -2449,6 +2443,10 @@
@After
public void tearDown() throws Exception {
+ // Don't attempt to tear down if setUp didn't even get as far as creating the service.
+ // Otherwise, exceptions here will mask the actual exception in setUp, making failures
+ // harder to diagnose.
+ if (mService == null) return;
unregisterDefaultNetworkCallbacks();
maybeTearDownEnterpriseNetwork();
setAlwaysOnNetworks(false);
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsSocketProviderTest.java b/tests/unit/java/com/android/server/connectivity/mdns/MdnsSocketProviderTest.java
index 1cc9985..f763bae 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsSocketProviderTest.java
+++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsSocketProviderTest.java
@@ -610,6 +610,7 @@
@Test
public void testSocketCreatedForMulticastInterface() throws Exception {
+ doReturn(true).when(mTestNetworkIfaceWrapper).isPointToPoint();
doReturn(true).when(mTestNetworkIfaceWrapper).supportsMulticast();
startMonitoringSockets();
@@ -621,18 +622,6 @@
}
@Test
- public void testNoSocketCreatedForPTPInterface() throws Exception {
- doReturn(true).when(mTestNetworkIfaceWrapper).isPointToPoint();
- startMonitoringSockets();
-
- final TestSocketCallback testCallback = new TestSocketCallback();
- runOnHandler(() -> mSocketProvider.requestSocket(TEST_NETWORK, testCallback));
-
- postNetworkAvailable(TRANSPORT_BLUETOOTH);
- testCallback.expectedNoCallback();
- }
-
- @Test
public void testNoSocketCreatedForVPNInterface() throws Exception {
// VPN interfaces generally also have IFF_POINTOPOINT, but even if they don't, they should
// not be included even with TRANSPORT_WIFI.
diff --git a/tests/unit/java/com/android/server/connectivityservice/CSL2capProviderTest.kt b/tests/unit/java/com/android/server/connectivityservice/CSL2capProviderTest.kt
index 489c3ad..babcba9 100644
--- a/tests/unit/java/com/android/server/connectivityservice/CSL2capProviderTest.kt
+++ b/tests/unit/java/com/android/server/connectivityservice/CSL2capProviderTest.kt
@@ -17,25 +17,37 @@
package com.android.server
import android.bluetooth.BluetoothAdapter
-import android.bluetooth.BluetoothManager
+import android.bluetooth.BluetoothDevice
import android.bluetooth.BluetoothServerSocket
import android.bluetooth.BluetoothSocket
+import android.net.INetworkMonitor
+import android.net.INetworkMonitorCallbacks
+import android.net.IpPrefix
import android.net.L2capNetworkSpecifier
import android.net.L2capNetworkSpecifier.HEADER_COMPRESSION_6LOWPAN
import android.net.L2capNetworkSpecifier.HEADER_COMPRESSION_NONE
+import android.net.L2capNetworkSpecifier.ROLE_CLIENT
import android.net.L2capNetworkSpecifier.ROLE_SERVER
+import android.net.LinkAddress
+import android.net.LinkProperties
+import android.net.MacAddress
import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED
import android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED
import android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH
import android.net.NetworkRequest
import android.net.NetworkSpecifier
+import android.net.RouteInfo
import android.os.Build
import android.os.HandlerThread
+import android.os.ParcelFileDescriptor
+import com.android.server.net.L2capNetwork.L2capIpClient
+import com.android.server.net.L2capPacketForwarder
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
import com.android.testutils.DevSdkIgnoreRunner
import com.android.testutils.RecorderCallback.CallbackEntry.Reserved
import com.android.testutils.RecorderCallback.CallbackEntry.Unavailable
import com.android.testutils.TestableNetworkCallback
+import com.android.testutils.anyNetwork
import com.android.testutils.waitForIdle
import java.io.IOException
import java.util.Optional
@@ -47,10 +59,13 @@
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.eq
+import org.mockito.ArgumentMatchers.isNull
import org.mockito.Mockito.doAnswer
import org.mockito.Mockito.doReturn
import org.mockito.Mockito.doThrow
import org.mockito.Mockito.mock
+import org.mockito.Mockito.verify
private const val PSM = 0x85
private val REMOTE_MAC = byteArrayOf(1, 2, 3, 4, 5, 6)
@@ -64,10 +79,17 @@
@IgnoreUpTo(Build.VERSION_CODES.R)
@DevSdkIgnoreRunner.MonitorThreadLeak
class CSL2capProviderTest : CSTest() {
+ private val networkMonitor = mock<INetworkMonitor>()
+
private val btAdapter = mock<BluetoothAdapter>()
+ private val btDevice = mock<BluetoothDevice>()
private val btServerSocket = mock<BluetoothServerSocket>()
private val btSocket = mock<BluetoothSocket>()
+ private val tunInterface = mock<ParcelFileDescriptor>()
+ private val l2capIpClient = mock<L2capIpClient>()
+ private val packetForwarder = mock<L2capPacketForwarder>()
private val providerDeps = mock<L2capNetworkProvider.Dependencies>()
+
// BlockingQueue does not support put(null) operations, as null is used as an internal sentinel
// value. Therefore, use Optional<BluetoothSocket> where an empty optional signals the
// BluetoothServerSocket#close() operation.
@@ -84,6 +106,8 @@
doReturn(btAdapter).`when`(bluetoothManager).getAdapter()
doReturn(btServerSocket).`when`(btAdapter).listenUsingInsecureL2capChannel()
doReturn(PSM).`when`(btServerSocket).getPsm()
+ doReturn(btDevice).`when`(btAdapter).getRemoteDevice(eq(REMOTE_MAC))
+ doReturn(btSocket).`when`(btDevice).createInsecureL2capChannel(eq(PSM))
doAnswer {
val sock = acceptQueue.take()
@@ -96,6 +120,30 @@
}.`when`(btServerSocket).close()
doReturn(handlerThread).`when`(providerDeps).getHandlerThread()
+ doReturn(tunInterface).`when`(providerDeps).createTunInterface(any())
+ doReturn(packetForwarder).`when`(providerDeps)
+ .createL2capPacketForwarder(any(), any(), any(), any(), any())
+ doReturn(l2capIpClient).`when`(providerDeps).createL2capIpClient(any(), any(), any())
+
+ val lp = LinkProperties()
+ val ifname = "l2cap-tun0"
+ lp.setInterfaceName(ifname)
+ lp.addLinkAddress(LinkAddress("fe80::1/64"))
+ lp.addRoute(RouteInfo(IpPrefix("fe80::/64"), null /* nextHop */, ifname))
+ doReturn(lp).`when`(l2capIpClient).start()
+
+ // Note: In order to properly register a NetworkAgent, a NetworkMonitor must be created for
+ // the agent. CSAgentWrapper already does some of this, but requires adding additional
+ // Dependencies to the production code. Create a mocked NM inside this test instead.
+ doAnswer { i ->
+ val cb = i.arguments[2] as INetworkMonitorCallbacks
+ cb.onNetworkMonitorCreated(networkMonitor)
+ }.`when`(networkStack).makeNetworkMonitor(
+ any() /* network */,
+ isNull() /* name */,
+ any() /* callbacks */
+ )
+
provider = L2capNetworkProvider(providerDeps, context)
provider.start()
}
@@ -241,4 +289,109 @@
cb2.expect<Reserved>()
cb2.assertNoCallback()
}
+
+ @Test
+ fun testServerNetwork() {
+ val specifier = L2capNetworkSpecifier.Builder()
+ .setRole(ROLE_SERVER)
+ .setHeaderCompression(HEADER_COMPRESSION_6LOWPAN)
+ .build()
+ val nr = REQUEST.copyWithSpecifier(specifier)
+ val cb = reserveNetwork(nr)
+ cb.expect<Reserved>()
+
+ // Unblock BluetoothServerSocket#accept()
+ doReturn(true).`when`(btSocket).isConnected()
+ acceptQueue.put(Optional.of(btSocket))
+
+ cb.expectAvailableCallbacks(anyNetwork(), validated = false)
+ cb.assertNoCallback()
+ // Verify that packet forwarding was started.
+ // TODO: stop mocking L2capPacketForwarder.
+ verify(providerDeps).createL2capPacketForwarder(any(), any(), any(), any(), any())
+ }
+
+ @Test
+ fun testBluetoothException_createInsecureL2capChannelThrows() {
+ doThrow(IOException()).`when`(btDevice).createInsecureL2capChannel(any())
+
+ val specifier = L2capNetworkSpecifier.Builder()
+ .setRole(ROLE_CLIENT)
+ .setHeaderCompression(HEADER_COMPRESSION_NONE)
+ .setRemoteAddress(MacAddress.fromBytes(REMOTE_MAC))
+ .setPsm(PSM)
+ .build()
+ val nr = REQUEST.copyWithSpecifier(specifier)
+ val cb = requestNetwork(nr)
+
+ cb.expect<Unavailable>()
+ }
+
+ @Test
+ fun testBluetoothException_bluetoothSocketConnectThrows() {
+ doThrow(IOException()).`when`(btSocket).connect()
+
+ val specifier = L2capNetworkSpecifier.Builder()
+ .setRole(ROLE_CLIENT)
+ .setHeaderCompression(HEADER_COMPRESSION_NONE)
+ .setRemoteAddress(MacAddress.fromBytes(REMOTE_MAC))
+ .setPsm(PSM)
+ .build()
+ val nr = REQUEST.copyWithSpecifier(specifier)
+ val cb = requestNetwork(nr)
+
+ cb.expect<Unavailable>()
+ }
+
+ @Test
+ fun testClientNetwork() {
+ val specifier = L2capNetworkSpecifier.Builder()
+ .setRole(ROLE_CLIENT)
+ .setHeaderCompression(HEADER_COMPRESSION_NONE)
+ .setRemoteAddress(MacAddress.fromBytes(REMOTE_MAC))
+ .setPsm(PSM)
+ .build()
+ val nr = REQUEST.copyWithSpecifier(specifier)
+ val cb = requestNetwork(nr)
+ cb.expectAvailableCallbacks(anyNetwork(), validated = false)
+ }
+
+ @Test
+ fun testClientNetwork_headerCompressionMismatch() {
+ var specifier = L2capNetworkSpecifier.Builder()
+ .setRole(ROLE_CLIENT)
+ .setHeaderCompression(HEADER_COMPRESSION_NONE)
+ .setRemoteAddress(MacAddress.fromBytes(REMOTE_MAC))
+ .setPsm(PSM)
+ .build()
+ var nr = REQUEST.copyWithSpecifier(specifier)
+ val cb = requestNetwork(nr)
+ cb.expectAvailableCallbacks(anyNetwork(), validated = false)
+
+ specifier = L2capNetworkSpecifier.Builder()
+ .setRole(ROLE_CLIENT)
+ .setHeaderCompression(HEADER_COMPRESSION_6LOWPAN)
+ .setRemoteAddress(MacAddress.fromBytes(REMOTE_MAC))
+ .setPsm(PSM)
+ .build()
+ nr = REQUEST.copyWithSpecifier(specifier)
+ val cb2 = requestNetwork(nr)
+ cb2.expect<Unavailable>()
+ }
+
+ @Test
+ fun testClientNetwork_multipleRequests() {
+ val specifier = L2capNetworkSpecifier.Builder()
+ .setRole(ROLE_CLIENT)
+ .setHeaderCompression(HEADER_COMPRESSION_NONE)
+ .setRemoteAddress(MacAddress.fromBytes(REMOTE_MAC))
+ .setPsm(PSM)
+ .build()
+ val nr = REQUEST.copyWithSpecifier(specifier)
+ val cb = requestNetwork(nr)
+ cb.expectAvailableCallbacks(anyNetwork(), validated = false)
+
+ val cb2 = requestNetwork(nr)
+ cb2.expectAvailableCallbacks(anyNetwork(), validated = false)
+ }
}
diff --git a/tests/unit/jni/Android.bp b/tests/unit/jni/Android.bp
index 1a833e1..1e9db03 100644
--- a/tests/unit/jni/Android.bp
+++ b/tests/unit/jni/Android.bp
@@ -22,6 +22,7 @@
],
shared_libs: [
+ "libbase",
"liblog",
"libnativehelper",
"libnetdutils",
diff --git a/thread/tests/cts/AndroidTest.xml b/thread/tests/cts/AndroidTest.xml
index e954d3b..89d2ce5 100644
--- a/thread/tests/cts/AndroidTest.xml
+++ b/thread/tests/cts/AndroidTest.xml
@@ -57,13 +57,4 @@
<option name="exclude-annotation" value="org.junit.Ignore"/>
</test>
- <!--
- This doesn't override a read-only flag, to run the tests locally with `epskc_enabled` flag
- enabled, set the flag to `is_fixed_read_only: false`. This should be removed after the
- `epskc_enabled` flag is rolled out.
- -->
- <target_preparer class="com.android.tradefed.targetprep.FeatureFlagTargetPreparer">
- <option name="flag-value"
- value="thread_network/com.android.net.thread.flags.epskc_enabled=true"/>
- </target_preparer>
</configuration>
diff --git a/thread/tests/integration/src/android/net/thread/InternetAccessTest.kt b/thread/tests/integration/src/android/net/thread/InternetAccessTest.kt
index 3c9aa07..46d4708 100644
--- a/thread/tests/integration/src/android/net/thread/InternetAccessTest.kt
+++ b/thread/tests/integration/src/android/net/thread/InternetAccessTest.kt
@@ -167,6 +167,8 @@
val ftd = ftds[0]
joinNetworkAndWaitForOmr(ftd, DEFAULT_DATASET)
dnsServer.start()
+ ftd.autoStartSrpClient()
+ ftd.waitForSrpServer()
val ipv4Addresses =
ftd.resolveHost("google.com", TYPE_A).map { extractIpv4AddressFromMappedAddress(it) }
@@ -181,6 +183,8 @@
val ftd = ftds[0]
joinNetworkAndWaitForOmr(ftd, DEFAULT_DATASET)
dnsServer.start()
+ ftd.autoStartSrpClient()
+ ftd.waitForSrpServer()
assertThat(ftd.resolveHost("google.com", TYPE_A)).isEmpty()
assertThat(ftd.resolveHost("google.com", TYPE_AAAA)).isEmpty()
diff --git a/thread/tests/integration/src/android/net/thread/utils/FullThreadDevice.java b/thread/tests/integration/src/android/net/thread/utils/FullThreadDevice.java
index 209eed6..38961a3 100644
--- a/thread/tests/integration/src/android/net/thread/utils/FullThreadDevice.java
+++ b/thread/tests/integration/src/android/net/thread/utils/FullThreadDevice.java
@@ -521,7 +521,7 @@
}
/** Waits for an SRP server to be present in Network Data */
- private void waitForSrpServer() throws TimeoutException {
+ public void waitForSrpServer() throws TimeoutException {
// CLI output:
// > srp client server
// [fd64:db12:25f4:7e0b:1bfc:6344:25ac:2dd7]:53538