Casos de éxito

Grab reduce los errores de ANR en un 32% y mejora el tiempo de inicio en un 35% con R8 y la optimización guiada por perfiles

Lectura de 5 min

Grab es la superapp líder del sudeste asiático, que ofrece servicios de entrega, movilidad y financieros a millones de usuarios en ocho países a través de una sola app. Con una base de código de 10 años que contiene más de 10 millones de líneas de código y cientos de bibliotecas de terceros creadas con una configuración híbrida de Bazel y Gradle, el equipo de Grab enfrentó tres desafíos crecientes: altas tasas de errores de aplicación no responde (ANR), un tamaño de la app que seguía creciendo a medida que la superapp agregaba nuevos servicios y un tiempo de inicio que aumentaba lentamente año tras año.  Al habilitar la optimización de R8, definir mejor las reglas de conservación y, además, implementar perfiles de Baseline y de inicio, Grab redujo su tasa de errores de ANR percibidos por el usuario en un 32%, disminuyó el tamaño de descarga de la app en un 30% aproximadamente y mejoró el tiempo de inicio en un 35%.

Eliminación de los picos de errores de ANR posteriores al lanzamiento para lograr una experiencia del usuario más fluida

Antes de optimizar su proceso de compilación, Grab enfrentaba demoras en el inicio en frío y aumentos repentinos de errores de aplicación no responde (ANR) inmediatamente después de las actualizaciones nuevas, principalmente debido a la sobrecarga de leer muchos archivos DEX durante la inicialización de la app. 

Si bien los perfiles de Cloud de Google Play proporcionaron optimización para los flujos estándar en toda la base de usuarios, no optimizan todas las rutas de inicialización necesarias para los recorridos críticos del usuario de Grab, como la inicialización de los gráficos de dependencia de Dagger durante el inicio de la app. En el caso de las instrucciones de código que no se incluyeron en la distribución inicial, los dispositivos dependían de la compilación JIT y de la optimización local en segundo plano durante los días posteriores. La implementación de un perfil de Baseline personalizado resolvió este problema, ya que proporcionó estos recorridos críticos del usuario directamente en los perfiles de Cloud de Google Play, lo que expandió su cobertura de optimización para que estas rutas clave se compilaran en código máquina inmediatamente después de la instalación. 

ANDDM_Grab_Inline_Quote_ALT.png

"Experimentábamos picos constantes en la Tasa de ANR con cada lanzamiento semanal de la app", explica Nguyen Van Minh, ingeniero de software principal del equipo de Passenger App Core de Grab. 

Para eliminar los errores de ANR y mejorar los tiempos de inicio, Grab implementó optimizaciones de R8, perfiles de Baseline y perfiles de inicio. La optimización guiada por perfiles junto con el optimizador de R8 proporcionaron una mejora inmediata del 12% en el inicio en frío de R8 y un 15% adicional de los perfiles de Baseline, lo que logró un tiempo de inicio un 27% más rápido y eliminó de forma eficaz los picos de ANR posteriores al lanzamiento.

Grab ejecutó esta optimización de la app en tres fases estratégicas: habilitar la optimización de R8 en el modo de compatibilidad, realizar la transición al modo completo de R8 y, luego, definir mejor las reglas de conservación con Configuration Analyzer y agregar la administración de CI/CD.

Fase 1: Habilitación de la optimización de R8  (lanzamiento en 2025)

En esta primera etapa, Grab dejó de usar el archivo Proguard predeterminado heredado para adoptar proguard-android-optimize.txt, que habilita las optimizaciones de R8.  Debido a que la base de código tenía más de una década de antigüedad y contiene más de 10 millones de líneas de código, habilitar el optimizador requirió abordar las configuraciones heredadas y el uso de la reflexión.

Para maximizar el impacto de esta fase, Grab lanzó la actualización de la app con el modo de compatibilidad de R8 habilitado con perfiles de Baseline y de inicio. Este esfuerzo combinado generó una reducción inmediata del 25% en las tasas de errores de ANR percibidos por el usuario, una reducción del 16% en el tamaño de descarga de la app y una mejora general del 27% en los tiempos de inicio en frío.

Fase 2: Modo completo y migración de R8 (se lanzará en 2026)

