Cambios de 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 que se ejecuten en la plataforma de Android 9, independientemente del nivel de API al que se orienten. Todos los desarrolladores deben revisar estos cambios y modificar sus apps para admitirlos correctamente, cuando corresponda.

Para conocer los cambios que solo afectan a las apps que se orientan al nivel de API 28 o versiones posteriores, consulta Cambios en los comportamientos: apps orientadas a niveles de API a partir del 28.

Administración de energía

Android 9 presenta nuevas funciones para mejorar la administración de la energía del dispositivo. Estos cambios, junto con las funciones que ya estaban presentes antes de Android 9, ayudan a garantizar que los recursos del sistema estén disponibles para las apps que más los necesitan.

Para obtener más información, consulta Administración de energía.

Cambios en la privacidad

Para mejorar la privacidad del usuario, Android 9 introduce varios cambios de comportamiento, como limitar el acceso de las apps en segundo plano a los sensores del dispositivo, restringir la información recuperada de las búsquedas de Wi-Fi y nuevas reglas y grupos de permisos relacionados con las llamadas telefónicas, el estado del teléfono y las búsquedas de Wi-Fi.

Estos cambios afectan a todas las apps que se ejecutan en Android 9, independientemente de la versión del SDK de destino.

Acceso limitado a los sensores en segundo plano

Android 9 limita la capacidad de las apps en segundo plano para acceder a la entrada del usuario y los datos del sensor. Si tu app se ejecuta en segundo plano en un dispositivo que ejecuta Android 9, el sistema aplica 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 continuo, como acelerómetros y giroscopios, no reciben eventos.
  • Los sensores que utilizan los modos de generación de informes cuando se producen cambios o por única vez no reciben eventos.

Si tu app necesita detectar eventos del sensor en dispositivos que ejecutan Android 9, usa un servicio en primer plano.

Acceso restringido a los registros de llamadas

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

Este grupo de permisos CALL_LOG les brinda a los usuarios un mejor control y visibilidad de las apps que necesitan acceso a información sensible sobre las llamadas telefónicas, como leer registros de llamadas y identificar números de teléfono.

Si tu app requiere acceso a los registros de llamadas o necesita procesar llamadas salientes, debes solicitar estos permisos de forma explícita al grupo de permisos CALL_LOG. De lo contrario, se produce una SecurityException.

Nota: Debido a que estos permisos cambiaron de grupo y se otorgan durante el tiempo de ejecución, es posible que el usuario niegue el acceso de tu app a la información de los registros de llamadas telefónicas. En este caso, tu app debería poder manejar la falta de acceso a la información con facilidad.

Si tu app ya sigue las prácticas recomendadas de permisos de tiempo de ejecución, puede controlar el cambio en el grupo de permisos.

Acceso restringido a los números de teléfono

Las apps que se ejecutan en Android 9 no pueden leer números de teléfono ni el estado del teléfono sin adquirir primero el permiso READ_CALL_LOG, además de los otros permisos que requieren los casos de uso de tu app.

Los números de teléfono asociados con las llamadas entrantes y salientes se pueden ver en la transmisión del estado del teléfono, como en las llamadas entrantes y salientes, y se puede acceder a ellos desde la clase PhoneStateListener. Sin el permiso de READ_CALL_LOG, sin embargo, el campo de número de teléfono que se proporciona en las transmisiones de PHONE_STATE_CHANGED y a través de PhoneStateListener está vacío.

Para leer números de teléfono desde el estado del teléfono, actualiza tu app para 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 búsquedas de Wi-Fi son más estrictos que en versiones anteriores. Para obtener más información, consulta Restricciones de escaneo de Wi-Fi.

Restricciones similares también se aplican al método getConnectionInfo(), que muestra un objeto WifiInfo que describe la conexión Wi-Fi actual. Solo puedes usar los métodos de este objeto para recuperar los 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 recuperar el SSID o el BSSID, también se deben habilitar los servicios de ubicación en el dispositivo (en Configuración > Ubicación).

Información que se quitó de los métodos de servicio de Wi-Fi

En Android 9, los siguientes eventos y transmisiones no reciben información sobre la ubicación del usuario ni los datos de identificación personal:

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

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

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

Restricciones en el uso de interfaces que no pertenecen al SDK

Para ayudar a garantizar la estabilidad y compatibilidad de las 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 directamente, a través de la reflexión o con JNI. En Android 9, tu app puede seguir accediendo a estas interfaces restringidas. La plataforma usa notificaciones y entradas de registro para llamar tu atención. Si tu app muestra un aviso de este tipo, es importante que sigas una estrategia de implementación distinta de la interfaz restringida. Si crees que no es posible implementar una estrategia alternativa, puedes informar un error para solicitar que se reconsidere la restricción.

Restricciones en interfaces que no pertenecen al SDK contiene más información importante. Debes revisarlo para asegurarte de que tu app siga funcionando correctamente.

Cambios en el comportamiento de seguridad

Cambios en la seguridad del dispositivo

Android 9 agrega varias funciones que mejoran la seguridad de tu app, independientemente de la versión a la que se oriente.

Cambios en la implementación de TLS

La implementación de TLS del sistema sufrió varios cambios en Android 9:

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

Filtro 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 SECCOMP que incluye Android 8.0 (nivel de API 26).

Cambios en la criptografía

Android 9 presenta varios cambios en la implementación y el manejo de algoritmos criptográficos.

Implementaciones de parámetros y algoritmos de Conscrypt

Android 9 proporciona implementaciones adicionales de parámetros de algoritmos en Conscrypt. Estos parámetros incluyen AES, DESEDE, OAEP y EC. Las versiones de Bouncy Castle de estos parámetros y muchos algoritmos dejaron de estar disponibles a partir de Android 9.

Si tu app se orienta a Android 8.1 (nivel de API 27) o versiones anteriores, recibirás una advertencia cuando solicites la implementación de Bouncy Castle de uno de estos algoritmos obsoletos. Sin embargo, si te orientas a Android 9, cada una de estas solicitudes arroja un NoSuchAlgorithmException.

Otros cambios

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

  • Cuando usas claves de PBE, si Bouncy Castle espera un vector de inicialización (IV) y tu app no lo proporciona, recibirás una advertencia.
  • La implementación de Conscrypt del algoritmo de cifrado ARC4 te permite especificar ARC4/ECB/NoPadding o ARC4/NONE/NoPadding.
  • Se quitó el proveedor de criptografía de arquitectura de criptografía de Java (JCA). Como resultado, si tu app llama a SecureRandom.getInstance("SHA1PRNG", "Crypto"), se produce un NoSuchProviderException.
  • Si tu app analiza claves RSA de búferes que son más grandes que la estructura de claves, ya no se produce una excepción.

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

Ya no se admiten archivos encriptados seguros de Android

Android 9 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 la tarjeta SD. En Android 6.0 (nivel de API 23), la plataforma introdujo una tecnología de dispositivo de almacenamiento adoptable 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 APIs públicas debajo de android.icu package y se usa internamente en la plataforma de 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 contiene muchos cambios pequeños pero útiles, como la compatibilidad con los datos de Emoji 5.0 y los formatos de fecha y hora mejorados, como se documenta en las notas de la versión de ICU 59 y ICU 60.

Cambios destacados en esta actualización:

  • Cambió la forma en que la plataforma controla las zonas horarias.
    • La plataforma controla mejor GMT y UTC. UTC ya no es sinónimo de GMT.

      ICU proporciona nombres de zonas traducidos para GMT y UTC. Este cambio afecta el comportamiento de formato y análisis de android.icu para zonas como "GMT", "Etc/GMT", "UTC", "Etc/UTC" y "Zulu".

    • java.text.SimpleDateFormat ahora usa ICU para proporcionar nombres visibles para UTC /GMT, lo que significa lo siguiente:
      • El formato zzzz genera una cadena localizada larga para muchas configuraciones regionales. Anteriormente, se generaba “UTC” para UTC y cadenas como “GMT+00:00” para GMT.
      • El análisis de zzzz reconoce cadenas como "Tiempo universal coordinado" y "Hora del meridiano de Greenwich".
      • Es posible que las apps tengan problemas de compatibilidad si suponen que "UTC" o "GMT+00:00" son la salida de zzzz en todos los idiomas.
    • Cambió el comportamiento de java.text.DateFormatSymbols.getZoneStrings():
      • Al igual que con SimpleDateFormat, UTC y GMT ahora tienen nombres largos. Las variantes de DST de los nombres de zonas horarias para la zona UTC, como "UTC", "Etc/UTC" y "Zulu", se convierten en GMT+00:00, que es el resguardo estándar cuando no hay nombres disponibles, en lugar de la cadena UTC codificada.
      • Algunos IDs de zona se reconocen correctamente como sinónimos de otras zonas, de modo que Android encuentre cadenas para IDs de zona arcaicas, como Eire, que antes no se podían resolver.
    • Asia/Hanoi ya no es una zona reconocida. Por este motivo, java.util.TimeZones.getAvailableIds() no muestra este valor y java.util.TimeZone.getTimeZone() no lo reconoce. Este comportamiento es coherente con el comportamiento existente de android.icu.
  • El método android.icu.text.NumberFormat.getInstance(ULocale, PLURALCURRENCYSTYLE).parse(String) puede generar un ParseException incluso cuando analiza texto de moneda legítimo. Para evitar este problema, usa NumberFormat.parseCurrency, disponible desde Android 7.0 (nivel de API 24), para el texto de moneda de estilo PLURALCURRENCYSTYLE.

