1 /* 2 * Copyright (C) 2020 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.util.ArraySet 24 import com.android.systemui.Dumpable 25 import com.android.systemui.broadcast.logging.BroadcastDispatcherLogger 26 import com.android.systemui.util.indentIfPossible 27 import java.io.FileDescriptor 28 import java.io.PrintWriter 29 import java.util.concurrent.Executor 30 import java.util.concurrent.atomic.AtomicInteger 31 32 /** 33 * Receiver for a given action-userId pair to be used by [UserBroadcastDispatcher]. 34 * 35 * Each object of this class will take care of a single Action. It will register if it has at least 36 * one [BroadcastReceiver] added to it, and unregister when none are left. 37 * 38 * It will also re-register if filters with new categories are added. But this should not happen 39 * often. 40 * 41 * This class has no sync controls, so make sure to only make modifications from the background 42 * thread. 43 */ 44 class ActionReceiver( 45 private val action: String, 46 private val userId: Int, 47 private val registerAction: BroadcastReceiver.(IntentFilter) -> Unit, 48 private val unregisterAction: BroadcastReceiver.() -> Unit, 49 private val bgExecutor: Executor, 50 private val logger: BroadcastDispatcherLogger 51 ) : BroadcastReceiver(), Dumpable { 52 53 companion object { 54 val index = AtomicInteger(0) 55 } 56 57 var registered = false 58 private set 59 private val receiverDatas = ArraySet<ReceiverData>() 60 private val activeCategories = ArraySet<String>() 61 62 @Throws(IllegalArgumentException::class) addReceiverDatanull63 fun addReceiverData(receiverData: ReceiverData) { 64 if (!receiverData.filter.hasAction(action)) { 65 throw(IllegalArgumentException("Trying to attach to $action without correct action," + 66 "receiver: ${receiverData.receiver}")) 67 } 68 val addedCategories = activeCategories 69 .addAll(receiverData.filter.categoriesIterator()?.asSequence() ?: emptySequence()) 70 71 if (receiverDatas.add(receiverData) && receiverDatas.size == 1) { 72 registerAction(createFilter()) 73 registered = true 74 } else if (addedCategories) { 75 unregisterAction() 76 registerAction(createFilter()) 77 } 78 } 79 hasReceivernull80 fun hasReceiver(receiver: BroadcastReceiver): Boolean { 81 return receiverDatas.any { it.receiver == receiver } 82 } 83 createFilternull84 private fun createFilter(): IntentFilter { 85 val filter = IntentFilter(action) 86 activeCategories.forEach(filter::addCategory) 87 return filter 88 } 89 removeReceivernull90 fun removeReceiver(receiver: BroadcastReceiver) { 91 if (receiverDatas.removeAll { it.receiver == receiver } && 92 receiverDatas.isEmpty() && registered) { 93 unregisterAction() 94 registered = false 95 activeCategories.clear() 96 } 97 } 98 99 @Throws(IllegalStateException::class) onReceivenull100 override fun onReceive(context: Context, intent: Intent) { 101 if (intent.action != action) { 102 throw(IllegalStateException("Received intent for ${intent.action} " + 103 "in receiver for $action}")) 104 } 105 val id = index.getAndIncrement() 106 logger.logBroadcastReceived(id, userId, intent) 107 // Immediately return control to ActivityManager 108 bgExecutor.execute { 109 receiverDatas.forEach { 110 if (it.filter.matchCategories(intent.categories) == null) { 111 it.executor.execute { 112 it.receiver.pendingResult = pendingResult 113 it.receiver.onReceive(context, intent) 114 logger.logBroadcastDispatched(id, action, it.receiver) 115 } 116 } 117 } 118 } 119 } 120 dumpnull121 override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) { 122 pw.indentIfPossible { 123 println("Registered: $registered") 124 println("Receivers:") 125 pw.indentIfPossible { 126 receiverDatas.forEach { 127 println(it.receiver) 128 } 129 } 130 println("Categories: ${activeCategories.joinToString(", ")}") 131 } 132 } 133 }