apply plugin: 'c' apply plugin: 'java' apply plugin: 'groovy' import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.lang.RuntimeException; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; import java.util.regex.Matcher; import java.util.regex.Pattern; // ---------------------------------------------------------------------------- model { buildTypes { release } components { mkbootfs(NativeExecutableSpec) { binaries.all { } } } } // ---------------------------------------------------------------------------- // global // ---------------------------------------------------------------------------- def workdir='build/unzip_boot' def defaultRootDir = workdir + "/root" String[] bins = [ "sh", "logcat", "logd", "linker", "toolbox", "toybox", "applypatch" ] String[] libs = [ "libdl.so", "libutils.so", "libc++.so", "libc.so", "libm.so", "libz.so", "libstdc++.so", "libcutils.so", "libselinux.so", "liblog.so", "libpcre.so", "libsysutils.so", "libnl.so", "libbase.so", "libbacktrace.so", "libunwind.so" ] boolean gDebug=true String activeImg = null; if (new File("boot.img").exists()) { activeImg = "boot.img"; } else if (new File("recovery.img").exists()) { activeImg = "recovery.img"; } println("Active image target: " + activeImg); // ---------------------------------------------------------------------------- // tasks // ---------------------------------------------------------------------------- task unpack_bootimg(type: JavaExec, dependsOn: ['abootimg:abootimg']) { doFirst { def rootdir = new File(workdir) if (rootdir.exists()) { rootdir.deleteDir() } rootdir.mkdirs() } main = 'cfig.bootimg.abootimg' classpath = files("abootimg/build/libs/abootimg.jar") maxHeapSize '512m' args String.format("%s", activeImg), workdir } task unpack_ramdisk_gz << { unGnuzipFile(workdir+"/ramdisk.img.gz", workdir + "/ramdisk.img") } unpack_ramdisk_gz.dependsOn(unpack_bootimg) task unpack_cpio(type: Exec, dependsOn: unpack_ramdisk_gz) { doFirst { def rootdir = new File(workdir+ "/root") if (rootdir.exists()) { rootdir.deleteDir() } rootdir.mkdirs() } workingDir workdir + "/root" executable 'cpio' args = ['-i', '-F', '../ramdisk.img'] } task unpack(type: Delete, dependsOn: unpack_cpio) { description "extract boot.img or recovery.img" delete workdir + "/ramdisk.img.gz" delete workdir + "/ramdisk.img" } task pack_ramdisk_and_gz { Task task -> def rootDir = defaultRootDir if (null != System.getProperty("ANDROID_PRODUCT_OUT")) { rootDir = System.getProperty("ANDROID_PRODUCT_OUT") + "/root" } doLast { if (!rootDir.equals(defaultRootDir)) { println("Warning:") println("Warning:") println("Warning:\tUsing [" + rootDir + "] for target root") println("Warning:") println("Warning:") } ByteArrayOutputStream mkbootfs_out = new ByteArrayOutputStream() task.project.exec { commandLine = [ 'build/exe/mkbootfs/mkbootfs', rootDir ] standardOutput = mkbootfs_out } def ByteArrayInputStream gzip_in = new ByteArrayInputStream(mkbootfs_out.buf) gnuZipFile(workdir + "/ramdisk.img.gz", gzip_in) } } pack_ramdisk_and_gz.dependsOn('mkbootfsExecutable') task pack_clear(type: Exec, dependsOn: [pack_ramdisk_and_gz]) { def theCmdLine = getRamdiskConfig(workdir, 'cmdline') if (gDebug) { theCmdLine = "androidboot.selinux=disabled " + theCmdLine } def theBaseAddr = getBaseAddress(workdir) workingDir '.' executable 'src/mkbootimg/mkbootimg' args = [ '--kernel', workdir + "/kernel", '--ramdisk', workdir + "/ramdisk.img.gz", '--cmdline', theCmdLine, '--base', theBaseAddr, '--output', activeImg + '.clear'] } void unGnuzipFile(String compressedFile, String decompressedFile) throws IOException { byte[] buffer = new byte[1024]; try { FileInputStream fileIn = new FileInputStream(compressedFile); GZIPInputStream gZIPInputStream = new GZIPInputStream(fileIn); FileOutputStream fileOutputStream = new FileOutputStream(decompressedFile); int bytes_read; while ((bytes_read = gZIPInputStream.read(buffer)) > 0) { fileOutputStream.write(buffer, 0, bytes_read); } gZIPInputStream.close(); fileOutputStream.close(); System.out.println("The file was decompressed successfully!"); } catch (IOException ex) { throw ex; } } void gnuZipFile(String compressedFile, InputStream fis) throws IOException { byte[] buffer = new byte[1024]; try { FileOutputStream fos = new FileOutputStream(compressedFile); GZIPOutputStream gos = new GZIPOutputStream(fos); int bytes_read; while ((bytes_read = fis.read(buffer)) > 0) { gos .write(buffer, 0, bytes_read); } gos.finish(); gos.close(); System.out.println("The file compressed successfully!"); } catch (IOException ex) { throw ex; } } void gnuZipFile(String compressedFile, String decompressedFile) throws IOException { byte[] buffer = new byte[1024]; try { FileOutputStream fos = new FileOutputStream(compressedFile); GZIPOutputStream gos = new GZIPOutputStream(fos); FileInputStream fis = new FileInputStream(decompressedFile); int bytes_read; while ((bytes_read = fis.read(buffer)) > 0) { gos .write(buffer, 0, bytes_read); } fis.close(); gos.finish(); gos.close(); System.out.println("The file compressed successfully!"); } catch (IOException ex) { throw ex; } } String getBaseAddress(String inWorkdir) { Long ret; try { ret = Long.parseLong(getRamdiskConfig(inWorkdir, "kerneladdr").substring(2), 16) - 0x8000L; } catch (NumberFormatException e) { throw new RuntimeException("NumberFormatException: invalid kerneladdr value") } return Long.toHexString(ret); } String getRamdiskConfig(String inWorkdir, String inKey) { String ret; if (!new File(inWorkdir+ "/bootimg.cfg").exists()) { return "0x0"; } try { BufferedReader br = new BufferedReader(new FileReader(inWorkdir + "/bootimg.cfg")); String item; while (true) { item = br.readLine(); if (null == item) { break; } Pattern r = Pattern.compile("(?<=" + inKey + " = ).*"); Matcher m = r.matcher(item); if (m.find()) { ret = m.group(0) } } } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("Fatal Error"); } return ret; } task pack(type: JavaExec, dependsOn: [pack_clear, 'boot_signer:jar']) { main = 'com.android.verity.BootSignature' classpath = files("boot_signer/build/libs/boot_signer.jar") maxHeapSize '512m' args '/boot', activeImg + '.clear', 'security/verity.pk8', 'security/verity.x509.pem', activeImg + '.signed' } task _setup(type: Copy) { from 'src/test/resources/boot.img' into '.' } void Run(List inCmd, String inWorkdir = null) { println("CMD:" + inCmd) if (inWorkdir == null) { inWorkdir = "."; } ProcessBuilder pb = new ProcessBuilder(inCmd) .directory(new File(inWorkdir)) .redirectErrorStream(true); Process p = pb.start() p.inputStream.eachLine {println it} p.waitFor(); assert 0 == p.exitValue() } void Run(String inCmd, String inWorkdir = null) { Run(Arrays.asList(inCmd.split()), inWorkdir); } boolean RunFunc(List inCmd, String inWorkdir = null) { println("CMD:" + inCmd) if (inWorkdir == null) { inWorkdir = "."; } ProcessBuilder pb = new ProcessBuilder(inCmd) .directory(new File(inWorkdir)) .redirectErrorStream(true); Process p = pb.start() p.inputStream.eachLine {println it} p.waitFor(); return 0 == p.exitValue(); } void RunFunc(String inCmd, String inWorkdir = null) { RunFunc(Arrays.asList(inCmd.split()), inWorkdir); } void updateBootImage(String activeImg) { String flashTarget = null; switch (activeImg) { case "boot.img": flashTarget = "/dev/block/by-name/boot"; break; case "recovery.img": flashTarget = "/dev/block/by-name/recovery"; break; } Run("adb root") Run("adb push " + activeImg + ".signed /cache/") List cmd2 = ["adb", "shell", "dd if=/cache/" + activeImg + ".signed of=" + flashTarget]; Run(cmd2) cmd2 = ["adb", "shell", "rm -f /cache/" + activeImg + ".signed"]; Run(cmd2) } task flash << { updateBootImage(activeImg) } void rebootRecovery() { Run("adb reboot recovery") } task rr << { rebootRecovery() } void updateLinks(String inWorkdir) { String sysBinDir = inWorkdir + "/root/system/bin"; String[] toolboxLinks = [ "df", "getevent", "iftop", "ioctl", "ionice", "log", "ls", "lsof", "mount", "nandread", "newfs_msdos", "ps", "prlimit", "renice", "sendevent", "start", "stop", "top", "uptime", "watchprops", "dd", "du" ]; String[] toyboxLinks = [ "acpi", "basename", "blockdev", "bzcat", "cal", "cat", "chcon", "chgrp", "chmod", "chown", "chroot", "cksum", "clear", "comm", "cmp", "cp", "cpio", "cut", "date", "dirname", "dmesg", "dos2unix", "echo", "env", "expand", "expr", "fallocate", "false", "find", "free", "getenforce", "getprop", "groups", "head", "hostname", "hwclock", "id", "ifconfig", "inotifyd", "insmod", "kill", "load_policy", "ln", "logname", "losetup", "lsmod", "lsusb", "md5sum", "mkdir", "mknod", "mkswap", "mktemp", "modinfo", "more", "mountpoint", "mv", "netstat", "nice", "nl", "nohup", "od", "paste", "patch", "pgrep", "pidof", "pkill", "pmap", "printenv", "printf", "pwd", "readlink", "realpath", "restorecon", "rm", "rmdir", "rmmod", "route", "runcon", "sed", "seq", "setenforce", "setprop", "setsid", "sha1sum", "sleep", "sort", "split", "stat", "strings", "swapoff", "swapon", "sync", "sysctl", "tac", "tail", "tar", "taskset", "tee", "time", "timeout", "touch", "tr", "true", "truncate", "umount", "uname", "uniq", "unix2dos", "usleep", "vmstat", "wc", "which", "whoami", "xargs", "yes" ]; for (String item : toolboxLinks) { RunFunc("unlink " + item, sysBinDir); } for (String item : toyboxLinks) { RunFunc("unlink " + item, sysBinDir); } for (String item : toolboxLinks) { Run("/bin/ln -s toolbox " + item, sysBinDir); } for (String item : toyboxLinks) { Run("/bin/ln -s toybox " + item, sysBinDir); } } task debug(dependsOn: ['addSystemBin', 'addSystemLib']) { description "add debug tools into recovery rootfs from ANDROID_PRODUCT_OUT" doLast { updateLinks(workdir); } } task addSystemBin(type: Copy) { from System.getProperty("ANDROID_PRODUCT_OUT") + '/system/bin' into workdir + "/root/system/bin" include { details -> inTargetList(details.file.name, bins) } } task addSystemLib(type: Copy) { from System.getProperty("ANDROID_PRODUCT_OUT") + '/system/lib' into workdir + "/root/system/lib" include { details -> inTargetList(details.file.name, libs) } } boolean inTargetList(String file, String[] inArray) { for (String item : inArray) { if (item.equals(file)) { return true; } } return false; } // ---------------------------------------------------------------------------- // post configs // ---------------------------------------------------------------------------- if (null == activeImg) { pack.enabled = false unpack.enabled = false unpack_cpio.enabled = false unpack_bootimg.enabled = false unpack_ramdisk_gz.enabled = false } if (!new File(workdir + "/bootimg.cfg").exists()) { pack_clear.enabled = false; }