Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 931974b4 authored by Adarsh Fernando's avatar Adarsh Fernando
Browse files

Docs: Updated 'NDK Apps Linking to Platform Libraries'

- updated compatibility with future platform releases
- expanded on ways to dignose and debug

Bug: 29215157
Change-Id: Ie63d024eac9914d4553419c734132696fb94d7e5
parent 189ef624
Loading
Loading
Loading
Loading
+273 −47
Original line number Diff line number Diff line
@@ -370,70 +370,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.
  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 -&gt; GetJavaVM from &lt;jni.h&gt;
AndroidRuntime::getJNIEnv -&gt; JavaVM::GetEnv or
@@ -441,18 +661,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>