Grab riduce gli ANR del 32% e migliora il tempo di avvio del 35% con R8 e l'ottimizzazione guidata dai profili
Tempo di lettura: 5 min
Grab è la superapp leader nel sud-est asiatico, che offre consegne, mobilità e servizi finanziari a milioni di utenti in otto paesi tramite un'unica app. Con un codebase di 10 anni contenente oltre 10 milioni di righe di codice e centinaia di librerie di terze parti create utilizzando una configurazione ibrida di Bazel e Gradle, il team di Grab ha dovuto affrontare tre sfide crescenti: tassi elevati di errori "L'applicazione non risponde" (ANR), dimensioni dell'app che continuavano a crescere man mano che la superapp aggiungeva nuovi servizi e un tempo di avvio che aumentava lentamente di anno in anno. Attivando l'ottimizzazione R8, perfezionando le regole di conservazione e implementando i profili di riferimento e di avvio, Grab ha ridotto del 32% la percentuale di ANR percepiti dagli utenti, di circa il 30% le dimensioni di download dell'app e del 35% il tempo di avvio.
Eliminating Post-Release ANR Spikes for a Smoother User Experience
Prima di ottimizzare il processo di build, Grab ha riscontrato ritardi nell'avvio a freddo e picchi di errori L'applicazione non risponde (ANR) subito dopo i nuovi aggiornamenti, principalmente a causa dell'overhead della lettura di molti file DEX durante l'inizializzazione dell'app.
Sebbene i profili cloud di Google Play abbiano fornito l'ottimizzazione per i flussi standard nell'intera base utenti, non ottimizzano tutti i percorsi di inizializzazione richiesti per i Critical User Journey di Grab, come l'inizializzazione dei grafici delle dipendenze di Dagger durante il lancio dell'app. Per i percorsi del codice non coperti dalla distribuzione iniziale, i dispositivi si sono affidati alla compilazione JIT e all'ottimizzazione locale in background nei giorni successivi. L'implementazione di un profilo di riferimento personalizzato ha risolto il problema fornendo questi Critical User Journey direttamente nei profili cloud di Google Play, ampliando la copertura dell'ottimizzazione in modo che questi percorsi chiave venissero compilati in codice macchina immediatamente al momento dell'installazione.
"Abbiamo riscontrato costantemente picchi nella percentuale di ANR con ogni release settimanale dell'app", spiega Nguyen Van Minh, Lead Software Engineer del team Passenger App Core di Grab.
Per eliminare gli ANR e migliorare i tempi di avvio, Grab ha implementato le ottimizzazioni R8, i profili di baseline e i profili di avvio. L'ottimizzazione guidata dai profili, insieme all'ottimizzatore R8, ha generato un miglioramento immediato del 12% dell'avvio a freddo da R8 e un ulteriore 15% dai profili di riferimento, ottenendo un tempo di avvio più rapido del 27% ed eliminando efficacemente i picchi di ANR post-release.
Grab ha eseguito questa ottimizzazione dell'app in tre fasi strategiche: attivazione dell'ottimizzazione R8 in modalità di compatibilità, passaggio alla modalità completa di R8 e, infine, perfezionamento delle regole di conservazione con Configuration Analyzer e aggiunta della governance CI/CD.
Fase 1: attivazione dell'ottimizzazione R8 (lancio nel 2025)
In questa prima fase, Grab ha abbandonato il file Proguard predefinito legacy per adottare proguard-android-optimize.txt, che attiva le ottimizzazioni di R8. Poiché il codebase aveva più di dieci anni e contiene oltre 10 milioni di righe di codice, l'attivazione dell'ottimizzatore ha richiesto la gestione delle configurazioni legacy e dell'utilizzo della riflessione.
Per massimizzare l'impatto di questa fase, Grab ha rilasciato l'aggiornamento dell'app con la modalità R8 Compat abilitata con i profili di baseline e i profili di avvio. Questo sforzo combinato ha portato a una riduzione immediata del 25% delle percentuali di ANR percepiti dagli utenti, a una riduzione del 16% delle dimensioni di download dell'app e a un miglioramento complessivo del 27% dei tempi di avvio a freddo.
Fase 2: modalità completa R8 e migrazione (rilasciata nel 2026)
Lanciata nove mesi dopo il primo lancio, questa fase ha spostato l'app in R8 Full Mode, che ha sbloccato ulteriori ottimizzazioni. Mentre le librerie standard come Retrofit, Firebase e Jetpack Compose funzionavano perfettamente con R8 utilizzando le regole integrate, la migrazione del resto dell'enorme codebase è stata ottenuta risolvendo percorsi del codice specifici con un uso intensivo della riflessione:
Per eseguire la migrazione alla modalità R8 Full, il team ha adottato le regole di conservazione dei consumer dell'ultima versione di Gson per garantire un'analisi JSON senza problemi. Hanno anche affrontato le sfide di ottimizzazione con i proxy dinamici Java, che utilizzano la riflessione per generare implementazioni di interfacce in fase di runtime. Poiché R8 non è in grado di rilevare questo utilizzo in fase di runtime durante la compilazione, rimuove o rinomina le classi necessarie, causando l'arresto anomalo dell'applicazione. Anziché applicare eccezioni generali che avrebbero aumentato le dimensioni dell'app, il team ha isolato le classi specifiche basate sulla riflessione e ha implementato regole di conservazione altamente mirate, preservando sia la stabilità dell'app sia l'efficienza dell'ottimizzazione.
In definitiva, la modalità completa di R8 ha offerto miglioramenti enormi e cumulativi, tra cui un'ulteriore riduzione del 14% delle dimensioni di download dell'app, un ulteriore miglioramento del 10% del tempo di avvio e un'ulteriore riduzione del 10% degli errori ANR percepiti dagli utenti. In seguito alla migrazione alla modalità completa di R8, il codebase di Grab ha ottenuto questi punteggi di ottimizzazione di R8.
- Punteggio di ottimizzazione: 72%
- Punteggio di riduzione: 73%
- Punteggio di offuscamento: 79,6%
Questi punteggi hanno fornito un feedback sulla configurazione di R8 e sulla necessità di perfezionare le regole di conservazione per massimizzare l'ottimizzazione di R8.
Fase 3: perfezionamento delle regole di conservazione
Nella fase finale del suo percorso di ottimizzazione, Grab si sta concentrando sulla creazione di un codebase integro a lungo termine, sul monitoraggio continuo delle prestazioni e su una governance rigorosa della compilazione. Per misurare sistematicamente l'igiene delle regole e prevenire le regressioni della configurazione nei cicli di release in corso, il team sta integrando R8 Configuration Analyzer nel proprio workflow di valutazione. Questo strumento offre una visibilità approfondita sull'efficacia con cui le regole di conservazione di Grab consentono a R8 di ottimizzare, ridurre e offuscare l'applicazione.
Sfruttando le basi della modalità completa di R8 e riducendo metodicamente le regole di conservazione legacy, Grab sta ottenendo miglioramenti sostanziali in tutte e tre le dimensioni principali valutate dall'analizzatore:
- Punteggio di ottimizzazione: sta aumentando dal 72% al 78,2%
- Punteggio di riduzione: sta aumentando dal 73% al 79,1%
- Punteggio di offuscamento: sta aumentando dal 79,6% all'81,7%
Oltre a migliorare questi punteggi diagnostici, questa fase dedicata di perfezionamento delle regole di conservazione sta producendo un'ulteriore riduzione di circa il 3,6% delle dimensioni di download dell'app. Inoltre, il monitoraggio di queste metriche fornisce al team di progettazione i dati oggettivi necessari per implementare i guardrail di CI pre-unione automatizzati, garantendo che il codice appena introdotto rispetti i rigorosi standard delle regole di conservazione e che i miglioramenti delle prestazioni ottenuti con fatica rimangano protetti nel tempo.
Risultati
Miglioramenti chiave delle prestazioni in seguito all'implementazione dello strumento di ottimizzazione R8:
| Fase di ottimizzazione | ANR | Dimensioni | Avvio a freddo |
|---|---|---|---|
| Fase 1: ottimizzatore R8 (rilasciato nel 2025) | Riduzione di circa il 25% | Riduzione del 16% | Miglioramento di circa il 27% |
| Fase 2: modalità completa R8 (rilasciata nel 2026) | Riduzione del 10% | Riduzione del 14% | Miglioramento del 10% |
| Ottimizzazione delle regole di conservazione | - | Riduzione del 3,6% | - |
| Complessivo (cumulativo) | Riduzione di circa il 32,5% | Riduzione di circa il 30,4% | Miglioramento di circa il 35% |
Technical Challenges
L'attivazione dell'ottimizzatore R8 nella codebase decennale di Grab ha introdotto ostacoli tecnici chiave su larga scala:
- Test: un decennio di riflessioni accumulate ha creato casi limite in condizioni di ottimizzazione completa. Poiché i test esaustivi su milioni di righe di codice erano impossibili, il team ha adottato un approccio incrementale e ad alta priorità, concentrando i test in modo specifico sulla copertura del codice coperta dalle regole di conservazione che venivano limitate e perfezionando in modo iterativo queste regole per scegliere come target solo le classi, i metodi o i campi specifici richiesti per la riflessione per massimizzare l'ottimizzazione di R8.
- Latenza di build e architettura ibrida:il sistema di build ibrido di Grab (Bazel per il debug, Gradle per le build di release R8) implicava che le modifiche sperimentali di R8 richiedessero fino a 2 ore nell'integrazione continua remota. Per colmare il divario di feedback, Grab ha allineato le sue build QA giornaliere in modo che corrispondessero al comportamento di R8 in produzione e ha automatizzato la raccolta di artefatti chiave delle build CI come mapping.txt, configuration.txt per un'indagine semplificata.
- Cicli di debug lenti: l'individuazione delle cause principali in centinaia di classi ottimizzate ha rappresentato un onere pesante per un team snello. Grab ha risolto questo problema automatizzando i caricamenti dei file di mappatura su Firebase Crashlytics tramite Gradle e raggruppando le mappature di deoffuscamento per Play Console, consentendo una risoluzione dei simboli istantanea e accurata per i problemi di runtime
Impatto del codice a lungo termine con R8
Oltre ai miglioramenti immediati delle prestazioni, l'attivazione dell'ottimizzatore R8 ha prodotto un vantaggio strutturale permanente per l'enorme codebase di Grab. Il team di Grab ha utilizzato lo strumento open source app-sizer per misurare l'impatto di R8 e ha osservato che R8 ha ridotto in modo permanente il costo di ogni riga di codice dell'app in termini di dimensioni del download.
Nell'era dello sviluppo assistito dall'AI, in cui il volume del codice si espande rapidamente, questa ottimizzazione è ancora più importante. Senza R8, l'espansione del codice aumenta proporzionalmente le dimensioni del download. R8 garantisce che lo stesso tasso di espansione del codice mantenga un footprint della memoria drasticamente ridotto.
Nota: metodologia: contributo di Kotlin/Java di app-sizer alle dimensioni di download dell'app (dispositivo rappresentativo), diviso per le righe di codice (LOC) di Kotlin in produzione (cloc; solo set di risorse principali; moduli di test, fittizi e di esempio esclusi).
Gestione delle regole e misure di sicurezza di Keep
Per evitare il peggioramento delle regole e mantenere le ottimizzazioni di R8 nel tempo, Grab prevede di integrare i guardrail di pre-unione automatizzati direttamente nella pipeline di CI. In base a questa policy, le nuove regole di conservazione sono rigorosamente limitate e qualsiasi regola aggiuntiva richiede una giustificazione e una revisione esplicite. Il team di Grab monitora i punteggi di ottimizzazione di R8 nell'integrazione continua. Sulla base di questi risultati, il team prevede di utilizzare queste metriche come un ciclo di feedback continuo, in modo da rilevare le regressioni prima dell'unione e preservare i vantaggi dell'ottimizzazione in ogni ciclo di rilascio.
Figura 1: dashboard CI che monitora i punteggi di riduzione, ottimizzazione e offuscamento di R8 nel tempo nelle build di Grab per individuare e prevenire in modo proattivo le regressioni tra le release.
Conclusion
Di fronte alle sfide di un codebase enorme e in fase di maturazione, il team Pax App Core di Grab ha affrontato in modo proattivo l'aumento dei tempi di avvio e i picchi di prestazioni post-release implementando i profili di baseline e migliorando continuamente la configurazione R8. Il team ha ridotto gli errori ANR percepiti dagli utenti di circa il 32,5%, ha ridotto le dimensioni di download dell'app di circa il 30,3% e ha migliorato il tempo di avvio a freddo di circa il 35%, migliorando al contempo l'efficienza della scalabilità del codebase.
Queste ottimizzazioni hanno offerto un'esperienza di superapp più rapida e stabile per milioni di utenti nel sud-est asiatico, fornendo al contempo agli ingegneri di Grab gli strumenti per creare funzionalità più velocemente senza lo svantaggio di un rapido aumento delle dimensioni di download.
Per iniziare e scoprire di più su R8, visita la pagina - d.android.com/r8.
-
Case studyLa missione di Tinder è promuovere e ispirare connessioni reali, rendendo gli incontri facili e divertenti per ogni nuova generazione di single.
Ajesh Pai, Ulises Uriel Verduzco Díaz , Tracy Agyemang • Tempo di lettura: 4 min -
Case studyWhatsApp è la più grande piattaforma di messaggistica al mondo, con miliardi di utenti a livello globale. È lo strumento di comunicazione predefinito per le persone di diverse regioni, che connette gli utenti tramite messaggi privati, affidabili e sicuri.
Niharika Arora, Tracy Agyemang, Mayank Jain • Tempo di lettura: 8 min -
Case studyKarrot è un'app di marketplace peer-to-peer iperlocale basata sulla community che consente agli utenti di acquistare, vendere e scambiare articoli con altri utenti verificati. Dal lancio in Corea del Sud nel 2015, la piattaforma si è espansa nei mercati globali, accumulando oltre 43 milioni di utenti registrati.
Thomas Ezan, Tracy Agyemang • Tempo di lettura: 2 min
Ricevi gli ultimi approfondimenti sullo sviluppo di Android direttamente nella tua casella di posta ogni settimana.