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.dump 18 19 import com.android.systemui.Dumpable 20 import com.android.systemui.ProtoDumpable 21 import com.android.systemui.dump.DumpsysEntry.DumpableEntry 22 import com.android.systemui.dump.DumpsysEntry.LogBufferEntry 23 import com.android.systemui.dump.DumpsysEntry.TableLogBufferEntry 24 import com.android.systemui.log.LogBuffer 25 import com.android.systemui.log.table.TableLogBuffer 26 import java.util.TreeMap 27 import javax.inject.Inject 28 import javax.inject.Singleton 29 30 /** 31 * Maintains a registry of things that should be dumped when a bug report is taken 32 * 33 * When a bug report is taken, SystemUI dumps various diagnostic information that we hope will be 34 * useful for the eventual readers of the bug report. Code that wishes to participate in this dump 35 * should register itself here. 36 * 37 * See [DumpHandler] for more information on how and when this information is dumped. 38 */ 39 @Singleton 40 open class DumpManager @Inject constructor() { 41 // NOTE: Using TreeMap ensures that iteration is in a predictable & alphabetical order. 42 private val dumpables: MutableMap<String, DumpableEntry> = TreeMap() 43 private val buffers: MutableMap<String, LogBufferEntry> = TreeMap() 44 private val tableLogBuffers: MutableMap<String, TableLogBufferEntry> = TreeMap() 45 46 /** See [registerCriticalDumpable]. */ registerCriticalDumpablenull47 fun registerCriticalDumpable(module: Dumpable) { 48 registerCriticalDumpable(module::class.java.name, module) 49 } 50 51 /** 52 * Registers a dumpable to be called during the CRITICAL section of the bug report. 53 * 54 * The CRITICAL section gets very high priority during a dump, but also a very limited amount of 55 * time to do the dumping. So, please don't dump an excessive amount of stuff using CRITICAL. 56 * 57 * See [registerDumpable]. 58 */ registerCriticalDumpablenull59 fun registerCriticalDumpable(name: String, module: Dumpable) { 60 registerDumpable(name, module, DumpPriority.CRITICAL) 61 } 62 63 /** See [registerNormalDumpable]. */ registerNormalDumpablenull64 fun registerNormalDumpable(module: Dumpable) { 65 registerNormalDumpable(module::class.java.name, module) 66 } 67 68 /** 69 * Registers a dumpable to be called during the NORMAL section of the bug report. 70 * 71 * The NORMAL section gets a lower priority during a dump, but also more time. This should be 72 * used by [LogBuffer] instances, [ProtoDumpable] instances, and any [Dumpable] instances that 73 * dump a lot of information. 74 */ registerNormalDumpablenull75 fun registerNormalDumpable(name: String, module: Dumpable) { 76 registerDumpable(name, module, DumpPriority.NORMAL) 77 } 78 79 /** 80 * Register a dumpable to be called during a bug report. 81 * 82 * @param name The name to register the dumpable under. This is typically the qualified class 83 * name of the thing being dumped (getClass().getName()), but can be anything as long as it 84 * doesn't clash with an existing registration. 85 * @param priority the priority level of this dumpable, which affects at what point in the bug 86 * report this gets dump. By default, the dumpable will be called during the CRITICAL section 87 * of the bug report, so don't dump an excessive amount of stuff here. 88 * 89 * TODO(b/259973758): Replace all calls to this method with calls to [registerCriticalDumpable] 90 * or [registerNormalDumpable] instead. 91 */ 92 @Synchronized 93 @JvmOverloads 94 @Deprecated("Use registerCriticalDumpable or registerNormalDumpable instead") registerDumpablenull95 fun registerDumpable( 96 name: String, 97 module: Dumpable, 98 priority: DumpPriority = DumpPriority.CRITICAL, 99 ) { 100 if (!canAssignToNameLocked(name, module)) { 101 throw IllegalArgumentException("'$name' is already registered") 102 } 103 104 dumpables[name] = DumpableEntry(module, name, priority) 105 } 106 107 /** Same as the above override, but automatically uses the class name as the dumpable name. */ 108 @Synchronized registerDumpablenull109 fun registerDumpable(module: Dumpable) { 110 registerDumpable(module::class.java.name, module) 111 } 112 113 /** Unregisters a previously-registered dumpable. */ 114 @Synchronized unregisterDumpablenull115 fun unregisterDumpable(name: String) { 116 dumpables.remove(name) 117 } 118 119 /** Register a [LogBuffer] to be dumped during a bug report. */ 120 @Synchronized registerBuffernull121 fun registerBuffer(name: String, buffer: LogBuffer) { 122 if (!canAssignToNameLocked(name, buffer)) { 123 throw IllegalArgumentException("'$name' is already registered") 124 } 125 126 buffers[name] = LogBufferEntry(buffer, name) 127 } 128 129 /** Register a [TableLogBuffer] to be dumped during a bugreport */ 130 @Synchronized registerTableLogBuffernull131 fun registerTableLogBuffer(name: String, buffer: TableLogBuffer) { 132 if (!canAssignToNameLocked(name, buffer)) { 133 throw IllegalArgumentException("'$name' is already registered") 134 } 135 136 // All buffers must be priority NORMAL, not CRITICAL, because they often contain a lot of 137 // data. 138 tableLogBuffers[name] = TableLogBufferEntry(buffer, name) 139 } 140 getDumpablesnull141 @Synchronized fun getDumpables(): Collection<DumpableEntry> = dumpables.values.toList() 142 143 @Synchronized fun getLogBuffers(): Collection<LogBufferEntry> = buffers.values.toList() 144 145 @Synchronized 146 fun getTableLogBuffers(): Collection<TableLogBufferEntry> = tableLogBuffers.values.toList() 147 148 @Synchronized 149 fun freezeBuffers() { 150 for (buffer in buffers.values) { 151 buffer.buffer.freeze() 152 } 153 } 154 155 @Synchronized unfreezeBuffersnull156 fun unfreezeBuffers() { 157 for (buffer in buffers.values) { 158 buffer.buffer.unfreeze() 159 } 160 } 161 canAssignToNameLockednull162 private fun canAssignToNameLocked(name: String, newDumpable: Any): Boolean { 163 val existingDumpable = 164 dumpables[name]?.dumpable ?: buffers[name]?.buffer ?: tableLogBuffers[name]?.table 165 return existingDumpable == null || newDumpable == existingDumpable 166 } 167 } 168 169 /** 170 * The priority level for a given dumpable, which affects at what point in the bug report this gets 171 * dumped. 172 */ 173 enum class DumpPriority { 174 CRITICAL, 175 NORMAL, 176 } 177