kotlin: upgrade to 1.4.0

travis: upgrade to Ubuntu 20.04 Focal
for/win
cfig 5 years ago
parent 2665fd0098
commit a39b870033
No known key found for this signature in database
GPG Key ID: B104C307F0FDABB7

@ -1,4 +1,4 @@
dist: bionic dist: focal
language: java language: java
before_install: before_install:
- sudo apt -qq update - sudo apt -qq update

@ -1,7 +1,8 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins { plugins {
id("org.jetbrains.kotlin.jvm").version("1.3.71") kotlin("jvm") version "1.4.0"
kotlin("plugin.serialization") version "1.4.0"
application application
} }
@ -13,10 +14,11 @@ dependencies {
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
implementation("org.jetbrains.kotlin:kotlin-reflect") implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.slf4j:slf4j-simple:1.7.29") implementation("org.slf4j:slf4j-simple:1.7.30")
implementation("org.slf4j:slf4j-api:1.7.29") implementation("org.slf4j:slf4j-api:1.7.30")
implementation("com.fasterxml.jackson.core:jackson-annotations:2.10.1") implementation("com.fasterxml.jackson.core:jackson-annotations:2.11.2")
implementation("com.fasterxml.jackson.core:jackson-databind:2.10.1") implementation("com.fasterxml.jackson.core:jackson-databind:2.11.2")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:1.0.0-RC")
implementation("com.google.guava:guava:18.0") implementation("com.google.guava:guava:18.0")
implementation("org.apache.commons:commons-exec:1.3") implementation("org.apache.commons:commons-exec:1.3")
implementation("org.apache.commons:commons-compress:1.16.1") implementation("org.apache.commons:commons-compress:1.16.1")

@ -46,6 +46,9 @@ class EnvironmentVerifier {
log.debug("lz4 available") log.debug("lz4 available")
} catch (e: Exception) { } catch (e: Exception) {
log.warn("lz4 not installed") log.warn("lz4 not installed")
if (isMacOS) {
log.warn("For Mac OS: \n\n\tbrew install lz4\n")
}
return false return false
} }
return true return true

