├── .gitignore
├── .idea
├── compiler.xml
├── copyright
│ └── profiles_settings.xml
├── dictionaries
│ └── kiva.xml
├── encodings.xml
├── gradle.xml
├── inspectionProfiles
│ ├── Project_Default.xml
│ └── profiles_settings.xml
├── misc.xml
└── modules.xml
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── kiva
│ │ └── bootimg
│ │ └── ExampleInstrumentationTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ └── res
│ │ ├── mipmap-hdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-mdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xhdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xxhdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xxxhdpi
│ │ └── ic_launcher.png
│ │ └── values
│ │ ├── colors.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── kiva
│ └── bootimg
│ └── ExampleUnitTest.java
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── jbootimage
├── .gitignore
├── build.gradle
└── src
│ └── main
│ └── java
│ └── com
│ └── kiva
│ ├── BootImage.java
│ ├── BootImageInfo.java
│ ├── BootType.java
│ ├── ByteArray.java
│ ├── Constant.java
│ ├── IOUtils.java
│ ├── MTKContacts.java
│ ├── Main.java
│ └── ramdisk
│ ├── MTKRamdisk.java
│ ├── QualcommRamdisk.java
│ ├── Ramdisk.java
│ ├── RamdiskFactory.java
│ ├── RamdiskProcessor.java
│ ├── RamdiskType.java
│ └── processor
│ └── GZipRamdiskProcessor.java
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/workspace.xml
5 | /.idea/libraries
6 | .DS_Store
7 | /build
8 | /captures
9 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/.idea/dictionaries/kiva.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | cpio
5 | lzma
6 | lzop
7 | ramdisk
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
18 |
19 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 | Android
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # JBootImage
2 | A Java library that can pack & unpack android boot.img
3 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 23
5 | buildToolsVersion "23.0.3"
6 | defaultConfig {
7 | applicationId "com.kiva.bootimg"
8 | minSdkVersion 15
9 | targetSdkVersion 23
10 | versionCode 1
11 | versionName "1.0"
12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | }
21 |
22 | dependencies {
23 | compile fileTree(dir: 'libs', include: ['*.jar'])
24 | compile 'com.android.support:appcompat-v7:23.4.0'
25 | testCompile 'junit:junit:4.12'
26 | androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.2'
27 | androidTestCompile 'com.android.support.test:runner:0.5'
28 | androidTestCompile 'com.android.support:support-annotations:23.4.0'
29 | }
30 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/kiva/devel/android-sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/kiva/bootimg/ExampleInstrumentationTest.java:
--------------------------------------------------------------------------------
1 | package com.kiva.bootimg;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.filters.MediumTest;
6 | import android.support.test.runner.AndroidJUnit4;
7 |
8 | import org.junit.Test;
9 | import org.junit.runner.RunWith;
10 |
11 |
12 | import static org.junit.Assert.*;
13 |
14 | /**
15 | * Instrumentation test, which will execute on an Android device.
16 | *
17 | * @see Testing documentation
18 | */
19 | @MediumTest
20 | @RunWith(AndroidJUnit4.class)
21 | public class ExampleInstrumentationTest {
22 | @Test
23 | public void useAppContext() throws Exception {
24 | // Context of the app under test.
25 | Context appContext = InstrumentationRegistry.getTargetContext();
26 |
27 | assertEquals("com.kiva.bootimg", appContext.getPackageName());
28 | }
29 | }
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asLody/JBootImage/d2f5a3782799b9586950167ce00f2f189851161b/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asLody/JBootImage/d2f5a3782799b9586950167ce00f2f189851161b/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asLody/JBootImage/d2f5a3782799b9586950167ce00f2f189851161b/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asLody/JBootImage/d2f5a3782799b9586950167ce00f2f189851161b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asLody/JBootImage/d2f5a3782799b9586950167ce00f2f189851161b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Bootimg
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/test/java/com/kiva/bootimg/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.kiva.bootimg;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:2.2.0-alpha2'
9 |
10 | // NOTE: Do not place your application dependencies here; they belong
11 | // in the individual module build.gradle files
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | jcenter()
18 | }
19 | }
20 |
21 | task clean(type: Delete) {
22 | delete rootProject.buildDir
23 | }
24 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asLody/JBootImage/d2f5a3782799b9586950167ce00f2f189851161b/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Dec 28 10:00:20 PST 2015
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/jbootimage/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/jbootimage/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'java'
2 |
3 | dependencies {
4 | compile fileTree(dir: 'libs', include: ['*.jar'])
5 | compile group: 'org.apache.commons', name: 'commons-compress', version: '1.11'
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/jbootimage/src/main/java/com/kiva/BootImage.java:
--------------------------------------------------------------------------------
1 | package com.kiva;
2 |
3 | import com.kiva.ramdisk.Ramdisk;
4 | import com.kiva.ramdisk.RamdiskFactory;
5 | import com.kiva.ramdisk.RamdiskProcessor;
6 | import com.kiva.ramdisk.RamdiskType;
7 |
8 | import java.io.File;
9 | import java.io.FileInputStream;
10 | import java.io.FileOutputStream;
11 | import java.io.IOException;
12 | import java.io.ObjectInputStream;
13 | import java.io.ObjectOutputStream;
14 | import java.io.RandomAccessFile;
15 | import java.util.Arrays;
16 |
17 | import static com.kiva.BootType.MTK;
18 |
19 | /**
20 | * @author Lody Kiva
21 | *
22 | */
23 | public class BootImage implements Constant {
24 | private static final byte MAGIC[] = {0x41, 0x4E, 0x44, 0x52, 0x4F, 0x49, 0x44, 0x21};
25 |
26 | private BootImageInfo bootImageInfo;
27 | private ByteArray image;
28 | private Ramdisk ramdisk;
29 | private boolean isUnpack;
30 | private String source;
31 |
32 | private byte[] kernelBuf;
33 | private byte[] ramdiskBuf;
34 | private byte[] secondBuf;
35 |
36 | private BootImage(String source, boolean isUnpack) {
37 | this.isUnpack = isUnpack;
38 | this.source = source;
39 | }
40 |
41 | public static BootImage fromFile(String file) throws IOException {
42 | File bootFile = new File(file);
43 | if (!bootFile.isFile()) {
44 | throw new IOException("Invalid file: " + file);
45 | }
46 |
47 | BootImage image = new BootImage(file, true);
48 |
49 | image.image = ByteArray.wrap(IOUtils.readFully(bootFile));
50 | image.bootImageInfo = new BootImageInfo();
51 |
52 | image.detectBootType();
53 | image.loadImage();
54 | return image;
55 | }
56 |
57 | public static BootImage fromDir(String dir) throws IOException {
58 | File bootDir = new File(dir);
59 | if (!bootDir.isDirectory()) {
60 | throw new IOException("Invalid directory: " + dir);
61 | }
62 |
63 | BootImage image = new BootImage(dir, false);
64 | image.loadConfig(new File(bootDir, CONFIG_FILE_NAME));
65 | return image;
66 | }
67 |
68 | private void loadConfig(File file) throws IOException {
69 | if (isUnpack) {
70 | return;
71 | }
72 |
73 | ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
74 | try {
75 | bootImageInfo = (BootImageInfo) ois.readObject();
76 | } catch (ClassNotFoundException e) {
77 | // Will not going to happen
78 | }
79 | ois.close();
80 | }
81 |
82 | private void detectBootType() {
83 | if (!isUnpack) {
84 | return;
85 | }
86 |
87 | // TODO
88 | bootImageInfo.bootType = MTK;
89 | }
90 |
91 | private void loadImage() throws IOException {
92 | if (!isUnpack) {
93 | return;
94 | }
95 |
96 | bootImageInfo.magic = image.readBytes(BootImageInfo.BOOT_MAGIC_SIZE);
97 | if (!checkMagic(bootImageInfo.magic)) {
98 | throw new IOException("Invalid boot.img");
99 | }
100 |
101 | bootImageInfo.kernelSize = image.readU4();
102 | bootImageInfo.kernelAddr = image.readU4();
103 | bootImageInfo.ramdiskSize = image.readU4();
104 | bootImageInfo.ramdiskAddr = image.readU4();
105 | bootImageInfo.secondSize = image.readU4();
106 | bootImageInfo.secondAddr = image.readU4();
107 | bootImageInfo.tagsAddr = image.readU4();
108 | bootImageInfo.pageSize = image.readU4();
109 | bootImageInfo.dtSize = image.readU4();
110 | bootImageInfo.unused = image.readBytes(BootImageInfo.UNUSED_SIZE);
111 | bootImageInfo.name = image.readBytes(BootImageInfo.BOOT_NAME_SIZE);
112 | bootImageInfo.cmdline = image.readBytes(BootImageInfo.BOOT_ARGS_SIZE);
113 | bootImageInfo.id = null;// Needn't
114 |
115 | // Peek kernel
116 | image.seek(bootImageInfo.pageSize);
117 | kernelBuf = image.readBytes(bootImageInfo.kernelSize);
118 |
119 | // Peek Ramdisk
120 | int ramdiskPos = (((bootImageInfo.kernelSize + bootImageInfo.pageSize)
121 | / (bootImageInfo.pageSize * 2)) + 1)
122 | * (bootImageInfo.pageSize * 2);
123 | image.seek(ramdiskPos);
124 | ramdiskBuf = image.readBytes(bootImageInfo.ramdiskSize);
125 |
126 | if (bootImageInfo.secondSize > 0) {
127 | // Peek Second stage
128 | int secondPos = (((ramdiskPos + bootImageInfo.ramdiskSize)
129 | / (bootImageInfo.pageSize * 2)) + 1)
130 | * (bootImageInfo.pageSize * 2);
131 | image.seek(secondPos);
132 | secondBuf = image.readBytes(bootImageInfo.secondSize);
133 | }
134 |
135 | ramdisk = RamdiskFactory.makeRamdisk(bootImageInfo.bootType, getRamdiskBuffer());
136 | if (ramdisk == null) {
137 | throw new IOException("Failed to create ramdisk instance");
138 | }
139 |
140 | bootImageInfo.ramdiskType = ramdisk.getRamdiskType();
141 | }
142 |
143 | private static boolean checkMagic(byte[] magic) {
144 | return Arrays.equals(magic, MAGIC);
145 | }
146 |
147 | public void unpack(String outputDir) throws IOException {
148 | if (!isUnpack) {
149 | return;
150 | }
151 |
152 | File outputDirFile = new File(outputDir);
153 |
154 | FileOutputStream kernelOutput = null;
155 | FileOutputStream secondOutput = null;
156 | ObjectOutputStream configOutput = null;
157 | try {
158 | if (!outputDirFile.exists()) {
159 | if (!outputDirFile.mkdirs()) {
160 | throw new IOException("Failed to create output directory");
161 | }
162 | }
163 |
164 | kernelOutput = new FileOutputStream(
165 | new File(outputDirFile, KERNEL_FILE_NAME));
166 | kernelOutput.write(getKernelBuffer());
167 |
168 | if (bootImageInfo.secondSize > 0) {
169 | secondOutput = new FileOutputStream(
170 | new File(outputDirFile, SECOND_FILE_NAME));
171 | secondOutput.write(getSecondBuffer());
172 | }
173 |
174 | ramdisk.writeExtraFile(outputDir);
175 | ramdisk.getRamdiskProcessor()
176 | .decompress(ramdisk.getRamdiskBuffer(),
177 | (outputDirFile.getAbsolutePath()
178 | + File.separator + RAMDISK_DIR_NAME));
179 |
180 | configOutput = new ObjectOutputStream(new FileOutputStream(
181 | new File(outputDirFile, CONFIG_FILE_NAME)));
182 | configOutput.writeObject(bootImageInfo);
183 | } catch (Exception e) {
184 | IOUtils.delete(outputDirFile);
185 | throw new IOException(e);
186 | } finally {
187 | IOUtils.safeClose(kernelOutput);
188 | IOUtils.safeClose(secondOutput);
189 | IOUtils.safeClose(configOutput);
190 | }
191 | }
192 |
193 | public void repack(String outputFile) throws IOException {
194 | if (isUnpack) {
195 | return;
196 | }
197 |
198 | File kernelFile = new File(source, KERNEL_FILE_NAME);
199 | if (!kernelFile.exists()) {
200 | throw new IOException("kernel does not exist");
201 | }
202 |
203 | File packedRamdiskFile = new File(source, RAMDISK_PACKED_FILE_NAME);
204 | File ramdiskDir = new File(source, RAMDISK_DIR_NAME);
205 | File secondFile = new File(source, SECOND_FILE_NAME);
206 |
207 | if (!ramdiskDir.exists() && !packedRamdiskFile.exists()) {
208 | throw new IOException("Neither ramdisk dir nor packed ramdisk exists");
209 | }
210 |
211 | if (getSecondSize() > 0 && !secondFile.exists()) {
212 | throw new IOException("Second stage file does not exist");
213 | }
214 |
215 | if (ramdiskDir.exists()) {
216 | RamdiskProcessor processor = RamdiskFactory.makeRamdiskProcessor(getRamdiskType());
217 | if (processor == null) {
218 | throw new IOException("Failed to create ramdisk processor");
219 | }
220 |
221 | File headerFile = new File(source, HEADER_FILE_NAME);
222 | File footerFile = new File(source, FOOTER_FILE_NAME);
223 | processor.compress(ramdiskDir.getAbsolutePath(),
224 | packedRamdiskFile.getAbsolutePath(),
225 | headerFile, footerFile);
226 | }
227 |
228 | int kernelSize = (int) kernelFile.length();
229 | int ramdiskSize = (int) packedRamdiskFile.length();
230 |
231 | RandomAccessFile raf = new RandomAccessFile(outputFile, "rw");
232 | raf.seek(0);
233 | raf.write(MAGIC);
234 | raf.writeInt(kernelSize);
235 | raf.writeInt(getKernelAddr());
236 | raf.writeInt(ramdiskSize);
237 | raf.writeInt(getRamdiskAddr());
238 | raf.writeInt(getSecondSize());
239 | raf.writeInt(getSecondAddr());
240 | raf.writeInt(getTagsSize());
241 | raf.writeInt(getPageSize());
242 | raf.writeInt(getDtSize());
243 | raf.write(new byte[BootImageInfo.UNUSED_SIZE]);
244 | raf.write(getName());
245 | raf.write(getCmdline());
246 | // id
247 |
248 | // kernel
249 | raf.seek(getPageSize());
250 | raf.write(IOUtils.readFully(kernelFile));
251 |
252 | // ramdisk
253 | int ramdiskPos = (((kernelSize + bootImageInfo.pageSize)
254 | / (bootImageInfo.pageSize * 2)) + 1)
255 | * (bootImageInfo.pageSize * 2);
256 | raf.seek(ramdiskPos);
257 | raf.write(IOUtils.readFully(packedRamdiskFile));
258 |
259 | // second
260 | if (getSecondSize() > 0) {
261 | int secondPos = (((ramdiskSize / (bootImageInfo.pageSize * 2)) + 1)
262 | * (bootImageInfo.pageSize * 2)) + ramdiskPos;
263 | raf.seek(secondPos);
264 | raf.write(IOUtils.readFully(secondFile));
265 | }
266 |
267 | raf.close();
268 | }
269 |
270 |
271 | public byte[] getMagic() {
272 | return bootImageInfo.magic;
273 | }
274 |
275 | public int getKernelSize() {
276 | return bootImageInfo.kernelSize;
277 | }
278 |
279 | public int getKernelAddr() {
280 | return bootImageInfo.kernelAddr;
281 | }
282 |
283 | public int getRamdiskSize() {
284 | return bootImageInfo.ramdiskSize;
285 | }
286 |
287 | public int getRamdiskAddr() {
288 | return bootImageInfo.ramdiskAddr;
289 | }
290 |
291 | public int getSecondSize() {
292 | return bootImageInfo.secondSize;
293 | }
294 |
295 | public int getSecondAddr() {
296 | return bootImageInfo.secondAddr;
297 | }
298 |
299 | public int getTagsSize() {
300 | return bootImageInfo.tagsAddr;
301 | }
302 |
303 | public int getPageSize() {
304 | return bootImageInfo.pageSize;
305 | }
306 |
307 | public int getDtSize() {
308 | return bootImageInfo.dtSize;
309 | }
310 |
311 | public byte[] getUnused() {
312 | return bootImageInfo.unused;
313 | }
314 |
315 | public byte[] getName() {
316 | return bootImageInfo.name;
317 | }
318 |
319 | public byte[] getCmdline() {
320 | return bootImageInfo.cmdline;
321 | }
322 |
323 | public byte[] getKernelBuffer() {
324 | return kernelBuf;
325 | }
326 |
327 | public byte[] getRamdiskBuffer() {
328 | return ramdiskBuf;
329 | }
330 |
331 | public byte[] getSecondBuffer() {
332 | return secondBuf;
333 | }
334 |
335 | public Ramdisk getRamdisk() {
336 | return ramdisk;
337 | }
338 |
339 | public RamdiskType getRamdiskType() {
340 | return bootImageInfo.ramdiskType;
341 | }
342 |
343 | public BootType getBootType() {
344 | return bootImageInfo.bootType;
345 | }
346 | }
347 |
--------------------------------------------------------------------------------
/jbootimage/src/main/java/com/kiva/BootImageInfo.java:
--------------------------------------------------------------------------------
1 | package com.kiva;
2 |
3 | import com.kiva.ramdisk.RamdiskType;
4 |
5 | import java.io.Serializable;
6 |
7 | /**
8 | * @author kiva
9 | */
10 |
11 | public class BootImageInfo implements Serializable {
12 | public static final int BOOT_MAGIC_SIZE = 8;
13 | public static final int BOOT_NAME_SIZE = 16;
14 | public static final int BOOT_ARGS_SIZE = 512;
15 | public static final int UNUSED_SIZE = 4;
16 |
17 | public transient byte[] magic;
18 | public int kernelSize; /* size in bytes */
19 | public int kernelAddr; /* physical load addr */
20 |
21 | public int ramdiskSize; /* size in bytes */
22 | public int ramdiskAddr; /* physical load addr */
23 |
24 | public int secondSize; /* size in bytes */
25 | public int secondAddr; /* physical load addr */
26 |
27 | public int tagsAddr; /* physical addr for kernel tags */
28 | public int pageSize; /* flash page size we assume */
29 | public int dtSize; /* device tree size in bytes */
30 | public transient byte[] unused; /* future expansion: should be 0 */
31 | public byte[] name; /* asciiz product name */
32 |
33 | public byte[] cmdline;
34 |
35 | public transient int[] id; /* timestamp / checksum / sha1 / etc */
36 |
37 | public BootType bootType;
38 | public RamdiskType ramdiskType;
39 | }
40 |
--------------------------------------------------------------------------------
/jbootimage/src/main/java/com/kiva/BootType.java:
--------------------------------------------------------------------------------
1 | package com.kiva;
2 |
3 | /**
4 | * @author kiva
5 | */
6 |
7 | public enum BootType {
8 | MTK,
9 | QUALCOMM,
10 | // More in feature
11 | }
12 |
--------------------------------------------------------------------------------
/jbootimage/src/main/java/com/kiva/ByteArray.java:
--------------------------------------------------------------------------------
1 | package com.kiva;
2 |
3 | import java.nio.ByteBuffer;
4 | import java.nio.ByteOrder;
5 |
6 | /**
7 | * @author kiva
8 | */
9 |
10 | public class ByteArray {
11 | private int length;
12 | private byte[] bytes;
13 | private int pos;
14 |
15 | public ByteArray(byte[] bytes) {
16 | this.length = bytes.length;
17 | this.bytes = bytes;
18 | seek(0);
19 | }
20 |
21 | public byte[] getBytes() {
22 | return bytes;
23 | }
24 |
25 | public byte[] readBytes(int count) {
26 | byte[] buf = new byte[count];
27 | int limit = count;
28 | if (count + pos >= length) {
29 | limit = length - pos - 1;
30 | }
31 | System.arraycopy(bytes, pos, buf, 0, limit);
32 | pos += count;
33 | return buf;
34 | }
35 |
36 | public int readU4() {
37 | return ByteBuffer.wrap(readBytes(4))
38 | .order(ByteOrder.LITTLE_ENDIAN)
39 | .getInt();
40 | }
41 |
42 | public void seek(int newPos) {
43 | this.pos = newPos;
44 | }
45 |
46 | public static ByteArray wrap(byte[] bytes) {
47 | return new ByteArray(bytes);
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/jbootimage/src/main/java/com/kiva/Constant.java:
--------------------------------------------------------------------------------
1 | package com.kiva;
2 |
3 | /**
4 | * @author kiva
5 | */
6 | public interface Constant {
7 | String CONFIG_FILE_NAME = "config.bin";
8 | String SECOND_FILE_NAME = "second";
9 | String KERNEL_FILE_NAME = "kernel";
10 | String RAMDISK_PACKED_FILE_NAME = "ramdisk.packed";
11 | String HEADER_FILE_NAME = "ramdisk-header";
12 | String FOOTER_FILE_NAME = "ramdisk-footer";
13 | String RAMDISK_DIR_NAME = "ramdisk";
14 | }
15 |
--------------------------------------------------------------------------------
/jbootimage/src/main/java/com/kiva/IOUtils.java:
--------------------------------------------------------------------------------
1 | package com.kiva;
2 |
3 | import java.io.ByteArrayOutputStream;
4 | import java.io.Closeable;
5 | import java.io.File;
6 | import java.io.FileInputStream;
7 | import java.io.FileOutputStream;
8 | import java.io.IOException;
9 | import java.io.InputStream;
10 |
11 | /**
12 | * @author kiva
13 | */
14 |
15 | public class IOUtils {
16 |
17 | public static void safeClose(Closeable is) {
18 | if (is != null) {
19 | try {
20 | is.close();
21 | } catch (Throwable e) {
22 | //Ignore
23 | }
24 | }
25 | }
26 |
27 | public static void write(File file, byte[] bytes) throws IOException {
28 | FileOutputStream os = null;
29 | try {
30 | os = new FileOutputStream(file);
31 | os.write(bytes);
32 | } catch (Exception e) {
33 | throw new IOException(e);
34 | } finally {
35 | if (os != null) {
36 | os.close();
37 | }
38 | }
39 | }
40 |
41 | public static byte[] read(InputStream is, int count) throws IOException {
42 | byte[] buf = new byte[count];
43 | is.read(buf);
44 | return buf;
45 | }
46 |
47 | public static byte[] readFully(InputStream is) throws IOException {
48 | ByteArrayOutputStream os = new ByteArrayOutputStream();
49 | byte[] buffer = new byte[128];
50 | int i;
51 | for (;;) {
52 | if ((i = is.read(buffer)) < 0) {
53 | break;
54 | }
55 | os.write(buffer, 0, i);
56 | }
57 | return os.toByteArray();
58 | }
59 |
60 | public static boolean delete(File dir) {
61 | if (!dir.exists()) {
62 | return false;
63 | }
64 |
65 | if (dir.isDirectory()) {
66 | String[] children = dir.list();
67 | //递归删除目录中的子目录下
68 | for (String child : children) {
69 | boolean success = delete(new File(dir, child));
70 | if (!success) {
71 | return false;
72 | }
73 | }
74 | }
75 | // 目录此时为空,可以删除
76 | return dir.delete();
77 | }
78 |
79 | public static byte[] readFully(File file) throws IOException {
80 | FileInputStream is = new FileInputStream(file);
81 | byte[] bytes = readFully(is);
82 | is.close();
83 | return bytes;
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/jbootimage/src/main/java/com/kiva/MTKContacts.java:
--------------------------------------------------------------------------------
1 | package com.kiva;
2 |
3 | /**
4 | * @author kiva
5 | */
6 |
7 | public class MTKContacts {
8 | public static final byte[] MTK_IDENTITY_ONE = {-120, 22, -120, 88};
9 | }
10 |
--------------------------------------------------------------------------------
/jbootimage/src/main/java/com/kiva/Main.java:
--------------------------------------------------------------------------------
1 | package com.kiva;
2 |
3 | import java.io.IOException;
4 |
5 | public class Main {
6 |
7 | public static void main(String... args) throws IOException {
8 | // for (int i = 0; i < 2; ++i) {
9 | // BootImage img = new BootImage("/Users/kiva/ss/mtk" + i + ".img");
10 | // img.unpack("/Users/kiva/ss/output" + i);
11 | // }
12 |
13 | // BootImage img = BootImage.fromFile("/Users/kiva/ss/mtk1.img");
14 | // img.unpack("/Users/kiva/ss/output");
15 | //
16 | BootImage repackImg = BootImage.fromDir("/Users/kiva/ss/output");
17 | repackImg.repack("/Users/kiva/ss/output/jboot.img");
18 |
19 | // BootImage reunpackImg = BootImage.fromFile("/Users/kiva/ss/output/jboot.img");
20 | // reunpackImg.unpack("/Users/kiva/ss/output-reunpack");
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/jbootimage/src/main/java/com/kiva/ramdisk/MTKRamdisk.java:
--------------------------------------------------------------------------------
1 | package com.kiva.ramdisk;
2 |
3 | import com.kiva.BootImage;
4 | import com.kiva.Constant;
5 | import com.kiva.IOUtils;
6 |
7 | import org.apache.commons.compress.archivers.cpio.CpioArchiveEntry;
8 | import org.apache.commons.compress.archivers.cpio.CpioArchiveInputStream;
9 |
10 | import java.io.ByteArrayInputStream;
11 | import java.io.File;
12 | import java.io.FileOutputStream;
13 | import java.io.IOException;
14 | import java.util.zip.GZIPInputStream;
15 |
16 | /**
17 | * @author kiva
18 | */
19 |
20 | public class MTKRamdisk extends Ramdisk implements Constant {
21 | private byte[] header;
22 | private byte[] ramdisk;
23 |
24 | public MTKRamdisk(byte[] bytes) {
25 | ramdisk = new byte[bytes.length - 512];
26 | header = new byte[512];
27 | System.arraycopy(bytes, 0, header, 0, 512);
28 | System.arraycopy(bytes, 512, ramdisk, 0, ramdisk.length);
29 | }
30 |
31 | @Override
32 | public void writeExtraFile(String baseDir) throws IOException {
33 | File headerFile = new File(baseDir, HEADER_FILE_NAME);
34 | IOUtils.write(headerFile, header);
35 | }
36 |
37 | @Override
38 | public byte[] getRamdiskBuffer() {
39 | return ramdisk;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/jbootimage/src/main/java/com/kiva/ramdisk/QualcommRamdisk.java:
--------------------------------------------------------------------------------
1 | package com.kiva.ramdisk;
2 |
3 | /**
4 | * @author kiva
5 | */
6 | public class QualcommRamdisk extends Ramdisk {
7 | private byte[] ramdisk;
8 |
9 | public QualcommRamdisk(byte[] bytes) {
10 | this.ramdisk = bytes;
11 | }
12 |
13 | @Override
14 | public byte[] getRamdiskBuffer() {
15 | return this.ramdisk;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/jbootimage/src/main/java/com/kiva/ramdisk/Ramdisk.java:
--------------------------------------------------------------------------------
1 | package com.kiva.ramdisk;
2 |
3 | import java.io.IOException;
4 |
5 | /**
6 | * @author kiva
7 | */
8 |
9 | public abstract class Ramdisk {
10 | private RamdiskType ramdiskType;
11 | private RamdiskProcessor ramdiskProcessor;
12 |
13 | public RamdiskProcessor getRamdiskProcessor() {
14 | return ramdiskProcessor;
15 | }
16 |
17 | void setRamdiskProcessor(RamdiskProcessor processor) {
18 | this.ramdiskProcessor = processor;
19 | }
20 |
21 | public void setRamdiskType(RamdiskType ramdiskType) {
22 | this.ramdiskType = ramdiskType;
23 | }
24 |
25 | public RamdiskType getRamdiskType() {
26 | return ramdiskType;
27 | }
28 |
29 | public void writeExtraFile(String baseDir) throws IOException {}
30 |
31 | public abstract byte[] getRamdiskBuffer();
32 | }
33 |
--------------------------------------------------------------------------------
/jbootimage/src/main/java/com/kiva/ramdisk/RamdiskFactory.java:
--------------------------------------------------------------------------------
1 | package com.kiva.ramdisk;
2 |
3 |
4 | import com.kiva.BootType;
5 | import com.kiva.ramdisk.processor.GZipRamdiskProcessor;
6 |
7 | /**
8 | * @author kiva
9 | */
10 |
11 | public class RamdiskFactory {
12 | public static Ramdisk makeRamdisk(BootType bootType, byte[] buffer)
13 | throws UnsupportedOperationException {
14 | Ramdisk ramdisk = null;
15 | switch (bootType) {
16 | case MTK:
17 | ramdisk = new MTKRamdisk(buffer);
18 | break;
19 | case QUALCOMM:
20 | ramdisk = new QualcommRamdisk(buffer);
21 | break;
22 | default:
23 | throw new UnsupportedOperationException("Unsupported boot type: " + bootType);
24 | }
25 |
26 | RamdiskType ramdiskType = RamdiskType.detect(bootType, ramdisk.getRamdiskBuffer());
27 | ramdisk.setRamdiskProcessor(makeRamdiskProcessor(ramdiskType));
28 | ramdisk.setRamdiskType(ramdiskType);
29 | return ramdisk;
30 | }
31 |
32 | public static RamdiskProcessor makeRamdiskProcessor(RamdiskType ramdiskType)
33 | throws UnsupportedOperationException {
34 | if (ramdiskType != null) {
35 | switch (ramdiskType) {
36 | case GZIP:
37 | return new GZipRamdiskProcessor();
38 | // TODO
39 | }
40 | }
41 |
42 | throw new UnsupportedOperationException("Unsupported ramdisk format: " + ramdiskType);
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/jbootimage/src/main/java/com/kiva/ramdisk/RamdiskProcessor.java:
--------------------------------------------------------------------------------
1 | package com.kiva.ramdisk;
2 |
3 | import java.io.File;
4 | import java.io.IOException;
5 |
6 | /**
7 | * @author kiva
8 | */
9 |
10 | public abstract class RamdiskProcessor {
11 | public abstract void decompress(byte[] buffer, String outputDir)
12 | throws IOException;
13 |
14 | public abstract void compress(String fromDir, String outputName, File headerFile, File footerFile)
15 | throws IOException;
16 | }
17 |
--------------------------------------------------------------------------------
/jbootimage/src/main/java/com/kiva/ramdisk/RamdiskType.java:
--------------------------------------------------------------------------------
1 | package com.kiva.ramdisk;
2 |
3 | import com.kiva.BootType;
4 |
5 | import org.apache.commons.compress.compressors.xz.XZCompressorInputStream;
6 |
7 | import java.io.ByteArrayInputStream;
8 | import java.io.EOFException;
9 | import java.io.IOException;
10 | import java.io.InputStream;
11 |
12 | /**
13 | * @author kiva
14 | */
15 | public enum RamdiskType {
16 | GZIP(new GZipMimeMatcher()),
17 | LZMA(new LzmaMimeMatcher()),
18 | LZOP(new LzopMimeMatcher()),
19 | LZ4(new Lz4MimeMatcher()),
20 | XZ(new XzMimeMatcher());
21 |
22 | public static RamdiskType detect(BootType bootType, byte[] bytes) {
23 | for (RamdiskType type : RamdiskType.values()) {
24 | if (type.matcher.isMatch(bootType, bytes)) {
25 | return type;
26 | }
27 | }
28 | return null;
29 | }
30 |
31 | public final MimeMatcher matcher;
32 |
33 | RamdiskType(MimeMatcher matcher) {
34 | this.matcher = matcher;
35 | }
36 |
37 | public interface MimeMatcher {
38 | boolean isMatch(BootType bootType, byte[] bytes);
39 | }
40 |
41 | private static class GZipMimeMatcher implements MimeMatcher {
42 |
43 | private final static int GZIP_MAGIC = 0x8b1f;
44 |
45 | @Override
46 | public boolean isMatch(BootType bootType, byte[] bytes) {
47 | try {
48 | return readUShort(new ByteArrayInputStream(bytes)) == GZIP_MAGIC;
49 | } catch (IOException e) {
50 | // Will not going to happen.
51 | }
52 | // But we have to process it.
53 | return false;
54 | }
55 |
56 | private int readUShort(InputStream in) throws IOException {
57 | int b = readUByte(in);
58 | return (readUByte(in) << 8) | b;
59 | }
60 |
61 | private int readUByte(InputStream in) throws IOException {
62 | int b = in.read();
63 | if (b == -1) {
64 | throw new EOFException();
65 | }
66 | if (b < -1 || b > 255) {
67 | // Report on this.in, not argument in; see read{Header, Trailer}.
68 | throw new IOException("read() returned value out of range -1..255: " + b);
69 | }
70 | return b;
71 | }
72 | }
73 |
74 | private static class LzmaMimeMatcher implements MimeMatcher {
75 | @Override
76 | public boolean isMatch(BootType bootType, byte[] bytes) {
77 | if (bytes == null || bytes.length < 3) {
78 | return false;
79 | }
80 |
81 | if (bytes[0] != 0x5d) {
82 | return false;
83 | }
84 |
85 | if (bytes[1] != 0) {
86 | return false;
87 | }
88 |
89 | if (bytes[2] != 0) {
90 | return false;
91 | }
92 | return true;
93 | }
94 | }
95 |
96 | private static class LzopMimeMatcher implements MimeMatcher {
97 | @Override
98 | public boolean isMatch(BootType bootType, byte[] bytes) {
99 | return false;
100 | }
101 | }
102 |
103 | private static class Lz4MimeMatcher implements MimeMatcher {
104 | @Override
105 | public boolean isMatch(BootType bootType, byte[] bytes) {
106 | return false;
107 | }
108 | }
109 |
110 | private static class XzMimeMatcher implements MimeMatcher {
111 | @Override
112 | public boolean isMatch(BootType bootType, byte[] bytes) {
113 | // return XZCompressorInputStream.matches(bytes, bytes.length);
114 | return false;
115 | }
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/jbootimage/src/main/java/com/kiva/ramdisk/processor/GZipRamdiskProcessor.java:
--------------------------------------------------------------------------------
1 | package com.kiva.ramdisk.processor;
2 |
3 | import com.kiva.Constant;
4 | import com.kiva.IOUtils;
5 | import com.kiva.ramdisk.RamdiskProcessor;
6 |
7 | import org.apache.commons.compress.archivers.ArchiveEntry;
8 | import org.apache.commons.compress.archivers.cpio.CpioArchiveEntry;
9 | import org.apache.commons.compress.archivers.cpio.CpioArchiveInputStream;
10 | import org.apache.commons.compress.archivers.cpio.CpioArchiveOutputStream;
11 |
12 | import java.io.ByteArrayInputStream;
13 | import java.io.ByteArrayOutputStream;
14 | import java.io.File;
15 | import java.io.FileOutputStream;
16 | import java.io.IOException;
17 | import java.util.zip.GZIPInputStream;
18 | import java.util.zip.GZIPOutputStream;
19 |
20 | /**
21 | * @author kiva
22 | */
23 |
24 | public class GZipRamdiskProcessor extends RamdiskProcessor {
25 | private byte[] decompressGzip(byte[] ramdisk) {
26 | GZIPInputStream is = null;
27 |
28 | try {
29 | is = new GZIPInputStream(new ByteArrayInputStream(ramdisk));
30 | return IOUtils.readFully(is);
31 |
32 | } catch (Exception e) {
33 | e.printStackTrace();
34 |
35 | } finally {
36 | IOUtils.safeClose(is);
37 | }
38 |
39 | return null;
40 | }
41 |
42 | @Override
43 | public void decompress(byte[] buffer, String outputDir) throws IOException {
44 | CpioArchiveInputStream is = null;
45 | File outputDirFile = new File(outputDir);
46 |
47 | try {
48 | if (!outputDirFile.exists()) {
49 | if (!outputDirFile.mkdirs()) {
50 | throw new IOException("Failed to create output directory");
51 | }
52 | }
53 |
54 | byte[] cpioBuffer = decompressGzip(buffer);
55 | if (cpioBuffer == null) {
56 | throw new IOException("Failed to decompress gzip");
57 | }
58 |
59 | is = new CpioArchiveInputStream(new ByteArrayInputStream(cpioBuffer));
60 | CpioArchiveEntry entry;
61 | while ((entry = is.getNextCPIOEntry()) != null) {
62 | File file = new File(outputDir, entry.getName());
63 | if (entry.isDirectory()) {
64 | if (!file.exists() && !file.mkdirs()) {
65 | throw new IOException("Failed to create directory");
66 | }
67 | } else {
68 | file.createNewFile();
69 | IOUtils.write(file, IOUtils.read(is, (int) entry.getSize()));
70 | }
71 | }
72 |
73 | } catch (Exception e) {
74 | IOUtils.delete(outputDirFile);
75 | throw new IOException(e);
76 | } finally {
77 | IOUtils.safeClose(is);
78 | }
79 | }
80 |
81 | @Override
82 | public void compress(String fromDir, String outputName, File headerFile, File footerFile)
83 | throws IOException {
84 | File fromDirFile = new File(fromDir);
85 | if (!fromDirFile.exists()) {
86 | throw new IOException("fromDir does not exist.");
87 | }
88 |
89 | ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
90 | CpioArchiveOutputStream cpioOut = new CpioArchiveOutputStream(byteOut);
91 | addAllFilesToCpio(cpioOut, fromDirFile);
92 | cpioOut.close();
93 |
94 | byte[] cpioBuffer = byteOut.toByteArray();
95 | byteOut = new ByteArrayOutputStream();
96 | GZIPOutputStream gzipOut = new GZIPOutputStream(byteOut);
97 | gzipOut.write(cpioBuffer);
98 | gzipOut.close();
99 |
100 | FileOutputStream os = new FileOutputStream(outputName);
101 | addFileIfFound(os, headerFile);
102 | os.write(byteOut.toByteArray());
103 | addFileIfFound(os, footerFile);
104 | os.close();
105 | byteOut.close();
106 | }
107 |
108 | private void addFileIfFound(FileOutputStream os, File file) throws IOException {
109 | if (file.exists()) {
110 | os.write(IOUtils.readFully(file));
111 | }
112 | }
113 |
114 | private void addAllFilesToCpio(CpioArchiveOutputStream cpioOut, File fromDirFile) throws IOException {
115 | for (String path : fromDirFile.list()) {
116 | File file = new File(fromDirFile, path);
117 |
118 | String cpioName = file.getAbsolutePath().substring(fromDirFile.getAbsolutePath().length());
119 | ArchiveEntry cpio = cpioOut.createArchiveEntry(file, cpioName);
120 | cpioOut.putArchiveEntry(cpio);
121 |
122 | if (file.isDirectory()) {
123 | cpioOut.closeArchiveEntry();
124 | addAllFilesToCpio(cpioOut, file);
125 | } else {
126 | byte[] content = IOUtils.readFully(file);
127 | cpioOut.write(content);
128 | cpioOut.closeArchiveEntry();
129 | }
130 | }
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':jbootimage'
2 |
--------------------------------------------------------------------------------