• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..21-Oct-2021-

golden/H21-Oct-2021-11,5899,737

java/src/org/chromium/H21-Oct-2021-931533

.style.yapfH A D21-Oct-202165 54

AndroidManifest.xmlH A D21-Oct-2021356 134

BUILD.gnH A D21-Oct-20213.1 KiB11696

OWNERSH A D21-Oct-202162 43

PRESUBMIT.pyH A D21-Oct-20211 KiB3824

ProcessorArgs.templateH A D21-Oct-2021298 107

README.mdH A D21-Oct-202111.4 KiB292237

TestSampleFeatureList.javaH A D21-Oct-2021464 137

android_jar.classesH A D21-Oct-20213.1 KiB9998

config.gniH A D21-Oct-2021416 97

jni_generator.pyH A D21-Oct-202161.9 KiB1,7941,467

jni_generator.pydepsH A D21-Oct-2021327 76

jni_generator_helper.hH A D21-Oct-20214.3 KiB13184

jni_generator_tests.pyH A D21-Oct-202163.6 KiB1,9211,715

jni_refactorer.pyH A D21-Oct-202114.4 KiB465355

jni_registration_generator.pyH A D21-Oct-202119.2 KiB616490

jni_registration_generator.pydepsH A D21-Oct-2021383 87

sample_entry_point.ccH A D21-Oct-2021955 2816

sample_for_tests.ccH A D21-Oct-20219.4 KiB282216

sample_for_tests.hH A D21-Oct-20213.6 KiB11435

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
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### Native Java Unittests and @CalledByNativeJavaTest
213
214Native Java Unittests are Java unit tests that run on Android (not on the host
215machine). Unlike junit and robolectric, these tests can use the native library,
216and real Android APIs. Unlike unit tests in ChromePublicTestApk and similar, the
217Activity is not restarted between tests, so the tests run much faster (and you
218must be careful not to leave state behind). Example tests may be found in
219chrome/android/native_java_unittests/.
220
221The @CalledByNativeJavaTest annotation causes the JNI generator to generate
222C++ test methods that simply call out to the Java test methods.
223
224For Example:
225```java
226class FooTest {
227  @CalledByNative public FooTest() {}
228  @CalledByNativeJavaTest public void testFoo() { ... }
229  @CalledByNativeJavaTest public void testOtherFoo() { ... }
230}
231```
232```c++
233class FooTest : public ::testing::Test {
234  FooTest() : j_test_(Java_FooTest_Constructor(AttachCurrentThread())) {}
235  const ScopedJavaGlobalRef<jobject>& j_test() { return j_test_; }
236 private:
237  ScopedJavaGlobalRef<jobject> j_test_;
238}
239JAVA_TESTS(AndroidPaymentAppFinderUnitTest, j_test())
240```
241
242In some cases you may want to run custom C++ code before running the Java test,
243in which case, use CalledByNative instead of CalledByNativeJavaTest and call the
244test method yourself. eg. Java_FooTest_testFancyFoo(env, j_test());
245
246#### Disabling @CalledByNativeJavaTest tests
247In order to disabled a Native Java Unittest, replace the @CalledByNativeJavaTest
248annotation with @DisabledCalledByNativeJavaTest. This will generate a native
249test prefixed with DISABLED_.
250
251Please note that unlike @DisabledTest, you should not provide a message in the
252annotation as to why the test is disabled, as this will be interpreted as the
253inner class name by the CalledByNative jni generator.
254
255#### Feature flag support in @CalledByNativeJavaTest tests
256Features may be enabled/disabled for the Java test methods by using the
257@NativeJavaTestFeatures.Enabled or @NativeJavaTestFeatures.Disabled annotations.
258
259Note that these annotations will re-initialize the feature list given they
260initialize through the command line approach, and so will clear any features
261set by, say, test setup.
262
263### Additional Guidelines / Advice
264
265Minimize the surface API between the two sides. Rather than calling multiple
266functions across boundaries, call only one (and then on the other side, call as
267many little functions as required).
268
269If a Java object "owns" a native one, store the pointer via
270`"long mNativeClassName"`. Ensure to eventually call a native method to delete
271the object. For example, have a `close()` that deletes the native object.
272
273The best way to pass "compound" types across in either direction is to
274create an inner class with PODs and a factory function. If possible, make mark
275all the fields as "final".
276
277## Build Rules
278
279 * `generate_jni` - Generates a header file with stubs for given `.java` files
280 * `generate_jar_jni` - Generates a header file with stubs for a given `.jar`
281   file
282 * `generate_jni_registration` - Generates a header file with functions to
283   register native-side JNI methods (required only when using crazy linker).
284
285Refer to [//build/config/android/rules.gni](https://cs.chromium.org/chromium/src/build/config/android/rules.gni)
286for more about the GN templates.
287
288## Changing `jni_generator`
289
290 * Python unit tests live in `jni_generator_tests.py`
291 * A working demo app exists as `//base/android/jni_generator:sample_jni_apk`
292