Cambios en el comportamiento: Todas las apps

Android 9 (nivel 28 de API) presenta varios cambios en el sistema de Android. Los siguientes cambios de comportamiento se aplican a todas las apps cuando se ejecutan en la plataforma de Android 9, independientemente del nivel de API al que se orienten. Todos los desarrollares deben revisar estos cambios y modificar sus apps para admitirlos de manera correspondiente, cuando sea pertinente para estas.

Para los cambios que solo afecten a las apps orientadas a niveles de API a partir del 28, consulta Cambios en el comportamiento: Apps orientadas a niveles de API a partir del 28.

Administración de energía

Android 9 presenta características nuevas para mejorar la administración de energía de los dispositivos. Estos cambios, sumados a características que ya estaban disponibles antes de Android 9, garantizan que se proporcionen los recursos de sistema a las apps que más los necesiten.

Para obtener información detallada, consulta Administración de energía.

Cambios relacionados con la privacidad

Con el objetivo de mejorar la privacidad del usuario, Android 9 introduce varios cambios de comportamiento, como la limitación del acceso de las apps en segundo plano a sensores del dispositivo, la restricción de la información obtenida en análisis de Wi-Fi, y nuevas reglas de permisos y grupos de permisos relacionados con llamadas telefónicas, el estado del teléfono y análisis de Wi-Fi.

Estos cambios afectan a todas las apps que se ejecuten en Android 9, sin importar la versión de SDK a la que se orienten.

Acceso limitado a sensores en segundo plano

Android 9 limita la capacidad de las apps en segundo plano para acceder a entradas del usuario y datos de sensores. Si tu app se ejecuta en segundo plano en un dispositivo con Android 9, el sistema aplica a esta las siguientes restricciones:

  • Tu app no puede acceder al micrófono ni a la cámara.
  • Los sensores que usan el modo de generación de informes continua, como acelerómetros y giroscopios, no reciben eventos.
  • Los sensores que usan los modos de generación de informes ante un cambio o de acción única no reciben eventos.

Si tu app debe detectar eventos de sensores en dispositivos con Android 9, usa un servicio en primer plano.

Acceso restringido a registros de llamadas

En Android 9, se introduce el grupo de permisos CALL_LOG y se mueven a este los permisos READ_CALL_LOG, WRITE_CALL_LOG y PROCESS_OUTGOING_CALLS. En versiones anteriores de Android, estos permisos se encontraban en el grupo de permisos PHONE.

Este grupo de permisos CALL_LOG brinda a los usuarios más control y visibilidad respecto de apps que necesiten acceder a información confidencial sobre llamadas telefónicas; la lectura de registros de llamadas telefónicas y la identificación de números telefónicos son algunos ejemplos.

Si tu app necesita acceder a registros de llamadas o necesita procesar llamadas salientes, debes solicitar estos permisos de forma explícita desde el grupo de permisos CALL_LOG. En caso contrario, se produce una SecurityException.

Nota: Debido a que estos permisos han cambiado de grupos y se otorgan en el tiempo de ejecución, el usuario puede denegar a tu app el acceso a la información de registros de llamadas. En este caso, tu app debería poder manejar correctamente la falta de acceso a la información.

Si tu app ya cumple con las prácticas recomendadas para permisos de tiempo de ejecución, puede manejar los cambios en el grupo de permisos.

Acceso restringido a números telefónicos

Las apps que se ejecutan en Android 9 no pueden leer números telefónicos ni estados de teléfonos sin adquirir primero el permiso READ_CALL_LOG, además de otros permisos que se requieran según el caso de uso de tu app.

Los números telefónicos asociados con llamadas entrantes o salientes son visibles en la transmisión del estado del teléfono, como en el caso de las llamadas entrantes y salientes, y puede accederse a ellos desde la clase PhoneStateListener. Sin embargo, sin el permiso READ_CALL_LOG, el campo del número telefónico que se proporciona en las transmisiones PHONE_STATE_CHANGED y a través de PhoneStateListener se encuentra vacío.

Para leer los números telefónicos del estado del teléfono, actualiza tu app a fin de solicitar los permisos necesarios según tu caso de uso:

