Howto: create an Android update.zip package

Tagged:

Last weekend, I built an update.zip package with a patched CA certificate store and took me quite some time to figure out the format of the zip file.
It turned out that most documentation still refers to the format that uses the update-script written in the "Amend" dialect. Since Donut (1.6), Android uses an alternative layout consisting of an updater-script and an update-binary. The binary parses the new script and is included in the zip file. For backward compatibility reasons, it's still possible to also add an update-script file.

The update scripts and binary should be placed in the folder "META-INF/com/google/android/", while the content of your package resides in the root of the zip file. This yields the following layout for the update.zip that I created:

META-INF/
    +- com/
       +- google/
             +- android/
                   +- update-script
                   +- update-binary
                   +- updater-script
system/
   +- etc/
       +- sysctl.conf
       +- security/
             +- cacerts.bks

Note that the structure of META-INF is always the same, while the /system folder can be anything you need for your update (I think you can even mount and write to the sdcard).

After you created your file hierarchy and put your own files in the root, you can populate the META-INF/com/google/android folder. The ARM update-binary can be found in a zip-file attached to this article. The updater-script should be written in Edify, a little scripting language from the Android project. The official README gives some background, but a quite complete description of all the commands is found on Synfulgeek.com.

My little script mounts the /system partition, copies the files and set the permissions. In Edify:

ui_print("Android Security Enhancements");
ui_print("By: Michiel Fokke - fokke.org/android");

show_progress(1.000000, 0);

ui_print("  Mounting /system");
mount("MTD", "system", "/system");
set_progress(0.100000);

ui_print("  Deleting /etc/sysctl.conf");
delete("/system/etc/sysctl.conf");
set_progress(0.200000);

ui_print("  Deleting /etc/security/cacerts.bks");
delete("/system/etc/security/cacerts.bks");
set_progress(0.300000);

ui_print("  Extracting files to /system");
package_extract_dir("system", "/system");
set_progress(0.400000);

ui_print("  Setting permissions to 0644...");
set_perm(0,0,0644,"/system/etc/sysctl.conf","/system/etc/security/cacerts.bks");
set_progress(0.500000);

ui_print("  Unmounting /system");
unmount("/system");
set_progress(0.900000);

ui_print("Update complete. Have a safe Android!");
set_progress(1.000000);

If your code is compatible with Cupcake (1.5) or lower, you might want to also include the legacy update-script that was written in Amend:

show_progress 0.5 0
delete SYSTEM:etc/sysctl.conf
delete SYSTEM:etc/security/cacerts.bks
copy_dir PACKAGE:system SYSTEM:
set_perm 0 0 00644 SYSTEM:etc/sysctl.conf
set_perm 0 0 00644 SYSTEM:etc/security/cacerts.bks
show_progress 0.1 10

An overview of the Amend command syntax is found on Lorenz's Blog.

At this point the package is complete and you can create the zip-file. In Linux this can be done (while in the root of the package) with:

zip -r ../update.zip *

Android requires you to sign your packages with a digital signature. I included a jar file that can take care of this. It contains an unencrypted sample key, that you could optionally exchange for your own key. Download the jar file and put it in the same folder as the newly created update.zip. The zip-file is signed with the following command:

java -classpath testsign.jar testsign update.zip update-signed.zip

The signed zip-file contains three additional files, the first two contain hashes of all files in the zip-file and the last one (CERT.RSA) a digital signature:

META-INF/
    +- MANIFEST.MF
    +- CERT.SF
    +- CERT.RSA
    +- com/
       +- google/
             +- android/
                   +- update-script
                   +- update-binary
                   +- updater-script
system/
   +- etc/
       +- sysctl.conf
       +- security/
             +- cacerts.bks

At this stage, the file update-signed.zip can be put on the SD-card of an Android phone and applied to the system from a recovery ROM.

AttachmentSize
update-binary.zip153.63 KB
testsign.jar13.16 KB

Comments

afgbkdg

Hello! dafadec interesting dafadec site!

mount wants 4 arguments

Hi,

Thank you for your tutorial. I tried creating an update file according to it. (Except taking the update-binary from the android build directory).

I got an error saying:
mount() expects 4 args, got 3
It seems the format with this version is:
mount("yaffs2", "MTD", "system", "/system");

Just thought you might be interested.

Clear and concise

Yes, thank you for posting. I have also searched for a good explanation of android update.zip and this one is very clear.

Where on the device i have to

Where on the device i have to put the public key, so that the signature verification does not fail?

Thanks for your article it

Thanks for your article it really helped me understand that update-binary is an ARM file & should explictly be copied to the Meta-Inf folder. Finally I have my update.zip working

Thank you for sharing this

Thank you for sharing this info. I've been looking all over and have found a lot on the subject - but it's utterly confusing and you're the first I've come across who has delivered a concise and lucid recitation on the matter; along with all the necessary materials. :-)