ART-Service-Konfiguration

Bevor Sie beginnen, sehen Sie sich einen allgemeinen Überblick über den ART-Service an.

Ab Android 14 wird die geräteinterne AOT-Kompilierung für Apps (auch Dexopt genannt) vom ART Service übernommen. ART Service ist Teil des ART-Moduls und kann über Systemeigenschaften und APIs angepasst werden.

Systemeigenschaften

ART Service unterstützt alle relevanten dex2oat-Optionen .

Darüber hinaus unterstützt ART Service die folgenden Systemeigenschaften:

pm.dexopt.<Grund>

Hierbei handelt es sich um eine Reihe von Systemeigenschaften, die die Standard-Compilerfilter für alle vordefinierten Kompilierungsgründe bestimmen, die in Dexopt-Szenarien beschrieben werden.

Weitere Informationen finden Sie unter Compiler-Filter .

Die Standardvorgabewerte 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-Compiler-Filter für Apps, die von anderen Apps verwendet werden.

Grundsätzlich führt ART Service nach Möglichkeit eine profilgesteuerte Kompilierung ( speed-profile ) für alle Apps durch, typischerweise während der Dexopt-Funktion im Hintergrund. Es gibt jedoch einige Apps, die von anderen Apps verwendet werden (entweder über <uses-library> oder dynamisch geladen mithilfe von Context#createPackageContext mit CONTEXT_INCLUDE_CODE ). Aus Datenschutzgründen können solche Apps keine lokalen Profile verwenden.

Wenn für eine solche App eine profilgeführte Zusammenstellung gewünscht wird, versucht ART Service zunächst, ein Cloud-Profil zu verwenden. Wenn kein Cloud-Profil vorhanden ist, greift ART Service auf die Verwendung des durch pm.dexopt.shared angegebenen Compilerfilters zurück.

Wenn die angeforderte Zusammenstellung nicht profilgesteuert ist, hat diese Eigenschaft keine Auswirkung.

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

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

Beachten Sie, dass die Wirkung dieser Option mit den Ressourcennutzungsoptionen von dex2oat ( dalvik.vm.*dex2oat-threads , dalvik.vm.*dex2oat-cpu-set und den Aufgabenprofilen) kombiniert wird:

  • 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 begrenzen immer die CPU-Kernauslastung, unabhängig von der maximalen Anzahl gleichzeitiger Threads (siehe oben).

Ein einzelner dex2oat-Aufruf nutzt möglicherweise nicht alle CPU-Kerne vollständig aus, unabhängig von dalvik.vm.*dex2oat-threads . Daher kann eine Erhöhung der Anzahl der dex2oat-Aufrufe ( pm.dexopt.<reason>.concurrency ) die CPU-Kerne besser nutzen und so den Gesamtfortschritt von dexopt beschleunigen. Dies ist besonders beim Booten nützlich.

Zu viele dex2oat-Aufrufe können jedoch dazu führen, dass dem Gerät nicht mehr genügend Arbeitsspeicher zur Verfügung steht. Dies kann jedoch abgemildert werden, indem dalvik.vm.dex2oat-swap auf „ true gesetzt wird, um die Verwendung einer Auslagerungsdatei zu ermöglichen. Zu viele Aufrufe können auch zu unnötigem Kontextwechsel führen. Daher sollte diese Zahl für jedes Produkt sorgfältig angepasst werden.

pm.dexopt.downgrade_after_inactive_days (Standard: nicht gesetzt)

Wenn diese Option aktiviert ist, dexopt ART Service nur Apps, die innerhalb der letzten angegebenen Anzahl von Tagen verwendet wurden.

Wenn der Speicherplatz fast erschöpft ist, stuft ART Service während der Dexopt-Aktivierung im Hintergrund außerdem den Compilerfilter von Apps herab, die innerhalb der letzten angegebenen Anzahl von Tagen nicht verwendet wurden, um Speicherplatz freizugeben. Der Compilergrund hierfür ist inactive und der Compilerfilter wird durch pm.dexopt.inactive bestimmt. Der Speicherplatzschwellenwert zum Auslösen dieser Funktion ist der niedrige Speicherplatzschwellenwert des Storage Managers (konfigurierbar über die globalen Einstellungen sys_storage_threshold_percentage und sys_storage_threshold_max_bytes , Standard: 500 MB) plus 500 MB.

Wenn Sie die Paketliste über ArtManagerLocal#setBatchDexoptStartCallback anpassen, werden die Pakete in der von BatchDexoptStartCallback für bg-dexopt bereitgestellten Liste niemals herabgestuft.

pm.dexopt.disable_bg_dexopt (Standard: false)

Dies dient nur zum Testen. Dadurch wird verhindert, dass ART Service den Dexopt-Job im Hintergrund plant.

Wenn der Dexopt-Hintergrundjob bereits geplant ist, aber noch nicht ausgeführt wurde, hat diese Option keine Auswirkung. Das heißt, der Job wird weiterhin ausgeführt.

Eine empfohlene Befehlsfolge, um die Ausführung des Dexopt-Jobs im Hintergrund zu verhindern, ist:

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

Die erste Zeile verhindert, dass der Dexopt-Hintergrundjob geplant wird, sofern er noch nicht geplant ist. Die zweite Zeile hebt die Planung des Dexopt-Hintergrundjobs auf, wenn er bereits geplant ist, und bricht den Dexopt-Hintergrundjob sofort ab, wenn er ausgeführt wird.

ART-Service-APIs

ART Service stellt Java-APIs zur Anpassung bereit. Die APIs werden in ArtManagerLocal definiert. Informationen zur Verwendung finden Sie im Javadoc in art/libartservice/service/java/com/android/server/art/ArtManagerLocal.java ( Android 14-Quelle , unveröffentlichte Entwicklungsquelle ).

ArtManagerLocal ist ein Singleton, der von LocalManagerRegistry gehalten wird. Eine Hilfsfunktion com.android.server.pm.DexOptHelper#getArtManagerLocal hilft Ihnen beim Abrufen.

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

Die meisten APIs erfordern eine Instanz von PackageManagerLocal.FilteredSnapshot , die die Informationen aller Apps enthält. Sie können es erhalten, indem Sie PackageManagerLocal#withFilteredSnapshot aufrufen, wobei PackageManagerLocal auch ein Singleton ist, der von LocalManagerRegistry gehalten wird und von com.android.server.pm.PackageManagerServiceUtils#getPackageManagerLocal abgerufen werden kann.

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 für jede App jederzeit 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 Ihren eigenen Dexopt-Grund angeben. In diesem Fall müssen die Prioritätsklasse und der Compilerfilter 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 ein Abbruchsignal übergeben, mit dem Sie den Vorgang irgendwann abbrechen können. Dies kann nützlich 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 Hintergrund-Dexopt abbrechen, das vom ART Service initiiert wird.

getArtManagerLocal().cancelBackgroundDexoptJob();

Erhalten Sie Dexopt-Ergebnisse

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

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

// Process the result here.
...

ART Service initiiert Dexopt-Vorgänge in vielen Szenarien auch selbst, beispielsweise als Dexopt-Vorgang im Hintergrund. Um alle Dexopt-Ergebnisse abzuhören, unabhängig davon, ob der Vorgang durch einen dexoptPackage Aufruf oder durch den ART-Service initiiert wird, verwenden Sie ArtManagerLocal#addDexoptDoneCallback .

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

Das erste Argument bestimmt, ob nur Aktualisierungen in das Ergebnis einbezogen werden sollen. Wenn Sie nur Pakete abhören möchten, die von dexopt aktualisiert werden, setzen Sie es auf true.

Das zweite Argument ist der Ausführende des Rückrufs. Um den Rückruf auf demselben Thread auszuführen, der Dexopt ausführt, verwenden Sie Runnable::run . Wenn Sie nicht möchten, dass der Rückruf Dexopt blockiert, verwenden Sie einen asynchronen Executor.

Sie können mehrere Rückrufe hinzufügen, und ART Service führt sie alle nacheinander aus. Alle Rückrufe bleiben für alle zukünftigen Anrufe aktiv, sofern Sie sie nicht entfernen.

Wenn Sie einen Rückruf entfernen möchten, behalten Sie beim Hinzufügen die Referenz des Rückrufs bei 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);

