In addition to providing many new features and functionality, Android 7.0 also makes a variety of changes to system and API behavior. This article highlights some of the major changes you should be aware of and consider when developing your application.
If you've previously published an Android app, be aware that your app may be affected by these platform changes.
Battery and memory
Android 7.0 includes system behavior changes designed to extend device battery life and reduce RAM usage. These changes may affect your app's access to system resources and how your app interacts with other apps through a specific implicit intent.
Low power consumption mode
Android 6.0 (API level 23) introduces a low-power mode that delays CPU and network activity when the user device is unplugged, in a stationary state, and the screen is turned off, prolonging battery life. While Android 7.0 uses some CPU and network restrictions when the device is unplugged and the screen is off, but not necessarily in a stationary state (such as when the user is out of the bag in the pocket), further enhancing the low power consumption mode.
Figure 1. How low power consumption mode applies the first-level system activity limit to extend the battery life of the illustration.
When the device is charging and the screen is off for a certain amount of time, the device enters low-power mode and applies the first part of the limit: Turn off app network access, postpone jobs, and synchronize. If the device is stationary for a certain amount of time after entering low-power mode, the system will PowerManager.WakeLock AlarmManager apply the remaining low-power mode limits for the alarm, GPS, and WLAN scans. The system wakes up the device to provide a short maintenance window, whether the application part or all low power mode limits, during which the application can access the network and perform any deferred jobs/synchronizations.
Figure 2. How low-Power mode applies a diagram of the second-level system activity limit after the device has reached a standstill for a certain amount of time.
Note that when you activate the screen or plug-in the device, the system exits low-power mode and removes these processing restrictions. This new behavior does not affect recommendations and best practices for adapting your app to the older versions of low power consumption models introduced in Android 6.0 (API level 23), as discussed in targeted optimizations for low-power mode and application Standby mode. You should still follow these recommendations, such as using Google cloud Messaging (GCM) to send and receive messages, and start scheduling update plans to accommodate the new low-power mode behavior.
Project Svelte: Background optimization
Android 7.0 removes three implicit broadcasts to help optimize memory usage and power consumption. This change is necessary because implicit broadcasts frequently start applications that are registered to listen for these broadcasts in the background. Removing these broadcasts can significantly improve device performance and user experience.
Mobile devices experience frequent connection changes, such as when switching between Wi-Fi and mobile data. Currently, you can listen to implicit broadcasts by registering a receiver in the app manifest to CONNECTIVITY_ACTION enable the app to monitor these changes. Because many applications register to receive this broadcast, a single network switchover can cause all apps to wake up and process the broadcast at the same time.
Similarly, in previous versions of Android, apps could register to receive implicit and broadcast from other apps, such as cameras ACTION_NEW_PICTURE ACTION_NEW_VIDEO . When a user takes a photo using the camera app, the apps are awakened to process the broadcast.
To mitigate these problems, Android 7.0 has the following optimizations applied:
- Apps developed for Android 7.0 don't receive
CONNECTIVITY_ACTION broadcasts, even if they already have a manifest entry to request notification of these events. Apps that run in the foreground BroadcastReceiver can still listen in the main thread if they are receiving notifications using a request CONNECTIVITY_CHANGE .
- Apps cannot be sent or received
ACTION_NEW_PICTURE or ACTION_NEW_VIDEO broadcast. This optimization affects all applications, not just Android 7.0-oriented apps.
If your app uses any intent, you still need to remove their dependencies as soon as possible to properly fit the Android 7.0 device. The Android framework provides multiple solutions to mitigate the need for these implicit broadcasts. For example, the JobScheduler API provides a robust mechanism to schedule network operations that meet specified conditions, such as connecting to an infinite traffic network. You can even use it JobScheduler to adapt to changes in the content provider.
For more information about background optimizations in Android N and how to overwrite apps, see background optimizations.
Permission changes
Android 7.0 has made some permissions changes that may affect your app.
System Permissions Change
To improve the security of private files, the app Private directory for Android 7.0 or later is restricted access ( 0700 ). This setting prevents the metadata disclosure of private files, such as their size or existence. This permission change has multiple side effects:
- File permissions for private files should no longer be relaxed by the owner, and
MODE_WORLD_READABLE such attempts to use and/or are MODE_WORLD_WRITEABLE triggered SecurityException .Note : So far, this limitation has not yet been fully implemented. Apps may still use native APIs or File APIs to modify their private directory permissions. However, we strongly oppose the privilege of relaxing a private directory.
- A URI that passes the outside of the package domain
file:// may leave an unreachable path to the sink. Therefore, the attempt to pass the file:// URI is triggered FileUriExposedException . The recommended way to share private file content is to use FileProvider .
DownloadManagerPrivate stored files are no longer shared by file name. Legacy apps may have inaccessible COLUMN_LOCAL_FILENAME paths when they visit. Apps that target Android 7.0 or later are triggered when they try to access COLUMN_LOCAL_FILENAME it SecurityException . DownloadManager.Request.setDestinationInExternalFilesDir()legacy apps that use or DownloadManager.Request.setDestinationInExternalPublicDir() set the download location to a common location can still access COLUMN_LOCAL_FILENAME paths in, but we strongly oppose using this approach. For DownloadManager files that are exposed by, the preferred way of access is to use ContentResolver.openFileDescriptor() .
To share files between apps
For Android 7.0-oriented apps, the Android framework enforces an StrictMode API policy that prohibits exposing URIs outside your app file:// . If a intent that contains a file URI leaves your app, the app fails with an FileUriExposedException exception.
To share files between apps, you should send a content:// URI and grant temporary access to the URI. The simplest way to make this authorization is to use a FileProvider class. For more information about permissions and shared files, see share files.
Barrier-free Improvement
Android 7.0 has made some changes to improve the usability of the platform for poor eyesight or visually impaired users. These changes generally do not require changes to your app code, but you should carefully review and test these features with your app to assess their potential impact on the user experience.
Screen Zoom
Android 7.0 enables users to set the display size to enlarge or reduce all elements on the screen, thereby improving the device's accessibility to visually impaired users. The user cannot scale the screen below the minimum screen width of SW320DP, which is the width of the Nexus 4 and the width of the regular medium-sized phone.
Figure 3. The right-hand screen shows the effect of a device running an Android 7.0 system image that increases the size of the display.
When device density changes, the system notifies the running app as follows:
- If the application is for an API level 23 or earlier system, all of its background processes are automatically terminated. This means that if a user switches away from such an app, turns on the Settings screen and changes the display size setting, the system terminates the app as if it were running out of memory. If the app has any foreground processes, the system notifies them of the configuration changes as described in processing the run-time changes as if they were a device screen orientation change.
- If you are an app for Android 7.0, all of its processes (foreground and background) receive notifications about configuration changes, as described in handling run-time changes.
Most apps do not need to make any changes to support this feature, but only if these apps follow Android best practices. Specific items to check for:
sw320dpTest your app on a screen-wide device and make sure it runs well.
- Updates any density-related cache information, such as cached bitmaps or resources loaded from the network, when the device configuration changes. Check for configuration changes when the app resumes running from a paused state.
Note : If you want to cache configuration-related data, it is also best to include related metadata, such as the screen size or pixel density for that data. Saving these metadata makes it easier for you to decide whether you need to refresh the cached data after you configure the changes.
- Avoid specifying dimensions in pixel units, because pixels do not scale with screen density. Instead, specify the dimensions using the density-independent pixel (
dp ) units.
Setting visual settings in the wizard
Android 7.0 adds "Vision Settings" to the "Welcome" screen, where users can set the following accessibility settings on the new device:magnification gesture,Font size ,Display size , and utterance hints . This change makes it easier for you to discover errors related to different screen settings. To evaluate the impact of this feature, you should test the app in a state where these settings are enabled. You can find these settings in Settings > Accessibility .
NDK app link to platform library
Starting with Android 7.0, the system will block the app's dynamic link nonpublic NDK library, which could cause your app to crash. This behavioral change is designed to provide a unified app experience for cross-platform updates and different devices. Even though your code might not link to a private library, third-party static libraries in your app might do so. As a result, all developers should check to make sure their apps don't crash on devices running Android 7.0. If your app uses native code, you can only use the public NDK API.
Your app can try to access the private platform API in three ways:
- Your app accesses the private platform library directly. You should update your app to add a copy of the library for that app, or use the public NDK API.
- Your app uses a third-party library that can access the private platform library. Even if you determine that your app does not directly access the private library, you should still test your app for this scenario.
- Your app references a library that is not included in its APK. This can happen, for example, if you try to use your own OpenSSL copy, but forget to bundle it with the app's APK. Under normal circumstances, this app can run on the included
libcrypto.so Android platform version. However, this app crashes on newer versions of Android that don't contain this library (for example, Android 6.0 and later). To fix this issue, make sure that your APK bundles all of your non-NDK libraries.
Apps should not use native libraries that are not included in the NDK, because these libraries may change or have different availability between different versions of Android. For example, switching from OpenSSL to Boringssl is a change of this kind. Also, because platform libraries that are not part of the NDK do not have compatibility requirements, different devices may offer different levels of compatibility.
To reduce the impact that this limit may have on currently published apps, apps that target API level 23 or lower can temporarily access a fairly common set of libraries, such as, libandroid_runtime.so libcutils.so ,, and, on Android N libcrypto.so libssl.so . If your app loads one of these libraries, Logcat generates a warning and displays a Toast on the target device to notify you. If you see these warnings, you should update your app to add the app's own copy of the library, or use only the public NDK API. Future releases of the Android platform may completely limit the use of private libraries and cause your app to crash.
All apps generate a run-time error when calling APIs that are neither public nor temporarily accessible. The result is System.loadLibrary and dlopen(3) returns at the same time NULL , and may cause your app to crash. You should review your app's code to remove the use of the private platform API and test your app thoroughly using a preview device or simulator. If you are unsure whether your app uses a private library, you can check Logcat to identify run-time errors.
The following table describes the behavior that is expected to be displayed, based on the private native library used by the app and its target API level ( android:targetSdkVersion ).
run-time error
| library |
target API level |
run-time access via dynamic linker |
n Developer Preview behavior |
final Android N version behavior |
future Android platform behavior |
| public NDK |
any |
accessible |
expected |
expected |
expected |
| Private (temporarily accessible private library) |
23 or lower |
temporarily accessible |
is expected, but you receive a LOGCAT warning and a message on the target device. |
is expected, but you receive a logcat warning. |
Run-time error |
| Private (temporarily accessible private library) |
24 or higher |
restricted |
run-time error |
run-time error |
| Private (other) |
any |
restricted |
run-time error |
run Error |
run-time error |
Check if your app is using a private library
To help you identify issues with loading a private library, Logcat may generate a warning or run-time 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 might 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" was not accessiblefor the namespace " Classloader-namespace "-The access is temporarily grantedas a workaround for http://b/26394120
These logcat warnings inform you which library is attempting to access the private platform API, but will not cause your app to crash. However, if your app targets API level 24 or higher, Logcat generates the following run-time 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" isn't accessible for the namespace ' Classloader-namespace ' at Java.lang.Runtime.loadLibrary0 (runtime.java:977) at java.lang.System.loadLibrary (system.java:1602)
If your app uses a third-party library that is dynamically linked to the private platform API, you may also see the logcat output above. Using the Readelf tool in Android 7.0DK, you can generate a .so list of all dynamically linked shared libraries for a given file by running the following command:
AARCH64-LINUX-ANDROID-READELF-DW libmylibrary.so
Update your App
With some of the steps below, you can fix the above types of errors and make sure your app doesn't crash on a future update platform:
- If your app uses a private platform library, you should update it to add the app's own copy of the library or use the public NDK API.
- If your app uses a third-party library that accesses private symbols, contact the library author to update the library.
- Be sure to pack all your non-NDK libraries with your APK.
- Use the standard JNI function instead
libandroid_runtime.so of the getJavaVM and getJNIEnv :ANDROIDRUNTIME::GETJAVAVM, GETJAVAVM from <jni.h>androidruntime::getjnienv, javavm::getenv OrJavaVM:: Attachcurrentthread from <jni.h>.
- Use
__system_property_get libcutils.so private symbols instead of from property_get . To do this, use __system_property_get the following include function:#include<sys/system_properties.h>
Note : The availability and content of system properties are not tested by the CTS. Further repairs should be performed to avoid using these properties at the same time.
- Use a
libcrypto.so SSL_ctrl local version of the symbol from. For example, you should .so statically link in your file libcyrpto.a , or add a dynamically linked version from Boringssl/openssl libcrypto.so and package it into your APK.
Android for work
Android 7.0 includes changes to apps that target Android for work, including changes to certificate installation, password reset, level two user management, and device identifier access. If you are developing an app for the Android for work environment, you should review these changes carefully and modify your app accordingly.
- You must install the Licensing certificate installer before DPC can set it up. For profile and device owner applications that target the N SDK, you should
DevicePolicyManager.setCertInstallerPackage() install the authorization Certificate installer before the device Specification controller (DPC) call. If you have not already installed this installer, the system is raised IllegalArgumentException .
- The Reset password limit for device Administrators now also applies to the profile owner. Device administrators can no longer use
DevicePolicyManager.resetPassword() to purge or change passwords that have been set. The device administrator can still set the password, but only when the device does not have a password, pin, or pattern.
- The device owner and the profile owner can still manage the account, even if the limit is set. And, even with
DISALLOW_MODIFY_ACCOUNTS user restrictions, the device owner and the profile owner can still invoke the account Management API.
- Device owners make it easier to manage level two users. When the device is running in device owner mode, the system automatically sets the
DISALLOW_ADD_USER limit. This prevents users from creating unmanaged level two users. In addition, CreateUser() and createAndInitializeUser() methods have been deprecated and replaced by DevicePolicyManager.createAndManageUser() methods.
- The device owner can access the device identifier. The device owner can use
DevicePolicyManagewr.getWifiMacAddress() the WLAN MAC address to access the device. If Wi-Fi is never enabled on the device, this method returns a null value.
- The work mode setting Controls access to the work app. When working mode is off, the system initiator indicates that they are not available by making the work app appear dimmed. Enabling work mode restores normal behavior again.
- When you install a PKCS #12 file that contains a client certificate chain and a corresponding private key from the Settings UI, the CA certificate in the certificate chain is no longer installed into the trusted credential store. This does not affect the results when the app tries to retrieve the client certificate chain later
KeyChain.getCertificateChain() . If necessary, install the CA certificate into the trusted credential store separately through the Settings UI by using the DER encoded format of the. crt or. cer file name extension.
- Starting with Android 7.0, fingerprint registration and storage space can be managed for each user. If the profile owner's Device Specification client (DPC) targets a previous version of Android N on an Android n device, the user can still set the thumbprint on the device, but the work app cannot access the device fingerprint. When DPC targets Android N and later, users can set their fingerprints specifically for managed profiles by going to Settings > Security > Work Profile security.
DevicePolicyManager.getStorageEncryptionStatus()Returns the new encryption state ENCRYPTION_STATUS_ACTIVE_PER_USER to indicate that encryption is active and that the cryptographic key is associated with the user. The new state is returned only if the DPC targets API level 24 and higher. For applications that target an earlier API level, the system returns even if the encryption key is unique to the user or profile ENCRYPTION_STATUS_ACTIVE .
- In Android 7.0, if a device installs a managed profile through a separate work challenge, multiple methods that would normally affect the entire device will change the way it behaves. These methods will apply only to managed profiles, not to the entire device. (The complete list of such methods is in the
DevicePolicyManager.getParentProfileInstance() document.) For example, instead of DevicePolicyManager.lockNow() locking the entire device, only the managed profile is locked. For each of these methods, you can get the previous behavior by calling the method on the parent instance of the pair, which DevicePolicyManager you can get by calling the DevicePolicyManager.getParentProfileInstance() parent. For example, if you call a method of a parent instance lockNow() , the entire device is locked.
For more information about the changes that you make to Android for work in Android 7.0, see Android for job update.
annotation retention
Android 7.0 Fixed a bug where annotation visibility was ignored. This issue causes the app to access annotations that were not allowed to be accessed at run time. These annotations include:
VISIBILITY_BUILD: should only be visible at compile time.
VISIBILITY_SYSTEM: The runtime should be visible, but only for the underlying system.
If your app relies on this behavior, add a retention policy for annotations that must be available at run time. You can do this by using it @Retention(RetentionPolicy.RUNTIME) .
Other important notes
- If an app is running on Android 7.0, but is developed for a lower API level, the system terminates the app process when the user changes the display size. The app must be able to handle this scenario properly. Otherwise, the app crashes when the user resumes running the app from a recent usage record.
You should test your app to make sure that this behavior does not occur. To perform this test, you can manually terminate the app with DDMS to cause the same crash.
Applications that target N and later are not automatically terminated when density changes, but these applications may still respond negatively to configuration changes.
- Apps on Android 7.0 should be able to handle configuration changes properly and not crash on subsequent startup. You can verify the app behavior by changing the font size (Setting >Display > font size) and then resuming the app from the most recently used record.
- Due to an error in previous versions of Android, the system failed to report a TCP socket write operation on the main thread as violating strict mode. This error has been fixed by Android 7.0. An application that renders this behavior will now be thrown
android.os.NetworkOnMainThreadException . In general, we do not recommend that network operations be performed on the main thread, as these operations typically result in high-tailed latencies that can lead to ANR and stutter.
Debug.startMethodTracing()The method series now defaults to storing the output in a package-specific directory on your shared storage, not the SD card root directory. This means that apps no longer need to request WRITE_EXTERNAL_STORAGE permissions to use these APIs.
- Many platform APIs now begin to check the
Binder heavy load that is sent between transactions, and the system will now be TransactionTooLargeExceptions RuntimeExceptions raised again, rather than silently recording or suppressing them. A common example is Activity.onSaveInstanceState() storing too much data on top, causing it to be ActivityThread.StopInfo raised when your app targets Android 7.0 RuntimeException .
- If the app is to
View publish a Runnable task and View is not attached to the window, the system is View queued for the task, and Runnable the task is View not performed until it is attached to the window Runnable . This behavior fixes the following error:
- If an application is published from another thread that is not the intended window UI thread
View , it Runnable may run the wrong thread.
- If
Runnable a task is published from another thread that is not a loop route, the app may expose the Runnable task.
- If an app with permission on Android 7.0
DELETE_PACKAGES tries to delete a package, but another app already has the package installed, the system needs to be confirmed by the user. In this case, the PackageInstaller.uninstall() expected return status of the app at the time of invocation should be STATUS_PENDING_USER_ACTION .
- The JCA provider named Crypto has been deprecated because its only sha1prng algorithm is weak encryption. The app can no longer use SHA1PRNG (unsafe) to derive the key because the provider is no longer available. For more information, please see the "Crypto" security provider deprecated in Android N.
Android 7.0 Behavioral Changes