The latest Android and Google Play news for app and game developers.
Posted by Dimitry Ivanov & Elliott Hughes, Software Engineers
As documented in the Android N
behavioral changes, to protect Android users and apps from unforeseen
crashes, Android N will restrict which libraries your C/C++ code can link
against at runtime. As a result, if your app uses any private symbols from
platform libraries, you will need to update it to either use the public NDK APIs
or to include its own copy of those libraries. Some libraries are public: the
NDK exposes libandroid, libc, libcamera2ndk, libdl,
libGLES, libjnigraphics, liblog, libm, libmediandk, libOpenMAXAL, libOpenSLES,
libstdc++, libvulkan, and libz as part of the NDK API. Other libraries are
private, and Android N only allows access to them for platform HALs, system
daemons, and the like. If you aren’t sure whether your app uses private
libraries, you can immediately check it for warnings on the N Developer Preview.
We’re making this change because it’s painful for users when their apps stop
working after a platform update. Whether they blame the app developer or the
platform, everybody loses. Users should have a consistent app experience across
updates, and developers shouldn’t have to make emergency app updates to handle
platform changes. For that reason, we recommend against using private C/C++
symbols. Private symbols aren’t tested as part of the Compatibility Test Suite
(CTS) that all Android devices must pass. They may not exist, or they may behave
differently. This makes apps that use them more likely to fail on specific
devices, or on future releases — as many developers found when Android 6.0
Marshmallow switched from OpenSSL to BoringSSL.
You may be surprised that there’s no STL in the list of NDK libraries. The three
STL implementations included in the NDK — the LLVM libc++, the GNU STL, and
libstlport — are intended to be bundled with your app, either by statically
linking into your library, or by inclusion as a separate shared library. In the
past, some developers have assumed that they didn’t need to package the library
because the OS itself had a copy. This assumption is incorrect: a particular STL
implementation may disappear (as was the case with stlport, which was removed in
Marshmallow), may never have been available (as is the case with the GNU STL),
or it may change in ABI incompatible ways (as is the case with the LLVM libc++).
In order to reduce the user impact of this transition, we’ve identified a set of
libraries that see significant use from Google Play’s most-installed apps, and
that are feasible for us to support in the short term (including
libandroid_runtime.so, libcutils.so, libcrypto.so, and libssl.so). For legacy
code in N, we will temporarily support these libraries in order to give you more
time to transition. Note that we don't intend to continue this support in any
future Android platform release, so if you see a warning that means your code
will not work in a future release — please fix it now!
Table 1. What to expect if your app is linking against private native libraries.
Please test your app during the N Previews.
Test your apps on the Developer Preview — if you see a toast like this one, your app is accessing private native APIs. Please fix your code soon!
Here’s some example logcat output from an app that hasn’t bumped its target SDK
version (and so the restriction isn’t fully enforced because this is only the
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
This is telling you that your library “libapplib.so” refers to the library
“libandroid_runtime.so”, which is a private library.
When Android N ships, or if you set your target SDK version to N now, you’ll see
something like this if you try to use System.loadLibrary from Java:
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"
If you’re using dlopen(3) from
C/C++ you’ll get a NULL return and dlerror(3) will
return the same “dlopen failed...” string as shown above.
For more information about how to check if your app is using private symbols,
see the FAQ on developer.android.com.