Zanim zaczniesz, zapoznaj się z ogólnym omówieniem usługi ART.
Począwszy od Androida 14, kompilacja AOT na urządzeniu dla (dexopt) jest obsługiwane przez usługę ART. Usługa ART jest częścią który możesz dostosować za pomocą właściwości systemu i 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 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 filtr zastępczy 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. Istnieją jednak
niektóre aplikacje używane przez inne aplikacje (za pomocą <uses-library>
lub wczytane
dynamiczne korzystanie z Context#createPackageContext
z
CONTEXT_INCLUDE_CODE
). Takie aplikacje nie mogą używać języka lokalnego
profilów ze względu na ochronę prywatności.
W przypadku takiej aplikacji, jeśli wymagana jest kompilacja prowadzona przez profil, najpierw usługa ART
próbuje użyć profilu w chmurze. Jeśli profil w chmurze nie istnieje, usługa ART
wraca do filtra kompilatora określonego przez funkcję 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 na każdy dex2oat wywołania, apm.dexopt.<reason>.concurrency
określa liczbę dex2oat. Oznacza to, że maksymalna liczba jednoczesnych wątków wynosi iloczyn dwóch właściwości systemowych.- Procesor
dalvik.vm.*dex2oat-cpu-set
i profile zadań zawsze 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 wykorzystywać w pełni wszystkich rdzeni procesora, niezależnie
z dalvik.vm.*dex2oat-threads
. W związku z tym zwiększenie liczby dex2oat
przez wywołania (pm.dexopt.<reason>.concurrency
) mogą lepiej wykorzystywać rdzenie procesora,
i przyspieszyć postęp prac dexopt. Jest to szczególnie przydatne podczas
uruchamianie.
Jednak zbyt duża liczba wywołań dex2oat może spowodować wyczerpanie się
nawet jeśli można to ograniczyć, ustawiając dalvik.vm.dex2oat-swap
na
true
, aby zezwolić na używanie pliku do wymiany. Zbyt wiele wywołań może też powodować
niepotrzebne przełączanie kontekstu. Dlatego należy dokładnie sprawdzać tę liczbę
z poszczególnych usług.
pm.dexopt.downgrade_after_inactive_days (domyślnie: nie ustawiono)
Jeśli ta opcja jest ustawiona, usługa ART pobiera tylko aplikacje używane w ciągu liczbę 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. Przyczyna wystąpienia kompilatora to inactive
,
a filtr kompilatora jest określany przez pm.dexopt.inactive
. Pokój
próg wymagany do aktywowania tej funkcji to niski próg dotyczący miejsca na dane określony przez menedżera miejsca
(można je skonfigurować za pomocą ustawień 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)
Służy tylko do testów. Uniemożliwia usłudze ART zaplanowanie działania w tle zadanie dexopt.
Jeśli zadanie dexopt w tle jest już zaplanowane, ale nie zostało jeszcze uruchomione, nie ma żadnego efektu. Oznacza to, że zadanie będzie nadal uruchamiane.
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 anuluje harmonogram zadania dexopt w tle, jeśli jest już zaplanowany, a zadanie deksoptowania w tle zostanie natychmiast anulowane, jeśli jego uruchomienie.
Interfejsy API usługi ART
Usługa ART udostępnia interfejsy API w Javie do dostosowania. Interfejsy API zostały zdefiniowane tutaj:
ArtManagerLocal
Zobacz dokument Javadoc w
art/libartservice/service/java/com/android/server/art/ArtManagerLocal.java
dla
zastosowania (źródło Androida 14, nieopublikowane nieopublikowane źródło programistyczne).
ArtManagerLocal
to singleton posiadany przez: LocalManagerRegistry
. Pomoc
funkcja com.android.server.pm.DexOptHelper#getArtManagerLocal
pomaga
go 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. Aby go uzyskać, zadzwoń
PackageManagerLocal#withFilteredSnapshot
, gdzie PackageManagerLocal
też jest
singleton w posiadaniu 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.
Aktywowanie deksoptowania dla aplikacji
Możesz w dowolnym momencie włączyć dexopt dla dowolnej aplikacji, wywołując
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. W takim przypadku klasa priorytetowa filtr kompilatora musi być wyraźnie ustawiony.
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());
}
Anuluj deksoptowanie
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();
Pobierz wyniki deksoptowania
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 również inicjuje same operacje deksoptacji w wielu sytuacjach, na przykład:
dexopt. 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 nasłuchiwać tylko pakietów zaktualizowanych przez dexopt, ustaw wartość true (prawda).
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 wywołań zwrotnych, a usługa ART Service je wszystkie wykona sekwencyjnie. Wszystkie wywołania zwrotne pozostaną aktywne w przypadku wszystkich przyszłych połączeń, chyba że możesz je usunąć.
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 deksoptowania podczas uruchamiania i w tle
deksopt. Aby dostosować listę pakietów lub parametry dexopt dla tych operacji,
użyj funkcji 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ć pozycje do listy pakietów, usuwać je z niej, sortować, 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 BatchDexoptStartCallback
. Oddzwanianie pozostanie bez zmian
aktywna dla wszystkich przyszłych połączeń, chyba że ją usuniesz.
Jeśli chcesz anulować oddzwanianie, użyj
ArtManagerLocal#clearBatchDexoptStartCallback
getArtManagerLocal().clearBatchDexoptStartCallback();
Dostosuj parametry zadania dexopt 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 ScheduleBackgroundDexoptJobCallback
. Oddzwanianie
pozostanie aktywne przy wszystkich przyszłych połączeniach, chyba że je usuniesz.
Jeśli chcesz anulować oddzwanianie, użyj
ArtManagerLocal#clearScheduleBackgroundDexoptJobCallback
getArtManagerLocal().clearScheduleBackgroundDexoptJobCallback();
Tymczasowo wyłącz 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 anulujesz operację deksoptowania w tle, będzie ona zgodna z domyślnym zasada ponawiania (30 sekund, wykładnicza, ograniczona do 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żyć funkcji
BatchDexoptStartCallback
, aby dostosować listę pakietów lub parametry dexopt.
musisz połączyć kod w jedno wywołanie zwrotne.
// Bad example.
// Disable dexopt.
getArtManagerLocal().unscheduleBackgroundDexoptJob();
// Re-enable dexopt.
getArtManagerLocal().scheduleBackgroundDexoptJob();
Operacja deksoptowania wykonywana podczas instalacji aplikacji nie jest inicjowana przez ART
posprzedażna. Zamiast tego jest inicjowane przez menedżera pakietów za pomocą polecenia
dexoptPackage
połączenie. Dlatego nie wywołuje
BatchDexoptStartCallback
Aby wyłączyć deksoptowanie podczas instalowania aplikacji, zablokuj
menedżera pakietów z wywołaniem dexoptPackage
.
Zastępowanie filtra kompilatora w przypadku niektórych pakietów (Android 15 i nowsze)
Filtr kompilatora dla niektórych pakietów możesz zastąpić, rejestrując plik
oddzwanianie pod numer setAdjustCompilerFilterCallback
. Wywołanie zwrotne
za każdym razem, gdy pakiet ma być deksoptowany, niezależnie od tego, czy deksopt został zainicjowany przez
Usługa ART podczas uruchamiania i deksoptowania w tle lub za pomocą wywołania 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ć funkcji
AdjustCompilerFilterCallback
, aby zastąpić filtr kompilatora dla wielu
musisz połączyć kod w jedno wywołanie zwrotne. Oddzwanianie pozostaje
aktywna dla wszystkich przyszłych połączeń, chyba że ją usuniesz.
Jeśli chcesz anulować oddzwanianie, użyj
ArtManagerLocal#clearAdjustCompilerFilterCallback
getArtManagerLocal().clearAdjustCompilerFilterCallback();
Inne dostosowania
Usługa ART obsługuje też inne modyfikacje.
Ustaw próg temperatury dla deksoptowania tła
Kontrolę termiczną zadania deksoptowania w tle jest wykonywana przez algorytm szeregowania zadań.
Zadanie zostanie anulowane natychmiast, gdy temperatura osiągnie
THERMAL_STATUS_MODERATE
Próg
THERMAL_STATUS_MODERATE
można dostrajać.
Sprawdzanie, czy uruchomiona jest deksoptacja w tle
Zadanie dexopt w tle jest zarządzane przez algorytm szeregowania zadań, a jego identyfikator zadania to
27873780
Aby sprawdzić, czy zadanie jest uruchomione, 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 do 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 nazwa pliku musi:
nazwa pliku APK + .prof
. Na przykład
base.apk.prof
Nazwa pliku .dm
musi być nazwą pliku APK z parametrem
rozszerzenie zostało zastąpione przez .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>
Pierwszy wiersz usuwa wszystkie profile utworzone przez środowisko wykonawcze (tj. te w
/data/misc/profiles
), aby upewnić się, że profil obok pliku APK jest
Jedyny profil, z którego może korzystać usługa ART. Druga linia korzysta z deksopttu
i speed-profile
, i przekazuje -v
, aby wydrukować szczegółowy wynik.
Jeśli profil jest używany, zobaczysz actualCompilerFilter=speed-profile
w
w konsekwencji wyniku. 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).