JNI is the Java Native Interface. It defines a way for the bytecode that Android compiles frommanaged code (written within the Java or Kotlin programming languages) to have interaction with local code(written in C/C++). JNI is dealer-impartial, has help for loading code from dynamic sharedlibraries, and even as cumbersome at instances is reasonably green.
Note: Because Android compiles Kotlin to ART-friendly bytecode ina comparable way because the Java programming language, you could apply the steering in this page to boththe Kotlin and Java programming languages in terms of JNI structure and its related charges.To research extra, seeKotlin and Android.
If you are not already acquainted with it, study through theJava Native Interface Specificationto get a feel for how JNI works and what features are to be had.Someaspects of the interface aren’t without delay obvious onfirst analyzing, so you may additionally find the next few sections reachable.
To browse global JNI references and see where international JNI references are created and deleted, usethe JNI heap view inside the Memory Profilerin Android Studio three.2 and higher.General recommendations
Try to decrease the footprint of your JNI layer. There are several dimensions to recollect right here.Your JNI solution have to try to follow these tips (listed beneath by means of order of importance,starting with the maximum crucial):Minimize marshalling of assets across the JNI layer. Marshalling acrossthe JNI layer has non-trivial expenses. Try to layout an interface that minimizes the quantity ofdata you need to marshall and the frequency with that you have to marshall information.Avoid asynchronous conversation among code written in a controlled programminglanguage and code written in C++ when feasible.This will maintain your JNI interface simpler to keep. You can usually simplify asynchronousUI updates by means of retaining the async update within the identical language because the UI. For instance, as a substitute ofinvoking a C++ feature from the UI thread in the Java code thru JNI, it’s betterto do a callback betweenthreads inside the Java programming language, with considered one of themmaking a blocking off C++ call after which notifying the UI thread when the blocking call iscomplete.Minimize the quantity of threads that want to the touch or be touched with the aid of JNI.If you do need to make use of thread swimming pools in both the Java and C++ languages, try to maintain JNIcommunication among the pool owners as opposed to among man or woman worker threads.Keep your interface code in a low variety of effortlessly recognized C++ and Java sourcelocations to facilitate destiny refactors. Consider using a JNI car-generationlibrary as appropriate.JavaVM and JNIEnv
JNI defines two key records structures, “JavaVM” and “JNIEnv”.Both of these are essentiallypointers to guidelines to characteristic tables.(In the C++ model, they’re classes with apointer to a characteristic table and a member characteristic for each JNI characteristic that indirects throughthe table.)The JavaVM presents the “invocation interface” functions,which allow you to create and spoil a JavaVM.In principle you can have a couple of JavaVMs in step with procedure,however Android simplest lets in one.
The JNIEnv gives maximum of the JNI functions.Your native features all get hold of a JNIEnv asthe first argument.
The JNIEnv is used for thread-nearby storage.For this cause, you cannot share a JNIEnv among threads.If a bit of code has no different manner to get its JNIEnv, you have to sharethe JavaVM, and use GetEnv to find out the thread’s JNIEnv. (Assuming it has one; see AttachCurrentThread under.)
The C declarations of JNIEnv and JavaVM are specific from the C++declarations.The “jni.h” consist of file offers special typedefsdepending on whether or not it is included into C or C++.For this reason it is a horrific idea toinclude JNIEnv arguments in header documents protected by each languages.(Put some other manner: if yourheader report calls for #ifdef __cplusplus, you could should perform a little more paintings if whatever inthat header refers to JNIEnv.)Threads
All threads are Linux threads, scheduled by means of the kernel.They’re usuallystarted from managed code (using Thread.begin()),however they also can be created someplace else and then attached to the JavaVM.Forexample, a thread commenced with pthread_create() or std::threadcan be connected the use of the AttachCurrentThread() orAttachCurrentThreadAsDaemon() capabilities.Until a thread isattached, it has no JNIEnv, and can’t make JNI calls.
It’s generally great to apply Thread.begin() to create any thread that needs tocall in to Java code. Doing so will ensure which you have enough stack area, which you’rein the correct ThreadGroup, and which you’re using the same ClassLoaderas your Java code. It’s also simpler to set the thread’s call for debugging in Java than fromnative code (see pthread_setname_np() when you have a pthread_t orthread_t, and std::thread::native_handle() if you have astd::thread and want a pthread_t).
Attaching a natively-created thread causes a java.lang.Threadobject to be constructed and delivered to the “most important” ThreadGroup,making it seen to the debugger.Calling AttachCurrentThread()on an already-connected thread is a no-op.
Android does no longer droop threads executing native code.Ifgarbage series is in progress, or the debugger has issued a suspendrequest, Android will pause the thread the following time it makes a JNI name.
Threads attached through JNI have to callDetachCurrentThread() earlier than they exit.If coding this directly is awkward, in Android 2.zero (Eclair) and higher youcan use pthread_key_create() to outline a destructorfunction to be able to be called before the thread exits, andcall DetachCurrentThread() from there.(Use thatkey with pthread_setspecific() to shop the JNIEnv inthread-local-storage; that way it will be passed into your destructor asthe argument.)jclass, jmethodID, and jfieldID
If you need to get entry to an object’s discipline from local code, you would do the following: Get the magnificence object reference for the elegance with FindClass Get the sector ID for the field with GetFieldID Get the contents of the field with something suitable, such asGetIntField
Similarly, to call a technique, you would first get a class item reference after which a way ID.The IDs are often justpointers to inner runtime statistics structures.Looking them up may additionally require several stringcomparisons, but as soon as you’ve got them the actual name to get the sphere or invoke the methodis very short.
If overall performance is vital, it’s useful to look the values up once and cache the resultsin your native code.Because there may be a limit of one JavaVM per method, it’s reasonableto save this records in a static neighborhood structure.
The magnificence references, subject IDs, and method IDs are assured valid till the elegance is unloaded.Classesare most effective unloaded if all instructions associated with a ClassLoader can be garbage gathered,which is uncommon but will now not be impossible in Android.Note but thatthe jclassis a class reference and must be protected with a callto NewGlobalRef (see the following phase).
If you would really like to cache the IDs while a category is loaded, and automatically re-cache themif the class is ever unloaded and reloaded, the right manner to initializethe IDs is to add a bit of code that looks as if this to the appropriate elegance:Kotlinpartner object /** We use a static elegance initializer to permit the local code to cache some* field offsets. This local characteristic appears up and caches interesting* magnificence/area/approach IDs. Throws on failure.*/private outside fun nativeInit()init nativeInit()Java/** We use a class initializer to allow the native code to cache a few* discipline offsets. This local characteristic seems up and caches exciting* elegance/discipline/technique IDs. Throws on failure.*/non-public static native void nativeInit();static nativeInit();
Create a nativeClassInit method on your C/C++ code that plays the ID lookups.The codewill be completed as soon as, whilst the elegance is initialized.If the magnificence is ever unloaded andthen reloaded, it is going to be performed again.Local and global references
Every argument surpassed to a native method, and nearly each object returnedby a JNI characteristic is a “nearby reference”.This manner that it is legitimate for theduration of the cutting-edge native technique inside the current thread.Even if the object itself maintains to stay on after the local methodreturns, the reference isn’t legitimate.
This applies to all sub-instructions of jobject, includingjclass, jstring, and jarray.(The runtime will provide you with a warning approximately most reference mis-makes use of whilst prolonged JNIchecks are enabled.)
The simplest way to get non-local references is through the functionsNewGlobalRef and NewWeakGlobalRef.
If you want to keep directly to a reference for a longer duration, you must usea “worldwide” reference.The NewGlobalRef function takes thelocal reference as an issue and returns a worldwide one. The international reference is guaranteed to be legitimate till you callDeleteGlobalRef.