Issue #145: staging

boot.img V3
unpack
java -jar bbootimg/build/libs/bbootimg.jar unpackInternal ../boot.img out
pack
java -jar bbootimg/build/libs/bbootimg.jar packInternal out ../x/boot.img.modified
pull/159/head
cfig 1 year ago
parent 979a9b9f77
commit 585e2fdcd5

@ -174,7 +174,8 @@ class Avb {
fun getJsonFileName(image_file: String): String { fun getJsonFileName(image_file: String): String {
val jsonFile = File(image_file).name.removeSuffix(".img") + ".avb.json" val jsonFile = File(image_file).name.removeSuffix(".img") + ".avb.json"
return Helper.prop("workDir") + jsonFile log.warn("XXXX: json file = " + Helper.joinPath(Helper.prop("workDir")!!, jsonFile))
return Helper.joinPath(Helper.prop("workDir")!!, jsonFile)
} }
fun hasAvbFooter(fileName: String): Boolean { fun hasAvbFooter(fileName: String): Boolean {

@ -120,6 +120,7 @@ class Common {
fun dumpKernel(s: Helper.Slice) { fun dumpKernel(s: Helper.Slice) {
Helper.extractFile(s.srcFile, s.dumpFile, s.offset.toLong(), s.length) Helper.extractFile(s.srcFile, s.dumpFile, s.offset.toLong(), s.length)
log.warn("s.srcFile: ${s.srcFile}, s.dumpFile: ${s.dumpFile}, s.offset: ${s.offset}, s.length: ${s.length}")
parseKernelInfo(s.dumpFile) parseKernelInfo(s.dumpFile)
} }

@ -128,7 +128,7 @@ data class BootV2(
} }
} }
ret.kernel.let { theKernel -> ret.kernel.let { theKernel ->
theKernel.file = "${workDir}kernel" theKernel.file = File(workDir, "kernel").path
theKernel.size = bh2.kernelLength theKernel.size = bh2.kernelLength
theKernel.loadOffset = bh2.kernelOffset theKernel.loadOffset = bh2.kernelOffset
theKernel.position = ret.getKernelPosition() theKernel.position = ret.getKernelPosition()
@ -138,28 +138,28 @@ data class BootV2(
theRamdisk.loadOffset = bh2.ramdiskOffset theRamdisk.loadOffset = bh2.ramdiskOffset
theRamdisk.position = ret.getRamdiskPosition() theRamdisk.position = ret.getRamdiskPosition()
if (bh2.ramdiskLength > 0) { if (bh2.ramdiskLength > 0) {
theRamdisk.file = "${workDir}ramdisk.img" theRamdisk.file = File(workDir, "ramdisk.img").path
} }
} }
if (bh2.secondBootloaderLength > 0) { if (bh2.secondBootloaderLength > 0) {
ret.secondBootloader = CommArgs() ret.secondBootloader = CommArgs()
ret.secondBootloader!!.size = bh2.secondBootloaderLength ret.secondBootloader!!.size = bh2.secondBootloaderLength
ret.secondBootloader!!.loadOffset = bh2.secondBootloaderOffset ret.secondBootloader!!.loadOffset = bh2.secondBootloaderOffset
ret.secondBootloader!!.file = "${workDir}second" ret.secondBootloader!!.file = File(workDir, "second").path
ret.secondBootloader!!.position = ret.getSecondBootloaderPosition() ret.secondBootloader!!.position = ret.getSecondBootloaderPosition()
} }
if (bh2.recoveryDtboLength > 0) { 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 = File(workDir, "recoveryDtbo").path
ret.recoveryDtbo!!.position = ret.getRecoveryDtboPosition() ret.recoveryDtbo!!.position = ret.getRecoveryDtboPosition()
} }
if (bh2.dtbLength > 0) { if (bh2.dtbLength > 0) {
ret.dtb = DtbArgsLong() ret.dtb = DtbArgsLong()
ret.dtb!!.size = bh2.dtbLength ret.dtb!!.size = bh2.dtbLength
ret.dtb!!.loadOffset = bh2.dtbOffset //Q ret.dtb!!.loadOffset = bh2.dtbOffset //Q
ret.dtb!!.file = "${workDir}dtb" ret.dtb!!.file = File(workDir, "dtb").path
ret.dtb!!.position = ret.getDtbPosition() ret.dtb!!.position = ret.getDtbPosition()
} }
} }
@ -220,7 +220,7 @@ data class BootV2(
//ramdisk //ramdisk
if (this.ramdisk.size > 0) { if (this.ramdisk.size > 0) {
val fmt = C.dumpRamdisk( val fmt = C.dumpRamdisk(
Helper.Slice(info.output, ramdisk.position.toInt(), ramdisk.size, ramdisk.file!!), "${workDir}root" Helper.Slice(info.output, ramdisk.position.toInt(), ramdisk.size, ramdisk.file!!), File(workDir, "root").path
) )
this.ramdisk.file = this.ramdisk.file!! + ".$fmt" this.ramdisk.file = this.ramdisk.file!! + ".$fmt"
if (fmt == "xz") { if (fmt == "xz") {
@ -333,8 +333,8 @@ data class BootV2(
it.addRule() it.addRule()
it.addRow("ramdisk", this.ramdisk.file) it.addRow("ramdisk", this.ramdisk.file)
prints.add(Pair("ramdisk", this.ramdisk.file.toString())) prints.add(Pair("ramdisk", this.ramdisk.file.toString()))
it.addRow("\\-- extracted ramdisk rootfs", "${workDir}root") it.addRow("\\-- extracted ramdisk rootfs", File(workDir, "root").path)
prints.add(Pair("\\-- extracted ramdisk rootfs", "${workDir}root")) prints.add(Pair("\\-- extracted ramdisk rootfs", File(workDir, "root").path))
} }
//second //second
this.secondBootloader?.let { theSecondBootloader -> this.secondBootloader?.let { theSecondBootloader ->
@ -440,7 +440,7 @@ data class BootV2(
File(this.ramdisk.file!!).deleleIfExists() File(this.ramdisk.file!!).deleleIfExists()
File(this.ramdisk.file!!.removeSuffix(".gz")).deleleIfExists() File(this.ramdisk.file!!.removeSuffix(".gz")).deleleIfExists()
//Common.packRootfs("${workDir}/root", this.ramdisk.file!!, Common.parseOsMajor(info.osVersion.toString())) //Common.packRootfs("${workDir}/root", this.ramdisk.file!!, Common.parseOsMajor(info.osVersion.toString()))
Common.packRootfs("${workDir}/root", 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() this.ramdisk.size = File(this.ramdisk.file!!).length().toInt()
} }

@ -49,14 +49,15 @@ data class BootV3(
private val log = LoggerFactory.getLogger(BootV3::class.java) private val log = LoggerFactory.getLogger(BootV3::class.java)
private val errLog = LoggerFactory.getLogger("uiderrors") private val errLog = LoggerFactory.getLogger("uiderrors")
private val mapper = ObjectMapper() private val mapper = ObjectMapper()
private val workDir = Helper.prop("workDir") private val workDir = Helper.prop("workDir")!!
fun parse(fileName: String): BootV3 { fun parse(fileName: String): BootV3 {
val ret = BootV3() val ret = BootV3()
FileInputStream(fileName).use { fis -> FileInputStream(fileName).use { fis ->
val header = BootHeaderV3(fis) val header = BootHeaderV3(fis)
//info //info
ret.info.output = File(fileName).name ret.info.input = File(fileName).canonicalPath
ret.info.role = File(fileName).name
ret.info.json = File(fileName).name.removeSuffix(".img") + ".json" ret.info.json = File(fileName).name.removeSuffix(".img") + ".json"
ret.info.cmdline = header.cmdline.trim() ret.info.cmdline = header.cmdline.trim()
ret.info.headerSize = header.headerSize ret.info.headerSize = header.headerSize
@ -66,17 +67,17 @@ data class BootV3(
ret.info.pageSize = BootHeaderV3.pageSize ret.info.pageSize = BootHeaderV3.pageSize
ret.info.signatureSize = header.signatureSize ret.info.signatureSize = header.signatureSize
//kernel //kernel
ret.kernel.file = workDir + "kernel" ret.kernel.file = Helper.joinPath(workDir, "kernel")
ret.kernel.size = header.kernelSize ret.kernel.size = header.kernelSize
ret.kernel.position = BootHeaderV3.pageSize ret.kernel.position = BootHeaderV3.pageSize
//ramdisk //ramdisk
ret.ramdisk.file = workDir + "ramdisk.img" ret.ramdisk.file = Helper.joinPath(workDir, "ramdisk.img")
ret.ramdisk.size = header.ramdiskSize ret.ramdisk.size = header.ramdiskSize
ret.ramdisk.position = ret.kernel.position + header.kernelSize + ret.ramdisk.position = ret.kernel.position + header.kernelSize +
getPaddingSize(header.kernelSize, BootHeaderV3.pageSize) getPaddingSize(header.kernelSize, BootHeaderV3.pageSize)
//boot signature //boot signature
if (header.signatureSize > 0) { if (header.signatureSize > 0) {
ret.bootSignature.file = workDir + "bootsig" ret.bootSignature.file = Helper.joinPath(workDir, "bootsig")
ret.bootSignature.size = header.signatureSize ret.bootSignature.size = header.signatureSize
ret.bootSignature.position = ret.ramdisk.position + ret.ramdisk.size + ret.bootSignature.position = ret.ramdisk.position + ret.ramdisk.size +
getPaddingSize(header.ramdiskSize, BootHeaderV3.pageSize) getPaddingSize(header.ramdiskSize, BootHeaderV3.pageSize)
@ -88,7 +89,8 @@ data class BootV3(
} }
data class MiscInfo( data class MiscInfo(
var output: String = "", var input: String = "",
var role: String = "",
var json: String = "", var json: String = "",
var headerVersion: Int = 0, var headerVersion: Int = 0,
var headerSize: Int = 0, var headerSize: Int = 0,
@ -118,22 +120,30 @@ data class BootV3(
this.kernel.size = File(this.kernel.file).length().toInt() this.kernel.size = File(this.kernel.file).length().toInt()
} }
if (this.ramdisk.size > 0) { if (this.ramdisk.size > 0) {
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
log.warn("Use prebuilt ramdisk file: ${this.ramdisk.file}") log.warn("Use prebuilt ramdisk file: ${this.ramdisk.file}")
} else { } else {
File(this.ramdisk.file).deleleIfExists() File(this.ramdisk.file).deleleIfExists()
File(this.ramdisk.file.replaceFirst("[.][^.]+$", "")).deleleIfExists() File(this.ramdisk.file.replaceFirst("[.][^.]+$", "")).deleleIfExists()
//TODO: remove cpio in C/C++ //TODO: remove cpio in C/C++
//C.packRootfs("$workDir/root", this.ramdisk.file, C.parseOsMajor(info.osVersion)) //C.packRootfs(Helper.joinPath($workDir, "root"), this.ramdisk.file, C.parseOsMajor(info.osVersion))
// enable advance JAVA cpio // enable advance JAVA cpio
C.packRootfs("$workDir/root", this.ramdisk.file, this.ramdisk.xzFlags) C.packRootfs(Helper.joinPath(workDir, "root"), this.ramdisk.file, this.ramdisk.xzFlags)
} }
this.ramdisk.size = File(this.ramdisk.file).length().toInt() this.ramdisk.size = File(this.ramdisk.file).length().toInt()
} }
//header //header
FileOutputStream(this.info.output + ".clear", false).use { fos -> val intermediateDir = Helper.joinPath(workDir, "intermediate")
File(intermediateDir).let {
if (!it.exists()) {
it.mkdir()
}
}
Helper.setProp("intermediateDir", intermediateDir)
val clearFile = Helper.joinPath(intermediateDir, this.info.role + ".clear")
FileOutputStream(clearFile, false).use { fos ->
//trim bootSig if it's not parsable //trim bootSig if it's not parsable
//https://github.com/cfig/Android_boot_image_editor/issues/88 //https://github.com/cfig/Android_boot_image_editor/issues/88
File(Avb.getJsonFileName(this.bootSignature.file)).let { bootSigJson -> File(Avb.getJsonFileName(this.bootSignature.file)).let { bootSigJson ->
@ -163,7 +173,7 @@ data class BootV3(
C.writePaddedFile(bf, this.ramdisk.file, this.info.pageSize) C.writePaddedFile(bf, this.ramdisk.file, this.info.pageSize)
} }
//write V3 data //write V3 data
FileOutputStream("${this.info.output}.clear", true).use { fos -> FileOutputStream(clearFile, true).use { fos ->
fos.write(bf.array(), 0, bf.position()) fos.write(bf.array(), 0, bf.position())
} }
@ -178,12 +188,12 @@ data class BootV3(
//replace new pub key //replace new pub key
readBackBootSig.auxBlob!!.pubkey!!.pubkey = AuxBlob.encodePubKey(alg) readBackBootSig.auxBlob!!.pubkey!!.pubkey = AuxBlob.encodePubKey(alg)
//update hash and sig //update hash and sig
readBackBootSig.auxBlob!!.hashDescriptors.get(0).update(this.info.output + ".clear") readBackBootSig.auxBlob!!.hashDescriptors.get(0).update(this.info.role + ".clear")
bootSigBytes = readBackBootSig.encodePadded() bootSigBytes = readBackBootSig.encodePadded()
} }
if (this.info.signatureSize > 0) { if (this.info.signatureSize > 0) {
//write V4 data //write V4 data
FileOutputStream("${this.info.output}.clear", true).use { fos -> FileOutputStream(clearFile, true).use { fos ->
fos.write(bootSigBytes) fos.write(bootSigBytes)
} }
} else { } else {
@ -192,22 +202,40 @@ data class BootV3(
} }
//google way //google way
this.toCommandLine().addArgument(this.info.output + ".google").let { val googleClearFile = Helper.joinPath(intermediateDir, this.info.role + ".google")
this.toCommandLine().addArgument(googleClearFile).let {
log.info(it.toString()) log.info(it.toString())
DefaultExecutor().execute(it) DefaultExecutor().execute(it)
} }
Helper.assertFileEquals(this.info.output + ".clear", this.info.output + ".google") Helper.assertFileEquals(clearFile, googleClearFile)
File(this.info.output + ".google").delete() File(googleClearFile).delete()
return this return this
} }
fun sign(fileName: String): BootV3 { fun sign(fileName: String): BootV3 {
if (File(Avb.getJsonFileName(info.output)).exists()) { log.warn("XXXX: sign $fileName")
Signer.signAVB(fileName, this.info.imageSize, String.format(Helper.prop("avbtool")!!, "v1.2")) if (File(Avb.getJsonFileName(info.role)).exists()) {
Signer.signAVB(
Helper.joinPath(Helper.prop("intermediateDir")!!, info.role),
this.info.imageSize,
String.format(Helper.prop("avbtool")!!, "v1.2")
)
} else { } else {
log.warn("no AVB info found, assume it's clear image") 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")
} 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")
}
return this return this
} }
@ -227,35 +255,37 @@ data class BootV3(
fun extractImages(): BootV3 { fun extractImages(): BootV3 {
val workDir = Helper.prop("workDir") val workDir = Helper.prop("workDir")
//info //info
mapper.writerWithDefaultPrettyPrinter().writeValue(File(workDir + this.info.json), this) mapper.writerWithDefaultPrettyPrinter().writeValue(File(workDir, this.info.json), this)
//kernel //kernel
if (kernel.size > 0) { if (kernel.size > 0) {
C.dumpKernel(Helper.Slice(info.output, kernel.position, kernel.size, kernel.file)) C.dumpKernel(Helper.Slice(info.input, kernel.position, kernel.size, kernel.file))
} else { } else {
log.warn("${this.info.output} has no kernel") log.warn("${this.info.role} has no kernel")
} }
//ramdisk //ramdisk
if (ramdisk.size > 0) { if (ramdisk.size > 0) {
val fmt = C.dumpRamdisk( val fmt = C.dumpRamdisk(
Helper.Slice(info.output, ramdisk.position, ramdisk.size, ramdisk.file), "${workDir}root" Helper.Slice(info.role, ramdisk.position, ramdisk.size, ramdisk.file), File(workDir, "root").toString()
) )
this.ramdisk.file = this.ramdisk.file + ".$fmt" this.ramdisk.file = this.ramdisk.file + ".$fmt"
if (fmt == "xz") { 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 this.ramdisk.xzFlags = checkType
} }
} }
//bootsig //bootsig
//dump info again //dump info again
mapper.writerWithDefaultPrettyPrinter().writeValue(File(workDir + this.info.json), this) mapper.writerWithDefaultPrettyPrinter().writeValue(File(workDir, this.info.json), this)
return this return this
} }
fun extractVBMeta(): BootV3 { fun extractVBMeta(): BootV3 {
// vbmeta in image // vbmeta in image
try { try {
val ai = AVBInfo.parseFrom(Dumpling(info.output)).dumpDefault(info.output) log.warn("XXXX: info.output ${info.input}")
val ai = AVBInfo.parseFrom(Dumpling(info.input)).dumpDefault(info.role)
if (File("vbmeta.img").exists()) { if (File("vbmeta.img").exists()) {
log.warn("Found vbmeta.img, parsing ...") log.warn("Found vbmeta.img, parsing ...")
VBMetaParser().unpack("vbmeta.img") VBMetaParser().unpack("vbmeta.img")
@ -268,7 +298,7 @@ data class BootV3(
//GKI 1.0 bootsig //GKI 1.0 bootsig
if (info.signatureSize > 0) { if (info.signatureSize > 0) {
log.info("GKI 1.0 signature") log.info("GKI 1.0 signature")
Dumpling(info.output).readFully(Pair(this.bootSignature.position.toLong(), this.bootSignature.size)) Dumpling(info.role).readFully(Pair(this.bootSignature.position.toLong(), this.bootSignature.size))
.let { bootsigData -> .let { bootsigData ->
File(this.bootSignature.file).writeBytes(bootsigData) File(this.bootSignature.file).writeBytes(bootsigData)
if (bootsigData.any { it.toInt() != 0 }) { if (bootsigData.any { it.toInt() != 0 }) {
@ -286,17 +316,17 @@ data class BootV3(
} }
//GKI 2.0 bootsig //GKI 2.0 bootsig
if (!File(Avb.getJsonFileName(info.output)).exists()) { if (!File(Avb.getJsonFileName(info.role)).exists()) {
log.info("no AVB info found in ${info.output}") log.info("no AVB info found in ${info.role}")
return this return this
} }
log.info("probing 16KB boot signature ...") log.info("probing 16KB boot signature ...")
val mainBlob = ObjectMapper().readValue( val mainBlob = ObjectMapper().readValue(
File(Avb.getJsonFileName(info.output)), File(Avb.getJsonFileName(info.role)),
AVBInfo::class.java AVBInfo::class.java
) )
val bootSig16kData = val bootSig16kData =
Dumpling(Dumpling(info.output).readFully(Pair(mainBlob.footer!!.originalImageSize - 16 * 1024, 16 * 1024))) Dumpling(Dumpling(info.input).readFully(Pair(mainBlob.footer!!.originalImageSize - 16 * 1024, 16 * 1024)))
try { try {
val blob1 = AVBInfo.parseFrom(bootSig16kData) val blob1 = AVBInfo.parseFrom(bootSig16kData)
.also { check(it.auxBlob!!.hashDescriptors[0].partition_name == "boot") } .also { check(it.auxBlob!!.hashDescriptors[0].partition_name == "boot") }
@ -306,8 +336,8 @@ data class BootV3(
.also { check(it.auxBlob!!.hashDescriptors[0].partition_name == "generic_kernel") } .also { check(it.auxBlob!!.hashDescriptors[0].partition_name == "generic_kernel") }
.also { it.dumpDefault("sig.kernel") } .also { it.dumpDefault("sig.kernel") }
val gkiAvbData = bootSig16kData.readFully(blob1.encode().size until bootSig16kData.getLength()) val gkiAvbData = bootSig16kData.readFully(blob1.encode().size until bootSig16kData.getLength())
File("${workDir}kernel.img").let { gki -> File(workDir, "kernel.img").let { gki ->
File("${workDir}kernel").copyTo(gki) File(workDir, "kernel").copyTo(gki)
System.setProperty("more", workDir) System.setProperty("more", workDir)
Avb.verify(blob2, Dumpling(gkiAvbData)) Avb.verify(blob2, Dumpling(gkiAvbData))
gki.delete() gki.delete()
@ -331,19 +361,26 @@ data class BootV3(
} }
val tab = AsciiTable().let { val tab = AsciiTable().let {
it.addRule() it.addRule()
it.addRow("image info", workDir + info.output.removeSuffix(".img") + ".json") it.addRow("image info", Helper.joinPath(workDir!!, info.role.removeSuffix(".img") + ".json"))
prints.add(Pair("image info", workDir + info.output.removeSuffix(".img") + ".json")) prints.add(Pair("image info", Helper.joinPath(workDir, info.role.removeSuffix(".img") + ".json")))
it.addRule() it.addRule()
if (this.kernel.size > 0) { if (this.kernel.size > 0) {
it.addRow("kernel", this.kernel.file) it.addRow("kernel", this.kernel.file)
prints.add(Pair("kernel", this.kernel.file)) prints.add(Pair("kernel", this.kernel.file))
File(Helper.prop("kernelVersionFile")).let { kernelVersionFile -> File(Helper.joinPath(workDir, Helper.prop("kernelVersionStem")!!)).let { kernelVersionFile ->
log.warn("XXXX: kernelVersionFile ${kernelVersionFile.path}")
if (kernelVersionFile.exists()) { if (kernelVersionFile.exists()) {
it.addRow("\\-- version " + kernelVersionFile.readLines().toString(), kernelVersionFile.path) it.addRow("\\-- version " + kernelVersionFile.readLines().toString(), kernelVersionFile.path)
prints.add(Pair("\\-- version " + kernelVersionFile.readLines().toString(), kernelVersionFile.path)) prints.add(
Pair(
"\\-- version " + kernelVersionFile.readLines().toString(),
kernelVersionFile.path
)
)
} }
} }
File(Helper.prop("kernelConfigFile")).let { kernelConfigFile -> File(Helper.joinPath(workDir, Helper.prop("kernelConfigStem")!!)).let { kernelConfigFile ->
log.warn("XXXX: kernelConfigFile ${kernelConfigFile.path}")
if (kernelConfigFile.exists()) { if (kernelConfigFile.exists()) {
it.addRow("\\-- config", kernelConfigFile.path) it.addRow("\\-- config", kernelConfigFile.path)
prints.add(Pair("\\-- config", kernelConfigFile.path)) prints.add(Pair("\\-- config", kernelConfigFile.path))
@ -354,11 +391,11 @@ data class BootV3(
if (this.ramdisk.size > 0) { if (this.ramdisk.size > 0) {
//fancy //fancy
it.addRow("ramdisk", this.ramdisk.file) it.addRow("ramdisk", this.ramdisk.file)
it.addRow("\\-- extracted ramdisk rootfs", "${workDir}root") it.addRow("\\-- extracted ramdisk rootfs", Helper.joinPath(workDir, "root"))
it.addRule() it.addRule()
//basic //basic
prints.add(Pair("ramdisk", this.ramdisk.file)) prints.add(Pair("ramdisk", this.ramdisk.file))
prints.add(Pair("\\-- extracted ramdisk rootfs", "${workDir}root")) prints.add(Pair("\\-- extracted ramdisk rootfs", Helper.joinPath(workDir, "root")))
} }
if (this.info.signatureSize > 0) { if (this.info.signatureSize > 0) {
it.addRow("GKI signature 1.0", this.bootSignature.file) it.addRow("GKI signature 1.0", this.bootSignature.file)
@ -368,7 +405,12 @@ data class BootV3(
prints.add(Pair("\\-- decoded boot signature", if (jsFile.exists()) jsFile.path else "N/A")) prints.add(Pair("\\-- decoded boot signature", if (jsFile.exists()) jsFile.path else "N/A"))
if (jsFile.exists()) { if (jsFile.exists()) {
it.addRow("\\------ signing key", Avb.inspectKey(mapper.readValue(jsFile, AVBInfo::class.java))) it.addRow("\\------ signing key", Avb.inspectKey(mapper.readValue(jsFile, AVBInfo::class.java)))
prints.add(Pair("\\------ signing key", Avb.inspectKey(mapper.readValue(jsFile, AVBInfo::class.java)))) prints.add(
Pair(
"\\------ signing key",
Avb.inspectKey(mapper.readValue(jsFile, AVBInfo::class.java))
)
)
} }
} }
it.addRule() it.addRule()
@ -383,7 +425,12 @@ data class BootV3(
//basic //basic
prints.add(Pair("GKI signature 2.0", this.bootSignature.file)) prints.add(Pair("GKI signature 2.0", this.bootSignature.file))
prints.add(Pair("\\-- boot", jsonFile.path)) prints.add(Pair("\\-- boot", jsonFile.path))
prints.add(Pair("\\------ signing key", Avb.inspectKey(mapper.readValue(jsonFile, AVBInfo::class.java)))) prints.add(
Pair(
"\\------ signing key",
Avb.inspectKey(mapper.readValue(jsonFile, AVBInfo::class.java))
)
)
} }
} }
File(Avb.getJsonFileName("sig.kernel")).let { jsonFile -> File(Avb.getJsonFileName("sig.kernel")).let { jsonFile ->
@ -399,7 +446,7 @@ data class BootV3(
} }
//AVB info //AVB info
Avb.getJsonFileName(info.output).let { jsonFile -> Avb.getJsonFileName(info.role).let { jsonFile ->
it.addRow("AVB info", if (File(jsonFile).exists()) jsonFile else "NONE") it.addRow("AVB info", if (File(jsonFile).exists()) jsonFile else "NONE")
prints.add(Pair("AVB info", if (File(jsonFile).exists()) jsonFile else "NONE")) prints.add(Pair("AVB info", if (File(jsonFile).exists()) jsonFile else "NONE"))
if (File(jsonFile).exists()) { if (File(jsonFile).exists()) {
@ -428,20 +475,20 @@ data class BootV3(
log.info("\n" + Common.table2String(prints)) log.info("\n" + Common.table2String(prints))
} else { } else {
log.info( log.info(
"\n\t\t\tUnpack Summary of ${info.output}\n{}\n{}{}", "\n\t\t\tUnpack Summary of ${info.role}\n{}\n{}{}",
tableHeader.render(), tab.render(), tabVBMeta tableHeader.render(), tab.render(), tabVBMeta
) )
} }
return this return this
} }
fun printPackSummary(): BootV3 { fun printPackSummary(fileName: String): BootV3 {
Common.printPackSummary(info.output) Common.printPackSummary(fileName)
return this return this
} }
fun updateVbmeta(): BootV3 { fun updateVbmeta(): BootV3 {
Avb.updateVbmeta(info.output) Avb.updateVbmeta(info.role)
return this return this
} }
@ -475,7 +522,8 @@ data class BootV3(
val alg = Algorithms.get(origSig.header!!.algorithm_type)!! val alg = Algorithms.get(origSig.header!!.algorithm_type)!!
ret.addArgument("--gki_signing_algorithm").addArgument(alg.name) ret.addArgument("--gki_signing_algorithm").addArgument(alg.name)
ret.addArgument("--gki_signing_key").addArgument(alg.defaultKey) ret.addArgument("--gki_signing_key").addArgument(alg.defaultKey)
ret.addArgument("--gki_signing_avbtool_path").addArgument(String.format(Helper.prop("avbtool")!!, "v1.2")) ret.addArgument("--gki_signing_avbtool_path")
.addArgument(String.format(Helper.prop("avbtool")!!, "v1.2"))
} }
ret.addArgument(" --id ") ret.addArgument(" --id ")
ret.addArgument(" --output ") ret.addArgument(" --output ")

@ -358,7 +358,7 @@ data class VendorBoot(
//ramdisk //ramdisk
//@formatter:off //@formatter:off
val fmt = C.dumpRamdisk( val fmt = C.dumpRamdisk(
Helper.Slice(info.output, ramdisk.position.toInt(), ramdisk.size, ramdisk.file), "${workDir}root", Helper.Slice(info.output, ramdisk.position.toInt(), ramdisk.size, ramdisk.file), File(workDir, "root").path,
this.ramdisk_table.ramdidks.isEmpty()) this.ramdisk_table.ramdidks.isEmpty())
//@formatter:on //@formatter:on
this.ramdisk.file = this.ramdisk.file + ".$fmt" this.ramdisk.file = this.ramdisk.file + ".$fmt"
@ -423,16 +423,16 @@ data class VendorBoot(
this.ramdisk_table.ramdidks.forEachIndexed { index, entry -> this.ramdisk_table.ramdidks.forEachIndexed { index, entry ->
//fancy ascii //fancy ascii
it.addRow("-- ${entry.type} ramdisk[${index + 1}/${this.ramdisk_table.ramdidks.size}]", entry.file) it.addRow("-- ${entry.type} ramdisk[${index + 1}/${this.ramdisk_table.ramdidks.size}]", entry.file)
it.addRow("------- extracted rootfs", "${workDir}root.${index + 1}") it.addRow("------- extracted rootfs", File(workDir, "root.${index + 1}").path)
//basic ascii //basic ascii
//@formatter:off //@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))
//@formatter:on //@formatter:on
prints.add(Pair(" ------- extracted rootfs", "${workDir}root.${index + 1}")) prints.add(Pair(" ------- extracted rootfs", File(workDir, "root.${index + 1}").path))
} }
} else { } else {
it.addRow("\\-- extracted ramdisk rootfs", "${workDir}root") it.addRow("\\-- extracted ramdisk rootfs", File(workDir, "root").path)
prints.add(Pair("\\-- extracted ramdisk rootfs", "${workDir}root")) prints.add(Pair("\\-- extracted ramdisk rootfs", File(workDir, "root").path))
} }
it.addRule() it.addRule()
if (this.dtb.size > 0) { if (this.dtb.size > 0) {

@ -157,11 +157,11 @@ class Payload {
ManifestInfo.DynamicPartGroup(name = it.name, size = it.size, partName = it.partitionNamesList) ManifestInfo.DynamicPartGroup(name = it.name, size = it.size, partName = it.partitionNamesList)
}) })
ObjectMapper().writerWithDefaultPrettyPrinter().writeValue(File("$workDir/header.json"), this.header) ObjectMapper().writerWithDefaultPrettyPrinter().writeValue(File("$workDir/header.json"), this.header)
log.info(" header info dumped to ${workDir}header.json") log.info(" header info dumped to " + File(workDir, "header.json").path)
ObjectMapper().writerWithDefaultPrettyPrinter().writeValue(File("$workDir/manifest.json"), mi) ObjectMapper().writerWithDefaultPrettyPrinter().writeValue(File("$workDir/manifest.json"), mi)
log.info(" manifest info dumped to ${workDir}manifest.json") log.info(" manifest info dumped to " + File(workDir, "manifest.json").path)
val signatureFile = "${workDir}signatures.txt" val signatureFile = File(workDir, "signatures.txt").path
FileOutputStream(signatureFile, false).use { fos -> FileOutputStream(signatureFile, false).use { fos ->
fos.writer().use { fWriter -> fos.writer().use { fWriter ->
fWriter.write("<Metadata> signatures: offset=" + this.header.manifestLen + ", size=" + this.header.metaSigLen + "\n") fWriter.write("<Metadata> signatures: offset=" + this.header.manifestLen + ", size=" + this.header.metaSigLen + "\n")

@ -27,6 +27,7 @@ import java.io.File
import java.io.FileInputStream import java.io.FileInputStream
import kotlin.io.path.Path import kotlin.io.path.Path
import kotlin.io.path.deleteIfExists import kotlin.io.path.deleteIfExists
import kotlin.system.exitProcess
class BootImgParser : IPackable { class BootImgParser : IPackable {
override val loopNo: Int override val loopNo: Int
@ -34,11 +35,25 @@ class BootImgParser : IPackable {
override fun capabilities(): List<String> { override fun capabilities(): List<String> {
//ramdisk.img : Issue #122 //ramdisk.img : Issue #122
return listOf("^boot(-debug)?\\.img$", "^recovery\\.img$", "^recovery-two-step\\.img$", "^init_boot\\.img$", "^ramdisk\\.img$") return listOf(
"^boot(-debug)?\\.img$",
"^recovery\\.img$",
"^recovery-two-step\\.img$",
"^init_boot\\.img$",
"^ramdisk\\.img$"
)
} }
override fun unpack(fileName: String) { override fun unpack(fileName: String) {
unpackInternal(fileName, fileName, outDir)
}
fun unpackInternal(targetFile: String, fileName: String, unpackDir: String) {
log.warn("Unpacking $fileName")
log.warn("fileName: $fileName, unpackDir: $unpackDir")
Helper.setProp("workDir", unpackDir)
clear() clear()
File("$outDir/role").writeText(File(File(fileName).canonicalPath).name)
val hv = probeHeaderVersion(fileName) val hv = probeHeaderVersion(fileName)
log.info("header version $hv") log.info("header version $hv")
when (hv) { when (hv) {
@ -50,6 +65,7 @@ class BootImgParser : IPackable {
.printUnpackSummary() .printUnpackSummary()
log.debug(b2.toString()) log.debug(b2.toString())
} }
in 3..4 -> { in 3..4 -> {
val b3 = BootV3 val b3 = BootV3
.parse(fileName) .parse(fileName)
@ -58,6 +74,7 @@ class BootImgParser : IPackable {
.printUnpackSummary() .printUnpackSummary()
log.debug(b3.toString()) log.debug(b3.toString())
} }
else -> { else -> {
val b2 = BootV2Dialects val b2 = BootV2Dialects
.parse(fileName) .parse(fileName)
@ -69,8 +86,10 @@ class BootImgParser : IPackable {
} }
} }
override fun pack(fileName: String) { fun packInternal(targetFile: String, workspace: String, fileName: String) {
val cfgFile = outDir + fileName.removeSuffix(".img") + ".json" log.warn("XXXX: 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") log.info("Loading config from $cfgFile")
if (!File(cfgFile).exists()) { if (!File(cfgFile).exists()) {
val tab = AsciiTable().let { val tab = AsciiTable().let {
@ -82,21 +101,47 @@ class BootImgParser : IPackable {
log.info("\n{}", tab.render()) log.info("\n{}", tab.render())
return return
} }
when (val hv = probeHeaderVersion(fileName)) {
0, 1, 2 -> val worker =
try {
ObjectMapper().readValue(File(cfgFile), BootV2::class.java) 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.warn("XXXX: worker is null")
exitProcess(2)
}
when (worker) {
is BootV2 -> {
worker
.pack() .pack()
.sign() .sign()
.updateVbmeta() .updateVbmeta()
.printPackSummary() .printPackSummary()
3, 4 -> }
ObjectMapper().readValue(File(cfgFile), BootV3::class.java)
is BootV3 -> {
worker
.pack() .pack()
.sign(fileName) .sign(fileName)
.updateVbmeta() .updateVbmeta()
.printPackSummary() .printPackSummary(fileName)
else -> throw IllegalArgumentException("do not support header version $hv")
} }
else -> {
log.error("unsupported boot image format")
exitProcess(2)
}
}
}
override fun pack(fileName: String) {
packInternal(fileName, outDir, fileName)
} }
override fun flash(fileName: String, deviceName: String) { override fun flash(fileName: String, deviceName: String) {
@ -122,7 +167,7 @@ class BootImgParser : IPackable {
} }
override fun `@verify`(fileName: String) { override fun `@verify`(fileName: String) {
File(Helper.prop("workDir")).let { File(Helper.prop("workDir")!!).let {
if (!it.exists()) { if (!it.exists()) {
it.mkdirs() it.mkdirs()
} }

@ -18,6 +18,7 @@ import rom.sparse.SparseImgParser
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import packable.DeviceTreeParser import packable.DeviceTreeParser
import java.io.File import java.io.File
import java.util.*
import java.util.regex.Pattern import java.util.regex.Pattern
import kotlin.reflect.KClass import kotlin.reflect.KClass
import kotlin.reflect.full.createInstance import kotlin.reflect.full.createInstance
@ -48,8 +49,33 @@ fun main(args: Array<String>) {
} }
var targetFile: String? = null var targetFile: String? = null
var targetHandler: KClass<IPackable>? = null var targetHandler: KClass<IPackable>? = null
log.info("XXXX: args: " + args.asList().toString())
run found@{ run found@{
for (currentLoopNo in 0..1) { //currently we have only 2 loops for (currentLoopNo in 0..1) { //currently we have only 2 loops
if (args.size > 1) { // manual mode
targetFile = if (File(args[1]).isFile) {
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())
exitProcess(1)
}
log.warn("manual mode: args= ${args[1]}, $targetFile")
packablePool
.filter { it.value.createInstance().loopNo == currentLoopNo }
.forEach { p ->
for (item in p.key) {
if (Pattern.compile(item).matcher(File(targetFile).name).matches()) {
log.info("Found: $targetFile, $item")
targetHandler = p.value
return@found
}
}
}
} else { // lazy mode
File(".").listFiles()!!.forEach { file -> File(".").listFiles()!!.forEach { file ->
packablePool packablePool
.filter { it.value.createInstance().loopNo == currentLoopNo } .filter { it.value.createInstance().loopNo == currentLoopNo }
@ -64,6 +90,7 @@ fun main(args: Array<String>) {
} }
} }
}//end-of-file-traversing }//end-of-file-traversing
}
}//end-of-range-loop }//end-of-range-loop
}//end-of-found@ }//end-of-found@
@ -71,8 +98,9 @@ fun main(args: Array<String>) {
// /* 2 */ no-args & handler : help for Handler // /* 2 */ no-args & handler : help for Handler
// /* 3 */ args & no-handler: do nothing // /* 3 */ args & no-handler: do nothing
// /* 4 */ args & handler : work // /* 4 */ args & handler : work
when (listOf(args.isEmpty(), targetHandler == null)) { when (listOf(args.isNotEmpty(), targetHandler != null)) {
listOf(true, true) -> { /* 1 */ listOf(false, false) -> { /* 1 */
log.warn("args: ${args.size}, targetHandler: $targetHandler")
log.info("help:") log.info("help:")
log.info("available IPackable subcommands are:") log.info("available IPackable subcommands are:")
IPackable::class.declaredFunctions.forEach { IPackable::class.declaredFunctions.forEach {
@ -81,7 +109,8 @@ fun main(args: Array<String>) {
exitProcess(1) exitProcess(1)
} }
listOf(true, false) -> {/* 2 */ listOf(false, true) -> {/* 2 */
log.warn("args: ${args.size}, targetHandler: $targetHandler")
log.info("available ${targetHandler!!.simpleName} subcommands are:") log.info("available ${targetHandler!!.simpleName} subcommands are:")
targetHandler!!.declaredFunctions.forEach { targetHandler!!.declaredFunctions.forEach {
log.info("\t" + it.name) log.info("\t" + it.name)
@ -89,13 +118,15 @@ fun main(args: Array<String>) {
exitProcess(1) exitProcess(1)
} }
listOf(false, true) -> {/* 3 */ listOf(true, false) -> {/* 3 */
log.warn("args: ${args.size}, targetHandler: $targetHandler")
log.warn("No handler is activated, DO NOTHING!") log.warn("No handler is activated, DO NOTHING!")
exitProcess(2) exitProcess(2)
} }
listOf(false, false) -> {/* 4 */ listOf(true, true) -> {/* 4 */
log.debug("continue ...") log.warn("args: ${args.size}, targetHandler: $targetHandler")
log.info("continue ...")
} }
} }
@ -111,12 +142,20 @@ fun main(args: Array<String>) {
exitProcess(3) exitProcess(3)
} }
log.warn("'${args[0]}' sequence initialized") 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) { val reflectRet = when (functions[0].parameters.size) {
1 -> { 1 -> {
log.warn("1: call null")
functions[0].call(it.createInstance()) functions[0].call(it.createInstance())
} }
2 -> { 2 -> {
log.warn("2: call $targetFile")
functions[0].call(it.createInstance(), targetFile!!) functions[0].call(it.createInstance(), targetFile!!)
} }
@ -141,6 +180,7 @@ fun main(args: Array<String>) {
if (functions[0].returnType.toString() != Unit.toString()) { if (functions[0].returnType.toString() != Unit.toString()) {
log.info("ret: $reflectRet") log.info("ret: $reflectRet")
} }
*/
log.warn("'${args[0]}' sequence completed") log.warn("'${args[0]}' sequence completed")
} }
} }

@ -30,7 +30,7 @@ class ErofsGenerator(inPartitionName: String) : BaseGenerator(inPartitionName, A
signingArgs = newArgs.toString() signingArgs = newArgs.toString()
val mkfsBin = "aosp/plugged/bin/mkfs.erofs" val mkfsBin = "aosp/plugged/bin/mkfs.erofs"
val fc = "${workDir}file_contexts" val fc = File(workDir, "file_contexts").path
val cmd = CommandLine.parse(mkfsBin).apply { val cmd = CommandLine.parse(mkfsBin).apply {
addArguments("-z lz4hc,9") addArguments("-z lz4hc,9")
addArguments("--mount-point $mount_point") addArguments("--mount-point $mount_point")

@ -123,7 +123,7 @@ class Ext4Generator(inPartitionName: String = "NA") : BaseGenerator(partitionNam
addArguments("-e") addArguments("-e")
addArguments("-p out/target/product/shiba/system") addArguments("-p out/target/product/shiba/system")
addArgument("-s") addArgument("-s")
addArguments("-S ${workDir}file_contexts.bin") addArguments("-S " + File(workDir, "file_contexts.bin").path)
addArguments("-f " + Helper.prop("workDir") + "/$mount_point") addArguments("-f " + Helper.prop("workDir") + "/$mount_point")
addArguments("-a /$mount_point") addArguments("-a /$mount_point")
addArgument(outFile) addArgument(outFile)

@ -33,8 +33,8 @@ data class SparseImage(var info: SparseInfo = SparseInfo()) {
readBackAi, readBackAi,
partName, partName,
workDir, workDir,
workDir + File(info.output).nameWithoutExtension, File(workDir, File(info.output).nameWithoutExtension).path,
workDir + File(info.pulp).name + ".signed" File(workDir, File(info.pulp).name + ".signed").path
) )
} }
@ -43,8 +43,8 @@ data class SparseImage(var info: SparseInfo = SparseInfo()) {
readBackAi, readBackAi,
partName, partName,
workDir, workDir,
workDir + File(info.output).nameWithoutExtension, File(workDir, File(info.output).nameWithoutExtension).path,
workDir + "${info.output}.signed" File(workDir, "${info.output}.signed").path
) )
} }
@ -66,26 +66,26 @@ data class SparseImage(var info: SparseInfo = SparseInfo()) {
addRow("What", "Where") addRow("What", "Where")
addRule() addRule()
addRow("image (${info.outerFsType})", fileName) addRow("image (${info.outerFsType})", fileName)
("${workDir}$stem.ext4").let { ext4 -> File(workDir, "$stem.ext4").path.let { ext4 ->
if (File(ext4).exists()) { if (File(ext4).exists()) {
addRule() addRule()
addRow("converted image (ext4)", ext4) addRow("converted image (ext4)", ext4)
} }
} }
("${workDir}$stem.erofs").let { File(workDir, "$stem.erofs").path.let {
if (File(it).exists()) { if (File(it).exists()) {
addRule() addRule()
addRow("converted image (erofs)", it) addRow("converted image (erofs)", it)
tail.addRule() tail.addRule()
tail.addRow("sudo mount $it -o loop -t erofs ${workDir}mount") tail.addRow("sudo mount $it -o loop -t erofs " + File(workDir, "mount").path)
tail.addRule() tail.addRule()
} else if (info.innerFsType == "erofs") { } else if (info.innerFsType == "erofs") {
tail.addRule() tail.addRule()
tail.addRow("sudo mount $fileName -o loop -t erofs ${workDir}mount") tail.addRow("sudo mount $fileName -o loop -t erofs " + File(workDir, "mount").path)
tail.addRule() tail.addRule()
} }
} }
("${workDir}$stem").let { File(workDir, "$stem").path.let {
if (File(it).exists()) { if (File(it).exists()) {
addRule() addRule()
if (File(it).isFile) { if (File(it).isFile) {
@ -95,7 +95,7 @@ data class SparseImage(var info: SparseInfo = SparseInfo()) {
} }
} }
} }
("${workDir}$stem.log").let { File(workDir, "$stem.log").path.let {
if (File(it).exists()) { if (File(it).exists()) {
addRule() addRule()
addRow("log", it) addRow("log", it)
@ -103,7 +103,7 @@ data class SparseImage(var info: SparseInfo = SparseInfo()) {
} }
if (info.innerFsType == "erofs") { if (info.innerFsType == "erofs") {
addRule() addRule()
addRow("mount point", "${workDir}mount") addRow("mount point", File(workDir, "mount").path)
} }
addRule() addRule()
} }
@ -117,7 +117,7 @@ data class SparseImage(var info: SparseInfo = SparseInfo()) {
fun unwrap(): SparseImage { fun unwrap(): SparseImage {
if (info.outerFsType == "sparse") { if (info.outerFsType == "sparse") {
img2simg(workDir + File(info.output).name + ".signed", File(info.output).name + ".signed") img2simg(File(workDir, (File(info.output).name + ".signed")).path, File(info.output).name + ".signed")
} else { } else {
val s = info.pulp + ".signed" val s = info.pulp + ".signed"
val t = info.output + ".signed" val t = info.output + ".signed"

@ -32,8 +32,8 @@ class KernelExtractor {
fun run(fileName: String, workDir: File? = null): List<String> { fun run(fileName: String, workDir: File? = null): List<String> {
val ret: MutableList<String> = mutableListOf() val ret: MutableList<String> = mutableListOf()
val kernelVersionFile = Helper.prop("kernelVersionFile")!! val kernelVersionFile = File(Helper.prop("workDir")!! , Helper.prop("kernelVersionStem")!!).toString()
val kernelConfigFile = Helper.prop("kernelConfigFile")!! val kernelConfigFile = File(Helper.prop("workDir")!! , Helper.prop("kernelConfigStem")!!).toString()
val cmdPrefix = if (EnvironmentVerifier().isWindows) "python " else "" val cmdPrefix = if (EnvironmentVerifier().isWindows) "python " else ""
val cmd = CommandLine.parse(cmdPrefix + Helper.prop("kernelExtracter")).let { val cmd = CommandLine.parse(cmdPrefix + Helper.prop("kernelExtracter")).let {
it.addArgument("--input") it.addArgument("--input")

@ -6,6 +6,8 @@ verity_pk8 = aosp/security/verity.pk8
verity_pem = aosp/security/verity.x509.pem verity_pem = aosp/security/verity.x509.pem
kernelVersionFile = build/unzip_boot/kernel_version.txt kernelVersionFile = build/unzip_boot/kernel_version.txt
kernelConfigFile = build/unzip_boot/kernel_configs.txt kernelConfigFile = build/unzip_boot/kernel_configs.txt
kernelVersionStem = kernel_version.txt
kernelConfigStem = kernel_configs.txt
kernelExtracter = aosp/make/tools/extract_kernel.py kernelExtracter = aosp/make/tools/extract_kernel.py
mkbootimg = aosp/system/tools/mkbootimg/mkbootimg.py mkbootimg = aosp/system/tools/mkbootimg/mkbootimg.py
dtboMaker = aosp/system/libufdt/utils/src/mkdtboimg.py dtboMaker = aosp/system/libufdt/utils/src/mkdtboimg.py

@ -21,9 +21,10 @@ should be compatible with "/usr/bin/env sh"
## TODO: command line usage ## TODO: command line usage
unpack unpack
``` ```
abe unpack boot.img abe unpack boot.img out
``` ```
pack pack
``` ```
abe pack abe pack out boot.img
``` ```

@ -23,6 +23,7 @@ import org.slf4j.LoggerFactory
import java.io.* import java.io.*
import java.nio.ByteBuffer import java.nio.ByteBuffer
import java.nio.ByteOrder import java.nio.ByteOrder
import java.nio.file.Paths
import java.nio.file.attribute.PosixFilePermission import java.nio.file.attribute.PosixFilePermission
import java.security.MessageDigest import java.security.MessageDigest
import java.util.* import java.util.*
@ -47,6 +48,15 @@ class Helper {
return gcfg.getProperty(k) return gcfg.getProperty(k)
} }
fun setProp(k: String, v: String) {
gcfg.setProperty(k, v)
}
fun joinPath(vararg args: String): String {
val joinedPath = Paths.get("", *args)
return joinedPath.normalize().toString()
}
fun joinWithNulls(vararg source: ByteArray?): ByteArray { fun joinWithNulls(vararg source: ByteArray?): ByteArray {
val baos = ByteArrayOutputStream() val baos = ByteArrayOutputStream()
for (src in source) { for (src in source) {

@ -22,6 +22,8 @@ fun main(args: Array<String>) {
println("bootchart: generate Android bootchart") println("bootchart: generate Android bootchart")
println("pidstat : given a pid, profile its CPU usage") println("pidstat : given a pid, profile its CPU usage")
println("tracecmd : analyze trace-cmd report") println("tracecmd : analyze trace-cmd report")
println("cpuinfo : get cpu info from /sys/devices/system/cpu/")
println("sysinfo : get overall system info from Android")
exitProcess(0) exitProcess(0)
} }
if (args[0] == "cpuinfo") { if (args[0] == "cpuinfo") {

Loading…
Cancel
Save