Esta fase, que se lanzó nueve meses después del primer lanzamiento, cambió la app al modo completo de R8, lo que permitió realizar más optimizaciones. Si bien las bibliotecas estándar, como Retrofit, Firebase y Jetpack Compose, funcionaron sin problemas con R8 usando sus reglas integradas, la migración del resto de la enorme base de código se logró resolviendo instrucciones de código específicas con un uso intensivo de la reflexión:

Para migrar al modo completo de R8, el equipo adoptó las reglas de conservación del consumidor de la versión más reciente de Gson para garantizar un análisis de JSON sin problemas. También abordaron los desafíos de optimización con los proxies dinámicos de Java, que usan la reflexión para generar implementaciones de interfaz en el entorno de ejecución. Como R8 no puede detectar este uso en el tiempo de ejecución durante la compilación, quita o cambia el nombre de las clases necesarias, lo que provoca que la aplicación falle. En lugar de aplicar excepciones amplias que aumentarían el tamaño de la app, el equipo aisló las clases específicas que dependían de la reflexión y, luego, implementó reglas de conservación muy específicas, lo que preservó la estabilidad de la app y la eficiencia de la optimización.

En última instancia, el modo completo de R8 generó mejoras masivas y acumulativas, incluida una reducción adicional del 14% en el tamaño de descarga de la app, una mejora adicional del 10% en el tiempo de inicio y otra disminución del 10% en los errores de ANR percibidos por el usuario. Después de la migración al modo completo de R8, la base de código de Grab logró estos niveles de optimización de R8. 

  • Nivel de optimización: 72%
  • Puntuación de reducción: 73%
  • Puntuación de ofuscación: 79.6%

Estas puntuaciones proporcionaron comentarios sobre la configuración de R8 y la necesidad de definir mejor las reglas de conservación para maximizar la optimización de R8. 

Fase 3: Define mejor las reglas de conservación 

En la fase final de su recorrido de optimización, Grab se enfoca en establecer un estado de la base de código a largo plazo, una supervisión continua del rendimiento y un control estricto de la compilación. Para medir de forma sistemática la higiene de las reglas y evitar regresiones de configuración en los ciclos de lanzamiento en curso, el equipo integrará el Analizador de configuración de R8 en su flujo de trabajo de evaluación. Esta herramienta proporciona una visibilidad profunda de la eficacia con la que las reglas de conservación de Grab permiten que R8 optimice, reduzca y ofusque la aplicación.

Aprovechando la base del modo completo de R8 y recortando de forma metódica las reglas de conservación heredadas, Grab está logrando mejoras sustanciales en las tres dimensiones principales que evalúa el analizador:

  • Nivel de optimización: aumenta del 72% al 78.2%
  • Puntuación de reducción: aumentó del 73% al 79.1%
  • Puntuación de ofuscación: aumentó del 79.6% al 81.7%

Además de mejorar estas puntuaciones de diagnóstico, esta fase dedicada de perfeccionamiento de las reglas de conservación genera una reducción adicional de aproximadamente un 3.6% en el tamaño de descarga de la app. Y lo que es más importante, el seguimiento de estas métricas le proporciona al equipo de ingeniería los datos objetivos necesarios para implementar protecciones de CI automatizadas previas a la combinación, lo que garantiza que el código recién introducido cumpla con los estrictos estándares de reglas de conservación y que las mejoras de rendimiento obtenidas con tanto esfuerzo sigan protegidas con el paso del tiempo.

Resultados

Estas son las mejoras clave de rendimiento que se obtuvieron tras el lanzamiento del optimizador de R8:

Fase de optimizaciónANRTamañoInicio en frío
Fase 1: Optimizador de R8 (lanzado en 2025)Reducción de ~25%Reducción del 16%Mejora de ~27%
Fase 2: Modo completo de R8 (lanzamiento en 2026)Reducción del 10%Reducción del 14%Mejora del 10%
Optimización de reglas de conservación-Reducción del 3.6%-
General (acumulativo)Reducción de ~32.5%Reducción de ~30.4%Mejora de ~35%

Desafíos técnicos 

