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.os.Handler 22 import android.os.Looper 23 import android.os.Message 24 import android.os.UserHandle 25 import android.util.ArrayMap 26 import android.util.ArraySet 27 import android.util.Log 28 import androidx.annotation.VisibleForTesting 29 import com.android.internal.util.Preconditions 30 import com.android.systemui.Dumpable 31 import com.android.systemui.broadcast.logging.BroadcastDispatcherLogger 32 import com.android.systemui.util.indentIfPossible 33 import java.io.FileDescriptor 34 import java.io.PrintWriter 35 import java.util.concurrent.Executor 36 import java.util.concurrent.atomic.AtomicInteger 37 38 private const val MSG_REGISTER_RECEIVER = 0 39 private const val MSG_UNREGISTER_RECEIVER = 1 40 private const val TAG = "UserBroadcastDispatcher" 41 private const val DEBUG = false 42 43 /** 44 * Broadcast dispatcher for a given user registration [userId]. 45 * 46 * Created by [BroadcastDispatcher] as needed by users. The value of [userId] can be 47 * [UserHandle.USER_ALL]. 48 */ 49 open class UserBroadcastDispatcher( 50 private val context: Context, 51 private val userId: Int, 52 private val bgLooper: Looper, 53 private val bgExecutor: Executor, 54 private val logger: BroadcastDispatcherLogger 55 ) : Dumpable { 56 57 companion object { 58 // Used only for debugging. If not debugging, this variable will not be accessed and all 59 // received broadcasts will be tagged with 0. However, as DEBUG is false, nothing will be 60 // logged 61 val index = AtomicInteger(0) 62 } 63 64 private val bgHandler = object : Handler(bgLooper) { 65 override fun handleMessage(msg: Message) { 66 when (msg.what) { 67 MSG_REGISTER_RECEIVER -> handleRegisterReceiver(msg.obj as ReceiverData) 68 MSG_UNREGISTER_RECEIVER -> handleUnregisterReceiver(msg.obj as BroadcastReceiver) 69 else -> Unit 70 } 71 } 72 } 73 74 // Only modify in BG thread 75 @VisibleForTesting 76 internal val actionsToActionsReceivers = ArrayMap<String, ActionReceiver>() 77 private val receiverToActions = ArrayMap<BroadcastReceiver, MutableSet<String>>() 78 79 @VisibleForTesting 80 internal fun isReceiverReferenceHeld(receiver: BroadcastReceiver): Boolean { 81 return actionsToActionsReceivers.values.any { 82 it.hasReceiver(receiver) 83 } || (receiver in receiverToActions) 84 } 85 86 /** 87 * Register a [ReceiverData] for this user. 88 */ 89 fun registerReceiver(receiverData: ReceiverData) { 90 bgHandler.obtainMessage(MSG_REGISTER_RECEIVER, receiverData).sendToTarget() 91 } 92 93 /** 94 * Unregister a given [BroadcastReceiver] for this user. 95 */ 96 fun unregisterReceiver(receiver: BroadcastReceiver) { 97 bgHandler.obtainMessage(MSG_UNREGISTER_RECEIVER, receiver).sendToTarget() 98 } 99 100 private fun handleRegisterReceiver(receiverData: ReceiverData) { 101 Preconditions.checkState(bgHandler.looper.isCurrentThread, 102 "This method should only be called from BG thread") 103 if (DEBUG) Log.w(TAG, "Register receiver: ${receiverData.receiver}") 104 receiverToActions 105 .getOrPut(receiverData.receiver, { ArraySet() }) 106 .addAll(receiverData.filter.actionsIterator()?.asSequence() ?: emptySequence()) 107 receiverData.filter.actionsIterator().forEach { 108 actionsToActionsReceivers 109 .getOrPut(it, { createActionReceiver(it) }) 110 .addReceiverData(receiverData) 111 } 112 logger.logReceiverRegistered(userId, receiverData.receiver) 113 } 114 115 @VisibleForTesting 116 internal open fun createActionReceiver(action: String): ActionReceiver { 117 return ActionReceiver( 118 action, 119 userId, 120 { 121 context.registerReceiverAsUser(this, UserHandle.of(userId), it, null, bgHandler) 122 logger.logContextReceiverRegistered(userId, it) 123 }, 124 { 125 try { 126 context.unregisterReceiver(this) 127 logger.logContextReceiverUnregistered(userId, action) 128 } catch (e: IllegalArgumentException) { 129 Log.e(TAG, "Trying to unregister unregistered receiver for user $userId, " + 130 "action $action", 131 IllegalStateException(e)) 132 } 133 }, 134 bgExecutor, 135 logger 136 ) 137 } 138 139 private fun handleUnregisterReceiver(receiver: BroadcastReceiver) { 140 Preconditions.checkState(bgHandler.looper.isCurrentThread, 141 "This method should only be called from BG thread") 142 if (DEBUG) Log.w(TAG, "Unregister receiver: $receiver") 143 receiverToActions.getOrDefault(receiver, mutableSetOf()).forEach { 144 actionsToActionsReceivers.get(it)?.removeReceiver(receiver) 145 } 146 receiverToActions.remove(receiver) 147 logger.logReceiverUnregistered(userId, receiver) 148 } 149 150 override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) { 151 pw.indentIfPossible { 152 actionsToActionsReceivers.forEach { (action, actionReceiver) -> 153 println("$action:") 154 actionReceiver.dump(fd, pw, args) 155 } 156 } 157 } 158 } 159