-
Notifications
You must be signed in to change notification settings - Fork 544
/
Copy pathFindJavaObjectsStep.cs
134 lines (101 loc) · 4.46 KB
/
FindJavaObjectsStep.cs
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
123
124
125
126
127
128
129
130
131
132
133
134
#nullable enable
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 bool UseMarshalMethods { get; set; }
public TaskLoggingHelper Log { get; set; }
public FindJavaObjectsStep (TaskLoggingHelper log) => Log = log;
public bool 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);
return false;
}
// This step does not change the assembly
return false;
}
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);",
};
if (UseMarshalMethods) {
var classifier = new MarshalMethodsClassifier (Context, Context.Resolver, Log);
reader_options.MethodClassifier = new MarshalMethodsCollection (classifier);
}
foreach (var type in types) {
var wrapper = CecilImporter.CreateType (type, Context, reader_options);
wrappers.Add (wrapper);
}
return wrappers;
}
}