Además de las nuevas funciones y capacidades, Android 7.0 incluye una variedad de cambios en el comportamiento del sistema y de la API. En este documento, se destacan algunos de los cambios clave que debes comprender y tener en cuenta en tus apps.
Si ya publicaste una app para Android, ten en cuenta que estos cambios en la plataforma podrían afectarla.
Batería y memoria
Android 7.0 incluye cambios en el comportamiento del sistema destinados a mejorar la duración de batería de los dispositivos y reducir el uso de RAM. Estos cambios pueden afectar el acceso de tu app a los recursos del sistema, así como la forma en que interactúa con otras apps mediante ciertos intents implícitos.
Descanso
La función Descanso, que se introdujo en Android 6.0 (nivel de API 23), mejora la duración de la batería, ya que aplaza las actividades de red y de la CPU cuando un usuario deja un dispositivo desconectado, quieto y con la pantalla apagada. Android 7.0 incluye más mejoras para la función Descanso, ya que aplica un subconjunto de restricciones de red y de la CPU mientras el dispositivo está desconectado con la pantalla apagada, pero no necesariamente quieto, por ejemplo, cuando un teléfono se encuentra en el bolsillo de un usuario.
Figura 1: Ilustración de cómo Doze aplica un primer nivel de restricciones de actividad del sistema para mejorar la duración de la batería
Cuando un dispositivo funciona con batería y la pantalla está apagada durante un tiempo determinado, el dispositivo entra en modo Descanso y aplica el primer subconjunto de restricciones: desactiva el acceso de las apps a la red y pospone los trabajos y las sincronizaciones. Si el dispositivo permanece
inmóvil durante un tiempo determinado después de ingresar al modo Descanso, el sistema aplica el
resto de las restricciones de este modo a las alarmas de PowerManager.WakeLock,
AlarmManager, el GPS y los análisis de Wi-Fi. Independientemente de si se aplican algunas o todas las restricciones de Doze, el sistema activa el dispositivo durante breves períodos de mantenimiento, en los que se permite que las aplicaciones accedan a la red y ejecuten trabajos o sincronizaciones diferidos.
Figura 2: Ilustración de cómo la función Descanso aplica un segundo nivel de restricciones de actividad del sistema después de que el dispositivo permanece inactivo durante un tiempo determinado
Ten en cuenta que, si activas la pantalla o conectas el dispositivo, se sale de Doze y se quitan estas restricciones de procesamiento. El comportamiento adicional no afecta las recomendaciones ni las prácticas recomendadas para adaptar tu app a la versión anterior de Descanso que se introdujo en Android 6.0 (nivel de API 23), como se explica en Cómo optimizar para Descanso y App Standby. Aún debes seguir esas recomendaciones, como usar Firebase Cloud Messaging (FCM) para enviar y recibir mensajes, y comenzar a planificar actualizaciones para adaptarte al comportamiento adicional de Doze.
Project Svelte: Optimizaciones en segundo plano
En Android 7.0, se quitan tres transmisiones implícitas para ayudar a optimizar el uso de memoria y el consumo de energía. Este cambio es necesario porque las transmisiones implícitas suelen iniciar apps que se registraron para escucharlas en segundo plano. Quitar estas transmisiones puede beneficiar de manera considerable el rendimiento del dispositivo y la experiencia del usuario.
Los dispositivos móviles experimentan cambios frecuentes de conectividad, como cuando se pasa de Wi-Fi a datos móviles. Actualmente, las apps pueden supervisar los cambios en la conectividad registrando un receptor para la transmisión implícita de CONNECTIVITY_ACTION en su manifiesto. Dado que muchas apps se registran para recibir esta transmisión, un solo cambio de red puede hacer que todas se activen y procesen la transmisión a la vez.
Del mismo modo, en versiones anteriores de Android, las apps podían registrarse para recibir transmisiones implícitas de ACTION_NEW_PICTURE y ACTION_NEW_VIDEO de otras apps, como la Cámara. Cuando un usuario toma una foto con la app de Cámara, estas apps se activan para procesar la transmisión.
Para mitigar estos problemas, Android 7.0 aplica las siguientes optimizaciones:
- Las apps que se orientan a Android 7.0 (nivel de API 24) y versiones posteriores no recibirán
transmisiones de
CONNECTIVITY_ACTIONsi declaran su receptor de transmisiones en el manifiesto. Las apps seguirán recibiendo transmisiones deCONNECTIVITY_ACTIONsi registran suBroadcastReceiverconContext.registerReceiver(), y ese contexto sigue siendo válido. - El sistema ya no envía transmisiones
ACTION_NEW_PICTUREniACTION_NEW_VIDEO. Esta optimización afecta a todas las apps, no solo a las orientadas a Android 7.0.
Si tu app usa alguno de estos intents, debes quitarles las dependencias tan pronto como sea posible para orientar de manera correcta a dispositivos con Android 7.0.
El framework de Android proporciona varias soluciones para mitigar la necesidad de estas transmisiones implícitas. Por ejemplo, la API de JobScheduler proporciona un mecanismo sólido para programar operaciones de red cuando se cumplen condiciones específicas, como la conexión a una red no medida. Incluso puedes usar JobScheduler para reaccionar a los cambios realizados en los proveedores de contenido.
Para obtener más información sobre las optimizaciones en segundo plano en Android 7.0 (nivel de API 24) y cómo adaptar tu app, consulta Optimizaciones en segundo plano.
Cambios de permisos
Android 7.0 incluye cambios en los permisos que podrían afectar tu app.
Cambios en los permisos del sistema de archivos
Para mejorar la seguridad de los archivos privados, el directorio privado de las apps orientadas a Android 7.0 o versiones posteriores tiene acceso restringido (0700). Esta configuración evita la filtración de metadatos de archivos privados, como su tamaño o existencia. Este cambio de permiso tiene varios efectos secundarios:
-
El propietario ya no debería flexibilizar los permisos de archivo privados, y cualquier intento de hacerlo con
MODE_WORLD_READABLEoMODE_WORLD_WRITEABLEactivará unaSecurityException.Nota: Por el momento, esta restricción no se aplica por completo. Las apps aún pueden modificar los permisos de su directorio privado con las APIs nativas o la API de
File. Sin embargo, no recomendamos flexibilizar los permisos del directorio privado. -
Pasar URIs
file://fuera del dominio del paquete puede dejar al receptor con una ruta de acceso inaccesible. Por lo tanto, los intentos de pasar un URIfile://activan unFileUriExposedException. La forma recomendada de compartir el contenido de un archivo privado es conFileProvider. -
El
DownloadManagerya no puede compartir archivos almacenados de forma privada por nombre de archivo. Las aplicaciones heredadas pueden terminar con una ruta de acceso inaccesible cuando se accede aCOLUMN_LOCAL_FILENAME. Las apps orientadas a Android 7.0 o versiones posteriores activan unaSecurityExceptioncuando intentan acceder aCOLUMN_LOCAL_FILENAME. Las aplicaciones heredadas que configuran la ubicación de descarga en una ubicación pública conDownloadManager.Request.setDestinationInExternalFilesDir()oDownloadManager.Request.setDestinationInExternalPublicDir()aún pueden acceder a la ruta de acceso enCOLUMN_LOCAL_FILENAME. Sin embargo, no se recomienda este método. La forma preferida de acceder a un archivo expuesto por elDownloadManageres usarContentResolver.openFileDescriptor().
Cómo compartir archivos entre apps
En el caso de las apps orientadas a Android 7.0, el framework de Android aplica
la política de la API de StrictMode que prohíbe exponer URIs file://
fuera de tu app. Si un intent que contiene un URI de archivo sale de tu app, esta falla
con una excepción FileUriExposedException.
Para compartir archivos entre aplicaciones, debes enviar un URI content:// y otorgar un permiso de acceso temporal en el URI. La forma más sencilla de otorgar este permiso es
usar la clase FileProvider. Para obtener más información sobre los permisos y el uso compartido de archivos, consulta Cómo compartir archivos.
Mejoras de accesibilidad
Android 7.0 incluye cambios destinados a mejorar la usabilidad de la plataforma para usuarios con visión reducida o con discapacidad visual. Por lo general, estos cambios no deberían requerir modificaciones en el código de tu app. Sin embargo, debes revisar estas funciones y probarlas con tu app para evaluar los posibles impactos en la experiencia del usuario.
Zoom de la pantalla
Android 7.0 permite que los usuarios establezcan el Tamaño de visualización, que amplía o reduce todos los elementos de la pantalla, lo que mejora la accesibilidad del dispositivo para los usuarios con visión reducida. Los usuarios no pueden ampliar la pantalla más allá de un ancho mínimo de sw320dp, que es el ancho de un Nexus 4, un teléfono común de tamaño mediano.
Figura 3: En la pantalla de la derecha, se muestra el efecto de aumentar el tamaño de la pantalla de un dispositivo que ejecuta una imagen del sistema Android 7.0.
Cuando cambia la densidad del dispositivo, el sistema notifica a las apps en ejecución de las siguientes maneras:
- Si una app se orienta al nivel de API 23 o uno anterior, el sistema finaliza automáticamente todos sus procesos en segundo plano. Esto significa que, si un usuario sale de una de esas apps para abrir la pantalla de Configuración y cambia el parámetro de configuración Tamaño de visualización, el sistema finaliza la app de la misma manera que lo haría en una situación de memoria insuficiente. Si la app tiene procesos en primer plano, el sistema les notifica el cambio de configuración, como se describe en Cómo controlar los cambios en el tiempo de ejecución, como si hubiera cambiado la orientación del dispositivo.
- Si una app se orienta a Android 7.0, todos sus procesos (en primer plano y en segundo plano) reciben notificaciones sobre el cambio de configuración, como se describe en Cómo controlar cambios en el tiempo de ejecución.
La mayoría de las apps no necesitan realizar ningún cambio para admitir esta función, siempre que sigan las prácticas recomendadas de Android. Aspectos específicos que se deben verificar:
- Prueba tu app en un dispositivo con un ancho de pantalla de
sw320dpy asegúrate de que funcione correctamente. - Cuando cambie la configuración del dispositivo, actualiza la información almacenada en caché que dependa de la densidad, como los mapas de bits o los recursos cargados desde la red. Verifica si hay cambios de configuración cuando la app se reanuda desde el estado
en pausa.
Nota: Si almacenas en caché datos que dependen de la configuración, te recomendamos que incluyas metadatos relevantes, como el tamaño de pantalla o la densidad de píxeles adecuados para esos datos. Guardar estos metadatos te permite decidir si necesitas actualizar los datos almacenados en caché después de un cambio de configuración.
- Evita especificar dimensiones con unidades px, ya que no se ajustan a la densidad de la pantalla. En su lugar, especifica las dimensiones con unidades de píxeles independientes de la densidad (
dp).
Configuración de visión en el asistente de configuración
Android 7.0 incluye la Configuración de visión en la pantalla de bienvenida, donde los usuarios pueden establecer la configuración de accesibilidad en un dispositivo nuevo: Gesto de ampliación, Tamaño de fuente, Tamaño de visualización y TalkBack. Este cambio aumenta la visibilidad de los errores relacionados con diferentes parámetros de configuración de la pantalla. Para evaluar el impacto de esta función, debes probar tus apps con estos parámetros de configuración habilitados. Puedes encontrar los parámetros de configuración en Configuración > Accesibilidad.
Vinculación de apps de NDK a bibliotecas de la plataforma
A partir de Android 7.0, el sistema impide que las apps se vinculen de forma dinámica con bibliotecas que no sean del NDK, lo que puede provocar que tu app falle. Este cambio de comportamiento tiene como objetivo crear una experiencia coherente en la app en todas las actualizaciones de la plataforma y en los diferentes dispositivos. Aunque es posible que tu código no se vincule a bibliotecas privadas, es posible que lo haga una biblioteca estática de terceros en tu app. Por lo tanto, todos los desarrolladores deben verificar que sus apps no fallen en dispositivos que ejecutan Android 7.0. Si tu app usa código nativo, solo debes usar las APIs públicas del NDK.
Existen tres maneras en las que tu app podría intentar acceder a las APIs privadas de la plataforma:
- Tu app accede directamente a bibliotecas privadas de la plataforma. Debes actualizar tu app para que incluya su propia copia de esas bibliotecas o usar las APIs públicas del NDK.
- Tu app usa una biblioteca de terceros que accede a bibliotecas privadas de la plataforma. Incluso si tienes la certeza de que tu app no accede directamente a bibliotecas privadas, debes probarla para este caso.
- Tu app hace referencia a una biblioteca que no se incluye en su APK. Por ejemplo, esto podría suceder si intentaste usar tu propia copia de OpenSSL, pero olvidaste incluirla en el APK de tu app. La app puede ejecutarse con normalidad en las versiones de la plataforma de Android que incluyen
libcrypto.so. Sin embargo, la app podría fallar en versiones posteriores de Android que no incluyan esta biblioteca (como Android 6.0 y versiones posteriores). Para solucionar este problema, asegúrate de empaquetar todas tus bibliotecas que no sean de NDK con tu APK.
Las apps no deben usar bibliotecas nativas que no estén incluidas en el NDK, ya que pueden cambiar o quitarse entre diferentes versiones de Android. El cambio de OpenSSL a BoringSSL es un ejemplo de este tipo de cambio. Además, como no hay requisitos de compatibilidad para las bibliotecas de la plataforma que no se incluyen en el NDK, es posible que diferentes dispositivos ofrezcan distintos niveles de compatibilidad.
Para reducir el impacto que esta restricción puede tener en las apps lanzadas actualmente, un conjunto de bibliotecas que se usan de forma significativa, como libandroid_runtime.so, libcutils.so, libcrypto.so y libssl.so, son accesibles temporalmente en Android 7.0 (nivel de API 24) para las apps orientadas al nivel de API 23 o versiones anteriores. Si tu app carga una de estas bibliotecas, logcat genera una advertencia y aparece un mensaje de aviso en el dispositivo de destino para notificarte. Si ves estas advertencias, debes actualizar tu app para que incluya su propia copia de esas bibliotecas o solo use las APIs públicas del NDK. Es posible que las versiones futuras de la plataforma de Android restrinjan por completo el uso de bibliotecas privadas y provoquen fallas en tu app.
Todas las apps generan un error de tiempo de ejecución cuando llaman a una API que no es pública ni accesible de forma temporal. El resultado es que System.loadLibrary y dlopen(3) devuelven NULL, lo que puede provocar que tu app falle. Debes revisar el código de tu app para quitar el uso de APIs de plataforma privadas y probar tus apps de forma exhaustiva con un dispositivo o emulador que ejecute Android 7.0 (nivel de API 24). Si no sabes con certeza si tu app usa bibliotecas privadas, puedes revisar logcat para identificar el error de tiempo de ejecución.
En la siguiente tabla, se describe el comportamiento que deberías esperar de una app según su uso de bibliotecas nativas privadas y su nivel de API objetivo (android:targetSdkVersion).
| Bibliotecas | Nivel de API objetivo | Acceso al entorno de ejecución con el vinculador dinámico | Comportamiento de Android 7.0 (nivel de API 24) | Comportamiento futuro de la plataforma de Android |
|---|---|---|---|---|
| NDK público | Cualquiera | Accesible | Funciona como se espera | Funciona como se espera |
| Privadas (bibliotecas privadas con acceso temporal) | 23 o anterior | Accesible temporalmente | Funciona como se espera, pero recibes una advertencia de logcat. | Error de tiempo de ejecución |
| Privadas (bibliotecas privadas con acceso temporal) | 24 o superior | Restringido | Error de tiempo de ejecución | Error de tiempo de ejecución |
| Privado (otro) | Cualquiera | Restringido | Error de tiempo de ejecución | Error de tiempo de ejecución |
Verifica si tu app usa bibliotecas privadas
Para ayudarte a identificar problemas de carga de bibliotecas privadas, logcat puede generar una advertencia o un error de tiempo de ejecución. Por ejemplo, si tu app se orienta al nivel de API 23 o uno inferior, y trata de acceder a una biblioteca privada en un dispositivo que ejecuta Android 7.0, es posible que veas una advertencia similar a la siguiente:
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
Estas advertencias de logcat te indican qué biblioteca intenta acceder a una API de plataforma privada, pero no harán que tu app falle. Sin embargo, si la app se orienta al nivel de API 24 o uno superior, logcat genera el siguiente error de tiempo de ejecución y es posible que la app falle:
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)
También es posible que veas estos resultados de logcat si tu app usa bibliotecas de terceros que se vinculan de forma dinámica a las APIs de plataformas privadas. La herramienta readelf del NDK de Android 7.0 te permite generar una lista de todas las bibliotecas compartidas vinculadas de forma dinámica de un archivo .so determinado ejecutando el siguiente comando:
aarch64-linux-android-readelf -dW libMyLibrary.so
Actualiza tu app
Estos son algunos pasos que puedes seguir para corregir estos tipos de errores y asegurarte de que tu app no falle en futuras actualizaciones de la plataforma:
- Si tu app usa bibliotecas de plataforma privadas, debes actualizarla para que incluya su propia copia de esas bibliotecas o use las APIs públicas del NDK.
- Si tu app usa una biblioteca de terceros que accede a símbolos privados, comunícate con el autor de la biblioteca para que la actualice.
- Asegúrate de empaquetar todas las bibliotecas que no sean del NDK con tu APK.
- Usa funciones de JNI estándar en lugar de
getJavaVMygetJNIEnvdelibandroid_runtime.so:AndroidRuntime::getJavaVM -> GetJavaVM from <jni.h> AndroidRuntime::getJNIEnv -> JavaVM::GetEnv or JavaVM::AttachCurrentThread from <jni.h>.
- Usa
__system_property_geten lugar del símbolo privadoproperty_getdelibcutils.so. Para ello, usa__system_property_getcon la siguiente inclusión:#include <sys/system_properties.h>Nota: La disponibilidad y el contenido de las propiedades del sistema no se prueban a través de CTS. Una mejor solución sería evitar el uso de estas propiedades por completo.
- Usa una versión local del símbolo
SSL_ctrldelibcrypto.so. Por ejemplo, debes vincular de forma estáticalibcyrpto.aen tu archivo.soo incluir una versión vinculada de forma dinámica delibcrypto.sode BoringSSL/OpenSSL y empaquetarla en tu APK.
Android for Work
Android 7.0 incluye cambios para las apps orientadas a Android for Work, incluidos cambios en la instalación de certificados, el restablecimiento de contraseñas, la administración de usuarios secundarios y el acceso a identificadores de dispositivos. Si compilas apps para entornos de Android for Work, debes revisar estos cambios y modificar tu app según corresponda.
- Debes instalar un instalador de certificados delegado antes de que el DPC pueda configurarlo. En el caso de las apps de propietario del perfil y del dispositivo orientadas a Android 7.0 (nivel de API 24), debes instalar el instalador de certificados delegado antes de que el controlador de política de dispositivos (DPC) llame a
DevicePolicyManager.setCertInstallerPackage(). Si el instalador aún no está instalado, el sistema arroja unaIllegalArgumentException. - Las restricciones de restablecimiento de contraseñas para los administradores de dispositivos ahora se aplican a los propietarios de perfiles. Los administradores de dispositivos ya no pueden usar
DevicePolicyManager.resetPassword()para borrar contraseñas ni cambiar las que ya están configuradas. Los administradores de dispositivos aún pueden establecer una contraseña, pero solo cuando el dispositivo no tiene contraseña, PIN ni patrón. - Los propietarios de dispositivos y perfiles pueden administrar cuentas incluso si se establecen restricciones. Los propietarios de dispositivos y de perfiles pueden llamar a las APIs de Account Management, incluso si se aplican restricciones de usuario de
DISALLOW_MODIFY_ACCOUNTS. - Los propietarios de dispositivos pueden administrar usuarios secundarios. Cuando un dispositivo se ejecuta en modo de propietario del dispositivo, la restricción
DISALLOW_ADD_USERse establece automáticamente. Esto evita que los usuarios creen usuarios secundarios no administrados. Además, los métodosCreateUser()ycreateAndInitializeUser()dejaron de estar disponibles, y el nuevo métodoDevicePolicyManager.createAndManageUser()los reemplaza. - Los propietarios de dispositivos pueden acceder a los identificadores de dispositivos. Un propietario del dispositivo puede acceder a la dirección MAC de Wi-Fi de un dispositivo con
DevicePolicyManager.getWifiMacAddress(). Si nunca se habilitó la conexión Wi-Fi en el dispositivo, este método devuelve un valor denull. - El parámetro de configuración Modo de trabajo controla el acceso a las apps de trabajo. Cuando el modo de trabajo está desactivado, el selector del sistema indica que las apps de trabajo no están disponibles y las muestra en gris. Si vuelves a habilitar el modo de trabajo, se restablecerá el comportamiento normal.
- Cuando se instala un archivo PKCS #12 que contiene una cadena de certificados de cliente y
la clave privada correspondiente desde la IU de Configuración, el certificado de la AC de la
cadena ya no se instala en el almacenamiento de credenciales de confianza. Esto no afecta el resultado de
KeyChain.getCertificateChain()cuando las apps intentan recuperar la cadena de certificados de cliente más adelante. Si es necesario, el certificado de la AC se debe instalar en el almacenamiento de credenciales de confianza con la IU de Configuración por separado, con un formato codificado en DER en una extensión de archivo .crt o .cer. - A partir de Android 7.0, la inscripción y el almacenamiento de huellas dactilares se administran por usuario. Si el controlador de política de dispositivo (DPC) de un propietario del perfil se orienta al nivel de API objetivo 23 (o uno inferior) en un dispositivo que ejecuta Android 7.0 (nivel de API 24), el usuario aún puede configurar la huella dactilar en el dispositivo, pero las aplicaciones de trabajo no pueden acceder a la huella dactilar del dispositivo. Cuando el DPC se orienta al nivel de API 24 y versiones posteriores, el usuario puede configurar la huella digital específicamente para el perfil de trabajo. Para ello, debe ir a Configuración > Seguridad > Seguridad del perfil de trabajo.
DevicePolicyManager.getStorageEncryptionStatus()devuelve un nuevo estado de encriptación,ENCRYPTION_STATUS_ACTIVE_PER_USER, para indicar que la encriptación está activa y que la clave de encriptación está vinculada al usuario. El estado nuevo solo se devuelve si el DPC se orienta al nivel de API 24 y versiones posteriores. En el caso de las apps que se orientan a niveles de API anteriores, se devuelveENCRYPTION_STATUS_ACTIVE, incluso si la clave de encriptación es específica del usuario o del perfil.- En Android 7.0, varios métodos que normalmente afectarían a todo el dispositivo se comportan de manera diferente si el dispositivo tiene un perfil de trabajo instalado con un desafío de trabajo independiente. En lugar de afectar a todo el dispositivo, estos métodos se aplican solo al perfil de trabajo. (La lista completa de estos métodos se encuentra en la documentación de
DevicePolicyManager.getParentProfileInstance()). Por ejemplo,DevicePolicyManager.lockNow()bloquea solo el perfil de trabajo, en lugar de bloquear todo el dispositivo. Para cada uno de estos métodos, puedes obtener el comportamiento anterior llamando al método en la instancia superior deDevicePolicyManager. Puedes obtener este elemento superior llamando aDevicePolicyManager.getParentProfileInstance(). Por ejemplo, si llamas al métodolockNow()de la instancia superior, se bloqueará todo el dispositivo.
Retención de anotaciones
En Android 7.0, se corrige un error por el que se ignoraba la visibilidad de las anotaciones. Este problema permitió que el entorno de ejecución accediera a anotaciones a las que no debería haber podido acceder. Estas anotaciones incluían lo siguiente:
VISIBILITY_BUILD: Se diseñó para que solo sea visible durante el tiempo de compilación.VISIBILITY_SYSTEM: Se diseñó para que sea visible durante el tiempo de ejecución, pero solo para el sistema subyacente.
Si tu app dependía de este comportamiento, agrega una política de retención a las anotaciones que deben estar disponibles durante el tiempo de ejecución. Para ello, usa @Retention(RetentionPolicy.RUNTIME).
Cambios en la configuración predeterminada de TLS/SSL
Android 7.0 realiza los siguientes cambios en la configuración predeterminada de TLS/SSL que usan las apps para HTTPS y otro tráfico de TLS/SSL:
- Ahora, los conjuntos de algoritmos de cifrado RC4 están inhabilitados.
- Los conjuntos de algoritmos de cifrado CHACHA20-POLY1305 ahora están habilitados.
Si se inhabilita RC4 de forma predeterminada, es posible que se produzcan interrupciones en la conectividad HTTPS o TLS/SSL cuando el servidor no negocie conjuntos de algoritmos de cifrado modernos. La solución preferida es mejorar la configuración del servidor para habilitar conjuntos de algoritmos de cifrado y protocolos más sólidos y modernos. Lo ideal es que TLSv1.2 y AES-GCM estén habilitados, y que los conjuntos de algoritmos de cifrado de confidencialidad directa (ECDHE) estén habilitados y se prefieran.
Una alternativa es modificar la app para que use un SSLSocketFactory personalizado para comunicarse con el servidor. La
fábrica debe diseñarse para crear instancias de SSLSocket
que tengan habilitados algunos de los conjuntos de algoritmos de cifrado que requiere el servidor,
además de los conjuntos de algoritmos de cifrado predeterminados.
Nota: Estos cambios no se aplican a WebView.
Apps orientadas a Android 7.0
Estos cambios en el comportamiento se aplican exclusivamente a las apps orientadas a Android 7.0 (nivel de API 24) o versiones posteriores. Las apps que se compilan para Android 7.0 o que establecen targetSdkVersion en Android 7.0 o versiones posteriores deben modificarse para admitir estos comportamientos correctamente, cuando corresponda.
Cambios en la serialización
En Android 7.0 (nivel de API 24), se corrigió un error en el cálculo del serialVersionUID predeterminado, en el que no coincidía con la especificación.
Las clases que implementan Serializable y no especifican un campo serialVersionUID explícito podrían ver un cambio en su serialVersionUID predeterminado, lo que provocaría que se arroje una excepción cuando se intenten deserializar instancias de la clase que se serializaron en una versión anterior o que se serializaron con una app orientada a una versión anterior. El mensaje de error se verá de la siguiente manera:
local class incompatible: stream classdesc serialVersionUID = 1234, local class serialVersionUID = 4567
Para solucionar estos problemas, se debe agregar un campo serialVersionUID a cualquier clase afectada con el valor de stream classdesc
serialVersionUID del mensaje de error, p.ej., 1234 en este caso. Ese cambio cumple con todas las recomendaciones de prácticas recomendadas para escribir código de serialización y funcionará en todas las versiones de Android.
El error específico que se corrigió estaba relacionado con la presencia de métodos de inicializador estáticos, es decir, <clinit>. Según la especificación, la presencia o ausencia de un método inicializador estático en la clase afectará el serialVersionUID predeterminado calculado para esa clase.
Antes de la corrección de errores, el cálculo también verificaba la superclase en busca de un inicializador estático si una clase no tenía uno.
Para aclarar, este cambio no afecta a las apps que se orientan a los niveles de API 23 o anteriores, las clases que tienen un campo serialVersionUID ni las clases que tienen un método inicializador estático.
Otros aspectos importantes
- Cuando una app se ejecuta en Android 7.0, pero se orienta a un nivel de API inferior, y el usuario cambia el tamaño de la pantalla, se finaliza el proceso de la app. La app debe poder controlar esta situación de forma correcta. De lo contrario, fallará cuando el usuario la restablezca desde Recientes.
Debes probar tu app para asegurarte de que no se produzca este comportamiento. Para ello, puedes provocar una falla idéntica cuando finalices la app de forma manual con DDMS.
Las apps orientadas a Android 7.0 (nivel de API 24) y versiones posteriores no se cierran automáticamente cuando se producen cambios de densidad. Sin embargo, es posible que no respondan bien a los cambios de configuración.
- Las apps en Android 7.0 deben poder controlar correctamente los cambios de configuración y no deben fallar en los inicios posteriores. Puedes verificar el comportamiento de la app cambiando el tamaño de la fuente (Configuración > Pantalla > Tamaño de la fuente) y, luego, restableciendo la app desde Recientes.
-
Debido a un error en las versiones anteriores de Android, el sistema no marcaba la escritura en un socket TCP en el subproceso principal como un incumplimiento del modo estricto. Android 7.0 corrige este error.
Las apps que presentan este comportamiento ahora arrojan una
android.os.NetworkOnMainThreadException. En general, realizar operaciones de red en el subproceso principal es una mala idea porque estas operaciones suelen tener una latencia alta que causa errores de ANR y bloqueos. -
La familia de métodos
Debug.startMethodTracing()ahora almacena de forma predeterminada el resultado en el directorio específico del paquete en el almacenamiento compartido, en lugar de hacerlo en el nivel superior de la tarjeta SD. Esto significa que las apps ya no necesitan solicitar el permisoWRITE_EXTERNAL_STORAGEpara usar estas APIs. -
Muchas APIs de la plataforma ahora comenzaron a verificar si se envían cargas útiles grandes
en las transacciones de
Binder, y el sistema ahora vuelve a arrojarTransactionTooLargeExceptionscomoRuntimeExceptions, en lugar de registrarlas o suprimirlas de forma silenciosa. Un ejemplo común es almacenar demasiados datos enActivity.onSaveInstanceState(), lo que hace queActivityThread.StopInfoarroje unRuntimeExceptioncuando tu app se orienta a Android 7.0. -
Si una app publica tareas
Runnableen unViewy elViewno está adjunto a una ventana, el sistema pone en cola la tareaRunnablecon elView; la tareaRunnableno se ejecuta hasta que elViewse adjunta a una ventana. Este comportamiento corrige los siguientes errores:- Si una app publicó en un
Viewdesde un subproceso que no es el subproceso de IU de la ventana prevista, es posible que, como resultado, elRunnablese ejecute en el subproceso incorrecto. - Si la tarea
Runnablese publicó desde un subproceso que no es un subproceso de bucle, la app podría exponer la tareaRunnable.
- Si una app publicó en un
-
Si una app en Android 7.0 con el permiso
DELETE_PACKAGESintenta borrar un paquete, pero otra app lo instaló, el sistema requiere la confirmación del usuario. En este caso, las apps deben esperarSTATUS_PENDING_USER_ACTIONcomo el estado de devolución cuando invocanPackageInstaller.uninstall(). - El proveedor de JCA llamado Crypto dejó de estar disponible, ya que su único algoritmo, SHA1PRNG, es criptográficamente débil. Las apps ya no pueden usar SHA1PRNG para derivar claves (de forma no segura), ya que este proveedor ya no está disponible. Para obtener más información, consulta la entrada de blog Security "Crypto" provider deprecated in Android N.