Remove the jni-tips.html document. It contains too many swear words :-)
This commit is contained in:
@@ -1,512 +0,0 @@
|
||||
<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="#jclassID_jmethodID_and_jfieldID">jclassID, 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>
|
||||
</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 and C++ declarations of JNIEnv and JavaVM are different. "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="jclassID_jmethodID_and_jfieldID"> jclassID, 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. The jclassID
|
||||
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 jobject, including jclass and jarray.
|
||||
(Dalvik VM will warn you about this when -Xcheck:jni is 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:
|
||||
|
||||
<p><pre>jobject* localRef = [...];
|
||||
jobject* globalRef;
|
||||
globalRef = env->NewGlobalRef(localRef);
|
||||
</pre>
|
||||
|
||||
The global reference is guaranteed to be valid until you call
|
||||
<code>DeleteGlobalRef</code>.
|
||||
</p><p>
|
||||
All JNI methods accept both local and global references as arguments.
|
||||
</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 the thread
|
||||
is about to exit or detach.
|
||||
</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 pointers to primitive types 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>
|
||||
</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 accomplishes the same thing, with several advantages:
|
||||
<ul>
|
||||
<li>Requires one JNI call instead of 3, reducing overhead.
|
||||
<li>Doesn't require pinning or extra data copies.
|
||||
<li>Reduces the risk of programmer error -- no need to match up
|
||||
<code>Get</code> and <code>Release</code> calls.
|
||||
</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>
|
||||
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>SetFieldInt</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>
|
||||
Some VMs support extended checking with the "<code>-Xcheck:jni</code>" flag. If the flag is set, the VM
|
||||
puts a different table of functions into the JavaVM and JNIEnv pointers. These functions do
|
||||
an extended series of checks before calling the standard implementation.
|
||||
|
||||
</p><p>
|
||||
Some things that may be verified:
|
||||
</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> 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 valid "modified UTF-8" data.
|
||||
</li>
|
||||
</ul>
|
||||
<p>Accessibility of methods and fields (i.e. public vs. private) is not
|
||||
checked.
|
||||
<p>
|
||||
The Dalvik VM supports the <code>-Xcheck:jni</code> flag. For a
|
||||
description of how to enable it 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.
|
||||
<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 nativeClassInit().) 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_4) != JNI_OK)
|
||||
return -1;
|
||||
|
||||
/* get class with (*env)->FindClass */
|
||||
/* register methods with (*env)->RegisterNatives */
|
||||
|
||||
return JNI_VERSION_1_4;
|
||||
}
|
||||
</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 can get the full path to the
|
||||
application's private data storage area from the context object.
|
||||
</p><p>
|
||||
Dalvik does support "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), but this is a less desirable
|
||||
approach. 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>
|
||||
|
||||
|
||||
</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><code>NewWeakGlobalRef</code> and <code>DeleteWeakGlobalRef</code>
|
||||
are not implemented. The
|
||||
VM supports weak references, but not JNI "weak global" references.
|
||||
These will be supported in a future release.</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>
|
||||
|
||||
<address>Copyright © 2008 The Android Open Source Project</address>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user