routine mass checkin

- VirtualABMsg: read and parse VAB info from misc
- Clear some detekt warnings
- dtbo: supress warnings
pull/80/head
cfig 4 years ago
parent 62bc8004c4
commit 1e2592c1c4
No known key found for this signature in database
GPG Key ID: B104C307F0FDABB7

3
.gitignore vendored

@ -1,5 +1,4 @@
.idea .idea
.gradle .gradle
build/ build/
boot.img* local.properties
local.properties

@ -10,7 +10,7 @@ A tool for reverse engineering Android ROM images.
Mac: `brew install lz4 xz dtc` Mac: `brew install lz4 xz dtc`
Linux: `sudo apt install git device-tree-compiler lz4 xz-utils zlib1g-dev openjdk-11-jdk gcc g++ python3` Linux: `sudo apt install git device-tree-compiler lz4 xz-utils zlib1g-dev openjdk-11-jdk gcc g++ python3 python-is-python3`
Windows Subsystem for Linux(WSL): `sudo apt install git device-tree-compiler lz4 xz-utils zlib1g-dev openjdk-11-jdk gcc g++ python` Windows Subsystem for Linux(WSL): `sudo apt install git device-tree-compiler lz4 xz-utils zlib1g-dev openjdk-11-jdk gcc g++ python`

