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ährendpm.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.)