From f243343c18602b5be7c467ad629816227b0a447d Mon Sep 17 00:00:00 2001
From: Elliott Hughes
You really should read through the -JNI spec for J2SE 1.6 +JNI spec for J2SE 6 to get a sense for how JNI works and what features are available. Some aspects of the interface aren't immediately obvious on first reading, so you may find the next few sections handy. @@ -48,8 +48,9 @@ The more detailed JNI Programmer's Guide and Specification can be found
JNI defines two key data structures, "JavaVM" and "JNIEnv". Both of these are essentially -pointers to pointers to function tables. (In the C++ version, it's a class whose sole member -is a pointer to a function table.) The JavaVM provides the "invocation interface" functions, +pointers to pointers to function tables. (In the C++ version, they're classes with a +pointer to a function table and a member function for each JNI function that indirects through +the table.) The JavaVM provides the "invocation interface" functions, which allow you to create and destroy the VM. In theory you can have multiple VMs per process, but Android's VM only allows one.
@@ -58,7 +59,7 @@ the first argument.On some VMs, the JNIEnv is used for thread-local storage. For this reason, you cannot share a JNIEnv between threads. If a piece of code has no other way to get its JNIEnv, you should share -the JavaVM, and use JavaVM->GetEnv to discover the thread's JNIEnv.
+the JavaVM, and use JavaVM->GetEnv to discover the thread's JNIEnv. (Assuming it has one; seeAttachCurrentThread
below.)
The C declarations of JNIEnv and JavaVM are different from the C++ declarations. "jni.h" provides different typedefs @@ -90,7 +91,7 @@ request, the VM will pause the thread the next time it makes a JNI call.
Threads attached through JNI must call
DetachCurrentThread
before they exit.
-If coding this directly is awkward, in Android >= 2.0 you
+If coding this directly is awkward, in Android >= 2.0 ("Eclair") you
can use pthread_key_create
to define a destructor
function that will be called before the thread exits, and
call DetachCurrentThread
from there. (Use that
@@ -98,6 +99,7 @@ key with pthread_setspecific
to store the JNIEnv in
thread-local-storage; that way it'll be passed into your destructor as
the argument.)
Create a nativeClassInit method in your C/C++ code that performs the ID lookups. The code will be executed once, when the class is initialized. If the class is ever unloaded and then reloaded, it will be executed again. (See the implementation of java.io.FileDescriptor @@ -324,7 +326,7 @@ to do is copy data in or out. Consider the following:
memcpy(buffer, data, len); env->ReleaseByteArrayElements(array, data, JNI_ABORT); } - +This grabs the array, copies the first len
byte
elements out of it, and then releases the array. Depending upon the VM
policies the Get
call will either pin or copy the array contents.
@@ -334,7 +336,7 @@ we use JNI_ABORT
so there's no chance of a third copy.
We can accomplish the same thing with this:
env->GetByteArrayRegion(array, 0, len, buffer);- +
This has several advantages:
DeleteWeakGlobalRef
. (The spec strongly encourages
programmers to create hard references to weak globals before doing
anything with them, so this should not be at all limiting.)GetObjectRefType
(new in 1.6) is implemented but not fully
+ GetObjectRefType
(new in JNI 1.6) is implemented but not fully
functional — it can't always tell the difference between "local" and
"global" references.For backward compatibility, you may need to be aware of:
pthread_key_create
+ pthread_key_create
destructor function to avoid the VM's "thread must be detached before
exit" check. (The VM also uses a pthread key destructor function,
so it'd be a race to see which gets called first.)
- Native code is primarily useful when you have an existing native codebase that you want to port to Android, not for "speeding up" parts of a Java app.
-We have JNI Tips for -more about JNI on Android.
+If you do need to use native code, you should read our +JNI Tips.
(See also Effective Java item 54.)
-- cgit v1.1