From 8eebe192d1659c541211d3b92bf8c33ddeb9c1d4 Mon Sep 17 00:00:00 2001 From: Jerome Laban Date: Sat, 7 Dec 2024 20:50:53 -0500 Subject: [PATCH] ci: Adjust for occasional emulator startup issues that cause retries. - Don't assume the order of ANR process reporting - Terminate the system UI preemptively in order to restart clean after boot --- azure-pipelines.yml | 2 +- build/scripts/android-uitest-run.sh | 45 ++++++-- build/scripts/android-uitest-wait-systemui.sh | 102 ++++++++++++++++++ build/stage-uitests-android.yml | 7 +- 4 files changed, 141 insertions(+), 15 deletions(-) create mode 100644 build/scripts/android-uitest-wait-systemui.sh diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 742dc816f..51f7b6a49 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -192,7 +192,7 @@ stages: displayName: 'WebAssembly' dependsOn: [] jobs: - - job: Linux + - job: WebAssembly timeoutInMinutes: 60 pool: vmImage: ubuntu-latest diff --git a/build/scripts/android-uitest-run.sh b/build/scripts/android-uitest-run.sh index 23f31a5db..42089abd0 100644 --- a/build/scripts/android-uitest-run.sh +++ b/build/scripts/android-uitest-run.sh @@ -13,6 +13,10 @@ export UNO_UITEST_BINARY=$BUILD_SOURCESDIRECTORY/Uno.Gallery.UITests/bin/Release export UNO_EMULATOR_INSTALLED=$BUILD_SOURCESDIRECTORY/build/.emulator_started export UITEST_TEST_TIMEOUT=60m export UNO_UITEST_ANDROIDAPK_PATH=$UNO_UITEST_ANDROIDAPK_BASEPATH/com.nventive.uno.ui.demo-Signed.apk +export ANDROID_SIMULATOR_APILEVEL=28 + +AVD_NAME=xamarin_android_emulator +AVD_CONFIG_FILE=~/.android/avd/$AVD_NAME.avd/config.ini # Override Android SDK tooling export ANDROID_HOME=$BUILD_SOURCESDIRECTORY/build/android-sdk @@ -30,28 +34,47 @@ then mv $ANDROID_HOME/platform-tools/platform-tools/* $ANDROID_HOME/platform-tools fi +AVD_NAME=xamarin_android_emulator +AVD_CONFIG_FILE=~/.android/avd/$AVD_NAME.avd/config.ini + # Install Android SDK emulators and SDKs if [ ! -f "$UNO_EMULATOR_INSTALLED" ]; then - echo "y" | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --sdk_root=${ANDROID_HOME} --install 'tools'| tr '\r' '\n' | uniq - echo "y" | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --sdk_root=${ANDROID_HOME} --install 'platform-tools' | tr '\r' '\n' | uniq - echo "y" | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --sdk_root=${ANDROID_HOME} --install 'build-tools;35.0.0' | tr '\r' '\n' | uniq - echo "y" | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --sdk_root=${ANDROID_HOME} --install 'platforms;android-28' | tr '\r' '\n' | uniq - echo "y" | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --sdk_root=${ANDROID_HOME} --install 'platforms;android-34' | tr '\r' '\n' | uniq - echo "y" | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --sdk_root=${ANDROID_HOME} --install 'extras;android;m2repository' | tr '\r' '\n' | uniq + echo "y" | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --sdk_root=${ANDROID_HOME} --install "tools"| tr '\r' '\n' | uniq + echo "y" | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --sdk_root=${ANDROID_HOME} --install "platform-tools" | tr '\r' '\n' | uniq + echo "y" | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --sdk_root=${ANDROID_HOME} --install "build-tools;35.0.0" | tr '\r' '\n' | uniq + echo "y" | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --sdk_root=${ANDROID_HOME} --install "platforms;android-$ANDROID_SIMULATOR_APILEVEL" | tr '\r' '\n' | uniq + echo "y" | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --sdk_root=${ANDROID_HOME} --install "extras;android;m2repository" | tr '\r' '\n' | uniq # Install AVD files - echo "y" | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --sdk_root=${ANDROID_HOME} --install 'system-images;android-28;google_apis_playstore;x86_64' + echo "y" | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --sdk_root=${ANDROID_HOME} --install "system-images;android-$ANDROID_SIMULATOR_APILEVEL;google_apis_playstore;x86_64" # Create emulator - echo "no" | $ANDROID_HOME/cmdline-tools/latest/bin/avdmanager create avd -n xamarin_android_emulator --abi "x86_64" -k 'system-images;android-28;google_apis_playstore;x86_64' --force + echo "no" | $ANDROID_HOME/cmdline-tools/latest/bin/avdmanager create avd -n $AVD_NAME --abi "x86_64" -k "system-images;android-$ANDROID_SIMULATOR_APILEVEL;google_apis_playstore;x86_64" --sdcard 128M --force + + # based on https://docs.microsoft.com/en-us/azure/devops/pipelines/agents/hosted?view=azure-devops&tabs=yaml#hardware + # >> Agents that run macOS images are provisioned on Mac pros with a 3 core CPU, 14 GB of RAM, and 14 GB of SSD disk space. + echo "hw.cpu.ncore=3" >> $AVD_CONFIG_FILE + + # Bump the heap size as the tests are stressing the application + echo "vm.heapSize=256M" >> $AVD_CONFIG_FILE echo $ANDROID_HOME/emulator/emulator -list-avds echo "Starting emulator" # Start emulator in background - nohup $ANDROID_HOME/emulator/emulator -avd xamarin_android_emulator -skin 1280x800 -memory 4096 -no-window -gpu swiftshader_indirect -no-snapshot -noaudio -no-boot-anim > /dev/null 2>&1 & + nohup $ANDROID_HOME/emulator/emulator \ + -avd $AVD_NAME \ + -skin 1280x800 \ + -memory 4096 \ + -no-window \ + -gpu swiftshader_indirect \ + -no-snapshot \ + -noaudio \ + -no-boot-anim \ + -prop ro.debuggable=1 \ + > $BUILD_ARTIFACTSTAGINGDIRECTORY/android-emulator-log.txt 2>&1 & touch "$UNO_EMULATOR_INSTALLED" fi @@ -61,7 +84,7 @@ mkdir -p $UNO_UITEST_SCREENSHOT_PATH cp $UNO_UITEST_ANDROIDAPK_PATH $UNO_UITEST_SCREENSHOT_PATH # Wait for the emulator to finish booting -$ANDROID_HOME/platform-tools/adb wait-for-device shell 'while [[ -z $(getprop sys.boot_completed | tr -d '\r') ]]; do sleep 1; done; input keyevent 82' +source $BUILD_SOURCESDIRECTORY/build/scripts/android-uitest-wait-systemui.sh 500 $ANDROID_HOME/platform-tools/adb devices @@ -79,3 +102,5 @@ dotnet test \ ## Dump the emulator's system log $ANDROID_HOME/platform-tools/adb shell logcat -d > $BUILD_ARTIFACTSTAGINGDIRECTORY/android-device-log.txt + +$ANDROID_HOME/platform-tools/adb exec-out screencap -p > $BUILD_ARTIFACTSTAGINGDIRECTORY/android-end-run.png diff --git a/build/scripts/android-uitest-wait-systemui.sh b/build/scripts/android-uitest-wait-systemui.sh new file mode 100644 index 000000000..2e000deb6 --- /dev/null +++ b/build/scripts/android-uitest-wait-systemui.sh @@ -0,0 +1,102 @@ +#!/usr/bin/env bash +BOOT_TIMEOUT=$1 +retry() { + local -r -i max_attempts="$1";shift 1 + local -i attempt_num=1 + local -a COMMANDS=( timeout $BOOT_TIMEOUT ) + + while (( "$#" )); do + local arg="$1"; + if [[ "$arg" = *" "* ]]; then + COMMANDS+=( $( printf "\''%s'\'" "$arg" ) ) + else + COMMANDS+=( "$arg" ) + fi + shift + done + + until "${COMMANDS[@]}" + do + if ((attempt_num==max_attempts)) + then + echo "Last attempt $attempt_num failed, exiting." + return 1 + else + echo "Attempt $attempt_num failed! Waiting $attempt_num seconds..." + sleep $((attempt_num++)) + fi + done +} + +echo "" +echo "[Waiting for device to boot] timeout $BOOT_TIMEOUT sec" + +if [ $ANDROID_SIMULATOR_APILEVEL -gt 25 ]; +then +retry 3 "$ANDROID_HOME/platform-tools/adb" wait-for-device shell 'echo "emulator is attached, wait for boot completion"; while [[ -z $(getprop sys.boot_completed | tr -d '\r') ]] && [[ "$SECONDS" -lt 300 ]]; do sleep 1; done; input keyevent 82; echo "boot is complete."' +else +retry 3 "$ANDROID_HOME/platform-tools/adb" wait-for-device shell 'echo "emulator is attached, wait for boot completion"; while [[ -z $(getprop sys.boot_completed) ]] && [[ "$SECONDS" -lt 300 ]]; do sleep 1; done; input keyevent 82; echo "boot is complete."' +fi + +# Wait for com.android.systemui to become available, +# as the CPU of the build machine may be slow +# See: https://stackoverflow.com/questions/52410440/error-system-ui-isnt-responding-while-running-aosp-build-on-emulator +# + +echo "boot_completed after $SECONDS" +echo "[Waiting for launcher to start]" +LAUNCHER_READY= +MAX_START_TIME=300 +START_TIME=$SECONDS +while [[ -z ${LAUNCHER_READY} ]]; do + + if [ $ANDROID_SIMULATOR_APILEVEL -ge 29 ]; + then + UI_FOCUS=`$ANDROID_HOME/platform-tools/adb shell dumpsys window 2>/dev/null | grep -E 'mCurrentFocus|mFocusedApp' || true` + else + UI_FOCUS=`$ANDROID_HOME/platform-tools/adb shell dumpsys window windows 2>/dev/null | grep -i mCurrentFocus || true` + fi + + ELAPSED_TIME=$(( SECONDS - START_TIME )) + if [ ${ELAPSED_TIME} -gt ${MAX_START_TIME} ]; + then + echo "(FAIL) Emulator failed to start properly after $MAX_START_TIME" + exit 1 + fi + + echo "(DEBUG $SECONDS) Current focus: ${UI_FOCUS}" + + case $UI_FOCUS in + *"Not Responding"*) + echo "Detected an ANR! Dismissing..." + $ANDROID_HOME/platform-tools/adb shell input keyevent KEYCODE_DPAD_RIGHT + $ANDROID_HOME/platform-tools/adb shell input keyevent KEYCODE_ENTER + ;; + *"Launcher"*) + LAUNCHER_READY=true + ;; + "") + echo "Waiting for window service..." + sleep 3 + ;; + *) + echo "Waiting for launcher..." + sleep 3 + + # For some reason the messaging app can be brought up in front + # (DEBUG) Current focus: mCurrentFocus=Window{1170051 u0 com.google.android.apps.messaging/com.google.android.apps.messaging.ui.ConversationListActivity} + # Try bringing back the home screen to check on the launcher. + $ANDROID_HOME/platform-tools/adb shell input keyevent KEYCODE_HOME + ;; + esac +done + +# Force terminate system UI to restart clean +adb shell am force-stop com.android.systemui + +adb shell settings put global animator_duration_scale 0 +adb shell settings put global transition_animation_scale 0 +adb shell settings put global window_animation_scale 0 + +echo "Launcher is ready!" + diff --git a/build/stage-uitests-android.yml b/build/stage-uitests-android.yml index ace863065..faa9a9900 100644 --- a/build/stage-uitests-android.yml +++ b/build/stage-uitests-android.yml @@ -14,6 +14,9 @@ clean: true - template: templates/dotnet-install-mac.yml + parameters: + UnoCheckParameters: '--tfm net9.0-android' + - template: templates/canary-updater.yml - task: PowerShell@2 @@ -59,10 +62,6 @@ - download: current artifact: Android_UITest - - template: templates/dotnet-install-mac.yml - parameters: - UnoCheckParameters: '--tfm net9.0-android' - - template: templates/canary-updater.yml - bash: |