Zanim zaczniesz, zapoznaj się z ogólnymi informacjami o usłudze ART.
Począwszy od Androida 14 kompilacja AOT na urządzeniu w przypadku aplikacji (czyli dexopt) jest obsługiwana przez usługę ART. Usługa ART jest częścią modułu ART i można ją dostosować za pomocą właściwości systemowych oraz interfejsów API.
Właściwości systemowe
Usługa ART obsługuje wszystkie odpowiednie opcje dex2oat.
Dodatkowo usługa ART obsługuje te właściwości systemu:
pm.dexopt.<reason>
Jest to zbiór właściwości systemowych, które określają domyślne filtry kompilatora dla wszystkich zdefiniowanych wstępnie przyczyn kompilacji opisanych w scenariuszach Dexopt.
Więcej informacji znajdziesz w artykule Filtry kompilatora.
Standardowe wartości domyślne to:
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 (domyślnie: szybkość)
Jest to domyślny filtr kompilatora dla aplikacji używanych przez inne aplikacje.
Zasadniczo usługa ART wykonuje kompilację kierowaną przez profil (speed-profile
) we wszystkich aplikacjach, gdy jest to możliwe, zwykle podczas optymalizacji dex w tle. Są jednak aplikacje, których używają inne aplikacje (poprzez <uses-library>
lub wczytywane dynamicznie za pomocą Context#createPackageContext
z CONTEXT_INCLUDE_CODE
). Z powodu prywatności takie aplikacje nie mogą używać lokalnych profili.
Jeśli w przypadku takiej aplikacji wymagana jest kompilacja z użyciem profilu, usługa ART najpierw próbuje użyć profilu w chmurze. Jeśli profil chmury nie istnieje, usługa ART Service używa filtra kompilatora określonego przez parametr pm.dexopt.shared
.
Jeśli żądana kompilacja nie jest kierowana przez profil, ta właściwość nie ma żadnego wpływu.
pm.dexopt.<reason>.concurrency (domyślnie: 1)
Liczba wywołań dex2oat z określonych wstępnie zdefiniowanych powodów kompilacji (first-boot
, boot-after-ota
, boot-after-mainline-update
i bg-dexopt
).
Pamiętaj, że działanie tej opcji jest łączone z opcjami dex2oat dotyczących użycia zasobów (dalvik.vm.*dex2oat-threads
, dalvik.vm.*dex2oat-cpu-set
i profilami zadań):
dalvik.vm.*dex2oat-threads
określa liczbę wątków dla każdego wywołania dex2oat, apm.dexopt.<reason>.concurrency
– liczbę wywołań dex2oat. Oznacza to, że maksymalna liczba wątków równoczesnych jest iloczynem tych dwóch właściwości systemu.dalvik.vm.*dex2oat-cpu-set
i profile zadań zawsze ograniczają wykorzystanie rdzeni procesora niezależnie od maksymalnej liczby równoczesnych wątków (omówionych powyżej).
Pojedyncze wywołanie dex2oat może nie w pełni wykorzystać wszystkich rdzeni procesora, niezależnie od dalvik.vm.*dex2oat-threads
. Dlatego zwiększenie liczby wywołań dex2oat (pm.dexopt.<reason>.concurrency
) może pozwolić na lepsze wykorzystanie rdzeni procesora i przyspieszenie ogólnego postępu dexopt. Jest to szczególnie przydatne podczas uruchamiania.
Jednak zbyt duża liczba wywołań dex2oat może spowodować wyczerpanie się pamięci na urządzeniu, nawet jeśli można to ograniczyć, ustawiając dalvik.vm.dex2oat-swap
na true
, aby umożliwić używanie pliku wymiany. Zbyt wiele wywołań może też powodować niepotrzebne przełączanie kontekstu. Dlatego należy ją dokładnie dostosować w poszczególnych przypadkach.
pm.dexopt.downgrade_after_inactive_days (domyślnie: nie ustawiono)
Jeśli ta opcja jest ustawiona, usługa ART dexoptuje tylko aplikacje używane w ciągu podanej liczby dni.
Jeśli ponadto ilość dostępnej pamięci jest niewielka, podczas optymalizacji dexopt na drugim planie usługa ART Service obniża poziom kompilacji aplikacji, których nie używano w ciągu ostatniej określonej liczby dni, aby zwolnić miejsce. Powód tego jest taki, że kompilator inactive
, a filtr kompilatora jest określany przez pm.dexopt.inactive
. Próg wolnego miejsca, który powoduje uruchomienie tej funkcji, to próg niskiego miejsca w Menedżerze miejsca na dysku (można go skonfigurować w ustawieniach globalnych sys_storage_threshold_percentage
i sys_storage_threshold_max_bytes
, domyślnie 500 MB) plus 500 MB.
Jeśli spersonalizujesz listę pakietów za pomocą funkcji ArtManagerLocal#setBatchDexoptStartCallback
, pakiety na liście udostępnionej przez BatchDexoptStartCallback
dla bg-dexopt
nigdy nie zostaną obniżone.
pm.dexopt.disable_bg_dexopt (domyślnie: false)
Jest to tylko test. Zapobiega to zaplanowaniu przez usługę ART zadania dexopt w tle.
Jeśli zadanie dexopt w tle zostało już zaplanowane, ale jeszcze się nie rozpoczęło, ta opcja nie będzie miała żadnego wpływu. Oznacza to, że zadanie nadal będzie wykonywane.
Zalecana sekwencja poleceń, która zapobiega uruchamianiu zadania dexopt w tle:
setprop pm.dexopt.disable_bg_dexopt true
pm bg-dexopt-job --disable
Pierwszy wiersz zapobiega planowaniu zadania dexopt w tle, jeśli nie zostało jeszcze zaplanowane. Drugi wiersz odwołuje zaplanowane zadanie dexopt w tle, jeśli jest już zaplanowane, i natychmiast anuluje zadanie dexopt w tle, jeśli jest uruchomione.
Interfejsy ART Service API
Usługa ART udostępnia interfejsy API Javy do dostosowywania. Interfejsy API są zdefiniowane w pliku ArtManagerLocal
. Zapoznaj się z dokumentacją Javadoc w pliku art/libartservice/service/java/com/android/server/art/ArtManagerLocal.java
, aby dowiedzieć się, jak korzystać z funkcji (kod źródłowy Androida 14, niepublikowany kod źródłowy w wersji rozwojowej).
ArtManagerLocal
jest pojedynczym elementem w holdingu LocalManagerRegistry
. Funkcja pomocnicza com.android.server.pm.DexOptHelper#getArtManagerLocal
pomaga Ci ją uzyskać.
import static com.android.server.pm.DexOptHelper.getArtManagerLocal;
Większość interfejsów API wymaga instancji PackageManagerLocal.FilteredSnapshot
, która zawiera informacje o wszystkich aplikacjach. Można go uzyskać, wywołując funkcję PackageManagerLocal#withFilteredSnapshot
, gdzie PackageManagerLocal
jest również singletonem przechowywanym przez LocalManagerRegistry
i można go uzyskać z com.android.server.pm.PackageManagerServiceUtils#getPackageManagerLocal
.
import static com.android.server.pm.PackageManagerServiceUtils.getPackageManagerLocal;
Poniżej znajdziesz kilka typowych zastosowań interfejsów API.
Uruchamianie dexopt w aplikacji
W dowolnym momencie możesz wywołać dexopt dla dowolnej aplikacji, wywołując funkcję ArtManagerLocal#dexoptPackage
.
try (var snapshot = getPackageManagerLocal().withFilteredSnapshot()) {
getArtManagerLocal().dexoptPackage(
snapshot,
"com.google.android.calculator",
new DexoptParams.Builder(ReasonMapping.REASON_INSTALL).build());
}
Możesz też podać własny powód dexopt. W takim przypadku klasa priorytetowa i filtr kompilatora muszą być ustawione w sposób jawny.
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());
}
Anulowanie dexopt
Jeśli operacja została zainicjowana przez wywołanie dexoptPackage
, możesz przekazać sygnał anulowania, który umożliwia anulowanie operacji w określonym momencie. Może to być przydatne, gdy uruchamiasz dexopt asynchronicznie.
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();
Możesz też anulować dexopt w tle, który jest inicjowany przez usługę ART.
getArtManagerLocal().cancelBackgroundDexoptJob();
Pobieranie wyników dexopt
Jeśli operacja jest inicjowana przez wywołanie dexoptPackage
, możesz uzyskać wynik z wartości zwracanej.
DexoptResult result;
try (var snapshot = getPackageManagerLocal().withFilteredSnapshot()) {
result = getArtManagerLocal().dexoptPackage(...);
}
// Process the result here.
...
Usługa ART Service inicjuje też samodzielnie operacje dexopt w wielu scenariuszach, np. dexopt w tle. Aby odsłuchać wszystkie wyniki dexopt, niezależnie od tego, czy operacja została zainicjowana przez wywołanie dexoptPackage
czy przez usługę ART, użyj polecenia ArtManagerLocal#addDexoptDoneCallback
.
getArtManagerLocal().addDexoptDoneCallback(
false /* onlyIncludeUpdates */,
Runnable::run,
(result) -> {
// Process the result here.
...
});
Pierwszy argument określa, czy w wyniku mają być uwzględniane tylko aktualizacje. Jeśli chcesz słuchać tylko pakietów aktualizowanych przez dexopt, ustaw tę opcję na wartość true.
Drugi argument to wykonawca wywołania zwrotnego. Aby wykonać wywołanie zwrotne w tym samym wątku, który wykonuje dexopt, użyj Runnable::run
. Jeśli nie chcesz, aby wywołanie blokowało dexopt, użyj asynchronicznego wykonawcy.
Możesz dodać wiele funkcji wywołania zwrotnego, a usługa ART Service wykona je wszystkie kolejno. Wszystkie wywołania zwrotne pozostaną aktywne we wszystkich przyszłych wywołaniach, chyba że je usuniesz.
Jeśli chcesz usunąć wywołanie zwrotne, zachowaj odwołanie do niego podczas dodawania i użyj 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);
Dostosowywanie listy pakietów i parametrów dexopt
Usługa ART inicjuje operacje dexopt samodzielnie podczas uruchamiania i tła dexopt. Aby dostosować listę pakietów lub parametry dexopt w przypadku tych operacji, użyj 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.
}
});
Możesz dodawać elementy do listy pakietów, usuwać je z niej, sortować ją, a nawet użyć zupełnie innej listy.
W przypadku wywołania zwrotnego należy zignorować nieznane przyczyny, ponieważ w przyszłości może być dodanych więcej przyczyn.
Możesz ustawić maksymalnie 1 BatchDexoptStartCallback
. Ponowne połączenie będzie aktywne w przypadku wszystkich przyszłych połączeń, chyba że je anulujesz.
Jeśli chcesz anulować wywołanie zwrotne, użyj opcji ArtManagerLocal#clearBatchDexoptStartCallback
.
getArtManagerLocal().clearBatchDexoptStartCallback();
Dostosowywanie parametrów zadania dexopt wykonywanego w tle
Domyślnie zadanie dexopt w tle jest wykonywane raz dziennie, gdy urządzenie jest nieaktywne i ładowane. Możesz to zmienić, korzystając z ArtManagerLocal#setScheduleBackgroundDexoptJobCallback
.
getArtManagerLocal().setScheduleBackgroundDexoptJobCallback(
Runnable::run,
builder -> {
builder.setPeriodic(TimeUnit.DAYS.toMillis(2));
});
Możesz ustawić maksymalnie 1 ScheduleBackgroundDexoptJobCallback
. Połączenie zwrotne będzie aktywne we wszystkich przyszłych rozmowach, chyba że je wyłączysz.
Jeśli chcesz anulować wywołanie zwrotne, użyj opcji ArtManagerLocal#clearScheduleBackgroundDexoptJobCallback
.
getArtManagerLocal().clearScheduleBackgroundDexoptJobCallback();
Tymczasowo wyłącz dexopt
Każda operacja dexopt zainicjowana przez usługę ART Service powoduje wywołanie BatchDexoptStartCallback
. Możesz nadal anulować operacje, aby skutecznie wyłączyć dexopt.
Jeśli anulowana operacja to dexopt w tle, stosuje się do niej domyślna zasada ponownego próby (30 sekund, wykładniczo, z maksymalnym czasem 5 godzin).
// 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);
Możesz mieć maksymalnie 1 BatchDexoptStartCallback
. Jeśli chcesz też używać elementu BatchDexoptStartCallback
do dostosowywania listy pakietów lub parametrów dexopt, musisz połączyć kod w jedną funkcję wywołania zwrotnego.
// Bad example.
// Disable dexopt.
getArtManagerLocal().unscheduleBackgroundDexoptJob();
// Re-enable dexopt.
getArtManagerLocal().scheduleBackgroundDexoptJob();
Operacja dexopt wykonywana podczas instalowania aplikacji nie jest inicjowana przez usługę ART. Zamiast tego jest inicjowany przez menedżera pakietów za pomocą wywołania dexoptPackage
. Dlatego nie uruchamia BatchDexoptStartCallback
. Aby wyłączyć dexopt podczas instalowania aplikacji, uniemożliw zarządzaniu pakietami wywoływanie funkcji dexoptPackage
.
Zastępowanie filtra kompilatora w przypadku niektórych pakietów (Android 15 lub nowszy)
Możesz zastąpić filtr kompilatora w przypadku niektórych pakietów, rejestrując funkcję wywołania zwrotnego za pomocą funkcji setAdjustCompilerFilterCallback
. Funkcja wywołania zwrotnego jest wywoływana za każdym razem, gdy pakiet ma zostać zdexoptowany, niezależnie od tego, czy dexopt został zainicjowany przez usługę ART podczas uruchamiania i dexopt w tle czy przez wywołanie interfejsu API dexoptPackage
.
Jeśli pakiet nie wymaga korekty, wywołanie zwrotne musi zwracaćoriginalCompilerFilter
.
getArtManagerLocal().setAdjustCompilerFilterCallback(
Runnable::run,
(packageName, originalCompilerFilter, reason) -> {
if (isVeryImportantPackage(packageName)) {
return "speed-profile";
}
return originalCompilerFilter;
});
Możesz ustawić tylko 1 wartość AdjustCompilerFilterCallback
. Jeśli chcesz użyć opcji AdjustCompilerFilterCallback
, aby zastąpić filtr kompilatora w przypadku wielu pakietów, musisz połączyć kod w jedną funkcję wywołania zwrotnego. Połączenie zwrotne pozostaje aktywne we wszystkich przyszłych rozmowach, chyba że je anulujesz.
Jeśli chcesz anulować wywołanie zwrotne, użyj opcji ArtManagerLocal#clearAdjustCompilerFilterCallback
.
getArtManagerLocal().clearAdjustCompilerFilterCallback();
Inne opcje personalizacji
Usługa ART obsługuje też inne opcje dostosowywania.
Ustawianie progu temperatury dla dexopt w tle
Usługa Job Scheduler zapewnia kontrolę termiczną zadania dexopt działającego w tle.
Zadania są anulowane natychmiast po osiągnięciu temperatury THERMAL_STATUS_MODERATE
. Próg THERMAL_STATUS_MODERATE
można dostosować.
Sprawdzanie, czy dexopt działa w tle
Zadaniem dexopt w tle zarządza harmonogram zadań, a jego identyfikator to 27873780
. Aby sprawdzić, czy zadanie jest wykonywane, użyj interfejsów Job Scheduler API.
// 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.
...
}
Podaj profil dla dexopt
Aby użyć profilu do kierowania dexopt, umieść plik .prof
lub .dm
obok pliku APK.
Plik .prof
musi być plikiem profilu w formacie binarnym, a jego nazwa musi być taka sama jak nazwa pliku APK + .prof
. Na przykład
base.apk.prof
Nazwa pliku .dm
musi być nazwą pliku APK z rozszerzeniem .dm
. Na przykład
base.dm
Aby sprawdzić, czy profil jest używany do dexopt, uruchom dexopt z parametrem speed-profile
i sprawdź wynik.
pm art clear-app-profiles <package-name>
pm compile -m speed-profile -f -v <package-name>
Pierwsza linijka usuwa wszystkie profile utworzone przez środowisko uruchomieniowe (czyli te w /data/misc/profiles
), jeśli takie istnieją, aby mieć pewność, że profil obok pliku APK jest jedynym profilem, którego usługa ART może użyć. Drugi wiersz uruchamia dexopt z parametrem speed-profile
i przekazuje parametr -v
, aby wydrukować szczegółowy wynik.
Jeśli profil jest używany, w wyniku zobaczysz actualCompilerFilter=speed-profile
. W przeciwnym razie zobaczysz actualCompilerFilter=verify
. Na przykład
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}
Typowe przyczyny, dla których usługa ART nie używa profilu:
- Profil ma nieprawidłową nazwę pliku lub nie znajduje się obok pliku APK.
- Profil ma nieprawidłowy format.
- Profil jest niezgodny z plikiem APK. (sumy kontrolne w profilu nie są zgodne z sumami kontrolnymi plików
.dex
w pliku APK).