Skip to content

Commit

Permalink
[Xamarin.Android.Build.Tasks] mechanism to skip ConvertResourcesCases
Browse files Browse the repository at this point in the history
Currently, we run the `ConvertResourcesCases` for all assemblies
(their `ResolveLibraryProjectImports` output). `ConvertResourcesCases`
is one of our slower targets. Luckily, there are some "well-known"
number of assemblies that we could skip, so it seems beneficial to
give library authors a way to do this.

So for example, an assembly could contain:

    [assembly: Android.SkipAndroidResourceProcessing]

And this would be an indicator for `ConvertResourcesCases` to just
completely skip this assembly.

Additionally, we can flat out skip `aar` files in the same manner.

To make this work:
- Added support to put `ITaskItem` metadata in the cache file produced
  by `ResolveLibraryProjectImports`
- Added item metadata for `SkipAndroidResourceProcessing` and
  `OriginalFile`.
- `ConvertResourcesCases` now skips these directories and logs
  `OriginalFile`.
- `CollectNonEmptyDirectories` needs to preserve item metadata for
  `$(AndroidUseAapt2)` to take advantage of the functionality.

The results appear to be well worth the effort!

To test this, I kept most of the changes here, except skipped any
assemblies starting with "Xamarin.Android.Support".

Results with `$(AndroidUseAapt2)` enabled:

    Before: 15650 ms  ConvertResourcesCases                      9 calls
    After:    112 ms  ConvertResourcesCases                      9 calls

Results with `$(AndroidUseAapt2)` disabled:

    Before:  2847 ms  ConvertResourcesCases                      1 calls
    After:     52 ms  ConvertResourcesCases                      1 calls

This was the Xamarin.Forms-Integration project in this repo, an
initial clean build. It is basically a "Hello World" Xamarin.Forms
project.

This is a proposal, so if someone has a nicer (better!) idea for
enabling this functionality, let me know!
  • Loading branch information
jonathanpeppers committed Oct 26, 2018
1 parent 19e3ce5 commit b9e8b2e
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 19 deletions.
10 changes: 10 additions & 0 deletions src/Mono.Android/Android/SkipAndroidResourceProcessingAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System;

namespace Android
{
[AttributeUsage (AttributeTargets.Assembly)]
public sealed class SkipAndroidResourceProcessingAttribute : Attribute
{
}
}

1 change: 1 addition & 0 deletions src/Mono.Android/Mono.Android.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@
<Compile Include="Android\LinkerSafeAttribute.cs" />
<Compile Include="Android\NativeLibraryReferenceAttribute.cs" />
<Compile Include="Android\ReferenceFilesAttribute.cs" />
<Compile Include="Android\SkipAndroidResourceProcessingAttribute.cs" />
<Compile Include="Android.Accounts\AccountManager.cs" />
<Compile Include="Android.Animation\Animator.cs" />
<Compile Include="Android.Animation\AnimatorSet.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@ public override bool Execute ()
foreach (var directory in Directories) {
var firstFile = Directory.EnumerateFiles(directory.ItemSpec, "*.*", SearchOption.AllDirectories).FirstOrDefault ();
if (firstFile != null) {
output.Add (new TaskItem (directory.ItemSpec, new Dictionary<string, string> () {
var taskItem = new TaskItem (directory.ItemSpec, new Dictionary<string, string> () {
{"FileFound", firstFile}
}));
});
directory.CopyMetadataTo (taskItem);
output.Add (taskItem);
}
}
return !Log.HasLoggedErrors;
Expand Down
11 changes: 9 additions & 2 deletions src/Xamarin.Android.Build.Tasks/Tasks/ConvertResourcesCases.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,18 @@ public override bool Execute ()
return true;
}


void FixupResources (Dictionary<string, string> acwMap)
{
foreach (var dir in ResourceDirectories)
foreach (var dir in ResourceDirectories) {
var skipResourceProcessing = dir.GetMetadata (ResolveLibraryProjectImports.SkipAndroidResourceProcessing);
if (skipResourceProcessing != null && skipResourceProcessing.Equals ("true", StringComparison.OrdinalIgnoreCase)) {
var originalFile = dir.GetMetadata (ResolveLibraryProjectImports.OriginalFile);
Log.LogDebugMessage ($"Skipping `{dir.ItemSpec}` due to `{ResolveLibraryProjectImports.SkipAndroidResourceProcessing}`, original file: `{originalFile}`...");
continue;
}

FixupResources (dir, acwMap);
}
}

void FixupResources (ITaskItem item, Dictionary<string, string> acwMap)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,13 @@ public class ResolveLibraryProjectImports : Task
[Output]
public ITaskItem [] ResolvedResourceDirectoryStamps { get; set; }

internal const string OriginalFile = "OriginalFile";
internal const string SkipAndroidResourceProcessing = "SkipAndroidResourceProcessing";
static readonly string [] knownMetadata = new [] {
"OriginalFile",
"SkipAndroidResourceProcessing"
};

AssemblyIdentityMap assemblyMap = new AssemblyIdentityMap();

public ResolveLibraryProjectImports ()
Expand All @@ -79,7 +86,7 @@ public override bool Execute ()
Log.LogDebugTaskItems (" AarLibraries: ", AarLibraries);

var jars = new List<string> ();
var resolvedResourceDirectories = new List<string> ();
var resolvedResourceDirectories = new List<ITaskItem> ();
var resolvedAssetDirectories = new List<string> ();
var resolvedEnvironmentFiles = new List<string> ();

Expand All @@ -95,9 +102,7 @@ public override bool Execute ()
}

