diff --git a/adb/adb.bash b/adb/adb.bash new file mode 100644 index 000000000..d36bec376 --- /dev/null +++ b/adb/adb.bash @@ -0,0 +1,499 @@ +# /* vim: set ai ts=4 ft=sh: */ +# +# Copyright 2011, The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +_adb() { + if ! type -t "$1" >/dev/null; then + return + fi + + if type -t _init_completion >/dev/null; then + _init_completion || return + fi + + local where i cur serial + COMPREPLY=() + + serial="${ANDROID_SERIAL:-none}" + where=OPTIONS + for ((i=1; i <= COMP_CWORD; i++)); do + cur="${COMP_WORDS[i]}" + case "${cur}" in + -s) + where=OPT_SERIAL + ;; + -p) + where=OPT_PATH + ;; + -*) + where=OPTIONS + ;; + *) + if [[ $where == OPT_SERIAL ]]; then + where=OPT_SERIAL_ARG + serial=${cur} + else + where=COMMAND + break + fi + ;; + esac + done + + if [[ $where == COMMAND && $i -ge $COMP_CWORD ]]; then + where=OPTIONS + fi + + OPTIONS="-d -e -s -p" + COMMAND="devices connect disconnect push pull sync shell emu logcat lolcat forward jdwp install uninstall bugreport help version start-server kill-server get-state get-serialno status-window remount reboot reboot-bootloader root usb tcpip disable-verity" + + case $where in + OPTIONS|OPT_SERIAL|OPT_PATH) + COMPREPLY=( $(compgen -W "$OPTIONS $COMMAND" -- "$cur") ) + ;; + OPT_SERIAL_ARG) + local devices=$(command adb devices 2> /dev/null | grep -v "List of devices" | awk '{ print $1 }') + COMPREPLY=( $(compgen -W "${devices}" -- ${cur}) ) + ;; + COMMAND) + if [[ $i -eq $COMP_CWORD ]]; then + COMPREPLY=( $(compgen -W "$COMMAND" -- "$cur") ) + else + i=$((i+1)) + case "${cur}" in + install) + _adb_cmd_install "$serial" $i + ;; + sideload) + _adb_cmd_sideload "$serial" $i + ;; + pull) + _adb_cmd_pull "$serial" $i + ;; + push) + _adb_cmd_push "$serial" $i + ;; + reboot) + if [[ $COMP_CWORD == $i ]]; then + args="bootloader recovery" + COMPREPLY=( $(compgen -W "${args}" -- "${COMP_WORDS[i]}") ) + fi + ;; + shell) + _adb_cmd_shell "$serial" $i + ;; + uninstall) + _adb_cmd_uninstall "$serial" $i + ;; + esac + fi + ;; + esac + + return 0 +} + +_adb_cmd_install() { + local serial i cur where + + serial=$1 + i=$2 + + where=OPTIONS + for ((; i <= COMP_CWORD; i++)); do + cur="${COMP_WORDS[i]}" + case "${cur}" in + -*) + where=OPTIONS + ;; + *) + where=FILE + break + ;; + esac + done + + cur="${COMP_WORDS[COMP_CWORD]}" + if [[ $where == OPTIONS ]]; then + COMPREPLY=( $(compgen -W "-d -l -r -s" -- "${cur}") ) + return + fi + + _adb_util_complete_local_file "${cur}" '!*.apk' +} + +_adb_cmd_sideload() { + local serial i cur + + serial=$1 + i=$2 + + cur="${COMP_WORDS[COMP_CWORD]}" + + _adb_util_complete_local_file "${cur}" '!*.zip' +} + +_adb_cmd_push() { + local serial IFS=$'\n' i cur + + serial=$1 + i=$2 + + cur="${COMP_WORDS[COMP_CWORD]}" + + if [[ $COMP_CWORD == $i ]]; then + _adb_util_complete_local_file "${cur}" + elif [[ $COMP_CWORD == $(($i+1)) ]]; then + if [ "${cur}" == "" ]; then + cur="/" + fi + _adb_util_list_files $serial "${cur}" + fi +} + +_adb_cmd_pull() { + local serial IFS=$'\n' i cur + + serial=$1 + i=$2 + + cur="${COMP_WORDS[COMP_CWORD]}" + + if [[ $COMP_CWORD == $i ]]; then + if [ "${cur}" == "" ]; then + cur="/" + fi + _adb_util_list_files $serial "${cur}" + elif [[ $COMP_CWORD == $(($i+1)) ]]; then + _adb_util_complete_local_file "${cur}" + fi +} + +_adb_cmd_shell() { + local serial IFS=$'\n' i cur + local -a args + + serial=$1 + i=$2 + + cur="${COMP_WORDS[i]}" + if [ "$serial" != "none" ]; then + args=(-s $serial) + fi + + if [[ $i -eq $COMP_CWORD && ${cur:0:1} != "/" ]]; then + paths=$(command adb ${args[@]} shell echo '$'PATH 2> /dev/null | tr -d '\r' | tr : '\n') + COMMAND=$(command adb ${args[@]} shell ls $paths '2>' /dev/null | tr -d '\r' | { + while read -r tmp; do + command=${tmp##*/} + printf '%s\n' "$command" + done + }) + COMPREPLY=( $(compgen -W "$COMMAND" -- "$cur") ) + return 0 + fi + + i=$((i+1)) + case "$cur" in + ls) + _adb_shell_file_command $serial $i "--color -A -C -F -H -L -R -S -Z -a -c -d -f -h -i -k -l -m -n -p -q -r -s -t -u -x -1" + ;; + cat) + _adb_shell_file_command $serial $i "-h -e -t -u -v" + ;; + dumpsys) + _adb_cmd_shell_dumpsys "$serial" $i + ;; + am) + _adb_cmd_shell_am "$serial" $i + ;; + pm) + _adb_cmd_shell_pm "$serial" $i + ;; + /*) + _adb_util_list_files $serial "$cur" + ;; + *) + COMPREPLY=( ) + ;; + esac + + return 0 +} + +_adb_cmd_shell_dumpsys() { + local serial i cur + local -a args + local candidates + + unset IFS + + serial=$1 + i=$2 + + if [ "$serial" != "none" ]; then + args=(-s $serial) + fi + + if (( $i == $COMP_CWORD )) ; then + cur="${COMP_WORDS[COMP_CWORD]}" + # First line is a header, so need "1d". + candidates=$(command adb ${args[@]} shell dumpsys -l 2> /dev/null | sed -e '1d;s/^ *//' | tr -d '\r') + candidates="-l $candidates" + COMPREPLY=( $(compgen -W "$candidates" -- "$cur") ) + return 0 + fi + + COMPREPLY=( ) + return 0 +} + +_adb_cmd_shell_am() { + local serial i cur + local candidates + + unset IFS + + serial=$1 + i=$2 + + if (( $i == $COMP_CWORD )) ; then + cur="${COMP_WORDS[COMP_CWORD]}" + candidates="broadcast clear-debug-app clear-watch-heap dumpheap force-stop get-config get-inactive hang idle-maintenance instrument kill kill-all monitor package-importance profile restart screen-compat send-trim-memory set-debug-app set-inactive set-watch-heap stack start startservice start-user stopservice stop-user suppress-resize-config-changes switch-user task to-app-uri to-intent-uri to-uri" + COMPREPLY=( $(compgen -W "$candidates" -- "$cur") ) + return 0 + fi + + COMPREPLY=( ) + return 0 +} + + +_adb_cmd_shell_pm() { + local serial i cur + local candidates + + unset IFS + + serial=$1 + i=$2 + + if (( $i == $COMP_CWORD )) ; then + cur="${COMP_WORDS[COMP_CWORD]}" + candidates="-l -lf -p clear create-user default-state disable" + candidates+=" disable-until-used disable-user dump enable" + candidates+=" get-app-link get-install-location get-max-users" + candidates+=" get-max-running-users grant hide install" + candidates+=" install-abandon install-commit install-create" + candidates+=" install-write list move-package" + candidates+=" move-primary-storage path remove-user" + candidates+=" reset-permissions revoke set-app-link" + candidates+=" set-installer set-install-location" + candidates+=" set-permission-enforced trim-caches unhide" + candidates+=" uninstall" + COMPREPLY=( $(compgen -W "$candidates" -- "$cur") ) + return 0 + fi + + if (( $i + 1 == $COMP_CWORD )) && [[ "${COMP_WORDS[COMP_CWORD -1]}" == "list" ]] ; then + cur="${COMP_WORDS[COMP_CWORD]}" + candidates="packages permission-groups permissions instrumentation features libraries users" + COMPREPLY=( $(compgen -W "$candidates" -- "$cur") ) + return 0 + fi + + COMPREPLY=( ) + return 0 +} + +_adb_cmd_uninstall() { + local serial i where cur packages + + serial=$1 + i=$2 + if [ "$serial" != "none" ]; then + args=(-s $serial) + fi + + where=OPTIONS + for ((; i <= COMP_CWORD; i++)); do + cur="${COMP_WORDS[i]}" + case "${cur}" in + -*) + where=OPTIONS + ;; + *) + where=FILE + break + ;; + esac + done + + cur="${COMP_WORDS[COMP_CWORD]}" + if [[ $where == OPTIONS ]]; then + COMPREPLY=( $(compgen -W "-k" -- "${cur}") ) + fi + + packages="$( + command adb ${args[@]} shell pm list packages '2>' /dev/null 2> /dev/null | tr -d '\r' | { + while read -r tmp; do + local package=${tmp#package:} + echo -n "${package} " + done + } + )" + + COMPREPLY=( ${COMPREPLY[@]:-} $(compgen -W "${packages}" -- "${cur}") ) +} + +_adb_shell_file_command() { + local serial i cur file options + local -a args + + serial=$1 + i=$2 + if [ "$serial" != "none" ]; then + args=(-s $serial) + fi + options=$3 + + where=OPTIONS + for ((; i <= COMP_CWORD; i++)); do + cur="${COMP_WORDS[i]}" + case "${cur}" in + -*) + where=OPTIONS + ;; + *) + where=FILE + break + ;; + esac + done + + file="${COMP_WORDS[COMP_CWORD]}" + if [[ ${file} == "" ]]; then + file="/" + fi + + case $where in + OPTIONS) + unset IFS + COMPREPLY=( $(compgen -W "$options" -- "$cur") ) + ;; + FILE) + _adb_util_list_files $serial "$file" + ;; + esac + + return 0 +} + +_adb_util_list_files() { + local serial dir IFS=$'\n' + local -a toks + local -a args + + serial="$1" + file="$2" + + if [ "$serial" != "none" ]; then + args=(-s $serial) + fi + + if [[ $( command adb ${args[@]} shell ls -dF / '2>/dev/null' | tr -d '\r' ) == "d /" ]] ; then + toks=( ${toks[@]-} $( + command adb ${args[@]} shell ls -dF ${file}"*" '2>' /dev/null 2> /dev/null | tr -d '\r' | { + while read -r tmp; do + filetype=${tmp%% *} + filename=${tmp:${#filetype}+1} + if [[ ${filetype:${#filetype}-1:1} == d ]]; then + printf '%s/\n' "$filename" + else + printf '%s\n' "$filename" + fi + done + } + )) + else + toks=( ${toks[@]-} $( + command adb ${args[@]} shell ls -dp ${file}"*" '2>/dev/null' 2> /dev/null | tr -d '\r' + )) + fi + + # Since we're probably doing file completion here, don't add a space after. + if [[ $(type -t compopt) = "builtin" ]]; then + compopt -o nospace + fi + + COMPREPLY=( ${COMPREPLY[@]:-} "${toks[@]}" ) +} + +_adb_util_complete_local_file() +{ + local file xspec i j IFS=$'\n' + local -a dirs files + + file=$1 + xspec=$2 + + # Since we're probably doing file completion here, don't add a space after. + if [[ $(type -t compopt) = "builtin" ]]; then + compopt -o plusdirs + if [[ "${xspec}" == "" ]]; then + COMPREPLY=( ${COMPREPLY[@]:-} $(compgen -f -- "${cur}") ) + else + compopt +o filenames + COMPREPLY=( ${COMPREPLY[@]:-} $(compgen -f -X "${xspec}" -- "${cur}") ) + fi + else + # Work-around for shells with no compopt + + dirs=( $(compgen -d -- "${cur}" ) ) + + if [[ "${xspec}" == "" ]]; then + files=( ${COMPREPLY[@]:-} $(compgen -f -- "${cur}") ) + else + files=( ${COMPREPLY[@]:-} $(compgen -f -X "${xspec}" -- "${cur}") ) + fi + + COMPREPLY=( $( + for i in "${files[@]}"; do + local skip= + for j in "${dirs[@]}"; do + if [[ $i == $j ]]; then + skip=1 + break + fi + done + [[ -n $skip ]] || printf "%s\n" "$i" + done + )) + + COMPREPLY=( ${COMPREPLY[@]:-} $( + for i in "${dirs[@]}"; do + printf "%s/\n" "$i" + done + )) + fi +} + + +if [[ $(type -t compopt) = "builtin" ]]; then + complete -F _adb adb +else + complete -o nospace -F _adb adb +fi diff --git a/fastboot/fastboot.bash b/fastboot/fastboot.bash new file mode 100644 index 000000000..b91ec723e --- /dev/null +++ b/fastboot/fastboot.bash @@ -0,0 +1,182 @@ +# /* vim: set ai ts=4 ft=sh: */ +# +# Copyright 2017, The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +_fastboot() { + if ! type -t "$1" >/dev/null; then + return + fi + + if type -t _init_completion >/dev/null; then + _init_completion || return + fi + + local where i cur serial + COMPREPLY=() + + serial="${ANDROID_SERIAL:-none}" + where=OPTIONS + for ((i=1; i <= COMP_CWORD; i++)); do + cur="${COMP_WORDS[i]}" + case "${cur}" in + -s) + where=OPT_SERIAL + ;; + --slot) + where=OPT_SLOT + ;; + -*) + where=OPTIONS + ;; + *) + if [[ $where == OPT_SERIAL ]]; then + where=OPT_SERIAL_ARG + serial=${cur} + elif [[ $where == OPT_SLOT ]]; then + where=OPT_SLOT_ARG + else + where=COMMAND + break + fi + ;; + esac + done + + if [[ $where == COMMAND && $i -ge $COMP_CWORD ]]; then + where=OPTIONS + fi + + OPTIONS="-a -c --disable-verification --disable-verity -h --help -s --set_active --skip-secondary --skip-reboot --slot -u --version -w" + COMMAND="continue devices erase flash flashall flashing format getvar get_staged help oem reboot stage update" + + case $where in + OPTIONS|OPT_SERIAL) + COMPREPLY=( $(compgen -W "$OPTIONS $COMMAND" -- "$cur") ) + ;; + OPT_SERIAL_ARG) + local devices=$(command fastboot devices 2> /dev/null | awk '{ print $1 }') + COMPREPLY=( $(compgen -W "${devices}" -- ${cur}) ) + ;; + OPT_SLOT_ARG) + local slots="a all b other" + COMPREPLY=( $(compgen -W "${slots}" -- ${cur}) ) + ;; + COMMAND) + if [[ $i -eq $COMP_CWORD ]]; then + COMPREPLY=( $(compgen -W "$COMMAND" -- "$cur") ) + else + i=$((i+1)) + case "${cur}" in + flash) + _fastboot_cmd_flash "$serial" $i + ;; + reboot) + if [[ $COMP_CWORD == $i ]]; then + args="bootloader emergency" + COMPREPLY=( $(compgen -W "${args}" -- "${COMP_WORDS[i]}") ) + fi + ;; + update) + _fastboot_cmd_update "$serial" $i + ;; + esac + fi + ;; + esac + + return 0 +} + +_fastboot_cmd_flash() { + local serial i cur + local partitions + + serial=$1 + i=$2 + + cur="${COMP_WORDS[COMP_CWORD]}" + if [[ $i -eq $COMP_CWORD ]]; then + partitions="boot bootloader dtbo modem radio recovery system vbmeta vendor" + COMPREPLY=( $(compgen -W "$partitions" -- $cur) ) + else + _fastboot_util_complete_local_file "${cur}" '!*.img' + fi +} + +_fastboot_cmd_update() { + local serial i cur + + serial=$1 + i=$2 + + cur="${COMP_WORDS[COMP_CWORD]}" + + _fastboot_util_complete_local_file "${cur}" '!*.zip' +} + +_fastboot_util_complete_local_file() { + local file xspec i j IFS=$'\n' + local -a dirs files + + file=$1 + xspec=$2 + + # Since we're probably doing file completion here, don't add a space after. + if [[ $(type -t compopt) = "builtin" ]]; then + compopt -o plusdirs + if [[ "${xspec}" == "" ]]; then + COMPREPLY=( ${COMPREPLY[@]:-} $(compgen -f -- "${cur}") ) + else + compopt +o filenames + COMPREPLY=( ${COMPREPLY[@]:-} $(compgen -f -X "${xspec}" -- "${cur}") ) + fi + else + # Work-around for shells with no compopt + + dirs=( $(compgen -d -- "${cur}" ) ) + + if [[ "${xspec}" == "" ]]; then + files=( ${COMPREPLY[@]:-} $(compgen -f -- "${cur}") ) + else + files=( ${COMPREPLY[@]:-} $(compgen -f -X "${xspec}" -- "${cur}") ) + fi + + COMPREPLY=( $( + for i in "${files[@]}"; do + local skip= + for j in "${dirs[@]}"; do + if [[ $i == $j ]]; then + skip=1 + break + fi + done + [[ -n $skip ]] || printf "%s\n" "$i" + done + )) + + COMPREPLY=( ${COMPREPLY[@]:-} $( + for i in "${dirs[@]}"; do + printf "%s/\n" "$i" + done + )) + fi +} + +if [[ $(type -t compopt) = "builtin" ]]; then + complete -F _fastboot fastboot +else + complete -o nospace -F _fastboot fastboot +fi