Acceso restringido a la información de conexión y ubicación de Wi-Fi

En Android 9, los requisitos de permisos para que una app realice análisis de Wi-Fi son más estrictos que en versiones anteriores. Para obtener información detallada, consulta la sección de restricciones para el análisis de Wi-Fi.

También se aplican restricciones similares al método getConnectionInfo(), el cual muestra un objeto WifiInfo que describe la conexión Wi-Fi actual. Solo puedes usar los métodos de estos objetos para obtener valores de SSID y BSSID si la app que realiza la llamada tiene los siguientes permisos:

  • ACCESS_FINE_LOCATION o ACCESS_COARSE_LOCATION
  • ACCESS_WIFI_STATE

Para obtener el SSID o BSSID también es necesario que los servicios de ubicación estén habilitados en el dispositivo (dentro de Settings > Location).

Información quitada de métodos de servicios de Wi-Fi

En Android 9, los eventos y las transmisiones siguientes no reciben información sobre la ubicación del usuario ni datos que puedan identificarse personalmente:

La transmisión de sistema NETWORK_STATE_CHANGED_ACTION de Wi-Fi ya no contiene SSID (anteriormente EXTRA_SSID), BSSID (anteriormente EXTRA_BBSID) ni información de conexión (anteriormente EXTRA_NETWORK_INFO). Si tu app necesita esta información, llama a getConnectionInfo() como alternativa.

La información de telefonía ahora depende de la configuración de ubicación del dispositivo

Si el usuario ha inhabilitado la ubicación del dispositivo en un dispositivo que ejecute Android 9, los siguientes métodos no proporcionan resultados:

Restricciones para el uso de interfaces que no pertenezcan al SDK

Para garantizar la estabilidad y compatibilidad con apps, la plataforma restringe el uso de algunos métodos y campos que no pertenecen al SDK; estas restricciones se aplican si intentas acceder a estos métodos y campos de manera directa mediante reflejo o a través de JNI. En Android 9, tu app puede seguir teniendo acceso a estas interfaces restringidas; la plataforma usa notificaciones y entradas de registro para llamar tu atención respecto de ellas. Si tu app muestra estas notificaciones, es importante que apliques una estrategia de implementación alternativa a la interfaz restringida. Si crees que no hay una estrategia alternativa viable, puedes notificar un error para solicitar la reconsideración de la restricción.

En Restricciones en interfaces que no pertenecen al SDK se ofrece más información importante. Te convendrá consultarla para asegurarte de que tu app siga funcionando correctamente.

Cambios de comportamiento vinculados a la seguridad

Cambios de seguridad para dispositivos

En Android 9 se introducen varias capacidades que mejoran la seguridad de tu app, sin importar la versión a la que esta se oriente.

Cambios en la implementación de TLS

La implementación de TLS del sistema se ha sometido a varias modificaciones en Android 9:

  • Si una instancia de SSLSocket no puede establecer conexión mientras se crea, el sistema genera una IOException en lugar de una NullPointerException.
  • La clase SSLEngine controla de manera ordenada cualquier alerta close_notify que se produzca.

Para obtener más información sobre cómo realizar solicitudes web seguras en una app para Android, consulta Un ejemplo HTTPS.

Filtro de SECCOMP más estricto

En Android 9 se imponen más restricciones a las llamadas al sistema disponibles para las apps. Este comportamiento es una extensión del filtro de SECCOMP que incluye Android 8.0 (nivel de API 26).

Nota: Este cambio solo afecta a las apps que usan llamadas de sistema con privilegios.

Cambios criptográficos

En Android 9, se presentan varias modificaciones para la implementación y el manejo de los algoritmos criptográficos.

Implementaciones de parámetros y algoritmos de Conscrypt

En Android 9 se proporcionan implementaciones adicionales de parámetros de algoritmos en Conscrypt. Entre estos parámetros se incluyen AES, DESEDE, OAEP y EC. Las versiones Bouncy Castle de estos parámetros y muchos algoritmos han quedado obsoletos a partir de Android 9.

Nota: La implementación del parámetro EC en Conscrypt solo es compatible con curvas designadas.