Jars = jars.ToArray ();
ResolvedResourceDirectories = resolvedResourceDirectories
.Select (s => new TaskItem (Path.GetFullPath (s)))
.ToArray ();
ResolvedResourceDirectories = resolvedResourceDirectories.ToArray ();
ResolvedAssetDirectories = resolvedAssetDirectories.ToArray ();
ResolvedEnvironmentFiles = resolvedEnvironmentFiles.ToArray ();

Expand All @@ -120,7 +125,15 @@ public override bool Execute ()
new XElement ("Jars",
Jars.Select(e => new XElement ("Jar", e))),
new XElement ("ResolvedResourceDirectories",
ResolvedResourceDirectories.Select(e => new XElement ("ResolvedResourceDirectory", e))),
ResolvedResourceDirectories.Select(dir => {
var e = new XElement ("ResolvedResourceDirectory", dir.ItemSpec);
foreach (var name in knownMetadata) {
var value = dir.GetMetadata (name);
if (!string.IsNullOrEmpty (value))
e.SetAttributeValue (name, value);
}
return e;
})),
new XElement ("ResolvedAssetDirectories",
ResolvedAssetDirectories.Select(e => new XElement ("ResolvedAssetDirectory", e))),
new XElement ("ResolvedEnvironmentFiles",
Expand Down Expand Up @@ -160,7 +173,7 @@ static string GetTargetAssembly (ITaskItem assemblyName)
void Extract (
DirectoryAssemblyResolver res,
ICollection<string> jars,
ICollection<string> resolvedResourceDirectories,
ICollection<ITaskItem> resolvedResourceDirectories,
ICollection<string> resolvedAssetDirectories,
ICollection<string> resolvedEnvironments)
{
Expand Down Expand Up @@ -210,8 +223,16 @@ void Extract (
if (Directory.Exists (binAssemblyDir))
resolvedAssetDirectories.Add (binAssemblyDir);
#endif
if (Directory.Exists (resDir))
resolvedResourceDirectories.Add (resDir);
if (Directory.Exists (resDir)) {
var taskItem = new TaskItem (resDir, new Dictionary<string, string> {
{ OriginalFile, assemblyPath },
});
//TODO: perhaps a better way to store this value here when stamp exists?
var a = res.GetAssembly (assemblyPath);
if (SkipResourceProcessing (a))
taskItem.SetMetadata (SkipAndroidResourceProcessing, "True");
resolvedResourceDirectories.Add (taskItem);
}
if (Directory.Exists (assemblyDir))
resolvedAssetDirectories.Add (assemblyDir);
foreach (var env in Directory.EnumerateFiles (outDirForDll, "__AndroidEnvironment__*", SearchOption.TopDirectoryOnly)) {
Expand Down Expand Up @@ -308,8 +329,14 @@ void Extract (
if (Directory.Exists (binAssemblyDir))
resolvedAssetDirectories.Add (binAssemblyDir);
#endif
if (Directory.Exists (resDir))
resolvedResourceDirectories.Add (resDir);
if (Directory.Exists (resDir)) {
var taskItem = new TaskItem (resDir, new Dictionary<string, string> {
{ OriginalFile, assemblyPath }
});
if (SkipResourceProcessing (assembly))
taskItem.SetMetadata (SkipAndroidResourceProcessing, "True");
resolvedResourceDirectories.Add (taskItem);
}
if (Directory.Exists (assemblyDir))
resolvedAssetDirectories.Add (assemblyDir);

Expand Down Expand Up @@ -362,7 +389,10 @@ void Extract (
}
}
if (Directory.Exists (resDir))
resolvedResourceDirectories.Add (resDir);
resolvedResourceDirectories.Add (new TaskItem (resDir, new Dictionary<string, string> {
{ OriginalFile, aarFile.ItemSpec },
{ SkipAndroidResourceProcessing, "True" },
}));
if (Directory.Exists (assetsDir))
resolvedAssetDirectories.Add (assetsDir);
}
Expand All @@ -373,5 +403,16 @@ void Extract (
jars.Add (f);
}
}

bool SkipResourceProcessing (AssemblyDefinition assembly)
{
if (assembly.HasCustomAttributes) {
foreach (var att in assembly.CustomAttributes) {
if (att.AttributeType.FullName == "Android.SkipAndroidResourceProcessingAttribute")
return true;
}
}
return false;
}
}
}
20 changes: 16 additions & 4 deletions src/Xamarin.Android.Build.Tasks/Utilities/XDocumentExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,28 @@ namespace Xamarin.Android.Tasks
{
public static class XDocumentExtensions
{
const string PathsElementName = "Paths";

public static ITaskItem[] GetPathsAsTaskItems (this XDocument doc, params string[] paths)
{
return doc.GetPaths (paths)
.Select(x => new TaskItem(x))
.ToArray ();
var e = doc.Elements (PathsElementName);
foreach (var p in paths)
e = e.Elements (p);
return e.Select (ToTaskItem).ToArray ();
}

static ITaskItem ToTaskItem (XElement element)
{
var taskItem = new TaskItem (element.Value);
foreach (var attribute in element.Attributes ()) {
taskItem.SetMetadata (attribute.Name.LocalName, attribute.Value);
}
return taskItem;
}

public static string[] GetPaths (this XDocument doc, params string[] paths)
{
var e = doc.Elements ("Paths");
var e = doc.Elements (PathsElementName);
foreach (var p in paths)
e = e.Elements (p);
return e.Select (p => p.Value).ToArray ();
Expand Down

0 comments on commit b9e8b2e

Please sign in to comment.