@@ -32,7 +32,7 @@ are described in the sections below.
32
32
This guide is meant to explain the technical implementation in a way
33
33
that is sufficient to understand the system without having to read the
34
34
actual source code.
35
-
35
+
36
36
# Java <-> Managed interoperability overview
37
37
38
38
Java VM and Managed VM are two entirely separate entities which
@@ -104,9 +104,9 @@ public class MainActivity : AppCompatActivity
104
104
protected override void OnCreate (Bundle savedInstanceState )
105
105
{
106
106
base .OnCreate (savedInstanceState );
107
- DoSomething (savedInstanceState );
107
+ DoSomething (savedInstanceState );
108
108
}
109
-
109
+
110
110
void DoSomething (Bundle bundle )
111
111
{
112
112
// do something with the bundle
@@ -161,7 +161,7 @@ Java.Interop's [`JavaTypeScanner`](../../external/Java.Interop/src/Java.Interop.
161
161
which uses ` Mono.Cecil ` to read all the assemblies referenced by the
162
162
application and its libraries. The returned list of assemblies is
163
163
then used by a variety of tasks, JCW being only one
164
- of them.
164
+ of them.
165
165
166
166
After all types are found,
167
167
[ ` JavaCallableWrapperGenerator ` ] ( ../../external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/JavaCallableWrapperGenerator.cs )
@@ -183,7 +183,7 @@ its constructor with three parameters:
183
183
1 . Java method name
184
184
2 . JNI method signature
185
185
3 . "Connector" method name
186
-
186
+
187
187
The "connector" is a static method which creates a delegate that
188
188
subsequently allows calling of the native callback method:
189
189
@@ -509,7 +509,7 @@ static get_function_pointer_fn get_function_pointer;
509
509
510
510
void xamarin_app_init (get_function_pointer_fn fn) noexcept
511
511
{
512
- get_function_pointer = fn;
512
+ get_function_pointer = fn;
513
513
}
514
514
515
515
using android_app_activity_on_create_bundle_fn = void (* ) (JNIEnv * env, jclass klass, jobject savedInstanceState);
@@ -520,11 +520,11 @@ JNICALL Java_helloandroid_MainActivity_n_1onCreate__Landroid_os_Bundle_2 (JNIEnv
520
520
{
521
521
if (android_app_activity_on_create_bundle == nullptr) {
522
522
get_function_pointer (
523
- 16, // mono image index
524
- 0, // class index
525
- 0x0600055B, // method token
526
- reinterpret_cast<void* &>(android_app_activity_on_create_bundle) // target pointer
527
- );
523
+ 16, // mono image index
524
+ 0, // class index
525
+ 0x0600055B, // method token
526
+ reinterpret_cast<void* &>(android_app_activity_on_create_bundle) // target pointer
527
+ );
528
528
}
529
529
530
530
android_app_activity_on_create_bundle (env, klass, savedInstanceState);
@@ -588,11 +588,13 @@ The exact modifications we apply are:
588
588
589
589
* Removal of the **connector backing field**
590
590
* Removal of the **connector method**
591
- * Addition of the `[UnmanagedCallersOnly]` attribute to the **native
592
- callback** method
593
- * Optionally, generation of a [non-blittable types
594
- wrapper](#wrappers-for-methods-with-non-blittable-types) for the
595
- **native callback** method.
591
+ * Generation of a **native callback wrapper** method, which catches
592
+ and propagates unhandled exceptions thrown by the native callback
593
+ or the target method. This method is decorated with the
594
+ `[UnmanagedCallersOnly]` attribute and called directly from the
595
+ native code.
596
+ * Optionally, generate code in the **native callback wrapper** to handle
597
+ [non-blittable types](#wrappers-for-methods-with-non-blittable-types).
596
598
597
599
All the modifications are performed with `Mono.Cecil`.
598
600
@@ -603,14 +605,24 @@ C# code for each marshal method:
603
605
public class MainActivity : AppCompatActivity
604
606
{
605
607
// Native callback
606
- [UnmanagedCallersOnly]
607
608
static void n_OnCreate_Landroid_os_Bundle_ (IntPtr jnienv, IntPtr native__this, IntPtr native_savedInstanceState)
608
609
{
609
610
var __this = global::Java.Lang.Object.GetObject<Android.App.Activity> (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!;
610
611
var savedInstanceState = global::Java.Lang.Object.GetObject<Android.OS.Bundle> (native_savedInstanceState, JniHandleOwnership.DoNotTransfer);
611
612
__this.OnCreate (savedInstanceState);
612
613
}
613
614
615
+ // Native callback exception wrapper
616
+ [UnmanagedCallersOnly]
617
+ static void n_OnCreate_Landroid_os_Bundle__mm_wrapper (IntPtr jnienv, IntPtr native__this, IntPtr native_savedInstanceState)
618
+ {
619
+ try {
620
+ n_OnCreate_Landroid_os_Bundle_ (jnienv, native__this, native_savedInstanceState)
621
+ } catch (Exception ex) {
622
+ Android.Runtime.AndroidEnvironmentInternal.UnhandledException (ex);
623
+ }
624
+ }
625
+
614
626
// Target method
615
627
[Register ("onCreate", "(Landroid/os/Bundle;)V", "GetOnCreate_Landroid_os_Bundle_Handler")]
616
628
protected virtual unsafe void OnCreate (Android.OS.Bundle? savedInstanceState)
@@ -665,13 +677,6 @@ value properly. Each wrapper method retains the native callback method
665
677
name, but appends the ` _mm_wrapper ` suffix to it:
666
678
667
679
``` csharp
668
-
669
- [UnmanagedCallersOnly ]
670
- static byte n_OnTouch_Landroid_view_View_Landroid_view_MotionEvent__mm_wrapper (IntPtr jnienv , IntPtr native__this , IntPtr native_v , IntPtr native_e )
671
- {
672
- return n_OnTouch_Landroid_view_View_Landroid_view_MotionEvent_ (jnienv , native__this , native_v , native_e ) ? 1 : 0 ;
673
- }
674
-
675
680
static bool n_OnTouch_Landroid_view_View_Landroid_view_MotionEvent_ (IntPtr jnienv , IntPtr native__this , IntPtr native_v , IntPtr native_e )
676
681
{
677
682
var __this = global :: Java .Lang .Object .GetObject <Android .Views .View .IOnTouchListener > (jnienv , native__this , JniHandleOwnership .DoNotTransfer )! ;
@@ -680,6 +685,17 @@ static bool n_OnTouch_Landroid_view_View_Landroid_view_MotionEvent_ (IntPtr jnie
680
685
bool __ret = __this .OnTouch (v , e );
681
686
return __ret ;
682
687
}
688
+
689
+ [UnmanagedCallersOnly ]
690
+ static byte n_OnTouch_Landroid_view_View_Landroid_view_MotionEvent__mm_wrapper (IntPtr jnienv , IntPtr native__this , IntPtr native_v , IntPtr native_e )
691
+ {
692
+ try {
693
+ return n_OnTouch_Landroid_view_View_Landroid_view_MotionEvent_ (jnienv , native__this , native_v , native_e ) ? 1 : 0 ;
694
+ } catch (Exception ex ) {
695
+ Android .Runtime .AndroidEnvironmentInternal .UnhandledException (ex );
696
+ return default ;
697
+ }
698
+ }
683
699
```
684
700
685
701
The wrapper's return statement uses the ternary operator to "cast" the
@@ -738,7 +754,7 @@ Dynamic registration uses the
738
754
[ ` RegisterNatives ` ] ( https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/functions.html#RegisterNatives )
739
755
JNI function at the runtime, which stores a pointer to the registered
740
756
method inside the structure which describes a Java class in the Java
741
- VM.
757
+ VM.
742
758
743
759
Marshal methods, however, don't register anything with the JNI,
744
760
instead they rely on the symbol lookup mechanism of the Java VM.
0 commit comments