From 71a7d2a07ff59d1e4ab917f39a411adda076326f Mon Sep 17 00:00:00 2001 From: cfig Date: Tue, 14 May 2024 18:06:49 +0800 Subject: [PATCH] update BootV3 for abe --- bbootimg/src/main/kotlin/avb/Avb.kt | 12 +++- bbootimg/src/main/kotlin/bootimg/Common.kt | 50 +++++++++++++- bbootimg/src/main/kotlin/bootimg/v3/BootV3.kt | 65 +++++++++++++------ .../src/main/kotlin/packable/BootImgParser.kt | 11 ++-- .../main/kotlin/packable/PackableLauncher.kt | 8 +-- doc/feature_list.md | 9 +++ tools/abe | 44 +++++++++++++ 7 files changed, 162 insertions(+), 37 deletions(-) create mode 100755 tools/abe diff --git a/bbootimg/src/main/kotlin/avb/Avb.kt b/bbootimg/src/main/kotlin/avb/Avb.kt index 5964ef8..a8e01a1 100644 --- a/bbootimg/src/main/kotlin/avb/Avb.kt +++ b/bbootimg/src/main/kotlin/avb/Avb.kt @@ -174,7 +174,6 @@ class Avb { fun getJsonFileName(image_file: String): String { val jsonFile = File(image_file).name.removeSuffix(".img") + ".avb.json" - log.warn("XXXX: json file = " + Helper.joinPath(Helper.prop("workDir")!!, jsonFile)) return Helper.joinPath(Helper.prop("workDir")!!, jsonFile) } @@ -201,10 +200,17 @@ class Avb { } fun updateVbmeta(fileName: String, desc: Any = HashDescriptor::class) { - if (File("vbmeta.img").exists()) { + val vbmetaCompanion = getJsonFileName("vbmeta.img") + if (File(vbmetaCompanion).exists()) { log.info("Updating vbmeta.img side by side ...") val readBackInfo = ObjectMapper().readValue(File(getJsonFileName(fileName)), AVBInfo::class.java) - val newHashDesc = AVBInfo.parseFrom(Dumpling("$fileName.signed")) + val intermediateDir = Helper.joinPath(Helper.prop("workDir")!!, "intermediate") + val newHashDesc = if (File(intermediateDir).exists()) { + AVBInfo.parseFrom(Dumpling(Helper.joinPath(intermediateDir, "$fileName.signed"))) + } else { + //FIXME: before BootV2 supports abe mode + AVBInfo.parseFrom(Dumpling("$fileName.signed")) + } when (desc) { HashDescriptor::class -> { diff --git a/bbootimg/src/main/kotlin/bootimg/Common.kt b/bbootimg/src/main/kotlin/bootimg/Common.kt index 1797036..ed99534 100644 --- a/bbootimg/src/main/kotlin/bootimg/Common.kt +++ b/bbootimg/src/main/kotlin/bootimg/Common.kt @@ -135,6 +135,7 @@ class Common { ) ZipHelper.zcat(s.dumpFile + ".gz", s.dumpFile) } + ZipHelper.isXz(s.dumpFile) -> { log.info("ramdisk is compressed xz") Files.move( @@ -144,15 +145,17 @@ class Common { ZipHelper.xzcat(s.dumpFile + ".xz", s.dumpFile) ret = "xz" } + ZipHelper.isLzma(s.dumpFile) -> { log.info("ramdisk is compressed lzma") Files.move( - Paths.get(s.dumpFile), Paths.get(s.dumpFile + ".lzma"), - java.nio.file.StandardCopyOption.REPLACE_EXISTING + Paths.get(s.dumpFile), Paths.get(s.dumpFile + ".lzma"), + java.nio.file.StandardCopyOption.REPLACE_EXISTING ) ZipHelper.lzcat(s.dumpFile + ".lzma", s.dumpFile) ret = "lzma" } + ZipHelper.isLz4(s.dumpFile) -> { log.info("ramdisk is compressed lz4") Files.move( @@ -162,6 +165,7 @@ class Common { ZipHelper.lz4cat(s.dumpFile + ".lz4", s.dumpFile) ret = "lz4" } + ZipHelper.isAndroidCpio(s.dumpFile) -> { log.info("ramdisk is uncompressed cpio") Files.copy( @@ -170,6 +174,7 @@ class Common { ) ret = "cpio" } + else -> { throw IllegalArgumentException("ramdisk is in unknown format") } @@ -248,9 +253,11 @@ class Common { ramdiskGz.endsWith(".gz") -> { ZipHelper.minigzip(ramdiskGz, ByteArrayInputStream(outputStream.toByteArray())) } + ramdiskGz.endsWith(".lz4") -> { ZipHelper.lz4(ramdiskGz, ByteArrayInputStream(outputStream.toByteArray())) } + else -> { throw IllegalArgumentException("$ramdiskGz is not supported") } @@ -268,26 +275,31 @@ class Common { AndroidCpio().pack(root, f, "${f}_filelist.txt") FileInputStream(f).use { ZipHelper.minigzip(ramdiskGz, it) } } + ramdiskGz.endsWith(".lz4") -> { val f = ramdiskGz.removeSuffix(".lz4") AndroidCpio().pack(root, f, "${f}_filelist.txt") FileInputStream(f).use { ZipHelper.lz4(ramdiskGz, it) } } + ramdiskGz.endsWith(".lzma") -> { val f = ramdiskGz.removeSuffix(".lzma") AndroidCpio().pack(root, f, "${f}_filelist.txt") FileInputStream(f).use { ZipHelper.lzma(ramdiskGz, it) } } + ramdiskGz.endsWith(".xz") -> { val f = ramdiskGz.removeSuffix(".xz") AndroidCpio().pack(root, f, "${f}_filelist.txt") FileInputStream(f).use { ZipHelper.xz(ramdiskGz, it, compressorArgs!!) } } + ramdiskGz.endsWith(".cpio") -> { val f = ramdiskGz.removeSuffix(".cpio") AndroidCpio().pack(root, f, "${f}_filelist.txt") File(f).copyTo(File(ramdiskGz), true) } + else -> { throw IllegalArgumentException("$ramdiskGz is not supported") } @@ -381,9 +393,11 @@ class Common { log.warn("Os Major exceeds current max $MAX_ANDROID_VER") MAX_ANDROID_VER } + ret < 10 -> { 10 } + else -> { ret } @@ -405,7 +419,8 @@ class Common { com.github.freva.asciitable.Column().header("Where") .headerAlign(HorizontalAlign.CENTER) .dataAlign(HorizontalAlign.LEFT) - .with { it.second })) + .with { it.second }) + ) } fun printPackSummary(imageName: String) { @@ -441,5 +456,34 @@ class Common { log.info("\n\t\t\tPack Summary of ${imageName}\n{}\n{}", tableHeader.render(), tab.render()) } } + + fun printPackSummaryInternal(imageName: String) { + val prints: MutableList> = mutableListOf() + val tableHeader = de.vandermeer.asciitable.AsciiTable().apply { + addRule(); addRow("What", "Where"); addRule() + } + val tab = de.vandermeer.asciitable.AsciiTable().let { + it.addRule() + it.addRow("re-packed $imageName", Helper.prop("out.file")) + prints.add(Pair("re-packed $imageName", Helper.prop("out.file")!!)) + it.addRule() + it + } + if (File("vbmeta.img").exists()) { + if (File("vbmeta.img.signed").exists()) { + tab.addRow("re-packed vbmeta", "vbmeta.img.signed") + prints.add(Pair("re-packed vbmeta", "vbmeta.img.signed")) + } else { + tab.addRow("re-packed vbmeta", "-") + prints.add(Pair("re-packed vbmeta", "-")) + } + tab.addRule() + } + if (EnvironmentVerifier().isWindows) { + log.info("\n" + Common.table2String(prints)) + } else { + log.info("\n\t\t\tPack Summary of ${imageName}\n{}\n{}", tableHeader.render(), tab.render()) + } + } } } diff --git a/bbootimg/src/main/kotlin/bootimg/v3/BootV3.kt b/bbootimg/src/main/kotlin/bootimg/v3/BootV3.kt index e757f71..0fd0fbe 100644 --- a/bbootimg/src/main/kotlin/bootimg/v3/BootV3.kt +++ b/bbootimg/src/main/kotlin/bootimg/v3/BootV3.kt @@ -214,27 +214,50 @@ data class BootV3( } fun sign(fileName: String): BootV3 { - log.warn("XXXX: sign $fileName") + var bSigningNeeded = false if (File(Avb.getJsonFileName(info.role)).exists()) { + bSigningNeeded = true Signer.signAVB( Helper.joinPath(Helper.prop("intermediateDir")!!, info.role), this.info.imageSize, String.format(Helper.prop("avbtool")!!, "v1.2") ) } else { + bSigningNeeded = false log.warn("no AVB info found, assume it's clear image") } + if (fileName != info.role) { - File(Helper.joinPath(Helper.prop("intermediateDir")!!, info.role + ".signed")).copyTo(File(fileName), true) - log.info("Signed image saved as $fileName") + Helper.setProp("out.file", fileName) + if (bSigningNeeded) { + //@formatter:off + File(Helper.joinPath(Helper.prop("intermediateDir")!!, info.role + ".signed")) + .copyTo(File(fileName), true) + //@formatter:on + log.info("Signed image saved as $fileName") + } else { + //@formatter:off + File(Helper.joinPath(Helper.prop("intermediateDir")!!, info.role + ".clear")) + .copyTo(File(fileName), true) + //@formatter:on + log.info("Unsigned image saved as $fileName") + } } else { - File( - Helper.joinPath( - Helper.prop("intermediateDir")!!, - info.role + ".signed" - ) - ).copyTo(File(info.role + ".signed"), true) - log.info("Signed image saved as ${info.role}.signed") + if (bSigningNeeded) { + Helper.setProp("out.file", info.role + ".signed") + //@formatter:off + File(Helper.joinPath(Helper.prop("intermediateDir")!!, info.role + ".signed")) + .copyTo(File(info.role + ".signed"), true) + //@formatter:on + log.info("Signed image saved as ${info.role}.signed") + } else { + Helper.setProp("out.file", info.role + ".clear") + //@formatter:off + File(Helper.joinPath(Helper.prop("intermediateDir")!!, info.role + ".clear")) + .copyTo(File(info.role + ".clear"), true) + //@formatter:on + log.info("Unsigned image saved as ${info.role}.clear") + } } return this } @@ -284,11 +307,12 @@ data class BootV3( fun extractVBMeta(): BootV3 { // vbmeta in image try { - log.warn("XXXX: info.output ${info.input}") + val vbmetaCompanion = Helper.joinPath(File(info.input).parentFile.normalize().path, "vbmeta.img") + log.info("XXXX: $vbmetaCompanion") val ai = AVBInfo.parseFrom(Dumpling(info.input)).dumpDefault(info.role) - if (File("vbmeta.img").exists()) { + if (File(vbmetaCompanion).exists()) { log.warn("Found vbmeta.img, parsing ...") - VBMetaParser().unpack("vbmeta.img") + VBMetaParser().unpack(vbmetaCompanion) } } catch (e: IllegalArgumentException) { log.warn(e.message) @@ -368,7 +392,6 @@ data class BootV3( it.addRow("kernel", this.kernel.file) prints.add(Pair("kernel", this.kernel.file)) File(Helper.joinPath(workDir, Helper.prop("kernelVersionStem")!!)).let { kernelVersionFile -> - log.warn("XXXX: kernelVersionFile ${kernelVersionFile.path}") if (kernelVersionFile.exists()) { it.addRow("\\-- version " + kernelVersionFile.readLines().toString(), kernelVersionFile.path) prints.add( @@ -380,7 +403,6 @@ data class BootV3( } } File(Helper.joinPath(workDir, Helper.prop("kernelConfigStem")!!)).let { kernelConfigFile -> - log.warn("XXXX: kernelConfigFile ${kernelConfigFile.path}") if (kernelConfigFile.exists()) { it.addRow("\\-- config", kernelConfigFile.path) prints.add(Pair("\\-- config", kernelConfigFile.path)) @@ -460,14 +482,19 @@ data class BootV3( it } val tabVBMeta = AsciiTable().let { - if (File("vbmeta.img").exists()) { + val vbmetaCompanion = Helper.joinPath(File(info.input).parentFile.normalize().path, "vbmeta.img") + log.warn("XXXX: vbmetaCompanion: $vbmetaCompanion") + if (File(vbmetaCompanion).exists()) { + log.warn("XXXX: Found vbmeta.img, parsing ...") + //basic + prints.add(Pair("vbmeta.img", Avb.getJsonFileName("vbmeta.img"))) + //table it.addRule() it.addRow("vbmeta.img", Avb.getJsonFileName("vbmeta.img")) it.addRule() "\n" + it.render() - //basic - prints.add(Pair("vbmeta.img", Avb.getJsonFileName("vbmeta.img"))) } else { + log.warn("XXXX: no vbmeta.img found") "" } } @@ -483,7 +510,7 @@ data class BootV3( } fun printPackSummary(fileName: String): BootV3 { - Common.printPackSummary(fileName) + Common.printPackSummaryInternal(fileName) return this } diff --git a/bbootimg/src/main/kotlin/packable/BootImgParser.kt b/bbootimg/src/main/kotlin/packable/BootImgParser.kt index 7379bb3..455db3a 100644 --- a/bbootimg/src/main/kotlin/packable/BootImgParser.kt +++ b/bbootimg/src/main/kotlin/packable/BootImgParser.kt @@ -49,11 +49,10 @@ class BootImgParser : IPackable { } fun unpackInternal(targetFile: String, fileName: String, unpackDir: String) { - log.warn("Unpacking $fileName") - log.warn("fileName: $fileName, unpackDir: $unpackDir") + log.info("unpackInternal(fileName: $fileName, unpackDir: $unpackDir)") Helper.setProp("workDir", unpackDir) clear() - File("$outDir/role").writeText(File(File(fileName).canonicalPath).name) + File("$outDir/role").writeText(File(File(targetFile).canonicalPath).name) val hv = probeHeaderVersion(fileName) log.info("header version $hv") when (hv) { @@ -87,7 +86,7 @@ class BootImgParser : IPackable { } fun packInternal(targetFile: String, workspace: String, fileName: String) { - log.warn("XXXX: targetFile: $targetFile, fileName: $fileName, workspace: $workspace") + log.info("packInternal(targetFile: $targetFile, fileName: $fileName, workspace: $workspace)") Helper.setProp("workDir", workspace) val cfgFile = Helper.joinPath(outDir, targetFile.removeSuffix(".img") + ".json") log.info("Loading config from $cfgFile") @@ -113,7 +112,7 @@ class BootImgParser : IPackable { } } if (worker == null) { - log.warn("XXXX: worker is null") + log.error("no worker available") exitProcess(2) } when (worker) { @@ -130,7 +129,7 @@ class BootImgParser : IPackable { .pack() .sign(fileName) .updateVbmeta() - .printPackSummary(fileName) + .printPackSummary(worker.info.role) } else -> { diff --git a/bbootimg/src/main/kotlin/packable/PackableLauncher.kt b/bbootimg/src/main/kotlin/packable/PackableLauncher.kt index ad576e7..0fd68d9 100644 --- a/bbootimg/src/main/kotlin/packable/PackableLauncher.kt +++ b/bbootimg/src/main/kotlin/packable/PackableLauncher.kt @@ -14,11 +14,10 @@ package cfig.packable -import rom.sparse.SparseImgParser import org.slf4j.LoggerFactory import packable.DeviceTreeParser +import rom.sparse.SparseImgParser import java.io.File -import java.util.* import java.util.regex.Pattern import kotlin.reflect.KClass import kotlin.reflect.full.createInstance @@ -98,9 +97,9 @@ fun main(args: Array) { // /* 2 */ no-args & handler : help for Handler // /* 3 */ args & no-handler: do nothing // /* 4 */ args & handler : work + log.warn("args: ${args.size}, targetHandler: $targetHandler") when (listOf(args.isNotEmpty(), targetHandler != null)) { listOf(false, false) -> { /* 1 */ - log.warn("args: ${args.size}, targetHandler: $targetHandler") log.info("help:") log.info("available IPackable subcommands are:") IPackable::class.declaredFunctions.forEach { @@ -110,7 +109,6 @@ fun main(args: Array) { } listOf(false, true) -> {/* 2 */ - log.warn("args: ${args.size}, targetHandler: $targetHandler") log.info("available ${targetHandler!!.simpleName} subcommands are:") targetHandler!!.declaredFunctions.forEach { log.info("\t" + it.name) @@ -119,13 +117,11 @@ fun main(args: Array) { } listOf(true, false) -> {/* 3 */ - log.warn("args: ${args.size}, targetHandler: $targetHandler") log.warn("No handler is activated, DO NOTHING!") exitProcess(2) } listOf(true, true) -> {/* 4 */ - log.warn("args: ${args.size}, targetHandler: $targetHandler") log.info("continue ...") } } diff --git a/doc/feature_list.md b/doc/feature_list.md index 33deeb8..70fd6b9 100644 --- a/doc/feature_list.md +++ b/doc/feature_list.md @@ -23,8 +23,17 @@ unpack ``` abe unpack boot.img out ``` + pack ``` abe pack out boot.img ``` +properties: "out.file": the final output file + +### something interesting in abe +a zsh script, parse the input command line parameters, for example, +if args are: "unpack file dir", the shell script will print 'gradle unpack --args="unpackInternal file dir"'; +if args are "pack dir file", the shell script will print 'gradle pack --args="packInternal dir file"'. +if args are "unpack", the shell script will print "gradle unpack" +if args are "pack", the shell script will print "gradle pack" diff --git a/tools/abe b/tools/abe new file mode 100755 index 0000000..b27c8d8 --- /dev/null +++ b/tools/abe @@ -0,0 +1,44 @@ +#!/bin/zsh + +baseDir=${0:a:h} +export baseDir +set -e + +# Parse command line arguments +if [[ $# -eq 0 ]]; then + echo "Usage: $0 [ ]" + exit 1 +fi + +operation=$1 + +# Determine which operation to perform +case $operation in + "unpack") + if [[ $# -eq 3 ]]; then + file=`realpath $2` + dir=`realpath $3` + cd ${baseDir}/../ + gradle unpack --args="unpackInternal $file $dir" + else + cd ${baseDir}/../ + gradle unpack + fi + ;; + "pack") + if [[ $# -eq 3 ]]; then + dir=`realpath $2` + file=`realpath $3` + cd ${baseDir}/../ + gradle pack --args="packInternal $dir $file" + else + cd ${baseDir}/../ + gradle pack + fi + ;; + *) + echo "Invalid operation: $operation. Please choose 'unpack' or 'pack'." + exit 1 + ;; +esac +