forked from chromium/chromium
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add README.md for //base/android/jni_generator
Bug: 683256 Change-Id: I3735b47e983028b08b379dfc716eea78e3b977fd Reviewed-on: https://chromium-review.googlesource.com/985641 Commit-Queue: agrieve <agrieve@chromium.org> Reviewed-by: Richard Coles <torne@chromium.org> Cr-Commit-Position: refs/heads/master@{#547046}
- Loading branch information
Showing
2 changed files
with
118 additions
and
58 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
# Overview | ||
JNI (Java Native Interface) is the mechanism that enables Java code to call | ||
native functions, and native code to call Java functions. | ||
|
||
* Native code calls into Java using apis from `<jni.h>`, which basically mirror | ||
Java's reflection APIs. | ||
* Java code calls native functions by declaring body-less functions with the | ||
`native` keyword, and then calling them as normal Java functions. | ||
|
||
`jni_generator` generates boiler-plate code with the goal of making our code: | ||
1. easier to write, and | ||
2. typesafe. | ||
|
||
`jni_generator` uses regular expressions to parse .Java files, so don't do | ||
anything too fancy. E.g.: | ||
* Classes must be either explicitly imported, or are assumed to be in | ||
the same package. To use `java.lang` classes, add an explicit import. | ||
* Inner classes need to be referenced through the outer class. E.g.: | ||
`void call(Outer.Inner inner)` | ||
|
||
The presense of any JNI within a class will result in ProGuard obfuscation for | ||
the class to be disabled. | ||
|
||
### Exposing Native Methods | ||
|
||
**Without Crazy Linker:** | ||
* Java->Native calls are exported from the shared library and lazily resolved | ||
by the runtime (via `dlsym()`). | ||
|
||
**With Crazy Linker:** | ||
* Java->Native calls are explicitly registered with JNI on the native side. | ||
Explicit registration is necessary because crazy linker provides its own | ||
`dlsym()`, but JNI is hardcoded to use the system's `dlsym()`. | ||
* The logic to explicitly register stubs is generated by | ||
`jni_registration_generator.py`. | ||
* This script finds all native methods by scanning all source `.java` files | ||
of an APK. Inefficient, but very convenient. | ||
* Since `dlsym()` is not used in this case, we use a linker script to avoid | ||
the cost of exporting symbols from the shared library (refer to | ||
`//build/config/android:hide_all_but_jni_onload`). | ||
* `jni_registration_generator.py` exposes two registrations methods: | ||
* `RegisterNonMainDexNatives` - Registers native functions needed by multiple | ||
process types (e.g. Rendereres, GPU process). | ||
* `RegisterMainDexNatives` - Registers native functions needed only by the | ||
browser process. | ||
|
||
### Exposing Java Methods | ||
|
||
Java methods just need to be annotated with `@CalledByNative`. The generated | ||
functions can be put into a namespace using `@JNINamespace("your_namespace")`. | ||
|
||
## Usage | ||
|
||
Because the generator does not generate any source files, generated headers must | ||
not be `#included` by multiple sources. If there are Java functions that need to | ||
be called by multiple sources, one source should be chosen to expose the | ||
functions to the others via additional wrapper functions. | ||
|
||
### Calling Java -> Native | ||
|
||
* Methods marked as `native` will have stubs generated for them that forward | ||
calls to C++ function (that you must write). | ||
* If the first parameter is a C++ object (e.g. `long mNativePointer`), then the | ||
bindings will automatically generate the appropriate cast and call into C++ | ||
code (JNI itself is only C). | ||
|
||
### Calling Native -> Java | ||
|
||
* Methods annotated with `@CalledByNative` will have stubs generated for them. | ||
* Just call the generated stubs defined in generated `.h` files. | ||
|
||
### Java Objects and Garbage Collection | ||
|
||
All pointers to Java objects must be registered with JNI in order to prevent | ||
garbage collection from invalidating them. | ||
|
||
For Strings & Arrays - it's common practice to use the `//base/android/jni_*` | ||
helpers to convert them to `std::vectors` and `std::strings` as soon as | ||
possible. | ||
|
||
For other objects - use smart pointers to store them: | ||
* `ScopedJavaLocalRef<>` - When lifetime is the current function's scope. | ||
* `ScopedJavaGlobalRef<>` - When lifetime is longer than the current function's | ||
scope. | ||
* `JavaObjectWeakGlobalRef<>` - Weak reference (do not prevent garbage | ||
collection). | ||
* `JavaParamRef<>` - Use to accept any of the above as a parameter to a | ||
function without creating a redundant registration. | ||
|
||
### Additional Guidelines / Advice | ||
|
||
Minimize the surface API between the two sides. Rather than calling multiple | ||
functions across boundaries, call only one (and then on the other side, call as | ||
many little functions as required). | ||
|
||
If a Java object "owns" a native one, store the pointer via | ||
`"long mNativeClassName"`. Ensure to eventually call a native method to delete | ||
the object. For example, have a `close()` that deletes the native object. | ||
|
||
The best way to pass "compound" types across in either direction is to | ||
create an inner class with PODs and a factory function. If possible, make mark | ||
all the fields as "final". | ||
|
||
## Build Rules | ||
|
||
* `generate_jni` - Generates a header file with stubs for given `.java` files | ||
* `generate_jar_jni` - Generates a header file with stubs for a given `.jar` | ||
file | ||
* `generate_jni_registration` - Generates a header file with functions to | ||
register native-side JNI methods (required only when using crazy linker). | ||
|
||
Refer to [//build/config/android/rules.gni](https://cs.chromium.org/chromium/src/build/config/android/rules.gni) | ||
for more about the GN templates. | ||
|
||
## Changing `jni_generator` | ||
|
||
* Python unit tests live in `jni_generator_tests.py` | ||
* A working demo app exists as `//base/android/jni_generator:sample_jni_apk` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters