Skip to content

[android] Run tests for libdispatch in x64 emulator (wip) #78762

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
e3d3571
[android] Run tests for libdispatch in x64 emulator (wip)
weliveindetail Jan 20, 2025
00a6f90
fixup! [android] Run tests for libdispatch in x64 emulator (wip)
weliveindetail Jan 22, 2025
d025ab2
[dev] Temporarily enable Android x86_64 in CI and test only dispatch
weliveindetail Jan 22, 2025
e256dff
Properly spawn and shutdown both, adb and the emulator
weliveindetail Jan 22, 2025
39c6b90
Switch to cross-compiled ctest driver
weliveindetail Jan 22, 2025
b9f18c0
For the moment install Java Runtime on the fly
weliveindetail Jan 24, 2025
e2a0912
Fix invalid 'zip is already extracted and up to date'
weliveindetail Jan 27, 2025
ff8a9fa
Add timer for FetchDependencies
weliveindetail Jan 27, 2025
366071a
utils: trim whitespace in build.ps1 (NFC)
weliveindetail Jan 27, 2025
bbc7c01
Don't mix up release NDK with the one installed via cmdline-tools
weliveindetail Jan 27, 2025
1d00e4b
Disable interactive mode in avdmanager
weliveindetail Jan 28, 2025
69bb836
Fix emulator path, drop ndk package, add comments
weliveindetail Jan 28, 2025
f9dd2f3
Rename: NDKDir -> SDKDir
weliveindetail Jan 28, 2025
37b97bb
Revert "Switch to cross-compiled ctest driver"
weliveindetail Jan 29, 2025
b3f8b3e
Polish script-based driver
weliveindetail Jan 29, 2025
caddf13
Use proposed ctest-android.sh from libdispatch
weliveindetail Jan 29, 2025
b23e171
[dev] Add version dumps to see what runs and what hangs
weliveindetail Jan 29, 2025
06ef134
[dev] Actually log device info before we run into wait-for-device for…
weliveindetail Jan 29, 2025
46c9954
[dev] Avoid exit if get-state fails and dump even more logs
weliveindetail Jan 30, 2025
61e96ca
[dev] Temporarily drop stdout/stderr redirects from Start-Process
weliveindetail Jan 30, 2025
4ebddee
Merge branch 'main' into android-ctest-libdispatch
weliveindetail Jan 30, 2025
4d0d2c7
[dev] Temporarily drop log dumps as well
weliveindetail Jan 30, 2025
cc59b11
[dev] Dump virtual devices with avdmanager to confirm that swift-test…
weliveindetail Jan 30, 2025
d328dcb
Set Java environment again when starting the emulator
weliveindetail Jan 30, 2025
26cfa08
[dev] Run and teardown the emulator with debug output and multipe att…
weliveindetail Feb 3, 2025
c2d9b34
Running avdmanager via Start-Process fixes the emulator crashes
weliveindetail Feb 4, 2025
f933288
Let's grant adb a few more attempts
weliveindetail Feb 4, 2025
d68524a
Merge branch 'main' into android-ctest-libdispatch
weliveindetail Feb 20, 2025
984688d
Try to grant network access permission to adb
weliveindetail Feb 20, 2025
a3595d7
[dev] More emulator params and dump verbose outputs
weliveindetail Feb 21, 2025
f12cf68
[dev] Run -accel-check and dump the output
weliveindetail Feb 21, 2025
c63f016
Dump logs in erro case as well
weliveindetail Feb 21, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions utils/android/emulator/ctest-libdispatch.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#!/system/bin/sh

if [ -z "$1" ]; then
echo "Usage: $0 <sub-directory>"
exit 1
fi

SUB_DIR=$1
if [ ! -d "$SUB_DIR" ]; then
echo "Error: Directory $SUB_DIR does not exist"
exit 1
fi

UTILITY="$SUB_DIR/bsdtestharness"
if [ ! -f "$UTILITY" ]; then
echo "Utility not found: $UTILITY."
exit 1
fi

