@@ -205,14 +211,15 @@ to detach the thread soon.</p>
modified encoding is useful for C code because it encodes \u0000 as 0xc0 0x80 instead of 0x00.
The nice thing about this is that you can count on having C-style zero-terminated strings,
suitable for use with standard libc string functions. The down side is that you cannot pass
arbitrary UTF-8 data into the VM and expect it to work correctly.</p>
arbitrary UTF-8 data to JNI and expect it to work correctly.</p>
<p>It's usually best to operate with UTF-16 strings. With Android's current VMs, the
<code>GetStringChars</code> method
does not require a copy, whereas <code>GetStringUTFChars</code> requires a malloc and a UTF conversion. Note that
<p>If possible, it's usually faster to operate with UTF-16 strings. Android
currently does not require a copy in <code>GetStringChars</code>, whereas
<code>GetStringUTFChars</code> requires an allocation and a conversion to
UTF-8. Note that
<strong>UTF-16 strings are not zero-terminated</strong>, and \u0000 is allowed,
so you need to hang on to the string length as well as
the string pointer.</p>
the jchar pointer.</p>
<p><strong>Don't forget to <code>Release</code> the strings you <code>Get</code></strong>. The
string functions return <code>jchar*</code> or <code>jbyte*</code>, which
@@ -237,9 +244,8 @@ While arrays of objects must be accessed one entry at a time, arrays of
primitives can be read and written directly as if they were declared in C.</p>
<p>To make the interface as efficient as possible without constraining
the VM implementation,
the <code>Get<PrimitiveType>ArrayElements</code> family of calls
allows the VM to either return a pointer to the actual elements, or
the VM implementation, the <code>Get<PrimitiveType>ArrayElements</code>
family of calls allows the runtime to either return a pointer to the actual elements, or
allocate some memory and make a copy. Either way, the raw pointer returned
is guaranteed to be valid until the corresponding <code>Release</code> call
is issued (which implies that, if the data wasn't copied, the array object
@@ -253,7 +259,7 @@ non-NULL pointer for the <code>isCopy</code> argument. This is rarely
useful.</p>
<p>The <code>Release</code> call takes a <code>mode</code> argument that can
have one of three values. The actions performed by the VM depend upon
have one of three values. The actions performed by the runtime depend upon
whether it returned a pointer to the actual data or a copy of it:</p>
<ul>
@@ -312,8 +318,9 @@ to do is copy data in or out. Consider the following:</p>
}</pre>
<p>This grabs the array, copies the first <code>len</code> byte
elements out of it, and then releases the array. Depending upon the VM
policies the <code>Get</code> call will either pin or copy the array contents.
elements out of it, and then releases the array. Depending upon the
implementation, the <code>Get</code> call will either pin or copy the array
contents.
The code copies the data (for perhaps a second time), then calls <code>Release</code>; in this case
<code>JNI_ABORT</code> ensures there's no chance of a third copy.</p>
@@ -335,7 +342,7 @@ to copy data into an array, and <code>GetStringRegion</code> or
<a name="exceptions" id="exceptions"></a>
<h2>Exception</h2>
<h2>Exceptions</h2>
<p><strong>You must not call most JNI functions while an exception is pending.</strong>
Your code is expected to notice the exception (via the function's return value,
@@ -369,11 +376,11 @@ you call a method (using a function like <code>CallObjectMethod</code>),
you must always check for an exception, because the return value is not
going to be valid if an exception was thrown.</p>
<p>Note that exceptions thrown by interpreted code do not "leap over" native code,
and C++ exceptions thrown by native code are not handled by Dalvik.
<p>Note that exceptions thrown by interpreted code do not unwind native stack
frames, and Android does not yet support C++ exceptions.
The JNI <code>Throw</code> and <code>ThrowNew</code> instructions just
set an exception pointer in the current thread. Upon returning to the VM from
native code, the exception will be noted and handled appropriately.</p>
set an exception pointer in the current thread. Upon returning to managed
from native code, the exception will be noted and handled appropriately.</p>
<p>Native code can "catch" an exception by calling <code>ExceptionCheck</code> or
<code>ExceptionOccurred</code>, and clear it with
@@ -476,23 +483,19 @@ written in C++:</p>
shared library. For Android apps, you may find it useful to get the full
path to the application's private data storage area from the context object.</p>
<p>This is the recommended approach, but not the only approach. The VM does
not require explicit registration, nor that you provide a
<p>This is the recommended approach, but not the only approach. Explicit
registration is not required, nor is it necessary that you provide a
<code>JNI_OnLoad</code> function.
You can instead use "discovery" of native methods that are named in a
specific way (see <a href="http://java.sun.com/javase/6/docs/technotes/guides/jni/spec/design.html#wp615">
the JNI spec</a> for details), though this is less desirable.
It requires more space in the shared object symbol table,
loading is slower because it requires string searches through all of the
loaded shared libraries, and if a method signature is wrong you won't know
specific way (see <a href="http://java.sun.com/javase/6/docs/technotes/guides/jni/spec/design.html#wp615">the JNI spec</a> for details), though this is less desirable because if a method signature is wrong you won't know
about it until the first time the method is actually used.</p>
<p>One other note about <code>JNI_OnLoad</code>: any <code>FindClass</code>
calls you make from there will happen in the context of the class loader
that was used to load the shared library. Normally <code>FindClass</code>
uses the loader associated with the method at the top of the interpreted
stack, or if there isn't one (because the thread was just attached to
the VM) it uses the "system" class loader. This makes
stack, or if there isn't one (because the thread was just attached) it uses
the "system" class loader. This makes
<code>JNI_OnLoad</code> a convenient place to look up and cache class
object references.</p>
@@ -515,10 +518,9 @@ that use 64-bit pointers, <strong>you need to stash your native pointers in a
<p>All JNI 1.6 features are supported, with the following exceptions:</p>
<ul>
<li><code>DefineClass</code> is not implemented. Dalvik does not use
<li><code>DefineClass</code> is not implemented. Android does not use
Java bytecodes or class files, so passing in binary class data
doesn't work. Translation facilities may be added in a future
version of the VM.</li>
doesn't work.</li>
<li>"Weak global" references are implemented, but may only be passed
to <code>NewLocalRef</code>, <code>NewGlobalRef</code>, and
<code>DeleteWeakGlobalRef</code>. (The spec strongly encourages
@@ -536,12 +538,16 @@ that use 64-bit pointers, <strong>you need to stash your native pointers in a
around this requires using explicit registration or moving the
native methods out of inner classes.
<li>Until Android 2.0 (Eclair), it was not possible to use a <code>pthread_key_create</code>
destructor function to avoid the VM's "thread must be detached before
exit" check. (The VM also uses a pthread key destructor function,
destructor function to avoid the "thread must be detached before
exit" check. (The runtime also uses a pthread key destructor function,
so it'd be a race to see which gets called first.)
<li>Until Android 2.2 (Froyo), weak global references were not implemented.
Older VMs will vigorously reject attempts to use them. You can use
Older versions will vigorously reject attempts to use them. You can use
the Android platform version constants to test for support.
<li>Until Android 4.0 (Ice Cream Sandwich), JNI local references were
actually direct pointers. Ice Cream Sandwich added the indirection
necessary to support better garbage collectors, but this means that lots
of JNI bugs are undetectable on older releases.
</ul>
@@ -572,8 +578,8 @@ the details of the failure can be found in the exception's detail message.</p>
<p>In logcat, you'll see:</p>
<pre>W/dalvikvm( 880): No implementation found for native LFoo;.myfunc ()V</pre>
<p>This means that the VM tried to find a matching method but was unsuccessful.
Some common reasons for this are:</p>
<p>This means that the runtime tried to find a matching method but was
unsuccessful. Some common reasons for this are:</p>
<ul>
<li>The library isn't getting loaded. Check the logcat output for
messages about library loading.
@@ -581,10 +587,15 @@ Some common reasons for this are:</p>
is commonly caused by:
<ul>
<li>For lazy method lookup, failing to declare C++ functions
with <code>extern "C"</code>. You can use <code>arm-eabi-nm</code>
with <code>extern "C"</code> and appropriate
visibility (<code>JNIEXPORT</code>). Note that prior to Ice Cream
Sandwich, the JNIEXPORT macro was incorrect, so using a new GCC with
an old <code>jni.h</code> won't work.
You can use <code>arm-eabi-nm</code>
to see the symbols as they appear in the library; if they look
mangled (something like <code>_Z15Java_Foo_myfuncP7_JNIEnvP7_jclass</code>
rather than <code>Java_Foo_myfunc</code>) then you need to
rather than <code>Java_Foo_myfunc</code>), or if the symbol type is
a lowercase 't' rather than an uppercase 'T', then you need to
adjust the declaration.
<li>For explicit registration, minor errors when entering the
method signature. Make sure that what you're passing to the
@@ -612,7 +623,7 @@ must also wrap the class with 'L' and ';', so a one-dimensional array of
<p>If the class name looks right, you could be running into a class loader
issue. <code>FindClass</code> wants to start the class search in the
class loader associated with your code. It examines the VM call stack,
class loader associated with your code. It examines the call stack,
which will look something like:
<pre> Foo.myfunc(Native Method)
Foo.main(Foo.java:10)
@@ -623,14 +634,14 @@ finds the <code>ClassLoader</code> object associated with the <code>Foo</code>
class and uses that.</p>
<p>This usually does what you want. You can get into trouble if you
create a thread outside the VM (perhaps by calling <code>pthread_create</code>
and then attaching it to the VM with <code>AttachCurrentThread</code>).
create a thread yourself (perhaps by calling <code>pthread_create</code>
and then attaching it with <code>AttachCurrentThread</code>).