1# Copyright (C) 2022 The Android Open Source Project
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#      http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15# gettop is duplicated here and in shell_utils.mk, because it's difficult
16# to find shell_utils.make without it for all the novel ways this file can be
17# sourced.  Other common functions should only be in one place or the other.
18function _gettop_once
19{
20    local TOPFILE=build/make/core/envsetup.mk
21    if [ -n "$TOP" -a -f "$TOP/$TOPFILE" ] ; then
22        # The following circumlocution ensures we remove symlinks from TOP.
23        (cd "$TOP"; PWD= /bin/pwd)
24    else
25        if [ -f $TOPFILE ] ; then
26            # The following circumlocution (repeated below as well) ensures
27            # that we record the true directory name and not one that is
28            # faked up with symlink names.
29            PWD= /bin/pwd
30        else
31            local HERE=$PWD
32            local T=
33            while [ \( ! \( -f $TOPFILE \) \) -a \( "$PWD" != "/" \) ]; do
34                \cd ..
35                T=`PWD= /bin/pwd -P`
36            done
37            \cd "$HERE"
38            if [ -f "$T/$TOPFILE" ]; then
39                echo "$T"
40            fi
41        fi
42    fi
43}
44T=$(_gettop_once)
45if [ ! "$T" ]; then
46    echo "Couldn't locate the top of the tree. Always source build/envsetup.sh from the root of the tree." >&2
47    return 1
48fi
49IMPORTING_ENVSETUP=true source $T/build/make/shell_utils.sh
50
51# Get all the build variables needed by this script in a single call to the build system.
52function build_build_var_cache()
53{
54    local T=$(gettop)
55    # Grep out the variable names from the script.
56    cached_vars=(`cat $T/build/envsetup.sh | tr '()' '  ' | awk '{for(i=1;i<=NF;i++) if($i~/_get_build_var_cached/) print $(i+1)}' | sort -u | tr '\n' ' '`)
57    cached_abs_vars=(`cat $T/build/envsetup.sh | tr '()' '  ' | awk '{for(i=1;i<=NF;i++) if($i~/_get_abs_build_var_cached/) print $(i+1)}' | sort -u | tr '\n' ' '`)
58    # Call the build system to dump the "<val>=<value>" pairs as a shell script.
59    build_dicts_script=`\builtin cd $T; build/soong/soong_ui.bash --dumpvars-mode \
60                        --vars="${cached_vars[*]}" \
61                        --abs-vars="${cached_abs_vars[*]}" \
62                        --var-prefix=var_cache_ \
63                        --abs-var-prefix=abs_var_cache_`
64    local ret=$?
65    if [ $ret -ne 0 ]
66    then
67        unset build_dicts_script
68        return $ret
69    fi
70    # Execute the script to store the "<val>=<value>" pairs as shell variables.
71    eval "$build_dicts_script"
72    ret=$?
73    unset build_dicts_script
74    if [ $ret -ne 0 ]
75    then
76        return $ret
77    fi
78    BUILD_VAR_CACHE_READY="true"
79}
80
81# Delete the build var cache, so that we can still call into the build system
82# to get build variables not listed in this script.
83function destroy_build_var_cache()
84{
85    unset BUILD_VAR_CACHE_READY
86    local v
87    for v in $cached_vars; do
88      unset var_cache_$v
89    done
90    unset cached_vars
91    for v in $cached_abs_vars; do
92      unset abs_var_cache_$v
93    done
94    unset cached_abs_vars
95}
96
97# Get the value of a build variable as an absolute path.
98function _get_abs_build_var_cached()
99{
100    if [ "$BUILD_VAR_CACHE_READY" = "true" ]
101    then
102        eval "echo \"\${abs_var_cache_$1}\""
103        return
104    fi
105
106    local T=$(gettop)
107    if [ ! "$T" ]; then
108        echo "Couldn't locate the top of the tree.  Try setting TOP." >&2
109        return
110    fi
111    (\cd $T; build/soong/soong_ui.bash --dumpvar-mode --abs $1)
112}
113
114# Get the exact value of a build variable.
115function _get_build_var_cached()
116{
117    if [ "$BUILD_VAR_CACHE_READY" = "true" ]
118    then
119        eval "echo \"\${var_cache_$1}\""
120        return 0
121    fi
122
123    local T=$(gettop)
124    if [ ! "$T" ]; then
125        echo "Couldn't locate the top of the tree.  Try setting TOP." >&2
126        return 1
127    fi
128    (\cd $T; build/soong/soong_ui.bash --dumpvar-mode $1)
129}
130
131# This logic matches envsetup.mk
132function get_host_prebuilt_prefix
133{
134  local un=$(uname)
135  if [[ $un == "Linux" ]] ; then
136    echo linux-x86
137  elif [[ $un == "Darwin" ]] ; then
138    echo darwin-x86
139  else
140    echo "Error: Invalid host operating system: $un" 1>&2
141  fi
142}
143
144# Add directories to PATH that are dependent on the lunch target.
145# For directories that are not lunch-specific, add them in set_global_paths
146function set_lunch_paths()
147{
148    local T=$(gettop)
149    if [ ! "$T" ]; then
150        echo "Couldn't locate the top of the tree.  Try setting TOP."
151        return
152    fi
153
154    ##################################################################
155    #                                                                #
156    #              Read me before you modify this code               #
157    #                                                                #
158    #   This function sets ANDROID_LUNCH_BUILD_PATHS to what it is   #
159    #   adding to PATH, and the next time it is run, it removes that #
160    #   from PATH.  This is required so lunch can be run more than   #
161    #   once and still have working paths.                           #
162    #                                                                #
163    ##################################################################
164
165    # Note: on windows/cygwin, ANDROID_LUNCH_BUILD_PATHS will contain spaces
166    # due to "C:\Program Files" being in the path.
167
168    # Handle compat with the old ANDROID_BUILD_PATHS variable.
169    # TODO: Remove this after we think everyone has lunched again.
170    if [ -z "$ANDROID_LUNCH_BUILD_PATHS" -a -n "$ANDROID_BUILD_PATHS" ] ; then
171      ANDROID_LUNCH_BUILD_PATHS="$ANDROID_BUILD_PATHS"
172      ANDROID_BUILD_PATHS=
173    fi
174    if [ -n "$ANDROID_PRE_BUILD_PATHS" ] ; then
175        export PATH=${PATH/$ANDROID_PRE_BUILD_PATHS/}
176        # strip leading ':', if any
177        export PATH=${PATH/:%/}
178        ANDROID_PRE_BUILD_PATHS=
179    fi
180
181    # Out with the old...
182    if [ -n "$ANDROID_LUNCH_BUILD_PATHS" ] ; then
183        export PATH=${PATH/$ANDROID_LUNCH_BUILD_PATHS/}
184    fi
185
186    # And in with the new...
187    ANDROID_LUNCH_BUILD_PATHS=$(_get_abs_build_var_cached SOONG_HOST_OUT_EXECUTABLES)
188    ANDROID_LUNCH_BUILD_PATHS+=:$(_get_abs_build_var_cached HOST_OUT_EXECUTABLES)
189
190    # Append llvm binutils prebuilts path to ANDROID_LUNCH_BUILD_PATHS.
191    local ANDROID_LLVM_BINUTILS=$(_get_abs_build_var_cached ANDROID_CLANG_PREBUILTS)/llvm-binutils-stable
192    ANDROID_LUNCH_BUILD_PATHS+=:$ANDROID_LLVM_BINUTILS
193
194    # Set up ASAN_SYMBOLIZER_PATH for SANITIZE_HOST=address builds.
195    export ASAN_SYMBOLIZER_PATH=$ANDROID_LLVM_BINUTILS/llvm-symbolizer
196
197    # Append asuite prebuilts path to ANDROID_LUNCH_BUILD_PATHS.
198    local os_arch=$(_get_build_var_cached HOST_PREBUILT_TAG)
199    ANDROID_LUNCH_BUILD_PATHS+=:$T/prebuilts/asuite/acloud/$os_arch
200    ANDROID_LUNCH_BUILD_PATHS+=:$T/prebuilts/asuite/aidegen/$os_arch
201    ANDROID_LUNCH_BUILD_PATHS+=:$T/prebuilts/asuite/atest/$os_arch
202
203    export ANDROID_JAVA_HOME=$(_get_abs_build_var_cached ANDROID_JAVA_HOME)
204    export JAVA_HOME=$ANDROID_JAVA_HOME
205    export ANDROID_JAVA_TOOLCHAIN=$(_get_abs_build_var_cached ANDROID_JAVA_TOOLCHAIN)
206    ANDROID_LUNCH_BUILD_PATHS+=:$ANDROID_JAVA_TOOLCHAIN
207
208    # Fix up PYTHONPATH
209    if [ -n $ANDROID_PYTHONPATH ]; then
210        export PYTHONPATH=${PYTHONPATH//$ANDROID_PYTHONPATH/}
211    fi
212    # //development/python-packages contains both a pseudo-PYTHONPATH which
213    # mimics an already assembled venv, but also contains real Python packages
214    # that are not in that layout until they are installed. We can fake it for
215    # the latter type by adding the package source directories to the PYTHONPATH
216    # directly. For the former group, we only need to add the python-packages
217    # directory itself.
218    #
219    # This could be cleaned up by converting the remaining packages that are in
220    # the first category into a typical python source layout (that is, another
221    # layer of directory nesting) and automatically adding all subdirectories of
222    # python-packages to the PYTHONPATH instead of manually curating this. We
223    # can't convert the packages like adb to the other style because doing so
224    # would prevent exporting type info from those packages.
225    #
226    # http://b/266688086
227    export ANDROID_PYTHONPATH=$T/development/python-packages/adb:$T/development/python-packages/gdbrunner:$T/development/python-packages:
228    if [ -n $VENDOR_PYTHONPATH ]; then
229        ANDROID_PYTHONPATH=$ANDROID_PYTHONPATH$VENDOR_PYTHONPATH
230    fi
231    export PYTHONPATH=$ANDROID_PYTHONPATH$PYTHONPATH
232
233    unset ANDROID_PRODUCT_OUT
234    export ANDROID_PRODUCT_OUT=$(_get_abs_build_var_cached PRODUCT_OUT)
235    export OUT=$ANDROID_PRODUCT_OUT
236
237    unset ANDROID_HOST_OUT
238    export ANDROID_HOST_OUT=$(_get_abs_build_var_cached HOST_OUT)
239
240    unset ANDROID_SOONG_HOST_OUT
241    export ANDROID_SOONG_HOST_OUT=$(_get_abs_build_var_cached SOONG_HOST_OUT)
242
243    unset ANDROID_HOST_OUT_TESTCASES
244    export ANDROID_HOST_OUT_TESTCASES=$(_get_abs_build_var_cached HOST_OUT_TESTCASES)
245
246    unset ANDROID_TARGET_OUT_TESTCASES
247    export ANDROID_TARGET_OUT_TESTCASES=$(_get_abs_build_var_cached TARGET_OUT_TESTCASES)
248
249    # Finally, set PATH
250    export PATH=$ANDROID_LUNCH_BUILD_PATHS:$PATH
251}
252
253# Add directories to PATH that are NOT dependent on the lunch target.
254# For directories that are lunch-specific, add them in set_lunch_paths
255function set_global_paths()
256{
257    local T=$(gettop)
258    if [ ! "$T" ]; then
259        echo "Couldn't locate the top of the tree.  Try setting TOP."
260        return
261    fi
262
263    ##################################################################
264    #                                                                #
265    #              Read me before you modify this code               #
266    #                                                                #
267    #   This function sets ANDROID_GLOBAL_BUILD_PATHS to what it is  #
268    #   adding to PATH, and the next time it is run, it removes that #
269    #   from PATH.  This is required so envsetup.sh can be sourced   #
270    #   more than once and still have working paths.                 #
271    #                                                                #
272    ##################################################################
273
274    # Out with the old...
275    if [ -n "$ANDROID_GLOBAL_BUILD_PATHS" ] ; then
276        export PATH=${PATH/$ANDROID_GLOBAL_BUILD_PATHS/}
277    fi
278
279    # And in with the new...
280    ANDROID_GLOBAL_BUILD_PATHS=$T/build/soong/bin
281    ANDROID_GLOBAL_BUILD_PATHS+=:$T/build/bazel/bin
282    ANDROID_GLOBAL_BUILD_PATHS+=:$T/development/scripts
283    ANDROID_GLOBAL_BUILD_PATHS+=:$T/prebuilts/devtools/tools
284
285    # add kernel specific binaries
286    if [ $(uname -s) = Linux ] ; then
287        ANDROID_GLOBAL_BUILD_PATHS+=:$T/prebuilts/misc/linux-x86/dtc
288        ANDROID_GLOBAL_BUILD_PATHS+=:$T/prebuilts/misc/linux-x86/libufdt
289    fi
290
291    # If prebuilts/android-emulator/<system>/ exists, prepend it to our PATH
292    # to ensure that the corresponding 'emulator' binaries are used.
293    case $(uname -s) in
294        Darwin)
295            ANDROID_EMULATOR_PREBUILTS=$T/prebuilts/android-emulator/darwin-x86_64
296            ;;
297        Linux)
298            ANDROID_EMULATOR_PREBUILTS=$T/prebuilts/android-emulator/linux-x86_64
299            ;;
300        *)
301            ANDROID_EMULATOR_PREBUILTS=
302            ;;
303    esac
304    if [ -n "$ANDROID_EMULATOR_PREBUILTS" -a -d "$ANDROID_EMULATOR_PREBUILTS" ]; then
305        ANDROID_GLOBAL_BUILD_PATHS+=:$ANDROID_EMULATOR_PREBUILTS
306        export ANDROID_EMULATOR_PREBUILTS
307    fi
308
309    # Finally, set PATH
310    export PATH=$ANDROID_GLOBAL_BUILD_PATHS:$PATH
311}
312
313function printconfig()
314{
315    local T=$(gettop)
316    if [ ! "$T" ]; then
317        echo "Couldn't locate the top of the tree.  Try setting TOP." >&2
318        return
319    fi
320    _get_build_var_cached report_config
321}
322
323function set_stuff_for_environment()
324{
325    set_lunch_paths
326    set_sequence_number
327
328    export ANDROID_BUILD_TOP=$(gettop)
329}
330
331function set_sequence_number()
332{
333    export BUILD_ENV_SEQUENCE_NUMBER=13
334}
335
336# Takes a command name, and check if it's in ENVSETUP_NO_COMPLETION or not.
337function should_add_completion() {
338    local cmd="$(basename $1| sed 's/_completion//' |sed 's/\.\(.*\)*sh$//')"
339    case :"$ENVSETUP_NO_COMPLETION": in
340        *:"$cmd":*)
341            return 1
342            ;;
343    esac
344    return 0
345}
346
347function addcompletions()
348{
349    local f=
350
351    # Keep us from trying to run in something that's neither bash nor zsh.
352    if [ -z "$BASH_VERSION" -a -z "$ZSH_VERSION" ]; then
353        return
354    fi
355
356    # Keep us from trying to run in bash that's too old.
357    if [ -n "$BASH_VERSION" -a ${BASH_VERSINFO[0]} -lt 3 ]; then
358        return
359    fi
360
361    local completion_files=(
362      packages/modules/adb/adb.bash
363      system/core/fastboot/fastboot.bash
364      tools/asuite/asuite.sh
365      prebuilts/bazel/common/bazel-complete.bash
366    )
367    # Completion can be disabled selectively to allow users to use non-standard completion.
368    # e.g.
369    # ENVSETUP_NO_COMPLETION=adb # -> disable adb completion
370    # ENVSETUP_NO_COMPLETION=adb:bit # -> disable adb and bit completion
371    local T=$(gettop)
372    for f in ${completion_files[*]}; do
373        f="$T/$f"
374        if [ ! -f "$f" ]; then
375          echo "Warning: completion file $f not found"
376        elif should_add_completion "$f"; then
377            . $f
378        fi
379    done
380
381    if [ -z "$ZSH_VERSION" ]; then
382        # Doesn't work in zsh.
383        complete -o nospace -F _croot croot
384        # TODO(b/244559459): Support b autocompletion for zsh
385        complete -F _bazel__complete -o nospace b
386    fi
387    complete -F _lunch lunch
388    complete -F _lunch_completion lunch2
389
390    complete -F _complete_android_module_names pathmod
391    complete -F _complete_android_module_names gomod
392    complete -F _complete_android_module_names outmod
393    complete -F _complete_android_module_names installmod
394    complete -F _complete_android_module_names m
395}
396
397function add_lunch_combo()
398{
399    if [ -n "$ZSH_VERSION" ]; then
400        echo -n "${funcfiletrace[1]}: "
401    else
402        echo -n "${BASH_SOURCE[1]}:${BASH_LINENO[0]}: "
403    fi
404    echo "add_lunch_combo is obsolete. Use COMMON_LUNCH_CHOICES in your AndroidProducts.mk instead."
405}
406
407function print_lunch_menu()
408{
409    local uname=$(uname)
410    local choices
411    choices=$(TARGET_BUILD_APPS= TARGET_PRODUCT= TARGET_RELEASE= TARGET_BUILD_VARIANT= _get_build_var_cached COMMON_LUNCH_CHOICES 2>/dev/null)
412    local ret=$?
413
414    echo
415    echo "You're building on" $uname
416    echo
417
418    if [ $ret -ne 0 ]
419    then
420        echo "Warning: Cannot display lunch menu."
421        echo
422        echo "Note: You can invoke lunch with an explicit target:"
423        echo
424        echo "  usage: lunch [target]" >&2
425        echo
426        return
427    fi
428
429    echo "Lunch menu .. Here are the common combinations:"
430
431    local i=1
432    local choice
433    for choice in $(echo $choices)
434    do
435        echo "     $i. $choice"
436        i=$(($i+1))
437    done
438
439    echo
440}
441
442function lunch()
443{
444    local answer
445
446    if [[ $# -gt 1 ]]; then
447        echo "usage: lunch [target]" >&2
448        return 1
449    fi
450
451    local used_lunch_menu=0
452
453    if [ "$1" ]; then
454        answer=$1
455    else
456        print_lunch_menu
457        echo "Which would you like? [aosp_cf_x86_64_phone-trunk_staging-eng]"
458        echo -n "Pick from common choices above (e.g. 13) or specify your own (e.g. aosp_barbet-trunk_staging-eng): "
459        read answer
460        used_lunch_menu=1
461    fi
462
463    local selection=
464
465    if [ -z "$answer" ]
466    then
467        selection=aosp_cf_x86_64_phone-trunk_staging-eng
468    elif (echo -n $answer | grep -q -e "^[0-9][0-9]*$")
469    then
470        local choices=($(TARGET_BUILD_APPS= TARGET_PRODUCT= TARGET_RELEASE= TARGET_BUILD_VARIANT= _get_build_var_cached COMMON_LUNCH_CHOICES 2>/dev/null))
471        if [ $answer -le ${#choices[@]} ]
472        then
473            # array in zsh starts from 1 instead of 0.
474            if [ -n "$ZSH_VERSION" ]
475            then
476                selection=${choices[$(($answer))]}
477            else
478                selection=${choices[$(($answer-1))]}
479            fi
480        fi
481    else
482        selection=$answer
483    fi
484
485    export TARGET_BUILD_APPS=
486
487    # This must be <product>-<release>-<variant>
488    local product release variant
489    # Split string on the '-' character.
490    IFS="-" read -r product release variant <<< "$selection"
491
492    if [[ -z "$product" ]] || [[ -z "$release" ]] || [[ -z "$variant" ]]
493    then
494        echo
495        echo "Invalid lunch combo: $selection"
496        echo "Valid combos must be of the form <product>-<release>-<variant>"
497        return 1
498    fi
499
500    _lunch_meat $product $release $variant
501}
502
503function _lunch_meat()
504{
505    local product=$1
506    local release=$2
507    local variant=$3
508
509    TARGET_PRODUCT=$product \
510    TARGET_RELEASE=$release \
511    TARGET_BUILD_VARIANT=$variant \
512    build_build_var_cache
513    if [ $? -ne 0 ]
514    then
515        if [[ "$product" =~ .*_(eng|user|userdebug) ]]
516        then
517            echo "Did you mean -${product/*_/}? (dash instead of underscore)"
518        fi
519        return 1
520    fi
521    export TARGET_PRODUCT=$(_get_build_var_cached TARGET_PRODUCT)
522    export TARGET_BUILD_VARIANT=$(_get_build_var_cached TARGET_BUILD_VARIANT)
523    export TARGET_RELEASE=$release
524    # Note this is the string "release", not the value of the variable.
525    export TARGET_BUILD_TYPE=release
526
527    [[ -n "${ANDROID_QUIET_BUILD:-}" ]] || echo
528
529    set_stuff_for_environment
530    [[ -n "${ANDROID_QUIET_BUILD:-}" ]] || printconfig
531
532    if [[ -z "${ANDROID_QUIET_BUILD}" ]]; then
533        local spam_for_lunch=$(gettop)/build/make/tools/envsetup/spam_for_lunch
534        if [[ -x $spam_for_lunch ]]; then
535            $spam_for_lunch
536        fi
537    fi
538
539    destroy_build_var_cache
540
541    if [[ -n "${CHECK_MU_CONFIG:-}" ]]; then
542      check_mu_config
543    fi
544}
545
546unset COMMON_LUNCH_CHOICES_CACHE
547# Tab completion for lunch.
548function _lunch()
549{
550    local cur prev opts
551    COMPREPLY=()
552    cur="${COMP_WORDS[COMP_CWORD]}"
553    prev="${COMP_WORDS[COMP_CWORD-1]}"
554
555    if [ -z "$COMMON_LUNCH_CHOICES_CACHE" ]; then
556        COMMON_LUNCH_CHOICES_CACHE=$(TARGET_BUILD_APPS= _get_build_var_cached COMMON_LUNCH_CHOICES)
557    fi
558
559    COMPREPLY=( $(compgen -W "${COMMON_LUNCH_CHOICES_CACHE}" -- ${cur}) )
560    return 0
561}
562
563function _lunch_usage()
564{
565    (
566        echo "The lunch command selects the configuration to use for subsequent"
567        echo "Android builds."
568        echo
569        echo "Usage: lunch TARGET_PRODUCT [TARGET_RELEASE [TARGET_BUILD_VARIANT]]"
570        echo
571        echo "  Choose the product, release and variant to use. If not"
572        echo "  supplied, TARGET_RELEASE will be 'trunk_staging' and"
573        echo "  TARGET_BUILD_VARIANT will be 'eng'"
574        echo
575        echo
576        echo "Usage: lunch TARGET_PRODUCT-TARGET_RELEASE-TARGET_BUILD_VARIANT"
577        echo
578        echo "  Chose the product, release and variant to use. This"
579        echo "  legacy format is maintained for compatibility."
580        echo
581        echo
582        echo "Note that the previous interactive menu and list of hard-coded"
583        echo "list of curated targets has been removed. If you would like the"
584        echo "list of products, release configs for a particular product, or"
585        echo "variants, run list_products, list_release_configs, list_variants"
586        echo "respectively."
587        echo
588    ) 1>&2
589}
590
591function lunch2()
592{
593    if [[ $# -eq 1 && $1 = "--help" ]]; then
594        _lunch_usage
595        return 0
596    fi
597    if [[ $# -eq 0 ]]; then
598        echo "No target specified. See lunch --help" 1>&2
599        return 1
600    fi
601    if [[ $# -gt 3 ]]; then
602        echo "Too many parameters given. See lunch --help" 1>&2
603        return 1
604    fi
605
606    local product release variant
607
608    # Handle the legacy format
609    local legacy=$(echo $1 | grep "-")
610    if [[ $# -eq 1 && -n $legacy ]]; then
611        IFS="-" read -r product release variant <<< "$1"
612        if [[ -z "$product" ]] || [[ -z "$release" ]] || [[ -z "$variant" ]]; then
613            echo "Invalid lunch combo: $1" 1>&2
614            echo "Valid combos must be of the form <product>-<release>-<variant> when using" 1>&2
615            echo "the legacy format.  Run 'lunch --help' for usage." 1>&2
616            return 1
617        fi
618    fi
619
620    # Handle the new format.
621    if [[ -z $legacy ]]; then
622        product=$1
623        release=$2
624        if [[ -z $release ]]; then
625            release=trunk_staging
626        fi
627        variant=$3
628        if [[ -z $variant ]]; then
629            variant=eng
630        fi
631    fi
632
633    # Validate the selection and set all the environment stuff
634    _lunch_meat $product $release $variant
635}
636
637unset ANDROID_LUNCH_COMPLETION_PRODUCT_CACHE
638unset ANDROID_LUNCH_COMPLETION_CHOSEN_PRODUCT
639unset ANDROID_LUNCH_COMPLETION_RELEASE_CACHE
640# Tab completion for lunch.
641function _lunch_completion()
642{
643    # Available products
644    if [[ $COMP_CWORD -eq 1 ]] ; then
645        if [[ -z $ANDROID_LUNCH_COMPLETION_PRODUCT_CACHE ]]; then
646            ANDROID_LUNCH_COMPLETION_PRODUCT_CACHE=$(list_products)
647        fi
648        COMPREPLY=( $(compgen -W "${ANDROID_LUNCH_COMPLETION_PRODUCT_CACHE}" -- "${COMP_WORDS[COMP_CWORD]}") )
649    fi
650
651    # Available release configs
652    if [[ $COMP_CWORD -eq 2 ]] ; then
653        if [[ -z $ANDROID_LUNCH_COMPLETION_RELEASE_CACHE || $ANDROID_LUNCH_COMPLETION_CHOSEN_PRODUCT != ${COMP_WORDS[1]} ]] ; then
654            ANDROID_LUNCH_COMPLETION_RELEASE_CACHE=$(list_releases ${COMP_WORDS[1]})
655            ANDROID_LUNCH_COMPLETION_CHOSEN_PRODUCT=${COMP_WORDS[1]}
656        fi
657        COMPREPLY=( $(compgen -W "${ANDROID_LUNCH_COMPLETION_RELEASE_CACHE}" -- "${COMP_WORDS[COMP_CWORD]}") )
658    fi
659
660    # Available variants
661    if [[ $COMP_CWORD -eq 3 ]] ; then
662        COMPREPLY=(user userdebug eng)
663    fi
664
665    return 0
666}
667
668
669# Configures the build to build unbundled apps.
670# Run tapas with one or more app names (from LOCAL_PACKAGE_NAME)
671function tapas()
672{
673    local showHelp="$(echo $* | xargs -n 1 echo | \grep -E '^(help)$' | xargs)"
674    local arch="$(echo $* | xargs -n 1 echo | \grep -E '^(arm|x86|arm64|x86_64)$' | xargs)"
675    # TODO(b/307975293): Expand tapas to take release arguments (and update hmm() usage).
676    local release="trunk_staging"
677    local variant="$(echo $* | xargs -n 1 echo | \grep -E '^(user|userdebug|eng)$' | xargs)"
678    local density="$(echo $* | xargs -n 1 echo | \grep -E '^(ldpi|mdpi|tvdpi|hdpi|xhdpi|xxhdpi|xxxhdpi|alldpi)$' | xargs)"
679    local keys="$(echo $* | xargs -n 1 echo | \grep -E '^(devkeys)$' | xargs)"
680    local apps="$(echo $* | xargs -n 1 echo | \grep -E -v '^(user|userdebug|eng|arm|x86|arm64|x86_64|ldpi|mdpi|tvdpi|hdpi|xhdpi|xxhdpi|xxxhdpi|alldpi|devkeys)$' | xargs)"
681
682
683    if [ "$showHelp" != "" ]; then
684      $(gettop)/build/make/tapasHelp.sh
685      return
686    fi
687
688    if [ $(echo $arch | wc -w) -gt 1 ]; then
689        echo "tapas: Error: Multiple build archs supplied: $arch"
690        return
691    fi
692    if [ $(echo $release | wc -w) -gt 1 ]; then
693        echo "tapas: Error: Multiple build releases supplied: $release"
694        return
695    fi
696    if [ $(echo $variant | wc -w) -gt 1 ]; then
697        echo "tapas: Error: Multiple build variants supplied: $variant"
698        return
699    fi
700    if [ $(echo $density | wc -w) -gt 1 ]; then
701        echo "tapas: Error: Multiple densities supplied: $density"
702        return
703    fi
704    if [ $(echo $keys | wc -w) -gt 1 ]; then
705        echo "tapas: Error: Multiple keys supplied: $keys"
706        return
707    fi
708
709    local product=aosp_arm
710    case $arch in
711      x86)    product=aosp_x86;;
712      arm64)  product=aosp_arm64;;
713      x86_64) product=aosp_x86_64;;
714    esac
715    if [ -n "$keys" ]; then
716        product=${product/aosp_/aosp_${keys}_}
717    fi;
718
719    if [ -z "$variant" ]; then
720        variant=eng
721    fi
722    if [ -z "$apps" ]; then
723        apps=all
724    fi
725    if [ -z "$density" ]; then
726        density=alldpi
727    fi
728
729    export TARGET_PRODUCT=$product
730    export TARGET_RELEASE=$release
731    export TARGET_BUILD_VARIANT=$variant
732    export TARGET_BUILD_DENSITY=$density
733    export TARGET_BUILD_TYPE=release
734    export TARGET_BUILD_APPS=$apps
735
736    build_build_var_cache
737    set_stuff_for_environment
738    printconfig
739    destroy_build_var_cache
740}
741
742# Configures the build to build unbundled Android modules (APEXes).
743# Run banchan with one or more module names (from apex{} modules).
744function banchan()
745{
746    local showHelp="$(echo $* | xargs -n 1 echo | \grep -E '^(help)$' | xargs)"
747    local product="$(echo $* | xargs -n 1 echo | \grep -E '^(.*_)?(arm|x86|arm64|riscv64|x86_64|arm64only|x86_64only)$' | xargs)"
748    # TODO: Expand banchan to take release arguments (and update hmm() usage).
749    local release="trunk_staging"
750    local variant="$(echo $* | xargs -n 1 echo | \grep -E '^(user|userdebug|eng)$' | xargs)"
751    local apps="$(echo $* | xargs -n 1 echo | \grep -E -v '^(user|userdebug|eng|(.*_)?(arm|x86|arm64|riscv64|x86_64))$' | xargs)"
752
753    if [ "$showHelp" != "" ]; then
754      $(gettop)/build/make/banchanHelp.sh
755      return
756    fi
757
758    if [ -z "$product" ]; then
759        product=arm64
760    elif [ $(echo $product | wc -w) -gt 1 ]; then
761        echo "banchan: Error: Multiple build archs or products supplied: $products"
762        return
763    fi
764    if [ $(echo $release | wc -w) -gt 1 ]; then
765        echo "banchan: Error: Multiple build releases supplied: $release"
766        return
767    fi
768    if [ $(echo $variant | wc -w) -gt 1 ]; then
769        echo "banchan: Error: Multiple build variants supplied: $variant"
770        return
771    fi
772    if [ -z "$apps" ]; then
773        echo "banchan: Error: No modules supplied"
774        return
775    fi
776
777    case $product in
778      arm)    product=module_arm;;
779      x86)    product=module_x86;;
780      arm64)  product=module_arm64;;
781      riscv64) product=module_riscv64;;
782      x86_64) product=module_x86_64;;
783      arm64only)  product=module_arm64only;;
784      x86_64only) product=module_x86_64only;;
785    esac
786    if [ -z "$variant" ]; then
787        variant=eng
788    fi
789
790    export TARGET_PRODUCT=$product
791    export TARGET_RELEASE=$release
792    export TARGET_BUILD_VARIANT=$variant
793    export TARGET_BUILD_DENSITY=alldpi
794    export TARGET_BUILD_TYPE=release
795
796    # This setup currently uses TARGET_BUILD_APPS just like tapas, but the use
797    # case is different and it may diverge in the future.
798    export TARGET_BUILD_APPS=$apps
799
800    build_build_var_cache
801    set_stuff_for_environment
802    printconfig
803    destroy_build_var_cache
804}
805
806function croot()
807{
808    local T=$(gettop)
809    if [ "$T" ]; then
810        if [ "$1" ]; then
811            \cd $(gettop)/$1
812        else
813            \cd $(gettop)
814        fi
815    else
816        echo "Couldn't locate the top of the tree.  Try setting TOP."
817    fi
818}
819
820function _croot()
821{
822    local T=$(gettop)
823    if [ "$T" ]; then
824        local cur="${COMP_WORDS[COMP_CWORD]}"
825        k=0
826        for c in $(compgen -d ${T}/${cur}); do
827            COMPREPLY[k++]=${c#${T}/}/
828        done
829    fi
830}
831
832function cproj()
833{
834    local TOPFILE=build/make/core/envsetup.mk
835    local HERE=$PWD
836    local T=
837    while [ \( ! \( -f $TOPFILE \) \) -a \( $PWD != "/" \) ]; do
838        T=$PWD
839        if [ -f "$T/Android.mk" ]; then
840            \cd $T
841            return
842        fi
843        \cd ..
844    done
845    \cd $HERE
846    echo "can't find Android.mk"
847}
848
849# Ensure that we're always using the adb in the tree. This works around the fact
850# that bash caches $PATH lookups, so if you use adb before lunching/building the
851# one in your tree, you'll continue to get /usr/bin/adb or whatever even after
852# you have the one from your current tree on your path. Historically this would
853# cause confusion because glinux had adb in /usr/bin/ by default, though that
854# doesn't appear to be the case on my rodete hosts; it is however still the case
855# that my Mac has /usr/local/bin/adb installed by default and on the default
856# path.
857function adb() {
858    # We need `command which` because zsh has a built-in `which` that's more
859    # like `type`.
860    local ADB=$(command which adb)
861    if [ -z "$ADB" ]; then
862        echo "Command adb not found; try lunch (and building) first?"
863        return 1
864    fi
865    run_tool_with_logging "ADB" $ADB "${@}"
866}
867
868function fastboot() {
869    local FASTBOOT=$(command which fastboot)
870    if [ -z "$FASTBOOT" ]; then
871        echo "Command fastboot not found; try lunch (and building) first?"
872        return 1
873    fi
874    # Support tool event logging for fastboot command.
875    run_tool_with_logging "FASTBOOT" $FASTBOOT "${@}"
876}
877
878# communicate with a running device or emulator, set up necessary state,
879# and run the hat command.
880function runhat()
881{
882    # process standard adb options
883    local adbTarget=""
884    if [ "$1" = "-d" -o "$1" = "-e" ]; then
885        adbTarget=$1
886        shift 1
887    elif [ "$1" = "-s" ]; then
888        adbTarget="$1 $2"
889        shift 2
890    fi
891    local adbOptions=${adbTarget}
892    #echo adbOptions = ${adbOptions}
893
894    # runhat options
895    local targetPid=$1
896
897    if [ "$targetPid" = "" ]; then
898        echo "Usage: runhat [ -d | -e | -s serial ] target-pid"
899        return
900    fi
901
902    # confirm hat is available
903    if [ -z $(which hat) ]; then
904        echo "hat is not available in this configuration."
905        return
906    fi
907
908    # issue "am" command to cause the hprof dump
909    local devFile=/data/local/tmp/hprof-$targetPid
910    echo "Poking $targetPid and waiting for data..."
911    echo "Storing data at $devFile"
912    adb ${adbOptions} shell am dumpheap $targetPid $devFile
913    echo "Press enter when logcat shows \"hprof: heap dump completed\""
914    echo -n "> "
915    read
916
917    local localFile=/tmp/$$-hprof
918
919    echo "Retrieving file $devFile..."
920    adb ${adbOptions} pull $devFile $localFile
921
922    adb ${adbOptions} shell rm $devFile
923
924    echo "Running hat on $localFile"
925    echo "View the output by pointing your browser at http://localhost:7000/"
926    echo ""
927    hat -JXmx512m $localFile
928}
929
930function godir () {
931    if [[ -z "$1" ]]; then
932        echo "Usage: godir <regex>"
933        return
934    fi
935    local T=$(gettop)
936    local FILELIST
937    if [ ! "$OUT_DIR" = "" ]; then
938        mkdir -p $OUT_DIR
939        FILELIST=$OUT_DIR/filelist
940    else
941        FILELIST=$T/filelist
942    fi
943    if [[ ! -f $FILELIST ]]; then
944        echo -n "Creating index..."
945        (\cd $T; find . -wholename ./out -prune -o -wholename ./.repo -prune -o -type f > $FILELIST)
946        echo " Done"
947        echo ""
948    fi
949    local lines
950    lines=($(\grep "$1" $FILELIST | sed -e 's/\/[^/]*$//' | sort | uniq))
951    if [[ ${#lines[@]} = 0 ]]; then
952        echo "Not found"
953        return
954    fi
955    local pathname
956    local choice
957    if [[ ${#lines[@]} > 1 ]]; then
958        while [[ -z "$pathname" ]]; do
959            local index=1
960            local line
961            for line in ${lines[@]}; do
962                printf "%6s %s\n" "[$index]" $line
963                index=$(($index + 1))
964            done
965            echo
966            echo -n "Select one: "
967            unset choice
968            read choice
969            if [[ $choice -gt ${#lines[@]} || $choice -lt 1 ]]; then
970                echo "Invalid choice"
971                continue
972            fi
973            pathname=${lines[@]:$(($choice-1)):1}
974        done
975    else
976        pathname=${lines[@]:0:1}
977    fi
978    \cd $T/$pathname
979}
980
981# Go to a specific module in the android tree, as cached in module-info.json. If any build change
982# is made, and it should be reflected in the output, you should run 'refreshmod' first.
983# Note: This function is in envsetup because changing the directory needs to happen in the current
984# shell. All other functions that use module-info.json should be in build/soong/bin.
985function gomod() {
986    if [[ $# -ne 1 ]]; then
987        echo "usage: gomod <module>" >&2
988        return 1
989    fi
990
991    local path="$(pathmod $@)"
992    if [ -z "$path" ]; then
993        return 1
994    fi
995    cd $path
996}
997
998function _complete_android_module_names() {
999    local word=${COMP_WORDS[COMP_CWORD]}
1000    COMPREPLY=( $(allmod | grep -E "^$word") )
1001}
1002
1003function get_make_command()
1004{
1005    # If we're in the top of an Android tree, use soong_ui.bash instead of make
1006    if [ -f build/soong/soong_ui.bash ]; then
1007        # Always use the real make if -C is passed in
1008        for arg in "$@"; do
1009            if [[ $arg == -C* ]]; then
1010                echo command make
1011                return
1012            fi
1013        done
1014        echo build/soong/soong_ui.bash --make-mode
1015    else
1016        echo command make
1017    fi
1018}
1019
1020function make()
1021{
1022    _wrap_build $(get_make_command "$@") "$@"
1023}
1024
1025# Zsh needs bashcompinit called to support bash-style completion.
1026function enable_zsh_completion() {
1027    # Don't override user's options if bash-style completion is already enabled.
1028    if ! declare -f complete >/dev/null; then
1029        autoload -U compinit && compinit
1030        autoload -U bashcompinit && bashcompinit
1031    fi
1032}
1033
1034function validate_current_shell() {
1035    local current_sh="$(ps -o command -p $$)"
1036    case "$current_sh" in
1037        *bash*)
1038            function check_type() { type -t "$1"; }
1039            ;;
1040        *zsh*)
1041            function check_type() { type "$1"; }
1042            enable_zsh_completion ;;
1043        *)
1044            echo -e "WARNING: Only bash and zsh are supported.\nUse of other shell would lead to erroneous results."
1045            ;;
1046    esac
1047}
1048
1049# Execute the contents of any vendorsetup.sh files we can find.
1050# Unless we find an allowed-vendorsetup_sh-files file, in which case we'll only
1051# load those.
1052#
1053# This allows loading only approved vendorsetup.sh files
1054function source_vendorsetup() {
1055    unset VENDOR_PYTHONPATH
1056    local T="$(gettop)"
1057    allowed=
1058    for f in $(cd "$T" && find -L device vendor product -maxdepth 4 -name 'allowed-vendorsetup_sh-files' 2>/dev/null | sort); do
1059        if [ -n "$allowed" ]; then
1060            echo "More than one 'allowed_vendorsetup_sh-files' file found, not including any vendorsetup.sh files:"
1061            echo "  $allowed"
1062            echo "  $f"
1063            return
1064        fi
1065        allowed="$T/$f"
1066    done
1067
1068    allowed_files=
1069    [ -n "$allowed" ] && allowed_files=$(cat "$allowed")
1070    for dir in device vendor product; do
1071        for f in $(cd "$T" && test -d $dir && \
1072            find -L $dir -maxdepth 4 -name 'vendorsetup.sh' 2>/dev/null | sort); do
1073
1074            if [[ -z "$allowed" || "$allowed_files" =~ $f ]]; then
1075                echo "including $f"; . "$T/$f"
1076            else
1077                echo "ignoring $f, not in $allowed"
1078            fi
1079        done
1080    done
1081
1082    if [[ "${PWD}" == /google/cog/* ]]; then
1083        f="build/make/cogsetup.sh"
1084        echo "including $f"; . "$T/$f"
1085    fi
1086}
1087
1088function showcommands() {
1089    local T=$(gettop)
1090    if [[ -z "$TARGET_PRODUCT" ]]; then
1091        >&2 echo "TARGET_PRODUCT not set. Run lunch."
1092        return
1093    fi
1094    case $(uname -s) in
1095        Darwin)
1096            PREBUILT_NAME=darwin-x86
1097            ;;
1098        Linux)
1099            PREBUILT_NAME=linux-x86
1100            ;;
1101        *)
1102            >&2 echo Unknown host $(uname -s)
1103            return
1104            ;;
1105    esac
1106    OUT_DIR="$(_get_abs_build_var_cached OUT_DIR)"
1107    if [[ "$1" == "--regenerate" ]]; then
1108      shift 1
1109      NINJA_ARGS="-t commands $@" m
1110    else
1111      (cd $T && prebuilts/build-tools/$PREBUILT_NAME/bin/ninja \
1112          -f $OUT_DIR/combined-${TARGET_PRODUCT}.ninja \
1113          -t commands "$@")
1114    fi
1115}
1116
1117# These functions used to be here but are now standalone scripts
1118# in build/soong/bin.  Unset these for the time being so the real
1119# script is picked up.
1120# TODO: Remove this some time after a suitable delay (maybe 2025?)
1121unset allmod
1122unset aninja
1123unset cgrep
1124unset core
1125unset coredump_enable
1126unset coredump_setup
1127unset dirmods
1128unset get_build_var
1129unset get_abs_build_var
1130unset getlastscreenshot
1131unset getprebuilt
1132unset getscreenshotpath
1133unset getsdcardpath
1134unset gettargetarch
1135unset ggrep
1136unset gogrep
1137unset hmm
1138unset installmod
1139unset is64bit
1140unset isviewserverstarted
1141unset jgrep
1142unset jsongrep
1143unset key_back
1144unset key_home
1145unset key_menu
1146unset ktgrep
1147unset m
1148unset mangrep
1149unset mgrep
1150unset mm
1151unset mma
1152unset mmm
1153unset mmma
1154unset outmod
1155unset overrideflags
1156unset owngrep
1157unset pathmod
1158unset pez
1159unset pygrep
1160unset qpid
1161unset rcgrep
1162unset refreshmod
1163unset resgrep
1164unset rsgrep
1165unset run_tool_with_logging
1166unset sepgrep
1167unset sgrep
1168unset startviewserver
1169unset stopviewserver
1170unset systemstack
1171unset syswrite
1172unset tomlgrep
1173unset treegrep
1174
1175
1176validate_current_shell
1177set_global_paths
1178source_vendorsetup
1179addcompletions
1180
1181
1182