blob: 7795d2caf091d09c5640ba25b282410cd407883c [file] [log] [blame]
/*
* Copyright (C) 2019 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.systemui.broadcast
import android.content.BroadcastReceiver
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
import android.testing.TestableLooper
import com.android.systemui.SysuiTestCase
import com.android.systemui.broadcast.logging.BroadcastDispatcherLogger
import com.android.systemui.dump.DumpManager
import com.android.systemui.settings.UserTracker
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.time.FakeSystemClock
import junit.framework.Assert.assertSame
import org.junit.Before
import org.junit.Test
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.anyInt
import org.mockito.Mockito.inOrder
import org.mockito.Mockito.mock
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
import java.util.concurrent.Executor
@RunWith(AndroidTestingRunner::class)
@TestableLooper.RunWithLooper
@SmallTest
class BroadcastDispatcherTest : SysuiTestCase() {
companion object {
val user0 = UserHandle.of(0)
val user1 = UserHandle.of(1)
const val DEFAULT_FLAG = Context.RECEIVER_EXPORTED
val DEFAULT_PERMISSION: String? = null
fun <T> capture(argumentCaptor: ArgumentCaptor<T>): 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
private lateinit var mockContext: Context
@Mock
private lateinit var mockUBRUser0: UserBroadcastDispatcher
@Mock
private lateinit var mockUBRUser1: UserBroadcastDispatcher
@Mock
private lateinit var broadcastReceiver: BroadcastReceiver
@Mock
private lateinit var broadcastReceiverOther: BroadcastReceiver
@Mock
private lateinit var intentFilter: IntentFilter
@Mock
private lateinit var intentFilterOther: IntentFilter
@Mock
private lateinit var mockHandler: Handler
@Mock
private lateinit var logger: BroadcastDispatcherLogger
@Mock
private lateinit var userTracker: UserTracker
@Mock
private lateinit var removalPendingStore: PendingRemovalStore
private lateinit var executor: Executor
@Captor
private lateinit var argumentCaptor: ArgumentCaptor<ReceiverData>
private lateinit var testableLooper: TestableLooper
private lateinit var broadcastDispatcher: BroadcastDispatcher
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
testableLooper = TestableLooper.get(this)
executor = FakeExecutor(FakeSystemClock())
`when`(mockContext.mainExecutor).thenReturn(executor)
broadcastDispatcher = TestBroadcastDispatcher(
mockContext,
testableLooper.looper,
mock(Executor::class.java),
mock(DumpManager::class.java),
logger,
userTracker,
removalPendingStore,
mapOf(0 to mockUBRUser0, 1 to mockUBRUser1))
// These should be valid filters
`when`(intentFilter.countActions()).thenReturn(1)
`when`(intentFilterOther.countActions()).thenReturn(1)
setUserMock(mockContext, user0)
}
@Test
fun testAddingReceiverToCorrectUBR() {
broadcastDispatcher.registerReceiverWithHandler(broadcastReceiver, intentFilter,
mockHandler, user0)
broadcastDispatcher.registerReceiverWithHandler(
broadcastReceiverOther, intentFilterOther, mockHandler, user1)
testableLooper.processAllMessages()
verify(mockUBRUser0).registerReceiver(capture(argumentCaptor), eq(DEFAULT_FLAG))
assertSame(broadcastReceiver, argumentCaptor.value.receiver)
assertSame(intentFilter, argumentCaptor.value.filter)
verify(mockUBRUser1).registerReceiver(capture(argumentCaptor), eq(DEFAULT_FLAG))
assertSame(broadcastReceiverOther, argumentCaptor.value.receiver)
assertSame(intentFilterOther, argumentCaptor.value.filter)
}
@Test
fun testAddingReceiverToCorrectUBR_executor() {
broadcastDispatcher.registerReceiver(broadcastReceiver, intentFilter, executor, user0)
broadcastDispatcher.registerReceiver(
broadcastReceiverOther, intentFilterOther, executor, user1)
testableLooper.processAllMessages()
verify(mockUBRUser0).registerReceiver(capture(argumentCaptor), eq(DEFAULT_FLAG))
assertSame(broadcastReceiver, argumentCaptor.value.receiver)
assertSame(intentFilter, argumentCaptor.value.filter)
verify(mockUBRUser1).registerReceiver(capture(argumentCaptor), eq(DEFAULT_FLAG))
assertSame(broadcastReceiverOther, argumentCaptor.value.receiver)
assertSame(intentFilterOther, argumentCaptor.value.filter)
}
@Test
fun testAddReceiverDefaultFlag_handler() {
broadcastDispatcher.registerReceiverWithHandler(
broadcastReceiver, intentFilter, mockHandler)
testableLooper.processAllMessages()
verify(mockUBRUser0).registerReceiver(capture(argumentCaptor), eq(DEFAULT_FLAG))
assertSame(broadcastReceiver, argumentCaptor.value.receiver)
assertSame(intentFilter, argumentCaptor.value.filter)
}
@Test
fun testAddReceiverCorrectFlag_handler() {
val flag = 3
broadcastDispatcher.registerReceiverWithHandler(
broadcastReceiver, intentFilter, mockHandler, flags = flag)
testableLooper.processAllMessages()
verify(mockUBRUser0).registerReceiver(capture(argumentCaptor), eq(flag))
assertSame(broadcastReceiver, argumentCaptor.value.receiver)
assertSame(intentFilter, argumentCaptor.value.filter)
}
@Test
fun testAddReceiverDefaultFlag_executor() {
broadcastDispatcher.registerReceiver(broadcastReceiver, intentFilter)
testableLooper.processAllMessages()
verify(mockUBRUser0).registerReceiver(capture(argumentCaptor), eq(DEFAULT_FLAG))
assertSame(broadcastReceiver, argumentCaptor.value.receiver)
assertSame(intentFilter, argumentCaptor.value.filter)
}
@Test
fun testAddReceiverCorrectPermission_executor() {
val flag = 3
val permission = "CUSTOM_PERMISSION"
broadcastDispatcher.registerReceiver(
broadcastReceiver,
intentFilter,
flags = flag,
permission = permission
)
testableLooper.processAllMessages()
verify(mockUBRUser0).registerReceiver(capture(argumentCaptor), eq(flag))
assertSame(broadcastReceiver, argumentCaptor.value.receiver)
assertSame(intentFilter, argumentCaptor.value.filter)
assertSame(permission, argumentCaptor.value.permission)
}
@Test
fun testAddReceiverDefaultPermission_executor() {
broadcastDispatcher.registerReceiver(broadcastReceiver, intentFilter)
testableLooper.processAllMessages()
verify(mockUBRUser0).registerReceiver(capture(argumentCaptor), eq(DEFAULT_FLAG))
assertSame(broadcastReceiver, argumentCaptor.value.receiver)
assertSame(intentFilter, argumentCaptor.value.filter)
assertSame(DEFAULT_PERMISSION, argumentCaptor.value.permission)
}
@Test
fun testAddReceiverCorrectFlag_executor() {
val flag = 3
broadcastDispatcher.registerReceiver(broadcastReceiver, intentFilter, flags = flag)
testableLooper.processAllMessages()
verify(mockUBRUser0).registerReceiver(capture(argumentCaptor), eq(flag))
assertSame(broadcastReceiver, argumentCaptor.value.receiver)
assertSame(intentFilter, argumentCaptor.value.filter)
}
@Test
fun testRemovingReceiversRemovesFromAllUBR() {
broadcastDispatcher.registerReceiverWithHandler(broadcastReceiver, intentFilter,
mockHandler, user0)
broadcastDispatcher.registerReceiverWithHandler(broadcastReceiver, intentFilter,
mockHandler, user1)
broadcastDispatcher.unregisterReceiver(broadcastReceiver)
testableLooper.processAllMessages()
verify(mockUBRUser0).unregisterReceiver(broadcastReceiver)
verify(mockUBRUser1).unregisterReceiver(broadcastReceiver)
}
@Test
fun testRemoveReceiverFromUser() {
broadcastDispatcher.registerReceiverWithHandler(broadcastReceiver, intentFilter,
mockHandler, user0)
broadcastDispatcher.registerReceiverWithHandler(broadcastReceiver, intentFilter,
mockHandler, user1)
broadcastDispatcher.unregisterReceiverForUser(broadcastReceiver, user0)
testableLooper.processAllMessages()
verify(mockUBRUser0).unregisterReceiver(broadcastReceiver)
verify(mockUBRUser1, never()).unregisterReceiver(broadcastReceiver)
}
@Test
fun testRegisterCurrentAsActualUser() {
`when`(userTracker.userId).thenReturn(user1.identifier)
broadcastDispatcher.registerReceiverWithHandler(broadcastReceiver, intentFilter,
mockHandler, UserHandle.CURRENT)
testableLooper.processAllMessages()
verify(mockUBRUser1).registerReceiver(
capture(argumentCaptor), eq(Context.RECEIVER_EXPORTED))
assertSame(broadcastReceiver, argumentCaptor.value.receiver)
}
@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)
}
@Test(expected = IllegalArgumentException::class)
fun testFilterMustNotSetPriority() {
val testFilter = IntentFilter(TEST_ACTION).apply {
priority = IntentFilter.SYSTEM_HIGH_PRIORITY
}
broadcastDispatcher.registerReceiver(broadcastReceiver, testFilter)
}
@Test
fun testTaggedReceiverForRemovalImmediately_allUsers() {
broadcastDispatcher.unregisterReceiver(broadcastReceiver)
verify(removalPendingStore).tagForRemoval(broadcastReceiver, UserHandle.USER_ALL)
verify(removalPendingStore, never()).clearPendingRemoval(eq(broadcastReceiver), anyInt())
}
@Test
fun testTaggedReceiverForRemovalImmediately_singleUser() {
val user = 0
broadcastDispatcher.unregisterReceiverForUser(broadcastReceiver, UserHandle.of(user))
verify(removalPendingStore).tagForRemoval(broadcastReceiver, user)
verify(removalPendingStore, never()).clearPendingRemoval(eq(broadcastReceiver), anyInt())
}
@Test
fun testUnregisterReceiverClearsPendingRemovalAfterRemoving_allUsers() {
broadcastDispatcher.registerReceiver(broadcastReceiver, intentFilter, null, user0)
broadcastDispatcher.registerReceiver(broadcastReceiver, intentFilter, null, user1)
broadcastDispatcher.unregisterReceiver(broadcastReceiver)
testableLooper.processAllMessages()
val inOrderUser0 = inOrder(mockUBRUser0, removalPendingStore)
inOrderUser0.verify(mockUBRUser0).unregisterReceiver(broadcastReceiver)
inOrderUser0.verify(removalPendingStore)
.clearPendingRemoval(broadcastReceiver, UserHandle.USER_ALL)
val inOrderUser1 = inOrder(mockUBRUser1, removalPendingStore)
inOrderUser1.verify(mockUBRUser1).unregisterReceiver(broadcastReceiver)
inOrderUser1.verify(removalPendingStore)
.clearPendingRemoval(broadcastReceiver, UserHandle.USER_ALL)
}
@Test
fun testUnregisterReceiverclearPendingRemovalAfterRemoving_singleUser() {
broadcastDispatcher.registerReceiver(broadcastReceiver, intentFilter, null, user1)
broadcastDispatcher.unregisterReceiverForUser(broadcastReceiver, user1)
testableLooper.processAllMessages()
val inOrderUser1 = inOrder(mockUBRUser1, removalPendingStore)
inOrderUser1.verify(mockUBRUser1).unregisterReceiver(broadcastReceiver)
inOrderUser1.verify(removalPendingStore)
.clearPendingRemoval(broadcastReceiver, user1.identifier)
}
private fun setUserMock(mockContext: Context, user: UserHandle) {
`when`(mockContext.user).thenReturn(user)
`when`(mockContext.userId).thenReturn(user.identifier)
}
private class TestBroadcastDispatcher(
context: Context,
bgLooper: Looper,
executor: Executor,
dumpManager: DumpManager,
logger: BroadcastDispatcherLogger,
userTracker: UserTracker,
removalPendingStore: PendingRemovalStore,
var mockUBRMap: Map<Int, UserBroadcastDispatcher>
) : BroadcastDispatcher(
context,
bgLooper,
executor,
dumpManager,
logger,
userTracker,
removalPendingStore
) {
override fun createUBRForUser(userId: Int): UserBroadcastDispatcher {
return mockUBRMap.getOrDefault(userId, mock(UserBroadcastDispatcher::class.java))
}
}
}