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 cuando se ejecutan 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 orientadas al nivel de API 28 o versiones posteriores, consulta Cambios en el comportamiento: apps orientadas a la API nivel 28 y versiones posteriores.

Administración de energía

Android 9 presenta funciones nuevas para mejorar la administración de 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 batería.

Cambios en la privacidad

Para mejorar la privacidad del usuario, Android 9 presenta 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 de 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 le aplica las siguientes restricciones:

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

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

Acceso restringido a registros de llamadas

Android 9 introduce el grupo de permisos CALL_LOG y mueve 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 brinda a los usuarios un mejor control y visibilidad de las apps que necesitan acceso a información sensible sobre llamadas telefónicas, como la lectura de registros de llamadas y la identificación de números de teléfono.

Si tu app requiere acceso a registros de llamadas o necesita procesar llamadas salientes, debes solicitar explícitamente estos permisos del grupo de permisos CALL_LOG. De lo contrario, ocurre una SecurityException.

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

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 estados 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 son visibles en la transmisión del estado del teléfono, como las llamadas entrantes y salientes, y se puede acceder a ellos desde la clase PhoneStateListener. Sin embargo, sin el permiso READ_CALL_LOG, el campo de número de teléfono que se proporciona en las transmisiones PHONE_STATE_CHANGED y a través de PhoneStateListener estará vacío.

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

Acceso restringido a la ubicación y a la información de conexió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 búsqueda de Wi-Fi.

También se aplican restricciones similares 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 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 BSSID, también es necesario habilitar los servicios de ubicación en el dispositivo (en Configuración > Ubicación).

Se quitó información 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 datos de identificación personal:

La transmisión del sistema NETWORK_STATE_CHANGED_ACTION desde Wi-Fi ya no contiene el 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() en su lugar.

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

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

Restricciones para el uso de interfaces que no pertenecen al SDK

Para 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 esos métodos y campos directamente, mediante reflexión o mediante JNI. En Android 9, tu app puede seguir accediendo a estas interfaces restringidas. La plataforma usa avisos y entradas de registro para llamar tu atención. Si tu app muestra este aviso, es importante que sigas una estrategia de implementación que no sea la interfaz restringida. Si crees que no hay una estrategia alternativa viable, puedes informar un error para solicitar que se reconsidere la restricción.

En el artículo Restricciones en interfaces que no pertenecen al SDK, encontrarás más información importante. Revísala para asegurarte de que siga funcionando correctamente.

Cambios en el comportamiento de seguridad

Cambios de seguridad del dispositivo

En Android 9, se agregan 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 se sometió a 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 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).

Cambios criptográficos

Android 9 presenta varios cambios en la implementación y el control de los 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 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 a uno de estos algoritmos obsoletos. Sin embargo, si la orientas a Android 9, estas solicitudes arrojan 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 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 una NoSuchProviderException.
  • Si tu app analiza las claves RSA de búferes que son más grandes que la estructura de claves, dejará de producirse 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 los archivos encriptados seguros de Android

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

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 APIs públicas debajo de android.icu package y se usa de forma interna 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 de ICU 60 contiene muchos cambios pequeños pero útiles, como la compatibilidad con 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 e ICU 60.

Cambios destacados en esta actualización:

  • Cambió la forma 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. Este cambio afecta el comportamiento de formato y análisis de android.icu para zonas como "GMT", "Etc/GMT", "UTC", "Etc/UTC" y "Zulú".

    • java.text.SimpleDateFormat ahora usa ICU para proporcionar nombres visibles para UTC /GMT. Esto significa lo siguiente:
      • El formato de zzzz genera una cadena localizada larga para muchas configuraciones regionales. Anteriormente, producía "UTC" para UTC y cadenas como "GMT+00:00" para GMT.
      • El análisis de zzzz reconoce strings como "hora universal coordinada" y "hora del meridiano de Greenwich".
      • Las apps pueden tener problemas de compatibilidad si suponen que se muestra "UTC" o "GMT+00:00" para 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 nombres de zona horaria para la zona UTC, como "UTC", "Etc/UTC" y "Zulú", se convierten en GMT + 00:00, que es el resguardo estándar cuando no hay nombres disponibles, en lugar de la cadena hard-coded UTC.
      • Algunos IDs de zona se reconocen correctamente como sinónimos de otras zonas, de modo que Android encuentra cadenas para IDs de zonas arcaicas, como Eire, que antes no se podían resolver.
    • Asia/Hanói 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 arrojar una ParseException incluso cuando se analiza un texto de moneda legítima. Para evitar este problema, usa 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 presenta varios cambios en la biblioteca del framework de Android Test y la estructura de clases. Estos cambios ayudan a los desarrolladores a usar APIs públicas compatibles con el framework, pero también brindan más flexibilidad en la compilación y ejecución de pruebas con bibliotecas de terceros o lógica personalizada.

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

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 Cómo configurar un proyecto para Android Test.

