Merge "Docs: Updated 'NDK Apps Linking to Platform Libraries'" into nyc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
ab62c65da9
@@ -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 -> GetJavaVM from <jni.h>
|
||||
AndroidRuntime::getJNIEnv -> JavaVM::GetEnv or
|
||||
@@ -449,18 +669,24 @@ JavaVM::AttachCurrentThread from <jni.h>.
|
||||
</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 <sys/system_properties.h>
|
||||
</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>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user