• After 15+ years, we've made a big change: Android Forums is now Early Bird Club. Learn more here.

Root [Tutorial] How to make a Flashable Zip

M

ModdingMyMind

Guest
This tutorial will help you to understand the making of a flashable zip or also known as an update zip

Setting up your zip directories:

You will need to create the following folder structure inside of your flashable zip (The flashable zip can be called whatever it is you want it to be. (These subfolders are case sensitive)):

Code:
/META-INF/com/google/android

All flashable zips include this file structure. The final folder, android, will contain two files within it:

Code:
update-binary
updater-script

Note: The update-binary is specific to our devices based on built API mostly, but with other factors as well. It is currently open source and therefore possible to be built on a personal basis. However, to insure you are using the correct one, I can suggest taking it from the most recent OTA available for your device.



Setting up the updater-script:

-- This we can create ourselves, to ensure it works properly we will use Notepad++ for Window Users, and Gedit for those using Linux.

Open the text editor and start a new file, with the following settings for Window Users:

Format: Unix
Encoding: ANSI
Default Language: Normal Text

Save this file as:

File name: updater-script
File type: All types (*.*)

And for Linux users:

Just leave it as is.

You can now edit this file, so from here I will be providing some examples:

Code:
[COLOR="Red"]assert(getprop("ro.product.device") == "k2cl" || getprop("ro.build.product") == "k2cl");[/COLOR]
[COLOR="brown"]ui_print(" ");[/COLOR]
[COLOR="brown"]ui_print("Checking Device");[/COLOR]
[COLOR="brown"]ui_print(" ");[/COLOR]
[COLOR="brown"]ui_print("Success");[/COLOR]
[COLOR="brown"]ui_print(" ");[/COLOR]
[COLOR="green"]show_progress(0.200000, 5);[/COLOR]
[COLOR="brown"]ui_print("Mounting System");[/COLOR]
[COLOR="red"]mount("ext4", "EMMC", "/dev/block/mmcblk0p35", "/system");[/COLOR]
[COLOR="brown"]ui_print(" ");[/COLOR]
[COLOR="green"]show_progress(0.200000, 5);[/COLOR]
[COLOR="brown"]ui_print("Updating System Files");[/COLOR]
[COLOR="red"]package_extract_dir("system", "/system");[/COLOR]
[COLOR="brown"]ui_print(" ");[/COLOR]
[COLOR="green"]show_progress(0.200000, 5);[/COLOR]
[COLOR="brown"]ui_print("unmounting system");[/COLOR]
[COLOR="red"]unmount("/system");[/COLOR]
[COLOR="brown"]ui_print(" ");[/COLOR]
[COLOR="green"]show_progress(0.200000, 5);[/COLOR]
[COLOR="brown"]ui_print("Complete!");[/COLOR]
[COLOR="green"]show_progress(0.200000, 5);[/COLOR]
[COLOR="brown"]ui_print(" ");[/COLOR]
***EMPTY LINE***

Ok, I've color coded this so we can break it down, the lines of code in RED are the actual commands, everything else is for visual appearance.

assert(getprop("ro.product.device") == "k2cl" || getprop("ro.build.product") == "k2cl");
This is checking to see if you are flashing the correct handset, this is not a requirement, but it insures that the flashable zip will only work for the specified device as to not be accidently flashed by others and to help prevent causing any possible damage to those who do not qualify to use that particular zip. Just insert another device name in the place of "k2cl" if you so wish, or remove the command all together.

To explain this a little further, you have told the script to check certain properties within your 'build.prop' file located in your /system folder. The above command ensures the following categories have the correct definitions before proceeding with the flash:
Code:
ro.product.device=
ro.build.product=
ro.product.board=

Take note, that if you apply this to a full rom which result you having to wipe out the system partition before flashing then this will obviously not work, because you also wiped out the build.prop file along with the /system, so the zip will be aborted due to an error by not being able to verify as instructed to do in the syntax.

Here are the main build properties within your build.prop (may slightly vary):

Code:
ro.build.id=
ro.build.display.id=
ro.build.version.incremental=
ro.build.version.sdk=
ro.build.version.codename=
ro.build.version.release=
ro.build.date=
ro.build.date.utc=
ro.build.type=
ro.build.user=
ro.build.host=
ro.build.tags=
ro.product.model=
ro.product.brand=
ro.product.name=
ro.product.device=
ro.product.board=
ro.product.cpu.abi=
ro.product.cpu.abi2=
ro.product.manufacturer=
ro.product.locale.language=
ro.product.locale.region=
ro.wifi.channels=
ro.board.platform=
ro.build.description=
ro.build.fingerprint=
ro.build.characteristics=