Si tu app se orienta a Android 8.1 (nivel de API 27) o versiones anteriores, recibirás una advertencia al solicitar la implementación de Bouncy Castle a uno de estos algoritmos obsoletos. Sin embargo, si tienes como objetivo Android 9, estas solicitudes generan una NoSuchAlgorithmException.

Otros cambios

En Android 9, se introducen varios cambios adicionales relacionados con la criptografía:

  • Cuando se usan claves PBE, si Bouncy Castle espera un vector de inicialización (IV) y tu app no proporciona uno, recibes una advertencia.
  • La implementación de Conscrypt del cifrado ARC4 te permite especificar ARC4/ECB/NoPadding o ARC4/NONE/NoPadding.
  • El proveedor Crypto Java Cryptography Architecture (JCA) se ha eliminado. Como resultado, si tu app llama a SecureRandom.getInstance("SHA1PRNG", "Crypto"), se produce una NoSuchProviderException .
  • Si tu app analiza las claves RSA desde búferes que son más grandes que la estructura principal, dejará de producirse una excepción.

Para obtener más información sobre las capacidades criptográficas de Android, visita Criptografía.

Los archivos encriptados seguros ya nos son compatibles

En Android 9, se quita por completo la compatibilidad con los archivos encriptados seguros de Android (ASEC).

En Android 2.2 (nivel de API 8), Android introdujo los ASEC para admitir la funcionalidad de apps en tarjetas SD. En Android 6.0 (nivel de API 23), la plataforma introdujo una tecnología de dispositivos de almacenamiento adoptables que los desarrolladores pueden usar en lugar de los ASEC.

Actualización de las bibliotecas de ICU

Android 9 usa la versión 60 de la biblioteca de ICU. Android 8.0 (nivel de API 26) y Android 8.1 (nivel de API 27) usan ICU 58.

ICU se usa para proporcionar API públicas debajo del android.icu package y se aplica internamente en la plataforma Android para admitir la internacionalización. Por ejemplo, se usa para implementar clases de Android en java.util, java.text y android.text.format.

La actualización a ICU 60 tiene varias modificaciones pequeñas pero útiles, como compatibilidad con datos de Emoji 5.0 y formatos mejorados de fecha y hora, tal como se documenta en las notas de la versión de ICU 59 e ICU 60.

Cambios destacados en esta actualización:

  • Se ha modificado el modo en que la plataforma administra las zonas horarias.
    • La plataforma maneja mejor las zonas GMT y UTC; UTC ya no es sinónimo de GMT.

      ICU proporciona nombres de zonas traducidos para GMT y UTC. Esta modificación afecta android.icu el comportamiento de formateo y análisis para zonas como “GMT”, “Etc/GMT”, “UTC”, “Etc/UTC” y “Zulu”.

    • java.text.SimpleDateFormat ahora usa ICU para proporcionar nombres de visualización para UTC y GMT. Esto implica lo siguiente:
      • El formateo de zzzz genera una string localizada extensa para muchas configuraciones regionales. Anteriormente, producía “UTC” para UTC y strings como “GMT+00:00” para GMT.
      • El análisis de zzzz reconoce strings como “hora universal coordinada” y “hora de Greenwich”.
      • Las apps pueden experimentar problemas de compatibilidad si prevén que se muestra “UTC” o “GMT+00:00” para zzzz en todos los idiomas.
    • El comportamiento de java.text.DateFormatSymbols.getZoneStrings() ha cambiado:
      • Como en el caso de SimpleDateFormat, UTC y GMT ahora tienen nombres largos. Las variantes de los nombres de zonas horarias DST para la zona UTC, como “UTC”, "Etc/UTC" y “Zulu”, se convirtió en “GMT+00:00”, que es la alternativa de reserva estándar cuando no hay nombres disponibles, en lugar de la string codificada en forma rígida UTC.
      • Algunos ID de zonas se reconocen correctamente como sinónimos para otras zonas, de modo que Android encuentre strings para los ID de zonas arcaicas, como Eire, que antes no se podían resolver.
    • Asia/Hanoi ya no es una zona reconocida. Por esta razón java.util.TimeZones.getAvailableIds() no muestra este valor y java.util.TimeZone.getTimeZone() no lo reconoce. Este comportamiento responde al comportamiento existente de android.icu.
  • El método android.icu.text.NumberFormat.getInstance(ULocale, PLURALCURRENCYSTYLE).parse(String) puede mostrar una ParseException incluso al analizar un texto de moneda legítima. Puedes evitar este problema usando NumberFormat.parseCurrency, disponible a partir de Android 7.0 (nivel de API 24), para texto de moneda de estilo PLURALCURRENCYSTYLE.

