Per IRogers@ , you check the VM version by calling System.getProperty("java.vm.version") -- not, as previously documented, "dalvik.vm.version" (Ian says there's no such property as dalvik.vm.version.) BDC@ and/or AnwarG@, can you confirm? Revised doc is staged to: http://asolovay.mtv:9001/guide/practices/verifying-apps-art.html#GC_Migration bug: 15836664 Change-Id: Ie5e2e058fa9ce033afd18a0f4079faa81bbf317e
297 lines
14 KiB
Plaintext
297 lines
14 KiB
Plaintext
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 didn’t. (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 <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 aren’t 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>
|