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