diff --git a/abootimg/build.gradle b/abootimg/build.gradle index 8f85c60..e6bf32a 100644 --- a/abootimg/build.gradle +++ b/abootimg/build.gradle @@ -32,3 +32,20 @@ task mkbootimg(type: Jar, dependsOn:['build']) { attributes 'Main-Class': 'cfig.bootimg.mkbootimg' } } + +task repack(type: Jar, dependsOn:['build']) { + from files(sourceSets.main.output.classesDir) + from configurations.runtime.asFileTree.files.collect { zipTree(it) } + + baseName = 'repack' + manifest { + attributes 'Main-Class': 'cfig.bootimg.repack' + } +} + +task pack_clear(type: JavaExec, dependsOn:[':pack_ramdisk_and_gz', 'build']) { + classpath = sourceSets.main.runtimeClasspath + main = "cfig.bootimg.repack_with_cmd" + args rootProject.outClearIMg, rootProject.rootWorkDir, rootProject.mkbootimgBin +} + diff --git a/abootimg/src/main/groovy/cfig/bootimg/CArgs.groovy b/abootimg/src/main/groovy/cfig/bootimg/CArgs.groovy index 1e8b4f7..d602b92 100644 --- a/abootimg/src/main/groovy/cfig/bootimg/CArgs.groovy +++ b/abootimg/src/main/groovy/cfig/bootimg/CArgs.groovy @@ -5,7 +5,7 @@ import groovy.transform.ToString /** * Created by yu at 09:57 on 2016-06-17 */ -@ToString(includeNames = true, includeFields = true) +@ToString(includeNames = true, includeFields = true, excludes = "toCommandLine, CArgs") class CArgs { public String kernel; public String ramdisk; @@ -24,11 +24,56 @@ class CArgs { public int tags_offset; public boolean id; - CArgs() { + public CArgs() { kernel = "kernel"; ramdisk = "ramdisk.img.gz"; second = "second"; output = "boot.img"; cfg = "bootimg.json"; } + + public List toCommandList() { + List ret = new ArrayList(); + ret.add("--base"); + ret.add("0x" + Integer.toHexString(base)); + ret.add("--kernel"); + ret.add(kernel); + ret.add("--kernel_offset"); + ret.add("0x" + Integer.toHexString(kernel_offset)); + if (null != ramdisk) { + ret.add("--ramdisk"); + ret.add(ramdisk); + ret.add("--ramdisk_offset"); + ret.add("0x" + Integer.toHexString(ramdisk_offset)); + } + if (null != second) { + ret.add("--second"); + ret.add(second); + ret.add("--second_offset"); + ret.add("0x" + Integer.toHexString(second_offset)); + } + if (null != board) { + ret.add("--board"); + ret.add(board); + } + ret.add("--cmdline"); + ret.add(cmdline); + if (null != os_version) { + ret.add("--os_version"); + ret.add(os_version); + } + if (null != os_patch_level) { + ret.add("--os_patch_level"); + ret.add(os_patch_level); + } + ret.add("--tags_offset"); + ret.add("0x" + Integer.toHexString(tags_offset)); + if (id) { + ret.add("--id"); + } + ret.add("--output"); + ret.add(output); + + return ret; + } } diff --git a/abootimg/src/main/groovy/cfig/bootimg/CImgInfo.groovy b/abootimg/src/main/groovy/cfig/bootimg/CImgInfo.groovy index 7fddf30..7d66d32 100644 --- a/abootimg/src/main/groovy/cfig/bootimg/CImgInfo.groovy +++ b/abootimg/src/main/groovy/cfig/bootimg/CImgInfo.groovy @@ -1,11 +1,12 @@ package cfig.bootimg +import groovy.json.JsonSlurper import groovy.transform.ToString /** * Created by yu at 09:58 on 2016-06-17 */ -@ToString(includeNames=true, includeFields=true) +@ToString(includeNames=true, includeFields=true, includeSuper = true) class CImgInfo extends CArgs { public int kernel_len; public int ramdisk_len; @@ -14,7 +15,43 @@ class CImgInfo extends CArgs { public int ramdisk_pos; public int second_pos; public byte[] hash; - public String dump() { - return super.toString() + " ; " + toString(); + + static CImgInfo fromJson(String outFile, String workDir) { + CImgInfo aArg = new CImgInfo(); + //preset info + aArg.kernel = workDir + File.separator + aArg.kernel; + aArg.ramdisk = workDir + File.separator + aArg.ramdisk; + aArg.second = workDir + File.separator + aArg.second; + aArg.cfg = workDir + File.separator + aArg.cfg; + aArg.output = outFile; + + JsonSlurper jsonSlurper = new JsonSlurper() + Map result = jsonSlurper.parseText(new File(aArg.cfg).text); + + //arg info + aArg.board = result.bootimg.args.board; + aArg.cmdline = result.bootimg.args.cmdline; + aArg.base = Integer.decode(result.bootimg.args.base); + aArg.kernel_offset = Integer.decode(result.bootimg.args.kernel_offset); + aArg.ramdisk_offset = Integer.decode(result.bootimg.args.ramdisk_offset); + aArg.second_offset = Integer.decode(result.bootimg.args.second_offset); + aArg.tags_offset = Integer.decode(result.bootimg.args.tags_offset); + aArg.id = true; + aArg.pagesize = result.bootimg.args.pagesize; + aArg.os_version = result.bootimg.args.os_version; + aArg.os_patch_level = result.bootimg.args.os_patch_level; + //image info + aArg.kernel_len = result.bootimg.img.kernel_len; + aArg.ramdisk_len = result.bootimg.img.ramdisk_len; + aArg.second_len = result.bootimg.img.second_len; + //adjust preset info + if (0 == aArg.ramdisk_len) { + aArg.ramdisk = null; + } + if (0 == aArg.second_len) { + aArg.second = null; + } + + return aArg; } } diff --git a/abootimg/src/main/groovy/cfig/bootimg/Packer.groovy b/abootimg/src/main/groovy/cfig/bootimg/Packer.groovy new file mode 100644 index 0000000..625f21b --- /dev/null +++ b/abootimg/src/main/groovy/cfig/bootimg/Packer.groovy @@ -0,0 +1,347 @@ +package cfig.bootimg + +import java.nio.ByteBuffer; +import joptsimple.OptionParser; +import joptsimple.OptionSet; +import java.nio.channels.FileChannel; +import java.nio.ByteOrder; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.security.MessageDigest; + +/** + * Created by yu at 10:52 on 2016-06-18 + */ +class Packer { + CArgs parse_cmdline(String[] inArgs) { + OptionParser parser = new OptionParser(); + parser.accepts("kernel", "path to the kernel").withRequiredArg(); + parser.accepts("ramdisk", "path to the ramdisk").withRequiredArg(); + parser.accepts("second", "path to the 2nd bootloader").withRequiredArg(); + parser.accepts("cmdline", "extra arguments to be passed on the kernel command line").withRequiredArg(); + parser.accepts("base", "base address").withRequiredArg(); + parser.accepts("kernel_offset", "kernel offset").withRequiredArg(); + parser.accepts("ramdisk_offset", "ramdisk offset").withRequiredArg(); + parser.accepts("second_offset", "2nd bootloader offset").withRequiredArg(); + parser.accepts("os_version", "operating system version").withRequiredArg(); + parser.accepts("os_patch_level", "operating system patch level").withRequiredArg(); + parser.accepts("tags_offset", "tags offset").withRequiredArg(); + parser.accepts("board", "board name").withRequiredArg(); + parser.accepts("pagesize", "page size").withRequiredArg(); + parser.accepts("id", "print the image ID on standard output"); + parser.accepts("output", "output file name").withRequiredArg(); + + OptionSet options = parser.parse(inArgs) + CArgs ret = new CArgs(); + + ret.kernel = options.valueOf("kernel") + + ret.output = options.valueOf("output") + + ret.ramdisk = options.valueOf("ramdisk") + + ret.second = options.valueOf("second") + + if (options.has("board")) { + ret.board = options.valueOf("board") + } else { + ret.board = "" + } + + ret.id = options.has("id") + + if (options.has("base")) { + ret.base = Integer.decode(options.valueOf("base")) + } else { + ret.base = 0x10000000; + } + + if (options.has("kernel_offset")) { + ret.kernel_offset = Integer.decode(options.valueOf("kernel_offset")) + } else { + ret.kernel_offset = 0x00008000; + } + + if (options.has("ramdisk_offset")) { + ret.ramdisk_offset = Integer.decode(options.valueOf("ramdisk_offset")) + } else { + ret.ramdisk_offset = 0x01000000 + } + + ret.os_version = options.valueOf("os_version") + + ret.os_patch_level = options.valueOf("os_patch_level") + + if (options.has("second_offset")) { + ret.second_offset = Integer.decode(options.valueOf("second_offset")) + } else { + ret.second_offset = 0x00f00000 + } + + if (options.has("tags_offset")) { + ret.tags_offset = Integer.decode(options.valueOf("tags_offset")) + } else { + ret.tags_offset = 0x00000100 + } + + if (options.has("pagesize")) { + ret.pagesize = Integer.decode(options.valueOf("pagesize")) + } else { + ret.pagesize = 2048 + } + + if (options.has("cmdline")) { + ret.cmdline = options.valueOf("cmdline") + } else { + ret.cmdline = "" + } + + if (ret.cmdline.length() > 1536) { + println("cmdline length must <= 1536, current is " + ret.cmdline.length()); + printUsage(parser); + } + if (null == ret.kernel) { + println("kernel must not be empty"); + printUsage(parser); + } + if (null == ret.output) { + println("output file must not be empty"); + printUsage(parser); + } + if (ret.board.length() > 16) { + println("board name length must <= 16") + printUsage(parser); + } + + return ret; + } + + byte[] write_header(CArgs inArgs) { + ByteBuffer bf = ByteBuffer.allocate(1024 * 32); + bf.order(ByteOrder.LITTLE_ENDIAN); + + //header start + bf.put("ANDROID!".getBytes()) + bf.putInt((int) new File(inArgs.kernel).length()); + bf.putInt(inArgs.base + inArgs.kernel_offset) + + if (null == inArgs.ramdisk) { + bf.putInt(0) + } else { + bf.putInt((int) new File(inArgs.ramdisk).length()); + } + + bf.putInt(inArgs.base + inArgs.ramdisk_offset) + + if (null == inArgs.second) { + bf.putInt(0) + } else { + bf.putInt((int) new File(inArgs.second).length()); + } + + bf.putInt(inArgs.base + inArgs.second_offset) + bf.putInt(inArgs.base + inArgs.tags_offset) + bf.putInt(inArgs.pagesize) + bf.putInt(0); + bf.putInt((parse_os_version(inArgs.os_version) << 11) | parse_os_patch_level(inArgs.os_patch_level)) + + bf.put(inArgs.board.getBytes()) + bf.put(new byte[16 - inArgs.board.length()]) + bf.put(inArgs.cmdline.substring(0, Math.min(512, inArgs.cmdline.length())).getBytes()) + bf.put(new byte[512 - Math.min(512, inArgs.cmdline.length())]) + byte[] img_id = hashFile(inArgs.kernel, inArgs.ramdisk, inArgs.second) + bf.put(img_id) + bf.put(new byte[32 - img_id.length]) + + if (inArgs.cmdline.length() > 512) { + bf.put(inArgs.cmdline.substring(512).getBytes()) + bf.put(new byte[1024 + 512 - inArgs.cmdline.length()]) + } else { + bf.put(new byte[1024]) + } + + //padding + pad_file(bf, inArgs.pagesize) + + //write + FileOutputStream fos = new FileOutputStream(inArgs.output, false); + fos.write(bf.array(), 0, bf.position()) + fos.close(); + + return img_id; + } + + void printUsage(OptionParser p) { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + out.write("Usage: mkbootimg