Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
73 changes: 73 additions & 0 deletions src/Xamarin.Android.Build.Tasks/Tasks/ResolveSdksTask.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
Expand All @@ -37,6 +38,7 @@
using Xamarin.Android.Tools;
using System.Xml.Linq;
using Xamarin.Android.Build.Utilities;
using System.Text.RegularExpressions;

namespace Xamarin.Android.Tasks
{
Expand All @@ -59,6 +61,12 @@ public class ResolveSdks : Task
public bool UseLatestAndroidPlatformSdk { get; set; }
public bool AotAssemblies { get; set; }

public string JavaToolExe { get; set; }

public string LatestSupportedJavaVersion { get; set; }

public string MinimumSupportedJavaVersion { get; set; }

[Output]
public string[] ReferenceAssemblyPaths { get; set; }

Expand Down Expand Up @@ -147,6 +155,8 @@ public bool RunTask ()
this.AndroidSdkPath = AndroidSdk.AndroidSdkPath;
this.JavaSdkPath = AndroidSdk.JavaSdkPath;

ValidateJavaVersion (TargetFrameworkVersion, AndroidSdkBuildToolsVersion);

if (string.IsNullOrEmpty (AndroidSdkPath)) {
Log.LogCodedError ("XA5205", "The Android SDK Directory could not be found. Please set via /p:AndroidSdkDirectory.");
return false;
Expand Down Expand Up @@ -302,6 +312,69 @@ public bool RunTask ()
return !Log.HasLoggedErrors;
}

static readonly Regex javaVersionRegex = new Regex (@"""(?<version>[\d\.]+)_\d+""");

Version GetJavaVersionForFramework (string targetFrameworkVersion)
{
var apiLevel = AndroidVersion.TryOSVersionToApiLevel (targetFrameworkVersion);
if (apiLevel >= 24)
return new Version (1, 8);
else if (apiLevel == 23)
return new Version (1, 7);
else
return new Version (1, 6);
}

Version GetJavaVersionForBuildTools (string buildToolsVersion)
{
Version buildTools;
if (!Version.TryParse (buildToolsVersion, out buildTools)) {
return Version.Parse (LatestSupportedJavaVersion);
}
if (buildTools >= new Version (24, 0, 1))
return new Version (1, 8);
return Version.Parse (MinimumSupportedJavaVersion);
}

void ValidateJavaVersion (string targetFrameworkVersion, string buildToolsVersion)
{
Version requiredJavaForFrameworkVersion = GetJavaVersionForFramework (targetFrameworkVersion);
Version requiredJavaForBuildTools = GetJavaVersionForBuildTools (buildToolsVersion);

Version required = requiredJavaForFrameworkVersion > requiredJavaForBuildTools ? requiredJavaForFrameworkVersion : requiredJavaForBuildTools;

var sb = new StringBuilder ();

var javaTool = Path.Combine (JavaSdkPath, "bin", JavaToolExe ?? (OS.IsWindows ? "java.exe" : "java"));
try {
MonoAndroidHelper.RunProcess (javaTool, "-version", (s, e) => {
if (!string.IsNullOrEmpty (e.Data))
sb.AppendLine (e.Data);
}, (s, e) => {
if (!string.IsNullOrEmpty (e.Data))
sb.AppendLine (e.Data);
}
);
} catch (Exception ex) {
Log.LogWarningFromException (ex);
Log.LogWarning ($"Failed to get the Java SDK version. Please ensure you have Java {required} or above installed.");
return;
}
var versionInfo = sb.ToString ();
var versionNumberMatch = javaVersionRegex.Match (versionInfo);
Version versionNumber;
if (versionNumberMatch.Success && Version.TryParse (versionNumberMatch.Groups ["version"]?.Value, out versionNumber)) {
Log.LogMessage (MessageImportance.Normal, $"Found Java SDK version {versionNumber}.");
if (versionNumber < requiredJavaForFrameworkVersion) {
Log.LogError ($"Java SDK {requiredJavaForFrameworkVersion} or above is required when targeting FrameworkVerison {targetFrameworkVersion}.");
}
if (versionNumber < requiredJavaForBuildTools) {
Log.LogError ($"Java SDK {requiredJavaForBuildTools} or above is required when using build-tools {buildToolsVersion}.");
}
} else
Log.LogWarning ($"Failed to get the Java SDK version. Found {versionInfo} but this does not seem to contain a valid version number.");
}

bool ValidateApiLevels ()
{
// Priority:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1788,6 +1788,101 @@ public void CheckLibraryImportsUpgrade ([Values(false, true)] bool useShortFileN
}
}

