xref: /aosp_15_r20/external/leakcanary2/shark-hprof/src/main/java/shark/StreamingRecordReaderAdapter.kt (revision d9e8da70d8c9df9a41d7848ae506fb3115cae6e6)

<lambda>null1 package shark
2 
3 import shark.HprofRecord.HeapDumpEndRecord
4 import shark.HprofRecord.HeapDumpRecord
5 import shark.HprofRecord.HeapDumpRecord.GcRootRecord
6 import shark.HprofRecord.HeapDumpRecord.HeapDumpInfoRecord
7 import shark.HprofRecord.HeapDumpRecord.ObjectRecord
8 import shark.HprofRecord.HeapDumpRecord.ObjectRecord.ClassDumpRecord
9 import shark.HprofRecord.HeapDumpRecord.ObjectRecord.InstanceDumpRecord
10 import shark.HprofRecord.HeapDumpRecord.ObjectRecord.ObjectArrayDumpRecord
11 import shark.HprofRecord.HeapDumpRecord.ObjectRecord.PrimitiveArrayDumpRecord
12 import shark.HprofRecord.LoadClassRecord
13 import shark.HprofRecord.StackFrameRecord
14 import shark.HprofRecord.StackTraceRecord
15 import shark.HprofRecord.StringRecord
16 import shark.HprofRecordTag.CLASS_DUMP
17 import shark.HprofRecordTag.HEAP_DUMP_END
18 import shark.HprofRecordTag.HEAP_DUMP_INFO
19 import shark.HprofRecordTag.INSTANCE_DUMP
20 import shark.HprofRecordTag.LOAD_CLASS
21 import shark.HprofRecordTag.OBJECT_ARRAY_DUMP
22 import shark.HprofRecordTag.PRIMITIVE_ARRAY_DUMP
23 import shark.HprofRecordTag.ROOT_DEBUGGER
24 import shark.HprofRecordTag.ROOT_FINALIZING
25 import shark.HprofRecordTag.ROOT_INTERNED_STRING
26 import shark.HprofRecordTag.ROOT_JAVA_FRAME
27 import shark.HprofRecordTag.ROOT_JNI_GLOBAL
28 import shark.HprofRecordTag.ROOT_JNI_LOCAL
29 import shark.HprofRecordTag.ROOT_JNI_MONITOR
30 import shark.HprofRecordTag.ROOT_MONITOR_USED
31 import shark.HprofRecordTag.ROOT_NATIVE_STACK
32 import shark.HprofRecordTag.ROOT_REFERENCE_CLEANUP
33 import shark.HprofRecordTag.ROOT_STICKY_CLASS
34 import shark.HprofRecordTag.ROOT_THREAD_BLOCK
35 import shark.HprofRecordTag.ROOT_THREAD_OBJECT
36 import shark.HprofRecordTag.ROOT_UNKNOWN
37 import shark.HprofRecordTag.ROOT_UNREACHABLE
38 import shark.HprofRecordTag.ROOT_VM_INTERNAL
39 import shark.HprofRecordTag.STACK_FRAME
40 import shark.HprofRecordTag.STACK_TRACE
41 import shark.HprofRecordTag.STRING_IN_UTF8
42 import java.util.EnumSet
43 import kotlin.reflect.KClass
44 
45 /**
46  * Wraps a [StreamingHprofReader] to provide a higher level API that streams [HprofRecord]
47  * instances.
48  */
49 class StreamingRecordReaderAdapter(private val streamingHprofReader: StreamingHprofReader) {
50 
51   /**
52    * Obtains a new source to read all hprof records from and calls [listener] back for each record
53    * that matches one of the provided [recordTypes].
54    *
55    * @return the number of bytes read from the source
56    */
57   @Suppress("ComplexMethod", "LongMethod", "NestedBlockDepth")
58   fun readRecords(
59     recordTypes: Set<KClass<out HprofRecord>>,
60     listener: OnHprofRecordListener
61   ): Long {
62     val recordTags = recordTypes.asHprofTags()
63     return streamingHprofReader.readRecords(
64       recordTags
65     ) { tag, length, reader ->
66       when (tag) {
67         STRING_IN_UTF8 -> {
68           val recordPosition = reader.bytesRead
69           val record = reader.readStringRecord(length)
70           listener.onHprofRecord(recordPosition, record)
71         }
72         LOAD_CLASS -> {
73           val recordPosition = reader.bytesRead
74           val record = reader.readLoadClassRecord()
75           listener.onHprofRecord(recordPosition, record)
76         }
77         STACK_FRAME -> {
78           val recordPosition = reader.bytesRead
79           val record = reader.readStackFrameRecord()
80           listener.onHprofRecord(recordPosition, record)
81         }
82         STACK_TRACE -> {
83           val recordPosition = reader.bytesRead
84           val record = reader.readStackTraceRecord()
85           listener.onHprofRecord(recordPosition, record)
86         }
87         ROOT_UNKNOWN -> {
88           val recordPosition = reader.bytesRead
89           val record = reader.readUnknownGcRootRecord()
90           listener.onHprofRecord(recordPosition, GcRootRecord(record))
91         }
92         ROOT_JNI_GLOBAL -> {
93           val recordPosition = reader.bytesRead
94           val gcRootRecord = reader.readJniGlobalGcRootRecord()
95           listener.onHprofRecord(recordPosition, GcRootRecord(gcRootRecord))
96         }
97         ROOT_JNI_LOCAL -> {
98           val recordPosition = reader.bytesRead
99           val gcRootRecord = reader.readJniLocalGcRootRecord()
100           listener.onHprofRecord(recordPosition, GcRootRecord(gcRootRecord))
101         }
102 
103         ROOT_JAVA_FRAME -> {
104           val recordPosition = reader.bytesRead
105           val gcRootRecord = reader.readJavaFrameGcRootRecord()
106           listener.onHprofRecord(recordPosition, GcRootRecord(gcRootRecord))
107         }
108 
109         ROOT_NATIVE_STACK -> {
110           val recordPosition = reader.bytesRead
111           val gcRootRecord = reader.readNativeStackGcRootRecord()
112           listener.onHprofRecord(recordPosition, GcRootRecord(gcRootRecord))
113         }
114 
115         ROOT_STICKY_CLASS -> {
116           val recordPosition = reader.bytesRead
117           val gcRootRecord = reader.readStickyClassGcRootRecord()
118           listener.onHprofRecord(recordPosition, GcRootRecord(gcRootRecord))
119         }
120 
121         ROOT_THREAD_BLOCK -> {
122           val recordPosition = reader.bytesRead
123           val gcRootRecord = reader.readThreadBlockGcRootRecord()
124           listener.onHprofRecord(recordPosition, GcRootRecord(gcRootRecord))
125         }
126 
127         ROOT_MONITOR_USED -> {
128           val recordPosition = reader.bytesRead
129           val gcRootRecord = reader.readMonitorUsedGcRootRecord()
130           listener.onHprofRecord(recordPosition, GcRootRecord(gcRootRecord))
131         }
132 
133         ROOT_THREAD_OBJECT -> {
134           val recordPosition = reader.bytesRead
135           val gcRootRecord = reader.readThreadObjectGcRootRecord()
136           listener.onHprofRecord(recordPosition, GcRootRecord(gcRootRecord))
137         }
138 
139         ROOT_INTERNED_STRING -> {
140           val recordPosition = reader.bytesRead
141           val gcRootRecord = reader.readInternedStringGcRootRecord()
142           listener.onHprofRecord(recordPosition, GcRootRecord(gcRootRecord))
143         }
144 
145         ROOT_FINALIZING -> {
146           val recordPosition = reader.bytesRead
147           val gcRootRecord = reader.readFinalizingGcRootRecord()
148           listener.onHprofRecord(recordPosition, GcRootRecord(gcRootRecord))
149         }
150 
151         ROOT_DEBUGGER -> {
152           val recordPosition = reader.bytesRead
153           val gcRootRecord = reader.readDebuggerGcRootRecord()
154           listener.onHprofRecord(recordPosition, GcRootRecord(gcRootRecord))
155         }
156 
157         ROOT_REFERENCE_CLEANUP -> {
158           val recordPosition = reader.bytesRead
159           val gcRootRecord = reader.readReferenceCleanupGcRootRecord()
160           listener.onHprofRecord(recordPosition, GcRootRecord(gcRootRecord))
161         }
162 
163         ROOT_VM_INTERNAL -> {
164           val recordPosition = reader.bytesRead
165           val gcRootRecord = reader.readVmInternalGcRootRecord()
166           listener.onHprofRecord(recordPosition, GcRootRecord(gcRootRecord))
167         }
168 
169         ROOT_JNI_MONITOR -> {
170           val recordPosition = reader.bytesRead
171           val gcRootRecord = reader.readJniMonitorGcRootRecord()
172           listener.onHprofRecord(recordPosition, GcRootRecord(gcRootRecord))
173         }
174 
175         ROOT_UNREACHABLE -> {
176           val recordPosition = reader.bytesRead
177           val gcRootRecord = reader.readUnreachableGcRootRecord()
178           listener.onHprofRecord(recordPosition, GcRootRecord(gcRootRecord))
179         }
180         CLASS_DUMP -> {
181           val recordPosition = reader.bytesRead
182           val record = reader.readClassDumpRecord()
183           listener.onHprofRecord(recordPosition, record)
184         }
185         INSTANCE_DUMP -> {
186           val recordPosition = reader.bytesRead
187           val record = reader.readInstanceDumpRecord()
188           listener.onHprofRecord(recordPosition, record)
189         }
190 
191         OBJECT_ARRAY_DUMP -> {
192           val recordPosition = reader.bytesRead
193           val arrayRecord = reader.readObjectArrayDumpRecord()
194           listener.onHprofRecord(recordPosition, arrayRecord)
195         }
196 
197         PRIMITIVE_ARRAY_DUMP -> {
198           val recordPosition = reader.bytesRead
199           val record = reader.readPrimitiveArrayDumpRecord()
200           listener.onHprofRecord(recordPosition, record)
201         }
202 
203         HEAP_DUMP_INFO -> {
204           val recordPosition = reader.bytesRead
205           val record = reader.readHeapDumpInfoRecord()
206           listener.onHprofRecord(recordPosition, record)
207         }
208         HEAP_DUMP_END -> {
209           val recordPosition = reader.bytesRead
210           val record = HeapDumpEndRecord
211           listener.onHprofRecord(recordPosition, record)
212         }
213         else -> error("Unexpected heap dump tag $tag at position ${reader.bytesRead}")
214       }
215     }
216   }
217 
218   companion object {
219     fun StreamingHprofReader.asStreamingRecordReader() = StreamingRecordReaderAdapter(this)
220 
221     fun Set<KClass<out HprofRecord>>.asHprofTags(): EnumSet<HprofRecordTag> {
222       val recordTypes = this
223       return if (HprofRecord::class in recordTypes) {
224         EnumSet.allOf(HprofRecordTag::class.java)
225       } else {
226         EnumSet.noneOf(HprofRecordTag::class.java).apply {
227           if (StringRecord::class in recordTypes) {
228             add(STRING_IN_UTF8)
229           }
230           if (LoadClassRecord::class in recordTypes) {
231             add(LOAD_CLASS)
232           }
233           if (HeapDumpEndRecord::class in recordTypes) {
234             add(HEAP_DUMP_END)
235           }
236           if (StackFrameRecord::class in recordTypes) {
237             add(STACK_FRAME)
238           }
239           if (StackTraceRecord::class in recordTypes) {
240             add(STACK_TRACE)
241           }
242           if (HeapDumpInfoRecord::class in recordTypes) {
243             add(HEAP_DUMP_INFO)
244           }
245           val readAllHeapDumpRecords = HeapDumpRecord::class in recordTypes
246           if (readAllHeapDumpRecords || GcRootRecord::class in recordTypes) {
247             addAll(HprofRecordTag.rootTags)
248           }
249           val readAllObjectRecords = readAllHeapDumpRecords || ObjectRecord::class in recordTypes
250           if (readAllObjectRecords || ClassDumpRecord::class in recordTypes) {
251             add(CLASS_DUMP)
252           }
253           if (readAllObjectRecords || InstanceDumpRecord::class in recordTypes) {
254             add(INSTANCE_DUMP)
255           }
256           if (readAllObjectRecords || ObjectArrayDumpRecord::class in recordTypes) {
257             add(OBJECT_ARRAY_DUMP)
258           }
259           if (readAllObjectRecords || PrimitiveArrayDumpRecord::class in recordTypes) {
260             add(PRIMITIVE_ARRAY_DUMP)
261           }
262         }
263       }
264     }
265   }
266 }
267