Loading packages/SystemUI/src/com/android/systemui/broadcast/ActionReceiver.kt +11 −2 Original line number Diff line number Diff line Loading @@ -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, Loading @@ -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 { Loading Loading @@ -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) Loading packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt +26 −4 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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() } Loading @@ -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:") Loading @@ -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() } Loading Loading @@ -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) } Loading packages/SystemUI/src/com/android/systemui/broadcast/PendingRemovalStore.kt 0 → 100644 +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 packages/SystemUI/src/com/android/systemui/broadcast/UserBroadcastDispatcher.kt +13 −19 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading @@ -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 { Loading @@ -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, Loading @@ -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>() Loading @@ -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 Loading Loading @@ -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 { Loading packages/SystemUI/src/com/android/systemui/broadcast/logging/BroadcastDispatcherLogger.kt +20 −0 Original line number Diff line number Diff line Loading @@ -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 Loading
packages/SystemUI/src/com/android/systemui/broadcast/ActionReceiver.kt +11 −2 Original line number Diff line number Diff line Loading @@ -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, Loading @@ -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 { Loading Loading @@ -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) Loading
packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt +26 −4 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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() } Loading @@ -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:") Loading @@ -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() } Loading Loading @@ -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) } Loading
packages/SystemUI/src/com/android/systemui/broadcast/PendingRemovalStore.kt 0 → 100644 +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
packages/SystemUI/src/com/android/systemui/broadcast/UserBroadcastDispatcher.kt +13 −19 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading @@ -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 { Loading @@ -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, Loading @@ -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>() Loading @@ -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 Loading Loading @@ -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 { Loading
packages/SystemUI/src/com/android/systemui/broadcast/logging/BroadcastDispatcherLogger.kt +20 −0 Original line number Diff line number Diff line Loading @@ -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