Merge "[Thread] In Integration test, let the DNS client wait for DNS server to show up in Network Data" into main
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/staticlibs/testutils/devicetests/com/android/testutils/ConnectivityDiagnosticsCollector.kt b/staticlibs/testutils/devicetests/com/android/testutils/ConnectivityDiagnosticsCollector.kt
index 4b9429b..c7d6850 100644
--- a/staticlibs/testutils/devicetests/com/android/testutils/ConnectivityDiagnosticsCollector.kt
+++ b/staticlibs/testutils/devicetests/com/android/testutils/ConnectivityDiagnosticsCollector.kt
@@ -430,32 +430,19 @@
* @param dumpsysCmd The dumpsys command to run (for example "connectivity").
* @param exceptionContext An exception to write a stacktrace to the dump for context.
*/
- fun collectDumpsys(dumpsysCmd: String, exceptionContext: Throwable? = null) =
- collectCommandOutput("dumpsys $dumpsysCmd", exceptionContext = exceptionContext)
-
- /**
- * Add the output of a command to the test data dump.
- *
- * <p>The output will be collected immediately, and exported to a test artifact file when the
- * test ends.
- * @param cmd The command to run. Stdout of the command will be collected.
- * @param shell The shell to run the command in.
- * @param exceptionContext An exception to write a stacktrace to the dump for context.
- */
- fun collectCommandOutput(
- cmd: String,
- shell: String = "sh",
- exceptionContext: Throwable? = null
- ) {
- Log.i(TAG, "Collecting '$cmd' for test artifacts")
+ fun collectDumpsys(dumpsysCmd: String, exceptionContext: Throwable? = null) {
+ Log.i(TAG, "Collecting dumpsys $dumpsysCmd for test artifacts")
PrintWriter(buffer).let {
- it.println("--- $cmd at ${ZonedDateTime.now()} ---")
+ it.println("--- Dumpsys $dumpsysCmd at ${ZonedDateTime.now()} ---")
maybeWriteExceptionContext(it, exceptionContext)
it.flush()
}
-
- runCommandInShell(cmd, shell) { stdout, _ ->
- stdout.copyTo(buffer)
+ ParcelFileDescriptor.AutoCloseInputStream(
+ InstrumentationRegistry.getInstrumentation().uiAutomation.executeShellCommand(
+ "dumpsys $dumpsysCmd"
+ )
+ ).use {
+ it.copyTo(buffer)
}
}
diff --git a/staticlibs/testutils/devicetests/com/android/testutils/PollingUtils.kt b/staticlibs/testutils/devicetests/com/android/testutils/PollingUtils.kt
index 0a0290a..a6e7ead 100644
--- a/staticlibs/testutils/devicetests/com/android/testutils/PollingUtils.kt
+++ b/staticlibs/testutils/devicetests/com/android/testutils/PollingUtils.kt
@@ -19,7 +19,7 @@
private const val POLLING_INTERVAL_MS: Int = 100
/** Calls condition() until it returns true or timeout occurs. */
-fun pollingCheck(condition: () -> Boolean, timeout_ms: Int): Boolean {
+fun pollingCheck(timeout_ms: Long, condition: () -> Boolean): Boolean {
var polling_time = 0
do {
Thread.sleep(POLLING_INTERVAL_MS.toLong())
diff --git a/staticlibs/testutils/devicetests/com/android/testutils/ShellUtil.kt b/staticlibs/testutils/devicetests/com/android/testutils/ShellUtil.kt
deleted file mode 100644
index fadc2ab..0000000
--- a/staticlibs/testutils/devicetests/com/android/testutils/ShellUtil.kt
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * 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.
- */
-
-@file:JvmName("ShellUtil")
-
-package com.android.testutils
-
-import android.app.UiAutomation
-import android.os.ParcelFileDescriptor.AutoCloseInputStream
-import android.os.ParcelFileDescriptor.AutoCloseOutputStream
-import androidx.test.platform.app.InstrumentationRegistry
-import java.io.InputStream
-
-/**
- * Run a command in a shell.
- *
- * Compared to [UiAutomation.executeShellCommand], this allows running commands with pipes and
- * redirections. [UiAutomation.executeShellCommand] splits the command on spaces regardless of
- * quotes, so it is not able to run commands like `sh -c "echo 123 > some_file"`.
- *
- * @param cmd Shell command to run.
- * @param shell Command used to run the shell.
- * @param outputProcessor Function taking stdout, stderr as argument. The streams will be closed
- * when this function returns.
- * @return Result of [outputProcessor].
- */
-fun <T> runCommandInShell(
- cmd: String,
- shell: String = "sh",
- outputProcessor: (InputStream, InputStream) -> T,
-): T {
- val (stdout, stdin, stderr) = InstrumentationRegistry.getInstrumentation().uiAutomation
- .executeShellCommandRwe(shell)
- AutoCloseOutputStream(stdin).bufferedWriter().use { it.write(cmd) }
- AutoCloseInputStream(stdout).use { outStream ->
- AutoCloseInputStream(stderr).use { errStream ->
- return outputProcessor(outStream, errStream)
- }
- }
-}
-
-/**
- * Run a command in a shell.
- *
- * Overload of [runCommandInShell] that reads and returns stdout as String.
- */
-fun runCommandInShell(
- cmd: String,
- shell: String = "sh",
-) = runCommandInShell(cmd, shell) { stdout, _ ->
- stdout.reader().use { it.readText() }
-}
-
-/**
- * Run a command in a root shell.
- *
- * This is generally only usable on devices on which [DeviceInfoUtils.isDebuggable] is true.
- * @see runCommandInShell
- */
-fun runCommandInRootShell(
- cmd: String
-) = runCommandInShell(cmd, shell = "su root sh")
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 dee5f71..2a372ce 100644
--- a/tests/cts/net/src/android/net/cts/ApfIntegrationTest.kt
+++ b/tests/cts/net/src/android/net/cts/ApfIntegrationTest.kt
@@ -150,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)
}
}
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/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>