Skip to content

Commit a547cb7

Browse files
[linker] move StripEmbeddedLibraries into the linker
Fixes: #1092 The `StripEmbeddedLibraries` MSBuild task can take 1-2 seconds, and it mainly removes `__AndroidLibraryProjects__.zip` from assemblies. If we moved this to happen during linking, it has various benefits: - The linker already has every assembly opened and loaded. - We know if the linker is going to `Skip`/`Delete` an assembly, so we can likewise skip it. - The linker writes all the assemblies out at the end, so we don't have a second "write" step. Changes to make this happen: - Removed the `StripEmbeddedLibraries` MSBuild task and related targets - Removed `$(_AndroidStripFlag)` from our targets, since it is no longer used - Created a new `StripEmbeddedLibraries` linker step that runs late during linking - Removed a `RemoveLibraryResourceZip` linker step, as it seemed to be duplicative. I timed before and after with the Xamarin.Forms test project: .\bin\Debug\bin\xabuild .\tests\Xamarin.Forms-Performance-Integration\Droid\Xamarin.Forms.Performance.Integration.Droid.csproj /p:Configuration=Release /t:Clean .\bin\Debug\bin\xabuild .\tests\Xamarin.Forms-Performance-Integration\Droid\Xamarin.Forms.Performance.Integration.Droid.csproj /p:Configuration=Release /t:Build /bl Before: 1233 ms StripEmbeddedLibraries 1 calls 14925 ms LinkAssemblies 1 calls After: 15437 ms LinkAssemblies 1 calls As expected, `LinkAssemblies` will be slightly slower. But since `StripEmbeddedLibraries` is not called at all, we have a net gain of around 700ms. Once this has been merged and working for `Release` builds, I plan to do some further research to find out if running the new `StripEmbeddedLibraries` linker step will help for `Debug` builds. It could be a net performance improvement, if the time taken to remove these files improves deployment and app startup times. Greatly expanded upon an existing test: - Made it a Xamarin.Forms project - Moved the `AndroidEnvironment` item to a referenced library project - Added an `$(AndroidLinkSkip)` option for a support library assembly - Made sure the `$(AndroidLinkSkip)` assembly is saved and stripped - Check and make sure `EmbeddedResource` items are stripped at the end Other changes: - Removed some assertions in tests looking for `_StripEmbeddedLibraries`, since it is removed now.
1 parent 743e69a commit a547cb7

File tree

9 files changed

+119
-169
lines changed

9 files changed

+119
-169
lines changed

src/Xamarin.Android.Build.Tasks/Linker/MonoDroid.Tuner/Linker.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,6 @@ static Pipeline CreatePipeline (LinkerOptions options)
103103
pipeline.AppendStep (new PreserveCrypto ());
104104
pipeline.AppendStep (new PreserveCode ());
105105

106-
pipeline.AppendStep (new RemoveLibraryResourceZip ());
107106
pipeline.AppendStep (new RemoveResources (options.I18nAssemblies)); // remove collation tables
108107
// end monodroid specific
109108

@@ -114,6 +113,7 @@ static Pipeline CreatePipeline (LinkerOptions options)
114113
// monodroid tuner steps
115114
if (!string.IsNullOrWhiteSpace (options.ProguardConfiguration))
116115
pipeline.AppendStep (new GenerateProguardConfiguration (options.ProguardConfiguration));
116+
pipeline.AppendStep (new StripEmbeddedLibraries ());
117117
// end monodroid specific
118118
pipeline.AppendStep (new RegenerateGuidStep ());
119119
pipeline.AppendStep (new OutputStep ());

src/Xamarin.Android.Build.Tasks/Linker/MonoDroid.Tuner/RemoveLibraryResourceZip.cs

Lines changed: 0 additions & 26 deletions
This file was deleted.
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
using Mono.Cecil;
2+
using Mono.Linker;
3+
using Mono.Linker.Steps;
4+
using System;
5+
using System.Linq;
6+
using Xamarin.Android.Tasks;
7+
8+
namespace MonoDroid.Tuner
9+
{
10+
public class StripEmbeddedLibraries : BaseStep
11+
{
12+
protected override void ProcessAssembly (AssemblyDefinition assembly)
13+
{
14+
if (!Annotations.HasAction (assembly))
15+
return;
16+
var action = Annotations.GetAction (assembly);
17+
if (action == AssemblyAction.Skip || action == AssemblyAction.Delete)
18+
return;
19+
20+
var fileName = assembly.Name.Name + ".dll";
21+
if (MonoAndroidHelper.IsFrameworkAssembly (fileName) && !MonoAndroidHelper.FrameworkEmbeddedJarLookupTargets.Contains (fileName))
22+
return;
23+
24+
bool assembly_modified = false;
25+
foreach (var mod in assembly.Modules) {
26+
foreach (var r in mod.Resources.ToArray ()) {
27+
if (ShouldStripResource (r)) {
28+
Context.LogMessage (" Stripped {0} from {1}", r.Name, fileName);
29+
mod.Resources.Remove (r);
30+
assembly_modified = true;
31+
}
32+
}
33+
}
34+
if (assembly_modified && action == AssemblyAction.Copy) {
35+
Annotations.SetAction (assembly, AssemblyAction.Save);
36+
}
37+
}
38+
39+
bool ShouldStripResource (Resource r)
40+
{
41+
if (!(r is EmbeddedResource))
42+
return false;
43+
// embedded jars
44+
if (r.Name.EndsWith (".jar", StringComparison.InvariantCultureIgnoreCase))
45+
return true;
46+
// embedded AndroidNativeLibrary archive
47+
if (r.Name == "__AndroidNativeLibraries__.zip")
48+
return true;
49+
// embedded AndroidResourceLibrary archive
50+
if (r.Name == "__AndroidLibraryProjects__.zip")
51+
return true;
52+
// embedded AndroidEnvironment item
53+
if (r.Name.StartsWith ("__AndroidEnvironment__", StringComparison.Ordinal))
54+
return true;
55+
return false;
56+
}
57+
}
58+
}

src/Xamarin.Android.Build.Tasks/Tasks/LinkAssemblies.cs

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -69,24 +69,6 @@ IEnumerable<AssemblyDefinition> GetRetainAssemblies (DirectoryAssemblyResolver r
6969

7070
public override bool Execute ()
7171
{
72-
Log.LogDebugMessage ("LinkAssemblies Task");
73-
Log.LogDebugMessage (" UseSharedRuntime: {0}", UseSharedRuntime);
74-
Log.LogDebugMessage (" MainAssembly: {0}", MainAssembly);
75-
Log.LogDebugMessage (" OutputDirectory: {0}", OutputDirectory);
76-
Log.LogDebugMessage (" OptionalDestinationDirectory: {0}", OptionalDestinationDirectory);
77-
Log.LogDebugMessage (" I18nAssemblies: {0}", I18nAssemblies);
78-
Log.LogDebugMessage (" LinkMode: {0}", LinkMode);
79-
Log.LogDebugMessage (" LinkSkip: {0}", LinkSkip);
80-
Log.LogDebugTaskItems (" LinkDescriptions:", LinkDescriptions);
81-
Log.LogDebugTaskItems (" ResolvedAssemblies:", ResolvedAssemblies);
82-
Log.LogDebugMessage (" EnableProguard: {0}", EnableProguard);
83-
Log.LogDebugMessage (" ProguardConfiguration: {0}", ProguardConfiguration);
84-
Log.LogDebugMessage (" DumpDependencies: {0}", DumpDependencies);
85-
Log.LogDebugMessage (" LinkOnlyNewerThan: {0}", LinkOnlyNewerThan);
86-
Log.LogDebugMessage (" HttpClientHandlerType: {0}", HttpClientHandlerType);
87-
Log.LogDebugMessage (" TlsProvider: {0}", TlsProvider);
88-
Log.LogDebugMessage (" PreserveJniMarshalMethods: {0}", PreserveJniMarshalMethods);
89-
9072
var rp = new ReaderParameters {
9173
InMemory = true,
9274
};

src/Xamarin.Android.Build.Tasks/Tasks/StripEmbeddedLibraries.cs

Lines changed: 0 additions & 93 deletions
This file was deleted.

src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs

Lines changed: 49 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using System.Threading.Tasks;
1010
using System.Xml.Linq;
1111
using Microsoft.Build.Framework;
12+
using Mono.Cecil;
1213
using NUnit.Framework;
1314
using Xamarin.ProjectTools;
1415

@@ -839,9 +840,6 @@ public void BasicApplicationRepetitiveBuild ()
839840
Assert.IsTrue (
840841
b.Output.IsTargetSkipped ("_Sign"),
841842
"the _Sign target should not run");
842-
Assert.IsTrue (
843-
b.Output.IsTargetSkipped ("_StripEmbeddedLibraries"),
844-
"the _StripEmbeddedLibraries target should not run");
845843
proj.AndroidResources.Last ().Timestamp = null;
846844
Assert.IsTrue (b.Build (proj), "third build failed");
847845
Assert.IsFalse (
@@ -875,9 +873,6 @@ public class Foo {
875873
Assert.IsTrue (
876874
b.Output.IsTargetSkipped ("_Sign"),
877875
"the _Sign target should not run");
878-
Assert.IsTrue (
879-
b.Output.IsTargetSkipped ("_StripEmbeddedLibraries"),
880-
"the _StripEmbeddedLibraries target should not run");
881876
Assert.IsTrue (
882877
b.Output.IsTargetSkipped ("_LinkAssembliesShrink"),
883878
"the _LinkAssembliesShrink target should not run");
@@ -1571,19 +1566,48 @@ public void CheckSequencePointGeneration (bool isRelease, bool monoSymbolArchive
15711566
[Test]
15721567
public void BuildApplicationWithMonoEnvironment ([Values ("", "Normal", "Offline")] string sequencePointsMode)
15731568
{
1574-
var proj = new XamarinAndroidApplicationProject () {
1569+
var lib = new XamarinAndroidLibraryProject {
1570+
ProjectName = "Library1",
15751571
IsRelease = true,
15761572
OtherBuildItems = { new AndroidItem.AndroidEnvironment ("Mono.env") {
15771573
TextContent = () => "MONO_DEBUG=soft-breakpoints"
15781574
},
15791575
},
15801576
};
1581-
proj.SetProperty ("_AndroidSequencePointsMode", sequencePointsMode);
1582-
using (var b = CreateApkBuilder (Path.Combine ("temp", TestName))) {
1583-
b.Verbosity = LoggerVerbosity.Diagnostic;
1584-
Assert.IsTrue (b.Build (proj), "Build should have succeeded.");
1585-
var apk = Path.Combine (Root, b.ProjectDirectory,
1586-
proj.IntermediateOutputPath, "android", "bin", "UnnamedProject.UnnamedProject.apk");
1577+
var app = new XamarinAndroidApplicationProject () {
1578+
IsRelease = true,
1579+
AndroidLinkModeRelease = AndroidLinkMode.Full,
1580+
References = {
1581+
new BuildItem ("ProjectReference","..\\Library1\\Library1.csproj"),
1582+
},
1583+
};
1584+
app.MainActivity = app.DefaultMainActivity.Replace ("public class MainActivity : Activity", "public class MainActivity : Xamarin.Forms.Platform.Android.FormsAppCompatActivity");
1585+
app.Packages.Add (KnownPackages.XamarinForms_3_0_0_561731);
1586+
app.Packages.Add (KnownPackages.Android_Arch_Core_Common_26_1_0);
1587+
app.Packages.Add (KnownPackages.Android_Arch_Lifecycle_Common_26_1_0);
1588+
app.Packages.Add (KnownPackages.Android_Arch_Lifecycle_Runtime_26_1_0);
1589+
app.Packages.Add (KnownPackages.AndroidSupportV4_27_0_2_1);
1590+
app.Packages.Add (KnownPackages.SupportCompat_27_0_2_1);
1591+
app.Packages.Add (KnownPackages.SupportCoreUI_27_0_2_1);
1592+
app.Packages.Add (KnownPackages.SupportCoreUtils_27_0_2_1);
1593+
app.Packages.Add (KnownPackages.SupportDesign_27_0_2_1);
1594+
app.Packages.Add (KnownPackages.SupportFragment_27_0_2_1);
1595+
app.Packages.Add (KnownPackages.SupportMediaCompat_27_0_2_1);
1596+
app.Packages.Add (KnownPackages.SupportV7AppCompat_27_0_2_1);
1597+
app.Packages.Add (KnownPackages.SupportV7CardView_27_0_2_1);
1598+
app.Packages.Add (KnownPackages.SupportV7MediaRouter_27_0_2_1);
1599+
app.Packages.Add (KnownPackages.SupportV7RecyclerView_27_0_2_1);
1600+
//LinkSkip one assembly that contains __AndroidLibraryProjects__.zip
1601+
string linkSkip = KnownPackages.SupportV7AppCompat_27_0_2_1.Id;
1602+
app.SetProperty ("AndroidLinkSkip", linkSkip);
1603+
app.SetProperty ("_AndroidSequencePointsMode", sequencePointsMode);
1604+
using (var libb = CreateDllBuilder (Path.Combine ("temp", TestName, lib.ProjectName)))
1605+
using (var appb = CreateApkBuilder (Path.Combine ("temp", TestName, app.ProjectName))) {
1606+
Assert.IsTrue (libb.Build (lib), "Library build should have succeeded.");
1607+
Assert.IsTrue (appb.Build (app), "App should have succeeded.");
1608+
Assert.IsTrue (StringAssertEx.ContainsText (appb.LastBuildOutput, $"Save assembly: {linkSkip}"), $"{linkSkip} should be saved, and not linked!");
1609+
var apk = Path.Combine (Root, appb.ProjectDirectory,
1610+
app.IntermediateOutputPath, "android", "bin", "UnnamedProject.UnnamedProject.apk");
15871611
using (var zipFile = ZipHelper.OpenZip (apk)) {
15881612
var data = ZipHelper.ReadFileFromZip (zipFile, "environment");
15891613
Assert.IsNotNull (data, "environment should exist in the apk.");
@@ -1595,6 +1619,18 @@ public void BuildApplicationWithMonoEnvironment ([Values ("", "Normal", "Offline
15951619
string.IsNullOrEmpty (sequencePointsMode) ? true : x.Contains ("gen-compact-seq-points")),
15961620
"The values from Mono.env should have been merged into environment");
15971621
}
1622+
var assemblyDir = Path.Combine (Root, appb.ProjectDirectory, app.IntermediateOutputPath, "android", "assets");
1623+
var rp = new ReaderParameters { ReadSymbols = false };
1624+
foreach (var assemblyFile in Directory.EnumerateFiles (assemblyDir, "*.dll")) {
1625+
using (var assembly = AssemblyDefinition.ReadAssembly (assemblyFile)) {
1626+
foreach (var module in assembly.Modules) {
1627+
var resources = module.Resources.Select (r => r.Name).ToArray ();
1628+
Assert.IsFalse (StringAssertEx.ContainsText (resources, "__AndroidEnvironment__"), "AndroidEnvironment EmbeddedResource should be stripped!");
1629+
Assert.IsFalse (StringAssertEx.ContainsText (resources, "__AndroidLibraryProjects__.zip"), "__AndroidLibraryProjects__.zip should be stripped!");
1630+
Assert.IsFalse (StringAssertEx.ContainsText (resources, "__AndroidNativeLibraries__.zip"), "__AndroidNativeLibraries__.zip should be stripped!");
1631+
}
1632+
}
1633+
}
15981634
}
15991635
}
16001636

src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Xamarin.Android.Build.Tests.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@
6161
<Project>{3F1F2F50-AF1A-4A5A-BEDB-193372F068D7}</Project>
6262
<Name>Xamarin.Android.Build.Tasks</Name>
6363
</ProjectReference>
64+
<ProjectReference Include="..\..\..\..\external\Java.Interop\src\Xamarin.Android.Cecil\Xamarin.Android.Cecil.csproj">
65+
<Project>{15945D4B-FF56-4BCC-B598-2718D199DD08}</Project>
66+
<Name>Xamarin.Android.Cecil</Name>
67+
</ProjectReference>
6468
<ProjectReference Include="..\..\..\..\external\xamarin-android-tools\src\Xamarin.Android.Tools.AndroidSdk\Xamarin.Android.Tools.AndroidSdk.csproj">
6569
<Project>{e34bcfa0-caa4-412c-aa1c-75db8d67d157}</Project>
6670
<Name>Xamarin.Android.Tools.AndroidSdk</Name>

src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.csproj

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@
107107
<Compile Include="Linker\MonoDroid.Tuner\LinkerOptions.cs" />
108108
<Compile Include="Linker\MonoDroid.Tuner\MonoDroidMarkStep.cs" />
109109
<Compile Include="Linker\MonoDroid.Tuner\PreserveHttpAndroidClientHandler.cs" />
110+
<Compile Include="Linker\MonoDroid.Tuner\StripEmbeddedLibraries.cs" />
110111
<Compile Include="Tasks\Aapt.cs" />
111112
<Compile Include="Tasks\Aapt2.cs" />
112113
<Compile Include="Tasks\Aapt2Compile.cs" />
@@ -194,7 +195,6 @@
194195
<Compile Include="Tasks\CreateLibraryResourceArchive.cs" />
195196
<Compile Include="Tasks\ResolveLibraryProjectImports.cs" />
196197
<Compile Include="Linker\MonoDroid.Tuner\PreserveExportedTypes.cs" />
197-
<Compile Include="Linker\MonoDroid.Tuner\RemoveLibraryResourceZip.cs" />
198198
<Compile Include="Linker\MonoDroid.Tuner\PreserveDynamicTypes.cs" />
199199
<Compile Include="Linker\MonoDroid.Tuner\PreserveLinqExpressions.cs" />
200200
<Compile Include="Tasks\NdkUtils.cs" />
@@ -205,7 +205,6 @@
205205
<Compile Include="Utilities\ResourceDesignerImportGenerator.cs" />
206206
<Compile Include="Tasks\CreateManagedLibraryResourceArchive.cs" />
207207
<Compile Include="Tasks\CheckForRemovedItems.cs" />
208-
<Compile Include="Tasks\StripEmbeddedLibraries.cs" />
209208
<Compile Include="Tasks\CheckProjectItems.cs" />
210209
<Compile Include="Tasks\CheckDuplicateJavaLibraries.cs" />
211210
<Compile Include="Mono.Android\PermissionAttribute.Partial.cs" />

0 commit comments

Comments
 (0)