Skip to content

Commit de004d7

Browse files
[TrimmableTypeMap] Always wire registerJniNativesFn, fail loudly if called
Always set the registerJniNativesFn function pointer during runtime initialization, even in trimmable mode. This ensures that if a JCW incorrectly calls Runtime.register(typeName, klass, methods) instead of Runtime.registerNatives(klass), the call flows through to C# where TrimmableTypeMapTypeManager.RegisterNativeMembers throws UnreachableException with a clear diagnostic message. Previously, the function pointer was set to nullptr for trimmable mode, causing the C++ side to silently drop the call — making JCW generation bugs invisible at runtime. Also adds a unit test verifying that trimmable JCWs never emit Runtime.register(). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent c2bdc5b commit de004d7

File tree

3 files changed

+12
-5
lines changed

3 files changed

+12
-5
lines changed

src/Mono.Android/Android.Runtime/JNIEnvInit.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -178,9 +178,7 @@ internal static unsafe void Initialize (JnienvInitializeArgs* args)
178178

179179
args->propagateUncaughtExceptionFn = (IntPtr)(delegate* unmanaged<IntPtr, IntPtr, IntPtr, void>)&PropagateUncaughtException;
180180

181-
if (!RuntimeFeature.TrimmableTypeMap) {
182-
args->registerJniNativesFn = (IntPtr)(delegate* unmanaged<IntPtr, int, IntPtr, IntPtr, int, void>)&RegisterJniNatives;
183-
}
181+
args->registerJniNativesFn = (IntPtr)(delegate* unmanaged<IntPtr, int, IntPtr, IntPtr, int, void>)&RegisterJniNatives;
184182
RunStartupHooksIfNeeded ();
185183
SetSynchronizationContext ();
186184
}

src/Mono.Android/Microsoft.Android.Runtime/TrimmableTypeMapTypeManager.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ public override void RegisterNativeMembers (
6767
ReadOnlySpan<char> methods)
6868
{
6969
throw new UnreachableException (
70-
$"RegisterNativeMembers should not be called in the trimmable typemap path. " +
71-
$"Native methods for '{type.FullName}' should be registered by JCW static initializer blocks.");
70+
$"Trimmable JCWs should only call Runtime.registerNatives(klass), never Runtime.register(typeName, klass, methods). " +
71+
$"Type '{type.FullName}' triggered a Runtime.register() call, which indicates a JCW generation bug.");
7272
}
7373
}

tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/Generator/JcwJavaSourceGeneratorTests.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,15 @@ public void Generate_AcwType_HasRegisterNativesStaticBlock ()
134134
AssertContainsLine ("mono.android.Runtime.registerNatives (MainActivity.class);\n", java);
135135
}
136136

137+
[Fact]
138+
public void Generate_AcwType_NeverCallsRuntimeRegister ()
139+
{
140+
var java = GenerateFixture ("my/app/MainActivity");
141+
// Runtime.register("typeName", klass, "methods") must never appear in trimmable JCWs.
142+
// Only Runtime.registerNatives(klass) is allowed.
143+
Assert.DoesNotContain ("Runtime.register (\"", java);
144+
}
145+
137146
[Fact]
138147
public void Generate_ApplicationType_SkipsRegisterNatives ()
139148
{

0 commit comments

Comments
 (0)