Skip to content

Instantly share code, notes, and snippets.

@leinardi
Created June 9, 2017 14:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save leinardi/da1eac168f43bd6a0d3af149bf3f15e0 to your computer and use it in GitHub Desktop.
Save leinardi/da1eac168f43bd6a0d3af149bf3f15e0 to your computer and use it in GitHub Desktop.
#!/usr/bin/env bash
if [ "$1" == "-h" ] || [ "$1" == "--help" ] ; then
echo "`basename $0` - run a command spawning an Android Emulator before. It can be used to run Android Tests."
echo "Usage: `basename $0` COMMAND"
echo "Example: $ `basename $0` ./gradlew connectedPayGermanyCompatDebugAndroidTest --info"
exit 0
fi
# grab some variables
ADB=$ANDROID_HOME/platform-tools/adb
AVD_PREFIX="avd_"
SUCCESS=0
ERROR_PORT_LOCKED=43
ERROR_CREATING_AVD=65
ERROR_STARTING_EMULATOR=69
ERROR_WAIT_FOR_BOOT_TIMEOUT=408
LOCK_TIMEOUT_IN_SECONDS=3600
WAIT_TIMEOUT_IN_SECONDS=120
## emulator_count
if [ "x${emulator_count}" != "x" ]; then
EMULATOR_COUNT="${emulator_count}"
else
EMULATOR_COUNT="1"
fi
## android_target
if [ "x${android_package}" != "x" ]; then
ANDROID_PACKAGE="${android_package}"
else
ANDROID_PACKAGE="system-images;android-25;google_apis;x86"
fi
## android_target
if [ "x${android_abi}" != "x" ]; then
ANDROID_ABI="${android_abi}"
else
ANDROID_ABI="google_apis/x86"
fi
## android_skin
if [ "x${android_skin}" != "x" ]; then
ANDROID_SKIN="${android_skin}"
else
ANDROID_SKIN="480x800"
fi
## sdcard_size
if [ "x${sdcard_size}" != "x" ]; then
SDCARD="${sdcard_size}"
else
SDCARD="256M"
fi
## port number to start searching for free ports for the console
if [ "x${console_port_start}" != "x" ]; then
console_port="${console_port_start}"
else
console_port="5554"
fi
## port number to start searching for free ports for the console
if [ "x${TMPDIR}" == "x" ]; then
TMPDIR="/tmp"
fi
# Functions
function checkPortAndLockIt {
local CONSOLE_PORT=$1
local LOCK_FILE_PATH="$TMPDIR/${AVD_PREFIX}${CONSOLE_PORT}.lock"
if lsof -i -P -n | grep ":${CONSOLE_PORT} (LISTEN)\|:$(( ${CONSOLE_PORT} + 1 )) (LISTEN)" --quiet; then
echo ">>>>>> Port NOT available"
return $ERROR_PORT_LOCKED
else
echo ">>>>>> Port available"
if [ -f $LOCK_FILE_PATH ]; then
local LOCK_TIME=`cat ${LOCK_FILE_PATH}`
local NOW=`date +%s`
local ELAPSED=`expr $NOW - $LOCK_TIME`
if [ $ELAPSED -gt $LOCK_TIMEOUT_IN_SECONDS ]; then
echo ">>>>>> Port locked for more than 1 hour. Overriding..."
killEmulator $CONSOLE_PORT
echo `date +%s` > $LOCK_FILE_PATH
return $SUCCESS
else
echo ">>>>>> File locked"
return $ERROR_PORT_LOCKED
fi
else
echo ">>>>>> File NOT locked. Locking..."
echo `date +%s` > $LOCK_FILE_PATH
return $SUCCESS
fi
fi
}
# Create an array of free port numbers to use for the emulators
# Yes, this looks unnecessarily complex, but CONSOLE_PORT needs to
# be an even integer and can only be within a range of 5554-5584.
function findFreePorts {
echo "Searching for available ports"
for (( i=0 ; i < $EMULATOR_COUNT; i++ ))
{
while ! checkPortAndLockIt ${console_port}
do
echo "Port ${console_port} busy"
#Console Port should and can only be an even number
#Android allows only even numbers
console_port=$(( ${console_port} + 2 ))
echo PORT1 ${console_port}
done
ports[k]=${console_port}
#Console Port should and can only be an even number
#Android allows only even numbers
console_port=$(( ${console_port} + 2 ))
}
}
# create the AVD
function createAVD {
local CONSOLE_PORT=$1
echo "[emulator-$CONSOLE_PORT] Creating emulator $AVD_PREFIX$CONSOLE_PORT"
if ! echo no | ${ANDROID_HOME}/tools/bin/avdmanager create avd --force --name $AVD_PREFIX$CONSOLE_PORT --package "$ANDROID_PACKAGE" --sdcard $SDCARD --abi $ANDROID_ABI --device "4in WVGA (Nexus S)"; then
exit $ERROR_CREATING_AVD
fi
}
# start the AVD
# This starts the emulator
function startEmulator {
local CONSOLE_PORT=$1
echo "[emulator-$CONSOLE_PORT] Starting emulator with avd $AVD_PREFIX$CONSOLE_PORT and console port $CONSOLE_PORT"
${ANDROID_HOME}/tools/emulator -avd $AVD_PREFIX$CONSOLE_PORT -port $CONSOLE_PORT -skin $ANDROID_SKIN -no-boot-anim -noaudio -no-window &
# Minimum boot up time of the emulator
sleep 10
# This waits for emulator to start up
echo "[emulator-$CONSOLE_PORT] Waiting for emulator to boot completely"
wait_for_boot_complete "getprop dev.bootcomplete" 1
wait_for_boot_complete "getprop sys.boot_completed" 1
}
# unlock Emulator
function unlockEmulator {
local CONSOLE_PORT=$1
echo "[emulator-$CONSOLE_PORT] Getting out of home screen"
$ADB -s emulator-$CONSOLE_PORT shell input keyevent 82
$ADB -s emulator-$CONSOLE_PORT shell input keyevent 4
}
# disable animations
function disableAnimations {
local CONSOLE_PORT=$1
echo "[emulator-$CONSOLE_PORT] Disabling animations for less flaky tests on all devices"
$ADB -s emulator-$CONSOLE_PORT shell settings put global window_animation_scale 0
$ADB -s emulator-$CONSOLE_PORT shell settings put global transition_animation_scale 0
$ADB -s emulator-$CONSOLE_PORT shell settings put global animator_duration_scale 0
$ADB -s emulator-$CONSOLE_PORT shell settings put system window_animation_scale 0
$ADB -s emulator-$CONSOLE_PORT shell settings put system transition_animation_scale 0
$ADB -s emulator-$CONSOLE_PORT shell settings put system animator_duration_scale 0
$ADB -s emulator-$CONSOLE_PORT reboot
# Minimum boot up time of the emulator
sleep 12
# This waits for emulator to start up
echo "[emulator-$CONSOLE_PORT] Waiting for emulator to boot completely"
wait_for_boot_complete "getprop dev.bootcomplete" 1
wait_for_boot_complete "getprop sys.boot_completed" 1
}
# create one emulator instance
function createOneEmulatorInstance {
local CONSOLE_PORT=$1
createAVD $CONSOLE_PORT
startEmulator $CONSOLE_PORT
unlockEmulator $CONSOLE_PORT
disableAnimations $CONSOLE_PORT
}
# kill emulator
function killEmulator {
local CONSOLE_PORT=$1
local LOCK_FILE_PATH="$TMPDIR/${AVD_PREFIX}${CONSOLE_PORT}.lock"
echo "[emulator-$CONSOLE_PORT] Killing emulator"
$ADB -s emulator-$CONSOLE_PORT emu kill || echo "Unable to kill emulator..."
rm $LOCK_FILE_PATH || echo "Lock file not found..."
}
# create the AVD
function deleteAVD {
local CONSOLE_PORT=$1
echo "[emulator-$CONSOLE_PORT] Deleting emulator $AVD_PREFIX$CONSOLE_PORT"
echo no | ${ANDROID_HOME}/tools/bin/avdmanager delete avd --name $AVD_PREFIX$CONSOLE_PORT
}
# kill and delete one emulator instance
function killAndDeleteOneEmulatorInstance {
local CONSOLE_PORT=$1
killEmulator $CONSOLE_PORT
deleteAVD $CONSOLE_PORT
}
# function to really, really check things are booted up
function wait_for_boot_complete {
local boot_property=$1
local boot_property_test=$2
echo "[emulator-$CONSOLE_PORT] Checking $boot_property..."
local ELAPSED=0
until $ADB -s emulator-$CONSOLE_PORT shell $boot_property | grep "$boot_property_test"; do
sleep 1
let "ELAPSED++"
if [ $ELAPSED -gt $WAIT_TIMEOUT_IN_SECONDS ] ; then
echo "[emulator-$CONSOLE_PORT] ERROR: \"$1\" timeout!"
killAndDeleteOneEmulatorInstance $CONSOLE_PORT
exit $ERROR_WAIT_FOR_BOOT_TIMEOUT
fi
done
echo "[emulator-$CONSOLE_PORT] \"$1\" succesful"
}
## The main function :)
function main {
# Get an array of free port numbers to use
findFreePorts
# Based on the port number found, create an instance of an emulator up to the EMULATOR_COUNT specified
for (( l=0, i=0 ; l < ${#ports[@]}, i < $EMULATOR_COUNT; i++, l=l+3 ))
{
echo "ports for emulator $((i+1)): console=${ports[$l]}"
createOneEmulatorInstance ${ports[$l]}
}
echo Emulator startup complete!
export ANDROID_SERIAL="emulator-${ports[0]}"
CMD_TO_RUN=$@
if [[ $CMD_TO_RUN == *"spoon"* ]]; then
CMD_TO_RUN="$CMD_TO_RUN -PspoonDevice=${ANDROID_SERIAL}"
fi
echo "Running \"$CMD_TO_RUN\""
$CMD_TO_RUN
RET_CODE=$?
# Based on the port number found, create an instance of an emulator up to the EMULATOR_COUNT specified
for (( l=0, i=0 ; l < ${#ports[@]}, i < $EMULATOR_COUNT; i++, l=l+3 ))
{
echo "killing and deleting emulator $((i+1)): console=${ports[$l]}"
killAndDeleteOneEmulatorInstance ${ports[$l]}
}
}
## Execute the script
main $@
exit $RET_CODE
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment