robotnix - Build Android (AOSP) using Nix
Robotnix is a build system for Android (AOSP) images on top of the Nix package manager. Instead of having to follow complicated instructions to install several build tools and fetch source code from multiple sources, robotnix encapsulates all this complexity in a simple Nix expression.
The documentation included here should help inform you how to create your configuration file, build your Android image, and install the image onto your phone.
If you find parts of this manual confusing, please create an issue, or (even better) create a pull request on Github.
Robotnix users and developers can also be contacted on #robotnix:nixos.org
on Matrix.
Configuration
Similarly to NixOS, robotnix configurations are "Nix expressions" specified using the "Nix language." Most end-user uses of robotnix should not require learning the Nix language, besides the very basics of syntax.
Inline Configuration
Robotnix can be built using configuration specified on the command line using --arg configuration ...
as an argument to nix-build
.
For example, if the current directory contains a checked out copy of robotnix, the following will produce a vanilla image for the crosshatch device (Pixel 3 XL):
$ nix-build --arg configuration '{ device="crosshatch"; flavor="vanilla"; }' -A img
By default, nix-build
uses the default.nix
in the current directory as the Nix entry point.
If robotnix is checked out in another directory, such as $HOME/src/robotnix
, the above command could instead be
$ nix-build $HOME/src/robotnix --arg configuration '{ device="crosshatch"; flavor="vanilla"; }' -A img
Configuration Files
A configuration file should be created for anything more complicated than the very simple configurations that could be conveniently specified on the command line.
The following is an example robotnix configuration that could be saved to (for example) crosshatch.nix
.
{
# Most uses of robotnix should at least set the device and flavor options.
device = "crosshatch";
flavor = "vanilla";
# variant = "user"; # Other options are userdebug, or eng. Builds used in production should use "user"
# Signing should be enabled for builds used in production.
signing.enable = true;
# When signing is enabled, keyStorePath should refer to a path containing keys created by `genereteKeysScript`
# This is used to automatically obtain key fingerprints / metadata from the generated public keys.
# Alternatively, it may be possible to manually set the required options like `signing.avb.fingerprint` or `apps.prebuilt.<name>.fingerprint` to avoid including this path.
signing.keyStorePath = "/var/secrets/android-keys";
# Additional modules can be enabled and included in the build. See individual module documentation
apps.fdroid.enable = true;
microg.enable = true;
}
The --arg configuration ...
option for nix-build
can also refer to a .nix
file containing the robotnix configuration.
If the above configuration was saved to crosshatch.nix
in the local directory, an image could be built using the following command:
$ nix-build --arg configuration ./crosshatch.nix -A img
See my own configuration under example.nix
for inspiration.
Reference documentation of the available options is here.
Flakes (experimental)
Nix flakes are an upcoming feature of Nix that provides an alternative configuration structure for use with the new nix
command.
It can provide the benefit of explicitly pinning your robotnix configuration against a particular revision of the robotnix repository.
The feature remains experimental for the time-being, and is not currently the recommended way to use robotnix for new users.
Robotnix provides an example nix flake template, which can be used to prepopulate the current directory with the command nix flake init -t github:danielfullmer/robotnix
.
Example usage:
$ mkdir flake-test
$ cd flake-test
$ nix flake init -t github:danielfullmer/robotnix
$ # Edit flake.nix in current directory
$ nix build .#robotnixConfigurations.dailydriver.img
Flavors
In normal usage, the user needs to select a robotnix "flavor" in their configuration file by setting the flavor
option.
Flavors may change the default settings of some other modules, which might not match the default setting shown on the Options reference page.
As an example, the GrapheneOS flavor enables apps.vanadium.enable
by default.
For further details, consult the implementation of the flavor under (for example) flavors/grapheneos/*
.
Currently, the vanilla and GrapheneOS flavors are based on Android 12, while the LineageOS flavor uses either Android 10 or Android 11, depending on the device.
If a robotnix flavor supports multiple Android versions (either older or experimental newer versions),
this can be overridden by setting (for example) androidVersion = 11
.
Vanilla
The vanilla flavor is meant to represent a (mostly) unaltered version of the AOSP code published by Google.
Vanilla AOSP support may be enabled by setting flavor = "vanilla";
.
It does, however, include some small fixes and usability improvements.
Enabling the vanilla flavor also enables the chromium webview/app by default as well.
The vanilla flavor in robotnix currently supports only Pixel phones which still receive updates from Google (>= Pixel 3a).
Older Pixel phones (e.g. marlin
/ Pixel 1 XL) may be still be built by overriding androidVersion = 10;
.
However, these might be removed in the future as they are no longer receiving device updates from Google.
The vanilla flavor retains working support for Android Verified Boot, and allows a user to re-lock the bootloader using the user's own generated root of trust.
GrapheneOS
GrapheneOS is a privacy and security focused mobile OS with Android app compatibility developed as a non-profit open source project.
GrapheneOS support may be enabled by setting flavor = "grapheneos";
.
Enabling the GrapheneOS flavor will also enable the Vanadium app/webview and Seedvault robotnix modules.
Additionally, the upstream GrapheneOS updater is disabled,
but the robotnix updater app (based on the GrapheneOS updater app) can be enabled by setting apps.updater.enable = true;
and apps.updater.url = "...";
.
The user should understand that enabling certain robotnix modules may have security implications as they produce a may produce a larger attack surface than is intended by the GrapheneOS project. Some modules, such as the MicroG and the F-Droid privileged extension, have been explicitly rejected by upstream GrapheneOS. If the user wishes to enable these modules, they should understand and be willing to accept the usability/security tradeoffs.
GrapheneOS releases are tagged in robotnix, but before 2021.05.16.04, the date suffix (YY.MM.DD.HH) did not match the one used in the upstream release. Only the latest GrapheneOS release is included with robotnix, even if that release is only a "beta" release upstream. If you would prefer to stick to only stable releases, wait until the release is marked "stable" upstream.
Before reporting bugs to upstream GrapheneOS, please ensure that you can reproduce your issue using the official GrapheneOS images.
Alternatively, feel free to ask about your issue on the #robotnix:nixos.org
channel on Matrix.
LineageOS
LineageOS is a free and open-source operating system for various devices, based on the Android mobile platform.
LineageOS support may be enabled by setting flavor = "lineageos";
.
At the time of writing, this includes support for ~160 devices.
Robotnix includes support for both LineageOS 17.1 as well as LineageOS 18.1.
By default, robotnix will select the latest supported version for the device specified in the configuration.
This can be overridden by setting androidVersion
to either 10 or 11, for LineageOS 17.1 and 18.1, respectively.
Since LineageOS does not produce tagged releases like vanilla AOSP or GrapheneOS,
we periodically take snapshots of the upstream repositories and include metadata in robotnix which pins the source repositories to particular revisions.
This metadata can be found under flavors/lineageos/*/*.json
.
LineageOS support in robotnix should be considered "experimental," as it does yet have the same level of support provided for vanilla
and grapheneos
flavors.
LineageOS source metadata may be updated irregularly in robotnix, and certain modules (such as the updater) are not guaranteed to work.
Moreover, LineageOS does not appear to provide the same level of security as even the vanilla flavor, as it disables dm-verity/AVB, sets userdebug
as the default variant, and uses vendor files with unclear origin.
LineageOS support is still valuable to include as it extends support to a much wider variety of devices, and provides the base that many other Android ROMs use to customize.
Contributions and fixes from LineageOS users are especially welcome!
For devices with "boot-as-recovery", the typical LineageOS flashing process involves first producing a boot.img
and ota
, flashing boot.img
with fastboot, and then sideloading the ota
in recovery mode.
The boot.img
and ota
targets can be built using nix-build ... -A bootImg
or nix-build ... -A ota
, respectively.
Check the upstream documentation for your particular device before following the above instructions.
Anbox
Anbox is a Free and open-source container-based approach at running Android on Linux systems.
Anbox support may be enabled by setting flavor = "anbox";
.
At the time of writing, support is experimental. Given that Anbox is based on an older Android release (7), support for Robotnix options is not guaranteed.
Waydroid
Waydroid is a Free and open-source container-based approach at running Android on Linux systems.
Waydroid support may be enabled by setting device and flavor, e.g. device="x86_64"; flavor="waydroid";
.
LineageOS based system/vendor images can be built using nix-build ... -A config.build.waydroid
.
At the time of writing, support is experimental.
F-Droid
The following configuration will enable the F-Droid app and the F-Droid privileged extension.
{
apps.fdroid.enable = true;
}
The F-Droid privileged extension enables F-Droid to install and delete apps without needing "Unknown Sources" to be enabled (e.g. just like Google Play does). It also enables F-Droid to install updates in the background without the user having to click "install".
Adding F-Droid repositories
F-Droid can manage multiple repositories to fetch apps from. These can be set up manually in the app, but with robotnix it is also possible to preload F-Droid with some repositories at build time.
To add an F-Droid repository you need at least the URL and a public key. Obtaining the URL is in general very easy but it's not obvious where to obtain the public key.
We'll take the microG repository as an example. The repository is located
here. To obtain the repository index
download the index.xml
file from the repository root:
$ curl -LO https://microg.org/fdroid/repo/index.xml
The content of this XML file contains metadata about the repository, including the public key:
<?xml version="1.0" encoding="utf-8"?>
<fdroid>
<repo name="microG F-Droid repo" icon="fdroid-icon.png" url="https://microg.org/fdroid/repo" version="19" timestamp="1606314565" pubkey="308202ed308201d5a003020102020426ffa009300d06092a864886f70d01010b05003027310b300906035504061302444531183016060355040a130f4e4f47415050532050726f6a656374301e170d3132313030363132303533325a170d3337303933303132303533325a3027310b300906035504061302444531183016060355040a130f4e4f47415050532050726f6a65637430820122300d06092a864886f70d01010105000382010f003082010a02820101009a8d2a5336b0eaaad89ce447828c7753b157459b79e3215dc962ca48f58c2cd7650df67d2dd7bda0880c682791f32b35c504e43e77b43c3e4e541f86e35a8293a54fb46e6b16af54d3a4eda458f1a7c8bc1b7479861ca7043337180e40079d9cdccb7e051ada9b6c88c9ec635541e2ebf0842521c3024c826f6fd6db6fd117c74e859d5af4db04448965ab5469b71ce719939a06ef30580f50febf96c474a7d265bb63f86a822ff7b643de6b76e966a18553c2858416cf3309dd24278374bdd82b4404ef6f7f122cec93859351fc6e5ea947e3ceb9d67374fe970e593e5cd05c905e1d24f5a5484f4aadef766e498adf64f7cf04bddd602ae8137b6eea40722d0203010001a321301f301d0603551d0e04160414110b7aa9ebc840b20399f69a431f4dba6ac42a64300d06092a864886f70d01010b0500038201010007c32ad893349cf86952fb5a49cfdc9b13f5e3c800aece77b2e7e0e9c83e34052f140f357ec7e6f4b432dc1ed542218a14835acd2df2deea7efd3fd5e8f1c34e1fb39ec6a427c6e6f4178b609b369040ac1f8844b789f3694dc640de06e44b247afed11637173f36f5886170fafd74954049858c6096308fc93c1bc4dd5685fa7a1f982a422f2a3b36baa8c9500474cf2af91c39cbec1bc898d10194d368aa5e91f1137ec115087c31962d8f76cd120d28c249cf76f4c70f5baa08c70a7234ce4123be080cee789477401965cfe537b924ef36747e8caca62dfefdd1a6288dcb1c4fd2aaa6131a7ad254e9742022cfd597d2ca5c660ce9e41ff537e5a4041e37">
<description>This is a repository of microG apps to be used with F-Droid. Applications in this repository are signed official binaries built by the microG Team from the corresponding source code. </description>
</repo>
<application id="...">
<!-- ... list of contained applications ... -->
</application>
</fdroid>
Simply copy the name
and pubkey
fields and use them as the name and public
key for the corresponding Nix expression respectively.
{
apps.fdroid.additionalRepos = {
"microG F-Droid repo" = {
enable = true;
url = "https://microg.org/fdroid/repo";
pubkey = "308202ed308201d5a003020102020426ffa009300d06092a864886f70d01010b05003027310b300906035504061302444531183016060355040a130f4e4f47415050532050726f6a656374301e170d3132313030363132303533325a170d3337303933303132303533325a3027310b300906035504061302444531183016060355040a130f4e4f47415050532050726f6a65637430820122300d06092a864886f70d01010105000382010f003082010a02820101009a8d2a5336b0eaaad89ce447828c7753b157459b79e3215dc962ca48f58c2cd7650df67d2dd7bda0880c682791f32b35c504e43e77b43c3e4e541f86e35a8293a54fb46e6b16af54d3a4eda458f1a7c8bc1b7479861ca7043337180e40079d9cdccb7e051ada9b6c88c9ec635541e2ebf0842521c3024c826f6fd6db6fd117c74e859d5af4db04448965ab5469b71ce719939a06ef30580f50febf96c474a7d265bb63f86a822ff7b643de6b76e966a18553c2858416cf3309dd24278374bdd82b4404ef6f7f122cec93859351fc6e5ea947e3ceb9d67374fe970e593e5cd05c905e1d24f5a5484f4aadef766e498adf64f7cf04bddd602ae8137b6eea40722d0203010001a321301f301d0603551d0e04160414110b7aa9ebc840b20399f69a431f4dba6ac42a64300d06092a864886f70d01010b0500038201010007c32ad893349cf86952fb5a49cfdc9b13f5e3c800aece77b2e7e0e9c83e34052f140f357ec7e6f4b432dc1ed542218a14835acd2df2deea7efd3fd5e8f1c34e1fb39ec6a427c6e6f4178b609b369040ac1f8844b789f3694dc640de06e44b247afed11637173f36f5886170fafd74954049858c6096308fc93c1bc4dd5685fa7a1f982a422f2a3b36baa8c9500474cf2af91c39cbec1bc898d10194d368aa5e91f1137ec115087c31962d8f76cd120d28c249cf76f4c70f5baa08c70a7234ce4123be080cee789477401965cfe537b924ef36747e8caca62dfefdd1a6288dcb1c4fd2aaa6131a7ad254e9742022cfd597d2ca5c660ce9e41ff537e5a4041e37";
};
};
}
The name can really be anything, but the one that is provided here is the one that shows up before refreshing the F-Droid repo list for the first time, so if you want that to look pretty, give it a pretty name here.
The apps.fdroid.additionalRepos
variable is only used to prepopulate the internal database of F-Droid repositories upon the first run of the application.
Changes to this variable will not have any effect on phones that have already started the F-Droid application.
Seedvault Backup
Seedvault is a backup application for the Android Open Source Project. The following configuration will enable the Seedvault:
{
apps.seedvault.enable = true;
}
Backing Up
Normally, the settings for the Seedvault backup application is available under "Settings -> System -> Backup".
However, if you have flashed a new ROM including Seedvault over one which did not have Seedvault initially (without wiping userdata), you may need to manually set the backup transport using adb
.
$ adb shell bmgr enable true
$ adb shell bmgr transport com.stevesoltys.seedvault.transport.ConfigurableBackupTransport
Restoring
The GrapheneOS and LineageOS flavors provide the option to use Seedvault upon first boot using the SetupWizard. The vanilla flavor currently does not use SetupWizard, so the restore activity must be manually started using:
adb shell am start-activity -a com.stevesoltys.seedvault.RESTORE_BACKUP
See the following issue: seedvault#85
MicroG
MicroG is a free-as-in-freedom re-implementation of Google’s proprietary Android user space apps and libraries. MicroG support may be enabled using:
{
microg.enable = true;
}
MicroG requires a patch to the Android system to allow spoofing Google's signature for MicroG's reimplemented version of Google services. The patch included in robotnix locks down this signature spoofing functionality to only the MicroG application and the Google signatures.
Over-the-Air (OTA) Updater
The following robotnix configuration enables the OTA updater app.
{
apps.updater.enable = true;
apps.updater.url = "...";
}
The apps.updater.url
setting needs to point to a URL hosting the OTA files described below.
Additionally, the buildDateTime
option is set by default by the flavor, and is updated when those flavors have new releases.
If you make new changes to your build that you want to be pushed by the OTA updater, you should set buildDateTime
yourself, using date "+%s"
to get the current time.
Building OTA updates
The OTA file and metadata can be generated as part of the releaseScript
output. If you are signing builds inside Nix using the sandbox exception,
robotnix additionally includes a convenient target which will build a directory
containing OTA files ready to be sideloaded or served over the web. To
generate the OTA directory, build the otaDir
attribute (here for sunfish):
$ nix-build --arg configuration ./sunfish.nix -A otaDir -o ota-dir
The directory structure will look similar to this (arrows indicate symbolic links) with possibly different timestamps and hashes of course:
$ tree -l ota-dir
├── sunfish-ota_update-2021.02.06.16.zip -> /nix/store/wwr49all6x868f0mdl11369ybfwyir0f-sunfish-ota_update-2021.02.06.16.zip
├── sunfish-stable -> /nix/store/c1rp46m9spncanacglqs5mxk6znfs44s-sunfish-stable
└── sunfish-target_files-2021.02.06.16.zip -> /nix/store/8ys21rzjqhi2055d7bd4iwa15fv1m446-sunfish-signed_target_files-2021.02.06.16.zip
The file sunfish-ota_update-2021.02.06.16.zip
can be sideloaded with adb as
described in the next section.
Actually serving OTA updates over the air
Note: The Vanilla and GrapheneOS flavors use a different updater than the LineageOS flavor, therefore they might behave slightly different from one another. The instructions below should however work for both.
Essentially this boils down to just serving the otaDir
build output on the
web, e.g. with nginx. To receive OTA updates on the device, enable the updater
and point it to the domain and possibly subdirectory that you will be serving
OTA updates from:
# Device configuration
{
apps = {
updater.enable = true;
updater.url = "https://example.com/android/";
};
}
On a NixOS server, it is as easy as serving a directory at the required endpoint:
# NixOS server configuration
{
services.nginx.enable = true;
systemd.services.nginx.serviceConfig.ReadOnlyPaths = [ "/var/www" ];
services.nginx.virtualHosts."example.com" = {
forceSSL = true;
enableACME = true;
locations."/android/" = {
root = "/var/www";
tryFiles = "$uri $uri/ =404";
};
};
}
The directory simply contains symlinks to the store paths that were contained in
the otaDir
output that was built earlier. I choose to just copy the result
symlink to /var/www/android
. It is recommended to use a symlink or mv
operation to expose the otaDir
to the web server, since (if you are
copying/uploading slowly) the OTA updater app on your phone might start
updating before the copy/upload is complete.
$ cp --no-dereference ota-dir /var/www/android
$ tree -l /var/www
/var/www
└── android -> /nix/store/dbjcl9lwn6xif9c0fy8d2wwpn9zi4hw4-sunfish-otaDir
├── sunfish-ota_update-2021.02.06.16.zip -> /nix/store/wwr49all6x868f0mdl11369ybfwyir0f-sunfish-ota_update-2021.02.06.16.zip
├── sunfish-stable -> /nix/store/c1rp46m9spncanacglqs5mxk6znfs44s-sunfish-stable
└── sunfish-target_files-2021.02.06.16.zip -> /nix/store/8ys21rzjqhi2055d7bd4iwa15fv1m446-sunfish-signed_target_files-2021.02.06.16.zip
Of course, this doesn't have to be located at /var/www
and it's totally
possible to integrate updating of the OTA directory into your other robotnix
build automation. In this case it is as easy as updating the /var/www/android
symlink with the new build output.
Here it was assumed that robotnix was built on the same machine that you will
serve the OTA from. If that is not the case you can conveniently copy the
closure to a remote host using nix copy
as in
$ nix copy --to ssh://user@example.com ./ota-dir
Don't forget to add the store path of the ota-dir
as a garbage collector root
on the remote machine or it might be collected in the next sweep.
Browsers / Webview
A properly functioning Android system requires the use of a "webview". Chromium-based browsers may also provide this webview
Robotnix can also build chromium-based browsers from source. We currently package Chromium, Bromite, and Vanadium for use with robotnix.
Chromium is an open-source browser project that aims to build a safer, faster, and more stable way for all users to experience the web.
Bromite is a Chromium fork with ad blocking and enhanced privacy.
Vanadium is a privacy and security hardened variant of Chromium providing the WebView (used by other apps to render web content) and standard browser for GrapheneOS. It depends on hardening and compatibility fixes in GrapheneOS rather than reinventing the wheel inside Vanadium
The following shows the available options for chromium
. The corresponding options for vanadium
and bromite
are similar.
{
apps.chromium.enable = true;
webview.chromium.enable = true;
webview.chromium.availableByDefault = true; # At least one webview must be availableByDefault
webview.chromium.isFallback = true; # If true, this provider will be disabled and only used if no others are available. At most one webview can be isFallback.
}
If multiple webview providers are included in a build, it is possible to select the one used on a running phone under "Settings -> System -> Developer Options -> Webview implementation".
The Vanilla and LineageOS flavors enable the standard Chromium browser and webview by default. The GrapheneOS flavor enables Vanadium browser and webview by default.
Set up remote attestation
GrapheneOS has created an Auditor app, as well as a Remote Attestation service, which "use hardware-based security features to validate the identity of a device along with authenticity and integrity of the operating system. See the About page for additional details.
Robotnix patches the Auditor app and Remote Attestation service to allow for using the user-created keys.
This makes the app (and also the Android build itself) depend on information derived from the device signing key(s).
The current code in robotnix only works with a single custom device type.
E.g. the attestation service cannot handle robotnix-customized versions of both crosshatch
and sunfish
.
Future improvements may allow the Auditor app and attestation service to work with multiple custom robotnix devices.
Android side
-
You can enable the Auditor app in the configuration:
{ signing.enable = true; signing.keyStorePath = "/dev/shm/android-keys"; apps = { auditor.enable = true; auditor.domain = "attestation.example.com"; }; }
You also need to have signing enabled during build time because the Auditor app needs to know its own signing key during build.
-
That's it from the Android side. Note that the custom Auditor app will be named “Robotnix Auditor”. When you build GrapheneOS the normal Auditor app will still be there in case you'd like to.
Server side
-
Before we begin we have to obtain the fingerprint of the custom Auditor app and the AVB fingerprint. To get the Auditor app fingerprint, we simply use OpenSSL to extract the fingerprint of the signing certificate:
$ openssl x509 -noout -fingerprint -sha256 -in keys/auditor.x509.pem | awk -F '=' '{gsub(/:/,""); print $2}' AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
The AVB fingerprint is a bit more tricky. I own a Pixel 4a (sunfish) and on this device the AVB fingerprint is simply the SHA256 hash of the AVB key, but this is not the case on other devices. Check the Auditor source code for details.
$ sha256sum keys/sunfish/avb_pkmd.bin | awk '{print toupper($1)}' BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
-
Now you can import robotnix in your NixOS configuration with the aforementioned fingerprints.
{ config, lib, pkgs, ... }: { imports = [ ((builtins.fetchTarball { name = "robotnix"; # Replace the git revision and sha256 with ones referring to a recent commit url = "https://github.com/danielfullmer/robotnix/archive/61b91d145f0b08cf0d4d73fb1d7ba74b9899b788.zip"; sha256 = "1dihmdw5w891jq2fm7mcx30ydjjd33ggbb60898841x5pzjx6ynv"; }) + "/nixos") ]; services.attestation-server = { enable = true; domain = "attestation.example.com"; device = "sunfish"; signatureFingerprint = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; avbFingerprint = "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"; #disableAccountCreation = true; # optionally uncomment after creating your account #nginx.enableACME = true; # optionally uncomment if you want to use Let's Encrypt for HTTPS }; }
-
Register and optionally disable account creation. The start the “Robotnix Auditor” app on your phone and open the menu (three dots). Choose “Enable remote verification” and scan the QR code on your attestation server.
-
The attestation server keeps its state in
/var/lib/private/attestation
. Make periodic backups!
Prebuilt Apps
Robotnix provides convenient configuration options for including additional prebuilt applications in the Android build using apps.prebuilt.*
options.
These apps are "prebuilt" from the perspective of the Android build step, and might even be built from source using Nix in another build step.
Perhaps the main reason to include additional prebuilt applications is to take advantage of privileged permissions only available to system applications. Secondarily, other Android applications that are built and customized from source inside Nix might be useful to include as prebuilts to the overall Android build. As each change to the robotnix configuration may require a long build process each time, try to avoid the temptation to include all of the applications you typically use in your robotnix configuration.
To include a prebuilt app in the robotnix build, consider the following example configuration:
{ pkgs, ... }:
{
apps.prebuilt.ExampleApp = {
apk = (pkgs.fetchurl {
url = "https://example.com/test.apk";
sha256 = "0000000000000000000000000000000000000000000000000000000000000000";
});
privileged = true; # Enable if the application needs access to privileged permissions
privappPermissions = [ "INSTALL_PACKAGES "];
packageName = "com.example.test"; # Needs to be set if using privappPermissions
};
}
The use of pkgs.fetchurl
above is for example only.
apps.prebuilt.<name>.apk
could also refer to an existing APK file by path, or could refer to some APK file output by another Nix expression.
In fact, many of the included robotnix modules (such as F-Droid and Chromium) are implemented using the apps.prebuilt
module.
Some of these Nix expressions for these apks are available under apks/
.
Source Directories
The AOSP source code is spread across a large number of git repositories.
The directories included in the robotnix build may be specified using the source.dirs.*
options.
For example, the following configuration will include a new repository checked out under foo/bar
by setting the source.dir.<name>.src
option.
{
source.dirs."foo/bar".src = pkgs.fetchGit {
url = "https://example.com/repo/foobar.git";
rev = "f506faf86b8f01f9c09aae877e00ad0a2b4bc511";
sha256 = "0000000000000000000000000000000000000000000000000000000000000000";
};
}
While the above uses pkgs.fetchGit
, the src
option could refer to any Nix derivation producing a directory.
Additionaly, robotnix provides a convenient mechanism for patching existing source directories:
{
# source.dirs.<name>.patches can refer to a list of patches to apply
source.dirs."frameworks/base".patches = [ ./example.patch ];
# source.dirs.<name>.postPatch can refer to a snippet of shell script to modify the source tree
source.dirs."frameworks/base".postPatch = ''
sed -i 's/hello/there/' example.txt
'';
}
Each flavor in robotnix conditionally sets the default source.dirs
to include the Android source directories required for the build.
Robotnix supports two alternative approaches for fetching source files:
- Build-time source fetching with
pkgs.fetchgit
. This is the default. An end user wanting to fetch sources not already included inrobotnix
would need to create a repo json file usingscripts/mk_repo_file.py
and setsource.dirs = lib.importJSON ./example.json;
- Evaluation-time source fetching with
builtins.fetchGit
. This is more convenient for development when changing branches, as it allows use of a shared user git cache. The end user will need to setsource.manifest.{url,rev,sha256}
and enablesource.evalTimeFetching
. However, withbuiltins.fetchGit
, thedrv
s themselves depend on the source, andnix-copy-closure
of even just the.drv
files would require downloading the source as well. This option is not as well tested as the build-time source fetching option.
Other Modules
Resources
Android applications may have resources which are additional static content such as bitmaps, user interface strings, configuration values, and others.
Some simple resources may be set for certain packages using the resources
option.
For example, the settings available here may be configured in robotnix by setting (for example):
{
resources."frameworks/base/core/res".config_displayWhiteBalanceAvailable = true;
}
The first key refers toe the relative path for the package resources, and the second key refers to the resource name.
The resource type is automatically determined based on value set.
Setting resources.<path>.<name>.type
can be used to override the automatically determined type.
Available values types are bool
, integer
, dimen
, color
, string
, integer-array
, and string-array
.
If this manual override is used, the value must be set using resources.<path>.<name>.value
.
CCache
Set ccache.enable = true
in configuration, and be sure to pass /var/cache/ccache
as a sandbox exception when building.
In NixOS, to set up the cache, also run (as root):
# mkdir -p -m0770 /var/cache/ccache
# chown root:nixbld /var/cache/ccache
# echo max_size = 100G > /var/cache/ccache/ccache.conf
This option only applies to the Android build process. (It does not apply to chromium, kernels, etc.) CCache support is deprecated in upstream AOSP, and might be removed from robotnix in the future.
Building
Build outputs
Robotnix provides a number of Nix outputs that can be built with a given configuration.
The specific output is selected using the -A
option of nix-build
.
For example, the following will build an img
zip associated with the configuration in config.nix
.
$ nix-build --arg configuration ./config.nix -A img
Some of the outputs provided by robotnix are the following:
img
- Image zip, which can be flashed to a device usingfastboot update
.factoryImg
- Factory image, a zip which contains the contents ofimg
as well as a radio / bootloader if available.ota
- Over-the-air zip, which can be flashed to a device in recovery mode usingadb sideload
.releaseScript
- Script which produces theimg
,ota
, andfactoryImg
products outside of Nix.generateKeysScript
- Script to generate required device / application keys for a given configuration.
Building and Signing Releases
After creating a configuration file, you need to generate keys for your device (if you are using signed builds, with signing.enable = true;
):
$ nix-build --arg configuration ./crosshatch.nix -A generateKeysScript -o generate-keys
$ ./generate-keys ./keys
This will create a keys
directory containing the app and device keys needed for the build.
The output of this script should be placed in the location specified by signing.keyStorePath
in the robotnix configuration.
If you intend to build the img
/factoryImg
/ota
Nix outputs instead of using the releaseScript
, do not apply a passphrase to your keys here.
(You can still encrypt them at rest on your own through other means.)
This is because we cannot prompt you for your passphrase during the Nix build, but we can outside of Nix using generateKeysScript
.
Sometimes changing your configuration will require that you generate additional new keys (e.g. for additional applications). Rebuilding and rerunning the generate keys script will produce the new keys (without overwriting your existing keys).
Next, build and sign your release. There are two ways to do this. The first option is to build the final products entirely inside Nix.
$ nix-build ./default.nix --arg configuration ./crosshatch.nix -A img --option extra-sandbox-paths /keys=$(pwd)/keys
If the Nix sandbox is enabled (it normally is), this will require a sandbox exception so the secret keys are available to the build scripts.
To use extra-sandbox-paths
, the user must be a trusted-user
in nix.conf
.
If the Nix sandbox is not enabled, we can instead set signing.buildTimeKeysStorePath
in addition to signing.keyStorePath
to a string of the absolute path to the generated keys.
Additionally, the nix builder will also need read access to these keys.
This can be set using chgrp -R nixbld ./keys
and chmod -R g+r ./keys
.
The second option involves building a "release script" with Nix, which depends on and therefore builds the unsigned image inside the Nix build sandbox. The final build steps of signing target files and creating img
/ota
files are then done outside the sandbox by running the release script:
$ nix-build --arg configuration ./crosshatch.nix -A releaseScript -o release
$ ./release ./keys
This has the additional benefit that the build can take place on a remote machine, and the releaseScript
could be copied using nix-copy-closure
to a local machine which containing the keys.
You might need to manually set certain required options like signing.avb.fingerprint
or apps.prebuilt.<name>.fingerprint
if you build on a remote machine that does not have access to the signing.keyStorePath
.
Binary Cache
Robotnix now has an optional binary cache provided by Cachix on robotnix.cachix.org.
Using the robotnix binary cache will allow the user to avoid building some parts that can be shared between users.
Currently, only the device kernels and browser builds are published through the binary cache.
This is because these derivation outputs are most likely to be shared between users, and those outputs also can take a very long time to build.
The build products previously discussed should be uploaded for at least every robotnix release tag.
To use, install cachix
, run cachix use robotnix
, and then build robotnix like normal.
Flakes
If the robotnix configuration is specified in a flake, the robotnix outputs can be produced by running (for example):
$ nix build .#robotnixConfigurations.dailydriver.img
This is assuming the flake.nix
is in the current directory, the desired configuration is named dailydriver
, and will produce the img
output.
Other robotnix outputs are available using a similar command.
Installing for the first time with (optional) verified boot
The following instructions are specific to Pixel phones using either the Vanilla or GrapheneOS flavors. For LineageOS, please refer to upstream device-specific documentation on how to install LineageOS builds on your device.
It is assumed that you have successfully built your factory image and signed it
with your own keys, either by using the factoryImg
Nix output or by running
releaseScript
. Make sure that you know the location of the image and the AVB
signing key. The instructions in this document were tested on the Google Pixel
4a (sunfish). Other Pixel phones are similar, but please refer to this
upstream documentation.
-
Before you can begin you have to boot the stock OS, go to "Settings / About phone" and tap the "Build number" field 7 times to enable the "Developer options" menu. Next go to “Settings / System / Advanced / Developer options” and enable “OEM unlocking”. This option is greyed out until you connect your device to Google at least once. This is part of Google's so called Factory Reset Protection (FRP) for anti-theft protection. You do not need to insert a SIM or log into a Google Account to make the “OEM unlocking” option available, but connecting to the internet is required.
-
First reboot into the bootloader. You can either do that physically by turning off your phone and then holding both the POWER and the VOLUME DOWN button to turn it back on, or your can connect the phone to your computer with USB Debugging turned on and issue
$ adb reboot bootloader
-
Connect your phone to your computer and run
$ fastboot devices 09071JEC217048 device
-
Unlock the bootloader by running
$ fastboot flashing unlock
Select the option to unlock the device and confirm. This step effectively performs a factory reset, and will remove all user data from the device.
-
Flash your custom AVB signing key using
$ fastboot erase avb_custom_key $ fastboot flash avb_custom_key ./avb_pkmd.bin $ fastboot reboot bootloader
-
Unzip the factory image built by robotnix. Double check that you're flashing to the correct device. To flash the image run
$ ./flash-all.sh
The factory image produced by robotnix includes the bootloader and radio firmware in addition to the android image. If you are certain the bootloader and radio are already up to date, you can instead build the standard
img
robotnix output, and flash the image with$ fastboot -w --skip-reboot update sunfish-img-2020.11.06.04.zip
This will erase the
userdata
partition (-w
) and prevent the automatic reboot after flashing (--skip-reboot
).After flashing with the
flash-all.sh
script or withfastboot update
, return to the bootloader with$ fastboot reboot bootloader
-
At this point you want to relock the bootloader to enable enforcement of the verified boot chain.
$ fastboot flashing lock
This step has to be confirmed on the device.
-
After rebooting you will be greeted with a yellow exclamation mark and a message like
Your device is loading a different operating system.
Visit this link on another device: g.co/ABH
ID: BA135E0F
This is expected because Android Verified Boot is designed to warn the user when not booting the stock OS, see https://source.android.com/security/verifiedboot/boot-flow. In fact, the ID on the last line are the first eight characters of the fingerprint of your AVB key.
-
Finally you can disable OEM unlocking and afterwards even the developer options again if you do not actively use them. Note that if you later lose the ability to re-enable OEM unlocking, for example by pushing a bad update that you cannot rollback, and you cannot push another working update because you also lost your signing keys, you might not even be able to recover your device by flashing a stock image, effectively bricking the device.
If you are unable to enroll a custom AVB key on your device, you could theoretically skip steps 4, 6 and 8. This is highly discouraged as it leaves your device in the vulnerable UNLOCKED state instead of being LOCKED with a custom root of trust..
Updating by sideloading OTA files
Preferably, you can update your Vanilla/GrapheneOS flavor device using true "over-the-air" mechanism provided by the apps.updater
module with a server hosting the OTA files, as shown here.
If this is not available, it is still possible to update by sideloading the OTA file.
It is recommended to update using the OTA file instead of using
fastboot update
with a newimg
. OTA files can also contain updates to the modem / bootloader that are not included in theimg
output.fastboot update
also cannot be used with a re-locked bootloader without wiping userdata.
To install OTA updates you have to put the device in sideload-mode.
-
First reboot into the bootloader. You can either do that physically by turning off your phone and then holding both the POWER and the VOLUME DOWN button to turn it back on, or your can connect the phone to your computer with USB Debugging turned on and issue
$ adb reboot recovery
If you used the physical method, at the bootloader prompt use the VOLUME keys to select “Recovery Mode” and confirm with the POWER button.
-
Now the recovery mode should have started and you should see a dead robot with a read exclamation mark on top. If you see “No command” on the screen, press and hold POWER. While holding POWER, press VOLUME UP and release both.
-
At the recovery menu use the VOLUME keys to select “Apply update from ADB” and use POWER to confirm.
-
Connect your phone to your computer and run
$ adb devices List of devices attached 09071JEC217048 sideload
The output should show that the device is in sideload mode.
-
Now you can proceed to sideload the new update.
$ adb sideload sunfish-ota_update-2021.02.06.16.zip
The sideload might terminate at 94% with “adb: failed to read command: Success”. This is not an error even though it is not obvious, see also here.
-
Once finished and the device doesn't automatically reboot just select reboot from the menu and confirm.
Development
Robotnix modules use the same Nix-based module system used in NixOS. To understand the NixOS module system, please read this.
Robotnix does not primarily aim to significantly decrease the complexity of Android development, but rather (once a developer has a working build) makes it easier to share that work with others.
As such, robotnix does not replace the existing Android build system, but provides a convenient Nix-based wrapper around the build system. (See blueprint2nix and soongnix for an experimental attempt at reimplementing part of the Android build system natively in Nix.)
Feel free to ask robotnix development questions in #robotnix:nixos.org
on Matrix.
Git mirrors
Robotnix can be configured to use local git mirrors of Android source code. The AOSP documentation includes instructions to create a local mirror of the Android source code. Maintaining a local mirror can save bandwidth in the long-run when repeatedly updating a flavor over time which contains incremental updates.
This functionality is enabled by setting the ROBOTNIX_GIT_MIRRORS
environment variable.
The value of ROBOTNIX_GIT_MIRRORS
contains a number of mappings, each separated by a |
character.
Each mapping is of the format <remote_url>=<local_url>
.
For example:
ROBOTNIX_GIT_MIRRORS=https://android.googlesource.com=/mnt/cache/mirror|https://github.com/LineageOS=/mnt/cache/lineageos/LineageOS
Both the robotnix update scripts as well as robotnix's overridden fetchgit
derivation use ROBOTNIX_GIT_MIRRORS
.
This environment variable is passed to fetchgit
via impureEnvVars
(search for impureEnvVars
in the Nix manual).
If the Nix daemon is being used, it needs to have this ROBOTNIX_GIT_MIRRORS
in its environment, not just in the user's environment when running nix-build
or nix build
.
The following NixOS configuration can be used to easily set this environment variable for the Nix daemon:
let
mirrors = {
"https://android.googlesource.com" = "/mnt/cache/mirror";
"https://github.com/LineageOS" = "/mnt/cache/lineageos/LineageOS";
};
in
{
nix.envVars.ROBOTNIX_GIT_MIRRORS = lib.concatStringsSep "|" (lib.mapAttrsToList (local: remote: "${local}=${remote}") mirrors);
# Also add local mirrors to nix sandbox exceptions
nix.sandboxPaths = lib.attrValues mirrors;
}
Helper scripts
Robotnix can produce a few helper scripts that can make Android development easier in some circumstances.
Running nix-build --arg configuration <cfg> -A <output>
for the outputs below will produce the corresponding helper script, using the provided robotnix configuration.
config.build.debugEnterEnv
produces a script which enters an FHS environment with the required dependencies, as well as the Android source files bind-mounted under the current directory. Useful in conjunction withcd $(mktemp -d)
to enter a temporary directory. Files are bind-mounted readonly, so files cannot be edited ad-hoc using this script.
The following outputs can be useful with an existing Android source checkout made using repo
.
config.build.env
produces arobotnix-build
script underbin/
which enters an FHS environment that contains all required dependencies to build Android.config.build.debugUnpackScript
produces a script which will copy the robotnix-specific source directories into./robotnix/
.config.build.debugPatchScript
produces a script which will patch all Android source directories under the current directory in a similar way they would be patched during a normal robotnix build.
External modules
Robotnix is welcome to contributions of well-written modules that can be maintained in an ongoing fashion. Modules can provide support for new flavors, additional devices with an existing flavor, included system/privileged applications, and others.
If the proposed module is not suitable for inclusion as an upstream robotnix module,
it can still be developed and maintained externally and easily included by a user.
This can be done in a similar way as is done with NixOS modules.
For instance, if the module is provided by default.nix
in the owner/repo
repository on GitHub:
{
imports = [ (builtins.fetchTarball {
url = "https://github.com/owner/repo/archive/9b034054166e1f01b3bdb6a1948daa3bdafe039a.tar.gz";
sha256 = "0000000000000000000000000000000000000000000000000000000000000000";
}) ];
}
The above imports
statement will include the provided module in the robotnix build, pinned by the provided revision and sha256
.
Any options or configuration set by the specified module will be included in the build.
Developing a new flavor
To create a new flavor, the developer should create a robotnix module that conditions on config.flavor
.
The flavor configuration defaults should be set conditionally using (for example) mkIf (config.flavor = "...") { ... }
.
Those configuration defaults should include:
- Setting
source.dirs
using a repo JSON file produced bymk_repo_file.py
. - Setting the default
androidVersion
. - Setting the default
buildDateTime
based on (for example) the time that the flavor was last updated. - Providing a warning if the user has not selected a valid device for this flavor.
Additionally, flavors should provide update scripts that can (at least) automatically produce an updated repo JSON file.
It is recommended to take a look at the Nix expressions implementing the current flavors under flavors/
.
Emulator
Robotnix can also build a script which will start the Android emulator using an attached robotnix-built system image.
This can be accomplished with the emulator
Nix output.
To build and run an emulator with an attached vanilla system image, use (for example):
$ nix-build ./default.nix --arg configuration '{device="x86_64"; flavor="vanilla";}' -A emulator
$ ./result
This currently only works well when using the generic x86_64
device.
Testing / CI / Reproducibility
All devices (Pixel 3-5(a) (XL)) have very basic checks to ensure that the android build process will at least start properly.
See release.nix
for the set of configurations with this minimal build testing.
This check is run using nix-build ./release.nix -A check
.
As each build takes approximately 4 hours--I only build marlin and crosshatch builds for myself.
At some point, I would love to set up a build farm and publish build products on s3 or cachix.
This would allow an end-user to simply sign releases using their own keys without building the entire AOSP themselves.
As of 2020-05-17, target_files
, signed_target_files
, img
, and ota
files have all been verified to be bit-for-bit reproducible for crosshatch
and marlin
using the vanilla
flavor.
Automated periodic testing of this is still desired.
One option being investigated is to have multiple independent remote builders produce unsigned target files for a number of device and flavor combinations.
An end-user could then verify that the builders produced the same unsigned target files, and finish the process by signing the target files and producing their own img
and ota
files.
This eliminates the requirement for an end-user to spend hours building android.
There are, however, a few places where user-specific public keys are included in the build for key pinning. This unfortunately decreases the possibility of sharing build products between users. The F-Droid privileged extension and Trichrome (disabled for now) are two components which have this issue. Fixes for this are still under investigation.
Building individual android components
For convenience, individual android components may be easily built using the components.nix
at the root of the repo.
For example, to build adb
, run
$ nix-build ./components.nix -A adb
The set of components available may be found in components.json
.
Only what Android considers the "installed output" of the components is copied into the resuting derivation, and not "intermediate" results.
Sometimes these intermediate results are what is desired, in which case the user should manually set the installPhase
for a mkAndroid
invokation.
For more detailed information about what exactly these components produce as "installed output", see the config.build.moduleInfo
output for a build.
Additional Notes
Robotnix bind mounts the source directories from /nix/store
.
These files/directories have their "user write" (u-w
) permission removed.
Sometimes, Android Makefiles which copy files from the source directories may assume the files have the write permission enabled, which can then break later steps.
To work around these issues, it is usually sufficient to add a chmod
command or add --no-preserve=owner,mode
to the cp
command in the Makefile.
Robotnix Configuration Options
Some robotnix flavors or modules may change the option defaults shown below. Refer to the flavor or module source for details
androidVersion
Used to select which Android version to use
Default: 12
Type: signed integer
Declared by: modules/base.nix
apps.auditor.domain
Domain running the AttestationServer (over HTTPS) for remote verification
Example: "attestation.example.com"
Type: string
Declared by: modules/apps/auditor.nix
apps.auditor.enable
Whether to enable Auditor.
Default: false
Example: true
Type: boolean
Declared by: modules/apps/auditor.nix
apps.bromite.enable
Whether to enable bromite browser.
Default: false
Example: true
Type: boolean
Declared by: modules/apps/chromium.nix
apps.chromium.enable
Whether to enable chromium browser.
Default: false
Example: true
Type: boolean
Declared by: modules/apps/chromium.nix
apps.fdroid.additionalRepos
Additional F-Droid repositories to include in the default build. Note that changes to this setting will only take effect on a freshly installed device--or if the F-Droid storage is cleared.
Default: { }
Type: attribute set of submodules
Declared by: modules/apps/fdroid.nix
apps.fdroid.additionalRepos.<name>.description
Longer textual description of this repository
Default: "Empty description"
Type: string
Declared by: modules/apps/fdroid.nix
apps.fdroid.additionalRepos.<name>.enable
Whether to enable this repository by default in F-Droid.
Default: false
Type: boolean
Declared by: modules/apps/fdroid.nix
apps.fdroid.additionalRepos.<name>.name
Display name to use for this repository
Default: "‹name›"
Type: string
Declared by: modules/apps/fdroid.nix
apps.fdroid.additionalRepos.<name>.pubkey
Public key associated with this repository. Can be found in /index.xml
under the repo URL.
Type: string
Declared by: modules/apps/fdroid.nix
apps.fdroid.additionalRepos.<name>.pushRequests
Allow this repository to specify apps which should be automatically installed/uninstalled
Default: "ignore"
Type: one of "ignore", "prompt", "always"
Declared by: modules/apps/fdroid.nix
apps.fdroid.additionalRepos.<name>.url
URL for F-Droid repository
Type: string
Declared by: modules/apps/fdroid.nix
apps.fdroid.enable
Whether to enable F-Droid.
Default: false
Example: true
Type: boolean
Declared by: modules/apps/fdroid.nix
apps.prebuilt
Prebuilt APKs to include in the robotnix build
Default: { }
Type: attribute set of submodules
Declared by: modules/apps/prebuilt.nix
apps.prebuilt.<name>.allowInPowerSave
Whether to allow this application to operate in "power save" mode. Disables battery optimization for this app.
Default: false
Type: boolean
Declared by: modules/apps/prebuilt.nix
apps.prebuilt.<name>.apk
APK file to include in build
Default: null
Type: null or path
Declared by: modules/apps/prebuilt.nix
apps.prebuilt.<name>.certificate
Name of certificate to sign APK with. Defaults to the name of the prebuilt app.
If it is a device-specific certificate, the cert/key should be under ${keyStorePath}/${device}/${certificate}.{x509.pem,pk8}
.
Otherwise, it should be ${keyStorePath}/${certificate}.{x509.pem,pk8}
.
Finally, the special string "PRESIGNED" will just use the APK as-is.
Default: "‹name›"
Type: string
Declared by: modules/apps/prebuilt.nix
apps.prebuilt.<name>.defaultPermissions
Permissions to be enabled by default without user prompting.
Default: [ ]
Example: ["INSTALL_PACKAGES"]
Type: list of strings
Declared by: modules/apps/prebuilt.nix
apps.prebuilt.<name>.enable
Include ‹name› APK in Android build
Default: true
Type: boolean
Declared by: modules/apps/prebuilt.nix
apps.prebuilt.<name>.modulePrefix
Prefix to prepend to the module name to avoid conflicts. (No spaces)
Default: "Robotnix"
Type: string
Declared by: modules/apps/prebuilt.nix
apps.prebuilt.<name>.name
Name of application. (No spaces)
Default: "‹name›"
Type: string
Declared by: modules/apps/prebuilt.nix
apps.prebuilt.<name>.packageName
APK's Java-style package name (applicationId). This setting only necessary to be set if also using privappPermissions
.
Example: "com.android.test"
Type: string matching the pattern [a-zA-Z0-9_.]*
Declared by: modules/apps/prebuilt.nix
apps.prebuilt.<name>.partition
Partition on which to place this app
Type: one of "vendor", "system", "product"
Declared by: modules/apps/prebuilt.nix
apps.prebuilt.<name>.privappPermissions
Privileged permissions to apply to this application. Refer to this link and note permissions which say "not for use by third-party applications".
Default: [ ]
Example: ["INSTALL_PACKAGES"]
Type: list of strings
Declared by: modules/apps/prebuilt.nix
apps.prebuilt.<name>.privileged
Whether this APK should be included as a privileged application.
Default: false
Type: boolean
Declared by: modules/apps/prebuilt.nix
apps.prebuilt.<name>.usesLibraries
Shared library dependencies of this app.
For more information, see https://android.googlesource.com/platform/build/+/75342c19323fea64dbc93fdc5a7def3f81113c83/Changes.md.
Default: [ ]
Type: list of strings
Declared by: modules/apps/prebuilt.nix
apps.prebuilt.<name>.usesOptionalLibraries
Optional shared library dependencies of this app.
For more information, see https://android.googlesource.com/platform/build/+/75342c19323fea64dbc93fdc5a7def3f81113c83/Changes.md.
Default: [ ]
Type: list of strings
Declared by: modules/apps/prebuilt.nix
apps.seedvault.enable
Whether to enable Seedvault (backup).
Default: false
Example: true
Type: boolean
Declared by: modules/apps/seedvault.nix
apps.updater.enable
Whether to enable OTA Updater.
Default: false
Example: true
Type: boolean
Declared by: modules/apps/updater.nix
apps.updater.flavor
Which updater package to use, and which kind of metadata to generate for it.
Default: "grapheneos"
Type: one of "grapheneos", "lineageos"
Declared by: modules/apps/updater.nix
apps.updater.url
URL for OTA updates
Type: string
Declared by: modules/apps/updater.nix
apps.vanadium.enable
Whether to enable vanadium browser.
Default: false
Example: true
Type: boolean
Declared by: modules/apps/chromium.nix
apv.buildID
Build ID associated with the upstream img/ota (used to select images)
Type: string
Declared by: modules/apv
apv.enable
Whether to enable android-prepare-vendor.
Default: false
Example: true
Type: boolean
Declared by: modules/apv
apv.img
A factory image .zip
from upstream whose vendor contents should be extracted and included in the build
Default: null
Type: path
Declared by: modules/apv
apv.ota
An OTA
from upstream whose vendor contents should be extracted and included in the build. (Android >=10 builds require this in addition to apv.img
)
Default: null
Type: path
Declared by: modules/apv
arch
Architecture of phone, usually set automatically by device
Default: "arm64"
Type: one of "arm64", "arm", "x86_64", "x86"
Declared by: modules/base.nix
buildDateTime
Unix time (seconds since the epoch) that this build is taking place.
Needs to be monotonically increasing for each build if you use the over-the-air (OTA) update mechanism.
e.g. output of date +%s
Default: "*maximum of source.dirs.<name>.dateTime*"
Example: 1565645583
Type: signed integer
Declared by: modules/base.nix
buildNumber
Set this to something meaningful to identify the build.
Defaults to YYYYMMDDHH
based on buildDateTime
.
Should be unique for each build for disambiguation.
Example: "201908121"
Type: string
Declared by: modules/base.nix
buildType
one of "release", "debug"
Default: "release"
Type: one of "release", "debug"
Declared by: modules/base.nix
ccache.enable
Whether to enable ccache.
Default: false
Example: true
Type: boolean
Declared by: modules/base.nix
channel
Default channel to use for updates (can be modified in app)
Default: "stable"
Type: one of "stable", "beta"
Declared by: modules/release.nix
device
Code name of device build target
Default: null
Example: "marlin"
Type: null or string
Declared by: modules/base.nix
deviceDisplayName
Display name of device build target
Default: null
Example: "Pixel XL"
Type: null or string
Declared by: modules/base.nix
etc
Set of files to be included under /etc
Default: { }
Type: attribute set of submodules
Declared by: modules/etc.nix
etc.<name>.partition
Partition on which to place this etc file
Type: one of "vendor", "system", "product"
Declared by: modules/etc.nix
etc.<name>.source
Path of the source file
Type: path
Declared by: modules/etc.nix
etc.<name>.target
Name of symlink (relative to /etc
). Defaults to the attribute name.
Type: string
Declared by: modules/etc.nix
etc.<name>.text
Text of the file
Default: null
Type: null or string
Declared by: modules/etc.nix
flavor
Set to one of robotnix's supported flavors.
Current options are vanilla
, grapheneos
, and lineageos
.
Default: null
Example: "vanilla"
Type: null or string
Declared by: modules/base.nix
hosts
Custom hosts file
Default: null
Type: null or path
Declared by: modules/hosts.nix
incremental
Whether to include an incremental build in otaDir
output
Default: false
Type: boolean
Declared by: modules/release.nix
kernel.buildDateTime
Unix time to use for kernel build timestamp
Default: "config.buildDateTime"
Type: signed integer
Declared by: modules/kernel.nix
kernel.clangVersion
Version of prebuilt clang to use for kernel. See https://android.googlesource.com/platform/prebuilts/clang/host/linux-x86/+/master/README.md"
Type: string
Declared by: modules/kernel.nix
kernel.enable
Whether to enable building custom kernel.
Default: false
Example: true
Type: boolean
Declared by: modules/kernel.nix
kernel.patches
List of patches to apply to kernel source
Default: [ ]
Type: list of paths
Declared by: modules/kernel.nix
kernel.postPatch
Commands to run after patching kernel source
Default: ""
Type: strings concatenated with "\n"
Declared by: modules/kernel.nix
kernel.relpath
Relative path in source tree to place kernel build artifacts
Type: string
Declared by: modules/kernel.nix
kernel.src
Path to kernel source
Type: path
Declared by: modules/kernel.nix
microg.enable
Whether to enable MicroG.
Default: false
Example: true
Type: boolean
Declared by: modules/microg.nix
nixpkgs.overlays
Nixpkgs overlays to override the default packages used while building robotnix.
Default: [ ]
Type: list of unspecifieds
Declared by:
pixel.activeEdge.enable
Whether to enable Active Edge gestures using the open-source implementation from LineageOS.
Default: false
Example: true
Type: boolean
Declared by: modules/pixel/active-edge.nix
pixel.useUpstreamDriverBinaries
Use device vendor binaries from https://developers.google.com/android/drivers
Default: false
Type: boolean
Declared by: modules/pixel/driver-binaries.nix
product.additionalProductPackages
PRODUCT_PACKAGES
to add under product
partition.
Default: [ ]
Type: list of strings
Declared by: modules/base.nix
productName
Product name for choosecombo/lunch
Default: "${productNamePrefix}${device}"
Example: "aosp_crosshatch"
Type: string
Declared by: modules/base.nix
productNamePrefix
Prefix for product name used with choosecombo/lunch
Default: "aosp_"
Type: string
Declared by: modules/base.nix
removedProductPackages
PRODUCT_PACKAGES
to remove from build
Default: [ ]
Type: list of strings
Declared by: modules/base.nix
resources
Additional package resources to include. The first key refers to the relative path for the package, and the second key refers to the resource name
Default: { }
Example: {"_type":"literalExpression","text":"{ \"frameworks/base/core/res\".config_enableAutoPowerModes = true; }"}
Type: attribute set of attribute set of boolean or signed integer or string or list of string or signed integers or submoduless
Declared by: modules/resources.nix
retrofit
Generate a retrofit OTA for upgrading a device without dynamic partitions. See also https://source.android.com/devices/tech/ota/dynamic_partitions/ab_legacy#generating-update-packages
Default: false
Type: boolean
Declared by: modules/release.nix
security.pki.certificateFiles
A list of files containing trusted root certificates in PEM format. These are added as system-level trust anchors.
Default: [ ]
Type: list of paths
Declared by: modules/security-pki.nix
signing.apex.enable
Whether to enable signing APEX packages.
Default: false
Example: true
Type: boolean
Declared by: modules/signing.nix
signing.apex.packageNames
APEX packages which need to be signed
Default: [ ]
Type: list of strings
Declared by: modules/signing.nix
signing.avb.enable
Whether to enable AVB signing.
Default: false
Example: true
Type: boolean
Declared by: modules/signing.nix
signing.avb.fingerprint
SHA256 hash of avb_pkmd.bin
. Should be set automatically based on file under keyStorePath
if signing.enable = true
Type: string matching the pattern [0-9A-F]{64}
Declared by: modules/signing.nix
signing.avb.mode
Mode of AVB signing to use.
Default: "vbmeta_chained"
Type: one of "verity_only", "vbmeta_simple", "vbmeta_chained", "vbmeta_chained_v2"
Declared by: modules/signing.nix
signing.avb.verityCert
Verity certificate for AVB. e.g. in x509 DER format.x509.pem. Only needed if signing.avb.mode = "verity_only"
Type: path
Declared by: modules/signing.nix
signing.buildTimeKeyStorePath
Path to generated keys for signing to use at build-time, as opposed to keyStorePath, which is used at evaluation-time.
Type: string or path
Declared by: modules/signing.nix
signing.enable
Whether to sign build using user-provided keys. Otherwise, build will be signed using insecure test-keys.
Default: false
Type: boolean
Declared by: modules/signing.nix
signing.keyStorePath
String containing absolute path to generated keys for signing.
This must be a string and not a "nix path" to ensure that your secret keys are not imported into the public /nix/store
.
Example: "/var/secrets/android-keys"
Type: string
Declared by: modules/signing.nix
source.dirs
Directories to include in Android build process.
Normally set by the output of mk_repo_file.py
.
However, additional source directories can be added to the build here using this option as well.
Default: { }
Type: attribute set of submodules
Declared by: modules/source.nix
source.dirs.<name>.enable
Whether to include this directory in the android build source tree.
Default: true
Type: boolean
Declared by: modules/source.nix
source.dirs.<name>.patches
Patches to apply to source directory.
Default: [ ]
Type: list of paths
Declared by: modules/source.nix
source.dirs.<name>.postPatch
Additional commands to run after patching source directory.
Default: ""
Type: strings concatenated with "\n"
Declared by: modules/source.nix
source.dirs.<name>.relpath
Relative path under android source tree to place this directory. Defaults to attribute name.
Default: "‹name›"
Type: string
Declared by: modules/source.nix
source.dirs.<name>.src
Source to use for this android source directory.
Default: <derivation empty>
Type: path
Declared by: modules/source.nix
source.evalTimeFetching
Set config.source.dirs automatically using IFD with information from source.manifest
.
Also enables use of builtins.fetchGit
instead of pkgs.fetchgit
if not all sha256 hashes are available.
(Can be useful for development, but not recommended normally)
Default: false
Type: unspecified
Declared by: modules/source.nix
source.excludeGroups
Project groups to exclude from source tree
Default: [ "darwin" "mips" ]
Type: list of strings
Declared by: modules/source.nix
source.includeGroups
Project groups to include in source tree (overrides excludeGroups
)
Default: [ ]
Type: list of strings
Declared by: modules/source.nix
source.manifest.rev
Revision/tag to use from repo manifest repository.
Type: string
Declared by: modules/source.nix
source.manifest.sha256
Nix sha256 hash of repo manifest repository.
Type: string
Declared by: modules/source.nix
source.manifest.url
URL to repo manifest repository. Not necessary to set if using source.dirs
directly.
Type: string
Declared by: modules/source.nix
system.additionalProductPackages
PRODUCT_PACKAGES
to add under system
partition.
Default: [ ]
Type: list of strings
Declared by: modules/base.nix
useReproducibilityFixes
Apply additional fixes for reproducibility
Default: true
Type: boolean
Declared by: modules/base.nix
variant
user
has limited access and is suited for production.
userdebug
is like user but with root access and debug capability.
eng
is the development configuration with additional debugging tools.
Default: "user"
Type: one of "user", "userdebug", "eng"
Declared by: modules/base.nix
vendor.additionalProductPackages
PRODUCT_PACKAGES
to add under vendor
partition.
Default: [ ]
Type: list of strings
Declared by: modules/base.nix
webview
Webview providers to include in Android build. Pre-specified options are chromium
, bromite
, and vanadium
.
Example: {"_type":"literalExpression","text":"{ bromite.enable = true; }"}
Type: attribute set of submodules
Declared by: modules/webview.nix
webview.<name>.apk
APK file containing webview package.
Type: path
Declared by: modules/webview.nix
webview.<name>.availableByDefault
If true
, this provider can be automatically selected by the
framework, if it's the first valid choice. If false
, this
provider will only be used if the user selects it themselves from
the developer settings menu.
Default: false
Type: boolean
Declared by: modules/webview.nix
webview.<name>.description
The name shown to the user in the developer settings menu.
Default: "Android System WebView"
Type: string
Declared by: modules/webview.nix
webview.<name>.enable
Whether to enable ‹name› webview.
Default: false
Example: true
Type: boolean
Declared by: modules/webview.nix
webview.<name>.isFallback
If true
, this provider will be automatically disabled by the
framework, preventing it from being used or updated by app
stores, unless there is no other valid provider available. Only
one provider can be a fallback.
Default: false
Type: boolean
Declared by: modules/webview.nix
webview.<name>.packageName
The Android package name of the APK.
Default: "com.android.webview"
Type: string
Declared by: modules/webview.nix