# FIXME: Add this script to libdispatch and let CMake inject actual test at configuration time
TESTS="apply api debug queue_finalizer overcommit context_for_key after timer timer_short timer_timeout sema timer_bit31 timer_bit63 timer_set_time data io_muxed io_net io_pipe io_pipe_close select c99 plusplus"
COUNT=$(echo "$TESTS" | tr ' ' '\n' | wc -l)
echo "Found $COUNT test-cases in $SUB_DIR"

# Tests depend on libdispatch.so and libBlocksRuntime.so
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$SUB_DIR"

TIMOUT=120
FAILURE=0
chmod +x "$UTILITY"

for TEST in $TESTS; do
chmod +x "$SUB_DIR/dispatch_$TEST"
OUTPUT=$(timeout "${TIMOUT}s" "$UTILITY" "$SUB_DIR/dispatch_$TEST" 2>&1)
EC=$?
if [ $EC -eq 124 ]; then
echo "Error: dispatch_$TEST timed out after $TIMOUT seconds"
echo "************\nOutput:\n$OUTPUT\n************"
FAILURE=1
elif [ $EC -ne 0 ]; then
echo "Error: dispatch_$TEST failed"
echo "************\nOutput:\n$OUTPUT\n************"
FAILURE=1
else
echo "dispatch_$TEST passed"
fi
done

exit $FAILURE
4 changes: 3 additions & 1 deletion utils/build-windows-toolchain.bat
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ set TMPDIR=%BuildRoot%\tmp
set NINJA_STATUS=[%%f/%%t][%%p][%%es]

:: Build the -Test argument, if any, by subtracting skipped tests
set TestArg=-Test lld,lldb,swift,dispatch,foundation,xctest,swift-format,sourcekit-lsp,
set TestArg=-Test dispatch,
for %%I in (%SKIP_TESTS%) do (call set TestArg=%%TestArg:%%I,=%%)
if "%TestArg:~-1%"=="," (set TestArg=%TestArg:~0,-1%) else (set TestArg= )

Expand All @@ -77,6 +77,8 @@ powershell.exe -ExecutionPolicy RemoteSigned -File %~dp0build.ps1 ^
-ImageRoot %BuildRoot% ^
%SkipPackagingArg% ^
%TestArg% ^
-AndroidSDKs x86_64 ^
-WindowsSDKs X64 ^
-Stage %PackageRoot% ^
-Summary || (exit /b 1)

Expand Down
243 changes: 241 additions & 2 deletions utils/build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -760,7 +760,12 @@ function Fetch-Dependencies {
}
}

if ($SkipBuild -and $SkipPackaging) { return }
if ($SkipBuild -and $SkipPackaging -and -not $Test) { return }

$Stopwatch = [Diagnostics.Stopwatch]::StartNew()
if ($ToBatch) {
Write-Host -ForegroundColor Cyan "[$([DateTime]::Now.ToString("yyyy-MM-dd HH:mm:ss"))] Fetch-Dependencies..."
}

