Skip to content

[Xamarin.Android.Build.Tasks] Asyncify Aapt Task#352

Merged
jonpryor merged 1 commit into
dotnet:masterfrom
dellis1972:asyncaapt
Jan 10, 2017
Merged

[Xamarin.Android.Build.Tasks] Asyncify Aapt Task#352
jonpryor merged 1 commit into
dotnet:masterfrom
dellis1972:asyncaapt

Conversation

@dellis1972

@dellis1972 dellis1972 commented Jan 6, 2017

Copy link
Copy Markdown
Contributor

We currently use MSBuild Batching to call the aapt tool
when processing the resources. This results in about 12 seperate
calls to aapt when building a standard Xamarin.Forms app.

The problem with Batching is that it is sequential. MSBuild and
xbuild are unable to run those batches in parallel. So this
commit reworks the Aapt task to be an AsyncTask. Which can take
multiple AndroidManifest files at once. It will then spin up
aapt in parallel rather than running them sequentially.

The difference between the two systems is clear

Using Batching:

6156.275 ms Aapt 10 calls

Using Async:

3207.201 ms Aapt 3 calls

This is a first build on a vanilla Xamarin.Form app with no changes.

@dellis1972 dellis1972 added the do-not-merge PR should not be merged. label Jan 6, 2017
@dellis1972 dellis1972 removed the do-not-merge PR should not be merged. label Jan 6, 2017
UncompressedFileExtensions="$(AndroidStoreUncompressedFileExtensions)"
AssetDirectory="$(MonoAndroidAssetsDirIntermediate)"
ToolPath="$(AaptToolPath)"
ToolExe="$(AaptToolExe)"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't want to remove this property, which means we'll need to add a ToolExe property and corresponding logic.

The rationale is that if (when?) Google changes the location of aapt in the future, we'd like developers to be able to specify the new location (file name?) without requiring a new release from us, Overriding $(AaptToolPath) and $(AaptToolExe) are the conventional ways to do this, which in turn means we need to continue supporting them.

(...and we should document those. doh!)

return 0;
}

ExecuteForAbi (GenerateCommandLineCommands (manifestFile.ItemSpec, null));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could "merge" this and the following if:

var sabis = SupportedAbis.Split (new char [] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries);
var def   = new string[]{null};
var abis  = (CreatePackagePerAbi && sabis.Length > 1) ? def.Concat (abis) : def;
foreach (var abi in abis) {
    ExecuteForAbi (GenerateCommandLineCommands (manifestFile.ItemSpec, abi));
}

This would reduce special-casing and help ensure that if we fix for one we fix for all.

foreach (var dir in AdditionalAndroidResourcePaths)
if (!string.IsNullOrEmpty (dir.ItemSpec))
upToDate = upToDate && ManifestIsUpToDate (string.Format ("{0}{1}{2}", dir, Path.DirectorySeparatorChar, "manifest", Path.DirectorySeparatorChar, "AndroidManifest.xml"));
ThreadingTasks.Parallel.ForEach (ManifestFiles, () => 0, (manifestFile, loopState, localSum) => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that so much is being re-indented and moved around anyway, can we move this (manifestFile, loopState, localSum) lambda into a separate and distinct method? That would reduce the complexity of Execute().

};

var proc = new Process ();
proc.OutputDataReceived += (sender, e) => { LogEventsFromTextOutput (e.Data, MessageImportance.Normal); };

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please format with multiple lines:

proc.OutputDataReceived += (sender, e) => {
     LogEventsFromTextOutput (e.Data, MessageImportance.Normal);
};


var proc = new Process ();
proc.OutputDataReceived += (sender, e) => { LogEventsFromTextOutput (e.Data, MessageImportance.Normal); };
proc.ErrorDataReceived += (sender, e) => { LogEventsFromTextOutput (e.Data, MessageImportance.Normal); };

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto.

@dellis1972 dellis1972 force-pushed the asyncaapt branch 3 times, most recently from e5435e1 to 61d4641 Compare January 9, 2017 09:55
protected string GenerateFullPathToTool ()
{
return Path.Combine (ToolPath, ToolExe);
return Path.Combine (ToolPath, ToolExe ?? ToolName);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should use string.IsNullOrEmpty().

We currently use MSBuild Batching to call the aapt tool
when processing the resources. This results in about 12 seperate
calls to aapt when building a standard Xamarin.Forms app.

The problem with Batching is that it is sequential. MSBuild and
xbuild are unable to run those batches in parallel. So this
commit reworks the Aapt task to be an AsyncTask. Which can take
multiple AndroidManifest files at once. It will then spin up
aapt in parallel rather than running them sequentially.

The difference between the two systems is clear

Using Batching:

6156.275 ms  Aapt  10 calls

Using Async:

3207.201 ms  Aapt  3 calls

This is a first build on a vanilla Xamarin.Form app with no changes.
@jonpryor jonpryor merged commit f93149e into dotnet:master Jan 10, 2017
@github-actions github-actions Bot locked and limited conversation to collaborators Feb 6, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants