Skip to content

Commit bbc7b8d

Browse files
committed
[XABT] Move additional provider source code generation out of <GenerateMainAndroidManifest> task.
1 parent 199efa8 commit bbc7b8d

File tree

4 files changed

+164
-102
lines changed

4 files changed

+164
-102
lines changed
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
using System;
2+
using System.IO;
3+
using System.Linq;
4+
using Java.Interop.Tools.JavaCallableWrappers;
5+
using Microsoft.Android.Build.Tasks;
6+
using Microsoft.Build.Framework;
7+
8+
namespace Xamarin.Android.Tasks;
9+
10+
public class GenerateAdditionalProviderSources : AndroidTask
11+
{
12+
public override string TaskPrefix => "GPS";
13+
14+
[Required]
15+
public ITaskItem [] AdditionalProviderSources { get; set; } = [];
16+
17+
[Required]
18+
public string AndroidRuntime { get; set; } = "";
19+
20+
public string CodeGenerationTarget { get; set; } = "";
21+
22+
[Required]
23+
public string IntermediateOutputDirectory { get; set; } = "";
24+
25+
public string? OutputDirectory { get; set; }
26+
27+
[Required]
28+
public string TargetName { get; set; } = "";
29+
30+
AndroidRuntime androidRuntime;
31+
JavaPeerStyle codeGenerationTarget;
32+
33+
public override bool RunTask ()
34+
{
35+
androidRuntime = MonoAndroidHelper.ParseAndroidRuntime (AndroidRuntime);
36+
codeGenerationTarget = MonoAndroidHelper.ParseCodeGenerationTarget (CodeGenerationTarget);
37+
38+
// Retrieve the stored NativeCodeGenStateObject
39+
var nativeCodeGenStates = BuildEngine4.GetRegisteredTaskObjectAssemblyLocal<NativeCodeGenStateCollection> (
40+
MonoAndroidHelper.GetProjectBuildSpecificTaskObjectKey (GenerateJavaStubs.NativeCodeGenStateObjectRegisterTaskKey, WorkingDirectory, IntermediateOutputDirectory),
41+
RegisteredTaskObjectLifetime.Build
42+
);
43+
44+
// We only need the first architecture, since this task is architecture-agnostic
45+
var templateCodeGenState = nativeCodeGenStates.States.First ().Value;
46+
47+
Generate (templateCodeGenState);
48+
49+
// Dispose the Cecil resolvers so the assemblies are closed.
50+
Log.LogDebugMessage ($"Disposing all {nameof (NativeCodeGenState)}.{nameof (NativeCodeGenState.Resolver)}");
51+
52+
return !Log.HasLoggedErrors;
53+
}
54+
55+
void Generate (NativeCodeGenStateObject codeGenState)
56+
{
57+
var additionalProviders = AdditionalProviderSources.Select (p => p.ItemSpec).ToList ();
58+
59+
// Create additional runtime provider java sources.
60+
bool isMonoVM = androidRuntime switch {
61+
Xamarin.Android.Tasks.AndroidRuntime.MonoVM => true,
62+
Xamarin.Android.Tasks.AndroidRuntime.CoreCLR => true,
63+
_ => false,
64+
};
65+
string providerTemplateFile = isMonoVM ?
66+
"MonoRuntimeProvider.Bundled.java" :
67+
"NativeAotRuntimeProvider.java";
68+
string providerTemplate = GetResource (providerTemplateFile);
69+
70+
foreach (var provider in additionalProviders) {
71+
var contents = providerTemplate.Replace (isMonoVM ? "MonoRuntimeProvider" : "NativeAotRuntimeProvider", provider);
72+
var real_provider = isMonoVM ?
73+
Path.Combine (OutputDirectory, "src", "mono", provider + ".java") :
74+
Path.Combine (OutputDirectory, "src", "net", "dot", "jni", "nativeaot", provider + ".java");
75+
Files.CopyIfStringChanged (contents, real_provider);
76+
}
77+
78+
// For NativeAOT, generate JavaInteropRuntime.java
79+
if (androidRuntime == Xamarin.Android.Tasks.AndroidRuntime.NativeAOT) {
80+
const string fileName = "JavaInteropRuntime.java";
81+
string template = GetResource (fileName);
82+
var contents = template.Replace ("@MAIN_ASSEMBLY_NAME@", TargetName);
83+
var path = Path.Combine (OutputDirectory, "src", "net", "dot", "jni", "nativeaot", fileName);
84+
Log.LogDebugMessage ($"Writing: {path}");
85+
Files.CopyIfStringChanged (contents, path);
86+
}
87+
88+
// Create additional application java sources.
89+
StringWriter regCallsWriter = new StringWriter ();
90+
regCallsWriter.WriteLine ("// Application and Instrumentation ACWs must be registered first.");
91+
92+
foreach ((string jniName, string assemblyQualifiedName) in codeGenState.ApplicationsAndInstrumentationsToReigster) {
93+
regCallsWriter.WriteLine (
94+
codeGenerationTarget == JavaPeerStyle.XAJavaInterop1 ?
95+
"\t\tmono.android.Runtime.register (\"{0}\", {1}.class, {1}.__md_methods);" :
96+
"\t\tnet.dot.jni.ManagedPeer.registerNativeMembers ({1}.class, {1}.__md_methods);",
97+
assemblyQualifiedName,
98+
jniName
99+
);
100+
}
101+
102+
regCallsWriter.Close ();
103+
104+
var real_app_dir = Path.Combine (OutputDirectory, "src", "net", "dot", "android");
105+
string applicationTemplateFile = "ApplicationRegistration.java";
106+
SaveResource (
107+
applicationTemplateFile,
108+
applicationTemplateFile,
109+
real_app_dir,
110+
template => template.Replace ("// REGISTER_APPLICATION_AND_INSTRUMENTATION_CLASSES_HERE", regCallsWriter.ToString ())
111+
);
112+
}
113+
114+
string GetResource (string resource)
115+
{
116+
using (var stream = GetType ().Assembly.GetManifestResourceStream (resource))
117+
using (var reader = new StreamReader (stream))
118+
return reader.ReadToEnd ();
119+
}
120+
121+
void SaveResource (string resource, string filename, string destDir, Func<string, string> applyTemplate)
122+
{
123+
string template = GetResource (resource);
124+
template = applyTemplate (template);
125+
Files.CopyIfStringChanged (template, Path.Combine (destDir, filename));
126+
}
127+
}
Lines changed: 9 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,10 @@
11
using System;
22
using System.Collections.Concurrent;
33
using System.Collections.Generic;
4-
using System.IO;
54
using System.Linq;
6-
using Java.Interop.Tools.Cecil;
7-
using Java.Interop.Tools.JavaCallableWrappers;
8-
using Java.Interop.Tools.TypeNameMappings;
95
using Microsoft.Android.Build.Tasks;
106
using Microsoft.Build.Framework;
11-
using Mono.Cecil;
7+
using Microsoft.Build.Utilities;
128
using Xamarin.Android.Tools;
139

