ART-Dienstkonfiguration

Bevor Sie beginnen, sehen Sie sich eine allgemeine Übersicht über den ART-Dienst an.

Ab Android 14 wird die On-Device-AOT-Kompilierung für Apps (auch als dexopt bezeichnet) vom ART-Dienst verwaltet. Der ART-Dienst ist Teil des ART-Moduls und kann über Systemeigenschaften und APIs angepasst werden.

Systemeigenschaften

Der ART-Dienst unterstützt alle relevanten dex2oat-Optionen.

Außerdem unterstützt der ART-Dienst die folgenden Systemeigenschaften:

pm.dexopt.<Grund>

Dies ist eine Reihe von Systemeigenschaften, die die Standardcompilerfilter für alle vordefinierten Kompilierungsgründe festlegen, die in Dexopt-Szenarien beschrieben sind.

Weitere Informationen finden Sie unter Compiler-Filter.

Die Standardwerte sind:

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 (Standard: Geschwindigkeit)

Dies ist der Fallback-Compilerfilter für Apps, die von anderen Apps verwendet werden.

Prinzipiell führt ART Service eine profilgestützte Kompilierung (speed-profile) für wenn möglich, in der Regel während der Hintergrund-Deaktivierung. Es gibt jedoch einige Apps, die von anderen Apps verwendet werden (entweder über <uses-library> oder dynamisch mit Context#createPackageContext über CONTEXT_INCLUDE_CODE geladen). Solche Apps können aus Datenschutzgründen keine lokalen Profile verwenden.

Wenn für eine solche App eine profilbasierte Kompilierung angefordert wird, versucht der ART-Dienst zuerst, ein Cloud-Profil zu verwenden. Wenn kein Cloud-Profil vorhanden ist, ART Service verwendet den von pm.dexopt.shared angegebenen Compiler-Filter.

Wenn die angeforderte Kompilierung nicht profilbasiert ist, hat diese Property keine Auswirkungen.

pm.dexopt.<reason>.concurrency (Standard: 1)

Dies ist die Anzahl der dex2oat-Aufrufe aus bestimmten vordefinierten Gründen für die Kompilierung (first-boot, boot-after-ota, boot-after-mainline-update und bg-dexopt).

Beachten Sie, dass der Effekt dieser Option mit dex2oat-Ressourcennutzungsoptionen (dalvik.vm.*dex2oat-threads, dalvik.vm.*dex2oat-cpu-set und die Aufgabenprofile):

  • dalvik.vm.*dex2oat-threads steuert die Anzahl der Threads für jeden dex2oat-Aufruf, während pm.dexopt.<reason>.concurrency die Anzahl der dex2oat-Aufrufe steuert. Das heißt, die maximale Anzahl gleichzeitiger Threads ist das Produkt der beiden Systemeigenschaften.
  • dalvik.vm.*dex2oat-cpu-set und die Aufgabenprofile binden immer den CPU-Kern. Auslastung, unabhängig von der maximalen Anzahl gleichzeitiger Threads (im Folgenden oben).

Ein einzelner dex2oat-Aufruf nutzt möglicherweise nicht alle CPU-Kerne, unabhängig davon, von dalvik.vm.*dex2oat-threads. Daher erhöht sich die Anzahl der dex2oat- Aufrufe (pm.dexopt.<reason>.concurrency) können CPU-Kerne besser nutzen, um den Gesamtfortschritt von Dexopt zu beschleunigen. Dies ist besonders nützlich, wenn Sie starten.

Zu viele dex2oat-Aufrufe können jedoch dazu führen, dass dem Gerät der Arbeitsspeicher ausgeht. Dies kann jedoch abgemildert werden, indem dalvik.vm.dex2oat-swap auf true festgelegt wird, um die Verwendung einer Auslagerungsdatei zu ermöglichen. Zu viele Aufrufe können auch zu unnötigen Kontextwechseln führen. Sie sollten diese Zahl daher sorgfältig für jedes Produkt einzeln bewerten.

pm.dexopt.downgrade_after_inactive_days (Standardeinstellung: nicht festgelegt)

Wenn diese Option aktiviert ist, deaktiviert der ART-Dienst nur Apps, die in den letzten angegebenen Tagen verwendet wurden.

Wenn nur noch wenig Speicherplatz verfügbar ist, wird während der Hintergrunddexoptimierung der ART-Service aktiviert. stufen den Compilerfilter von Anwendungen herunter, die in den letzten angegebenen Anzahl der Tage, um Speicherplatz freizugeben. Der Compiler-Grund hierfür ist inactive, und der Compiler-Filter wird durch pm.dexopt.inactive bestimmt. Der Gruppenbereich Der Grenzwert zum Auslösen dieser Funktion ist der Grenzwert für wenig Speicherplatz des Speichermanagers (konfigurierbar über die globalen Einstellungen sys_storage_threshold_percentage und sys_storage_threshold_max_bytes, Standard: 500 MB) plus 500 MB.

Wenn Sie die Liste der Pakete über ArtManagerLocal#setBatchDexoptStartCallback anpassen, werden die Pakete in der Liste, die BatchDexoptStartCallback für bg-dexopt zur Verfügung stellt, nie herabgestuft.

pm.dexopt.disable_bg_dexopt (Standardeinstellung: false)

Diese Funktion ist nur für Tests vorgesehen. Dadurch wird verhindert, dass der ART-Dienst den Deopt-Job im Hintergrund plant.

Wenn der Hintergrund-Dexopt-Job bereits geplant ist, aber noch nicht ausgeführt wurde: hat keine Auswirkung. Der Job wird also weiterhin ausgeführt.

Eine empfohlene Abfolge von Befehlen, um zu verhindern, dass der Hintergrund-Entfernungsjob ausgeführt wird:

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

Mit der ersten Zeile wird verhindert, dass der dexopt-Job im Hintergrund geplant wird, falls er noch nicht geplant ist. In der zweiten Zeile wird die Planung des dexopt-Jobs im Hintergrund aufgehoben, falls er bereits geplant ist, und er wird sofort abgebrochen, falls er gerade ausgeführt wird.

ART-Service-APIs

Der ART-Dienst stellt Java APIs für die Anpassung bereit. Die APIs sind definiert in ArtManagerLocal Siehe Javadoc in art/libartservice/service/java/com/android/server/art/ArtManagerLocal.java für Nutzungen (Android 14-Quelle, unveröffentlichte Entwicklungsquelle).

ArtManagerLocal ist ein Singleton, der von LocalManagerRegistry verwaltet wird. Die Hilfsfunktion com.android.server.pm.DexOptHelper#getArtManagerLocal hilft Ihnen dabei.

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

Die meisten APIs erfordern eine Instanz von PackageManagerLocal.FilteredSnapshot, die die Informationen aller Apps enthält. Rufen Sie dazu einfach PackageManagerLocal#withFilteredSnapshot, wobei PackageManagerLocal ebenfalls ein Singleton-Paket von LocalManagerRegistry, das hier erhältlich ist: com.android.server.pm.PackageManagerServiceUtils#getPackageManagerLocal.

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

Im Folgenden sind einige typische Anwendungsfälle der APIs aufgeführt.

Dexopt für eine App auslösen

Sie können dexopt jederzeit für eine beliebige App auslösen, indem Sie ArtManagerLocal#dexoptPackage aufrufen.

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

Sie können auch einen eigenen Grund für die Deaktivierung von Dexopt angeben. In diesem Fall werden die Prioritätsklasse Der Compilerfilter muss explizit festgelegt werden.

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());
}

