-
Notifications
You must be signed in to change notification settings - Fork 564
Description
Android application type
Android for .NET (net6.0-android, etc.)
Affected platform version
net6.0-android, net7.0-android
Description
I need a class which looks like this:
[Register("com.bug.exportconstructor.SampleManagedClass")]
public class SampleManagedClass : Java.Lang.Object
{
[Export(SuperArgumentsString = "")]
public SampleManagedClass(Context context)
{
System.Diagnostics.Debug.WriteLine("success");
}
public SampleManagedClass(nint handle, JniHandleOwnership transfer)
{
}
public SampleManagedClass()
{
}
}So the class inherits from Java.Lang.Object and has an exported constructor with the parameter Android.Content.Context.
The resulting code for the constructor in the ACW (Android Callable Wrapper) looks like this:
public SampleManagedClass (android.content.Context p0)
{
super ();
if (getClass () == SampleManagedClass.class) {
mono.android.TypeManager.Activate ("ExportConstructorBug.SampleManagedClass, ExportConstructorBug", "", this, new java.lang.Object[] { p0 });
}
}But should look like this:
public SampleManagedClass (android.content.Context p0)
{
super ();
if (getClass () == SampleManagedClass.class) {
mono.android.TypeManager.Activate ("ExportConstructorBug.SampleManagedClass, ExportConstructorBug", "Android.Content.Context, Mono.Android", this, new java.lang.Object[] { p0 });
}
}So the generator of the ACW forgets to add the appropriate type information in the TypeManager.Activate call.
The result of this problem is the following exception when the affected class is instantiated with the affected constructor in an unmanaged way:
**System.NotSupportedException:** 'Could not activate JNI Handle 0x7ffd2bd94e70 (key_handle 0x65d856e) of Java type 'com/bug/exportconstructor/SampleManagedClass' as managed type 'ExportConstructorBug.SampleManagedClass'.'
Background information:
I encountered this problem when I wanted to use the Samsung Accessory SDK in my net6.0-android app.
This SDK expects a constructor of this type and calls it from an external Android service.
So this issue is slightly related to #3490.
Steps to Reproduce
-
Download the minimal reproducible sample app from: ExportConstructorBug.zip
-
All relevant code is in
MainActivity.cs -
Run the app ->
line 23will throwSystem.NotSupportedException
This is the full code of MainActivity.cs:
using Android.Content;
using Android.Runtime;
using Java.Interop;
using Java.Lang;
namespace ExportConstructorBug
{
[Activity(Label = "@string/app_name", MainLauncher = true)]
public class MainActivity : Activity
{
protected override void OnCreate(Bundle? savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Simulate a unmanaged/native call of the problematic constructor
var smapleClass = Class.ForName("com.bug.exportconstructor.SampleManagedClass");
var contextClass = Class.ForName("android.content.Context");
var constructor = smapleClass.GetConstructor(contextClass);
try
{
constructor.NewInstance(Application.Context);
}
catch (System.Exception ex)
{
// Will throw a System.NotSupportedException
// 'Could not activate JNI Handle of Java type 'com/bug/exportconstructor/SampleManagedClass'
// as managed type 'ExportConstructorBug.SampleManagedClass'.'
System.Diagnostics.Debug.WriteLine(ex);
throw;
}
}
}
[Register("com.bug.exportconstructor.SampleManagedClass")]
public class SampleManagedClass : Java.Lang.Object
{
[Export(SuperArgumentsString = "")]
public SampleManagedClass(Context context)
{
System.Diagnostics.Debug.WriteLine("success");
}
public SampleManagedClass(nint handle, JniHandleOwnership transfer)
{
}
public SampleManagedClass()
{
}
}
}Did you find any workaround?
No, real workaround but you can go to "obj\Debug\net6.0-android\android\src\com\bug\exportconstructor\SampleManagedClass.java" and correct the generated constructor with:
public SampleManagedClass (android.content.Context p0)
{
super ();
if (getClass () == SampleManagedClass.class) {
mono.android.TypeManager.Activate ("ExportConstructorBug.SampleManagedClass, ExportConstructorBug", "Android.Content.Context, Mono.Android", this, new java.lang.Object[] { p0 });
}
}Then start the app again. Now the app should run fine and output "success".
However, your edit will be overriden by a clean build.
Relevant log output
[monodroid] Could not activate JNI Handle 0x7ffd2bd94e50 (key_handle 0x65d856e) of Java type 'com/bug/exportconstructor/SampleManagedClass' as managed type 'ExportConstructorBug.SampleManagedClass'.
[monodroid] Java.Interop.JavaLocationException: Exception of type 'Java.Interop.JavaLocationException' was thrown.
[monodroid] Java.Lang.Error: Exception of type 'Java.Lang.Error' was thrown.
[monodroid]
[monodroid] --- End of managed Java.Lang.Error stack trace ---
[monodroid] java.lang.Error: Java callstack:
[monodroid] at mono.android.TypeManager.n_activate(Native Method)
[monodroid] at mono.android.TypeManager.Activate(TypeManager.java:7)
[monodroid] at com.bug.exportconstructor.SampleManagedClass.<init>(SampleManagedClass.java:22)
[monodroid] at java.lang.reflect.Constructor.newInstance0(Native Method)
[monodroid] at java.lang.reflect.Constructor.newInstance(Constructor.java:343)
[monodroid] at crc646e3a9ae673c40143.MainActivity.n_onCreate(Native Method)
[monodroid] at crc646e3a9ae673c40143.MainActivity.onCreate(MainActivity.java:29)
[monodroid] at android.app.Activity.performCreate(Activity.java:8057)
[monodroid] at android.app.Activity.performCreate(Activity.java:8037)
[monodroid] at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1341)
[monodroid] at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3688)
[monodroid] at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3864)
[monodroid] at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:103)
[monodroid] at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
[monodroid] at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
[monodroid] at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2253)
[monodroid] at android.os.Handler.dispatchMessage(Handler.java:106)
[monodroid] at android.os.Looper.loopOnce(Looper.java:201)
[monodroid] at android.os.Looper.loop(Looper.java:288)
[monodroid] at android.app.ActivityThread.main(ActivityThread.java:7870)
[monodroid] at java.lang.reflect.Method.invoke(Native Method)
[monodroid] at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
[monodroid] at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)