#pragma warning disable 414
static object [] validateJavaVersionTestCases = new object [] {
new object [] {
/*targetFrameworkVersion*/ "v7.1",
/*buildToolsVersion*/ "24.0.1",
/*JavaVersion*/ "1.8.0_101",
/*expectedResult*/ true,
},
new object [] {
/*targetFrameworkVersion*/ "v7.1",
/*buildToolsVersion*/ "24.0.1",
/*JavaVersion*/ "1.7.0_101",
/*expectedResult*/ false,
},
new object [] {
/*targetFrameworkVersion*/ "v7.1",
/*buildToolsVersion*/ "24.0.1",
/*JavaVersion*/ "1.6.0_101",
/*expectedResult*/ false,
},
new object [] {
/*targetFrameworkVersion*/ "v6.0",
/*buildToolsVersion*/ "24.0.1",
/*JavaVersion*/ "1.8.0_101",
/*expectedResult*/ true,
},
new object [] {
/*targetFrameworkVersion*/ "v6.0",
/*buildToolsVersion*/ "24.0.0",
/*JavaVersion*/ "1.7.0_101",
/*expectedResult*/ true,
},
new object [] {
/*targetFrameworkVersion*/ "v6.0",
/*buildToolsVersion*/ "24.0.0",
/*JavaVersion*/ "1.6.0_101",
/*expectedResult*/ false,
},
new object [] {
/*targetFrameworkVersion*/ "v5.0",
/*buildToolsVersion*/ "24.0.1",
/*JavaVersion*/ "1.8.0_101",
/*expectedResult*/ true,
},
new object [] {
/*targetFrameworkVersion*/ "v5.0",
/*buildToolsVersion*/ "24.0.0",
/*JavaVersion*/ "1.7.0_101",
/*expectedResult*/ true,
},
new object [] {
/*targetFrameworkVersion*/ "v5.0",
/*buildToolsVersion*/ "24.0.0",
/*JavaVersion*/ "1.6.0_101",
/*expectedResult*/ true,
},
new object [] {
/*targetFrameworkVersion*/ "v5.0",
/*buildToolsVersion*/ "24.0.1",
/*JavaVersion*/ "1.6.0_101",
/*expectedResult*/ false,
},
new object [] {
/*targetFrameworkVersion*/ "v7.1",
/*buildToolsVersion*/ "24.0.1",
/*JavaVersion*/ "1.6.x_101",
/*expectedResult*/ true,
},
};
#pragma warning restore 414

[Test]
[TestCaseSource ("validateJavaVersionTestCases")]
public void ValidateJavaVersion (string targetFrameworkVersion, string buildToolsVersion, string javaVersion, bool expectedResult)
{
var path = Path.Combine ("temp", $"ValidateJavaVersion_{targetFrameworkVersion}_{buildToolsVersion}_{javaVersion}");
string javaExe = "java";
var javaPath = CreateFauxJavaSdkDirectory (Path.Combine (path, "JavaSDK"), javaVersion, out javaExe);
var AndroidSdkDirectory = CreateFauxAndroidSdkDirectory (Path.Combine (path, "android-sdk"), buildToolsVersion);
var proj = new XamarinAndroidApplicationProject () {
IsRelease = true,
TargetFrameworkVersion = targetFrameworkVersion,
};
using (var builder = CreateApkBuilder (Path.Combine (path, proj.ProjectName), false, false)) {
builder.ThrowOnBuildFailure = false;
builder.Target = "_SetLatestTargetFrameworkVersion";
Assert.AreEqual (expectedResult, builder.Build (proj, parameters: new string[] {
$"JavaSdkDirectory={javaPath}",
$"JavaToolExe={javaExe}",
$"AndroidSdkBuildToolsVersion={buildToolsVersion}",
$"AndroidSdkDirectory={AndroidSdkDirectory}",
} ), string.Format ("Build should have {0}", expectedResult ? "succeeded" : "failed"));
}
}

[Test]
public void BuildAMassiveApp()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using NUnit.Framework;
using System.Linq;
using System.Threading;
using System.Text;

namespace Xamarin.Android.Build.Tests
{
Expand Down Expand Up @@ -72,6 +73,68 @@ protected static string RunAdbCommand (string command, bool ignoreErrors = true)
return result;
}

protected string RunProcess (string exe, string args) {
var proc = System.Diagnostics.Process.Start (new System.Diagnostics.ProcessStartInfo (exe, args) { RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false });
proc.WaitForExit ();
var result = proc.StandardOutput.ReadToEnd ().Trim () + proc.StandardError.ReadToEnd ().Trim ();
return result;
}

