Wait for carrier config to apply in tests

TetheringManagerTest#testRequestLatestEntitlementResult in particular
set carrier config overrides without waiting for the override to be
applied, which caused flakes.

Wait for the override to be applied when adding and clearing them.

This makes the logic to wait for the update in NetworkAgentTest
unnecessary.

Bug: 391966043
Test: atest
Change-Id: I371ff5742627ca0b1b6eb6be5f0fd19a0487ae83
diff --git a/staticlibs/testutils/devicetests/com/android/testutils/CarrierConfigRule.kt b/staticlibs/testutils/devicetests/com/android/testutils/CarrierConfigRule.kt
index a93ae3e..ae0de79 100644
--- a/staticlibs/testutils/devicetests/com/android/testutils/CarrierConfigRule.kt
+++ b/staticlibs/testutils/devicetests/com/android/testutils/CarrierConfigRule.kt
@@ -18,28 +18,36 @@
 
 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<Int, PersistableBundle>()
@@ -61,6 +69,33 @@
         }
     }
 
+    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 @@
         originalConfig.putAll(previousValues)
 
         runAsShell(MODIFY_PHONE_STATE) {
-            ccm.overrideConfig(subId, config)
+            overrideConfigAndWait(subId, config)
         }
     }
 
@@ -93,10 +128,10 @@
         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 4ba41cd..8fcc703 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 @@
                 }
                 return@tryTest
             }
-            cv.close()
             if (hold) {
                 carrierConfigRule.addConfigOverrides(subId, PersistableBundle().also {
                     it.putStringArray(CarrierConfigManager.KEY_CARRIER_CERTIFICATE_STRING_ARRAY,
@@ -752,7 +751,6 @@
             } 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)