Passen Sie die Paketliste und die Dexopt-Parameter an

ART Service initiiert Dexopt-Vorgänge selbst beim Booten und im Hintergrund. Um die Paketliste oder Dexopt-Parameter für diese Vorgänge anzupassen, verwenden Sie 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.
      }
    });

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

Ihr Rückruf muss unbekannte Gründe ignorieren, da in Zukunft möglicherweise weitere Gründe hinzugefügt werden.

Sie können höchstens einen BatchDexoptStartCallback festlegen. Der Rückruf bleibt für alle zukünftigen Anrufe aktiv, sofern Sie ihn nicht deaktivieren.

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

getArtManagerLocal().clearBatchDexoptStartCallback();

Passen Sie die Parameter des Hintergrund-Dexopt-Jobs an

Standardmäßig wird der Dexopt-Job im Hintergrund einmal täglich ausgeführt, wenn das Gerät inaktiv ist und aufgeladen wird. Dies kann mit ArtManagerLocal#setScheduleBackgroundDexoptJobCallback geändert werden.

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

Sie können höchstens einen ScheduleBackgroundDexoptJobCallback festlegen. Der Rückruf bleibt für alle zukünftigen Anrufe aktiv, sofern Sie ihn nicht deaktivieren.

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 einen BatchDexoptStartCallback aus. Sie können die Vorgänge weiterhin abbrechen, um Dexopt effektiv zu deaktivieren.

