From 67b6be047dbd25ed09d2c485ed4e7ec8353bd3e5 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Thu, 14 May 2026 09:04:54 -0500 Subject: [PATCH 1/5] Move OpenJDK installation from xaprepare to MSBuild NoTargets project Migrate the JDK download/install from the xaprepare bootstrapper (Step_InstallAdoptOpenJDK) to a new src/openjdk MSBuild NoTargets project, modeled after src/binutils. The new project: - Downloads the Microsoft OpenJDK archive (platform-specific) - Downloads and verifies hash of all downloads - Extracts and installs to $(AndroidToolchainDirectory)/jdk-21 - Supports incremental builds via MSBuild Inputs/Outputs - Validates root directory and key JDK files after install - Handles Windows (.zip via Unzip task) and Linux/macOS (.tar.gz via tar) - Handles macOS Contents/Home subdirectory structure Projects that depend on the JDK now have a ProjectReference to src/openjdk, ensuring correct build ordering: - src/manifestmerger (gradle + JAVA_HOME) - src/r8 (gradle + JAVA_HOME) - src/proguard-android (gradle + JAVA_HOME) - src/bundletool (uses jar to extract/repack) - src/java-runtime (uses javac, jar, java) Also removes all JI_JAVA_HOME usage, which was a redundant alias for JAVA_HOME set in CI pipelines. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- Configuration.props | 5 + Xamarin.Android.sln | 7 + .../automation/azure-pipelines-nightly.yaml | 2 +- .../yaml-templates/setup-jdk-variables.yaml | 9 +- .../ConfigAndData/Configurables.Linux.cs | 7 - .../ConfigAndData/Configurables.MacOS.cs | 3 - .../ConfigAndData/Configurables.Unix.cs | 3 - .../ConfigAndData/Configurables.Windows.cs | 9 - .../xaprepare/ConfigAndData/Configurables.cs | 15 - .../xaprepare/OperatingSystems/OS.cs | 5 +- .../Scenario_AndroidTestDependencies.cs | 3 +- .../Scenario_EmulatorTestDependencies.cs | 2 +- .../xaprepare/Scenarios/Scenario_Standard.cs | 1 - .../Steps/Step_InstallAdoptOpenJDK.Linux.cs | 14 - .../Steps/Step_InstallAdoptOpenJDK.MacOS.cs | 21 -- .../Steps/Step_InstallAdoptOpenJDK.Unix.cs | 14 - .../Steps/Step_InstallAdoptOpenJDK.Windows.cs | 44 --- .../Steps/Step_InstallAdoptOpenJDK.cs | 296 ------------------ .../Android/AndroidSdkResolver.cs | 2 - src/bundletool/bundletool.csproj | 4 + src/java-runtime/java-runtime.csproj | 1 + src/manifestmerger/manifestmerger.csproj | 4 + src/openjdk/openjdk.csproj | 13 + src/openjdk/openjdk.targets | 135 ++++++++ src/proguard-android/proguard-android.csproj | 5 + src/r8/r8.csproj | 1 + 26 files changed, 181 insertions(+), 444 deletions(-) delete mode 100644 build-tools/xaprepare/xaprepare/Steps/Step_InstallAdoptOpenJDK.Linux.cs delete mode 100644 build-tools/xaprepare/xaprepare/Steps/Step_InstallAdoptOpenJDK.MacOS.cs delete mode 100644 build-tools/xaprepare/xaprepare/Steps/Step_InstallAdoptOpenJDK.Unix.cs delete mode 100644 build-tools/xaprepare/xaprepare/Steps/Step_InstallAdoptOpenJDK.Windows.cs delete mode 100644 build-tools/xaprepare/xaprepare/Steps/Step_InstallAdoptOpenJDK.cs create mode 100644 src/openjdk/openjdk.csproj create mode 100644 src/openjdk/openjdk.targets diff --git a/Configuration.props b/Configuration.props index 0508c786162..a7afd867f20 100644 --- a/Configuration.props +++ b/Configuration.props @@ -125,6 +125,11 @@ A099CFA1543F55593BC2ED16A70A7C67FE54B1747BB7301F37FDFD6D91028E29 L_18.1.6-8.0.0-1 5394EA6C411DA3A08BF0E6A87E1DD1B98BD2562B896C0CACD18E29E2FD4C0660 + + 21.0.8 + jdk-21 + jdk-21.0.8+9 + $(AndroidToolchainDirectory)\$(MicrosoftOpenJDKFolder) $(NUGET_PACKAGES) $(userprofile)\.nuget\packages $(HOME)/.nuget/packages diff --git a/Xamarin.Android.sln b/Xamarin.Android.sln index c6fd17c93c2..098c1230156 100644 --- a/Xamarin.Android.sln +++ b/Xamarin.Android.sln @@ -93,6 +93,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "bundletool", "src\bundletoo EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "binutils", "src\binutils\binutils.csproj", "{B2BC20D1-F468-46A9-B9B0-1C80CC4D4F36}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "openjdk", "src\openjdk\openjdk.csproj", "{7A180B05-DE3F-4D89-9F40-03A8E186AE82}" +EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "jit-times", "tools\jit-times\jit-times.csproj", "{F3CFF31C-037B-450F-B22D-1D6E529B2DCC}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MSBuildDeviceIntegration", "tests\MSBuildDeviceIntegration\MSBuildDeviceIntegration.csproj", "{16DB2680-399B-4111-AA26-6CDBBFA334D8}" @@ -307,6 +309,10 @@ Global {B2BC20D1-F468-46A9-B9B0-1C80CC4D4F36}.Debug|AnyCPU.Build.0 = Debug|Any CPU {B2BC20D1-F468-46A9-B9B0-1C80CC4D4F36}.Release|AnyCPU.ActiveCfg = Release|Any CPU {B2BC20D1-F468-46A9-B9B0-1C80CC4D4F36}.Release|AnyCPU.Build.0 = Release|Any CPU + {7A180B05-DE3F-4D89-9F40-03A8E186AE82}.Debug|AnyCPU.ActiveCfg = Debug|Any CPU + {7A180B05-DE3F-4D89-9F40-03A8E186AE82}.Debug|AnyCPU.Build.0 = Debug|Any CPU + {7A180B05-DE3F-4D89-9F40-03A8E186AE82}.Release|AnyCPU.ActiveCfg = Release|Any CPU + {7A180B05-DE3F-4D89-9F40-03A8E186AE82}.Release|AnyCPU.Build.0 = Release|Any CPU {F3CFF31C-037B-450F-B22D-1D6E529B2DCC}.Debug|AnyCPU.ActiveCfg = Debug|Any CPU {F3CFF31C-037B-450F-B22D-1D6E529B2DCC}.Debug|AnyCPU.Build.0 = Debug|Any CPU {F3CFF31C-037B-450F-B22D-1D6E529B2DCC}.Release|AnyCPU.ActiveCfg = Release|Any CPU @@ -438,6 +444,7 @@ Global {0C31DE30-F9DF-4312-BFFE-DCAD558CCF08} = {04E3E11E-B47D-4599-8AFC-50515A95E715} {A0AEF446-3368-4591-9DE6-BC3B2B33337D} = {04E3E11E-B47D-4599-8AFC-50515A95E715} {B2BC20D1-F468-46A9-B9B0-1C80CC4D4F36} = {04E3E11E-B47D-4599-8AFC-50515A95E715} + {7A180B05-DE3F-4D89-9F40-03A8E186AE82} = {04E3E11E-B47D-4599-8AFC-50515A95E715} {F3CFF31C-037B-450F-B22D-1D6E529B2DCC} = {864062D3-A415-4A6F-9324-5820237BA058} {16DB2680-399B-4111-AA26-6CDBBFA334D8} = {CAB438D8-B0F5-4AF0-BEBD-9E2ADBD7B483} {372E8E3E-29D5-4B4D-88A2-4711CD628C4E} = {05C3B1D6-A4CE-4534-A9E4-E9117591ADF7} diff --git a/build-tools/automation/azure-pipelines-nightly.yaml b/build-tools/automation/azure-pipelines-nightly.yaml index 2e942eb248d..e95bc47d727 100644 --- a/build-tools/automation/azure-pipelines-nightly.yaml +++ b/build-tools/automation/azure-pipelines-nightly.yaml @@ -138,7 +138,7 @@ stages: avdApiLevel: $(avdApiLevel) avdAbi: $(avdAbi) avdType: $(avdType) - emulatorMSBuildArgs: -p:JavaSdkDirectory=$(JI_JAVA_HOME_DEFAULT) + emulatorMSBuildArgs: -p:JavaSdkDirectory=$(JAVA_HOME) - template: /build-tools/automation/yaml-templates/apk-instrumentation.yaml parameters: diff --git a/build-tools/automation/yaml-templates/setup-jdk-variables.yaml b/build-tools/automation/yaml-templates/setup-jdk-variables.yaml index 8282fcaf6a9..07946b2a35b 100644 --- a/build-tools/automation/yaml-templates/setup-jdk-variables.yaml +++ b/build-tools/automation/yaml-templates/setup-jdk-variables.yaml @@ -13,14 +13,9 @@ steps: } $jdkHomePath=$xaPrepareJdkPath if ("${{ parameters.useAgentJdkPath }}" -eq "true") { - $defaultJdkHomeVarName="JAVA_HOME_$(DefaultJavaSdkMajorVersion)_${agentArch}" - $defaultJdkHomePath=(Get-Item -Path "env:$defaultJdkHomeVarName").Value $jdkHomeVarName="JAVA_HOME_${jdkMajorVersion}_${agentArch}" $jdkHomePath=(Get-Item -Path "env:$jdkHomeVarName").Value } - Write-Host "Setting variable 'JI_JAVA_HOME_DEFAULT' to '$defaultJdkHomePath'" - Write-Host "##vso[task.setvariable variable=JI_JAVA_HOME_DEFAULT]$defaultJdkHomePath" - Write-Host "Setting variable 'JAVA_HOME' and 'JI_JAVA_HOME' to '$jdkHomePath'" + Write-Host "Setting variable 'JAVA_HOME' to '$jdkHomePath'" Write-Host "##vso[task.setvariable variable=JAVA_HOME]$jdkHomePath" - Write-Host "##vso[task.setvariable variable=JI_JAVA_HOME]$jdkHomePath" - displayName: set JAVA_HOME and JI_JAVA_HOME + displayName: set JAVA_HOME diff --git a/build-tools/xaprepare/xaprepare/ConfigAndData/Configurables.Linux.cs b/build-tools/xaprepare/xaprepare/ConfigAndData/Configurables.Linux.cs index 3c8c33b2a26..be98ee37cb6 100644 --- a/build-tools/xaprepare/xaprepare/ConfigAndData/Configurables.Linux.cs +++ b/build-tools/xaprepare/xaprepare/ConfigAndData/Configurables.Linux.cs @@ -4,13 +4,6 @@ namespace Xamarin.Android.Prepare { partial class Configurables { - const string AdoptOpenJDKUpdate = "345"; - const string AdoptOpenJDKBuild = "b01"; - - const string JetBrainsOpenJDKOperatingSystem = "linux-x64"; - const string MicrosoftOpenJDKOperatingSystem = "linux-x64"; - const string AdoptOpenJDKOperatingSystem = "x64_linux"; - partial class Defaults { public const string NativeLibraryExtension = ".so"; diff --git a/build-tools/xaprepare/xaprepare/ConfigAndData/Configurables.MacOS.cs b/build-tools/xaprepare/xaprepare/ConfigAndData/Configurables.MacOS.cs index 0ef308b7101..3ea71d15b40 100644 --- a/build-tools/xaprepare/xaprepare/ConfigAndData/Configurables.MacOS.cs +++ b/build-tools/xaprepare/xaprepare/ConfigAndData/Configurables.MacOS.cs @@ -1,12 +1,9 @@ using System; -using System.Runtime.InteropServices; namespace Xamarin.Android.Prepare { partial class Configurables { - static string MicrosoftOpenJDKOperatingSystem = RuntimeInformation.OSArchitecture == Architecture.Arm64 ? "macos-aarch64": "macos-x64"; - partial class Defaults { public const string NativeLibraryExtension = ".dylib"; diff --git a/build-tools/xaprepare/xaprepare/ConfigAndData/Configurables.Unix.cs b/build-tools/xaprepare/xaprepare/ConfigAndData/Configurables.Unix.cs index 0b74c9d285c..01b91fbcf68 100644 --- a/build-tools/xaprepare/xaprepare/ConfigAndData/Configurables.Unix.cs +++ b/build-tools/xaprepare/xaprepare/ConfigAndData/Configurables.Unix.cs @@ -5,9 +5,6 @@ namespace Xamarin.Android.Prepare { partial class Configurables { - const string MicrosoftOpenJDKFileExtension = "tar.gz"; - const string AdoptOpenJDKArchiveExtension = "tar.gz"; - partial class Defaults { public const string DefaultCompiler = "cc"; diff --git a/build-tools/xaprepare/xaprepare/ConfigAndData/Configurables.Windows.cs b/build-tools/xaprepare/xaprepare/ConfigAndData/Configurables.Windows.cs index 77e92649628..e4b80c85147 100644 --- a/build-tools/xaprepare/xaprepare/ConfigAndData/Configurables.Windows.cs +++ b/build-tools/xaprepare/xaprepare/ConfigAndData/Configurables.Windows.cs @@ -5,15 +5,6 @@ namespace Xamarin.Android.Prepare { partial class Configurables { - const string AdoptOpenJDKUpdate = "345"; - const string AdoptOpenJDKBuild = "b01"; - - const string JetBrainsOpenJDKOperatingSystem = "windows-x64"; - const string MicrosoftOpenJDKOperatingSystem = "windows-x64"; - const string MicrosoftOpenJDKFileExtension = "zip"; - const string AdoptOpenJDKOperatingSystem = "x64_windows"; - const string AdoptOpenJDKArchiveExtension = "zip"; - partial class Defaults { public const string NativeLibraryExtension = ".dll"; diff --git a/build-tools/xaprepare/xaprepare/ConfigAndData/Configurables.cs b/build-tools/xaprepare/xaprepare/ConfigAndData/Configurables.cs index 77a9c8a440a..a48f23b95f7 100644 --- a/build-tools/xaprepare/xaprepare/ConfigAndData/Configurables.cs +++ b/build-tools/xaprepare/xaprepare/ConfigAndData/Configurables.cs @@ -16,18 +16,11 @@ namespace Xamarin.Android.Prepare partial class Configurables { const string MicrosoftOpenJDKVersion = "21.0.8"; - const string MicrosoftOpenJDKRelease = "21.0.8"; - const string MicrosoftOpenJDKRootDirName = "jdk-21.0.8+9"; static Context ctx => Context.Instance; public static partial class Urls { - // https://aka.ms/download-jdk/microsoft-jdk-17.0.11-linux-x64.tar.gz - // https://aka.ms/download-jdk/microsoft-jdk-17.0.11-macOS-x64.tar.gz or https://aka.ms/download-jdk/microsoft-jdk-17.0.11-macos-aarch64.pkg - // https://aka.ms/download-jdk/microsoft-jdk-17.0.11-windows-x64.zip - public static readonly Uri MicrosoftOpenJDK = new Uri ($"https://aka.ms/download-jdk/microsoft-jdk-{MicrosoftOpenJDKVersion}-{MicrosoftOpenJDKOperatingSystem}.{MicrosoftOpenJDKFileExtension}"); - /// /// Base URL for all Android SDK and NDK downloads. Used in /// @@ -42,8 +35,6 @@ public static partial class Defaults public static readonly Version MicrosoftMinOpenJDKVersion = new Version (17, 0); public static readonly Version MicrosoftOpenJDKVersion = new Version (Configurables.MicrosoftOpenJDKVersion); - public static readonly Version MicrosoftOpenJDKRelease = new Version (Configurables.MicrosoftOpenJDKRelease); - public static readonly string MicrosoftOpenJDKRootDirName = Configurables.MicrosoftOpenJDKRootDirName; public const string DotNetTestRuntimeVersion = "3.1.11"; @@ -207,10 +198,6 @@ public static partial class Paths public static string MonoAndroidFrameworksRootDir => GetCachedPath (ref monoAndroidFrameworksRootDir, () => Path.Combine (XAInstallPrefix, MonoAndroidFrameworksSubDir)); public static string InstallMSBuildDir => GetCachedPath (ref installMSBuildDir, () => ctx.Properties.GetRequiredValue (KnownProperties.MicrosoftAndroidSdkOutDir)); - // OpenJDK - public static string OpenJDKInstallDir => GetCachedPath (ref openJDKInstallDir, () => Path.Combine (ctx.Properties.GetRequiredValue (KnownProperties.AndroidToolchainDirectory), Defaults.JdkFolder)); - public static string OpenJDKCacheDir => GetCachedPath (ref openJDKCacheDir, () => ctx.Properties.GetRequiredValue (KnownProperties.AndroidToolchainCacheDirectory)); - // .NET 6+ public static string NetcoreAppRuntimeAndroidARM => GetCachedPath (ref netcoreAppRuntimeAndroidARM, () => GetNetcoreAppRuntimePath (ctx, "arm")); public static string NetcoreAppRuntimeAndroidARM64 => GetCachedPath (ref netcoreAppRuntimeAndroidARM64, () => GetNetcoreAppRuntimePath (ctx, "arm64")); @@ -305,8 +292,6 @@ static string GetCachedPath (ref string? variable, Func creator) static string? installMSBuildDir; static string? monoAndroidFrameworksRootDir; static string? externalJavaInteropDir; - static string? openJDKInstallDir; - static string? openJDKCacheDir; static string? configurationPropsGeneratedPath; static string? netcoreAppRuntimeAndroidARM; static string? netcoreAppRuntimeAndroidARM64; diff --git a/build-tools/xaprepare/xaprepare/OperatingSystems/OS.cs b/build-tools/xaprepare/xaprepare/OperatingSystems/OS.cs index 122b6611bcc..91c4247851f 100644 --- a/build-tools/xaprepare/xaprepare/OperatingSystems/OS.cs +++ b/build-tools/xaprepare/xaprepare/OperatingSystems/OS.cs @@ -134,10 +134,7 @@ abstract class OS : AppObject /// protected virtual bool InitOS () { - JavaHome = Environment.GetEnvironmentVariable ("JI_JAVA_HOME") ?? String.Empty; - if (string.IsNullOrEmpty (JavaHome)) { - JavaHome = Context.Instance.Properties.GetValue (KnownProperties.JavaSdkDirectory)?.Trim () ?? String.Empty; - } + JavaHome = Context.Instance.Properties.GetValue (KnownProperties.JavaSdkDirectory)?.Trim () ?? String.Empty; if (String.IsNullOrEmpty (JavaHome)) { var androidToolchainDirectory = Context.Instance.Properties.GetValue (KnownProperties.AndroidToolchainDirectory)?.Trim () ?? String.Empty; JavaHome = Path.Combine (androidToolchainDirectory, Configurables.Defaults.JdkFolder); diff --git a/build-tools/xaprepare/xaprepare/Scenarios/Scenario_AndroidTestDependencies.cs b/build-tools/xaprepare/xaprepare/Scenarios/Scenario_AndroidTestDependencies.cs index 455750413e0..d3f58521063 100644 --- a/build-tools/xaprepare/xaprepare/Scenarios/Scenario_AndroidTestDependencies.cs +++ b/build-tools/xaprepare/xaprepare/Scenarios/Scenario_AndroidTestDependencies.cs @@ -8,7 +8,7 @@ partial class Scenario_AndroidTestDependencies : ScenarioNoStandardEndSteps protected virtual AndroidToolchainComponentType AndroidSdkNdkType => AndroidToolchainComponentType.CoreDependency; public Scenario_AndroidTestDependencies () - : base ("AndroidTestDependencies", "Install Android SDK, OpenJDK and .NET preview test dependencies.") + : base ("AndroidTestDependencies", "Install Android SDK and .NET preview test dependencies.") {} protected Scenario_AndroidTestDependencies (string name, string description) @@ -18,7 +18,6 @@ protected Scenario_AndroidTestDependencies (string name, string description) protected override void AddSteps (Context context) { Steps.Add (new Step_InstallDotNetPreview ()); - Steps.Add (new Step_InstallMicrosoftOpenJDK (allowJIJavaHomeMatch: true)); Steps.Add (new Step_Android_SDK_NDK (AndroidSdkNdkType)); // disable installation of missing programs... diff --git a/build-tools/xaprepare/xaprepare/Scenarios/Scenario_EmulatorTestDependencies.cs b/build-tools/xaprepare/xaprepare/Scenarios/Scenario_EmulatorTestDependencies.cs index 4710b58ee2b..5370f0c6364 100644 --- a/build-tools/xaprepare/xaprepare/Scenarios/Scenario_EmulatorTestDependencies.cs +++ b/build-tools/xaprepare/xaprepare/Scenarios/Scenario_EmulatorTestDependencies.cs @@ -8,7 +8,7 @@ partial class Scenario_EmulatorTestDependencies : Scenario_AndroidTestDependenci protected override AndroidToolchainComponentType AndroidSdkNdkType => AndroidToolchainComponentType.CoreDependency | AndroidToolchainComponentType.EmulatorDependency; public Scenario_EmulatorTestDependencies () - : base ("EmulatorTestDependencies", "Install Android SDK (with emulator), OpenJDK, and .NET preview test dependencies.") + : base ("EmulatorTestDependencies", "Install Android SDK (with emulator) and .NET preview test dependencies.") {} } } diff --git a/build-tools/xaprepare/xaprepare/Scenarios/Scenario_Standard.cs b/build-tools/xaprepare/xaprepare/Scenarios/Scenario_Standard.cs index ac32d24bd9b..0442cbe9387 100644 --- a/build-tools/xaprepare/xaprepare/Scenarios/Scenario_Standard.cs +++ b/build-tools/xaprepare/xaprepare/Scenarios/Scenario_Standard.cs @@ -19,7 +19,6 @@ protected override void AddSteps (Context context) throw new ArgumentNullException (nameof (context)); Steps.Add (new Step_InstallDotNetPreview ()); - Steps.Add (new Step_InstallMicrosoftOpenJDK ()); Steps.Add (new Step_Android_SDK_NDK ()); Steps.Add (new Step_GenerateFiles (atBuildStart: true)); Steps.Add (new Step_PrepareProps ()); diff --git a/build-tools/xaprepare/xaprepare/Steps/Step_InstallAdoptOpenJDK.Linux.cs b/build-tools/xaprepare/xaprepare/Steps/Step_InstallAdoptOpenJDK.Linux.cs deleted file mode 100644 index dd174847e31..00000000000 --- a/build-tools/xaprepare/xaprepare/Steps/Step_InstallAdoptOpenJDK.Linux.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using System.IO; -using System.Threading.Tasks; - -namespace Xamarin.Android.Prepare -{ - partial class Step_InstallOpenJDK - { - void MoveContents (string sourceDir, string destinationDir) - { - Utilities.MoveDirectoryContentsRecursively (sourceDir, destinationDir); - } - } -} diff --git a/build-tools/xaprepare/xaprepare/Steps/Step_InstallAdoptOpenJDK.MacOS.cs b/build-tools/xaprepare/xaprepare/Steps/Step_InstallAdoptOpenJDK.MacOS.cs deleted file mode 100644 index 8e7e38d1635..00000000000 --- a/build-tools/xaprepare/xaprepare/Steps/Step_InstallAdoptOpenJDK.MacOS.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using System.IO; -using System.Threading.Tasks; - -namespace Xamarin.Android.Prepare -{ - partial class Step_InstallOpenJDK - { - void MoveContents (string sourceDir, string destinationDir) - { - string realSourceDir = Path.Combine (sourceDir, "Contents", "Home"); - Utilities.MoveDirectoryContentsRecursively (realSourceDir, destinationDir); - - var xattr_d = new ProcessRunner ("xattr", "-d", "-r", "com.apple.quarantine", ".") { - EchoStandardError = true, - WorkingDirectory = destinationDir, - }; - xattr_d.Run (); - } - } -} diff --git a/build-tools/xaprepare/xaprepare/Steps/Step_InstallAdoptOpenJDK.Unix.cs b/build-tools/xaprepare/xaprepare/Steps/Step_InstallAdoptOpenJDK.Unix.cs deleted file mode 100644 index 24b5768a07a..00000000000 --- a/build-tools/xaprepare/xaprepare/Steps/Step_InstallAdoptOpenJDK.Unix.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using System.IO; -using System.Threading.Tasks; - -namespace Xamarin.Android.Prepare -{ - partial class Step_InstallOpenJDK - { - async Task Unpack (string fullArchivePath, string destinationDirectory, bool cleanDestinationBeforeUnpacking = false) - { - return await Utilities.Unpack (fullArchivePath, destinationDirectory, cleanDestinatioBeforeUnpacking: true); - } - } -} diff --git a/build-tools/xaprepare/xaprepare/Steps/Step_InstallAdoptOpenJDK.Windows.cs b/build-tools/xaprepare/xaprepare/Steps/Step_InstallAdoptOpenJDK.Windows.cs deleted file mode 100644 index 3f92f5614da..00000000000 --- a/build-tools/xaprepare/xaprepare/Steps/Step_InstallAdoptOpenJDK.Windows.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System; -using System.IO; -using System.Threading.Tasks; - -namespace Xamarin.Android.Prepare -{ - partial class Step_InstallOpenJDK - { - async Task Unpack (string fullArchivePath, string destinationDirectory, bool cleanDestinationBeforeUnpacking = false) - { - if (cleanDestinationBeforeUnpacking) - Utilities.DeleteDirectorySilent (destinationDirectory); - Utilities.CreateDirectory (destinationDirectory); - - var sevenZip = new SevenZipRunner (Context.Instance); - Log.DebugLine ($"Uncompressing {fullArchivePath} to {destinationDirectory}"); - if (!await sevenZip.Extract (fullArchivePath, destinationDirectory)) { - Log.DebugLine ($"Failed to decompress {fullArchivePath}"); - return false; - } - - if (fullArchivePath.EndsWith ("tar.gz", StringComparison.OrdinalIgnoreCase)) { - // On Windows we don't have Tar available and the Windows package is a .tar.gz - // 7zip can unpack tar.gz but it's a two-stage process - first it decompresses the package, then it can be - // invoked again to extract the actual tar contents. - string tarPath = Path.Combine (destinationDirectory, Path.GetFileNameWithoutExtension (fullArchivePath)); - bool ret = await sevenZip.Extract (tarPath, destinationDirectory); - Utilities.DeleteFileSilent (tarPath); - - if (!ret) { - Log.DebugLine ($"Failed to extract TAR contents from {tarPath}"); - return false; - } - } - - return true; - } - - void MoveContents (string sourceDir, string destinationDir) - { - Utilities.MoveDirectoryContentsRecursively (sourceDir, destinationDir); - } - } -} diff --git a/build-tools/xaprepare/xaprepare/Steps/Step_InstallAdoptOpenJDK.cs b/build-tools/xaprepare/xaprepare/Steps/Step_InstallAdoptOpenJDK.cs deleted file mode 100644 index 92cacaa7c1f..00000000000 --- a/build-tools/xaprepare/xaprepare/Steps/Step_InstallAdoptOpenJDK.cs +++ /dev/null @@ -1,296 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Net; -using System.Reflection; -using System.Threading.Tasks; -using System.Xml.Linq; - -namespace Xamarin.Android.Prepare -{ - abstract partial class Step_InstallOpenJDK : StepWithDownloadProgress, IBuildInventoryItem - { - const string XAVersionInfoFile = "xa_jdk_version.txt"; - const string URLQueryFilePathField = "file_path"; - - static readonly char[] QuerySeparator = new char[] { ';', '&' }; - - // Paths relative to JDK installation root, just for a cursory check whether we have a sane JDK instance - // NOTE: file extensions are not necessary here - static readonly List jdkFiles = new List { - Path.Combine ("bin", "java"), - Path.Combine ("bin", "javac"), - Path.Combine ("include", "jni.h"), - }; - - bool AllowJIJavaHomeMatch = false; - - public Step_InstallOpenJDK (string description, bool allowJIJavaHomeMatch = false) - : base (description) - { - AllowJIJavaHomeMatch = allowJIJavaHomeMatch; - } - - protected abstract string ProductName {get;} - protected abstract string JdkInstallDir {get;} - protected abstract Version JdkVersion {get;} - protected abstract Version JdkRelease {get;} - protected abstract Uri JdkUrl {get;} - protected abstract string JdkCacheDir {get;} - protected abstract string RootDirName {get;} - public string BuildToolName => ProductName; - public string BuildToolVersion => JdkVersion.ToString (); - - protected override async Task Execute (Context context) - { - AddToInventory (); - - string jdkInstallDir = JdkInstallDir; - if (OpenJDKExistsAndIsValid (jdkInstallDir, out string? installedVersion)) { - Log.Status ($"{ProductName} version "); - Log.Status (installedVersion ?? "Unknown", ConsoleColor.Yellow); - Log.StatusLine (" already installed in: ", jdkInstallDir, tailColor: ConsoleColor.Cyan); - return true; - } - - // Check for a JDK installed on CI to use for test jobs - var jiJavaHomeVarValue = Environment.GetEnvironmentVariable ("JI_JAVA_HOME"); - if (AllowJIJavaHomeMatch && Directory.Exists (jiJavaHomeVarValue) && JdkFilesExist (jiJavaHomeVarValue)) { - Log.StatusLine ("Skipping JDK install for test job, JDK exists at: ", jdkInstallDir, tailColor: ConsoleColor.Cyan); - return true; - } - - Log.StatusLine ($"{ProductName} {JdkVersion} r{JdkRelease} will be installed to {jdkInstallDir}"); - Uri jdkURL = JdkUrl; - if (jdkURL == null) - throw new InvalidOperationException ($"{ProductName} URL must not be null"); - - string? packageName = GetPackageName (jdkURL); - - if (String.IsNullOrEmpty (packageName)) { - Log.ErrorLine ($"Unable to extract file name from {ProductName} URL"); - return false; - } - - string localPackagePath = Path.Combine (JdkCacheDir, packageName); - if (!await DownloadOpenJDK (context, localPackagePath, jdkURL)) - return false; - - string tempDir = $"{jdkInstallDir}.temp"; - try { - if (!await Unpack (localPackagePath, tempDir, cleanDestinationBeforeUnpacking: true)) { - Log.ErrorLine ($"Failed to install {ProductName}"); - return false; - } - - string rootDir = Path.Combine (tempDir, RootDirName); - if (!Directory.Exists (rootDir)) { - Log.ErrorLine ($"${ProductName} root directory not found after unpacking: {RootDirName}"); - return false; - } - - MoveContents (rootDir, jdkInstallDir); - File.WriteAllText (Path.Combine (jdkInstallDir, XAVersionInfoFile), $"{JdkRelease}{Environment.NewLine}"); - } finally { - Utilities.DeleteDirectorySilent (tempDir); - // Clean up zip after extraction if running on a hosted azure pipelines agent. - if (context.IsRunningOnHostedAzureAgent) - Utilities.DeleteFileSilent (localPackagePath); - } - - return true; - } - - string? GetPackageName (Uri jdkURL) - { - string[] queryParams = jdkURL.Query.TrimStart ('?').Split (QuerySeparator, StringSplitOptions.RemoveEmptyEntries); - if (queryParams.Length == 0) { - if (jdkURL.Segments.Length > 0) { - return jdkURL.Segments [jdkURL.Segments.Length-1]; - } - Log.ErrorLine ($"Unable to extract file name from {ProductName} URL as it contains no query component"); - return null; - } - - string? packageName = null; - foreach (string p in queryParams) { - if (!p.StartsWith (URLQueryFilePathField, StringComparison.Ordinal)) { - continue; - } - - int idx = p.IndexOf ('='); - if (idx < 0) { - Log.DebugLine ($"{ProductName} URL query field '{URLQueryFilePathField}' has no value, unable to detect file name"); - break; - } - - packageName = p.Substring (idx + 1).Trim (); - } - return packageName; - } - - async Task DownloadOpenJDK (Context context, string localPackagePath, Uri url) - { - if (File.Exists (localPackagePath)) { - Log.StatusLine ($"{ProductName} archive already downloaded"); - return true; - } - - Log.StatusLine ($"Downloading {ProductName} from ", url.ToString (), tailColor: ConsoleColor.White); - (bool success, ulong size, HttpStatusCode status) = await Utilities.GetDownloadSizeWithStatus (url); - if (!success) { - if (status == HttpStatusCode.NotFound) - Log.ErrorLine ($"{ProductName} archive URL not found"); - else - Log.ErrorLine ($"Failed to obtain {ProductName} size. HTTP status code: {status} ({(int)status})"); - return false; - } - - DownloadStatus downloadStatus = Utilities.SetupDownloadStatus (context, size, context.InteractiveSession); - Log.StatusLine ($" {context.Characters.Link} {url}", ConsoleColor.White); - await Download (context, url, localPackagePath, ProductName, Path.GetFileName (localPackagePath), downloadStatus); - - if (!File.Exists (localPackagePath)) { - Log.ErrorLine ($"Download of {ProductName} from {url} failed."); - return false; - } - - return true; - } - - bool OpenJDKExistsAndIsValid (string installDir, out string? installedVersion) - { - installedVersion = null; - if (!Directory.Exists (installDir)) { - Log.DebugLine ($"{ProductName} directory {installDir} does not exist"); - return false; - } - - string corettoVersionFile = Path.Combine (installDir, "version.txt"); - if (File.Exists (corettoVersionFile)) { - Log.DebugLine ($"Corretto version file {corettoVersionFile} found, will replace Corretto with {ProductName}"); - return false; - } - - string openJDKReleaseFile = Path.Combine (installDir, "release"); - if (!File.Exists (openJDKReleaseFile)) { - Log.DebugLine ($"{ProductName} release file {openJDKReleaseFile} does not exist, cannot determine version"); - return false; - } - - string[] lines = File.ReadAllLines (openJDKReleaseFile); - if (lines == null || lines.Length == 0) { - Log.DebugLine ($"{ProductName} release file {openJDKReleaseFile} is empty, cannot determine version"); - return false; - } - - string? cv = null; - foreach (string l in lines) { - string line = l.Trim (); - if (!line.StartsWith ("JAVA_VERSION=", StringComparison.Ordinal)) { - continue; - } - - cv = line.Substring (line.IndexOf ('=') + 1).Trim ('"'); - cv = cv.Replace ("_", "."); - break; - } - - if (String.IsNullOrEmpty (cv)) { - Log.DebugLine ($"Unable to find version of {ProductName} in release file {openJDKReleaseFile}"); - return false; - } - - installedVersion = cv; - string xaVersionFile = Path.Combine (installDir, XAVersionInfoFile); - if (!File.Exists (xaVersionFile)) { - Log.DebugLine ($"Unable to find .NET for Android version file {xaVersionFile}"); - return false; - } - - lines = File.ReadAllLines (xaVersionFile); - if (lines == null || lines.Length == 0) { - Log.DebugLine ($".NET for Android version file {xaVersionFile} is empty, cannot determine release version"); - return false; - } - - string rv = lines[0].Trim (); - if (String.IsNullOrEmpty (rv)) { - Log.DebugLine ($".NET for Android version file {xaVersionFile} does not contain release version information"); - return false; - } - - if (!Version.TryParse (cv, out Version? cversion) || cversion == null) { - Log.DebugLine ($"Unable to parse {ProductName} version from: {cv}"); - return false; - } - - if (cversion != JdkVersion) { - Log.DebugLine ($"Invalid {ProductName} version. Need {JdkVersion}, found {cversion}"); - return false; - } - - if (!Version.TryParse (rv, out cversion)) { - Log.DebugLine ($"Unable to parse {ProductName} release version from: {rv}"); - return false; - } - - if (cversion != JdkRelease) { - Log.DebugLine ($"Invalid {ProductName} version. Need {JdkRelease}, found {cversion}"); - return false; - } - - return JdkFilesExist (installDir); - } - - bool JdkFilesExist (string installDir) - { - foreach (string f in jdkFiles) { - string file = Path.Combine (installDir, f); - if (!File.Exists (file)) { - bool foundExe = false; - foreach (string exe in Utilities.FindExecutable (f)) { - file = Path.Combine (installDir, exe); - if (File.Exists (file)) { - foundExe = true; - break; - } - } - - if (!foundExe) { - Log.DebugLine ($"JDK file {file} missing from {ProductName}"); - return false; - } - } - } - - return true; - } - - public void AddToInventory () - { - if (!string.IsNullOrEmpty (BuildToolName) && !string.IsNullOrEmpty (BuildToolVersion) && !Context.Instance.BuildToolsInventory.ContainsKey (BuildToolName)) { - Context.Instance.BuildToolsInventory.Add (BuildToolName, BuildToolVersion); - } - } - } - - class Step_InstallMicrosoftOpenJDK : Step_InstallOpenJDK { - - const string _ProductName = "Microsoft OpenJDK"; - - public Step_InstallMicrosoftOpenJDK (bool allowJIJavaHomeMatch = false) - : base ($"Installing {_ProductName}", allowJIJavaHomeMatch) - { - } - - protected override string ProductName => _ProductName; - protected override string JdkInstallDir => Configurables.Paths.OpenJDKInstallDir; - protected override Version JdkVersion => Configurables.Defaults.MicrosoftOpenJDKVersion; - protected override Version JdkRelease => Configurables.Defaults.MicrosoftOpenJDKRelease; - protected override Uri JdkUrl => Configurables.Urls.MicrosoftOpenJDK; - protected override string JdkCacheDir => Configurables.Paths.OpenJDKCacheDir; - protected override string RootDirName => Configurables.Defaults.MicrosoftOpenJDKRootDirName; - } -} diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/AndroidSdkResolver.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/AndroidSdkResolver.cs index 13e27f82d3e..d4106453efe 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/AndroidSdkResolver.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/AndroidSdkResolver.cs @@ -50,8 +50,6 @@ public static string GetAndroidNdkPath () public static string GetJavaSdkPath () { var javaSdkPath = Environment.GetEnvironmentVariable ("TEST_ANDROID_JDK_PATH"); - if (string.IsNullOrEmpty (javaSdkPath)) - javaSdkPath = JavaSdkPath ??= Environment.GetEnvironmentVariable ("JI_JAVA_HOME"); if (string.IsNullOrEmpty (javaSdkPath)) javaSdkPath = JavaSdkPath ??= Environment.GetEnvironmentVariable ("JAVA_HOME"); if (string.IsNullOrEmpty (javaSdkPath)) diff --git a/src/bundletool/bundletool.csproj b/src/bundletool/bundletool.csproj index 99596487642..6e2eb4e92a6 100644 --- a/src/bundletool/bundletool.csproj +++ b/src/bundletool/bundletool.csproj @@ -7,6 +7,10 @@ bin\$(Configuration) + + + + diff --git a/src/java-runtime/java-runtime.csproj b/src/java-runtime/java-runtime.csproj index d09fb57b735..5047f014385 100644 --- a/src/java-runtime/java-runtime.csproj +++ b/src/java-runtime/java-runtime.csproj @@ -18,6 +18,7 @@ + diff --git a/src/manifestmerger/manifestmerger.csproj b/src/manifestmerger/manifestmerger.csproj index 7aafd3b11a8..7a58e185d8e 100644 --- a/src/manifestmerger/manifestmerger.csproj +++ b/src/manifestmerger/manifestmerger.csproj @@ -5,6 +5,10 @@ false bin\$(Configuration) + + + + diff --git a/src/openjdk/openjdk.csproj b/src/openjdk/openjdk.csproj new file mode 100644 index 00000000000..ee545d45a03 --- /dev/null +++ b/src/openjdk/openjdk.csproj @@ -0,0 +1,13 @@ + + + netstandard2.0 + false + + + + bin\$(Configuration) + + + + + diff --git a/src/openjdk/openjdk.targets b/src/openjdk/openjdk.targets new file mode 100644 index 00000000000..cf6fa4202a1 --- /dev/null +++ b/src/openjdk/openjdk.targets @@ -0,0 +1,135 @@ + + + + + <_OpenJDKPlatform>windows-x64 + <_OpenJDKExtension>.zip + + + <_OpenJDKPlatform>linux-x64 + <_OpenJDKExtension>.tar.gz + + + <_OpenJDKPlatform>macos-x64 + <_OpenJDKExtension>.tar.gz + + + <_OpenJDKPlatform>macos-aarch64 + <_OpenJDKExtension>.tar.gz + + + + <_OpenJDKFileName>microsoft-jdk-$(MicrosoftOpenJDKVersion)-$(_OpenJDKPlatform)$(_OpenJDKExtension) + <_OpenJDKHashFileName>$(_OpenJDKFileName).sha256sum.txt + <_OpenJDKArchiveUrl>https://aka.ms/download-jdk/$(_OpenJDKFileName) + <_OpenJDKHashUrl>$(_OpenJDKArchiveUrl).sha256sum.txt + <_OpenJDKArchive>$(AndroidToolchainCacheDirectory)\$(_OpenJDKFileName) + <_OpenJDKHashFile>$(AndroidToolchainCacheDirectory)\$(_OpenJDKHashFileName) + <_OpenJDKExtractDir>$(AndroidToolchainCacheDirectory)\openjdk-$(MicrosoftOpenJDKVersion) + <_OpenJDKInstallDir>$(AndroidToolchainDirectory)\$(MicrosoftOpenJDKFolder) + <_OpenJDKVersionFile>$(_OpenJDKInstallDir)\xa_jdk_version.txt + + <_OpenJDKExtractSubdir Condition=" '$(HostOS)' != 'Darwin' ">$(_OpenJDKExtractDir)\$(MicrosoftOpenJDKRootDirName) + <_OpenJDKExtractSubdir Condition=" '$(HostOS)' == 'Darwin' ">$(_OpenJDKExtractDir)\$(MicrosoftOpenJDKRootDirName)\Contents\Home + + + + + + + + <_OpenJDKExpectedHash>$([System.IO.File]::ReadAllText('$(_OpenJDKHashFile)').Substring(0, 64).ToUpperInvariant()) + + + + + + + + + + + + + + + + + + + + + <_OpenJDKFiles Include="$(_OpenJDKExtractSubdir)\**\*" /> + + + + + + + + + + + + + + + + + + + diff --git a/src/proguard-android/proguard-android.csproj b/src/proguard-android/proguard-android.csproj index 80ee062aaf8..ab76841e8eb 100644 --- a/src/proguard-android/proguard-android.csproj +++ b/src/proguard-android/proguard-android.csproj @@ -5,6 +5,11 @@ false bin\$(Configuration) + + + + + \ No newline at end of file diff --git a/src/r8/r8.csproj b/src/r8/r8.csproj index f355168160b..e8e20b56907 100644 --- a/src/r8/r8.csproj +++ b/src/r8/r8.csproj @@ -12,6 +12,7 @@ + From e1571c5da65b2440ef07dacc797f36d65ec2bf48 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Thu, 14 May 2026 11:10:50 -0500 Subject: [PATCH 2/5] Move Android SDK license acceptance from xaprepare to MSBuild NoTargets project Create a new src/androidsdk MSBuild NoTargets project that runs sdkmanager --licenses with JAVA_HOME set correctly. This project depends on src/openjdk via ProjectReference, ensuring the JDK is installed before sdkmanager runs. The gradle/JDK-dependent projects now reference androidsdk instead of openjdk directly, since androidsdk transitively depends on openjdk. Remove the AcceptLicenses method from xaprepare Step_Android_SDK_NDK, which was failing in CI because it ran before the JDK was installed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- Xamarin.Android.sln | 7 +++ .../xaprepare/Steps/Step_Android_SDK_NDK.cs | 56 ------------------- src/androidsdk/androidsdk.csproj | 17 ++++++ src/androidsdk/androidsdk.targets | 38 +++++++++++++ src/bundletool/bundletool.csproj | 2 +- src/java-runtime/java-runtime.csproj | 2 +- src/manifestmerger/manifestmerger.csproj | 2 +- src/proguard-android/proguard-android.csproj | 2 +- src/r8/r8.csproj | 2 +- 9 files changed, 67 insertions(+), 61 deletions(-) create mode 100644 src/androidsdk/androidsdk.csproj create mode 100644 src/androidsdk/androidsdk.targets diff --git a/Xamarin.Android.sln b/Xamarin.Android.sln index 098c1230156..82205d0743a 100644 --- a/Xamarin.Android.sln +++ b/Xamarin.Android.sln @@ -95,6 +95,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "binutils", "src\binutils\bi EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "openjdk", "src\openjdk\openjdk.csproj", "{7A180B05-DE3F-4D89-9F40-03A8E186AE82}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "androidsdk", "src\androidsdk\androidsdk.csproj", "{3E45D81B-4C4A-4E3F-B891-A0D8A3E2F0C1}" +EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "jit-times", "tools\jit-times\jit-times.csproj", "{F3CFF31C-037B-450F-B22D-1D6E529B2DCC}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MSBuildDeviceIntegration", "tests\MSBuildDeviceIntegration\MSBuildDeviceIntegration.csproj", "{16DB2680-399B-4111-AA26-6CDBBFA334D8}" @@ -313,6 +315,10 @@ Global {7A180B05-DE3F-4D89-9F40-03A8E186AE82}.Debug|AnyCPU.Build.0 = Debug|Any CPU {7A180B05-DE3F-4D89-9F40-03A8E186AE82}.Release|AnyCPU.ActiveCfg = Release|Any CPU {7A180B05-DE3F-4D89-9F40-03A8E186AE82}.Release|AnyCPU.Build.0 = Release|Any CPU + {3E45D81B-4C4A-4E3F-B891-A0D8A3E2F0C1}.Debug|AnyCPU.ActiveCfg = Debug|Any CPU + {3E45D81B-4C4A-4E3F-B891-A0D8A3E2F0C1}.Debug|AnyCPU.Build.0 = Debug|Any CPU + {3E45D81B-4C4A-4E3F-B891-A0D8A3E2F0C1}.Release|AnyCPU.ActiveCfg = Release|Any CPU + {3E45D81B-4C4A-4E3F-B891-A0D8A3E2F0C1}.Release|AnyCPU.Build.0 = Release|Any CPU {F3CFF31C-037B-450F-B22D-1D6E529B2DCC}.Debug|AnyCPU.ActiveCfg = Debug|Any CPU {F3CFF31C-037B-450F-B22D-1D6E529B2DCC}.Debug|AnyCPU.Build.0 = Debug|Any CPU {F3CFF31C-037B-450F-B22D-1D6E529B2DCC}.Release|AnyCPU.ActiveCfg = Release|Any CPU @@ -445,6 +451,7 @@ Global {A0AEF446-3368-4591-9DE6-BC3B2B33337D} = {04E3E11E-B47D-4599-8AFC-50515A95E715} {B2BC20D1-F468-46A9-B9B0-1C80CC4D4F36} = {04E3E11E-B47D-4599-8AFC-50515A95E715} {7A180B05-DE3F-4D89-9F40-03A8E186AE82} = {04E3E11E-B47D-4599-8AFC-50515A95E715} + {3E45D81B-4C4A-4E3F-B891-A0D8A3E2F0C1} = {04E3E11E-B47D-4599-8AFC-50515A95E715} {F3CFF31C-037B-450F-B22D-1D6E529B2DCC} = {864062D3-A415-4A6F-9324-5820237BA058} {16DB2680-399B-4111-AA26-6CDBBFA334D8} = {CAB438D8-B0F5-4AF0-BEBD-9E2ADBD7B483} {372E8E3E-29D5-4B4D-88A2-4711CD628C4E} = {05C3B1D6-A4CE-4534-A9E4-E9117591ADF7} diff --git a/build-tools/xaprepare/xaprepare/Steps/Step_Android_SDK_NDK.cs b/build-tools/xaprepare/xaprepare/Steps/Step_Android_SDK_NDK.cs index 274efa6950a..64a4f98a832 100644 --- a/build-tools/xaprepare/xaprepare/Steps/Step_Android_SDK_NDK.cs +++ b/build-tools/xaprepare/xaprepare/Steps/Step_Android_SDK_NDK.cs @@ -1,7 +1,5 @@ using System; using System.Collections.Generic; -using System.Diagnostics; -using System.Globalization; using System.IO; using System.Linq; using System.Threading.Tasks; @@ -70,10 +68,6 @@ protected override async Task Execute (Context context) toolchain.Components.ForEach (c => Check (context, packageCacheDir, sdkRoot, c, toInstall, 4)); if (toInstall.Count == 0) { - if (!AcceptLicenses (context, sdkRoot)) { - Log.ErrorLine ("Failed to accept Android SDK licenses"); - return false; - } WritePackageXmls (sdkRoot); return GatherNDKInfo (context); } @@ -114,61 +108,11 @@ protected override async Task Execute (Context context) await Unpack (context, tempDir, p); } - if (!AcceptLicenses (context, sdkRoot)) { - Log.ErrorLine ("Failed to accept Android SDK licenses"); - return false; - } - WritePackageXmls (sdkRoot); return GatherNDKInfo (context); } - bool AcceptLicenses (Context context, string sdkRoot) - { - string[] sdkManagerPaths = new[]{ - Path.Combine (sdkRoot, "cmdline-tools", context.Properties [KnownProperties.CommandLineToolsFolder] ?? String.Empty, "bin", "sdkmanager"), - Path.Combine (sdkRoot, "cmdline-tools", "latest", "bin", "sdkmanager"), - }; - string sdkManager = ""; - foreach (var sdkManagerPath in sdkManagerPaths) { - sdkManager = context.OS.Which (sdkManagerPath, required: false); - if (!string.IsNullOrEmpty (sdkManager)) - break; - } - if (sdkManager.Length == 0) - throw new InvalidOperationException ("sdkmanager not found"); - string jdkDir = context.OS.JavaHome; - - Log.Todo ("Modify ProcessRunner to allow standard input writing and switch to it here"); - // var runner = new ProcessRunner (sdkManager, "--licenses"); - // runner.StartInfoCallback = (ProcessStartInfo psi) => { - // if (!String.IsNullOrEmpty (jdkDir)) - // psi.EnvironmentVariables.Add ("JAVA_HOME", jdkDir); - // psi.RedirectStandardInput = true; - // }; - - var psi = new ProcessStartInfo (sdkManager, "--licenses") { - UseShellExecute = false, - RedirectStandardInput = true - }; - if (!String.IsNullOrEmpty (jdkDir) && !psi.EnvironmentVariables.ContainsKey ("JAVA_HOME")) - psi.EnvironmentVariables.Add ("JAVA_HOME", jdkDir); - - Log.DebugLine ($"Starting {psi.FileName} {psi.Arguments}"); - Process? proc = Process.Start (psi); - if (proc != null) { - for (int i = 0; i < 10; i++) - proc.StandardInput.WriteLine ('y'); - - proc.WaitForExit (); - } else { - Log.DebugLine ("Failed to start process"); - } - - return true; - } - bool GatherNDKInfo (Context context) { if (!CopyRedistributableFiles (context)) { diff --git a/src/androidsdk/androidsdk.csproj b/src/androidsdk/androidsdk.csproj new file mode 100644 index 00000000000..fa5f31809ef --- /dev/null +++ b/src/androidsdk/androidsdk.csproj @@ -0,0 +1,17 @@ + + + netstandard2.0 + false + + + + bin\$(Configuration) + + + + + + + + + diff --git a/src/androidsdk/androidsdk.targets b/src/androidsdk/androidsdk.targets new file mode 100644 index 00000000000..98ee4b1d00d --- /dev/null +++ b/src/androidsdk/androidsdk.targets @@ -0,0 +1,38 @@ + + + + <_SdkManagerDir>$(AndroidSdkFullPath)\cmdline-tools\$(CommandLineToolsFolder)\bin + <_SdkManagerPath Condition=" '$(HostOS)' == 'Windows' ">$(_SdkManagerDir)\sdkmanager.bat + <_SdkManagerPath Condition=" '$(HostOS)' != 'Windows' ">$(_SdkManagerDir)\sdkmanager + <_LicensesAcceptedFile>$(AndroidSdkFullPath)\licenses\.licenses-accepted + + + + + + + + + + + + + + + diff --git a/src/bundletool/bundletool.csproj b/src/bundletool/bundletool.csproj index 6e2eb4e92a6..299d283bbcf 100644 --- a/src/bundletool/bundletool.csproj +++ b/src/bundletool/bundletool.csproj @@ -9,7 +9,7 @@ - + diff --git a/src/java-runtime/java-runtime.csproj b/src/java-runtime/java-runtime.csproj index 5047f014385..a47628385c9 100644 --- a/src/java-runtime/java-runtime.csproj +++ b/src/java-runtime/java-runtime.csproj @@ -18,7 +18,7 @@ - + diff --git a/src/manifestmerger/manifestmerger.csproj b/src/manifestmerger/manifestmerger.csproj index 7a58e185d8e..0af62c782e3 100644 --- a/src/manifestmerger/manifestmerger.csproj +++ b/src/manifestmerger/manifestmerger.csproj @@ -7,7 +7,7 @@ - + diff --git a/src/proguard-android/proguard-android.csproj b/src/proguard-android/proguard-android.csproj index ab76841e8eb..0f4530816e1 100644 --- a/src/proguard-android/proguard-android.csproj +++ b/src/proguard-android/proguard-android.csproj @@ -7,7 +7,7 @@ - + diff --git a/src/r8/r8.csproj b/src/r8/r8.csproj index e8e20b56907..c658a9323ed 100644 --- a/src/r8/r8.csproj +++ b/src/r8/r8.csproj @@ -12,7 +12,7 @@ - + From 5ec5cca8a625d9e82977fc10cfa8e178a8229533 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Thu, 14 May 2026 13:22:10 -0500 Subject: [PATCH 3/5] Add androidsdk ProjectReference to TestApks.targets Test projects that import TestApks.targets call sdkmanager with JAVA_HOME, so they need androidsdk to ensure the JDK is installed first. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- build-tools/scripts/TestApks.targets | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/build-tools/scripts/TestApks.targets b/build-tools/scripts/TestApks.targets index 00182feb939..badd802b1c4 100644 --- a/build-tools/scripts/TestApks.targets +++ b/build-tools/scripts/TestApks.targets @@ -16,6 +16,10 @@ + + + + android-arm64;android-x86;android-x64; From 109670219fa47b5a4d857300e381c20b5e9c2dde Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Thu, 14 May 2026 16:35:17 -0500 Subject: [PATCH 4/5] Add androidsdk ProjectReference to Jar.targets and JavaCallableWrappers.targets Test binding projects that import Jar.targets call javac/jar with JavaSdkDirectory, and Mono.Android imports JavaCallableWrappers.targets which runs D8 with JAVA_HOME. Both need the JDK installed first. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- build-tools/scripts/Jar.targets | 3 +++ build-tools/scripts/JavaCallableWrappers.targets | 3 +++ 2 files changed, 6 insertions(+) diff --git a/build-tools/scripts/Jar.targets b/build-tools/scripts/Jar.targets index 680aa93e75e..e0de30027f7 100644 --- a/build-tools/scripts/Jar.targets +++ b/build-tools/scripts/Jar.targets @@ -1,5 +1,8 @@ + + + diff --git a/build-tools/scripts/JavaCallableWrappers.targets b/build-tools/scripts/JavaCallableWrappers.targets index 4ee26c823d4..c975ce97f6e 100644 --- a/build-tools/scripts/JavaCallableWrappers.targets +++ b/build-tools/scripts/JavaCallableWrappers.targets @@ -1,5 +1,8 @@ + + + Date: Fri, 15 May 2026 14:06:25 -0500 Subject: [PATCH 5/5] Add androidsdk ProjectReference to Emulator.csproj ProjectReference in .targets files does not work. Add it directly to Emulator.csproj which is the project built standalone by the CI pipeline to start/stop the Android emulator. This ensures the JDK is installed before sdkmanager is called. Revert the ineffective .targets changes from the previous commit. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- build-tools/scripts/Jar.targets | 3 --- build-tools/scripts/JavaCallableWrappers.targets | 3 --- build-tools/scripts/TestApks.targets | 4 ---- .../Tests/Xamarin.Android.Build.Tests/Emulator.csproj | 3 +++ 4 files changed, 3 insertions(+), 10 deletions(-) diff --git a/build-tools/scripts/Jar.targets b/build-tools/scripts/Jar.targets index e0de30027f7..680aa93e75e 100644 --- a/build-tools/scripts/Jar.targets +++ b/build-tools/scripts/Jar.targets @@ -1,8 +1,5 @@ - - - diff --git a/build-tools/scripts/JavaCallableWrappers.targets b/build-tools/scripts/JavaCallableWrappers.targets index c975ce97f6e..4ee26c823d4 100644 --- a/build-tools/scripts/JavaCallableWrappers.targets +++ b/build-tools/scripts/JavaCallableWrappers.targets @@ -1,8 +1,5 @@ - - - - - - - android-arm64;android-x86;android-x64; diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Emulator.csproj b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Emulator.csproj index 1962bfdcd1a..c93eb78a648 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Emulator.csproj +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Emulator.csproj @@ -4,5 +4,8 @@ false + + + \ No newline at end of file