From cbea5d63f4a1703b23068c856c75ee3a24e1b1ea Mon Sep 17 00:00:00 2001 From: Jonathan Pryor Date: Thu, 19 May 2016 15:00:09 -0400 Subject: [PATCH] [Java.Interop.Tools.JavaCallableWrappers] Fix android.app.Application android.app.Application is special: Android contructs it before the mono runtime has been initialized, requiring that the [activation constructor][0] be used for all Android.App.Application subclasses: [Application] partial class MyApp : Android.App.Application { public MyApp (IntPtr r, JniHandleOwnership transfer) : base (r, transfer) { } } As a consequence of this, the Android.App.Application..ctor() default constructor *is never used in normal use*, which means that the linker is free to remove it. This in turn means that in Release (linked) apps, *no* constructor would be present in the `MyApp` Java Callable Wrappers, because constructor generation requires that the binding assembly contain the constructor to emit. This is kinda/sorta fine, in that the Java compiler-provided default constructor would still be emitted, allowing the `MyApp` Java Callable Wrapper to be constructed, but that's only true so long as the default constructor is sufficient. Unfortunately, the default constructor isn't always sufficient: on certain Android versions (API <= 15), the Application instance isn't provided to the bootstrap `MonoRuntimeProvider.attachInfo()` method, which means that the Android.App.Application.Context property returns the wrong value. Fixing this requires updating the Java Callable Wrapper of the Application subclass to contain code to preserve the first Application instance created in the process, which in turn means the default Application constructor is no longer sufficient. Update JavaCallableWrapperGenerator so that (in Debug builds) the default Application constructor is skipped, and in *all* configurations a custom constructor is generated within the Java Callable Wrapper for android.app.Application subclasses. [0]: https://developer.xamarin.com/guides/android/under_the_hood/architecture/#Java_Activation --- .../JavaCallableWrapperGenerator.cs | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/JavaCallableWrapperGenerator.cs b/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/JavaCallableWrapperGenerator.cs index 93e35f90b..904978193 100644 --- a/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/JavaCallableWrapperGenerator.cs +++ b/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/JavaCallableWrapperGenerator.cs @@ -543,8 +543,13 @@ void GenerateHeader (StreamWriter sw) void GenerateBody (StreamWriter sw) { - foreach (Signature ctor in ctors) + foreach (Signature ctor in ctors) { + if (string.IsNullOrEmpty (ctor.Params) && JniType.IsApplication (type)) + continue; GenerateConstructor (ctor, sw); + } + + GenerateApplicationConstructor (sw); foreach (JavaFieldInfo field in exported_fields) GenerateExportedField (field, sw); @@ -755,6 +760,19 @@ void GenerateConstructor (Signature ctor, StreamWriter sw) sw.WriteLine ("\t}"); } + void GenerateApplicationConstructor (StreamWriter sw) + { + if (!JniType.IsApplication (type)) { + return; + } + + sw.WriteLine (); + sw.WriteLine ("\tpublic {0} ()", name); + sw.WriteLine ("\t{"); + sw.WriteLine ("\t\tmono.MonoPackageManager.setContext (this);"); + sw.WriteLine ("\t}"); + } + void GenerateExportedField (JavaFieldInfo field, StreamWriter sw) { sw.WriteLine ();