xref: /aosp_15_r20/external/cronet/third_party/jni_zero/README.md (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker# JNI Zero
2*6777b538SAndroid Build Coastguard WorkerA zero-overhead (or better!) middleware for JNI.
3*6777b538SAndroid Build Coastguard Worker
4*6777b538SAndroid Build Coastguard Worker## Overview
5*6777b538SAndroid Build Coastguard WorkerJNI (Java Native Interface) is the mechanism that enables Java code to call
6*6777b538SAndroid Build Coastguard Workernative functions, and native code to call Java functions.
7*6777b538SAndroid Build Coastguard Worker
8*6777b538SAndroid Build Coastguard Worker * Native code calls into Java using apis from `<jni.h>`, which basically mirror
9*6777b538SAndroid Build Coastguard Worker   Java's reflection APIs.
10*6777b538SAndroid Build Coastguard Worker * Java code calls native functions by declaring body-less functions with the
11*6777b538SAndroid Build Coastguard Worker  `native` keyword, and then calling them as normal Java functions.
12*6777b538SAndroid Build Coastguard Worker
13*6777b538SAndroid Build Coastguard WorkerJNI Zero generates boiler-plate code with the goal of making our code:
14*6777b538SAndroid Build Coastguard Worker 1. easier to write,
15*6777b538SAndroid Build Coastguard Worker 2. typesafe.
16*6777b538SAndroid Build Coastguard Worker 3. more optimizable.
17*6777b538SAndroid Build Coastguard Worker
18*6777b538SAndroid Build Coastguard WorkerJNI Zero uses regular expressions to parse .Java files, so don't do
19*6777b538SAndroid Build Coastguard Workeranything too fancy. E.g.:
20*6777b538SAndroid Build Coastguard Worker * Classes must be either explicitly imported, or are assumed to be in
21*6777b538SAndroid Build Coastguard Workerthe same package. To use `java.lang` classes, add an explicit import.
22*6777b538SAndroid Build Coastguard Worker * Inner classes need to be referenced through the outer class. E.g.:
23*6777b538SAndroid Build Coastguard Worker   `void call(Outer.Inner inner)`
24*6777b538SAndroid Build Coastguard Worker
25*6777b538SAndroid Build Coastguard Worker### Exposing Native Methods
26*6777b538SAndroid Build Coastguard Worker
27*6777b538SAndroid Build Coastguard WorkerThere are two ways to have native methods be found by Java:
28*6777b538SAndroid Build Coastguard Worker1) Explicitly register the name -> function pointer mapping using JNI's
29*6777b538SAndroid Build Coastguard Worker   `RegisterNatives()` function.
30*6777b538SAndroid Build Coastguard Worker2) Export the symbols from the shared library, and let the runtime resolve them
31*6777b538SAndroid Build Coastguard Worker   on-demand (using `dlsym()`) the first time a native method is called.
32*6777b538SAndroid Build Coastguard Worker
33*6777b538SAndroid Build Coastguard Worker2) Is generally preferred due to a smaller code size and less up-front work, but
34*6777b538SAndroid Build Coastguard Worker1) is sometimes required (e.g. when OS bugs prevent `dlsym()` from working).
35*6777b538SAndroid Build Coastguard WorkerBoth ways are supported by this tool.
36*6777b538SAndroid Build Coastguard Worker
37*6777b538SAndroid Build Coastguard Worker### Exposing Java Methods
38*6777b538SAndroid Build Coastguard Worker
39*6777b538SAndroid Build Coastguard WorkerJava methods just need to be annotated with `@CalledByNative`. By default the
40*6777b538SAndroid Build Coastguard Workergenerated method stubs on the native side are not namespaced. The generated
41*6777b538SAndroid Build Coastguard Workerfunctions can be put into a namespace using `@JNINamespace("your_namespace")`.
42*6777b538SAndroid Build Coastguard Worker
43*6777b538SAndroid Build Coastguard Worker## Usage
44*6777b538SAndroid Build Coastguard Worker
45*6777b538SAndroid Build Coastguard Worker### Writing Build Rules
46*6777b538SAndroid Build Coastguard Worker1. Find or add a `generate_jni` target with your .java file, then add this
47*6777b538SAndroid Build Coastguard Worker   `generate_jni` target to your `srcjar_deps` of your `android_library` target:
48*6777b538SAndroid Build Coastguard Worker
49*6777b538SAndroid Build Coastguard Worker   ```python
50*6777b538SAndroid Build Coastguard Worker   generate_jni("abcd_jni") {
51*6777b538SAndroid Build Coastguard Worker     sources = [ "path/to/java/sources/with/jni/Annotations.java" ]
52*6777b538SAndroid Build Coastguard Worker   }
53*6777b538SAndroid Build Coastguard Worker
54*6777b538SAndroid Build Coastguard Worker   android_library("abcd_java") {
55*6777b538SAndroid Build Coastguard Worker     ...
56*6777b538SAndroid Build Coastguard Worker     # Allows the java files to see the generated `${OriginalClassName}Jni`
57*6777b538SAndroid Build Coastguard Worker     # classes.
58*6777b538SAndroid Build Coastguard Worker     srcjar_deps = [ ":abcd_jni" ]
59*6777b538SAndroid Build Coastguard Worker   }
60*6777b538SAndroid Build Coastguard Worker
61*6777b538SAndroid Build Coastguard Worker   source_set("abcd") {
62*6777b538SAndroid Build Coastguard Worker    ...
63*6777b538SAndroid Build Coastguard Worker    # Allows the cpp files to include the generated `${OriginalClassName}_jni.h`
64*6777b538SAndroid Build Coastguard Worker    # headers.
65*6777b538SAndroid Build Coastguard Worker    deps = [ ":abcd_jni" ]
66*6777b538SAndroid Build Coastguard Worker   }
67*6777b538SAndroid Build Coastguard Worker   ```
68*6777b538SAndroid Build Coastguard Worker
69*6777b538SAndroid Build Coastguard Worker### Calling Java -> Native
70*6777b538SAndroid Build Coastguard Worker
71*6777b538SAndroid Build Coastguard Worker- For each JNI method:
72*6777b538SAndroid Build Coastguard Worker  - C++ stubs are generated that forward to C++ functions that you must write.
73*6777b538SAndroid Build Coastguard Worker    By default the c++ functions you are expected to implement are not
74*6777b538SAndroid Build Coastguard Worker    associated with a class.
75*6777b538SAndroid Build Coastguard Worker  - If the first parameter is a C++ object (e.g.
76*6777b538SAndroid Build Coastguard Worker    `long native${OriginalClassName}`), then the bindings will not call a static
77*6777b538SAndroid Build Coastguard Worker    function but instead cast the variable into a cpp `${OriginalClassName}`
78*6777b538SAndroid Build Coastguard Worker    pointer type and then call a member method with that name on said object.
79*6777b538SAndroid Build Coastguard Worker
80*6777b538SAndroid Build Coastguard WorkerTo add JNI to a class:
81*6777b538SAndroid Build Coastguard Worker
82*6777b538SAndroid Build Coastguard Worker1. Create a nested-interface annotated with `@NativeMethods` that contains
83*6777b538SAndroid Build Coastguard Worker   the declaration of the corresponding static methods you wish to have
84*6777b538SAndroid Build Coastguard Worker   implemented.
85*6777b538SAndroid Build Coastguard Worker2. Call native functions using `${OriginalClassName}Jni.get().${method}`
86*6777b538SAndroid Build Coastguard Worker3. In C++ code, #include the header `${OriginalClassName}_jni.h`. (The path will
87*6777b538SAndroid Build Coastguard Worker   depend on the location of the `generate_jni` BUILD rule that lists your Java
88*6777b538SAndroid Build Coastguard Worker   source code.) Only include this header from a single `.cc` file as the
89*6777b538SAndroid Build Coastguard Worker   header defines functions. That `.cc` must implement your native code by
90*6777b538SAndroid Build Coastguard Worker   defining non-member functions named `JNI_${OriginalClassName}_${UpperCamelCaseMethod}`
91*6777b538SAndroid Build Coastguard Worker   for static methods and member functions named `${OriginalClassName}::${UpperCamelCaseMethod}`
92*6777b538SAndroid Build Coastguard Worker   for non-static methods. Member functions need be declared in the header
93*6777b538SAndroid Build Coastguard Worker   file as well.
94*6777b538SAndroid Build Coastguard Worker
95*6777b538SAndroid Build Coastguard WorkerExample:
96*6777b538SAndroid Build Coastguard Worker#### Java
97*6777b538SAndroid Build Coastguard Worker```java
98*6777b538SAndroid Build Coastguard Workerclass MyClass {
99*6777b538SAndroid Build Coastguard Worker  // Cannot be private. Must be package or public.
100*6777b538SAndroid Build Coastguard Worker  @NativeMethods
101*6777b538SAndroid Build Coastguard Worker  /* package */ interface Natives {
102*6777b538SAndroid Build Coastguard Worker    void foo();
103*6777b538SAndroid Build Coastguard Worker    double bar(int a, int b);
104*6777b538SAndroid Build Coastguard Worker    // Either the |MyClass| part of the |nativeMyClass| parameter name must
105*6777b538SAndroid Build Coastguard Worker    // match the native class name exactly, or the method annotation
106*6777b538SAndroid Build Coastguard Worker    // @NativeClassQualifiedName("MyClass") must be used.
107*6777b538SAndroid Build Coastguard Worker    //
108*6777b538SAndroid Build Coastguard Worker    // If the native class is nested, use
109*6777b538SAndroid Build Coastguard Worker    // @NativeClassQualifiedName("FooClassName::BarClassName") and call the
110*6777b538SAndroid Build Coastguard Worker    // parameter |nativePointer|.
111*6777b538SAndroid Build Coastguard Worker    void nonStatic(long nativeMyClass);
112*6777b538SAndroid Build Coastguard Worker  }
113*6777b538SAndroid Build Coastguard Worker
114*6777b538SAndroid Build Coastguard Worker  void callNatives() {
115*6777b538SAndroid Build Coastguard Worker    // MyClassJni is generated by the generate_jni rule.
116*6777b538SAndroid Build Coastguard Worker    // Storing MyClassJni.get() in a field defeats some of the desired R8
117*6777b538SAndroid Build Coastguard Worker    // optimizations, but local variables are fine.
118*6777b538SAndroid Build Coastguard Worker    Natives jni = MyClassJni.get();
119*6777b538SAndroid Build Coastguard Worker    jni.foo();
120*6777b538SAndroid Build Coastguard Worker    jni.bar(1,2);
121*6777b538SAndroid Build Coastguard Worker    jni.nonStatic(mNativePointer);
122*6777b538SAndroid Build Coastguard Worker  }
123*6777b538SAndroid Build Coastguard Worker}
124*6777b538SAndroid Build Coastguard Worker```
125*6777b538SAndroid Build Coastguard Worker#### C++
126*6777b538SAndroid Build Coastguard Worker```c++
127*6777b538SAndroid Build Coastguard Worker#include "third_party/jni_zero/jni_zero.h"
128*6777b538SAndroid Build Coastguard Worker#include "<path to BUILD.gn>/<generate_jni target name>/MyClass_jni.h"
129*6777b538SAndroid Build Coastguard Worker
130*6777b538SAndroid Build Coastguard Workerclass MyClass {
131*6777b538SAndroid Build Coastguard Workerpublic:
132*6777b538SAndroid Build Coastguard Worker  void NonStatic(JNIEnv* env);
133*6777b538SAndroid Build Coastguard Worker}
134*6777b538SAndroid Build Coastguard Worker
135*6777b538SAndroid Build Coastguard Worker// Notice that unlike Java, function names are capitalized in C++.
136*6777b538SAndroid Build Coastguard Worker// Static function names should follow this format and don't need to be declared.
137*6777b538SAndroid Build Coastguard Workervoid JNI_MyClass_Foo(JNIEnv* env) { ... }
138*6777b538SAndroid Build Coastguard Workervoid JNI_MyClass_Bar(JNIEnv* env, jint a, jint b) { ... }
139*6777b538SAndroid Build Coastguard Worker
140*6777b538SAndroid Build Coastguard Worker// Member functions need to be declared.
141*6777b538SAndroid Build Coastguard Workervoid MyClass::NonStatic(JNIEnv* env) { ... }
142*6777b538SAndroid Build Coastguard Worker```
143*6777b538SAndroid Build Coastguard Worker
144*6777b538SAndroid Build Coastguard Worker### Calling Native -> Java
145*6777b538SAndroid Build Coastguard Worker
146*6777b538SAndroid Build Coastguard WorkerBecause the generated header files contain definitions as well as declarations,
147*6777b538SAndroid Build Coastguard Workerthe must not be `#included` by multiple sources. If there are Java functions
148*6777b538SAndroid Build Coastguard Workerthat need to be called by multiple sources, one source should be chosen to
149*6777b538SAndroid Build Coastguard Workerexpose the functions to the others via additional wrapper functions.
150*6777b538SAndroid Build Coastguard Worker
151*6777b538SAndroid Build Coastguard Worker1. Annotate some methods with `@CalledByNative`, the generator will now generate
152*6777b538SAndroid Build Coastguard Worker   stubs in `${OriginalClassName}_jni.h` header to call into those java methods
153*6777b538SAndroid Build Coastguard Worker   from cpp.
154*6777b538SAndroid Build Coastguard Worker   * Inner class methods must provide the inner class name explicitly
155*6777b538SAndroid Build Coastguard Worker     (ex. `@CalledByNative("InnerClassName")`)
156*6777b538SAndroid Build Coastguard Worker
157*6777b538SAndroid Build Coastguard Worker2. In C++ code, `#include` the header `${OriginalClassName}_jni.h`. (The path
158*6777b538SAndroid Build Coastguard Worker   will depend on the location of the `generate_jni` build rule that lists your
159*6777b538SAndroid Build Coastguard Worker   Java source code). That `.cc` can call the stubs with their generated name
160*6777b538SAndroid Build Coastguard Worker   `JAVA_${OriginalClassName}_${UpperCamelCaseMethod}`.
161*6777b538SAndroid Build Coastguard Worker
162*6777b538SAndroid Build Coastguard WorkerNote: For test-only methods, use `@CalledByNativeForTesting` which will ensure
163*6777b538SAndroid Build Coastguard Workerthat it is stripped in our release binaries.
164*6777b538SAndroid Build Coastguard Worker
165*6777b538SAndroid Build Coastguard Worker### Automatic Type Conversions using @JniType
166*6777b538SAndroid Build Coastguard Worker
167*6777b538SAndroid Build Coastguard WorkerNormally, Java types map to C++ types from `<jni.h>` (e.g. `jstring` for
168*6777b538SAndroid Build Coastguard Worker`java.lang.String`). The first thing most people do is convert the jni spec
169*6777b538SAndroid Build Coastguard Workertypes into standard C++ types.
170*6777b538SAndroid Build Coastguard Worker
171*6777b538SAndroid Build Coastguard Worker`@JniType` to the rescue. By annotating a parameter or a return type with
172*6777b538SAndroid Build Coastguard Worker`@JniType("cpp_type_here")` the generated code will automatically convert from
173*6777b538SAndroid Build Coastguard Workerthe jni type to the type listed inside the annotation. See example:
174*6777b538SAndroid Build Coastguard Worker
175*6777b538SAndroid Build Coastguard Worker#### Original Code:
176*6777b538SAndroid Build Coastguard Worker```java
177*6777b538SAndroid Build Coastguard Workerclass MyClass {
178*6777b538SAndroid Build Coastguard Worker  @NativeMethods
179*6777b538SAndroid Build Coastguard Worker  interface Natives {
180*6777b538SAndroid Build Coastguard Worker    void foo(
181*6777b538SAndroid Build Coastguard Worker            String string,
182*6777b538SAndroid Build Coastguard Worker            String[] strings,
183*6777b538SAndroid Build Coastguard Worker            MyClass obj,
184*6777b538SAndroid Build Coastguard Worker            MyClass[] objs)
185*6777b538SAndroid Build Coastguard Worker  }
186*6777b538SAndroid Build Coastguard Worker}
187*6777b538SAndroid Build Coastguard Worker```
188*6777b538SAndroid Build Coastguard Worker
189*6777b538SAndroid Build Coastguard Worker```c++
190*6777b538SAndroid Build Coastguard Worker#include "third_party/jni_zero/jni_zero.h"
191*6777b538SAndroid Build Coastguard Worker#include "<path to BUILD.gn>/<generate_jni target name>/MyClass_jni.h"
192*6777b538SAndroid Build Coastguard Worker
193*6777b538SAndroid Build Coastguard Workervoid JNI_MyClass_Foo(JNIEnv* env, const JavaParamRef<jstring>&, const JavaParamRef<jobjectArray>&, const JavaParamRef<jobject>&, JavaParamRef<jobjectArray>&) {...}
194*6777b538SAndroid Build Coastguard Worker```
195*6777b538SAndroid Build Coastguard Worker
196*6777b538SAndroid Build Coastguard Worker#### After using `@JniType`
197*6777b538SAndroid Build Coastguard Worker```java
198*6777b538SAndroid Build Coastguard Workerclass MyClass {
199*6777b538SAndroid Build Coastguard Worker  @NativeMethods
200*6777b538SAndroid Build Coastguard Worker  interface Natives {
201*6777b538SAndroid Build Coastguard Worker    void foo(
202*6777b538SAndroid Build Coastguard Worker            @JniType("std::string") String convertedString,
203*6777b538SAndroid Build Coastguard Worker            @JniType("std::vector<std::string>") String[] convertedStrings,
204*6777b538SAndroid Build Coastguard Worker            @JniType("myModule::CPPClass") MyClass convertedObj,
205*6777b538SAndroid Build Coastguard Worker            @JniType("std::vector<myModule::CPPClass>") MyClass[] convertedObjects);
206*6777b538SAndroid Build Coastguard Worker  }
207*6777b538SAndroid Build Coastguard Worker}
208*6777b538SAndroid Build Coastguard Worker```
209*6777b538SAndroid Build Coastguard Worker```c++
210*6777b538SAndroid Build Coastguard Worker#include "third_party/jni_zero/jni_zero.h"
211*6777b538SAndroid Build Coastguard Worker#include "<path to BUILD.gn>/<generate_jni target name>/MyClass_jni.h"
212*6777b538SAndroid Build Coastguard Worker
213*6777b538SAndroid Build Coastguard Workervoid JNI_MyClass_Foo(JNIEnv* env, std::string&, std::vector<std::string>>&, myModule::CPPClass&, std::vector<myModule::CPPClass>&) {...}
214*6777b538SAndroid Build Coastguard Worker```
215*6777b538SAndroid Build Coastguard Worker
216*6777b538SAndroid Build Coastguard Worker#### Implementing Conversion Functions
217*6777b538SAndroid Build Coastguard Worker
218*6777b538SAndroid Build Coastguard WorkerConversion functions must be defined for all types that appear in `@JniType`.
219*6777b538SAndroid Build Coastguard WorkerForgetting to add one will result in errors at link time.
220*6777b538SAndroid Build Coastguard Worker
221*6777b538SAndroid Build Coastguard Worker```c++
222*6777b538SAndroid Build Coastguard Worker// The conversion function primary templates.
223*6777b538SAndroid Build Coastguard Workertemplate <typename O>
224*6777b538SAndroid Build Coastguard WorkerO FromJniType(JNIEnv*, const JavaRef<jobject>&);
225*6777b538SAndroid Build Coastguard Workertemplate <typename O>
226*6777b538SAndroid Build Coastguard WorkerO FromJniType(JNIEnv*, const JavaRef<jstring>&);
227*6777b538SAndroid Build Coastguard Workertemplate <typename O>
228*6777b538SAndroid Build Coastguard WorkerScopedJavaLocalRef<jobject> ToJniType(JNIEnv*, const O&);
229*6777b538SAndroid Build Coastguard Worker```
230*6777b538SAndroid Build Coastguard Worker
231*6777b538SAndroid Build Coastguard WorkerAn example conversion function can look like:
232*6777b538SAndroid Build Coastguard Worker```c++
233*6777b538SAndroid Build Coastguard Worker#include "third_party/jni_zero/jni_zero.h"
234*6777b538SAndroid Build Coastguard Worker
235*6777b538SAndroid Build Coastguard Workernamespace jni_zero {
236*6777b538SAndroid Build Coastguard Workertemplate <>
237*6777b538SAndroid Build Coastguard WorkerEXPORT std::string FromJniType<std::string>(
238*6777b538SAndroid Build Coastguard Worker    JNIEnv* env,
239*6777b538SAndroid Build Coastguard Worker    const JavaRef<jstring>& input) {
240*6777b538SAndroid Build Coastguard Worker  // Do the actual conversion to std::string.
241*6777b538SAndroid Build Coastguard Worker}
242*6777b538SAndroid Build Coastguard Worker
243*6777b538SAndroid Build Coastguard Workertemplate <>
244*6777b538SAndroid Build Coastguard WorkerEXPORT ScopedJavaLocalRef<jstring> ToJniType<std::string>(
245*6777b538SAndroid Build Coastguard Worker    JNIEnv* env,
246*6777b538SAndroid Build Coastguard Worker    const std::string& input) {
247*6777b538SAndroid Build Coastguard Worker  // Do the actual conversion from std::string.
248*6777b538SAndroid Build Coastguard Worker}
249*6777b538SAndroid Build Coastguard Worker}  // namespace jni_zero
250*6777b538SAndroid Build Coastguard Worker```
251*6777b538SAndroid Build Coastguard Worker
252*6777b538SAndroid Build Coastguard WorkerIf a conversion function is missing, you will get a linker error since we
253*6777b538SAndroid Build Coastguard Workerforward declare the conversion functions before using them.
254*6777b538SAndroid Build Coastguard Worker
255*6777b538SAndroid Build Coastguard Worker#### Array Conversion Functions
256*6777b538SAndroid Build Coastguard Worker
257*6777b538SAndroid Build Coastguard WorkerArray conversion functions look different due to the partial specializations.
258*6777b538SAndroid Build Coastguard WorkerThe `ToJniType` direction also takes a `jclass` parameter which is the class of the
259*6777b538SAndroid Build Coastguard Workerarray elements, because java requires it when creating a non-primitive array.
260*6777b538SAndroid Build Coastguard Worker
261*6777b538SAndroid Build Coastguard Worker```c++
262*6777b538SAndroid Build Coastguard Workertemplate <typename O>
263*6777b538SAndroid Build Coastguard Workerstruct ConvertArray {
264*6777b538SAndroid Build Coastguard Worker  static O FromJniType(JNIEnv*, const JavaRef<jobjectArray>&);
265*6777b538SAndroid Build Coastguard Worker  static ScopedJavaLocalRef<jobjectArray> ToJniType(JNIEnv*, const O&, jclass);
266*6777b538SAndroid Build Coastguard Worker};
267*6777b538SAndroid Build Coastguard Worker```
268*6777b538SAndroid Build Coastguard Worker
269*6777b538SAndroid Build Coastguard WorkerJniZero provides implementations for partial specializations to wrap and unwrap
270*6777b538SAndroid Build Coastguard Worker`std::vector` for object arrays and some primitive arrays.
271*6777b538SAndroid Build Coastguard Worker
272*6777b538SAndroid Build Coastguard Worker#### Nullability
273*6777b538SAndroid Build Coastguard Worker
274*6777b538SAndroid Build Coastguard WorkerAll non-primitive default JNI C++ types (e.g. `jstring`, `jobject`) are pointer
275*6777b538SAndroid Build Coastguard Workertypes (i.e. nullable). Some C++ types (e.g. `std::string`) are not pointer types
276*6777b538SAndroid Build Coastguard Workerand thus cannot be `nullptr`. This means some conversion functions that return
277*6777b538SAndroid Build Coastguard Workernon-nullable types have to handle the situation where the passed in java type is
278*6777b538SAndroid Build Coastguard Workernull.
279*6777b538SAndroid Build Coastguard Worker
280*6777b538SAndroid Build Coastguard WorkerYou can get around this by having the conversion be to `std::optional<T>` rather
281*6777b538SAndroid Build Coastguard Workerthan just `T` if `T` is not a nullable type.
282*6777b538SAndroid Build Coastguard Worker
283*6777b538SAndroid Build Coastguard Worker
284*6777b538SAndroid Build Coastguard Worker### Testing Mockable Natives
285*6777b538SAndroid Build Coastguard Worker
286*6777b538SAndroid Build Coastguard Worker1. Add the `JniMocker` rule to your test.
287*6777b538SAndroid Build Coastguard Worker2. Call `JniMocker#mock` in a `setUp()` method for each interface you want to
288*6777b538SAndroid Build Coastguard Worker   stub out.
289*6777b538SAndroid Build Coastguard Worker
290*6777b538SAndroid Build Coastguard Worker`JniMocker` will reset the stubs during `tearDown()`.
291*6777b538SAndroid Build Coastguard Worker
292*6777b538SAndroid Build Coastguard Worker```java
293*6777b538SAndroid Build Coastguard Worker/**
294*6777b538SAndroid Build Coastguard Worker * Tests for {@link AnimationFrameTimeHistogram}
295*6777b538SAndroid Build Coastguard Worker */
296*6777b538SAndroid Build Coastguard Worker@RunWith(BaseRobolectricTestRunner.class)
297*6777b538SAndroid Build Coastguard Worker@Config(manifest = Config.NONE)
298*6777b538SAndroid Build Coastguard Workerpublic class AnimationFrameTimeHistogramTest {
299*6777b538SAndroid Build Coastguard Worker    @Rule
300*6777b538SAndroid Build Coastguard Worker    public JniMocker mocker = new JniMocker();
301*6777b538SAndroid Build Coastguard Worker
302*6777b538SAndroid Build Coastguard Worker    @Mock
303*6777b538SAndroid Build Coastguard Worker    AnimationFrameTimeHistogram.Natives mNativeMock;
304*6777b538SAndroid Build Coastguard Worker
305*6777b538SAndroid Build Coastguard Worker    @Before
306*6777b538SAndroid Build Coastguard Worker    public void setUp() {
307*6777b538SAndroid Build Coastguard Worker        MockitoAnnotations.initMocks(this);
308*6777b538SAndroid Build Coastguard Worker        mocker.mock(AnimationFrameTimeHistogramJni.TEST_HOOKS, mNativeMock);
309*6777b538SAndroid Build Coastguard Worker    }
310*6777b538SAndroid Build Coastguard Worker
311*6777b538SAndroid Build Coastguard Worker    @Test
312*6777b538SAndroid Build Coastguard Worker    public void testNatives() {
313*6777b538SAndroid Build Coastguard Worker        AnimationFrameTimeHistogram hist = new AnimationFrameTimeHistogram("histName");
314*6777b538SAndroid Build Coastguard Worker        hist.startRecording();
315*6777b538SAndroid Build Coastguard Worker        hist.endRecording();
316*6777b538SAndroid Build Coastguard Worker        verify(mNativeMock).saveHistogram(eq("histName"), any(long[].class), anyInt());
317*6777b538SAndroid Build Coastguard Worker    }
318*6777b538SAndroid Build Coastguard Worker}
319*6777b538SAndroid Build Coastguard Worker```
320*6777b538SAndroid Build Coastguard Worker
321*6777b538SAndroid Build Coastguard WorkerIf a native method is called without setting a mock in a unit test, an
322*6777b538SAndroid Build Coastguard Worker`UnsupportedOperationException` will be thrown.
323*6777b538SAndroid Build Coastguard Worker
324*6777b538SAndroid Build Coastguard Worker### Special case: DFMs
325*6777b538SAndroid Build Coastguard WorkerDFMs have their own generated `GEN_JNI`s, which are `<module_name>_GEN_JNI`. In
326*6777b538SAndroid Build Coastguard Workerorder to get your DFM's JNI to use the `<module_name>` prefix, you must add your
327*6777b538SAndroid Build Coastguard Workermodule name into the argument of the `@NativeMethods` annotation.
328*6777b538SAndroid Build Coastguard Worker
329*6777b538SAndroid Build Coastguard WorkerSo, for example, say your module was named `test_module`. You would annotate
330*6777b538SAndroid Build Coastguard Workeryour `Natives` interface with `@NativeMethods("test_module")`, and this would
331*6777b538SAndroid Build Coastguard Workerresult in `test_module_GEN_JNI`.
332*6777b538SAndroid Build Coastguard Worker
333*6777b538SAndroid Build Coastguard Worker
334*6777b538SAndroid Build Coastguard Worker### Testing for readiness: use `get()`
335*6777b538SAndroid Build Coastguard Worker
336*6777b538SAndroid Build Coastguard WorkerJNI Generator automatically produces asserts that verify that the Natives interface can be safely
337*6777b538SAndroid Build Coastguard Workercalled. These checks are compiled out of Release builds, making these an excellent way to determine
338*6777b538SAndroid Build Coastguard Workerwhether your code is called safely.
339*6777b538SAndroid Build Coastguard Worker
340*6777b538SAndroid Build Coastguard WorkerIt is not sufficient, however, to use `<Class>Jni.get()` to guarantee native is initialized - it is
341*6777b538SAndroid Build Coastguard Workeronly a debugging tool to ensure that you're using native after native is loaded.
342*6777b538SAndroid Build Coastguard Worker
343*6777b538SAndroid Build Coastguard WorkerIf you expect your code to be called by an external caller, it's often helpful to know _ahead of
344*6777b538SAndroid Build Coastguard Workertime_ that the context is valid (ie. either native libraries are loaded or mocks are installed).
345*6777b538SAndroid Build Coastguard WorkerIn this case it is helpful to call `get()` method, that performs all the Debug checks listed
346*6777b538SAndroid Build Coastguard Workerabove, but does not instantiate a new object for interfacing Native libraries.
347*6777b538SAndroid Build Coastguard WorkerNote that the unused value returned by the `get()` method will be optimized away in release builds
348*6777b538SAndroid Build Coastguard Workerso there's no harm in ignoring it.
349*6777b538SAndroid Build Coastguard Worker
350*6777b538SAndroid Build Coastguard Worker#### Addressing `Jni.get()` exceptions.
351*6777b538SAndroid Build Coastguard Worker
352*6777b538SAndroid Build Coastguard WorkerWhen you identify a scenario leading to an exception, relocate (or defer) the appropriate call to
353*6777b538SAndroid Build Coastguard Workerbe made to a place where (or time when) you know the native libraries have been initialized (eg.
354*6777b538SAndroid Build Coastguard Worker`onStartWithNative`, `onNativeInitialized` etc).
355*6777b538SAndroid Build Coastguard Worker
356*6777b538SAndroid Build Coastguard WorkerPlease avoid calling `LibraryLoader.isInitialized()` / `LibraryLoader.isLoaded()` in new code.
357*6777b538SAndroid Build Coastguard WorkerUsing `LibraryLoader` calls makes unit-testing more difficult:
358*6777b538SAndroid Build Coastguard Worker* this call can not verify whether Mock object is used, making the use of mocks more complicated,
359*6777b538SAndroid Build Coastguard Worker* using `LibraryLoader.setLibrariesLoadedForNativeTests()` alters the state for subsequently
360*6777b538SAndroid Build Coastguard Workerexecuted tests, inaccurately reporting flakiness and failures of these victim tests.
361*6777b538SAndroid Build Coastguard Worker* Introducing `LibraryLoader.is*()` calls in your code immediately affects all callers, forcing
362*6777b538SAndroid Build Coastguard Workerthe authors of the code up the call stack to override `LibraryLoader` internal state in order to be
363*6777b538SAndroid Build Coastguard Workerable to unit-test their code.
364*6777b538SAndroid Build Coastguard Worker
365*6777b538SAndroid Build Coastguard WorkerHowever, if your code is going to be called both before and after native is initialized, you are
366*6777b538SAndroid Build Coastguard Workerforced to call `LibraryLoader.isInitialized()` to be able to differentiate. Calling
367*6777b538SAndroid Build Coastguard Worker`<Class>Jni.get()` only provides assertions, and will fail in debug builds if you call it when
368*6777b538SAndroid Build Coastguard Workernative isn't ready.
369*6777b538SAndroid Build Coastguard Worker
370*6777b538SAndroid Build Coastguard Worker### Java Objects and Garbage Collection
371*6777b538SAndroid Build Coastguard Worker
372*6777b538SAndroid Build Coastguard WorkerAll pointers to Java objects must be registered with JNI in order to prevent
373*6777b538SAndroid Build Coastguard Workergarbage collection from invalidating them.
374*6777b538SAndroid Build Coastguard Worker
375*6777b538SAndroid Build Coastguard WorkerFor Strings & Arrays - it's common practice to use the `//base/android/jni_*`
376*6777b538SAndroid Build Coastguard Workerhelpers to convert them to `std::vectors` and `std::strings` as soon as
377*6777b538SAndroid Build Coastguard Workerpossible.
378*6777b538SAndroid Build Coastguard Worker
379*6777b538SAndroid Build Coastguard WorkerFor other objects - use smart pointers to store them:
380*6777b538SAndroid Build Coastguard Worker * `ScopedJavaLocalRef<>` - When lifetime is the current function's scope.
381*6777b538SAndroid Build Coastguard Worker * `ScopedJavaGlobalRef<>` - When lifetime is longer than the current function's
382*6777b538SAndroid Build Coastguard Worker   scope.
383*6777b538SAndroid Build Coastguard Worker * `JavaObjectWeakGlobalRef<>` - Weak reference (do not prevent garbage
384*6777b538SAndroid Build Coastguard Worker   collection).
385*6777b538SAndroid Build Coastguard Worker * `JavaParamRef<>` - Use to accept any of the above as a parameter to a
386*6777b538SAndroid Build Coastguard Worker   function without creating a redundant registration.
387*6777b538SAndroid Build Coastguard Worker
388*6777b538SAndroid Build Coastguard Worker### Additional Guidelines / Advice
389*6777b538SAndroid Build Coastguard Worker
390*6777b538SAndroid Build Coastguard WorkerMinimize the surface API between the two sides. Rather than calling multiple
391*6777b538SAndroid Build Coastguard Workerfunctions across boundaries, call only one (and then on the other side, call as
392*6777b538SAndroid Build Coastguard Workermany little functions as required).
393*6777b538SAndroid Build Coastguard Worker
394*6777b538SAndroid Build Coastguard WorkerIf a Java object "owns" a native one, store the pointer via
395*6777b538SAndroid Build Coastguard Worker`"long mNativeClassName"`. Ensure to eventually call a native method to delete
396*6777b538SAndroid Build Coastguard Workerthe object. For example, have a `close()` that deletes the native object.
397*6777b538SAndroid Build Coastguard Worker
398*6777b538SAndroid Build Coastguard WorkerThe best way to pass "compound" types across in either direction is to
399*6777b538SAndroid Build Coastguard Workercreate an inner class with PODs and a factory function. If possible, mark
400*6777b538SAndroid Build Coastguard Workerall the fields as "final".
401*6777b538SAndroid Build Coastguard Worker
402*6777b538SAndroid Build Coastguard Worker## Build Rules
403*6777b538SAndroid Build Coastguard Worker
404*6777b538SAndroid Build Coastguard Worker * `generate_jni` - Generates a header file with stubs for given `.java` files
405*6777b538SAndroid Build Coastguard Worker * `generate_jar_jni` - Generates a header file with stubs for a given `.jar`
406*6777b538SAndroid Build Coastguard Worker   file
407*6777b538SAndroid Build Coastguard Worker * `generate_jni_registration` - Generates a header file with functions to
408*6777b538SAndroid Build Coastguard Worker   register native-side JNI methods.
409*6777b538SAndroid Build Coastguard Worker
410*6777b538SAndroid Build Coastguard WorkerRefer to [//build/config/android/rules.gni](https://cs.chromium.org/chromium/src/build/config/android/rules.gni)
411*6777b538SAndroid Build Coastguard Workerfor more about the GN templates.
412*6777b538SAndroid Build Coastguard Worker
413*6777b538SAndroid Build Coastguard Worker## Changing JNI Zero
414*6777b538SAndroid Build Coastguard Worker
415*6777b538SAndroid Build Coastguard Worker * Python tests live in `test/integration_tests.py`
416*6777b538SAndroid Build Coastguard Worker * A working demo app exists as `//third_party/jni_zero/sample:jni_zero_sample_apk`
417