blob: 8a88222ee2a025c48f232210b0253e89b6bc7552 [file] [log] [blame]
page.title=Verifying App Behavior on the Android Runtime (ART)
@jd:body
<div id="qv-wrapper">
<div id="qv">
<h2>Quickview</h2>
<ul>
<li>The new Android runtime (ART) is available on some of the newest Android
devices, though all of them currently have Dalvik as the default
runtime.</li>
<li>App developers should make sure their apps are compatible with ART,
especially if you use JNI to run native code or if you use certain tools
that produce non-standard code (such as some obfuscators).</li>
</ul>
<h2 id="Contents">In this document</h2>
<ol>
<li><a href="#GC_Migration">Addressing Garbage Collection (GC) Issues</a></li>
<li><a href="#JNI_Issues">Preventing JNI Issues</a>
<ol>
<li><a href="#JNI_and_GC">Checking JNI code for garbage-collection
issues</a></li>
<li><a href="#Error_Handling">Error handling</a></li>
<li><a href="#Object_Model_Changes">Object model changes</a></li>
</ol>
</li>
<li><a href="#Stack_Size">Preventing Stack Size Issues</a></li>
<li><a href="#AOT_Fails">Fixing AOT Compilation Issues</a></li>
<li><a href="#Reporting_Problems">Reporting Problems</a></li>
</ol>
<h2>See also</h2>
<ol>
<li><a href="http://source.android.com/devices/tech/dalvik/art.html">Introducing ART</a></li>
<li><a
href="http://android-developers.blogspot.com/2011/07/debugging-android-jni-with-checkjni.html">Debugging
Android JNI with CheckJNI</a></li>
</ol>
</div>
</div>
<p>With Android 4.4, we are beginning to roll out a new Android runtime,
<strong>ART</strong>. This runtime offers a number of new features that improve
performance and smoothness of the Android platform and apps. (You can find more
information about ART's new features in <a
href="http://source.android.com/devices/tech/dalvik/art.html">Introducing
ART</a>.)</p>
<p>Currently, ART is available on a number of Android 4.4 devices, such as the
Nexus 4, Nexus 5, Nexus 7, and Google Play edition devices.
At this time, all devices still use Dalvik as the default runtime. We encourage
you to test your apps for ART compatibility and to take advantage of ART's new
features. However, for the time being, you should also take care to maintain
compatibility with Dalvik.</p>
<p>This document lets you know about things to watch for when migrating an
existing app to be compatible with ART. Most apps should just work when
running with ART. However, some techniques that work on Dalvik do not work on
ART. This document discusses some of these issues.</p>
<h2 id="GC_Migration">Addressing Garbage Collection (GC) Issues</h2>
<p>Under Dalvik, apps frequently find it useful to explicitly call {@link
java.lang.System#gc() System.gc()} to prompt garbage collection (GC). This should be
far less necessary with ART, particularly if you're invoking garbage collection
to prevent <a
href="{@docRoot}/tools/debugging/debugging-memory.html#LogMessages"><code>GC_FOR_ALLOC</code></a>-type
occurrences or to reduce fragmentation. You can verify which runtime is in use
by calling {@link java.lang.System#getProperty(java.lang.String)
System.getProperty("java.vm.version")}. If ART is in use, the property's value
is <code>"2.0.0"</code> or higher.</p>
<p>Furthermore, a compacting garbage collector is under development in the <a
href="https://source.android.com">Android Open-Source Project (AOSP)</a> to
improve memory management. Because of this, you should avoid using techniques
that are incompatible with compacting GC (such as saving pointers to object
instance data). This is particularly important for apps that make use of the
Java Native Interface (JNI). For more information, see <a
href="#JNI_Issues">Preventing JNI Issues</a>.</p>
<h2 id="JNI_Issues">Preventing JNI Issues</h2>
<p>ART's JNI is somewhat stricter than Dalvik's. It is an especially good idea
to use CheckJNI mode to catch common problems. If your app makes use of C/C++
code, you should review the following article:</p>
<p><a
href="http://android-developers.blogspot.com/2011/07/debugging-android-jni-with-checkjni.html">Debugging
Android JNI with CheckJNI</a></p>
<h3 id="JNI_and_GC">Checking JNI code for garbage-collection issues</h3>
<p>ART has a compacting garbage collector under development on the
Android Open Source Project (AOSP). Once the compacting garbage collector is in
use, objects may be moved in memory. If you use C/C++ code, do not
perform operations that are incompatible with compacting GC. We have enhanced
CheckJNI to identify some potential issues (as described in <a
href="http://android-developers.blogspot.com/2011/11/jni-local-reference-changes-in-ics.html">JNI
Local Reference Changes in ICS</a>).</p>
<p>One area to watch for in particular is the use of
<code>Get...ArrayElements()</code> and <code>Release...ArrayElements()</code>
functions. In runtimes with non-compacting GC, the
<code>Get...ArrayElements()</code> functions typically return a reference to the
actual memory backing the array object. If you make a change to one of the
returned array elements, the array object is itself changed (and the arguments
to <code>Release...ArrayElements()</code> are usually ignored). However, if
compacting GC is in use, the <code>Get...ArrayElements()</code> functions may
return a copy of the memory. If you misuse the reference when compacting GC is
in use, this can lead to memory corruption or other problems. For example:</p>
<ul>
<li>If you make any changes to the returned array elements, you must call the
appropriate <code>Release...ArrayElements()</code> function when you are done,
to make sure the changes you made are correctly copied back to the underlying
array object.</li>
<li>When you release the memory array elements, you must use the appropriate
mode, depending on what changes you made:
<ul>
<li>If you did not make any changes to the array elements, use
<code>JNI_ABORT</code> mode, which releases the memory without copying
changes back to the underlying array object.</li>
<li>If you made changes to the array, and do not need the reference any
more, use code <code>0</code> (which updates the array object and frees
the copy of the memory).</li>
<li>If you made changes to the array that you want to commit, and you want
to keep the copy of the array, use <code>JNI_COMMIT</code> (which updates
the underlying array object and retains the copy).</li>
</ul>
</li>
<li>When you call <code>Release...ArrayElements()</code>, return the same
pointer that was originally returned by <code>Get...ArrayElements()</code>. For
example, it's not safe to increment the original pointer (to scan through the
returned array elements) then pass the incremented pointer to
<code>Release...ArrayElements()</code>. Passing this modified pointer can cause
the wrong memory to be freed, resulting in memory corruption.</li>
</ul>
<h3 id="Error_Handling">Error handling</h3>
<p>ART's JNI throws errors in a number of cases where Dalvik didnt. (Once
again, you can catch many such cases by testing with CheckJNI.)</p>
<p>For example, if <code>RegisterNatives</code> is called with a method that
does not exist (perhaps because the method was removed by a tool such as
<strong>ProGuard</strong>), ART now properly throws {@link
java.lang.NoSuchMethodError}:</p>
<pre class="no-pretty-print">
08-12 17:09:41.082 13823 13823 E AndroidRuntime: FATAL EXCEPTION: main
08-12 17:09:41.082 13823 13823 E AndroidRuntime: java.lang.NoSuchMethodError:
no static or non-static method
"Lcom/foo/Bar;.native_frob(Ljava/lang/String;)I"
08-12 17:09:41.082 13823 13823 E AndroidRuntime:
at java.lang.Runtime.nativeLoad(Native Method)
08-12 17:09:41.082 13823 13823 E AndroidRuntime:
at java.lang.Runtime.doLoad(Runtime.java:421)
08-12 17:09:41.082 13823 13823 E AndroidRuntime:
at java.lang.Runtime.loadLibrary(Runtime.java:362)
08-12 17:09:41.082 13823 13823 E AndroidRuntime:
at java.lang.System.loadLibrary(System.java:526)
</pre>
<p>ART also logs an error (visible in logcat) if <code>RegisterNatives</code> is
called with no methods:</p>
<pre class="no-pretty-print">
W/art ( 1234): JNI RegisterNativeMethods: attempt to register 0 native
methods for &lt;classname>
</pre>
<p>In addition, the JNI functions <code>GetFieldID()</code> and
<code>GetStaticFieldID()</code> now properly throw {@link java.lang.NoSuchFieldError}
instead of simply returning null. Similarly, <code>GetMethodID()</code> and
<code>GetStaticMethodID()</code> now properly throw {@link java.lang.NoSuchMethodError}.
This can lead to CheckJNI failures because of the unhandled exceptions or the
exceptions being thrown to Java callers of native code. This makes it
particularly important to test ART-compatible apps with CheckJNI mode.</p>
<p>ART expects users of the JNI <code>CallNonvirtual...Method()</code> methods
(such as <code>CallNonvirtualVoidMethod()</code>) to use the method's declaring
class, not a subclass, as required by the JNI specification.</p>
<h2 id="Stack_Size">Preventing Stack Size Issues</h2>
<p>Dalvik had separate stacks for native and Java code, with a default Java
stack size of 32KB and a default native stack size of 1MB. ART has a unified
stack for better locality. Ordinarily, the ART {@link java.lang.Thread} stack
size should be approximately the same as for Dalvik. However, if you explicitly
set stack sizes, you may need to revisit those values for apps running in
ART.</p>
<ul>
<li>In Java, review calls to the {@link
java.lang.Thread#Thread(java.lang.ThreadGroup, java.lang.Runnable,
java.lang.String, long) Thread} constructor that specify an explicit stack
size. For example, you will need to increase the size if {@link
java.lang.StackOverflowError} occurs.</li>
<li>In C/C++, review use of <code>pthread_attr_setstack()</code> and
<code>pthread_attr_setstacksize()</code> for threads that also run Java code via
JNI. Here is an example of the error logged when an app attempts to call JNI
<code>AttachCurrentThread()</code> when the pthread size is too small:
<pre class="no-pretty-print">F/art: art/runtime/thread.cc:435]
Attempt to attach a thread with a too-small stack (16384 bytes)</pre>
</li>
</ul>
<h2 id="Object_Model_Changes">Object model changes</h2>
<p>Dalvik incorrectly allowed subclasses to override package-private methods.
ART issues a warning in such cases:</p>
<pre class="no-pretty-print">
Before Android 4.1, method void com.foo.Bar.quux()
would have incorrectly overridden the package-private method in
com.quux.Quux
</pre>
<p>If you intend to override a class's method in a different package, declare the
method as <code>public</code> or <code>protected</code>.</p>
<p>{@link java.lang.Object} now has private fields. Apps that reflect on fields
in their class hierarchies should be careful not to attempt to look at the
fields of {@link java.lang.Object}. For example, if you are iterating up a class
hierarchy as part of a serialization framework, stop when
<pre>Class.getSuperclass() == java.lang.Object.class</pre>
instead of continuing until the method returns <code>null</code>.</p>
<p>Proxy {@link
java.lang.reflect.InvocationHandler#invoke(java.lang.Object,java.lang.reflect.Method,java.lang.Object[])
InvocationHandler.invoke()} now receives <code>null</code> if there are no
arguments instead of an empty array. This behavior was documented previously but
not correctly handled in Dalvik. Previous versions of <a
href="https://code.google.com/p/mockito/">Mockito</a> have difficulties with
this, so use an updated Mockito version when testing with ART.</p>
<h2 id="AOT_Fails">Fixing AOT Compilation Issues</h2>
<p>ART's Ahead-Of-Time (AOT) Java compilation should work for all standard Java
code. Compilation is performed by ART's
<code>dex2oat</code> tool; if you encounter any issues related to
<code>dex2oat</code> at install time, let us know (see <a
href="#Reporting_Problems">Reporting Problems</a>) so we can fix them as quickly
as possible. A couple of issues to note:</p>
<ul>
<li>ART does tighter bytecode verification at install time than Dalvik does.
Code produced by the Android build tools should be fine. However, some
post-processing tools (especially tools that perform obfuscation) may produce
invalid files that are tolerated by Dalvik but rejected by ART. We have been
working with tool vendors to find and fix such issues. In many cases, getting
the latest versions of your tools and regenerating the DEX files can fix these
problems.</li>
<li>Some typical problems that are flagged by the ART verifier include:
<ul>
<li>invalid control flow</li>
<li>unbalanced <code>moniterenter</code>/<code>moniterexit</code></li>
<li>0-length parameter type list size</li>
</ul>
</li>
<li>Some apps have dependencies on the installed <code>.odex</code> file
format in <code>/system/framework</code>, <code>/data/dalvik-cache</code>, or
in {@link dalvik.system.DexClassLoader}’s optimized output directory. These
files are now ELF files and not an extended form of DEX files. While ART tries
to follow the same naming and locking rules as Dalvik, apps should not depend
on the file format; the format is subject to change without notice.</li>
<h2 id="Reporting_Problems">Reporting Problems</h2>
<p>If you run into any issues that arent due to app JNI issues, report
them via the Android Open Source Project Issue Tracker at <a
href="https://code.google.com/p/android/issues/list">https://code.google.com/p/android/issues/list</a>.
Include an <code>"adb bugreport"</code> and a link to the app in the Google
Play store if available. Otherwise, if possible, attach an APK that reproduces
the issue. Note that issues (including attachments) are publicly
visible.</p>