Cambios de prueba de Android

Android 9 introduce varios cambios en la biblioteca del marco de trabajo de Android Test y en la estructura de clases. Estos cambios ayudan a los desarrolladores a usar API públicas compatibles con el marco de trabajo, pero también brindan mayor flexibilidad al compilar y ejecutar pruebas usando bibliotecas de terceros o lógica personalizada.

Bibliotecas eliminadas del marco de trabajo

Android 9 reorganiza las clases basadas en JUnit en tres bibliotecas: android.test.base, android.test.runner y android.test.mock. Este cambio te permite realizar pruebas con una versión de JUnit que funcione mejor con las dependencias de tu proyecto. Esta versión de JUnit podría ser diferente de la que android.jar proporciona.

Para obtener más información sobre cómo se organizan las clases basadas en JUnit en estas bibliotecas, y sobre cómo preparar el proyecto de tu app para escribir y ejecutar pruebas, consulta Configurar un proyecto para Android Test.

Cambios de compilación en conjuntos de pruebas

El método addRequirements() de la clase TestSuiteBuilder se eliminó y la clase TestSuiteBuilder pasó a ser obsoleta. El método addRequirements() exigía a los desarrolladores proporcionar argumentos cuyos tipos representaban API ocultas, con lo cual estas resultaban inválidas.

Decodificador UTF para Java

UTF-8 es el grupo de caracteres predeterminado en Android. Una secuencia de bytes UTF-8 se puede decodificar con un constructor String, como String(byte[] bytes).

El decodificador UTF-8 en Android 9 sigue los estándares Unicode de manera más estricta que en las versiones anteriores. Se incluyen los siguientes cambios:

  • La forma no corta de UTF-8, como <C0, AF>, se trata como incorrecta.
  • La forma suplente de UTF-8, como U+D800..U+DFFF, se trata como incorrecta.
  • La subsección máxima se reemplaza por una única U+FFFD. Por ejemplo, en la secuencia de bytes “41 C0 AF 41 F4 80 80 41”, las subsecciones máximas son “C0”, “AF” y “F4 80 80”. “F4 80 80” puede ser la subsecuencia inicial de “F4 80 80 80”, pero “C0” no puede ser la subsecuencia inicial de cualquier secuencia de unidades de código bien formada. Por lo tanto, el resultado debe ser “A\ufffd\ufffdA\ufffdA”.
  • Para decodificar una secuencia modificada UTF-8 o CESU-8 en Android 9 o versiones posteriores, usa el método DataInputStream.readUTF() o el método de JNI NewStringUTF().

Verificación del nombre de host con un certificado

En la RFC 2818 se describen dos métodos para hacer coincidir el nombre de un dominio con un certificado usando los nombres disponibles dentro de la extensión subjectAltName (SAN) o, ante la ausencia de una extensión SAN, volviendo al commonName (CN).

Sin embargo, la reserva para el CN dejó de estar disponible en RFC 2818. Por esto, en Android ya no se usa el CN. Para verificar un nombre de host, el servidor debe presentar un certificado con un SAN coincidente. Los certificados que no contienen un SAN que coincida con el nombre de host ya no se consideran confiables.

Las búsquedas de direcciones de red pueden generar violaciones de red

Las búsquedas de direcciones de red que requieren resolución de nombres pueden implicar entradas y salidas de red y, por lo tanto, se consideran como operaciones de bloqueo. Las operaciones de bloqueo en el subproceso principal pueden ocasionar pausas o bloqueos.

La clase StrictMode es una herramienta de desarrollo que permite a los desarrolladores detectar problemas en su código.

En Android 9 y versiones posteriores, StrictMode detecta las violaciones de red causadas por las búsquedas de direcciones de red que requieren resolución de nombres.