dexopt abbrechen

Wenn ein Vorgang durch einen dexoptPackage-Aufruf initiiert wird, können Sie eine Abbruchsignal, mit dem Sie den Vorgang an einem bestimmten Punkt abbrechen können. Das kann hilfreich sein, wenn Sie dexopt asynchron ausführen.

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();

Sie können auch die Deaktivierung von dexopt im Hintergrund abbrechen, die vom ART-Dienst initiiert wird.

getArtManagerLocal().cancelBackgroundDexoptJob();

Dexopt-Ergebnisse abrufen

Wenn ein Vorgang durch einen dexoptPackage-Aufruf initiiert wird, können Sie das Ergebnis abrufen aus dem Rückgabewert.

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

// Process the result here.
...

Der ART-Dienst initiiert in vielen Fällen auch selbst DeXOpt-Vorgänge, z. B. im Hintergrund. Wenn Sie alle dexopt-Ergebnisse abhören möchten, unabhängig davon, ob der Vorgang durch einen dexoptPackage-Aufruf oder durch den ART-Dienst initiiert wird, verwenden Sie ArtManagerLocal#addDexoptDoneCallback.

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

Das erste Argument bestimmt, ob nur Aktualisierungen im Ergebnis berücksichtigt werden sollen. Wenn nur Pakete überwachen möchten, die per Dexopt aktualisiert wurden, setzen Sie den Wert auf "true".