To mount a partition you need to use the following syntax. Below, will visually show you what each arguement represents:

Code:
mount("filesystem-type", "partition-type", "device-specific-mountpoint (DSM)", "mount-point");

filesystem-type: "ext4" or "yaffs2" (k2cl is ext4)
partition-type: "EMMC" or "MTD" (k2cl is EMMC)
DSM: Device specific address - this will be your specified partition
mount-point: /system, /data, /userdata, /cache, etc

mount("ext4", "EMMC", "/dev/block/mmcblk0p35", "/system");
This is the specific mount point for the k2cl system partition, if you wish to flash a different partition, data for instance, you can get the mount points for your device by entering the following code over ADB via PC or on our phone via terminal emulator:

Code:
adb shell
mount > /sdcard/PHONENAME_mountinfo.txt
This will place a text file on your sdcard with the mount points for your specific device. (Remember to swap 'PHONENAME' with your device name e.g. 'k2cl', as a means of remembrance and for record keeping).

package_extract_dir("system", "/system");
This command extracts the files you wish to flash from the zip and flashes them to the phone, it is formatted as follows ("package-path", "/destination-path"). So for this example you are telling it to flash everything from the 'system' folder in your zip to the /system partition of your handset. You can obviously change these values for different partitions.

To flash an entire directory:

Code:
package_extract_dir("system", "/system");

To flash a single file:

Code:
package_extract_file("boot.img", "/dev/block/mmcblk0p20");


These commands are structured as follows:

Entire directory: ("zipfileSource", "destination-partition");
Single File: ("file", "device-specific-mountpoint");

unmount("/system");
This simply unmounts whatever partition you previously mounted.

ui_print(" ");
Shows text in the recovery while the flash is currently taking place. You would just enter what ever text you feel is necessary to be displayed on the screen.

show_progress(0.200000, 5);
Controls what the progress bar in the background is displaying, it is formatted as follows (fragment, seconds).

***EMPTY LINE***
This is not actually a text, you simply need to leave a blank line at the end of your script before you save it for it to work properly.



Some Additional commands

Deleting folders & files:

You can delete multiple folders or files using just one command, as follows:

To delete files:

