Install
From a Windows, macOS or Linux computer, with fastboot and a USB cable.
The steps follow the GrapheneOS command line install, in the same order, with our signing key
added. About half an hour.
Commands below are for the computer you pick, guessed from your browser.
Installing erases everything on the phone. Unlocking the bootloader and locking it again each wipe all data. Back up first. This is an alpha from a personal research project: only install it on a phone you can afford to lose data on. See the terms. Problems: get in touch.
The quick way: the install script
One script does steps 2 and 4 to 8 for you. It checks the computer, gets fastboot if yours
is missing or too old, finds the phone, downloads the newest build and checks it against our
key, then unlocks, flashes and locks. Before each wipe it stops and asks you to type
UNLOCK or LOCK.
Do step 1 on the phone first, and put the phone in the bootloader (step 3). Then:
Windows
In PowerShell, in a normal window, not Run as administrator:
curl.exe -fLO https://ee1os.com/install.ps1
powershell -ExecutionPolicy Bypass -File .\install.ps1macOS and Linux
In Terminal:
curl -fLO https://ee1os.com/install.sh
bash install.sh- Try it without changing anything by adding
--check(on Windows,-Check). It checks the computer, fastboot and the phone, then stops. - It logs everything to
ee1os-installin your home folder. If something fails, it shows what and asks whether to send the log to Ivan. Nothing is sent unless you say yes: see error reports. - Lock later without flashing again. If you left the bootloader
unlocked at the end,
bash install.sh --lock-only(on Windows,-LockOnly) locks it. Run the full install again instead if you aren't sure what's on the phone. - Read it before you run it: install.sh, install.ps1.
Rather type each command yourself? The steps below do the same by hand.
Before you start
- A supported Pixel with a build. The supported models are the ones
GrapheneOS supports. Builds so far: Pixel 8 Pro (
husky) and Pixel 10a (stallion, not tried on a phone yet). Check devices. Never flash a build made for another model. - OEM unlocking must be possible. Some carrier-sold phones block it. If the switch in step 1 is greyed out, you can't install.
- A computer running Windows 10 or 11, a current macOS, or a current Linux, with about 10 GB free. Not a virtual machine: USB passthrough is unreliable.
- A good USB cable, ideally the one that came with the phone. Plug it straight into the computer, not into a hub or a front-panel port.
- Backups of everything you want to keep.
Coming from GrapheneOS? Your phone runs GrapheneOS with a locked bootloader and GrapheneOS's key. Start at step 1 like everyone else: turn OEM unlocking back on (GrapheneOS's setup turns it off), unlock (a wipe), flash, flash our key, lock again. Our builds can't be installed over GrapheneOS without that wipe, and GrapheneOS updates won't install over ours.
01Enable OEM unlocking
- On the phone, open Settings → About phone and tap Build number seven times to enable Developer options.
- Open Settings → System → Developer options and turn on OEM unlocking. The phone may need an internet connection before the switch can be used.
02Get fastboot
You need Google's platform-tools, version 35.0.1 or newer. Download them into a folder of their own and use them from one terminal window for every step below. The PATH change only lasts for that window: if you close it, open a new one in the same folder and repeat the PATH line.
Windows
Open PowerShell from the Start menu (or Windows Terminal). Use a normal window, not Run as administrator. Then:
mkdir ee1os; cd ee1os
curl.exe -LO https://dl.google.com/android/repository/platform-tools-latest-windows.zip
tar -xf platform-tools-latest-windows.zip
$env:Path = "$pwd\platform-tools;$env:Path"
fastboot --versionType curl.exe, not curl: in PowerShell, plain curl is a different command.
macOS
Open Terminal (Applications → Utilities). Then:
mkdir ee1os && cd ee1os
curl -LO https://dl.google.com/android/repository/platform-tools-latest-darwin.zip
unzip -q platform-tools-latest-darwin.zip
export PATH="$PWD/platform-tools:$PATH"
fastboot --versionmacOS needs no driver.
Linux
Open a terminal. Then:
mkdir ee1os && cd ee1os
curl -LO https://dl.google.com/android/repository/platform-tools-latest-linux.zip
unzip -q platform-tools-latest-linux.zip
export PATH="$PWD/platform-tools:$PATH"
fastboot --versionDistribution packages of fastboot are often too old; use these. To flash without root you
need the udev rules for Android devices: android-udev on Arch,
android-sdk-platform-tools-common on Debian and Ubuntu. If fastboot later says
the device is claimed or in use, stop fwupd for this session:
sudo systemctl stop fwupd.service.
The last command prints the version. It must be 35.0.1 or newer.
03Connect the phone
- Turn the phone off. Hold volume down and press power. The bootloader opens: a red warning triangle and the words Fastboot Mode. Don't press power again: that would pick Start and leave the bootloader.
- Connect the phone to the computer and check that it's seen:
fastboot devicesIt prints one line with the phone's serial number. If it prints nothing:
Windows
Windows 10 and 11 include a fastboot driver. If the phone still isn't listed, open Settings → Windows Update → Advanced options → Optional updates → Driver updates, install the Android bootloader interface driver (it may be called LeMobile Android Device), then unplug and reconnect. Google's USB driver for Windows also works.
macOS
Try another cable or another port on the computer itself, then reconnect.
Linux
Install the udev rules from step 2 if you haven't, then unplug and reconnect.
Still nothing: change the cable and avoid hubs. Bad cables are the most common cause.
04Unlock the bootloaderWipes the phone
fastboot flashing unlockThe phone asks for confirmation. Use the volume keys to select Unlock the bootloader and press power. This wipes the phone. It returns to the bootloader, unlocked.
05Download and verify
Releases are published at github.com/ee1os/releases,
one release per build, tagged with the build number. Builds for different models can have
different numbers, so GitHub's "Latest" release may be for another model. Find yours with
the phone's codename (fastboot getvar product, for example husky
for the Pixel 8 Pro, stallion for the Pixel 10a). This prints the newest build
for it as the first word:
curl -sL https://github.com/ee1os/releases/releases/download/updates/<codename>-stable(on Windows, curl.exe). That release holds the install zip,
<codename>-install-<build>.zip, and a checksum file,
SHA256SUMS-<build>. The release notes list the same SHA-256 values. Download
both into the same folder, with <codename> and <build>
replaced:
Windows
curl.exe -LO https://github.com/ee1os/releases/releases/download/<build>/<codename>-install-<build>.zip
curl.exe -LO https://github.com/ee1os/releases/releases/download/<build>/SHA256SUMS-<build>
Get-FileHash *-install-*.zip -Algorithm SHA256
Get-Content SHA256SUMS-*Compare the hash with the line for the install zip in the checksum file and in the release notes. Windows prints it in capitals; the letters are the same.
macOS
curl -LO https://github.com/ee1os/releases/releases/download/<build>/<codename>-install-<build>.zip
curl -LO https://github.com/ee1os/releases/releases/download/<build>/SHA256SUMS-<build>
shasum -a 256 *-install-*.zip
cat SHA256SUMS-*Compare the hash with the line for the install zip in the checksum file and in the release notes.
Linux
curl -LO https://github.com/ee1os/releases/releases/download/<build>/<codename>-install-<build>.zip
curl -LO https://github.com/ee1os/releases/releases/download/<build>/SHA256SUMS-<build>
sha256sum -c --ignore-missing SHA256SUMS-*It must print OK for the install zip. Also compare with the release notes.
Zips over 2 GB come in parts (GitHub's file limit), for example the Pixel 10a's:
the release then holds <codename>-install-<build>.zip.part1,
.part2 and so on instead of the zip. Download every part, join them in order
and check the joined zip as above (the checksum file lists the parts and the whole zip):
Windows
cmd /c copy /b <codename>-install-<build>.zip.part1+<codename>-install-<build>.zip.part2 <codename>-install-<build>.zipmacOS and Linux
cat <codename>-install-<build>.zip.part1 <codename>-install-<build>.zip.part2 > <codename>-install-<build>.zipVerify the SHA-256 against the release notes and the SHA256SUMS-<build> file.
If they don't match, delete the file and download it again. Don't flash a file that doesn't match.
06Flash the build
Extract the zip and run its flash script, with the phone still in the bootloader and connected:
Windows
tar -xf <codename>-install-<build>.zip
cd <codename>-install-<build>
.\flash-all.batmacOS and Linux
unzip -q <codename>-install-<build>.zip
cd <codename>-install-<build>
sh flash-all.shRun it with sh as shown: the zip doesn't keep the executable bit, so
./flash-all.sh stops with "permission denied".
Before running it, check the key it will flash: the SHA-256 of avb_pkmd.bin
must be 65894abf95040084e7f27ff8cb8e0d291b04abc266103fb88cef5e0c8c8bf161
(Windows: Get-FileHash avb_pkmd.bin; macOS: shasum -a 256 avb_pkmd.bin;
Linux: sha256sum avb_pkmd.bin). If it differs, stop: the zip isn't ours.
It flashes the firmware, restarts into the bootloader, flashes our public key
(avb_pkmd.bin) and then the OS. Don't touch or unplug the phone until it
finishes and the phone is back in the bootloader. It starts with GrapheneOS's banner pointing
to grapheneos.org/install: ignore it, it's left over from the upstream script.
There's no separate step for the key. Don't run fastboot flash avb_custom_key
again afterwards: with the key already in place, the phone answers
FAILED (remote: 'failed to flash partition (avb_custom_key): -1').
If it stops with an error, keep the full output: it's what's needed to help (see error reports).
Linux
If it fails for lack of space in /tmp, run it as
mkdir tmp && TMPDIR="$PWD/tmp" sh flash-all.sh.
07Lock the bootloaderWipes the phone
Locking turns on full verified boot and stops anyone from flashing the phone over USB. Don't skip it: see why an unlocked bootloader is unsafe.
Lock only with our build and our key on the phone, together. If the
avb_custom_key doesn't match the installed build, or the installed build isn't
ours, the phone will refuse to boot once locked. Getting it back means unlocking the
bootloader again (another wipe), which only works while OEM unlocking is still on. If
flashing failed or you aren't sure what is on the phone, flash again before locking.
fastboot flashing lockConfirm on the phone with the volume keys and the power button. This wipes the phone again.
08First boot
With Start selected in the bootloader, press power. From now on the phone shows a yellow notice on every boot: "Your device is loading a different operating system". That is expected for an OS signed with its own key on a locked bootloader. An orange warning instead means the bootloader is still unlocked.
The yellow notice shows the fingerprint of the key the phone boots with. Compare it with ours:
Verified boot key fingerprint (SHA-256 of avb_pkmd.bin)
65894abf 95040084 e7f27ff8 cb8e0d29 1b04abc2 66103fb8 8cef5e0c 8c8bf161
Once the phone has booted and you've checked it, go back to Developer options and turn OEM unlocking off. Leave it on until then.
Setting up
Everyday PIN Protected space PIN Reboot PIN Duress PIN
- Setup offers the protected space right after the screen lock step. You can skip it and set it up later in Settings → Security & privacy → Device unlock → Protected space.
- The everyday profile and the protected space both use PINs, of at least 6 digits.
- All PINs share one length: the length of the everyday PIN you choose at setup. The protected space PIN, the duress PIN and the reboot PIN must have the same number of digits. Changing later to a longer PIN means a factory reset (all data gone) and setting the phone up again, so pick the length you want to keep.
- The protected space PIN must differ from the everyday PIN. The duress and reboot PINs must differ from both. This is checked at setup and for changes made in the protected space. A later change of the everyday PIN isn't checked against the others: if you give it the protected space PIN, that PIN opens the everyday profile from then on.
- The duress and reboot PINs are optional, and are managed only inside the protected space, not from the everyday profile.
- The duress PIN wipes the phone at once, with no question and no undo: every profile, all data, and the keys that would decrypt it. The lock screen may show "wrong PIN" for a moment first. On the next start the phone shows "Cannot load Android system": pick Factory data reset there and set it up again. Try it only on a phone with nothing on it you need. With auto-confirm on, typing it is enough.
- PIN auto-confirm (unlock without pressing enter) is off by default. You can turn it on in the everyday profile's Settings → Screen lock.
- Fingerprint unlock works for the everyday profile only.
- Calls work in the protected space. Text messages arrive in the everyday profile only. Neither has been tried with a SIM yet.
- Android's own private space can't be used beside the protected space. Setup won't create a protected space while a private space exists.
- In the everyday profile the Vanadium browser is labelled "Browser".
- The boot animation shows "ee1os" until the first setup is done, then the plain Android logo.
Updates
- The built-in updater reads the rolling release tagged
updates, which holds<codename>-ota_update-<build>.zipand the channel file<codename>-stable. Updates are signed with the same release key and checked on the phone before installing. - New GrapheneOS releases are tracked automatically: our changes are rebased and rebuilt on each new GrapheneOS stable release. Publishing a release is still done by hand, and each release says which GrapheneOS release it is based on.
About our keys
Builds are signed with our own keys, generated on 2026-10-13. Their certificates use
CN=os.ivan.gg, the project's earlier name; a phone keeps its key. These are not GrapheneOS's keys: official GrapheneOS releases and
updates won't install over our builds, and ours won't install over theirs without a wipe.
A locked phone only boots a build whose key is in avb_custom_key.
The signing keys are kept with an offline backup by the maintainer.
Going back
To leave ee1os, first turn OEM unlocking back on in Developer
options (step 1) while the phone still boots: without it the bootloader can't be unlocked.
Then follow the install guide of the OS you want (for example
GrapheneOS, or Google's
Android Flash Tool for the stock OS) from the unlock
step. That wipes the phone. If you go back to the stock OS, run
fastboot erase avb_custom_key before locking the bootloader.