From f716e34d6d54312be63255786243433cf469cc74 Mon Sep 17 00:00:00 2001 From: cfig Date: Wed, 6 Apr 2022 00:31:22 +0800 Subject: [PATCH] Issue #84: support misc.img Actions: unpack pack pull flash Signed-off-by: cfig --- bbootimg/build.gradle.kts | 6 +- bbootimg/src/main/kotlin/bcb/BootloaderMsg.kt | 135 ---------- .../src/main/kotlin/bcb/BootloaderMsgAB.kt | 49 ---- bbootimg/src/main/kotlin/bcb/VirtualABMsg.kt | 74 ------ bbootimg/src/main/kotlin/init/Reboot.kt | 19 +- .../kotlin/{bcb => miscimg}/BootControl.kt | 0 bbootimg/src/main/kotlin/miscimg/MiscImage.kt | 231 ++++++++++++++++++ .../src/main/kotlin/packable/IPackable.kt | 4 +- .../src/main/kotlin/packable/MiscImgParser.kt | 87 +++++++ .../main/kotlin/packable/PackableLauncher.kt | 25 +- .../src/test/kotlin/bcb/BootloaderMsgTest.kt | 94 ------- .../src/test/kotlin/bcb/VirtualABMsgTest.kt | 46 ---- bbootimg/src/test/kotlin/init/RebootTest.kt | 17 +- helper/build.gradle.kts | 6 +- integrationTest.py | 2 + 15 files changed, 359 insertions(+), 436 deletions(-) delete mode 100644 bbootimg/src/main/kotlin/bcb/BootloaderMsg.kt delete mode 100644 bbootimg/src/main/kotlin/bcb/BootloaderMsgAB.kt delete mode 100644 bbootimg/src/main/kotlin/bcb/VirtualABMsg.kt rename bbootimg/src/main/kotlin/{bcb => miscimg}/BootControl.kt (100%) create mode 100644 bbootimg/src/main/kotlin/miscimg/MiscImage.kt create mode 100644 bbootimg/src/main/kotlin/packable/MiscImgParser.kt delete mode 100644 bbootimg/src/test/kotlin/bcb/BootloaderMsgTest.kt delete mode 100644 bbootimg/src/test/kotlin/bcb/VirtualABMsgTest.kt diff --git a/bbootimg/build.gradle.kts b/bbootimg/build.gradle.kts index 06edb44..7e0caa5 100644 --- a/bbootimg/build.gradle.kts +++ b/bbootimg/build.gradle.kts @@ -15,7 +15,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { - kotlin("jvm") version "1.6.10" + kotlin("jvm") version "1.6.20" application } @@ -59,8 +59,8 @@ application { tasks.withType().all { kotlinOptions { - freeCompilerArgs += "-Xopt-in=kotlin.RequiresOptIn" - freeCompilerArgs += "-Xopt-in=kotlin.ExperimentalUnsignedTypes" + freeCompilerArgs += "-opt-in=kotlin.RequiresOptIn" + freeCompilerArgs += "-opt-in=kotlin.ExperimentalUnsignedTypes" jvmTarget = "11" } } diff --git a/bbootimg/src/main/kotlin/bcb/BootloaderMsg.kt b/bbootimg/src/main/kotlin/bcb/BootloaderMsg.kt deleted file mode 100644 index 4b8d486..0000000 --- a/bbootimg/src/main/kotlin/bcb/BootloaderMsg.kt +++ /dev/null @@ -1,135 +0,0 @@ -// Copyright 2021 yuyezhong@gmail.com -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package cfig.bcb - -import cc.cfig.io.Struct -import org.slf4j.LoggerFactory -import java.io.File -import java.io.FileInputStream -import java.io.FileOutputStream -import java.lang.IllegalStateException - -data class BootloaderMsg(//offset 0, size 2k - var command: String = "", - var status: String = "", - var recovery: String = "", - var stage: String = "", - var reserved: ByteArray = byteArrayOf() -) { - companion object { - private const val FORMAT_STRING = "32s32s768s32s1184b" - const val miscFile = "misc.file" - const val SIZE = 2048 - private val log = LoggerFactory.getLogger("BootloaderMsg") - - init { - assert(SIZE == Struct(FORMAT_STRING).calcSize()) - } - } - - constructor(fis: FileInputStream) : this() { - val info = Struct(FORMAT_STRING).unpack(fis) - this.command = info[0] as String - this.status = info[1] as String - this.recovery = info[2] as String - this.stage = info[3] as String - this.reserved = info[4] as ByteArray - } - - fun encode(): ByteArray { - return Struct(FORMAT_STRING).pack( - this.command, - this.stage, - this.recovery, - this.stage, - byteArrayOf()) - } - - fun clearBootloaderMessage() { - val boot = BootloaderMsg() - boot.writeBootloaderMessage() - } - - fun writeBootloaderMessage(options: Array) { - this.updateBootloaderMessageInStruct(options) - this.writeBootloaderMessage() - } - - fun readBootloaderMsg() { - if (File(miscFile).exists()) { - log.info("readBootloaderMsg() from $miscFile") - val fis = FileInputStream(miscFile) - val info = Struct(FORMAT_STRING).unpack(fis) - this.command = info[0] as String - this.status = info[1] as String - this.recovery = info[2] as String - this.stage = info[3] as String - this.reserved = info[4] as ByteArray - fis.close() - } else { - log.info("$miscFile missing") - } - } - - fun writeRebootBootloader() { - if (this.command.isNotBlank()) { - throw IllegalStateException("Bootloader command pending.") - } - this.command = "bootonce-bootloader" - writeBootloaderMessage() - } - - fun writeBootloaderMessage() { - log.info("writing ... $this") - if (!File(miscFile).exists()) { - File(miscFile).createNewFile() - } - FileOutputStream(miscFile, false).use { fos -> - fos.write(this.encode()) - } - } - - fun updateBootloaderMessageInStruct(options: Array) { - this.command = "boot-recovery" - this.recovery = "recovery\n" - options.forEach { - this.recovery += if (it.endsWith("\n")) { - it - } else { - it + "\n" - } - } - } - - fun updateBootloaderMessage(command: String, recovery: String, options: Array?) { - this.command = command - this.recovery = "$recovery\n" - options?.forEach { - this.recovery += if (it.endsWith("\n")) { - it - } else { - it + "\n" - } - } - } - - /* - https://android-review.googlesource.com/c/platform/bootable/recovery/+/735984 - */ - fun updateBootFastboot() { - this.command = "boot-fastboot" - this.recovery = "" - } -} diff --git a/bbootimg/src/main/kotlin/bcb/BootloaderMsgAB.kt b/bbootimg/src/main/kotlin/bcb/BootloaderMsgAB.kt deleted file mode 100644 index 6a8f742..0000000 --- a/bbootimg/src/main/kotlin/bcb/BootloaderMsgAB.kt +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2021 yuyezhong@gmail.com -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package cfig.bcb - -import cc.cfig.io.Struct -import org.slf4j.LoggerFactory -import java.io.FileInputStream - -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 == Struct(FORMAT_STRING).calcSize()) - } - } - - constructor(fis: FileInputStream) : this() { - val info = Struct(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 Struct(FORMAT_STRING).pack( - this.slotSuffix, - this.updateChannel, - byteArrayOf()) - } -} diff --git a/bbootimg/src/main/kotlin/bcb/VirtualABMsg.kt b/bbootimg/src/main/kotlin/bcb/VirtualABMsg.kt deleted file mode 100644 index 8dc51cc..0000000 --- a/bbootimg/src/main/kotlin/bcb/VirtualABMsg.kt +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2021 yuyezhong@gmail.com -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package cfig.bcb - -import cc.cfig.io.Struct -import cfig.helper.Helper -import org.slf4j.LoggerFactory -import java.io.FileInputStream - -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") - private const val MAGIC = "b00a7456" - - init { - assert(SIZE == Struct(FORMAT_STRING).calcSize()) - } - } - - constructor(fis: FileInputStream) : this() { - val info = Struct(FORMAT_STRING).unpack(fis) - this.version = (info[0] as ByteArray)[0].toInt() - this.magic = info[1] as ByteArray - this.mergeStatus = (info[2] as ByteArray)[0].toInt() - this.sourceSlot = (info[3] as ByteArray)[0].toInt() - this.reserved = info[4] as ByteArray - if (MAGIC != Helper.Companion.toHexString(this.magic)) { - throw IllegalArgumentException("stream is not VirtualAB message") - } - } - - fun encode(): ByteArray { - return Struct(FORMAT_STRING).pack( - this.version, - this.magic, - this.mergeStatus, - this.sourceSlot, - 0 - ) - } - - override fun toString(): String { - return "VABMsg(v=$version, magic=${Helper.toHexString(magic)}, mergeStatus=$mergeStatus:${MergeStatus.values().get(this.mergeStatus)}, sourceSlot=$sourceSlot)" - } - - - enum class MergeStatus(val status: Int) { - NONE(0), - UNKNOWN(1), - SNAPSHOTTED(2), - MERGING(3), - CANCELLED(4) - } -} diff --git a/bbootimg/src/main/kotlin/init/Reboot.kt b/bbootimg/src/main/kotlin/init/Reboot.kt index 3cda74c..bf0d5fa 100644 --- a/bbootimg/src/main/kotlin/init/Reboot.kt +++ b/bbootimg/src/main/kotlin/init/Reboot.kt @@ -14,7 +14,7 @@ package cfig.init -import cfig.bcb.BootloaderMsg +import miscimg.MiscImage import org.slf4j.LoggerFactory import java.util.* @@ -87,23 +87,28 @@ class Reboot { } when (rebootTarget) { "fastboot" -> { + val bcb: MiscImage.BootloaderMessage if (bDynamicPartition == null || bDynamicPartition == false) { log.warn("$dynamicPartitionKey=false, using 'bootloader fastboot' instead of 'fastbootd'") rebootTarget = "bootloader" - BootloaderMsg().writeRebootBootloader() + bcb = MiscImage.BootloaderMessage.rebootBootloader() + log.info(bcb.toString()) } else { log.info("$dynamicPartitionKey=true, using fastbootd") - BootloaderMsg().writeBootloaderMessage(arrayOf("--fastboot")) + bcb = MiscImage.BootloaderMessage.rebootFastboot2() rebootTarget = "recovery" } + log.info(bcb.toString()) } "bootloader" -> { - BootloaderMsg().writeRebootBootloader() + val bcb = MiscImage.BootloaderMessage.rebootBootloader() + log.info(bcb.toString()) } "sideload", "sideload-auto-reboot" -> { - BootloaderMsg().writeBootloaderMessage( - arrayOf("--" + rebootTarget.replace("-", "_")) - ) + val bcb = MiscImage.BootloaderMessage().apply { + updateBootloaderMessageInStruct(arrayOf("--" + rebootTarget.replace("-", "_"))) + } + log.info(bcb.toString()) rebootTarget = "recovery" } else -> { diff --git a/bbootimg/src/main/kotlin/bcb/BootControl.kt b/bbootimg/src/main/kotlin/miscimg/BootControl.kt similarity index 100% rename from bbootimg/src/main/kotlin/bcb/BootControl.kt rename to bbootimg/src/main/kotlin/miscimg/BootControl.kt diff --git a/bbootimg/src/main/kotlin/miscimg/MiscImage.kt b/bbootimg/src/main/kotlin/miscimg/MiscImage.kt new file mode 100644 index 0000000..4931906 --- /dev/null +++ b/bbootimg/src/main/kotlin/miscimg/MiscImage.kt @@ -0,0 +1,231 @@ +package miscimg + +import cc.cfig.io.Struct +import cfig.helper.Helper +import com.fasterxml.jackson.databind.ObjectMapper +import org.slf4j.LoggerFactory +import java.io.FileInputStream + +data class MiscImage( + var bcb: BootloaderMessage = BootloaderMessage(), + var virtualAB: VirtualABMessage? = null +) { + companion object { + private val log = LoggerFactory.getLogger(MiscImage::class.java) + private val mapper = ObjectMapper() + private val workDir = Helper.prop("workDir") + + fun parse(fileName: String): MiscImage { + val ret = MiscImage() + FileInputStream(fileName).use { fis -> + ret.bcb = BootloaderMessage(fis) + } + FileInputStream(fileName).use { fis -> + fis.skip(32 * 1024) + try { + ret.virtualAB = VirtualABMessage(fis) + } catch (e: IllegalArgumentException) { + log.info(e.toString()) + } + } + return ret + } + } + + //offset 0, size 2k + data class BootloaderMessage( + var command: String = "", + var status: String = "", + var recovery: String = "", + var stage: String = "", + var reserved: ByteArray = byteArrayOf() + ) { + constructor(fis: FileInputStream) : this() { + val info = Struct(FORMAT_STRING).unpack(fis) + this.command = info[0] as String + this.status = info[1] as String + this.recovery = info[2] as String + this.stage = info[3] as String + //this.reserved = info[4] as ByteArray + } + + fun encode(): ByteArray { + return Struct(FORMAT_STRING).pack( + this.command, + this.stage, + this.recovery, + this.stage, + byteArrayOf() + ) + } + + fun updateBootloaderMessageInStruct(options: Array) { + this.command = "boot-recovery" + this.recovery = "recovery\n" + options.forEach { + this.recovery += if (it.endsWith("\n")) { + it + } else { + it + "\n" + } + } + } + + fun updateBootloaderMessage(command: String, recovery: String, options: Array?) { + this.command = command + this.recovery = "$recovery\n" + options?.forEach { + this.recovery += if (it.endsWith("\n")) { + it + } else { + it + "\n" + } + } + } + + companion object { + private const val FORMAT_STRING = "32s32s768s32s1184b" + private val log = LoggerFactory.getLogger(BootloaderMessage::class.java) + const val SIZE = 2048 + + init { + assert(SIZE == Struct(FORMAT_STRING).calcSize()) + } + + /* + https://android-review.googlesource.com/c/platform/bootable/recovery/+/735984 + */ + fun rebootFastboot1(): BootloaderMessage { + return BootloaderMessage().apply { + command = "boot-fastboot" + } + } + + fun rebootFastboot2(): BootloaderMessage { + return BootloaderMessage().apply { + updateBootloaderMessageInStruct(arrayOf("--fastboot")) + } + } + + fun rebootBootloader(): BootloaderMessage { + return BootloaderMessage().apply { + command = "bootonce-bootloader" + } + } + + fun rebootRecovery(): BootloaderMessage { + return BootloaderMessage().apply { + this.updateBootloaderMessageInStruct(arrayOf()) + } + } + + fun rebootCrash(): BootloaderMessage { + return BootloaderMessage().apply { + //@formatter:off + updateBootloaderMessageInStruct(arrayOf( + "--prompt_and_wipe_data", + "--reason=RescueParty", + "--locale=en_US")) + //@formatter:on + } + } + + fun rebootOTA(): BootloaderMessage { + return BootloaderMessage().apply { + updateBootloaderMessageInStruct(arrayOf("--update_package=/cache/update.zip", "--security")) + } + } + + fun rebootWipeData(): BootloaderMessage { + return BootloaderMessage().apply { + //@formatter:off + updateBootloaderMessageInStruct(arrayOf( + "--wipe_data", + "--reason=convert_fbe", + "--locale=en_US")) + //@formatter:on + } + } + + fun rebootWipeAb(): BootloaderMessage { + return BootloaderMessage().apply { + //@formatter:off + updateBootloaderMessageInStruct(arrayOf( + "--wipe_ab", + "--wipe_package_size=1024", + "--locale=en_US")) + //@formatter:on + } + } + + fun generateSamples(): MutableList { + return mutableListOf( + rebootFastboot1(), + rebootFastboot2(), + rebootBootloader(), + rebootRecovery(), + rebootCrash(), + rebootOTA(), + rebootWipeData(), + rebootWipeAb() + ) + } + } + } + + //offset 32KB, size 64B + data class VirtualABMessage( + 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" + private val log = LoggerFactory.getLogger("VirtualABMsg") + private const val MAGIC = "b00a7456" + const val SIZE = 64 + + init { + assert(SIZE == Struct(FORMAT_STRING).calcSize()) + } + } + + constructor(fis: FileInputStream) : this() { + val info = Struct(FORMAT_STRING).unpack(fis) + this.version = (info[0] as ByteArray)[0].toInt() + this.magic = info[1] as ByteArray + this.mergeStatus = (info[2] as ByteArray)[0].toInt() + this.sourceSlot = (info[3] as ByteArray)[0].toInt() + this.reserved = info[4] as ByteArray + if (MAGIC != Helper.Companion.toHexString(this.magic)) { + throw IllegalArgumentException("stream is not VirtualAB message") + } + } + + fun encode(): ByteArray { + return Struct(FORMAT_STRING).pack( + byteArrayOf(this.version.toByte()), + this.magic, + byteArrayOf(this.mergeStatus.toByte()), + byteArrayOf(this.sourceSlot.toByte()), + byteArrayOf(0) + ) + } + + override fun toString(): String { + return "VABMsg(v=$version, magic=${Helper.toHexString(magic)}, mergeStatus=$mergeStatus:${ + MergeStatus.values().get(this.mergeStatus) + }, sourceSlot=$sourceSlot)" + } + + enum class MergeStatus(val status: Int) { + NONE(0), + UNKNOWN(1), + SNAPSHOTTED(2), + MERGING(3), + CANCELLED(4) + } + } +} diff --git a/bbootimg/src/main/kotlin/packable/IPackable.kt b/bbootimg/src/main/kotlin/packable/IPackable.kt index 213c92b..b03976b 100644 --- a/bbootimg/src/main/kotlin/packable/IPackable.kt +++ b/bbootimg/src/main/kotlin/packable/IPackable.kt @@ -38,7 +38,7 @@ interface IPackable { "adb root".check_call() val abUpdateProp = "adb shell getprop ro.build.ab_update".check_output() log.info("ro.build.ab_update=$abUpdateProp") - val slotSuffix = if (abUpdateProp == "true") { + val slotSuffix = if (abUpdateProp == "true" && !fileName.startsWith("misc.img")) { "adb shell getprop ro.boot.slot_suffix".check_output() } else { "" @@ -53,7 +53,7 @@ interface IPackable { "adb root".check_call() val abUpdateProp = "adb shell getprop ro.build.ab_update".check_output() log.info("ro.build.ab_update=$abUpdateProp") - val slotSuffix = if (abUpdateProp == "true") { + val slotSuffix = if (abUpdateProp == "true" && !fileName.startsWith("misc.img")) { "adb shell getprop ro.boot.slot_suffix".check_output() } else { "" diff --git a/bbootimg/src/main/kotlin/packable/MiscImgParser.kt b/bbootimg/src/main/kotlin/packable/MiscImgParser.kt new file mode 100644 index 0000000..9c38208 --- /dev/null +++ b/bbootimg/src/main/kotlin/packable/MiscImgParser.kt @@ -0,0 +1,87 @@ +// Copyright 2022 yuyezhong@gmail.com +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package cfig.packable + +import cc.cfig.io.Struct +import miscimg.MiscImage +import cfig.helper.Helper.Companion.deleteIfExists +import com.fasterxml.jackson.databind.ObjectMapper +import org.slf4j.LoggerFactory +import java.io.File +import java.io.FileOutputStream +import java.io.RandomAccessFile + +class MiscImgParser : IPackable { + override val loopNo: Int + get() = 0 + + override fun capabilities(): List { + return listOf("^misc\\.img$") + } + + override fun unpack(fileName: String) { + cleanUp() + val misc = MiscImage.parse(fileName) + log.info(misc.toString()) + ObjectMapper().writerWithDefaultPrettyPrinter() + .writeValue(File(File(fileName).name.removeSuffix(".img") + ".json"), misc) + ObjectMapper().writerWithDefaultPrettyPrinter().writeValue( + File("sample.json"), + MiscImage.BootloaderMessage.generateSamples() + ) + } + + override fun pack(fileName: String) { + val misc = ObjectMapper().readValue( + File(File(fileName).name.removeSuffix(".img") + ".json"), + MiscImage::class.java + ) + val out = File("$fileName.new") + File(fileName).copyTo(out, true) + RandomAccessFile(out.name, "rw").use { raf -> + raf.write(misc.bcb.encode()) + raf.seek(32 * 1024) + if (misc.virtualAB != null) { + raf.write(misc.virtualAB!!.encode()) + } + } + log.info("${out.name} is ready") + } + + override fun flash(fileName: String, deviceName: String) { + val stem = fileName.substring(0, fileName.indexOf(".")) + super.flash("$fileName.new", stem) + } + + override fun `@verify`(fileName: String) { + super.`@verify`(fileName) + } + + override fun pull(fileName: String, deviceName: String) { + super.pull(fileName, deviceName) + } + + fun clean(fileName: String) { + super.cleanUp() + listOf("", ".clear", ".google", ".clear", ".signed", ".signed2").forEach { + "$fileName$it".deleteIfExists() + } + VBMetaParser().clean("vbmeta.img") + } + + companion object { + private val log = LoggerFactory.getLogger(MiscImgParser::class.java) + } +} diff --git a/bbootimg/src/main/kotlin/packable/PackableLauncher.kt b/bbootimg/src/main/kotlin/packable/PackableLauncher.kt index ee667fe..8df350b 100644 --- a/bbootimg/src/main/kotlin/packable/PackableLauncher.kt +++ b/bbootimg/src/main/kotlin/packable/PackableLauncher.kt @@ -28,7 +28,10 @@ class PackableLauncher fun main(args: Array) { val log = LoggerFactory.getLogger(PackableLauncher::class.java) val packablePool = mutableMapOf, KClass>() - listOf(DtboParser(), VBMetaParser(), BootImgParser(), SparseImgParser(), VendorBootParser(), PayloadBinParser()).forEach { + listOf( + DtboParser(), VBMetaParser(), BootImgParser(), SparseImgParser(), VendorBootParser(), PayloadBinParser(), + MiscImgParser() + ).forEach { @Suppress("UNCHECKED_CAST") packablePool.put(it.capabilities(), it::class as KClass) } @@ -41,17 +44,17 @@ fun main(args: Array) { for (currentLoopNo in 0..1) { //currently we have only 2 loops File(".").listFiles()!!.forEach { file -> packablePool - .filter { it.value.createInstance().loopNo == currentLoopNo } - .forEach { p -> - for (item in p.key) { - if (Pattern.compile(item).matcher(file.name).matches()) { - log.debug("Found: " + file.name + ", " + item) - targetFile = file.name - targetHandler = p.value - return@found - } + .filter { it.value.createInstance().loopNo == currentLoopNo } + .forEach { p -> + for (item in p.key) { + if (Pattern.compile(item).matcher(file.name).matches()) { + log.debug("Found: " + file.name + ", " + item) + targetFile = file.name + targetHandler = p.value + return@found } } + } }//end-of-file-traversing }//end-of-range-loop }//end-of-found@ @@ -105,7 +108,7 @@ fun main(args: Array) { functions[0].call(it.createInstance(), targetFile!!) } 3 -> { - if (args.size != 2 ) { + if (args.size != 2) { log.info("invoke: ${it.qualifiedName}, $targetFile, " + targetFile!!.removeSuffix(".img")) functions[0].call(it.createInstance(), targetFile!!, targetFile!!.removeSuffix(".img")) } else { diff --git a/bbootimg/src/test/kotlin/bcb/BootloaderMsgTest.kt b/bbootimg/src/test/kotlin/bcb/BootloaderMsgTest.kt deleted file mode 100644 index 4940bc2..0000000 --- a/bbootimg/src/test/kotlin/bcb/BootloaderMsgTest.kt +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2021 yuyezhong@gmail.com -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package bcb - -import cfig.bcb.BootloaderMsg -import cfig.bootimg.Common.Companion.deleleIfExists -import org.junit.After -import org.junit.Test -import org.slf4j.LoggerFactory -import java.io.File - -class BootloaderMsgTest { - private val log = LoggerFactory.getLogger(BootloaderMsgTest::class.java) - - @After - fun tearDown() { - File(BootloaderMsg.miscFile).deleleIfExists() - } - - @Test - fun writeRebootBootloaderTest() { - val msg = BootloaderMsg() - msg.clearBootloaderMessage() - } - - @Test - fun readBootloaderMsgTest() { - val msg = BootloaderMsg() - msg.readBootloaderMsg() - log.info(msg.toString()) - } - - @Test - fun writeOptions() { - val msg = BootloaderMsg() - msg.updateBootloaderMessageInStruct(arrayOf( - "--prompt_and_wipe_data", - "--locale=zh_CN")) - msg.writeBootloaderMessage() - } - - - @Test - fun rebootRecovery() { - val msg = BootloaderMsg() - msg.updateBootloaderMessageInStruct(arrayOf()) - msg.writeBootloaderMessage() - } - - @Test - fun rebootCrash() { - val msg = BootloaderMsg() - msg.writeBootloaderMessage(arrayOf( - "--prompt_and_wipe_data", - "--reason=RescueParty", - "--locale=en_US")) - } - - @Test - fun rebootOTA() { - val msg = BootloaderMsg() - msg.writeBootloaderMessage(arrayOf("--update_package=/cache/update.zip", "--security")) - } - - @Test - fun rebootWipeAb() { - val msg = BootloaderMsg() - msg.writeBootloaderMessage(arrayOf( - "--wipe_ab", - "--wipe_package_size=1024", - "--locale=en_US")) - } - - @Test - fun rebootWipeData() { - val msg = BootloaderMsg() - msg.writeBootloaderMessage(arrayOf( - "--wipe_data", - "--reason=convert_fbe", - "--locale=en_US")) - } -} diff --git a/bbootimg/src/test/kotlin/bcb/VirtualABMsgTest.kt b/bbootimg/src/test/kotlin/bcb/VirtualABMsgTest.kt deleted file mode 100644 index 80b1d8b..0000000 --- a/bbootimg/src/test/kotlin/bcb/VirtualABMsgTest.kt +++ /dev/null @@ -1,46 +0,0 @@ -package bcb - -import cfig.bcb.VirtualABMsg -import cfig.bootimg.Common.Companion.deleleIfExists -import cfig.helper.Helper -import cfig.helper.Helper.Companion.check_call -import org.apache.commons.exec.CommandLine -import org.junit.* - -import org.slf4j.LoggerFactory -import java.io.File -import java.io.FileInputStream -import java.io.IOException - -class VirtualABMsgTest { - private val log = LoggerFactory.getLogger(VirtualABMsgTest::class.java) - - @Before - fun setUp() { - Assume.assumeTrue( - try { - "adb --version".check_call() - true - } catch (e: IOException) { - false - } - ) - Assume.assumeTrue(Helper.powerRun3(CommandLine.parse("adb root"), null)[0] as Boolean) - "adb wait-for-device".check_call() - "adb shell dd if=/dev/block/by-name/misc of=/data/vendor/debug.misc skip=512 bs=64 count=1".check_call() - "adb pull /data/vendor/debug.misc".check_call() - } - - @Test - fun parseVAB() { - FileInputStream("debug.misc").use { - val vab = VirtualABMsg(it) - log.info("VAB msg: $vab") - } - } - - @After - fun tearDown() { - File("debug.misc").deleleIfExists() - } -} \ No newline at end of file diff --git a/bbootimg/src/test/kotlin/init/RebootTest.kt b/bbootimg/src/test/kotlin/init/RebootTest.kt index c48c3d4..3399b94 100644 --- a/bbootimg/src/test/kotlin/init/RebootTest.kt +++ b/bbootimg/src/test/kotlin/init/RebootTest.kt @@ -14,13 +14,11 @@ package init -import cfig.bcb.BootloaderMsg +import miscimg.MiscImage import org.junit.Test import org.junit.After -import java.io.File import java.util.* import cfig.init.Reboot -import cfig.bootimg.Common.Companion.deleleIfExists import org.slf4j.LoggerFactory class RebootTest { @@ -28,7 +26,6 @@ class RebootTest { @After fun tearDown() { - File(BootloaderMsg.miscFile).deleleIfExists() } @Test @@ -86,10 +83,8 @@ class RebootTest { put(Reboot.dynamicPartitionKey, "true") }) log.info("fastbootd test 2") - BootloaderMsg().let { - it.updateBootloaderMessage("boot-fastboot", "recovery", null) - it.writeBootloaderMessage() - } + val bcb = MiscImage.BootloaderMessage(command = "boot-fastboot", recovery = "recovery") + log.info(bcb.toString()) log.info("fastbootd test 3: not supported, change to bootloader") Reboot.handlePowerctlMessage("reboot,fastboot", Properties()) } @@ -103,10 +98,8 @@ class RebootTest { @Test fun recovery_rescue() { log.info("recovery test 1: rescue") - BootloaderMsg().let { - it.updateBootloaderMessage("boot-rescue", "recovery", null) - it.writeBootloaderMessage() - } + val bcb = MiscImage.BootloaderMessage(command = "boot-rescue", recovery = "recovery") + log.info(bcb.toString()) log.info("recovery test 2: rescue") Reboot.handlePowerctlMessage("reboot,rescue") } diff --git a/helper/build.gradle.kts b/helper/build.gradle.kts index b928bf0..d953c19 100644 --- a/helper/build.gradle.kts +++ b/helper/build.gradle.kts @@ -15,7 +15,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { - id("org.jetbrains.kotlin.jvm") version "1.6.10" + id("org.jetbrains.kotlin.jvm") version "1.6.20" `java-library` application } @@ -52,8 +52,8 @@ dependencies { tasks.withType().all { kotlinOptions { - freeCompilerArgs += "-Xopt-in=kotlin.RequiresOptIn" - freeCompilerArgs += "-Xopt-in=kotlin.ExperimentalUnsignedTypes" + freeCompilerArgs += "-opt-in=kotlin.RequiresOptIn" + freeCompilerArgs += "-opt-in=kotlin.ExperimentalUnsignedTypes" jvmTarget = "11" } } diff --git a/integrationTest.py b/integrationTest.py index ac6becf..84f6774 100755 --- a/integrationTest.py +++ b/integrationTest.py @@ -42,6 +42,8 @@ def cleanUp(): "boot.img", "boot.img.clear", "boot.img.google", "boot.img.signed", "boot.img.signed2", "recovery.img", "recovery.img.clear", "recovery.img.google", "recovery.img.signed", "recovery.img.signed2", "vbmeta.img", "vbmeta.img.signed", + "dtbo.img", "dtbo.img.clear", "dtbo.img.signed", "dtbo.img.signed2", + "misc.img", "misc.img.new", "payload.bin", "init_boot.img", "init_boot.img.signed", "vendor_boot.img", "vendor_boot.img.clear", "vendor_boot.img.google", "vendor_boot.img.signed", "vendor_boot.img.signed2",