Configuration du service ART

Avant de commencer, consultez une présentation générale du service ART.

À partir d'Android 14, compilation anticipée (ou anticipée) sur l'appareil pour (ou dexopt) est gérée par le service ART. Le service ART est intégré à ART. par l'intermédiaire des propriétés système et des API.

Propriétés système

Le service ART prend en charge toutes les fonctionnalités Options dex2oat.

De plus, le service ART prend en charge les propriétés système suivantes:

pm.dexopt.<reason>

Il s'agit d'un ensemble de propriétés système qui déterminent les filtres de compilation par défaut pour tous les motifs de compilation prédéfinis décrits dans les scénarios de DevOps.

Pour en savoir plus, consultez Filtres du compilateur.

Les valeurs par défaut standards sont les suivantes:

pm.dexopt.first-boot=verify
pm.dexopt.boot-after-ota=verify
pm.dexopt.boot-after-mainline-update=verify
pm.dexopt.bg-dexopt=speed-profile
pm.dexopt.inactive=verify
pm.dexopt.cmdline=verify

pm.dexopt.shared (valeur par défaut: vitesse)

Il s'agit du filtre de compilation de remplacement pour les applications utilisées par d'autres applications.

En principe, le service ART effectue une compilation guidée par profil (speed-profile) pour toutes les applications lorsque cela est possible, généralement lors du dexopt en arrière-plan. Cependant, il existe certaines applications utilisées par d'autres applications (via <uses-library> ou chargées de manière dynamique à l'aide de Context#createPackageContext avec CONTEXT_INCLUDE_CODE). Ces applications ne peuvent pas utiliser l'accès local pour des raisons de confidentialité.

Pour ce type d'application, si la compilation guidée par profil est demandée, le service ART doit d'abord être utilisé. tente d'utiliser un profil cloud. Si aucun profil cloud n'existe, le service ART revient à utiliser le filtre de compilation spécifié par pm.dexopt.shared.

Si la compilation demandée n'est pas guidée par le profil, cette propriété n'a aucun effet.

pm.dexopt.<reason>.concurrency (par défaut: 1)

Il s'agit du nombre d'appels dex2oat pour certaines compilations prédéfinies motifs (first-boot, boot-after-ota, boot-after-mainline-update et bg-dexopt).

Notez que l'effet de cette option est combiné Options d'utilisation des ressources dex2oat (dalvik.vm.*dex2oat-threads, dalvik.vm.*dex2oat-cpu-set et les profils de tâches):

  • dalvik.vm.*dex2oat-threads contrôle le nombre de threads pour chaque dex2oat appel, tandis que pm.dexopt.<reason>.concurrency contrôle le nombre des appels dex2oat. Autrement dit, le nombre maximal de threads simultanés est de produit des deux propriétés système.
  • dalvik.vm.*dex2oat-cpu-set et les profils de tâche ont toujours lié le cœur de processeur quel que soit le nombre maximal de threads simultanés (abordés ci-dessus).

Un seul appel de dex2oat peut ne pas exploiter pleinement tous les cœurs de processeur, sur dalvik.vm.*dex2oat-threads. L'augmentation du nombre de "dex2oat" les appels (pm.dexopt.<reason>.concurrency) peuvent mieux utiliser les cœurs de processeur pour accélérer la progression globale de dexopt. Ceci est particulièrement utile pendant démarrer.

Toutefois, un trop grand nombre d'appels dex2oat peut entraîner l'épuisement mémoire, même si cela peut être atténué en définissant dalvik.vm.dex2oat-swap sur true pour permettre l'utilisation d'un fichier d'échange. Un trop grand nombre d'appels peut aussi entraîner un changement de contexte inutile. Ce nombre doit donc être réglé avec soin. produit par produit.

pm.dexopt.downgrade_after_inactive_days (valeur par défaut: non définie)

Si cette option est définie, le service ART ne dexopte que les applications utilisées au cours de la dernière nombre de jours.

De plus, si l'espace de stockage est presque faible, en arrière-plan, le service ART rétrograde le filtre de compilation des applications qui ne sont pas utilisées au cours de la pour libérer de l'espace. Pour le compilateur, cela est inactive, et le filtre de compilateur est déterminé par pm.dexopt.inactive. L'espace de déclenchement de cette fonctionnalité est le seuil de faible espace du gestionnaire d'espace de stockage (configurable via les paramètres globaux sys_storage_threshold_percentage et sys_storage_threshold_max_bytes, valeur par défaut: 500 Mo) plus 500 Mo.

Si vous personnalisez la liste des packages via ArtManagerLocal#setBatchDexoptStartCallback, les packages de la liste fournie. par BatchDexoptStartCallback pour bg-dexopt ne sont jamais rétrogradés.

pm.dexopt.disable_bg_dexopt (valeur par défaut : "false")

Ces informations ne sont utilisées qu'à des fins de test. Cela empêche le service ART de planifier l'arrière-plan dexopt.

Si le job dexopt en arrière-plan est déjà planifié, mais n'a pas encore été exécuté, n'a aucun effet. Autrement dit, le job continue de s'exécuter.

Séquence de commandes recommandée pour empêcher le job dexopt en arrière-plan en cours d'exécution:

setprop pm.dexopt.disable_bg_dexopt true
pm bg-dexopt-job --disable

La première ligne empêche la planification de la tâche dexopt en arrière-plan, si elle est pas encore planifiée. La deuxième ligne annule la planification du job dexopt en arrière-plan, si il est déjà planifié et annule immédiatement la tâche dexopt en arrière-plan, si s'il est exécuté.

API de service ART

Le service ART expose des API Java pour la personnalisation. Les API sont définies ArtManagerLocal Consultez le Javadoc dans art/libartservice/service/java/com/android/server/art/ArtManagerLocal.java pour (source Android 14, source de développement non publiée).

ArtManagerLocal est un singleton détenu par LocalManagerRegistry. Une aide la fonction com.android.server.pm.DexOptHelper#getArtManagerLocal vous aide l'obtenir.

import static com.android.server.pm.DexOptHelper.getArtManagerLocal;

La plupart des API nécessitent une instance de PackageManagerLocal.FilteredSnapshot, qui contient les informations de toutes les applications. Pour l'obtenir, appelez PackageManagerLocal#withFilteredSnapshot, où PackageManagerLocal est également un singleton détenu par LocalManagerRegistry et pouvant être obtenu via com.android.server.pm.PackageManagerServiceUtils#getPackageManagerLocal

import static com.android.server.pm.PackageManagerServiceUtils.getPackageManagerLocal;

Voici quelques cas d'utilisation types des API.

Déclencher dexopt pour une application

Vous pouvez déclencher dexopt pour n'importe quelle appli à tout moment en appelant ArtManagerLocal#dexoptPackage

try (var snapshot = getPackageManagerLocal().withFilteredSnapshot()) {
  getArtManagerLocal().dexoptPackage(
      snapshot,
      "com.google.android.calculator",
      new DexoptParams.Builder(ReasonMapping.REASON_INSTALL).build());
}

Vous pouvez également transmettre votre propre motif dexopt. Dans ce cas, la classe de priorité et le filtre du compilateur doit être défini explicitement.

try (var snapshot = getPackageManagerLocal().withFilteredSnapshot()) {
  getArtManagerLocal().dexoptPackage(
      snapshot,
      "com.google.android.calculator",
      new DexoptParams.Builder("my-reason")
          .setCompilerFilter("speed-profile")
          .setPriorityClass(ArtFlags.PRIORITY_BACKGROUND)
          .build());
}

Annuler dexopt

Si une opération est lancée par un appel dexoptPackage, vous pouvez transmettre un signal d'annulation, qui vous permet d'annuler l'opération à un moment donné. Cela peut être utile lorsque vous exécutez dexopt de manière asynchrone.

Executor executor = ...;  // Your asynchronous executor here.
var cancellationSignal = new CancellationSignal();
executor.execute(() -> {
  try (var snapshot = getPackageManagerLocal().withFilteredSnapshot()) {
    getArtManagerLocal().dexoptPackage(
        snapshot,
        "com.google.android.calculator",
        new DexoptParams.Builder(ReasonMapping.REASON_INSTALL).build(),
        cancellationSignal);
  }
});

// When you want to cancel the operation.
cancellationSignal.cancel();

Vous pouvez également annuler le dexopt en arrière-plan, initié par le service ART.

getArtManagerLocal().cancelBackgroundDexoptJob();

Obtenir des résultats dexopt

Si une opération est lancée par un appel dexoptPackage, vous pouvez obtenir le résultat de la valeur renvoyée.

DexoptResult result;
try (var snapshot = getPackageManagerLocal().withFilteredSnapshot()) {
  result = getArtManagerLocal().dexoptPackage(...);
}

// Process the result here.
...

Le service ART lance lui-même des opérations dexopt dans de nombreux scénarios : dexopt. Pour écouter tous les résultats dexopt, que l'opération soit initié par un appel dexoptPackage ou par le service ART, utilisez ArtManagerLocal#addDexoptDoneCallback

getArtManagerLocal().addDexoptDoneCallback(
    false /* onlyIncludeUpdates */,
    Runnable::run,
    (result) -> {
      // Process the result here.
      ...
    });

Le premier argument détermine s'il faut inclure uniquement les mises à jour dans le résultat. Si vous ne voulez écouter que les packs mis à jour par dexopt, définissez-le sur true.

Le deuxième argument est l'exécuteur du rappel. Pour exécuter le rappel sur le même thread qui exécute dexopt, utilisez Runnable::run. Si vous ne souhaitez pas pour bloquer dexopt, utilisez un exécuteur asynchrone.

Vous pouvez ajouter plusieurs rappels, et le service ART les exécutera tous de manière séquentielle. Tous les rappels resteront actifs pour tous les appels ultérieurs, sauf si vous les supprimez.

Si vous souhaitez supprimer un rappel, conservez la référence du rappel lorsque vous l'ajouter et utiliser ArtManagerLocal#removeDexoptDoneCallback.

DexoptDoneCallback callback = (result) -> {
  // Process the result here.
  ...
};

getArtManagerLocal().addDexoptDoneCallback(
    false /* onlyIncludeUpdates */, Runnable::run, callback);

// When you want to remove it.
getArtManagerLocal().removeDexoptDoneCallback(callback);

Personnaliser la liste des packages et les paramètres dexopt

Le service ART lance lui-même les opérations dexopt au démarrage et en arrière-plan dexopt. Pour personnaliser la liste de packages ou les paramètres dexopt pour ces opérations, utiliser ArtManagerLocal#setBatchDexoptStartCallback.

getArtManagerLocal().setBatchDexoptStartCallback(
    Runnable::run,
    (snapshot, reason, defaultPackages, builder, cancellationSignal) -> {
      switch (reason) {
        case ReasonMapping.REASON_BG_DEXOPT:
          var myPackages = new ArrayList<String>(defaultPackages);
          myPackages.add(...);
          myPackages.remove(...);
          myPackages.sort(...);
          builder.setPackages(myPackages);
          break;
        default:
          // Ignore unknown reasons.
      }
    });

Vous pouvez ajouter des éléments à la liste de packages, en supprimer, la trier ou même utiliser une liste complètement différente.

Votre rappel doit ignorer des motifs inconnus, car d'autres motifs peuvent être ajoutés dans à l'avenir.

Vous ne pouvez définir qu'un seul BatchDexoptStartCallback. Le rappel sera maintenu active pour tous les prochains appels, sauf si vous l'effacez.

Si vous souhaitez effacer le rappel, utilisez ArtManagerLocal#clearBatchDexoptStartCallback

getArtManagerLocal().clearBatchDexoptStartCallback();

Personnaliser les paramètres de la tâche dexopt en arrière-plan

Par défaut, la tâche dexopt en arrière-plan s'exécute une fois par jour lorsque l'appareil est inactif et en charge. Vous pouvez modifier ce paramètre à l'aide de ArtManagerLocal#setScheduleBackgroundDexoptJobCallback

getArtManagerLocal().setScheduleBackgroundDexoptJobCallback(
    Runnable::run,
    builder -> {
      builder.setPeriodic(TimeUnit.DAYS.toMillis(2));
    });

Vous ne pouvez définir qu'un seul ScheduleBackgroundDexoptJobCallback. Le rappel reste actif pour tous les prochains appels, sauf si vous l'effacez.

Si vous souhaitez effacer le rappel, utilisez ArtManagerLocal#clearScheduleBackgroundDexoptJobCallback

getArtManagerLocal().clearScheduleBackgroundDexoptJobCallback();

Désactiver temporairement dexopt

Toute opération dexopt initiée par le service ART déclenche une BatchDexoptStartCallback Vous pouvez continuer à annuler les opérations pour désactiver efficacement dexopt.

Si l'opération que vous annulez est dexopt en arrière-plan, elle suit la stratégie de nouvelle tentative (30 secondes, exponentielle, plafonnée à 5 heures).

// Good example.

var shouldDisableDexopt = new AtomicBoolean(false);

getArtManagerLocal().setBatchDexoptStartCallback(
    Runnable::run,
    (snapshot, reason, defaultPackages, builder, cancellationSignal) -> {
      if (shouldDisableDexopt.get()) {
        cancellationSignal.cancel();
      }
    });

// Disable dexopt.
shouldDisableDexopt.set(true);
getArtManagerLocal().cancelBackgroundDexoptJob();

// Re-enable dexopt.
shouldDisableDexopt.set(false);

Vous ne pouvez avoir qu'un seul BatchDexoptStartCallback. Si vous souhaitez également utiliser BatchDexoptStartCallback pour personnaliser la liste de packages ou les paramètres dexopt ; vous devez combiner le code dans un seul rappel.

// Bad example.

// Disable dexopt.
getArtManagerLocal().unscheduleBackgroundDexoptJob();

// Re-enable dexopt.
getArtManagerLocal().scheduleBackgroundDexoptJob();

L'opération dexopt effectuée lors de l'installation de l'application n'est pas lancée par ART. de service. Il est lancé par le gestionnaire de packages dexoptPackage appel. Par conséquent, elle ne déclenche pas BatchDexoptStartCallback Pour désactiver dexopt lors de l'installation de l'application, empêchez le d'appeler dexoptPackage.

Remplacer le filtre de compilation pour certains packages (Android 15 et versions ultérieures)

Vous pouvez remplacer le filtre de compilateur pour certains packages en enregistrant un via setAdjustCompilerFilterCallback. Le rappel est appelé chaque fois qu'un package va être dexopted, peu importe que dexopt soit initié par Service ART pendant le démarrage et l'opération dexopt en arrière-plan ou par un appel d'API dexoptPackage

Si un colis n'a pas besoin d'être ajusté, le rappel doit renvoyer originalCompilerFilter

getArtManagerLocal().setAdjustCompilerFilterCallback(
    Runnable::run,
    (packageName, originalCompilerFilter, reason) -> {
      if (isVeryImportantPackage(packageName)) {
        return "speed-profile";
      }
      return originalCompilerFilter;
    });

Vous ne pouvez définir qu'un seul AdjustCompilerFilterCallback. Si vous souhaitez utiliser AdjustCompilerFilterCallback pour remplacer le filtre de compilation pour plusieurs vous devez combiner le code dans un seul rappel. Le rappel est maintenu active pour tous les prochains appels, sauf si vous l'effacez.

Si vous souhaitez effacer le rappel, utilisez ArtManagerLocal#clearAdjustCompilerFilterCallback

getArtManagerLocal().clearAdjustCompilerFilterCallback();

Autres personnalisations

Le service ART prend également en charge d'autres personnalisations.

Définir le seuil thermique pour la dexopt en arrière-plan

Le contrôle thermique du job dexopt en arrière-plan est effectué par le planificateur de jobs. Le job est immédiatement annulé lorsque la température atteint THERMAL_STATUS_MODERATE Le seuil de THERMAL_STATUS_MODERATE est réglable.

Déterminer si dexopt est en cours d'exécution en arrière-plan

Le job dexopt en arrière-plan est géré par le planificateur de jobs, et son ID de job est 27873780 Pour déterminer si le job est en cours d'exécution, utilisez les API Job Scheduler.

// Good example.

var jobScheduler =
    Objects.requireNonNull(mContext.getSystemService(JobScheduler.class));
int reason = jobScheduler.getPendingJobReason(27873780);

if (reason == PENDING_JOB_REASON_EXECUTING) {
  // Do something when the job is running.
  ...
}
// Bad example.

var backgroundDexoptRunning = new AtomicBoolean(false);

getArtManagerLocal().setBatchDexoptStartCallback(
    Runnable::run,
    (snapshot, reason, defaultPackages, builder, cancellationSignal) -> {
      if (reason.equals(ReasonMapping.REASON_BG_DEXOPT)) {
        backgroundDexoptRunning.set(true);
      }
    });

getArtManagerLocal().addDexoptDoneCallback(
    false /* onlyIncludeUpdates */,
    Runnable::run,
    (result) -> {
      if (result.getReason().equals(ReasonMapping.REASON_BG_DEXOPT)) {
        backgroundDexoptRunning.set(false);
      }
    });

if (backgroundDexoptRunning.get()) {
  // Do something when the job is running.
  ...
}

Fournir un profil pour dexopt

Pour utiliser un profil afin de guider dexopt, placez un fichier .prof ou .dm à côté de APK.

Le fichier .prof doit être un fichier de profil au format binaire et le nom du fichier doit être Le nom de fichier de l'APK suivi de .prof Par exemple :

base.apk.prof

Le nom du fichier .dm doit être celui de l'APK avec le extension remplacée par .dm. Par exemple :

base.dm

Pour vérifier que le profil est utilisé pour dexopt, exécutez dexopt avec speed-profile et vérifiez le résultat.

pm art clear-app-profiles <package-name>
pm compile -m speed-profile -f -v <package-name>

La première ligne efface tous les profils produits par l'environnement d'exécution (c'est-à-dire ceux de /data/misc/profiles), le cas échéant, pour vous assurer que le profil situé à côté de l'APK est bien le seul profil que le service ART peut utiliser. La deuxième ligne exécute dexopt avec speed-profile et transmet -v pour imprimer le résultat détaillé.

Si le profil est utilisé, actualCompilerFilter=speed-profile s'affiche dans le résultat. Sinon, actualCompilerFilter=verify s'affiche. Par exemple :

DexContainerFileDexoptResult{dexContainerFile=/data/app/~~QR0fTV0UbDbIP1Su7XzyPg==/com.google.android.gms-LvusF2uARKOtBbcaPHdUtQ==/base.apk, primaryAbi=true, abi=x86_64, actualCompilerFilter=speed-profile, status=PERFORMED, dex2oatWallTimeMillis=4549, dex2oatCpuTimeMillis=14550, sizeBytes=3715344, sizeBeforeBytes=3715344}

Le service ART n'utilise généralement pas le profil pour les raisons suivantes:

  • Le nom du profil est incorrect ou il ne figure pas à côté de l'APK.
  • Le format du profil est incorrect.
  • Le profil ne correspond pas à l'APK. (Les sommes de contrôle du profil ne correspondent aux sommes de contrôle des fichiers .dex dans l'APK.)