| <html> |
| <head> |
| <title>Android JNI Tips</title> |
| <link rel=stylesheet href="android.css"> |
| </head> |
| |
| <body> |
| <h1><a name="JNI_Tips"></a>Android JNI Tips</h1> |
| <p> |
| </p><p> |
| </p><ul> |
| <li> <a href="#What_s_JNI_">What's JNI?</a> |
| </li> |
| <li> <a href="#JavaVM_and_JNIEnv">JavaVM and JNIEnv</a> |
| |
| </li> |
| <li> <a href="#jclass_jmethodID_and_jfieldID">jclass, jmethodID, and jfieldID</a> |
| </li> |
| <li> <a href="#local_vs_global_references">Local vs. Global References</a> |
| </li> |
| <li> <a href="#UTF_8_and_UTF_16_strings">UTF-8 and UTF-16 Strings</a> |
| </li> |
| <li> <a href="#Arrays">Primitive Arrays</a> |
| </li> |
| <li> <a href="#RegionCalls">Region Calls</a> |
| </li> |
| <li> <a href="#Exceptions">Exceptions</a> |
| </li> |
| |
| <li> <a href="#Extended_checking">Extended Checking</a> |
| </li> |
| <li> <a href="#Native_Libraries">Native Libraries</a> |
| </li> |
| <li> <a href="#64bit">64-bit Considerations</a> |
| </li> |
| |
| <li> <a href="#Unsupported">Unsupported Features</a> |
| </li> |
| |
| <li> <a href="#FAQUnsatisfied">FAQ: UnsatisfiedLinkError</a> |
| </li> |
| <li> <a href="#FAQFindClass">FAQ: FindClass didn't find my class</a> |
| </li> |
| <li> <a href="#FAQSharing">FAQ: Sharing raw data with native code</a> |
| </li> |
| |
| </ul> |
| <p> |
| <noautolink> |
| </noautolink></p><p> |
| </p><h2><a name="What_s_JNI_"> </a> What's JNI? </h2> |
| <p> |
| |
| JNI is the Java Native Interface. It defines a way for code written in the |
| Java programming language to interact with native |
| code, e.g. functions written in C/C++. It's VM-neutral, has support for loading code from |
| dynamic shared libraries, and while cumbersome at times is reasonably efficient. |
| </p><p> |
| You really should read through the |
| <a href="http://java.sun.com/javase/6/docs/technotes/guides/jni/spec/jniTOC.html">JNI spec for J2SE 1.6</a> |
| 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. |
| The more detailed <i>JNI Programmer's Guide and Specification</i> can be found |
| <a href="http://java.sun.com/docs/books/jni/html/jniTOC.html">here</a>. |
| </p><p> |
| </p><p> |
| </p><h2><a name="JavaVM_and_JNIEnv"> </a> JavaVM and JNIEnv </h2> |
| <p> |
| 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, |
| which allow you to create and destroy the VM. In theory you can have multiple VMs per process, |
| but Android's VMs only allow one. |
| </p><p> |
| The JNIEnv provides most of the JNI functions. Your native functions all receive a JNIEnv as |
| the first argument. |
| </p><p> |
| |
| On some VMs, the JNIEnv is used for thread-local storage. For this reason, <strong>you cannot share a JNIEnv between threads</strong>. |
| 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. |
| </p><p> |
| The C declarations of JNIEnv and JavaVM are different from the C++ |
| declarations. "jni.h" provides different typedefs |
| depending on whether it's included into ".c" or ".cpp". For this reason it's a bad idea to |
| include JNIEnv arguments in header files included by both languages. (Put another way: if your |
| header file requires "#ifdef __cplusplus", you may have to do some extra work if anything in |
| that header refers to JNIEnv.) |
| </p><p> |
| </p><p> |
| </p><h2><a name="jclass_jmethodID_and_jfieldID"> jclass, jmethodID, and jfieldID </a></h2> |
| <p> |
| If you want to access an object's field from native code, you would do the following: |
| </p><p> |
| </p><ul> |
| <li> Get the class object reference for the class with <code>FindClass</code> |
| </li> |
| <li> Get the field ID for the field with <code>GetFieldID</code> |
| </li> |
| <li> Get the contents of the field with something appropriate, e.g. |
| <code>GetIntField</code> |
| </li> |
| </ul> |
| <p> |
| Similarly, to call a method, you'd first get a class object reference and then a method ID. The IDs are often just |
| pointers to internal VM data structures. Looking them up may require several string |
| comparisons, but once you have them the actual call to get the field or invoke the method |
| is very quick. |
| </p><p> |
| If performance is important, it's useful to look the values up once and cache the results |
| in your native code. Because we are limiting ourselves to one VM per process, it's reasonable |
| to store this data in a static local structure. |
| </p><p> |
| The class references, field IDs, and method IDs are guaranteed valid until the class is unloaded. Classes |
| are only unloaded if all classes associated with a ClassLoader can be garbage collected, |
| which is rare but will not be impossible in our system. Note however that |
| the <code>jclass</code> |
| is a class reference and <strong>must be protected</strong> with a call |
| to <code>NewGlobalRef</code> (see the next section). |
| </p><p> |
| If you would like to cache the IDs when a class is loaded, and automatically re-cache them |
| if the class is ever unloaded and reloaded, the correct way to initialize |
| the IDs is to add a piece of code that looks like this to the appropriate class: |
| </p><p> |
| |
| </p><pre> /* |
| * We use a class initializer to allow the native code to cache some |
| * field offsets. |
| */ |
| |
| /* |
| * A native function that looks up and caches interesting |
| * class/field/method IDs for this class. Returns false on failure. |
| */ |
| native private static boolean nativeClassInit(); |
| |
| /* |
| * Invoke the native initializer when the class is loaded. |
| */ |
| static { |
| if (!nativeClassInit()) |
| throw new RuntimeException("native init failed"); |
| } |
| </pre> |
| <p> |
| 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 |
| for an example in our source tree.) |
| </p><p> |
| </p><p> |
| </p><p> |
| </p><h2><a name="local_vs_global_references"> Local vs. Global References </a></h2> |
| <p> |
| Every object that JNI returns is a "local reference". This means that it's valid for the |
| duration of the current native method in the current thread. |
| <strong>Even if the object itself continues to live on after the native method returns, the reference is not valid.</strong> |
| This applies to all sub-classes of <code>jobject</code>, including |
| <code>jclass</code>, <code>jstring</code>, and <code>jarray</code>. |
| (Dalvik VM will warn you about most reference mis-uses when extended JNI |
| checks are enabled.) |
| </p><p> |
| |
| If you want to hold on to a reference for a longer period, you must use |
| a "global" reference. The <code>NewGlobalRef</code> function takes the |
| local reference as an argument and returns a global one. |
| The global reference is guaranteed to be valid until you call |
| <code>DeleteGlobalRef</code>. |
| |
| </p><p> |
| This pattern is commonly used when caching copies of class objects obtained |
| from <code>FindClass</code>, e.g.: |
| <p><pre>jclass* localClass = env->FindClass("MyClass"); |
| jclass* globalClass = (jclass*) env->NewGlobalRef(localClass); |
| </pre> |
| |
| </p><p> |
| All JNI methods accept both local and global references as arguments. |
| It's possible for references to the same object to have different values; |
| for example, the return values from consecutive calls to |
| <code>NewGlobalRef</code> on the same object may be different. |
| <strong>To see if two references refer to the same object, |
| you must use the <code>IsSameObject</code> function.</strong> Never compare |
| references with "==" in native code. |
| </p><p> |
| One consequence of this is that you |
| <strong>must not assume object references are constant or unique</strong> |
| in native code. The 32-bit value representing an object may be different |
| from one invocation of a method to the next, and it's possible that two |
| different objects could have the same 32-bit value on consecutive calls. Do |
| not use <code>jobject</code> values as keys. |
| </p><p> |
| Programmers are required to "not excessively allocate" local references. In practical terms this means |
| that if you're creating large numbers of local references, perhaps while running through an array of |
| Objects, you should free them manually with |
| <code>DeleteLocalRef</code> instead of letting JNI do it for you. The |
| VM is only required to reserve slots for |
| 16 local references, so if you need more than that you should either delete as you go or use |
| <code>EnsureLocalCapacity</code> to reserve more. |
| </p><p> |
| Note: method and field IDs are just 32-bit identifiers, not object |
| references, and should not be passed to <code>NewGlobalRef</code>. The raw data |
| pointers returned by functions like <code>GetStringUTFChars</code> |
| and <code>GetByteArrayElements</code> are also not objects. |
| </p><p> |
| One unusual case deserves separate mention. If you attach a native |
| thread to the VM with AttachCurrentThread, the code you are running will |
| never "return" to the VM until the thread detaches from the VM. Any local |
| references you create will have to be deleted manually unless you're going |
| to detach the thread soon. |
| </p><p> |
| </p><p> |
| </p><p> |
| </p><h2><a name="UTF_8_and_UTF_16_strings"> </a> UTF-8 and UTF-16 Strings </h2> |
| <p> |
| The Java programming language uses UTF-16. For convenience, JNI provides methods that work with "modified UTF-8" encoding |
| as well. (Some VMs use the modified UTF-8 internally to store strings; ours do not.) The |
| modified encoding only supports the 8- and 16-bit forms, and stores ASCII NUL values in a 16-bit encoding. |
| The nice thing about it 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><p> |
| It's usually best to operate with UTF-16 strings. With our 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 |
| <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><p> |
| <strong>Don't forget to Release the strings you Get</strong>. The |
| string functions return <code>jchar*</code> or <code>jbyte*</code>, which |
| are C-style pointers to primitive data rather than local references. They |
| are guaranteed valid until Release is called, which means they are not |
| released when the native method returns. |
| </p><p> |
| <strong>Data passed to NewStringUTF must be in "modified" UTF-8 format</strong>. A |
| common mistake is reading character data from a file or network stream |
| and handing it to <code>NewStringUTF</code> without filtering it. |
| Unless you know the data is 7-bit ASCII, you need to strip out high-ASCII |
| characters or convert them to proper "modified" UTF-8 form. If you don't, |
| the UTF-16 conversion will likely not be what you expect. The extended |
| JNI checks will scan strings and warn you about invalid data, but they |
| won't catch everything. |
| </p><p> |
| </p><p> |
| |
| |
| </p><h2><a name="Arrays"> </a> Primitive Arrays </h2> |
| <p> |
| JNI provides functions for accessing the contents of array objects. |
| 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 |
| 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 |
| will be pinned down and can't be relocated as part of compacting the heap). |
| <strong>You must Release every array you Get.</strong> Also, if the Get |
| call fails, you must ensure that your code doesn't try to Release a NULL |
| pointer later. |
| </p><p> |
| You can determine whether or not the data was copied by passing in a |
| 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 |
| whether it returned a pointer to the actual data or a copy of it: |
| <ul> |
| <li><code>0</code> |
| <ul> |
| <li>Actual: the array object is un-pinned. |
| <li>Copy: data is copied back. The buffer with the copy is freed. |
| </ul> |
| <li><code>JNI_COMMIT</code> |
| <ul> |
| <li>Actual: does nothing. |
| <li>Copy: data is copied back. The buffer with the copy |
| <strong>is not freed</strong>. |
| </ul> |
| <li><code>JNI_ABORT</code> |
| <ul> |
| <li>Actual: the array object is un-pinned. Earlier |
| writes are <strong>not</strong> aborted. |
| <li>Copy: the buffer with the copy is freed; any changes to it are lost. |
| </ul> |
| </ul> |
| </p><p> |
| One reason for checking the <code>isCopy</code> flag is to know if |
| you need to call <code>Release</code> with <code>JNI_COMMIT</code> |
| after making changes to an array — if you're alternating between making |
| changes and executing code that uses the contents of the array, you may be |
| able to |
| skip the no-op commit. Another possible reason for checking the flag is for |
| efficient handling of <code>JNI_ABORT</code>. For example, you might want |
| to get an array, modify it in place, pass pieces to other functions, and |
| then discard the changes. If you know that JNI is making a new copy for |
| you, there's no need to create another "editable" copy. If JNI is passing |
| you the original, then you do need to make your own copy. |
| </p><p> |
| Some have asserted that you can skip the <code>Release</code> call if |
| <code>*isCopy</code> is false. This is not the case. If no copy buffer was |
| allocated, then the original memory must be pinned down and can't be moved by |
| the garbage collector. |
| </p><p> |
| Also note that the <code>JNI_COMMIT</code> flag does NOT release the array, |
| and you will need to call <code>Release</code> again with a different flag |
| eventually. |
| </p><p> |
| </p><p> |
| |
| |
| </p><h2><a name="RegionCalls"> Region Calls </a></h2> |
| |
| <p> |
| There is an alternative to calls like <code>Get<Type>ArrayElements</code> |
| and <code>GetStringChars</code> that may be very helpful when all you want |
| to do is copy data in or out. Consider the following: |
| <pre> |
| jbyte* data = env->GetByteArrayElements(array, NULL); |
| if (data != NULL) { |
| memcpy(buffer, data, len); |
| env->ReleaseByteArrayElements(array, data, JNI_ABORT); |
| } |
| </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. |
| We copy the data (for perhaps a second time), then call Release; in this case |
| we use <code>JNI_ABORT</code> so there's no chance of a third copy. |
| </p><p> |
| We can accomplish the same thing with this: |
| <pre> |
| env->GetByteArrayRegion(array, 0, len, buffer); |
| </pre> |
| </p><p> |
| This has several advantages: |
| <ul> |
| <li>Requires one JNI call instead of 2, reducing overhead. |
| <li>Doesn't require pinning or extra data copies. |
| <li>Reduces the risk of programmer error — no risk of forgetting |
| to call <code>Release</code> after something fails. |
| </ul> |
| </p><p> |
| Similarly, you can use the <code>Set<Type>ArrayRegion</code> call |
| to copy data into an array, and <code>GetStringRegion</code> or |
| <code>GetStringUTFRegion</code> to copy characters out of a |
| <code>String</code>. |
| |
| |
| </p><h2><a name="Exceptions"> Exceptions </a></h2> |
| <p> |
| <strong>You may 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, |
| <code>ExceptionCheck()</code>, or <code>ExceptionOccurred()</code>) and return, |
| or clear the exception and handle it. |
| </p><p> |
| The only JNI functions that you are allowed to call while an exception is |
| pending are: |
| <font size="-1"><ul> |
| <li>DeleteGlobalRef |
| <li>DeleteLocalRef |
| <li>DeleteWeakGlobalRef |
| <li>ExceptionCheck |
| <li>ExceptionClear |
| <li>ExceptionDescribe |
| <li>ExceptionOccurred |
| <li>MonitorExit |
| <li>PopLocalFrame |
| <li>PushLocalFrame |
| <li>Release<PrimitiveType>ArrayElements |
| <li>ReleasePrimitiveArrayCritical |
| <li>ReleaseStringChars |
| <li>ReleaseStringCritical |
| <li>ReleaseStringUTFChars |
| </ul></font> |
| </p><p> |
| Many JNI calls can throw an exception, but often provide a simpler way |
| of checking for failure. For example, if <code>NewString</code> returns |
| a non-NULL value, you don't need to check for an exception. However, if |
| 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. |
| 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><p> |
| Native code can "catch" an exception by calling <code>ExceptionCheck</code> or |
| <code>ExceptionOccurred</code>, and clear it with |
| <code>ExceptionClear</code>. As usual, |
| discarding exceptions without handling them can lead to problems. |
| </p><p> |
| There are no built-in functions for manipulating the Throwable object |
| itself, so if you want to (say) get the exception string you will need to |
| find the Throwable class, look up the method ID for |
| <code>getMessage "()Ljava/lang/String;"</code>, invoke it, and if the result |
| is non-NULL use <code>GetStringUTFChars</code> to get something you can |
| hand to printf or a LOG macro. |
| |
| </p><p> |
| </p><p> |
| </p><h2><a name="Extended_checking"> Extended Checking </a></h2> |
| <p> |
| JNI does very little error checking. Calling <code>SetIntField</code> |
| on an Object field will succeed, even if the field is marked |
| <code>private</code> and <code>final</code>. The |
| goal is to minimize the overhead on the assumption that, if you've written it in native code, |
| you probably did it for performance reasons. |
| </p><p> |
| In Dalvik, you can enable additional checks by setting the |
| "<code>-Xcheck:jni</code>" flag. If the flag is set, the VM directs |
| the JavaVM and JNIEnv pointers to a different table of functions. |
| These functions perform an extended series of checks before calling the |
| standard implementation. |
| |
| </p><p> |
| The additional tests include: |
| </p><p> |
| </p> |
| <ul> |
| <li> Check for null pointers where not allowed. |
| </li> |
| <li> Verify argument type correctness (jclass is a class object, |
| jfieldID points to field data, jstring is a java.lang.String). |
| </li> |
| <li> Field type correctness, e.g. don't store a HashMap in a String field. |
| </li> |
| <li> Ensure jmethodID is appropriate when making a static or virtual |
| method call. |
| </li> |
| <li> Check to see if an exception is pending on calls where pending exceptions are not legal. |
| </li> |
| <li> Check for calls to inappropriate functions between Critical get/release calls. |
| </li> |
| <li> Check that JNIEnv structs aren't being shared between threads. |
| |
| </li> |
| <li> Make sure local references aren't used outside their allowed lifespan. |
| </li> |
| <li> UTF-8 strings contain only valid "modified UTF-8" data. |
| </li> |
| </ul> |
| <p>Accessibility of methods and fields (i.e. public vs. private) is not |
| checked. |
| <p> |
| For a description of how to enable CheckJNI for Android apps, see |
| <a href="embedded-vm-control.html">Controlling the Embedded VM</a>. |
| It's currently enabled by default in the Android emulator and on |
| "engineering" device builds. |
| |
| </p><p> |
| JNI checks can be modified with the <code>-Xjniopts</code> command-line |
| flag. Currently supported values include: |
| </p> |
| <blockquote><dl> |
| <dt>forcecopy |
| <dd>When set, any function that can return a copy of the original data |
| (array of primitive values, UTF-16 chars) will always do so. The buffers |
| are over-allocated and surrounded with a guard pattern to help identify |
| code writing outside the buffer, and the contents are erased before the |
| storage is freed to trip up code that uses the data after calling Release. |
| This will have a noticeable performance impact on some applications. |
| <dt>warnonly |
| <dd>By default, JNI "warnings" cause the VM to abort. With this flag |
| it continues on. |
| </dl></blockquote> |
| |
| |
| </p><p> |
| </p><h2><a name="Native_Libraries"> Native Libraries </a></h2> |
| <p> |
| You can load native code from shared libraries with the standard |
| <code>System.loadLibrary()</code> call. The |
| preferred way to get at your native code is: |
| </p><p> |
| </p><ul> |
| <li> Call <code>System.loadLibrary()</code> from a static class |
| initializer. (See the earlier example, where one is used to call |
| <code>nativeClassInit()</code>.) The argument is the "undecorated" |
| library name, e.g. to load "libfubar.so" you would pass in "fubar". |
| |
| </li> |
| <li> Provide a native function: <code><strong>jint JNI_OnLoad(JavaVM* vm, void* reserved)</strong></code> |
| </li> |
| <li>In <code>JNI_OnLoad</code>, register all of your native methods. You |
| should declare |
| the methods "static" so the names don't take up space in the symbol table |
| on the device. |
| </li> |
| </ul> |
| <p> |
| The <code>JNI_OnLoad</code> function should look something like this if |
| written in C: |
| </p><blockquote><pre>jint JNI_OnLoad(JavaVM* vm, void* reserved) |
| { |
| JNIEnv* env; |
| if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_6) != JNI_OK) |
| return -1; |
| |
| /* get class with (*env)->FindClass */ |
| /* register methods with (*env)->RegisterNatives */ |
| |
| return JNI_VERSION_1_6; |
| } |
| </pre></blockquote> |
| </p><p> |
| You can also call <code>System.load()</code> with the full path name of the |
| 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 |
| <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 |
| 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 |
| <code>JNI_OnLoad</code> a convenient place to look up and cache class |
| object references. |
| </p><p> |
| |
| |
| </p><h2><a name="64bit"> 64-bit Considerations </a></h2> |
| |
| <p> |
| Android is currently expected to run on 32-bit platforms. In theory it |
| could be built for a 64-bit system, but that is not a goal at this time. |
| For the most part this isn't something that you will need to worry about |
| when interacting with native code, |
| but it becomes significant if you plan to store pointers to native |
| structures in integer fields in an object. To support architectures |
| that use 64-bit pointers, <strong>you need to stash your native pointers in a |
| <code>long</code> field rather than an <code>int</code></strong>. |
| |
| |
| </p><h2><a name="Unsupported"> Unsupported Features </a></h2> |
| <p>All JNI 1.6 features are supported, with the following exceptions: |
| <ul> |
| <li><code>DefineClass</code> is not implemented. Dalvik 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> |
| <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 |
| programmers to create hard references to weak globals before doing |
| anything with them, so this should not be at all limiting.)</li> |
| <li><code>GetObjectRefType</code> (new in 1.6) is implemented but not fully |
| functional — it can't always tell the difference between "local" and |
| "global" references.</li> |
| </ul> |
| |
| <p>For backward compatibility, you may need to be aware of: |
| <ul> |
| <li>Until 2.0 ("Eclair"), the '$' character was not properly |
| converted to "_00024" during searches for method names. Working |
| around this requires using explicit registration or moving the |
| native methods out of inner classes. |
| <li>"Weak global" references were not implemented until 2.2 ("Froyo"). |
| Older VMs will vigorously reject attempts to use them. You can use |
| the Android platform version constants to test for support. |
| </ul> |
| |
| |
| </p><h2><a name="FAQUnsatisfied"> FAQ: UnsatisfiedLinkError </a></h2> |
| <p> |
| When working on native code it's not uncommon to see a failure like this: |
| <pre>java.lang.UnsatisfiedLinkError: Library foo not found</pre> |
| <p> |
| In some cases it means what it says — the library wasn't found. In |
| other cases the library exists but couldn't be opened by dlopen(), and |
| the details of the failure can be found in logcat. For example: |
| <pre>D/dalvikvm( 870): Trying to load lib /sdcard/libfoo.so 0x4001ff48 |
| I/dalvikvm( 870): Unable to dlopen(/sdcard/libfoo.so): Cannot load library: /sdcard/libfoo.so is not a valid ELF object |
| </pre> |
| <p> |
| Common reasons why you might encounter "library not found" exceptions: |
| <ul> |
| <li>The library doesn't exist or isn't accessible to the app. Use |
| <code>adb shell ls -l <path></code> to check its presence |
| and permissions. |
| <li>The library wasn't built with the NDK. This can result in |
| dependencies on functions or libraries that don't exist on the device. |
| </ul> |
| </p><p> |
| Another class of <code>UnsatisfiedLinkError</code> failures looks like: |
| <pre>java.lang.UnsatisfiedLinkError: myfunc |
| at Foo.myfunc(Native Method) |
| at Foo.main(Foo.java:10)</pre> |
| <p> |
| In logcat, you'll see: |
| <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: |
| <ul> |
| <li>The library isn't getting loaded. Check the logcat output for |
| messages about library loading. |
| <li>The method isn't being found due to a name or signature mismatch. This |
| 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> |
| to see the symbols as they appear in the library; if they look |
| mangled (e.g. <code>_Z15Java_Foo_myfuncP7_JNIEnvP7_jclass</code> |
| rather than <code>Java_Foo_myfunc</code>) 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 |
| registration call matches the signature in the log file. |
| Remember that 'B' is <code>byte</code> and 'Z' is <code>boolean</code>. |
| Class name components in signatures start with 'L', end with ';', |
| use '/' to separate package/class names, and use '$' to separate |
| inner-class names |
| (e.g. <code>Ljava/util/Map$Entry;</code>). |
| </ul> |
| </ul> |
| <p> |
| Using <code>javah</code> to automatically generate JNI headers may help |
| avoid some problems. |
| |
| |
| </p><h2><a name="FAQFindClass"> FAQ: FindClass didn't find my class </a></h2> |
| <p> |
| Make sure that the class name string has the correct format. JNI class |
| names start with the package name and are separated with slashes, |
| e.g. <code>java/lang/String</code>. If you're looking up an array class, |
| you need to start with the appropriate number of square brackets and |
| must also wrap the class with 'L' and ';', so a one-dimensional array of |
| <code>String</code> would be <code>[Ljava/lang/String;</code>. |
| </p><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, |
| which will look something like: |
| <pre> Foo.myfunc(Native Method) |
| Foo.main(Foo.java:10) |
| dalvik.system.NativeStart.main(Native Method)</pre> |
| <p> |
| The topmost method is <code>Foo.myfunc</code>. <code>FindClass</code> |
| 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>). |
| Now the stack trace looks like this: |
| <pre> dalvik.system.NativeStart.run(Native Method)</pre> |
| <p> |
| The topmost method is <code>NativeStart.run</code>, which isn't part of |
| your application. If you call <code>FindClass</code> from this thread, the |
| VM will start in the "system" class loader instead of the one associated |
| with your application, so attempts to find app-specific classes will fail. |
| </p><p> |
| There are a few ways to work around this: |
| <ul> |
| <li>Do your <code>FindClass</code> lookups once, in |
| <code>JNI_OnLoad</code>, and cache the class references for later |
| use. Any <code>FindClass</code> calls made as part of executing |
| <code>JNI_OnLoad</code> will use the class loader associated with |
| the function that called <code>System.loadLibrary</code> (this is a |
| special rule, provided to make library initialization more convenient). |
| If your app code is loading the library, <code>FindClass</code> |
| will use the correct class loader. |
| <li>Pass an instance of the class into the functions that need |
| it, e.g. declare your native method to take a Class argument and |
| then pass <code>Foo.class</code> in. |
| <li>Cache a reference to the <code>ClassLoader</code> object somewhere |
| handy, and issue <code>loadClass</code> calls directly. This requires |
| some effort. |
| </ul> |
| |
| </p><p> |
| |
| |
| </p><h2><a name="FAQSharing"> FAQ: Sharing raw data with native code </a></h2> |
| <p> |
| You may find yourself in a situation where you need to access a large |
| buffer of raw data from code written in Java and C/C++. Common examples |
| include manipulation of bitmaps or sound samples. There are two |
| basic approaches. |
| </p><p> |
| You can store the data in a <code>byte[]</code>. This allows very fast |
| access from code written in Java. On the native side, however, you're |
| not guaranteed to be able to access the data without having to copy it. In |
| some implementations, <code>GetByteArrayElements</code> and |
| <code>GetPrimitiveArrayCritical</code> will return actual pointers to the |
| raw data in the managed heap, but in others it will allocate a buffer |
| on the native heap and copy the data over. |
| </p><p> |
| The alternative is to store the data in a direct byte buffer. These |
| can be created with <code>java.nio.ByteBuffer.allocateDirect</code>, or |
| the JNI <code>NewDirectByteBuffer</code> function. Unlike regular |
| byte buffers, the storage is not allocated on the managed heap, and can |
| always be accessed directly from native code (get the address |
| with <code>GetDirectBufferAddress</code>). Depending on how direct |
| byte buffer access is implemented in the VM, accessing the data from code |
| written in Java can be very slow. |
| </p><p> |
| The choice of which to use depends on two factors: |
| <ol> |
| <li>Will most of the data accesses happen from code written in Java |
| or in C/C++? |
| <li>If the data is eventually being passed to a system API, what form |
| must it be in? (For example, if the data is eventually passed to a |
| function that takes a byte[], doing processing in a direct |
| <code>ByteBuffer</code> might be unwise.) |
| </ol> |
| If there's no clear winner, use a direct byte buffer. Support for them |
| is built directly into JNI, and access to them from code written in |
| Java can be made faster with VM improvements. |
| </p> |
| |
| <address>Copyright © 2008 The Android Open Source Project</address> |
| |
| </body> |
| </html> |