diff --git a/tests/cts/net/src/android/net/cts/NetworkValidationTestUtil.kt b/tests/cts/net/src/android/net/cts/NetworkValidationTestUtil.kt index dde14ac585..391d03a18e 100644 --- a/tests/cts/net/src/android/net/cts/NetworkValidationTestUtil.kt +++ b/tests/cts/net/src/android/net/cts/NetworkValidationTestUtil.kt @@ -19,12 +19,20 @@ package android.net.cts import android.Manifest import android.net.util.NetworkStackUtils import android.provider.DeviceConfig +import android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY +import android.util.Log import com.android.testutils.runAsShell +import com.android.testutils.tryTest +import java.util.concurrent.CompletableFuture +import java.util.concurrent.Executor +import java.util.concurrent.TimeUnit /** * Collection of utility methods for configuring network validation. */ internal object NetworkValidationTestUtil { + val TAG = NetworkValidationTestUtil::class.simpleName + const val TIMEOUT_MS = 20_000L /** * Clear the test network validation URLs. @@ -59,10 +67,52 @@ internal object NetworkValidationTestUtil { @JvmStatic fun setUrlExpirationDeviceConfig(timestamp: Long?) = setConfig(NetworkStackUtils.TEST_URL_EXPIRATION_TIME, timestamp?.toString()) - private fun setConfig(configKey: String, value: String?) { - runAsShell(Manifest.permission.WRITE_DEVICE_CONFIG) { - DeviceConfig.setProperty( - DeviceConfig.NAMESPACE_CONNECTIVITY, configKey, value, false /* makeDefault */) + private fun setConfig(configKey: String, value: String?): String? { + Log.i(TAG, "Setting config \"$configKey\" to \"$value\"") + val readWritePermissions = arrayOf( + Manifest.permission.READ_DEVICE_CONFIG, + Manifest.permission.WRITE_DEVICE_CONFIG) + + val existingValue = runAsShell(*readWritePermissions) { + DeviceConfig.getProperty(NAMESPACE_CONNECTIVITY, configKey) + } + if (existingValue == value) { + // Already the correct value. There may be a race if a change is already in flight, + // but if multiple threads update the config there is no way to fix that anyway. + Log.i(TAG, "\$configKey\" already had value \"$value\"") + return value + } + + val future = CompletableFuture() + val listener = DeviceConfig.OnPropertiesChangedListener { + // The listener receives updates for any change to any key, so don't react to + // changes that do not affect the relevant key + if (!it.keyset.contains(configKey)) return@OnPropertiesChangedListener + if (it.getString(configKey, null) == value) { + future.complete(value) + } + } + + return tryTest { + runAsShell(*readWritePermissions) { + DeviceConfig.addOnPropertiesChangedListener( + NAMESPACE_CONNECTIVITY, + inlineExecutor, + listener) + DeviceConfig.setProperty( + NAMESPACE_CONNECTIVITY, + configKey, + value, + false /* makeDefault */) + // Don't drop the permission until the config is applied, just in case + future.get(TIMEOUT_MS, TimeUnit.MILLISECONDS) + }.also { + Log.i(TAG, "Config \"$configKey\" successfully set to \"$value\"") + } + } cleanup { + DeviceConfig.removeOnPropertiesChangedListener(listener) } } -} \ No newline at end of file + + private val inlineExecutor get() = Executor { r -> r.run() } +} diff --git a/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java b/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java index 05e40f9106..ce873f7f0b 100644 --- a/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java +++ b/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java @@ -476,6 +476,7 @@ public final class CtsNetUtils { NetworkCallback callback = new NetworkCallback() { @Override public void onLinkPropertiesChanged(Network n, LinkProperties lp) { + Log.i(TAG, "Link properties of network " + n + " changed to " + lp); if (requiresValidatedServer && lp.getValidatedPrivateDnsServers().isEmpty()) { return; }