Cambios en Android Test

Android 9 presenta varios cambios en la biblioteca y la estructura de clases del framework de Android Test. Estos cambios ayudan a los desarrolladores a usar APIs públicas compatibles con el framework, pero también permiten una mayor flexibilidad en la compilación y ejecución de pruebas con bibliotecas de terceros o lógica personalizada.

Bibliotecas quitadas del framework

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 ejecutar pruebas en una versión de JUnit que funcione mejor con las dependencias de tu proyecto. Esta versión de JUnit puede ser diferente de la que proporciona android.jar.

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

Prueba los cambios de compilación del paquete de pruebas

Se quitó el método addRequirements() de la clase TestSuiteBuilder, y la clase TestSuiteBuilder dejó de estar disponible. El método addRequirements() exigía a los desarrolladores que proporcionaran argumentos cuyos tipos son APIs ocultas, lo que hacía que la API no fuera válida.

Decodificador de UTF de Java

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

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

  • La forma no más corta de UTF-8, como <C0, AF>, se considera mal formada.
  • El formato de sustituto de UTF-8, como U+D800..U+DFFF, se considera mal formado.
  • La subparte máxima se reemplaza por un solo U+FFFD. Por ejemplo, en la secuencia de bytes "41 C0 AF 41 F4 80 80 41", las subpartes máximas son "C0", "AF" y "F4 80 80". "F4 80 80" puede ser la subsecuente inicial de "F4 80 80 80", pero "C0" no puede ser la subsecuente inicial de ninguna secuencia de unidad de código bien formada. Por lo tanto, el resultado debería ser “A\ufffd\ufffdA\ufffdA”.
  • Para decodificar una secuencia UTF-8 o CESU-8 modificada en Android 9 o versiones posteriores, usa el método DataInputStream.readUTF() o el método JNI NewStringUTF().

Verificación del nombre de host con un certificado

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

Sin embargo, el resguardo a CN dejó de estar disponible en la RFC 2818. Por este motivo, Android ya no recurre al uso de CN. Para verificar un nombre de host, el servidor debe presentar un certificado con un SAN coincidente. Ya no se confía en los certificados que no contienen un SAN que coincida con el nombre de host.

Las búsquedas de direcciones de red pueden causar infracciones de red

Las búsquedas de direcciones de red que requieren resolución de nombres pueden implicar E/S de red y, por lo tanto, se consideran operaciones de bloqueo. El bloqueo de operaciones en el subproceso principal puede provocar pausas o bloqueos.

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

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

No debes enviar tus apps con StrictMode habilitado. Si lo haces, tus apps pueden experimentar excepciones, como NetworkOnMainThreadException cuando usas los métodos detectNetwork() o detectAll() para obtener una política que detecte incumplimientos de red.

La resolución de una dirección IP numérica no se considera una operación de bloqueo. La resolución de direcciones IP numéricas funciona de la misma manera que en las versiones anteriores a Android 9.

Etiquetado de sockets

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

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

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

Cantidad informada de bytes disponibles en el socket

El método available() muestra 0 cuando se lo llama después de invocar el método shutdownInput().

Informes de capacidades de red más detallados para las VPN

En Android 8.1 (nivel de API 27) y versiones anteriores, la clase NetworkCapabilities solo informaba un conjunto limitado de información para las VPN, como TRANSPORT_VPN, pero omitía NET_CAPABILITY_NOT_VPN. Esta información limitada dificultaba determinar si el uso de una VPN generaría cargos para el usuario de la app. Por ejemplo, verificar NET_CAPABILITY_NOT_METERED no determinaría si las redes subyacentes se midieron o no.

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

