Skip to content

Commit 3fb5b8d

Browse files
jpobstjonathanpeppers
authored andcommitted
Changes: dotnet/java-interop@6bc87e8...57f7bc8 * dotnet/java-interop@57f7bc84: [generator] Avoid non-blittable types in native callback methods (dotnet/java-interop#1296) * dotnet/java-interop@9369d4fd: [tests] fix `NU1510` warning as error (dotnet/java-interop#1306) Context: dotnet/java-interop@57f7bc8 Context: dotnet/java-interop#1027 dotnet/java-interop@57f7bc84 updated `generator --codegen-target=XAJavaInterop1` marshal methods to contain only blittable types in parameter and return types. Instead of `bool`, use `sbyte`; instead of `char`, use `ushort`. This change causes warnings when `MarshalMethodsClassifier` verifies that the marshal types match the native types: …/Xamarin.Android.Common.targets(1502,3): Method 'System.SByte Java.Lang.Object::n_Equals_Ljava_lang_Object_(System.IntPtr,System.IntPtr,System.IntPtr)' doesn't match native callback signature (invalid return type: expected 'System.Boolean', found 'System.SByte') …/Xamarin.Android.Common.targets(1502,3): Unable to find native callback method 'n_Equals_Ljava_lang_Object_' in type 'Java.Lang.Object', matching the 'System.Boolean Java.Lang.Object::Equals(Java.Lang.Object)' signature (jniName: 'equals') [Arch: X86_64; Assembly: obj/Release/android-x64/linked/Mono.Android.dll] …/Xamarin.Android.Common.targets(1502,3): Method 'System.Boolean Java.Lang.Object::Equals(Java.Lang.Object)' will be registered dynamically [Arch: X86_64; Assembly: obj/Release/android-x64/linked/Mono.Android.dll] …/Xamarin.Android.Common.targets(1502,3): Method 'System.SByte Java.Lang.Object::n_Equals_Ljava_lang_Object_(System.IntPtr,System.IntPtr,System.IntPtr)' doesn't match native callback signature (invalid return type: expected 'System.Boolean', found 'System.SByte') …/Xamarin.Android.Common.targets(1502,3): Unable to find native callback method 'n_Equals_Ljava_lang_Object_' in type 'Java.Lang.Object', matching the 'System.Boolean Java.Lang.Object::Equals(Java.Lang.Object)' signature (jniName: 'equals') [Arch: Arm64; Assembly: obj/Release/android-arm64/linked/Mono.Android.dll] …/Xamarin.Android.Common.targets(1502,3): Method 'System.Boolean Java.Lang.Object::Equals(Java.Lang.Object)' will be registered dynamically [Arch: Arm64; Assembly: obj/Release/android-arm64/linked/Mono.Android.dll] …/Xamarin.Android.Common.targets(1502,3): Type 'Android.Runtime.JavaObject, Mono.Android, Version=0.0.0.0, Culture=neutral, PublicKeyToken=84e04ff9cfb79065' will register some of its Java override methods dynamically. This may adversely affect runtime performance. See preceding warnings for names of dynamically registered methods. …/Xamarin.Android.Common.targets(1502,3): [Arm64] Number of methods in the project that will be registered dynamically: 1 …/Xamarin.Android.Common.targets(1502,3): [X86_64] Number of methods in the project that will be registered dynamically: 1 These warnings occur because the marshal method signature now differs from the public API signature. Consider: namespace Java.Lang; partial class Object { static sbyte n_Equals_Ljava_lang_Object_ (IntPtr jnienv, IntPtr native__this, IntPtr native_obj) => … [Register ("equals", "(Ljava/lang/Object;)Z", "GetEquals_Ljava_lang_Object_Handler")] public virtual unsafe bool Equals (Java.Lang.Object? obj) => … } `MarshalMethodsClassifier` uses the 3rd `connector` parameter to `RegisterAttribute` to determine the name of the marshal method -- string processing `GetEquals_Ljava_lang_Object_Handler` to obtain `n_Equals_Ljava_lang_Object_` -- and then checks that the parameter and return types match between the two methods. Now that we're emitting blittable types, they *don't* match, thus the warning. Fix this by treating our blittable types as equivalent to their native types in `MarshalMethodsClassifier`. Additionally, `Mono.Android` has "built-in delegates" that marshal `bool` types, e.g. `_JniMarshal_PP_Z`. Because `generator` no longer creates these delegates -- it will now create `_JniMarshal_PP_B` instead -- we need to add them manually.
1 parent bd6daad commit 3fb5b8d

File tree

3 files changed

+56
-2
lines changed

3 files changed

+56
-2
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// There are built-in delegates for these, but we no longer generate them in Mono.Android.dll
2+
// because bool is not a blittable type. But we still need them for pre-existing bindings.
3+
using System;
4+
5+
[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)]
6+
delegate bool _JniMarshal_PP_Z (IntPtr jnienv, IntPtr klass);
7+
[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)]
8+
delegate bool _JniMarshal_PPL_Z (IntPtr jnienv, IntPtr klass, IntPtr p0);
9+
[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)]
10+
delegate bool _JniMarshal_PPJ_Z (IntPtr jnienv, IntPtr klass, long p0);
11+
[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)]
12+
delegate void _JniMarshal_PPLZ_V (IntPtr jnienv, IntPtr klass, IntPtr p0, bool p1);
13+
[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)]
14+
delegate bool _JniMarshal_PPLL_Z (IntPtr jnienv, IntPtr klass, IntPtr p0, IntPtr p1);
15+
[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)]
16+
delegate bool _JniMarshal_PPIL_Z (IntPtr jnienv, IntPtr klass, int p0, IntPtr p1);
17+
[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)]
18+
delegate bool _JniMarshal_PPLII_Z (IntPtr jnienv, IntPtr klass, IntPtr p0, int p1, int p2);
19+
[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)]
20+
delegate bool _JniMarshal_PPLLJ_Z (IntPtr jnienv, IntPtr klass, IntPtr p0, IntPtr p1, long p2);
21+
[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)]
22+
delegate bool _JniMarshal_PPLIL_Z (IntPtr jnienv, IntPtr klass, IntPtr p0, int p1, IntPtr p2);
23+
[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)]
24+
delegate bool _JniMarshal_PPLLL_Z (IntPtr jnienv, IntPtr klass, IntPtr p0, IntPtr p1, IntPtr p2);
25+
[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)]
26+
delegate IntPtr _JniMarshal_PPIZI_L (IntPtr jnienv, IntPtr klass, int p0, bool p1, int p2);
27+
[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)]
28+
delegate bool _JniMarshal_PPLZZL_Z (IntPtr jnienv, IntPtr klass, IntPtr p0, bool p1, bool p2, IntPtr p3);
29+
[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)]
30+
delegate void _JniMarshal_PPZIIII_V (IntPtr jnienv, IntPtr klass, bool p0, int p1, int p2, int p3, int p4);

src/Mono.Android/Mono.Android.csproj

+1
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@
9696
<Compile Include="Android.Icu\DateIntervalFormat.cs" />
9797
<Compile Include="Android.Net.Wifi.P2p\WifiP2pManager.cs" />
9898
<Compile Include="Android.Runtime\DynamicMethodNameCounter.cs" />
99+
<Compile Include="Android.Runtime\ExtraDelegates.cs" />
99100
<Compile Include="Android.Runtime\IJavaObjectValueMarshaler.cs" />
100101
<Compile Include="Android.Telecom\InCallService.cs" />
101102
<Compile Include="Android.Telephony.Mbms\StreamingService.cs" />

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

+25-2
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ public bool Matches (MethodDefinition method)
208208
return false;
209209
}
210210

211-
if (String.Compare (returnType, method.ReturnType.FullName, StringComparison.Ordinal) != 0) {
211+
if (!TypeMatches (returnType, method.ReturnType.FullName)) {
212212
log.LogWarning ($"Method '{method.FullName}' doesn't match native callback signature (invalid return type: expected '{returnType}', found '{method.ReturnType.FullName}')");
213213
return false;
214214
}
@@ -223,14 +223,37 @@ public bool Matches (MethodDefinition method)
223223
parameterTypeName = pd.ParameterType.FullName;
224224
}
225225

226-
if (String.Compare (parameterTypeName, paramTypes[i], StringComparison.Ordinal) != 0) {
226+
if (!TypeMatches (parameterTypeName, paramTypes[i])) {
227227
log.LogWarning ($"Method '{method.FullName}' doesn't match native callback signature, expected parameter type '{paramTypes[i]}' at position {i}, found '{parameterTypeName}'");
228228
return false;
229229
}
230230
}
231231

232232
return true;
233233
}
234+
235+
// Because these types are marshaled as different blittable types,
236+
// we need to accept them as equivalent
237+
static readonly (string Source, string Replacement)[] equivalent_types = [
238+
(Source: "System.Boolean", Replacement: "System.SByte"),
239+
(Source: "System.Char", Replacement: "System.UInt16"),
240+
];
241+
242+
static bool TypeMatches (string type, string methodType)
243+
{
244+
if (String.Compare (type, methodType, StringComparison.Ordinal) == 0)
245+
return true;
246+
247+
foreach (var eq in equivalent_types) {
248+
if (string.Compare (eq.Source, type, StringComparison.Ordinal) == 0 && string.Compare (eq.Replacement, methodType, StringComparison.Ordinal) == 0)
249+
return true;
250+
251+
if (string.Compare (eq.Source, methodType, StringComparison.Ordinal) == 0 && string.Compare (eq.Replacement, type, StringComparison.Ordinal) == 0)
252+
return true;
253+
}
254+
255+
return false;
256+
}
234257
}
235258

236259
TypeDefinitionCache tdCache;

0 commit comments

Comments
 (0)