@ -205,6 +205,15 @@ class Helper {
} }
} }
fun round_to_multiple(size: Int, page: Int): Int {
val remainder = size % page
return if (remainder == 0) {
size
} else {
size + page - remainder
}
}
/* /*
read RSA private key read RSA private key
assert exp == 65537 assert exp == 65537

@ -74,9 +74,9 @@ class Avb {
// + AvbFooter + padding // + AvbFooter + padding
newAvbInfo.footer!!.apply { newAvbInfo.footer!!.apply {
originalImageSize = newImageSize.toULong() originalImageSize = newImageSize
vbMetaOffset = vbmetaOffset.toULong() vbMetaOffset = vbmetaOffset
vbMetaSize = vbmetaBlob.size.toULong() vbMetaSize = vbmetaBlob.size.toLong()
} }
log.info(newAvbInfo.footer.toString()) log.info(newAvbInfo.footer.toString())
val footerBlobWithPadding = newAvbInfo.footer!!.encode().paddingWith(BLOCK_SIZE.toUInt(), true) val footerBlobWithPadding = newAvbInfo.footer!!.encode().paddingWith(BLOCK_SIZE.toUInt(), true)
@ -113,7 +113,7 @@ class Avb {
FileOutputStream(File(image_file), true).channel.use { fc -> FileOutputStream(File(image_file), true).channel.use { fc ->
log.info("original image $image_file has AVB footer, " + log.info("original image $image_file has AVB footer, " +
"truncate it to original SIZE: ${it.originalImageSize}") "truncate it to original SIZE: ${it.originalImageSize}")
fc.truncate(it.originalImageSize.toLong()) fc.truncate(it.originalImageSize)
} }
} }
} }
@ -146,7 +146,7 @@ class Avb {
log.info("parsing $image_file ...") log.info("parsing $image_file ...")
val jsonFile = getJsonFileName(image_file) val jsonFile = getJsonFileName(image_file)
var footer: Footer? = null var footer: Footer? = null
var vbMetaOffset: ULong = 0U var vbMetaOffset: Long = 0
// footer // footer
FileInputStream(image_file).use { fis -> FileInputStream(image_file).use { fis ->
fis.skip(File(image_file).length() - Footer.SIZE) fis.skip(File(image_file).length() - Footer.SIZE)
@ -160,26 +160,26 @@ class Avb {
} }
// header // header
var vbMetaHeader = Header() var vbMetaHeader: Header
FileInputStream(image_file).use { fis -> FileInputStream(image_file).use { fis ->
fis.skip(vbMetaOffset.toLong()) fis.skip(vbMetaOffset)
vbMetaHeader = Header(fis) vbMetaHeader = Header(fis)
} }
log.info(vbMetaHeader.toString()) log.info(vbMetaHeader.toString())
log.debug(ObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(vbMetaHeader)) log.debug(ObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(vbMetaHeader))
val authBlockOffset = vbMetaOffset + Header.SIZE.toUInt() val authBlockOffset = vbMetaOffset + Header.SIZE
val auxBlockOffset = authBlockOffset + vbMetaHeader.authentication_data_block_size val auxBlockOffset = authBlockOffset + vbMetaHeader.authentication_data_block_size
val descStartOffset = auxBlockOffset + vbMetaHeader.descriptors_offset val descStartOffset = auxBlockOffset + vbMetaHeader.descriptors_offset
val ai = AVBInfo(vbMetaHeader, null, AuxBlob(), footer) val ai = AVBInfo(vbMetaHeader, null, AuxBlob(), footer)
// Auth blob // Auth blob
if (vbMetaHeader.authentication_data_block_size > 0U) { if (vbMetaHeader.authentication_data_block_size > 0) {
FileInputStream(image_file).use { fis -> FileInputStream(image_file).use { fis ->
fis.skip(vbMetaOffset.toLong()) fis.skip(vbMetaOffset)
fis.skip(Header.SIZE.toLong()) fis.skip(Header.SIZE.toLong())
fis.skip(vbMetaHeader.hash_offset.toLong()) fis.skip(vbMetaHeader.hash_offset)
val ba = ByteArray(vbMetaHeader.hash_size.toInt()) val ba = ByteArray(vbMetaHeader.hash_size.toInt())
fis.read(ba) fis.read(ba)
log.debug("Parsed Auth Hash (Header & Aux Blob): " + Hex.encodeHexString(ba)) log.debug("Parsed Auth Hash (Header & Aux Blob): " + Hex.encodeHexString(ba))
@ -197,10 +197,10 @@ class Avb {
// aux - desc // aux - desc
var descriptors: List<Any> = mutableListOf() var descriptors: List<Any> = mutableListOf()
if (vbMetaHeader.descriptors_size > 0U) { if (vbMetaHeader.descriptors_size > 0) {
FileInputStream(image_file).use { fis -> FileInputStream(image_file).use { fis ->
fis.skip(descStartOffset.toLong()) fis.skip(descStartOffset)
descriptors = UnknownDescriptor.parseDescriptors2(fis, vbMetaHeader.descriptors_size.toLong()) descriptors = UnknownDescriptor.parseDescriptors2(fis, vbMetaHeader.descriptors_size)
} }
descriptors.forEach { descriptors.forEach {
log.debug(it.toString()) log.debug(it.toString())
@ -230,28 +230,28 @@ class Avb {
} }
} }
// aux - pubkey // aux - pubkey
if (vbMetaHeader.public_key_size > 0U) { if (vbMetaHeader.public_key_size > 0) {
ai.auxBlob!!.pubkey = AuxBlob.PubKeyInfo() ai.auxBlob!!.pubkey = AuxBlob.PubKeyInfo()
ai.auxBlob!!.pubkey!!.offset = vbMetaHeader.public_key_offset.toLong() ai.auxBlob!!.pubkey!!.offset = vbMetaHeader.public_key_offset
ai.auxBlob!!.pubkey!!.size = vbMetaHeader.public_key_size.toLong() ai.auxBlob!!.pubkey!!.size = vbMetaHeader.public_key_size
FileInputStream(image_file).use { fis -> FileInputStream(image_file).use { fis ->
fis.skip(auxBlockOffset.toLong()) fis.skip(auxBlockOffset)
fis.skip(vbMetaHeader.public_key_offset.toLong()) fis.skip(vbMetaHeader.public_key_offset)
ai.auxBlob!!.pubkey!!.pubkey = ByteArray(vbMetaHeader.public_key_size.toInt()) ai.auxBlob!!.pubkey!!.pubkey = ByteArray(vbMetaHeader.public_key_size.toInt())
fis.read(ai.auxBlob!!.pubkey!!.pubkey) fis.read(ai.auxBlob!!.pubkey!!.pubkey)
log.debug("Parsed Pub Key: " + Hex.encodeHexString(ai.auxBlob!!.pubkey!!.pubkey)) log.debug("Parsed Pub Key: " + Hex.encodeHexString(ai.auxBlob!!.pubkey!!.pubkey))
} }
} }
// aux - pkmd // aux - pkmd
if (vbMetaHeader.public_key_metadata_size > 0U) { if (vbMetaHeader.public_key_metadata_size > 0) {
ai.auxBlob!!.pubkeyMeta = AuxBlob.PubKeyMetadataInfo() ai.auxBlob!!.pubkeyMeta = AuxBlob.PubKeyMetadataInfo()
ai.auxBlob!!.pubkeyMeta!!.offset = vbMetaHeader.public_key_metadata_offset.toLong() ai.auxBlob!!.pubkeyMeta!!.offset = vbMetaHeader.public_key_metadata_offset
ai.auxBlob!!.pubkeyMeta!!.size = vbMetaHeader.public_key_metadata_size.toLong() ai.auxBlob!!.pubkeyMeta!!.size = vbMetaHeader.public_key_metadata_size
FileInputStream(image_file).use { fis -> FileInputStream(image_file).use { fis ->
fis.skip(auxBlockOffset.toLong()) fis.skip(auxBlockOffset)
fis.skip(vbMetaHeader.public_key_metadata_offset.toLong()) fis.skip(vbMetaHeader.public_key_metadata_offset)
ai.auxBlob!!.pubkeyMeta!!.pkmd = ByteArray(vbMetaHeader.public_key_metadata_size.toInt()) ai.auxBlob!!.pubkeyMeta!!.pkmd = ByteArray(vbMetaHeader.public_key_metadata_size.toInt())
fis.read(ai.auxBlob!!.pubkeyMeta!!.pkmd) fis.read(ai.auxBlob!!.pubkeyMeta!!.pkmd)
log.debug("Parsed Pub Key Metadata: " + Helper.toHexString(ai.auxBlob!!.pubkeyMeta!!.pkmd)) log.debug("Parsed Pub Key Metadata: " + Helper.toHexString(ai.auxBlob!!.pubkeyMeta!!.pkmd))
@ -271,30 +271,30 @@ class Avb {
private fun packVbMeta(info: AVBInfo? = null, image_file: String? = null): ByteArray { private fun packVbMeta(info: AVBInfo? = null, image_file: String? = null): ByteArray {
val ai = info ?: ObjectMapper().readValue(File(getJsonFileName(image_file!!)), AVBInfo::class.java) val ai = info ?: ObjectMapper().readValue(File(getJsonFileName(image_file!!)), AVBInfo::class.java)
val alg = Algorithms.get(ai.header!!.algorithm_type.toInt())!! val alg = Algorithms.get(ai.header!!.algorithm_type)!!
//3 - whole aux blob //3 - whole aux blob
val auxBlob = ai.auxBlob?.encode(alg) ?: byteArrayOf() val auxBlob = ai.auxBlob?.encode(alg) ?: byteArrayOf()
//1 - whole header blob //1 - whole header blob
val headerBlob = ai.header!!.apply { val headerBlob = ai.header!!.apply {
auxiliary_data_block_size = auxBlob.size.toULong() auxiliary_data_block_size = auxBlob.size.toLong()
authentication_data_block_size = Helper.round_to_multiple( authentication_data_block_size = Helper.round_to_multiple(
(alg.hash_num_bytes + alg.signature_num_bytes).toLong(), 64).toULong() (alg.hash_num_bytes + alg.signature_num_bytes).toLong(), 64)
descriptors_offset = 0U descriptors_offset = 0
descriptors_size = ai.auxBlob?.descriptorSize?.toULong() ?: 0U descriptors_size = ai.auxBlob?.descriptorSize?.toLong() ?: 0
hash_offset = 0U hash_offset = 0
hash_size = alg.hash_num_bytes.toULong() hash_size = alg.hash_num_bytes.toLong()
signature_offset = alg.hash_num_bytes.toULong() signature_offset = alg.hash_num_bytes.toLong()
signature_size = alg.signature_num_bytes.toULong() signature_size = alg.signature_num_bytes.toLong()
public_key_offset = descriptors_size public_key_offset = descriptors_size
public_key_size = AuxBlob.encodePubKey(alg).size.toULong() public_key_size = AuxBlob.encodePubKey(alg).size.toLong()
public_key_metadata_size = ai.auxBlob!!.pubkeyMeta?.pkmd?.size?.toULong() ?: 0U public_key_metadata_size = ai.auxBlob!!.pubkeyMeta?.pkmd?.size?.toLong() ?: 0L
public_key_metadata_offset = public_key_offset + public_key_size public_key_metadata_offset = public_key_offset + public_key_size
log.info("pkmd size: $public_key_metadata_size, pkmd offset : $public_key_metadata_offset") log.info("pkmd size: $public_key_metadata_size, pkmd offset : $public_key_metadata_offset")
}.encode() }.encode()
@ -316,8 +316,8 @@ class Avb {
companion object { companion object {
private val log = LoggerFactory.getLogger(Avb::class.java) private val log = LoggerFactory.getLogger(Avb::class.java)
const val AVB_VERSION_MAJOR = 1U const val AVB_VERSION_MAJOR = 1
const val AVB_VERSION_MINOR = 1U const val AVB_VERSION_MINOR = 1
const val AVB_VERSION_SUB = 0 const val AVB_VERSION_SUB = 0
fun getJsonFileName(image_file: String): String { fun getJsonFileName(image_file: String): String {

@ -8,8 +8,8 @@ import java.security.MessageDigest
@OptIn(ExperimentalUnsignedTypes::class) @OptIn(ExperimentalUnsignedTypes::class)
data class AuthBlob( data class AuthBlob(
var offset: ULong = 0U, var offset: Long = 0,
var size: ULong = 0U, var size: Long = 0,
var hash: String? = null, var hash: String? = null,
var signature: String? = null) { var signature: String? = null) {
companion object { companion object {

@ -25,11 +25,11 @@ https://github.com/cfig/Android_boot_image_editor/blob/master/doc/layout.md#32-a
@OptIn(ExperimentalUnsignedTypes::class) @OptIn(ExperimentalUnsignedTypes::class)
data class Footer constructor( data class Footer constructor(
var versionMajor: UInt = FOOTER_VERSION_MAJOR, var versionMajor: Int = FOOTER_VERSION_MAJOR,
var versionMinor: UInt = FOOTER_VERSION_MINOR, var versionMinor: Int = FOOTER_VERSION_MINOR,
var originalImageSize: ULong = 0U, var originalImageSize: Long = 0,
var vbMetaOffset: ULong = 0U, var vbMetaOffset: Long = 0,
var vbMetaSize: ULong = 0U var vbMetaSize: Long = 0
) { ) {
@Throws(IllegalArgumentException::class) @Throws(IllegalArgumentException::class)
constructor(iS: InputStream) : this() { constructor(iS: InputStream) : this() {
@ -38,14 +38,14 @@ data class Footer constructor(
if (MAGIC != (info[0] as String)) { if (MAGIC != (info[0] as String)) {
throw IllegalArgumentException("stream doesn't look like valid AVB Footer") throw IllegalArgumentException("stream doesn't look like valid AVB Footer")
} }
versionMajor = info[1] as UInt versionMajor = (info[1] as UInt).toInt()
versionMinor = info[2] as UInt versionMinor = (info[2] as UInt).toInt()
originalImageSize = info[3] as ULong originalImageSize = (info[3] as ULong).toLong()
vbMetaOffset = info[4] as ULong vbMetaOffset = (info[4] as ULong).toLong()
vbMetaSize = info[5] as ULong vbMetaSize = (info[5] as ULong).toLong()
} }
constructor(originalImageSize: ULong, vbMetaOffset: ULong, vbMetaSize: ULong) constructor(originalImageSize: Long, vbMetaOffset: Long, vbMetaSize: Long)
: this(FOOTER_VERSION_MAJOR, FOOTER_VERSION_MINOR, originalImageSize, vbMetaOffset, vbMetaSize) : this(FOOTER_VERSION_MAJOR, FOOTER_VERSION_MINOR, originalImageSize, vbMetaOffset, vbMetaSize)
@Throws(IllegalArgumentException::class) @Throws(IllegalArgumentException::class)
@ -75,8 +75,8 @@ data class Footer constructor(
private const val MAGIC = "AVBf" private const val MAGIC = "AVBf"
const val SIZE = 64 const val SIZE = 64
private const val RESERVED = 28 private const val RESERVED = 28
private const val FOOTER_VERSION_MAJOR = 1U private const val FOOTER_VERSION_MAJOR = 1
private const val FOOTER_VERSION_MINOR = 0U private const val FOOTER_VERSION_MINOR = 0
private const val FORMAT_STRING = "!4s2L3Q${RESERVED}x" private const val FORMAT_STRING = "!4s2L3Q${RESERVED}x"
init { init {

@ -7,23 +7,23 @@ import java.io.InputStream
//avbtool::AvbVBMetaHeader //avbtool::AvbVBMetaHeader
@OptIn(ExperimentalUnsignedTypes::class) @OptIn(ExperimentalUnsignedTypes::class)
data class Header( data class Header(
var required_libavb_version_major: UInt = Avb.AVB_VERSION_MAJOR, var required_libavb_version_major: Int = Avb.AVB_VERSION_MAJOR,
var required_libavb_version_minor: UInt = 0U, var required_libavb_version_minor: Int = 0,
var authentication_data_block_size: ULong = 0U, var authentication_data_block_size: Long = 0,
var auxiliary_data_block_size: ULong = 0U, var auxiliary_data_block_size: Long = 0,
var algorithm_type: UInt = 0U, var algorithm_type: Int = 0,
var hash_offset: ULong = 0U, var hash_offset: Long = 0,
var hash_size: ULong = 0U, var hash_size: Long = 0,
var signature_offset: ULong = 0U, var signature_offset: Long = 0,
var signature_size: ULong = 0U, var signature_size: Long = 0,
var public_key_offset: ULong = 0U, var public_key_offset: Long = 0,
var public_key_size: ULong = 0U, var public_key_size: Long = 0,
var public_key_metadata_offset: ULong = 0U, var public_key_metadata_offset: Long = 0,
var public_key_metadata_size: ULong = 0U, var public_key_metadata_size: Long = 0,
var descriptors_offset: ULong = 0U, var descriptors_offset: Long = 0,
var descriptors_size: ULong = 0U, var descriptors_size: Long = 0,
var rollback_index: ULong = 0U, var rollback_index: Long = 0,
var flags: UInt = 0U, var flags: Int = 0,
var release_string: String = "avbtool ${Avb.AVB_VERSION_MAJOR}.${Avb.AVB_VERSION_MINOR}.${Avb.AVB_VERSION_SUB}") { var release_string: String = "avbtool ${Avb.AVB_VERSION_MAJOR}.${Avb.AVB_VERSION_MINOR}.${Avb.AVB_VERSION_SUB}") {
@Throws(IllegalArgumentException::class) @Throws(IllegalArgumentException::class)
constructor(iS: InputStream) : this() { constructor(iS: InputStream) : this() {
@ -32,23 +32,23 @@ data class Header(
if (info[0] != magic) { if (info[0] != magic) {
throw IllegalArgumentException("stream doesn't look like valid VBMeta Header") throw IllegalArgumentException("stream doesn't look like valid VBMeta Header")
} }
this.required_libavb_version_major = info[1] as UInt this.required_libavb_version_major = (info[1] as UInt).toInt()
this.required_libavb_version_minor = info[2] as UInt this.required_libavb_version_minor = (info[2] as UInt).toInt()
this.authentication_data_block_size = info[3] as ULong this.authentication_data_block_size = (info[3] as ULong).toLong()
this.auxiliary_data_block_size = info[4] as ULong this.auxiliary_data_block_size = (info[4] as ULong).toLong()
this.algorithm_type = info[5] as UInt this.algorithm_type = (info[5] as UInt).toInt()
this.hash_offset = info[6] as ULong this.hash_offset = (info[6] as ULong).toLong()
this.hash_size = info[7] as ULong this.hash_size = (info[7] as ULong).toLong()
this.signature_offset = info[8] as ULong this.signature_offset = (info[8] as ULong).toLong()
this.signature_size = info[9] as ULong this.signature_size = (info[9] as ULong).toLong()
this.public_key_offset = info[10] as ULong this.public_key_offset = (info[10] as ULong).toLong()
this.public_key_size = info[11] as ULong this.public_key_size = (info[11] as ULong).toLong()
this.public_key_metadata_offset = info[12] as ULong this.public_key_metadata_offset = (info[12] as ULong).toLong()
this.public_key_metadata_size = info[13] as ULong this.public_key_metadata_size = (info[13] as ULong).toLong()
this.descriptors_offset = info[14] as ULong this.descriptors_offset = (info[14] as ULong).toLong()
this.descriptors_size = info[15] as ULong this.descriptors_size = (info[15] as ULong).toLong()
this.rollback_index = info[16] as ULong this.rollback_index = (info[16] as ULong).toLong()
this.flags = info[17] as UInt this.flags = (info[17] as UInt).toInt()
//padding: info[18] //padding: info[18]
this.release_string = info[19] as String this.release_string = info[19] as String
} }
@ -72,7 +72,7 @@ data class Header(
null) //${REVERSED}x null) //${REVERSED}x
} }
fun bump_required_libavb_version_minor(minor: UInt) { fun bump_required_libavb_version_minor(minor: Int) {
this.required_libavb_version_minor = maxOf(required_libavb_version_minor, minor) this.required_libavb_version_minor = maxOf(required_libavb_version_minor, minor)
} }

@ -8,22 +8,22 @@ import java.util.*
@OptIn(ExperimentalUnsignedTypes::class) @OptIn(ExperimentalUnsignedTypes::class)
class ChainPartitionDescriptor( class ChainPartitionDescriptor(
var rollback_index_location: UInt = 0U, var rollback_index_location: Int = 0,
var partition_name_len: UInt = 0U, var partition_name_len: Int = 0,
var public_key_len: UInt = 0U, var public_key_len: Int = 0,
var partition_name: String = "", var partition_name: String = "",
var pubkey: ByteArray = byteArrayOf(), var pubkey: ByteArray = byteArrayOf(),
var pubkey_sha1: String = "" var pubkey_sha1: String = ""
) : Descriptor(TAG, 0U, 0) { ) : Descriptor(TAG, 0, 0) {
override fun encode(): ByteArray { override fun encode(): ByteArray {
this.partition_name_len = this.partition_name.length.toUInt() this.partition_name_len = this.partition_name.length
this.public_key_len = this.pubkey.size.toUInt() this.public_key_len = this.pubkey.size
this.num_bytes_following = (SIZE.toUInt() + this.partition_name_len + this.public_key_len - 16U).toULong() this.num_bytes_following = SIZE + this.partition_name_len + this.public_key_len - 16
val nbf_with_padding = Helper.round_to_multiple(this.num_bytes_following.toLong(), 8).toULong() val nbf_with_padding = Helper.round_to_multiple(this.num_bytes_following, 8).toULong()
val padding_size = nbf_with_padding - this.num_bytes_following val padding_size = nbf_with_padding - this.num_bytes_following.toUInt()
val desc = Struct3(FORMAT_STRING + "${RESERVED}x").pack( val desc = Struct3(FORMAT_STRING + "${RESERVED}x").pack(
TAG, TAG,
nbf_with_padding.toULong(), nbf_with_padding,
this.rollback_index_location, this.rollback_index_location,
this.partition_name.length.toUInt(), this.partition_name.length.toUInt(),
this.public_key_len, this.public_key_len,
@ -33,7 +33,7 @@ class ChainPartitionDescriptor(
} }
companion object { companion object {
const val TAG: ULong = 4U const val TAG: Long = 4L
const val RESERVED = 64 const val RESERVED = 64
const val SIZE = 28L + RESERVED const val SIZE = 28L + RESERVED
const val FORMAT_STRING = "!2Q3L" const val FORMAT_STRING = "!2Q3L"
@ -45,14 +45,14 @@ class ChainPartitionDescriptor(
} }
this.sequence = seq this.sequence = seq
val info = Struct3(FORMAT_STRING + "${RESERVED}s").unpack(data) val info = Struct3(FORMAT_STRING + "${RESERVED}s").unpack(data)
this.tag = info[0] as ULong this.tag = (info[0] as ULong).toLong()
this.num_bytes_following = info[1] as ULong this.num_bytes_following = (info[1] as ULong).toLong()
this.rollback_index_location = info[2] as UInt this.rollback_index_location = (info[2] as UInt).toInt()
this.partition_name_len = info[3] as UInt this.partition_name_len = (info[3] as UInt).toInt()
this.public_key_len = info[4] as UInt this.public_key_len = (info[4] as UInt).toInt()
val expectedSize = Helper.round_to_multiple( val expectedSize = Helper.round_to_multiple(
SIZE.toUInt() - 16U + this.partition_name_len + this.public_key_len, 8U) SIZE - 16 + this.partition_name_len + this.public_key_len, 8)
if (this.tag != TAG || this.num_bytes_following != expectedSize.toULong()) { if (this.tag != TAG || this.num_bytes_following != expectedSize.toLong()) {
throw IllegalArgumentException("Given data does not look like a chain/delegation descriptor") throw IllegalArgumentException("Given data does not look like a chain/delegation descriptor")
} }
val info2 = Struct3("${this.partition_name_len}s${this.public_key_len}b").unpack(data) val info2 = Struct3("${this.partition_name_len}s${this.public_key_len}b").unpack(data)

@ -1,6 +1,6 @@
package avb.desc package avb.desc
@OptIn(ExperimentalUnsignedTypes::class) @OptIn(ExperimentalUnsignedTypes::class)
abstract class Descriptor(var tag: ULong, var num_bytes_following: ULong, var sequence: Int = 0) { abstract class Descriptor(var tag: Long, var num_bytes_following: Long, var sequence: Int = 0) {
abstract fun encode(): ByteArray abstract fun encode(): ByteArray
} }

@ -11,19 +11,19 @@ import java.io.InputStream
import java.security.MessageDigest import java.security.MessageDigest
@OptIn(ExperimentalUnsignedTypes::class) @OptIn(ExperimentalUnsignedTypes::class)
class HashDescriptor(var flags: UInt = 0U, class HashDescriptor(var flags: Int = 0,
var partition_name: String = "", var partition_name: String = "",
var hash_algorithm: String = "", var hash_algorithm: String = "",
var image_size: ULong = 0U, var image_size: Long = 0,
var salt: ByteArray = byteArrayOf(), var salt: ByteArray = byteArrayOf(),
var digest: ByteArray = byteArrayOf(), var digest: ByteArray = byteArrayOf(),
var partition_name_len: UInt = 0U, var partition_name_len: Int = 0,
var salt_len: UInt = 0U, var salt_len: Int = 0,
var digest_len: UInt = 0U) var digest_len: Int = 0)
: Descriptor(TAG, 0U, 0) { : Descriptor(TAG, 0, 0) {
var flagsInterpretation: String = "" var flagsInterpretation: String = ""
get() { get() {
return if (this.flags and Header.HashDescriptorFlags.AVB_HASH_DESCRIPTOR_FLAGS_DO_NOT_USE_AB.inFlags.toUInt() == 1U) { return if (this.flags and Header.HashDescriptorFlags.AVB_HASH_DESCRIPTOR_FLAGS_DO_NOT_USE_AB.inFlags == 1) {
"1:no-A/B system" "1:no-A/B system"
} else { } else {
"0:A/B system" "0:A/B system"
@ -32,17 +32,17 @@ class HashDescriptor(var flags: UInt = 0U,
constructor(data: InputStream, seq: Int = 0) : this() { constructor(data: InputStream, seq: Int = 0) : this() {
val info = Struct3(FORMAT_STRING).unpack(data) val info = Struct3(FORMAT_STRING).unpack(data)
this.tag = info[0] as ULong this.tag = (info[0] as ULong).toLong()
this.num_bytes_following = info[1] as ULong this.num_bytes_following = (info[1] as ULong).toLong()
this.image_size = info[2] as ULong this.image_size = (info[2] as ULong).toLong()
this.hash_algorithm = info[3] as String this.hash_algorithm = info[3] as String
this.partition_name_len = info[4] as UInt this.partition_name_len = (info[4] as UInt).toInt()
this.salt_len = info[5] as UInt this.salt_len = (info[5] as UInt).toInt()
this.digest_len = info[6] as UInt this.digest_len = (info[6] as UInt).toInt()
this.flags = info[7] as UInt this.flags = (info[7] as UInt).toInt()
this.sequence = seq this.sequence = seq
val expectedSize = Helper.round_to_multiple( val expectedSize = Helper.round_to_multiple(
SIZE - 16 + (partition_name_len + salt_len + digest_len).toLong(), 8).toULong() SIZE - 16 + (partition_name_len + salt_len + digest_len).toLong(), 8)
if (this.tag != TAG || expectedSize != this.num_bytes_following) { if (this.tag != TAG || expectedSize != this.num_bytes_following) {
throw IllegalArgumentException("Given data does not look like a |hash| descriptor") throw IllegalArgumentException("Given data does not look like a |hash| descriptor")
} }
@ -55,8 +55,8 @@ class HashDescriptor(var flags: UInt = 0U,
override fun encode(): ByteArray { override fun encode(): ByteArray {
val payload_bytes_following = SIZE + this.partition_name.length + this.salt.size + this.digest.size - 16L val payload_bytes_following = SIZE + this.partition_name.length + this.salt.size + this.digest.size - 16L
this.num_bytes_following = Helper.round_to_multiple(payload_bytes_following, 8).toULong() this.num_bytes_following = Helper.round_to_multiple(payload_bytes_following, 8)
val padding_size = num_bytes_following - payload_bytes_following.toUInt() val padding_size = num_bytes_following - payload_bytes_following
val desc = Struct3(FORMAT_STRING).pack( val desc = Struct3(FORMAT_STRING).pack(
TAG, TAG,
this.num_bytes_following, this.num_bytes_following,
@ -88,17 +88,17 @@ class HashDescriptor(var flags: UInt = 0U,
it.read(randomSalt) it.read(randomSalt)
log.warn("salt is empty, using random salt[$expectedDigestSize]: " + Helper.toHexString(randomSalt)) log.warn("salt is empty, using random salt[$expectedDigestSize]: " + Helper.toHexString(randomSalt))
this.salt = randomSalt this.salt = randomSalt
this.salt_len = this.salt.size.toUInt() this.salt_len = this.salt.size
} }
} else { } else {
log.info("preset salt[${this.salt.size}] is valid: ${Hex.encodeHexString(this.salt)}") log.info("preset salt[${this.salt.size}] is valid: ${Hex.encodeHexString(this.salt)}")
} }
//size //size
this.image_size = File(image_file).length().toULong() this.image_size = File(image_file).length()
//flags //flags
if (this.flags and 1U == 1U) { if (this.flags and 1 == 1) {
log.info("flag: use_ab = 0") log.info("flag: use_ab = 0")
} else { } else {
log.info("flag: use_ab = 1") log.info("flag: use_ab = 1")
@ -112,14 +112,14 @@ class HashDescriptor(var flags: UInt = 0U,
}.digest() }.digest()
log.info("Digest(salt + file): " + Helper.toHexString(newDigest)) log.info("Digest(salt + file): " + Helper.toHexString(newDigest))
this.digest = newDigest this.digest = newDigest
this.digest_len = this.digest.size.toUInt() this.digest_len = this.digest.size
} }
return this return this
} }
companion object { companion object {
const val TAG: ULong = 2U const val TAG: Long = 2L
private const val RESERVED = 60 private const val RESERVED = 60
private const val SIZE = 72 + RESERVED private const val SIZE = 72 + RESERVED
private const val FORMAT_STRING = "!3Q32s4L${RESERVED}x" private const val FORMAT_STRING = "!3Q32s4L${RESERVED}x"

@ -8,24 +8,24 @@ import java.util.*
@OptIn(ExperimentalUnsignedTypes::class) @OptIn(ExperimentalUnsignedTypes::class)
class HashTreeDescriptor( class HashTreeDescriptor(
var flags: UInt = 0U, var flags: Int = 0,
var dm_verity_version: UInt = 0u, var dm_verity_version: Int = 0,
var image_size: ULong = 0UL, var image_size: Long = 0,
var tree_offset: ULong = 0UL, var tree_offset: Long = 0,
var tree_size: ULong = 0UL, var tree_size: Long = 0,
var data_block_size: UInt = 0U, var data_block_size: Int = 0,
var hash_block_size: UInt = 0U, var hash_block_size: Int = 0,
var fec_num_roots: UInt = 0U, var fec_num_roots: Int = 0,
var fec_offset: ULong = 0U, var fec_offset: Long = 0,
var fec_size: ULong = 0U, var fec_size: Long = 0,
var hash_algorithm: String = "", var hash_algorithm: String = "",
var partition_name: String = "", var partition_name: String = "",
var salt: ByteArray = byteArrayOf(), var salt: ByteArray = byteArrayOf(),
var root_digest: ByteArray = byteArrayOf()) : Descriptor(TAG, 0U, 0) { var root_digest: ByteArray = byteArrayOf()) : Descriptor(TAG, 0, 0) {
var flagsInterpretation: String = "" var flagsInterpretation: String = ""
get() { get() {
var ret = "" var ret = ""
if (this.flags and Header.HashTreeDescriptorFlags.AVB_HASHTREE_DESCRIPTOR_FLAGS_DO_NOT_USE_AB.inFlags.toUInt() == 1U) { if (this.flags and Header.HashTreeDescriptorFlags.AVB_HASHTREE_DESCRIPTOR_FLAGS_DO_NOT_USE_AB.inFlags == 1) {
ret += "1:no-A/B system" ret += "1:no-A/B system"
} else { } else {
ret += "0:A/B system" ret += "0:A/B system"
@ -36,24 +36,24 @@ class HashTreeDescriptor(
constructor(data: InputStream, seq: Int = 0) : this() { constructor(data: InputStream, seq: Int = 0) : this() {
this.sequence = seq this.sequence = seq
val info = Struct3(FORMAT_STRING).unpack(data) val info = Struct3(FORMAT_STRING).unpack(data)
this.tag = info[0] as ULong this.tag = (info[0] as ULong).toLong()
this.num_bytes_following = info[1] as ULong this.num_bytes_following = (info[1] as ULong).toLong()
this.dm_verity_version = info[2] as UInt this.dm_verity_version = (info[2] as UInt).toInt()
this.image_size = info[3] as ULong this.image_size = (info[3] as ULong).toLong()
this.tree_offset = info[4] as ULong this.tree_offset = (info[4] as ULong).toLong()
this.tree_size = info[5] as ULong this.tree_size = (info[5] as ULong).toLong()
this.data_block_size = info[6] as UInt this.data_block_size = (info[6] as UInt).toInt()
this.hash_block_size = info[7] as UInt this.hash_block_size = (info[7] as UInt).toInt()
this.fec_num_roots = info[8] as UInt this.fec_num_roots = (info[8] as UInt).toInt()
this.fec_offset = info[9] as ULong this.fec_offset = (info[9] as ULong).toLong()
this.fec_size = info[10] as ULong this.fec_size = (info[10] as ULong).toLong()
this.hash_algorithm = info[11] as String this.hash_algorithm = info[11] as String
val partition_name_len = info[12] as UInt val partition_name_len = info[12] as UInt
val salt_len = info[13] as UInt val salt_len = info[13] as UInt
val root_digest_len = info[14] as UInt val root_digest_len = info[14] as UInt
this.flags = info[15] as UInt this.flags = (info[15] as UInt).toInt()
val expectedSize = Helper.round_to_multiple(SIZE.toUInt() - 16U + partition_name_len + salt_len + root_digest_len, 8U) val expectedSize = Helper.round_to_multiple(SIZE.toUInt() - 16U + partition_name_len + salt_len + root_digest_len, 8U)
if (this.tag != TAG || this.num_bytes_following != expectedSize.toULong()) { if (this.tag != TAG || this.num_bytes_following != expectedSize.toLong()) {
throw IllegalArgumentException("Given data does not look like a hashtree descriptor") throw IllegalArgumentException("Given data does not look like a hashtree descriptor")
} }
@ -64,7 +64,7 @@ class HashTreeDescriptor(
} }
override fun encode(): ByteArray { override fun encode(): ByteArray {
this.num_bytes_following = (SIZE + this.partition_name.length + this.salt.size + this.root_digest.size - 16).toULong() this.num_bytes_following = SIZE + this.partition_name.length + this.salt.size + this.root_digest.size - 16
val nbf_with_padding = Helper.round_to_multiple(this.num_bytes_following.toLong(), 8) val nbf_with_padding = Helper.round_to_multiple(this.num_bytes_following.toLong(), 8)
val padding_size = nbf_with_padding - this.num_bytes_following.toLong() val padding_size = nbf_with_padding - this.num_bytes_following.toLong()
val desc = Struct3(FORMAT_STRING).pack( val desc = Struct3(FORMAT_STRING).pack(
@ -94,7 +94,7 @@ class HashTreeDescriptor(
} }
companion object { companion object {
const val TAG: ULong = 1U const val TAG: Long = 1L
private const val RESERVED = 60L private const val RESERVED = 60L
private const val SIZE = 120 + RESERVED private const val SIZE = 120 + RESERVED
private const val FORMAT_STRING = "!2QL3Q3L2Q32s4L${RESERVED}x" private const val FORMAT_STRING = "!2QL3Q3L2Q32s4L${RESERVED}x"

@ -9,7 +9,7 @@ class KernelCmdlineDescriptor(
var flags: UInt = 0U, var flags: UInt = 0U,
var cmdlineLength: UInt = 0U, var cmdlineLength: UInt = 0U,
var cmdline: String = "") var cmdline: String = "")
: Descriptor(TAG, 0U, 0) { : Descriptor(TAG, 0, 0) {
var flagsInterpretation: String = "" var flagsInterpretation: String = ""
get() { get() {
var ret = "" var ret = ""
@ -24,13 +24,13 @@ class KernelCmdlineDescriptor(
@Throws(IllegalArgumentException::class) @Throws(IllegalArgumentException::class)
constructor(data: InputStream, seq: Int = 0) : this() { constructor(data: InputStream, seq: Int = 0) : this() {
val info = Struct3(FORMAT_STRING).unpack(data) val info = Struct3(FORMAT_STRING).unpack(data)
this.tag = info[0] as ULong this.tag = (info[0] as ULong).toLong()
this.num_bytes_following = info[1] as ULong this.num_bytes_following = (info[1] as ULong).toLong()
this.flags = info[2] as UInt this.flags = info[2] as UInt
this.cmdlineLength = info[3] as UInt this.cmdlineLength = info[3] as UInt
this.sequence = seq this.sequence = seq
val expectedSize = Helper.round_to_multiple(SIZE.toUInt() - 16U + this.cmdlineLength, 8U) val expectedSize = Helper.round_to_multiple(SIZE.toUInt() - 16U + this.cmdlineLength, 8U)
if ((this.tag != TAG) || (this.num_bytes_following != expectedSize.toULong())) { if ((this.tag != TAG) || (this.num_bytes_following != expectedSize.toLong())) {
throw IllegalArgumentException("Given data does not look like a kernel cmdline descriptor") throw IllegalArgumentException("Given data does not look like a kernel cmdline descriptor")
} }
this.cmdline = Struct3("${this.cmdlineLength}s").unpack(data)[0] as String this.cmdline = Struct3("${this.cmdlineLength}s").unpack(data)[0] as String
@ -50,7 +50,7 @@ class KernelCmdlineDescriptor(
} }
companion object { companion object {
const val TAG: ULong = 3U const val TAG: Long = 3L
const val SIZE = 24 const val SIZE = 24
const val FORMAT_STRING = "!2Q2L" //# tag, num_bytes_following (descriptor header), flags, cmdline length (bytes) const val FORMAT_STRING = "!2Q2L" //# tag, num_bytes_following (descriptor header), flags, cmdline length (bytes)
//AVB_KERNEL_CMDLINE_FLAGS_USE_ONLY_IF_HASHTREE_NOT_DISABLED //AVB_KERNEL_CMDLINE_FLAGS_USE_ONLY_IF_HASHTREE_NOT_DISABLED

@ -7,14 +7,14 @@ import java.io.InputStream
@OptIn(ExperimentalUnsignedTypes::class) @OptIn(ExperimentalUnsignedTypes::class)
class PropertyDescriptor( class PropertyDescriptor(
var key: String = "", var key: String = "",
var value: String = "") : Descriptor(TAG, 0U, 0) { var value: String = "") : Descriptor(TAG, 0, 0) {
override fun encode(): ByteArray { override fun encode(): ByteArray {
if (SIZE != Struct3(FORMAT_STRING).calcSize().toUInt()) { if (SIZE != Struct3(FORMAT_STRING).calcSize().toUInt()) {
throw RuntimeException() throw RuntimeException()
} }
this.num_bytes_following = (SIZE + this.key.length.toUInt() + this.value.length.toUInt() + 2U - 16U).toULong() this.num_bytes_following = (SIZE + this.key.length.toUInt() + this.value.length.toUInt() + 2U - 16U).toLong()
val nbfWithPadding = Helper.round_to_multiple(this.num_bytes_following.toLong(), 8).toULong() val nbfWithPadding = Helper.round_to_multiple(this.num_bytes_following.toLong(), 8).toULong()
val paddingSize = nbfWithPadding - num_bytes_following val paddingSize = nbfWithPadding - num_bytes_following.toUInt()
val padding = Struct3("${paddingSize}x").pack(0) val padding = Struct3("${paddingSize}x").pack(0)
val desc = Struct3(FORMAT_STRING).pack( val desc = Struct3(FORMAT_STRING).pack(
TAG, TAG,
@ -29,12 +29,12 @@ class PropertyDescriptor(
constructor(data: InputStream, seq: Int = 0) : this() { constructor(data: InputStream, seq: Int = 0) : this() {
val info = Struct3(FORMAT_STRING).unpack(data) val info = Struct3(FORMAT_STRING).unpack(data)
this.tag = info[0] as ULong this.tag = (info[0] as ULong).toLong()
this.num_bytes_following = info[1] as ULong this.num_bytes_following = (info[1] as ULong).toLong()
val keySize = (info[2] as ULong).toUInt() val keySize = (info[2] as ULong).toUInt()
val valueSize = (info[3] as ULong).toUInt() val valueSize = (info[3] as ULong).toUInt()
val expectedSize = Helper.round_to_multiple(SIZE - 16U + keySize + 1U + valueSize + 1U, 8U) val expectedSize = Helper.round_to_multiple(SIZE - 16U + keySize + 1U + valueSize + 1U, 8U)
if (this.tag != TAG || expectedSize.toULong() != this.num_bytes_following) { if (this.tag != TAG || expectedSize.toLong() != this.num_bytes_following) {
throw IllegalArgumentException("Given data does not look like a |property| descriptor") throw IllegalArgumentException("Given data does not look like a |property| descriptor")
} }
this.sequence = seq this.sequence = seq
@ -45,7 +45,7 @@ class PropertyDescriptor(
} }
companion object { companion object {
const val TAG: ULong = 0U const val TAG: Long = 0L
const val SIZE = 32U const val SIZE = 32U
const val FORMAT_STRING = "!4Q" const val FORMAT_STRING = "!4Q"
} }

@ -8,13 +8,13 @@ import java.io.ByteArrayInputStream
import java.io.InputStream import java.io.InputStream
@OptIn(ExperimentalUnsignedTypes::class) @OptIn(ExperimentalUnsignedTypes::class)
class UnknownDescriptor(var data: ByteArray = byteArrayOf()) : Descriptor(0U, 0U, 0) { class UnknownDescriptor(var data: ByteArray = byteArrayOf()) : Descriptor(0, 0, 0) {
@Throws(IllegalArgumentException::class) @Throws(IllegalArgumentException::class)
constructor(stream: InputStream, seq: Int = 0) : this() { constructor(stream: InputStream, seq: Int = 0) : this() {
this.sequence = seq this.sequence = seq
val info = Struct3(FORMAT).unpack(stream) val info = Struct3(FORMAT).unpack(stream)
this.tag = info[0] as ULong this.tag = (info[0] as ULong).toLong()
this.num_bytes_following = info[1] as ULong this.num_bytes_following = (info[1] as ULong).toLong()
log.debug("UnknownDescriptor: tag = $tag, len = ${this.num_bytes_following}") log.debug("UnknownDescriptor: tag = $tag, len = ${this.num_bytes_following}")
this.data = ByteArray(this.num_bytes_following.toInt()) this.data = ByteArray(this.num_bytes_following.toInt())
if (this.num_bytes_following.toInt() != stream.read(data)) { if (this.num_bytes_following.toInt() != stream.read(data)) {

@ -9,27 +9,27 @@ import kotlin.math.pow
@OptIn(ExperimentalUnsignedTypes::class) @OptIn(ExperimentalUnsignedTypes::class)
open class BootHeaderV2( open class BootHeaderV2(
var kernelLength: UInt = 0U, var kernelLength: Int = 0,
var kernelOffset: UInt = 0U, var kernelOffset: Long = 0L, //UInt
var ramdiskLength: UInt = 0U, var ramdiskLength: Int = 0,
var ramdiskOffset: UInt = 0U, var ramdiskOffset: Long = 0L, //UInt
var secondBootloaderLength: UInt = 0U, var secondBootloaderLength: Int = 0,
var secondBootloaderOffset: UInt = 0U, var secondBootloaderOffset: Long = 0L, //UInt
var recoveryDtboLength: UInt = 0U, var recoveryDtboLength: Int = 0,
var recoveryDtboOffset: ULong = 0UL,//Q var recoveryDtboOffset: Long = 0L,//Q
var dtbLength: UInt = 0U, var dtbLength: Int = 0,
var dtbOffset: ULong = 0UL,//Q var dtbOffset: Long = 0L,//Q
var tagsOffset: UInt = 0U, var tagsOffset: Long = 0L, //UInt
var pageSize: UInt = 0U, var pageSize: Int = 0,
var headerSize: UInt = 0U, var headerSize: Int = 0,
var headerVersion: UInt = 0U, var headerVersion: Int = 0,
var board: String = "", var board: String = "",
@ -50,15 +50,15 @@ open class BootHeaderV2(
if (info[0] != magic) { if (info[0] != magic) {
throw IllegalArgumentException("stream doesn't look like Android Boot Image Header") throw IllegalArgumentException("stream doesn't look like Android Boot Image Header")
} }
this.kernelLength = info[1] as UInt this.kernelLength = (info[1] as UInt).toInt()
this.kernelOffset = info[2] as UInt this.kernelOffset = (info[2] as UInt).toLong()
this.ramdiskLength = info[3] as UInt this.ramdiskLength = (info[3] as UInt).toInt()
this.ramdiskOffset = info[4] as UInt this.ramdiskOffset = (info[4] as UInt).toLong()
this.secondBootloaderLength = info[5] as UInt this.secondBootloaderLength = (info[5] as UInt).toInt()
this.secondBootloaderOffset = info[6] as UInt this.secondBootloaderOffset = (info[6] as UInt).toLong()
this.tagsOffset = info[7] as UInt this.tagsOffset = (info[7] as UInt).toLong()
this.pageSize = info[8] as UInt this.pageSize = (info[8] as UInt).toInt()
this.headerVersion = info[9] as UInt this.headerVersion = (info[9] as UInt).toInt()
val osNPatch = info[10] as UInt val osNPatch = info[10] as UInt
if (0U != osNPatch) { //treated as 'reserved' in this boot image if (0U != osNPatch) { //treated as 'reserved' in this boot image
this.osVersion = Common.parseOsVersion(osNPatch.toInt() shr 11) this.osVersion = Common.parseOsVersion(osNPatch.toInt() shr 11)
@ -68,25 +68,25 @@ open class BootHeaderV2(
this.cmdline = (info[12] as String) + (info[14] as String) this.cmdline = (info[12] as String) + (info[14] as String)
this.hash = info[13] as ByteArray this.hash = info[13] as ByteArray
if (this.headerVersion > 0U) { if (this.headerVersion > 0) {
this.recoveryDtboLength = info[15] as UInt this.recoveryDtboLength = (info[15] as UInt).toInt()
this.recoveryDtboOffset = info[16] as ULong this.recoveryDtboOffset = (info[16] as ULong).toLong()
} }
this.headerSize = info[17] as UInt this.headerSize = (info[17] as UInt).toInt()
assert(this.headerSize.toInt() in intArrayOf(BOOT_IMAGE_HEADER_V2_SIZE, assert(this.headerSize.toInt() in intArrayOf(BOOT_IMAGE_HEADER_V2_SIZE,
BOOT_IMAGE_HEADER_V1_SIZE, BOOT_IMAGE_HEADER_V0_SIZE)) { BOOT_IMAGE_HEADER_V1_SIZE, BOOT_IMAGE_HEADER_V0_SIZE)) {
"header size ${this.headerSize} illegal" "header size ${this.headerSize} illegal"
} }
if (this.headerVersion > 1U) { if (this.headerVersion > 1) {
this.dtbLength = info[18] as UInt this.dtbLength = (info[18] as UInt).toInt()
this.dtbOffset = info[19] as ULong this.dtbOffset = (info[19] as ULong).toLong()
} }
} }
private fun get_recovery_dtbo_offset(): UInt { private fun get_recovery_dtbo_offset(): Long {
return Helper.round_to_multiple(this.headerSize, pageSize) + return Helper.round_to_multiple(this.headerSize.toLong(), pageSize) +
Helper.round_to_multiple(this.kernelLength, pageSize) + Helper.round_to_multiple(this.kernelLength, pageSize) +
Helper.round_to_multiple(this.ramdiskLength, pageSize) + Helper.round_to_multiple(this.ramdiskLength, pageSize) +
Helper.round_to_multiple(this.secondBootloaderLength, pageSize) Helper.round_to_multiple(this.secondBootloaderLength, pageSize)
@ -121,18 +121,18 @@ open class BootHeaderV2(
//I //I
recoveryDtboLength, recoveryDtboLength,
//Q //Q
if (headerVersion > 0U) recoveryDtboOffset else 0, if (headerVersion > 0) recoveryDtboOffset else 0,
//I //I
when (headerVersion) { when (headerVersion) {
0U -> BOOT_IMAGE_HEADER_V0_SIZE 0 -> BOOT_IMAGE_HEADER_V0_SIZE
1U -> BOOT_IMAGE_HEADER_V1_SIZE 1 -> BOOT_IMAGE_HEADER_V1_SIZE
2U -> BOOT_IMAGE_HEADER_V2_SIZE 2 -> BOOT_IMAGE_HEADER_V2_SIZE
else -> java.lang.IllegalArgumentException("headerVersion $headerVersion illegal") else -> java.lang.IllegalArgumentException("headerVersion $headerVersion illegal")
}, },
//I //I
dtbLength, dtbLength,
//Q //Q
if (headerVersion > 1U) dtbOffset else 0 if (headerVersion > 1) dtbOffset else 0
) )
} }

@ -30,12 +30,12 @@ data class BootV2(
data class MiscInfo( data class MiscInfo(
var output: String = "", var output: String = "",
var json: String = "", var json: String = "",
var headerVersion: UInt = 0U, var headerVersion: Int = 0,
var headerSize: UInt = 0U, var headerSize: Int = 0,
var loadBase: UInt = 0U, var loadBase: Long = 0,
var tagsOffset: UInt = 0U, var tagsOffset: Long = 0,
var board: String? = null, var board: String? = null,
var pageSize: UInt = 0U, var pageSize: Int = 0,
var cmdline: String = "", var cmdline: String = "",
var osVersion: String? = null, var osVersion: String? = null,
var osPatchLevel: String? = null, var osPatchLevel: String? = null,
@ -45,15 +45,15 @@ data class BootV2(
data class CommArgs( data class CommArgs(
var file: String? = null, var file: String? = null,
var position: UInt = 0U, var position: Long = 0,
var size: Int = 0, var size: Int = 0,
var loadOffset: UInt = 0U) var loadOffset: Long = 0)
data class CommArgsLong( data class CommArgsLong(
var file: String? = null, var file: String? = null,
var position: UInt = 0U, var position: Long = 0,
var size: UInt = 0U, var size: Int = 0,
var loadOffset: ULong = 0U) var loadOffset: Long = 0)
companion object { companion object {
private val log = LoggerFactory.getLogger(BootV2::class.java) private val log = LoggerFactory.getLogger(BootV2::class.java)
@ -93,25 +93,25 @@ data class BootV2(
theRamdisk.size = bh2.ramdiskLength.toInt() theRamdisk.size = bh2.ramdiskLength.toInt()
theRamdisk.loadOffset = bh2.ramdiskOffset theRamdisk.loadOffset = bh2.ramdiskOffset
theRamdisk.position = ret.getRamdiskPosition() theRamdisk.position = ret.getRamdiskPosition()
if (bh2.ramdiskLength > 0U) { if (bh2.ramdiskLength > 0) {
theRamdisk.file = "${workDir}ramdisk.img.gz" theRamdisk.file = "${workDir}ramdisk.img.gz"
} }
} }
if (bh2.secondBootloaderLength > 0U) { if (bh2.secondBootloaderLength > 0) {
ret.secondBootloader = CommArgs() ret.secondBootloader = CommArgs()
ret.secondBootloader!!.size = bh2.secondBootloaderLength.toInt() ret.secondBootloader!!.size = bh2.secondBootloaderLength.toInt()
ret.secondBootloader!!.loadOffset = bh2.secondBootloaderOffset ret.secondBootloader!!.loadOffset = bh2.secondBootloaderOffset
ret.secondBootloader!!.file = "${workDir}second" ret.secondBootloader!!.file = "${workDir}second"
ret.secondBootloader!!.position = ret.getSecondBootloaderPosition() ret.secondBootloader!!.position = ret.getSecondBootloaderPosition()
} }
if (bh2.recoveryDtboLength > 0U) { if (bh2.recoveryDtboLength > 0) {
ret.recoveryDtbo = CommArgsLong() ret.recoveryDtbo = CommArgsLong()
ret.recoveryDtbo!!.size = bh2.recoveryDtboLength ret.recoveryDtbo!!.size = bh2.recoveryDtboLength
ret.recoveryDtbo!!.loadOffset = bh2.recoveryDtboOffset //Q ret.recoveryDtbo!!.loadOffset = bh2.recoveryDtboOffset //Q
ret.recoveryDtbo!!.file = "${workDir}recoveryDtbo" ret.recoveryDtbo!!.file = "${workDir}recoveryDtbo"
ret.recoveryDtbo!!.position = ret.getRecoveryDtboPosition().toUInt() ret.recoveryDtbo!!.position = ret.getRecoveryDtboPosition()
} }
if (bh2.dtbLength > 0U) { if (bh2.dtbLength > 0) {
ret.dtb = CommArgsLong() ret.dtb = CommArgsLong()
ret.dtb!!.size = bh2.dtbLength ret.dtb!!.size = bh2.dtbLength
ret.dtb!!.loadOffset = bh2.dtbOffset //Q ret.dtb!!.loadOffset = bh2.dtbOffset //Q
@ -123,35 +123,35 @@ data class BootV2(
} }
} }
private fun getHeaderSize(pageSize: UInt): UInt { private fun getHeaderSize(pageSize: Int): Int {
val pad = (pageSize - (1648U and (pageSize - 1U))) and (pageSize - 1U) val pad = (pageSize - (1648 and (pageSize - 1))) and (pageSize - 1)
return pad + 1648U return pad + 1648
} }
private fun getKernelPosition(): UInt { private fun getKernelPosition(): Long {
return getHeaderSize(info.pageSize) return getHeaderSize(info.pageSize).toLong()
} }
private fun getRamdiskPosition(): UInt { private fun getRamdiskPosition(): Long {
return (getKernelPosition() + kernel.size.toUInt() + return (getKernelPosition() + kernel.size +
Common.getPaddingSize(kernel.size.toUInt(), info.pageSize)) Common.getPaddingSize(kernel.size, info.pageSize))
} }
private fun getSecondBootloaderPosition(): UInt { private fun getSecondBootloaderPosition(): Long {
return getRamdiskPosition() + ramdisk.size.toUInt() + return getRamdiskPosition() + ramdisk.size +
Common.getPaddingSize(ramdisk.size.toUInt(), info.pageSize) Common.getPaddingSize(ramdisk.size, info.pageSize)
} }
private fun getRecoveryDtboPosition(): UInt { private fun getRecoveryDtboPosition(): Long {
return if (this.secondBootloader == null) { return if (this.secondBootloader == null) {
getSecondBootloaderPosition() getSecondBootloaderPosition()
} else { } else {
getSecondBootloaderPosition() + secondBootloader!!.size.toUInt() + getSecondBootloaderPosition() + secondBootloader!!.size +
Common.getPaddingSize(secondBootloader!!.size.toUInt(), info.pageSize) Common.getPaddingSize(secondBootloader!!.size, info.pageSize)
} }
} }
private fun getDtbPosition(): UInt { private fun getDtbPosition(): Long {
return if (this.recoveryDtbo == null) { return if (this.recoveryDtbo == null) {
getRecoveryDtboPosition() getRecoveryDtboPosition()
} else { } else {
@ -244,14 +244,14 @@ data class BootV2(
} }
//dtbo //dtbo
this.recoveryDtbo?.let { theDtbo -> this.recoveryDtbo?.let { theDtbo ->
if (theDtbo.size > 0U) { if (theDtbo.size > 0) {
it.addRule() it.addRule()
it.addRow("recovery dtbo", theDtbo.file) it.addRow("recovery dtbo", theDtbo.file)
} }
} }
//dtb //dtb
this.dtb?.let { theDtb -> this.dtb?.let { theDtb ->
if (theDtb.size > 0u) { if (theDtb.size > 0) {
it.addRule() it.addRule()
it.addRow("dtb", theDtb.file) it.addRow("dtb", theDtb.file)
if (File(theDtb.file + ".src").exists()) { if (File(theDtb.file + ".src").exists()) {
@ -280,16 +280,16 @@ data class BootV2(
private fun toHeader(): BootHeaderV2 { private fun toHeader(): BootHeaderV2 {
return BootHeaderV2( return BootHeaderV2(
kernelLength = kernel.size.toUInt(), kernelLength = kernel.size,
kernelOffset = kernel.loadOffset, kernelOffset = kernel.loadOffset,
ramdiskLength = ramdisk.size.toUInt(), ramdiskLength = ramdisk.size,
ramdiskOffset = ramdisk.loadOffset, ramdiskOffset = ramdisk.loadOffset,
secondBootloaderLength = if (secondBootloader != null) secondBootloader!!.size.toUInt() else 0U, secondBootloaderLength = if (secondBootloader != null) secondBootloader!!.size else 0,
secondBootloaderOffset = if (secondBootloader != null) secondBootloader!!.loadOffset else 0U, secondBootloaderOffset = if (secondBootloader != null) secondBootloader!!.loadOffset else 0,
recoveryDtboLength = if (recoveryDtbo != null) recoveryDtbo!!.size.toUInt() else 0U, recoveryDtboLength = if (recoveryDtbo != null) recoveryDtbo!!.size else 0,
recoveryDtboOffset = if (recoveryDtbo != null) recoveryDtbo!!.loadOffset else 0U, recoveryDtboOffset = if (recoveryDtbo != null) recoveryDtbo!!.loadOffset else 0,
dtbLength = if (dtb != null) dtb!!.size else 0U, dtbLength = if (dtb != null) dtb!!.size else 0,
dtbOffset = if (dtb != null) dtb!!.loadOffset else 0U, dtbOffset = if (dtb != null) dtb!!.loadOffset else 0,
tagsOffset = info.tagsOffset, tagsOffset = info.tagsOffset,
pageSize = info.pageSize, pageSize = info.pageSize,
headerSize = info.headerSize, headerSize = info.headerSize,
@ -318,7 +318,7 @@ data class BootV2(
//refresh ramdisk size //refresh ramdisk size
if (this.ramdisk.file.isNullOrBlank()) { if (this.ramdisk.file.isNullOrBlank()) {
ramdisk.file = null ramdisk.file = null
ramdisk.loadOffset = 0U ramdisk.loadOffset = 0
} else { } else {
if (File(this.ramdisk.file!!).exists() && !File(workDir + "root").exists()) { if (File(this.ramdisk.file!!).exists() && !File(workDir + "root").exists()) {
//do nothing if we have ramdisk.img.gz but no /root //do nothing if we have ramdisk.img.gz but no /root
@ -336,24 +336,24 @@ data class BootV2(
} }
//refresh recovery dtbo size //refresh recovery dtbo size
recoveryDtbo?.let { theDtbo -> recoveryDtbo?.let { theDtbo ->
theDtbo.size = File(theDtbo.file!!).length().toUInt() theDtbo.size = File(theDtbo.file!!).length().toInt()
theDtbo.loadOffset = getRecoveryDtboPosition().toULong() theDtbo.loadOffset = getRecoveryDtboPosition()
log.warn("using fake recoveryDtboOffset ${theDtbo.loadOffset} (as is in AOSP avbtool)") log.warn("using fake recoveryDtboOffset ${theDtbo.loadOffset} (as is in AOSP avbtool)")
} }
//refresh dtb size //refresh dtb size
dtb?.let { theDtb -> dtb?.let { theDtb ->
theDtb.size = File(theDtb.file!!).length().toUInt() theDtb.size = File(theDtb.file!!).length().toInt()
} }
//refresh image hash //refresh image hash
info.hash = when (info.headerVersion) { info.hash = when (info.headerVersion) {
0U -> { 0 -> {
Common.hashFileAndSize(kernel.file, ramdisk.file, secondBootloader?.file) Common.hashFileAndSize(kernel.file, ramdisk.file, secondBootloader?.file)
} }
1U -> { 1 -> {
Common.hashFileAndSize(kernel.file, ramdisk.file, Common.hashFileAndSize(kernel.file, ramdisk.file,
secondBootloader?.file, recoveryDtbo?.file) secondBootloader?.file, recoveryDtbo?.file)
} }
2U -> { 2 -> {
Common.hashFileAndSize(kernel.file, ramdisk.file, Common.hashFileAndSize(kernel.file, ramdisk.file,
secondBootloader?.file, recoveryDtbo?.file, dtb?.file) secondBootloader?.file, recoveryDtbo?.file, dtb?.file)
} }
@ -367,7 +367,7 @@ data class BootV2(
//write //write
FileOutputStream("${info.output}.clear", false).use { fos -> FileOutputStream("${info.output}.clear", false).use { fos ->
fos.write(encodedHeader) fos.write(encodedHeader)
fos.write(ByteArray((Helper.round_to_multiple(encodedHeader.size.toUInt(), info.pageSize) - encodedHeader.size.toUInt()).toInt())) fos.write(ByteArray((Helper.round_to_multiple(encodedHeader.size, info.pageSize) - encodedHeader.size)))
} }
log.info("Writing data ...") log.info("Writing data ...")
@ -431,13 +431,13 @@ data class BootV2(
ret.addArgument(" --board ") ret.addArgument(" --board ")
ret.addArgument(info.board) ret.addArgument(info.board)
} }
if (info.headerVersion > 0U) { if (info.headerVersion > 0) {
if (recoveryDtbo != null) { if (recoveryDtbo != null) {
ret.addArgument(" --recovery_dtbo ") ret.addArgument(" --recovery_dtbo ")
ret.addArgument(recoveryDtbo!!.file!!) ret.addArgument(recoveryDtbo!!.file!!)
} }
} }
if (info.headerVersion > 1U) { if (info.headerVersion > 1) {
if (dtb != null) { if (dtb != null) {
ret.addArgument("--dtb ") ret.addArgument("--dtb ")
ret.addArgument(dtb!!.file!!) ret.addArgument(dtb!!.file!!)

@ -7,12 +7,12 @@ import java.io.InputStream
@OptIn(ExperimentalUnsignedTypes::class) @OptIn(ExperimentalUnsignedTypes::class)
class BootHeaderV3( class BootHeaderV3(
var kernelSize: UInt = 0U, var kernelSize: Int = 0,
var ramdiskSize: UInt = 0U, var ramdiskSize: Int = 0,
var osVersion: String = "", var osVersion: String = "",
var osPatchLevel: String = "", var osPatchLevel: String = "",
var headerSize: UInt = 0U, var headerSize: Int = 0,
var headerVersion: UInt = 0U, var headerVersion: Int = 0,
var cmdline: String = "" var cmdline: String = ""
) { ) {
@Throws(IllegalArgumentException::class) @Throws(IllegalArgumentException::class)
@ -26,20 +26,20 @@ class BootHeaderV3(
if (info[0] != magic) { if (info[0] != magic) {
throw IllegalArgumentException("stream doesn't look like Android Boot Image V3 Header") throw IllegalArgumentException("stream doesn't look like Android Boot Image V3 Header")
} }
this.kernelSize = info[1] as UInt this.kernelSize = (info[1] as UInt).toInt()
this.ramdiskSize = info[2] as UInt this.ramdiskSize = (info[2] as UInt).toInt()
val osNPatch = info[3] as UInt val osNPatch = info[3] as UInt
if (0U != osNPatch) { //treated as 'reserved' in this boot image if (0U != osNPatch) { //treated as 'reserved' in this boot image
this.osVersion = Common.parseOsVersion(osNPatch.toInt() shr 11) this.osVersion = Common.parseOsVersion(osNPatch.toInt() shr 11)
this.osPatchLevel = Common.parseOsPatchLevel((osNPatch and 0x7ff.toUInt()).toInt()) this.osPatchLevel = Common.parseOsPatchLevel((osNPatch and 0x7ff.toUInt()).toInt())
} }
this.headerSize = info[4] as UInt this.headerSize = (info[4] as UInt).toInt()
//5,6,7,8 reserved //5,6,7,8 reserved
this.headerVersion = info[9] as UInt this.headerVersion = (info[9] as UInt).toInt()
this.cmdline = info[10] as String this.cmdline = info[10] as String
assert(this.headerSize.toInt() in intArrayOf(BOOT_IMAGE_HEADER_V3_SIZE)) assert(this.headerSize in intArrayOf(BOOT_IMAGE_HEADER_V3_SIZE))
} }
fun encode(): ByteArray { fun encode(): ByteArray {
@ -70,7 +70,7 @@ class BootHeaderV3(
"I" + //header version "I" + //header version
"1536s" //cmdline "1536s" //cmdline
private const val BOOT_IMAGE_HEADER_V3_SIZE = 1580 private const val BOOT_IMAGE_HEADER_V3_SIZE = 1580
val pageSize: UInt = 4096U const val pageSize: Int = 4096
init { init {
assert(BOOT_IMAGE_HEADER_V3_SIZE == Struct3(FORMAT_STRING).calcSize()) { assert(BOOT_IMAGE_HEADER_V3_SIZE == Struct3(FORMAT_STRING).calcSize()) {

@ -42,13 +42,13 @@ data class BootV3(var info: MiscInfo = MiscInfo(),
ret.info.pageSize = BootHeaderV3.pageSize ret.info.pageSize = BootHeaderV3.pageSize
//kernel //kernel
ret.kernel.file = workDir + "kernel" ret.kernel.file = workDir + "kernel"
ret.kernel.size = header.kernelSize.toInt() ret.kernel.size = header.kernelSize
ret.kernel.position = BootHeaderV3.pageSize.toInt() ret.kernel.position = BootHeaderV3.pageSize
//ramdisk //ramdisk
ret.ramdisk.file = workDir + "ramdisk.img.gz" ret.ramdisk.file = workDir + "ramdisk.img.gz"
ret.ramdisk.size = header.ramdiskSize.toInt() ret.ramdisk.size = header.ramdiskSize
ret.ramdisk.position = ret.kernel.position + header.kernelSize.toInt() + ret.ramdisk.position = ret.kernel.position + header.kernelSize +
getPaddingSize(header.kernelSize, BootHeaderV3.pageSize).toInt() getPaddingSize(header.kernelSize, BootHeaderV3.pageSize)
} }
ret.info.imageSize = File(fileName).length() ret.info.imageSize = File(fileName).length()
return ret return ret
@ -58,9 +58,9 @@ data class BootV3(var info: MiscInfo = MiscInfo(),
data class MiscInfo( data class MiscInfo(
var output: String = "", var output: String = "",
var json: String = "", var json: String = "",
var headerVersion: UInt = 0U, var headerVersion: Int = 0,
var headerSize: UInt = 0U, var headerSize: Int = 0,
var pageSize: UInt = 0U, var pageSize: Int = 0,
var cmdline: String = "", var cmdline: String = "",
var osVersion: String = "", var osVersion: String = "",
var osPatchLevel: String = "", var osPatchLevel: String = "",
@ -97,10 +97,9 @@ data class BootV3(var info: MiscInfo = MiscInfo(),
FileOutputStream(this.info.output + ".clear", false).use { fos -> FileOutputStream(this.info.output + ".clear", false).use { fos ->
val encodedHeader = this.toHeader().encode() val encodedHeader = this.toHeader().encode()
fos.write(encodedHeader) fos.write(encodedHeader)
fos.write(ByteArray(( fos.write(ByteArray(
Helper.round_to_multiple(encodedHeader.size.toUInt(), Helper.round_to_multiple(encodedHeader.size,
this.info.pageSize) - encodedHeader.size.toUInt()).toInt() this.info.pageSize) - encodedHeader.size))
))
} }
//data //data
@ -131,8 +130,8 @@ data class BootV3(var info: MiscInfo = MiscInfo(),
private fun toHeader(): BootHeaderV3 { private fun toHeader(): BootHeaderV3 {
return BootHeaderV3( return BootHeaderV3(
kernelSize = kernel.size.toUInt(), kernelSize = kernel.size,
ramdiskSize = ramdisk.size.toUInt(), ramdiskSize = ramdisk.size,
headerVersion = info.headerVersion, headerVersion = info.headerVersion,
osVersion = info.osVersion, osVersion = info.osVersion,
osPatchLevel = info.osPatchLevel, osPatchLevel = info.osPatchLevel,

@ -23,20 +23,20 @@ data class VendorBoot(var info: MiscInfo = MiscInfo(),
var dtb: CommArgs = CommArgs()) { var dtb: CommArgs = CommArgs()) {
data class CommArgs( data class CommArgs(
var file: String = "", var file: String = "",
var position: UInt = 0U, var position: Long = 0,
var size: UInt = 0U, var size: Int = 0,
var loadAddr: UInt = 0U) var loadAddr: Long = 0)
data class MiscInfo( data class MiscInfo(
var output: String = "", var output: String = "",
var json: String = "", var json: String = "",
var headerVersion: UInt = 0U, var headerVersion: Int = 0,
var product: String = "", var product: String = "",
var headerSize: UInt = 0U, var headerSize: Int = 0,
var pageSize: UInt = 0U, var pageSize: Int = 0,
var cmdline: String = "", var cmdline: String = "",
var tagsLoadAddr: UInt = 0U, var tagsLoadAddr: Long = 0,
var kernelLoadAddr: UInt = 0U, var kernelLoadAddr: Long = 0,
var imageSize: Long = 0 var imageSize: Long = 0
) )
@ -61,12 +61,12 @@ data class VendorBoot(var info: MiscInfo = MiscInfo(),
ret.ramdisk.size = header.vndRamdiskSize ret.ramdisk.size = header.vndRamdiskSize
ret.ramdisk.loadAddr = header.ramdiskLoadAddr ret.ramdisk.loadAddr = header.ramdiskLoadAddr
ret.ramdisk.position = Helper.round_to_multiple( ret.ramdisk.position = Helper.round_to_multiple(
VendorBootHeader.VENDOR_BOOT_IMAGE_HEADER_V3_SIZE, VendorBootHeader.VENDOR_BOOT_IMAGE_HEADER_V3_SIZE.toLong(),
header.pageSize) header.pageSize)
//dtb //dtb
ret.dtb.file = workDir + "dtb" ret.dtb.file = workDir + "dtb"
ret.dtb.size = header.dtbSize ret.dtb.size = header.dtbSize
ret.dtb.loadAddr = header.dtbLoadAddr.toUInt() ret.dtb.loadAddr = header.dtbLoadAddr
ret.dtb.position = ret.ramdisk.position + ret.dtb.position = ret.ramdisk.position +
Helper.round_to_multiple(ret.ramdisk.size, header.pageSize) Helper.round_to_multiple(ret.ramdisk.size, header.pageSize)
} }
@ -89,16 +89,15 @@ data class VendorBoot(var info: MiscInfo = MiscInfo(),
File(this.ramdisk.file.removeSuffix(".gz")).deleleIfExists() File(this.ramdisk.file.removeSuffix(".gz")).deleleIfExists()
C.packRootfs("$workDir/root", this.ramdisk.file, parseOsMajor()) C.packRootfs("$workDir/root", this.ramdisk.file, parseOsMajor())
} }
this.ramdisk.size = File(this.ramdisk.file).length().toUInt() this.ramdisk.size = File(this.ramdisk.file).length().toInt()
this.dtb.size = File(this.dtb.file).length().toUInt() this.dtb.size = File(this.dtb.file).length().toInt()
//header //header
FileOutputStream(this.info.output + ".clear", false).use { fos -> FileOutputStream(this.info.output + ".clear", false).use { fos ->
val encodedHeader = this.toHeader().encode() val encodedHeader = this.toHeader().encode()
fos.write(encodedHeader) fos.write(encodedHeader)
fos.write(ByteArray(( fos.write(ByteArray(
Helper.round_to_multiple(encodedHeader.size.toUInt(), Helper.round_to_multiple(encodedHeader.size,
this.info.pageSize) - encodedHeader.size.toUInt()).toInt() this.info.pageSize) - encodedHeader.size))
))
} }
//data //data
log.info("Writing data ...") log.info("Writing data ...")
@ -138,7 +137,7 @@ data class VendorBoot(var info: MiscInfo = MiscInfo(),
product = info.product, product = info.product,
headerSize = info.headerSize, headerSize = info.headerSize,
dtbSize = dtb.size, dtbSize = dtb.size,
dtbLoadAddr = dtb.loadAddr.toULong() dtbLoadAddr = dtb.loadAddr
) )
} }

@ -6,17 +6,17 @@ import java.io.InputStream
@OptIn(ExperimentalUnsignedTypes::class) @OptIn(ExperimentalUnsignedTypes::class)
class VendorBootHeader( class VendorBootHeader(
var headerVersion: UInt = 0U, var headerVersion: Int = 0,
var pageSize: UInt = 0U, var pageSize: Int = 0,
var kernelLoadAddr: UInt = 0U, var kernelLoadAddr: Long = 0,
var ramdiskLoadAddr: UInt = 0U, var ramdiskLoadAddr: Long = 0,
var vndRamdiskSize: UInt = 0U, var vndRamdiskSize: Int = 0,
var cmdline: String = "", var cmdline: String = "",
var tagsLoadAddr: UInt = 0U, var tagsLoadAddr: Long = 0,
var product: String = "", var product: String = "",
var headerSize: UInt = 0U, var headerSize: Int = 0,
var dtbSize: UInt = 0U, var dtbSize: Int = 0,
var dtbLoadAddr: ULong = 0U var dtbLoadAddr: Long = 0
) { ) {
@Throws(IllegalArgumentException::class) @Throws(IllegalArgumentException::class)
constructor(iS: InputStream?) : this() { constructor(iS: InputStream?) : this() {
@ -29,20 +29,24 @@ class VendorBootHeader(
if (info[0] != magic) { if (info[0] != magic) {
throw IllegalArgumentException("stream doesn't look like Android Vendor Boot Image") throw IllegalArgumentException("stream doesn't look like Android Vendor Boot Image")
} }
this.headerVersion = info[1] as UInt this.headerVersion = (info[1] as UInt).toInt()
this.pageSize = info[2] as UInt this.pageSize = (info[2] as UInt).toInt()
this.kernelLoadAddr = info[3] as UInt this.kernelLoadAddr = (info[3] as UInt).toLong()
this.ramdiskLoadAddr = info[4] as UInt this.ramdiskLoadAddr = (info[4] as UInt).toLong()
this.vndRamdiskSize = info[5] as UInt this.vndRamdiskSize = (info[5] as UInt).toInt()
this.cmdline = info[6] as String this.cmdline = info[6] as String
this.tagsLoadAddr = info[7] as UInt this.tagsLoadAddr = (info[7] as UInt).toLong()
this.product = info[8] as String this.product = info[8] as String
this.headerSize = info[9] as UInt this.headerSize = (info[9] as UInt).toInt()
this.dtbSize = info[10] as UInt this.dtbSize = (info[10] as UInt).toInt()
this.dtbLoadAddr = info[11] as ULong this.dtbLoadAddr = (info[11] as ULong).toLong()
assert(this.headerSize in arrayOf(VENDOR_BOOT_IMAGE_HEADER_V3_SIZE)) if (this.headerSize !in arrayOf(VENDOR_BOOT_IMAGE_HEADER_V3_SIZE)) {
assert(this.headerVersion == 3U) throw IllegalArgumentException("header size " + this.headerSize + " invalid")
}
if (this.headerVersion != 3) {
throw IllegalArgumentException("header version " + this.headerVersion + " invalid")
}
} }
fun encode(): ByteArray { fun encode(): ByteArray {
@ -64,7 +68,7 @@ class VendorBootHeader(
companion object { companion object {
private val log = LoggerFactory.getLogger(VendorBootHeader::class.java) private val log = LoggerFactory.getLogger(VendorBootHeader::class.java)
const val magic = "VNDRBOOT" const val magic = "VNDRBOOT"
const val VENDOR_BOOT_IMAGE_HEADER_V3_SIZE = 2112U const val VENDOR_BOOT_IMAGE_HEADER_V3_SIZE = 2112
const val FORMAT_STRING = "8s" + //magic const val FORMAT_STRING = "8s" + //magic
"I" + //header version "I" + //header version
"I" + //page size "I" + //page size
@ -78,7 +82,7 @@ class VendorBootHeader(
"I" + //dtb size "I" + //dtb size
"Q" //dtb physical load addr "Q" //dtb physical load addr
init { init {
assert(Struct3(FORMAT_STRING).calcSize().toUInt() == VENDOR_BOOT_IMAGE_HEADER_V3_SIZE) assert(Struct3(FORMAT_STRING).calcSize() == VENDOR_BOOT_IMAGE_HEADER_V3_SIZE)
} }
} }

@ -0,0 +1,23 @@
package cfig.bootloader_message
class BootControl {
data class SlotMetadata(//size: 16
var priority: Int = 0,
var triesRemaining: Int = 0,
var successfulBoot: Boolean = false,
var verityCorrupted: Boolean = false,
var reserved: ByteArray = byteArrayOf()
)
class BootloaderControl(
var slotSuffix: String = "",
var magic: ByteArray = byteArrayOf(),
var version: Int = 0,
var slots: Int = 0,
var recoveryTriesRemaining: Int = 0,
var mergeStatus: Int = 0,
var slotMetaData: ByteArray= byteArrayOf(),
var reserved: ByteArray = byteArrayOf(),
var crc32: Int = 0
)
}

@ -8,7 +8,7 @@ import java.io.FileOutputStream
import java.lang.IllegalStateException import java.lang.IllegalStateException
@OptIn(ExperimentalUnsignedTypes::class) @OptIn(ExperimentalUnsignedTypes::class)
data class BootloaderMsg( data class BootloaderMsg(//offset 0, size 2k
var command: String = "", var command: String = "",
var status: String = "", var status: String = "",
var recovery: String = "", var recovery: String = "",

@ -0,0 +1,36 @@
package cfig.bootloader_message
import cfig.io.Struct3
import org.slf4j.LoggerFactory
import java.io.FileInputStream
@OptIn(ExperimentalUnsignedTypes::class)
class BootloaderMsgAB( //offset 2k, size 2k
var slotSuffix: String = "",
var updateChannel: String = "",
var reserved: ByteArray = byteArrayOf()
) {
companion object {
private const val FORMAT_STRING = "32s128s1888b"
const val SIZE = 2048
private val log = LoggerFactory.getLogger(BootloaderMsgAB::class.java.simpleName)
init {
assert(SIZE == Struct3(FORMAT_STRING).calcSize())
}
}
constructor(fis: FileInputStream) : this() {
val info = Struct3(FORMAT_STRING).unpack(fis)
this.slotSuffix = info[0] as String
this.updateChannel = info[1] as String
this.reserved = info[2] as ByteArray
}
fun encode(): ByteArray {
return Struct3(FORMAT_STRING).pack(
this.slotSuffix,
this.updateChannel,
byteArrayOf())
}
}

@ -0,0 +1,42 @@
package cfig.bootloader_message
import cfig.io.Struct3
import org.slf4j.LoggerFactory
import java.io.FileInputStream
@OptIn(ExperimentalUnsignedTypes::class)
data class VirtualABMsg(
var version: Int = 0,
var magic: ByteArray = byteArrayOf(),
var mergeStatus: Int = 0,
var sourceSlot: Int = 0,
var reserved: ByteArray = byteArrayOf()
) {
companion object {
private const val FORMAT_STRING = "b4bbb57b"
const val SIZE = 64
private val log = LoggerFactory.getLogger("VirtualABMsg")
init {
assert(SIZE == Struct3(FORMAT_STRING).calcSize())
}
}
constructor(fis: FileInputStream) : this() {
val info = Struct3(FORMAT_STRING).unpack(fis)
this.version = info[0] as Int
this.magic = info[1] as ByteArray
this.mergeStatus = info[2] as Int
this.sourceSlot = info[3] as Int
this.reserved = info[4] as ByteArray
}
fun encode(): ByteArray {
return Struct3(FORMAT_STRING).pack(
this.version,
this.magic,
this.mergeStatus,
this.sourceSlot,
0)
}
}
Loading…
Cancel
Save