xref: /aosp_15_r20/kernel/tests/tools/launch_cvd.sh (revision 2f2c4c7ab4226c71756b9c31670392fdd6887c4f)
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