Skip to content
This repository was archived by the owner on Jul 13, 2026. It is now read-only.

Commit 13cc497

Browse files
authored
[Xamarin.Android.Tools.AndroidSdk] Prefer JAVA_HOME (#86)
Context: dotnet/android#4567 `JdkInfo.GetKnownSystemJdkInfos()` returns a list of "known JDK locations", and the order of the returned paths was, basically, "locations that Xamarin/Microsoft controls come first." `AndroidSdkWindows.GetJdkInfos()` reads the Windows registry and is "controlled by" Visual Studio (unless someone is editing the Registry by hand…). If not on Windows, `GetConfiguredJdks()` reads `monodroid-config.xml` (managed by Visual Studio for Mac); failing that we probe some "well known Microsoft-controlled" directory locations… …and only failing *that* do we try the `$JAVA_HOME` environment variable, the ["de-facto" way][0] to tell software where Java is installed, and if `$JAVA_HOME` isn't set we further fallback to checking directories in `$PATH` and other mechanisms. The problem with this approach is that it isn't overridable, which is a usefully important feature if you want to *test new JDK versions*, as is the case in dotnet/android#4567. The "obvious" way to "try out" a new JDK would be to export the `JAVA_HOME` environment variable to the location of the JDK to use, but *that won't work* because `JdkInfo.GetKnownSystemJdkInfos()` *explicitly prefers* locations that aren't easily controllable in a CI environment. Given that *existing convention* is for JDK installs to set the `JAVA_HOME` environment variable -- and thus `JAVA_HOME` may very well refer to a JDK which Xamarin.Android doesn't support -- we are leery of making `JAVA_HOME` the "primary" override. Instead, add support for a new `JI_JAVA_HOME` environment variable which, if set, is the *preferred* JDK to use within Xamarin.Android (unless otherwise overridden by e.g. `$(JavaSdkDirectory)`). This will allow CI to export the `JAVA_HOME` environment variable, allowing it to be preferred over others. Additionally, remove some `JAVA_HOME` "duplication" between `JdkInfo` and `AndroidSdkWindows`, so that things are easier to reason about. [0]: https://docs.oracle.com/cd/E19182-01/821-0917/inst_jdk_javahome_t/index.html
1 parent 967c278 commit 13cc497

4 files changed

Lines changed: 34 additions & 24 deletions

File tree

‎src/Xamarin.Android.Tools.AndroidSdk/JdkInfo.cs‎

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -281,10 +281,11 @@ public static IEnumerable<JdkInfo> GetKnownSystemJdkInfos (Action<TraceLevel, st
281281
{
282282
logger=logger??AndroidSdkInfo.DefaultConsoleLogger;
283283

284-
returnGetWindowsJdks(logger)
284+
returnGetEnvironmentVariableJdks("JI_JAVA_HOME",logger)
285+
.Concat(GetWindowsJdks(logger))
285286
.Concat(GetConfiguredJdks(logger))
286287
.Concat(GetMacOSMicrosoftJdks(logger))
287-
.Concat(GetJavaHomeEnvironmentJdks(logger))
288+
.Concat(GetEnvironmentVariableJdks("JAVA_HOME",logger))
288289
.Concat(GetPathEnvironmentJdks(logger))
289290
.Concat(GetLibexecJdks(logger))
290291
.Concat(GetJavaAlternativesJdks(logger))
@@ -352,12 +353,12 @@ static IEnumerable<JdkInfo> GetWindowsJdks (Action<TraceLevel, string> logger)
352353
returnAndroidSdkWindows.GetJdkInfos(logger);
353354
}
354355

355-
staticIEnumerable<JdkInfo>GetJavaHomeEnvironmentJdks(Action<TraceLevel,string>logger)
356+
staticIEnumerable<JdkInfo>GetEnvironmentVariableJdks(stringenvVar,Action<TraceLevel,string>logger)
356357
{
357-
varjava_home=Environment.GetEnvironmentVariable("JAVA_HOME");
358+
varjava_home=Environment.GetEnvironmentVariable(envVar);
358359
if(string.IsNullOrEmpty(java_home))
359360
yieldbreak;
360-
varjdk=TryGetJdkInfo(java_home,logger,"$JAVA_HOME");
361+
varjdk=TryGetJdkInfo(java_home,logger,$"${envVar}");
361362
if(jdk!=null)
362363
yieldreturnjdk;
363364
}

‎src/Xamarin.Android.Tools.AndroidSdk/Sdks/AndroidSdkWindows.cs‎

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ protected override IEnumerable<string> GetAllAvailableAndroidSdks ()
108108

109109
protectedoverridestring?GetJavaSdkPath()
110110
{
111-
varjdk=GetJdkInfos(Logger).FirstOrDefault();
111+
varjdk=JdkInfo.GetKnownSystemJdkInfos(Logger).FirstOrDefault();
112112
returnjdk?.HomePath;
113113
}
114114

@@ -139,18 +139,7 @@ IEnumerable<JdkInfo> ToJdkInfos (IEnumerable<string> paths, string locator)
139139
.Concat(ToJdkInfos(GetOpenJdkPaths(),"OpenJDK"))
140140
.Concat(ToJdkInfos(GetKnownOpenJdkPaths(),"Well-known OpenJDK paths"))
141141
.Concat(ToJdkInfos(GetOracleJdkPaths(),"Oracle JDK"))
142-
.Concat(ToJdkInfos(GetEnvironmentJdkPaths(),"Environment Variables"));
143-
}
144-
145-
privatestaticIEnumerable<string>GetEnvironmentJdkPaths()
146-
{
147-
varenvironment=new[]{"JAVA_HOME"};
148-
foreach(varkeyinenvironment){
149-
varvalue=Environment.GetEnvironmentVariable(key);
150-
if(!string.IsNullOrEmpty(value)){
151-
yieldreturnvalue;
152-
}
153-
}
142+
;
154143
}
155144

156145
privatestaticIEnumerable<string>GetPreferredJdkPaths()

‎tests/Xamarin.Android.Tools.AndroidSdk-Tests/AndroidSdkInfoTests.cs‎

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -136,9 +136,13 @@ public void Constructor_SetValuesFromPath ()
136136
}
137137

