1#!/bin/bash
2#
3# This script contains helper functions to wait-for-device for an adb device with recovery.
4
5readonly DEVICE_CONNECTION_TIMEOUT_SECONDS=120
6readonly DEVICE_CONNECTION_RETRY_COUNT=5
7# This constant may be updated by the inheriting script.
8OUTPUT_DIR=${PWD}/out
9HARDWARE_TYPE=""
10DEVICE_SERIAL=""
11
12function print_log() {
13  echo -e "[$(date +'%Y-%m-%d %H:%M:%S%z')] ${@}" | tee -a ${OUTPUT_DIR}/log.txt
14}
15
16# Fetches device information from the adb device.
17# This method should be called during the script initialization and while the device is still
18# connected.
19function fetch_device_info() {
20  readonly HARDWARE_TYPE=$(adb shell getprop ro.hardware.type)
21  if [ -z ${ANDROID_SERIAL} ]; then
22    readonly DEVICE_SERIAL=$(adb devices | grep -e "device$" | sed 's/\t/ /g' | cut -f1 -d' ')
23  else
24    readonly DEVICE_SERIAL=${ANDROID_SERIAL}
25  fi
26  if [[ -z ${DEVICE_SERIAL} || $(wc -l <<< "${DEVICE_SERIAL}") -ne 1 ]]; then
27    print_log "Failed to get device serial '${DEVICE_SERIAL}'. Exiting"
28    exit 1
29  fi
30}
31
32function aae_device_recover() {
33  if [[ ${HARDWARE_TYPE} != "automotive" ]]; then
34    print_log "Non automotive device detected. Skipping device recovery"
35  fi
36  if [ ! -f ~/.aae-toolbox/bin/bashrc ]; then
37    print_log "AAE toolbox not found at '~/.aae-toolbox/bin/bashrc'. Skipping device recovery"
38  fi
39  source ~/.aae-toolbox/bin/bashrc
40  device_state=$(aae device list | grep ${DEVICE_SERIAL})
41  device_count=$(grep -e missing -e recovery -e fastboot <<< ${device_state} | wc -l)
42  if [ ${device_count} -eq 0 ]; then
43    print_log "Don't have to recover ${DEVICE_SERIAL}. Skipping device recovery."\
44      "\n\tDevice state:\n\t\t${device_state}"
45    return
46  fi
47  aae device recover ${DEVICE_SERIAL}
48}
49
50is_exit_on_err_set=false
51function _set_no_exit_on_error() {
52  if [[ $- =~ "e" ]]; then
53    is_exit_on_err_set=true
54  else
55    is_exit_on_err_set=false
56  fi
57  set +e
58}
59
60function _reset_exit_on_error() {
61  if [ ${is_exit_on_err_set} == true ]; then
62    set -e
63  else
64    set +e
65  fi
66}
67
68is_adb_device_connected=false
69function adb_wait_for_device_with_recovery() {
70  print_log "Waiting for device connection with recovery after"\
71    "${DEVICE_CONNECTION_TIMEOUT_SECONDS} seconds"
72  is_adb_device_connected=false
73  _set_no_exit_on_error
74  timeout -k 10 ${DEVICE_CONNECTION_TIMEOUT_SECONDS} adb wait-for-device
75  if [ $? -eq 0 ]; then
76    is_adb_device_connected=true
77    print_log "\t...Device connected"
78    _reset_exit_on_error
79    return
80  fi
81  total_retries=0
82  while [ ${total_retries} -lt ${DEVICE_CONNECTION_RETRY_COUNT} ]; do
83    total_retries+=1
84    print_log "Device is in bad state. Trying to recover device. Recovery attempt #${total_retries}"
85    aae_device_recover
86    timeout -k 10 ${DEVICE_CONNECTION_TIMEOUT_SECONDS} adb wait-for-device
87    if [ $? -eq 0 ]; then # Exit status is 124 if the command times out. Refer to `timeout --help`
88      print_log "\t...Device connected"
89      print_log "Generating post recovery bugreport for attempt #${total_retries}"
90      adb bugreport ${OUTPUT_DIR}/post_recovery_bugreport_${total_retries}.zip
91      is_adb_device_connected=true
92      break
93    fi
94  done
95  _reset_exit_on_error
96}
97
98function execute_on_adb_connect() {
99  command="$@"
100  adb_wait_for_device_with_recovery
101  if [ ${is_adb_device_connected} != true ]; then
102    print_log "ADB device '${DEVICE_SERIAL}' is not connected. Exiting"
103    return
104  fi
105  command
106}
107
108function adb_wait_with_recovery() {
109  adb_wait_for_device_with_recovery
110  if [ ${is_adb_device_connected} != true ]; then
111    print_log "ADB device '${DEVICE_SERIAL}' is not connected. Exiting"
112    exit 1
113  fi
114}
115