dev
cfig 4 weeks ago
parent c6152d5755
commit 43078016d4

@ -15,7 +15,7 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
kotlin("jvm") version "2.1.0"
kotlin("jvm") version "2.1.20"
application
}
@ -62,11 +62,13 @@ java {
targetCompatibility = JavaVersion.VERSION_11
}
tasks.withType<KotlinCompile>().all {
kotlinOptions {
freeCompilerArgs += "-opt-in=kotlin.RequiresOptIn"
freeCompilerArgs += "-opt-in=kotlin.ExperimentalUnsignedTypes"
jvmTarget = "11"
tasks.withType<KotlinCompile>().configureEach {
compilerOptions {
freeCompilerArgs.addAll(
"-opt-in=kotlin.RequiresOptIn",
"-opt-in=kotlin.ExperimentalUnsignedTypes"
)
jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_11)
}
}

@ -20,6 +20,7 @@ import cfig.bootimg.cpio.AndroidCpio
import rom.fdt.DTC
import cfig.helper.Helper
import cfig.helper.ZipHelper
import cfig.packable.BootImgParser
import cfig.utils.KernelExtractor
import com.github.freva.asciitable.HorizontalAlign
import org.apache.commons.exec.CommandLine
@ -32,6 +33,8 @@ import java.io.File
import java.nio.file.Files
import java.nio.file.Paths
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.IOException
import java.lang.NumberFormatException
import java.nio.ByteBuffer
import java.nio.ByteOrder
@ -52,6 +55,12 @@ class Common {
private val log = LoggerFactory.getLogger(Common::class.java)
private const val MAX_ANDROID_VER = 11
val loadProperties: (String) -> Properties = { fileName ->
Properties().apply {
File(fileName).inputStream().use { load(it) }
}
}
@Throws(IllegalArgumentException::class)
fun packOsVersion(x: String?): Int {
if (x.isNullOrBlank()) return 0
@ -423,19 +432,24 @@ class Common {
)
}
fun printPackSummary(imageName: String) {
fun printPackSummary(imageName: String, outFile: String? = null) {
val prints: MutableList<Pair<String, String>> = mutableListOf()
val tableHeader = de.vandermeer.asciitable.AsciiTable().apply {
addRule(); addRow("What", "Where"); addRule()
}
val tab = de.vandermeer.asciitable.AsciiTable().let {
it.addRule()
if (File("$imageName.signed").exists()) {
it.addRow("re-packed $imageName", "$imageName.signed")
prints.add(Pair("re-packed $imageName", "$imageName.signed"))
if (outFile != null) {
it.addRow("re-packed $imageName", outFile)
prints.add(Pair("re-packed $imageName", outFile))
} else {
it.addRow("re-packed $imageName", "$imageName.clear")
prints.add(Pair("re-packed $imageName", "$imageName.clear"))
if (File("$imageName.signed").exists()) {
it.addRow("re-packed $imageName", "$imageName.signed")
prints.add(Pair("re-packed $imageName", "$imageName.signed"))
} else {
it.addRow("re-packed $imageName", "$imageName.clear")
prints.add(Pair("re-packed $imageName", "$imageName.clear"))
}
}
it.addRule()
it
@ -457,6 +471,31 @@ class Common {
}
}
/*
be_caller_dir: set in "be" script, to support out of tree invocation
*/
fun shortenPath(fullPath: String, inCurrentPath: String = System.getProperty("user.dir")): String {
val currentPath = System.getenv("be_caller_dir") ?: inCurrentPath
val full = Paths.get(fullPath).normalize().toAbsolutePath()
val base = Paths.get(currentPath).normalize().toAbsolutePath()
return try {
base.relativize(full).toString()
} catch (e: IllegalArgumentException) {
full.toString()
}
}
fun String.toShortenPath(inCurrentPath: String = System.getProperty("user.dir")): String {
val currentPath = System.getenv("be_caller_dir") ?: inCurrentPath
val full = Paths.get(this).normalize().toAbsolutePath()
val base = Paths.get(currentPath).normalize().toAbsolutePath()
return try {
base.relativize(full).toString()
} catch (e: IllegalArgumentException) {
full.toString()
}
}
fun printPackSummaryInternal(imageName: String) {
val prints: MutableList<Pair<String, String>> = mutableListOf()
val tableHeader = de.vandermeer.asciitable.AsciiTable().apply {
@ -485,5 +524,24 @@ class Common {
log.info("\n\t\t\tPack Summary of ${imageName}\n{}\n{}", tableHeader.render(), tab.render())
}
}
fun createWorkspaceIni(fileName: String) {
//create workspace file
val workspaceFile = File(Helper.prop("workDir"), "workspace.ini").canonicalPath
try {
FileOutputStream(workspaceFile).use { output ->
Properties().also {
it.setProperty("file", fileName)
it.setProperty("workDir", Helper.prop("workDir"))
it.setProperty("role", File(fileName).name)
it.store(output, "unpackInternal configuration")
}
log.info("workspace file created: $workspaceFile")
}
} catch (e: IOException) {
log.error("error writing workspace file: ${e.message}")
}
//create workspace file done
}
}
}

@ -30,8 +30,58 @@ class Signer {
companion object {
private val log = LoggerFactory.getLogger(Signer::class.java)
fun signAVB2(inFile: String, //"$output.clear"
outFile: String, //"$output.signed"
aiFile: String, //AVBInfo
imageSize: Long,
avbtool: String) {
log.info("Adding hash_footer with verified-boot 2.0 style: $inFile -> $outFile")
val ai = ObjectMapper().readValue(File(aiFile), AVBInfo::class.java)
val alg = Algorithms.get(ai.header!!.algorithm_type)
val bootDesc = ai.auxBlob!!.hashDescriptors[0]
val newAvbInfo = ObjectMapper().readValue(File(aiFile), AVBInfo::class.java)
//our signer
File(inFile).copyTo(File(outFile), overwrite = true)
Avb().addHashFooter(outFile,
imageSize,
partition_name = bootDesc.partition_name,
newAvbInfo = newAvbInfo)
//original signer
val cmdPrefix = if (EnvironmentVerifier().isWindows) "python " else ""
CommandLine.parse("$cmdPrefix$avbtool add_hash_footer").apply {
addArguments("--image ${outFile}2") //boot.img.signed2
addArguments("--flags ${ai.header!!.flags}")
addArguments("--partition_size ${imageSize}")
addArguments("--salt ${Helper.toHexString(bootDesc.salt)}")
addArguments("--partition_name ${bootDesc.partition_name}")
addArguments("--hash_algorithm ${bootDesc.hash_algorithm}")
addArguments("--algorithm ${alg!!.name}")
addArguments("--rollback_index ${ai.header!!.rollback_index}")
if (alg.defaultKey.isNotBlank()) {
addArguments("--key ${alg.defaultKey}")
}
newAvbInfo.auxBlob?.let { newAuxblob ->
newAuxblob.propertyDescriptors.forEach { newProp ->
addArguments(arrayOf("--prop", "${newProp.key}:${newProp.value}"))
}
}
addArgument("--internal_release_string")
addArgument(ai.header!!.release_string, false)
log.info(this.toString())
File(inFile).copyTo(File("${outFile}2"), overwrite = true)
DefaultExecutor().execute(this)
}
Helper.assertFileEquals(outFile, "${outFile}2")
File("${outFile}2").delete()
//TODO: decide what to verify
//Parser.verifyAVBIntegrity(cfg.info.output + ".signed", avbtool)
//Parser.verifyAVBIntegrity(cfg.info.output + ".signed2", avbtool)
}
fun signAVB(output: String, imageSize: Long, avbtool: String) {
log.info("Adding hash_footer with verified-boot 2.0 style")
log.info("Adding hash_footer with verified-boot 2.0 style: $output")
val ai = ObjectMapper().readValue(File(getJsonFileName(output)), AVBInfo::class.java)
val alg = Algorithms.get(ai.header!!.algorithm_type)
val bootDesc = ai.auxBlob!!.hashDescriptors[0]

@ -194,6 +194,7 @@ class AndroidCpio {
val rounded = Helper.round_to_multiple(len, 256) //file in page 256
if (len != rounded) {
FileOutputStream(outFile, true).use { fos ->
log.info("cpio padding size: " + (rounded - len) + " bytes")
fos.write(ByteArray((rounded - len).toInt()))
}
}

@ -16,15 +16,14 @@ package cfig.bootimg.v2
import avb.AVBInfo
import cfig.Avb
import cfig.bootimg.Common as C
import cfig.bootimg.Common
import cfig.bootimg.Common.Companion.deleleIfExists
import cfig.bootimg.Common.Companion.shortenPath
import cfig.bootimg.Signer
import cfig.helper.Dumpling
import cfig.helper.Helper
import cfig.helper.ZipHelper
import cfig.packable.VBMetaParser
import rom.fdt.DTC
import cfig.utils.EnvironmentVerifier
import com.fasterxml.jackson.databind.ObjectMapper
import com.github.freva.asciitable.HorizontalAlign
@ -32,11 +31,13 @@ import de.vandermeer.asciitable.AsciiTable
import org.apache.commons.exec.CommandLine
import org.apache.commons.exec.DefaultExecutor
import org.slf4j.LoggerFactory
import rom.fdt.DTC
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.nio.ByteBuffer
import java.nio.ByteOrder
import cfig.bootimg.Common as C
data class BootV2(
var info: MiscInfo = MiscInfo(),
@ -95,7 +96,9 @@ data class BootV2(
companion object {
private val log = LoggerFactory.getLogger(BootV2::class.java)
private val workDir = Helper.prop("workDir")
private val workDir: () -> String = {
Helper.prop("workDir")!!
}
private val mapper = ObjectMapper()
private val dtsSuffix = Helper.prop("config.dts_suffix")
@ -128,7 +131,7 @@ data class BootV2(
}
}
ret.kernel.let { theKernel ->
theKernel.file = File(workDir, "kernel").path
theKernel.file = File(workDir(), "kernel").path
theKernel.size = bh2.kernelLength
theKernel.loadOffset = bh2.kernelOffset
theKernel.position = ret.getKernelPosition()
@ -138,28 +141,28 @@ data class BootV2(
theRamdisk.loadOffset = bh2.ramdiskOffset
theRamdisk.position = ret.getRamdiskPosition()
if (bh2.ramdiskLength > 0) {
theRamdisk.file = File(workDir, "ramdisk.img").path
theRamdisk.file = File(workDir(), "ramdisk.img").path
}
}
if (bh2.secondBootloaderLength > 0) {
ret.secondBootloader = CommArgs()
ret.secondBootloader!!.size = bh2.secondBootloaderLength
ret.secondBootloader!!.loadOffset = bh2.secondBootloaderOffset
ret.secondBootloader!!.file = File(workDir, "second").path
ret.secondBootloader!!.file = File(workDir(), "second").path
ret.secondBootloader!!.position = ret.getSecondBootloaderPosition()
}
if (bh2.recoveryDtboLength > 0) {
ret.recoveryDtbo = CommArgsLong()
ret.recoveryDtbo!!.size = bh2.recoveryDtboLength
ret.recoveryDtbo!!.loadOffset = bh2.recoveryDtboOffset //Q
ret.recoveryDtbo!!.file = File(workDir, "recoveryDtbo").path
ret.recoveryDtbo!!.file = File(workDir(), "recoveryDtbo").path
ret.recoveryDtbo!!.position = ret.getRecoveryDtboPosition()
}
if (bh2.dtbLength > 0) {
ret.dtb = DtbArgsLong()
ret.dtb!!.size = bh2.dtbLength
ret.dtb!!.loadOffset = bh2.dtbOffset //Q
ret.dtb!!.file = File(workDir, "dtb").path
ret.dtb!!.file = File(workDir(), "dtb").path
ret.dtb!!.position = ret.getDtbPosition()
}
}
@ -206,7 +209,7 @@ data class BootV2(
fun extractImages(): BootV2 {
//info
mapper.writerWithDefaultPrettyPrinter().writeValue(File(workDir + info.json), this)
mapper.writerWithDefaultPrettyPrinter().writeValue(File(workDir(), info.json), this)
//kernel
if (kernel.size > 0) {
Common.dumpKernel(Helper.Slice(info.output, kernel.position.toInt(), kernel.size, kernel.file!!))
@ -220,15 +223,17 @@ data class BootV2(
//ramdisk
if (this.ramdisk.size > 0) {
val fmt = C.dumpRamdisk(
Helper.Slice(info.output, ramdisk.position.toInt(), ramdisk.size, ramdisk.file!!), File(workDir, "root").path
Helper.Slice(info.output, ramdisk.position.toInt(), ramdisk.size, ramdisk.file!!),
File(workDir(), "root").path
)
this.ramdisk.file = this.ramdisk.file!! + ".$fmt"
if (fmt == "xz") {
val checkType = ZipHelper.xzStreamFlagCheckTypeToString(ZipHelper.parseStreamFlagCheckType(this.ramdisk.file!!))
val checkType =
ZipHelper.xzStreamFlagCheckTypeToString(ZipHelper.parseStreamFlagCheckType(this.ramdisk.file!!))
this.ramdisk.xzFlags = checkType
}
//dump info again
mapper.writerWithDefaultPrettyPrinter().writeValue(File(workDir + this.info.json), this)
mapper.writerWithDefaultPrettyPrinter().writeValue(File(workDir(), this.info.json), this)
}
//second bootloader
secondBootloader?.let {
@ -254,7 +259,7 @@ data class BootV2(
this.dtb!!.dtbList = DTC.parseMultiple(dtb!!.file!!)
log.info("dtb sz = " + this.dtb!!.dtbList.size)
//dump info again
mapper.writerWithDefaultPrettyPrinter().writeValue(File(workDir + info.json), this)
mapper.writerWithDefaultPrettyPrinter().writeValue(File(workDir(), info.json), this)
//dump dtb items
DTC.extractMultiple(dtb!!.file!!, this.dtb!!.dtbList)
@ -285,8 +290,8 @@ data class BootV2(
}
val tab = AsciiTable().let {
it.addRule()
it.addRow("image info", workDir + info.output.removeSuffix(".img") + ".json")
prints.add(Pair("image info", workDir + info.output.removeSuffix(".img") + ".json"))
it.addRow("image info", shortenPath( File(Helper.prop("workDir"), info.output.removeSuffix(".img") + ".json").path))
prints.add(Pair("image info", shortenPath(File(workDir(), info.output.removeSuffix(".img") + ".json").path)))
if (this.info.verify.startsWith("VB2.0")) {
it.addRule()
val verifyStatus = if (this.info.verify.contains("PASS")) {
@ -311,11 +316,11 @@ data class BootV2(
//kernel
it.addRule()
if (this.kernel.size > 0) {
it.addRow("kernel", this.kernel.file)
it.addRow("kernel", shortenPath(this.kernel.file!!))
} else { //only for ramdisk.img, Issue #122
it.addRow("kernel", "NONE")
}
prints.add(Pair("kernel", this.kernel.file.toString()))
prints.add(Pair("kernel", shortenPath(this.kernel.file.toString())))
File(Helper.prop("kernelVersionFile")).let { kernelVersionFile ->
if (kernelVersionFile.exists()) {
it.addRow("\\-- version " + kernelVersionFile.readLines().toString(), kernelVersionFile.path)
@ -331,10 +336,10 @@ data class BootV2(
//ramdisk
if (this.ramdisk.size > 0) {
it.addRule()
it.addRow("ramdisk", this.ramdisk.file)
prints.add(Pair("ramdisk", this.ramdisk.file.toString()))
it.addRow("\\-- extracted ramdisk rootfs", File(workDir, "root").path)
prints.add(Pair("\\-- extracted ramdisk rootfs", File(workDir, "root").path))
it.addRow("ramdisk", shortenPath(this.ramdisk.file!!))
prints.add(Pair("ramdisk", shortenPath(this.ramdisk.file.toString())))
it.addRow("\\-- extracted ramdisk rootfs", shortenPath(File(workDir(), "root").path))
prints.add(Pair("\\-- extracted ramdisk rootfs", shortenPath(File(workDir(), "root").path)))
}
//second
this.secondBootloader?.let { theSecondBootloader ->
@ -382,15 +387,17 @@ data class BootV2(
}
if (EnvironmentVerifier().isWindows) {
log.info("\n" +
com.github.freva.asciitable.AsciiTable.getTable(
com.github.freva.asciitable.AsciiTable.BASIC_ASCII,
prints, mutableListOf(
com.github.freva.asciitable.Column().header("What")
.dataAlign(HorizontalAlign.LEFT)
.with { it.first },
com.github.freva.asciitable.Column().header("Where").with { it.second })
))
log.info(
"\n" +
com.github.freva.asciitable.AsciiTable.getTable(
com.github.freva.asciitable.AsciiTable.BASIC_ASCII,
prints, mutableListOf(
com.github.freva.asciitable.Column().header("What")
.dataAlign(HorizontalAlign.LEFT)
.with { it.first },
com.github.freva.asciitable.Column().header("Where").with { it.second })
)
)
} else {
log.info(
"\n\t\t\tUnpack Summary of ${info.output}\n{}\n{}{}",
@ -433,14 +440,14 @@ data class BootV2(
ramdisk.file = null
ramdisk.loadOffset = 0
} 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
log.warn("Use prebuilt ramdisk file: ${this.ramdisk.file}")
} else {
File(this.ramdisk.file!!).deleleIfExists()
File(this.ramdisk.file!!.removeSuffix(".gz")).deleleIfExists()
//Common.packRootfs("${workDir}/root", this.ramdisk.file!!, Common.parseOsMajor(info.osVersion.toString()))
Common.packRootfs(File(workDir, "root").path, this.ramdisk.file!!, this.ramdisk.xzFlags)
Common.packRootfs(File(workDir(), "root").path, this.ramdisk.file!!, this.ramdisk.xzFlags)
}
this.ramdisk.size = File(this.ramdisk.file!!).length().toInt()
}
@ -466,18 +473,21 @@ data class BootV2(
0 -> {
Common.hashFileAndSize(kernel.file, ramdisk.file, secondBootloader?.file)
}
1 -> {
Common.hashFileAndSize(
kernel.file, ramdisk.file,
secondBootloader?.file, recoveryDtbo?.file
)
}
2 -> {
Common.hashFileAndSize(
kernel.file, ramdisk.file,
secondBootloader?.file, recoveryDtbo?.file, dtb?.file
)
}
else -> {
throw IllegalArgumentException("headerVersion ${info.headerVersion} illegal")
}

@ -22,6 +22,7 @@ import cfig.bootimg.Common
import cfig.utils.EnvironmentVerifier
import cfig.bootimg.Common.Companion.deleleIfExists
import cfig.bootimg.Common.Companion.getPaddingSize
import cfig.bootimg.Common.Companion.shortenPath
import cfig.bootimg.Signer
import cfig.helper.Helper
import cfig.helper.Dumpling
@ -228,22 +229,26 @@ data class BootV3(
}
if (fileName != info.role) {
Helper.setProp("out.file", fileName)
if (bSigningNeeded) {
log.info("x1")
Helper.setProp("out.file", "$fileName.signed")
//@formatter:off
File(Helper.joinPath(Helper.prop("intermediateDir")!!, info.role + ".signed"))
.copyTo(File(fileName), true)
.copyTo(File(Helper.prop("out.file")!!), true)
//@formatter:on
log.info("Signed image saved as $fileName")
log.info("Signed image saved as " + Helper.prop("out.file"))
} else {
log.info("x2")
Helper.setProp("out.file", fileName)
//@formatter:off
File(Helper.joinPath(Helper.prop("intermediateDir")!!, info.role + ".clear"))
.copyTo(File(fileName), true)
.copyTo(File(Helper.prop("out.file")!!), true)
//@formatter:on
log.info("Unsigned image saved as $fileName")
log.info("Unsigned image saved as " + Helper.prop("out.file"))
}
} else {
if (bSigningNeeded) {
log.info("x3")
Helper.setProp("out.file", info.role + ".signed")
//@formatter:off
File(Helper.joinPath(Helper.prop("intermediateDir")!!, info.role + ".signed"))
@ -251,6 +256,7 @@ data class BootV3(
//@formatter:on
log.info("Signed image saved as ${info.role}.signed")
} else {
log.info("x4")
Helper.setProp("out.file", info.role + ".clear")
//@formatter:off
File(Helper.joinPath(Helper.prop("intermediateDir")!!, info.role + ".clear"))
@ -385,27 +391,27 @@ data class BootV3(
}
val tab = AsciiTable().let {
it.addRule()
it.addRow("image info", Helper.joinPath(workDir!!, info.role.removeSuffix(".img") + ".json"))
prints.add(Pair("image info", Helper.joinPath(workDir, info.role.removeSuffix(".img") + ".json")))
it.addRow("image info", shortenPath(Helper.joinPath(workDir!!, info.role.removeSuffix(".img") + ".json")))
prints.add(Pair("image info", shortenPath(Helper.joinPath(workDir, info.role.removeSuffix(".img") + ".json"))))
it.addRule()
if (this.kernel.size > 0) {
it.addRow("kernel", this.kernel.file)
prints.add(Pair("kernel", this.kernel.file))
it.addRow("kernel", shortenPath(this.kernel.file))
prints.add(Pair("kernel", shortenPath(this.kernel.file)))
File(Helper.joinPath(workDir, Helper.prop("kernelVersionStem")!!)).let { kernelVersionFile ->
if (kernelVersionFile.exists()) {
it.addRow("\\-- version " + kernelVersionFile.readLines().toString(), kernelVersionFile.path)
it.addRow("\\-- version " + kernelVersionFile.readLines().toString(), shortenPath( kernelVersionFile.path))
prints.add(
Pair(
"\\-- version " + kernelVersionFile.readLines().toString(),
kernelVersionFile.path
shortenPath(kernelVersionFile.path)
)
)
}
}
File(Helper.joinPath(workDir, Helper.prop("kernelConfigStem")!!)).let { kernelConfigFile ->
if (kernelConfigFile.exists()) {
it.addRow("\\-- config", kernelConfigFile.path)
prints.add(Pair("\\-- config", kernelConfigFile.path))
it.addRow("\\-- config", shortenPath(kernelConfigFile.path))
prints.add(Pair("\\-- config", shortenPath(kernelConfigFile.path)))
}
}
it.addRule()
@ -442,11 +448,11 @@ data class BootV3(
File(Avb.getJsonFileName("sig.boot")).let { jsonFile ->
if (jsonFile.exists()) {
it.addRow("GKI signature 2.0", this.bootSignature.file)
it.addRow("\\-- boot", jsonFile.path)
it.addRow("\\-- boot", shortenPath(jsonFile.path))
it.addRow("\\------ signing key", Avb.inspectKey(mapper.readValue(jsonFile, AVBInfo::class.java)))
//basic
prints.add(Pair("GKI signature 2.0", this.bootSignature.file))
prints.add(Pair("\\-- boot", jsonFile.path))
prints.add(Pair("\\-- boot", shortenPath(jsonFile.path)))
prints.add(
Pair(
"\\------ signing key",
@ -458,19 +464,19 @@ data class BootV3(
File(Avb.getJsonFileName("sig.kernel")).let { jsonFile ->
if (jsonFile.exists()) {
val readBackAvb = mapper.readValue(jsonFile, AVBInfo::class.java)
it.addRow("\\-- kernel", jsonFile.path)
it.addRow("\\-- kernel", shortenPath(jsonFile.path))
it.addRow("\\------ signing key", Avb.inspectKey(readBackAvb))
it.addRule()
//basic
prints.add(Pair("\\-- kernel", jsonFile.path))
prints.add(Pair("\\-- kernel", shortenPath(jsonFile.path)))
prints.add(Pair("\\------ signing key", Avb.inspectKey(readBackAvb)))
}
}
//AVB info
Avb.getJsonFileName(info.role).let { jsonFile ->
it.addRow("AVB info", if (File(jsonFile).exists()) jsonFile else "NONE")
prints.add(Pair("AVB info", if (File(jsonFile).exists()) jsonFile else "NONE"))
it.addRow("AVB info", if (File(jsonFile).exists()) shortenPath(jsonFile) else "NONE")
prints.add(Pair("AVB info", if (File(jsonFile).exists()) shortenPath(jsonFile) else "NONE"))
if (File(jsonFile).exists()) {
mapper.readValue(File(jsonFile), AVBInfo::class.java).let { ai ->
it.addRow("\\------ signing key", Avb.inspectKey(ai))
@ -487,10 +493,10 @@ data class BootV3(
if (File(vbmetaCompanion).exists()) {
log.warn("XXXX: Found vbmeta.img, parsing ...")
//basic
prints.add(Pair("vbmeta.img", Avb.getJsonFileName("vbmeta.img")))
prints.add(Pair("vbmeta.img", shortenPath(Avb.getJsonFileName("vbmeta.img"))))
//table
it.addRule()
it.addRow("vbmeta.img", Avb.getJsonFileName("vbmeta.img"))
it.addRow("vbmeta.img", shortenPath(Avb.getJsonFileName("vbmeta.img")))
it.addRule()
"\n" + it.render()
} else {

@ -19,18 +19,19 @@ import cc.cfig.io.Struct
import cfig.Avb
import cfig.bootimg.Common
import cfig.bootimg.Common.Companion.deleleIfExists
import cfig.bootimg.Common.Companion.toShortenPath
import cfig.bootimg.Signer
import cfig.helper.Dumpling
import cfig.helper.Helper
import cfig.helper.ZipHelper
import cfig.packable.VBMetaParser
import rom.fdt.DTC
import cfig.utils.EnvironmentVerifier
import com.fasterxml.jackson.databind.ObjectMapper
import de.vandermeer.asciitable.AsciiTable
import org.apache.commons.exec.CommandLine
import org.apache.commons.exec.DefaultExecutor
import org.slf4j.LoggerFactory
import rom.fdt.DTC
import java.io.*
import java.nio.ByteBuffer
import java.nio.ByteOrder
@ -265,7 +266,9 @@ data class VendorBoot(
}
this.dtb.size = File(this.dtb.file).length().toInt()
//header
FileOutputStream(this.info.role + ".clear", false).use { fos ->
val clearFile = Helper.joinPath(Helper.prop("intermediateDir")!!, this.info.role + ".clear")
val googleFile = Helper.joinPath(Helper.prop("intermediateDir")!!, this.info.role + ".google")
FileOutputStream(clearFile, false).use { fos ->
val encodedHeader = this.toHeader().encode()
fos.write(encodedHeader)
fos.write(ByteArray(Helper.round_to_multiple(encodedHeader.size, this.info.pageSize) - encodedHeader.size))
@ -303,17 +306,17 @@ data class VendorBoot(
}
}
//write
FileOutputStream("${this.info.role}.clear", true).use { fos ->
FileOutputStream(clearFile, true).use { fos ->
fos.write(bf.array(), 0, bf.position())
}
//google way
this.toCommandLine().addArgument(this.info.role + ".google").let {
this.toCommandLine().addArgument(googleFile).let {
log.info(it.toString())
DefaultExecutor().execute(it)
}
Helper.assertFileEquals(this.info.role + ".clear", this.info.role + ".google")
Helper.assertFileEquals(clearFile, googleFile)
return this
}
@ -321,7 +324,15 @@ data class VendorBoot(
val avbtool = String.format(Helper.prop("avbtool")!!, "v1.2")
File(Avb.getJsonFileName(info.role)).let {
if (it.exists()) {
Signer.signAVB(info.role, this.info.imageSize, avbtool)
//Signer.signAVB(info.role, this.info.imageSize, avbtool)
val clearFile = Helper.joinPath(Helper.prop("intermediateDir")!!, this.info.role + ".clear")
val signedFile = Helper.joinPath(Helper.prop("intermediateDir")!!, this.info.role + ".signed")
Signer.signAVB2(clearFile,
signedFile,
Avb.getJsonFileName(info.role),
this.info.imageSize,
avbtool
)
} else {
log.warn("skip signing of ${info.role}")
}
@ -329,6 +340,13 @@ data class VendorBoot(
return this
}
fun postCopy(outFile: String): VendorBoot {
val signedFile = Helper.joinPath(Helper.prop("intermediateDir")!!, this.info.role + ".signed")
log.info("COPY $signedFile -> $outFile")
File(signedFile).copyTo(File(outFile), overwrite = true)
return this
}
fun updateVbmeta(): VendorBoot {
Avb.updateVbmeta(info.role)
return this
@ -416,31 +434,31 @@ data class VendorBoot(
}
val tab = AsciiTable().let {
it.addRule()
val imageInfoJsonFile = Helper.joinPath(workDir!!, info.role.removeSuffix(".img") + ".json")
val imageInfoJsonFile = Helper.joinPath(workDir!!, info.role.removeSuffix(".img") + ".json").toShortenPath()
it.addRow("image info", imageInfoJsonFile)
prints.add(Pair("image info", imageInfoJsonFile))
it.addRule()
it.addRow("ramdisk", this.ramdisk.file)
prints.add(Pair("ramdisk", this.ramdisk.file))
it.addRow("ramdisk", this.ramdisk.file.toShortenPath())
prints.add(Pair("ramdisk", this.ramdisk.file.toShortenPath()))
if (this.ramdisk_table.size > 0) {
this.ramdisk_table.ramdidks.forEachIndexed { index, entry ->
//fancy ascii
it.addRow("-- ${entry.type} ramdisk[${index + 1}/${this.ramdisk_table.ramdidks.size}]", entry.file)
it.addRow("------- extracted rootfs", File(workDir, "root.${index + 1}").path)
it.addRow("-- ${entry.type} ramdisk[${index + 1}/${this.ramdisk_table.ramdidks.size}]", entry.file.toShortenPath())
it.addRow("------- extracted rootfs", File(workDir, "root.${index + 1}").path.toShortenPath())
//basic ascii
//@formatter:off
prints.add(Pair(" -- ${entry.type} ramdisk[${index + 1}/${this.ramdisk_table.ramdidks.size}]", entry.file))
prints.add(Pair(" -- ${entry.type} ramdisk[${index + 1}/${this.ramdisk_table.ramdidks.size}]", entry.file.toShortenPath()))
//@formatter:on
prints.add(Pair(" ------- extracted rootfs", File(workDir, "root.${index + 1}").path))
prints.add(Pair(" ------- extracted rootfs", File(workDir, "root.${index + 1}").path.toShortenPath()))
}
} else {
it.addRow("\\-- extracted ramdisk rootfs", File(workDir, "root").path)
prints.add(Pair("\\-- extracted ramdisk rootfs", File(workDir, "root").path))
it.addRow("\\-- extracted ramdisk rootfs", File(workDir, "root").path.toShortenPath())
prints.add(Pair("\\-- extracted ramdisk rootfs", File(workDir, "root").path.toShortenPath()))
}
it.addRule()
if (this.dtb.size > 0) {
it.addRow("dtb", this.dtb.file)
prints.add(Pair("dtb", this.dtb.file))
it.addRow("dtb", this.dtb.file.toShortenPath())
prints.add(Pair("dtb", this.dtb.file.toShortenPath()))
if (File(this.dtb.file + ".0.${dtsSuffix}").exists()) {
it.addRow("\\-- decompiled dts [${dtb.dtbList.size}]", dtb.file + "*.${dtsSuffix}")
prints.add(Pair("\\-- decompiled dts [${dtb.dtbList.size}]", dtb.file + "*.${dtsSuffix}"))
@ -451,14 +469,14 @@ data class VendorBoot(
}
if (this.bootconfig.size > 0) {
it.addRule()
it.addRow("bootconfig", this.bootconfig.file)
prints.add(Pair("bootconfig", this.bootconfig.file))
it.addRow("bootconfig", this.bootconfig.file.toShortenPath())
prints.add(Pair("bootconfig", this.bootconfig.file.toShortenPath()))
}
it.addRule()
Avb.getJsonFileName(info.role).let { jsonFile ->
if (File(jsonFile).exists()) {
it.addRow("AVB info", jsonFile)
prints.add(Pair("AVB info", jsonFile))
it.addRow("AVB info", jsonFile.toShortenPath())
prints.add(Pair("AVB info", jsonFile.toShortenPath()))
mapper.readValue(File(jsonFile), AVBInfo::class.java).let { ai ->
it.addRow("\\-- signing key", Avb.inspectKey(ai))
prints.add(Pair(" \\-- signing key", Avb.inspectKey(ai)))
@ -474,8 +492,8 @@ data class VendorBoot(
val tabVBMeta = AsciiTable().let {
if (File("vbmeta.img").exists()) {
it.addRule()
it.addRow("vbmeta.img", Avb.getJsonFileName("vbmeta.img"))
prints.add(Pair("vbmeta.img", Avb.getJsonFileName("vbmeta.img")))
it.addRow("vbmeta.img", Avb.getJsonFileName("vbmeta.img").toShortenPath())
prints.add(Pair("vbmeta.img", Avb.getJsonFileName("vbmeta.img").toShortenPath()))
it.addRule()
"\n" + it.render()
} else {
@ -492,8 +510,8 @@ data class VendorBoot(
return this
}
fun printPackSummary(): VendorBoot {
Common.printPackSummary(info.role)
fun printPackSummary(outFileName: String): VendorBoot {
Common.printPackSummary(info.role, outFileName)
return this
}

@ -15,6 +15,7 @@
package cfig.packable
import avb.blob.Footer
import cfig.bootimg.Common
import cfig.bootimg.Common.Companion.probeHeaderVersion
import cfig.bootimg.v2.BootV2
import cfig.bootimg.v2.BootV2Dialects
@ -45,14 +46,20 @@ class BootImgParser : IPackable {
}
override fun unpack(fileName: String) {
unpackInternal(fileName, fileName, outDir)
unpackInternal(fileName, outDir)
}
fun unpackInternal(targetFile: String, fileName: String, unpackDir: String) {
log.info("unpackInternal(fileName: $fileName, unpackDir: $unpackDir)")
Helper.setProp("workDir", unpackDir)
// called via reflection
fun unpackInternal(inFileName: String, unpackDir: String) {
log.info("unpackInternal(fileName: $inFileName, unpackDir: $unpackDir)")
val fileName = File(inFileName).canonicalPath
Helper.setProp("workDir", File(unpackDir).canonicalPath)
log.info("workspace set to $unpackDir")
clear()
File("$outDir/role").writeText(File(File(targetFile).canonicalPath).name)
//create workspace file
Common.createWorkspaceIni(fileName)
//create workspace file done
val hv = probeHeaderVersion(fileName)
log.info("header version $hv")
when (hv) {
@ -85,7 +92,64 @@ class BootImgParser : IPackable {
}
}
fun packInternal(targetFile: String, workspace: String, fileName: String) {
// called via reflection
fun packInternal(workspace: String, outFileName: String) {
log.info("packInternal($workspace, $outFileName)")
Helper.setProp("workDir", workspace)
val targetFile = outFileName
val iniRole = Common.loadProperties(File(workspace, "workspace.ini").canonicalPath).getProperty("role")
val cfgFile = File(workspace, iniRole.removeSuffix(".img") + ".json").canonicalPath
log.info("Loading config from $cfgFile")
if (!File(cfgFile).exists()) {
val tab = AsciiTable().let {
it.addRule()
it.addRow("'$cfgFile' doesn't exist, did you forget to 'unpack' ?")
it.addRule()
it
}
log.info("\n{}", tab.render())
return
}
val worker =
try {
ObjectMapper().readValue(File(cfgFile), BootV2::class.java)
} catch (e: com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException) {
try {
ObjectMapper().readValue(File(cfgFile), BootV3::class.java)
} catch (e: com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException) {
null
}
}
if (worker == null) {
log.error("no worker available")
exitProcess(2)
}
when (worker) {
is BootV2 -> {
worker
.pack()
.sign()
.updateVbmeta()
.printPackSummary()
}
is BootV3 -> {
worker
.pack()
.sign(targetFile)
.updateVbmeta()
.printPackSummary(worker.info.role)
}
else -> {
log.error("unsupported boot image format")
exitProcess(2)
}
}
}
fun packInternalLegacy(targetFile: String, workspace: String, fileName: String) {
log.info("packInternal(targetFile: $targetFile, fileName: $fileName, workspace: $workspace)")
Helper.setProp("workDir", workspace)
val cfgFile = Helper.joinPath(outDir, targetFile.removeSuffix(".img") + ".json")
@ -140,7 +204,8 @@ class BootImgParser : IPackable {
}
override fun pack(fileName: String) {
packInternal(fileName, outDir, fileName)
val targetFile = Common.loadProperties(File(outDir, "workspace.ini").canonicalPath).getProperty("role")
packInternal(outDir, targetFile)
}
fun flash(fileName: String) {

@ -14,10 +14,12 @@
package cfig.packable
import cfig.helper.Helper
import org.slf4j.LoggerFactory
import packable.DeviceTreeParser
import rom.sparse.SparseImgParser
import java.io.File
import java.util.Properties
import java.util.regex.Pattern
import kotlin.reflect.KClass
import kotlin.reflect.full.createInstance
@ -28,6 +30,12 @@ class PackableLauncher
fun main(args: Array<String>) {
val log = LoggerFactory.getLogger(PackableLauncher::class.java)
val devLog = LoggerFactory.getLogger("XXXX")
val loadProperties: (String) -> Properties = { fileName ->
Properties().apply {
File(fileName).inputStream().use { load(it) }
}
}
val packablePool = mutableMapOf<List<String>, KClass<IPackable>>()
listOf(
BootImgParser(),
@ -44,25 +52,43 @@ fun main(args: Array<String>) {
packablePool.put(it.capabilities(), it::class as KClass<IPackable>)
}
packablePool.forEach {
log.debug("" + it.key + "/" + it.value)
log.info("" + it.key + "/" + it.value)
}
var targetFile: String? = null
var targetHandler: KClass<IPackable>? = null
var targetDir: String? = null
log.info("XXXX: args: " + args.asList().toString())
devLog.info("args: " + args.asList().toString())
args.forEachIndexed { index, s ->
devLog.info(" arg: #$index - $s")
}
run found@{
for (currentLoopNo in 0..1) { //currently we have only 2 loops
devLog.info("loop #" + currentLoopNo)
if (args.size > 1) { // manual mode
targetFile = if (File(args[1]).isFile) {
devLog.info("manual mode")
targetFile = if (File(args[1]).isFile) { //unpack
File(args[1]).canonicalPath
} else if (File(args[1] + "/role").isFile) {
File(args[1] + "/role").readText().trim()
} else {
log.error("Not sure of what to do: " + args.asList().toString())
} else if (File(args[1]).isDirectory and File(args[1], "workspace.ini").isFile) { //pack
loadProperties(File(args[1], "workspace.ini").canonicalPath).getProperty("role")
} else { //wrong
log.error("Not a file: " + args[1])
exitProcess(1)
}
log.warn("manual mode: args= ${args[1]}, $targetFile")
devLog.warn("manual mode: file=$targetFile")
targetDir = when (args.size) {
2 -> if (File(args[1]).isDirectory and File(args[1], "workspace.ini").isFile) { //arg = outDir
File(args[1]).canonicalPath
} else {
Helper.prop("workDir") // arg = outDir
}
3 -> File(args[2]).canonicalPath // arg = file
else -> {
throw IllegalArgumentException("too many args")
}
}
devLog.warn("manual mode: file=$targetFile, dir=$targetDir")
packablePool
.filter { it.value.createInstance().loopNo == currentLoopNo }
.forEach { p ->
@ -75,14 +101,15 @@ fun main(args: Array<String>) {
}
}
} else { // lazy mode
devLog.info("lazy mode (in current dir)")
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
log.info("Found: " + file.name + ", " + item)
targetFile = File(file.name).canonicalPath
targetHandler = p.value
return@found
}
@ -140,43 +167,26 @@ fun main(args: Array<String>) {
log.warn("'${args[0]}' sequence initialized")
log.warn("XXXX: args.size: ${args.size}")
val convertedArgs = args.copyOf().apply { set(0, targetFile!!) }
functions[0].call(it.createInstance(), *convertedArgs)
/*
val reflectRet = when (functions[0].parameters.size) {
1 -> {
log.warn("1: call null")
functions[0].call(it.createInstance())
}
2 -> {
log.warn("2: call $targetFile")
functions[0].call(it.createInstance(), targetFile!!)
}
3 -> {
if (args.size != 2) {
log.info("invoke: ${it.qualifiedName}, $targetFile, " + targetFile!!.removeSuffix(".img"))
functions[0].call(it.createInstance(), targetFile!!, targetFile!!.removeSuffix(".img"))
} else {
log.info("invoke: ${it.qualifiedName}, $targetFile, " + args[1])
functions[0].call(it.createInstance(), targetFile!!, args[1])
}
}
else -> {
functions[0].parameters.forEach { kp ->
println("Param: " + kp.index + " " + kp.type + " " + kp.name)
}
log.error("I am confused by so many parameters")
exitProcess(4)
val c = (if (args.size == 1) { //lazy mode
args.drop(1).toMutableList().apply {
add(targetFile!!)
//add(System.getProperty("user.dir"))
}
} else {
args.drop(1)
}).toTypedArray()
val convertedArgs = c
println("clazz = " + it.simpleName)
println("func = " + functions[0])
println("orig args:")
args.forEachIndexed { index, s ->
println("$index: $s")
}
if (functions[0].returnType.toString() != Unit.toString()) {
log.info("ret: $reflectRet")
println("Converted args:")
convertedArgs.forEachIndexed { index, s ->
println("$index: $s")
}
*/
functions[0].call(it.createInstance(), *convertedArgs)
log.warn("'${args[0]}' sequence completed")
}
}

@ -16,6 +16,7 @@ package cfig.packable
import avb.AVBInfo
import cfig.Avb
import cfig.bootimg.Common
import cfig.helper.Dumpling
import cfig.helper.Helper
import com.fasterxml.jackson.databind.ObjectMapper
@ -35,20 +36,42 @@ class VBMetaParser : IPackable {
return listOf("^vbmeta\\.img$", "^vbmeta\\_[a-z]+.img$")
}
// lazy mode
override fun unpack(fileName: String) {
File(Helper.prop("workDir")).let {
unpackInternal(fileName, Helper.prop("workDir")!!)
}
// manual mode
fun unpackInternal(inFileName: String, unpackDir: String) {
//common
log.info("unpackInternal(fileName: $inFileName, unpackDir: $unpackDir)")
val fileName = File(inFileName).canonicalPath
Helper.setProp("workDir", File(unpackDir).canonicalPath)
//prepare workdir
File(Helper.prop("workDir")!!).let {
if (!it.exists()) {
it.mkdirs()
}
}
log.info("workspace set to $unpackDir")
Common.createWorkspaceIni(fileName)
val ai = AVBInfo.parseFrom(Dumpling(fileName)).dumpDefault(fileName)
log.info("Signing Key: " + Avb.inspectKey(ai))
}
override fun pack(fileName: String) {
val blob = ObjectMapper().readValue(File(Avb.getJsonFileName(fileName)), AVBInfo::class.java).encodePadded()
log.info("Writing padded vbmeta to file: $fileName.signed")
Files.write(Paths.get("$fileName.signed"), blob, StandardOpenOption.CREATE)
packInternal(outDir, fileName)
}
// called via reflection
fun packInternal(workspace: String, outFileName: String) {
log.info("packInternal(workspace: $workspace)")
Helper.setProp("workDir", workspace)
val iniRole = Common.loadProperties(File(workspace, "workspace.ini").canonicalPath).getProperty("role")
val blob = ObjectMapper().readValue(File(Avb.getJsonFileName(iniRole)), AVBInfo::class.java).encodePadded()
log.info("Writing padded vbmeta to file: $outFileName.signed")
Files.write(Paths.get("$outFileName.signed"), blob, StandardOpenOption.CREATE)
}
override fun flash(fileName: String, deviceName: String) {

@ -14,6 +14,7 @@
package cfig.packable
import cfig.bootimg.Common
import cfig.bootimg.v3.VendorBoot
import cfig.helper.Helper
import com.fasterxml.jackson.databind.ObjectMapper
@ -30,19 +31,17 @@ class VendorBootParser : IPackable {
}
override fun unpack(fileName: String) {
clear()
val vb = VendorBoot
.parse(fileName)
.extractImages()
.extractVBMeta()
.printUnpackSummary()
log.debug(vb.toString())
log.info("unpack(fileName: $fileName)")
unpackInternal(fileName, Helper.prop("workDir")!!)
}
fun unpackInternal(targetFile: String, fileName: String, unpackDir: String) {
fun unpackInternal(fileName: String, unpackDir: String) {
log.info("unpackInternal(fileName: $fileName, unpackDir: $unpackDir)")
Helper.setProp("workDir", unpackDir)
clear()
//create workspace file
Common.createWorkspaceIni(fileName)
//create workspace file done
val vb = VendorBoot
.parse(fileName)
.extractImages()
@ -52,13 +51,32 @@ class VendorBootParser : IPackable {
}
override fun pack(fileName: String) {
val cfgFile = "$outDir/${fileName.removeSuffix(".img")}.json"
log.info("packInternal($fileName)")
packInternal(Helper.prop("workDir")!!, fileName)
}
fun packInternal(workspace: String, outFileName: String) {
log.info("packInternal($workspace, $outFileName)")
Helper.setProp("workDir", workspace)
//intermediate
Helper.joinPath(workspace, "intermediate").also { intermediateDir ->
File(intermediateDir).let {
if (!it.exists()) {
it.mkdir()
}
}
Helper.setProp("intermediateDir", intermediateDir)
}
//workspace+cfg
val iniRole = Common.loadProperties(File(workspace, "workspace.ini").canonicalPath).getProperty("role")
val cfgFile = File(workspace, iniRole.removeSuffix(".img") + ".json").canonicalPath
log.info("Loading config from $cfgFile")
ObjectMapper().readValue(File(cfgFile), VendorBoot::class.java)
.pack()
.sign()
.postCopy(outFileName)
.updateVbmeta()
.printPackSummary()
.printPackSummary(outFileName)
}
override fun `@verify`(fileName: String) {

@ -21,16 +21,16 @@ should be compatible with "/usr/bin/env sh"
## TODO: command line usage
unpack
```
abe unpack boot.img out
be unpack file
be unpack file dir
```
pack
```
abe pack out boot.img
be pack dir
```
properties: "out.file": the final output file
### something interesting in abe
### something interesting in be
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"'.

@ -15,7 +15,7 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
kotlin("jvm") version "2.1.0"
kotlin("jvm") version "2.1.20"
`java-library`
application
}
@ -58,11 +58,13 @@ java {
targetCompatibility = JavaVersion.VERSION_11
}
tasks.withType<KotlinCompile>().all {
kotlinOptions {
freeCompilerArgs += "-opt-in=kotlin.RequiresOptIn"
freeCompilerArgs += "-opt-in=kotlin.ExperimentalUnsignedTypes"
jvmTarget = "11"
tasks.withType<KotlinCompile>().configureEach {
compilerOptions {
freeCompilerArgs.addAll(
"-opt-in=kotlin.RequiresOptIn",
"-opt-in=kotlin.ExperimentalUnsignedTypes"
)
jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_11)
}
}

@ -8,7 +8,7 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
kotlin("jvm") version "2.1.0"
kotlin("jvm") version "2.1.20"
application
}
@ -30,6 +30,7 @@ dependencies {
// Use the JUnit 5 integration.
testImplementation("org.junit.jupiter:junit-jupiter-engine:5.9.3")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
implementation(kotlin("stdlib"))
}
java {
@ -37,11 +38,13 @@ java {
targetCompatibility = JavaVersion.VERSION_11
}
tasks.withType<KotlinCompile>().all {
kotlinOptions {
freeCompilerArgs += "-opt-in=kotlin.RequiresOptIn"
freeCompilerArgs += "-opt-in=kotlin.ExperimentalUnsignedTypes"
jvmTarget = "11"
tasks.withType<KotlinCompile>().configureEach {
compilerOptions {
freeCompilerArgs.addAll(
"-opt-in=kotlin.RequiresOptIn",
"-opt-in=kotlin.ExperimentalUnsignedTypes"
)
jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_11)
}
}

@ -1,3 +1,8 @@
pluginManagement {
plugins {
kotlin("jvm") version "2.1.20"
}
}
rootProject.name = "boot"
include("bbootimg")
include("aosp:apksigner")

@ -73,6 +73,12 @@ unknown_list = [
"super_empty_all.img", #ADT-3
"bootloader.img", #many
"dt.img",
"fastboot.img", #anon
"fastlogo.img", #anon
"bl.img", #anon
"tzl.img", #anon
"preboot.img", #anon
"tzk.img", #anon
]
tmp2 = "tmp2"

@ -2,10 +2,12 @@
baseDir=${0:a:h}
export baseDir
be_caller_dir=${PWD}
export be_caller_dir
set -e
# Parse command line arguments
if [[ $# -eq 0 ]]; then
if [[ $# -lt 2 ]]; then
echo "Usage: $0 <operation> [<file> <dir>]"
exit 1
fi
@ -13,40 +15,48 @@ fi
operation=$1
echo arg num: $#
echo "args: $0 $1 $2"
echo "baseDir: $baseDir"
echo "callerDir: $be_caller_dir"
source_code_dir=/home/yu/work/boot
# Determine which operation to perform
set -x
case $operation in
"unpack")
cd ${source_code_dir}
pwd
if [[ $# -eq 2 ]]; then
file=`realpath $2`
dir=`realpath out`
cd ${source_code_dir}
pwd
gradle unpack --args="unpackInternal $file $dir"
elif [[ $# -eq 3 ]]; then
file=`realpath $2`
dir=`realpath $3`
cd ${baseDir}/../../../
cd ${source_code_dir}
gradle unpack --args="unpackInternal $file $dir"
else
echo "Invalid args"
cd ${baseDir}/../../../
gradle unpack
fi
;;
"pack")
pwd
if [[ $# -eq 3 ]]; then
if [[ $# -eq 2 ]]; then
dir=`realpath $2`
cd ${source_code_dir}
file=${be_caller_dir}/$(grep -m1 '^role=' $dir/workspace.ini | cut -d'=' -f2-)
gradle pack --args="packInternal $dir $file"
elif [[ $# -eq 3 ]]; then
dir=`realpath $2`
file=`realpath $3`
#cd ${baseDir}/../../../
cd ${source_code_dir}
gradle pack --args="packInternal $dir $file"
else
#cd ${baseDir}/../../../
cd ${source_code_dir}
gradle pack
##cd ${baseDir}/../../../
#cd ${source_code_dir}
#gradle pack
echo "Invalid args"
fi
;;
*)
Loading…
Cancel
Save