Grab réduit les ANR de 32% et améliore le temps de démarrage de 35% grâce à R8 et à l'optimisation guidée par profil
Temps de lecture : 5 min
Grab est la super-application leader en Asie du Sud-Est. Elle propose des services de livraison, de mobilité et financiers à des millions d'utilisateurs dans huit pays via une seule application. Avec une codebase de 10 ans contenant plus de 10 millions de lignes de code et des centaines de bibliothèques tierces créées à l'aide d'une configuration hybride Bazel et Gradle, l'équipe Grab a été confrontée à trois défis croissants : des taux d'erreurs ANR élevés, une taille d'application qui ne cessait de croître à mesure que la super-application ajoutait de nouveaux services et un temps de démarrage qui augmentait lentement d'une année sur l'autre. En activant l'optimisation R8, en affinant les règles de conservation et en implémentant des profils de référence et de démarrage, Grab a réduit de 32 % le taux d'erreurs ANR perçues par l'utilisateur, d'environ 30 % la taille de téléchargement de l'application et de 35 % le temps de démarrage.
Éliminer les pics d'erreurs ANR après une version pour une expérience utilisateur plus fluide
Avant d'optimiser son processus de compilation, Grab était confronté à des retards de démarrage à froid et à des pics d'erreurs "L'application ne répond pas" (ANR) immédiatement après les nouvelles mises à jour, principalement en raison de la surcharge liée à la lecture de nombreux fichiers DEX lors de l'initialisation de l'application.
Bien que les profils cloud de Google Play optimisent les flux standards pour l'ensemble de la base d'utilisateurs, ils n'optimisent pas tous les chemins d'initialisation requis pour les critical user journeys de Grab, comme l'initialisation des graphiques de dépendance Dagger lors du lancement de l'application. Pour les chemins de code non couverts par la distribution initiale, les appareils s'appuyaient sur la compilation JIT et l'optimisation locale en arrière-plan au cours des jours suivants. L'implémentation d'un profil de référence personnalisé a permis de résoudre ce problème en fournissant ces critical user journeys directement dans les profils cloud de Google Play, ce qui a permis d'étendre la couverture d'optimisation afin que ces chemins clés soient compilés en code machine dès l'installation.
"Nous constations systématiquement des pics de taux d'erreurs ANR à chaque version hebdomadaire de l'application", explique Nguyen Van Minh, Lead Software Engineer au sein de l'équipe Passenger App Core de Grab.
Pour éliminer les erreurs ANR et améliorer les temps de démarrage, Grab a implémenté des optimisations R8, des profils de référence et des profils de démarrage. L'optimisation guidée par les profils, associée à l'optimiseur R8, a permis d'améliorer immédiatement le démarrage à froid de 12% grâce à R8 et de 15% supplémentaires grâce aux profils de référence. Cela a permis d'accélérer le temps de démarrage de 27% et d'éliminer efficacement les pics d'ANR après la publication.
Grab a procédé à cette optimisation de l'application en trois phases stratégiques : activation de l'optimisation R8 en mode compatibilité, passage au mode complet R8, puis affinement des règles de conservation avec l'analyseur de configuration et ajout de la gouvernance CI/CD.
Phase 1 : Activer l'optimisation R8 (lancée en 2025)
Dans un premier temps, Grab a abandonné l'ancien fichier Proguard par défaut pour adopter proguard-android-optimize.txt, qui permet d'optimiser R8. Comme le codebase avait plus de dix ans et contenait plus de 10 millions de lignes de code, l'activation de l'optimiseur a nécessité de résoudre les problèmes liés aux anciennes configurations et à l'utilisation de la réflexion.
Pour maximiser l'impact de cette phase, Grab a publié la mise à jour d'application avec le mode de compatibilité R8 activé, ainsi que des profils de référence et de démarrage. Ces efforts combinés ont permis de réduire immédiatement de 25% le taux d'erreurs ANR perçues par l'utilisateur, de 16% la taille de téléchargement de l'application et de 27% le temps de démarrage à froid global.
Phase 2 : Mode complet R8 et migration (livré en 2026)
Lancée neuf mois après le premier déploiement, cette phase a permis de faire passer l'application en mode complet R8, ce qui a permis d'effectuer d'autres optimisations. Alors que les bibliothèques standards telles que Retrofit, Firebase et Jetpack Compose fonctionnaient parfaitement avec R8 grâce à leurs règles intégrées, la migration du reste de l'énorme codebase a été réalisée en résolvant des chemins de code spécifiques fortement basés sur la réflexion :
Pour migrer vers le mode complet de R8, l'équipe a adopté les règles de conservation des consommateurs de la dernière version de Gson afin d'assurer une analyse JSON fluide. Ils ont également résolu les problèmes d'optimisation liés aux proxys dynamiques Java, qui utilisent la réflexion pour générer des implémentations d'interface au moment de l'exécution. Comme R8 ne peut pas détecter cette utilisation de l'environnement d'exécution lors de la compilation, il supprime ou renomme les classes nécessaires, ce qui entraîne le plantage de l'application. Plutôt que d'appliquer des exceptions générales qui auraient augmenté la taille de l'application, l'équipe a isolé les classes spécifiques qui s'appuient sur la réflexion et a implémenté des règles de conservation très ciblées, préservant ainsi la stabilité de l'application et l'efficacité de l'optimisation.
En fin de compte, le mode complet de R8 a permis d'apporter des améliorations massives et cumulées, notamment une réduction supplémentaire de 14% de la taille de téléchargement de l'application, une amélioration de 10% du temps de démarrage et une diminution de 10% des erreurs ANR perçues par l'utilisateur. Après la migration vers le mode complet de R8, la codebase de Grab a obtenu les scores d'optimisation R8 suivants.
- Score d'optimisation : 72%
- Score de réduction : 73%
- Score d'obscurcissement : 79,6%
Ces scores ont fourni des commentaires sur la configuration de R8 et sur la nécessité d'affiner les règles de conservation pour maximiser l'optimisation de R8.
Phase 3 : Affinement des règles de conservation
Dans la phase finale de son parcours d'optimisation, Grab se concentre sur l'établissement d'une codebase saine à long terme, la surveillance continue des performances et une gouvernance stricte de la compilation. Pour mesurer systématiquement l'hygiène des règles et éviter les régressions de configuration au cours des cycles de publication, l'équipe intègre l'analyseur de configuration R8 à son workflow d'évaluation. Cet outil offre une visibilité approfondie sur l'efficacité avec laquelle les règles de conservation de Grab permettent à R8 d'optimiser, de réduire et d'obscurcir l'application.
En s'appuyant sur le mode complet de R8 et en supprimant méthodiquement les anciennes règles de conservation, Grab améliore considérablement les trois dimensions principales évaluées par l'analyseur :
- Score d'optimisation : passe de 72% à 78,2%
- Score de réduction : passe de 73% à 79,1%
- Score d'obscurcissement : passe de 79,6% à 81,7%
En plus d'améliorer ces scores de diagnostic, cette phase dédiée d'ajustement des règles de conservation permet de réduire d'environ 3,6% la taille de téléchargement de l'application. Plus important encore, le suivi de ces métriques fournit à l'équipe d'ingénierie les données objectives nécessaires pour mettre en œuvre des garde-fous d'intégration continue automatisés avant la fusion. Cela permet de s'assurer que le code nouvellement introduit respecte des normes strictes de règles de conservation et que les gains de performances durement acquis restent protégés au fil du temps.
Résultats
Principales améliorations des performances suite au déploiement de l'optimiseur R8 :
| Phase d'optimisation | ANR | Taille | Démarrage à froid |
|---|---|---|---|
| Phase 1 : Optimiseur R8 (lancé en 2025) | Réduction d'environ 25 % | Réduction de 16 % | ~27% d'amélioration |
| Phase 2 : Mode complet R8 (lancé en 2026) | Réduction de 10 % | Réduction de 14 % | Amélioration de 10 % |
| Optimisation des règles de conservation | - | Réduction de 3,6 % | - |
| Global (cumulé) | Réduction d'environ 32,5 % | Réduction d'environ 30,4 % | ~35% d'amélioration |
Défis techniques
L'activation de l'optimiseur R8 dans la codebase de Grab, qui date d'une dizaine d'années, a entraîné des difficultés techniques majeures à grande échelle :
- Tests : une décennie de réflexion accumulée a créé des cas extrêmes dans le cadre d'une optimisation complète. Comme il était impossible de tester de manière exhaustive des millions de lignes de code, l'équipe a adopté une approche incrémentielle et prioritaire. Elle a concentré ses tests sur le code couvert par les règles de conservation en cours de réduction, et a affiné ces règles de manière itérative pour ne cibler que les classes, méthodes ou champs spécifiques requis pour la réflexion afin de maximiser l'optimisation de R8.
- Latence de compilation et architecture hybride : le système de compilation hybride de Grab (Bazel pour le débogage, Gradle pour les compilations de versions R8) nécessitait jusqu'à deux heures pour les modifications expérimentales de R8 dans l'intégration continue à distance. Pour combler le manque de commentaires, Grab a aligné ses builds d'assurance qualité quotidiens sur le comportement de production de R8 et a automatisé la collecte des artefacts de build d'intégration continue clés, tels que mapping.txt et configuration.txt, pour simplifier l'investigation.
- Cycles de débogage lents : l'identification des causes fondamentales parmi des centaines de classes optimisées représentait une charge de travail importante pour une équipe réduite. Grab a résolu ce problème en automatisant l'importation des fichiers de mappage vers Firebase Crashlytics via Gradle et en regroupant les mappages de désobscurcissement pour la Play Console, ce qui permet une résolution instantanée et précise des symboles pour les problèmes d'exécution.
Impact à long terme du code avec R8
Au-delà des gains de performances immédiats, l'activation de l'optimiseur R8 a permis à Grab de bénéficier d'un avantage structurel permanent pour son codebase massif. Chez Grab, l'équipe a utilisé l'outil Open Source app-sizer pour mesurer l'impact de R8. Elle a constaté que R8 réduisait de manière permanente l'impact de chaque ligne de code de l'application sur la taille de téléchargement.
À l'ère du développement assisté par l'IA, où le volume de code augmente rapidement, cette optimisation est encore plus importante. Sans R8, l'expansion du code augmente proportionnellement la taille de téléchargement. R8 garantit que le même taux d'expansion du code maintient un espace mémoire utilisé considérablement réduit.
Remarque : Méthodologie : contribution Kotlin/Java d'app-sizer à la taille de téléchargement de l'application (appareil représentatif), divisée par les lignes de code Kotlin de production (cloc ; ensembles de sources principaux uniquement ; modules de test, de simulation et d'exemple exclus).
Conserver la gestion des règles et les garde-fous
Pour éviter la dégradation des règles et maintenir les optimisations de R8 au fil du temps, Grab prévoit d'intégrer des garde-fous automatisés avant la fusion directement dans son pipeline d'intégration continue. En vertu de cette règle, les nouvelles règles de conservation sont strictement limitées, et toute règle supplémentaire nécessite une justification explicite et un examen. L'équipe de Grab suit les scores d'optimisation de R8 dans l'intégration continue. L'équipe prévoit d'utiliser ces métriques comme une boucle de rétroaction continue, afin de détecter les régressions avant la fusion et de préserver les gains d'optimisation à chaque cycle de publication.
Figure 1 : Tableau de bord d'intégration continue qui suit les scores de minification, d'optimisation et d'obscurcissement de R8 au fil du temps dans les builds Grab afin de détecter et d'éviter de manière proactive les régressions entre les versions.
Conclusion
Confrontée aux défis d'une codebase massive et en pleine maturation, l'équipe Pax App Core de Grab a pris les devants pour résoudre les problèmes d'augmentation des temps de démarrage et de pics de performances après la publication en implémentant des profils de référence et en améliorant continuellement la configuration R8. L'équipe a réduit les ANR perçues par l'utilisateur d'environ 32,5%, la taille de téléchargement de l'application d'environ 30,3 % et le temps de démarrage à froid d'environ 35%, tout en améliorant fondamentalement l'efficacité de la mise à l'échelle de sa codebase.
Ces optimisations ont permis d'offrir une expérience de super-application plus rapide et plus stable à des millions d'utilisateurs en Asie du Sud-Est, tout en fournissant aux ingénieurs de Grab les outils nécessaires pour créer des fonctionnalités plus rapidement sans que la taille de téléchargement n'augmente trop vite.
Pour vous lancer et en savoir plus sur R8, consultez - d.android.com/r8.
-
Études de casTinder s'est donné pour mission de favoriser et d'inspirer de vraies rencontres en les rendant faciles et amusantes pour chaque nouvelle génération de célibataires.
Ajesh Pai, Ulises Uriel Verduzco Díaz , Tracy Agyemang • Temps de lecture : 4 min -
Études de casWhatsApp est la plus grande plate-forme de messagerie au monde, avec des milliards d'utilisateurs dans le monde entier. C'est l'outil de communication par défaut pour les personnes de différentes régions, qui connecte les utilisateurs via une messagerie privée, fiable et sécurisée.
Niharika Arora, Tracy Agyemang, Mayank Jain • Temps de lecture : 8 min -
Études de casKarrot est une application de place de marché peer-to-peer hyperlocale et axée sur la communauté, qui permet aux utilisateurs d'acheter, de vendre et d'échanger des articles avec d'autres utilisateurs validés. Depuis son lancement en Corée du Sud en 2015, la plate-forme s'est étendue à l'international et compte plus de 43 millions d'utilisateurs inscrits.
Thomas Ezan, Tracy Agyemang • Temps de lecture : 2 min
Recevez chaque semaine les dernières informations sur le développement Android dans votre boîte de réception.