param( [Parameter(Mandatory = $true)] [string]$OutputDir, [string]$AndroidSdk, [string]$NdkRoot ) $ErrorActionPreference = 'Stop' $repo = (Resolve-Path (Join-Path $PSScriptRoot '..')).Path if (-not $AndroidSdk) { if (-not $env:LOCALAPPDATA) { throw 'pass -AndroidSdk when LOCALAPPDATA is unavailable' } $AndroidSdk = Join-Path $env:LOCALAPPDATA 'Android\Sdk' } $sdk = (Resolve-Path $AndroidSdk).Path if (-not $NdkRoot) { $NdkRoot = Join-Path $sdk 'ndk\27.0.12077973' } $ndk = (Resolve-Path $NdkRoot).Path $clang = Join-Path $ndk 'toolchains\llvm\prebuilt\windows-x86_64\bin\aarch64-linux-android34-clang.cmd' $ar = Join-Path $ndk 'toolchains\llvm\prebuilt\windows-x86_64\bin\llvm-ar.exe' foreach ($tool in @($clang, $ar)) { if (-not (Test-Path -LiteralPath $tool -PathType Leaf)) { throw "missing NDK tool: $tool" } } $sourceProperties = Get-Content -Raw -LiteralPath (Join-Path $ndk 'source.properties') if ($sourceProperties -notmatch '(?m)^Pkg\.Revision\s*=\s*27\.') { throw "DinoVision's API-34 camera build requires NDK r27; got $sourceProperties" } $destination = [System.IO.Path]::GetFullPath($OutputDir) if (Test-Path -LiteralPath $destination) { if (@(Get-ChildItem -LiteralPath $destination -Force).Count -ne 0) { throw "Refusing to merge Android build output into non-empty directory: $destination" } } else { New-Item -ItemType Directory -Path $destination | Out-Null } $env:ANDROID_HOME = $sdk $env:ANDROID_SDK_ROOT = $sdk $env:ANDROID_NDK_ROOT = $ndk $env:ANDROID_NDK_HOME = $ndk $env:CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER = $clang $env:CC_aarch64_linux_android = $clang $env:AR_aarch64_linux_android = $ar $cargo = (Get-Command cargo).Source function Run-Cargo([string[]]$Arguments, [string]$Name) { $process = Start-Process ` -FilePath $cargo ` -ArgumentList $Arguments ` -NoNewWindow ` -Wait ` -PassThru ` -RedirectStandardOutput (Join-Path $destination "$Name.stdout.log") ` -RedirectStandardError (Join-Path $destination "$Name.stderr.log") if ($process.ExitCode -ne 0) { throw "$Name failed with code $($process.ExitCode)" } } Push-Location $repo try { Run-Cargo @( 'build', '--locked', '--release', '--target', 'aarch64-linux-android', '--example', 'bench', '--example', 'evaluate_decoder' ) 'native-build' Run-Cargo @('apk', 'build', '--release', '--package', 'dinovision-xr') 'apk-build' } finally { Pop-Location } $built = [ordered]@{ 'bench' = Join-Path $repo 'target\aarch64-linux-android\release\examples\bench' 'evaluate_decoder' = Join-Path $repo 'target\aarch64-linux-android\release\examples\evaluate_decoder' 'dinovision_xr.apk' = Join-Path $repo 'target\release\apk\dinovision_xr.apk' } $artifacts = @() foreach ($entry in $built.GetEnumerator()) { if (-not (Test-Path -LiteralPath $entry.Value -PathType Leaf)) { throw "expected Android artifact is missing: $($entry.Value)" } $target = Join-Path $destination $entry.Key Copy-Item -LiteralPath $entry.Value -Destination $target $artifacts += [ordered]@{ name = $entry.Key bytes = (Get-Item -LiteralPath $target).Length sha256 = (Get-FileHash -LiteralPath $target -Algorithm SHA256).Hash.ToLowerInvariant() } } $buildTools = Get-ChildItem -LiteralPath (Join-Path $sdk 'build-tools') -Directory | Sort-Object { [version]$_.Name } -Descending | Select-Object -First 1 $aapt = Join-Path $buildTools.FullName 'aapt.exe' if (-not (Test-Path -LiteralPath $aapt -PathType Leaf)) { throw 'aapt.exe was not found' } & $aapt dump badging (Join-Path $destination 'dinovision_xr.apk') | Set-Content -LiteralPath (Join-Path $destination 'apk-badging.txt') -Encoding utf8 if ($LASTEXITCODE -ne 0) { throw 'could not inspect the XR APK manifest' } $badging = Get-Content -Raw -LiteralPath (Join-Path $destination 'apk-badging.txt') if ($badging -notmatch "package: name='rust\.dinovision_xr'" -or $badging -notmatch "launchable-activity: name='android\.app\.NativeActivity'") { throw 'XR APK package/activity does not match the device harness defaults' } $cargoApk = (Get-Command cargo-apk).Source $record = [ordered]@{ schema_version = 1 completed_utc = [DateTime]::UtcNow.ToString('o') target = 'aarch64-linux-android' android_api = 34 android_sdk = $sdk ndk = $ndk ndk_source_properties = $sourceProperties.Trim() rustc = (& rustc --version --verbose) -join "`n" cargo = (& $cargo --version --verbose) -join "`n" cargo_apk_sha256 = (Get-FileHash -LiteralPath $cargoApk -Algorithm SHA256).Hash.ToLowerInvariant() package = 'rust.dinovision_xr' activity = 'android.app.NativeActivity' artifacts = $artifacts } $record | ConvertTo-Json -Depth 6 | Set-Content -LiteralPath (Join-Path $destination 'android-build.json') -Encoding utf8 Write-Output "wrote checked Android artifacts to $destination"