1#!/usr/bin/env bash 2# SPDX-License-Identifier: GPL-2.0 3 4# A handy tool to launch CVD with local build or remote build. 5 6# Constants 7ACLOUD_PREBUILT="prebuilts/asuite/acloud/linux-x86/acloud" 8OPT_SKIP_PRERUNCHECK='--skip-pre-run-check' 9PRODUCT='aosp_cf_x86_64_phone' 10# Color constants 11#BOLD="$(tput bold)" # Unused 12END="$(tput sgr0)" 13GREEN="$(tput setaf 2)" 14RED="$(tput setaf 198)" 15YELLOW="$(tput setaf 3)" 16# BLUE="$(tput setaf 34)" # Unused 17 18SKIP_BUILD=false 19GCOV=false 20DEBUG=false 21KASAN=false 22EXTRA_OPTIONS=() 23 24function print_help() { 25 echo "Usage: $0 [OPTIONS]" 26 echo "" 27 echo "This script will build images and launch a Cuttlefish device." 28 echo "" 29 echo "Available options:" 30 echo " --skip-build Skip the image build step. Will build by default if in repo." 31 echo " --gcov Launch CVD with gcov enabled kernel" 32 echo " --debug Launch CVD with debug enabled kernel" 33 echo " --kasan Launch CVD with kasan enabled kernel" 34 echo " -pb <platform_build>, --platform-build=<platform_build>" 35 echo " The platform build path. Can be a local path or a remote build" 36 echo " as ab://<branch>/<build_target>/<build_id>." 37 echo " If not specified, it will use the platform build in the local" 38 echo " repo, or the default compatible platform build for the kernel." 39 echo " -sb <system_build>, --system-build=<system_build>" 40 echo " The system build path for GSI testing. Can be a local path or" 41 echo " remote build as ab://<branch>/<build_target>/<build_id>." 42 echo " If not specified, no system build will be used." 43 echo " -kb <kernel_build>, --kernel-build=<kernel_build>" 44 echo " The kernel build path. Can be a local path or a remote build" 45 echo " as ab://<branch>/<build_target>/<build_id>." 46 echo " If not specified, it will use the kernel in the local repo." 47 echo " --acloud-bin=<acloud_bin>" 48 echo " The alternative alcoud binary path." 49 echo " --cf-product=<product_type>" 50 echo " The alternative cuttlefish product type for local build." 51 echo " Will use default aosp_cf_x86_64_phone if not specified." 52 echo " --acloud-arg=<acloud_arg>" 53 echo " Additional acloud command arg. Can be repeated." 54 echo " For example --acloud-arg=--local-instance to launch a local cvd." 55 echo " -h, --help Display this help message and exit" 56 echo "" 57 echo "Examples:" 58 echo "$0" 59 echo "$0 --acloud-arg=--local-instance" 60 echo "$0 -pb ab://git_main/aosp_cf_x86_64_phone-userdebug/latest" 61 echo "$0 -pb ~/aosp-main/out/target/product/vsoc_x86_64/" 62 echo "$0 -kb ~/android-mainline/out/virtual_device_x86_64/" 63 echo "" 64 exit 0 65} 66 67function parse_arg() { 68 while test $# -gt 0; do 69 case "$1" in 70 -h|--help) 71 print_help 72 ;; 73 --skip-build) 74 SKIP_BUILD=true 75 shift 76 ;; 77 -pb) 78 shift 79 if test $# -gt 0; then 80 PLATFORM_BUILD=$1 81 else 82 print_error "platform build is not specified" 83 fi 84 shift 85 ;; 86 --platform-build=*) 87 PLATFORM_BUILD=$(echo "$1" | sed -e "s/^[^=]*=//g") 88 shift 89 ;; 90 -sb) 91 shift 92 if test $# -gt 0; then 93 SYSTEM_BUILD=$1 94 else 95 print_error "system build is not specified" 96 fi 97 shift 98 ;; 99 --system-build=*) 100 SYSTEM_BUILD=$(echo "$1" | sed -e "s/^[^=]*=//g") 101 shift 102 ;; 103 -kb) 104 shift 105 if test $# -gt 0; then 106 KERNEL_BUILD=$1 107 else 108 print_error "kernel build path is not specified" 109 fi 110 shift 111 ;; 112 --kernel-build=*) 113 KERNEL_BUILD=$(echo "$1" | sed -e "s/^[^=]*=//g") 114 shift 115 ;; 116 --acloud-arg=*) 117 EXTRA_OPTIONS+=("$(echo "$1" | sed -e "s/^[^=]*=//g")") # Use array append syntax 118 shift 119 ;; 120 --acloud-bin=*) 121 ACLOUD_BIN=$(echo "$1" | sed -e "s/^[^=]*=//g") 122 shift 123 ;; 124 --cf-product=*) 125 PRODUCT=$(echo "$1" | sed -e "s/^[^=]*=//g") 126 shift 127 ;; 128 --gcov) 129 GCOV=true 130 shift 131 ;; 132 --debug) 133 DEBUG=true 134 shift 135 ;; 136 --kasan) 137 KASAN=true 138 shift 139 ;; 140 *) 141 print_error "Unsupported flag: $1" >&2 142 ;; 143 esac 144 done 145} 146 147function adb_checker() { 148 if ! which adb &> /dev/null; then 149 print_error "adb not found!" 150 fi 151} 152 153function go_to_repo_root() { 154 current_dir="$1" 155 while [ ! -d ".repo" ] && [ "$current_dir" != "/" ]; do 156 current_dir=$(dirname "$current_dir") # Go up one directory 157 cd "$current_dir" || print_error "Failed to cd to $current_dir" 158 done 159} 160 161function print_info() { 162 echo "[$MY_NAME]: ${GREEN}$1${END}" 163} 164 165function print_warn() { 166 echo "[$MY_NAME]: ${YELLOW}$1${END}" 167} 168 169function print_error() { 170 echo -e "[$MY_NAME]: ${RED}$1${END}" 171 cd "$OLD_PWD" || echo "Failed to cd to $OLD_PWD" 172 exit 1 173} 174 175function set_platform_repo () { 176 print_warn "Build target product '${TARGET_PRODUCT}' does not match expected '$1'" 177 local lunch_cli="source build/envsetup.sh && lunch $1" 178 if [ -f "build/release/release_configs/trunk_staging.textproto" ]; then 179 lunch_cli+="-trunk_staging-userdebug" 180 else 181 lunch_cli+="-userdebug" 182 fi 183 print_info "Setup build environment with: $lunch_cli" 184 eval "$lunch_cli" 185} 186 187function find_repo () { 188 manifest_output=$(grep -e "superproject" -e "gs-pixel" -e "private/google-modules/soc/gs" \ 189 -e "kernel/common" -e "common-modules/virtual-device" .repo/manifests/default.xml) 190 case "$manifest_output" in 191 *platform/superproject*) 192 PLATFORM_REPO_ROOT="$PWD" 193 PLATFORM_VERSION=$(grep -e "platform/superproject" .repo/manifests/default.xml | \ 194 grep -oP 'revision="\K[^"]*') 195 print_info "PLATFORM_REPO_ROOT=$PLATFORM_REPO_ROOT, PLATFORM_VERSION=$PLATFORM_VERSION" 196 if [ -z "$PLATFORM_BUILD" ]; then 197 PLATFORM_BUILD="$PLATFORM_REPO_ROOT" 198 fi 199 ;; 200 *kernel/superproject*) 201 if [[ "$manifest_output" == *common-modules/virtual-device* ]]; then 202 CF_KERNEL_REPO_ROOT="$PWD" 203 CF_KERNEL_VERSION=$(grep -e "common-modules/virtual-device" \ 204 .repo/manifests/default.xml | grep -oP 'revision="\K[^"]*') 205 print_info "CF_KERNEL_REPO_ROOT=$CF_KERNEL_REPO_ROOT, \ 206 CF_KERNEL_VERSION=$CF_KERNEL_VERSION" 207 if [ -z "$KERNEL_BUILD" ]; then 208 KERNEL_BUILD="$CF_KERNEL_REPO_ROOT/out/virtual_device_x86_64/dist" 209 fi 210 fi 211 ;; 212 *) 213 print_warn "Unexpected manifest output. Could not determine repository type." 214 ;; 215 esac 216} 217 218function rebuild_platform () { 219 build_cmd="m -j12" 220 print_warn "Flag --skip-build is not set. Rebuilt images at $PWD with: $build_cmd" 221 eval "$build_cmd" 222 exit_code=$? 223 if [ $exit_code -eq 0 ]; then 224 if [ -f "${ANDROID_PRODUCT_OUT}/system.img" ]; then 225 print_info "$build_cmd succeeded" 226 else 227 print_error "${ANDROID_PRODUCT_OUT}/system.img doesn't exist" 228 fi 229 else 230 print_warn "$build_cmd returned exit_code $exit_code or ${ANDROID_PRODUCT_OUT}/system.img is not found" 231 print_error "$build_cmd failed" 232 fi 233} 234 235adb_checker 236 237# LOCAL_REPO= $ Unused 238 239OLD_PWD=$PWD 240MY_NAME=$0 241 242parse_arg "$@" 243 244FULL_COMMAND_PATH=$(dirname "$PWD/$0") 245REPO_LIST_OUT=$(repo list 2>&1) 246if [[ "$REPO_LIST_OUT" == "error"* ]]; then 247 echo -e "[$MY_NAME]: ${RED}Current path $PWD is not in an Android repo. Change path to repo root.${END}" 248 go_to_repo_root "$FULL_COMMAND_PATH" 249 print_info "Changed path to $PWD" 250else 251 go_to_repo_root "$PWD" 252fi 253 254# REPO_ROOT_PATH="$PWD" # unused 255 256find_repo 257 258if [ "$SKIP_BUILD" = false ] && [ -n "$PLATFORM_BUILD" ] && [[ "$PLATFORM_BUILD" != ab://* ]] \ 259&& [ -d "$PLATFORM_BUILD" ]; then 260 # Check if PLATFORM_BUILD is an Android platform repo, if yes rebuild 261 cd "$PLATFORM_BUILD" || print_error "Failed to cd to $PLATFORM_BUILD" 262 PLATFORM_REPO_LIST_OUT=$(repo list 2>&1) 263 if [[ "$PLATFORM_REPO_LIST_OUT" != "error"* ]]; then 264 go_to_repo_root "$PWD" 265 if [ -z "${TARGET_PRODUCT}" ] || [[ "${TARGET_PRODUCT}" != "$PRODUCT" ]]; then 266 set_platform_repo "$PRODUCT" 267 rebuild_platform 268 PLATFORM_BUILD=${ANDROID_PRODUCT_OUT} 269 fi 270 fi 271fi 272 273if [ "$SKIP_BUILD" = false ] && [ -n "$SYSTEM_BUILD" ] && [[ "$SYSTEM_BUILD" != ab://* ]] \ 274&& [ -d "$SYSTEM_BUILD" ]; then 275 # Get GSI build 276 cd "$SYSTEM_BUILD" || print_error "Failed to cd to $SYSTEM_BUILD" 277 SYSTEM_REPO_LIST_OUT=$(repo list 2>&1) 278 if [[ "$SYSTEM_REPO_LIST_OUT" != "error"* ]]; then 279 go_to_repo_root "$PWD" 280 if [ -z "${TARGET_PRODUCT}" ] || [[ "${TARGET_PRODUCT}" != "aosp_x86_64" ]]; then 281 set_platform_repo "aosp_x86_64" 282 rebuild_platform 283 SYSTEM_BUILD="${ANDROID_PRODUCT_OUT}/system.img" 284 fi 285 fi 286fi 287 288if [ "$SKIP_BUILD" = false ] && [ -n "$KERNEL_BUILD" ] && [[ "$KERNEL_BUILD" != ab://* ]] \ 289&& [ -d "$KERNEL_BUILD" ]; then 290 # Check if kernel repo is provided, if yes rebuild 291 cd "$KERNEL_BUILD" || print_error "Failed to cd to $KERNEL_BUILD" 292 KERNEL_REPO_LIST_OUT=$(repo list 2>&1) 293 if [[ "$KERNEL_REPO_LIST_OUT" != "error"* ]]; then 294 go_to_repo_root "$PWD" 295 if [ ! -f "common-modules/virtual-device/BUILD.bazel" ]; then 296 # TODO(b/365590299): Add build support to android12 and earlier kernels 297 print_error "bazel build common-modules/virtual-device is not supported in this kernel tree" 298 fi 299 300 # KERNEL_VERSION=$(grep -e "common-modules/virtual-device" .repo/manifests/default.xml | grep -oP 'revision="\K[^"]*') # unused 301 302 # Build a new kernel 303 build_cmd="tools/bazel run --config=fast" 304 if [ "$GCOV" = true ]; then 305 build_cmd+=" --gcov" 306 fi 307 if [ "$DEBUG" = true ]; then 308 build_cmd+=" --debug" 309 fi 310 if [ "$KASAN" = true ]; then 311 build_cmd+=" --kasan" 312 fi 313 build_cmd+=" //common-modules/virtual-device:virtual_device_x86_64_dist" 314 print_warn "Flag --skip-build is not set. Rebuild the kernel with: $build_cmd." 315 eval "$build_cmd" 316 exit_code=$? 317 if [ $exit_code -eq 0 ]; then 318 print_info "$build_cmd succeeded" 319 else 320 print_error "$build_cmd failed" 321 fi 322 KERNEL_BUILD="$PWD/out/virtual_device_x86_64/dist" 323 fi 324fi 325 326 327if [ -z "$ACLOUD_BIN" ] || ! [ -x "$ACLOUD_BIN" ]; then 328 output=$(which acloud 2>&1) 329 if [ -z "$output" ]; then 330 print_info "Use acloud binary from $ACLOUD_PREBUILT" 331 ACLOUD_BIN="$ACLOUD_PREBUILT" 332 else 333 print_info "Use acloud binary from $output" 334 ACLOUD_BIN="$output" 335 fi 336 337 # Check if the newly found or prebuilt ACLOUD_BIN is executable 338 if ! [ -x "$ACLOUD_BIN" ]; then 339 print_error "$ACLOUD_BIN is not executable" 340 fi 341fi 342 343acloud_cli="$ACLOUD_BIN create" 344EXTRA_OPTIONS+=("$OPT_SKIP_PRERUNCHECK") 345 346# Add in branch if not specified 347 348if [ -z "$PLATFORM_BUILD" ]; then 349 print_warn "Platform build is not specified, will use the latest aosp-main build." 350 acloud_cli+=' --branch aosp-main' 351elif [[ "$PLATFORM_BUILD" == ab://* ]]; then 352 IFS='/' read -ra array <<< "$PLATFORM_BUILD" 353 acloud_cli+=" --branch ${array[2]}" 354 355 # Check if array[3] exists before using it 356 if [ ${#array[@]} -ge 3 ] && [ -n "${array[3]}" ]; then 357 acloud_cli+=" --build-target ${array[3]}" 358 359 # Check if array[4] exists and is not 'latest' before using it 360 if [ ${#array[@]} -ge 4 ] && [ -n "${array[4]}" ] && [ "${array[4]}" != 'latest' ]; then 361 acloud_cli+=" --build-id ${array[4]}" 362 fi 363 fi 364else 365 acloud_cli+=" --local-image $PLATFORM_BUILD" 366fi 367 368if [ -z "$KERNEL_BUILD" ]; then 369 print_warn "Flag --kernel-build is not set, will not launch Cuttlefish with different kernel." 370elif [[ "$KERNEL_BUILD" == ab://* ]]; then 371 IFS='/' read -ra array <<< "$KERNEL_BUILD" 372 acloud_cli+=" --kernel-branch ${array[2]}" 373 374 # Check if array[3] exists before using it 375 if [ ${#array[@]} -ge 3 ] && [ -n "${array[3]}" ]; then 376 acloud_cli+=" --kernel-build-target ${array[3]}" 377 378 # Check if array[4] exists and is not 'latest' before using it 379 if [ ${#array[@]} -ge 4 ] && [ -n "${array[4]}" ] && [ "${array[4]}" != 'latest' ]; then 380 acloud_cli+=" --kernel-build-id ${array[4]}" 381 fi 382 fi 383else 384 acloud_cli+=" --local-kernel-image $KERNEL_BUILD" 385fi 386 387if [ -z "$SYSTEM_BUILD" ]; then 388 print_warn "System build is not specified, will not launch Cuttlefish with GSI mixed build." 389elif [[ "$SYSTEM_BUILD" == ab://* ]]; then 390 IFS='/' read -ra array <<< "$SYSTEM_BUILD" 391 acloud_cli+=" --system-branch ${array[2]}" 392 393 # Check if array[3] exists before using it 394 if [ ${#array[@]} -ge 3 ] && [ -n "${array[3]}" ]; then 395 acloud_cli+=" --system-build-target ${array[3]}" 396 397 # Check if array[4] exists and is not 'latest' before using it 398 if [ ${#array[@]} -ge 4 ] && [ -n "${array[4]}" ] && [ "${array[4]}" != 'latest' ]; then 399 acloud_cli+=" --system-build-id ${array[4]}" 400 fi 401 fi 402else 403 acloud_cli+=" --local-system-image $SYSTEM_BUILD" 404fi 405 406acloud_cli+=" ${EXTRA_OPTIONS[*]}" 407print_info "Launch CVD with command: $acloud_cli" 408eval "$acloud_cli" 409