| # 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` |