No deberías publicar tus apps con StrictMode habilitado. De lo contrario, estas pueden experimentar excepciones, como NetworkOnMainThreadException, al usar los métodos detectNetwork() o detectAll() para obtener una política que detecte violaciones de red.

La resolución de una dirección IP numérica no se considera como una operación de bloqueo. La resolución de la dirección IP numérica funciona del mismo modo que en versiones anteriores a Android 9.

Etiquetado de socket

En las versiones de plataforma anteriores a Android 9, si un socket se etiqueta con el método setThreadStatsTag(), pierde la etiqueta cuando se envía a otro proceso mediante IPC de enlace con un contenedor ParcelFileDescriptor.

En Android 9 y versiones posteriores, la etiqueta del socket se conserva cuando este se envía a otro proceso mediante IPC de enlace. Este cambio puede afectar las estadísticas del tráfico de red, por ejemplo, cuando se usa el método queryDetailsForUidTag().

Si quieres conservar el comportamiento de las versiones anteriores, que quita la etiqueta de un socket enviado a otro proceso, puedes llamar a untagSocket() antes de enviar el socket.

Cantidad registrada de bytes disponibles en el socket

El método available() muestra 0 cuando se lo llama luego de invocar al método shutdownInput().

Informe más detallado de capacidades de red para VPN

En Android 8.1 (nivel de API 28) y versiones anteriores, la clase NetworkCapabilities solo proporcionaba un conjunto limitado de información para VPN, como TRANSPORT_VPN, pero omitía NET_CAPABILITY_NOT_VPN. Esta información limitada hacía que fuera más difícil determinar si usar una VPN supondría costos para el usuario de la app. Por ejemplo, la comprobación de NET_CAPABILITY_NOT_METERED no determinaba si las redes subyacentes eran medidas o no.

En Android 9 y versiones posteriores, cuando una VPN llama al método setUnderlyingNetworks(), el sistema de Android combina los transportes y las capacidades de cualquier red subyacente, y muestra el resultado como las capacidades efectivas de red de la VPN.

En Android 9 y versiones posteriores, las apps que ya buscan NET_CAPABILITY_NOT_METERED reciben las capacidades de redes de la VPN y las redes subyacentes.

Los archivos de la carpeta xt_qtaguid ya no están disponibles para las apps

A partir de Android 9, las apps no pueden tener acceso directo de lectura a archivos de la carpeta /proc/net/xt_qtaguid. Esto se aplica para garantizar la uniformidad con algunos dispositivos que no cuenten con estos archivos.

Las API públicas que se basan en estos archivos, TrafficStats y NetworkStatsManager, continúan funcionando de la forma prevista. Sin embargo, es posible que las funciones cutils no compatibles, como qtaguid_tagSocket(), no funcionen como se espera o que ni siquiera lo hagan en diferentes dispositivos.

Ahora se aplica el requisito FLAG_ACTIVITY_NEW_TASK

Con Android 9, no puedes iniciar una actividad desde un contexto sin actividades a menos que pases el indicador de intent FLAG_ACTIVITY_NEW_TASK. Si intentas iniciar una actividad sin pasar este indicador, esta no se iniciará y el sistema mostrará un mensaje en el registro.

Nota: El requisito del indicador siempre fue el comportamiento deseado, y se implementaba de manera forzosa en versiones anteriores a Android 7.0 (nivel de API 24). Un error en Android 7.0 evitó que este requisito se implementara.

Cambios de rotación de pantallas

A partir de Android 9, se introdujeron cambios importantes en el modo de rotación de retrato. En Android 8.0 (nivel de API 26), los usuarios podían activar o desactivar los modos de rotación de giro automático y retrato usando una configuración de mosaicos o visualización Quicksettings. El nombre del modo de retrato se ha cambiado a bloqueo de rotación y permanece activo cuando la rotación automática se desactiva. No hay modificaciones en el modo de rotación automática.