Cambios en la 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 fueran APIs ocultas, lo que hacía que la API no fuera válida.

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 subrogada de UTF-8, como U+D800..U+DFFF, se trata como incorrecta.
  • La subparte máxima se reemplaza por una sola 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 subsecuencia inicial de "F4 80 80 80", pero "C0" no puede ser la subsecuencia inicial de ninguna 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 NewStringUTF() de JNI.

Verificación del nombre de host con un certificado

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

Sin embargo, el resguardo de CN dejó de estar disponible en RFC 2818. Por esta razón, Android ya no 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 causar incumplimientos 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. Las operaciones de bloqueo en el subproceso principal pueden 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 incumplimientos de red causados 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 usen 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 la dirección IP numérica funciona de la misma manera que en versiones anteriores a Android 9.

Etiquetado de sockets

En las versiones de plataforma anteriores a Android 9, si un socket se etiqueta con el método setThreadStatsTag(), este se quita 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 se envía a otro proceso mediante IPC de Binder. Este cambio puede afectar las estadísticas del tráfico de red, por ejemplo, cuando se usa el método queryDetailsForUidTag().

Si deseas conservar el comportamiento de las versiones anteriores, que quitan 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 llama después de invocar el método shutdownInput().

Informes más detallados sobre las capacidades de red de 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 hacía que fuera difícil determinar si el uso de una VPN generaría cargos para el usuario de la app. Por ejemplo, la verificación de NET_CAPABILITY_NOT_METERED no determinaría si las redes subyacentes eran de uso medido 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 efectivas de red de la red VPN.

En Android 9 y versiones posteriores, las apps que ya buscan 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. Esto se hace para garantizar la coherencia con algunos dispositivos que no cuentan con 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 cutils no compatibles, como qtaguid_tagSocket(), no funcionen como se espera (o en absoluto) en diferentes dispositivos.

Ahora se aplica el requisito 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 este indicador, esta no se iniciará y el sistema mostrará un mensaje en el registro.

Cambios en la rotación de pantallas

A partir de Android 9, hay cambios significativos en el modo de rotación del vertical. En Android 8.0 (nivel de API 26), los usuarios podían activar o desactivar los modos de rotación de rotación automática y vertical con la configuración de una tarjeta de Configuración rápida o de la pantalla. Se cambió el nombre del modo vertical de bloqueo de rotación y permanece activo cuando la opción de rotación automática se desactiva. No hay cambios en el modo de rotación automática.

Cuando el dispositivo está en el modo de bloqueo de rotación, los usuarios pueden bloquear la pantalla en cualquier rotación que admita la Actividad superior y visible. Una Activity no debe suponer que siempre se renderizará en modo 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 basadas en la configuración de screenOrientation de la actividad (consulta la tabla a continuación).

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 en el nivel de Activity en el manifiesto de Android o de manera programática con setRequestedOrientation().

El modo de bloqueo de rotación funciona configurando la preferencia de rotación del usuario que el WindowManager usa cuando controla la rotación de la Activity. La preferencia de rotación del usuario se puede cambiar en los siguientes casos. Ten en cuenta que existe un sesgo de volver a la rotación natural del dispositivo, que normalmente es vertical para dispositivos de 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 vertical forzada (que incluye la pantalla de bloqueo o el selector), la preferencia de rotación cambia al modo vertical.

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

Orientación de pantalla Comportamiento
sin especificar, usuario En la rotación automática y el 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.
Panorama de usuario 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 el modo vertical o vertical inverso. Se prevé compatibilidad solo con diseños verticales.
usuariocompleto En la rotación automática y el 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.

Los usuarios del bloqueo de rotación tendrán la opción de bloquear a la vertical inversa, que suele ser de 180°.
sensor, fullSensor, sensorPortrait y sensorLandscape Se ignora la preferencia del modo de bloqueo de rotación y se trata como si el giro automático estuviera activo. 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 se orientan 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 las apps no se orientan a Android 9 o versiones posteriores.

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

Cómo enumerar cámaras

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

Por ejemplo, si tu app tiene un botón para alternar entre la cámara frontal y la posterior, puede haber 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 de ellas y decidir qué cámaras mostrar al usuario.