Antes de começar, consulte a visão geral de alto nível do serviço ART.
No Android 14 e versões mais recentes, a compilação AOT no dispositivo para (conhecido como dexopt) é gerenciado pelo ART Service. O serviço ART é parte da ART e você pode personalizá-lo por meio de propriedades do sistema e APIs.
Propriedades do sistema
O serviço ART oferece suporte a todos os opções dodex2oat.
Além disso, o Serviço ART é compatível com as seguintes propriedades do sistema:
pm.dexopt.<reason>
Esse é um conjunto de propriedades do sistema que determinam os filtros padrão do compilador para todos os motivos de compilação predefinidos descritos em Cenários de DEXopt.
Para mais informações, consulte Filtros do compilador.
Os valores padrão são:
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 (padrão: velocidade)
Esse é o filtro do compilador substituto para apps usados por outros apps.
Em princípio, o serviço ART faz a compilação guiada por perfil (speed-profile
) para
todos os apps quando possível, geralmente durante o dexopt em segundo plano. No entanto, existem
alguns apps usados por outros apps (por meio do <uses-library>
ou já carregados)
dinamicamente usando Context#createPackageContext
com
CONTEXT_INCLUDE_CODE
). Esses apps não podem usar o
do YouTube por motivos de privacidade.
Para esse app, se a compilação guiada por perfil for solicitada, o serviço ART será necessário primeiro
tenta usar um perfil na nuvem. Se não houver um perfil de nuvem, o ART Service
volta a usar o filtro do compilador especificado por pm.dexopt.shared
.
Se a compilação solicitada não for orientada pelo perfil, essa propriedade não terá efeito.
pm.dexopt.<reason>.concurrency (padrão: 1)
Este é o número de invocações de dex2oat para determinada compilação predefinida
(first-boot
, boot-after-ota
, boot-after-mainline-update
e
bg-dexopt
).
Observe que o efeito dessa opção é combinado
opções de uso de recursos do dex2oat (dalvik.vm.*dex2oat-threads
,
dalvik.vm.*dex2oat-cpu-set
e os perfis de tarefas):
dalvik.vm.*dex2oat-threads
controla o número de linhas de execução de cada dex2oat. da invocação, enquantopm.dexopt.<reason>.concurrency
controla o número de dex2oat. Ou seja, o número máximo de threads simultâneos é de o produto das duas propriedades do sistema.- O
dalvik.vm.*dex2oat-cpu-set
e os perfis de tarefa sempre vinculam o núcleo da CPU independentemente do número máximo de linhas de execução simultâneas (discutido) acima).
Uma única invocação de dex2oat pode não utilizar todos os núcleos da CPU, independentemente
de dalvik.vm.*dex2oat-threads
. Portanto, aumentar o número de dex2oat
(pm.dexopt.<reason>.concurrency
) podem utilizar melhor os núcleos da CPU para
acelerar o progresso geral do dexopt. Isso é particularmente útil durante
inicialização.
No entanto, com muitas invocações de dex2oat, o dispositivo pode ficar sem
na memória, embora isso possa ser atenuado definindo dalvik.vm.dex2oat-swap
como
true
para permitir o uso de um arquivo de troca. Muitas invocações também podem causar
troca de contexto desnecessária. Por isso, esse número deve ser cuidadosamente ajustado
produto por produto.
pm.dexopt.downgrade_after_inactive_days (padrão: não definido)
Se esta opção for definida, o ART Service só dexoptará os apps usados nos últimos número de dias.
Além disso, se o armazenamento estiver quase baixo, durante o dexopt em segundo plano, o ART Service
faz downgrade do filtro do compilador de apps que não foram usados no último período
dias, para liberar espaço. O motivo do compilador para isso é inactive
,
e o filtro do compilador é determinado por pm.dexopt.inactive
. O espaço
o limite para acionar esse atributo é o baixo limite de espaço do gerenciador de armazenamento
(configurável por meio das configurações globais sys_storage_threshold_percentage
e
sys_storage_threshold_max_bytes
, padrão: 500 MB) mais 500 MB.
Se você personalizar a lista de pacotes por meio
ArtManagerLocal#setBatchDexoptStartCallback
, os pacotes na lista fornecido
por BatchDexoptStartCallback
para bg-dexopt
nunca sofrem downgrade.
pm.dexopt.disable_bg_dexopt (padrão: false)
Isso é apenas para testes. Impede que o serviço ART programe o segundo plano dexopt.
Se o job de dexopt em segundo plano já estiver programado, mas ainda não tiver sido executado, esse não tem efeito. Ou seja, o job ainda será executado.
Uma sequência recomendada de comandos para evitar que o job dexopt em segundo plano seja em execução é:
setprop pm.dexopt.disable_bg_dexopt true
pm bg-dexopt-job --disable
A primeira linha impede que o job dexopt em segundo plano seja programado, se for ainda não agendado. A segunda linha cancela a programação do job de dexopt em segundo plano, se ele já está agendado e cancela imediatamente o job dexopt em segundo plano, se quando ele está em execução.
APIs ART Service
O serviço ART expõe APIs Java para personalização. As APIs são definidas em
ArtManagerLocal
: Confira o Javadoc em
art/libartservice/service/java/com/android/server/art/ArtManagerLocal.java
para
usos (origem do Android 14 e origem de desenvolvimento não lançada).
ArtManagerLocal
é um Singleton mantido por LocalManagerRegistry
. Um ajudante
a função com.android.server.pm.DexOptHelper#getArtManagerLocal
ajuda você
obtê-lo.
import static com.android.server.pm.DexOptHelper.getArtManagerLocal;
A maioria das APIs requer uma instância de PackageManagerLocal.FilteredSnapshot
,
que contém as informações de todos os apps. Você pode obtê-lo chamando
PackageManagerLocal#withFilteredSnapshot
, em que PackageManagerLocal
também é
Um Singleton mantido por LocalManagerRegistry
e pode ser obtido de
com.android.server.pm.PackageManagerServiceUtils#getPackageManagerLocal
.
import static com.android.server.pm.PackageManagerServiceUtils.getPackageManagerLocal;
Veja a seguir alguns casos de uso típicos das APIs.
Acionar dexopt para um app
Você pode acionar o dexopt para qualquer app a qualquer momento chamando
ArtManagerLocal#dexoptPackage
:
try (var snapshot = getPackageManagerLocal().withFilteredSnapshot()) {
getArtManagerLocal().dexoptPackage(
snapshot,
"com.google.android.calculator",
new DexoptParams.Builder(ReasonMapping.REASON_INSTALL).build());
}
Você também pode informar seu próprio motivo para o dexopt. Se fizer isso, a classe de prioridade e o filtro do compilador precisa ser definido explicitamente.
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());
}
Cancelar dexopt
Se uma operação for iniciada por uma chamada dexoptPackage
, será possível transmitir um
de cancelamento, que permite cancelar a operação em algum momento. Isso pode
será útil ao executar o dexopt de forma assíncrona.
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();
Você também pode cancelar o dexopt em segundo plano, que é iniciado pelo serviço ART.
getArtManagerLocal().cancelBackgroundDexoptJob();
Ver resultados do dexopt
Se uma operação for iniciada por uma chamada dexoptPackage
, você poderá receber o resultado
do valor de retorno.
DexoptResult result;
try (var snapshot = getPackageManagerLocal().withFilteredSnapshot()) {
result = getArtManagerLocal().dexoptPackage(...);
}
// Process the result here.
...
O serviço ART também inicia operações de dexopt por conta própria em muitos cenários, como
dexopt em segundo plano. Para detectar todos os resultados do dexopt, independentemente de a operação
iniciado por uma chamada dexoptPackage
ou pelo serviço ART, use
ArtManagerLocal#addDexoptDoneCallback
.
getArtManagerLocal().addDexoptDoneCallback(
false /* onlyIncludeUpdates */,
Runnable::run,
(result) -> {
// Process the result here.
...
});
O primeiro argumento determina se serão incluídas apenas atualizações no resultado. Se você só quiser ouvir pacotes que são atualizados pelo dexopt, defina-o como verdadeiro.
O segundo argumento é o executor do callback. Para executar o callback no
na mesma linha de execução que executa o dexopt, use Runnable::run
. Se você não quiser que
para bloquear o dexopt, use um executor assíncrono.
Você pode adicionar vários callbacks. O serviço ART executará todos eles sequencialmente. Todos os retornos de chamada permanecerão ativos para todas as chamadas futuras, a menos que removê-los.
Se você quiser remover um callback, mantenha a referência dele ao
adicioná-lo e usar 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);
Personalizar a lista de pacotes e os parâmetros de dexopt
O ART Service inicia as operações dexopt durante a inicialização e em segundo plano
dexopt. Para personalizar a lista de pacotes ou os parâmetros dexopt para essas operações,
use 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.
}
});
É possível adicionar ou remover itens da lista de pacotes, classificá-los ou até mesmo usar uma lista completamente diferente.
Seu callback precisa ignorar os motivos desconhecidos, porque mais motivos podem ser adicionados em no futuro.
É possível definir no máximo um BatchDexoptStartCallback
. O callback permanecerá
ativo para todas as chamadas futuras, a menos que você permita isso.
Se quiser limpar o callback, use
ArtManagerLocal#clearBatchDexoptStartCallback
:
getArtManagerLocal().clearBatchDexoptStartCallback();
Personalizar os parâmetros do job de dexopt em segundo plano
Por padrão, o job de dexopt em segundo plano é executado uma vez por dia quando o dispositivo está inativo
e carregando. Isso pode ser alterado usando
ArtManagerLocal#setScheduleBackgroundDexoptJobCallback
:
getArtManagerLocal().setScheduleBackgroundDexoptJobCallback(
Runnable::run,
builder -> {
builder.setPeriodic(TimeUnit.DAYS.toMillis(2));
});
É possível definir no máximo um ScheduleBackgroundDexoptJobCallback
. A chamada de retorno
permanecerá ativo para todas as chamadas futuras, a menos que você o autorize.
Se quiser limpar o callback, use
ArtManagerLocal#clearScheduleBackgroundDexoptJobCallback
:
getArtManagerLocal().clearScheduleBackgroundDexoptJobCallback();
Desativar temporariamente o dexopt
Qualquer operação de dexopt iniciada pelo serviço ART aciona uma
BatchDexoptStartCallback
: Você pode continuar cancelando as operações
desativar o dexopt.
Se a operação que você cancelar for dexopt em segundo plano, ela seguirá o padrão política de nova tentativa (30 segundos, exponencial, limitada a 5 horas).
// 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);
Você pode ter no máximo um BatchDexoptStartCallback
. Se você também quiser usar
BatchDexoptStartCallback
para personalizar a lista de pacotes ou os parâmetros dexopt;
você precisa combinar o código em um callback.
// Bad example.
// Disable dexopt.
getArtManagerLocal().unscheduleBackgroundDexoptJob();
// Re-enable dexopt.
getArtManagerLocal().scheduleBackgroundDexoptJob();
A operação de dexopt realizada na instalação do app não é iniciada pelo ART.
Serviço. Em vez disso, ele é iniciado pelo gerenciador de pacotes por meio de uma
dexoptPackage
. Portanto, ele não aciona
BatchDexoptStartCallback
Para desativar o dexopt na instalação do app, evite o
gerenciador de pacotes chame dexoptPackage
.
Substituir o filtro do compilador para determinados pacotes (Android 15 ou versões mais recentes).
Você pode substituir o filtro do compilador para determinados pacotes registrando um
usando setAdjustCompilerFilterCallback
. O callback é chamado
sempre que um pacote será dexoptado, não importa se ele for iniciado pelo
Serviço ART durante a inicialização e o dexopt em segundo plano ou por uma chamada de API dexoptPackage
.
Se um pacote não precisar de ajuste, o callback precisará retornar
originalCompilerFilter
:
getArtManagerLocal().setAdjustCompilerFilterCallback(
Runnable::run,
(packageName, originalCompilerFilter, reason) -> {
if (isVeryImportantPackage(packageName)) {
return "speed-profile";
}
return originalCompilerFilter;
});
Só é possível definir um AdjustCompilerFilterCallback
. Se você quiser usar
AdjustCompilerFilterCallback
para substituir o filtro do compilador para vários
pacotes, combine o código em um callback. O callback permanece
ativo para todas as chamadas futuras, a menos que você permita isso.
Se quiser limpar o callback, use
ArtManagerLocal#clearAdjustCompilerFilterCallback
:
getArtManagerLocal().clearAdjustCompilerFilterCallback();
Outras personalizações
O serviço ART também é compatível com algumas outras personalizações.
Definir o limite térmico do dexopt em segundo plano
O controle térmico do job dexopt em segundo plano é realizado pelo Programador de jobs.
O job é cancelado imediatamente quando a temperatura atinge
THERMAL_STATUS_MODERATE
O limite de
THERMAL_STATUS_MODERATE
é ajustável.
Determinar se o dexopt em segundo plano está em execução
O job dexopt em segundo plano é gerenciado pelo Programador de jobs, e o ID dele é
27873780
: Para determinar se o job está em execução, use as APIs 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.
...
}
Fornecer um perfil para o dexopt
Para usar um perfil para orientar o dexopt, coloque um arquivo .prof
ou .dm
ao lado do
APK.
O arquivo .prof
precisa ser um arquivo de perfil em formato binário, e o nome do arquivo precisa ser
o nome de arquivo do APK + .prof
. Por exemplo:
base.apk.prof
O nome do arquivo .dm
precisa ser o mesmo do APK com o
extensão substituída por .dm
. Por exemplo:
base.dm
Para verificar se o perfil está sendo usado para o dexopt, execute dexopt com
speed-profile
e verifique o resultado.
pm art clear-app-profiles <package-name>
pm compile -m speed-profile -f -v <package-name>
A primeira linha limpa todos os perfis produzidos pelo tempo de execução (ou seja, aqueles em
/data/misc/profiles
), se houver, para garantir que o perfil ao lado do APK seja
o único perfil que o ART Service poderia usar. A segunda linha executa o dexopt
com speed-profile
e transmite -v
para exibir o resultado detalhado.
Se o perfil estiver sendo usado, você verá actualCompilerFilter=speed-profile
no
o resultado. Caso contrário, você verá actualCompilerFilter=verify
. Por exemplo:
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}
Motivos típicos para o serviço ART não usar o perfil incluem:
- O perfil tem um nome de arquivo incorreto ou não está ao lado do APK.
- O perfil está no formato errado.
- O perfil não corresponde ao APK. As somas de verificação no perfil não têm
correspondem às somas de verificação dos arquivos
.dex
no APK.