Habilitar el optimizador de R8 en la base de código de Grab, que tiene una década de antigüedad, presentó obstáculos técnicos clave a gran escala:

  • Pruebas: Una década de reflexión acumulada creó casos extremos con una optimización completa. Como era imposible realizar pruebas exhaustivas en millones de LOC, el equipo adoptó un enfoque incremental de alta prioridad: se enfocó específicamente en probar la cobertura de código cubierta por las reglas de conservación que se estaban restringiendo y, luego, perfeccionó esas reglas de forma iterativa para orientarlas solo a las clases, los métodos o los campos específicos necesarios para la reflexión, con el objetivo de maximizar la optimización de R8.
  • Latencia de compilación y arquitectura híbrida: El sistema de compilación híbrido de Grab (Bazel para la depuración y Gradle para las compilaciones de lanzamiento de R8) implicaba que los cambios experimentales de R8 requerían hasta 2 horas en la CI remota. Para cerrar la brecha de comentarios, Grab alineó sus compilaciones de QA diarias para que coincidan con el comportamiento de R8 de producción y automatizó la recopilación de artefactos de compilación de CI clave, como mapping.txt y configuration.txt, para agilizar la investigación.
  • Ciclos de depuración lentos: El seguimiento de las causas raíz en cientos de clases optimizadas representaba una gran carga para un equipo lean. Grab resolvió este problema automatizando las cargas de archivos de asignación a Firebase Crashlytics a través de Gradle y agrupando las asignaciones de desofuscación para Play Console, lo que permitió una resolución de símbolos instantánea y precisa para los problemas de tiempo de ejecución.

Impacto a largo plazo del código con R8

Más allá de las mejoras inmediatas en el rendimiento, habilitar el optimizador de R8 generó una ventaja estructural permanente para la enorme base de código de Grab. En Grab, el equipo usó la herramienta de código abierto app-sizer para medir el impacto de R8 y observó que R8 redujo de forma permanente el costo de cada línea de código de la app en el tamaño de descarga.

ANDDM_Grab_Inline_Metric.png

En la era del desarrollo asistido por IA, en la que el volumen de código se expande con rapidez, esta optimización es aún más importante. Sin R8, la expansión del código aumenta proporcionalmente el tamaño de la descarga. R8 garantiza que la misma tasa de expansión de código mantenga un espacio en memoria drásticamente reducido.

Nota: Metodología: Contribución de Kotlin/Java de app-sizer al tamaño de descarga de la app (dispositivo representativo), dividido por las LOC de Kotlin de producción (cloc; solo conjuntos de orígenes principales; se excluyen los módulos de prueba, simulación y ejemplo).

Mantén la administración de reglas y los límites de seguridad

Para evitar la degradación de las reglas y mantener las optimizaciones de R8 con el tiempo, Grab planea integrar protecciones automatizadas previas a la combinación directamente en su canalización de CI. Según esta política, las nuevas reglas de conservación están estrictamente restringidas, y cualquier regla adicional requiere una justificación y una revisión explícitas. El equipo de Grab hace un seguimiento de los niveles de optimización de R8 en la CI. A partir de esto, el equipo planea usar estas métricas como un ciclo de reacción continuo, de modo que las regresiones se detecten antes de la combinación y las mejoras de optimización se conserven en cada ciclo de lanzamiento. 

R8-rules-score (1).png

Figura 1: Panel de CI que hace un seguimiento de las puntuaciones de reducción, optimización y ofuscación de R8 a lo largo del tiempo en las compilaciones de Grab para detectar y evitar regresiones de forma proactiva en todas las versiones.

Conclusión 

Ante los desafíos de una base de código masiva y en proceso de maduración, el equipo de Pax App Core de Grab abordó de forma proactiva el aumento de los tiempos de inicio y los picos de rendimiento posteriores al lanzamiento implementando perfiles de Baseline y mejorando continuamente la configuración de R8. El equipo redujo los errores de ANR percibidos por el usuario en un 32.5% aproximadamente, disminuyó el tamaño de descarga de la app en un 30.3% aproximadamente y mejoró el tiempo de inicio en frío en un 35% aproximadamente, a la vez que mejoró de forma fundamental la eficiencia con la que se escala su base de código.

Estas optimizaciones proporcionaron una experiencia de superapp más rápida y estable para millones de usuarios en el sudeste asiático, a la vez que les brindaron a los ingenieros de Grab las herramientas para crear funciones más rápido sin la penalización de un aumento rápido del tamaño de descarga.

Para comenzar y obtener más información sobre R8, visita - d.android.com/r8.

Escrito por:
Continuar leyendo