parent
3c6ad3de94
commit
f03315b08a
@ -0,0 +1,13 @@
|
||||
t:
|
||||
external/extract_kernel.py \
|
||||
--input build/unzip_boot/kernel \
|
||||
--output-configs kernel_configs.txt \
|
||||
--output-version kernel_version.txt
|
||||
|
||||
t2:
|
||||
rm -fr dtbo
|
||||
mkdir dtbo
|
||||
external/mkdtboimg.py \
|
||||
dump dtbo.img \
|
||||
--dtb dtbo/dtb.dump \
|
||||
--output dtbo/header.dump
|
@ -0,0 +1,77 @@
|
||||
package cfig
|
||||
|
||||
import org.apache.commons.exec.CommandLine
|
||||
import org.apache.commons.exec.DefaultExecutor
|
||||
import org.apache.commons.exec.PumpStreamHandler
|
||||
import org.slf4j.LoggerFactory
|
||||
import java.io.ByteArrayOutputStream
|
||||
|
||||
class EnvironmentVerifier {
|
||||
val hasXz: Boolean
|
||||
get() : Boolean {
|
||||
try {
|
||||
val outputStream = ByteArrayOutputStream()
|
||||
val exec = DefaultExecutor()
|
||||
exec.streamHandler = PumpStreamHandler(outputStream)
|
||||
exec.execute(CommandLine.parse("xz --version"))
|
||||
val os = outputStream.toString().trim()
|
||||
log.debug(os)
|
||||
log.debug("xz available")
|
||||
} catch (e: Exception) {
|
||||
log.warn("'xz' not installed. Please install it manually to analyze DTB files")
|
||||
if (isMacOS) {
|
||||
log.warn("For Mac OS: \n\n\tbrew install xz\n")
|
||||
}
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
val hasGzip: Boolean
|
||||
get(): Boolean {
|
||||
try {
|
||||
Runtime.getRuntime().exec("gzip -V")
|
||||
log.debug("gzip available")
|
||||
} catch (e: Exception) {
|
||||
log.warn("gzip unavailable")
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
val hasLz4: Boolean
|
||||
get() : Boolean {
|
||||
try {
|
||||
Runtime.getRuntime().exec("lz4 --version")
|
||||
log.debug("lz4 available")
|
||||
} catch (e: Exception) {
|
||||
log.warn("lz4 not installed")
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
val hasDtc: Boolean
|
||||
get(): Boolean {
|
||||
try {
|
||||
Runtime.getRuntime().exec("dtc --version")
|
||||
log.debug("dtc available")
|
||||
} catch (e: Exception) {
|
||||
log.warn("'dtc' not installed. Please install it manually to analyze DTB files")
|
||||
if (isMacOS) {
|
||||
log.warn("For Mac OS: \n\n\tbrew install dtc\n")
|
||||
} else {
|
||||
log.warn("Like this: \n\n\t$ sudo apt install device-tree-compiler")
|
||||
}
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
val isMacOS: Boolean
|
||||
get() = System.getProperty("os.name").contains("Mac")
|
||||
|
||||
companion object {
|
||||
private val log = LoggerFactory.getLogger("EnvironmentVerifier")
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
package cfig.dtb_util
|
||||
|
||||
import org.apache.commons.exec.CommandLine
|
||||
import org.apache.commons.exec.DefaultExecutor
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
class DTC {
|
||||
private val log = LoggerFactory.getLogger(DTC::class.java)
|
||||
|
||||
fun decompile(dtbFile: String, outFile: String): Boolean {
|
||||
log.info("parsing DTB: $dtbFile")
|
||||
val cmd = CommandLine.parse("dtc -I dtb -O dts").let {
|
||||
it.addArguments("$dtbFile")
|
||||
it.addArguments("-o $outFile")
|
||||
}
|
||||
|
||||
CommandLine.parse("fdtdump").let {
|
||||
it.addArguments("$dtbFile")
|
||||
}
|
||||
|
||||
DefaultExecutor().let {
|
||||
try {
|
||||
it.execute(cmd)
|
||||
log.info(cmd.toString())
|
||||
} catch (e: org.apache.commons.exec.ExecuteException) {
|
||||
log.error("can not parse DTB: $dtbFile")
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
fun compile(dtsFile: String, outFile: String): Boolean {
|
||||
log.info("compiling DTS: $dtsFile")
|
||||
val cmd = CommandLine.parse("dtc -I dts -O dtb").let {
|
||||
it.addArguments("$dtsFile")
|
||||
it.addArguments("-o $outFile")
|
||||
}
|
||||
|
||||
DefaultExecutor().let {
|
||||
try {
|
||||
it.execute(cmd)
|
||||
log.info(cmd.toString())
|
||||
} catch (e: org.apache.commons.exec.ExecuteException) {
|
||||
log.error("can not compile DTB: $dtsFile")
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
package cfig.packable
|
||||
|
||||
import cfig.*
|
||||
import cfig.bootimg.BootImgInfo
|
||||
import de.vandermeer.asciitable.AsciiTable
|
||||
import org.slf4j.LoggerFactory
|
||||
import java.io.File
|
||||
import java.lang.IllegalArgumentException
|
||||
|
||||
class BootImgParser : IPackable {
|
||||
private val log = LoggerFactory.getLogger(BootImgParser::class.java)
|
||||
|
||||
override fun capabilities(): List<String> {
|
||||
return listOf("^boot\\.img$", "^recovery\\.img$")
|
||||
}
|
||||
|
||||
override fun unpack(fileName: String) {
|
||||
if (File(UnifiedConfig.workDir).exists()) File(UnifiedConfig.workDir).deleteRecursively()
|
||||
File(UnifiedConfig.workDir).mkdirs()
|
||||
try {
|
||||
val info = Parser().parseBootImgHeader(fileName, avbtool = "avb/avbtool")
|
||||
InfoTable.instance.addRule()
|
||||
InfoTable.instance.addRow("image info", ParamConfig().cfg)
|
||||
if (info.signatureType == BootImgInfo.VerifyType.AVB) {
|
||||
log.info("continue to analyze vbmeta info in $fileName")
|
||||
Avb().parseVbMeta(fileName)
|
||||
InfoTable.instance.addRule()
|
||||
InfoTable.instance.addRow("AVB info", Avb.getJsonFileName(fileName))
|
||||
}
|
||||
Parser().extractBootImg(fileName, info2 = info)
|
||||
|
||||
InfoTable.instance.addRule()
|
||||
val tableHeader = AsciiTable().apply {
|
||||
addRule()
|
||||
addRow("What", "Where")
|
||||
addRule()
|
||||
}
|
||||
log.info("\n\t\t\tUnpack Summary of $fileName\n{}\n{}", tableHeader.render(), InfoTable.instance.render())
|
||||
log.info("Following components are not present: ${InfoTable.missingParts}")
|
||||
} catch (e: IllegalArgumentException) {
|
||||
log.error(e.message)
|
||||
log.error("Parser can not continue")
|
||||
}
|
||||
}
|
||||
|
||||
override fun pack(fileName: String) {
|
||||
Packer().pack(mkbootfsBin = "mkbootfs/build/exe/mkbootfs/mkbootfs")
|
||||
Signer.sign(avbtool = "avb/avbtool", bootSigner = "boot_signer/build/libs/boot_signer.jar")
|
||||
}
|
||||
}
|
@ -0,0 +1,85 @@
|
||||
package cfig.packable
|
||||
|
||||
import cfig.EnvironmentVerifier
|
||||
import cfig.UnifiedConfig
|
||||
import cfig.dtb_util.DTC
|
||||
import org.apache.commons.exec.CommandLine
|
||||
import org.apache.commons.exec.DefaultExecutor
|
||||
import org.slf4j.LoggerFactory
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
import java.util.*
|
||||
|
||||
class DtboParser(val workDir: File) : IPackable {
|
||||
constructor() : this(File("."))
|
||||
|
||||
private val log = LoggerFactory.getLogger(DtboParser::class.java)
|
||||
private val envv = EnvironmentVerifier()
|
||||
|
||||
override fun capabilities(): List<String> {
|
||||
return listOf("^dtbo\\.img$")
|
||||
}
|
||||
|
||||
override fun unpack(fileName: String) {
|
||||
val outputDir = UnifiedConfig.workDir
|
||||
val dtbPath = File("$outputDir/dtb").path!!
|
||||
val headerPath = File("$outputDir/dtbo.header").path!!
|
||||
val cmd = CommandLine.parse("external/mkdtboimg.py dump $fileName").let {
|
||||
it.addArguments("--dtb $dtbPath")
|
||||
it.addArguments("--output $headerPath")
|
||||
}
|
||||
|
||||
DefaultExecutor().let {
|
||||
it.workingDirectory = this.workDir
|
||||
try {
|
||||
log.info(cmd.toString())
|
||||
it.execute(cmd)
|
||||
} catch (e: org.apache.commons.exec.ExecuteException) {
|
||||
log.error("can not parse $fileName")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
val props = Properties()
|
||||
props.load(FileInputStream(File(headerPath)))
|
||||
if (envv.hasDtc) {
|
||||
for (i in 0 until Integer.parseInt(props.getProperty("dt_entry_count"))) {
|
||||
val inputDtb = "$dtbPath.$i"
|
||||
val outputSrc = File(UnifiedConfig.workDir + "/" + File(inputDtb).name + ".src").path
|
||||
DTC().decompile(inputDtb, outputSrc)
|
||||
}
|
||||
} else {
|
||||
log.error("'dtc' is unavailable, task aborted")
|
||||
}
|
||||
}
|
||||
|
||||
override fun pack(fileName: String) {
|
||||
if (!envv.hasDtc) {
|
||||
log.error("'dtc' is unavailable, task aborted")
|
||||
return
|
||||
}
|
||||
|
||||
val headerPath = File("${UnifiedConfig.workDir}/dtbo.header").path!!
|
||||
val props = Properties()
|
||||
props.load(FileInputStream(File(headerPath)))
|
||||
val cmd = CommandLine.parse("external/mkdtboimg.py create $fileName.clear").let {
|
||||
it.addArguments("--version=1")
|
||||
for (i in 0 until Integer.parseInt(props.getProperty("dt_entry_count"))) {
|
||||
val dtsName = File(UnifiedConfig.workDir + "/dtb.$i").path
|
||||
it.addArguments("$dtsName")
|
||||
}
|
||||
it
|
||||
}
|
||||
|
||||
DefaultExecutor().let {
|
||||
it.workingDirectory = this.workDir
|
||||
try {
|
||||
log.info(cmd.toString())
|
||||
it.execute(cmd)
|
||||
} catch (e: org.apache.commons.exec.ExecuteException) {
|
||||
log.error("can not parse $fileName")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package cfig.packable
|
||||
|
||||
interface IPackable {
|
||||
fun capabilities(): List<String> {
|
||||
return listOf("^dtbo\\.img$")
|
||||
}
|
||||
fun unpack(fileName: String = "dtbo.img")
|
||||
fun pack(fileName: String = "dtbo.img")
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
package cfig.packable
|
||||
|
||||
import cfig.UnifiedConfig
|
||||
import org.slf4j.LoggerFactory
|
||||
import java.io.File
|
||||
import java.util.regex.Pattern
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.full.createInstance
|
||||
|
||||
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()).forEach {
|
||||
packablePool.put(it.capabilities(), it::class as KClass<IPackable>)
|
||||
}
|
||||
packablePool.forEach {
|
||||
log.debug("" + it.key + "/" + it.value)
|
||||
}
|
||||
var targetFile: String? = null
|
||||
var targetHandler: KClass<IPackable>? = null
|
||||
run found@{
|
||||
File(".").listFiles().forEach { file ->
|
||||
packablePool.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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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!!)
|
||||
}
|
||||
"pack" -> {
|
||||
targetHandler!!.createInstance().pack(targetFile!!)
|
||||
}
|
||||
else -> {
|
||||
log.error("Unknown cmd: " + args[0])
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.warn("Nothing to do")
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package cfig.packable
|
||||
|
||||
import cfig.Avb
|
||||
|
||||
class VBMetaParser: IPackable {
|
||||
override fun capabilities(): List<String> {
|
||||
return listOf("^vbmeta\\.img$")
|
||||
}
|
||||
|
||||
override fun unpack(fileName: String) {
|
||||
Avb().parseVbMeta(fileName)
|
||||
}
|
||||
|
||||
override fun pack(fileName: String) {
|
||||
Avb().packVbMetaWithPadding()
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
import cfig.EnvironmentVerifier
|
||||
import org.junit.Test
|
||||
|
||||
import org.junit.Assert.*
|
||||
import org.junit.Before
|
||||
|
||||
class EnvironmentVerifierTest {
|
||||
private val envv = EnvironmentVerifier()
|
||||
|
||||
@Test
|
||||
fun getHasLz4() {
|
||||
val hasLz4 = envv.hasLz4
|
||||
println("hasLz4 = $hasLz4")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getHasDtc() {
|
||||
val hasDtc = envv.hasDtc
|
||||
println("hasDtc = $hasDtc")
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getHasXz() {
|
||||
val hasXz = envv.hasXz
|
||||
println("hasXz = $hasXz")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getGzip() {
|
||||
val h = envv.hasGzip
|
||||
println("hasGzip = $h")
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
1c1
|
||||
< #!/usr/bin/env python
|
||||
---
|
||||
> #!/usr/bin/env python2.7
|
||||
181c181
|
||||
< "Cannot extract kernel configs in {}".format(args.input.name))
|
||||
---
|
||||
> "Cannot extract kernel configs in {}\n".format(args.input.name))
|
||||
189c189
|
||||
< "Cannot extract kernel versions in {}".format(args.input.name))
|
||||
---
|
||||
> "Cannot extract kernel versions in {}\n".format(args.input.name))
|
File diff suppressed because it is too large
Load Diff
@ -1 +1 @@
|
||||
Subproject commit 3cddd2559cb7965abf96f2bbd6b3469a959abf63
|
||||
Subproject commit b33e958f598f8cb56df60a6f50654c09e85b4996
|
@ -0,0 +1,5 @@
|
||||
#!/bin/bash
|
||||
set -x
|
||||
|
||||
git submodule init
|
||||
git submodule update
|
Loading…
Reference in New Issue