1 /* 2 * 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.dump.DumpManager 35 import com.android.systemui.settings.UserTracker 36 import java.io.FileDescriptor 37 import java.io.PrintWriter 38 import java.util.concurrent.Executor 39 40 data class ReceiverData( 41 val receiver: BroadcastReceiver, 42 val filter: IntentFilter, 43 val executor: Executor, 44 val user: UserHandle 45 ) 46 47 private const val MSG_ADD_RECEIVER = 0 48 private const val MSG_REMOVE_RECEIVER = 1 49 private const val MSG_REMOVE_RECEIVER_FOR_USER = 2 50 private const val TAG = "BroadcastDispatcher" 51 private const val DEBUG = true 52 53 /** 54 * SystemUI master Broadcast Dispatcher. 55 * 56 * This class allows [BroadcastReceiver] to register and centralizes registrations to [Context] 57 * from SystemUI. That way the number of calls to [BroadcastReceiver.onReceive] can be reduced for 58 * a given broadcast. 59 * 60 * Use only for IntentFilters with actions and optionally categories. It does not support, 61 * permissions, schemes, data types, data authorities or priority different than 0. 62 * Cannot be used for getting sticky broadcasts (either as return of registering or as re-delivery). 63 */ 64 open class BroadcastDispatcher constructor ( 65 private val context: Context, 66 private val bgLooper: Looper, 67 private val bgExecutor: Executor, 68 private val dumpManager: DumpManager, 69 private val logger: BroadcastDispatcherLogger, 70 private val userTracker: UserTracker 71 ) : Dumpable { 72 73 // Only modify in BG thread 74 private val receiversByUser = SparseArray<UserBroadcastDispatcher>(20) 75 76 fun initialize() { 77 dumpManager.registerDumpable(javaClass.name, this) 78 } 79 80 /** 81 * Register a receiver for broadcast with the dispatcher 82 * 83 * @param receiver A receiver to dispatch the [Intent] 84 * @param filter A filter to determine what broadcasts should be dispatched to this receiver. 85 * It will only take into account actions and categories for filtering. It must 86 * have at least one action. 87 * @param handler A handler to dispatch [BroadcastReceiver.onReceive]. 88 * @param user A user handle to determine which broadcast should be dispatched to this receiver. 89 * By default, it is the user of the context (system user in SystemUI). 90 * @throws IllegalArgumentException if the filter has other constraints that are not actions or 91 * categories or the filter has no actions. 92 */ 93 @Deprecated(message = "Replacing Handler for Executor in SystemUI", 94 replaceWith = ReplaceWith("registerReceiver(receiver, filter, executor, user)")) 95 @JvmOverloads 96 open fun registerReceiverWithHandler( 97 receiver: BroadcastReceiver, 98 filter: IntentFilter, 99 handler: Handler, 100 user: UserHandle = context.user 101 ) { 102 registerReceiver(receiver, filter, HandlerExecutor(handler), user) 103 } 104 105 /** 106 * Register a receiver for broadcast with the dispatcher 107 * 108 * @param receiver A receiver to dispatch the [Intent] 109 * @param filter A filter to determine what broadcasts should be dispatched to this receiver. 110 * It will only take into account actions and categories for filtering. It must 111 * have at least one action. 112 * @param executor An executor to dispatch [BroadcastReceiver.onReceive]. Pass null to use an 113 * executor in the main thread (default). 114 * @param user A user handle to determine which broadcast should be dispatched to this receiver. 115 * Pass `null` to use the user of the context (system user in SystemUI). 116 * @throws IllegalArgumentException if the filter has other constraints that are not actions or 117 * categories or the filter has no actions. 118 */ 119 @JvmOverloads 120 open fun registerReceiver( 121 receiver: BroadcastReceiver, 122 filter: IntentFilter, 123 executor: Executor? = null, 124 user: UserHandle? = null 125 ) { 126 checkFilter(filter) 127 this.handler 128 .obtainMessage(MSG_ADD_RECEIVER, ReceiverData( 129 receiver, 130 filter, 131 executor ?: context.mainExecutor, 132 user ?: context.user 133 )) 134 .sendToTarget() 135 } 136 137 private fun checkFilter(filter: IntentFilter) { 138 val sb = StringBuilder() 139 if (filter.countActions() == 0) sb.append("Filter must contain at least one action. ") 140 if (filter.countDataAuthorities() != 0) sb.append("Filter cannot contain DataAuthorities. ") 141 if (filter.countDataPaths() != 0) sb.append("Filter cannot contain DataPaths. ") 142 if (filter.countDataSchemes() != 0) sb.append("Filter cannot contain DataSchemes. ") 143 if (filter.countDataTypes() != 0) sb.append("Filter cannot contain DataTypes. ") 144 if (filter.priority != 0) sb.append("Filter cannot modify priority. ") 145 if (!TextUtils.isEmpty(sb)) throw IllegalArgumentException(sb.toString()) 146 } 147 148 /** 149 * Unregister receiver for all users. 150 * <br> 151 * This will remove every registration of [receiver], not those done just with [UserHandle.ALL]. 152 * 153 * @param receiver The receiver to unregister. It will be unregistered for all users. 154 */ 155 open fun unregisterReceiver(receiver: BroadcastReceiver) { 156 handler.obtainMessage(MSG_REMOVE_RECEIVER, receiver).sendToTarget() 157 } 158 159 /** 160 * Unregister receiver for a particular user. 161 * 162 * @param receiver The receiver to unregister. 163 * @param user The user associated to the registered [receiver]. It can be [UserHandle.ALL]. 164 */ 165 open fun unregisterReceiverForUser(receiver: BroadcastReceiver, user: UserHandle) { 166 handler.obtainMessage(MSG_REMOVE_RECEIVER_FOR_USER, user.identifier, 0, receiver) 167 .sendToTarget() 168 } 169 170 @VisibleForTesting 171 protected open fun createUBRForUser(userId: Int) = 172 UserBroadcastDispatcher(context, userId, bgLooper, bgExecutor, logger) 173 174 override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) { 175 pw.println("Broadcast dispatcher:") 176 val ipw = IndentingPrintWriter(pw, " ") 177 ipw.increaseIndent() 178 for (index in 0 until receiversByUser.size()) { 179 ipw.println("User ${receiversByUser.keyAt(index)}") 180 receiversByUser.valueAt(index).dump(fd, ipw, args) 181 } 182 ipw.decreaseIndent() 183 } 184 185 private val handler = object : Handler(bgLooper) { 186 187 override fun handleMessage(msg: Message) { 188 when (msg.what) { 189 MSG_ADD_RECEIVER -> { 190 val data = msg.obj as ReceiverData 191 // If the receiver asked to be registered under the current user, we register 192 // under the actual current user. 193 val userId = if (data.user.identifier == UserHandle.USER_CURRENT) { 194 userTracker.userId 195 } else { 196 data.user.identifier 197 } 198 if (userId < UserHandle.USER_ALL) { 199 throw IllegalStateException( 200 "Attempting to register receiver for invalid user {$userId}") 201 } 202 val uBR = receiversByUser.get(userId, createUBRForUser(userId)) 203 receiversByUser.put(userId, uBR) 204 uBR.registerReceiver(data) 205 } 206 207 MSG_REMOVE_RECEIVER -> { 208 for (it in 0 until receiversByUser.size()) { 209 receiversByUser.valueAt(it).unregisterReceiver(msg.obj as BroadcastReceiver) 210 } 211 } 212 213 MSG_REMOVE_RECEIVER_FOR_USER -> { 214 receiversByUser.get(msg.arg1)?.unregisterReceiver(msg.obj as BroadcastReceiver) 215 } 216 else -> super.handleMessage(msg) 217 } 218 } 219 } 220 } 221