En Android 9 y versiones posteriores, las apps que ya verifican NET_CAPABILITY_NOT_METERED reciben las capacidades de red 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 de lectura directo a los archivos de la carpeta /proc/net/xt_qtaguid. El motivo es garantizar la coherencia con algunos dispositivos que no tienen estos archivos.

Las APIs públicas que dependen de estos archivos, TrafficStats y NetworkStatsManager, siguen funcionando según lo previsto. Sin embargo, es posible que las funciones de cutils que no son compatibles, como qtaguid_tagSocket(), no funcionen como se espera o que ni siquiera funcionen en diferentes dispositivos.

Ahora se aplica el requisito de FLAG_ACTIVITY_NEW_TASK.

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

Cambios en la rotación de la pantalla

A partir de Android 9, hay cambios significativos en el modo de rotación vertical. En Android 8.0 (nivel de API 26), los usuarios podían alternar entre los modos de rotación automática y vertical con una tarjeta de Configuración rápida o la configuración de pantalla. Se cambió el nombre del modo vertical a bloqueo de rotación y está activo cuando la función Girar automáticamente está desactivada. No se realizaron cambios en el modo Girar automáticamente.

Cuando el dispositivo está en modo de bloqueo de rotación, los usuarios pueden bloquear la pantalla en cualquier rotación compatible con la actividad visible superior. Una actividad no debe suponer que siempre se renderizará en orientación vertical. Si la actividad superior se puede renderizar en varias rotaciones en el modo de rotación automática, las mismas opciones deberían estar disponibles en el modo de rotación bloqueada, con algunas excepciones según la configuración de screenOrientation de la actividad (consulta la siguiente tabla).

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

La preferencia de orientación de la pantalla se puede establecer a nivel de la actividad en el manifiesto de Android o de forma programática con setRequestedOrientation().

El modo de bloqueo de rotación funciona configurando la preferencia de rotación del usuario que usa WindowManager cuando controla la rotación de la actividad. La preferencia de rotación del usuario podría cambiar en los siguientes casos. Ten en cuenta que hay una preferencia por volver a la rotación natural del dispositivo, que suele ser vertical para los dispositivos con factor de forma de teléfono:

  • Cuando el usuario acepta una sugerencia de rotación, la preferencia de rotación cambia a la sugerencia.
  • Cuando el usuario cambia a una app con orientación vertical forzada (incluida la pantalla de bloqueo o el selector), la preferencia de rotación cambia a vertical.

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

Orientación de pantalla Comportamiento
sin especificar, usuario En la opción de giro automático y bloqueo de rotación, la actividad se puede renderizar en orientación vertical u horizontal (y viceversa). Se prevé compatibilidad con diseños verticales y horizontales.
userLandscape En la rotación automática y el bloqueo de rotación, la actividad se puede renderizar en orientación horizontal o inversa. Se prevé asistencia solo para diseños horizontales.
userPortrait En la rotación automática y el bloqueo de rotación, la actividad se puede renderizar en orientación vertical o inversa. Se prevé compatibilidad solo con diseños verticales.
fullUser En la opción de giro automático y bloqueo de rotación, la actividad se puede renderizar en orientación vertical u horizontal (y viceversa). Se espera que admita diseños verticales y horizontales.

Los usuarios del bloqueo de rotación tendrán la opción de bloquear la orientación vertical inversa, a menudo de 180°.
sensor, fullSensor, sensorPortrait, sensorLandscape Se ignora la preferencia del modo de bloqueo de rotación y se trata como si la opción de giro automático estuviera activa. Solo debe usarse en circunstancias excepcionales, con especial consideración de la experiencia del usuario.

La baja del cliente HTTP de Apache afecta a las apps con ClassLoader no estándar

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

Una app puede verse afectada si usa un ClassLoader no estándar que delegue de forma explícita al ClassLoader del sistema. Estas apps deben delegar a la app ClassLoader en su lugar cuando busquen clases en org.apache.http.*. Si delegan en el ClassLoader del sistema, las apps fallarán en Android 9 o versiones posteriores con un NoClassDefFoundError, ya que el ClassLoader del sistema ya no conoce esas clases. Para evitar problemas similares en el futuro, las apps, en general, deben cargar clases a través de ClassLoader de la app en lugar de acceder directamente a ClassLoader del sistema.

Enumeración de cámaras

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

Por ejemplo, si tu app tiene un botón para alternar entre la cámara frontal y la posterior, es posible que haya más de una cámara frontal o posterior para elegir. Debes revisar la lista de cámaras, examinar las características de cada una y decidir cuáles exponer al usuario.