Skip to content

[Mono.Android] Java.Interop Unification! - #9640

Merged
jonpryor merged 10 commits into
mainfrom
dev/jonp/jonp-JavaObject-unification
Jan 17, 2025
Merged

[Mono.Android] Java.Interop Unification!#9640
jonpryor merged 10 commits into
mainfrom
dev/jonp/jonp-JavaObject-unification

Conversation

@jonpryor

Copy link
Copy Markdown
Contributor

Context: https://github.com/xamarin/monodroid/commit/e318861ed8eb20a71852378ddd558409d6b1c234
Context: 130905e
Context: de04316
Context: #9636

In the beginning there was Mono for Android, which had a set of Mono.Android.dll assemblies (one per supported API level), each of which contained "duplicated" binding logic: each API level had its own Java.Lang.Object, Android.Runtime.JNIEnv, etc.

dotnet/java-interop started, in part, as a way to "split out" the core integration logic, so that it wouldn't need to be duplicated across every assembly. As part of this, it introduced its own core abstractions, notably Java.Interop.IJavaPeerable and Java.Interop.JavaObject.

When dotnet/java-interop was first introduced into Xamarin.Android, with xamarin/monodroid@e318861e, the integration was incomplete. Integration continued with 130905e, allowing unit tests within Java.Interop-Tests.dll to run within Xamarin.Android and construction of instances of e.g. JavaInt32Array, but one large piece of integration remained:

Moving GC bridge code out of Java.Lang.Object, and instead relying on Java.Interop.JavaObject, turning this:

namespace Java.Lang {
    public partial class Object : System.Object, IJavaPeerable /* … */ {
    }
}

into this:

namespace Java.Lang {
    public partial class Object : Java.Interop.JavaObject, IJavaPeerable /* … */ {
    }
}

Why? In part because @jonpryor has wanted to do this for literal years at this point, but also in part because of #9636 and related efforts to use Native AOT, which involves avoiding / bypassing DllImportAttribute invocations (for now, everything touched by Native AOT becomes a single .so binary, which we don't know the name of). Avoiding P/Invoke means embracing and extending existing Java.Interop constructs (e.g. de04316).

In addition to altering the base types of Java.Lang.Object and Java.Lang.Throwable:

  • Remove handle and related fields from Java.Lang.Object and Java.Lang.Throwable.

  • Update PreserveLists/Mono.Android.xml so that the removed fields are note preserved.

  • Rename JNIenvInit.AndroidValueManager to JNIEnvInit.ValueManager, and change its type to JniRuntime.JniValueManager. This is to help "force" usage of JnIRuntime.JniValueManager in more places, as we can't currently use AndroidValueManager in Native AOT (P/Invokes!).

  • Cleanup: Remove JNIEnv.Exit() and related code. These were used by the Android Designer, which is no longer supported.

  • Update (internal) interface IJavaObjectEx to remove constructs present on IJavaPeerable.

Known issues:

  • Java.Lang.Throwable(IntPtr, JniHandleOwnership) invocation will result in construction of an "extra" java.lang.Throwable instance on the Java side, which will be immediately discarded. This is because it uses the JavaException(string, Exception) constructor, which implicitly creates a Java peer.

    We may need dotnet/java-interop changes to better address this.

Loading
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants