├── LICENSE ├── build-releases ├── common.sh ├── decrypt-keys ├── encrypt-keys ├── finalize.sh ├── fork ├── generate-delta.sh ├── generate-deltas.sh ├── generate-keys ├── generate-metadata ├── generate-release.sh ├── generate-releases.sh ├── kernel-copy-microdroid ├── kernel-copy-pixel └── manage.sh /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright © 2015-2025 GrapheneOS 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /build-releases: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source build/envsetup.sh 4 | 5 | if [[ $HOSTNAME == raphael ]]; then 6 | readonly devices=(comet tokay shiba lynx bluejay) 7 | elif [[ $HOSTNAME = raptor ]]; then 8 | readonly devices=(komodo akita felix cheetah raven) 9 | elif [[ $HOSTNAME = vermeer ]]; then 10 | readonly devices=(caiman husky tangorpro panther oriole) 11 | else 12 | echo invalid hostname >&2 13 | exit 1 14 | fi 15 | 16 | for device in ${devices[@]}; do 17 | rm -rf out || exit 1 18 | lunch $device-cur-user || exit 1 19 | if [[ $device = @(bluejay|raven|oriole) ]]; then 20 | m vendorbootimage target-files-package otatools-package || exit 1 21 | else 22 | m vendorbootimage vendorkernelbootimage target-files-package otatools-package || exit 1 23 | fi 24 | script/finalize.sh || exit 1 25 | rm -rf out || exit 1 26 | done 27 | -------------------------------------------------------------------------------- /common.sh: -------------------------------------------------------------------------------- 1 | readonly branch=15-qpr2 2 | readonly aosp_tag_old=android-15.0.0_r36 3 | readonly aosp_tag=android-15.0.0_r36 4 | 5 | user_error() { 6 | echo $1 >&2 7 | exit 1 8 | } 9 | 10 | readonly aosp_forks=( 11 | device_common 12 | device_generic_goldfish 13 | device_google_akita 14 | device_google_bluejay 15 | device_google_caimito 16 | device_google_comet 17 | device_google_felix 18 | device_google_gs-common 19 | device_google_gs101 20 | device_google_gs101-sepolicy 21 | device_google_gs201 22 | device_google_gs201-sepolicy 23 | device_google_lynx 24 | device_google_pantah 25 | device_google_raviole 26 | device_google_shusky 27 | device_google_tangorpro 28 | device_google_zuma 29 | device_google_zuma-sepolicy 30 | device_google_zumapro 31 | device_google_zumapro-sepolicy 32 | kernel_configs 33 | platform_art 34 | platform_bionic 35 | platform_bootable_recovery 36 | platform_build 37 | platform_build_release 38 | platform_build_soong 39 | platform_development 40 | platform_external_conscrypt 41 | platform_external_robolectric 42 | platform_external_selinux 43 | platform_frameworks_av 44 | platform_frameworks_base 45 | platform_frameworks_libs_systemui 46 | platform_frameworks_native 47 | platform_frameworks_opt_net_wifi 48 | platform_frameworks_opt_telephony 49 | platform_hardware_google_pixel 50 | platform_hardware_google_pixel-sepolicy 51 | platform_hardware_interfaces 52 | platform_libcore 53 | platform_manifest 54 | platform_packages_apps_Calendar 55 | platform_packages_apps_CellBroadcastReceiver 56 | platform_packages_apps_Contacts 57 | platform_packages_apps_Dialer 58 | platform_packages_apps_DocumentsUI 59 | platform_packages_apps_EmergencyInfo 60 | platform_packages_apps_Gallery2 61 | platform_packages_apps_Launcher3 62 | platform_packages_apps_ManagedProvisioning 63 | platform_packages_apps_Nfc 64 | platform_packages_apps_Settings 65 | platform_packages_apps_SettingsIntelligence 66 | platform_packages_apps_StorageManager 67 | platform_packages_apps_ThemePicker 68 | platform_packages_apps_WallpaperPicker2 69 | platform_packages_inputmethods_LatinIME 70 | platform_packages_modules_adb 71 | platform_packages_modules_AppSearch 72 | platform_packages_modules_Bluetooth 73 | platform_packages_modules_common 74 | platform_packages_modules_ConfigInfrastructure 75 | platform_packages_modules_Connectivity 76 | platform_packages_modules_DnsResolver 77 | platform_packages_modules_HealthFitness 78 | platform_packages_modules_NetworkStack 79 | platform_packages_modules_Permission 80 | platform_packages_modules_RemoteKeyProvisioning 81 | platform_packages_modules_StatsD 82 | platform_packages_modules_Uwb 83 | platform_packages_modules_Virtualization 84 | platform_packages_modules_Wifi 85 | platform_packages_providers_ContactsProvider 86 | platform_packages_providers_DownloadProvider 87 | platform_packages_providers_MediaProvider 88 | platform_packages_services_Mms 89 | platform_packages_services_Telecomm 90 | platform_packages_services_Telephony 91 | platform_system_ca-certificates 92 | platform_system_core 93 | platform_system_extras 94 | platform_system_librustutils 95 | platform_system_logging 96 | platform_system_netd 97 | platform_system_sepolicy 98 | platform_system_vold 99 | platform_tools_metalava 100 | ) 101 | 102 | readonly kernels=( 103 | kernel_build 104 | kernel_devices_google_akita 105 | kernel_devices_google_bluejay 106 | kernel_devices_google_caimito 107 | kernel_devices_google_comet 108 | kernel_devices_google_felix 109 | kernel_devices_google_lynx 110 | kernel_devices_google_pantah 111 | kernel_devices_google_raviole 112 | kernel_devices_google_shusky 113 | kernel_devices_google_tangorpro 114 | kernel_google-modules_amplifiers 115 | kernel_google-modules_bms 116 | kernel_google-modules_edgetpu_rio 117 | kernel_google-modules_gxp_gs201 118 | kernel_google-modules_gxp_zuma 119 | kernel_google-modules_power_reset 120 | kernel_google-modules_soc_gs 121 | kernel_google-modules_wlan_bcmdhd_bcm4383 122 | kernel_google-modules_wlan_bcmdhd_bcm4389 123 | kernel_google-modules_wlan_bcmdhd_bcm4390 124 | kernel_google-modules_wlan_bcmdhd_bcm4398 125 | kernel_google-modules_wlan_syna_dhd43752p 126 | ) 127 | 128 | declare -Ar kernel_tags_old=( 129 | # May 2025 130 | [kernel_build]=android-15.0.0_r0.99 131 | [kernel_devices_google_akita]=android-15.0.0_r0.99 132 | [kernel_devices_google_bluejay]=android-15.0.0_r0.99 133 | [kernel_devices_google_caimito]=android-15.0.0_r0.99 134 | [kernel_devices_google_comet]=android-15.0.0_r0.99 135 | [kernel_devices_google_felix]=android-15.0.0_r0.99 136 | [kernel_devices_google_lynx]=android-15.0.0_r0.99 137 | [kernel_devices_google_pantah]=android-15.0.0_r0.99 138 | [kernel_devices_google_raviole]=android-15.0.0_r0.99 139 | [kernel_devices_google_shusky]=android-15.0.0_r0.99 140 | [kernel_devices_google_tangorpro]=android-15.0.0_r0.99 141 | [kernel_google-modules_amplifiers]=android-15.0.0_r0.99 142 | [kernel_google-modules_bms]=android-15.0.0_r0.99 143 | [kernel_google-modules_edgetpu_rio]=android-15.0.0_r0.99 144 | [kernel_google-modules_gxp_gs201]=android-15.0.0_r0.99 145 | [kernel_google-modules_gxp_zuma]=android-15.0.0_r0.99 146 | [kernel_google-modules_power_reset]=android-15.0.0_r0.99 147 | [kernel_google-modules_soc_gs]=android-15.0.0_r0.99 148 | [kernel_google-modules_wlan_bcmdhd_bcm4383]=android-15.0.0_r0.99 149 | [kernel_google-modules_wlan_bcmdhd_bcm4389]=android-15.0.0_r0.99 150 | [kernel_google-modules_wlan_bcmdhd_bcm4390]=android-15.0.0_r0.99 151 | [kernel_google-modules_wlan_bcmdhd_bcm4398]=android-15.0.0_r0.99 152 | [kernel_google-modules_wlan_syna_dhd43752p]=android-15.0.0_r0.99 153 | ) 154 | 155 | declare -Ar kernel_tags=( 156 | # May 2025 157 | [kernel_build]=android-15.0.0_r0.99 158 | [kernel_devices_google_akita]=android-15.0.0_r0.99 159 | [kernel_devices_google_bluejay]=android-15.0.0_r0.99 160 | [kernel_devices_google_caimito]=android-15.0.0_r0.99 161 | [kernel_devices_google_comet]=android-15.0.0_r0.99 162 | [kernel_devices_google_felix]=android-15.0.0_r0.99 163 | [kernel_devices_google_lynx]=android-15.0.0_r0.99 164 | [kernel_devices_google_pantah]=android-15.0.0_r0.99 165 | [kernel_devices_google_raviole]=android-15.0.0_r0.99 166 | [kernel_devices_google_shusky]=android-15.0.0_r0.99 167 | [kernel_devices_google_tangorpro]=android-15.0.0_r0.99 168 | [kernel_google-modules_amplifiers]=android-15.0.0_r0.99 169 | [kernel_google-modules_bms]=android-15.0.0_r0.99 170 | [kernel_google-modules_edgetpu_rio]=android-15.0.0_r0.99 171 | [kernel_google-modules_gxp_gs201]=android-15.0.0_r0.99 172 | [kernel_google-modules_gxp_zuma]=android-15.0.0_r0.99 173 | [kernel_google-modules_power_reset]=android-15.0.0_r0.99 174 | [kernel_google-modules_soc_gs]=android-15.0.0_r0.99 175 | [kernel_google-modules_wlan_bcmdhd_bcm4383]=android-15.0.0_r0.99 176 | [kernel_google-modules_wlan_bcmdhd_bcm4389]=android-15.0.0_r0.99 177 | [kernel_google-modules_wlan_bcmdhd_bcm4390]=android-15.0.0_r0.99 178 | [kernel_google-modules_wlan_bcmdhd_bcm4398]=android-15.0.0_r0.99 179 | [kernel_google-modules_wlan_syna_dhd43752p]=android-15.0.0_r0.99 180 | ) 181 | 182 | readonly independent=( 183 | adevtool 184 | branding 185 | device_google_akita-kernels_6.1 186 | device_google_bluejay-kernels_6.1 187 | device_google_caimito-kernels_6.1 188 | device_google_comet-kernels_6.1 189 | device_google_felix-kernels_6.1 190 | device_google_lynx-kernels_6.1 191 | device_google_pantah-kernels_6.1 192 | device_google_raviole-kernels_6.1 193 | device_google_shusky-kernels_6.1 194 | device_google_tangorpro-kernels_6.1 195 | hardened_malloc 196 | kernel_common-6.1 197 | kernel_common-6.6 198 | kernel_manifest-6.1 199 | kernel_manifest-6.6 200 | kernel_manifest-pixel 201 | platform_external_AppCompatConfig 202 | platform_external_AppStore 203 | platform_external_Auditor 204 | platform_external_Camera 205 | platform_external_GmsCompatConfig 206 | platform_external_Info 207 | platform_external_Messaging 208 | platform_external_PdfViewer 209 | platform_external_talkback 210 | platform_external_vanadium 211 | platform_packages_apps_AppCompatConfig 212 | platform_packages_apps_CarrierConfig2 213 | platform_packages_apps_DeskClock # temporarily based on AOSP 11 instead of AOSP 13 214 | platform_packages_apps_ExactCalculator 215 | platform_packages_apps_GmsCompat 216 | platform_packages_apps_LogViewer 217 | platform_packages_apps_NetworkLocation 218 | platform_packages_apps_Seedvault 219 | platform_packages_apps_SetupWizard2 220 | platform_packages_apps_Updater 221 | script 222 | vendor_state 223 | ) 224 | -------------------------------------------------------------------------------- /decrypt-keys: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -o errexit -o nounset -o pipefail 4 | 5 | source "$(dirname ${BASH_SOURCE[0]})/common.sh" 6 | 7 | [[ $# -ne 1 ]] && user_error "expected 1 argument (key directory)" 8 | 9 | cd $1 10 | 11 | [[ "${password+defined}" = defined ]] || read -rp "Enter key passphrase (empty if none): " -s password 12 | echo 13 | 14 | tmp="$(mktemp -d /dev/shm/decrypt-keys.XXXXXXXXXX)" 15 | trap "rm -rf \"$tmp\"" EXIT 16 | 17 | export password 18 | 19 | for key in releasekey platform shared media networkstack bluetooth sdk_sandbox; do 20 | if [[ -n $password ]]; then 21 | openssl pkcs8 -inform DER -in $key.pk8 -passin env:password | openssl pkcs8 -topk8 -outform DER -out "$tmp/$key.pk8" -nocrypt 22 | else 23 | openssl pkcs8 -topk8 -inform DER -in $key.pk8 -outform DER -out "$tmp/$key.pk8" -nocrypt 24 | fi 25 | done 26 | 27 | if [[ -f avb.pem ]]; then 28 | if [[ -n $password ]]; then 29 | openssl pkcs8 -topk8 -in avb.pem -passin env:password -out "$tmp/avb.pem" -nocrypt 30 | else 31 | openssl pkcs8 -topk8 -in avb.pem -out "$tmp/avb.pem" -nocrypt 32 | fi 33 | fi 34 | 35 | unset password 36 | 37 | mv "$tmp"/* . 38 | -------------------------------------------------------------------------------- /encrypt-keys: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -o errexit -o nounset -o pipefail 4 | 5 | source "$(dirname ${BASH_SOURCE[0]})/common.sh" 6 | 7 | [[ $# -ne 1 ]] && user_error "expected 1 argument (key directory)" 8 | 9 | cd $1 10 | 11 | read -rp "Enter old key passphrase (empty if none): " -s password 12 | echo 13 | 14 | read -rp "Enter new key passphrase: " -s new_password 15 | echo 16 | read -rp "Confirm new key passphrase: " -s confirm_new_password 17 | echo 18 | 19 | if [[ "$new_password" != "$confirm_new_password" ]]; then 20 | echo new password does not match 21 | exit 1 22 | fi 23 | 24 | tmp="$(mktemp -d /dev/shm/encrypt-keys.XXXXXXXXXX)" 25 | trap "rm -rf \"$tmp\"" EXIT 26 | 27 | export password 28 | export new_password 29 | 30 | for key in releasekey platform shared media networkstack bluetooth sdk_sandbox; do 31 | if [[ -n $password ]]; then 32 | openssl pkcs8 -inform DER -in $key.pk8 -passin env:password | openssl pkcs8 -topk8 -outform DER -out "$tmp/$key.pk8" -passout env:new_password -scrypt 33 | else 34 | openssl pkcs8 -topk8 -inform DER -in $key.pk8 -outform DER -out "$tmp/$key.pk8" -passout env:new_password -scrypt 35 | fi 36 | done 37 | 38 | if [[ -f avb.pem ]]; then 39 | if [[ -n $password ]]; then 40 | openssl pkcs8 -topk8 -in avb.pem -passin env:password -out "$tmp/avb.pem" -passout env:new_password -scrypt 41 | else 42 | openssl pkcs8 -topk8 -in avb.pem -out "$tmp/avb.pem" -passout env:new_password -scrypt 43 | fi 44 | fi 45 | 46 | unset password 47 | unset new_password 48 | 49 | mv "$tmp"/* . 50 | -------------------------------------------------------------------------------- /finalize.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -o errexit -o nounset -o pipefail 4 | 5 | source "$(dirname ${BASH_SOURCE[0]})/common.sh" 6 | 7 | [[ $# -eq 0 ]] || user_error "expected no arguments" 8 | [[ -n $TARGET_PRODUCT ]] || user_error "expected TARGET_PRODUCT in the environment" 9 | [[ -n $BUILD_NUMBER ]] || user_error "expected BUILD_NUMBER in the environment" 10 | [[ -n $OUT ]] || user_error "expected OUT in the environment" 11 | 12 | readonly releases=releases/$BUILD_NUMBER 13 | mkdir -p $releases 14 | cp "$OUT/otatools.zip" "$releases/$TARGET_PRODUCT-otatools.zip" 15 | cp "$OUT/obj/PACKAGING/target_files_intermediates/$TARGET_PRODUCT-target_files.zip" "$releases/" 16 | -------------------------------------------------------------------------------- /fork: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -o errexit -o nounset -o pipefail 4 | 5 | source "$(dirname ${BASH_SOURCE[0]})/common.sh" 6 | 7 | if [[ $# -ne 1 ]]; then 8 | user_error "expected 1 argument" 9 | fi 10 | 11 | repo=${1%/} 12 | local_repo=${repo//\//_} 13 | 14 | upstream="https://android.googlesource.com/$repo" 15 | 16 | git clone $upstream -b $aosp_tag 17 | mv $(basename $repo) $local_repo 18 | cd $local_repo 19 | git checkout -b $branch 20 | git remote add upstream $upstream 21 | git fetch upstream --tags 22 | git remote rm origin 23 | gh repo create --public --push --source . GrapheneOS/$local_repo -h https://grapheneos.org/ --disable-issues --disable-wiki 24 | gh repo edit --enable-projects=false --enable-merge-commit=false 25 | gh repo view --web 26 | -------------------------------------------------------------------------------- /generate-delta.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -o errexit -o nounset -o pipefail 4 | 5 | source "$(dirname ${BASH_SOURCE[0]})/common.sh" 6 | 7 | [[ $# -eq 3 ]] || user_error "expected 3 arguments (device, source and target version)" 8 | 9 | chrt -b -p 0 $$ 10 | 11 | PERSISTENT_KEY_DIR=keys/$1 12 | DEVICE=$1 13 | OLD=$2 14 | NEW=$3 15 | 16 | # decrypt keys in advance for improved performance and modern algorithm support 17 | KEY_DIR=$(mktemp -d /dev/shm/generate-delta.XXXXXXXXXX) 18 | trap "rm -rf \"$KEY_DIR\"" EXIT 19 | cp "$PERSISTENT_KEY_DIR"/* "$KEY_DIR" 20 | script/decrypt-keys "$KEY_DIR" 21 | 22 | export PATH="$PWD/prebuilts/build-tools/linux-x86/bin:$PATH" 23 | export PATH="$PWD/prebuilts/build-tools/path/linux-x86:$PATH" 24 | export PATH="$PWD/releases/$NEW/release-$DEVICE-$NEW/bin:$PATH" 25 | 26 | cd "releases/$NEW" 27 | 28 | ota_from_target_files "${EXTRA_OTA[@]}" -k "$KEY_DIR/releasekey" \ 29 | -i ../$OLD/release-$DEVICE-$OLD/$DEVICE-target_files.zip \ 30 | release-$DEVICE-$NEW/$DEVICE-target_files.zip \ 31 | $DEVICE-incremental-$OLD-$NEW.zip 32 | -------------------------------------------------------------------------------- /generate-deltas.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -o errexit -o nounset -o pipefail 4 | 5 | source "$(dirname ${BASH_SOURCE[0]})/common.sh" 6 | 7 | [[ $# -ge 2 ]] || user_error "expected 2 or more arguments (target and source versions)" 8 | 9 | read -rp "Enter key passphrase (empty if none): " -s password 10 | echo 11 | export password 12 | 13 | chrt -b -p 0 $$ 14 | 15 | SOURCE=$1 16 | shift 17 | 18 | export TMPDIR="${OUT:-$PWD/delta-generation}" 19 | 20 | parallel -j4 -q script/generate-delta.sh ::: comet komodo caiman tokay akita husky shiba felix tangorpro lynx cheetah panther bluejay raven oriole ::: $@ ::: $SOURCE 21 | -------------------------------------------------------------------------------- /generate-keys: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | devices=() 4 | 5 | for device in ${devices[@]}; do 6 | mkdir -p keys/$device 7 | cd keys/$device 8 | CN=GrapheneOS 9 | ../../development/tools/make_key releasekey "/CN=$CN/" 10 | ../../development/tools/make_key platform "/CN=$CN/" 11 | ../../development/tools/make_key shared "/CN=$CN/" 12 | ../../development/tools/make_key media "/CN=$CN/" 13 | ../../development/tools/make_key networkstack "/CN=$CN/" 14 | ../../development/tools/make_key sdk_sandbox "/CN=$CN/" 15 | ../../development/tools/make_key bluetooth "/CN=$CN/" 16 | openssl genrsa 4096 | openssl pkcs8 -topk8 -scrypt -out avb.pem 17 | ../../external/avb/avbtool.py extract_public_key --key avb.pem --output avb_pkmd.bin 18 | cd ../.. 19 | done 20 | -------------------------------------------------------------------------------- /generate-metadata: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from argparse import ArgumentParser 4 | from os import path 5 | from zipfile import ZipFile 6 | 7 | parser = ArgumentParser(description="Generate update server metadata") 8 | parser.add_argument("zip") 9 | 10 | zip_path = parser.parse_args().zip 11 | 12 | with ZipFile(zip_path) as f: 13 | with f.open("META-INF/com/android/metadata") as metadata: 14 | data = dict(line[:-1].decode().split("=") for line in metadata) 15 | for channel in ("beta", "stable", "alpha", "testing"): 16 | with open(path.join(path.dirname(zip_path), data["pre-device"] + "-" + channel), "w") as output: 17 | incremental = data["post-build"].split("/")[4].split(":")[0] 18 | print(incremental, data["post-timestamp"], data["pre-device"], channel, file=output) 19 | -------------------------------------------------------------------------------- /generate-release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -o errexit -o pipefail 4 | 5 | source "$(dirname ${BASH_SOURCE[0]})/common.sh" 6 | 7 | [[ $# -eq 2 ]] || user_error "expected two arguments: DEVICE BUILD_NUMBER" 8 | 9 | chrt -b -p 0 $$ 10 | 11 | DEVICE=$1 12 | BUILD_NUMBER=$2 13 | 14 | PERSISTENT_KEY_DIR=keys/$DEVICE 15 | RELEASE_OUT=releases/$BUILD_NUMBER/release-$DEVICE-$BUILD_NUMBER 16 | 17 | # decrypt keys in advance for improved performance and modern algorithm support 18 | KEY_DIR=$(mktemp -d /dev/shm/generate-release.XXXXXXXXXX) 19 | trap "rm -rf \"$KEY_DIR\" && rm -f \"$PWD/$RELEASE_OUT/keys\"" EXIT 20 | cp "$PERSISTENT_KEY_DIR"/* "$KEY_DIR" 21 | script/decrypt-keys "$KEY_DIR" 22 | 23 | OLD_PATH="$PATH" 24 | export PATH="$PWD/prebuilts/build-tools/linux-x86/bin:$PATH" 25 | export PATH="$PWD/prebuilts/build-tools/path/linux-x86:$PATH" 26 | 27 | TARGET_FILES=$DEVICE-target_files.zip 28 | TARGET_FILES_INPUT=$PWD/releases/$BUILD_NUMBER/$TARGET_FILES 29 | 30 | rm -rf $RELEASE_OUT 31 | mkdir -p $RELEASE_OUT 32 | unzip releases/$BUILD_NUMBER/$DEVICE-otatools.zip -d $RELEASE_OUT 33 | cd $RELEASE_OUT 34 | # remove duplicate Android.bp from unpacked otatools, otherwise they get 35 | # detected by soong, which breaks subsequent builds 36 | find -name Android.bp -delete 37 | 38 | # reproducible key path for otacerts.zip 39 | ln -s "$KEY_DIR" keys 40 | KEY_DIR=keys 41 | 42 | export PATH="$PWD/bin:$PATH" 43 | 44 | source device/common/clear-factory-images-variables.sh 45 | 46 | BUILD=$BUILD_NUMBER 47 | VERSION=$BUILD_NUMBER 48 | DEVICE=$1 49 | PRODUCT=$DEVICE 50 | 51 | get_radio_image() { 52 | grep "require version-$1" OTA/android-info.txt | cut -d '=' -f 2 | tr '[:upper:]' '[:lower:]' 53 | } 54 | 55 | unzip $TARGET_FILES_INPUT OTA/android-info.txt 56 | 57 | if [[ $DEVICE == @(tegu|comet|komodo|caiman|tokay|akita|husky|shiba|felix|tangorpro|lynx|cheetah|panther|bluejay|raven|oriole) ]]; then 58 | BOOTLOADER=$(get_radio_image bootloader) 59 | [[ $DEVICE != tangorpro ]] && RADIO=$(get_radio_image baseband) 60 | DISABLE_UART=true 61 | DISABLE_FIPS=true 62 | DISABLE_DPM=true 63 | else 64 | user_error "$DEVICE is not supported by the release script" 65 | fi 66 | 67 | AVB_PKMD="$KEY_DIR/avb_pkmd.bin" 68 | AVB_ALGORITHM=SHA256_RSA4096 69 | 70 | sign_target_files_apks -o -d "$KEY_DIR" --avb_vbmeta_key "$KEY_DIR/avb.pem" --avb_vbmeta_algorithm $AVB_ALGORITHM \ 71 | --extra_apks AdServicesApk.apk="$KEY_DIR/releasekey" \ 72 | --extra_apks Bluetooth.apk="$KEY_DIR/bluetooth" \ 73 | --extra_apks HalfSheetUX.apk="$KEY_DIR/releasekey" \ 74 | --extra_apks OsuLogin.apk="$KEY_DIR/releasekey" \ 75 | --extra_apks PdfViewer.apk="$KEY_DIR/releasekey" \ 76 | --extra_apks SafetyCenterResources.apk="$KEY_DIR/releasekey" \ 77 | --extra_apks ServiceConnectivityResources.apk="$KEY_DIR/releasekey" \ 78 | --extra_apks ServiceUwbResources.apk="$KEY_DIR/releasekey" \ 79 | --extra_apks ServiceWifiResources.apk="$KEY_DIR/releasekey" \ 80 | --extra_apks WifiDialog.apk="$KEY_DIR/releasekey" \ 81 | --extra_apks com.android.adbd.apex="$KEY_DIR/releasekey" \ 82 | --extra_apex_payload_key com.android.adbd.apex="$KEY_DIR/avb.pem" \ 83 | --extra_apks com.android.adservices.apex="$KEY_DIR/releasekey" \ 84 | --extra_apex_payload_key com.android.adservices.apex="$KEY_DIR/avb.pem" \ 85 | --extra_apks com.android.apex.cts.shim.apex="$KEY_DIR/releasekey" \ 86 | --extra_apex_payload_key com.android.apex.cts.shim.apex="$KEY_DIR/avb.pem" \ 87 | --extra_apks com.android.appsearch.apex="$KEY_DIR/releasekey" \ 88 | --extra_apex_payload_key com.android.appsearch.apex="$KEY_DIR/avb.pem" \ 89 | --extra_apks com.android.art.apex="$KEY_DIR/releasekey" \ 90 | --extra_apex_payload_key com.android.art.apex="$KEY_DIR/avb.pem" \ 91 | --extra_apks com.android.art.debug.apex="$KEY_DIR/releasekey" \ 92 | --extra_apex_payload_key com.android.art.debug.apex="$KEY_DIR/avb.pem" \ 93 | --extra_apks com.android.btservices.apex="$KEY_DIR/bluetooth" \ 94 | --extra_apex_payload_key com.android.btservices.apex="$KEY_DIR/avb.pem" \ 95 | --extra_apks com.android.cellbroadcast.apex="$KEY_DIR/releasekey" \ 96 | --extra_apex_payload_key com.android.cellbroadcast.apex="$KEY_DIR/avb.pem" \ 97 | --extra_apks com.android.compos.apex="$KEY_DIR/releasekey" \ 98 | --extra_apex_payload_key com.android.compos.apex="$KEY_DIR/avb.pem" \ 99 | --extra_apks com.android.configinfrastructure.apex="$KEY_DIR/releasekey" \ 100 | --extra_apex_payload_key com.android.configinfrastructure.apex="$KEY_DIR/avb.pem" \ 101 | --extra_apks com.android.conscrypt.apex="$KEY_DIR/releasekey" \ 102 | --extra_apex_payload_key com.android.conscrypt.apex="$KEY_DIR/avb.pem" \ 103 | --extra_apks com.android.devicelock.apex="$KEY_DIR/releasekey" \ 104 | --extra_apex_payload_key com.android.devicelock.apex="$KEY_DIR/avb.pem" \ 105 | --extra_apks com.android.extservices.apex="$KEY_DIR/releasekey" \ 106 | --extra_apex_payload_key com.android.extservices.apex="$KEY_DIR/avb.pem" \ 107 | --extra_apks com.android.hardware.biometrics.face.virtual.apex="$KEY_DIR/releasekey" \ 108 | --extra_apex_payload_key com.android.hardware.biometrics.face.virtual.apex="$KEY_DIR/avb.pem" \ 109 | --extra_apks com.android.hardware.biometrics.fingerprint.virtual.apex="$KEY_DIR/releasekey" \ 110 | --extra_apex_payload_key com.android.hardware.biometrics.fingerprint.virtual.apex="$KEY_DIR/avb.pem" \ 111 | --extra_apks com.android.hardware.cas.apex="$KEY_DIR/releasekey" \ 112 | --extra_apex_payload_key com.android.hardware.cas.apex="$KEY_DIR/avb.pem" \ 113 | --extra_apks com.android.healthfitness.apex="$KEY_DIR/releasekey" \ 114 | --extra_apex_payload_key com.android.healthfitness.apex="$KEY_DIR/avb.pem" \ 115 | --extra_apks com.android.i18n.apex="$KEY_DIR/releasekey" \ 116 | --extra_apex_payload_key com.android.i18n.apex="$KEY_DIR/avb.pem" \ 117 | --extra_apks com.android.ipsec.apex="$KEY_DIR/releasekey" \ 118 | --extra_apex_payload_key com.android.ipsec.apex="$KEY_DIR/avb.pem" \ 119 | --extra_apks com.android.media.apex="$KEY_DIR/releasekey" \ 120 | --extra_apex_payload_key com.android.media.apex="$KEY_DIR/avb.pem" \ 121 | --extra_apks com.android.media.swcodec.apex="$KEY_DIR/releasekey" \ 122 | --extra_apex_payload_key com.android.media.swcodec.apex="$KEY_DIR/avb.pem" \ 123 | --extra_apks com.android.mediaprovider.apex="$KEY_DIR/releasekey" \ 124 | --extra_apex_payload_key com.android.mediaprovider.apex="$KEY_DIR/avb.pem" \ 125 | --extra_apks com.android.neuralnetworks.apex="$KEY_DIR/releasekey" \ 126 | --extra_apex_payload_key com.android.neuralnetworks.apex="$KEY_DIR/avb.pem" \ 127 | --extra_apks com.android.nfcservices.apex="$KEY_DIR/releasekey" \ 128 | --extra_apex_payload_key com.android.nfcservices.apex="$KEY_DIR/avb.pem" \ 129 | --extra_apks com.android.ondevicepersonalization.apex="$KEY_DIR/releasekey" \ 130 | --extra_apex_payload_key com.android.ondevicepersonalization.apex="$KEY_DIR/avb.pem" \ 131 | --extra_apks com.android.os.statsd.apex="$KEY_DIR/releasekey" \ 132 | --extra_apex_payload_key com.android.os.statsd.apex="$KEY_DIR/avb.pem" \ 133 | --extra_apks com.android.permission.apex="$KEY_DIR/releasekey" \ 134 | --extra_apex_payload_key com.android.permission.apex="$KEY_DIR/avb.pem" \ 135 | --extra_apks com.android.profiling.apex="$KEY_DIR/releasekey" \ 136 | --extra_apex_payload_key com.android.profiling.apex="$KEY_DIR/avb.pem" \ 137 | --extra_apks com.android.resolv.apex="$KEY_DIR/releasekey" \ 138 | --extra_apex_payload_key com.android.resolv.apex="$KEY_DIR/avb.pem" \ 139 | --extra_apks com.android.rkpd.apex="$KEY_DIR/releasekey" \ 140 | --extra_apex_payload_key com.android.rkpd.apex="$KEY_DIR/avb.pem" \ 141 | --extra_apks com.android.runtime.apex="$KEY_DIR/releasekey" \ 142 | --extra_apex_payload_key com.android.runtime.apex="$KEY_DIR/avb.pem" \ 143 | --extra_apks com.android.scheduling.apex="$KEY_DIR/releasekey" \ 144 | --extra_apex_payload_key com.android.scheduling.apex="$KEY_DIR/avb.pem" \ 145 | --extra_apks com.android.sdkext.apex="$KEY_DIR/releasekey" \ 146 | --extra_apex_payload_key com.android.sdkext.apex="$KEY_DIR/avb.pem" \ 147 | --extra_apks com.android.tethering.apex="$KEY_DIR/releasekey" \ 148 | --extra_apex_payload_key com.android.tethering.apex="$KEY_DIR/avb.pem" \ 149 | --extra_apks com.android.tzdata.apex="$KEY_DIR/releasekey" \ 150 | --extra_apex_payload_key com.android.tzdata.apex="$KEY_DIR/avb.pem" \ 151 | --extra_apks com.android.uwb.apex="$KEY_DIR/releasekey" \ 152 | --extra_apex_payload_key com.android.uwb.apex="$KEY_DIR/avb.pem" \ 153 | --extra_apks com.android.virt.apex="$KEY_DIR/releasekey" \ 154 | --extra_apex_payload_key com.android.virt.apex="$KEY_DIR/avb.pem" \ 155 | --extra_apks com.android.vndk.current.apex="$KEY_DIR/releasekey" \ 156 | --extra_apex_payload_key com.android.vndk.current.apex="$KEY_DIR/avb.pem" \ 157 | --extra_apks com.android.vndk.current.on_vendor.apex="$KEY_DIR/releasekey" \ 158 | --extra_apex_payload_key com.android.vndk.current.on_vendor.apex="$KEY_DIR/avb.pem" \ 159 | --extra_apks com.android.wifi.apex="$KEY_DIR/releasekey" \ 160 | --extra_apex_payload_key com.android.wifi.apex="$KEY_DIR/avb.pem" \ 161 | --extra_apks com.google.pixel.camera.hal.apex="$KEY_DIR/releasekey" \ 162 | --extra_apex_payload_key com.google.pixel.camera.hal.apex="$KEY_DIR/avb.pem" \ 163 | $TARGET_FILES_INPUT $TARGET_FILES 164 | 165 | ota_from_target_files -k "$KEY_DIR/releasekey" "${EXTRA_OTA[@]}" $TARGET_FILES \ 166 | $DEVICE-ota_update-$BUILD_NUMBER.zip 167 | script/generate-metadata $DEVICE-ota_update-$BUILD_NUMBER.zip 168 | 169 | img_from_target_files $TARGET_FILES $DEVICE-img-$BUILD_NUMBER.zip 170 | 171 | source device/common/generate-factory-images-common.sh 172 | 173 | MAX_DOWNLOAD_SIZE=0xf900000 174 | 175 | # Second arg to optimize-factory-image is the name of outer zip directory. 176 | # Output zip name defaults to .zip 177 | fastboot -S $MAX_DOWNLOAD_SIZE optimize-factory-image $DEVICE-factory-$BUILD_NUMBER.zip $DEVICE-install-$BUILD_NUMBER 178 | 179 | if [[ -f "$KEY_DIR/id_ed25519" ]]; then 180 | export PATH="$OLD_PATH" 181 | ssh-keygen -Y sign -n "factory images" -f "$KEY_DIR/id_ed25519" $DEVICE-install-$BUILD_NUMBER.zip 182 | fi 183 | -------------------------------------------------------------------------------- /generate-releases.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -o errexit -o nounset -o pipefail 4 | 5 | source "$(dirname ${BASH_SOURCE[0]})/common.sh" 6 | 7 | [[ $# -eq 1 ]] || user_error "expected 1 argument: BUILD_NUMBER" 8 | 9 | read -rp "Enter key passphrase (empty if none): " -s password 10 | echo 11 | export password 12 | 13 | chrt -b -p 0 $$ 14 | 15 | export TMPDIR="${OUT:-$PWD/delta-generation}" 16 | 17 | parallel -j4 -q script/generate-release.sh ::: comet komodo caiman tokay akita husky shiba felix tangorpro lynx cheetah panther bluejay raven oriole ::: $1 18 | -------------------------------------------------------------------------------- /kernel-copy-microdroid: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -o errexit -o nounset -o pipefail 4 | 5 | devices=(microdroid-arm64 microdroid-x86_64) 6 | parallel 'rm -rf {} && cp -a 6.6 {}' ::: ${devices[@]} 7 | -------------------------------------------------------------------------------- /kernel-copy-pixel: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -o errexit -o nounset -o pipefail 4 | 5 | devices=(raviole bluejay pantah lynx tangorpro felix shusky akita caimito comet) 6 | parallel 'rm -rf {} && cp -a pixel {}' ::: ${devices[@]} 7 | -------------------------------------------------------------------------------- /manage.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -o errexit -o nounset -o pipefail 4 | 5 | source "$(dirname ${BASH_SOURCE[0]})/common.sh" 6 | 7 | [[ $# -eq 0 ]] && user_error "expected action as argument" 8 | readonly action=$1 9 | 10 | if [[ $action == @(push|fetch|update|default) ]]; then 11 | [[ $# -ne 1 ]] && user_error "expected no arguments for $action" 12 | elif [[ $action == @(release|delete) ]]; then 13 | readonly tag_name=$2 14 | [[ $# -ne 2 ]] && user_error "expected tag name as argument for $action" 15 | else 16 | user_error "unrecognized action" 17 | fi 18 | 19 | if [[ $OFFICIAL_BUILD = true ]]; then 20 | export GIT_AUTHOR_NAME=GrapheneOS 21 | export GIT_AUTHOR_EMAIL=contact@grapheneos.org 22 | export GIT_COMMITTER_NAME=$GIT_AUTHOR_NAME 23 | export GIT_COMMITTER_EMAIL=$GIT_AUTHOR_EMAIL 24 | fi 25 | 26 | for repo in "${aosp_forks[@]}"; do 27 | echo -e "\n>>> $(tput setaf 3)Handling $repo$(tput sgr0)" 28 | 29 | cd $repo 30 | git checkout $branch 31 | 32 | if [[ $action == delete ]]; then 33 | git tag -d $tag_name || true 34 | git push origin --delete $tag_name || true 35 | elif [[ $action == release ]]; then 36 | if [[ $repo == platform_manifest ]]; then 37 | git checkout -B tmp 38 | sed -i s%refs/heads/$branch%refs/tags/$tag_name% default.xml 39 | git commit default.xml -m $tag_name 40 | git push -fu origin tmp 41 | else 42 | git tag -s $tag_name -m $tag_name 43 | git push origin $tag_name 44 | fi 45 | elif [[ $action == update ]]; then 46 | git fetch upstream --tags 47 | git rebase --onto $aosp_tag $aosp_tag_old 48 | git push -f 49 | elif [[ $action == push ]]; then 50 | git push 51 | elif [[ $action == fetch ]]; then 52 | git fetch upstream --tags 53 | elif [[ $action == default ]]; then 54 | if [[ $repo != platform_packages_modules_Connectivity ]]; then 55 | gh repo edit GrapheneOS/$repo --default-branch $branch 56 | fi 57 | fi 58 | 59 | cd .. 60 | done 61 | 62 | for repo in ${kernels[@]}; do 63 | echo -e "\n>>> $(tput setaf 3)Handling $repo$(tput sgr0)" 64 | 65 | cd $repo 66 | git checkout $branch 67 | 68 | if [[ $action == delete ]]; then 69 | git tag -d $tag_name || true 70 | git push origin --delete $tag_name || true 71 | elif [[ $action == release ]]; then 72 | git tag -s $tag_name -m $tag_name 73 | git push origin $tag_name 74 | elif [[ $action == update ]]; then 75 | git fetch upstream --tags 76 | git rebase --onto ${kernel_tags[$repo]} ${kernel_tags_old[$repo]} 77 | git push -f 78 | elif [[ $action == push ]]; then 79 | git push 80 | elif [[ $action == fetch ]]; then 81 | git fetch upstream --tags 82 | elif [[ $action == default ]]; then 83 | gh repo edit GrapheneOS/$repo --default-branch $branch 84 | fi 85 | 86 | cd .. 87 | done 88 | 89 | for repo in ${independent[@]}; do 90 | echo -e "\n>>> $(tput setaf 3)Handling $repo$(tput sgr0)" 91 | 92 | cd $repo 93 | git checkout $branch 94 | 95 | if [[ $action == delete ]]; then 96 | git tag -d $tag_name || true 97 | git push origin --delete $tag_name || true 98 | elif [[ $action == release ]]; then 99 | if [[ $repo == @(kernel_manifest-pixel|kernel_manifest-6.1|kernel_manifest-6.6) ]]; then 100 | git checkout -B tmp 101 | sed -i s%refs/heads/$branch%refs/tags/$tag_name% default.xml 102 | git commit default.xml -m $tag_name 103 | git push -fu origin tmp 104 | else 105 | git tag -s $tag_name -m $tag_name 106 | git push origin $tag_name 107 | fi 108 | elif [[ $action == push ]]; then 109 | git push 110 | elif [[ $action == default ]]; then 111 | if [[ $repo != platform_external_vanadium ]]; then 112 | gh repo edit GrapheneOS/$repo --default-branch $branch 113 | fi 114 | fi 115 | 116 | cd .. 117 | done 118 | --------------------------------------------------------------------------------