1410
namespace Xamarin.Android.Tasks;
@@ -17,6 +13,8 @@ public class GenerateMainAndroidManifest : AndroidTask
1713
{
1814
public override string TaskPrefix => "GMM";
1915

16+
[Output]
17+
public ITaskItem []? AdditionalProviderSources { get; set; }
2018
[Required]
2119
public string AndroidRuntime { get; set; } = "";
2220
public string? AndroidSdkDir { get; set; }
@@ -25,10 +23,8 @@ public class GenerateMainAndroidManifest : AndroidTask
2523
public string? ApplicationLabel { get; set; }
2624
public string? BundledWearApplicationName { get; set; }
2725
public string? CheckedBuild { get; set; }
28-
public string CodeGenerationTarget { get; set; } = "";
2926
public bool Debug { get; set; }
3027
public bool EmbedAssemblies { get; set; }
31-
public bool EnableMarshalMethods { get; set; }
3228
[Required]
3329
public string IntermediateOutputDirectory { get; set; } = "";
3430
public string []? ManifestPlaceholders { get; set; }
@@ -37,22 +33,16 @@ public class GenerateMainAndroidManifest : AndroidTask
3733
public string []? MergedManifestDocuments { get; set; }
3834
public bool MultiDex { get; set; }
3935
public bool NeedsInternet { get; set; }
40-
public string? OutputDirectory { get; set; }
4136
public string? PackageName { get; set; }
4237
[Required]
4338
public ITaskItem [] ResolvedUserAssemblies { get; set; } = [];
4439
[Required]
4540
public string [] SupportedAbis { get; set; } = [];
4641
public string? SupportedOSPlatformVersion { get; set; }
47-
[Required]
48-
public string TargetName { get; set; } = "";
4942
public string? VersionCode { get; set; }
5043
public string? VersionName { get; set; }
5144

5245
AndroidRuntime androidRuntime;
53-
JavaPeerStyle codeGenerationTarget;
54-
55-
bool UseMarshalMethods => !Debug && EnableMarshalMethods;
5646

5747
public override bool RunTask ()
5848
{
@@ -68,21 +58,18 @@ public override bool RunTask ()
6858
var userAssembliesPerArch = MonoAndroidHelper.GetPerArchAssemblies (ResolvedUserAssemblies, SupportedAbis, validate: true);
6959

7060
androidRuntime = MonoAndroidHelper.ParseAndroidRuntime (AndroidRuntime);
71-
codeGenerationTarget = MonoAndroidHelper.ParseCodeGenerationTarget (CodeGenerationTarget);
7261

7362
// Generate the merged manifest
7463
var additionalProviders = MergeManifest (templateCodeGenState, GenerateJavaStubs.MaybeGetArchAssemblies (userAssembliesPerArch, templateCodeGenState.TargetArch));
75-
GenerateAdditionalProviderSources (templateCodeGenState, additionalProviders);
7664

65+
AdditionalProviderSources = additionalProviders.Select (p => new TaskItem (p)).ToArray ();
7766

78-
// If we still need the NativeCodeGenState in the <GenerateNativeMarshalMethodSources> task because we're using marshal methods,
79-
// we're going to transfer it to a new object that doesn't require holding open Cecil AssemblyDefinitions.
80-
if (UseMarshalMethods) {
81-
var nativeCodeGenStateObject = MarshalMethodCecilAdapter.GetNativeCodeGenStateCollection (Log, nativeCodeGenStates);
67+
// We still need the NativeCodeGenState for later tasks, but we're going to transfer
68+
// it to a new object that doesn't require holding open Cecil AssemblyDefinitions.
69+
var nativeCodeGenStateObject = MarshalMethodCecilAdapter.GetNativeCodeGenStateCollection (Log, nativeCodeGenStates);
8270

83-
Log.LogDebugMessage ($"Saving {nameof (NativeCodeGenStateObject)} to {nameof (GenerateJavaStubs.NativeCodeGenStateObjectRegisterTaskKey)}");
84-
BuildEngine4.RegisterTaskObjectAssemblyLocal (MonoAndroidHelper.GetProjectBuildSpecificTaskObjectKey (GenerateJavaStubs.NativeCodeGenStateObjectRegisterTaskKey, WorkingDirectory, IntermediateOutputDirectory), nativeCodeGenStateObject, RegisteredTaskObjectLifetime.Build);
85-
}
71+
Log.LogDebugMessage ($"Saving {nameof (NativeCodeGenStateObject)} to {nameof (GenerateJavaStubs.NativeCodeGenStateObjectRegisterTaskKey)}");
72+
BuildEngine4.RegisterTaskObjectAssemblyLocal (MonoAndroidHelper.GetProjectBuildSpecificTaskObjectKey (GenerateJavaStubs.NativeCodeGenStateObjectRegisterTaskKey, WorkingDirectory, IntermediateOutputDirectory), nativeCodeGenStateObject, RegisteredTaskObjectLifetime.Build);
8673

8774
// Dispose the Cecil resolvers so the assemblies are closed.
8875
Log.LogDebugMessage ($"Disposing all {nameof (NativeCodeGenState)}.{nameof (NativeCodeGenState.Resolver)}");
@@ -140,80 +127,4 @@ IList<string> MergeManifest (NativeCodeGenState codeGenState, Dictionary<string,
140127

141128
return additionalProviders;
142129
}
143-
144-
void GenerateAdditionalProviderSources (NativeCodeGenState codeGenState, IList<string> additionalProviders)
145-
{
146-
// Create additional runtime provider java sources.
147-
bool isMonoVM = androidRuntime switch {
148-
Xamarin.Android.Tasks.AndroidRuntime.MonoVM => true,
149-
Xamarin.Android.Tasks.AndroidRuntime.CoreCLR => true,
150-
_ => false,
151-
};
152-
string providerTemplateFile = isMonoVM ?
153-
"MonoRuntimeProvider.Bundled.java" :
154-
"NativeAotRuntimeProvider.java";
155-
string providerTemplate = GetResource (providerTemplateFile);
156-
157-
foreach (var provider in additionalProviders) {
158-
var contents = providerTemplate.Replace (isMonoVM ? "MonoRuntimeProvider" : "NativeAotRuntimeProvider", provider);
159-
var real_provider = isMonoVM ?
160-
Path.Combine (OutputDirectory, "src", "mono", provider + ".java") :
161-
Path.Combine (OutputDirectory, "src", "net", "dot", "jni", "nativeaot", provider + ".java");
162-
Files.CopyIfStringChanged (contents, real_provider);
163-
}
164-
165-
// For NativeAOT, generate JavaInteropRuntime.java
166-
if (androidRuntime == Xamarin.Android.Tasks.AndroidRuntime.NativeAOT) {
167-
const string fileName = "JavaInteropRuntime.java";
168-
string template = GetResource (fileName);
169-
var contents = template.Replace ("@MAIN_ASSEMBLY_NAME@", TargetName);
170-
var path = Path.Combine (OutputDirectory, "src", "net", "dot", "jni", "nativeaot", fileName);
171-
Log.LogDebugMessage ($"Writing: {path}");
172-
Files.CopyIfStringChanged (contents, path);
173-
}
174-
175-
// Create additional application java sources.
176-
StringWriter regCallsWriter = new StringWriter ();
177-
regCallsWriter.WriteLine ("// Application and Instrumentation ACWs must be registered first.");
178-
foreach (TypeDefinition type in codeGenState.JavaTypesForJCW) {
179-
if (JavaNativeTypeManager.IsApplication (type, codeGenState.TypeCache) || JavaNativeTypeManager.IsInstrumentation (type, codeGenState.TypeCache)) {
180-
if (codeGenState.Classifier != null && !codeGenState.Classifier.TypeHasDynamicallyRegisteredMethods (type)) {
181-
continue;
182-
}
183-
184-
string javaKey = JavaNativeTypeManager.ToJniName (type, codeGenState.TypeCache).Replace ('/', '.');
185-
regCallsWriter.WriteLine (
186-
codeGenerationTarget == JavaPeerStyle.XAJavaInterop1 ?
187-
"\t\tmono.android.Runtime.register (\"{0}\", {1}.class, {1}.__md_methods);" :
188-
"\t\tnet.dot.jni.ManagedPeer.registerNativeMembers ({1}.class, {1}.__md_methods);",
189-
type.GetAssemblyQualifiedName (codeGenState.TypeCache),
190-
javaKey
191-
);
192-
}
193-
}
194-
regCallsWriter.Close ();
195-
196-
var real_app_dir = Path.Combine (OutputDirectory, "src", "net", "dot", "android");
197-
string applicationTemplateFile = "ApplicationRegistration.java";
198-
SaveResource (
199-
applicationTemplateFile,
200-
applicationTemplateFile,
201-
real_app_dir,
202-
template => template.Replace ("// REGISTER_APPLICATION_AND_INSTRUMENTATION_CLASSES_HERE", regCallsWriter.ToString ())
203-
);
204-
}
205-
206-
string GetResource (string resource)
207-
{
208-
using (var stream = GetType ().Assembly.GetManifestResourceStream (resource))
209-
using (var reader = new StreamReader (stream))
210-
return reader.ReadToEnd ();
211-
}
212-
213-
void SaveResource (string resource, string filename, string destDir, Func<string, string> applyTemplate)
214-
{
215-
string template = GetResource (resource);
216-
template = applyTemplate (template);
217-
Files.CopyIfStringChanged (template, Path.Combine (destDir, filename));
218-
}
219130
}

src/Xamarin.Android.Build.Tasks/Utilities/MarshalMethodCecilAdapter.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
using System.Collections.Concurrent;
33
using System.Collections.Generic;
44
using System.Diagnostics.CodeAnalysis;
5+
using Java.Interop.Tools.Cecil;
6+
using Java.Interop.Tools.JavaCallableWrappers;
7+
using Java.Interop.Tools.TypeNameMappings;
58
using Microsoft.Android.Build.Tasks;
69
using Microsoft.Build.Utilities;
710
using Mono.Cecil;
@@ -35,6 +38,19 @@ static NativeCodeGenStateObject CreateNativeCodeGenState (AndroidTargetArch arch
3538
{
3639
var obj = new NativeCodeGenStateObject ();
3740

41+
foreach (var type in state.JavaTypesForJCW) {
42+
if (JavaNativeTypeManager.IsApplication (type, state.TypeCache) || JavaNativeTypeManager.IsInstrumentation (type, state.TypeCache)) {
43+
if (state.Classifier != null && !state.Classifier.TypeHasDynamicallyRegisteredMethods (type)) {
44+
continue;
45+
}
46+
47+
var jniName = JavaNativeTypeManager.ToJniName (type, state.TypeCache).Replace ('/', '.');
48+
var assemblyQualifiedName = type.GetAssemblyQualifiedName (state.TypeCache);
49+
50+
obj.ApplicationsAndInstrumentationsToReigster.Add ((jniName, assemblyQualifiedName));
51+
}
52+
}
53+
3854
if (state.Classifier is null)
3955
return obj;
4056

@@ -140,6 +156,7 @@ class NativeCodeGenStateCollection
140156
class NativeCodeGenStateObject
141157
{
142158
public Dictionary<string, IList<MarshalMethodEntryObject>> MarshalMethods { get; } = [];
159+
public List<(string JniName, string AssemblyQualifiedName)> ApplicationsAndInstrumentationsToReigster { get; } = [];
143160
}
144161

145162
class MarshalMethodEntryObject

src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ Copyright (C) 2011-2012 Xamarin. All rights reserved.
6464
<UsingTask TaskName="Xamarin.Android.Tasks.FilterAssemblies" AssemblyFile="Xamarin.Android.Build.Tasks.dll" />
6565
<UsingTask TaskName="Xamarin.Android.Tasks.FindLayoutsToBind" AssemblyFile="Xamarin.Android.Build.Tasks.dll" />
6666
<UsingTask TaskName="Xamarin.Android.Tasks.GenerateACWMap" AssemblyFile="Xamarin.Android.Build.Tasks.dll" />
67+
<UsingTask TaskName="Xamarin.Android.Tasks.GenerateAdditionalProviderSources" AssemblyFile="Xamarin.Android.Build.Tasks.dll" />
6768
<UsingTask TaskName="Xamarin.Android.Tasks.GenerateLayoutBindings" AssemblyFile="Xamarin.Android.Build.Tasks.dll" />
6869
<UsingTask TaskName="Xamarin.Android.Tasks.GenerateLibraryResources" AssemblyFile="Xamarin.Android.Build.Tasks.dll" />
6970
<UsingTask TaskName="Xamarin.Android.Tasks.GenerateManagedAidlProxies" AssemblyFile="Xamarin.Android.Build.Tasks.dll" />
@@ -1641,27 +1642,33 @@ because xbuild doesn't support framework reference assemblies.
16411642
ApplicationLabel="$(_ApplicationLabel)"
16421643
BundledWearApplicationName="$(BundledWearApplicationPackageName)"
16431644
CheckedBuild="$(_AndroidCheckedBuild)"
1644-
CodeGenerationTarget="$(_AndroidJcwCodegenTarget)"
16451645
Debug="$(AndroidIncludeDebugSymbols)"
16461646
EmbedAssemblies="$(EmbedAssembliesIntoApk)"
1647-
EnableMarshalMethods="$(_AndroidUseMarshalMethods)"
16481647
IntermediateOutputDirectory="$(IntermediateOutputPath)"
16491648
ManifestPlaceholders="$(AndroidManifestPlaceholders)"
16501649
ManifestTemplate="$(_AndroidManifestAbs)"
16511650
MergedAndroidManifestOutput="$(_ManifestOutput)"
16521651
MergedManifestDocuments="@(_MergedManifestDocuments)"
16531652
MultiDex="$(AndroidEnableMultiDex)"
16541653
NeedsInternet="$(AndroidNeedsInternetPermission)"
1655-
OutputDirectory="$(IntermediateOutputPath)android"
16561654
PackageName="$(_AndroidPackage)"
16571655
ResolvedUserAssemblies="@(_ResolvedUserMonoAndroidAssemblies)"
16581656
SupportedAbis="@(_BuildTargetAbis)"
16591657
SupportedOSPlatformVersion="$(SupportedOSPlatformVersion)"
1660-
TargetName="$(TargetName)"
16611658
VersionCode="$(_AndroidVersionCode)"
16621659
VersionName="$(_AndroidVersionName)">
1660+
<Output TaskParameter="AdditionalProviderSources" ItemName="_AdditionalProviderSources" />
16631661
</GenerateMainAndroidManifest>
16641662

1663+
<GenerateAdditionalProviderSources
1664+
AdditionalProviderSources="@(_AdditionalProviderSources)"
1665+
AndroidRuntime="$(_AndroidRuntime)"
1666+
CodeGenerationTarget="$(_AndroidJcwCodegenTarget)"
1667+
IntermediateOutputDirectory="$(IntermediateOutputPath)"
1668+
OutputDirectory="$(IntermediateOutputPath)android"
1669+
TargetName="$(TargetName)">
1670+
</GenerateAdditionalProviderSources>
1671+
16651672
<ItemGroup>
16661673
<FileWrites Include="@(_TypeMapAssemblySource)" />
16671674
<FileWrites Include="@(_TypeMapAssemblyInclude)" />

0 commit comments

Comments
 (0)