Das zweite Argument ist der Ausführende des Callbacks. Wenn Sie den Rückruf in demselben Thread ausführen möchten, in dem dexopt ausgeführt wird, verwenden Sie Runnable::run. Wenn Sie das nicht möchten, -Callback zum Blockieren von Dexopt. Verwenden Sie einen asynchronen Executor.

Sie können mehrere Callbacks hinzufügen. Der ART-Dienst führt sie dann nacheinander aus. Alle Callbacks bleiben für alle zukünftigen Anrufe aktiv, es sei denn, Sie entfernen sie.

Wenn du einen Callback entfernen möchtest, behalte die Referenz des Callbacks bei, wenn du fügen Sie sie hinzu und verwenden Sie 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);

Paketliste und Dexopt-Parameter anpassen

Der ART-Dienst startet die DeXOpt-Vorgänge selbst beim Starten und im Hintergrund. Verwenden Sie ArtManagerLocal#setBatchDexoptStartCallback, um die Paketliste oder die dexopt-Parameter für diese Vorgänge anzupassen.

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.
      }
    });

Sie können der Paketliste Elemente hinzufügen, Elemente daraus entfernen, sie sortieren oder sogar eine ganz andere Liste verwenden.

Unbekannte Gründe müssen von deinem Rückruf ignoriert werden, da weitere Gründe hinzugefügt werden können in in die Zukunft zu führen.

Sie können maximal einen BatchDexoptStartCallback festlegen. Der Callback bleibt Für alle zukünftigen Anrufe aktiv, es sei denn, Sie löschen sie.

Wenn Sie den Rückruf löschen möchten, verwenden Sie ArtManagerLocal#clearBatchDexoptStartCallback.

getArtManagerLocal().clearBatchDexoptStartCallback();

Parameter des dexopt-Jobs im Hintergrund anpassen

Standardmäßig wird der Job zur Hintergrunddexopt-Funktion einmal täglich ausgeführt, wenn das Gerät inaktiv ist und Aufladen. Das lässt sich mit ArtManagerLocal#setScheduleBackgroundDexoptJobCallback ändern.

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

Du kannst maximal ein ScheduleBackgroundDexoptJobCallback festlegen. Der Rückruf bleibt für alle zukünftigen Anrufe aktiv, es sei denn, Sie löschen ihn.

Wenn Sie den Rückruf löschen möchten, verwenden Sie ArtManagerLocal#clearScheduleBackgroundDexoptJobCallback.

getArtManagerLocal().clearScheduleBackgroundDexoptJobCallback();

Dexopt vorübergehend deaktivieren

Jeder von ART Service initiierte Dexopt-Vorgang löst ein BatchDexoptStartCallback Sie können die Vorgänge weiter abbrechen, Dexopt effektiv deaktivieren.

Wenn Sie die Hintergrunddexopt-Funktion abbrechen, wird die Standardeinstellung verwendet. Wiederholungsrichtlinie (30 Sekunden, exponentiell, begrenzt auf 5 Stunden).

// 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);

Sie können maximal eine BatchDexoptStartCallback haben. Wenn Sie auch BatchDexoptStartCallback zum Anpassen der Paketliste oder zum Entfernen der Parameter müssen Sie den Code in einem Callback kombinieren.

// Bad example.

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

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

Der DeXOpt-Vorgang, der bei der App-Installation ausgeführt wird, wird nicht vom ART-Dienst initiiert. Stattdessen wird der Vorgang vom Paketmanager über ein dexoptPackage Anruf. Daher wird BatchDexoptStartCallback nicht ausgelöst. Um die Deaktivierung bei der App-Installation zu deaktivieren, Paketmanager kann dexoptPackage nicht aufrufen.

Compilerfilter für bestimmte Pakete überschreiben (Android 15 und höher)

Sie können den Compiler-Filter für bestimmte Pakete überschreiben, indem Sie eine über setAdjustCompilerFilterCallback zurückrufen. Der Rückruf wird immer dann aufgerufen, wenn ein Paket dexoptiert wird, unabhängig davon, ob die Deaktivierung durch den ART-Dienst während des Bootens und der Deaktivierung im Hintergrund oder durch einen dexoptPackage API-Aufruf initiiert wird.

Wenn ein Paket keine Anpassung erfordert, muss der Callback originalCompilerFilter

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

Du kannst nur eine AdjustCompilerFilterCallback festlegen. Wenn Sie AdjustCompilerFilterCallback zum Überschreiben des Compiler-Filters für mehrere Paketen, müssen Sie den Code in einem Callback kombinieren. Der Callback bleibt Für alle zukünftigen Anrufe aktiv, es sei denn, Sie löschen sie.

Wenn du den Callback löschen möchtest, verwende ArtManagerLocal#clearAdjustCompilerFilterCallback

getArtManagerLocal().clearAdjustCompilerFilterCallback();

Weitere Anpassungen

Der ART-Dienst unterstützt auch einige andere Anpassungen.

Grenzwert zu Temperatur für Hintergrund-Dexopt festlegen

Die thermische Steuerung des dexopt-Jobs im Hintergrund erfolgt über den Job Scheduler. Der Job wird sofort abgebrochen, wenn die Temperatur erreicht THERMAL_STATUS_MODERATE Der Schwellenwert von THERMAL_STATUS_MODERATE ist einstellbar.

Prüfen, ob dexopt im Hintergrund ausgeführt wird

Der Hintergrund-dexopt-Job wird vom Job Scheduler verwaltet und seine Job-ID lautet 27873780. Verwenden Sie Job Scheduler APIs, um festzustellen, ob der Job ausgeführt wird.

// 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.
  ...
}

Profil für Dexopt angeben

Wenn Sie ein Profil für dexopt verwenden möchten, legen Sie eine .prof- oder .dm-Datei neben die APK-Datei ab.

Die Datei .prof muss eine Profildatei im Binärformat sein und der Dateiname muss Der Dateiname des APK + .prof. Beispiel:

base.apk.prof

Der Dateiname der .dm-Datei muss der Dateiname der APK-Datei mit dem Erweiterung durch .dm ersetzt. Beispiel:

base.dm

Um zu prüfen, ob das Profil für dexopt verwendet wird, führen Sie dexopt mit speed-profile aus und prüfen Sie das Ergebnis.

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

Die erste Zeile löscht alle von der Laufzeit erstellten Profile (d.h. die in /data/misc/profiles) und prüfen Sie, ob das Profil neben dem APK das einzige Profil, das ART Service verwenden kann. In der zweiten Zeile wird dexopt mit speed-profile ausgeführt und -v übergeben, um das ausführliche Ergebnis zu drucken.

Wenn das Profil verwendet wird, wird in den Ergebnissen actualCompilerFilter=speed-profile angezeigt. Andernfalls wird actualCompilerFilter=verify angezeigt. Beispiel:

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}

Typische Gründe, warum der ART-Dienst das Profil nicht verwendet:

  • Das Profil hat einen falschen Dateinamen oder befindet sich nicht neben dem APK.
  • Das Profil hat das falsche Format.
  • Das Profil entspricht nicht dem APK. (Die Prüfsummen im Profil stimmt mit den Prüfsummen der .dex-Dateien im APK überein.)