$Stopwatch = [Diagnostics.Stopwatch]::StartNew()
if ($ToBatch) {
Expand All @@ -772,7 +777,7 @@ function Fetch-Dependencies {
DownloadAndVerify $WixURL "$BinaryCache\WiX-$WiXVersion.zip" $WiXHash
Extract-ZipFile WiX-$WiXVersion.zip $BinaryCache WiX-$WiXVersion

if ($SkipBuild) { return }
if ($SkipBuild -and -not $Test) { return }

DownloadAndVerify $PinnedBuild "$BinaryCache\$PinnedToolchain.exe" $PinnedSHA256

Expand Down Expand Up @@ -865,6 +870,62 @@ function Fetch-Dependencies {
DownloadAndVerify $NDKURL "$BinaryCache\android-ndk-$AndroidNDKVersion-windows.zip" $NDKHash

Extract-ZipFile -ZipFileName "android-ndk-$AndroidNDKVersion-windows.zip" -BinaryCache $BinaryCache -ExtractPath "android-ndk-$AndroidNDKVersion" -CreateExtractPath $false

# FIXME: Both Java and Android emulator must be available in the environment.
# This is a terrible workaround. It's a waste of time and resources.
$SDKDir = "$BinaryCache\android-sdk"
if ($Test -and -not(Test-Path "$SDKDir\licenses")) {
# Download Java Runtime
switch ($BuildArchName) {
"AMD64" {
$JavaURL = "https://aka.ms/download-jdk/microsoft-jdk-17.0.14-windows-x64.zip"
$JavaHash = "3619082f4a667f52c97cce983364a517993f798ae248c411765becfd9705767f"
}
"ARM64" {
$JavaURL = "https://aka.ms/download-jdk/microsoft-jdk-17.0.14-windows-aarch64.zip"
$JavaHash = "2a12c7b3d46712de9671f5f011a3cae9ee53d5ff3b0604136ee079a906146448"
}
default { throw "Unsupported processor architecture" }
}
DownloadAndVerify $JavaURL "$BinaryCache\microsoft-jdk.zip" $JavaHash
Extract-ZipFile -ZipFileName "microsoft-jdk.zip" -BinaryCache $BinaryCache -ExtractPath "android-sdk-jdk"

# Download cmdline-tools
$CLToolsURL = "https://dl.google.com/android/repository/commandlinetools-win-11076708_latest.zip"
$CLToolsHash = "4d6931209eebb1bfb7c7e8b240a6a3cb3ab24479ea294f3539429574b1eec862"
DownloadAndVerify $CLToolsURL "$BinaryCache\android-cmdline-tools.zip" $CLToolsHash
Extract-ZipFile -ZipFileName "android-cmdline-tools.zip" -BinaryCache $BinaryCache -ExtractPath "android-sdk-cmdline-tools"

# Accept licenses
New-Item -Type Directory -Path "$SDKDir\licenses" -ErrorAction Ignore | Out-Null
Set-Content -Path "$SDKDir\licenses\android-sdk-license" -Value "24333f8a63b6825ea9c5514f83c2829b004d1fee"
Set-Content -Path "$SDKDir\licenses\android-sdk-preview-license" -Value "84831b9409646a918e30573bab4c9c91346d8abd"

# Install packages and create test device
Isolate-EnvVars {
$env:JAVA_HOME = "$BinaryCache\android-sdk-jdk\jdk-17.0.14+7"
$env:Path = "${env:JAVA_HOME}\bin;${env:Path}"

# Let cmdline-tools install itself. This is idiomatic for installing the Android SDK.
Invoke-Program "$BinaryCache\android-sdk-cmdline-tools\cmdline-tools\bin\sdkmanager.bat" -OutNull "--sdk_root=$SDKDir" '"cmdline-tools;latest"' '--channel=3'
$AndroidSdkMgr = "$SDKDir\cmdline-tools\latest\bin\sdkmanager.bat"
foreach ($Package in @('"system-images;android-29;default;x86_64"', '"platforms;android-29"', '"platform-tools"')) {
Write-Host "$AndroidSdkMgr $Package"
Invoke-Program -OutNull $AndroidSdkMgr $Package
}

# There is no way to disable interactive mode in avdmanager
"no" | & "$SDKDir\cmdline-tools\latest\bin\avdmanager.bat" create avd --force --name '"swift-test-device"' --package '"system-images;android-29;default;x86_64"'

# Dump virtual devices to confirm that swift-test-device exists
Invoke-Program "$SDKDir\cmdline-tools\latest\bin\avdmanager.bat" list avd

# Grant network access permission to CLI tool
$adb = "$BinaryCache\android-sdk\platform-tools\adb.exe"
New-NetFirewallRule -DisplayName "abd inbound" -Direction Inbound -Program $adb -RemoteAddress LocalSubnet -Action Allow
New-NetFirewallRule -DisplayName "abd outbound" -Direction Outbound -Program $adb -RemoteAddress LocalSubnet -Action Allow
}
}
}

if ($IncludeDS2) {
Expand Down Expand Up @@ -916,6 +977,124 @@ function Fetch-Dependencies {
}
}

$AndroidEmulatorPid = $null
$AndroidEmulatorArchName = $null

function AndroidEmulator-CreateDevice($ArchName) {
$DeviceName = "swift-test-device-$ArchName"
$Packages = "system-images;android-29;default;$ArchName"
$AvdTool = "$BinaryCache\android-sdk\cmdline-tools\latest\bin\avdmanager.bat"

$Output = & $AvdTool list avd
if ($Output -match $DeviceName) {
Write-Host "Found Android virtual device for arch $ArchName"
} else {
Write-Host "Create Android virtual device for arch $ArchName"
# We had issues with not closing file handles to the created AVD, which
# caused the emulator to crash at startup. Using `Start-Process` instead of
# the `&` operator prevents that.
Start-Process "cmd.exe" -ArgumentList "/c echo no | $AvdTool create avd --force --name $DeviceName --package $Packages" -NoNewWindow -Wait
}
return $DeviceName
}

function AndroidEmulator-Run($ArchName) {
if ($AndroidEmulatorArchName -ne $ArchName) {
AndroidEmulator-TearDown
}
if ($AndroidEmulatorPid -eq $null) {
Isolate-EnvVars {
$env:ANDROID_SDK_HOME = "$BinaryCache\android-sdk"
$env:JAVA_HOME = "$BinaryCache\android-sdk-jdk\jdk-17.0.14+7"
$env:Path = "${env:JAVA_HOME}\bin;${env:Path}"

Write-Host "ANDROID_SDK_HOME = $env:ANDROID_SDK_HOME"
$AvdTool = "$BinaryCache\android-sdk\cmdline-tools\latest\bin\avdmanager.bat"
Write-Host "$AvdTool list avd reports:"
Invoke-Program $AvdTool list avd

$Device = (AndroidEmulator-CreateDevice $ArchName)

Write-Host "$AvdTool list avd reports:"
Invoke-Program $AvdTool list avd

$EmuTool = "$BinaryCache\android-sdk\emulator\emulator.exe"
Write-Host "$EmuTool -list-avds reports:"
Invoke-Program $EmuTool -list-avds

Write-Host "$EmuTool -accel-check reports:"
Invoke-Program $EmuTool -accel-check

Write-Host "Start Android emulator for arch $ArchName"
$Args = "-verbose -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none -avd $Device"
foreach($Attempt in 1..5) {
$Process = Start-Process -PassThru -NoNewWindow $EmuTool -ArgumentList $Args `
-RedirectStandardError "$BinaryCache\emulator-stderr.log" `
-RedirectStandardOutput "$BinaryCache\emulator-stdout.log"
try {
Write-Host "Waiting for process $($Process.Id) to start"
Start-Sleep -Seconds 1
$_ = Get-Process -Id $Process.Id
break
} catch {
if ($Attempt -lt 5) {
Write-Host "Process $($Process.Id) failed to start, trying again..."
Start-Sleep -Seconds 3
} else {
throw "Android emulator process $($Process.Id) failed to start."
}
}
}

$global:AndroidEmulatorPid = $Process.Id
$global:AndroidEmulatorArchName = $ArchName

Write-Host "Waiting while Android emulator boots in process $AndroidEmulatorPid"
$adb = "$BinaryCache\android-sdk\platform-tools\adb.exe"
foreach($Attempt in 1..5) {
Start-Sleep -Seconds 10
$Process = Start-Process $adb "wait-for-device" -PassThru -NoNewWindow
try {
Write-Host "adb wait-for-device running in process $($Process.Id)"
Wait-Process -Id $Process.Id -Timeout 20
break
} catch {
if ($Attempt -lt 5) {
Write-Host "adb failed to connect. Shutting it down."
Stop-Process -Force -Id $Process.Id
} else {
throw "Android Debug Bridge process $($Process.Id) failed to connect."
}
}
}

Write-Host "SUCCESS: Emulator ready"
}
}
}

function AndroidEmulator-TearDown() {
if ($AndroidEmulatorPid -ne $null) {
if (Get-Process -Id $AndroidEmulatorPid -ErrorAction SilentlyContinue) {
Write-Host "Tear down Android emulator for arch $AndroidEmulatorArchName"
$adb = "$BinaryCache\android-sdk\platform-tools\adb.exe"
& $adb emu kill | Out-Null
& $adb kill-server | Out-Null

try {
Write-Host "Waiting for process $AndroidEmulatorPid to exit"
Wait-Process -Id $AndroidEmulatorPid -Timeout 1
} catch {
Write-Host "Process $AndroidEmulatorPid failed to exit. Shutting it down."
Stop-Process -Force -Id $AndroidEmulatorPid
}

$global:AndroidEmulatorPid = $null
$global:AndroidEmulatorArchName = $null
}
}
}

function Get-PinnedToolchainToolsDir() {
# NOTE: add a workaround for the main snapshots that used the wrong version
# when building that was not noticed. This allows use of the nightly snapshot
Expand Down Expand Up @@ -2165,6 +2344,50 @@ function Build-Dispatch([Platform]$Platform, $Arch, [switch]$Test = $false) {
}
}

function Test-Dispatch([Platform]$Platform) {
# Install packages and create test device
Isolate-EnvVars {
$env:JAVA_HOME = "$BinaryCache\android-sdk-jdk\jdk-17.0.14+7"
$env:Path = "${env:JAVA_HOME}\bin;${env:Path}"

# TODO: One emulator instance for all tests?
$emulator = "$BinaryCache\android-sdk\emulator\emulator.exe"
Write-Host "$emulator -version"
Invoke-Program $emulator "-version"

# Dump virtual devices (again) to confirm that swift-test-device exists
Invoke-Program "$BinaryCache\android-sdk\cmdline-tools\latest\bin\avdmanager.bat" list avd

Start-Process -FilePath $emulator -ArgumentList "@swift-test-device"
Start-Sleep -Seconds 30

# This is just a hack for now
$CachePath = (Get-TargetProjectBinaryCache $AndroidX64 Dispatch)
$CacheName = Split-Path $CachePath -Leaf
$RemoteRoot = "/data/local/tmp"

# TODO: On my local machine I have to grant adb.exe network access once. How to do that in CI?
$adb = "$BinaryCache\android-sdk\platform-tools\adb.exe"
Write-Host "$adb version"
Invoke-Program $adb "version"
Write-Host "$adb get-state @swift-test-device"
& $adb get-state "@swift-test-device"
Write-Host "$adb logcat -d @swift-test-device"
& $adb logcat -d "@swift-test-device"
#Write-Host "$BinaryCache\android-sdk\.temp\emulator.out log:"
#Write-Host (Get-Content -Path "$BinaryCache\android-sdk\.temp\emulator.out")
#Write-Host "$BinaryCache\android-sdk\.temp\emulator.err log:"
#Write-Host (Get-Content -Path "$BinaryCache\android-sdk\.temp\emulator.err")
Invoke-Program $adb "wait-for-device"
Write-Host "$adb push $CachePath $RemoteRoot"
Invoke-Program $adb push $CachePath $RemoteRoot
Write-Host "$adb shell sh $RemoteRoot/$CacheName/tests/ctest-android.sh"
Invoke-Program $adb shell "sh $RemoteRoot/$CacheName/tests/ctest-android.sh"
Invoke-Program $adb emu kill
Invoke-Program $adb kill-server
}
}

function Build-Foundation {
[CmdletBinding(PositionalBinding = $false)]
param
Expand Down Expand Up @@ -3092,6 +3315,10 @@ try {

Fetch-Dependencies

AndroidEmulator-Run $AndroidX64.LLVMName
AndroidEmulator-TearDown
exit(1)

if ($Clean) {
foreach ($project in [HostComponent]::GetNames([HostComponent])) {
if ($project -eq "Compilers") { continue }
Expand Down Expand Up @@ -3261,6 +3488,10 @@ if (-not $IsCrossCompiling) {

if ($Test -contains "dispatch") {
Build-Dispatch Windows $HostArch -Test
# TODO: This is a hack. We need different devices for different arches.
if ($AndroidSDKs -contains "x86_64") {
Test-Dispatch Android $AndroidX64
}
}
if ($Test -contains "foundation") {
Build-Foundation Windows $HostArch -Test
Expand Down Expand Up @@ -3304,6 +3535,14 @@ if (-not $IsCrossCompiling) {

exit 1
} finally {
AndroidEmulator-TearDown

Write-Host "******** emulator-stderr.log ********"
Get-Content -Path "$BinaryCache\emulator-stderr.log"

Write-Host "******** emulator-stdout.log ********"
Get-Content -Path "$BinaryCache\emulator-stdout.log"

if ($Summary) {
$TimingData | Select-Object Platform,Arch,Checkout,"Elapsed Time" | Sort-Object -Descending -Property "Elapsed Time" | Format-Table -AutoSize
}
Expand Down