<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.
+ There are three ways your app might be trying to access private platform
+ APIs:
</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>
+<ul>
+ <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>
-<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>
+ <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>
- 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.
+ 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>
- 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:
+ 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>
-<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"
+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>Example NDK error:</p>
+<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">
-dlopen failed: cannot locate symbol "__system_property_get" referenced by ...
+aarch64-linux-android-readelf -dW libMyLibrary.so
</pre>
+<h3 id="ndk-update">
+ Update your app
+</h3>
<p>
- Here are some typical fixes for apps encountering these types of errors:
+ 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>Use of getJavaVM and getJNIEnv from libandroid_runtime.so can be replaced
- with standard JNI functions:
+ <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
</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>