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

Commit 8af79601 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Make unregister receiver "sync"." into tm-dev

parents 11000cfd 87457295
Loading
Loading
Loading
Loading
+11 −2
Original line number Diff line number Diff line
@@ -39,6 +39,13 @@ import java.util.concurrent.atomic.AtomicInteger
 *
 * This class has no sync controls, so make sure to only make modifications from the background
 * thread.
 *
 * This class takes the following actions:
 * * [registerAction]: action to register this receiver (with the proper filter) with [Context].
 * * [unregisterAction]: action to unregister this receiver with [Context].
 * * [testPendingRemovalAction]: action to check if a particular [BroadcastReceiver] registered
 *   with [BroadcastDispatcher] has been unregistered and is pending removal. See
 *   [PendingRemovalStore].
 */
class ActionReceiver(
    private val action: String,
@@ -46,7 +53,8 @@ class ActionReceiver(
    private val registerAction: BroadcastReceiver.(IntentFilter) -> Unit,
    private val unregisterAction: BroadcastReceiver.() -> Unit,
    private val bgExecutor: Executor,
    private val logger: BroadcastDispatcherLogger
    private val logger: BroadcastDispatcherLogger,
    private val testPendingRemovalAction: (BroadcastReceiver, Int) -> Boolean
) : BroadcastReceiver(), Dumpable {

    companion object {
@@ -106,7 +114,8 @@ class ActionReceiver(
        // Immediately return control to ActivityManager
        bgExecutor.execute {
            receiverDatas.forEach {
                if (it.filter.matchCategories(intent.categories) == null) {
                if (it.filter.matchCategories(intent.categories) == null &&
                    !testPendingRemovalAction(it.receiver, userId)) {
                    it.executor.execute {
                        it.receiver.pendingResult = pendingResult
                        it.receiver.onReceive(context, intent)
+26 −4
Original line number Diff line number Diff line
@@ -63,13 +63,14 @@ private const val DEBUG = true
 * Broadcast handling may be asynchronous *without* calling goAsync(), as it's running within sysui
 * and doesn't need to worry about being killed.
 */
open class BroadcastDispatcher constructor (
open class BroadcastDispatcher @JvmOverloads constructor (
    private val context: Context,
    private val bgLooper: Looper,
    private val bgExecutor: Executor,
    private val dumpManager: DumpManager,
    private val logger: BroadcastDispatcherLogger,
    private val userTracker: UserTracker
    private val userTracker: UserTracker,
    private val removalPendingStore: PendingRemovalStore = PendingRemovalStore(logger)
) : Dumpable {

    // Only modify in BG thread
@@ -167,6 +168,7 @@ open class BroadcastDispatcher constructor (
     * @param receiver The receiver to unregister. It will be unregistered for all users.
     */
    open fun unregisterReceiver(receiver: BroadcastReceiver) {
        removalPendingStore.tagForRemoval(receiver, UserHandle.USER_ALL)
        handler.obtainMessage(MSG_REMOVE_RECEIVER, receiver).sendToTarget()
    }

@@ -177,13 +179,21 @@ open class BroadcastDispatcher constructor (
     * @param user The user associated to the registered [receiver]. It can be [UserHandle.ALL].
     */
    open fun unregisterReceiverForUser(receiver: BroadcastReceiver, user: UserHandle) {
        removalPendingStore.tagForRemoval(receiver, user.identifier)
        handler.obtainMessage(MSG_REMOVE_RECEIVER_FOR_USER, user.identifier, 0, receiver)
                .sendToTarget()
    }

    @VisibleForTesting
    protected open fun createUBRForUser(userId: Int) =
            UserBroadcastDispatcher(context, userId, bgLooper, bgExecutor, logger)
            UserBroadcastDispatcher(
                context,
                userId,
                bgLooper,
                bgExecutor,
                logger,
                removalPendingStore
            )

    override fun dump(pw: PrintWriter, args: Array<out String>) {
        pw.println("Broadcast dispatcher:")
@@ -193,6 +203,8 @@ open class BroadcastDispatcher constructor (
            ipw.println("User ${receiversByUser.keyAt(index)}")
            receiversByUser.valueAt(index).dump(ipw, args)
        }
        ipw.println("Pending removal:")
        removalPendingStore.dump(ipw, args)
        ipw.decreaseIndent()
    }

@@ -223,10 +235,20 @@ open class BroadcastDispatcher constructor (
                    for (it in 0 until receiversByUser.size()) {
                        receiversByUser.valueAt(it).unregisterReceiver(msg.obj as BroadcastReceiver)
                    }
                    removalPendingStore.clearPendingRemoval(
                        msg.obj as BroadcastReceiver,
                        UserHandle.USER_ALL
                    )
                }

                MSG_REMOVE_RECEIVER_FOR_USER -> {
                    receiversByUser.get(msg.arg1)?.unregisterReceiver(msg.obj as BroadcastReceiver)
                    val userId = if (msg.arg1 == UserHandle.USER_CURRENT) {
                        userTracker.userId
                    } else {
                        msg.arg1
                    }
                    receiversByUser.get(userId)?.unregisterReceiver(msg.obj as BroadcastReceiver)
                    removalPendingStore.clearPendingRemoval(msg.obj as BroadcastReceiver, userId)
                }
                else -> super.handleMessage(msg)
            }
+58 −0
Original line number Diff line number Diff line
package com.android.systemui.broadcast

import android.content.BroadcastReceiver
import android.os.UserHandle
import android.util.SparseSetArray
import androidx.annotation.GuardedBy
import com.android.systemui.Dumpable
import com.android.systemui.broadcast.logging.BroadcastDispatcherLogger
import com.android.systemui.util.indentIfPossible
import java.io.PrintWriter

/**
 * Store information about requests for unregistering receivers from [BroadcastDispatcher], before
 * they have been completely removed from the system.
 *
 * This helps make unregistering a receiver a *sync* operation.
 */
class PendingRemovalStore(
    private val logger: BroadcastDispatcherLogger
) : Dumpable {
    @GuardedBy("pendingRemoval")
    private val pendingRemoval: SparseSetArray<BroadcastReceiver> = SparseSetArray()

    fun tagForRemoval(broadcastReceiver: BroadcastReceiver, userId: Int) {
        logger.logTagForRemoval(userId, broadcastReceiver)
        synchronized(pendingRemoval) {
            pendingRemoval.add(userId, broadcastReceiver)
        }
    }

    fun isPendingRemoval(broadcastReceiver: BroadcastReceiver, userId: Int): Boolean {
        return synchronized(pendingRemoval) {
            pendingRemoval.contains(userId, broadcastReceiver) ||
                pendingRemoval.contains(UserHandle.USER_ALL, broadcastReceiver)
        }
    }

    fun clearPendingRemoval(broadcastReceiver: BroadcastReceiver, userId: Int) {
        synchronized(pendingRemoval) {
            pendingRemoval.remove(userId, broadcastReceiver)
        }
        logger.logClearedAfterRemoval(userId, broadcastReceiver)
    }

    override fun dump(pw: PrintWriter, args: Array<out String>) {
        synchronized(pendingRemoval) {
            pw.indentIfPossible {
                val size = pendingRemoval.size()
                for (i in 0 until size) {
                    val user = pendingRemoval.keyAt(i)
                    print(user)
                    print("->")
                    println(pendingRemoval.get(user))
                }
            }
        }
    }
}
 No newline at end of file
+13 −19
Original line number Diff line number Diff line
@@ -20,12 +20,12 @@ import android.content.BroadcastReceiver
import android.content.Context
import android.os.Handler
import android.os.Looper
import android.os.Message
import android.os.UserHandle
import android.util.ArrayMap
import android.util.ArraySet
import android.util.Log
import androidx.annotation.VisibleForTesting
import androidx.annotation.WorkerThread
import com.android.internal.util.Preconditions
import com.android.systemui.Dumpable
import com.android.systemui.broadcast.logging.BroadcastDispatcherLogger
@@ -34,8 +34,6 @@ import java.io.PrintWriter
import java.util.concurrent.Executor
import java.util.concurrent.atomic.AtomicInteger

private const val MSG_REGISTER_RECEIVER = 0
private const val MSG_UNREGISTER_RECEIVER = 1
private const val TAG = "UserBroadcastDispatcher"
private const val DEBUG = false

@@ -50,7 +48,8 @@ open class UserBroadcastDispatcher(
    private val userId: Int,
    private val bgLooper: Looper,
    private val bgExecutor: Executor,
    private val logger: BroadcastDispatcherLogger
    private val logger: BroadcastDispatcherLogger,
    private val removalPendingStore: PendingRemovalStore
) : Dumpable {

    companion object {
@@ -60,16 +59,6 @@ open class UserBroadcastDispatcher(
        val index = AtomicInteger(0)
    }

    private val bgHandler = object : Handler(bgLooper) {
        override fun handleMessage(msg: Message) {
            when (msg.what) {
                MSG_REGISTER_RECEIVER -> handleRegisterReceiver(msg.obj as ReceiverData, msg.arg1)
                MSG_UNREGISTER_RECEIVER -> handleUnregisterReceiver(msg.obj as BroadcastReceiver)
                else -> Unit
            }
        }
    }

    // Used for key in actionsToActionsReceivers
    internal data class ReceiverProperties(
        val action: String,
@@ -77,6 +66,8 @@ open class UserBroadcastDispatcher(
        val permission: String?
    )

    private val bgHandler = Handler(bgLooper)

    // Only modify in BG thread
    @VisibleForTesting
    internal val actionsToActionsReceivers = ArrayMap<ReceiverProperties, ActionReceiver>()
@@ -92,19 +83,21 @@ open class UserBroadcastDispatcher(
    /**
     * Register a [ReceiverData] for this user.
     */
    @WorkerThread
    fun registerReceiver(receiverData: ReceiverData, flags: Int) {
        bgHandler.obtainMessage(MSG_REGISTER_RECEIVER, flags, 0, receiverData).sendToTarget()
        handleRegisterReceiver(receiverData, flags)
    }

    /**
     * Unregister a given [BroadcastReceiver] for this user.
     */
    @WorkerThread
    fun unregisterReceiver(receiver: BroadcastReceiver) {
        bgHandler.obtainMessage(MSG_UNREGISTER_RECEIVER, receiver).sendToTarget()
        handleUnregisterReceiver(receiver)
    }

    private fun handleRegisterReceiver(receiverData: ReceiverData, flags: Int) {
        Preconditions.checkState(bgHandler.looper.isCurrentThread,
        Preconditions.checkState(bgLooper.isCurrentThread,
                "This method should only be called from BG thread")
        if (DEBUG) Log.w(TAG, "Register receiver: ${receiverData.receiver}")
        receiverToActions
@@ -151,12 +144,13 @@ open class UserBroadcastDispatcher(
                    }
                },
                bgExecutor,
                logger
                logger,
                removalPendingStore::isPendingRemoval
        )
    }

    private fun handleUnregisterReceiver(receiver: BroadcastReceiver) {
        Preconditions.checkState(bgHandler.looper.isCurrentThread,
        Preconditions.checkState(bgLooper.isCurrentThread,
                "This method should only be called from BG thread")
        if (DEBUG) Log.w(TAG, "Unregister receiver: $receiver")
        receiverToActions.getOrDefault(receiver, mutableSetOf()).forEach {
+20 −0
Original line number Diff line number Diff line
@@ -87,6 +87,26 @@ class BroadcastDispatcherLogger @Inject constructor(
        })
    }

    fun logTagForRemoval(user: Int, receiver: BroadcastReceiver) {
        val receiverString = receiver.toString()
        log(DEBUG, {
            int1 = user
            str1 = receiverString
        }, {
            "Receiver $str1 tagged for removal from user $int1"
        })
    }

    fun logClearedAfterRemoval(user: Int, receiver: BroadcastReceiver) {
        val receiverString = receiver.toString()
        log(DEBUG, {
            int1 = user
            str1 = receiverString
        }, {
            "Receiver $str1 has been completely removed for user $int1"
        })
    }

    fun logReceiverUnregistered(user: Int, receiver: BroadcastReceiver) {
        val receiverString = receiver.toString()
        log(INFO, {
Loading