Commit 2197579
authored
[Hello-NativeAOTFromJNI] Add NativeAOT sample (#1153)
Context: 28849ec
Context: bc5bcf4
Context: 25850ba
Context: 56955d9
Context: #1157
Context: c6c487b
Context: dotnet/android@180dd52
Commit 28849ec noted:
> [JNI][0] supports *two* modes of operation:
>
> 1. Native code creates the JVM, e.g. via [`JNI_CreateJavaVM()`][1]
>
> 2. The JVM already exists, and when Java code calls
> [`System.loadLibrary()`][3], the JVM calls the
> [`JNI_OnLoad()`][2] function on the specified library.
>
> [0]: https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/jniTOC.html
> [1]: https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/invocation.html#creating_the_vm
> [2]: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Runtime.html#loadLibrary(java.lang.String)
> [3]: https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/invocation.html#JNJI_OnLoad
Our existing unit tests, e.g. `tests/Java.Interop-Tests`, exercise
the first mode of operation.
The second mode of operation is how .NET Android executes.
Add `samples/Hello-NativeAOTFromJNI`, a new sample which exercises
the second mode of operation:
1. `Hello-NativeAOTFromJNI` contains C# methods which use
[`UnmanagedCallersOnlyAttribute`][4] to export `JNI_OnLoad()` and
various other native symbols for JNI to execute.
2. `dotnet publish Hello-NativeAOTFromJNI.csproj` will use
[NativeAOT][5] to produce a native library which can be loaded
and used by a desktop JVM.
3. `Hello-NativeAOTFromJNI` references `Java.Base.dll` (bc5bcf4),
and contains a C# `Java.Lang.Object` subclass, which contains a
`[JavaCallable]` method.
4. `jcw-gen` is called during the build process to generate
Java Callable Wrappers for (3), containing the `[JavaCallable]`
method.
5. `jnimarshalmethod-gen` (25850ba) is called during the build
process to generate marshal methods for (3), as `generator`
output for JavaInterop1 doesn't contain marshal methods (unlike
XAJavaInterop1, used by .NET Android), and NativeAOT doesn't
support System.Reflection.Emit.
6. The type in (3) is instantiated *from Java*, and Java invokes the
`[JavaCallable]` method.
7. `Hello-NativeAOTFromJNI` also contains Java code including a
`main()` method (to start execution from Java)
Conceptually straightforward!
See `samples/Hello-NativeAOTFromJNI/README.md` for more details.
~~ `$(Standalone)`=true is now the default build config ~~
The `$(Standalone)` build config (c6c487b) is now enabled by
default. This means that neither `Java.Interop.dll` nor
`Java.Runtime.Environment.dll` *require* a `java-interop` native
library, which (1) was already the case for xamarin-android as of
dotnet/android@180dd520, and (2) simplifies NativeAOT
support immensely.
~~ Avoid Adding Public API ~~
In order to avoid adding new public API to `Java.Interop.dll`, update
`Java.Interop.dll` to have `[InternalsVisibleTo]` for
`Java.Runtime.Environment.dll`. This allows `JreTypeManager` to use
`JniRuntime.UseMarshalMemberBuilder`, without needing to worry about
`try`/`catch` blocks.
This in turn requires renaming `NativeMethods` within
`Java.Runtime.Environment.dll` to `JreNativeMethods`, as
`Java.Interop.dll` *also* has a `NativeMethods` type.
~~ NativeAOT Integration ~~
Conceptually straightforward, but not without lots of pitfalls.
In order for Java code to call into C# code, there must be a
Java Callable Wrapper, which contains Java `native` methods, and
those Java `native` methods must be *registered with Java* before
they are executed.
Method registration involves lots of delegates, which need to be
stored in the `JniNativeMethodRegistration.Delegate` field, of type
`System.Delegate`.
NativeAOT doesn't like this by default. In order to convince
NativeAOT to support this, every delegate instance provided to
`JniNativeMethodRegistration.Delegate` must be of a delegate type
which has [`UnmanagedFunctionPointerAttribute`][6]. This coerces
NativeAOT to emit "stubs" for the referenced method, allowing things
to work with fewer changes.
Linux builds require `-Wl,-soname` to be set manually in order for
the resulting `.so` to work properly.
~~ Trimmer Warnings ~~
Fix additional trimmer warnings, a'la #1157.
`Type.MakeGenericType()` needs to ensure constructors are preserved:
src/Java.Interop/Java.Interop/JniRuntime.JniValueManager.cs(378): Trim analysis warning IL2068:
Java.Interop.JniRuntime.JniValueManager.<GetInvokerType>g__MakeGenericType|31_1(Type,Type[]):
'Java.Interop.JniRuntime.JniValueManager.<GetInvokerType>g__MakeGenericType|31_1(Type,Type[])' method return value does not satisfy
'DynamicallyAccessedMemberTypes.PublicConstructors', 'DynamicallyAccessedMemberTypes.NonPublicConstructors' requirements.
The parameter 'type' of method 'Java.Interop.JniRuntime.JniValueManager.<GetInvokerType>g__MakeGenericType|31_1(Type,Type[])'
does not have matching annotations.
The source value must declare at least the same requirements as those declared on the target location it is assigned to.
`Expression.New()` requires the constructor be kept, so "fake it" by
wrapping `Type.GetType()` w/ `[DynamicallyAccessedMembers]`:
src/Java.Interop/Java.Interop/JniValueMarshaler.cs(175): Trim analysis warning IL2072:
Java.Interop.JniValueMarshaler.CreateSelf(JniValueMarshalerContext,ParameterExpression):
'type' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicParameterlessConstructor' in call to 'System.Linq.Expressions.Expression.New(Type)'.
The return value of method 'System.Object.GetType()' does not have matching annotations.
The source value must declare at least the same requirements as those declared on the target location it is assigned to.
`[DynamicallyAccessedMembers]` should be on properties, not getters:
src/Java.Interop/Java.Interop/JniValueMarshalerAttribute.cs(33): Trim analysis warning IL2078:
Java.Interop.JniValueMarshalerAttribute.MarshalerType.get:
'Java.Interop.JniValueMarshalerAttribute.MarshalerType.get' method return value does not satisfy
'DynamicallyAccessedMemberTypes.PublicParameterlessConstructor', 'DynamicallyAccessedMemberTypes.Interfaces' requirements.
The field 'Java.Interop.JniValueMarshalerAttribute.<MarshalerType>k__BackingField' does not have matching annotations.
The source value must declare at least the same requirements as those declared on the target location it is assigned to.
Silence use of `Assembly.Location`, when it's optional:
src/Java.Runtime.Environment/Java.Interop/JreRuntime.cs(106): warning IL3000:
Java.Interop.JreRuntime.CreateJreVM(JreRuntimeOptions):
'System.Reflection.Assembly.Location.get' always returns an empty string for assemblies embedded in a single-file app.
If the path to the app directory is needed, consider calling 'System.AppContext.BaseDirectory'.
src/Java.Runtime.Environment/Java.Interop/JreRuntime.cs(323): warning IL3000: Java.Interop.JreNativeMethods..cctor():
'System.Reflection.Assembly.Location.get' always returns an empty string for assemblies embedded in a single-file app.
If the path to the app directory is needed, consider calling 'System.AppContext.BaseDirectory'.
~~ Future Work ~~
Make `JniRuntime.UseMarshalMemberBuilder` public for .NET 9, and
remove the `InternalsVisibleTo` from `Java.Interop.dll` to
`Java.Runtime.Environment.dll`.
`generator` should be updated to apply
`UnmanagedFunctionPointerAttribute` onto all `_JniMarshal_*` delegate
type declarations (56955d9).
[4]: https://learn.microsoft.com/dotnet/api/system.runtime.interopservices.unmanagedcallersonlyattribute?view=net-8.0
[5]: https://learn.microsoft.com/dotnet/core/deploying/native-aot
[6]: https://learn.microsoft.com/dotnet/api/system.runtime.interopservices.unmanagedfunctionpointerattribute?view=net-8.01 parent c8fcf70 commit 2197579
File tree
24 files changed
+613
-49
lines changed- build-tools/automation
- templates
- samples/Hello-NativeAOTFromJNI
- java/net/dot/jni/hello
- src
- Java.Interop
- Java.Interop
- Properties
- Java.Runtime.Environment/Java.Interop
24 files changed
+613
-49
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
113 | 113 | | |
114 | 114 | | |
115 | 115 | | |
| 116 | + | |
| 117 | + | |
116 | 118 | | |
117 | 119 | | |
118 | 120 | | |
| |||
320 | 322 | | |
321 | 323 | | |
322 | 324 | | |
| 325 | + | |
| 326 | + | |
| 327 | + | |
| 328 | + | |
323 | 329 | | |
324 | 330 | | |
325 | 331 | | |
| |||
374 | 380 | | |
375 | 381 | | |
376 | 382 | | |
| 383 | + | |
377 | 384 | | |
378 | 385 | | |
379 | 386 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
57 | 57 | | |
58 | 58 | | |
59 | 59 | | |
| 60 | + | |
60 | 61 | | |
61 | 62 | | |
62 | 63 | | |
| |||
87 | 88 | | |
88 | 89 | | |
89 | 90 | | |
| 91 | + | |
90 | 92 | | |
91 | 93 | | |
92 | 94 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2 | 2 | | |
3 | 3 | | |
4 | 4 | | |
| 5 | + | |
5 | 6 | | |
6 | 7 | | |
7 | 8 | | |
| |||
173 | 174 | | |
174 | 175 | | |
175 | 176 | | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
176 | 190 | | |
177 | 191 | | |
178 | 192 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 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 | + | |
Lines changed: 52 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 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 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
Lines changed: 106 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 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 | + | |
| 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 | + | |
| 80 | + | |
| 81 | + | |
| 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 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 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 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 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 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
0 commit comments