-
Notifications
You must be signed in to change notification settings - Fork 569
Expand file tree
/
Copy pathFindJavaObjectsStep.cs
More file actions
122 lines (92 loc) · 4.13 KB
/
FindJavaObjectsStep.cs
File metadata and controls
122 lines (92 loc) · 4.13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
using System;
using System.Collections.Generic;
using System.Linq;
using Java.Interop.Tools.JavaCallableWrappers;
using Java.Interop.Tools.JavaCallableWrappers.Adapters;
using Java.Interop.Tools.JavaCallableWrappers.CallableWrapperMembers;
using Microsoft.Android.Build.Tasks;
using Microsoft.Build.Utilities;
using Mono.Cecil;
using Mono.Linker;
using Mono.Linker.Steps;
using Xamarin.Android.Tasks;
namespace MonoDroid.Tuner;
/// <summary>
/// Scans an assembly for JLOs that need JCWs generated and writes them to an XML file.
/// </summary>
public class FindJavaObjectsStep : BaseStep, IAssemblyModifierPipelineStep
{
public string ApplicationJavaClass { get; set; } = "";
public bool ErrorOnCustomJavaObject { get; set; }
public TaskLoggingHelper Log { get; set; }
public FindJavaObjectsStep (TaskLoggingHelper log) => Log = log;
public void ProcessAssembly (AssemblyDefinition assembly, StepContext context)
{
var destinationJLOXml = JavaObjectsXmlFile.GetJavaObjectsXmlFilePath (context.Destination.ItemSpec);
var scanned = ScanAssembly (assembly, context, destinationJLOXml);
if (!scanned) {
// We didn't scan for Java objects, so write an empty .xml file for later steps
JavaObjectsXmlFile.WriteEmptyFile (destinationJLOXml, Log);
}
}
public bool ScanAssembly (AssemblyDefinition assembly, StepContext context, string destinationJLOXml)
{
if (!ShouldScan (context))
return false;
var action = Annotations.HasAction (assembly) ? Annotations.GetAction (assembly) : AssemblyAction.Skip;
if (action == AssemblyAction.Delete)
return false;
var types = ScanForJavaTypes (assembly);
var initial_count = types.Count;
// Filter out Java types we don't care about
types = types.Where (t => !JavaTypeScanner.ShouldSkipJavaCallableWrapperGeneration (t, Context)).ToList ();
Log.LogDebugMessage ($"{assembly.Name.Name} - Found {initial_count} Java types, filtered to {types.Count}");
var xml = new JavaObjectsXmlFile ();
xml.ACWMapEntries.AddRange (types.Select (t => ACWMapEntry.Create (t, Context)));
xml.JavaCallableWrappers.AddRange (ConvertToCallableWrappers (types.Where (t => !t.IsInterface).ToList ()));
xml.Export (destinationJLOXml);
Log.LogDebugMessage ($"Wrote '{destinationJLOXml}', {xml.JavaCallableWrappers.Count} JCWs, {xml.ACWMapEntries.Count} ACWs");
return true;
}
bool ShouldScan (StepContext context)
{
if (!context.IsAndroidAssembly)
return false;
// When marshal methods or non-JavaPeerStyle.XAJavaInterop1 are in use we do not want to skip non-user assemblies (such as Mono.Android) - we need to generate JCWs for them during
// application build, unlike in Debug configuration or when marshal methods are disabled, in which case we use JCWs generated during Xamarin.Android
// build and stored in a jar file.
var useMarshalMethods = !context.IsDebug && context.EnableMarshalMethods;
var shouldSkipNonUserAssemblies = !useMarshalMethods && context.CodeGenerationTarget == JavaPeerStyle.XAJavaInterop1;
if (shouldSkipNonUserAssemblies && !context.IsUserAssembly) {
Log.LogDebugMessage ($"Skipping assembly '{context.Source.ItemSpec}' because it is not a user assembly and we don't need JLOs from non-user assemblies");
return false;
}
return true;
}
List<TypeDefinition> ScanForJavaTypes (AssemblyDefinition assembly)
{
var types = new List<TypeDefinition> ();
var scanner = new XAJavaTypeScanner (Xamarin.Android.Tools.AndroidTargetArch.None, Log, Context) {
ErrorOnCustomJavaObject = ErrorOnCustomJavaObject
};
foreach (ModuleDefinition md in assembly.Modules) {
foreach (TypeDefinition td in md.Types) {
scanner.AddJavaType (td, types);
}
}
return types;
}
List<CallableWrapperType> ConvertToCallableWrappers (List<TypeDefinition> types)
{
var wrappers = new List<CallableWrapperType> ();
var reader_options = new CallableWrapperReaderOptions {
DefaultApplicationJavaClass = ApplicationJavaClass,
DefaultMonoRuntimeInitialization = "mono.MonoPackageManager.LoadApplication (context);",
};
foreach (var type in types) {
var wrapper = CecilImporter.CreateType (type, Context, reader_options);
wrappers.Add (wrapper);
}
return wrappers;
}
}