Wenn der von Ihnen stornierte Operation von Hintergrund dexopt ist, folgt die Standard -Wiederholungsrichtlinie (30 Sekunden, exponentiell, nach 5 Stunden begrenzt).

// 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 höchstens eine BatchDexoptStartCallback haben. Wenn Sie auch BatchDexoptStartCallback verwenden möchten, um die Paketliste oder die DEXOPT -Parameter anzupassen, müssen Sie den Code in einem Rückruf kombinieren.

// Bad example.

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

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

Der in der App -Installation durchgeführte Dexopt -Betrieb wird nicht vom ART -Service initiiert. Stattdessen wird es vom Paketmanager über einen dexoptPackage -Anruf initiiert. Daher löst es BatchDexoptStartCallback nicht aus. Um Dexopt in der App -Installation zu deaktivieren, verhindern Sie, dass der Paketmanager dexoptPackage aufruft.

Überschreiben Sie den Compiler -Filter für bestimmte Pakete (Android 15 (AOSP -Experimental)+).

Sie können den Compiler -Filter für bestimmte Pakete überschreiben, indem Sie einen Rückruf über setAdjustCompilerFilterCallback registrieren. Der Rückruf wird aufgerufen, wenn ein Paket dexoptiert wird, unabhängig von der Dexopt durch den Kunstdienst während des Starts und des Hintergrunds Dexopt oder durch einen dexoptPackage -API -Anruf.

Wenn ein Paket keine Anpassung erfordert, muss der Rückruf originalCompilerFilter zurückgeben.

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

Sie können nur einen AdjustCompilerFilterCallback festlegen. Wenn Sie AdjustCompilerFilterCallback verwenden möchten, um den Compilerfilter für mehrere Pakete zu überschreiben, müssen Sie den Code in einem Rückruf kombinieren. Der Rückruf bleibt für alle zukünftigen Anrufe aktiv, sofern Sie ihn nicht deaktivieren.

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

getArtManagerLocal().clearAdjustCompilerFilterCallback();

Andere Anpassungen

ART Service unterstützt auch einige andere Anpassungen.

Legen Sie den thermischen Schwellenwert für den Hintergrund-Dexopt fest

Die thermische Kontrolle des Dexopt-Jobs im Hintergrund wird vom Job Scheduler durchgeführt. Der Auftrag wird sofort abgebrochen, wenn die Temperatur THERMAL_STATUS_MODERATE erreicht. Der Schwellenwert von THERMAL_STATUS_MODERATE ist einstellbar.

Stellen Sie fest, ob Dexopt im Hintergrund ausgeführt wird

Der Dexopt-Job im Hintergrund wird vom Job Scheduler verwaltet und seine Job-ID lautet 27873780 . Um festzustellen, ob der Job ausgeführt wird, verwenden Sie Job Scheduler-APIs.

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

Stellen Sie ein Profil für Dexopt bereit

Um ein Profil zur Steuerung von Dexopt zu verwenden, legen Sie neben dem APK eine .prof Datei oder eine .dm Datei ab.

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

base.apk.prof

Der Dateiname der .dm Datei muss der Dateiname des APK sein, wobei die Erweiterung durch .dm ersetzt wird. Zum Beispiel,

base.dm

Um zu überprüfen, ob das Profil für Dexopt verwendet wird, führen Sie Dexopt mit speed-profile aus und überprü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 erzeugten Profile (also die in /data/misc/profiles ), falls vorhanden, um sicherzustellen, dass das Profil neben dem APK das einzige Profil ist, das ART Service möglicherweise verwenden kann. Die zweite Zeile führt dexopt mit speed-profile aus und übergibt -v , um das ausführliche Ergebnis auszugeben.

Wenn das Profil verwendet wird, sehen Sie im Ergebnis actualCompilerFilter=speed-profile . Andernfalls wird actualCompilerFilter=verify angezeigt. Zum 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}

Zu den typischen Gründen, warum ART Service das Profil nicht verwendet, gehören:

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