third_party/jni_zero/skills/jni-zero/SKILL.md
JNI Zero is a code generator that lives at //third_party/jni_zero. It's
written in Python and has both C++ and Java APIs. The main reference is in
//third_party/jni_zero/README.md.
_jni as a suffix for all generate_jni() and generate_jar_jni()
targets.generate_jni() targets should be in the same BUILD.gn as the
android_library() that owns the sources.android_library() targets that have a .java file that is
listed in a generate_jni() target also contain a deps entry onto the
foo_jni_java target.Generated headers:
{OUTPUT_DIR}/gen/jni_headers/{BUILD_GN_SUBDIR}/{TARGET_NAME}/{JavaClass}_jni.hgen/jni_headers prefix when #include'ing them._jni.h headers from .cc files should come after all other
#includes and be preceded with the comment:
// Must come after headers that provide symbols used by @JniType._jni.h headers from .h files should always use the
_shared_jni.h variants.API Usage:
JavaRef, use nullptr rather than calling
a constructor.JArray<jobject> over jobjectArray, as well as for other array types
(JArray<*> over j*Array)jni_zero:: namespace instead of the base::android:: aliases (e.g.
for *JavaRef, and AttachBaseContext())Java_Clazz_method() functions
directly. Call them through their typed wrappers: ClazzJni::method()ClazzJni::New()JavaRef<jobject>, use Java_Clazz_method()JavaRef<JFoo>, use foo->method()Defining native entry point methods:
_jni.h filesJNIEnv* parameter if it will be unused.@JniType() on as many parameters and return types as possible.null must be annotated as
@Nullable to avoid a runtime null-check.onDestroy()
method that calls delete via JNI, and sets the field 0.FromJniType or ToJniType to discover which types
are currently supported.std::string or std::u16string.std::optional for @Nullable types except when the type itself contains
a null-state (e.g. GURL, Callback, Strings where "" is not a valid value).List<> over typed object arrays.JavaRef<jobject> and ScopedJavaLocalRef<jobject> to use generated
classes that extend jobject.JavaRef<jobject> for a FooBar class becomes JavaRef<JFooBar>.java.lang.Object maps to jobjectjava.lang.String maps to jstringjava.lang.Throwable maps to jthrowablejava.lang.Class maps to jclass.As<JFoo>() to convert from JavaRef<jobject> to a specific generated
type.ScopedJavaLocalRef<jobject>() (empty constructor) to nullptr.Java_MyClass_method(env, ref, ...) with
ref->method(env, ...).Java_MyClass_method(env, ...) with
JMyClassClass::method(env, ...).java.lang.Object will take jobject. If you have a
JavaRef<jobject>, you can pass it directly.::org::chromium::base::JFoo).using statement isn't already in the _jni.h file, add an alias at the
top of the .cc file.using ::org::chromium::base::JLogo;..cc files when an
alias is available.JFoo is used in a .h file:
foo_shared_jni.h.BUILD.gn, add a public_dep onto the generate_jni() target that
produces it._shared_jni.h in .cc files; use regular _jni.h headers
there.List, Set, Map):
//third_party/jni_zero:system_jni.See examples.md for concrete before/after snippets.
Build all affected .cc and .java files using autoninja:
autoninja -C {OUTPUT_DIR} ../../path/to/foo.cc^ ../../path/to/Foo.java^
Note: Use the specified OUTPUT_DIR (typically out/Default or out/Debug).