Merge "Docs: Updated 'NDK Apps Linking to Platform Libraries'" into nyc-dev

This commit is contained in:
Adarsh Fernando
2016-06-15 03:43:14 +00:00
committed by Android (Google) Code Review

View File

@@ -378,70 +378,290 @@ see <a href="{@docRoot}training/secure-file-sharing/index.html">Sharing Files</a
<h2 id="ndk">NDK Apps Linking to Platform Libraries</h2>
<p>
Android N includes namespace changes to prevent loading of non-public APIs.
If you use the NDK, you should only be using public APIs from the Android
platform. Using non-public APIs in the next official release of Android
can cause your app to crash.
Starting in Android N, the system prevents apps from dynamically linking
against non-NDK libraries, which may cause your app to crash. This change in
behavior aims to create a consistent app experience across platform updates
and different devices. Even though your code might not be linking against
private libraries, it's possible that a third-party static library in your
app could be doing so. Therefore, all developers should check to make sure
that their apps do not crash on devices running Android N. If your app uses
native code, you should only be using <a href=
"{@docRoot}ndk/guides/stable_apis.html">public NDK APIs</a>.
</p>
<p>
In order to alert you to use of non-public APIs, apps running on an Android N
device generate an error in logcat output when an app calls a non-public API.
This error is also displayed on the device screen as a message to help
raise awareness of this situation. You should review your app code to
remove use of non-public platform APIs and thoroughly test your apps using
a preview device or emulator.
</p>
<p>
If your app depends on platform libraries, see the NDK documentation for
typical fixes for replacing common private APIs with public API equivalents.
You may also be linking to platform libraries without realizing it,
especially if your app uses a library that is part of the platform (such as
<code>libpng</code>), but is not part of the NDK. In that case, ensure that
your APK contains all the .so files you intended to link against.
</p>
<p class="caution">
<strong>Caution:</strong> Some third-party libraries may link to non-public
APIs. If your app uses these libraries, your app may crash when running
on the next official release of Android.
</p>
<p>
Apps should not depend on or use native libraries that are not included in
the NDK, because they may change, or be removed from one Android release to
another. The switch from OpenSSL to BoringSSL is an example of such a change.
Also, different devices may offer different levels of compatibility, because
there are no compatibility requirements for platform libraries not included
in the NDK. If you must access non-NDK libraries on older devices, make the
loading dependent on the Android API level.
</p>
<p>
To help you diagnose these types problems here are some example Java and NDK
errors you might encounter when attempting to build your app with Android N:
</p>
<p>Example Java error:</p>
<pre class="no-pretty-print">
java.lang.UnsatisfiedLinkError: dlopen failed: library "/system/lib/libcutils.so"
is not accessible for the namespace "classloader-namespace"
</pre>
<p>Example NDK error:</p>
<pre class="no-pretty-print">
dlopen failed: cannot locate symbol "__system_property_get" referenced by ...
</pre>
<p>
Here are some typical fixes for apps encountering these types of errors:
There are three ways your app might be trying to access private platform
APIs:
</p>
<ul>
<li>Use of getJavaVM and getJNIEnv from libandroid_runtime.so can be replaced
with standard JNI functions:
<li>Your app directly accesses private platform libraries. You should update
your app to include its own copy of those libraries or use the <a href=
"{@docRoot}ndk/guides/stable_apis.html">public NDK APIs</a>.
</li>
<li>Your app uses a third-party library that accesses private platform
libraries. Even if you are certain your app doesn't access private libraries
directly, you should still test your app for this scenario.
</li>
<li>Your app references a library that is not included in its APK. For
example, this could happen if you tried to use your own copy of OpenSSL but
forgot to bundle it with your app's APK. The app may run normally on versions
of Android platform that includes <code>libcrypto.so</code>. However, the app
could crash on later versions of Android that do not include this library
(such as, Android 6.0 and later). To fix this, ensure that you bundle all
your non-NDK libraries with your APK.
</li>
</ul>
<p>
Apps should not use native libraries that are not included in the NDK because
they may change or be removed between different versions of Android. The
switch from OpenSSL to BoringSSL is an example of such a change. Also,
because there are no compatibility requirements for platform libraries not
included in the NDK, different devices may offer different levels of
compatibility.
</p>
<p>
In order to reduce the impact that this restriction may have on currently
released apps, a set of libraries that see significant use—such as
<code>libandroid_runtime.so</code>, <code>libcutils.so</code>,
<code>libcrypto.so</code>, and <code>libssl.so</code>—are temporarily
accessible on N for apps targeting API level 23 or lower. If your app loads
one of these libraries, logcat generates a warning and a toast appears on the
target device to notify you. If you see these warnings, you should update
your app to either include its own copy of those libraries or only use the
public NDK APIs. Future releases of the Android platform may restrict the use
of private libraries altogether and cause your app to crash.
</p>
<p>
All apps generate a runtime error when they call an API that is neither
public nor temporarily accessible. The result is that
<code>System.loadLibrary</code> and <code>dlopen(3)</code> both return
<code>NULL</code>, and may cause your app to crash. You should review your
app code to remove use of private platform APIs and thoroughly test your apps
using a preview device or emulator. If you are unsure whether your app uses
private libraries, you can <a href="#ndk-errors">check logcat</a> to identify
the runtime error.
</p>
<p>
The following table describes the behavior you should expect to see from an
app depending on its use of private native libraries and its target API
level (<code>android:targetSdkVersion</code>).
</p>
<table id="ndk-table">
<col width="15%">
<col width="15%">
<col width="15%">
<col width="20%">
<col width="20%">
<col width="20%">
<tr>
<th scope="col">
Libraries
</th>
<th scope="col">
Target API level
</th>
<th scope="col">
Runtime access via dynamic linker
</th>
<th scope="col">
N Developer Preview behavior
</th>
<th scope="col">
Final N Release behavior
</th>
<th scope="col">
Future Android platform behavior
</th>
</tr>
<tr>
<td>
NDK Public
</td>
<td>
Any
</td>
<td style="background-color:#DCEDC8">
Accessible
</td>
<td style="background-color:#DCEDC8">
Works as expected
</td>
<td style="background-color:#DCEDC8">
Works as expected
</td>
<td style="background-color:#DCEDC8">
Works as expected
</td>
</tr>
<tr>
<td>
Private (temporarily accessible private libraries)
</td>
<td>
23 or lower
</td>
<td style="background-color:#FFF9C4">
Temporarily accessible
</td>
<td style="background-color:#FFF9C4">
Works as expected, but you receive a logcat warning and a message on the
target device.
</td>
<td style="background-color:#FFF9C4">
Works as expected, but you receive a logcat warning.
</td>
<td style="background-color:#ffcdd2">
Runtime error
</td>
</tr>
<tr>
<td>
Private (temporarily accessible private libraries)
</td>
<td>
24 or higher
</td>
<td style="background-color:#ffcdd2">
Restricted
</td>
<td style="background-color:#ffcdd2">
Runtime error
</td>
<td style="background-color:#ffcdd2">
Runtime error
</td>
<td style="background-color:#ffcdd2">
Runtime error
</td>
</tr>
<tr>
<td>
Private (other)
</td>
<td>
Any
</td>
<td style="background-color:#ffcdd2">
Restricted
</td>
<td style="background-color:#ffcdd2">
Runtime error
</td>
<td style="background-color:#ffcdd2">
Runtime error
</td>
<td style="background-color:#ffcdd2">
Runtime error
</td>
</tr>
</table>
<h3 id="ndk-errors">
Check if your app uses private libraries
</h3>
<p>
To help you identify issues loading private libraries, logcat may generate a
warning or runtime error. For example, if your app targets API level 23 or
lower, and tries to access a private library on a device running Android N,
you may see a warning similar to the following:
</p>
<pre class="no-pretty-print">
03-21 17:07:51.502 31234 31234 W linker : library "libandroid_runtime.so"
("/system/lib/libandroid_runtime.so") needed or dlopened by
"/data/app/com.popular-app.android-2/lib/arm/libapplib.so" is not accessible
for the namespace "classloader-namespace" - the access is temporarily granted
as a workaround for http://b/26394120
</pre>
<p>
These logcat warnings tell you which which library is trying to access a
private platform API, but will not cause your app to crash. If the app
targets API level 24 or higher, however, logcat generates the following
runtime error and your app may crash:
</p>
<pre class="no-pretty-print">
java.lang.UnsatisfiedLinkError: dlopen failed: library "libcutils.so"
("/system/lib/libcutils.so") needed or dlopened by
"/system/lib/libnativeloader.so" is not accessible for the namespace
"classloader-namespace"
at java.lang.Runtime.loadLibrary0(Runtime.java:977)
at java.lang.System.loadLibrary(System.java:1602)
</pre>
<p>
You may also see these logcat outputs if your app uses third-party libraries
that dynamically link to private platform APIs. The readelf tool in the
Android NDK allows you to generate a list of all dynamically linked shared
libraries of a given <code>.so</code> file by running the following command:
</p>
<pre class="no-pretty-print">
aarch64-linux-android-readelf -dW libMyLibrary.so
</pre>
<h3 id="ndk-update">
Update your app
</h3>
<p>
Here are some steps you can take to fix these types of errors and make
sure your app doesn't crash on future platform updates:
</p>
<ul>
<li>
If your app uses private platform libraries, you should update it to include
its own copy of those libraries or use the <a href=
"{@docRoot}ndk/guides/stable_apis.html">public NDK APIs</a>.
</li>
<li>
If your app uses a third-party library that accesses private symbols, contact
the library author to update the library.
</li>
<li>
Make sure you package all your non-NDK libraries with your APK.
</li>
<li>Use standard JNI functions instead of <code>getJavaVM</code> and
<code>getJNIEnv</code> from <code>libandroid_runtime.so</code>:
<pre class="no-pretty-print">
AndroidRuntime::getJavaVM -&gt; GetJavaVM from &lt;jni.h&gt;
AndroidRuntime::getJNIEnv -&gt; JavaVM::GetEnv or
@@ -449,18 +669,24 @@ JavaVM::AttachCurrentThread from &lt;jni.h&gt;.
</pre>
</li>
<li>Use of {@code property_get} symbol from {@code libcutils.so} can be
replaced with the public {@code alternative __system_property_get}.
To do this, use {@code __system_property_get} with the following include:
<li>Use {@code __system_property_get} instead of the private {@code property_get}
symbol from {@code libcutils.so}. To do this, use {@code __system_property_get}
with the following include:
<pre>
#include &lt;sys/system_properties.h&gt;
</pre>
<p class="note">
<strong>Note:</strong> The availability and contents of system properties is
not tested through CTS. A better fix would be to avoid using these
properties altogether.
</p>
</li>
<li>Use of {@code SSL_ctrl} symbol from {@code libcrypto.so} should be
replaced with an app local version. For example, you should statically link
{@code libcyrpto.a} in your {@code .so} file or include your own dynamically
{@code libcrypto.so} from BoringSSL or OpenSSL in your app.
<li>Use a local version of the {@code SSL_ctrl} symbol from {@code
libcrypto.so}. For example, you should statically link {@code libcyrpto.a} in
your {@code .so} file, or include a dynamically linked version of {@code
libcrypto.so} from BoringSSL/OpenSSL and package it in your APK.
</li>
</ul>