• Home
Name Date Size #Lines LOC

..--

doc/03-May-2024-6921

golden/03-May-2024-14,43912,296

java/src/org/chromium/03-May-2024-919530

.style.yapfD03-May-202465 54

AndroidManifest.xmlD03-May-2024333 134

BUILD.gnD03-May-20242.7 KiB10383

DIR_METADATAD03-May-202467 54

PRESUBMIT.pyD03-May-20241.1 KiB4227

README.mdD03-May-202410.9 KiB276219

android_jar.classesD03-May-20243.1 KiB9998

jni_generator.pyD03-May-202461.2 KiB1,7271,394

jni_generator.pydepsD03-May-2024360 87

jni_generator_helper.hD03-May-20244.3 KiB13184

jni_generator_tests.pyD03-May-202463.7 KiB1,8151,613

jni_registration_generator.pyD03-May-202431.7 KiB922731

jni_registration_generator.pydepsD03-May-2024446 109

sample_entry_point.ccD03-May-2024794 2211

sample_for_tests.ccD03-May-20249.3 KiB282216

sample_for_tests.hD03-May-20243.4 KiB11236

README.md

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
26Generally Java->Native calls are exported from the shared library and lazily
27resolved by the runtime (via `dlsym()`). There are a number of notable
28exceptions to this. See usage of `jni_registration_generator.py` in the
29codebase.
30
31The `jni_registration_generator.py` exposes a registration function when using
32manual registation:
33* `RegisterNatives` - Registers all native functions.
34
35### Exposing Java Methods
36
37Java methods just need to be annotated with `@CalledByNative`. The generated
38functions can be put into a namespace using `@JNINamespace("your_namespace")`.
39
40## Usage
41
42Because the generator does not generate any source files, generated headers must
43not be `#included` by multiple sources. If there are Java functions that need to
44be called by multiple sources, one source should be chosen to expose the
45functions to the others via additional wrapper functions.
46
47### Calling Java -> Native
48
49- Declare methods using a nested interface annotated with `@NativeMethods`.
50- The JNI annotation processor generates a class named `${OriginalClassName}Jni`
51  with a `get()` method that returns an implementation of the annotated
52  interface. The C++ function that it routes to is the same as if it would be
53  in the legacy method.
54- For each JNI method:
55  - C++ stubs are generated that forward to C++ functions that you must write.
56  - If the first parameter is a C++ object (e.g.
57    `long native${OriginalClassName}`), then the bindings will generate the
58    appropriate cast and call into C++ code.
59
60To add JNI to a class:
61
621. Enable the JNI processor by adding to your `android_library` target:
63   ```python
64   annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
65   deps = [ "//base:jni_java" ]
66   ```
672. Create a nested-interface annotated with `@NativeMethods` that contains
68   the declaration of the corresponding static methods you wish to have
69   implemented.
703. Call native functions using `${OriginalClassName}Jni.get().${method}`
714. In C++ code, #include the header `${OriginalClassName}_jni.h`. (The path will
72   depend on the location of the `generate_jni` BUILD rule that lists your Java
73   source code.) Only include this header from a single `.cc` file as the
74   header defines functions. That `.cc` must implement your native code by
75   defining non-member functions named `JNI_${OriginalClassName}_${UpperCamelCaseMethod}`
76   for static methods and member functions named `${OriginalClassName}::${UpperCamelCaseMethod}`
77   for non-static methods. Member functions need be declared in the header
78   file as well.
79
80Example:
81#### Java
82```java
83class MyClass {
84  // Cannot be private. Must be package or public.
85  @NativeMethods
86  /* package */ interface Natives {
87    void foo();
88    double bar(int a, int b);
89    // Either the |MyClass| part of the |nativeMyClass| parameter name must
90    // match the native class name exactly, or the method annotation
91    // @NativeClassQualifiedName("MyClass") must be used.
92    //
93    // If the native class is nested, use
94    // @NativeClassQualifiedName("FooClassName::BarClassName") and call the
95    // parameter |nativePointer|.
96    void nonStatic(long nativeMyClass);
97  }
98
99  void callNatives() {
100    // MyClassJni is generated by the JNI annotation processor.
101    // Storing MyClassJni.get() in a field defeats some of the desired R8
102    // optimizations, but local variables are fine.
103    Natives jni = MyClassJni.get();
104    jni.foo();
105    jni.bar(1,2);
106    jni.nonStatic(mNativePointer);
107  }
108}
109```
110#### C++
111```c++
112#include "base/android/jni_android.h"
113#include "<path to BUILD.gn>/<generate_jni target name>/MyClass_jni.h"
114
115class MyClass {
116public:
117  void NonStatic(JNIEnv* env);
118}
119
120// Notice that unlike Java, function names are capitalized in C++.
121// Static function names should follow this format and don't need to be declared.
122void JNI_MyClass_Foo(JNIEnv* env) { ... }
123void JNI_MyClass_Bar(JNIEnv* env, jint a, jint b) { ... }
124
125// Member functions need to be declared.
126void MyClass::NonStatic(JNIEnv* env) { ... }
127```
128
129**Using the 'native' keyword**
130
131- The binding generator also looks for `native` JNI method declarations and
132  generates stubs for them. This used to be the norm, but is now obsolete.
133- If you have native methods that you don't want stubs generated for, you should
134  add @JniIgnoreNatives to the class.
135
136#### Testing Mockable Natives
137
1381. Add the `JniMocker` rule to your test.
1392. Call `JniMocker#mock` in a `setUp()` method for each interface you want to
140   stub out.
141
142`JniMocker` will reset the stubs during `tearDown()`.
143
144```java
145/**
146 * Tests for {@link AnimationFrameTimeHistogram}
147 */
148@RunWith(BaseRobolectricTestRunner.class)
149@Config(manifest = Config.NONE)
150public class AnimationFrameTimeHistogramTest {
151    @Rule
152    public JniMocker mocker = new JniMocker();
153
154    @Mock
155    AnimationFrameTimeHistogram.Natives mNativeMock;
156
157    @Before
158    public void setUp() {
159        MockitoAnnotations.initMocks(this);
160        mocker.mock(AnimationFrameTimeHistogramJni.TEST_HOOKS, mNativeMock);
161    }
162
163    @Test
164    public void testNatives() {
165        AnimationFrameTimeHistogram hist = new AnimationFrameTimeHistogram("histName");
166        hist.startRecording();
167        hist.endRecording();
168        verify(mNativeMock).saveHistogram(eq("histName"), any(long[].class), anyInt());
169    }
170}
171```
172
173If a native method is called without setting a mock in a unit test, an
174`UnsupportedOperationException` will be thrown.
175
176#### Special case: DFMs
177DFMs have their own generated `GEN_JNI`s, which are `<module_name>_GEN_JNI`. In
178order to get your DFM's JNI to use the `<module_name>` prefix, you must add your
179module name into the argument of the `@NativeMethods` annotation.
180
181So, for example, say your module was named `test_module`. You would annotate
182your `Natives` interface with `@NativeMethods("test_module")`, and this would
183result in `test_module_GEN_JNI`.
184
185
186### Testing for readiness: use `get()`
187
188JNI Generator automatically produces checks that verify that the Natives interface can be safely
189called. These checks are compiled out of Release builds, making these an excellent way to determine
190whether your code is called safely.
191
192![Check Flow](doc/jni-check-flow.svg)
193
194Most of the time you would write your code so that you only use JNI once the native libraries are
195loaded. There's nothing extra you need to do here.
196
197If you expect your code to be called by an external caller, it's often helpful to know _ahead of
198time_ that the context is valid (ie. either native libraries are loaded or mocks are installed).
199In this case it is helpful to call `get()` method, that performs all the Debug checks listed
200above, but does not instantiate a new object for interfacing Native libraries.
201Note that the unused value returned by the `get()` method will be optimized away in release builds
202so there's no harm in ignoring it.
203
204#### Addressing `Jni.get()` exceptions.
205
206When you identify a scenario leading to an exception, relocate (or defer) the appropriate call to
207be made to a place where (or time when) you know the native libraries have been initialized (eg.
208`onStartWithNative`, `onNativeInitialized` etc).
209
210Please avoid calling `LibraryLoader.isInitialized()` / `LibraryLoader.isLoaded()` in new code.
211Using `LibraryLoader` calls makes unit-testing more difficult:
212* this call can not verify whether Mock object is used, making the use of mocks more complicated,
213* using `LibraryLoader.setLibrariesLoadedForNativeTests()` alters the state for subsequently
214executed tests, inaccurately reporting flakiness and failures of these victim tests.
215* Introducing `LibraryLoader.is*()` calls in your code immediately affects all callers, forcing
216the authors of the code up the call stack to override `LibraryLoader` internal state in order to be
217able to unit-test their code.
218
219### Calling Native -> Java
220
221 * Methods annotated with `@CalledByNative` will have stubs generated for them.
222   * Inner class methods must provide the inner class name explicitly
223     (ex. `@CalledByNative("InnerClassName")`)
224 * Just call the generated stubs defined in generated `.h` files.
225 * For test-only methods you want to call from native, use
226   `@CalledByNativeForTesting` which will ensure that it is stripped in our
227   release binaries.
228
229### Java Objects and Garbage Collection
230
231All pointers to Java objects must be registered with JNI in order to prevent
232garbage collection from invalidating them.
233
234For Strings & Arrays - it's common practice to use the `//base/android/jni_*`
235helpers to convert them to `std::vectors` and `std::strings` as soon as
236possible.
237
238For other objects - use smart pointers to store them:
239 * `ScopedJavaLocalRef<>` - When lifetime is the current function's scope.
240 * `ScopedJavaGlobalRef<>` - When lifetime is longer than the current function's
241   scope.
242 * `JavaObjectWeakGlobalRef<>` - Weak reference (do not prevent garbage
243   collection).
244 * `JavaParamRef<>` - Use to accept any of the above as a parameter to a
245   function without creating a redundant registration.
246
247### Additional Guidelines / Advice
248
249Minimize the surface API between the two sides. Rather than calling multiple
250functions across boundaries, call only one (and then on the other side, call as
251many little functions as required).
252
253If a Java object "owns" a native one, store the pointer via
254`"long mNativeClassName"`. Ensure to eventually call a native method to delete
255the object. For example, have a `close()` that deletes the native object.
256
257The best way to pass "compound" types across in either direction is to
258create an inner class with PODs and a factory function. If possible, mark
259all the fields as "final".
260
261## Build Rules
262
263 * `generate_jni` - Generates a header file with stubs for given `.java` files
264 * `generate_jar_jni` - Generates a header file with stubs for a given `.jar`
265   file
266 * `generate_jni_registration` - Generates a header file with functions to
267   register native-side JNI methods.
268
269Refer to [//build/config/android/rules.gni](https://cs.chromium.org/chromium/src/build/config/android/rules.gni)
270for more about the GN templates.
271
272## Changing `jni_generator`
273
274 * Python unit tests live in `jni_generator_tests.py`
275 * A working demo app exists as `//base/android/jni_generator:sample_jni_apk`
276