protected string CreateFauxAndroidSdkDirectory (string path, string buildToolsVersion, int minApiLevel = 10, int maxApiLevel = 26)
{
var androidSdkDirectory = Path.Combine (Root, path);
var androidSdkToolsPath = Path.Combine (androidSdkDirectory, "tools");
var androidSdkBinPath = Path.Combine (androidSdkToolsPath, "bin");
var androidSdkPlatformToolsPath = Path.Combine (androidSdkDirectory, "platform-tools");
var androidSdkPlatformsPath = Path.Combine (androidSdkDirectory, "platforms");
var androidSdkBuildToolsPath = Path.Combine (androidSdkDirectory, "build-tools", buildToolsVersion);
Directory.CreateDirectory (androidSdkDirectory);
Directory.CreateDirectory (androidSdkToolsPath);
Directory.CreateDirectory (androidSdkBinPath);
Directory.CreateDirectory (androidSdkPlatformToolsPath);
Directory.CreateDirectory (androidSdkPlatformsPath);
Directory.CreateDirectory (androidSdkBuildToolsPath);

File.WriteAllText (Path.Combine (androidSdkPlatformToolsPath, IsWindows ? "adb.exe" : "adb"), "");
File.WriteAllText (Path.Combine (androidSdkBuildToolsPath, IsWindows ? "zipalign.exe" : "zipalign"), "");
File.WriteAllText (Path.Combine (androidSdkBuildToolsPath, IsWindows ? "aapt.exe" : "aapt"), "");

for (int i=minApiLevel; i < maxApiLevel; i++) {
var dir = Path.Combine (androidSdkPlatformsPath, $"android-{i}");
Directory.CreateDirectory(dir);
File.WriteAllText (Path.Combine (dir, "android.jar"), "");
}
return androidSdkDirectory;
}

protected string CreateFauxJavaSdkDirectory (string path, string javaVersion, out string javaExe)
{
javaExe = IsWindows ? "Java.cmd" : "java.bash";
var jarSigner = IsWindows ? "jarsigner.exe" : "jarsigner";
var javaPath = Path.Combine (Root, path);
var javaBinPath = Path.Combine (javaPath, "bin");
Directory.CreateDirectory (javaBinPath);
var sb = new StringBuilder ();
if (IsWindows) {
sb.AppendLine ("@echo off");
sb.AppendLine ($"echo java version \"{javaVersion}\"");
sb.AppendLine ($"echo Java(TM) SE Runtime Environment (build {javaVersion}-b13)");
sb.AppendLine ($"echo Java HotSpot(TM) 64-Bit Server VM (build 25.101-b13, mixed mode)");
} else {
sb.AppendLine ("#!/bin/bash");
sb.AppendLine ($"echo \"java version \\\"{javaVersion}\\\"\"");
sb.AppendLine ($"echo \"Java(TM) SE Runtime Environment (build {javaVersion}-b13)\"");
sb.AppendLine ($"echo \"Java HotSpot(TM) 64-Bit Server VM (build 25.101-b13, mixed mode)\"");
}

File.WriteAllText (Path.Combine (javaBinPath, javaExe), sb.ToString ());
if (!IsWindows) {
RunProcess ("chmod", $"u+x {Path.Combine (javaBinPath, javaExe)}");
}
File.WriteAllText (Path.Combine (javaBinPath, jarSigner), "");
return javaPath;
}

protected ProjectBuilder CreateApkBuilder (string directory, bool cleanupAfterSuccessfulBuild = false, bool cleanupOnDispose = true)
{
TestContext.CurrentContext.Test.Properties ["Output"] = new string [] { Path.Combine (Root, directory) };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,9 @@ Copyright (C) 2012 Xamarin Inc. All rights reserved.
TargetFrameworkVersion="$(TargetFrameworkVersion)"
SequencePointsMode="$(AndroidSequencePointsMode)"
UseLatestAndroidPlatformSdk="$(AndroidUseLatestPlatformSdk)"
JavaToolExe="$(JavaToolExe)"
LatestSupportedJavaVersion="$(LatestSupportedJavaVersion)"
MinimumSupportedJavaVersion="$(MinimumSupportedJavaVersion)"
>
<Output TaskParameter="AndroidApiLevel" PropertyName="_AndroidApiLevel" Condition="'$(_AndroidApiLevel)' == ''" />
<Output TaskParameter="AndroidApiLevelName" PropertyName="_AndroidApiLevelName" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,7 @@
<DependsOnSystemRuntime Condition=" '$(DependsOnSystemRuntime)' == '' ">true</DependsOnSystemRuntime>
<CopyNuGetImplementations Condition=" '$(CopyNuGetImplementations)' == ''">true</CopyNuGetImplementations>
<YieldDuringToolExecution Condition="'$(YieldDuringToolExecution)' == ''">true</YieldDuringToolExecution>
<LatestSupportedJavaVersion>1.8.0</LatestSupportedJavaVersion>
<MinimumSupportedJavaVersion>1.6.0</MinimumSupportedJavaVersion>
</PropertyGroup>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,9 @@ Copyright (C) 2011-2012 Xamarin. All rights reserved.
ReferenceAssemblyPaths="$(_XATargetFrameworkDirectories)"
TargetFrameworkVersion="$(TargetFrameworkVersion)"
UseLatestAndroidPlatformSdk="$(AndroidUseLatestPlatformSdk)"
JavaToolExe="$(JavaToolExe)"
LatestSupportedJavaVersion="$(LatestSupportedJavaVersion)"
MinimumSupportedJavaVersion="$(MinimumSupportedJavaVersion)"
LintToolPath="$(LintToolPath)"
ZipAlignPath="$(ZipAlignToolPath)">
<Output TaskParameter="AndroidApiLevel" PropertyName="_AndroidApiLevel" Condition="'$(_AndroidApiLevel)' == ''" />
Expand Down