diff options
5 files changed, 107 insertions, 50 deletions
diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterManagerTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterManagerTest.kt index 1e972a51b..7dc183c7f 100644 --- a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterManagerTest.kt +++ b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterManagerTest.kt @@ -812,10 +812,7 @@ class SafetyCenterManagerTest { val enabledChangedReceiver = SafetyCenterEnabledChangedReceiver(context) assertFailsWith(TimeoutCancellationException::class) { - enabledChangedReceiver.setSafetyCenterEnabledWithoutReceiverPermissionAndWait( - false, - TIMEOUT_SHORT - ) + enabledChangedReceiver.setSafetyCenterEnabledWithoutReceiverPermissionAndWait(false) } enabledChangedReceiver.unregister() } @@ -852,10 +849,7 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) assertFailsWith(TimeoutCancellationException::class) { - SafetySourceReceiver.setSafetyCenterEnabledWithoutReceiverPermissionAndWait( - false, - TIMEOUT_SHORT - ) + SafetySourceReceiver.setSafetyCenterEnabledWithoutReceiverPermissionAndWait(false) } } @@ -933,7 +927,7 @@ class SafetyCenterManagerTest { assertFailsWith(TimeoutCancellationException::class) { safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait( REFRESH_REASON_PAGE_OPEN, - TIMEOUT_SHORT + timeout = TIMEOUT_SHORT ) } @@ -991,7 +985,7 @@ class SafetyCenterManagerTest { assertFailsWith(TimeoutCancellationException::class) { safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait( REFRESH_REASON_PAGE_OPEN, - TIMEOUT_SHORT + timeout = TIMEOUT_SHORT ) } val apiSafetySourceDataBeforeSettingFlag = @@ -1113,8 +1107,7 @@ class SafetyCenterManagerTest { assertFailsWith(TimeoutCancellationException::class) { safetyCenterManager.refreshSafetySourcesWithoutReceiverPermissionAndWait( - REFRESH_REASON_RESCAN_BUTTON_CLICK, - TIMEOUT_SHORT + REFRESH_REASON_RESCAN_BUTTON_CLICK ) } val apiSafetySourceData = @@ -1132,7 +1125,7 @@ class SafetyCenterManagerTest { assertFailsWith(TimeoutCancellationException::class) { safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait( REFRESH_REASON_PAGE_OPEN, - TIMEOUT_SHORT + timeout = TIMEOUT_SHORT ) } } @@ -1404,7 +1397,7 @@ class SafetyCenterManagerTest { assertFailsWith(TimeoutCancellationException::class) { safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait( REFRESH_REASON_PAGE_OPEN, - TIMEOUT_SHORT + timeout = TIMEOUT_SHORT ) } } @@ -1500,7 +1493,7 @@ class SafetyCenterManagerTest { assertFailsWith(TimeoutCancellationException::class) { safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait( REFRESH_REASON_PERIODIC, - TIMEOUT_SHORT + timeout = TIMEOUT_SHORT ) } @@ -1573,8 +1566,8 @@ class SafetyCenterManagerTest { assertFailsWith(TimeoutCancellationException::class) { safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait( REFRESH_REASON_PAGE_OPEN, - TIMEOUT_SHORT, - emptyList() + safetySourceIds = emptyList(), + timeout = TIMEOUT_SHORT, ) } diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterUnsupportedTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterUnsupportedTest.kt index a4d1ef436..d882fc3cb 100644 --- a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterUnsupportedTest.kt +++ b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterUnsupportedTest.kt @@ -215,7 +215,7 @@ class SafetyCenterUnsupportedTest { assertFailsWith(TimeoutCancellationException::class) { safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait( REFRESH_REASON_PAGE_OPEN, - TIMEOUT_SHORT + timeout = TIMEOUT_SHORT ) } } diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterEnabledChangedReceiver.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterEnabledChangedReceiver.kt index b948dc52c..f8926caac 100644 --- a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterEnabledChangedReceiver.kt +++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterEnabledChangedReceiver.kt @@ -24,8 +24,8 @@ import android.content.IntentFilter import android.os.Build.VERSION_CODES.TIRAMISU import android.safetycenter.SafetyCenterManager.ACTION_SAFETY_CENTER_ENABLED_CHANGED import androidx.annotation.RequiresApi -import com.android.compatibility.common.util.SystemUtil import com.android.safetycenter.testing.Coroutines.TIMEOUT_LONG +import com.android.safetycenter.testing.Coroutines.TIMEOUT_SHORT import com.android.safetycenter.testing.Coroutines.runBlockingWithTimeout import com.android.safetycenter.testing.ShellPermissions.callWithShellPermissionIdentity import java.time.Duration @@ -55,20 +55,18 @@ class SafetyCenterEnabledChangedReceiver(private val context: Context) : Broadca fun setSafetyCenterEnabledWithReceiverPermissionAndWait( value: Boolean, timeout: Duration = TIMEOUT_LONG - ) = + ): Boolean = callWithShellPermissionIdentity(READ_SAFETY_CENTER_STATUS) { - setSafetyCenterEnabledWithoutReceiverPermissionAndWait(value, timeout) + SafetyCenterFlags.isEnabled = value + receiveSafetyCenterEnabledChanged(timeout) } fun setSafetyCenterEnabledWithoutReceiverPermissionAndWait( value: Boolean, - timeout: Duration = TIMEOUT_LONG - ): Boolean { + ) { SafetyCenterFlags.isEnabled = value - if (timeout < TIMEOUT_LONG) { - SystemUtil.waitForBroadcasts() - } - return receiveSafetyCenterEnabledChanged(timeout) + WaitForBroadcasts.waitForBroadcasts() + receiveSafetyCenterEnabledChanged(TIMEOUT_SHORT) } fun unregister() { diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetySourceReceiver.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetySourceReceiver.kt index 2ba87040a..29072c989 100644 --- a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetySourceReceiver.kt +++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetySourceReceiver.kt @@ -35,8 +35,8 @@ import android.safetycenter.SafetyCenterManager import android.safetycenter.SafetyCenterManager.ACTION_SAFETY_CENTER_ENABLED_CHANGED import androidx.annotation.RequiresApi import androidx.test.core.app.ApplicationProvider -import com.android.compatibility.common.util.SystemUtil import com.android.safetycenter.testing.Coroutines.TIMEOUT_LONG +import com.android.safetycenter.testing.Coroutines.TIMEOUT_SHORT import com.android.safetycenter.testing.Coroutines.runBlockingWithTimeout import com.android.safetycenter.testing.SafetyCenterApisWithShellPermissions.dismissSafetyCenterIssueWithPermission import com.android.safetycenter.testing.SafetyCenterApisWithShellPermissions.executeSafetyCenterIssueActionWithPermission @@ -164,46 +164,38 @@ class SafetySourceReceiver : BroadcastReceiver() { fun SafetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait( refreshReason: Int, - timeout: Duration = TIMEOUT_LONG, - safetySourceIds: List<String>? = null - ) = + safetySourceIds: List<String>? = null, + timeout: Duration = TIMEOUT_LONG + ): String = callWithShellPermissionIdentity(SEND_SAFETY_CENTER_UPDATE) { - refreshSafetySourcesWithoutReceiverPermissionAndWait( - refreshReason, - timeout, - safetySourceIds - ) + refreshSafetySourcesWithPermission(refreshReason, safetySourceIds) + receiveRefreshSafetySources(timeout) } fun SafetyCenterManager.refreshSafetySourcesWithoutReceiverPermissionAndWait( refreshReason: Int, - timeout: Duration, safetySourceIds: List<String>? = null - ): String { + ) { refreshSafetySourcesWithPermission(refreshReason, safetySourceIds) - if (timeout < TIMEOUT_LONG) { - SystemUtil.waitForBroadcasts() - } - return receiveRefreshSafetySources(timeout) + WaitForBroadcasts.waitForBroadcasts() + receiveRefreshSafetySources(TIMEOUT_SHORT) } fun setSafetyCenterEnabledWithReceiverPermissionAndWait( value: Boolean, timeout: Duration = TIMEOUT_LONG - ) = + ): Boolean = callWithShellPermissionIdentity(SEND_SAFETY_CENTER_UPDATE) { - setSafetyCenterEnabledWithoutReceiverPermissionAndWait(value, timeout) + SafetyCenterFlags.isEnabled = value + receiveSafetyCenterEnabledChanged(timeout) } fun setSafetyCenterEnabledWithoutReceiverPermissionAndWait( value: Boolean, - timeout: Duration = TIMEOUT_LONG - ): Boolean { + ) { SafetyCenterFlags.isEnabled = value - if (timeout < TIMEOUT_LONG) { - SystemUtil.waitForBroadcasts() - } - return receiveSafetyCenterEnabledChanged(timeout) + WaitForBroadcasts.waitForBroadcasts() + receiveSafetyCenterEnabledChanged(TIMEOUT_SHORT) } fun SafetyCenterManager.executeSafetyCenterIssueActionWithPermissionAndWait( diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/WaitForBroadcasts.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/WaitForBroadcasts.kt new file mode 100644 index 000000000..3c19ea180 --- /dev/null +++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/WaitForBroadcasts.kt @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2023 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.safetycenter.testing + +import android.util.Log +import androidx.annotation.GuardedBy +import com.android.compatibility.common.util.SystemUtil +import com.android.safetycenter.testing.Coroutines.TIMEOUT_LONG +import com.android.safetycenter.testing.Coroutines.runBlockingWithTimeout +import kotlinx.coroutines.DelicateCoroutinesApi +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.Job +import kotlinx.coroutines.TimeoutCancellationException +import kotlinx.coroutines.launch +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock + +/** A class to help waiting on broadcasts to be processed by the system. */ +object WaitForBroadcasts { + + private const val TAG: String = "WaitForBroadcasts" + + private val mutex = Mutex() + @GuardedBy("mutex") private var currentJob: Job? = null + + /** + * Waits for broadcasts for at most [TIMEOUT_LONG] and prints a warning if that operation timed + * out. + * + * The [SystemUtil.waitForBroadcasts] operation will keep on running even after the timeout as + * it is not interruptible. Further calls to [WaitForBroadcasts.waitForBroadcasts] will re-use + * the currently running [SystemUtil.waitForBroadcasts] call if it hasn't completed. + */ + fun waitForBroadcasts() { + try { + runBlockingWithTimeout { + mutex + .withLock { + val newJob = currentJob.maybeStartNewWaitForBroadcasts() + currentJob = newJob + newJob + } + .join() + } + } catch (e: TimeoutCancellationException) { + Log.w(TAG, "Waiting for broadcasts timed out, proceeding anyway", e) + } + } + + // We're using a GlobalScope here as there doesn't seem to be a straightforward way to timeout + // and interrupt the waitForBroadcasts() call. Given it's uninterruptible, we'd rather just have + // at most one globally-bound waitForBroadcasts() call running at any given time. + @OptIn(DelicateCoroutinesApi::class) + private fun Job?.maybeStartNewWaitForBroadcasts(): Job = + if (this != null && isActive) { + this + } else { + GlobalScope.launch(Dispatchers.IO) { SystemUtil.waitForBroadcasts() } + } +} |