generalize command recognization/invocation

Now we can directly call "java -jar bbootimg.jar".
Also add hidden command '@footer' in BootImgParser
pull/41/head
cfig 5 years ago
parent 67667c803c
commit 40a31fd655
No known key found for this signature in database
GPG Key ID: B104C307F0FDABB7

@ -20,6 +20,7 @@ Supported images:
- recovery.img (also recovery-two-step.img)
- vbmeta.img (also vbmeta\_system.img, vbmeta\_vendor.img etc.)
- dtbo.img (only 'unpack' is supported)
- sparse images (system.img, vendor.img ...)
(2) These utilities are known to work for Nexus/Pixel boot.img for the following Android releases:
@ -85,7 +86,7 @@ We now support both VB 1.0 and AVB 2.0 layouts.
| Pixel 3 (blueline) | Google | Y | Q preview (qpp2.190228.023, <Br>2019)| [more ...](doc/additional_tricks.md#pixel-3-blueline) |
| Pixel XL (marlin) | HTC | Y | 9.0.0 (PPR2.180905.006, <Br>Sep 2018)| [more ...](doc/additional_tricks.md#pixel-xl-marlin) |
| K3 (CPH1955) | OPPO | Y for recovery.img<Br> N for boot.img | Pie | [more](doc/additional_tricks.md#k3-cph1955) |
| Z18(NX606J) | ZTE | Y | 8.1.0 | [more...](doc/additional_tricks.md#nx606j) |
| Z18 (NX606J) | ZTE | Y | 8.1.0 | [more...](doc/additional_tricks.md#nx606j) |
| Nexus 9 (volantis/flounder) | HTC | Y(with some tricks) | 7.1.1 (N9F27M, Oct 2017) | [tricks](doc/additional_tricks.md#tricks-for-nexus-9volantis)|
| Nexus 5x (bullhead) | LG | Y | 6.0.0_r12 (MDA89E) | |
| Moto X (2013) T-Mobile | Motorola | N | | |
@ -116,3 +117,6 @@ https://android.googlesource.com/platform/system/libufdt/
libsparse
https://android.googlesource.com/platform/system/core/+/refs/heads/master/libsparse/
Android Nexus/Pixle factory images
https://developers.google.cn/android/images

@ -1,12 +1,14 @@
package cfig.packable
import avb.AVBInfo
import avb.blob.Footer
import cfig.*
import cfig.bootimg.BootImgInfo
import com.fasterxml.jackson.databind.ObjectMapper
import de.vandermeer.asciitable.AsciiTable
import org.slf4j.LoggerFactory
import java.io.File
import java.io.FileInputStream
import java.lang.IllegalArgumentException
@ExperimentalUnsignedTypes
@ -20,18 +22,17 @@ class BootImgParser() : IPackable {
}
private fun unpackVBMeta(): Boolean {
if (File("vbmeta.img").exists()) {
return if (File("vbmeta.img").exists()) {
log.warn("Found vbmeta.img, parsing ...")
VBMetaParser().unpack("vbmeta.img")
return true
true
} else {
return false
false
}
}
override fun unpack(fileName: String) {
if (File(UnifiedConfig.workDir).exists()) File(UnifiedConfig.workDir).deleteRecursively()
File(UnifiedConfig.workDir).mkdirs()
cleanUp()
try {
val info = Parser().parseBootImgHeader(fileName, avbtool = "aosp/avb/avbtool")
InfoTable.instance.addRule()
@ -98,4 +99,17 @@ class BootImgParser() : IPackable {
val stem = fileName.substring(0, fileName.indexOf("."))
super.flash("$fileName.signed", stem)
}
// invoked solely by reflection
fun `@footer`(image_file: String) {
FileInputStream(image_file).use { fis ->
fis.skip(File(image_file).length() - Footer.SIZE)
try {
val footer = Footer(fis)
log.info("\n" + ObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(footer))
} catch (e: IllegalArgumentException) {
log.info("image $image_file has no AVB Footer")
}
}
}
}

@ -25,6 +25,7 @@ class DtboParser(val workDir: File) : IPackable {
}
override fun unpack(fileName: String) {
cleanUp()
val outputDir = UnifiedConfig.workDir
val dtbPath = File("$outputDir/dtb").path!!
val headerPath = File("$outputDir/dtbo.header").path!!

@ -2,8 +2,10 @@ package cfig.packable
import cfig.Helper.Companion.check_call
import cfig.Helper.Companion.check_output
import cfig.UnifiedConfig
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import java.io.File
@ExperimentalUnsignedTypes
interface IPackable {
@ -29,6 +31,11 @@ interface IPackable {
"adb shell rm /cache/file.to.burn".check_call()
}
fun cleanUp() {
if (File(UnifiedConfig.workDir).exists()) File(UnifiedConfig.workDir).deleteRecursively()
File(UnifiedConfig.workDir).mkdirs()
}
companion object {
val log: Logger = LoggerFactory.getLogger(IPackable::class.java)
}

@ -1,12 +1,13 @@
package cfig.packable
import cfig.UnifiedConfig
import cfig.sparse_util.SparseImg
import cfig.sparse_util.SparseImgParser
import org.slf4j.LoggerFactory
import java.io.File
import java.util.regex.Pattern
import kotlin.reflect.KClass
import kotlin.reflect.full.createInstance
import kotlin.reflect.full.declaredFunctions
import kotlin.system.exitProcess
class PackableLauncher
@ -14,7 +15,7 @@ class PackableLauncher
fun main(args: Array<String>) {
val log = LoggerFactory.getLogger(PackableLauncher::class.java)
val packablePool = mutableMapOf<List<String>, KClass<IPackable>>()
listOf(DtboParser(), VBMetaParser(), BootImgParser(), SparseImg()).forEach {
listOf(DtboParser(), VBMetaParser(), BootImgParser(), SparseImgParser()).forEach {
@Suppress("UNCHECKED_CAST")
packablePool.put(it.capabilities(), it::class as KClass<IPackable>)
}
@ -24,56 +25,83 @@ fun main(args: Array<String>) {
var targetFile: String? = null
var targetHandler: KClass<IPackable>? = null
run found@{
File(".").listFiles().forEach { file ->
packablePool
.filter { it.value.createInstance().loopNo == 0 }
.forEach { p ->
for (item in p.key) {
if (Pattern.compile(item).matcher(file.name).matches()) {
log.debug("Found: " + file.name + ", " + item)
targetFile = file.name
targetHandler = p.value
return@found
for (currentLoopNo in 0..1) { //currently we have only 2 loops
File(".").listFiles()!!.forEach { file ->
packablePool
.filter { it.value.createInstance().loopNo == currentLoopNo }
.forEach { p ->
for (item in p.key) {
if (Pattern.compile(item).matcher(file.name).matches()) {
log.debug("Found: " + file.name + ", " + item)
targetFile = file.name
targetHandler = p.value
return@found
}
}
}
}
}
}//end-of-file-traversing
}//end-of-range-loop
}//end-of-found@
File(".").listFiles().forEach { file ->
packablePool
.filter { it.value.createInstance().loopNo != 0 }
.forEach { p ->
for (item in p.key) {
if (Pattern.compile(item).matcher(file.name).matches()) {
log.debug("Found: " + file.name + ", " + item)
targetFile = file.name
targetHandler = p.value
return@found
}
}
}
// /* 1 */ no-args & no-handler: help for IPackable
// /* 2 */ no-args & handler : help for Handler
// /* 3 */ args & no-handler: do nothing
// /* 4 */ args & handler : work
when (listOf(args.isEmpty(), targetHandler == null)) {
listOf(true, true) -> { /* 1 */
log.info("help:")
log.info("available IPackable subcommands are:")
IPackable::class.declaredFunctions.forEach {
log.info("\t" + it.name)
}
exitProcess(1)
}
listOf(true, false) -> {/* 2 */
log.info("available ${targetHandler!!.simpleName} subcommands are:")
targetHandler!!.declaredFunctions.forEach {
log.info("\t" + it.name)
}
exitProcess(1)
}
listOf(false, true) -> {/* 3 */
log.warn("No handler is activated, DO NOTHING!")
exitProcess(2)
}
listOf(false, false) -> {/* 4 */
log.debug("continue ...")
}
}
if (targetHandler != null) {
log.warn("Active image target: $targetFile")
when (args[0]) {
"unpack" -> {
if (File(UnifiedConfig.workDir).exists()) File(UnifiedConfig.workDir).deleteRecursively()
File(UnifiedConfig.workDir).mkdirs()
targetHandler!!.createInstance().unpack(targetFile!!)
targetHandler?.let {
log.warn("[$targetFile] will be handled by [${it.simpleName}]")
val functions = it.declaredFunctions.filter { funcItem -> funcItem.name == args[0] }
if (functions.size != 1) {
log.error("command '${args[0]}' can not be recognized")
log.info("available ${it.simpleName} subcommands are:")
it.declaredFunctions.forEach {
log.info("\t" + it.name)
}
"pack" -> {
targetHandler!!.createInstance().pack(targetFile!!)
exitProcess(3)
}
log.warn("'${args[0]}' sequence initialized")
val reflectRet = when (functions[0].parameters.size) {
1 -> {
functions[0].call(it.createInstance())
}
"flash" -> {
targetHandler!!.createInstance().flash(targetFile!!)
2 -> {
functions[0].call(it.createInstance(), targetFile!!)
}
else -> {
log.error("Unknown cmd: " + args[0])
functions[0].parameters.forEach { kp ->
println("Param: " + kp.index + " " + kp.type + " " + kp.name)
}
log.error("I am confused by so many parameters")
exitProcess(4)
}
}
} else {
log.warn("Nothing to do")
if (functions[0].returnType.toString() != Unit.toString()) {
log.info("ret: $reflectRet")
}
log.warn("'${args[0]}' sequence completed")
}
}

@ -1,6 +1,8 @@
package cfig.packable
import cfig.Avb
import cfig.UnifiedConfig
import java.io.File
@ExperimentalUnsignedTypes
class VBMetaParser: IPackable {
@ -11,7 +13,12 @@ class VBMetaParser: IPackable {
return listOf("^vbmeta\\.img$", "^vbmeta\\_[a-z]+.img$")
}
override fun cleanUp() {
File(UnifiedConfig.workDir).mkdirs()
}
override fun unpack(fileName: String) {
cleanUp()
Avb().parseVbMeta(fileName)
}

@ -6,10 +6,10 @@ import org.slf4j.LoggerFactory
import cfig.Helper.Companion.check_call
@ExperimentalUnsignedTypes
class SparseImg : IPackable {
class SparseImgParser : IPackable {
override val loopNo: Int
get() = 0
private val log = LoggerFactory.getLogger(SparseImg::class.java)
private val log = LoggerFactory.getLogger(SparseImgParser::class.java)
private val simg2imgBin: String
private val img2simgBin: String
@ -24,6 +24,7 @@ class SparseImg : IPackable {
}
override fun unpack(fileName: String) {
cleanUp()
simg2img(fileName, "$fileName.unsparse")
}

@ -34,10 +34,12 @@ def cleanUp():
deleteIfExists("boot.img.clear")
deleteIfExists("boot.img.google")
deleteIfExists("boot.img.signed")
deleteIfExists("boot.img.signed2")
deleteIfExists("recovery.img")
deleteIfExists("recovery.img.clear")
deleteIfExists("recovery.img.google")
deleteIfExists("recovery.img.signed")
deleteIfExists("recovery.img.signed2")
deleteIfExists("vbmeta.img")
deleteIfExists("vbmeta.img.signed")

Loading…
Cancel
Save