From 2350a60e977b04ccfc87398b79dd020484934038 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Tue, 30 Jun 2026 09:35:12 -0700 Subject: [PATCH 1/3] Fix Android NativeAOT JNI string access Use an ABI-shaped byte* parameter for GetStringUTFChars instead of an out byte byref. This avoids requiring runtime marshalling in NativeAOT test assemblies that disable runtime marshalling. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Assisted-by: Copilot:gpt-5.5 --- src/tasks/AndroidAppBuilder/Templates/monodroid-nativeaot.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/tasks/AndroidAppBuilder/Templates/monodroid-nativeaot.cs b/src/tasks/AndroidAppBuilder/Templates/monodroid-nativeaot.cs index 963c1bef392caa..7229d841b78762 100644 --- a/src/tasks/AndroidAppBuilder/Templates/monodroid-nativeaot.cs +++ b/src/tasks/AndroidAppBuilder/Templates/monodroid-nativeaot.cs @@ -120,7 +120,8 @@ internal unsafe struct JNIEnv { fixed (JNIEnv* thisptr = &this) { - byte* chars = NativeInterface->GetStringUTFChars(thisptr, str, out byte isCopy); + byte isCopy; + byte* chars = NativeInterface->GetStringUTFChars(thisptr, str, &isCopy); if (chars is null) return null; @@ -383,7 +384,7 @@ unsafe struct JNINativeInterface void* NewStringUTF; delegate* unmanaged[Cdecl] GetStringUTFLength; - public delegate* unmanaged[Cdecl] GetStringUTFChars; + public delegate* unmanaged[Cdecl] GetStringUTFChars; public delegate* unmanaged[Cdecl] ReleaseStringUTFChars; public delegate* unmanaged[Cdecl] GetArrayLength; From 38f1005b38c49e2965ecd5887e52f7930ffb7f43 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Tue, 30 Jun 2026 09:51:27 -0700 Subject: [PATCH 2/3] Re-enable Android NativeAOT tests fixed by JNI change Remove the Android NativeAOT project exclusions that were tracked by dotnet/runtime#120725 now that the JNI GetStringUTFChars signature no longer requires byref marshalling. Also initialize the local isCopy byte before passing it to JNI. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Assisted-by: Copilot:gpt-5.5 --- src/libraries/tests.proj | 11 ----------- .../Templates/monodroid-nativeaot.cs | 2 +- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/src/libraries/tests.proj b/src/libraries/tests.proj index 51a1fad79f154b..a1dcb7c8b7baa4 100644 --- a/src/libraries/tests.proj +++ b/src/libraries/tests.proj @@ -600,17 +600,6 @@ - - - - - - - - - - - diff --git a/src/tasks/AndroidAppBuilder/Templates/monodroid-nativeaot.cs b/src/tasks/AndroidAppBuilder/Templates/monodroid-nativeaot.cs index 7229d841b78762..17d8ee6bab36a7 100644 --- a/src/tasks/AndroidAppBuilder/Templates/monodroid-nativeaot.cs +++ b/src/tasks/AndroidAppBuilder/Templates/monodroid-nativeaot.cs @@ -120,7 +120,7 @@ internal unsafe struct JNIEnv { fixed (JNIEnv* thisptr = &this) { - byte isCopy; + byte isCopy = 0; byte* chars = NativeInterface->GetStringUTFChars(thisptr, str, &isCopy); if (chars is null) return null; From c425bc51ee26cf60ec6f389a757e0082eb0f8583 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Tue, 30 Jun 2026 10:09:55 -0700 Subject: [PATCH 3/3] Always release JNI UTF chars Pass null for the JNI isCopy pointer since the value is unused, and pair every successful GetStringUTFChars call with ReleaseStringUTFChars in a finally block. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Assisted-by: Copilot:gpt-5.5 --- .../Templates/monodroid-nativeaot.cs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/tasks/AndroidAppBuilder/Templates/monodroid-nativeaot.cs b/src/tasks/AndroidAppBuilder/Templates/monodroid-nativeaot.cs index 17d8ee6bab36a7..736d7cc33893e2 100644 --- a/src/tasks/AndroidAppBuilder/Templates/monodroid-nativeaot.cs +++ b/src/tasks/AndroidAppBuilder/Templates/monodroid-nativeaot.cs @@ -120,16 +120,18 @@ internal unsafe struct JNIEnv { fixed (JNIEnv* thisptr = &this) { - byte isCopy = 0; - byte* chars = NativeInterface->GetStringUTFChars(thisptr, str, &isCopy); + byte* chars = NativeInterface->GetStringUTFChars(thisptr, str, null); if (chars is null) return null; - string result = Marshal.PtrToStringUTF8((nint)chars)!; - if (isCopy != 0) + try + { + return Marshal.PtrToStringUTF8((nint)chars)!; + } + finally + { NativeInterface->ReleaseStringUTFChars(thisptr, str, chars); - - return result; + } } }