Squashed commit of all strict checkings

1. make my groovy code more java like
add @groovy.transform.TypeChecked and @groovy.transform.CompileStatic to
eliminate runtime surprise
2. add strict checking before 'pack' task
3. all boot.img.clear* will be hashed and the hash code will be compared to
    assert equation
4. upgrade gradle and groovy version
pull/8/head
cfig 9 years ago
parent 601453ef84
commit 3e5449af04

@ -1,7 +1,7 @@
# Nexus_boot_image_editor
[![Build Status](https://travis-ci.org/cfig/Nexus_boot_image_editor.svg?branch=master)](https://travis-ci.org/cfig/Nexus_boot_image_editor)
# Android_boot_image_editor
[![Build Status](https://travis-ci.org/cfig/Android_boot_image_editor.svg?branch=master)](https://travis-ci.org/cfig/Android_boot_image_editor)
Utilies for editing Nexus(or Nexus compatible) devices boot.img , then you don't need full Android source code to edit your boot images.
Utilies for editing Android boot.img.
## Prerequisite
#### Host OS requirement:
@ -10,7 +10,7 @@ Linux or Mac.
#### Target Android requirement:
(1) Targeted boot.img MUST follows AOSP [verified boot flow](https://source.android.com/security/verifiedboot/index.html), which means it packs linux kernel and rootfs together, then sign it with OEM/USER keys.
(1) Targeted boot.img MUST follows AOSP [verified boot flow](https://source.android.com/security/verifiedboot/index.html), which means it packs linux kernel, rootfs , and a optional second state bootloader, then sign it with OEM/USER keys.
(2) These utilities are known to work for Nexus (or Nexus compatible) boot.img for the following Android releases:
@ -23,8 +23,8 @@ You can get a full [Android version list](https://source.android.com/source/buil
## Usage
Get tools via git:
git clone https://github.com/cfig/Nexus_boot_image_editor.git
cd Nexus_boot_image_editor
git clone https://github.com/cfig/Android_boot_image_editor.git
cd Android_boot_image_editor
Then put your boot.img at **$(CURDIR)/boot.img**, then start gradle 'unpack' task:
@ -50,3 +50,7 @@ You get the repacked boot.img at $(CURDIR):
## example & test
An example boot.img has been placed at **src/test/resources/boot.img**, which is extracted from Nexus 5x(code: bullhead) factory images from [Google](https://dl.google.com/dl/android/aosp/bullhead-mda89e-factory-29247942.tgz), you can take it as a quick start.
## boot.img layout
Read [layout](https://github.com/cfig/Android_boot_image_editor/blob/master/README.expert.md) of Android boot.img.
We now support **os\_version** and **os\_patch\_level**.

@ -8,7 +8,7 @@ repositories {
}
dependencies {
compile 'org.codehaus.groovy:groovy-all:2.3.11'
compile 'org.codehaus.groovy:groovy-all:2.4.7'
compile group: 'net.sf.jopt-simple', name: 'jopt-simple', version: '5.0.2'
testCompile group: 'junit', name: 'junit', version: '4.11'
}

@ -5,6 +5,7 @@ import groovy.transform.ToString
/**
* Created by yu at 09:57 on 2016-06-17
*/
@groovy.transform.TypeChecked
@ToString(includeNames = true, includeFields = true, excludes = "toCommandLine, CArgs")
class CArgs {
public String kernel;

@ -1,6 +1,7 @@
package cfig.bootimg
import groovy.json.JsonSlurper
import groovy.json.JsonBuilder
import groovy.transform.ToString
/**
@ -16,7 +17,7 @@ class CImgInfo extends CArgs {
public int second_pos;
public byte[] hash;
static CImgInfo fromJson(String outFile, String workDir) {
public static CImgInfo fromJson(String outFile, String workDir) {
CImgInfo aArg = new CImgInfo();
//preset info
aArg.kernel = workDir + File.separator + aArg.kernel;
@ -54,4 +55,45 @@ class CImgInfo extends CArgs {
return aArg;
}
private String bytes2String(byte[] inData) {
StringBuilder sb = new StringBuilder("");
for (int i = 0; i < inData.length; i++) {
sb.append(Integer.toString((inData[i] & 0xff) + 0x100, 16).substring(1));
}
return sb.toString();
}
public void toJson() {
JsonBuilder jb = new JsonBuilder();
String hashString = bytes2String(this.hash);
jb.bootimg {
args {
base "0x" + Integer.toHexString(this.base);
kernel_offset "0x" + Integer.toHexString(this.kernel_offset);
ramdisk_offset "0x" + Integer.toHexString(this.ramdisk_offset);
second_offset "0x" + Integer.toHexString(this.second_offset);
tags_offset "0x" + Integer.toHexString(this.tags_offset);
pagesize this.pagesize;
board this.board;
cmdline this.cmdline;
os_version this.os_version;
os_patch_level this.os_patch_level;
id this.id;
}
img {
kernel_pos this.kernel_pos;
kernel_len this.kernel_len;
ramdisk_pos this.ramdisk_pos;
ramdisk_len this.ramdisk_len;
second_pos this.second_pos;
second_len this.second_len;
hash hashString;
}
}
FileWriter fw = new FileWriter(this.cfg);
fw.write(jb.toPrettyString());
fw.flush();
fw.close();
}
}

@ -12,6 +12,7 @@ import java.security.MessageDigest;
/**
* Created by yu at 10:52 on 2016-06-18
*/
@groovy.transform.CompileStatic
class Packer {
CArgs parse_cmdline(String[] inArgs) {
OptionParser parser = new OptionParser();
@ -51,19 +52,19 @@ class Packer {
ret.id = options.has("id")
if (options.has("base")) {
ret.base = Integer.decode(options.valueOf("base"))
ret.base = Integer.decode(String.valueOf(options.valueOf("base")))
} else {
ret.base = 0x10000000;
}
if (options.has("kernel_offset")) {
ret.kernel_offset = Integer.decode(options.valueOf("kernel_offset"))
ret.kernel_offset = Integer.decode(String.valueOf(options.valueOf("kernel_offset")))
} else {
ret.kernel_offset = 0x00008000;
}
if (options.has("ramdisk_offset")) {
ret.ramdisk_offset = Integer.decode(options.valueOf("ramdisk_offset"))
ret.ramdisk_offset = Integer.decode(String.valueOf(options.valueOf("ramdisk_offset")))
} else {
ret.ramdisk_offset = 0x01000000
}
@ -73,25 +74,25 @@ class Packer {
ret.os_patch_level = options.valueOf("os_patch_level")
if (options.has("second_offset")) {
ret.second_offset = Integer.decode(options.valueOf("second_offset"))
ret.second_offset = Integer.decode(String.valueOf(options.valueOf("second_offset")))
} else {
ret.second_offset = 0x00f00000
}
if (options.has("tags_offset")) {
ret.tags_offset = Integer.decode(options.valueOf("tags_offset"))
ret.tags_offset = Integer.decode(String.valueOf(options.valueOf("tags_offset")))
} else {
ret.tags_offset = 0x00000100
}
if (options.has("pagesize")) {
ret.pagesize = Integer.decode(options.valueOf("pagesize"))
ret.pagesize = Integer.decode(String.valueOf(options.valueOf("pagesize")))
} else {
ret.pagesize = 2048
}
if (options.has("cmdline")) {
ret.cmdline = options.valueOf("cmdline")
ret.cmdline = String.valueOf(options.valueOf("cmdline"))
} else {
ret.cmdline = ""
}

@ -1,13 +1,13 @@
package cfig.bootimg
import groovy.json.JsonBuilder
import java.nio.ByteBuffer
import java.nio.ByteOrder
/**
* Created by yu at 10:58 on 2016-06-18
*/
@groovy.transform.CompileStatic
class Parser {
int readInt(InputStream is) {
@ -52,14 +52,6 @@ class Parser {
return (pagesize - (position & (pagesize - 1))) & (pagesize - 1);
}
String bytes2String(byte[] inData) {
StringBuilder sb = new StringBuilder("");
for (int i = 0; i < inData.length; i++) {
sb.append(Integer.toString((inData[i] & 0xff) + 0x100, 16).substring(1));
}
return sb.toString();
}
void parse_header(String fileName, CImgInfo inImgInfo) {
InputStream is = new FileInputStream(new File(fileName))
assert Arrays.equals(readBytes(is, 8), "ANDROID!".getBytes())
@ -102,43 +94,6 @@ class Parser {
}
}
void extract_img_header(CImgInfo inImgInfo) {
JsonBuilder jb = new JsonBuilder();
String hashString = bytes2String(inImgInfo.hash);
jb.bootimg {
args {
// kernel inImgInfo.kernel;
// ramdisk inImgInfo.ramdisk;
// second inImgInfo.second;
// output inImgInfo.output;
base "0x" + Integer.toHexString(inImgInfo.base);
kernel_offset "0x" + Integer.toHexString(inImgInfo.kernel_offset);
ramdisk_offset "0x" + Integer.toHexString(inImgInfo.ramdisk_offset);
second_offset "0x" + Integer.toHexString(inImgInfo.second_offset);
tags_offset "0x" + Integer.toHexString(inImgInfo.tags_offset);
pagesize inImgInfo.pagesize;
board inImgInfo.board;
cmdline inImgInfo.cmdline;
os_version inImgInfo.os_version;
os_patch_level inImgInfo.os_patch_level;
id inImgInfo.id;
}
img {
kernel_pos inImgInfo.kernel_pos;
kernel_len inImgInfo.kernel_len;
ramdisk_pos inImgInfo.ramdisk_pos;
ramdisk_len inImgInfo.ramdisk_len;
second_pos inImgInfo.second_pos;
second_len inImgInfo.second_len;
hash hashString;
}
}
FileWriter fw = new FileWriter(inImgInfo.cfg);
fw.write(jb.toPrettyString());
fw.flush();
fw.close();
}
void extract_img_data(String inBootImg, String outImgName, int offset, int length) {
if (0 == length) {
return;
@ -180,6 +135,6 @@ class Parser {
extract_img_data(fileName, imgInfo.kernel, imgInfo.kernel_pos, imgInfo.kernel_len)
extract_img_data(fileName, imgInfo.ramdisk, imgInfo.ramdisk_pos, imgInfo.ramdisk_len)
extract_img_data(fileName, imgInfo.second, imgInfo.second_pos, imgInfo.second_len)
extract_img_header(imgInfo);
imgInfo.toJson();
}
}

@ -5,11 +5,14 @@ apply plugin: 'groovy'
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.lang.RuntimeException;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.security.MessageDigest;
// ----------------------------------------------------------------------------
model {
@ -165,7 +168,11 @@ void gnuZipFile(String compressedFile, String decompressedFile) throws IOExcepti
}
}
task pack(type: JavaExec, dependsOn: ['abootimg:pack_clear', 'abootimg:pack_clear2', 'abootimg:pack_clear3', 'boot_signer:jar']) {
task verify_clear(dependsOn: ['abootimg:pack_clear', 'abootimg:pack_clear2', 'abootimg:pack_clear3']) << {
verifyClearImages(activeImg + ".clear", activeImg + ".clear2", activeImg + ".clear3");
}
task pack(type: JavaExec, dependsOn: [verify_clear, 'boot_signer:jar']) {
main = 'com.android.verity.BootSignature'
classpath = files("boot_signer/build/libs/boot_signer.jar")
maxHeapSize '512m'
@ -304,3 +311,43 @@ if (null == activeImg) {
unpack_bootimg.enabled = false
unpack_ramdisk_gz.enabled = false
}
if (!new File(workdir + File.separator + "root").exists()) {
pack_ramdisk_and_gz.enabled = false
}
byte[] hashFile(String inFile) {
MessageDigest md = MessageDigest.getInstance("SHA1")
ByteBuffer itemBF = ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN);
InputStream is = new FileInputStream(new File(inFile))
int byteRead;
byte[] dataRead = new byte[128]
while (true) {
byteRead = is.read(dataRead)
if (-1 == byteRead) {
break;
}
md.update(dataRead, 0, byteRead)
}
is.close();
md.update(itemBF.putInt((int) new File(inFile).length()).array())
return md.digest();
}
void verifyClearImages(String... inFiles) {
assert (inFiles.length > 1)
byte[] ref;
for (String item : inFiles) {
if (null == ref) {
print(" Hashing " + item + "...");
ref = hashFile(item);
println("DONE");
} else {
print("Verifying " + item + "...");
byte[] tgt = hashFile(item);
assert Arrays.equals(ref, tgt);
println("PASSED");
}
}
}

@ -1,6 +1,6 @@
#Fri Apr 15 23:02:44 CST 2016
#Mon Jun 20 13:41:04 CST 2016
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.12-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14-bin.zip

Loading…
Cancel
Save