Cuando el dispositivo se encuentra en el modo de bloqueo de rotación, los usuarios pueden bloquear su pantalla en cualquier rotación compatible con la Activity visible en la parte superior. Una Activity no debe prever que siempre se representará en el modo de retrato. Si la Activity de la parte superior se puede representar en varias rotaciones en el modo de rotación automática, las mismas opciones deben estar disponibles en el modo de bloqueo de rotación, con algunas excepciones según la configuración de la Activity screenOrientation (consulta la tabla que aparece a continuación).

Las Activity que solicitan una orientación específica (por ejemplo, screenOrientation=landscape) ignoran la preferencia de bloqueo del usuario y se comportan del mismo modo que en Android 8.0.

La preferencia respecto de la orientación de la pantalla se puede fijar en el nivel de Activity del manifiesto de Android, o mediante programación con setRequestedOrientation().

El modo de bloqueo de rotación funciona fijando la preferencia de rotación del usuario que el WindowManager usa cuando maneja la rotación de la Activity. La preferencia de la rotación del usuario se puede cambiar en los siguientes casos. Ten en cuenta que hay una tendencia a volver a la rotación natural de los dispositivos, que normalmente es de retrato para los dispositivos con factor de forma de teléfono:

  • Cuando el usuario acepta una sugerencia de rotación, la preferencia de rotación se modifica según la sugerencia.
  • Cuando el usuario realiza un cambio a una app vertical forzada (se incluyen la pantalla bloqueada o el lanzador), la preferencia de rotación cambia al modo de retrato.

En la siguiente tabla se resume el comportamiento de rotación para las orientaciones comunes de pantalla:

Orientación de la pantalla Comportamiento
unspecified, user En la rotación automática y el bloqueo de rotación, la Activity se puede representar en sentido vertical u horizontal (y a la inversa). Se prevé compatibilidad con diseños verticales y horizontales.
userLandscape En la rotación automática y el bloqueo de rotación, la Activity se puede representar de manera horizontal u horizontal inversa. Se prevé asistencia solo para diseños horizontales.
userPortrait En la rotación automática y el bloqueo de rotación, la Activity se puede representar en el modo de retrato o de retrato inverso. Se prevé compatibilidad solo con diseños verticales.
fullUser En la rotación automática y el bloqueo de rotación, la Activity se puede representar en el modo de retrato u horizontal (e inverso). Se prevé compatibilidad con diseños verticales y horizontales.

Los usuarios del bloqueo de rotación tendrán la opción de aplicar bloqueo en el modo de retrato inverso; a menudo, a 180º.
sensor, fullSensor, sensorPortrait y sensorLandscape La preferencia del modo de bloqueo de rotación se ignora y se trata como si el giro automático estuviese activo. Solo debe usarse en circunstancias excepcionales, con especial consideración de la experiencia del usuario.

La interrupción del cliente de HTTP de Apache afecta las apps con ClassLoader no estándar

En Android 6.0, eliminamos la compatibilidad con el cliente HTTP de Apache. Este cambio afecta a la gran mayoría de apps que no tengan como destino Android 9 o versiones posteriores. Sin embargo, el cambio puede afectar a ciertas apps que usen una estructura ClassLoader no estándar, incluso si las apps no están orientadas a Android 9 o versiones posteriores.

Una app puede verse afectada si usa un ClassLoader no estándar que realiza delegaciones de manera explícita al ClassLoader del sistema. En cambio, estas apps deben realizar la delegación al ClassLoader de la app cuando buscan clases en org.apache.http.*. Si realizan la delegación al ClassLoader del sistema, las apps fallarán en Android 9 o versiones posteriores con un NoClassDefFoundError, debido a que el ClassLoader del sistema ya no conoce esas clases. Para evitar problemas similares en el futuro, las apps en general deben cargar las clases a través del ClassLoader de la app en vez de acceder directamente al ClassLoader del sistema.

Enumerar cámaras

Las apps que se ejecuten en dispositivos con Android 9 pueden descubrir todas las cámaras disponibles llamando a getCameraIdList(). Una app no debe suponer que el dispositivo solo tiene una cámara trasera o una delantera.

Por ejemplo, si tu app tiene un botón para alternar las cámaras delantera y trasera, puede haber más de una cámara delantera o trasera para elegir. Debes revisar la lista de cámaras, examinar las características de cada una de estas y decidir qué cámaras mostrar al usuario.