Merge "Add logs for BroadcastDispatcher" into rvc-dev

This commit is contained in:
Fabian Kozynski
2020-06-11 14:20:36 +00:00
committed by Android (Google) Code Review
9 changed files with 258 additions and 13 deletions

View File

@@ -28,12 +28,12 @@ import android.text.TextUtils
import android.util.SparseArray
import com.android.internal.annotations.VisibleForTesting
import com.android.systemui.Dumpable
import com.android.systemui.broadcast.logging.BroadcastDispatcherLogger
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dump.DumpManager
import java.io.FileDescriptor
import java.io.PrintWriter
import java.lang.IllegalStateException
import java.util.concurrent.Executor
import javax.inject.Inject
import javax.inject.Singleton
@@ -67,7 +67,8 @@ open class BroadcastDispatcher @Inject constructor (
private val context: Context,
@Main private val mainHandler: Handler,
@Background private val bgLooper: Looper,
dumpManager: DumpManager
dumpManager: DumpManager,
private val logger: BroadcastDispatcherLogger
) : Dumpable {
// Only modify in BG thread
@@ -156,7 +157,7 @@ open class BroadcastDispatcher @Inject constructor (
/**
* Unregister receiver for a particular user.
*
* @param receiver The receiver to unregister. It will be unregistered for all users.
* @param receiver The receiver to unregister.
* @param user The user associated to the registered [receiver]. It can be [UserHandle.ALL].
*/
open fun unregisterReceiverForUser(receiver: BroadcastReceiver, user: UserHandle) {
@@ -166,7 +167,7 @@ open class BroadcastDispatcher @Inject constructor (
@VisibleForTesting
protected open fun createUBRForUser(userId: Int) =
UserBroadcastDispatcher(context, userId, bgLooper)
UserBroadcastDispatcher(context, userId, bgLooper, logger)
override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
pw.println("Broadcast dispatcher:")

View File

@@ -30,6 +30,7 @@ import android.util.Log
import androidx.annotation.VisibleForTesting
import com.android.internal.util.Preconditions
import com.android.systemui.Dumpable
import com.android.systemui.broadcast.logging.BroadcastDispatcherLogger
import java.io.FileDescriptor
import java.io.PrintWriter
import java.lang.IllegalArgumentException
@@ -54,7 +55,8 @@ private const val DEBUG = false
class UserBroadcastDispatcher(
private val context: Context,
private val userId: Int,
private val bgLooper: Looper
private val bgLooper: Looper,
private val logger: BroadcastDispatcherLogger
) : BroadcastReceiver(), Dumpable {
companion object {
@@ -109,10 +111,12 @@ class UserBroadcastDispatcher(
}
override fun onReceive(context: Context, intent: Intent) {
val id = if (DEBUG) index.getAndIncrement() else 0
val id = index.getAndIncrement()
if (DEBUG) Log.w(TAG, "[$id] Received $intent")
logger.logBroadcastReceived(id, userId, intent)
bgHandler.post(
HandleBroadcastRunnable(actionsToReceivers, context, intent, pendingResult, id))
HandleBroadcastRunnable(
actionsToReceivers, context, intent, pendingResult, id, logger))
}
/**
@@ -143,6 +147,7 @@ class UserBroadcastDispatcher(
ArraySet()
}.add(receiverData)
}
logger.logReceiverRegistered(userId, receiverData.receiver)
if (changed) {
createFilterAndRegisterReceiverBG()
}
@@ -163,6 +168,7 @@ class UserBroadcastDispatcher(
actionsToReceivers.remove(action)
}
}
logger.logReceiverUnregistered(userId, receiver)
if (changed) {
createFilterAndRegisterReceiverBG()
}
@@ -187,7 +193,8 @@ class UserBroadcastDispatcher(
val context: Context,
val intent: Intent,
val pendingResult: PendingResult,
val index: Int
val index: Int,
val logger: BroadcastDispatcherLogger
) : Runnable {
override fun run() {
if (DEBUG) Log.w(TAG, "[$index] Dispatching $intent")
@@ -199,6 +206,7 @@ class UserBroadcastDispatcher(
it.executor.execute {
if (DEBUG) Log.w(TAG,
"[$index] Dispatching ${intent.action} to ${it.receiver}")
logger.logBroadcastDispatched(index, intent.action, it.receiver)
it.receiver.pendingResult = pendingResult
it.receiver.onReceive(context, intent)
}
@@ -215,6 +223,7 @@ class UserBroadcastDispatcher(
if (registered.get()) {
try {
context.unregisterReceiver(this@UserBroadcastDispatcher)
logger.logContextReceiverUnregistered(userId)
} catch (e: IllegalArgumentException) {
Log.e(TAG, "Trying to unregister unregistered receiver for user $userId",
IllegalStateException(e))
@@ -230,6 +239,7 @@ class UserBroadcastDispatcher(
null,
bgHandler)
registered.set(true)
logger.logContextReceiverRegistered(userId, intentFilter)
}
}
}

View File

@@ -0,0 +1,117 @@
/*
* Copyright (C) 2020 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.logging
import android.content.BroadcastReceiver
import android.content.Intent
import android.content.IntentFilter
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.LogLevel
import com.android.systemui.log.LogLevel.DEBUG
import com.android.systemui.log.LogLevel.INFO
import com.android.systemui.log.LogMessage
import com.android.systemui.log.dagger.BroadcastDispatcherLog
import javax.inject.Inject
private const val TAG = "BroadcastDispatcherLog"
class BroadcastDispatcherLogger @Inject constructor(
@BroadcastDispatcherLog private val buffer: LogBuffer
) {
fun logBroadcastReceived(broadcastId: Int, user: Int, intent: Intent) {
val intentString = intent.toString()
log(INFO, {
int1 = broadcastId
int2 = user
str1 = intentString
}, {
"[$int1] Broadcast received for user $int2: $str1"
})
}
fun logBroadcastDispatched(broadcastId: Int, action: String?, receiver: BroadcastReceiver) {
val receiverString = receiver.toString()
log(DEBUG, {
int1 = broadcastId
str1 = action
str2 = receiverString
}, {
"Broadcast $int1 ($str1) dispatched to $str2"
})
}
fun logReceiverRegistered(user: Int, receiver: BroadcastReceiver) {
val receiverString = receiver.toString()
log(INFO, {
int1 = user
str1 = receiverString
}, {
"Receiver $str1 registered for user $int1"
})
}
fun logReceiverUnregistered(user: Int, receiver: BroadcastReceiver) {
val receiverString = receiver.toString()
log(INFO, {
int1 = user
str1 = receiverString
}, {
"Receiver $str1 unregistered for user $int1"
})
}
fun logContextReceiverRegistered(user: Int, filter: IntentFilter) {
val actions = filter.actionsIterator().asSequence()
.joinToString(separator = ",", prefix = "Actions(", postfix = ")")
val categories = if (filter.countCategories() != 0) {
filter.categoriesIterator().asSequence()
.joinToString(separator = ",", prefix = "Categories(", postfix = ")")
} else {
""
}
log(INFO, {
int1 = user
str1 = if (categories != "") {
"${actions}\n$categories"
} else {
actions
}
}, {
"""
Receiver registered with Context for user $int1.
$str1
""".trimIndent()
})
}
fun logContextReceiverUnregistered(user: Int) {
log(INFO, {
int1 = user
}, {
"Receiver unregistered with Context for user $int1."
})
}
private inline fun log(
logLevel: LogLevel,
initializer: LogMessage.() -> Unit,
noinline printer: LogMessage.() -> String
) {
buffer.log(TAG, logLevel, initializer, printer)
}
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright (C) 2020 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.log.dagger;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import com.android.systemui.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import javax.inject.Qualifier;
/** A {@link LogBuffer} for BroadcastDispatcher-related messages. */
@Qualifier
@Documented
@Retention(RUNTIME)
public @interface BroadcastDispatcherLog {
}

View File

@@ -97,6 +97,18 @@ public class LogModule {
return buffer;
}
/** Provides a logging buffer for {@link com.android.systemui.broadcast.BroadcastDispatcher} */
@Provides
@Singleton
@BroadcastDispatcherLog
public static LogBuffer provideBroadcastDispatcherLogBuffer(
LogcatEchoTracker bufferFilter,
DumpManager dumpManager) {
LogBuffer buffer = new LogBuffer("BroadcastDispatcherLog", 500, 10, bufferFilter);
buffer.attach(dumpManager);
return buffer;
}
/** Allows logging buffers to be tweaked via adb on debug builds but not on prod builds. */
@Provides
@Singleton

View File

@@ -35,6 +35,7 @@ import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.broadcast.FakeBroadcastDispatcher;
import com.android.systemui.broadcast.logging.BroadcastDispatcherLogger;
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.plugins.FalsingManager;
@@ -73,7 +74,7 @@ public abstract class SysuiTestCase {
SystemUIFactory.createFromConfig(mContext);
mDependency = new TestableDependency(mContext);
mFakeBroadcastDispatcher = new FakeBroadcastDispatcher(mContext, mock(Handler.class),
mock(Looper.class), mock(DumpManager.class));
mock(Looper.class), mock(DumpManager.class), mock(BroadcastDispatcherLogger.class));
mRealInstrumentation = InstrumentationRegistry.getInstrumentation();
Instrumentation inst = spy(mRealInstrumentation);

View File

@@ -27,6 +27,7 @@ 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.util.concurrency.FakeExecutor
import com.android.systemui.util.time.FakeSystemClock
@@ -76,6 +77,8 @@ class BroadcastDispatcherTest : SysuiTestCase() {
private lateinit var intentFilterOther: IntentFilter
@Mock
private lateinit var mockHandler: Handler
@Mock
private lateinit var logger: BroadcastDispatcherLogger
private lateinit var executor: Executor
@@ -96,6 +99,7 @@ class BroadcastDispatcherTest : SysuiTestCase() {
Handler(testableLooper.looper),
testableLooper.looper,
mock(DumpManager::class.java),
logger,
mapOf(0 to mockUBRUser0, 1 to mockUBRUser1))
// These should be valid filters
@@ -239,8 +243,9 @@ class BroadcastDispatcherTest : SysuiTestCase() {
mainHandler: Handler,
bgLooper: Looper,
dumpManager: DumpManager,
logger: BroadcastDispatcherLogger,
var mockUBRMap: Map<Int, UserBroadcastDispatcher>
) : BroadcastDispatcher(context, mainHandler, bgLooper, dumpManager) {
) : BroadcastDispatcher(context, mainHandler, bgLooper, dumpManager, logger) {
override fun createUBRForUser(userId: Int): UserBroadcastDispatcher {
return mockUBRMap.getOrDefault(userId, mock(UserBroadcastDispatcher::class.java))
}

View File

@@ -24,6 +24,7 @@ import android.os.UserHandle
import android.util.ArraySet
import android.util.Log
import com.android.systemui.SysuiTestableContext
import com.android.systemui.broadcast.logging.BroadcastDispatcherLogger
import com.android.systemui.dump.DumpManager
import java.util.concurrent.Executor
@@ -31,8 +32,9 @@ class FakeBroadcastDispatcher(
context: SysuiTestableContext,
handler: Handler,
looper: Looper,
dumpManager: DumpManager
) : BroadcastDispatcher(context, handler, looper, dumpManager) {
dumpManager: DumpManager,
logger: BroadcastDispatcherLogger
) : BroadcastDispatcher(context, handler, looper, dumpManager, logger) {
private val registeredReceivers = ArraySet<BroadcastReceiver>()

View File

@@ -26,6 +26,7 @@ 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.util.concurrency.FakeExecutor
import com.android.systemui.util.time.FakeSystemClock
import junit.framework.Assert.assertEquals
@@ -40,6 +41,7 @@ import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.eq
import org.mockito.Captor
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.Mockito.anyString
import org.mockito.Mockito.atLeastOnce
import org.mockito.Mockito.never
@@ -62,6 +64,8 @@ class UserBroadcastDispatcherTest : SysuiTestCase() {
private val USER_HANDLE = UserHandle.of(USER_ID)
fun <T> capture(argumentCaptor: ArgumentCaptor<T>): T = argumentCaptor.capture()
fun <T> any(): T = Mockito.any()
fun <T> eq(v: T) = Mockito.eq(v) ?: v
}
@Mock
@@ -72,6 +76,8 @@ class UserBroadcastDispatcherTest : SysuiTestCase() {
private lateinit var mockContext: Context
@Mock
private lateinit var mPendingResult: BroadcastReceiver.PendingResult
@Mock
private lateinit var logger: BroadcastDispatcherLogger
@Captor
private lateinit var argumentCaptor: ArgumentCaptor<IntentFilter>
@@ -91,7 +97,7 @@ class UserBroadcastDispatcherTest : SysuiTestCase() {
fakeExecutor = FakeExecutor(FakeSystemClock())
userBroadcastDispatcher = UserBroadcastDispatcher(
mockContext, USER_ID, testableLooper.looper)
mockContext, USER_ID, testableLooper.looper, logger)
userBroadcastDispatcher.pendingResult = mPendingResult
}
@@ -105,6 +111,13 @@ class UserBroadcastDispatcherTest : SysuiTestCase() {
verify(mockContext, never()).registerReceiverAsUser(any(), any(), any(), anyString(), any())
}
@Test
fun testNotRegisteredOnStart_logging() {
testableLooper.processAllMessages()
verify(logger, never()).logContextReceiverRegistered(anyInt(), any())
}
@Test
fun testSingleReceiverRegistered() {
intentFilter = IntentFilter(ACTION_1)
@@ -125,6 +138,18 @@ class UserBroadcastDispatcherTest : SysuiTestCase() {
assertEquals(0, argumentCaptor.value.countCategories())
}
@Test
fun testSingleReceiverRegistered_logging() {
intentFilter = IntentFilter(ACTION_1)
userBroadcastDispatcher.registerReceiver(
ReceiverData(broadcastReceiver, intentFilter, fakeExecutor, USER_HANDLE))
testableLooper.processAllMessages()
verify(logger).logReceiverRegistered(USER_HANDLE.identifier, broadcastReceiver)
verify(logger).logContextReceiverRegistered(eq(USER_HANDLE.identifier), any())
}
@Test
fun testSingleReceiverUnregistered() {
intentFilter = IntentFilter(ACTION_1)
@@ -144,6 +169,21 @@ class UserBroadcastDispatcherTest : SysuiTestCase() {
assertFalse(userBroadcastDispatcher.isRegistered())
}
@Test
fun testSingleReceiverUnregistered_logger() {
intentFilter = IntentFilter(ACTION_1)
userBroadcastDispatcher.registerReceiver(
ReceiverData(broadcastReceiver, intentFilter, fakeExecutor, USER_HANDLE))
testableLooper.processAllMessages()
userBroadcastDispatcher.unregisterReceiver(broadcastReceiver)
testableLooper.processAllMessages()
verify(logger).logReceiverUnregistered(USER_HANDLE.identifier, broadcastReceiver)
verify(logger).logContextReceiverUnregistered(USER_HANDLE.identifier)
}
@Test
fun testFilterHasAllActionsAndCategories_twoReceivers() {
intentFilter = IntentFilter(ACTION_1)
@@ -195,6 +235,30 @@ class UserBroadcastDispatcherTest : SysuiTestCase() {
verify(broadcastReceiverOther).onReceive(mockContext, intent)
}
@Test
fun testDispatch_logger() {
intentFilter = IntentFilter(ACTION_1)
intentFilterOther = IntentFilter(ACTION_2)
userBroadcastDispatcher.registerReceiver(
ReceiverData(broadcastReceiver, intentFilter, fakeExecutor, USER_HANDLE))
userBroadcastDispatcher.registerReceiver(
ReceiverData(broadcastReceiverOther, intentFilterOther, fakeExecutor, USER_HANDLE))
val intent = Intent(ACTION_2)
userBroadcastDispatcher.onReceive(mockContext, intent)
testableLooper.processAllMessages()
fakeExecutor.runAllReady()
val captor = ArgumentCaptor.forClass(Int::class.java)
verify(logger)
.logBroadcastReceived(captor.capture(), eq(USER_HANDLE.identifier), eq(intent))
verify(logger).logBroadcastDispatched(captor.value, ACTION_2, broadcastReceiverOther)
verify(logger, never())
.logBroadcastDispatched(eq(captor.value), any(), eq(broadcastReceiver))
}
@Test
fun testDispatchToCorrectReceiver_differentFiltersSameReceiver() {
intentFilter = IntentFilter(ACTION_1)