Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

android: Add flashable zip output #320

merged 30 commits into from Feb 28, 2021


Copy link

@samueldr samueldr commented Feb 27, 2021

Whew, this is a bit of a fun PR!

The gist of it is that this adds an output for Android flashable zips, confirmed to work with TWRP.

 $ nix-build --argstr device $DEVICE -A

Obviously, limited to Android-based devices.

I don't think this is going the main way to flash Android-based devices, but it is a way. For amonet-using devices, (e.g. amazon hardware), it will be easier as amonet does some required shenanigans to add an exploit when flashing through TWRP.

Though, in a future where this is building usable "appliance" systems, this may very well be the main installation method that community using Mobile NixOS as a build framework uses to install things!


  • Implement A/B devices install (known how)
  • Try some shenanigans for "fill as it flashes" progress bar
  • Write documentation for using flashable zip as an installation method for Android-based devices
  • Add android-flashable-zip-binaries to tested; it exercises pkgsStatic which sometimes has hiccups. Though armv7l cross to testedPlus.

Android Flashable Zip Binaries

What is this? It's the interpreter and framework for the script that does the flashing.

Basically, my good friend mruby, again. With some helper functions to make a unique binary build per platform.

This, in turn, executes a Ruby DSL that describes a plan. This plan is validated before being executed. Once all parts are found to be okay, it then executes the flash.

Useful as it would e.g. bail on trying to flash a system.img that is too big, before even flashing the boot.img assumed to fit.

I see some shenanigans

That's not a section title.

But indeed, there are shenanigans!

I do not trust all recoveries to ship with a usable unzip binary. It is not part of the API. Normally you should use Edify to unpack things.

The recovery will unzip only one file from the zip file. How can you unzip a file, e.g. a static unzip binary, if you don't have unzip?

Well, maybe you already unzipped it!

Here unzip is part of a customized busybox build. It is (mostly) simply appended to the main script binary. Mostly?

Here's the rub: how fun is it to scan a binary to figure out where another is? Not much. It could have been added as a symbol in C, but is that fun to write? Not really. What if, instead, we appended a third element, a simple uint32_t with the offset to dump from? Now we're talking!

| ELF script-loader |
|       [...]       |
|                   |
| ELF busybox       |
|       [...]       |
|                   |
| 0xABCDE           | <- uint32_t with the offset for busybox.

So the script, first looks at the last four bytes of itself, reads it as an offset, reads from that offset up to the last four bytes. And here it is, a busybox we handily got extracted by the recovery for us!

CC-ing android device maintainers, if possible, could you boot TWRP or another recovery and validate adb shell getprop ro.product.device gives the expected value? (The one I set for I used two sources that I believe are trustable for the values.

cc @lheckemann (xiaomi-tissot)
cc @danielfullmer (google-marlin)

@samueldr samueldr force-pushed the feature/android-flashable-zip branch from 02eeceb to bd6ee60 Compare February 27, 2021 04:01
@samueldr samueldr added topic: device Changes specific to a device, but not itself "a port" contribution type: enhancement New feature or request labels Feb 27, 2021
Copy link
Member Author

It looks like flashing through TWRP is not enough to reset the boot count for A/B devices.

This is out of scope of this PR, but will be handled soon with generic A/B support.

If the boot count was already 0, the flashed boot image will fail. In TWRP, switch back and forth between current/non-current slots to reset the boot count, and it should work.

There are multiple things to consider doing:

  • Reset count numbers but not mark as valid when flashing
  • Create a cheaty "mark current as valid" flashable zip
  • Support marking boot image as valid during boot (when, how?)

@samueldr samueldr force-pushed the feature/android-flashable-zip branch 2 times, most recently from a391ccc to da55119 Compare February 27, 2021 21:36
Copy link
Member Author

And with this last update, the progress bar updates for each block flashed!

Totally not needed, but a real nice to have, since it was mostly free.

@samueldr samueldr force-pushed the feature/android-flashable-zip branch from da55119 to 9ae05fa Compare February 27, 2021 21:39
sha256 = "197g7qvrrijmajixa2h9c4jw26l36y8ig6qjb5d43qg4qykhqfcx";

# TODO: select only desired applets.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# TODO: select only desired applets.

Copy link
Member Author

This was tested against NixOS/nixpkgs@56bb1b0. Tested to build and work for aarch64 and armv7.

Recent master checkouts seems to cause new issues in pkgsStatic and armv7. Though it looks like for aarch64 it is fine. Odd.

Woopsie, we were creating a script for the target!!
Includes a PR authored by myself.
@samueldr samueldr force-pushed the feature/android-flashable-zip branch 5 times, most recently from cf22ed4 to 46b52aa Compare February 28, 2021 20:50
This package provides a unique binary per architecture, which can load
an additional script from the flashable zip.

This way, one "expensive" (not really) build of mruby+script is shared
for the whole architecture.
`android-device` was a poor name choice. Especially now that we have
flashable zips, which are equally as usable as fastboot-flashable
There is no reason to stow this in the system-type module. Other than
making it harder for external uses.
@samueldr samueldr force-pushed the feature/android-flashable-zip branch from 46b52aa to 6e8ec64 Compare February 28, 2021 20:53
@samueldr samueldr merged commit 52d88c3 into NixOS:master Feb 28, 2021
@samueldr samueldr deleted the feature/android-flashable-zip branch February 28, 2021 21:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
topic: device Changes specific to a device, but not itself "a port" contribution type: enhancement New feature or request
None yet

Successfully merging this pull request may close these issues.

None yet

1 participant