Along with new features and capabilities, Android 7.0 includes a variety of system and API behavior changes. This document highlights some of the key changes that you should understand and account for in your apps.
If you have previously published an app for Android, be aware that your app might be affected by these changes in the platform.
Android 7.0 includes system behavior changes aimed at improving the battery life of devices and reducing RAM usage. These changes can affect your app’s access to system resources, along with the way your app interacts with other apps via certain implicit intents.
Introduced in Android 6.0 (API level 23), Doze improves battery life by deferring CPU and network activities when a user leaves a device unplugged, stationary, and with the screen turned off. Android 7.0 brings further enhancements to Doze by applying a subset of CPU and network restrictions while the device is unplugged with the screen turned off, but not necessarily stationary, for example, when a handset is traveling in a user’s pocket.
When a device is on battery power, and the screen has been off for a certain
time, the device enters Doze and applies the first subset of restrictions: It
shuts off app network access, and defers jobs and syncs. If the device is
stationary for a certain time after entering Doze, the system applies the
rest of the Doze restrictions to
AlarmManager alarms, GPS, and Wi-Fi scans. Regardless of
whether some or all Doze restrictions are being applied, the system wakes the
device for brief maintenance windows, during which applications are allowed
network access and can execute any deferred jobs/syncs.
Note that activating the screen on or plugging in the device exits Doze and removes these processing restrictions. The additional behavior does not affect recommendations and best practices in adapting your app to the prior version of Doze introduced in Android 6.0 (API level 23), as discussed in Optimizing for Doze and App Standby. You should still follow those recommendations, such as using Google Cloud Messaging (GCM) to send and receive messages, and start planning updates to accomodate the additional Doze behavior.
Android 7.0 removes three implicit broadcasts in order to help optimize both memory use and power consumption. This change is necessary because implicit broadcasts frequently start apps that have registered to listen for them in the background. Removing these broadcasts can substantially benefit device performance and user experience.
Mobile devices experience frequent connectivity changes, such as when moving
between Wi-Fi and mobile data. Currently, apps can monitor for changes in
connectivity by registering a receiver for the implicit
CONNECTIVITY_ACTION broadcast in their
manifest. Since many apps register to receive this broadcast, a single
network switch can cause them all to wake up and process the broadcast at
Similarly, in previous versions of Android, apps could register to receive implicit
ACTION_NEW_VIDEO broadcasts from other apps, such as
Camera. When a user takes a picture with the Camera app, these apps wake up
to process the broadcast.
To alleviate these issues, Android 7.0 applies the following optimizations:
CONNECTIVITY_ACTIONbroadcasts, even if they have manifest entries to request notification of these events. Apps that are running can still listen for
CONNECTIVITY_CHANGEon their main thread if they request notification with a
ACTION_NEW_VIDEObroadcasts. This optimization affects all apps, not only those targeting Android 7.0.
If your app uses any of these intents, you should remove dependencies
on them as soon as possible so that you can target Android 7.0 devices properly.
The Android framework provides several solutions to mitigate the need for
these implicit broadcasts. For example, the
JobScheduler API provides a robust mechanism to schedule
network operations when specified conditions, such as connection to an
unmetered network, are met. You can even use
JobScheduler to react to changes to content providers.
For more information about background optimizations in N and how to adapt your app, see Background Optimizations.
Android 7.0 includes changes to permissions that may affect your app.
In order to improve the security of private files, the private directory of
apps targeting Android 7.0 or higher has restricted access (
This setting prevents leakage of metadata of private files, such as their size
or existence. This permission change has multiple side effects:
MODE_WORLD_WRITEABLE, will trigger a
Note: As of yet, this restriction is not fully enforced.
Apps may still modify permissions to their private directory using
native APIs or the
File API. However, we strongly
discourage relaxing the permissions to the private directory.
file://URIs outside the package domain may leave the receiver with an unaccessible path. Therefore, attempts to pass a
file://URI trigger a
FileUriExposedException. The recommended way to share the content of a private file is using the
DownloadManagercan no longer share privately stored files by filename. Legacy applications may end up with an unaccessible path when accessing
COLUMN_LOCAL_FILENAME. Apps targeting Android 7.0 or higher trigger a
SecurityExceptionwhen attempting to access
COLUMN_LOCAL_FILENAME. Legacy applications that set the download location to a public location by using
DownloadManager.Request.setDestinationInExternalPublicDir()can still access the path in
COLUMN_LOCAL_FILENAME, however, this method is strongly discouraged. The preferred way of accessing a file exposed by the
For apps targeting Android 7.0, the Android framework enforces
StrictMode API policy that prohibits exposing
outside your app. If an intent containing a file URI leaves your app, the app fails
To share files between applications, you should send a
and grant a temporary access permission on the URI. The easiest way to grant this permission is by
FileProvider class. For more information
on permissions and sharing files,
see Sharing Files.
Android 7.0 includes changes intended to improve the usability of the platform for users with low or impaired vision. These changes should generally not require code changes in your app, however you should review these feature and test them with your app to assess potential impacts to user experience.
Android 7.0 enables users to set Display sizewhich magnifies or shrinks all elements on the screen, thereby improving device accessibility for users with low vision. Users cannot zoom the screen past a minimum screen width of sw320dp, which is the width of a Nexus 4, a common medium-sized phone.
When the device density changes, the system notifies running apps in the following ways:
Most apps do not need to make any changes to support this feature, provided the apps follow Android best practices. Specific things to check for:
sw320dpand be sure it performs adequately.
Note: If you cache configuration-dependent data, it's a good idea to include relevant metadata such as the appropriate screen size or pixel density for that data. Saving this metadata allows you to decide whether you need to refresh the cached data after a configuration change.
Android 7.0 includes Vision Settings on the Welcome screen, where users can set up the following accessibility settings on a new device: Magnification gesture, Font size, Display size and TalkBack. This change increases the visibility of bugs related to different screen settings. To assess the impact of this feature, you should test your apps with these settings enabled. You can find the settings under Settings > Accessibility.
Starting in Android 7.0, 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 7.0. If your app uses native code, you should only be using public NDK APIs.
There are three ways your app might be trying to access private platform APIs:
libcrypto.so. 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.
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.
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
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.
All apps generate a runtime error when they call an API that is neither
public nor temporarily accessible. The result is that
dlopen(3) both return
NULL, 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 check logcat to identify
the runtime error.
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
|Libraries||Target API level||Runtime access via dynamic linker||N Developer Preview behavior||Final N Release behavior||Future Android platform behavior|
|NDK Public||Any||Accessible||Works as expected||Works as expected||Works as expected|
|Private (temporarily accessible private libraries)||23 or lower||Temporarily accessible||Works as expected, but you receive a logcat warning and a message on the target device.||Works as expected, but you receive a logcat warning.||Runtime error|
|Private (temporarily accessible private libraries)||24 or higher||Restricted||Runtime error||Runtime error||Runtime error|
|Private (other)||Any||Restricted||Runtime error||Runtime error||Runtime error|
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 7.0, you may see a warning similar to the following:
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
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:
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)
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 7.0DK allows you to generate a list of all dynamically linked shared
libraries of a given
.so file by running the following command:
aarch64-linux-android-readelf -dW libMyLibrary.so
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:
AndroidRuntime::getJavaVM -> GetJavaVM from <jni.h> AndroidRuntime::getJNIEnv -> JavaVM::GetEnv or JavaVM::AttachCurrentThread from <jni.h>.
__system_property_getinstead of the private
libcutils.so. To do this, use
__system_property_getwith the following include:
Note: The availability and contents of system properties is not tested through CTS. A better fix would be to avoid using these properties altogether.
libcrypto.so. For example, you should statically link
.sofile, or include a dynamically linked version of
libcrypto.sofrom BoringSSL/OpenSSL and package it in your APK.
Android 7.0 contains changes for apps that target Android for Work, including changes to certificate installation, password resetting, secondary user management, and access to device identifiers. If you are building apps for Android for Work environments, you should review these changes and modify your app accordingly.
DevicePolicyManager.setCertInstallerPackage(). If the installer is not already installed, the system throws an
DevicePolicyManager.resetPassword()to clear passwords or change ones that are already set. Device admins can still set a password, but only when the device has no password, PIN, or pattern.
DISALLOW_MODIFY_ACCOUNTSuser restrictions are in place.
DISALLOW_ADD_USERrestriction is automatically set. This prevents users from creating unmanaged secondary users. In addition, the
createAndInitializeUser()methods are deprecated; the new
DevicePolicyManager.createAndManageUser()method replaces them.
DevicePolicyManagewr.getWifiMacAddress(). If Wi-Fi has never been enabled on the device, this method returns a value of
KeyChain.getCertificateChain()when apps attempt to retrieve the client certificate chain later. If required, the CA certificate should be installed to the trusted credentials storage via Settings UI separately, with a DER-encoded format under a .crt or .cer file extension.
ENCRYPTION_STATUS_ACTIVE_PER_USERis returned by
DevicePolicyManager.getStorageEncryptionStatus(), to indicate that encryption is active and the encryption key is tied to the user. The new status is only returned if DPC targets API Level 24 and above. For apps targeting earlier API levels,
ENCRYPTION_STATUS_ACTIVEis returned, even if the encryption key is specific to the user or profile.
DevicePolicyManager.getParentProfileInstance()documentation.) For example,
DevicePolicyManager.lockNow()locks just the work profile, instead of locking the entire device. For each of these methods, you can get the old behavior by calling the method on the parent instance of the
DevicePolicyManager; you can get this parent by calling
DevicePolicyManager.getParentProfileInstance(). So for example, if you call the parent instance's
lockNow()method, the entire device is locked.
For more information about changes to Android for Work in Android 7.0, see Android for Work Updates.
Android 7.0 fixes a bug where the visibility of annotations was being ignored. This issue enabled the runtime to access annotations that it should not have been able to. These annotations included:
VISIBILITY_BUILD: Intended to be visible only at build time.
VISIBILITY_SYSTEM: Intended to be visible at runtime, but only to the underlying system.
If your app has relied on this behavior, please add a retention policy to annotations that must
be available at runtime. You do so by using
You should test your app to ensure that this behavior does not occur. You can do so by causing an identical crash when killing the app manually via DDMS.
Apps targeting N and above are not automatically killed on density changes; however, they may still respond poorly to configuration changes.
android.os.NetworkOnMainThreadException. Generally, performing network operations on the main thread is a bad idea because these operations usually have a high tail latency that causes ANRs and jank.
Debug.startMethodTracing()family of methods now defaults to storing output in your package-specific directory on shared storage, instead of at the top level of the SD card. This means apps no longer need to request the
WRITE_EXTERNAL_STORAGEpermission to use these APIs.
Bindertransactions, and the system now rethrows
RuntimeExceptions, instead of silently logging or suppressing them. One common example is storing too much data in
Activity.onSaveInstanceState(), which causes
ActivityThread.StopInfoto throw a
RuntimeExceptionwhen your app targets Android 7.0.
Runnabletasks to a
View, and the
Viewis not attached to a window, the system queues the
Runnabletask with the
Runnabletask does not execute until the
Viewis attached to a window. This behavior fixes the following bugs:
DELETE_PACKAGESpermission tries to delete a package, but a different app had installed that package, the system requires user confirmation. In this scenario, apps should expect
STATUS_PENDING_USER_ACTIONas the return status when they invoke