1 package shark 2 3 import okio.BufferedSource 4 import okio.Okio 5 import java.io.File 6 7 /** 8 * Represents the header metadata of a Hprof file. 9 */ 10 data class HprofHeader( 11 /** Unix timestamp at which the heap was dumped. */ 12 val heapDumpTimestamp: Long = System.currentTimeMillis(), 13 /** Hprof version, which is tied to the runtime where the heap was dumped. */ 14 val version: HprofVersion = HprofVersion.ANDROID, 15 /** 16 * Size of Hprof identifiers. Identifiers are used to represent UTF8 strings, objects, 17 * stack traces, etc. They can have the same size as host pointers or sizeof(void*), but are not 18 * required to be. 19 */ 20 val identifierByteSize: Int = 4 21 ) { 22 /** 23 * How many bytes from the beginning of the file can we find the hprof records at. 24 * Version string, 0 delimiter (1 byte), identifier byte size int (4 bytes) ,timestamp long 25 * (8 bytes) 26 */ 27 val recordsPosition: Int = version.versionString.toByteArray(Charsets.UTF_8).size + 1 + 4 + 8 28 29 companion object { <lambda>null30 private val supportedVersions = HprofVersion.values().associateBy { it.versionString } 31 32 /** 33 * Reads the header of the provided [hprofFile] and returns it as a [HprofHeader] 34 */ parseHeaderOfnull35 fun parseHeaderOf(hprofFile: File): HprofHeader { 36 val fileLength = hprofFile.length() 37 if (fileLength == 0L) { 38 throw IllegalArgumentException("Hprof file is 0 byte length") 39 } 40 return Okio.buffer(Okio.source(hprofFile.inputStream())).use { 41 parseHeaderOf(it) 42 } 43 } 44 45 /** 46 * Reads the header of the provided [source] and returns it as a [HprofHeader]. 47 * This does not close the [source]. 48 */ parseHeaderOfnull49 fun parseHeaderOf(source: BufferedSource): HprofHeader { 50 require(!source.exhausted()) { 51 throw IllegalArgumentException("Source has no available bytes") 52 } 53 val endOfVersionString = source.indexOf(0) 54 val versionName = source.readUtf8(endOfVersionString) 55 56 val version = supportedVersions[versionName] 57 checkNotNull(version) { 58 "Unsupported Hprof version [$versionName] not in supported list ${supportedVersions.keys}" 59 } 60 // Skip the 0 at the end of the version string. 61 source.skip(1) 62 val identifierByteSize = source.readInt() 63 val heapDumpTimestamp = source.readLong() 64 return HprofHeader(heapDumpTimestamp, version, identifierByteSize) 65 } 66 } 67 } 68