Skip to content
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

[Xamarin.Android.Build.Tasks] helpers for AsyncTask + TPL #2881

Merged
merged 1 commit into from
Mar 29, 2019
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
28 changes: 24 additions & 4 deletions Documentation/guides/messages/xa0000.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,27 @@
# Compiler Error XA0000

This error means you are using a `$(TargetFrameworkVersion)` which cannot be
mapped to a valid android api-level.
An unhandled exception (or error case) was encountered in one of
Xamarin.Android's MSBuild tasks.

Check you have selected a valid `$(TargetFrameworkVersion)` and the required
android api-level is installed in `$(AndroidSdkDirectory)\platforms`.
Consider submitting a [bug][bug] if you are getting this warning under
normal circumstances.

[bug]: https://github.com/xamarin/xamarin-android/wiki/Submitting-Bugs,-Feature-Requests,-and-Pull-Requests

## Examples

* An exception was thrown and logged, including a C# exception stack
trace showing where the failure occurred.

Solution:

Likely, the only option is to submit a [bug][bug].

* You are using a `$(TargetFrameworkVersion)` which cannot be mapped
to a valid android api-level.

Solution:

Check you have selected a valid `$(TargetFrameworkVersion)` and the
required android api-level is installed in
`$(AndroidSdkDirectory)\platforms`.
12 changes: 2 additions & 10 deletions src/Xamarin.Android.Build.Tasks/Tasks/Aapt.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
using System.Text.RegularExpressions;
using System.Collections.Generic;
using Xamarin.Android.Tools;
using ThreadingTasks = System.Threading.Tasks;
using Xamarin.Build;

namespace Xamarin.Android.Tasks
Expand Down Expand Up @@ -236,9 +235,7 @@ public override bool Execute ()
resourceDirectory = Path.Combine (WorkingDirectory, resourceDirectory);
Yield ();
try {
var task = ThreadingTasks.Task.Run (() => {
DoExecute ();
}, CancellationToken);
var task = this.RunTask (DoExecute);

task.ContinueWith (Complete);

Expand All @@ -256,12 +253,7 @@ void DoExecute ()

assemblyMap.Load (Path.Combine (WorkingDirectory, AssemblyIdentityMapFile));

ThreadingTasks.ParallelOptions options = new ThreadingTasks.ParallelOptions {
CancellationToken = CancellationToken,
TaskScheduler = ThreadingTasks.TaskScheduler.Default,
};

ThreadingTasks.Parallel.ForEach (ManifestFiles, options, ProcessManifest);
this.ParallelForEach (ManifestFiles, ProcessManifest);
}

protected string GenerateCommandLineCommands (string ManifestFile, string currentAbi, string currentResourceOutputFile)
Expand Down
15 changes: 3 additions & 12 deletions src/Xamarin.Android.Build.Tasks/Tasks/Aapt2Compile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,11 @@
using System.Text.RegularExpressions;
using System.Collections.Generic;
using Xamarin.Android.Tools;
using ThreadingTasks = System.Threading.Tasks;

