1# Overview 2JNI (Java Native Interface) is the mechanism that enables Java code to call 3native functions, and native code to call Java functions. 4 5 * Native code calls into Java using apis from `<jni.h>`, which basically mirror 6 Java's reflection APIs. 7 * Java code calls native functions by declaring body-less functions with the 8 `native` keyword, and then calling them as normal Java functions. 9 10`jni_generator` generates boiler-plate code with the goal of making our code: 11 1. easier to write, and 12 2. typesafe. 13 14`jni_generator` uses regular expressions to parse .Java files, so don't do 15anything too fancy. E.g.: 16 * Classes must be either explicitly imported, or are assumed to be in 17the same package. To use `java.lang` classes, add an explicit import. 18 * Inner classes need to be referenced through the outer class. E.g.: 19 `void call(Outer.Inner inner)` 20 21The presense of any JNI within a class will result in ProGuard obfuscation for 22the class to be disabled. 23 24### Exposing Native Methods 25 26**Without Crazy Linker:** 27 * Java->Native calls are exported from the shared library and lazily resolved 28 by the runtime (via `dlsym()`). 29 30**With Crazy Linker:** 31 * Java->Native calls are explicitly registered with JNI on the native side. 32 Explicit registration is necessary because crazy linker provides its own 33 `dlsym()`, but JNI is hardcoded to use the system's `dlsym()`. 34 * The logic to explicitly register stubs is generated by 35 `jni_registration_generator.py`. 36 * This script finds all native methods by scanning all source `.java` files 37 of an APK. Inefficient, but very convenient. 38 * Since `dlsym()` is not used in this case, we use a linker script to avoid 39 the cost of exporting symbols from the shared library (refer to 40 `//build/config/android:hide_all_but_jni_onload`). 41 * `jni_registration_generator.py` exposes two registrations methods: 42 * `RegisterNonMainDexNatives` - Registers native functions needed by multiple 43 process types (e.g. Rendereres, GPU process). 44 * `RegisterMainDexNatives` - Registers native functions needed only by the 45 browser process. 46 47### Exposing Java Methods 48 49Java methods just need to be annotated with `@CalledByNative`. The generated 50functions can be put into a namespace using `@JNINamespace("your_namespace")`. 51 52## Usage 53 54Because the generator does not generate any source files, generated headers must 55not be `#included` by multiple sources. If there are Java functions that need to 56be called by multiple sources, one source should be chosen to expose the 57functions to the others via additional wrapper functions. 58 59### Calling Java -> Native 60 61- Declare methods using a nested interface annotated with `@NativeMethods`. 62- The JNI annotation processor generates a class named `${OriginalClassName}Jni` 63 with a `get()` method that returns an implementation of the annotated 64 interface. The C++ function that it routes to is the same as if it would be 65 in the legacy method. 66- For each JNI method: 67 - C++ stubs are generated that forward to C++ functions that you must write. 68 - If the first parameter is a C++ object (e.g. `long mNativePointer`), then 69 the bindings will generate the appropriate cast and call into C++ code. 70 71To add JNI to a class: 72 731. Enable the JNI processor by adding to your `android_library` target: 74 ```python 75 annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ] 76 deps = [ "//base:jni_java" ] 77 ``` 782. Create a nested-interface annotated with `@NativeMethods` that contains 79 the declaration of the corresponding static methods you wish to have 80 implemented. 813. Call native functions using `${OriginalClassName}Jni.get().${method}` 824. In C++ code, #include the header `${OriginalClassName}_jni.h`. (The path will 83 depend on the location of the `generate_jni` BUILD rule that lists your Java 84 source code.) Only include this header from a single `.cc` file as the 85 header defines functions. That `.cc` must implement your native code by 86 defining non-member functions named `JNI_${OriginalClassName}_${UpperCamelCaseMethod}` 87 for static methods and member functions named `${OriginalClassName}::${UpperCamelCaseMethod}` 88 for non-static methods. Member functions need be declared in the header 89 file as well. 90 91Example: 92#### Java 93```java 94class MyClass { 95 // Cannot be private. Must be package or public. 96 @NativeMethods 97 /* package */ interface Natives { 98 void foo(); 99 double bar(int a, int b); 100 // Either the |MyClass| part of the |nativeMyClass| parameter name must 101 // match the native class name exactly, or the method annotation 102 // @NativeClassQualifiedName("MyClass") must be used. 103 // 104 // If the native class is nested, use 105 // @NativeClassQualifiedName("FooClassName::BarClassName") and call the 106 // parameter |nativePointer|. 107 void nonStatic(long nativeMyClass); 108 } 109 110 void callNatives() { 111 // MyClassJni is generated by the JNI annotation processor. 112 // Storing MyClassJni.get() in a field defeats some of the desired R8 113 // optimizations, but local variables are fine. 114 Natives jni = MyClassJni.get(); 115 jni.foo(); 116 jni.bar(1,2); 117 jni.nonStatic(mNativePointer); 118 } 119} 120``` 121#### C++ 122```c++ 123#include "base/android/jni_android.h" 124#include "<path to BUILD.gn>/<generate_jni target name>/MyClass_jni.h" 125 126class MyClass { 127public: 128 void NonStatic(JNIEnv* env); 129} 130 131// Notice that unlike Java, function names are capitalized in C++. 132// Static function names should follow this format and don't need to be declared. 133void JNI_MyClass_Foo(JNIEnv* env) { ... } 134void JNI_MyClass_Bar(JNIEnv* env, jint a, jint b) { ... } 135 136// Member functions need to be declared. 137void MyClass::NonStatic(JNIEnv* env) { ... } 138``` 139 140**Using the 'native' keyword** 141 142- The binding generator also looks for `native` JNI method declarations and 143 generates stubs for them. This used to be the norm, but is now obsolete. 144- If you have native methods that you don't want stubs generated for, you should 145 add @JniIgnoreNatives to the class. 146 147#### Testing Mockable Natives 148 1491. Add the `JniMocker` rule to your test. 1502. Call `JniMocker#mock` in a `setUp()` method for each interface you want to 151 stub out. 152 153`JniMocker` will reset the stubs during `tearDown()`. 154 155```java 156/** 157 * Tests for {@link AnimationFrameTimeHistogram} 158 */ 159@RunWith(BaseRobolectricTestRunner.class) 160@Config(manifest = Config.NONE) 161public class AnimationFrameTimeHistogramTest { 162 @Rule 163 public JniMocker mocker = new JniMocker(); 164 165 @Mock 166 AnimationFrameTimeHistogram.Natives mNativeMock; 167 168 @Before 169 public void setUp() { 170 MockitoAnnotations.initMocks(this); 171 mocker.mock(AnimationFrameTimeHistogramJni.TEST_HOOKS, mNativeMock); 172 } 173 174 @Test 175 public void testNatives() { 176 AnimationFrameTimeHistogram hist = new AnimationFrameTimeHistogram("histName"); 177 hist.startRecording(); 178 hist.endRecording(); 179 verify(mNativeMock).saveHistogram(eq("histName"), any(long[].class), anyInt()); 180 } 181} 182``` 183 184If a native method is called without setting a mock in a unit test, an 185`UnsupportedOperationException` will be thrown. 186 187### Calling Native -> Java 188 189 * Methods annotated with `@CalledByNative` will have stubs generated for them. 190 * Inner class methods must provide the inner class name explicitly 191 (ex. `@CalledByNative("InnerClassName")`) 192 * Just call the generated stubs defined in generated `.h` files. 193 194### Java Objects and Garbage Collection 195 196All pointers to Java objects must be registered with JNI in order to prevent 197garbage collection from invalidating them. 198 199For Strings & Arrays - it's common practice to use the `//base/android/jni_*` 200helpers to convert them to `std::vectors` and `std::strings` as soon as 201possible. 202 203For other objects - use smart pointers to store them: 204 * `ScopedJavaLocalRef<>` - When lifetime is the current function's scope. 205 * `ScopedJavaGlobalRef<>` - When lifetime is longer than the current function's 206 scope. 207 * `JavaObjectWeakGlobalRef<>` - Weak reference (do not prevent garbage 208 collection). 209 * `JavaParamRef<>` - Use to accept any of the above as a parameter to a 210 function without creating a redundant registration. 211 212### Additional Guidelines / Advice 213 214Minimize the surface API between the two sides. Rather than calling multiple 215functions across boundaries, call only one (and then on the other side, call as 216many little functions as required). 217 218If a Java object "owns" a native one, store the pointer via 219`"long mNativeClassName"`. Ensure to eventually call a native method to delete 220the object. For example, have a `close()` that deletes the native object. 221 222The best way to pass "compound" types across in either direction is to 223create an inner class with PODs and a factory function. If possible, make mark 224all the fields as "final". 225 226## Build Rules 227 228 * `generate_jni` - Generates a header file with stubs for given `.java` files 229 * `generate_jar_jni` - Generates a header file with stubs for a given `.jar` 230 file 231 * `generate_jni_registration` - Generates a header file with functions to 232 register native-side JNI methods (required only when using crazy linker). 233 234Refer to [//build/config/android/rules.gni](https://cs.chromium.org/chromium/src/build/config/android/rules.gni) 235for more about the GN templates. 236 237## Changing `jni_generator` 238 239 * Python unit tests live in `jni_generator_tests.py` 240 * A working demo app exists as `//base/android/jni_generator:sample_jni_apk` 241