Commit b7a368a
authored
[Mono.Android] Marshal exceptions in RegisterNativeMembers() (dotnet#6672)
Context: dotnet/maui#4262
Context: dotnet#6675
If you run the `maui-blazor` template in a Release build:
dotnet build -t:Run -c Release
it crashes at runtime:
D monodroid-assembly: typemap: type with token 33555274 (0x200034a) in module {C7B4CC8F-7A03-4A3F-A34A-DC66EDC548B9} (Mono.Android) corresponds to Java type 'android/runtime/JavaProxyThrowable'
…
F DEBUG : backtrace:
F DEBUG : #00 pc 000000000065d8fc /apex/com.android.art/lib64/libart.so (void art::StackVisitor::WalkStack<(art::StackVisitor::CountTransitions)0>(bool)+156) (BuildId: 7fbaf2a1a3317bd634b00eb90e32291e)
F DEBUG : #1 pc 000000000069b25d /apex/com.android.art/lib64/libart.so (art::Thread::GetCurrentMethod(unsigned int*, bool, bool) const+157) (BuildId: 7fbaf2a1a3317bd634b00eb90e32291e)
F DEBUG : #2 pc 0000000000430fed /apex/com.android.art/lib64/libart.so (art::JNI<false>::FindClass(_JNIEnv*, char const*)+765) (BuildId: 7fbaf2a1a3317bd634b00eb90e32291e)
F DEBUG : #3 pc 0000000000047e5a /data/app/~~0Qm6D1S0sO3f1lwfakN0PA==/com.companyname.mauiapp2-08UokVCH5k_PlbZEH_hhkA==/split_config.x86_64.apk!libmono-android.release.so (offset 0x11e000) (java_interop_jnienv_find_class+26) (BuildId: 3d04f8b946590175e97b89aee2e3b19ceed4b524)
F DEBUG : dotnet#4 pc 00000000000128ac <anonymous:41640000>
The crash can be avoided by disabling the linker:
dotnet build -t:Run -c Release -p:AndroidLinkMode=None
# -or-
dotnet build -t:Run -c Release -p:PublishTrimmed=false
However, let us return to the crash: *why* is it crashing?
This isn't a "good debugging experience"; we have no useful context.
Lots of investigation later -- all hail printf debugging -- and we
found that the cause of the crash was an unhandled exception:
1. `Mono.Android.dll` has it's Java Callable Wrappers generated
from the *unlinked* assembly, into `mono.android.jar` and
`mono.android.dex` files. The Java Callable Wrapper for
`Android.Runtime.InputStreamAdapter` thus includes *all*
`Read()` method overloads.
2. When the app is built in Release configuration, linking is
enabled, and *some* of the `InputStreamAdapter.Read()` methods
are removed by the linker, along with the
`Java.IO.InputStream.Read()` methods that were overridden.
3. At runtime, we perform [Java Type Registration][0] for the
`Android.Runtime.InputStreamAdapter` type, which eventually calls
`AndroidTypeManager.RegisterNativeMembers()`, which eventually
attempts to *effectively* do:
Delegate.CreateDelegate (
typeof(Func<Delegate>),
typeof(InputStreamAdapter),
"GetReadHandler");
4. Because of (2), `Java.IO.InputStream.GetReadHandler()`
*does not exist*, and thus `Delegate.CreateDelegate()` throws an
`ArgumentException`.
So far, so reasonable, but…
5. `AndroidTypeManager.RegisterNativeMembers()` didn't catch any
exceptions, nor did any other method between the original Java
`Runtime.register()` invocation and
`AndroidTypeManager.RegisterNativeMembers()`. The result is that
a C# exception was "in flight", and Mono then proceeded to
*tear down the stack frame* as it unwound the callstack looking
for `catch` handlers.
At this point, the process is toast: the runtime stack is FUBAR.
This is also why the `backtrace:` is "rooted" in
`JNIEnv::FindClass()`: `JNIEnv::FindClass()` invokes Java static
constructors before returning, which is how the static constructor in
the Java Callable Wrapper for `InputStreamAdapter` called
`Runtime.register()` in the first place.
All of this makes for a miserable debugging experience.
Fixing the "original" linker issue will be done in
dotnet#6675.
This hasn't been an issue in "Classic" Xamarin.Android, presumably
because the classic linker isn't as good as the net6 linker.
What we want to do *here* is improve this debugging experience, by
"wrapping" `AndroidTypeManager.RegisterNativeMembers()` in a
`try`/`catch` block, which can then *marshal the thrown exception*
back to Java. This *prevents* Mono from unwinding the callstack past
a JNI boundary, and avoids the annoying-to-debug app crash.
After this change, we get a much friendlier unhandled exception crash:
I MonoDroid: Android.Runtime.JavaProxyThrowable: Exception_WasThrown, Android.Runtime.JavaProxyThrowable
I MonoDroid:
I MonoDroid: --- End of managed Android.Runtime.JavaProxyThrowable stack trace ---
I MonoDroid: android.runtime.JavaProxyThrowable: System.ArgumentException: Arg_DlgtTargMeth
I MonoDroid: at System.Delegate.CreateDelegate(Type , Type , String , Boolean , Boolean )
I MonoDroid: at System.Delegate.CreateDelegate(Type , Type , String )
I MonoDroid: at Android.Runtime.AndroidTypeManager.RegisterNativeMembers(JniType , Type , String )
I MonoDroid: --- End of stack trace from previous location ---
I MonoDroid: at Java.Interop.JniEnvironment.StaticMethods.CallStaticObjectMethod(JniObjectReference , JniMethodInfo , JniArgumentValue* )
I MonoDroid: at Android.Runtime.JNIEnv.CallStaticObjectMethod(IntPtr , IntPtr , JValue* )
I MonoDroid: at Android.Runtime.JNIEnv.CallStaticObjectMethod(IntPtr , IntPtr , JValue[] )
I MonoDroid: at Android.Runtime.JNIEnv.FindClass(String )
I MonoDroid: at Android.Runtime.JNIEnv.AllocObject(String )
I MonoDroid: at Android.Runtime.JNIEnv.StartCreateInstance(String , String , JValue* )
I MonoDroid: at Android.Runtime.JNIEnv.StartCreateInstance(String , String , JValue[] )
I MonoDroid: at Android.Runtime.InputStreamAdapter..ctor(Stream )
I MonoDroid: at Android.Runtime.InputStreamAdapter.ToLocalJniHandle(Stream )
I MonoDroid: at Android.Webkit.WebResourceResponse..ctor(String , String , Int32 , String , IDictionary`2 , Stream )
I MonoDroid: at Microsoft.AspNetCore.Components.WebView.Maui.WebKitWebViewClient.ShouldInterceptRequest(WebView view, IWebResourceRequest request)
I MonoDroid: at Android.Webkit.WebViewClient.n_ShouldInterceptRequest_Landroid_webkit_WebView_Landroid_webkit_WebResourceRequest_(IntPtr , IntPtr , IntPtr , IntPtr )
I MonoDroid: at crc64d693e2d9159537db.WebKitWebViewClient.n_shouldInterceptRequest(Native Method)
I MonoDroid: at crc64d693e2d9159537db.WebKitWebViewClient.shouldInterceptRequest(WebKitWebViewClient.java:39)
I MonoDroid: at Rr.a(chromium-TrichromeWebViewGoogle.apk-stable-410410686:16)
I MonoDroid: at org.chromium.android_webview.AwContentsBackgroundThreadClient.shouldInterceptRequestFromNative(chromium-TrichromeWebViewGoogle.apk-stable-410410686:2)
I MonoDroid:
I MonoDroid: --- End of managed Android.Runtime.JavaProxyThrowable stack trace ---
I MonoDroid: android.runtime.JavaProxyThrowable: System.ArgumentException: Arg_DlgtTargMeth
I MonoDroid: at System.Delegate.CreateDelegate(Type , Type , String , Boolean , Boolean )
I MonoDroid: at System.Delegate.CreateDelegate(Type , Type , String )
I MonoDroid: at Android.Runtime.AndroidTypeManager.RegisterNativeMembers(JniType , Type , String )
I MonoDroid: --- End of stack trace from previous location ---
I MonoDroid: at Java.Interop.JniEnvironment.StaticMethods.CallStaticObjectMethod(JniObjectReference , JniMethodInfo , JniArgumentValue* )
I MonoDroid: at Android.Runtime.JNIEnv.CallStaticObjectMethod(IntPtr , IntPtr , JValue* )
I MonoDroid: at Android.Runtime.JNIEnv.CallStaticObjectMethod(IntPtr , IntPtr , JValue[] )
I MonoDroid: at Android.Runtime.JNIEnv.FindClass(String )
I MonoDroid: at Android.Runtime.JNIEnv.AllocObject(String )
I MonoDroid: at Android.Runtime.JNIEnv.StartCreateInstance(String , String , JValue* )
I MonoDroid: at Android.Runtime.JNIEnv.StartCreateInstance(String , String , JValue[] )
I MonoDroid: at Android.Runtime.InputStreamAdapter..ctor(Stream )
I MonoDroid: at Android.Runtime.InputStreamAdapter.ToLocalJniHandle(Stream )
I MonoDroid: at Android.Webkit.WebResourceResponse..ctor(String , String , Int32 , String , IDictionary`2 , Stream )
I MonoDroid: at Microsoft.AspNetCore.Components.WebView.Maui.WebKitWebViewClient.ShouldInterceptRequest(WebView view, IWebResourceRequest request)
I MonoDroid: at Android.Webkit.WebViewClient.n_ShouldInterceptRequest_Landroid_webkit_WebView_Landroid_webkit_WebResourceRequest_(IntPtr , IntPtr , IntPtr , IntPtr )
I MonoDroid: at crc64d693e2d9159537db.WebKitWebViewClient.n_shouldInterceptRequest(Native Method)
I MonoDroid: at crc64d693e2d9159537db.WebKitWebViewClient.shouldInterceptRequest(WebKitWebViewClient.java:39)
I MonoDroid: at Rr.a(chromium-TrichromeWebViewGoogle.apk-stable-410410686:16)
I MonoDroid: at org.chromium.android_webview.AwContentsBackgroundThreadClient.shouldInterceptRequestFromNative(chromium-TrichromeWebViewGoogle.apk-stable-410410686:2)
This is much easier to reason about, and will save us time in
the future.
[0]: https://github.com/xamarin/xamarin-android/wiki/Blueprint#java-type-registration1 parent f8ad887 commit b7a368a
1 file changed
+48
-44
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
378 | 378 | | |
379 | 379 | | |
380 | 380 | | |
381 | | - | |
382 | | - | |
| 381 | + | |
| 382 | + | |
| 383 | + | |
383 | 384 | | |
384 | | - | |
385 | | - | |
386 | | - | |
387 | | - | |
388 | | - | |
| 385 | + | |
| 386 | + | |
| 387 | + | |
| 388 | + | |
| 389 | + | |
389 | 390 | | |
390 | | - | |
391 | | - | |
392 | | - | |
393 | | - | |
394 | | - | |
395 | | - | |
| 391 | + | |
| 392 | + | |
| 393 | + | |
| 394 | + | |
| 395 | + | |
| 396 | + | |
396 | 397 | | |
397 | | - | |
398 | | - | |
399 | | - | |
400 | | - | |
401 | | - | |
402 | | - | |
403 | | - | |
404 | | - | |
405 | | - | |
406 | | - | |
407 | | - | |
408 | | - | |
409 | | - | |
410 | | - | |
| 398 | + | |
| 399 | + | |
| 400 | + | |
| 401 | + | |
| 402 | + | |
| 403 | + | |
| 404 | + | |
| 405 | + | |
| 406 | + | |
| 407 | + | |
| 408 | + | |
| 409 | + | |
| 410 | + | |
| 411 | + | |
| 412 | + | |
| 413 | + | |
| 414 | + | |
| 415 | + | |
| 416 | + | |
| 417 | + | |
| 418 | + | |
| 419 | + | |
| 420 | + | |
411 | 421 | | |
412 | | - | |
413 | | - | |
414 | | - | |
415 | | - | |
416 | | - | |
417 | | - | |
418 | | - | |
419 | | - | |
420 | | - | |
421 | | - | |
422 | | - | |
| 422 | + | |
| 423 | + | |
| 424 | + | |
| 425 | + | |
| 426 | + | |
| 427 | + | |
423 | 428 | | |
424 | | - | |
425 | | - | |
426 | | - | |
| 429 | + | |
427 | 430 | | |
428 | | - | |
429 | | - | |
430 | 431 | | |
431 | | - | |
| 432 | + | |
| 433 | + | |
| 434 | + | |
| 435 | + | |
432 | 436 | | |
433 | 437 | | |
434 | 438 | | |
| |||
0 commit comments