1 /* <lambda>null2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 17 package com.android.systemui.broadcast 18 19 import android.content.BroadcastReceiver 20 import android.content.Context 21 import android.content.Intent 22 import android.content.IntentFilter 23 import android.os.Handler 24 import android.os.HandlerExecutor 25 import android.os.Looper 26 import android.os.Message 27 import android.os.UserHandle 28 import android.text.TextUtils 29 import android.util.IndentingPrintWriter 30 import android.util.SparseArray 31 import com.android.internal.annotations.VisibleForTesting 32 import com.android.systemui.Dumpable 33 import com.android.systemui.broadcast.logging.BroadcastDispatcherLogger 34 import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging 35 import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow 36 import com.android.systemui.dagger.SysUISingleton 37 import com.android.systemui.dagger.qualifiers.BroadcastRunning 38 import com.android.systemui.dagger.qualifiers.Main 39 import com.android.systemui.dump.DumpManager 40 import com.android.systemui.settings.UserTracker 41 import java.io.PrintWriter 42 import java.util.concurrent.Executor 43 import javax.inject.Inject 44 import kotlinx.coroutines.channels.awaitClose 45 import kotlinx.coroutines.flow.Flow 46 47 data class ReceiverData( 48 val receiver: BroadcastReceiver, 49 val filter: IntentFilter, 50 val executor: Executor, 51 val user: UserHandle, 52 val permission: String? = null 53 ) 54 55 private const val MSG_ADD_RECEIVER = 0 56 private const val MSG_REMOVE_RECEIVER = 1 57 private const val MSG_REMOVE_RECEIVER_FOR_USER = 2 58 private const val TAG = "BroadcastDispatcher" 59 60 /** 61 * SystemUI master Broadcast Dispatcher. 62 * 63 * This class allows [BroadcastReceiver] to register and centralizes registrations to [Context] 64 * from SystemUI. That way the number of calls to [BroadcastReceiver.onReceive] can be reduced for 65 * a given broadcast. 66 * 67 * Use only for IntentFilters with actions and optionally categories. It does not support schemes, 68 * data types, data authorities or priority different than 0. 69 * 70 * Cannot be used for getting sticky broadcasts (either as return of registering or as re-delivery). 71 * Broadcast handling may be asynchronous *without* calling goAsync(), as it's running within sysui 72 * and doesn't need to worry about being killed. 73 */ 74 @SysUISingleton 75 open class BroadcastDispatcher @Inject constructor( 76 private val context: Context, 77 @Main private val mainExecutor: Executor, 78 @BroadcastRunning private val broadcastLooper: Looper, 79 @BroadcastRunning private val broadcastExecutor: Executor, 80 private val dumpManager: DumpManager, 81 private val logger: BroadcastDispatcherLogger, 82 private val userTracker: UserTracker, 83 private val removalPendingStore: PendingRemovalStore 84 ) : Dumpable { 85 86 // Only modify in BroadcastRunning thread 87 private val receiversByUser = SparseArray<UserBroadcastDispatcher>(20) 88 89 fun initialize() { 90 dumpManager.registerDumpable(this) 91 } 92 93 /** 94 * Register a receiver for broadcast with the dispatcher 95 * 96 * @param receiver A receiver to dispatch the [Intent] 97 * @param filter A filter to determine what broadcasts should be dispatched to this receiver. 98 * It will only take into account actions and categories for filtering. It must 99 * have at least one action. 100 * @param handler A handler to dispatch [BroadcastReceiver.onReceive]. 101 * @param user A user handle to determine which broadcast should be dispatched to this receiver. 102 * By default, it is the user of the context (system user in SystemUI). 103 * @param flags Flags to use when registering the receiver. [Context.RECEIVER_EXPORTED] by 104 * default. 105 * @throws IllegalArgumentException if the filter has other constraints that are not actions or 106 * categories or the filter has no actions. 107 * 108 */ 109 @Deprecated(message = "Replacing Handler for Executor in SystemUI", 110 replaceWith = ReplaceWith("registerReceiver(receiver, filter, executor, user, permission)") 111 ) 112 @JvmOverloads 113 open fun registerReceiverWithHandler( 114 receiver: BroadcastReceiver, 115 filter: IntentFilter, 116 handler: Handler, 117 user: UserHandle = context.user, 118 @Context.RegisterReceiverFlags flags: Int = Context.RECEIVER_EXPORTED, 119 permission: String? = null 120 ) { 121 registerReceiver(receiver, filter, HandlerExecutor(handler), user, flags, permission) 122 } 123 124 /** 125 * Register a receiver for broadcast with the dispatcher 126 * 127 * @param receiver A receiver to dispatch the [Intent] 128 * @param filter A filter to determine what broadcasts should be dispatched to this receiver. 129 * It will only take into account actions and categories for filtering. It must 130 * have at least one action. 131 * @param executor An executor to dispatch [BroadcastReceiver.onReceive]. Pass null to use an 132 * executor in the main thread (default). 133 * @param user A user handle to determine which broadcast should be dispatched to this receiver. 134 * Pass `null` to use the user of the context (system user in SystemUI). 135 * @param flags Flags to use when registering the receiver. [Context.RECEIVER_EXPORTED] by 136 * default. 137 * @throws IllegalArgumentException if the filter has other constraints that are not actions or 138 * categories or the filter has no actions. 139 */ 140 @JvmOverloads 141 open fun registerReceiver( 142 receiver: BroadcastReceiver, 143 filter: IntentFilter, 144 executor: Executor? = null, 145 user: UserHandle? = null, 146 @Context.RegisterReceiverFlags flags: Int = Context.RECEIVER_EXPORTED, 147 permission: String? = null 148 ) { 149 checkFilter(filter) 150 val data = ReceiverData( 151 receiver, 152 filter, 153 executor ?: mainExecutor, 154 user ?: context.user, 155 permission 156 ) 157 this.handler 158 .obtainMessage(MSG_ADD_RECEIVER, flags, 0, data) 159 .sendToTarget() 160 } 161 162 /** 163 * Returns a [Flow] that, when collected, emits a new value whenever a broadcast matching 164 * [filter] is received. The value will be computed from the intent and the registered receiver 165 * using [map]. 166 * 167 * @see registerReceiver 168 */ 169 @JvmOverloads 170 fun <T> broadcastFlow( 171 filter: IntentFilter, 172 user: UserHandle? = null, 173 @Context.RegisterReceiverFlags flags: Int = Context.RECEIVER_EXPORTED, 174 permission: String? = null, 175 map: (Intent, BroadcastReceiver) -> T, 176 ): Flow<T> = conflatedCallbackFlow { 177 val receiver = object : BroadcastReceiver() { 178 override fun onReceive(context: Context, intent: Intent) { 179 trySendWithFailureLogging(map(intent, this), TAG) 180 } 181 } 182 183 registerReceiver( 184 receiver, 185 filter, 186 broadcastExecutor, 187 user, 188 flags, 189 permission, 190 ) 191 192 awaitClose { 193 unregisterReceiver(receiver) 194 } 195 } 196 197 /** 198 * Returns a [Flow] that, when collected, emits `Unit` whenever a broadcast matching [filter] is 199 * received. 200 * 201 * @see registerReceiver 202 */ 203 @JvmOverloads 204 fun broadcastFlow( 205 filter: IntentFilter, 206 user: UserHandle? = null, 207 @Context.RegisterReceiverFlags flags: Int = Context.RECEIVER_EXPORTED, 208 permission: String? = null, 209 ): Flow<Unit> = broadcastFlow(filter, user, flags, permission) { _, _ -> Unit } 210 211 private fun checkFilter(filter: IntentFilter) { 212 val sb = StringBuilder() 213 if (filter.countActions() == 0) sb.append("Filter must contain at least one action. ") 214 if (filter.countDataAuthorities() != 0) sb.append("Filter cannot contain DataAuthorities. ") 215 if (filter.countDataPaths() != 0) sb.append("Filter cannot contain DataPaths. ") 216 if (filter.countDataSchemes() != 0) sb.append("Filter cannot contain DataSchemes. ") 217 if (filter.countDataTypes() != 0) sb.append("Filter cannot contain DataTypes. ") 218 if (filter.priority != 0) sb.append("Filter cannot modify priority. ") 219 if (!TextUtils.isEmpty(sb)) throw IllegalArgumentException(sb.toString()) 220 } 221 222 /** 223 * Unregister receiver for all users. 224 * <br> 225 * This will remove every registration of [receiver], not those done just with [UserHandle.ALL]. 226 * 227 * @param receiver The receiver to unregister. It will be unregistered for all users. 228 */ 229 open fun unregisterReceiver(receiver: BroadcastReceiver) { 230 removalPendingStore.tagForRemoval(receiver, UserHandle.USER_ALL) 231 handler.obtainMessage(MSG_REMOVE_RECEIVER, receiver).sendToTarget() 232 } 233 234 /** 235 * Unregister receiver for a particular user. 236 * 237 * @param receiver The receiver to unregister. 238 * @param user The user associated to the registered [receiver]. It can be [UserHandle.ALL]. 239 */ 240 open fun unregisterReceiverForUser(receiver: BroadcastReceiver, user: UserHandle) { 241 removalPendingStore.tagForRemoval(receiver, user.identifier) 242 handler.obtainMessage(MSG_REMOVE_RECEIVER_FOR_USER, user.identifier, 0, receiver) 243 .sendToTarget() 244 } 245 246 @VisibleForTesting 247 protected open fun createUBRForUser(userId: Int) = 248 UserBroadcastDispatcher( 249 context, 250 userId, 251 broadcastLooper, 252 broadcastExecutor, 253 logger, 254 removalPendingStore 255 ) 256 257 override fun dump(pw: PrintWriter, args: Array<out String>) { 258 pw.println("Broadcast dispatcher:") 259 val ipw = IndentingPrintWriter(pw, " ") 260 ipw.increaseIndent() 261 for (index in 0 until receiversByUser.size()) { 262 ipw.println("User ${receiversByUser.keyAt(index)}") 263 receiversByUser.valueAt(index).dump(ipw, args) 264 } 265 ipw.println("Pending removal:") 266 removalPendingStore.dump(ipw, args) 267 ipw.decreaseIndent() 268 } 269 270 private val handler = object : Handler(broadcastLooper) { 271 272 override fun handleMessage(msg: Message) { 273 when (msg.what) { 274 MSG_ADD_RECEIVER -> { 275 val data = msg.obj as ReceiverData 276 val flags = msg.arg1 277 // If the receiver asked to be registered under the current user, we register 278 // under the actual current user. 279 val userId = if (data.user.identifier == UserHandle.USER_CURRENT) { 280 userTracker.userId 281 } else { 282 data.user.identifier 283 } 284 if (userId < UserHandle.USER_ALL) { 285 throw IllegalStateException( 286 "Attempting to register receiver for invalid user {$userId}") 287 } 288 val uBR = receiversByUser.get(userId, createUBRForUser(userId)) 289 receiversByUser.put(userId, uBR) 290 uBR.registerReceiver(data, flags) 291 } 292 293 MSG_REMOVE_RECEIVER -> { 294 for (it in 0 until receiversByUser.size()) { 295 receiversByUser.valueAt(it).unregisterReceiver(msg.obj as BroadcastReceiver) 296 } 297 removalPendingStore.clearPendingRemoval( 298 msg.obj as BroadcastReceiver, 299 UserHandle.USER_ALL 300 ) 301 } 302 303 MSG_REMOVE_RECEIVER_FOR_USER -> { 304 val userId = if (msg.arg1 == UserHandle.USER_CURRENT) { 305 userTracker.userId 306 } else { 307 msg.arg1 308 } 309 receiversByUser.get(userId)?.unregisterReceiver(msg.obj as BroadcastReceiver) 310 removalPendingStore.clearPendingRemoval(msg.obj as BroadcastReceiver, userId) 311 } 312 else -> super.handleMessage(msg) 313 } 314 } 315 } 316 } 317