Code:
delete("file-path-1", "file-path-2", "file-path-3);

Example:
Code:
delete("/system/bin/su","/system/xbin/su","/system/app/Superuser.apk");

You can list as many file-path's as needed in the script. Three is not its limit.

To delete folders/directories:

Code:
delete_recursive("directory-path-1", "directory-path-2", "directory-path-3");

This is also not limited to three directory-path's.



Setting Permissions:

Set permissions of a file or set of files:

Code:
set_perm(uid, gid, mode, "filepath1", "filepath2")

Example:
Code:
set_perm(0, 0, 06755, "/system/xbin/su");

uid - user id
gid - group id
mode - permission mode
filepath... - file to set permission on

Setting permissions of a directory or a set of directories and all files and folders within them:

Code:
set_perm_recursive(uid, gid, dirmode, filemode, "dirpath1", "dirpath2")

Example:
Code:
set_perm_recursive(0, 0, 0755, 0644, "/system");

uid - user id
gid - group id
dirmode - permission to set to directories contained within the specified directory
filemode - permission to set to files contained within the specified directory
dirpath... - directory to set permission on

You will need to also understand the way file permissions are represented:

Example = drwxrwxrwx

-- Use a Root Explorer to find the UID, GID, and permissions for a file. Permissions are the string that looks like some variation on 'rwxr-xr--' next to each file. Long press and choose "change owner" to get the UID and GID. You just want the number next to "owner" and "group", respectively.

-- If you're replacing a file, look up these settings for the existing copy and use them. If you're adding a file, just find a file that does the same functions and copy what it has (for example, installing an app to /system/app? Just look at these settings for any other app in that directory).

-- MODE is technically a 4-bit string, but the first character can be omitted. There doesn't seem to be any android file permissions with the first character set. For good practice, I think it's safe to assume you can always use a leading 0 unless you know otherwise for something specific. Or, just use a 3-digit MODE, which says to leave those settings as they are (disabled by default). (I.e. 0644=644).

The next 9 characters define the file permissions. These permissions are
given in groups of 3 each.

The first 3 characters are the permissions for the owner of the file or directory.
Example = -rwx------

The next 3 are permissions for the group that the file is owned by.
Example = ----rwx---

The final 3 characters define the access permissions for everyone not part of the group.
Example = -------rwx

There are 3 possible attributes that make up file access permissions.

r -- Read permission. Whether the file may be read. In the case of a
directory* this would mean the ability to list the contents of the
directory.

w -- Write permission. Whether the file may be written to or modified. For
a directory this defines whether you can make any changes to the contents
of the directory. If write permission is not set then you will not be able
to delete rename or create a file.

x -- Execute permission. Whether the file may be executed. In the case of a
directory this attribute decides whether you have permission to enter,
run a search through that directory or execute some program from that
directory

You set these permissions using the following binary based numerical system:
Code:
0:  ---   No Permissions (the user(s) cannot do anything)
1:  --x   Execute Only (the user(s) can only execute the file)
2:  -w-   Write Only (the user(s) can only write to the file)
3:  -wx   Write and Execute Permissions
4:  r--   Read Only
5:  r-x   Read and Execute Permissions
6:  rw-   Read and Write Permissions
7:  rwx   Read, Write and Execute Permissions

Default Linux permissions:

For Files:
"Read" means to be able to open and view the file
"Write" means to overwrite or modify the file
"eXecute" means to run the file as a binary

For Directories:
"Read" means to be able to view the contents of the directory
"Write" means to be able to create new files/directories within the directory
"eXecute" means to be able to "Change Directory" (cd) into the directory

For further understanding on calculating CHMOD permissions, then click on the following link to another thread here on XDA:
CHMOD Permissions - Reference Guide


Here are two examples of using edify scripting to help give a better visual on all of this:

Example 1:
Folders = Green
Files = Black

SuperSU_1.75_Flashable.zip
|--META-INF
|...|--CERT.RSA
|...|--CERT.SF
|...|--MANIFEST.MF
|...|--com
|.......|--google
|...........|--android
|...............|--update-binary
|...............|--updater-script
|--data
|...|--data
|........|--eu.chainfire.supersu
|............|--files
|............|...|--99SuperSUDaemon
|............|...|--install-recovery.sh
|............|...|--otasurvival.sh
|............|...|--supersu.arm.png
|............|...|--supersu.cfg
|............|--shared_prefs
|................|--eu.chainfire.supersu_preferences.xml
|--system
|...|--app
|...|...|--Superuser.apk
|...|--bin
|...|...|--.ext
|...|...|...|--.su
|...|...|--su
|...|--xbin
|.......|--otasurvival.sh
Code:
ui_print("****************************************");
ui_print("*       Created by Modding.MyMind      *");
ui_print("****************************************");
ui_print("*          Rooting your Device         *");
ui_print("****************************************");
ui_print("");

show_progress(1.000000, 0);
ui_print("Mounting filesystems...");
run_program("/sbin/busybox", "mount", "/system");
run_program("/sbin/busybox", "mount", "/data");
set_progress(0.100000);

# Delete old files that may interfere.
ui_print("Preparing install...");
delete("/data/dalvik-cache/system@app@Superuser.apk@classes.dex","/system/bin/su","/system/xbin/su","/system/app/Superuser.apk","/system/app/Superuser.odex","/data/app/Superuser.apk","/system/xbin/daemonsu","/system/bin/.ext/.su","/system/etc/install-recovery.sh","/system/etc/init.d/99SuperSUDaemon","/system/etc/.has_su_daemon","/system/etc/.installed_su_daemon","/system/app/SuperUser.apk","/system/app/SuperUser.odex","/system/app/superuser.apk","/system/app/superuser.odex","/system/app/Supersu.apk","/system/app/Supersu.odex","/system/app/SuperSU.apk","/system/app/SuperSU.odex","/system/app/supersu.apk","/system/app/supersu.odex");
set_progress(0.200000);

ui_print("Extracting files...");
package_extract_dir("system", "/system");
package_extract_dir("data", "/data");
set_progress(0.300000);

ui_print("Setting SU permissions...");
set_perm(0, 0, 06755, "/system/bin/su");
set_perm(0, 0, 06755, "/system/bin/.ext/.su");
set_perm(0, 0, 06755, "/system/xbin/otasurvival.sh");
set_progress(0.400000);

ui_print("Symlinking SU Binary for Root...");
symlink("/system/bin/su", "/system/xbin/su");
set_progress(0.500000);

ui_print("Setting SuperSU permissions...");
set_perm(0, 0, 0644, "/system/app/Superuser.apk");
set_perm(1000, 1000, 0755, "/data/data/eu.chainfire.supersu");
set_perm_recursive(1000, 1000, 0771, 0771, "/data/data/eu.chainfire.supersu/files");
set_perm_recursive(1000, 1000, 0771, 0660, "/data/data/eu.chainfire.supersu/shared_prefs");
set_progress(0.600000);
set_progress(0.800000);

# Unmounting filesystems...
ui_print("Unmounting filesystems...");
run_program("/sbin/busybox", "umount", "/system");
run_program("/sbin/busybox", "umount", "/data");
set_progress(0.900000);
ui_print("");

set_progress(1.000000);
ui_print("****************************************");
ui_print("*          Install Complete!           *");
ui_print("****************************************");

Example 2:
Code:
ui_print("****************************************");
ui_print("                                        ");
ui_print("          4.2.2 CCONVERSIONN            ");
ui_print("    Modding.MyMind - XDA Senior Member  ");
ui_print("                                        ");
ui_print("****************************************");
ui_print("");
ui_print("");

#MOUNTING
show_progress(0.1, 0);
ui_print("MOUNTING /system");
mount("ext4", "EMMC", "/dev/block/mmcblk0p35", "/system");
delete_recursive("/system");

#EXTRACTING
ui_print("EXTRACTING SYSTEM FOLDER TO /system");
package_extract_dir("system", "/system");

#SYMLINKING
ui_print("SYMLINKING");
symlink("dumpstate", "/system/bin/dumpcrash");
symlink("toolbox", "/system/bin/cat");
symlink("toolbox", "/system/bin/chmod");
symlink("toolbox", "/system/bin/chown");
symlink("toolbox", "/system/bin/cmp");
symlink("debuggerd", "/system/bin/csview");
symlink("toolbox", "/system/bin/date");
symlink("toolbox", "/system/bin/dd");
symlink("toolbox", "/system/bin/df");
symlink("toolbox", "/system/bin/dmesg");
symlink("toolbox", "/system/bin/getevent");
symlink("toolbox", "/system/bin/getprop");
symlink("toolbox", "/system/bin/hd");
symlink("toolbox", "/system/bin/id");
symlink("toolbox", "/system/bin/ifconfig");
symlink("toolbox", "/system/bin/iftop");
symlink("toolbox", "/system/bin/insmod");
symlink("toolbox", "/system/bin/ioctl");
symlink("toolbox", "/system/bin/ionice");
symlink("toolbox", "/system/bin/kill");
symlink("toolbox", "/system/bin/ln");
symlink("toolbox", "/system/bin/log");
symlink("toolbox", "/system/bin/ls");
symlink("toolbox", "/system/bin/lsmod");
symlink("toolbox", "/system/bin/lsof");
symlink("toolbox", "/system/bin/mkdir");
symlink("toolbox", "/system/bin/mount");
symlink("toolbox", "/system/bin/mv");
symlink("toolbox", "/system/bin/nandread");
symlink("toolbox", "/system/bin/netstat");
symlink("toolbox", "/system/bin/newfs_msdos");
symlink("toolbox", "/system/bin/notify");
symlink("toolbox", "/system/bin/printenv");
symlink("toolbox", "/system/bin/ps");
symlink("toolbox", "/system/bin/renice");
symlink("toolbox", "/system/bin/rm");
symlink("toolbox", "/system/bin/rmdir");
symlink("toolbox", "/system/bin/rmmod");
symlink("toolbox", "/system/bin/route");
symlink("toolbox", "/system/bin/schedtop");
symlink("toolbox", "/system/bin/sendevent");
symlink("toolbox", "/system/bin/setconsole");
symlink("toolbox", "/system/bin/setprop");
symlink("mksh", "/system/bin/sh");
symlink("toolbox", "/system/bin/sleep");
symlink("toolbox", "/system/bin/smd");
symlink("toolbox", "/system/bin/start");
symlink("toolbox", "/system/bin/stop");
symlink("toolbox", "/system/bin/sync");
symlink("toolbox", "/system/bin/top");
symlink("toolbox", "/system/bin/touch");
symlink("toolbox", "/system/bin/umount");
symlink("toolbox", "/system/bin/uptime");
symlink("toolbox", "/system/bin/vmstat");
symlink("toolbox", "/system/bin/watchprops");
symlink("toolbox", "/system/bin/wipe");
symlink("wiperiface_v02.so", "/system/bin/wiperiface");
symlink("libwiperjni_v02.so", "/system/lib/libwiperjni.so");

#PERMISSIONS
ui_print("SETTING PERMISSIONS TO /system");
set_perm_recursive(0, 0, 0755, 0644, "/system");
set_perm_recursive(0, 2000, 0755, 0755, "/system/bin");
set_perm(0, 3003, 06755, "/system/bin/ip");
set_perm(0, 3003, 02750, "/system/bin/netcfg");
set_perm(0, 3004, 02755, "/system/bin/ping");
set_perm(0, 2000, 06750, "/system/bin/run-as");
set_perm_recursive(1002, 1002, 0755, 0440, "/system/etc/bluetooth");
set_perm(0, 0, 0755, "/system/etc/bluetooth");
set_perm(3002, 3002, 0444, "/system/etc/bluetooth/blacklist.conf");
set_perm(1002, 1002, 0440, "/system/etc/dbus.conf");
set_perm(1014, 2000, 0550, "/system/etc/dhcpcd/dhcpcd-run-hooks");
set_perm(0, 2000, 0550, "/system/etc/init.goldfish.sh");
set_perm_recursive(0, 0, 0755, 0555, "/system/etc/ppp");
set_perm_recursive(0, 2000, 0755, 0644, "/system/vendor");
set_perm_recursive(0, 0, 0755, 0644, "/system/vendor/firmware");
set_perm(0, 2000, 0755, "/system/vendor/firmware");
set_perm(0, 2000, 0755, "/system/vendor/lib");
set_perm_recursive(0, 2000, 0755, 0755, "/system/xbin");
show_progress(0.1, 10);

#EXTRACTING
ui_print("INSTALLING boot.img TO mmcblk0p20");
show_progress(0.2, 0);
package_extract_file("boot.img", "/dev/block/mmcblk0p20");
show_progress(0.2, 10);

#UNMOUNTING
ui_print("UNMOUNTING /system");
unmount("/system");
ui_print("****************************************");
ui_print("*        CconversionN Complete!        *");
ui_print("****************************************");

Files to flash:

You now need to create some other folder(s), this needs to be named based on where within the system you are flashing to help keep it simple (you can technically name them whatever, just as long as they are placed in the proper location of your current daily rom); for the sake of this example we are flashing to the system partition, so:

Code:
/META-INF/com/google/android
/system/app

Place whatever files you wish to flash within this file. For example:

Code:
/META-INF/com/google/android
/system/app/nameofapp.apk



Creating your .zip file:

Select both of your top directories and their contents 'META-INF' and 'system' and package them into a .zip file with 7zip or any other method you may currently use, using the following settings:

Archive: name_of_your_file
Archive Format: zip
Compression level: Store
Update mode: Add and replace files

And there you have it, your very own flashable .zip file.



How to sign your flashable zip:

You don't actually need to sign your zip file for it to work as most custom recoveries like, TWRP, now support unsigned zips. For the learning developers and the more cautious among us though, here is how. First, go ahead and place your newly made flashable zip on to your device. I preferably place it on the root of my internal sdcard, though the choice is ultimately yours.

Download the free application on the playstore called, zipsigner. Open it up and select the option for, Choose In/Out....

Go and select your zip, and then select, auto-testkey, under where it says, Key/mode. Once done, proceed to sign it. You will recieve an output zip file with the same name as the previous unsigned zip but with it ending in *-signed.zip. At this point, you are now good and you can either apply your zip to your device, or share your work with others.

There are so many different ways you can go about signing the zip, but for something like a simple flashable zip file, I will normally always go this route.

-- Happy Hunting!!!
 

Attachments

  • flashable_example.zip
    173.1 KB · Views: 707
Upvote 0

BEST TECH IN 2023

We've been tracking upcoming products and ranking the best tech since 2007. Thanks for trusting our opinion: we get rewarded through affiliate links that earn us a commission and we invite you to learn more about us.

Smartphones