-
Notifications
You must be signed in to change notification settings - Fork 6
Initialization
JNI can operate in 2 modes:
- Native code loaded from Java
- Java VM loaded from native code The first scenario is by far the most common, but SimpleJNI can work in either. In both case SimpleJNI needs to be properly initialized. Doing so is easy but is important to get it, especially the error handling part right. If you haven't already done so please read Error Handling section that explain how SimpleJNI reports errors in general. In either scenario SimpleJNI initialization consists of two parts
- Initialize SimpleJNI underlying machinery
- Initialize any SimpleJNI global data, most notably
java_class_table
(see Representing Java Classes) The two parts differ in how you can react to any exceptions reported. if there is any exception reported at stage 1 you cannot use SimpleJNI to handle it. After all it hadn't successfully been initialized. At stage 2 you can use the same error handling facilities as you do elsewhere. SimpleJNI itself is available.
The stage 1 initialization consist of at least the following calls
JavaVM * vm = ...;
//Initialize jni_provider.
jni_provider::init(vm);
//Now we can get JNIEnv anywhere
JNIEnv * env = jni_provider::get_jni();
//Initialize core Java support
java_runtime::init(env);
The stage 2 initialization is usually an initialization of java_class_table
as described in Representing Java Classes
When JNI shared library is loaded code JNI calls JNI_OnLoad
exported function where your code can initialize itself. SimpleJNI is best initialized there too. Note that JNI_OnLoad
can fail, including failing with Java exception, that will be reported to Java code attempting to load your library. The general structure of JNI_OnLoad
should be along these lines.
typedef java_class_table<...> java_classes;
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)
{
try
{
jni_provider::init(vm);
JNIEnv * env = jni_provider::get_jni();
java_runtime::init(env);
try
{
//Let's load everything we need
java_classes::init(env);
return JNI_VERSION_1_6;
}
catch(java_exception & ex)
{
//pass any Java exception back to Java
ex.raise(env);
}
catch(std::exception & ex)
{
//Translate any other error
//This will use built-in translation. This is fine for simple cases
//but for more complicated scenarios you might want to write your
//own translation logic
java_exception::translate(env, ex);
}
}
catch(std::exception & ex)
{
//If we are here there is no way to communicate with
//Java - something really bad happened.
//Let's just log and report failure
__android_log_print(ANDROID_LOG_ERROR, "mystuff", "%s\n", ex.what());
}
return 0;
}
The example above uses Android's __android_log_print
for failure logging. Substitute as needed for your environment.
When you load Java VM from native code yourself the flow is similar to the one above. Your loading will produce JavaVM *
that you can use as above. The only difference is that there is no Java code above to report exception so you are probably better off doing uniform error handling.
JavaVM * vm = ...;
try
{
jni_provider::init(vm);
JNIEnv * env = jni_provider::get_jni();
java_runtime::init(env);
//Let's load everything we need
java_classes::init(env);
}
catch(std::exception & ex)
{
//alternatively let the exception terminate the process
fprintf(stderr, "%s\n", ex.what());
abort();
}
- Building
-
User's Guide
Declaring Java Types
Accessing Methods and Fields
Representing Java Classes
Implementing Native Methods
Smart References
Error Handling
Obtaining JNIEnv
Initialization
Strings
Arrays
Direct Buffers
Booleans
Sizes -
JniGen Code Generator
Integrating JniGen
Annotations
Processor Options