Merge "Ensure that maps are only accessed in BG thread"
This commit is contained in:
committed by
Android (Google) Code Review
commit
99497310de
@@ -27,6 +27,8 @@ import android.os.UserHandle
|
||||
import android.util.ArrayMap
|
||||
import android.util.ArraySet
|
||||
import android.util.Log
|
||||
import androidx.annotation.MainThread
|
||||
import com.android.internal.util.Preconditions
|
||||
import com.android.systemui.Dumpable
|
||||
import java.io.FileDescriptor
|
||||
import java.io.PrintWriter
|
||||
@@ -72,7 +74,14 @@ class UserBroadcastDispatcher(
|
||||
|
||||
internal fun isRegistered() = registered.get()
|
||||
|
||||
private val registerReceiver = Runnable {
|
||||
// Only modify in BG thread
|
||||
private val actionsToReceivers = ArrayMap<String, MutableSet<ReceiverData>>()
|
||||
private val receiverToReceiverData = ArrayMap<BroadcastReceiver, MutableSet<ReceiverData>>()
|
||||
|
||||
// Only call on BG thread as it reads from the maps
|
||||
private fun createFilter(): IntentFilter {
|
||||
Preconditions.checkState(bgHandler.looper.isCurrentThread,
|
||||
"This method should only be called from BG thread")
|
||||
val categories = mutableSetOf<String>()
|
||||
receiverToReceiverData.values.flatten().forEach {
|
||||
it.filter.categoriesIterator()?.asSequence()?.let {
|
||||
@@ -80,30 +89,13 @@ class UserBroadcastDispatcher(
|
||||
}
|
||||
}
|
||||
val intentFilter = IntentFilter().apply {
|
||||
actionsToReceivers.keys.forEach { addAction(it) }
|
||||
// The keys of the arrayMap are of type String! so null check is needed
|
||||
actionsToReceivers.keys.forEach { if (it != null) addAction(it) else Unit }
|
||||
categories.forEach { addCategory(it) }
|
||||
}
|
||||
|
||||
if (registered.get()) {
|
||||
context.unregisterReceiver(this)
|
||||
registered.set(false)
|
||||
}
|
||||
// Short interval without receiver, this can be problematic
|
||||
if (intentFilter.countActions() > 0 && !registered.get()) {
|
||||
context.registerReceiverAsUser(
|
||||
this,
|
||||
UserHandle.of(userId),
|
||||
intentFilter,
|
||||
null,
|
||||
bgHandler)
|
||||
registered.set(true)
|
||||
}
|
||||
return intentFilter
|
||||
}
|
||||
|
||||
// Only modify in BG thread
|
||||
private val actionsToReceivers = ArrayMap<String, MutableSet<ReceiverData>>()
|
||||
private val receiverToReceiverData = ArrayMap<BroadcastReceiver, MutableSet<ReceiverData>>()
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
val id = if (DEBUG) index.getAndIncrement() else 0
|
||||
if (DEBUG) Log.w(TAG, "[$id] Received $intent")
|
||||
@@ -126,6 +118,8 @@ class UserBroadcastDispatcher(
|
||||
}
|
||||
|
||||
private fun handleRegisterReceiver(receiverData: ReceiverData) {
|
||||
Preconditions.checkState(bgHandler.looper.isCurrentThread,
|
||||
"This method should only be called from BG thread")
|
||||
if (DEBUG) Log.w(TAG, "Register receiver: ${receiverData.receiver}")
|
||||
receiverToReceiverData.getOrPut(receiverData.receiver, { ArraySet() }).add(receiverData)
|
||||
var changed = false
|
||||
@@ -138,11 +132,13 @@ class UserBroadcastDispatcher(
|
||||
}.add(receiverData)
|
||||
}
|
||||
if (changed) {
|
||||
mainHandler.post(registerReceiver)
|
||||
createFilterAndRegisterReceiverBG()
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleUnregisterReceiver(receiver: BroadcastReceiver) {
|
||||
Preconditions.checkState(bgHandler.looper.isCurrentThread,
|
||||
"This method should only be called from BG thread")
|
||||
if (DEBUG) Log.w(TAG, "Unregister receiver: $receiver")
|
||||
val actions = receiverToReceiverData.getOrElse(receiver) { return }
|
||||
.flatMap { it.filter.actionsIterator().asSequence().asIterable() }.toSet()
|
||||
@@ -156,10 +152,16 @@ class UserBroadcastDispatcher(
|
||||
}
|
||||
}
|
||||
if (changed) {
|
||||
mainHandler.post(registerReceiver)
|
||||
createFilterAndRegisterReceiverBG()
|
||||
}
|
||||
}
|
||||
|
||||
// Only call this from a BG thread
|
||||
private fun createFilterAndRegisterReceiverBG() {
|
||||
val intentFilter = createFilter()
|
||||
mainHandler.post(RegisterReceiverRunnable(intentFilter))
|
||||
}
|
||||
|
||||
override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
|
||||
pw.println(" Registered=${registered.get()}")
|
||||
actionsToReceivers.forEach { (action, list) ->
|
||||
@@ -191,4 +193,30 @@ class UserBroadcastDispatcher(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private inner class RegisterReceiverRunnable(val intentFilter: IntentFilter) : Runnable {
|
||||
|
||||
/*
|
||||
* Registers and unregisters the BroadcastReceiver
|
||||
*
|
||||
* Must be called from Main Thread
|
||||
*/
|
||||
@MainThread
|
||||
override fun run() {
|
||||
if (registered.get()) {
|
||||
context.unregisterReceiver(this@UserBroadcastDispatcher)
|
||||
registered.set(false)
|
||||
}
|
||||
// Short interval without receiver, this can be problematic
|
||||
if (intentFilter.countActions() > 0 && !registered.get()) {
|
||||
context.registerReceiverAsUser(
|
||||
this@UserBroadcastDispatcher,
|
||||
UserHandle.of(userId),
|
||||
intentFilter,
|
||||
null,
|
||||
bgHandler)
|
||||
registered.set(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user