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>
|
<h2 id="ndk">NDK Apps Linking to Platform Libraries</h2>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Android N includes namespace changes to prevent loading of non-public APIs.
|
Starting in Android N, the system prevents apps from dynamically linking
|
||||||
If you use the NDK, you should only be using public APIs from the Android
|
against non-NDK libraries, which may cause your app to crash. This change in
|
||||||
platform. Using non-public APIs in the next official release of Android
|
behavior aims to create a consistent app experience across platform updates
|
||||||
can cause your app to crash.
|
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>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
In order to alert you to use of non-public APIs, apps running on an Android N
|
There are three ways your app might be trying to access private platform
|
||||||
device generate an error in logcat output when an app calls a non-public API.
|
APIs:
|
||||||
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:
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<li>Use of getJavaVM and getJNIEnv from libandroid_runtime.so can be replaced
|
<li>Your app directly accesses private platform libraries. You should update
|
||||||
with standard JNI functions:
|
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">
|
<pre class="no-pretty-print">
|
||||||
AndroidRuntime::getJavaVM -> GetJavaVM from <jni.h>
|
AndroidRuntime::getJavaVM -> GetJavaVM from <jni.h>
|
||||||
AndroidRuntime::getJNIEnv -> JavaVM::GetEnv or
|
AndroidRuntime::getJNIEnv -> JavaVM::GetEnv or
|
||||||
@@ -449,18 +669,24 @@ JavaVM::AttachCurrentThread from <jni.h>.
|
|||||||
</pre>
|
</pre>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li>Use of {@code property_get} symbol from {@code libcutils.so} can be
|
<li>Use {@code __system_property_get} instead of the private {@code property_get}
|
||||||
replaced with the public {@code alternative __system_property_get}.
|
symbol from {@code libcutils.so}. To do this, use {@code __system_property_get}
|
||||||
To do this, use {@code __system_property_get} with the following include:
|
with the following include:
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
#include <sys/system_properties.h>
|
#include <sys/system_properties.h>
|
||||||
</pre>
|
</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>
|
||||||
|
|
||||||
<li>Use of {@code SSL_ctrl} symbol from {@code libcrypto.so} should be
|
<li>Use a local version of the {@code SSL_ctrl} symbol from {@code
|
||||||
replaced with an app local version. For example, you should statically link
|
libcrypto.so}. For example, you should statically link {@code libcyrpto.a} in
|
||||||
{@code libcyrpto.a} in your {@code .so} file or include your own dynamically
|
your {@code .so} file, or include a dynamically linked version of {@code
|
||||||
{@code libcrypto.so} from BoringSSL or OpenSSL in your app.
|
libcrypto.so} from BoringSSL/OpenSSL and package it in your APK.
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user