Im new Xamarin developer and I want to prepare diagnostic tool for Xamarin development. In my case I want to get managed stack trace from C# exception and unmanaged stack trace from rest of libraries (C++ if possible Java). I tried to invoke C++ methods, initialize controls with some weird options, invoke java libraries (google maps) but I still don't have a stack trace with native call stack.
Could you help me and explain how can I get stack trace with managed and unmanaged stack frames from Xamarin Android application?
Thanks a lot!
unmanaged stack trace from rest of libraries (C++, java)
In terms of C, there is no exception handing, C++ does have exceptions, but they are a totally different animal than CIL managed exceptions. Now you could implement C++ exceptions in your NDK/C++ code, and if possible based upon the exception and the ability to continue running, suppress the exception, and create a managed exception via the Mono runtime that somehow represents the C++ exception. Consult the Mono docs for more information on runtime exception propagation. Personally I just handle the C++ exceptions at the C++ level, log them, report them, etc... and do not try to do exception propagation back to managed code (to much overhead for too little return on the effort).
In terms of the various Xamarin.Android
/Android exceptions:
Consider something like libc's string strncpy
:
[DllImport("libc.so")]
private static extern void strncpy(StringBuilder dest, string src, uint n);
And calling it with nulls (or IntPtr.Zero):
strncpy(null, null, 1);
One nasty runtime crash:
[mono-rt] Stacktrace:
[mono-rt]
[mono-rt] at <unknown> <0xffffffff>
[mono-rt] at (wrapper managed-to-native) Android_Clipboard.MainActivity.strncpy (System.Text.StringBuilder,string,uint) <0x00012>
[mono-rt] at Android_Clipboard.MainActivity/<>c__DisplayClass5_0.<OnCreate>b__0 (object,System.EventArgs) [0x0004f] in /Volumes/Code/code/Projects/Android_Clipboard/Android_Clipboard/MainActivity.cs:57
[mono-rt] at Android.Views.View/IOnClickListenerImplementor.OnClick (Android.Views.View) [0x00011] in <25661073a35344a89f215a4cf81af37c>:0
[mono-rt] at Android.Views.View/IOnClickListenerInvoker.n_OnClick_Landroid_view_View_ (intptr,intptr,intptr) [0x00011] in <25661073a35344a89f215a4cf81af37c>:0
[mono-rt] at (wrapper dynamic-method) object.cea8479a-a63b-41ac-a9f6-b0fe3b09df49 (intptr,intptr,intptr) [0x00017] in <f32579baafc1404fa37ba3ec1abdc0bd>:0
[mono-rt] at (wrapper native-to-managed) object.cea8479a-a63b-41ac-a9f6-b0fe3b09df49 (intptr,intptr,intptr) [0x00022] in <f32579baafc1404fa37ba3ec1abdc0bd>:0
[mono-rt] /proc/self/maps:
[mono-rt] 12c00000-42c00000 rw-p 00000000 00:01 207683 /dev/ashmem/dalvik-main space (region space) (deleted)
[mono-rt] 70dca000-70f78000 rw-p 00000000 fc:00 106531 /data/dalvik-cache/x86/system@[email protected]
[mono-rt] 70f78000-71014000 rw-p 00000000 fc:00 106532
~~~
[mono-rt] No native Android stacktrace (see debuggerd output).
[mono-rt]
[mono-rt]
[mono-rt] =================================================================
[mono-rt] Got a SIGSEGV while executing native code. This usually indicates
[mono-rt] a fatal error in the mono runtime or one of the native libraries
[mono-rt] used by your application.
[mono-rt] =================================================================
[mono-rt]
[libc] Fatal signal 11 (SIGSEGV), code 1, fault addr 0x0 in tid 14916 (droid_Clipboard), pid 14916 (droid_Clipboard)
Anything called from the CIL Mono VM to Java passes over the VM2VM bridge (CilVM<->Mono/JNI<->JavaVM) are handled by the Mono JNIEnv and thus are wrapped in managed exceptions by the Mono runtime.
Consider reflecting on a Java field (from C#) that does not exist:
var someWidget = FindViewById<Button>(Resource.Id.myButton);
Java.Lang.Reflect.Field f = someWidget.Class.GetField("SomethingThatDoesNotExist");
Produces a Java-based java.lang.NoSuchFieldException that is wrapped and presented as a managed exception:
MonoDroid] UNHANDLED EXCEPTION:
[MonoDroid] Java.Lang.NoSuchFieldException: SomethingThatDoesNotExist
[MonoDroid] at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in <f32579baafc1404fa37ba3ec1abdc0bd>:0
[MonoDroid] at Java.Interop.JniEnvironment+InstanceMethods.CallObjectMethod (Java.Interop.JniObjectReference instance, Java.Interop.JniMethodInfo method, Java.Interop.JniArgumentValue* args) [0x00069] in <09bf3e262b934ffab2ba01f9fc7fd54d>:0
[MonoDroid] at Java.Interop.JniPeerMembers+JniInstanceMethods.InvokeAbstractObjectMethod (System.String encodedMember, Java.Interop.IJavaPeerable self, Java.Interop.JniArgumentValue* parameters) [0x00014] in <09bf3e262b934ffab2ba01f9fc7fd54d>:0
[MonoDroid] at Java.Lang.Class.GetField (System.String name) [0x00029] in <25661073a35344a89f215a4cf81af37c>:0
[MonoDroid] at Android_Clipboard.MainActivity+<>c__DisplayClass5_0.<OnCreate>b__0 (System.Object <p0>, System.EventArgs <p1>) [0x00048] in /Volumes/Code/code/Projects/Android_Clipboard/Android_Clipboard/MainActivity.cs:53
[MonoDroid] at Android.Views.View+IOnClickListenerImplementor.OnClick (Android.Views.View v) [0x00011] in <25661073a35344a89f215a4cf81af37c>:0
[MonoDroid] at Android.Views.View+IOnClickListenerInvoker.n_OnClick_Landroid_view_View_ (System.IntPtr jnienv, System.IntPtr native__this, System.IntPtr native_v) [0x0000f] in <25661073a35344a89f215a4cf81af37c>:0
[MonoDroid] at (wrapper dynamic-method) System.Object.7ad62bce-4e52-4d67-9099-969546fceb57(intptr,intptr,intptr)
[MonoDroid] --- End of managed Java.Lang.NoSuchFieldException stack trace ---
[MonoDroid] java.lang.NoSuchFieldException: SomethingThatDoesNotExist
[MonoDroid] at java.lang.Class.getField(Class.java:1601)
[MonoDroid] at mono.android.view.View_OnClickListenerImplementor.n_onClick(Native Method)
[MonoDroid] at mono.android.view.View_OnClickListenerImplementor.onClick(View_OnClickListenerImplementor.java:30)
[MonoDroid] at android.view.View.performClick(View.java:6294)
[MonoDroid] at android.view.View$PerformClick.run(View.java:24770)
[MonoDroid] at android.os.Handler.handleCallback(Handler.java:790)
[MonoDroid] at android.os.Handler.dispatchMessage(Handler.java:99)
[MonoDroid] at android.os.Looper.loop(Looper.java:164)
[MonoDroid] at android.app.ActivityThread.main(ActivityThread.java:6494)
[MonoDroid] at java.lang.reflect.Method.invoke(Native Method)
[MonoDroid] at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
[MonoDroid] at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
[MonoDroid]
Consider a Java exception the does not occur within the context of a Mono/CIL call:
Java:
private static void stackOverflowLoop() {
CrashMe.stackOverflowLoop();
}
public void stackOverflow() {
new Handler().postDelayed(new Runnable() {
public void run() {
CrashMe.stackOverflowLoop();
}
}, 2000);
}
C#:
new CrashMe().StackOverflow();
Produces a "pure" Java exception that is caught within the Android Runtime (remember that a Xamarin.Android
app is just a NDK-based C
app with a CIL VM and access to the Java VM)
AndroidRuntime] Shutting down VM
[AndroidRuntime] FATAL EXCEPTION: main
[AndroidRuntime] Process: com.sushihangover.Android_Clipboard, PID: 23664
[AndroidRuntime] java.lang.StackOverflowError: stack size 8MB
[AndroidRuntime] at com.sushihangover.mylibrary.CrashMe.stackOverflowLoop(CrashMe.java:7)
~~~~
[AndroidRuntime] at com.sushihangover.mylibrary.CrashMe.stackOverflowLoop(CrashMe.java:7)
[AndroidRuntime] at com.sushihangover.mylibrary.CrashMe.access$000(CrashMe.java:5)
[AndroidRuntime] at com.sushihangover.mylibrary.CrashMe$1.run(CrashMe.java:12)
[AndroidRuntime] at android.os.Handler.handleCallback(Handler.java:790)
[AndroidRuntime] at android.os.Handler.dispatchMessage(Handler.java:99)
[AndroidRuntime] at android.os.Looper.loop(Looper.java:164)
[AndroidRuntime] at android.app.ActivityThread.main(ActivityThread.java:6494)
[AndroidRuntime] at java.lang.reflect.Method.invoke(Native Method)
[AndroidRuntime] at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
[AndroidRuntime] at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
ANR
)Only caught/trapped by the Android operating system.
Java:
public void androidNotReponding() {
new Handler().postDelayed(new Runnable() {
public void run() {
while (true) {
}
}
}, 2000);
C#
new CrashMe().AndroidNotReponding();
[zygote] Thread[3,tid=25575,WaitingInMainSignalCatcherLoop,Thread*=0xb224ec00,peer=0x13880020,"Signal Catcher"]: reacting to signal 3
[zygote]
[zygote] Wrote stack traces to '[tombstoned]'
E ActivityManager: ANR in com.sushihangover.Android_Clipboard (com.sushihangover.Android_Clipboard/md58bbdf49b937b7d185e88b8dfe7516c89.MainActivity)
E ActivityManager: PID: 25886
E ActivityManager: Reason: Input dispatching timed out (Waiting to send non-key event because the touched window has not finished processing certain input events that were delivered to it over 500.0ms ago.
Cmd line: com.sushihangover.Android_Clipboard
~~~~
Total blocking GC count: 0
Total blocking GC time: 0
~~~~
suspend all histogram: Sum: 576us 99% C.I. 2us-329.200us Avg: 30.315us Max: 346us
DALVIK THREADS (13):
"main" prio=5 tid=1 Runnable
| group="main" sCount=0 dsCount=0 obj=0x73997258 self=0xb4034500
| sysTid=4484 nice=0 cgrp=default sched=0/0 handle=0xb7728c00
| state=R schedstat=( 0 0 0 ) utm=6486 stm=688 core=3 HZ=100
| stack=0xbf21d000-0xbf21f000 stackSize=8MB
| held mutexes= "mutator lock"(shared held)
at com.sushihangover.mylibrary.CrashMe$3.run(CrashMe.java:26)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke!(Native method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
"Signal Catcher" daemon prio=5 tid=2 Runnable
| group="system" sCount=0 dsCount=0 obj=0x12c840a0 self=0xae4c2000
| sysTid=4488 nice=0 cgrp=default sched=0/0 handle=0xb3432930
| state=R schedstat=( 0 0 0 ) utm=0 stm=0 core=0 HZ=100
| stack=0xb3336000-0xb3338000 stackSize=1014KB
| held mutexes= "mutator lock"(shared held)
native: #00 pc 0058bd02 /system/lib/libart.so (art::DumpNativeStack(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, int, char const*, art::ArtMethod*, void*)+226)
native: #01 pc 0055194e /system/lib/libart.so (art::Thread::Dump(std::__1::basic_ostream<char, std::__1::char_traits<char> >&) const+286)
~~~~