diff --git a/staticlibs/testutils/devicetests/com/android/testutils/CarrierConfigRule.kt b/staticlibs/testutils/devicetests/com/android/testutils/CarrierConfigRule.kt index a93ae3e1e6..ae0de794b9 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/CarrierConfigRule.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/CarrierConfigRule.kt @@ -18,28 +18,36 @@ package com.android.testutils.com.android.testutils import android.Manifest.permission.MODIFY_PHONE_STATE import android.Manifest.permission.READ_PHONE_STATE +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.content.IntentFilter +import android.os.ConditionVariable import android.os.PersistableBundle import android.telephony.CarrierConfigManager +import android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED +import android.telephony.SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX import android.util.Log import androidx.test.platform.app.InstrumentationRegistry import com.android.modules.utils.build.SdkLevel.isAtLeastU import com.android.testutils.runAsShell import com.android.testutils.tryTest import kotlin.test.assertNotNull +import kotlin.test.assertTrue import org.junit.rules.TestRule import org.junit.runner.Description import org.junit.runners.model.Statement private val TAG = CarrierConfigRule::class.simpleName +private const val CARRIER_CONFIG_CHANGE_TIMEOUT_MS = 10_000L /** * A [TestRule] that helps set [CarrierConfigManager] overrides for tests and clean up the test * configuration automatically on teardown. */ class CarrierConfigRule : TestRule { - private val ccm by lazy { InstrumentationRegistry.getInstrumentation().context.getSystemService( - CarrierConfigManager::class.java - ) } + private val context by lazy { InstrumentationRegistry.getInstrumentation().context } + private val ccm by lazy { context.getSystemService(CarrierConfigManager::class.java) } // Map of (subId) -> (original values of overridden settings) private val originalConfigs = mutableMapOf() @@ -61,6 +69,33 @@ class CarrierConfigRule : TestRule { } } + private class ConfigChangeReceiver(private val subId: Int) : BroadcastReceiver() { + val cv = ConditionVariable() + override fun onReceive(context: Context, intent: Intent) { + if (intent.action != ACTION_CARRIER_CONFIG_CHANGED || + intent.getIntExtra(EXTRA_SUBSCRIPTION_INDEX, -1) != subId) { + return + } + // This may race with other config changes for the same subId, but there is no way to + // know which update is being reported, and querying the override would return the + // latest values even before the config is applied. Config changes should be rare, so it + // is unlikely they would happen exactly after the override applied here and cause + // flakes. + cv.open() + } + } + + private fun overrideConfigAndWait(subId: Int, config: PersistableBundle) { + val changeReceiver = ConfigChangeReceiver(subId) + context.registerReceiver(changeReceiver, IntentFilter(ACTION_CARRIER_CONFIG_CHANGED)) + ccm.overrideConfig(subId, config) + assertTrue( + changeReceiver.cv.block(CARRIER_CONFIG_CHANGE_TIMEOUT_MS), + "Timed out waiting for config change for subId $subId" + ) + context.unregisterReceiver(changeReceiver) + } + /** * Add carrier config overrides with the specified configuration. * @@ -79,7 +114,7 @@ class CarrierConfigRule : TestRule { originalConfig.putAll(previousValues) runAsShell(MODIFY_PHONE_STATE) { - ccm.overrideConfig(subId, config) + overrideConfigAndWait(subId, config) } } @@ -93,10 +128,10 @@ class CarrierConfigRule : TestRule { runAsShell(MODIFY_PHONE_STATE) { originalConfigs.forEach { (subId, config) -> try { - // Do not use overrideConfig with null, as it would reset configs that may + // Do not use null as the config to reset, as it would reset configs that may // have been set by target preparers such as // ConnectivityTestTargetPreparer / CarrierConfigSetupTest. - ccm.overrideConfig(subId, config) + overrideConfigAndWait(subId, config) } catch (e: Throwable) { Log.e(TAG, "Error resetting carrier config for subId $subId") } diff --git a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt index 4ba41cdef6..8fcc703c0a 100644 --- a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt +++ b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt @@ -743,7 +743,6 @@ class NetworkAgentTest { } return@tryTest } - cv.close() if (hold) { carrierConfigRule.addConfigOverrides(subId, PersistableBundle().also { it.putStringArray(CarrierConfigManager.KEY_CARRIER_CERTIFICATE_STRING_ARRAY, @@ -752,7 +751,6 @@ class NetworkAgentTest { } else { carrierConfigRule.cleanUpNow() } - assertTrue(cv.block(DEFAULT_TIMEOUT_MS), "Can't change carrier privilege") } cleanup @JvmSerializableLambda { runAsShell(READ_PRIVILEGED_PHONE_STATE) @JvmSerializableLambda { tm.unregisterCarrierPrivilegesCallback(cpb)