1 # /* vim: set ai ts=4 ft=sh: */ 2 # 3 # Copyright 2011, The Android Open Source Project 4 # 5 # Licensed under the Apache License, Version 2.0 (the "License"); 6 # you may not use this file except in compliance with the License. 7 # You may obtain a copy of the License at 8 # 9 # http://www.apache.org/licenses/LICENSE-2.0 10 # 11 # Unless required by applicable law or agreed to in writing, software 12 # distributed under the License is distributed on an "AS IS" BASIS, 13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 # See the License for the specific language governing permissions and 15 # limitations under the License. 16 # 17 18 _adb() { 19 if ! type -t "$1" >/dev/null; then 20 return 21 fi 22 23 if type -t _init_completion >/dev/null; then 24 _init_completion || return 25 fi 26 27 local where i cur serial 28 COMPREPLY=() 29 30 serial="${ANDROID_SERIAL:-none}" 31 where=OPTIONS 32 for ((i=1; i <= COMP_CWORD; i++)); do 33 cur="${COMP_WORDS[i]}" 34 case "${cur}" in 35 -s) 36 where=OPT_SERIAL 37 ;; 38 -p) 39 where=OPT_PATH 40 ;; 41 -*) 42 where=OPTIONS 43 ;; 44 *) 45 if [[ $where == OPT_SERIAL ]]; then 46 where=OPT_SERIAL_ARG 47 serial=${cur} 48 else 49 where=COMMAND 50 break 51 fi 52 ;; 53 esac 54 done 55 56 if [[ $where == COMMAND && $i -ge $COMP_CWORD ]]; then 57 where=OPTIONS 58 fi 59 60 OPTIONS="-d -e -s -p" 61 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" 62 63 case $where in 64 OPTIONS|OPT_SERIAL|OPT_PATH) 65 COMPREPLY=( $(compgen -W "$OPTIONS $COMMAND" -- "$cur") ) 66 ;; 67 OPT_SERIAL_ARG) 68 local devices=$(command adb devices 2> /dev/null | grep -v "List of devices" | awk '{ print $1 }') 69 COMPREPLY=( $(compgen -W "${devices}" -- ${cur}) ) 70 ;; 71 COMMAND) 72 if [[ $i -eq $COMP_CWORD ]]; then 73 COMPREPLY=( $(compgen -W "$COMMAND" -- "$cur") ) 74 else 75 i=$((i+1)) 76 case "${cur}" in 77 install) 78 _adb_cmd_install "$serial" $i 79 ;; 80 sideload) 81 _adb_cmd_sideload "$serial" $i 82 ;; 83 pull) 84 _adb_cmd_pull "$serial" $i 85 ;; 86 push) 87 _adb_cmd_push "$serial" $i 88 ;; 89 reboot) 90 if [[ $COMP_CWORD == $i ]]; then 91 args="bootloader recovery" 92 COMPREPLY=( $(compgen -W "${args}" -- "${COMP_WORDS[i]}") ) 93 fi 94 ;; 95 shell) 96 _adb_cmd_shell "$serial" $i 97 ;; 98 uninstall) 99 _adb_cmd_uninstall "$serial" $i 100 ;; 101 esac 102 fi 103 ;; 104 esac 105 106 return 0 107 } 108 109 _adb_cmd_install() { 110 local serial i cur where 111 112 serial=$1 113 i=$2 114 115 where=OPTIONS 116 for ((; i <= COMP_CWORD; i++)); do 117 cur="${COMP_WORDS[i]}" 118 case "${cur}" in 119 -*) 120 where=OPTIONS 121 ;; 122 *) 123 where=FILE 124 break 125 ;; 126 esac 127 done 128 129 cur="${COMP_WORDS[COMP_CWORD]}" 130 if [[ $where == OPTIONS ]]; then 131 COMPREPLY=( $(compgen -W "-d -l -r -s" -- "${cur}") ) 132 return 133 fi 134 135 _adb_util_complete_local_file "${cur}" '!*.apk' 136 } 137 138 _adb_cmd_sideload() { 139 local serial i cur 140 141 serial=$1 142 i=$2 143 144 cur="${COMP_WORDS[COMP_CWORD]}" 145 146 _adb_util_complete_local_file "${cur}" '!*.zip' 147 } 148 149 _adb_cmd_push() { 150 local serial IFS=$'\n' i cur 151 152 serial=$1 153 i=$2 154 155 cur="${COMP_WORDS[COMP_CWORD]}" 156 157 if [[ $COMP_CWORD == $i ]]; then 158 _adb_util_complete_local_file "${cur}" 159 elif [[ $COMP_CWORD == $(($i+1)) ]]; then 160 if [ "${cur}" == "" ]; then 161 cur="/" 162 fi 163 _adb_util_list_files $serial "${cur}" 164 fi 165 } 166 167 _adb_cmd_pull() { 168 local serial IFS=$'\n' i cur 169 170 serial=$1 171 i=$2 172 173 cur="${COMP_WORDS[COMP_CWORD]}" 174 175 if [[ $COMP_CWORD == $i ]]; then 176 if [ "${cur}" == "" ]; then 177 cur="/" 178 fi 179 _adb_util_list_files $serial "${cur}" 180 elif [[ $COMP_CWORD == $(($i+1)) ]]; then 181 _adb_util_complete_local_file "${cur}" 182 fi 183 } 184 185 _adb_cmd_shell() { 186 local serial IFS=$'\n' i cur 187 local -a args 188 189 serial=$1 190 i=$2 191 192 cur="${COMP_WORDS[i]}" 193 if [ "$serial" != "none" ]; then 194 args=(-s $serial) 195 fi 196 197 if [[ $i -eq $COMP_CWORD && ${cur:0:1} != "/" ]]; then 198 paths=$(command adb ${args[@]} shell echo '$'PATH 2> /dev/null | tr -d '\r' | tr : '\n') 199 COMMAND=$(command adb ${args[@]} shell ls $paths '2>' /dev/null | tr -d '\r' | { 200 while read -r tmp; do 201 command=${tmp##*/} 202 printf '%s\n' "$command" 203 done 204 }) 205 COMPREPLY=( $(compgen -W "$COMMAND" -- "$cur") ) 206 return 0 207 fi 208 209 i=$((i+1)) 210 case "$cur" in 211 ls) 212 _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" 213 ;; 214 cat) 215 _adb_shell_file_command $serial $i "-h -e -t -u -v" 216 ;; 217 dumpsys) 218 _adb_cmd_shell_dumpsys "$serial" $i 219 ;; 220 am) 221 _adb_cmd_shell_am "$serial" $i 222 ;; 223 pm) 224 _adb_cmd_shell_pm "$serial" $i 225 ;; 226 /*) 227 _adb_util_list_files $serial "$cur" 228 ;; 229 *) 230 COMPREPLY=( ) 231 ;; 232 esac 233 234 return 0 235 } 236 237 _adb_cmd_shell_dumpsys() { 238 local serial i cur 239 local -a args 240 local candidates 241 242 unset IFS 243 244 serial=$1 245 i=$2 246 247 if [ "$serial" != "none" ]; then 248 args=(-s $serial) 249 fi 250 251 if (( $i == $COMP_CWORD )) ; then 252 cur="${COMP_WORDS[COMP_CWORD]}" 253 # First line is a header, so need "1d". 254 candidates=$(command adb ${args[@]} shell dumpsys -l 2> /dev/null | sed -e '1d;s/^ *//' | tr -d '\r') 255 candidates="-l $candidates" 256 COMPREPLY=( $(compgen -W "$candidates" -- "$cur") ) 257 return 0 258 fi 259 260 COMPREPLY=( ) 261 return 0 262 } 263 264 _adb_cmd_shell_am() { 265 local serial i cur 266 local candidates 267 268 unset IFS 269 270 serial=$1 271 i=$2 272 273 if (( $i == $COMP_CWORD )) ; then 274 cur="${COMP_WORDS[COMP_CWORD]}" 275 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" 276 COMPREPLY=( $(compgen -W "$candidates" -- "$cur") ) 277 return 0 278 fi 279 280 COMPREPLY=( ) 281 return 0 282 } 283 284 285 _adb_cmd_shell_pm() { 286 local serial i cur 287 local candidates 288 289 unset IFS 290 291 serial=$1 292 i=$2 293 294 if (( $i == $COMP_CWORD )) ; then 295 cur="${COMP_WORDS[COMP_CWORD]}" 296 candidates="-l -lf -p clear create-user default-state disable disable-until-used disable-user dump enable get-app-link get-install-location get-max-users grant hide install install-abandon install-commit install-create install-write list move-package move-primary-storage path remove-user reset-permissions revoke set-app-link set-installer set-install-location set-permission-enforced trim-caches unhide uninstall" 297 COMPREPLY=( $(compgen -W "$candidates" -- "$cur") ) 298 return 0 299 fi 300 301 if (( $i + 1 == $COMP_CWORD )) && [[ "${COMP_WORDS[COMP_CWORD -1]}" == "list" ]] ; then 302 cur="${COMP_WORDS[COMP_CWORD]}" 303 candidates="packages permission-groups permissions instrumentation features libraries users" 304 COMPREPLY=( $(compgen -W "$candidates" -- "$cur") ) 305 return 0 306 fi 307 308 COMPREPLY=( ) 309 return 0 310 } 311 312 _adb_cmd_uninstall() { 313 local serial i where cur packages 314 315 serial=$1 316 i=$2 317 if [ "$serial" != "none" ]; then 318 args=(-s $serial) 319 fi 320 321 where=OPTIONS 322 for ((; i <= COMP_CWORD; i++)); do 323 cur="${COMP_WORDS[i]}" 324 case "${cur}" in 325 -*) 326 where=OPTIONS 327 ;; 328 *) 329 where=FILE 330 break 331 ;; 332 esac 333 done 334 335 cur="${COMP_WORDS[COMP_CWORD]}" 336 if [[ $where == OPTIONS ]]; then 337 COMPREPLY=( $(compgen -W "-k" -- "${cur}") ) 338 fi 339 340 packages="$( 341 command adb ${args[@]} shell pm list packages '2>' /dev/null 2> /dev/null | tr -d '\r' | { 342 while read -r tmp; do 343 local package=${tmp#package:} 344 echo -n "${package} " 345 done 346 } 347 )" 348 349 COMPREPLY=( ${COMPREPLY[@]:-} $(compgen -W "${packages}" -- "${cur}") ) 350 } 351 352 _adb_shell_file_command() { 353 local serial i cur file options 354 local -a args 355 356 serial=$1 357 i=$2 358 if [ "$serial" != "none" ]; then 359 args=(-s $serial) 360 fi 361 options=$3 362 363 where=OPTIONS 364 for ((; i <= COMP_CWORD; i++)); do 365 cur="${COMP_WORDS[i]}" 366 case "${cur}" in 367 -*) 368 where=OPTIONS 369 ;; 370 *) 371 where=FILE 372 break 373 ;; 374 esac 375 done 376 377 file="${COMP_WORDS[COMP_CWORD]}" 378 if [[ ${file} == "" ]]; then 379 file="/" 380 fi 381 382 case $where in 383 OPTIONS) 384 unset IFS 385 COMPREPLY=( $(compgen -W "$options" -- "$cur") ) 386 ;; 387 FILE) 388 _adb_util_list_files $serial "$file" 389 ;; 390 esac 391 392 return 0 393 } 394 395 _adb_util_list_files() { 396 local serial dir IFS=$'\n' 397 local -a toks 398 local -a args 399 400 serial="$1" 401 file="$2" 402 403 if [ "$serial" != "none" ]; then 404 args=(-s $serial) 405 fi 406 407 if [[ $( command adb ${args[@]} shell ls -dF / '2>/dev/null' | tr -d '\r' ) == "d /" ]] ; then 408 toks=( ${toks[@]-} $( 409 command adb ${args[@]} shell ls -dF ${file}"*" '2>' /dev/null 2> /dev/null | tr -d '\r' | { 410 while read -r tmp; do 411 filetype=${tmp%% *} 412 filename=${tmp:${#filetype}+1} 413 if [[ ${filetype:${#filetype}-1:1} == d ]]; then 414 printf '%s/\n' "$filename" 415 else 416 printf '%s\n' "$filename" 417 fi 418 done 419 } 420 )) 421 else 422 toks=( ${toks[@]-} $( 423 command adb ${args[@]} shell ls -dp ${file}"*" '2>/dev/null' 2> /dev/null | tr -d '\r' 424 )) 425 fi 426 427 # Since we're probably doing file completion here, don't add a space after. 428 if [[ $(type -t compopt) = "builtin" ]]; then 429 compopt -o nospace 430 fi 431 432 COMPREPLY=( ${COMPREPLY[@]:-} "${toks[@]}" ) 433 } 434 435 _adb_util_complete_local_file() 436 { 437 local file xspec i j IFS=$'\n' 438 local -a dirs files 439 440 file=$1 441 xspec=$2 442 443 # Since we're probably doing file completion here, don't add a space after. 444 if [[ $(type -t compopt) = "builtin" ]]; then 445 compopt -o plusdirs 446 if [[ "${xspec}" == "" ]]; then 447 COMPREPLY=( ${COMPREPLY[@]:-} $(compgen -f -- "${cur}") ) 448 else 449 compopt +o filenames 450 COMPREPLY=( ${COMPREPLY[@]:-} $(compgen -f -X "${xspec}" -- "${cur}") ) 451 fi 452 else 453 # Work-around for shells with no compopt 454 455 dirs=( $(compgen -d -- "${cur}" ) ) 456 457 if [[ "${xspec}" == "" ]]; then 458 files=( ${COMPREPLY[@]:-} $(compgen -f -- "${cur}") ) 459 else 460 files=( ${COMPREPLY[@]:-} $(compgen -f -X "${xspec}" -- "${cur}") ) 461 fi 462 463 COMPREPLY=( $( 464 for i in "${files[@]}"; do 465 local skip= 466 for j in "${dirs[@]}"; do 467 if [[ $i == $j ]]; then 468 skip=1 469 break 470 fi 471 done 472 [[ -n $skip ]] || printf "%s\n" "$i" 473 done 474 )) 475 476 COMPREPLY=( ${COMPREPLY[@]:-} $( 477 for i in "${dirs[@]}"; do 478 printf "%s/\n" "$i" 479 done 480 )) 481 fi 482 } 483 484 485 if [[ $(type -t compopt) = "builtin" ]]; then 486 complete -F _adb adb 487 else 488 complete -o nospace -F _adb adb 489 fi 490