Prima di iniziare, visualizza una panoramica generale di ART Service.
A partire da Android 14, compilation AOT sul dispositivo per le app (ovvero dexopt) vengono gestite da ART Service. ART Service fa parte di ART e potrai personalizzarlo tramite le proprietà di sistema e le API.
Proprietà di sistema
ART Service supporta tutte le opzioni dex2oat.
Inoltre, ART Service supporta le seguenti proprietà di sistema:
pm.dexopt.<motivo>
Si tratta di un insieme di proprietà di sistema che determina i filtri del compilatore predefiniti per tutti i motivi di compilazione predefiniti descritti in Scenari Dexopt.
Per ulteriori informazioni, vedi Filtri del compilatore.
I valori predefiniti standard sono:
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 (impostazione predefinita: velocità)
Questo è il filtro del compilatore di riserva per le app utilizzate da altre app.
In linea di principio, ART Service esegue la compilazione guidata dal profilo (speed-profile
) per
tutte le app quando possibile, in genere durante la disattivazione in background. Tuttavia, ci sono
alcune app usate da altre app (tramite <uses-library>
o caricate
in modo dinamico utilizzando Context#createPackageContext
con
CONTEXT_INCLUDE_CODE
). Queste app non possono usare
profili per motivi di privacy.
Per un'app di questo tipo, se viene richiesta la compilazione guidata dal profilo, prima ART Service
prova a utilizzare un profilo cloud. Se un profilo cloud non esiste, ART Service
utilizza il filtro del compilatore specificato da pm.dexopt.shared
.
Se la compilazione richiesta non è guidata dal profilo, questa proprietà non ha alcun effetto.
pm.dexopt.<reason>.concurrency (valore predefinito: 1)
Questo è il numero di chiamate dex2oat per determinate compilazioni predefinite
motivi (first-boot
, boot-after-ota
, boot-after-mainline-update
e
bg-dexopt
).
Tieni presente che l'effetto di questa opzione è combinato con
opzioni di utilizzo delle risorse dex2oat (dalvik.vm.*dex2oat-threads
,
dalvik.vm.*dex2oat-cpu-set
e i profili delle attività):
dalvik.vm.*dex2oat-threads
controlla il numero di thread per ogni dex2oat chiamata, mentrepm.dexopt.<reason>.concurrency
controlla il numero chiamate dex2oat. Ciò significa che il numero massimo di thread simultanei è il prodotto delle due proprietà di sistema.dalvik.vm.*dex2oat-cpu-set
e i profili delle attività associano sempre il core della CPU di archiviazione, indipendentemente dal numero massimo di thread simultanei (considerati sopra).
Una singola chiamata a dex2oat potrebbe non utilizzare completamente tutti i core della CPU,
di dalvik.vm.*dex2oat-threads
. Pertanto, aumentando il numero
(pm.dexopt.<reason>.concurrency
) possono utilizzare meglio i core della CPU,
velocizzando l'avanzamento complessivo di dexopt. Ciò è particolarmente utile durante
avvio.
Tuttavia, un numero eccessivo di chiamate a dex2oat può causare l'esaurimento delle
di memoria, anche se può essere mitigato impostando dalvik.vm.dex2oat-swap
su
true
per consentire l'utilizzo di un file di scambio. Anche troppe chiamate potrebbero causare
cambio di contesto non necessario. Pertanto, questo numero deve essere ottimizzato
prodotto per prodotto.
pm.dexopt.downgrade_after_inactive_days (predefinito: non impostato)
Se questa opzione è impostata, ART Service decide solo le app utilizzate negli ultimi numero di giorni.
Inoltre, se lo spazio di archiviazione è quasi esaurito, durante la disattivazione in background, ART Service
esegue il downgrade del filtro del compilatore delle app che non vengono utilizzate negli ultimi
di giorni, per liberare spazio. Il motivo del compilatore è inactive
,
mentre il filtro del compilatore è determinato dal criterio pm.dexopt.inactive
. Spazio
per attivare questa funzionalità è la soglia di spazio in esaurimento di Storage Manager
(configurabile tramite le impostazioni globali sys_storage_threshold_percentage
e
sys_storage_threshold_max_bytes
, valore predefinito: 500 MB) più 500 MB.
Se personalizzi l'elenco dei pacchetti mediante
ArtManagerLocal#setBatchDexoptStartCallback
, i pacchetti nell'elenco fornito
di BatchDexoptStartCallback
per bg-dexopt
non viene mai eseguito il downgrade.
pm.dexopt.disable_bg_dexopt (impostazione predefinita: false)
Solo a scopo di test. Impedisce ad ART Service di pianificare il background dexopt per il job.
Se il job di dexopt in background è già pianificato ma non è ancora stato eseguito, non ha alcun effetto. Ciò significa che il job continuerà a essere eseguito.
Una sequenza consigliata di comandi per impedire che il job di dexopt in background in esecuzione è:
setprop pm.dexopt.disable_bg_dexopt true
pm bg-dexopt-job --disable
La prima riga impedisce la pianificazione del job di dexopt in background, se non ancora pianificate. La seconda riga annulla la pianificazione del job di dexopt in background, se è già pianificato e il job di rimozione in background viene annullato immediatamente, se sia in esecuzione.
API ART Service
ART Service espone le API Java per la personalizzazione. Le API sono definite
ArtManagerLocal
. Visualizza il Javadoc in
art/libartservice/service/java/com/android/server/art/ArtManagerLocal.java
per
(fonte Android 14, fonte sviluppo non rilasciata).
ArtManagerLocal
è un singleton detenuto da LocalManagerRegistry
. Un aiutante
la funzione com.android.server.pm.DexOptHelper#getArtManagerLocal
ti aiuta
ottenerlo.
import static com.android.server.pm.DexOptHelper.getArtManagerLocal;
La maggior parte delle API richiede un'istanza di PackageManagerLocal.FilteredSnapshot
,
che contiene le informazioni di tutte le app. Puoi riceverlo chiamando
PackageManagerLocal#withFilteredSnapshot
, dove PackageManagerLocal
è anche
un singleton detenuto da LocalManagerRegistry
e può essere ottenuto da
com.android.server.pm.PackageManagerServiceUtils#getPackageManagerLocal
.
import static com.android.server.pm.PackageManagerServiceUtils.getPackageManagerLocal;
Di seguito sono riportati alcuni casi d'uso tipici delle API.
Attivare la funzionalità Dexopt per un'app
Puoi attivare dexopt per qualsiasi app in qualsiasi momento chiamando
ArtManagerLocal#dexoptPackage
.
try (var snapshot = getPackageManagerLocal().withFilteredSnapshot()) {
getArtManagerLocal().dexoptPackage(
snapshot,
"com.google.android.calculator",
new DexoptParams.Builder(ReasonMapping.REASON_INSTALL).build());
}
Puoi anche indicare un motivo specifico per la decisione. In questo caso, la classe di priorità e il filtro del compilatore deve essere impostato in modo esplicito.
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());
}
Annulla dexopt
Se un'operazione viene avviata da una chiamata dexoptPackage
, puoi passare un
che ti consente di annullare l'operazione in un determinato momento. Questo può
utile quando esegui dexopt in modo asincrono.
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();
Puoi anche annullare la dexopt in background, che viene avviata da ART Service.
getArtManagerLocal().cancelBackgroundDexoptJob();
Visualizza i risultati di Dexopt
Se un'operazione viene avviata da una chiamata dexoptPackage
, puoi ottenere il risultato
dal valore restituito.
DexoptResult result;
try (var snapshot = getPackageManagerLocal().withFilteredSnapshot()) {
result = getArtManagerLocal().dexoptPackage(...);
}
// Process the result here.
...
ART Service avvia automaticamente le operazioni dexopt in molti scenari, ad esempio:
dexopt sullo sfondo. Per ascoltare tutti i risultati di dexopt, se l'operazione è
avviato da una chiamata dexoptPackage
o da ART Service, utilizza
ArtManagerLocal#addDexoptDoneCallback
.
getArtManagerLocal().addDexoptDoneCallback(
false /* onlyIncludeUpdates */,
Runnable::run,
(result) -> {
// Process the result here.
...
});
Il primo argomento determina se includere solo gli aggiornamenti nel risultato. Se vuoi ascoltare solo i pacchetti aggiornati da dexopt, impostalo su true.
Il secondo argomento è l'esecutore del callback. Per eseguire il callback
lo stesso thread che esegue dexopt, usa Runnable::run
. Se non vuoi che il
per bloccare dexopt, usa un esecutore asincrono.
Puoi aggiungere più callback e ART Service li eseguirà tutti in sequenza. Tutti i callback rimarranno attivi per tutte le chiamate future a meno che per poi rimuoverli.
Se vuoi rimuovere un callback, tieni il riferimento al callback quando
aggiungilo e usa 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);
Personalizza l'elenco di pacchetti e i parametri dexopt
ART Service avvia automaticamente le operazioni dexopt durante l'avvio e in background
dexopt. Per personalizzare l'elenco di pacchetti o i parametri di dexopt per queste operazioni,
usa 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.
}
});
Puoi aggiungere articoli all'elenco di pacchi, rimuoverli, ordinarli o persino usare un elenco completamente diverso.
Il callback deve ignorare i motivi sconosciuti perché potrebbero essere aggiunti altri motivi per il futuro.
Puoi impostare al massimo un BatchDexoptStartCallback
. Il callback verrà mantenuto
attivo per tutte le chiamate future, a meno che non la cancelli.
Se vuoi cancellare il callback, usa
ArtManagerLocal#clearBatchDexoptStartCallback
.
getArtManagerLocal().clearBatchDexoptStartCallback();
Personalizza i parametri del job di dexopt in background
Per impostazione predefinita, il job di dexopt in background viene eseguito una volta al giorno quando il dispositivo è inattivo
e ricarica. Questa opzione può essere modificata utilizzando
ArtManagerLocal#setScheduleBackgroundDexoptJobCallback
.
getArtManagerLocal().setScheduleBackgroundDexoptJobCallback(
Runnable::run,
builder -> {
builder.setPeriodic(TimeUnit.DAYS.toMillis(2));
});
Puoi impostare al massimo un ScheduleBackgroundDexoptJobCallback
. Il callback
rimangono attive per tutte le chiamate future, a meno che non la cancelli.
Se vuoi cancellare il callback, usa
ArtManagerLocal#clearScheduleBackgroundDexoptJobCallback
.
getArtManagerLocal().clearScheduleBackgroundDexoptJobCallback();
Disattiva temporaneamente dexopt
Qualsiasi operazione di esclusione avviata dal servizio ART attiva un
BatchDexoptStartCallback
. Puoi continuare ad annullare le operazioni
disattivare in modo efficace dexopt.
Se l'operazione annullata è dexopt in background, viene seguito il valore predefinito criterio di ripetizione (30 secondi, esponenziale, limitato a 5 ore).
// 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);
Puoi avere al massimo un BatchDexoptStartCallback
. Se vuoi utilizzare anche
BatchDexoptStartCallback
per personalizzare l'elenco di pacchetti o i parametri dexopt,
devi combinare il codice in un solo callback.
// Bad example.
// Disable dexopt.
getArtManagerLocal().unscheduleBackgroundDexoptJob();
// Re-enable dexopt.
getArtManagerLocal().scheduleBackgroundDexoptJob();
L'operazione di dexopt eseguita all'installazione dell'app non viene avviata da ART
assistenza. Viene invece avviato dal gestore di pacchetti tramite una
Chiamata dexoptPackage
. Di conseguenza, non attiva
BatchDexoptStartCallback
. Per disattivare la funzionalità dexopt all'installazione di app, impedisci il
gestore di pacchetti di chiamare dexoptPackage
.
Esegui l'override del filtro del compilatore per determinati pacchetti (Android 15 (sperimentale AOSP)+)
Puoi eseguire l'override del filtro del compilatore per alcuni pacchetti registrando un'istanza
da richiamare tramite setAdjustCompilerFilterCallback
. Il callback viene chiamato
ogni volta che un pacchetto viene dexoptato, indipendentemente dal fatto che la decisione venga avviata
ART Service durante l'avvio e la disattivazione in background o tramite una chiamata API dexoptPackage
.
Se un pacchetto non richiede modifiche, il callback deve restituire
originalCompilerFilter
.
getArtManagerLocal().setAdjustCompilerFilterCallback(
Runnable::run,
(packageName, originalCompilerFilter, reason) -> {
if (isVeryImportantPackage(packageName)) {
return "speed-profile";
}
return originalCompilerFilter;
});
Puoi impostare un solo AdjustCompilerFilterCallback
. Se vuoi utilizzare
AdjustCompilerFilterCallback
per eseguire l'override del filtro del compilatore per più
devi combinare il codice in un unico callback. Il callback rimane
attivo per tutte le chiamate future, a meno che non la cancelli.
Se vuoi cancellare il callback, usa
ArtManagerLocal#clearAdjustCompilerFilterCallback
.
getArtManagerLocal().clearAdjustCompilerFilterCallback();
Altre personalizzazioni
ART Service supporta anche altre personalizzazioni.
Imposta la soglia termica per dexopt sfondo
Il controllo termico del job di dexopt in background viene eseguito dal programma di pianificazione dei job.
Il job viene annullato immediatamente quando la temperatura raggiunge
THERMAL_STATUS_MODERATE
La soglia di
THERMAL_STATUS_MODERATE
è ottimizzabile.
Determina se dexopt in background è in esecuzione
Il job di dexopt in background è gestito dal job Scheduler e il suo ID job è
27873780
. Per determinare se il job è in esecuzione, utilizza le API Job Scheduler.
// 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.
...
}
Fornisci un profilo per dexopt
Per utilizzare un profilo come guida per dexopt, inserisci un file .prof
o .dm
accanto a
.
Il file .prof
deve essere un file profilo in formato binario, mentre il nome del file deve essere
il nome file dell'APK + .prof
. Ad esempio,
base.apk.prof
Il nome del file .dm
deve essere il nome dell'APK con
estensione sostituita da .dm
. Ad esempio,
base.dm
Per verificare che il profilo venga utilizzato per dexopt, esegui dexopt con
speed-profile
e controlla il risultato.
pm art clear-app-profiles <package-name>
pm compile -m speed-profile -f -v <package-name>
La prima riga cancella tutti i profili prodotti dal runtime (ovvero quelli in
/data/misc/profiles
), se presente, per assicurarti che il profilo accanto all'APK sia
l'unico profilo che ART Service può usare eventualmente. La seconda riga esegue dexopt
con speed-profile
e passa -v
per stampare il risultato dettagliato.
Se il profilo è in uso, vedrai actualCompilerFilter=speed-profile
in
per ottenere il risultato. Altrimenti, vedrai actualCompilerFilter=verify
. Ad esempio,
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}
Ecco alcuni motivi tipici per cui ART Service non utilizza il profilo:
- Il nome file del profilo non è corretto oppure non è accanto all'APK.
- Il formato del profilo non è corretto.
- Il profilo non corrisponde all'APK. (I checksum nel profilo non
corrispondono ai checksum dei file
.dex
nell'APK.)