Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 99497310 authored by Fabian Kozynski's avatar Fabian Kozynski Committed by Android (Google) Code Review
Browse files

Merge "Ensure that maps are only accessed in BG thread"

parents c4e27989 213049e6
Loading
Loading
Loading
Loading
+51 −23
Original line number Diff line number Diff line
@@ -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)
            }
        }
    }
}