Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
ee565e4
Improve JavaProxyThrowable by translating managed stack trace
grendello Jul 12, 2023
7c0a507
Update apkdiffs
grendello Jul 12, 2023
6ee31a3
Create JavaProxyThrowable with `Create` and reflection
grendello Jul 12, 2023
7cfc3dc
Oops
grendello Jul 12, 2023
78839fb
Seal the class and add test
grendello Jul 13, 2023
b2b38b1
Merge branch 'main' into throwable-stacktrace
grendello Jul 14, 2023
ada140c
Optionally append java stack trace
grendello Jul 14, 2023
45b3e72
oops
grendello Jul 14, 2023
241ed9b
Merge branch 'main' into throwable-stacktrace
grendello Jul 17, 2023
c1cabbc
oops #2
grendello Jul 17, 2023
4c38c11
Let's see if this works
grendello Jul 17, 2023
7a8964b
Java and managed traces differ, let's see what's the difference
grendello Jul 17, 2023
1bac358
Merge branch 'main' into throwable-stacktrace
grendello Jul 18, 2023
998c012
That should do it
grendello Jul 18, 2023
a25636d
Merge branch 'main' into throwable-stacktrace
grendello Jul 18, 2023
92e5db3
Merge branch 'main' into throwable-stacktrace
grendello Jul 24, 2023
4b5b56e
Update JavaProxyThrowable.cs
grendello Jul 26, 2023
b68dcc2
Merge branch 'main' into throwable-stacktrace
grendello Jul 27, 2023
32130ab
Get the Java stack trace from `self` directly
grendello Jul 27, 2023
603f1e4
Merge branch 'throwable-stacktrace' of github.com:grendello/xamarin-a…
grendello Jul 27, 2023
cdf4714
Merge branch 'main' into throwable-stacktrace
grendello Jul 31, 2023
784014c
Address comments
grendello Jul 31, 2023
a78d466
Merge remote-tracking branch 'origin/main' into throwable-stacktrace
jonpryor Aug 18, 2023
691e075
Update ExceptionTest.cs
jonpryor Aug 22, 2023
af90f92
Fix unit test.
jonpryor Aug 22, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Mono.Android/Android.Runtime/AndroidRuntime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ public override void RaisePendingException (Exception pendingException)
{
var je = pendingException as JavaProxyThrowable;
if (je == null) {
je = new JavaProxyThrowable (pendingException);
je = JavaProxyThrowable.Create (pendingException);
}
var r = new JniObjectReference (je.Handle);
JniEnvironment.Exceptions.Throw (r);
Expand Down
53 changes: 47 additions & 6 deletions src/Mono.Android/Android.Runtime/JavaProxyThrowable.cs
Original file line number Diff line number Diff line change
@@ -1,23 +1,64 @@
using System;
using System.Diagnostics;
using System.Reflection;

using StackTraceElement = Java.Lang.StackTraceElement;

namespace Android.Runtime {

class JavaProxyThrowable : Java.Lang.Error {

public readonly Exception InnerException;

public JavaProxyThrowable (Exception innerException)
: base (GetDetailMessage (innerException))
protected JavaProxyThrowable (string message, Exception innerException)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This type should probably be sealed -- nothing subclasses it, and I can't think of anything to subclass it ever -- and this constructor could thus be private.

: base (message)
{
InnerException = innerException;
}

static string GetDetailMessage (Exception innerException)
public static JavaProxyThrowable Create (Exception? innerException)
{
if (innerException == null)
throw new ArgumentNullException ("innerException");
if (innerException == null) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why have Exception? innerException if you're gonna throw ArgumentNullException here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was a typo

throw new ArgumentNullException (nameof (innerException));
}

var proxy = new JavaProxyThrowable (innerException.Message, innerException);

try {
proxy.TranslateStackTrace ();
} catch {
// We shouldn't throw here, just try to do the best we can do
proxy = new JavaProxyThrowable (innerException.ToString (), innerException);
}

return proxy;
}

void TranslateStackTrace ()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem with this method is that it doesn't "merge", it "replaces". #1188 should have provided examples for desired behavior.

Consider:

var e = new Java.Lang.Error ("here!");
e.PrintStackTrace(Java.Lang.JavaSystem.Out);

This produces the output:

java.lang.Error: here!
   at crc641c2f9234c37aaa3c.MainActivity.n_onCreate(Native Method)
   at crc641c2f9234c37aaa3c.MainActivity.onCreate(MainActivity.java:30)
   at android.app.Activity.performCreate(Activity.java:8341)
   at android.app.Activity.performCreate(Activity.java:8320)
   at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1417)
   at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3622)
   at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3778)
   at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:101)
   at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:138)
   at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
   at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2303)
   at android.os.Handler.dispatchMessage(Handler.java:106)
   at android.os.Looper.loopOnce(Looper.java:201)
   at android.os.Looper.loop(Looper.java:288)
   at android.app.ActivityThread.main(ActivityThread.java:7884)
   at java.lang.reflect.Method.invoke(Native Method)
   at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)

If the assumption in #1188 is correct, and we want printStackTrace() to be "more useful", replacing all of the above is not "more useful". What we'd want is to instead produce:

