Commit 6820a9c
[Java.Interop] Make JavaProxyObject.RegisterNativeMembers private again (#1468)
#1441 changed `JavaProxyObject.RegisterNativeMembers` from `private` to
`internal` so the new reflection-free
`JniRuntime.JniTypeManager.TryRegisterBuiltInNativeMembers ()` could call
it directly.
A side effect is that the `[JniAddNativeMethodRegistrationAttribute]`-
annotated method now appears in Java.Interop's *reference* assembly.
dotnet/android's trimmable typemap scanner reads reference assemblies and
rejects any type carrying that attribute (XA4251), so every trimmable
typemap build now fails on the built-in `JavaProxyObject`
(see dotnet/android#11622).
Restore the method to `private` (so it is stripped from the reference
assembly) and expose a small attribute-free `internal` entry point,
`RegisterBuiltInNativeMembers (JniType)`, for the built-in registration
path to call. Runtime behavior is unchanged.
### [Java.Interop] Restore pure-reflection registration for JavaProxyObject
#1441 added `JniRuntime.JniTypeManager.TryRegisterBuiltInNativeMembers ()`
-- a reflection-free direct call to `JavaProxyObject.RegisterNativeMembers`
-- and bumped that method to `internal` so the call would compile.
That method is dead code: nothing in Java.Interop (or dotnet/android) ever
calls it, and the base `JniTypeManager.RegisterNativeMembers` is a no-op.
`JavaProxyObject`'s native members are -- and were before #1441 --
registered purely via reflection in `ReflectionJniTypeManager`
(`FindAndCallRegisterMethod` discovering the
`[JniAddNativeMethodRegistrationAttribute]`-annotated method), which finds
private methods just fine via `GetRuntimeMethods ()`.
Remove the unused `TryRegisterBuiltInNativeMembers` and restore
`RegisterNativeMembers` to `private` (its state before #1441). Making it
private again also strips the attribute-bearing method from the reference
assembly, which fixes dotnet/android's trimmable typemap scanner falsely
rejecting the built-in `JavaProxyObject` with XA4251 (dotnet/android#11622).
### Address review: restore TryRegisterBuiltInNativeMembers (not dead code)
The previous commit deleted JniRuntime.JniTypeManager.TryRegisterBuiltInNativeMembers
claiming it was unused. That was wrong: it has two live callers in the NativeAOT
samples (samples/Hello-NativeAOTFromJNI/NativeAotTypeManager.cs and
samples/Hello-NativeAOTFromAndroid/NativeAotTypeManager.cs), both JniTypeManager
subclasses. Deleting it broke them (CS0103) and removed the only path that
registers JavaProxyObject's equals/hashCode/toString natives for NativeAOT type
managers (which don't use the reflection-based FindAndCallRegisterMethod path).
The breakage was hidden in CI only because the NativeAOT sample steps use
continueOnError: true.
Keep the XA4251 fix (RegisterNativeMembers stays private, so the
[JniAddNativeMethodRegistrationAttribute] is stripped from the reference assembly)
and restore TryRegisterBuiltInNativeMembers by extracting the registration logic
into a new attribute-free internal helper, JavaProxyObject.AddBuiltInRegistrations.
Both the private attributed RegisterNativeMembers (reflection path) and
TryRegisterBuiltInNativeMembers (NativeAOT path) call it. Restore the
PublicAPI.Unshipped.txt entry as well.
Verified: Java.Interop.dll builds clean; the reference assembly contains no method
carrying [JniAddNativeMethodRegistration]; the sample's call to
TryRegisterBuiltInNativeMembers resolves (no CS0103).
### Keep built-in registration in the samples via ReflectionJniTypeManager
Replaces the production TryRegisterBuiltInNativeMembers helper with a
samples-only solution, restoring the pre-#1441 behavior for the NativeAOT
type managers.
Background: making JavaProxyObject.RegisterNativeMembers private (the XA4251
fix) is sufficient for the default Android runtime, which discovers and invokes
it via reflection (FindAndCallRegisterMethod -> GetRuntimeMethods(), which
returns private methods). The only thing that needed JavaProxyObject's
registration via a non-reflection path was the two NativeAOT samples, which
#1441 had rewritten to derive from the reflection-free JniRuntime.JniTypeManager
base. That is why #1441 introduced TryRegisterBuiltInNativeMembers.
Instead of carrying that helper in production, have the sample type managers
derive from JniRuntime.ReflectionJniTypeManager again - exactly what the base
JniRuntime.JniTypeManager provided before #1441. Built-in types such as
JavaProxyObject/JavaProxyThrowable are then registered automatically via
reflection, and the samples no longer need any custom registration code.
Changes:
- JavaProxyObject.RegisterNativeMembers: internal -> private. The marshalers
stay (the default reflection runtime registers them by reflecting over this
type); only the visibility changes, which strips the attribute from the
reference assembly and fixes the dotnet/android XA4251 scanner failure.
- Delete JniRuntime.JniTypeManager.TryRegisterBuiltInNativeMembers (+ its
PublicAPI.Unshipped.txt entry); no longer needed.
- Hello-NativeAOTFromJNI / Hello-NativeAOTFromAndroid: derive from
JniRuntime.ReflectionJniTypeManager and drop the reflection-free overrides and
hand-written JavaProxyObject registration. ReflectionJniTypeManager is
[RequiresDynamicCode]/[RequiresUnreferencedCode], so the constructor suppresses
IL2026/IL3050 with [UnconditionalSuppressMessage]. A #pragma is insufficient
here: it silences the Roslyn analyzer but not the ILLink/ILC publish passes,
which only honor the attribute (verified with a trim-publish of the real type
manager against Java.Interop.dll).
Net: production loses code (1-line visibility change + deletions) and the samples
shrink substantially.
### Drop verbose explanatory comments from the NativeAOT sample type managers
The [UnconditionalSuppressMessage] Justification strings already convey the
necessary context.
### Fix NativeAOT sample type resolution: override GetTypeForSimpleReference
Build 1465402's "run Hello-NativeAOTFromJNI" step failed at runtime:
System.NotSupportedException: Could not find System.Type corresponding to
Java type JniTypeSignature(TypeName=example/ManagedType ...)
at Java.Interop.ManagedPeer.RegisterNativeMembers(...)
at example.ManagedType.<clinit>(ManagedType.java:15)
Root cause: after #1441, JniRuntime.JniTypeManager.GetType() dispatches through
GetTypeForSimpleReference (singular), not GetTypesForSimpleReference (plural).
The previous sample rewrite only overrode the plural method, so app types like
example/ManagedType were never resolved (the base ReflectionJniTypeManager's
GetTypeForSimpleReference only knows built-in types), and ManagedPeer
registration threw before it could register the type.
Fix: override GetTypeForSimpleReference (singular) in both NativeAOT sample type
managers to resolve the sample's own managed types, falling back to the base for
built-ins. Registration and the reverse Type->JNI mapping continue to be handled
by the reflection base (the pre-#1441 behavior). The override carries the same
[return: DynamicallyAccessedMembers(...)] as the base to satisfy IL2093.
### Address review: drop unreachable null guard in FromAndroid sample
`typeMappings` is assigned in its field initializer and never set to null, so the
`if (typeMappings == null) yield break;` guard in CreateSimpleReferencesEnumerator
was unreachable dead code. Remove it.
### Document why the NativeAOT sample trim/AOT suppressions are acceptable
Add a class-level comment to both NativeAOT sample type managers explaining the
rationale for the [UnconditionalSuppressMessage] IL2026/IL3050 suppressions:
- These are *samples*, not product code. .NET for Android (what we ship) does not
pair ReflectionJniTypeManager with NativeAOT, so it isn't worth the effort to make
these samples fully trim/AOT-clean right now.
- The reflection paths were always trim/AOT-unsafe. Before #1441 the equivalent
suppressions lived inside JniTypeManager itself (justified "NotUsedInAndroid");
#1441 simply moved that responsibility to callers via
[RequiresDynamicCode]/[RequiresUnreferencedCode].
### Reword NativeAOT sample suppression justifications to describe why it's safe
The previous IL2026/IL3050 justifications ("does not require unreferenced code /
runtime code generation") read as the opposite of reality, since
ReflectionJniTypeManager is exactly [RequiresUnreferencedCode]/[RequiresDynamicCode].
Reword to describe why the suppression is correct for this sample:
- IL2026: the assembly is rooted via TrimmerRootAssembly and the reflected
registration members are preserved by the [DynamicallyAccessedMembers]
annotations on the RegisterNativeMembers(Type) -> FindAndCallRegisterMethod path.
- IL3050: registration uses CreateDelegate on compile-time-known static methods
(no MakeGenericType / expression compilation), so no runtime codegen is required.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>1 parent a2159d7 commit 6820a9c
5 files changed
Lines changed: 69 additions & 269 deletions
File tree
- samples
- Hello-NativeAOTFromAndroid
- Hello-NativeAOTFromJNI
- src/Java.Interop
- Java.Interop
Lines changed: 31 additions & 115 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
4 | 4 | | |
5 | 5 | | |
6 | 6 | | |
7 | | - | |
8 | | - | |
9 | | - | |
10 | | - | |
11 | | - | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
12 | 23 | | |
13 | 24 | | |
14 | 25 | | |
| |||
20 | 31 | | |
21 | 32 | | |
22 | 33 | | |
23 | | - | |
24 | | - | |
25 | | - | |
26 | | - | |
27 | | - | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
28 | 37 | | |
29 | | - | |
30 | | - | |
31 | | - | |
32 | | - | |
33 | 38 | | |
34 | 39 | | |
35 | | - | |
36 | | - | |
37 | | - | |
38 | | - | |
39 | | - | |
40 | | - | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
41 | 44 | | |
42 | | - | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
43 | 48 | | |
44 | 49 | | |
45 | 50 | | |
46 | 51 | | |
47 | | - | |
48 | | - | |
| 52 | + | |
49 | 53 | | |
50 | | - | |
51 | | - | |
52 | | - | |
53 | | - | |
54 | | - | |
55 | | - | |
56 | | - | |
57 | | - | |
58 | | - | |
59 | | - | |
60 | | - | |
61 | | - | |
62 | | - | |
63 | | - | |
64 | | - | |
65 | | - | |
66 | | - | |
67 | | - | |
68 | | - | |
69 | | - | |
70 | | - | |
71 | | - | |
72 | | - | |
73 | | - | |
74 | | - | |
75 | | - | |
76 | | - | |
77 | | - | |
78 | | - | |
79 | | - | |
80 | | - | |
81 | | - | |
82 | | - | |
83 | | - | |
84 | | - | |
85 | | - | |
86 | | - | |
| 54 | + | |
| 55 | + | |
87 | 56 | | |
88 | 57 | | |
89 | 58 | | |
90 | 59 | | |
91 | | - | |
| 60 | + | |
| 61 | + | |
92 | 62 | | |
93 | 63 | | |
94 | 64 | | |
95 | 65 | | |
96 | | - | |
97 | | - | |
98 | 66 | | |
99 | 67 | | |
100 | 68 | | |
101 | 69 | | |
102 | 70 | | |
103 | | - | |
104 | | - | |
105 | | - | |
106 | | - | |
107 | | - | |
108 | | - | |
109 | | - | |
110 | | - | |
111 | | - | |
112 | | - | |
113 | | - | |
114 | | - | |
115 | | - | |
116 | | - | |
117 | | - | |
118 | | - | |
119 | | - | |
120 | | - | |
121 | | - | |
122 | | - | |
123 | | - | |
124 | | - | |
125 | | - | |
126 | | - | |
127 | | - | |
128 | | - | |
129 | | - | |
130 | | - | |
131 | | - | |
132 | | - | |
133 | | - | |
134 | | - | |
135 | | - | |
136 | | - | |
137 | | - | |
138 | | - | |
139 | | - | |
140 | | - | |
141 | | - | |
142 | | - | |
143 | | - | |
144 | | - | |
145 | | - | |
146 | | - | |
147 | | - | |
148 | | - | |
149 | | - | |
150 | | - | |
151 | | - | |
152 | | - | |
153 | | - | |
154 | | - | |
155 | 71 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | | - | |
2 | 1 | | |
3 | 2 | | |
4 | | - | |
5 | | - | |
6 | | - | |
7 | | - | |
8 | | - | |
9 | | - | |
| 3 | + | |
10 | 4 | | |
11 | | - | |
12 | | - | |
13 | | - | |
14 | | - | |
15 | | - | |
16 | | - | |
| 5 | + | |
17 | 6 | | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
18 | 34 | | |
19 | 35 | | |
20 | 36 | | |
21 | | - | |
22 | | - | |
23 | | - | |
24 | | - | |
25 | | - | |
26 | | - | |
27 | | - | |
28 | | - | |
29 | | - | |
30 | | - | |
31 | | - | |
32 | | - | |
33 | | - | |
34 | | - | |
35 | | - | |
36 | | - | |
37 | | - | |
38 | | - | |
39 | | - | |
40 | | - | |
41 | | - | |
42 | | - | |
43 | | - | |
44 | | - | |
45 | | - | |
46 | | - | |
47 | | - | |
48 | | - | |
49 | | - | |
50 | | - | |
51 | | - | |
52 | | - | |
53 | | - | |
54 | | - | |
55 | | - | |
56 | | - | |
57 | | - | |
58 | | - | |
59 | | - | |
60 | | - | |
61 | | - | |
62 | | - | |
63 | | - | |
64 | | - | |
65 | | - | |
66 | | - | |
67 | | - | |
68 | | - | |
69 | | - | |
70 | | - | |
71 | | - | |
72 | | - | |
73 | | - | |
74 | | - | |
75 | | - | |
76 | | - | |
77 | | - | |
78 | | - | |
79 | | - | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
80 | 40 | | |
81 | 41 | | |
82 | | - | |
83 | | - | |
84 | | - | |
85 | | - | |
86 | | - | |
87 | | - | |
88 | | - | |
89 | | - | |
90 | | - | |
91 | | - | |
92 | | - | |
93 | | - | |
94 | | - | |
95 | | - | |
96 | | - | |
97 | | - | |
98 | | - | |
99 | | - | |
100 | | - | |
101 | | - | |
102 | | - | |
103 | | - | |
104 | | - | |
105 | | - | |
106 | | - | |
107 | | - | |
108 | | - | |
109 | | - | |
110 | | - | |
111 | | - | |
112 | | - | |
113 | | - | |
114 | | - | |
115 | | - | |
116 | | - | |
117 | | - | |
118 | | - | |
119 | | - | |
120 | | - | |
121 | | - | |
122 | | - | |
123 | | - | |
124 | | - | |
125 | | - | |
126 | | - | |
127 | | - | |
128 | | - | |
129 | | - | |
130 | | - | |
131 | | - | |
132 | | - | |
133 | | - | |
134 | | - | |
135 | | - | |
136 | | - | |
137 | | - | |
138 | | - | |
139 | | - | |
140 | | - | |
141 | | - | |
142 | | - | |
143 | | - | |
144 | | - | |
| 42 | + | |
145 | 43 | | |
146 | | - | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
147 | 48 | | |
148 | 49 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
16 | 16 | | |
17 | 17 | | |
18 | 18 | | |
19 | | - | |
| 19 | + | |
20 | 20 | | |
21 | 21 | | |
22 | 22 | | |
| |||
Lines changed: 0 additions & 16 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
253 | 253 | | |
254 | 254 | | |
255 | 255 | | |
256 | | - | |
257 | | - | |
258 | | - | |
259 | | - | |
260 | | - | |
261 | | - | |
262 | | - | |
263 | | - | |
264 | | - | |
265 | | - | |
266 | | - | |
267 | | - | |
268 | | - | |
269 | | - | |
270 | | - | |
271 | | - | |
272 | 256 | | |
273 | 257 | | |
274 | 258 | | |
| |||
0 commit comments