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