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

Commit 58a08bbd authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Automerger Merge Worker
Browse files

Merge "Make unregister receiver "sync"." into tm-dev am: 8af79601

parents 455c2816 8af79601
Loading
Loading
Loading
Loading
+11 −2
Original line number Original line 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
 * This class has no sync controls, so make sure to only make modifications from the background
 * thread.
 * 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(
class ActionReceiver(
    private val action: String,
    private val action: String,
@@ -46,7 +53,8 @@ class ActionReceiver(
    private val registerAction: BroadcastReceiver.(IntentFilter) -> Unit,
    private val registerAction: BroadcastReceiver.(IntentFilter) -> Unit,
    private val unregisterAction: BroadcastReceiver.() -> Unit,
    private val unregisterAction: BroadcastReceiver.() -> Unit,
    private val bgExecutor: Executor,
    private val bgExecutor: Executor,
    private val logger: BroadcastDispatcherLogger
    private val logger: BroadcastDispatcherLogger,
    private val testPendingRemovalAction: (BroadcastReceiver, Int) -> Boolean
) : BroadcastReceiver(), Dumpable {
) : BroadcastReceiver(), Dumpable {


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


    // Only modify in BG thread
    // 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.
     * @param receiver The receiver to unregister. It will be unregistered for all users.
     */
     */
    open fun unregisterReceiver(receiver: BroadcastReceiver) {
    open fun unregisterReceiver(receiver: BroadcastReceiver) {
        removalPendingStore.tagForRemoval(receiver, UserHandle.USER_ALL)
        handler.obtainMessage(MSG_REMOVE_RECEIVER, receiver).sendToTarget()
        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].
     * @param user The user associated to the registered [receiver]. It can be [UserHandle.ALL].
     */
     */
    open fun unregisterReceiverForUser(receiver: BroadcastReceiver, user: UserHandle) {
    open fun unregisterReceiverForUser(receiver: BroadcastReceiver, user: UserHandle) {
        removalPendingStore.tagForRemoval(receiver, user.identifier)
        handler.obtainMessage(MSG_REMOVE_RECEIVER_FOR_USER, user.identifier, 0, receiver)
        handler.obtainMessage(MSG_REMOVE_RECEIVER_FOR_USER, user.identifier, 0, receiver)
                .sendToTarget()
                .sendToTarget()
    }
    }


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


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


                MSG_REMOVE_RECEIVER_FOR_USER -> {
                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)
                else -> super.handleMessage(msg)
            }
            }
+58 −0
Original line number Original line 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 Original line Diff line number Diff line
@@ -20,12 +20,12 @@ import android.content.BroadcastReceiver
import android.content.Context
import android.content.Context
import android.os.Handler
import android.os.Handler
import android.os.Looper
import android.os.Looper
import android.os.Message
import android.os.UserHandle
import android.os.UserHandle
import android.util.ArrayMap
import android.util.ArrayMap
import android.util.ArraySet
import android.util.ArraySet
import android.util.Log
import android.util.Log
import androidx.annotation.VisibleForTesting
import androidx.annotation.VisibleForTesting
import androidx.annotation.WorkerThread
import com.android.internal.util.Preconditions
import com.android.internal.util.Preconditions
import com.android.systemui.Dumpable
import com.android.systemui.Dumpable
import com.android.systemui.broadcast.logging.BroadcastDispatcherLogger
import com.android.systemui.broadcast.logging.BroadcastDispatcherLogger
@@ -34,8 +34,6 @@ import java.io.PrintWriter
import java.util.concurrent.Executor
import java.util.concurrent.Executor
import java.util.concurrent.atomic.AtomicInteger
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 TAG = "UserBroadcastDispatcher"
private const val DEBUG = false
private const val DEBUG = false


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


    companion object {
    companion object {
@@ -60,16 +59,6 @@ open class UserBroadcastDispatcher(
        val index = AtomicInteger(0)
        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
    // Used for key in actionsToActionsReceivers
    internal data class ReceiverProperties(
    internal data class ReceiverProperties(
        val action: String,
        val action: String,
@@ -77,6 +66,8 @@ open class UserBroadcastDispatcher(
        val permission: String?
        val permission: String?
    )
    )


    private val bgHandler = Handler(bgLooper)

    // Only modify in BG thread
    // Only modify in BG thread
    @VisibleForTesting
    @VisibleForTesting
    internal val actionsToActionsReceivers = ArrayMap<ReceiverProperties, ActionReceiver>()
    internal val actionsToActionsReceivers = ArrayMap<ReceiverProperties, ActionReceiver>()
@@ -92,19 +83,21 @@ open class UserBroadcastDispatcher(
    /**
    /**
     * Register a [ReceiverData] for this user.
     * Register a [ReceiverData] for this user.
     */
     */
    @WorkerThread
    fun registerReceiver(receiverData: ReceiverData, flags: Int) {
    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.
     * Unregister a given [BroadcastReceiver] for this user.
     */
     */
    @WorkerThread
    fun unregisterReceiver(receiver: BroadcastReceiver) {
    fun unregisterReceiver(receiver: BroadcastReceiver) {
        bgHandler.obtainMessage(MSG_UNREGISTER_RECEIVER, receiver).sendToTarget()
        handleUnregisterReceiver(receiver)
    }
    }


    private fun handleRegisterReceiver(receiverData: ReceiverData, flags: Int) {
    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")
                "This method should only be called from BG thread")
        if (DEBUG) Log.w(TAG, "Register receiver: ${receiverData.receiver}")
        if (DEBUG) Log.w(TAG, "Register receiver: ${receiverData.receiver}")
        receiverToActions
        receiverToActions
@@ -151,12 +144,13 @@ open class UserBroadcastDispatcher(
                    }
                    }
                },
                },
                bgExecutor,
                bgExecutor,
                logger
                logger,
                removalPendingStore::isPendingRemoval
        )
        )
    }
    }


    private fun handleUnregisterReceiver(receiver: BroadcastReceiver) {
    private fun handleUnregisterReceiver(receiver: BroadcastReceiver) {
        Preconditions.checkState(bgHandler.looper.isCurrentThread,
        Preconditions.checkState(bgLooper.isCurrentThread,
                "This method should only be called from BG thread")
                "This method should only be called from BG thread")
        if (DEBUG) Log.w(TAG, "Unregister receiver: $receiver")
        if (DEBUG) Log.w(TAG, "Unregister receiver: $receiver")
        receiverToActions.getOrDefault(receiver, mutableSetOf()).forEach {
        receiverToActions.getOrDefault(receiver, mutableSetOf()).forEach {
+20 −0
Original line number Original line 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) {
    fun logReceiverUnregistered(user: Int, receiver: BroadcastReceiver) {
        val receiverString = receiver.toString()
        val receiverString = receiver.toString()
        log(INFO, {
        log(INFO, {
Loading