138138
[Test]
139-
[Ignore("This test will only work locally if you rename/remove your Open JDK directory.")]
140-
publicvoidJdkDirectory_JavaHome()
139+
publicvoidJdkDirectory_JavaHome([Values("JI_JAVA_HOME","JAVA_HOME")]stringenvVar)
141140
{
141+
if(envVar.Equals("JAVA_HOME",StringComparison.OrdinalIgnoreCase)){
142+
Assert.Ignore("This test will only work locally if you rename/remove your Open JDK directory.");
143+
return;
144+
}
145+
142146
CreateSdks(outstringroot,outstringjdk,outstringndk,outstringsdk);
143147
JdkInfoTests.CreateFauxJdk(jdk,releaseVersion:"1.8.999",releaseBuildNumber:"9",javaVersion:"1.8.999-9");
144148

@@ -150,16 +154,15 @@ public void JdkDirectory_JavaHome ()
150154
stringjava_home=null;
151155
try{
152156
// We only set via JAVA_HOME
153-
java_home=Environment.GetEnvironmentVariable("JAVA_HOME",EnvironmentVariableTarget.Process);
154-
Environment.SetEnvironmentVariable("JAVA_HOME",jdk);
157+
java_home=Environment.GetEnvironmentVariable(envVar,EnvironmentVariableTarget.Process);
158+
Environment.SetEnvironmentVariable(envVar,jdk,EnvironmentVariableTarget.Process);
155159
varinfo=newAndroidSdkInfo(logger,androidSdkPath:sdk,androidNdkPath:ndk,javaSdkPath:"");
156160

157161
Assert.AreEqual(ndk,info.AndroidNdkPath,"AndroidNdkPath not preserved!");
158162
Assert.AreEqual(sdk,info.AndroidSdkPath,"AndroidSdkPath not preserved!");
159163
Assert.AreEqual(jdk,info.JavaSdkPath,"JavaSdkPath not preserved!");
160164
}finally{
161-
if(java_home!=null)
162-
Environment.SetEnvironmentVariable("JAVA_HOME",java_home,EnvironmentVariableTarget.Process);
165+
Environment.SetEnvironmentVariable(envVar,java_home,EnvironmentVariableTarget.Process);
163166
Directory.Delete(root,recursive:true);
164167
}
165168
}

‎tests/Xamarin.Android.Tools.AndroidSdk-Tests/JdkInfoTests.cs‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,23 @@ namespace Xamarin.Android.Tools.Tests
1111
[TestFixture]
1212
publicclassJdkInfoTests
1313
{
14+
[Test]
15+
publicvoidGetKnownSystemJdkInfos_PrefersJiJavaHome()
16+
{
17+
varprevious=Environment.GetEnvironmentVariable("JI_JAVA_HOME",EnvironmentVariableTarget.Process);
18+
try{
19+
Environment.SetEnvironmentVariable("JI_JAVA_HOME",FauxJdkDir,EnvironmentVariableTarget.Process);
20+
21+
vardefaultJdkDir=JdkInfo.GetKnownSystemJdkInfos()
22+
.FirstOrDefault();
23+
Assert.IsNotNull(defaultJdkDir);
24+
Assert.AreEqual(FauxJdkDir,defaultJdkDir.HomePath);
25+
}
26+
finally{
27+
Environment.SetEnvironmentVariable("JI_JAVA_HOME",previous,EnvironmentVariableTarget.Process);
28+
}
29+
}
30+
1431
[Test]
1532
publicvoidConstructor_NullPath()
1633
{

0 commit comments

Comments
 (0)