namespace Xamarin.Android.Tasks {

public class Aapt2Compile : Aapt2 {

readonly object lockObject = new object ();
List<ITaskItem> archives = new List<ITaskItem> ();

public bool ExplicitCrunch { get; set; }
Expand All @@ -39,9 +37,7 @@ public override bool Execute ()

Yield ();
try {
var task = ThreadingTasks.Task.Run (() => {
DoExecute ();
}, CancellationToken);
var task = this.RunTask (DoExecute);

task.ContinueWith (Complete);

Expand All @@ -57,15 +53,10 @@ void DoExecute ()
{
LoadResourceCaseMap ();

ThreadingTasks.ParallelOptions options = new ThreadingTasks.ParallelOptions {
CancellationToken = CancellationToken,
TaskScheduler = ThreadingTasks.TaskScheduler.Default,
};

ThreadingTasks.Parallel.ForEach (ResourceDirectories, options, ProcessDirectory);
this.ParallelForEachWithLock (ResourceDirectories, ProcessDirectory);
}

void ProcessDirectory (ITaskItem resourceDirectory)
void ProcessDirectory (ITaskItem resourceDirectory, object lockObject)
{
if (!Directory.EnumerateDirectories (resourceDirectory.ItemSpec).Any ())
return;
Expand Down
12 changes: 2 additions & 10 deletions src/Xamarin.Android.Build.Tasks/Tasks/Aapt2Link.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
using System.Text.RegularExpressions;
using System.Collections.Generic;
using Xamarin.Android.Tools;
using ThreadingTasks = System.Threading.Tasks;

namespace Xamarin.Android.Tasks {

Expand Down Expand Up @@ -81,9 +80,7 @@ public override bool Execute ()

Yield ();
try {
var task = ThreadingTasks.Task.Run (() => {
DoExecute ();
}, CancellationToken);
var task = this.RunTask (DoExecute);

task.ContinueWith (Complete);

Expand All @@ -102,12 +99,7 @@ void DoExecute ()

assemblyMap.Load (Path.Combine (WorkingDirectory, AssemblyIdentityMapFile));

ThreadingTasks.ParallelOptions options = new ThreadingTasks.ParallelOptions {
CancellationToken = CancellationToken,
TaskScheduler = ThreadingTasks.TaskScheduler.Default,
};

ThreadingTasks.Parallel.ForEach (ManifestFiles, options, ProcessManifest);
this.ParallelForEach (ManifestFiles, ProcessManifest);
} finally {
foreach (var temp in tempFiles) {
File.Delete (temp);
Expand Down
13 changes: 2 additions & 11 deletions src/Xamarin.Android.Build.Tasks/Tasks/Aot.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@
using System.Linq;
using System.Reflection;
using System.Threading;
// using System.Threading.Tasks conflicts with Microsoft.Build.Utilities because of the Task type
using ThreadingTasks = System.Threading.Tasks;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;

Expand Down Expand Up @@ -261,9 +259,7 @@ bool DoExecute () {

Yield ();
try {
var task = ThreadingTasks.Task.Run ( () => {
return RunParallelAotCompiler (nativeLibs);
}, CancellationToken);
var task = this.RunTask (() => RunParallelAotCompiler (nativeLibs));

task.ContinueWith (Complete);

Expand All @@ -286,12 +282,7 @@ bool DoExecute () {
bool RunParallelAotCompiler (List<string> nativeLibs)
{
try {
ThreadingTasks.ParallelOptions options = new ThreadingTasks.ParallelOptions {
CancellationToken = CancellationToken,
TaskScheduler = ThreadingTasks.TaskScheduler.Default,
};

ThreadingTasks.Parallel.ForEach (GetAotConfigs (), options,
this.ParallelForEach (GetAotConfigs (),
config => {
if (!config.Valid) {
Cancel ();
Expand Down
12 changes: 2 additions & 10 deletions src/Xamarin.Android.Build.Tasks/Tasks/CalculateLayoutCodeBehind.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
using Microsoft.Build.Utilities;
using Microsoft.Build.Framework;

using TPL = System.Threading.Tasks;
using Xamarin.Build;

namespace Xamarin.Android.Tasks
Expand Down Expand Up @@ -147,15 +146,8 @@ public override bool Execute ()
// is changed!
Log.LogDebugMessage ($"Parsing layouts in parallel (threshold of {ParallelGenerationThreshold} layouts met)");

TPL.ParallelOptions options = new TPL.ParallelOptions {
CancellationToken = CancellationToken,
TaskScheduler = TPL.TaskScheduler.Default,
};
TPL.Task.Factory.StartNew (
() => TPL.Parallel.ForEach (layoutsByName, options, kvp => ParseAndLoadGroup (layoutsByName, kvp.Key, kvp.Value.InputItems, ref kvp.Value.LayoutBindingItems, ref kvp.Value.LayoutPartialClassItems)),
CancellationToken,
TPL.TaskCreationOptions.None,
TPL.TaskScheduler.Default
this.RunTask (
() => this.ParallelForEach (layoutsByName, kvp => ParseAndLoadGroup (layoutsByName, kvp.Key, kvp.Value.InputItems, ref kvp.Value.LayoutBindingItems, ref kvp.Value.LayoutPartialClassItems))
).ContinueWith (t => Complete ());

base.Execute ();
Expand Down
12 changes: 2 additions & 10 deletions src/Xamarin.Android.Build.Tasks/Tasks/Crunch.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
using System.Text.RegularExpressions;
using Xamarin.Android.Tools;
using Xamarin.Android.Tools.Aidl;
using ThreadingTasks = System.Threading.Tasks;
using Xamarin.Build;

namespace Xamarin.Android.Tasks
Expand Down Expand Up @@ -73,9 +72,7 @@ public override bool Execute ()
{
Yield ();
try {
var task = ThreadingTasks.Task.Run ( () => {
DoExecute ();
}, CancellationToken);
var task = this.RunTask (DoExecute);

task.ContinueWith (Complete);

Expand All @@ -97,14 +94,9 @@ void DoExecute ()
if (!imageFiles.Any ())
return;

ThreadingTasks.ParallelOptions options = new ThreadingTasks.ParallelOptions {
CancellationToken = CancellationToken,
TaskScheduler = ThreadingTasks.TaskScheduler.Default,
};

var imageGroups = imageFiles.GroupBy (x => Path.GetDirectoryName (Path.GetFullPath (x.ItemSpec)));

ThreadingTasks.Parallel.ForEach (imageGroups, options, DoExecute);
this.ParallelForEach (imageGroups, DoExecute);

return;
}
Expand Down
12 changes: 2 additions & 10 deletions src/Xamarin.Android.Build.Tasks/Tasks/GenerateLayoutBindings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
using Microsoft.Build.Utilities;
using Microsoft.Build.Framework;

using TPL = System.Threading.Tasks;
using Xamarin.Build;

namespace Xamarin.Android.Tasks
Expand Down Expand Up @@ -197,15 +196,8 @@ bool Generate (BindingGenerator generator)
// is changed!
Log.LogDebugMessage ($"Generating binding code in parallel (threshold of {CalculateLayoutCodeBehind.ParallelGenerationThreshold} layouts met)");
var fileSet = new ConcurrentBag <string> ();
TPL.ParallelOptions options = new TPL.ParallelOptions {
CancellationToken = CancellationToken,
TaskScheduler = TPL.TaskScheduler.Default,
};
TPL.Task.Factory.StartNew (
() => TPL.Parallel.ForEach (layoutGroups, options, kvp => GenerateSourceForLayoutGroup (generator, kvp.Value, rpath => fileSet.Add (rpath))),
CancellationToken,
TPL.TaskCreationOptions.None,
TPL.TaskScheduler.Default
this.RunTask (
() => this.ParallelForEach (layoutGroups, kvp => GenerateSourceForLayoutGroup (generator, kvp.Value, rpath => fileSet.Add (rpath)))
).ContinueWith (t => Complete ());
generatedFilePaths = fileSet;
} else {
Expand Down
66 changes: 66 additions & 0 deletions src/Xamarin.Android.Build.Tasks/Utilities/AsyncTaskExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Xamarin.Build;

namespace Xamarin.Android.Tasks
{
static class AsyncTaskExtensions
{
/// <summary>
/// Calls Parallel.ForEach() with appropriate ParallelOptions and exception handling.
/// </summary>
public static ParallelLoopResult ParallelForEach<TSource> (this AsyncTask asyncTask, IEnumerable<TSource> source, Action<TSource> body)
{
var options = ParallelOptions (asyncTask);
return Parallel.ForEach (source, options, s => {
try {
body (s);
} catch (Exception exc) {
LogErrorAndCancel (asyncTask, exc);
}
});
}

/// <summary>
/// Calls Parallel.ForEach() with appropriate ParallelOptions and exception handling.
/// Passes an object the inner method can use for locking. The callback is of the form: (T item, object lockObject)
/// </summary>
public static ParallelLoopResult ParallelForEachWithLock<TSource> (this AsyncTask asyncTask, IEnumerable<TSource> source, Action<TSource, object> body)
{
var options = ParallelOptions (asyncTask);
var lockObject = new object ();
return Parallel.ForEach (source, options, s => {
try {
body (s, lockObject);
} catch (Exception exc) {
LogErrorAndCancel (asyncTask, exc);
}
});
}

static ParallelOptions ParallelOptions (AsyncTask asyncTask) => new ParallelOptions {
CancellationToken = asyncTask.CancellationToken,
TaskScheduler = TaskScheduler.Default,
};

static void LogErrorAndCancel (AsyncTask asyncTask, Exception exc)
{
asyncTask.LogCodedError ("XA0000", "Unhandled exception: {0}", exc);
asyncTask.Cancel ();
}

/// <summary>
/// Calls Task.Run() with a proper CancellationToken.
/// </summary>
public static Task RunTask (this AsyncTask asyncTask, Action body) =>
Task.Run (body, asyncTask.CancellationToken);


/// <summary>
/// Calls Task.Run<T>() with a proper CancellationToken.
/// </summary>
public static Task<TSource> RunTask<TSource> (this AsyncTask asyncTask, Func<TSource> body) =>
Task.Run (body, asyncTask.CancellationToken);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@
<Compile Include="Linker\MonoDroid.Tuner\PreserveJavaExceptions.cs" />
<Compile Include="Linker\MonoDroid.Tuner\PreserveJavaTypeRegistrations.cs" />
<Compile Include="Linker\MonoDroid.Tuner\RemoveAttributes.cs" />
<Compile Include="Utilities\AsyncTaskExtensions.cs" />
<Compile Include="Utilities\MSBuildExtensions.cs" />
<Compile Include="Utilities\ZipArchiveEx.cs" />
<Compile Include="Mono.Android\ServiceAttribute.Partial.cs" />
Expand Down