@ -15,7 +15,7 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins { plugins {
kotlin("jvm") version "1.5.30" kotlin("jvm") version "1.5.31"
application application
} }
@ -56,7 +56,10 @@ application {
} }
tasks.withType<KotlinCompile>().all { tasks.withType<KotlinCompile>().all {
kotlinOptions.freeCompilerArgs += "-Xopt-in=kotlin.RequiresOptIn" kotlinOptions {
freeCompilerArgs += "-Xopt-in=kotlin.RequiresOptIn"
jvmTarget = "11"
}
} }
tasks { tasks {

@ -88,121 +88,93 @@ class AVBInfo(
private val log = LoggerFactory.getLogger(AVBInfo::class.java) private val log = LoggerFactory.getLogger(AVBInfo::class.java)
private val mapper = ObjectMapper() private val mapper = ObjectMapper()
fun parseFrom(imageFile: String): AVBInfo { private data class Glance(
log.info("parseFrom($imageFile) ...") var footer: Footer?,
var footer: Footer? = null var vbMetaOffset: Long
var vbMetaOffset: Long = 0 )
private fun imageGlance(imageFile: String): Glance {
val ret = Glance(null, 0)
// footer // footer
FileInputStream(imageFile).use { fis -> FileInputStream(imageFile).use { fis ->
fis.skip(File(imageFile).length() - Footer.SIZE) fis.skip(File(imageFile).length() - Footer.SIZE)
try { try {
footer = Footer(fis) ret.footer = Footer(fis)
vbMetaOffset = footer!!.vbMetaOffset ret.vbMetaOffset = ret.footer!!.vbMetaOffset
log.info("$imageFile: $footer") log.info("$imageFile: $ret.footer")
} catch (e: IllegalArgumentException) { } catch (e: IllegalArgumentException) {
log.info("image $imageFile has no AVB Footer") log.info("image $imageFile has no AVB Footer")
} }
} }
return ret
}
fun parseFrom(imageFile: String): AVBInfo {
log.info("parseFrom($imageFile) ...")
// glance
val (footer, vbMetaOffset) = imageGlance(imageFile)
// header // header
val rawHeaderBlob = ByteArray(Header.SIZE).apply { val vbMetaHeader = Header(ByteArrayInputStream(Helper.readFully(imageFile, vbMetaOffset, Header.SIZE)))
FileInputStream(imageFile).use { fis ->
fis.skip(vbMetaOffset)
fis.read(this)
}
}
val vbMetaHeader = Header(ByteArrayInputStream(rawHeaderBlob))
log.debug(vbMetaHeader.toString())
log.debug(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(vbMetaHeader)) log.debug(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(vbMetaHeader))
val authBlockOffset = vbMetaOffset + Header.SIZE val atlas = mutableMapOf<String, Pair<Long, Int>>()
val auxBlockOffset = authBlockOffset + vbMetaHeader.authentication_data_block_size atlas["auth"] =
Pair(vbMetaOffset + Header.SIZE, vbMetaHeader.authentication_data_block_size.toInt())
atlas["auth.hash"] =
Pair(atlas["auth"]!!.first + vbMetaHeader.hash_offset, vbMetaHeader.hash_size.toInt())
atlas["auth.sig"] =
Pair(atlas["auth.hash"]!!.first + atlas["auth.hash"]!!.second, vbMetaHeader.signature_size.toInt())
atlas["aux"] =
Pair(atlas["auth"]!!.first + atlas["auth"]!!.second, vbMetaHeader.auxiliary_data_block_size.toInt())
val ai = AVBInfo(vbMetaHeader, null, AuxBlob(), footer) val ai = AVBInfo(vbMetaHeader, null, AuxBlob(), footer)
// Auth blob // Auth blob
if (vbMetaHeader.authentication_data_block_size > 0) { if (vbMetaHeader.authentication_data_block_size > 0) {
FileInputStream(imageFile).use { fis -> val ba = Helper.readFully(imageFile, atlas["auth.hash"]!!)
fis.skip(vbMetaOffset) log.debug("Parsed Auth Hash (Header & Aux Blob): " + Hex.encodeHexString(ba))
fis.skip(Header.SIZE.toLong()) val bb = Helper.readFully(imageFile, atlas["auth.sig"]!!)
fis.skip(vbMetaHeader.hash_offset) log.debug("Parsed Auth Signature (of hash): " + Hex.encodeHexString(bb))
val ba = ByteArray(vbMetaHeader.hash_size.toInt()) ai.authBlob = AuthBlob()
fis.read(ba) ai.authBlob!!.offset = atlas["auth"]!!.first
log.debug("Parsed Auth Hash (Header & Aux Blob): " + Hex.encodeHexString(ba)) ai.authBlob!!.size = atlas["auth"]!!.second.toLong()
val bb = ByteArray(vbMetaHeader.signature_size.toInt()) ai.authBlob!!.hash = Hex.encodeHexString(ba)
fis.read(bb) ai.authBlob!!.signature = Hex.encodeHexString(bb)
log.debug("Parsed Auth Signature (of hash): " + Hex.encodeHexString(bb))
ai.authBlob = AuthBlob()
ai.authBlob!!.offset = authBlockOffset
ai.authBlob!!.size = vbMetaHeader.authentication_data_block_size
ai.authBlob!!.hash = Hex.encodeHexString(ba)
ai.authBlob!!.signature = Hex.encodeHexString(bb)
}
} }
// aux // aux
val rawAuxBlob = ByteArray(vbMetaHeader.auxiliary_data_block_size.toInt()).apply { val rawAuxBlob = Helper.readFully(imageFile, atlas["aux"]!!)
FileInputStream(imageFile).use { fis ->
fis.skip(auxBlockOffset)
fis.read(this)
}
}
// aux - desc // aux - desc
var descriptors: List<Any>
if (vbMetaHeader.descriptors_size > 0) { if (vbMetaHeader.descriptors_size > 0) {
ByteArrayInputStream(rawAuxBlob).use { bis -> val descriptors = UnknownDescriptor.parseDescriptors2(
bis.skip(vbMetaHeader.descriptors_offset) ByteArrayInputStream(
descriptors = UnknownDescriptor.parseDescriptors2(bis, vbMetaHeader.descriptors_size) rawAuxBlob.copyOfRange(vbMetaHeader.descriptors_offset.toInt(), rawAuxBlob.size)
} ),
descriptors.forEach { vbMetaHeader.descriptors_size
log.debug(it.toString()) )
when (it) { ai.auxBlob!!.populateDescriptors(descriptors)
is PropertyDescriptor -> { } else {
ai.auxBlob!!.propertyDescriptors.add(it) log.warn("no descriptors in AVB aux blob")
}
is HashDescriptor -> {
ai.auxBlob!!.hashDescriptors.add(it)
}
is KernelCmdlineDescriptor -> {
ai.auxBlob!!.kernelCmdlineDescriptors.add(it)
}
is HashTreeDescriptor -> {
ai.auxBlob!!.hashTreeDescriptors.add(it)
}
is ChainPartitionDescriptor -> {
ai.auxBlob!!.chainPartitionDescriptors.add(it)
}
is UnknownDescriptor -> {
ai.auxBlob!!.unknownDescriptors.add(it)
}
else -> {
throw IllegalArgumentException("invalid descriptor: $it")
}
}
}
} }
// aux - pubkey // aux - pubkey
if (vbMetaHeader.public_key_size > 0) { if (vbMetaHeader.public_key_size > 0) {
ai.auxBlob!!.pubkey = AuxBlob.PubKeyInfo() ai.auxBlob!!.pubkey = AuxBlob.PubKeyInfo()
ai.auxBlob!!.pubkey!!.offset = vbMetaHeader.public_key_offset ai.auxBlob!!.pubkey!!.offset = vbMetaHeader.public_key_offset
ai.auxBlob!!.pubkey!!.size = vbMetaHeader.public_key_size ai.auxBlob!!.pubkey!!.size = vbMetaHeader.public_key_size
ai.auxBlob!!.pubkey!!.pubkey = rawAuxBlob.copyOfRange(
ByteArrayInputStream(rawAuxBlob).use { bis -> vbMetaHeader.public_key_offset.toInt(),
bis.skip(vbMetaHeader.public_key_offset) (vbMetaHeader.public_key_offset + vbMetaHeader.public_key_size).toInt()
ai.auxBlob!!.pubkey!!.pubkey = ByteArray(vbMetaHeader.public_key_size.toInt()) )
bis.read(ai.auxBlob!!.pubkey!!.pubkey) log.debug("Parsed Pub Key: " + Hex.encodeHexString(ai.auxBlob!!.pubkey!!.pubkey))
log.debug("Parsed Pub Key: " + Hex.encodeHexString(ai.auxBlob!!.pubkey!!.pubkey))
}
} }
// aux - pkmd // aux - pkmd
if (vbMetaHeader.public_key_metadata_size > 0) { if (vbMetaHeader.public_key_metadata_size > 0) {
ai.auxBlob!!.pubkeyMeta = AuxBlob.PubKeyMetadataInfo() ai.auxBlob!!.pubkeyMeta = AuxBlob.PubKeyMetadataInfo()
ai.auxBlob!!.pubkeyMeta!!.offset = vbMetaHeader.public_key_metadata_offset ai.auxBlob!!.pubkeyMeta!!.offset = vbMetaHeader.public_key_metadata_offset
ai.auxBlob!!.pubkeyMeta!!.size = vbMetaHeader.public_key_metadata_size ai.auxBlob!!.pubkeyMeta!!.size = vbMetaHeader.public_key_metadata_size
ai.auxBlob!!.pubkeyMeta!!.pkmd = rawAuxBlob.copyOfRange(
ByteArrayInputStream(rawAuxBlob).use { bis -> vbMetaHeader.public_key_metadata_offset.toInt(),
bis.skip(vbMetaHeader.public_key_metadata_offset) (vbMetaHeader.public_key_metadata_offset + vbMetaHeader.public_key_metadata_size).toInt()
ai.auxBlob!!.pubkeyMeta!!.pkmd = ByteArray(vbMetaHeader.public_key_metadata_size.toInt()) )
bis.read(ai.auxBlob!!.pubkeyMeta!!.pkmd) log.debug("Parsed Pub Key Metadata: " + Helper.toHexString(ai.auxBlob!!.pubkeyMeta!!.pkmd))
log.debug("Parsed Pub Key Metadata: " + Helper.toHexString(ai.auxBlob!!.pubkeyMeta!!.pkmd))
}
} }
log.debug("vbmeta info of [$imageFile] has been analyzed") log.debug("vbmeta info of [$imageFile] has been analyzed")
return ai return ai

@ -14,6 +14,7 @@
package avb.blob package avb.blob
import avb.AVBInfo
import avb.alg.Algorithm import avb.alg.Algorithm
import avb.desc.* import avb.desc.*
import cfig.helper.Helper import cfig.helper.Helper
@ -101,6 +102,36 @@ class AuxBlob(
return Struct3("${auxSize}b").pack(Helper.join(encodedDesc, encodedKey, encodedPkmd)) return Struct3("${auxSize}b").pack(Helper.join(encodedDesc, encodedKey, encodedPkmd))
} }
fun populateDescriptors(descriptors: List<Descriptor>): AuxBlob {
descriptors.forEach {
log.debug(it.toString())
when (it) {
is PropertyDescriptor -> {
this.propertyDescriptors.add(it)
}
is HashDescriptor -> {
this.hashDescriptors.add(it)
}
is KernelCmdlineDescriptor -> {
this.kernelCmdlineDescriptors.add(it)
}
is HashTreeDescriptor -> {
this.hashTreeDescriptors.add(it)
}
is ChainPartitionDescriptor -> {
this.chainPartitionDescriptors.add(it)
}
is UnknownDescriptor -> {
this.unknownDescriptors.add(it)
}
else -> {
throw IllegalArgumentException("invalid descriptor: $it")
}
}
}
return this
}
companion object { companion object {
fun encodePubKey(alg: Algorithm, key: ByteArray? = null): ByteArray { fun encodePubKey(alg: Algorithm, key: ByteArray? = null): ByteArray {
var encodedKey = byteArrayOf() var encodedKey = byteArrayOf()

@ -58,7 +58,7 @@ class ChainPartitionDescriptor(
constructor(data: InputStream, seq: Int = 0) : this() { constructor(data: InputStream, seq: Int = 0) : this() {
if (SIZE - RESERVED != Struct3(FORMAT_STRING).calcSize().toLong()) { if (SIZE - RESERVED != Struct3(FORMAT_STRING).calcSize().toLong()) {
throw RuntimeException() throw RuntimeException("ChainPartitionDescriptor size check failed")
} }
this.sequence = seq this.sequence = seq
val info = Struct3(FORMAT_STRING + "${RESERVED}s").unpack(data) val info = Struct3(FORMAT_STRING + "${RESERVED}s").unpack(data)

@ -245,7 +245,7 @@ class HashTreeDescriptor(
var hashOffset: Long = 0 var hashOffset: Long = 0
) { ) {
override fun toString(): String { override fun toString(): String {
return String.format( return String.format(Locale.getDefault(),
"MT{data: %10s(%6s blocks), hash: %7s @%-5s}", "MT{data: %10s(%6s blocks), hash: %7s @%-5s}",
dataSize, dataSize,
dataBlockCount, dataBlockCount,

@ -23,7 +23,7 @@ class PropertyDescriptor(
var value: String = "") : Descriptor(TAG, 0, 0) { var value: String = "") : Descriptor(TAG, 0, 0) {
override fun encode(): ByteArray { override fun encode(): ByteArray {
if (SIZE != Struct3(FORMAT_STRING).calcSize().toUInt()) { if (SIZE != Struct3(FORMAT_STRING).calcSize().toUInt()) {
throw RuntimeException() throw RuntimeException("PropertyDesc size check failed")
} }
this.num_bytes_following = (SIZE + this.key.length.toUInt() + this.value.length.toUInt() + 2U - 16U).toLong() this.num_bytes_following = (SIZE + this.key.length.toUInt() + this.value.length.toUInt() + 2U - 16U).toLong()
val nbfWithPadding = Helper.round_to_multiple(this.num_bytes_following.toLong(), 8).toULong() val nbfWithPadding = Helper.round_to_multiple(this.num_bytes_following.toLong(), 8).toULong()

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
package cfig.bootloader_message package cfig.bcb
class BootControl { class BootControl {
data class SlotMetadata(//size: 16 data class SlotMetadata(//size: 16

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
package cfig.bootloader_message package cfig.bcb
import cfig.io.Struct3 import cfig.io.Struct3
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
package cfig.bootloader_message package cfig.bcb
import cfig.io.Struct3 import cfig.io.Struct3
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory

@ -12,23 +12,25 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
package cfig.bootloader_message package cfig.bcb
import cfig.helper.Helper
import cfig.io.Struct3 import cfig.io.Struct3
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import java.io.FileInputStream import java.io.FileInputStream
data class VirtualABMsg( data class VirtualABMsg(
var version: Int = 0, var version: Int = 0,
var magic: ByteArray = byteArrayOf(), var magic: ByteArray = byteArrayOf(),
var mergeStatus: Int = 0, var mergeStatus: Int = 0,
var sourceSlot: Int = 0, var sourceSlot: Int = 0,
var reserved: ByteArray = byteArrayOf() var reserved: ByteArray = byteArrayOf()
) { ) {
companion object { companion object {
private const val FORMAT_STRING = "b4bbb57b" private const val FORMAT_STRING = "b4bbb57b"
const val SIZE = 64 const val SIZE = 64
private val log = LoggerFactory.getLogger("VirtualABMsg") private val log = LoggerFactory.getLogger("VirtualABMsg")
private const val MAGIC = "b00a7456"
init { init {
assert(SIZE == Struct3(FORMAT_STRING).calcSize()) assert(SIZE == Struct3(FORMAT_STRING).calcSize())
@ -37,19 +39,36 @@ data class VirtualABMsg(
constructor(fis: FileInputStream) : this() { constructor(fis: FileInputStream) : this() {
val info = Struct3(FORMAT_STRING).unpack(fis) val info = Struct3(FORMAT_STRING).unpack(fis)
this.version = info[0] as Int this.version = (info[0] as ByteArray)[0].toInt()
this.magic = info[1] as ByteArray this.magic = info[1] as ByteArray
this.mergeStatus = info[2] as Int this.mergeStatus = (info[2] as ByteArray)[0].toInt()
this.sourceSlot = info[3] as Int this.sourceSlot = (info[3] as ByteArray)[0].toInt()
this.reserved = info[4] as ByteArray this.reserved = info[4] as ByteArray
if (MAGIC != Helper.Companion.toHexString(this.magic)) {
throw IllegalArgumentException("stream is not VirtualAB message")
}
} }
fun encode(): ByteArray { fun encode(): ByteArray {
return Struct3(FORMAT_STRING).pack( return Struct3(FORMAT_STRING).pack(
this.version, this.version,
this.magic, this.magic,
this.mergeStatus, this.mergeStatus,
this.sourceSlot, this.sourceSlot,
0) 0
)
}
override fun toString(): String {
return "VABMsg(v=$version, magic=${Helper.toHexString(magic)}, mergeStatus=$mergeStatus:${MergeStatus.values().get(this.mergeStatus)}, sourceSlot=$sourceSlot)"
}
enum class MergeStatus(val status: Int) {
NONE(0),
UNKNOWN(1),
SNAPSHOTTED(2),
MERGING(3),
CANCELLED(4)
} }
} }

@ -14,13 +14,13 @@
package cfig.bootimg package cfig.bootimg
import cfig.EnvironmentVerifier import cfig.utils.EnvironmentVerifier
import cfig.bootimg.cpio.AndroidCpio import cfig.bootimg.cpio.AndroidCpio
import cfig.dtb_util.DTC import cfig.utils.DTC
import cfig.helper.Helper import cfig.helper.Helper
import cfig.helper.ZipHelper import cfig.helper.ZipHelper
import cfig.io.Struct3.InputStreamExt.Companion.getInt import cfig.io.Struct3.InputStreamExt.Companion.getInt
import cfig.kernel_util.KernelExtractor import cfig.utils.KernelExtractor
import org.apache.commons.exec.CommandLine import org.apache.commons.exec.CommandLine
import org.apache.commons.exec.DefaultExecutor import org.apache.commons.exec.DefaultExecutor
import org.apache.commons.exec.PumpStreamHandler import org.apache.commons.exec.PumpStreamHandler
@ -35,6 +35,7 @@ import java.lang.NumberFormatException
import java.nio.ByteBuffer import java.nio.ByteBuffer
import java.nio.ByteOrder import java.nio.ByteOrder
import java.security.MessageDigest import java.security.MessageDigest
import java.util.*
import java.util.regex.Pattern import java.util.regex.Pattern
class Common { class Common {
@ -78,7 +79,7 @@ class Common {
val a = x shr 14 val a = x shr 14
val b = x - (a shl 14) shr 7 val b = x - (a shl 14) shr 7
val c = x and 0x7f val c = x and 0x7f
return String.format("%d.%d.%d", a, b, c) return String.format(Locale.getDefault(), "%d.%d.%d", a, b, c)
} }
fun packOsPatchLevel(x: String?): Int { fun packOsPatchLevel(x: String?): Int {
@ -234,7 +235,7 @@ class Common {
//using mkbootfs //using mkbootfs
fun packRootfs(rootDir: String, ramdiskGz: String, osMajor: Int = 10) { fun packRootfs(rootDir: String, ramdiskGz: String, osMajor: Int = 10) {
val mkbootfs = String.format(Helper.prop("mkbootfsBin"), osMajor) val mkbootfs = String.format(Locale.getDefault(), Helper.prop("mkbootfsBin"), osMajor)
log.info("Packing rootfs $rootDir ...") log.info("Packing rootfs $rootDir ...")
val outputStream = ByteArrayOutputStream() val outputStream = ByteArrayOutputStream()
DefaultExecutor().let { exec -> DefaultExecutor().let { exec ->

@ -24,7 +24,7 @@ import org.apache.commons.exec.CommandLine
import org.apache.commons.exec.DefaultExecutor import org.apache.commons.exec.DefaultExecutor
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import java.io.File import java.io.File
import cfig.EnvironmentVerifier import cfig.utils.EnvironmentVerifier
class Signer { class Signer {
companion object { companion object {

@ -15,16 +15,16 @@
package cfig.bootimg.cpio package cfig.bootimg.cpio
import cfig.helper.Helper import cfig.helper.Helper
import cfig.EnvironmentVerifier import cfig.utils.EnvironmentVerifier
import com.fasterxml.jackson.core.JsonParser import com.fasterxml.jackson.core.JsonParser
import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.ObjectMapper
import org.apache.commons.compress.archivers.cpio.CpioArchiveInputStream import org.apache.commons.compress.archivers.cpio.CpioArchiveInputStream
import org.apache.commons.compress.archivers.cpio.CpioConstants import org.apache.commons.compress.archivers.cpio.CpioConstants
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import java.io.* import java.io.*
import java.nio.charset.Charset
import java.nio.file.Files import java.nio.file.Files
import java.nio.file.Paths import java.nio.file.Paths
import java.util.*
import java.util.regex.Pattern import java.util.regex.Pattern
class AndroidCpio { class AndroidCpio {
@ -213,7 +213,7 @@ class AndroidCpio {
name = entry.name, name = entry.name,
statMode = entry.mode, statMode = entry.mode,
ino = entry.inode, ino = entry.inode,
note = String.format("%6s", java.lang.Long.toOctalString(entry.mode)) note = String.format(Locale.getDefault(), "%6s", java.lang.Long.toOctalString(entry.mode))
) )
if (!cis.canReadEntryData(entry)) { if (!cis.canReadEntryData(entry)) {
throw RuntimeException("can not read entry ??") throw RuntimeException("can not read entry ??")
@ -224,7 +224,7 @@ class AndroidCpio {
if (((entry.mode and PERM_MASK).shr(7)).toInt() != 0b11) { if (((entry.mode and PERM_MASK).shr(7)).toInt() != 0b11) {
//@formatter:off //@formatter:off
log.warn(" root/${entry.name} has improper file mode " log.warn(" root/${entry.name} has improper file mode "
+ String.format("%03o, ", entry.mode and PERM_MASK) + "fix it" + String.format(Locale.getDefault(), "%03o, ", entry.mode and PERM_MASK) + "fix it"
) )
//@formatter:on //@formatter:on
} }

@ -16,6 +16,7 @@ package cfig.bootimg.cpio
import cfig.io.Struct3 import cfig.io.Struct3
import org.apache.commons.compress.archivers.cpio.CpioConstants import org.apache.commons.compress.archivers.cpio.CpioConstants
import java.util.*
/* /*
cpio "New ASCII Format" with 070701 as magic cpio "New ASCII Format" with 070701 as magic
@ -38,26 +39,26 @@ class NewAsciiCpio(
) { ) {
init { init {
if (SIZE != Struct3(FORMAT_STRING).calcSize()) { if (SIZE != Struct3(FORMAT_STRING).calcSize()) {
throw RuntimeException() throw RuntimeException("cpio format check failed")
} }
} }
fun encode(): ByteArray { fun encode(): ByteArray {
return Struct3(FORMAT_STRING).pack( return Struct3(FORMAT_STRING).pack(
String.format("%s", c_magic), String.format(Locale.getDefault(), "%s", c_magic),
String.format("%08x", c_ino), String.format(Locale.getDefault(), "%08x", c_ino),
String.format("%08x", c_mode), String.format(Locale.getDefault(), "%08x", c_mode),
String.format("%08x", c_uid), String.format(Locale.getDefault(),"%08x", c_uid),
String.format("%08x", c_gid), String.format(Locale.getDefault(),"%08x", c_gid),
String.format("%08x", c_nlink), String.format(Locale.getDefault(),"%08x", c_nlink),
String.format("%08x", c_mtime), String.format(Locale.getDefault(),"%08x", c_mtime),
String.format("%08x", c_filesize), String.format(Locale.getDefault(),"%08x", c_filesize),
String.format("%08x", c_devmajor), String.format(Locale.getDefault(),"%08x", c_devmajor),
String.format("%08x", c_devminor), String.format(Locale.getDefault(),"%08x", c_devminor),
String.format("%08x", c_rdevmajor), String.format(Locale.getDefault(),"%08x", c_rdevmajor),
String.format("%08x", c_rdevminor), String.format(Locale.getDefault(),"%08x", c_rdevminor),
String.format("%08x", c_namesize), String.format(Locale.getDefault(),"%08x", c_namesize),
String.format("%08x", c_check), String.format(Locale.getDefault(),"%08x", c_check),
) )
} }

@ -16,7 +16,7 @@ package cfig.bootimg.v2
import avb.AVBInfo import avb.AVBInfo
import cfig.Avb import cfig.Avb
import cfig.EnvironmentVerifier import cfig.utils.EnvironmentVerifier
import cfig.bootimg.Common import cfig.bootimg.Common
import cfig.bootimg.Common.Companion.deleleIfExists import cfig.bootimg.Common.Companion.deleleIfExists
import cfig.bootimg.Signer import cfig.bootimg.Signer

@ -18,7 +18,7 @@ import avb.AVBInfo
import avb.alg.Algorithms import avb.alg.Algorithms
import avb.blob.AuxBlob import avb.blob.AuxBlob
import cfig.Avb import cfig.Avb
import cfig.EnvironmentVerifier import cfig.utils.EnvironmentVerifier
import cfig.bootimg.Common.Companion.deleleIfExists import cfig.bootimg.Common.Companion.deleleIfExists
import cfig.bootimg.Common.Companion.getPaddingSize import cfig.bootimg.Common.Companion.getPaddingSize
import cfig.bootimg.Signer import cfig.bootimg.Signer

@ -16,7 +16,7 @@ package cfig.bootimg.v3
import avb.AVBInfo import avb.AVBInfo
import cfig.Avb import cfig.Avb
import cfig.EnvironmentVerifier import cfig.utils.EnvironmentVerifier
import cfig.bootimg.Common.Companion.deleleIfExists import cfig.bootimg.Common.Companion.deleleIfExists
import cfig.bootimg.Signer import cfig.bootimg.Signer
import cfig.helper.Helper import cfig.helper.Helper
@ -73,7 +73,7 @@ data class VendorBoot(
PLATFORM.ordinal -> PLATFORM PLATFORM.ordinal -> PLATFORM
RECOVERY.ordinal -> RECOVERY RECOVERY.ordinal -> RECOVERY
DLKM.ordinal -> DLKM DLKM.ordinal -> DLKM
else -> throw IllegalArgumentException() else -> throw IllegalArgumentException("illegal VrtType $value")
} }
} }
} }

@ -14,7 +14,7 @@
package cfig.init package cfig.init
import cfig.bootloader_message.BootloaderMsg import cfig.bcb.BootloaderMsg
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import java.util.* import java.util.*

@ -26,7 +26,7 @@ import org.slf4j.LoggerFactory
import java.io.File import java.io.File
import java.io.FileInputStream import java.io.FileInputStream
class BootImgParser() : IPackable { class BootImgParser : IPackable {
override val loopNo: Int override val loopNo: Int
get() = 0 get() = 0
private val workDir = Helper.prop("workDir") private val workDir = Helper.prop("workDir")

@ -15,10 +15,9 @@
package cfig.packable package cfig.packable
import avb.blob.Footer import avb.blob.Footer
import cfig.EnvironmentVerifier import cfig.utils.EnvironmentVerifier
import cfig.dtb_util.DTC import cfig.utils.DTC
import cfig.helper.Helper import cfig.helper.Helper
import cfig.Avb
import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.ObjectMapper
import org.apache.commons.exec.CommandLine import org.apache.commons.exec.CommandLine
import org.apache.commons.exec.DefaultExecutor import org.apache.commons.exec.DefaultExecutor
@ -46,7 +45,8 @@ class DtboParser(val workDir: File) : IPackable {
cleanUp() cleanUp()
val dtbPath = File("$outDir/dtb").path val dtbPath = File("$outDir/dtb").path
val headerPath = File("$outDir/dtbo.header").path val headerPath = File("$outDir/dtbo.header").path
val cmd = CommandLine.parse("$dtboMaker dump $fileName").let { val cmdPrefix = if (EnvironmentVerifier().isWindows) "python " else ""
val cmd = CommandLine.parse("$cmdPrefix$dtboMaker dump $fileName").let {
it.addArguments("--dtb $dtbPath") it.addArguments("--dtb $dtbPath")
it.addArguments("--output $headerPath") it.addArguments("--output $headerPath")
} }

@ -14,7 +14,7 @@
package cfig.packable package cfig.packable
import cfig.sparse_util.SparseImgParser import cfig.utils.SparseImgParser
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import java.io.File import java.io.File
import java.util.regex.Pattern import java.util.regex.Pattern

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
package cfig.dtb_util package cfig.utils
import org.apache.commons.exec.CommandLine import org.apache.commons.exec.CommandLine
import org.apache.commons.exec.DefaultExecutor import org.apache.commons.exec.DefaultExecutor
@ -23,7 +23,7 @@ class DTC {
fun decompile(dtbFile: String, outFile: String): Boolean { fun decompile(dtbFile: String, outFile: String): Boolean {
log.info("parsing DTB: $dtbFile") log.info("parsing DTB: $dtbFile")
val cmd = CommandLine.parse("dtc -I dtb -O dts").let { val cmd = CommandLine.parse("dtc -q -I dtb -O dts").let {
it.addArguments("$dtbFile") it.addArguments("$dtbFile")
it.addArguments("-o $outFile") it.addArguments("-o $outFile")
} }
@ -46,7 +46,7 @@ class DTC {
fun compile(dtsFile: String, outFile: String): Boolean { fun compile(dtsFile: String, outFile: String): Boolean {
log.info("compiling DTS: $dtsFile") log.info("compiling DTS: $dtsFile")
val cmd = CommandLine.parse("dtc -I dts -O dtb").let { val cmd = CommandLine.parse("dtc -q -I dts -O dtb").let {
it.addArguments("$dtsFile") it.addArguments("$dtsFile")
it.addArguments("-o $outFile") it.addArguments("-o $outFile")
} }

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
package cfig package cfig.utils
import org.apache.commons.exec.CommandLine import org.apache.commons.exec.CommandLine
import org.apache.commons.exec.DefaultExecutor import org.apache.commons.exec.DefaultExecutor

@ -12,9 +12,8 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
package cfig.kernel_util package cfig.utils
import cfig.EnvironmentVerifier
import cfig.helper.Helper import cfig.helper.Helper
import org.apache.commons.exec.CommandLine import org.apache.commons.exec.CommandLine
import org.apache.commons.exec.DefaultExecutor import org.apache.commons.exec.DefaultExecutor

@ -12,9 +12,8 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
package cfig.sparse_util package cfig.utils
import cfig.EnvironmentVerifier
import cfig.packable.IPackable import cfig.packable.IPackable
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import cfig.helper.Helper.Companion.check_call import cfig.helper.Helper.Companion.check_call
@ -22,7 +21,6 @@ import java.io.FileInputStream
import java.io.File import java.io.File
import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.ObjectMapper
import avb.blob.Footer import avb.blob.Footer
import cfig.Avb
class SparseImgParser : IPackable { class SparseImgParser : IPackable {
override val loopNo: Int override val loopNo: Int

@ -12,12 +12,9 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
import cfig.EnvironmentVerifier import cfig.utils.EnvironmentVerifier
import org.junit.Test import org.junit.Test
import org.junit.Assert.*
import org.junit.Before
class EnvironmentVerifierTest { class EnvironmentVerifierTest {
private val envv = EnvironmentVerifier() private val envv = EnvironmentVerifier()

@ -278,16 +278,20 @@ class ReadTest {
fun String.executeCmd(inServices: MutableList<Service>, fun String.executeCmd(inServices: MutableList<Service>,
inTriggers: List<Trigger>, inIndent: String) { inTriggers: List<Trigger>, inIndent: String) {
val aPre = inIndent + " " val aPre = "$inIndent "
if (this.startsWith("trigger ")) { if (this.startsWith("trigger ")) {
println(aPre + "|-- " + this) println("$aPre|-- $this")
queueEventTrigger(inServices, inTriggers, this.substring(8).trim(), aPre + "| ") queueEventTrigger(inServices, inTriggers, this.substring(8).trim(), aPre + "| ")
} else if (this.startsWith("chmod")) { } else if (this.startsWith("chmod")) {
//ignore
} else if (this.startsWith("chown")) { } else if (this.startsWith("chown")) {
//ignore
} else if (this.startsWith("mkdir")) { } else if (this.startsWith("mkdir")) {
//ignore
} else if (this.startsWith("write")) { } else if (this.startsWith("write")) {
//ignore
} else if (Pattern.compile("class_start\\s+\\S+").matcher(this).find()) { } else if (Pattern.compile("class_start\\s+\\S+").matcher(this).find()) {
println(aPre + "|-- " + this) println("$aPre|-- $this")
val m = Pattern.compile("class_start\\s+(\\S+)$").matcher(this) val m = Pattern.compile("class_start\\s+(\\S+)$").matcher(this)
if (m.find()) { if (m.find()) {
inServices inServices
@ -304,15 +308,15 @@ class ReadTest {
println("$aPre|-- $this") println("$aPre|-- $this")
println("""$aPre| \-- Starting ${this.substring(5).trim()}...""") println("""$aPre| \-- Starting ${this.substring(5).trim()}...""")
} else { } else {
println(aPre + "|-- " + this) println("$aPre|-- $this")
} }
} }
@Test @Test
fun parseTest() { fun parseTest() {
System.out.println(System.getProperty("user.dir")) System.out.println(System.getProperty("user.dir"))
var gTriggers: MutableList<Trigger> = mutableListOf() val gTriggers: MutableList<Trigger> = mutableListOf()
var gServices: MutableList<Service> = mutableListOf() val gServices: MutableList<Service> = mutableListOf()
parseConfig("__temp/", "/init.rc", gTriggers, gServices) parseConfig("__temp/", "/init.rc", gTriggers, gServices)
parseConfig("__temp/", "/system/etc/init", gTriggers, gServices) parseConfig("__temp/", "/system/etc/init", gTriggers, gServices)

@ -44,6 +44,7 @@ class FooterTest {
Footer(it) Footer(it)
assertEquals("Should never reach here", true, false) assertEquals("Should never reach here", true, false)
} catch (e: IllegalArgumentException) { } catch (e: IllegalArgumentException) {
//expected
} }
} }
} }

@ -1,27 +0,0 @@
// Copyright 2021 yuyezhong@gmail.com
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package avb.alg
import org.junit.Test
import org.junit.Assert.*
import java.nio.ByteBuffer
class AlgorithmTest {
@Test
fun getName() {
}
}

@ -21,10 +21,10 @@ import org.junit.Test
class AlgorithmsTest { class AlgorithmsTest {
@Test @Test
fun test1() { fun test1() {
val alg = Algorithms.get("NONE")!! Assert.assertEquals(
Helper.toHexString(Algorithms.get("SHA256_RSA4096")!!.padding),
Assert.assertEquals(Helper.toHexString(Algorithms.get("SHA256_RSA4096")!!.padding), "0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003031300d060960864801650304020105000420"
"0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003031300d060960864801650304020105000420") )
println(alg) println(Algorithms.get("NONE")!!)
} }
} }

@ -12,10 +12,10 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
package bootloader_message package bcb
import cfig.bcb.BootloaderMsg
import cfig.bootimg.Common.Companion.deleleIfExists import cfig.bootimg.Common.Companion.deleleIfExists
import cfig.bootloader_message.BootloaderMsg
import org.junit.After import org.junit.After
import org.junit.Test import org.junit.Test
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory

@ -0,0 +1,37 @@
package bcb
import cfig.bcb.VirtualABMsg
import cfig.bootimg.Common.Companion.deleleIfExists
import cfig.helper.Helper.Companion.check_call
import org.junit.After
import org.junit.Before
import org.junit.Ignore
import org.junit.Test
import org.slf4j.LoggerFactory
import java.io.File
import java.io.FileInputStream
class VirtualABMsgTest {
private val log = LoggerFactory.getLogger(VirtualABMsgTest::class.java)
@Before
fun setUp() {
"adb root".check_call()
"adb wait-for-device".check_call()
"adb shell dd if=/dev/block/by-name/misc of=/data/vendor/debug.misc skip=512 bs=64 count=1".check_call()
"adb pull /data/vendor/debug.misc".check_call()
}
@Test
@Ignore
fun parseVAB() {
val vab = VirtualABMsg(FileInputStream("debug.misc"))
log.info("VAB msg: $vab")
}
@After
fun tearDown() {
File("debug.misc").deleleIfExists()
}
}

@ -14,11 +14,11 @@
package init package init
import cfig.bcb.BootloaderMsg
import org.junit.Test import org.junit.Test
import org.junit.After import org.junit.After
import java.io.File import java.io.File
import java.util.* import java.util.*
import cfig.bootloader_message.BootloaderMsg
import cfig.init.Reboot import cfig.init.Reboot
import cfig.bootimg.Common.Companion.deleleIfExists import cfig.bootimg.Common.Companion.deleleIfExists
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory

@ -15,7 +15,7 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins { plugins {
id("org.jetbrains.kotlin.jvm") version "1.5.30" id("org.jetbrains.kotlin.jvm") version "1.5.31"
`java-library` `java-library`
} }
@ -49,5 +49,5 @@ dependencies {
tasks.withType<KotlinCompile>().all { tasks.withType<KotlinCompile>().all {
kotlinOptions.freeCompilerArgs += "-Xopt-in=kotlin.RequiresOptIn" kotlinOptions.freeCompilerArgs += "-Xopt-in=kotlin.RequiresOptIn"
kotlinOptions.jvmTarget = "1.8" kotlinOptions.jvmTarget = "11"
} }

@ -369,6 +369,20 @@ class Helper {
return String.format("%.1f %ciB", value / 1024.0, ci.current()) return String.format("%.1f %ciB", value / 1024.0, ci.current())
} }
fun readFully(fileName: String, offset: Long, byteCount: Int): ByteArray {
val data = ByteArray(byteCount).apply {
FileInputStream(fileName).use { fis ->
fis.skip(offset)
fis.read(this)
}
}
return data
}
fun readFully(fileName: String, coordinate: Pair<Long, Int>): ByteArray {
return readFully(fileName, coordinate.first, coordinate.second)
}
private val log = LoggerFactory.getLogger("Helper") private val log = LoggerFactory.getLogger("Helper")
} }
} }

@ -19,6 +19,7 @@ import org.junit.Assert
import org.junit.Test import org.junit.Test
import java.io.ByteArrayInputStream import java.io.ByteArrayInputStream
@OptIn(kotlin.ExperimentalUnsignedTypes::class)
class Struct3Test { class Struct3Test {
private fun getConvertedFormats(inStruct: Struct3): ArrayList<Map<String, Int>> { private fun getConvertedFormats(inStruct: Struct3): ArrayList<Map<String, Int>> {
val f = inStruct.javaClass.getDeclaredField("formats") val f = inStruct.javaClass.getDeclaredField("formats")

Loading…
Cancel
Save