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 dex2oat.
Dodatkowo ART Service obsługuje te właściwości systemowe:
pm.dexopt.<reason>
To jest zestaw właściwości systemowych, które określają domyślne filtry kompilatora ze wszystkich wstępnie zdefiniowanych powodów kompilacji opisanych w scenariuszach Dexopt.
Więcej informacji: Filtry kompilatora.
Standardowe wartości domyślne:
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.
Z reguły usługa ART tworzy kompilację zgodną z profilem (speed-profile
) dla:
wszystkich aplikacji, gdy jest to możliwe, zwykle podczas deksoptowania 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 używa filtra kompilatora określonego przez pm.dexopt.shared
.
Jeśli żądana kompilacja nie jest obsługiwana przez profil, ta właściwość nie powoduje żadnych skutków.
pm.dexopt.<reason>.concurrency (domyślnie: 1)
To jest liczba wywołań dex2oat dla określonej wstępnie zdefiniowanej kompilacji
przyczyny (first-boot
, boot-after-ota
, boot-after-mainline-update
i
bg-dexopt
).
Pamiętaj, że efekt tej opcji jest połączony z
opcje wykorzystania zasobów dex2oat (dalvik.vm.*dex2oat-threads
,
dalvik.vm.*dex2oat-cpu-set
i profili zadań):
dalvik.vm.*dex2oat-threads
określa liczbę wątków dla każdego wywołania dex2oat, apm.dexopt.<reason>.concurrency
określa liczbę wywołań dex2oat. Oznacza to, że maksymalna liczba wątków równoczesnych jest iloczynem tych dwóch właściwości systemu.- Procesor
dalvik.vm.*dex2oat-cpu-set
i profile zadań zawsze są powiązane z rdzeniem procesora bez względu na maksymalną liczbę równoczesnych wątków (omówione powyżej).
Pojedyncze wywołanie dex2oat może nie wykorzystać w pełni 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
uruchamianie.
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 go dokładnie dostosować w poszczególnych usługach.
pm.dexopt.downgrade_after_inactive_days (domyślnie: nie ustawiono)
Jeśli ta opcja jest ustawiona, usługa ART dezaktywuje tylko aplikacje używane w ciągu podanej liczby dni.
Ponadto, jeśli ilość miejsca na dane jest prawie niewystarczająca, podczas deksoptowania w tle usługa ART
obniża filtr kompilatora dla aplikacji, które nie są używane w ciągu ostatnich
liczby dni, aby zwolnić miejsce. Powód podany przez kompilator to inactive
, a filtr kompilatora jest określany przez pm.dexopt.inactive
. Próg miejsca na dane, który powoduje uruchomienie tej funkcji, to próg niskiego miejsca na dane w Menedżerze miejsca na dane (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 dostosujesz listę pakietów na stronie
ArtManagerLocal#setBatchDexoptStartCallback
, pakiety na liście podanej
od BatchDexoptStartCallback
dla bg-dexopt
nigdy nie są obniżane.
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 jest już zaplanowane, ale nie zostało jeszcze uruchomione, nie ma żadnego efektu. Oznacza to, że zadanie nadal będzie wykonywane.
Zalecana sekwencja poleceń, które uniemożliwiają zadanie deksoptowania w tle uruchomiony jest:
setprop pm.dexopt.disable_bg_dexopt true
pm bg-dexopt-job --disable
Pierwszy wiersz zapobiega zaplanowaniu zadania dexopt w tle, jeśli nie zaplanowano. 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 API usługi ART
Usługa ART udostępnia interfejsy API Javy do dostosowywania. Interfejsy API zostały zdefiniowane tutaj:
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
to singleton posiadany przez: 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óry 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 podano kilka typowych przypadków użycia 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 deksoptowania. Jeśli to zrobisz, 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 jest inicjowana przez wywołanie dexoptPackage
, możesz przekazać
sygnału anulowania, który pozwala w pewnym momencie anulować operację. Może to spowodować
może być przydatne przy asynchronicznym uruchamianiu narzędzia dexopt.
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ć dexopting w tle inicjowany przez usługę ART.
getArtManagerLocal().cancelBackgroundDexoptJob();
Pobieranie wyników dexopt
Jeśli operacja została zainicjowana przez wywołanie dexoptPackage
, możesz uzyskać wynik
od zwracanej wartości.
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 nasłuchiwać wszystkich wyników deksoptowania, niezależnie od tego, czy operacja
zainicjowane przez wywołanie dexoptPackage
lub przez usługę ART, użyj
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 jest wykonawcą wywołania zwrotnego. Aby wykonać wywołanie zwrotne
w tym samym wątku, w którym przeprowadza się deksoptowanie, użyj parametru Runnable::run
. Jeśli nie chcesz, aby rozszerzenie
wywołanie zwrotne do zablokowania dexopt, użyj wykonawcy asynchronicznego.
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 jego odniesienie
i dodać 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);
Dostosuj listę pakietów i parametry dexopt
Usługa ART inicjuje operacje dexopt samodzielnie podczas uruchamiania i w tledexopt. 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.
Oddzwanianie musi ignorować nieznane przyczyny, ponieważ można dodać więcej powodów przyszłości.
Możesz ustawić maksymalnie 1 wartość BatchDexoptStartCallback
. Oddzwanianie pozostanie bez zmian
aktywna dla wszystkich przyszłych połączeń, chyba że ją usuniesz.
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 deksoptowania w tle jest uruchamiane raz dziennie, gdy urządzenie jest bezczynne
i ładowanie. Można to zmienić za pomocą
ArtManagerLocal#setScheduleBackgroundDexoptJobCallback
getArtManagerLocal().setScheduleBackgroundDexoptJobCallback(
Runnable::run,
builder -> {
builder.setPeriodic(TimeUnit.DAYS.toMillis(2));
});
Możesz ustawić maksymalnie 1 wartość ScheduleBackgroundDexoptJobCallback
. Połączenie zwrotne będzie aktywne we wszystkich przyszłych rozmowach, chyba że je wyłączysz.
Jeśli chcesz anulować oddzwonienie, użyj
ArtManagerLocal#clearScheduleBackgroundDexoptJobCallback
getArtManagerLocal().clearScheduleBackgroundDexoptJobCallback();
Tymczasowe wyłączenie dexopt
Każda operacja deksoptowania zainicjowana przez usługę ART powoduje wywołanie
BatchDexoptStartCallback
Możesz anulować operacje, aby:
skutecznie wyłączyć dexopt.
Jeśli anulowana operacja to dexopt w tle, stosuje się do niej domyślna zasada ponownych prób (30 sekund, wykładniczo, z maksimum 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ć parametru 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 instalacji aplikacji nie jest inicjowana przez usługę ART. Zamiast tego jest inicjowane przez menedżera pakietów za pomocą polecenia
dexoptPackage
połączenie. Dlatego nie uruchamia się
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 i nowsze)
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 tła dexopt, czy przez wywołanie interfejsu API dexoptPackage
.
Jeśli pakiet nie wymaga korekty, wywołanie zwrotne musi zwrócić originalCompilerFilter
.
getArtManagerLocal().setAdjustCompilerFilterCallback(
Runnable::run,
(packageName, originalCompilerFilter, reason) -> {
if (isVeryImportantPackage(packageName)) {
return "speed-profile";
}
return originalCompilerFilter;
});
Możesz ustawić tylko jeden element 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. Oddzwanianie pozostaje
aktywna dla wszystkich przyszłych połączeń, chyba że ją usuniesz.
Jeśli chcesz anulować wywołanie zwrotne, użyj opcji ArtManagerLocal#clearAdjustCompilerFilterCallback
.
getArtManagerLocal().clearAdjustCompilerFilterCallback();
Inne dostosowania
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.
Zadanie zostanie anulowane natychmiast, gdy temperatura osiągnie
THERMAL_STATUS_MODERATE
Próg THERMAL_STATUS_MODERATE
można dostosować.
Sprawdź, czy uruchomiona jest deksoptacja w tle
Zadanie dexopt w tle jest zarządzane przez 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żywać profilu do prowadzenia dexopt, umieść plik .prof
lub .dm
obok
plik 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 za pomocą polecenia
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ć. Druga linia 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}
Oto kilka typowych powodów, 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 nie pasuje do pliku APK. (Sumy kontrolne w profilu nie
pasują do sum kontrolnych plików
.dex
w pakiecie APK).