ProfilingManager permet de capturer des profils en fonction de déclencheurs système. Le système gère le processus d'enregistrement et fournit le profil obtenu à votre application.
Les déclencheurs sont liés à des événements critiques pour les performances. Les profils enregistrés par le système fournissent des informations de débogage détaillées pour les critical user journeys (CUJ) associés à ces déclencheurs.
Capturer les données historiques
De nombreux déclencheurs nécessitent d'analyser les données historiques précédant l'événement. Le déclencheur lui-même est souvent la conséquence d'un problème plutôt que sa cause première. Si vous ne démarrez un profil qu'après le déclenchement, la cause première peut déjà être perdue.
Par exemple, une opération de longue durée sur le thread UI entraîne une erreur Application Not Responding (ANR). Lorsque le système détecte l'ANR et le signale à l'application, l'opération peut être terminée. Si vous démarrez un profil à ce moment-là, vous ne verrez pas le travail de blocage réel.
Il est impossible de prédire exactement quand certains déclencheurs se produisent, ce qui empêche de démarrer manuellement un profil à l'avance.
Pourquoi utiliser la capture basée sur des déclencheurs ?
La principale raison d'utiliser des déclencheurs de profilage est de capturer des données pour des événements imprévisibles pour lesquels il est impossible pour une application de commencer à enregistrer manuellement avant qu'ils ne se produisent. Les déclencheurs de profilage peuvent être utilisés pour :
- Déboguer les problèmes de performances : diagnostiquez les erreurs ANR, les fuites de mémoire et d'autres problèmes de stabilité.
- Optimiser les critical user journeys : analysez et améliorez les flux, par exemple le démarrage de l'application.
- Comprendre le comportement des utilisateurs : obtenez des insights sur les événements, par exemple les sorties d'application initiées par l'utilisateur.
Configurer un déclencheur
Le code suivant montre comment enregistrer le déclencheur TRIGGER_TYPE_APP_FULLY_DRAWN et lui appliquer une limitation du débit.
Kotlin
fun recordWithTrigger() { val profilingManager = applicationContext.getSystemService(ProfilingManager::class.java) val triggers = ArrayList<ProfilingTrigger>() val triggerBuilder = ProfilingTrigger.Builder(ProfilingTrigger.TRIGGER_TYPE_APP_FULLY_DRAWN) .setRateLimitingPeriodHours(1) triggers.add(triggerBuilder.build()) val mainExecutor: Executor = Executors.newSingleThreadExecutor() val resultCallback = Consumer<ProfilingResult> { profilingResult -> if (profilingResult.errorCode == ProfilingResult.ERROR_NONE) { Log.d( "ProfileTest", "Received profiling result file=" + profilingResult.resultFilePath ) setupProfileUploadWorker(profilingResult.resultFilePath) } else { Log.e( "ProfileTest", "Profiling failed errorcode=" + profilingResult.errorCode + " errormsg=" + profilingResult.errorMessage ) } } profilingManager.registerForAllProfilingResults(mainExecutor, resultCallback) profilingManager.addProfilingTriggers(triggers) }
Java
public void recordWithTrigger() { ProfilingManager profilingManager = getApplicationContext().getSystemService( ProfilingManager.class); List<ProfilingTrigger> triggers = new ArrayList<>(); ProfilingTrigger.Builder triggerBuilder = new ProfilingTrigger.Builder( ProfilingTrigger.TRIGGER_TYPE_APP_FULLY_DRAWN); triggerBuilder.setRateLimitingPeriodHours(1); triggers.add(triggerBuilder.build()); Executor mainExecutor = Executors.newSingleThreadExecutor(); Consumer<ProfilingResult> resultCallback = new Consumer<ProfilingResult>() { @Override public void accept(ProfilingResult profilingResult) { if (profilingResult.getErrorCode() == ProfilingResult.ERROR_NONE) { Log.d( "ProfileTest", "Received profiling result file=" + profilingResult.getResultFilePath()); setupProfileUploadWorker(profilingResult.getResultFilePath()); } else { Log.e( "ProfileTest", "Profiling failed errorcode=" + profilingResult.getErrorCode() + " errormsg=" + profilingResult.getErrorMessage()); } } }; profilingManager.registerForAllProfilingResults(mainExecutor, resultCallback); profilingManager.addProfilingTriggers(triggers); }
Le code effectue les étapes suivantes :
- Obtenir le gestionnaire : récupère le service
ProfilingManager. - Définir un déclencheur : crée un
ProfilingTriggerpourTRIGGER_TYPE_APP_FULLY_DRAWN. Cet événement se produit lorsque l'application signale qu'elle a terminé son démarrage et qu'elle est interactive. - Définir des limites de débit : applique une limite de débit d'une heure à ce déclencheur spécifique (
setRateLimitingPeriodHours(1)). Cela empêche l'application d'enregistrer plus d'un profil de démarrage par heure. - Enregistrer l'écouteur : appelle
registerForAllProfilingResultspour définir le rappel qui gère le résultat. Ce rappel reçoit le chemin d'accès du profil enregistré viagetResultFilePath(). - Ajouter des déclencheurs : enregistre la liste des déclencheurs auprès de
ProfilingManagerà l'aide deaddProfilingTriggers. - Déclencher un événement : appelle
reportFullyDrawn(), qui émet l'événementTRIGGER_TYPE_APP_FULLY_DRAWNvers le système, déclenchant une collecte de profils en supposant qu'une trace système en arrière-plan était en cours d'exécution et qu'un quota de limiteur de débit est disponible. Cette étape facultative illustre un flux de bout en bout, car votre application doit appelerreportFullyDrawn()pour ce déclencheur.
Récupérer la trace
Le système enregistre les profils basés sur des déclencheurs dans le même répertoire que les autres profils. Le nom de fichier des traces déclenchées respecte le format suivant :
profile_trigger_<profile_type_code>_<datetime>.<profile-type-name>
Vous pouvez extraire le fichier à l'aide d'ADB. Par exemple, pour extraire la trace système capturée avec l'exemple de code à l'aide d'ADB, procédez comme suit :
adb pull /data/user/0/com.example.sampleapp/files/profiling/profile_trigger_1_2025-05-06-14-12-40.perfetto-trace
Pour en savoir plus sur la visualisation de ces traces, consultez Récupérer et analyser les données de profilage.
Fonctionnement du traçage en arrière-plan
Pour capturer des données avant un déclencheur, l'OS démarre régulièrement une trace en arrière-plan. Si un déclencheur se produit alors que cette trace en arrière-plan est active et que votre application est enregistrée pour celui-ci, le système enregistre le profil de trace dans le répertoire de votre application. Le profil inclura alors les informations qui ont conduit au déclencheur.
Une fois le profil enregistré, le système en informe votre application à l'aide du rappel fourni à registerForAllProfilingResults. Ce rappel fournit le chemin d'accès au profil capturé, auquel vous pouvez accéder en appelant ProfilingResult#getResultFilePath().
Pour réduire l'impact sur les performances de l'appareil et l'autonomie de la batterie, le système n'exécute pas de traces en arrière-plan en continu. À la place, il utilise une méthode d'échantillonnage. Le système démarre de manière aléatoire une trace en arrière-plan dans un délai défini (avec une durée minimale et maximale). L'espacement aléatoire de ces traces améliore la couverture des déclencheurs.
Les profils déclenchés par le système ont une taille maximale définie par le système. Ils utilisent donc un tampon circulaire. Une fois le tampon plein, les nouvelles données de trace écrasent les données les plus anciennes. Comme illustré dans la figure 1, une trace capturée peut ne pas couvrir toute la durée de l'enregistrement en arrière-plan si la mémoire tampon se remplit. Elle représente plutôt l'activité la plus récente qui a conduit au déclencheur.
Implémenter une limitation du débit spécifique au déclencheur
Les déclencheurs à haute fréquence peuvent rapidement consommer le quota du limiteur de débit de votre application. Pour mieux comprendre le limiteur de débit, nous vous encourageons à consulter Fonctionnement du limiteur de débit. Pour éviter qu'un seul type de déclencheur n'épuise votre quota, vous pouvez implémenter une limitation du débit spécifique au déclencheur.
ProfilingManager accepte la limitation du débit spécifique aux déclencheurs définie par l'application. Cela vous permet d'ajouter une autre couche de limitation basée sur le temps en plus de la limitation du débit existante. Utilisez l'API setRateLimitingPeriodHours pour définir un temps de recharge spécifique pour un déclencheur. Une fois le délai d'attente expiré, vous pouvez le déclencher à nouveau.
Déboguer des déclencheurs localement
Comme les traces en arrière-plan s'exécutent à des moments aléatoires, il est difficile de déboguer les déclencheurs localement. Pour forcer une trace en arrière-plan à des fins de test, utilisez la commande ADB suivante :
adb shell device_config put profiling_testing system_triggered_profiling.testing_package_name <com.example.myapp>
Cette commande force le système à démarrer une trace continue en arrière-plan pour le package spécifié, ce qui permet à chaque déclencheur de collecter un profil si la limitation du débit l'autorise.
Vous pouvez également activer d'autres options de débogage, par exemple désactiver le limiteur de débit lors du débogage local. Pour en savoir plus, consultez Commandes de débogage pour le profilage local.