first update in 2020

update gradle managed modules
update gradle to 6
refactor directory for aosp modules
pull/41/head
cfig 6 years ago
parent 4d1a3912d0
commit c1d4133f79
No known key found for this signature in database
GPG Key ID: B104C307F0FDABB7

@ -95,9 +95,6 @@ We now support both VB 1.0 and AVB 2.0 layouts.
boot\_signer boot\_signer
https://android.googlesource.com/platform/system/extras https://android.googlesource.com/platform/system/extras
bouncycastle
https://android.googlesource.com/platform/external/bouncycastle
cpio / fs\_config cpio / fs\_config
https://android.googlesource.com/platform/system/core https://android.googlesource.com/platform/system/core
@ -105,7 +102,7 @@ AVB
https://android.googlesource.com/platform/external/avb/ https://android.googlesource.com/platform/external/avb/
mkbootimg mkbootimg
https://android.googlesource.com/platform/system/core/+/master/mkbootimg/ https://android.googlesource.com/platform/system/tools/mkbootimg/+/refs/heads/master/
Android version list Android version list
https://source.android.com/source/build-numbers.html https://source.android.com/source/build-numbers.html

File diff suppressed because it is too large Load Diff

@ -77,6 +77,12 @@ public class BootSignature extends ASN1Object
* or equal to 1. * or equal to 1.
*/ */
private static final int BOOT_IMAGE_HEADER_V1_RECOVERY_DTBO_SIZE_OFFSET = 1632; private static final int BOOT_IMAGE_HEADER_V1_RECOVERY_DTBO_SIZE_OFFSET = 1632;
/**
* Offset of DTB length in a boot image header of version greater than
* or equal to 2.
*/
private static final int BOOT_IMAGE_HEADER_V2_DTB_SIZE_OFFSET = 1648;
/** /**
* Initializes the object for signing an image file * Initializes the object for signing an image file
@ -221,14 +227,18 @@ public class BootSignature extends ASN1Object
length += ((recoveryDtboLength + pageSize - 1) / pageSize) * pageSize; length += ((recoveryDtboLength + pageSize - 1) / pageSize) * pageSize;
image.getLong(); // recovery_dtbo address image.getLong(); // recovery_dtbo address
if (headerVersion == 1) {
int headerSize = image.getInt(); int headerSize = image.getInt();
if (headerVersion == 2) {
image.position(BOOT_IMAGE_HEADER_V2_DTB_SIZE_OFFSET);
int dtbLength = image.getInt();
length += ((dtbLength + pageSize - 1) / pageSize) * pageSize;
image.getLong(); // dtb address
}
if (image.position() != headerSize) { if (image.position() != headerSize) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"Invalid image header: invalid header length"); "Invalid image header: invalid header length");
} }
} }
}
length = ((length + pageSize - 1) / pageSize) * pageSize; length = ((length + pageSize - 1) / pageSize) * pageSize;

@ -187,7 +187,7 @@ def main():
args.output_configs.write(o) args.output_configs.write(o)
else: else:
sys.stderr.write( sys.stderr.write(
"Cannot extract kernel configs in {}\n".format(args.input.name)) "Cannot extract kernel configs in {}".format(args.input.name))
ret = 1 ret = 1
if args.output_version is not None: if args.output_version is not None:
o = decompress_dump(dump_version, input_bytes) o = decompress_dump(dump_version, input_bytes)
@ -195,7 +195,7 @@ def main():
args.output_version.write(o) args.output_version.write(o)
else: else:
sys.stderr.write( sys.stderr.write(
"Cannot extract kernel versions in {}\n".format(args.input.name)) "Cannot extract kernel versions in {}".format(args.input.name))
ret = 1 ret = 1
return ret return ret

@ -1,4 +1,4 @@
#!/usr/bin/env python2.7 #!/usr/bin/env python
# Copyright 2015, The Android Open Source Project # Copyright 2015, The Android Open Source Project
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
@ -14,13 +14,15 @@
# limitations under the License. # limitations under the License.
from __future__ import print_function from __future__ import print_function
from sys import argv, exit, stderr
from argparse import ArgumentParser, FileType, Action from argparse import ArgumentParser, FileType, Action
from os import fstat
from struct import pack
from hashlib import sha1 from hashlib import sha1
import sys from os import fstat
import re import re
from struct import pack
BOOT_IMAGE_HEADER_V3_PAGESIZE = 4096
def filesize(f): def filesize(f):
if f is None: if f is None:
@ -61,18 +63,61 @@ def get_recovery_dtbo_offset(args):
return dtbo_offset return dtbo_offset
def write_header_v3(args):
BOOT_IMAGE_HEADER_V3_SIZE = 1596
BOOT_MAGIC = 'ANDROID!'.encode()
args.output.write(pack('8s', BOOT_MAGIC))
args.output.write(pack(
'4I',
filesize(args.kernel), # kernel size in bytes
filesize(args.ramdisk), # ramdisk size in bytes
(args.os_version << 11) | args.os_patch_level, # os version and patch level
BOOT_IMAGE_HEADER_V3_SIZE))
args.output.write(pack('4I', 0, 0, 0, 0)) # reserved
args.output.write(pack('I', args.header_version)) # version of bootimage header
args.output.write(pack('1536s', args.cmdline.encode()))
pad_file(args.output, BOOT_IMAGE_HEADER_V3_PAGESIZE)
def write_vendor_boot_header(args):
VENDOR_BOOT_IMAGE_HEADER_V3_SIZE = 2108
BOOT_MAGIC = 'VNDRBOOT'.encode()
args.vendor_boot.write(pack('8s', BOOT_MAGIC))
args.vendor_boot.write(pack(
'5I',
args.header_version, # version of header
args.pagesize, # flash page size we assume
args.base + args.kernel_offset, # kernel physical load addr
args.base + args.ramdisk_offset, # ramdisk physical load addr
filesize(args.vendor_ramdisk))) # vendor ramdisk size in bytes
args.vendor_boot.write(pack('2048s', args.vendor_cmdline.encode()))
args.vendor_boot.write(pack('I', args.base + args.tags_offset)) # physical addr for kernel tags
args.vendor_boot.write(pack('16s', args.board.encode())) # asciiz product name
args.vendor_boot.write(pack('I', VENDOR_BOOT_IMAGE_HEADER_V3_SIZE)) # header size in bytes
if filesize(args.dtb) == 0:
raise ValueError("DTB image must not be empty.")
args.vendor_boot.write(pack('I', filesize(args.dtb))) # size in bytes
args.vendor_boot.write(pack('Q', args.base + args.dtb_offset)) # dtb physical load address
pad_file(args.vendor_boot, args.pagesize)
def write_header(args): def write_header(args):
BOOT_IMAGE_HEADER_V1_SIZE = 1648 BOOT_IMAGE_HEADER_V1_SIZE = 1648
BOOT_IMAGE_HEADER_V2_SIZE = 1660 BOOT_IMAGE_HEADER_V2_SIZE = 1660
BOOT_MAGIC = 'ANDROID!'.encode() BOOT_MAGIC = 'ANDROID!'.encode()
if (args.header_version > 2): if args.header_version > 3:
raise ValueError('Boot header version %d not supported' % args.header_version) raise ValueError('Boot header version %d not supported' % args.header_version)
elif args.header_version == 3:
return write_header_v3(args)
args.output.write(pack('8s', BOOT_MAGIC)) args.output.write(pack('8s', BOOT_MAGIC))
final_ramdisk_offset = (args.base + args.ramdisk_offset) if filesize(args.ramdisk) > 0 else 0 final_ramdisk_offset = (args.base + args.ramdisk_offset) if filesize(args.ramdisk) > 0 else 0
final_second_offset = (args.base + args.second_offset) if filesize(args.second) > 0 else 0 final_second_offset = (args.base + args.second_offset) if filesize(args.second) > 0 else 0
args.output.write(pack('10I', args.output.write(pack(
'10I',
filesize(args.kernel), # size in bytes filesize(args.kernel), # size in bytes
args.base + args.kernel_offset, # physical load addr args.base + args.kernel_offset, # physical load addr
filesize(args.ramdisk), # size in bytes filesize(args.ramdisk), # size in bytes
@ -135,8 +180,8 @@ class ValidateStrLenAction(Action):
def __call__(self, parser, namespace, values, option_string=None): def __call__(self, parser, namespace, values, option_string=None):
if len(values) > self.maxlen: if len(values) > self.maxlen:
raise ValueError('String argument too long: max {0:d}, got {1:d}'. raise ValueError(
format(self.maxlen, len(values))) 'String argument too long: max {0:d}, got {1:d}'.format(self.maxlen, len(values)))
setattr(namespace, self.dest, values) setattr(namespace, self.dest, values)
@ -150,6 +195,7 @@ def write_padded_file(f_out, f_in, padding):
def parse_int(x): def parse_int(x):
return int(x, 0) return int(x, 0)
def parse_os_version(x): def parse_os_version(x):
match = re.search(r'^(\d{1,3})(?:\.(\d{1,3})(?:\.(\d{1,3}))?)?', x) match = re.search(r'^(\d{1,3})(?:\.(\d{1,3})(?:\.(\d{1,3}))?)?', x)
if match: if match:
@ -166,33 +212,40 @@ def parse_os_version(x):
return (a << 14) | (b << 7) | c return (a << 14) | (b << 7) | c
return 0 return 0
def parse_os_patch_level(x): def parse_os_patch_level(x):
match = re.search(r'^(\d{4})-(\d{2})-(\d{2})', x) match = re.search(r'^(\d{4})-(\d{2})-(\d{2})', x)
if match: if match:
y = int(match.group(1)) - 2000 y = int(match.group(1)) - 2000
m = int(match.group(2)) m = int(match.group(2))
# 7 bits allocated for the year, 4 bits for the month # 7 bits allocated for the year, 4 bits for the month
assert y >= 0 and y < 128 assert 0 <= y < 128
assert m > 0 and m <= 12 assert 0 < m <= 12
return (y << 4) | m return (y << 4) | m
return 0 return 0
def parse_cmdline(): def parse_cmdline():
parser = ArgumentParser() parser = ArgumentParser()
parser.add_argument('--kernel', help='path to the kernel', type=FileType('rb'), parser.add_argument('--kernel', help='path to the kernel', type=FileType('rb'))
required=True)
parser.add_argument('--ramdisk', help='path to the ramdisk', type=FileType('rb')) parser.add_argument('--ramdisk', help='path to the ramdisk', type=FileType('rb'))
parser.add_argument('--second', help='path to the 2nd bootloader', type=FileType('rb')) parser.add_argument('--second', help='path to the 2nd bootloader', type=FileType('rb'))
parser.add_argument('--dtb', help='path to dtb', type=FileType('rb')) parser.add_argument('--dtb', help='path to dtb', type=FileType('rb'))
recovery_dtbo_group = parser.add_mutually_exclusive_group() recovery_dtbo_group = parser.add_mutually_exclusive_group()
recovery_dtbo_group.add_argument('--recovery_dtbo', help='path to the recovery DTBO', type=FileType('rb')) recovery_dtbo_group.add_argument('--recovery_dtbo', help='path to the recovery DTBO',
type=FileType('rb'))
recovery_dtbo_group.add_argument('--recovery_acpio', help='path to the recovery ACPIO', recovery_dtbo_group.add_argument('--recovery_acpio', help='path to the recovery ACPIO',
type=FileType('rb'), metavar='RECOVERY_ACPIO', dest='recovery_dtbo') type=FileType('rb'), metavar='RECOVERY_ACPIO',
dest='recovery_dtbo')
parser.add_argument('--cmdline', help='extra arguments to be passed on the ' parser.add_argument('--cmdline', help='extra arguments to be passed on the '
'kernel command line', default='', action=ValidateStrLenAction, maxlen=1536) 'kernel command line', default='', action=ValidateStrLenAction, maxlen=1536)
parser.add_argument('--vendor_cmdline',
help='kernel command line arguments contained in vendor boot',
default='', action=ValidateStrLenAction, maxlen=2048)
parser.add_argument('--base', help='base address', type=parse_int, default=0x10000000) parser.add_argument('--base', help='base address', type=parse_int, default=0x10000000)
parser.add_argument('--kernel_offset', help='kernel offset', type=parse_int, default=0x00008000) parser.add_argument('--kernel_offset', help='kernel offset', type=parse_int, default=0x00008000)
parser.add_argument('--ramdisk_offset', help='ramdisk offset', type=parse_int, default=0x01000000) parser.add_argument('--ramdisk_offset', help='ramdisk offset', type=parse_int,
default=0x01000000)
parser.add_argument('--second_offset', help='2nd bootloader offset', type=parse_int, parser.add_argument('--second_offset', help='2nd bootloader offset', type=parse_int,
default=0x00f00000) default=0x00f00000)
parser.add_argument('--dtb_offset', help='dtb offset', type=parse_int, default=0x01f00000) parser.add_argument('--dtb_offset', help='dtb offset', type=parse_int, default=0x01f00000)
@ -208,31 +261,56 @@ def parse_cmdline():
choices=[2**i for i in range(11, 15)], default=2048) choices=[2**i for i in range(11, 15)], default=2048)
parser.add_argument('--id', help='print the image ID on standard output', parser.add_argument('--id', help='print the image ID on standard output',
action='store_true') action='store_true')
parser.add_argument('--header_version', help='boot image header version', type=parse_int, default=0) parser.add_argument('--header_version', help='boot image header version', type=parse_int,
parser.add_argument('-o', '--output', help='output file name', type=FileType('wb'), default=0)
required=True) parser.add_argument('-o', '--output', help='output file name', type=FileType('wb'))
parser.add_argument('--vendor_boot', help='vendor boot output file name', type=FileType('wb'))
parser.add_argument('--vendor_ramdisk', help='path to the vendor ramdisk', type=FileType('rb'))
return parser.parse_args() return parser.parse_args()
def write_data(args): def write_data(args, pagesize):
write_padded_file(args.output, args.kernel, args.pagesize) write_padded_file(args.output, args.kernel, pagesize)
write_padded_file(args.output, args.ramdisk, args.pagesize) write_padded_file(args.output, args.ramdisk, pagesize)
write_padded_file(args.output, args.second, args.pagesize) write_padded_file(args.output, args.second, pagesize)
if args.header_version > 0 and args.header_version < 3:
write_padded_file(args.output, args.recovery_dtbo, pagesize)
if args.header_version == 2:
write_padded_file(args.output, args.dtb, pagesize)
def write_vendor_boot_data(args):
write_padded_file(args.vendor_boot, args.vendor_ramdisk, args.pagesize)
write_padded_file(args.vendor_boot, args.dtb, args.pagesize)
if args.header_version > 0:
write_padded_file(args.output, args.recovery_dtbo, args.pagesize)
if args.header_version > 1:
write_padded_file(args.output, args.dtb, args.pagesize)
def main(): def main():
args = parse_cmdline() args = parse_cmdline()
if args.vendor_boot is not None:
if args.header_version < 3:
raise ValueError('--vendor_boot not compatible with given header version')
if args.vendor_ramdisk is None:
raise ValueError('--vendor_ramdisk missing or invalid')
write_vendor_boot_header(args)
write_vendor_boot_data(args)
if args.output is not None:
if args.kernel is None:
raise ValueError('kernel must be supplied when creating a boot image')
if args.second is not None and args.header_version > 2:
raise ValueError('--second not compatible with given header version')
img_id = write_header(args) img_id = write_header(args)
write_data(args) if args.header_version > 2:
if args.id: write_data(args, BOOT_IMAGE_HEADER_V3_PAGESIZE)
if isinstance(img_id, str): else:
write_data(args, args.pagesize)
if args.id and img_id is not None:
# Python 2's struct.pack returns a string, but py3 returns bytes. # Python 2's struct.pack returns a string, but py3 returns bytes.
if isinstance(img_id, str):
img_id = [ord(x) for x in img_id] img_id = [ord(x) for x in img_id]
print('0x' + ''.join('{:02x}'.format(c) for c in img_id)) print('0x' + ''.join('{:02x}'.format(c) for c in img_id))
if __name__ == '__main__': if __name__ == '__main__':
main() main()

@ -1,5 +1,5 @@
plugins { plugins {
id("org.jetbrains.kotlin.jvm").version("1.3.41") id("org.jetbrains.kotlin.jvm").version("1.3.61")
application application
} }
@ -11,10 +11,10 @@ dependencies {
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
implementation("org.jetbrains.kotlin:kotlin-reflect") implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.slf4j:slf4j-simple:1.7.25") implementation("org.slf4j:slf4j-simple:1.7.29")
implementation("org.slf4j:slf4j-api:1.7.25") implementation("org.slf4j:slf4j-api:1.7.29")
implementation("com.fasterxml.jackson.core:jackson-annotations:2.9.4") implementation("com.fasterxml.jackson.core:jackson-annotations:2.10.1")
implementation("com.fasterxml.jackson.core:jackson-databind:2.9.4") implementation("com.fasterxml.jackson.core:jackson-databind:2.10.1")
implementation("com.google.guava:guava:18.0") implementation("com.google.guava:guava:18.0")
implementation("org.apache.commons:commons-exec:1.3") implementation("org.apache.commons:commons-exec:1.3")
implementation("org.apache.commons:commons-compress:1.16.1") implementation("org.apache.commons:commons-compress:1.16.1")

@ -83,18 +83,6 @@ class Helper {
return data return data
} }
//similar to this.toString(StandardCharsets.UTF_8).replace("${Character.MIN_VALUE}", "")
@Deprecated("by 1.3.41 experimental api: String.decodeToString()")
fun toCString(ba: ByteArray): String {
val str = ba.toString(StandardCharsets.UTF_8)
val nullPos = str.indexOf(Character.MIN_VALUE)
return if (nullPos >= 0) {
str.substring(0, nullPos)
} else {
str
}
}
@Throws(IOException::class) @Throws(IOException::class)
fun gnuZipFile(compressedFile: String, decompressedFile: String) { fun gnuZipFile(compressedFile: String, decompressedFile: String) {
val buffer = ByteArray(1024) val buffer = ByteArray(1024)
@ -302,7 +290,7 @@ class Helper {
} }
fun String.check_call(): Boolean { fun String.check_call(): Boolean {
var ret = false val ret: Boolean
try { try {
val cmd = CommandLine.parse(this) val cmd = CommandLine.parse(this)
log.info(cmd.toString()) log.info(cmd.toString())

@ -9,4 +9,5 @@ data class ParamConfig(
var dtbo: String? = UnifiedConfig.workDir + "recoveryDtbo", var dtbo: String? = UnifiedConfig.workDir + "recoveryDtbo",
var dtb: String? = UnifiedConfig.workDir + "dtb", var dtb: String? = UnifiedConfig.workDir + "dtb",
var cfg: String = UnifiedConfig.workDir + "bootimg.json", var cfg: String = UnifiedConfig.workDir + "bootimg.json",
val mkbootimg: String = "./external/mkbootimg") val mkbootimg: String = "./aosp/system/tools/mkbootimg/mkbootimg.py")

@ -36,7 +36,7 @@ class Algorithms {
intArrayOf(0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, intArrayOf(0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05,
0x00, 0x04, 0x20)), 0x00, 0x04, 0x20)),
defaultKey = "avb/avb_test_data/testkey_rsa2048.pem") defaultKey = "aosp/avb/avb_test_data/testkey_rsa2048.pem")
val SHA256_RSA4096 = Algorithm( val SHA256_RSA4096 = Algorithm(
name = "SHA256_RSA4096", name = "SHA256_RSA4096",
@ -53,7 +53,7 @@ class Algorithms {
0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05,
0x00, 0x04, 0x20) 0x00, 0x04, 0x20)
), ),
defaultKey = "avb/avb_test_data/testkey_rsa4096.pem" defaultKey = "aosp/avb/avb_test_data/testkey_rsa4096.pem"
) )
val SHA256_RSA8192 = Algorithm( val SHA256_RSA8192 = Algorithm(
@ -70,7 +70,7 @@ class Algorithms {
intArrayOf(0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, intArrayOf(0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05,
0x00, 0x04, 0x20)), 0x00, 0x04, 0x20)),
defaultKey = "avb/avb_test_data/testkey_rsa8192.pem") defaultKey = "aosp/avb/avb_test_data/testkey_rsa8192.pem")
val SHA512_RSA2048 = Algorithm( val SHA512_RSA2048 = Algorithm(
name = "SHA512_RSA2048", name = "SHA512_RSA2048",
@ -86,7 +86,7 @@ class Algorithms {
intArrayOf(0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, intArrayOf(0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05,
0x00, 0x04, 0x40)), 0x00, 0x04, 0x40)),
defaultKey = "avb/avb_test_data/testkey_rsa2048.pem") defaultKey = "aosp/avb/avb_test_data/testkey_rsa2048.pem")
val SHA512_RSA4096 = Algorithm( val SHA512_RSA4096 = Algorithm(
name = "SHA512_RSA4096", name = "SHA512_RSA4096",
@ -102,7 +102,7 @@ class Algorithms {
intArrayOf(0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, intArrayOf(0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05,
0x00, 0x04, 0x40)), 0x00, 0x04, 0x40)),
defaultKey = "avb/avb_test_data/testkey_rsa4096.pem") defaultKey = "aosp/avb/avb_test_data/testkey_rsa4096.pem")
val SHA512_RSA8192 = Algorithm( val SHA512_RSA8192 = Algorithm(
name = "SHA512_RSA8192", name = "SHA512_RSA8192",
@ -119,7 +119,7 @@ class Algorithms {
intArrayOf(0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, intArrayOf(0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05,
0x00, 0x04, 0x40)), 0x00, 0x04, 0x40)),
defaultKey = "avb/avb_test_data/testkey_rsa8192.pem") defaultKey = "aosp/avb/avb_test_data/testkey_rsa8192.pem")
algMap[NONE.name] = NONE algMap[NONE.name] = NONE

@ -40,7 +40,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()
} }
this.sequence = seq this.sequence = seq

@ -9,7 +9,7 @@ class PropertyDescriptor(
var key: String = "", var key: String = "",
var value: String = "") : Descriptor(TAG, 0U, 0) { var value: String = "") : Descriptor(TAG, 0U, 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()
} }
this.num_bytes_following = (SIZE + this.key.length.toUInt() + this.value.length.toUInt() + 2U - 16U).toULong() this.num_bytes_following = (SIZE + this.key.length.toUInt() + this.value.length.toUInt() + 2U - 16U).toULong()

@ -32,7 +32,7 @@ data class ImgInfo(
data class VeritySignature( data class VeritySignature(
var type: String = "dm-verity", var type: String = "dm-verity",
var path: String = "/boot", var path: String = "/boot",
var verity_pk8: String = "security/verity.pk8", var verity_pk8: String = "aosp/security/verity.pk8",
var verity_pem: String = "security/verity.x509.pem", var verity_pem: String = "aosp/security/verity.x509.pem",
var jarPath: String = "aosp/boot_signer/build/libs/boot_signer.jar") var jarPath: String = "aosp/boot_signer/build/libs/boot_signer.jar")
} }

@ -1,14 +1,36 @@
package cfig.io package cfig.io
import cfig.Helper import cfig.io.Struct3.ByteArrayExt.Companion.toCString
import cfig.io.Struct3.ByteArrayExt.Companion.toInt
import cfig.io.Struct3.ByteArrayExt.Companion.toLong
import cfig.io.Struct3.ByteArrayExt.Companion.toShort
import cfig.io.Struct3.ByteArrayExt.Companion.toUInt
import cfig.io.Struct3.ByteArrayExt.Companion.toULong
import cfig.io.Struct3.ByteArrayExt.Companion.toUShort
import cfig.io.Struct3.ByteBufferExt.Companion.appendByteArray
import cfig.io.Struct3.ByteBufferExt.Companion.appendPadding
import cfig.io.Struct3.ByteBufferExt.Companion.appendUByteArray
import cfig.io.Struct3.InputStreamExt.Companion.getByteArray
import cfig.io.Struct3.InputStreamExt.Companion.getCString
import cfig.io.Struct3.InputStreamExt.Companion.getChar
import cfig.io.Struct3.InputStreamExt.Companion.getInt
import cfig.io.Struct3.InputStreamExt.Companion.getLong
import cfig.io.Struct3.InputStreamExt.Companion.getPadding
import cfig.io.Struct3.InputStreamExt.Companion.getShort
import cfig.io.Struct3.InputStreamExt.Companion.getUByteArray
import cfig.io.Struct3.InputStreamExt.Companion.getUInt
import cfig.io.Struct3.InputStreamExt.Companion.getULong
import cfig.io.Struct3.InputStreamExt.Companion.getUShort
import org.junit.Assert import org.junit.Assert
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import java.io.IOException import java.io.IOException
import java.io.InputStream import java.io.InputStream
import java.nio.ByteBuffer import java.nio.ByteBuffer
import java.nio.ByteOrder import java.nio.ByteOrder
import java.nio.charset.StandardCharsets
import java.util.* import java.util.*
import java.util.regex.Pattern import java.util.regex.Pattern
import kotlin.random.Random
@ExperimentalUnsignedTypes @ExperimentalUnsignedTypes
class Struct3 { class Struct3 {
@ -17,85 +39,44 @@ class Struct3 {
private var byteOrder = ByteOrder.LITTLE_ENDIAN private var byteOrder = ByteOrder.LITTLE_ENDIAN
private val formats = ArrayList<Array<Any?>>() private val formats = ArrayList<Array<Any?>>()
enum class Type {
Padding,
}
constructor(inFormatString: String) { constructor(inFormatString: String) {
Assert.assertTrue("FORMAT_STRING must not be empty",
inFormatString.isNotEmpty())
formatString = inFormatString formatString = inFormatString
val m = Pattern.compile("(\\d*)([a-zA-Z])").matcher(formatString) val m = Pattern.compile("(\\d*)([a-zA-Z])").matcher(formatString)
when (formatString[0]) {
if (formatString.startsWith(">") || formatString.startsWith("!")) { '>', '!' -> this.byteOrder = ByteOrder.BIG_ENDIAN
this.byteOrder = ByteOrder.BIG_ENDIAN '@', '=' -> this.byteOrder = ByteOrder.nativeOrder()
log.debug("Parsing BIG_ENDIAN format: $formatString") else -> this.byteOrder = ByteOrder.LITTLE_ENDIAN
} else if (formatString.startsWith("@") || formatString.startsWith("=")) {
this.byteOrder = ByteOrder.nativeOrder()
log.debug("Parsing native ENDIAN format: $formatString")
} else {
log.debug("Parsing LITTLE_ENDIAN format: $formatString")
} }
while (m.find()) { while (m.find()) {
var bExploded = false
val multiple = if (m.group(1).isEmpty()) 1 else Integer.decode(m.group(1))
//item[0]: Type, item[1]: multiple //item[0]: Type, item[1]: multiple
// if need to expand format items, explode it // if need to expand format items, explode it
// eg: "4L" will be exploded to "1L 1L 1L 1L" // eg: "4L" will be exploded to "1L 1L 1L 1L", so it's treated as primitive
// eg: "10x" won't be exploded, it's still "10x" // eg: "10x" won't be exploded, it's still "10x", so it's treated as non-primitive
val item = arrayOfNulls<Any?>(2) val typeName: Any = when (m.group(2)) {
//primitive types
when (m.group(2)) { "x" -> Random //byte 1 (exploded)
//exploded types "b" -> Byte //byte 1 (exploded)
"x" -> {//byte 1 "B" -> UByte //UByte 1 (exploded)
item[0] = Type.Padding "s" -> String //string (exploded)
bExploded = true //zippable types, which need to be exploded with multiple=1
} "c" -> Char
"b" -> {//byte 1 "h" -> Short //2
item[0] = Byte "H" -> UShort //2
bExploded = true "i", "l" -> Int //4
} "I", "L" -> UInt //4
"B" -> {//UByte 1 "q" -> Long //8
item[0] = UByte "Q" -> ULong //8
bExploded = true else -> throw IllegalArgumentException("type [" + m.group(2) + "] not supported")
} }
"s" -> {//string val bPrimitive = m.group(2) in listOf("x", "b", "B", "s")
item[0] = String val multiple = if (m.group(1).isEmpty()) 1 else Integer.decode(m.group(1))
bExploded = true if (bPrimitive) {
} formats.add(arrayOf<Any?>(typeName, multiple))
//combo types, which need to be exploded with multiple=1
"c" -> {//char 1
item[0] = Char
bExploded = false
}
"h" -> {//2
item[0] = Short
}
"H" -> {//2
item[0] = UShort
}
"i", "l" -> {//4
item[0] = Int
}
"I", "L" -> {//4
item[0] = UInt
}
"q" -> {//8
item[0] = Long
}
"Q" -> {//8
item[0] = ULong
}
else -> {
throw IllegalArgumentException("type [" + m.group(2) + "] not supported")
}
}
if (bExploded) {
item[1] = multiple
formats.add(item)
} else { } else {
item[1] = 1
for (i in 0 until multiple) { for (i in 0 until multiple) {
formats.add(item) formats.add(arrayOf<Any?>(typeName, 1))
} }
} }
} }
@ -105,25 +86,39 @@ class Struct3 {
return ("type=" + formats.get(inCursor)[0] + ", value=" + formats.get(inCursor)[1]) return ("type=" + formats.get(inCursor)[0] + ", value=" + formats.get(inCursor)[1])
} }
fun calcSize(): Int? { override fun toString(): String {
var ret = 0 val formatStr = mutableListOf<String>()
for (format in formats) { formats.forEach {
when (val formatType = format[0]) { val fs = StringBuilder()
Byte, UByte, Char, String, Type.Padding -> { when (it[0]) {
ret += format[1] as Int Random -> fs.append("x")
Byte -> fs.append("b")
UByte -> fs.append("B")
String -> fs.append("s")
Char -> fs.append("c")
Short -> fs.append("h")
UShort -> fs.append("H")
Int -> fs.append("i")
UInt -> fs.append("I")
Long -> fs.append("q")
ULong -> fs.append("Q")
else -> throw IllegalArgumentException("type [" + it[0] + "] not supported")
} }
Short, UShort -> { fs.append(":" + it[1])
ret += 2 * format[1] as Int formatStr.add(fs.toString())
} }
Int, UInt -> { return "Struct3(formatString='$formatString', byteOrder=$byteOrder, formats=$formatStr)"
ret += 4 * format[1] as Int
}
Long, ULong -> {
ret += 8 * format[1] as Int
}
else -> {
throw IllegalArgumentException("Class [" + formatType + "] not supported")
} }
fun calcSize(): Int {
var ret = 0
for (format in formats) {
ret += when (val formatType = format[0]) {
Random, Byte, UByte, Char, String -> format[1] as Int
Short, UShort -> 2 * format[1] as Int
Int, UInt -> 4 * format[1] as Int
Long, ULong -> 8 * format[1] as Int
else -> throw IllegalArgumentException("Class [$formatType] not supported")
} }
} }
return ret return ret
@ -133,129 +128,88 @@ class Struct3 {
if (args.size != this.formats.size) { if (args.size != this.formats.size) {
throw IllegalArgumentException("argument size " + args.size + throw IllegalArgumentException("argument size " + args.size +
" doesn't match format size " + this.formats.size) " doesn't match format size " + this.formats.size)
} else {
log.debug("byte buffer size: " + this.calcSize()!!)
} }
val bf = ByteBuffer.allocate(this.calcSize()!!) val bf = ByteBuffer.allocate(this.calcSize())
bf.order(this.byteOrder) bf.order(this.byteOrder)
var formatCursor = -1 //which format item to handle
for (i in args.indices) { for (i in args.indices) {
formatCursor++
val arg = args[i] val arg = args[i]
val format2 = formats[i][0] val typeName = formats[i][0]
val size = formats[i][1] as Int val multiple = formats[i][1] as Int
if (typeName !in arrayOf(Random, Byte, String, UByte)) {
Assert.assertEquals(1, multiple)
}
//x: padding: //x: padding:
// arg == null: if (Random == typeName) {
// arg is Byte.class
// arg is Integer.class
if (Type.Padding == format2) {
val b = ByteArray(size)
when (arg) { when (arg) {
null -> Arrays.fill(b, 0.toByte()) null -> bf.appendPadding(0, multiple)
is Byte -> Arrays.fill(b, arg) is Byte -> bf.appendPadding(arg, multiple)
is Int -> Arrays.fill(b, arg.toByte()) is Int -> bf.appendPadding(arg.toByte(), multiple)
else -> throw IllegalArgumentException("Index[" + i + "] Unsupported arg [" else -> throw IllegalArgumentException("Index[" + i + "] Unsupported arg ["
+ arg + "] with type [" + formats[i][0] + "]") + arg + "] with type [" + formats[i][0] + "]")
} }
bf.put(b)
continue continue
} }
//c: character //c: character
if (Char == format2) { if (Char == typeName) {
Assert.assertEquals(1, size.toLong()) Assert.assertTrue("[$arg](${arg!!::class.java}) is NOT Char",
Assert.assertTrue("[$arg](${arg!!::class.java}) is NOT instance of Character.class",
arg is Char) arg is Char)
bf.put(getLowerByte(arg as Char)) if ((arg as Char) !in '\u0000'..'\u00ff') {
throw IllegalArgumentException("arg[${arg.toInt()}] exceeds 8-bit bound")
}
bf.put(arg.toByte())
continue continue
} }
//b: byte array //b: byte array
if (Byte == format2) { if (Byte == typeName) {
Assert.assertTrue("[$arg](${arg!!::class.java}) is NOT instance of ByteArray/IntArray", when (arg) {
arg is ByteArray || arg is IntArray) is IntArray -> bf.appendByteArray(arg, multiple)
val argInternal = if (arg is IntArray) { is ByteArray -> bf.appendByteArray(arg, multiple)
val arg2: MutableList<Byte> = mutableListOf() else -> throw IllegalArgumentException("[$arg](${arg!!::class.java}) is NOT ByteArray/IntArray")
for (item in arg) {
Assert.assertTrue("$item is not valid Byte",
item in Byte.MIN_VALUE..Byte.MAX_VALUE)
arg2.add(item.toByte())
}
arg2.toByteArray()
} else {
arg as ByteArray
}
val paddingSize = size - argInternal.size
Assert.assertTrue("argument size overflow: " + argInternal.size + " > " + size,
paddingSize >= 0)
bf.put(argInternal)
if (paddingSize > 0) {
val padBytes = ByteArray(paddingSize)
Arrays.fill(padBytes, 0.toByte())
bf.put(padBytes)
log.debug("paddingSize $paddingSize")
} else {
log.debug("paddingSize is zero, perfect match")
} }
continue continue
} }
//B: UByte array //B: UByte array
if (UByte == format2) { if (UByte == typeName) {
Assert.assertTrue("[$arg](${arg!!::class.java}) is NOT instance of ByteArray/IntArray", when (arg) {
arg is ByteArray || arg is IntArray || arg is UByteArray) is ByteArray -> bf.appendByteArray(arg, multiple)
val argInternal = if (arg is IntArray) { is UByteArray -> bf.appendUByteArray(arg, multiple)
val arg2: MutableList<Byte> = mutableListOf() is IntArray -> bf.appendUByteArray(arg, multiple)
for (item in arg) { else -> throw IllegalArgumentException("[$arg](${arg!!::class.java}) is NOT ByteArray/IntArray")
Assert.assertTrue("$item is not valid UByte",
item in UByte.MIN_VALUE.toInt()..UByte.MAX_VALUE.toInt())
arg2.add(item.toByte())
}
arg2.toByteArray()
} else if (arg is UByteArray) {
arg as ByteArray
} else {
arg as ByteArray
} }
continue
val paddingSize = size - argInternal.size
Assert.assertTrue("argument size overflow: " + argInternal.size + " > " + size,
paddingSize >= 0)
bf.put(argInternal)
if (paddingSize > 0) {
val padBytes = ByteArray(paddingSize)
Arrays.fill(padBytes, 0.toByte())
bf.put(padBytes)
log.debug("paddingSize $paddingSize")
} else {
log.debug("paddingSize is zero, perfect match")
} }
//s: String
if (String == typeName) {
Assert.assertNotNull("arg can not be NULL for String, formatString=$formatString, ${getFormatInfo(i)}", arg)
Assert.assertTrue("[$arg](${arg!!::class.java}) is NOT String, ${getFormatInfo(i)}",
arg is String)
bf.appendByteArray((arg as String).toByteArray(), multiple)
continue continue
} }
//h: Short //h: Short
if (Short == format2) { if (Short == typeName) {
Assert.assertEquals(1, size.toLong())
Assert.assertTrue("[$arg](${arg!!::class.java}) is NOT instance of Short/Int",
arg is Short || arg is Int)
when (arg) { when (arg) {
is Int -> { is Int -> {
Assert.assertTrue("[$arg] is truncated as type Short.class", Assert.assertTrue("[$arg] is truncated as type Short.class",
arg in java.lang.Short.MIN_VALUE..java.lang.Short.MAX_VALUE) arg in Short.MIN_VALUE..Short.MAX_VALUE)
bf.putShort(arg.toShort()) bf.putShort(arg.toShort())
} }
is Short -> //instance Short is Short -> bf.putShort(arg) //instance Short
bf.putShort(arg) else -> throw IllegalArgumentException("[$arg](${arg!!::class.java}) is NOT Short/Int")
} }
continue continue
} }
//H: UShort //H: UShort
if (UShort == format2) { if (UShort == typeName) {
Assert.assertEquals(1, size.toLong()) Assert.assertTrue("[$arg](${arg!!::class.java}) is NOT UShort/UInt/Int",
Assert.assertTrue("[$arg](${arg!!::class.java}) is NOT instance of UShort/UInt/Int",
arg is UShort || arg is UInt || arg is Int) arg is UShort || arg is UInt || arg is Int)
when (arg) { when (arg) {
is Int -> { is Int -> {
@ -274,18 +228,14 @@ class Struct3 {
} }
//i, l: Int //i, l: Int
if (Int == format2) { if (Int == typeName) {
Assert.assertEquals(1, size.toLong()) Assert.assertTrue("[$arg](${arg!!::class.java}) is NOT Int", arg is Int)
Assert.assertTrue("[$arg](${arg!!::class.java}) is NOT instance of Int", arg is Int)
bf.putInt(arg as Int) bf.putInt(arg as Int)
continue continue
} }
//I, L: UInt //I, L: UInt
if (UInt == format2) { if (UInt == typeName) {
Assert.assertEquals(1, size.toLong())
Assert.assertTrue("[$arg](${arg!!::class.java}) is NOT instance of UInt/Int/Long",
arg is UInt || arg is Int || arg is Long)
when (arg) { when (arg) {
is Int -> { is Int -> {
Assert.assertTrue("[$arg] is invalid as type UInt", arg >= 0) Assert.assertTrue("[$arg] is invalid as type UInt", arg >= 0)
@ -296,30 +246,23 @@ class Struct3 {
Assert.assertTrue("[$arg] is invalid as type UInt", arg >= 0) Assert.assertTrue("[$arg] is invalid as type UInt", arg >= 0)
bf.putInt(arg.toInt()) bf.putInt(arg.toInt())
} }
else -> { else -> throw IllegalArgumentException("[$arg](${arg!!::class.java}) is NOT UInt/Int/Long")
Assert.fail("program bug")
}
} }
continue continue
} }
//q: Long //q: Long
if (Long == format2) { if (Long == typeName) {
Assert.assertEquals(1, size.toLong())
Assert.assertTrue("[$arg](${arg!!::class.java}) is NOT instance of Long/Int",
arg is Long || arg is Int)
when (arg) { when (arg) {
is Long -> bf.putLong(arg) is Long -> bf.putLong(arg)
is Int -> bf.putLong(arg.toLong()) is Int -> bf.putLong(arg.toLong())
else -> throw IllegalArgumentException("[$arg](${arg!!::class.java}) is NOT Long/Int")
} }
continue continue
} }
//Q: ULong //Q: ULong
if (ULong == format2) { if (ULong == typeName) {
Assert.assertEquals(1, size.toLong())
Assert.assertTrue("[$arg](${arg!!::class.java}) is NOT instance of Int/Long/ULong",
arg is Int || arg is Long || arg is ULong)
when (arg) { when (arg) {
is Int -> { is Int -> {
Assert.assertTrue("[$arg] is invalid as type ULong", arg >= 0) Assert.assertTrue("[$arg] is invalid as type ULong", arg >= 0)
@ -329,36 +272,14 @@ class Struct3 {
Assert.assertTrue("[$arg] is invalid as type ULong", arg >= 0) Assert.assertTrue("[$arg] is invalid as type ULong", arg >= 0)
bf.putLong(arg) bf.putLong(arg)
} }
is ULong -> { is ULong -> bf.putLong(arg.toLong())
bf.putLong(arg.toLong()) else -> throw IllegalArgumentException("[$arg](${arg!!::class.java}) is NOT Int/Long/ULong")
}
} }
continue continue
} }
//s: String throw IllegalArgumentException("unrecognized format $typeName")
if (String == format2) {
Assert.assertNotNull("arg can not be NULL for String, formatString=$formatString, ${getFormatInfo(formatCursor)}", arg)
Assert.assertTrue("[$arg](${arg!!::class.java}) is NOT instance of String.class, ${getFormatInfo(formatCursor)}",
arg is String)
val paddingSize = size - (arg as String).length
Assert.assertTrue("argument size overflow: " + arg.length + " > " + size,
paddingSize >= 0)
bf.put(arg.toByteArray())
if (paddingSize > 0) {
val padBytes = ByteArray(paddingSize)
Arrays.fill(padBytes, 0.toByte())
bf.put(padBytes)
log.debug("paddingSize $paddingSize")
} else {
log.debug("paddingSize is zero, perfect match")
} }
continue
}
throw java.lang.IllegalArgumentException("unrecognized format $format2")
}
log.debug("Pack Result:" + Helper.toHexString(bf.array()))
return bf.array() return bf.array()
} }
@ -366,143 +287,251 @@ class Struct3 {
fun unpack(iS: InputStream): List<*> { fun unpack(iS: InputStream): List<*> {
val ret = ArrayList<Any>() val ret = ArrayList<Any>()
for (format in this.formats) { for (format in this.formats) {
//x: padding when (format[0]) {
//return padding byte Random -> ret.add(iS.getPadding(format[1] as Int)) //return padding byte
if (format[0] === Type.Padding) { Byte -> ret.add(iS.getByteArray(format[1] as Int)) //b: byte array
val multip = format[1] as Int UByte -> ret.add(iS.getUByteArray(format[1] as Int)) //B: ubyte array
val data = ByteArray(1) Char -> ret.add(iS.getChar()) //char: 1
iS.read(data)//sample the 1st byte String -> ret.add(iS.getCString(format[1] as Int)) //c string
val skipped = iS.skip(multip.toLong() - 1)//skip remaining Short -> ret.add(iS.getShort(this.byteOrder)) //h: short
Assert.assertEquals(multip.toLong() - 1, skipped) UShort -> ret.add(iS.getUShort(this.byteOrder)) //H: UShort
ret.add(data[0]) Int -> ret.add(iS.getInt(this.byteOrder)) //i, l: Int
continue UInt -> ret.add(iS.getUInt(this.byteOrder)) //I, L: UInt
Long -> ret.add(iS.getLong(this.byteOrder)) //q: Long
ULong -> ret.add(iS.getULong(this.byteOrder)) //Q: ULong
else -> throw IllegalArgumentException("Class [" + format[0] + "] not supported")
}//end-of-when
}//end-of-for
return ret
} }
//b: byte array class ByteBufferExt {
if (format[0] === Byte) { companion object {
val data = ByteArray(format[1] as Int) private val log = LoggerFactory.getLogger(ByteBufferExt::class.java)
Assert.assertEquals(format[1] as Int, iS.read(data))
ret.add(data) fun ByteBuffer.appendPadding(b: Byte, bufSize: Int) {
continue when {
bufSize == 0 -> {
log.debug("paddingSize is zero, perfect match")
return
}
bufSize < 0 -> {
throw IllegalArgumentException("illegal padding size: $bufSize")
}
else -> {
log.debug("paddingSize $bufSize")
}
}
val padding = ByteArray(bufSize)
Arrays.fill(padding, b)
this.put(padding)
} }
//B: ubyte array fun ByteBuffer.appendByteArray(inIntArray: IntArray, bufSize: Int) {
if (format[0] === UByte) { val arg2 = mutableListOf<Byte>()
val data = ByteArray(format[1] as Int) inIntArray.toMutableList().mapTo(arg2, {
Assert.assertEquals(format[1] as Int, iS.read(data)) if (it in Byte.MIN_VALUE..Byte.MAX_VALUE)
val innerData = UByteArray(data.size) it.toByte()
for (i in 0 until data.size) { else
innerData[i] = data[i].toUByte() throw IllegalArgumentException("$it is not valid Byte")
})
appendByteArray(arg2.toByteArray(), bufSize)
} }
ret.add(innerData)
continue fun ByteBuffer.appendByteArray(inByteArray: ByteArray, bufSize: Int) {
val paddingSize = bufSize - inByteArray.size
if (paddingSize < 0) throw IllegalArgumentException("arg length [${inByteArray.size}] exceeds limit: $bufSize")
//data
this.put(inByteArray)
//padding
this.appendPadding(0.toByte(), paddingSize)
log.debug("paddingSize $paddingSize")
} }
//char: 1 fun ByteBuffer.appendUByteArray(inIntArray: IntArray, bufSize: Int) {
if (format[0] === Char) { val arg2 = mutableListOf<UByte>()
val data = ByteArray(format[1] as Int)//now its size is fixed at 1 inIntArray.toMutableList().mapTo(arg2, {
Assert.assertEquals(format[1] as Int, iS.read(data)) if (it in UByte.MIN_VALUE.toInt()..UByte.MAX_VALUE.toInt())
ret.add(data[0].toChar()) it.toUByte()
continue else
throw IllegalArgumentException("$it is not valid Byte")
})
appendUByteArray(arg2.toUByteArray(), bufSize)
} }
//string fun ByteBuffer.appendUByteArray(inUByteArray: UByteArray, bufSize: Int) {
if (format[0] === String) { val bl = mutableListOf<Byte>()
val data = ByteArray(format[1] as Int) inUByteArray.toMutableList().mapTo(bl, { it.toByte() })
Assert.assertEquals(format[1] as Int, iS.read(data)) this.appendByteArray(bl.toByteArray(), bufSize)
ret.add(Helper.toCString(data)) }
continue }
} }
//h: short class InputStreamExt {
if (format[0] === Short) { companion object {
val data = ByteArray(2) fun InputStream.getChar(): Char {
Assert.assertEquals(2, iS.read(data).toLong()) val data = ByteArray(Byte.SIZE_BYTES)
ByteBuffer.allocate(2).let { Assert.assertEquals(Byte.SIZE_BYTES, this.read(data))
it.order(this.byteOrder) return data[0].toChar()
it.put(data)
it.flip()
ret.add(it.short)
} }
continue
fun InputStream.getShort(inByteOrder: ByteOrder): Short {
val data = ByteArray(Short.SIZE_BYTES)
Assert.assertEquals(Short.SIZE_BYTES, this.read(data))
return data.toShort(inByteOrder)
} }
//H: UShort fun InputStream.getInt(inByteOrder: ByteOrder): Int {
if (format[0] === UShort) { val data = ByteArray(Int.SIZE_BYTES)
val data = ByteArray(2) Assert.assertEquals(Int.SIZE_BYTES, this.read(data))
Assert.assertEquals(2, iS.read(data).toLong()) return data.toInt(inByteOrder)
ByteBuffer.allocate(2).let { }
it.order(this.byteOrder)
it.put(data) fun InputStream.getLong(inByteOrder: ByteOrder): Long {
val data = ByteArray(Long.SIZE_BYTES)
Assert.assertEquals(Long.SIZE_BYTES, this.read(data))
return data.toLong(inByteOrder)
}
fun InputStream.getUShort(inByteOrder: ByteOrder): UShort {
val data = ByteArray(UShort.SIZE_BYTES)
Assert.assertEquals(UShort.SIZE_BYTES, this.read(data))
return data.toUShort(inByteOrder)
}
fun InputStream.getUInt(inByteOrder: ByteOrder): UInt {
val data = ByteArray(UInt.SIZE_BYTES)
Assert.assertEquals(UInt.SIZE_BYTES, this.read(data))
return data.toUInt(inByteOrder)
}
fun InputStream.getULong(inByteOrder: ByteOrder): ULong {
val data = ByteArray(ULong.SIZE_BYTES)
Assert.assertEquals(ULong.SIZE_BYTES, this.read(data))
return data.toULong(inByteOrder)
}
fun InputStream.getByteArray(inSize: Int): ByteArray {
val data = ByteArray(inSize)
Assert.assertEquals(inSize, this.read(data))
return data
}
fun InputStream.getUByteArray(inSize: Int): UByteArray {
val data = ByteArray(inSize)
Assert.assertEquals(inSize, this.read(data))
val innerData2 = mutableListOf<UByte>()
data.toMutableList().mapTo(innerData2, { it.toUByte() })
return innerData2.toUByteArray()
}
fun InputStream.getCString(inSize: Int): String {
val data = ByteArray(inSize)
Assert.assertEquals(inSize, this.read(data))
return data.toCString()
}
fun InputStream.getPadding(inSize: Int): Byte {
val data = ByteArray(Byte.SIZE_BYTES)
Assert.assertEquals(Byte.SIZE_BYTES, this.read(data)) //sample the 1st byte
val skipped = this.skip(inSize.toLong() - Byte.SIZE_BYTES)//skip remaining to save memory
Assert.assertEquals(inSize.toLong() - Byte.SIZE_BYTES, skipped)
return data[0]
}
}
}
class ByteArrayExt {
companion object {
fun ByteArray.toShort(inByteOrder: ByteOrder): Short {
val typeSize = Short.SIZE_BYTES / Byte.SIZE_BYTES
Assert.assertEquals("Short must have $typeSize bytes", typeSize, this.size)
var ret: Short
ByteBuffer.allocate(typeSize).let {
it.order(inByteOrder)
it.put(this)
it.flip() it.flip()
ret.add(it.short.toUShort()) ret = it.getShort()
} }
continue return ret
} }
//i, l: Int fun ByteArray.toInt(inByteOrder: ByteOrder): Int {
if (format[0] === Int) { val typeSize = Int.SIZE_BYTES / Byte.SIZE_BYTES
val data = ByteArray(4) Assert.assertEquals("Int must have $typeSize bytes", typeSize, this.size)
Assert.assertEquals(4, iS.read(data).toLong()) var ret: Int
ByteBuffer.allocate(4).let { ByteBuffer.allocate(typeSize).let {
it.order(this.byteOrder) it.order(inByteOrder)
it.put(data) it.put(this)
it.flip() it.flip()
ret.add(it.int) ret = it.getInt()
} }
continue return ret
} }
//I, L: UInt fun ByteArray.toLong(inByteOrder: ByteOrder): Long {
if (format[0] === UInt) { val typeSize = Long.SIZE_BYTES / Byte.SIZE_BYTES
val data = ByteArray(4) Assert.assertEquals("Long must have $typeSize bytes", typeSize, this.size)
Assert.assertEquals(4, iS.read(data).toLong()) var ret: Long
ByteBuffer.allocate(4).let { ByteBuffer.allocate(typeSize).let {
it.order(this.byteOrder) it.order(inByteOrder)
it.put(data) it.put(this)
it.flip() it.flip()
ret.add(it.int.toUInt()) ret = it.getLong()
} }
continue return ret
} }
//q: Long fun ByteArray.toUShort(inByteOrder: ByteOrder): UShort {
if (format[0] === Long) { val typeSize = UShort.SIZE_BYTES / Byte.SIZE_BYTES
val data = ByteArray(8) Assert.assertEquals("UShort must have $typeSize bytes", typeSize, this.size)
Assert.assertEquals(8, iS.read(data).toLong()) var ret: UShort
ByteBuffer.allocate(8).let { ByteBuffer.allocate(typeSize).let {
it.order(this.byteOrder) it.order(inByteOrder)
it.put(data) it.put(this)
it.flip() it.flip()
ret.add(it.long) ret = it.getShort().toUShort()
} }
continue return ret
} }
//Q: ULong fun ByteArray.toUInt(inByteOrder: ByteOrder): UInt {
if (format[0] === ULong) { val typeSize = UInt.SIZE_BYTES / Byte.SIZE_BYTES
val data = ByteArray(8) Assert.assertEquals("UInt must have $typeSize bytes", typeSize, this.size)
Assert.assertEquals(8, iS.read(data).toLong()) var ret: UInt
ByteBuffer.allocate(8).let { ByteBuffer.allocate(typeSize).let {
it.order(this.byteOrder) it.order(inByteOrder)
it.put(data) it.put(this)
it.flip() it.flip()
ret.add(it.long.toULong()) ret = it.getInt().toUInt()
} }
continue return ret
} }
throw IllegalArgumentException("Class [" + format[0] + "] not supported") fun ByteArray.toULong(inByteOrder: ByteOrder): ULong {
val typeSize = ULong.SIZE_BYTES / Byte.SIZE_BYTES
Assert.assertEquals("ULong must have $typeSize bytes", typeSize, this.size)
var ret: ULong
ByteBuffer.allocate(typeSize).let {
it.order(inByteOrder)
it.put(this)
it.flip()
ret = it.getLong().toULong()
} }
return ret return ret
} }
//get lower 1 byte //similar to this.toString(StandardCharsets.UTF_8).replace("${Character.MIN_VALUE}", "")
private fun getLowerByte(obj: Char?): Byte { // not Deprecated for now, "1.3.41 experimental api: ByteArray.decodeToString()") is a little different
val bf2 = ByteBuffer.allocate(Character.SIZE / 8) //aka. 16/8 fun ByteArray.toCString(): String {
bf2.putChar(obj!!) val str = this.toString(StandardCharsets.UTF_8)
bf2.flip() val nullPos = str.indexOf(Character.MIN_VALUE)
bf2.get() return if (nullPos >= 0) {
return bf2.get() str.substring(0, nullPos)
} else {
str
}
}
}
} }
} }

@ -20,7 +20,7 @@ class KernelExtractor {
val baseDir = "build/unzip_boot" val baseDir = "build/unzip_boot"
val kernelVersionFile = "$baseDir/kernel_version.txt" val kernelVersionFile = "$baseDir/kernel_version.txt"
val kernelConfigFile = "$baseDir/kernel_configs.txt" val kernelConfigFile = "$baseDir/kernel_configs.txt"
val cmd = CommandLine.parse("external/extract_kernel.py").let { val cmd = CommandLine.parse("aosp/build/tools/extract_kernel.py").let {
it.addArgument("--input") it.addArgument("--input")
it.addArgument(fileName) it.addArgument(fileName)
it.addArgument("--output-configs") it.addArgument("--output-configs")

@ -33,7 +33,7 @@ class BootImgParser() : IPackable {
if (File(UnifiedConfig.workDir).exists()) File(UnifiedConfig.workDir).deleteRecursively() if (File(UnifiedConfig.workDir).exists()) File(UnifiedConfig.workDir).deleteRecursively()
File(UnifiedConfig.workDir).mkdirs() File(UnifiedConfig.workDir).mkdirs()
try { try {
val info = Parser().parseBootImgHeader(fileName, avbtool = "avb/avbtool") val info = Parser().parseBootImgHeader(fileName, avbtool = "aosp/avb/avbtool")
InfoTable.instance.addRule() InfoTable.instance.addRule()
InfoTable.instance.addRow("image info", ParamConfig().cfg) InfoTable.instance.addRow("image info", ParamConfig().cfg)
if (info.signatureType == BootImgInfo.VerifyType.AVB) { if (info.signatureType == BootImgInfo.VerifyType.AVB) {
@ -69,7 +69,7 @@ class BootImgParser() : IPackable {
override fun pack(fileName: String) { override fun pack(fileName: String) {
Packer().pack(mkbootfsBin = "./aosp/mkbootfs/build/exe/mkbootfs/mkbootfs") Packer().pack(mkbootfsBin = "./aosp/mkbootfs/build/exe/mkbootfs/mkbootfs")
Signer.sign(avbtool = "avb/avbtool", bootSigner = "aosp/boot_signer/build/libs/boot_signer.jar") Signer.sign(avbtool = "aosp/avb/avbtool", bootSigner = "aosp/boot_signer/build/libs/boot_signer.jar")
if (File("vbmeta.img").exists()) { if (File("vbmeta.img").exists()) {
val partitionName = ObjectMapper().readValue(File(Avb.getJsonFileName(fileName)), AVBInfo::class.java).let { val partitionName = ObjectMapper().readValue(File(Avb.getJsonFileName(fileName)), AVBInfo::class.java).let {
it.auxBlob!!.hashDescriptors.get(0).partition_name it.auxBlob!!.hashDescriptors.get(0).partition_name

@ -5,6 +5,7 @@ import cfig.Helper.Companion.check_output
import org.slf4j.Logger import org.slf4j.Logger
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
@ExperimentalUnsignedTypes
interface IPackable { interface IPackable {
val loopNo: Int val loopNo: Int
fun capabilities(): List<String> { fun capabilities(): List<String> {

@ -46,6 +46,11 @@ class Struct3Test {
Assert.assertEquals(9, Struct3("9c").calcSize()) Assert.assertEquals(9, Struct3("9c").calcSize())
} }
@Test
fun toStringTest() {
println(Struct3("!4s2L2QL11QL4x47sx80x"))
}
//x //x
@Test @Test
fun paddingTest() { fun paddingTest() {
@ -189,7 +194,7 @@ class Struct3Test {
Struct3("3s").pack("abcd") Struct3("3s").pack("abcd")
Assert.fail("should throw exception here") Assert.fail("should throw exception here")
} catch (e: Throwable) { } catch (e: Throwable) {
Assert.assertTrue(e is AssertionError || e is IllegalArgumentException) Assert.assertTrue(e.toString(), e is AssertionError || e is IllegalArgumentException)
} }
//unpack //unpack

Binary file not shown.

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-6.0.1-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

51
gradlew vendored

@ -1,5 +1,21 @@
#!/usr/bin/env sh #!/usr/bin/env sh
#
# Copyright 2015 the original author or authors.
#
# 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
#
# https://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.
#
############################################################################## ##############################################################################
## ##
## Gradle start up script for UN*X ## Gradle start up script for UN*X
@ -28,7 +44,7 @@ APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"` APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m"' DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value. # Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum" MAX_FD="maximum"
@ -109,8 +125,8 @@ if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi fi
# For Cygwin, switch paths to Windows format before running java # For Cygwin or MSYS, switch paths to Windows format before running java
if $cygwin ; then if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"` APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"` JAVACMD=`cygpath --unix "$JAVACMD"`
@ -138,19 +154,19 @@ if $cygwin ; then
else else
eval `echo args$i`="\"$arg\"" eval `echo args$i`="\"$arg\""
fi fi
i=$((i+1)) i=`expr $i + 1`
done done
case $i in case $i in
(0) set -- ;; 0) set -- ;;
(1) set -- "$args0" ;; 1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;; 2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;; 3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;; 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac esac
fi fi
@ -159,14 +175,9 @@ save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " " echo " "
} }
APP_ARGS=$(save "$@") APP_ARGS=`save "$@"`
# Collect all arguments for the java command, following the shell quoting and substitution rules # Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@" exec "$JAVACMD" "$@"

18
gradlew.bat vendored

@ -1,3 +1,19 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off @if "%DEBUG%" == "" @echo off
@rem ########################################################################## @rem ##########################################################################
@rem @rem
@ -14,7 +30,7 @@ set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME% set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe @rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome if defined JAVA_HOME goto findJavaFromJavaHome

@ -8,4 +8,4 @@ include("aosp:libsparse:simg2img")
include("aosp:libsparse:simg2simg") include("aosp:libsparse:simg2simg")
include("aosp:libsparse:append2simg") include("aosp:libsparse:append2simg")
include("aosp:libavb") include("aosp:libavb")
include("avbImpl") //include("avbImpl")

Loading…
Cancel
Save