java.lang.Error: here!
   at android_cwd.MainActivity.OnCreate(MainActivity.cs:11)
   at crc641c2f9234c37aaa3c.MainActivity.n_onCreate(Native Method)
   at crc641c2f9234c37aaa3c.MainActivity.onCreate(MainActivity.java:30)
…

As far as I can tell, TranslateStackTrace() does not do any such "merging". It would thus instead produce:

   at android_cwd.MainActivity.OnCreate(MainActivity.cs:11)

as the complete stack trace, which I don't believe would be useful.

(Now, this PR/#1188 is about JavaProxyThrowable, not for new Error().PrintStackTrace(), but PrintStackTrace() is the main point.)

{
var trace = new StackTrace (InnerException, fNeedFileInfo: true);
if (trace.FrameCount <= 0) {
return;
}

StackFrame[] frames = trace.GetFrames ();
StackTraceElement[] elements = new StackTraceElement[frames.Length];

for (int i = 0; i < frames.Length; i++) {
StackFrame managedFrame = frames[i];
MethodBase? managedMethod = managedFrame.GetMethod ();

var throwableFrame = new StackTraceElement (
declaringClass: managedMethod?.DeclaringType?.FullName,
methodName: managedMethod?.Name,
fileName: managedFrame?.GetFileName (),
lineNumber: managedFrame?.GetFileLineNumber () ?? 0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably be ?? -1, as negative numbers appear to be the "don't have one" behavior. See e.g.

W *jonp*  : # jonp: stack[3]=crc64ef325ad1a3b68b57.MainActivity.n_onCreate(MainActivity.java:-2)

No idea where -2 came from; I assume it's because the file has no line number info? (Which also makes no sense, as the declaration for n_onCreate() does have a line number…)

);

elements[i] = throwableFrame;
}

return innerException.ToString ();
SetStackTrace (elements);
}
}
}
2 changes: 1 addition & 1 deletion src/Mono.Android/Java.Lang/Throwable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ public static Throwable FromException (System.Exception e)
if (e is Throwable)
return (Throwable) e;

return new Android.Runtime.JavaProxyThrowable (e);
return Android.Runtime.JavaProxyThrowable.Create (e);
}

public static System.Exception ToException (Throwable e)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,64 +2,64 @@
"Comment": null,
"Entries": {
"AndroidManifest.xml": {
"Size": 3032
"Size": 3036
},
"assemblies/_Microsoft.Android.Resource.Designer.dll": {
"Size": 1024
},
"assemblies/Java.Interop.dll": {
"Size": 58703
"Size": 58980
},
"assemblies/Mono.Android.dll": {
"Size": 86588
"Size": 91505
},
"assemblies/Mono.Android.Runtime.dll": {
"Size": 5798
"Size": 5822
},
"assemblies/rc.bin": {
"Size": 1235
},
"assemblies/System.Console.dll": {
"Size": 6442
"Size": 6444
},
"assemblies/System.Linq.dll": {
"Size": 9123
"Size": 9129
},
"assemblies/System.Private.CoreLib.dll": {
"Size": 536436
"Size": 537202
},
"assemblies/System.Runtime.dll": {
"Size": 2623
"Size": 2625
},
"assemblies/System.Runtime.InteropServices.dll": {
"Size": 3752
"Size": 3761
},
"assemblies/UnnamedProject.dll": {
"Size": 3349
"Size": 3225
},
"classes.dex": {
"Size": 19748
"Size": 19716
},
"lib/arm64-v8a/libmono-component-marshal-ilgen.so": {
"Size": 93552
"Size": 97392
},
"lib/arm64-v8a/libmonodroid.so": {
"Size": 380832
"Size": 380704
},
"lib/arm64-v8a/libmonosgen-2.0.so": {
"Size": 3160360
"Size": 3177936
},
"lib/arm64-v8a/libSystem.IO.Compression.Native.so": {
"Size": 723560
},
"lib/arm64-v8a/libSystem.Native.so": {
"Size": 94392
"Size": 94000
},
"lib/arm64-v8a/libSystem.Security.Cryptography.Native.Android.so": {
"Size": 154904
},
"lib/arm64-v8a/libxamarin-app.so": {
"Size": 16624
"Size": 16712
},
"META-INF/BNDLTOOL.RSA": {
"Size": 1213
Expand Down Expand Up @@ -95,5 +95,5 @@
"Size": 1904
}
},
"PackageSize": 2685258
"PackageSize": 2701642
}
10 changes: 9 additions & 1 deletion tests/Mono.Android-Tests/System/ExceptionTest.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Globalization;
using System.Reflection;

using Android.App;
using Android.Content;
Expand All @@ -17,7 +18,14 @@ static Java.Lang.Throwable CreateJavaProxyThrowable (Exception e)
var JavaProxyThrowable_type = typeof (Java.Lang.Object)
.Assembly
.GetType ("Android.Runtime.JavaProxyThrowable");
return (Java.Lang.Throwable) Activator.CreateInstance (JavaProxyThrowable_type, e);
MethodInfo? create = JavaProxyThrowable_type.GetMethod (
"Create",
BindingFlags.Static | BindingFlags.Public,
new Type[] { typeof(Exception) }
);

Assert.AreNotEqual (null, create, "Unable to find the Android.Runtime.JavaProxyThrowable.Create(Exception) method");
return (Java.Lang.Throwable)create.Invoke (null, new object[] { e });
}

[Test]
Expand Down