• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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