From cfe8045933197019b768be0eb6eab4164ca98d9e Mon Sep 17 00:00:00 2001 From: Fabian Kozynski Date: Thu, 17 Oct 2019 14:29:03 +0000 Subject: [PATCH] Throw exception if IntentFilter is not valid If the IntentFilter used with BroadcastDispatcher doesn't have at least one action or has other information that's not actions or categories, throw an exception when device is trying to register Bug: 134566046 Test: atest BroadcastDispatcherTest Change-Id: I6be844a1650f1a6d4d6ff32ddaaa32ca7832c43b --- .../systemui/broadcast/BroadcastDispatcher.kt | 20 +++++++- .../broadcast/BroadcastDispatcherTest.kt | 49 +++++++++++++++++++ 2 files changed, 67 insertions(+), 2 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt b/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt index ff4711cb208ae..98d7f8b864fb4 100644 --- a/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt +++ b/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt @@ -23,6 +23,7 @@ import android.os.Handler import android.os.Looper import android.os.Message import android.os.UserHandle +import android.text.TextUtils import android.util.Log import android.util.SparseArray import com.android.internal.annotations.VisibleForTesting @@ -55,7 +56,8 @@ private const val DEBUG = false * a given broadcast. * * Use only for IntentFilters with actions and optionally categories. It does not support, - * permissions, schemes or data types. Cannot be used for getting sticky broadcasts. + * permissions, schemes, data types or data authorities. + * Cannot be used for getting sticky broadcasts. */ @Singleton open class BroadcastDispatcher @Inject constructor ( @@ -72,11 +74,14 @@ open class BroadcastDispatcher @Inject constructor ( * * @param receiver A receiver to dispatch the [Intent] * @param filter A filter to determine what broadcasts should be dispatched to this receiver. - * It will only take into account actions and categories for filtering. + * It will only take into account actions and categories for filtering. It must + * have at least one action. * @param handler A handler to dispatch [BroadcastReceiver.onReceive]. By default, it is the * main handler. Pass `null` to use the default. * @param user A user handle to determine which broadcast should be dispatched to this receiver. * By default, it is the current user. + * @throws IllegalArgumentException if the filter has other constraints that are not actions or + * categories or the filter has no actions. */ @JvmOverloads fun registerReceiver( @@ -85,12 +90,23 @@ open class BroadcastDispatcher @Inject constructor ( handler: Handler? = mainHandler, user: UserHandle = context.user ) { + checkFilter(filter) this.handler .obtainMessage(MSG_ADD_RECEIVER, ReceiverData(receiver, filter, handler ?: mainHandler, user)) .sendToTarget() } + private fun checkFilter(filter: IntentFilter) { + val sb = StringBuilder() + if (filter.countActions() == 0) sb.append("Filter must contain at least one action. ") + if (filter.countDataAuthorities() != 0) sb.append("Filter cannot contain DataAuthorities. ") + if (filter.countDataPaths() != 0) sb.append("Filter cannot contain DataPaths. ") + if (filter.countDataSchemes() != 0) sb.append("Filter cannot contain DataSchemes. ") + if (filter.countDataTypes() != 0) sb.append("Filter cannot contain DataTypes. ") + if (!TextUtils.isEmpty(sb)) throw IllegalArgumentException(sb.toString()) + } + /** * Unregister receiver for all users. *
diff --git a/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt b/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt index 2bff5488937db..ead14e5011939 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt @@ -21,6 +21,7 @@ import android.content.Context import android.content.IntentFilter import android.os.Handler import android.os.Looper +import android.os.PatternMatcher import android.os.UserHandle import android.test.suitebuilder.annotation.SmallTest import android.testing.AndroidTestingRunner @@ -33,6 +34,7 @@ import org.junit.runner.RunWith import org.mockito.ArgumentCaptor import org.mockito.Captor import org.mockito.Mock +import org.mockito.Mockito.`when` import org.mockito.Mockito.mock import org.mockito.Mockito.never import org.mockito.Mockito.verify @@ -48,6 +50,10 @@ class BroadcastDispatcherTest : SysuiTestCase() { val user1 = UserHandle.of(1) fun capture(argumentCaptor: ArgumentCaptor): T = argumentCaptor.capture() + const val TEST_ACTION = "TEST_ACTION" + const val TEST_SCHEME = "TEST_SCHEME" + const val TEST_PATH = "TEST_PATH" + const val TEST_TYPE = "test/type" } @Mock @@ -83,6 +89,11 @@ class BroadcastDispatcherTest : SysuiTestCase() { Handler(testableLooper.looper), testableLooper.looper, mapOf(0 to mockUBRUser0, 1 to mockUBRUser1)) + + // These should be valid filters + `when`(intentFilter.countActions()).thenReturn(1) + `when`(intentFilterOther.countActions()).thenReturn(1) + `when`(mockContext.user).thenReturn(user0) } @Test @@ -129,6 +140,44 @@ class BroadcastDispatcherTest : SysuiTestCase() { verify(mockUBRUser1, never()).unregisterReceiver(broadcastReceiver) } + @Test(expected = IllegalArgumentException::class) + fun testFilterMustContainActions() { + val testFilter = IntentFilter() + broadcastDispatcher.registerReceiver(broadcastReceiver, testFilter) + } + + @Test(expected = IllegalArgumentException::class) + fun testFilterMustNotContainDataScheme() { + val testFilter = IntentFilter(TEST_ACTION).apply { + addDataScheme(TEST_SCHEME) + } + broadcastDispatcher.registerReceiver(broadcastReceiver, testFilter) + } + + @Test(expected = IllegalArgumentException::class) + fun testFilterMustNotContainDataAuthority() { + val testFilter = IntentFilter(TEST_ACTION).apply { + addDataAuthority(mock(IntentFilter.AuthorityEntry::class.java)) + } + broadcastDispatcher.registerReceiver(broadcastReceiver, testFilter) + } + + @Test(expected = IllegalArgumentException::class) + fun testFilterMustNotContainDataPath() { + val testFilter = IntentFilter(TEST_ACTION).apply { + addDataPath(TEST_PATH, PatternMatcher.PATTERN_LITERAL) + } + broadcastDispatcher.registerReceiver(broadcastReceiver, testFilter) + } + + @Test(expected = IllegalArgumentException::class) + fun testFilterMustNotContainDataType() { + val testFilter = IntentFilter(TEST_ACTION).apply { + addDataType(TEST_TYPE) + } + broadcastDispatcher.registerReceiver(broadcastReceiver, testFilter) + } + private class TestBroadcastDispatcher( context: Context, mainHandler: Handler,