Antes de comenzar, consulta una descripción general de alto nivel del servicio de ART.
A partir de Android 14, la compilación AOT en el dispositivo para (también conocido como dexopt) es manejada por el servicio de ART. El servicio de ART forma parte del servicio de ART y puedes personalizarlo con las propiedades del sistema y las APIs.
Propiedades del sistema
el servicio de ART admite todas las opciones de dex2oat.
Además, el servicio de ART admite las siguientes propiedades del sistema:
pm.dexopt.<motivo>
Este es un conjunto de propiedades del sistema que determina los filtros predeterminados del compilador. para todos los motivos de compilación predefinidos que se describen en situaciones de Dexopt.
Para obtener más información, consulta Filtros del compilador.
Los valores predeterminados estándar son los siguientes:
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 (predeterminado: velocidad)
Este es el filtro de resguardo del compilador para apps que usan otras apps.
En principio, el servicio de ART realiza compilaciones guiadas por perfiles (speed-profile
) para
todas las apps cuando sea posible, generalmente durante el dexopt en segundo plano. Sin embargo, existen
algunas apps que usan otras apps (ya sea a través de <uses-library>
o cargadas)
de forma dinámica con Context#createPackageContext
CONTEXT_INCLUDE_CODE
). Esas apps no pueden usar la configuración
perfiles por motivos de privacidad.
Para una app de este tipo, si se solicita una compilación guiada por perfil, primero el servicio de ART
intenta usar un perfil en la nube. Si no existe un perfil de nube, el servicio de ART
recurre al uso del filtro de compilador especificado por pm.dexopt.shared
.
Si la compilación solicitada no está guiada por perfiles, esta propiedad no tiene efecto.
pm.dexopt.<reason>.concurrency (predeterminado: 1)
Este es el número de invocaciones de dex2oat para cierta compilación predefinida
motivos (first-boot
, boot-after-ota
, boot-after-mainline-update
y
bg-dexopt
).
Ten en cuenta que el efecto de esta opción se combina con
opciones de uso de recursos de dex2oat (dalvik.vm.*dex2oat-threads
,
dalvik.vm.*dex2oat-cpu-set
y los perfiles de tareas):
dalvik.vm.*dex2oat-threads
controla la cantidad de subprocesos para cada dex2oat. invocación, mientras quepm.dexopt.<reason>.concurrency
controla la cantidad de invocaciones de dex2oat. Es decir, si la cantidad máxima de subprocesos simultáneos es el producto de las dos propiedades del sistema.dalvik.vm.*dex2oat-cpu-set
y los perfiles de tareas siempre vinculan el núcleo de la CPU independientemente de la cantidad máxima de subprocesos simultáneos (datos que se analizan arriba).
Es posible que una sola invocación de dex2oat no use por completo todos los núcleos de la CPU, sin importar
de dalvik.vm.*dex2oat-threads
. Por lo tanto, aumentar el número de dex2oat
las invocaciones (pm.dexopt.<reason>.concurrency
) pueden usar mejor los núcleos de CPU para
acelerar el progreso general del dexopt. Esto es particularmente útil durante
inicio.
Sin embargo, tener demasiadas invocaciones de dex2oat podría provocar que el dispositivo se quede sin
memoria, aunque esto se puede mitigar si configuras dalvik.vm.dex2oat-swap
como
true
para permitir el uso de un archivo de intercambio. Demasiadas invocaciones, también pueden provocar
cambios de contexto innecesarios. Por lo tanto, este número debe ajustarse cuidadosamente
producto por producto.
pm.dexopt.downgrade_after_inactive_days (valor predeterminado: sin establecer)
Si se establece esta opción, el servicio de ART solo dexopta las apps usadas en las últimas la cantidad de días.
Además, si el almacenamiento es casi bajo, durante el dexopt en segundo plano, el servicio de ART
cambia a una versión inferior el filtro del compilador de aplicaciones que no se utilizan en las últimas aplicaciones
cantidad de días, para liberar espacio. El motivo del compilador es inactive
,
y el filtro del compilador está determinado por pm.dexopt.inactive
. El espacio
para activar esta función es el umbral de poco espacio del Administrador de almacenamiento
(se configura a través de la configuración global sys_storage_threshold_percentage
y
sys_storage_threshold_max_bytes
, predeterminado: 500 MB) más 500 MB.
Si personalizas la lista de paquetes a través de
ArtManagerLocal#setBatchDexoptStartCallback
, los paquetes de la lista proporcionada
de BatchDexoptStartCallback
para bg-dexopt
nunca se cambian a una versión inferior.
pm.dexopt.disable_bg_dexopt (predeterminado: false)
Esto es solo para pruebas. Impide que el servicio de ART programe la ejecución en segundo plano dexopt.
Si el trabajo de dexopt en segundo plano ya está programado, pero aún no se ejecutó, este no tiene efecto. Es decir, el trabajo se seguirá ejecutando.
Una secuencia recomendada de comandos para evitar que el trabajo de dexopt en segundo plano en ejecución es:
setprop pm.dexopt.disable_bg_dexopt true
pm bg-dexopt-job --disable
La primera línea evita que se programe el trabajo de dexopt en segundo plano, si está aún no está programado. La segunda línea anula la programación del trabajo de dexopt en segundo plano si ya está programado y cancela de inmediato el trabajo de dexopt en segundo plano, si mientras se está ejecutando.
APIs de servicio de ART
El servicio de ART expone las APIs de Java para la personalización. Las APIs se definen en
ArtManagerLocal
Consulta Javadoc en
art/libartservice/service/java/com/android/server/art/ArtManagerLocal.java
para
(fuente de Android 14, fuente de desarrollo no publicada).
ArtManagerLocal
es un singleton que mantiene LocalManagerRegistry
. Un asistente
la función com.android.server.pm.DexOptHelper#getArtManagerLocal
te ayuda
y obtenerlo.
import static com.android.server.pm.DexOptHelper.getArtManagerLocal;
La mayoría de las APIs requieren una instancia de PackageManagerLocal.FilteredSnapshot
,
que contiene la información de todas las apps. Para obtenerlo, llama a
PackageManagerLocal#withFilteredSnapshot
, donde PackageManagerLocal
también es
un singleton de LocalManagerRegistry
y que se puede obtener de
com.android.server.pm.PackageManagerServiceUtils#getPackageManagerLocal
import static com.android.server.pm.PackageManagerServiceUtils.getPackageManagerLocal;
A continuación, se muestran algunos casos de uso típicos de las APIs.
Activar dexopt para una app
Puedes activar el dexopt para cualquier app en cualquier momento llamando a
ArtManagerLocal#dexoptPackage
try (var snapshot = getPackageManagerLocal().withFilteredSnapshot()) {
getArtManagerLocal().dexoptPackage(
snapshot,
"com.google.android.calculator",
new DexoptParams.Builder(ReasonMapping.REASON_INSTALL).build());
}
También puede pasar su propio motivo de dexopt. Si haces eso, la clase de prioridad y el filtro del compilador debe establecerse de manera explícita.
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
Si una llamada a dexoptPackage
inicia una operación, puedes pasar un
como indicador de cancelación, que te permite cancelar la operación en algún momento. Esto puede
puede ser útil cuando se ejecuta dexopt de manera así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();
También puedes cancelar el dexopt en segundo plano, iniciado por el servicio de ART.
getArtManagerLocal().cancelBackgroundDexoptJob();
Obtener resultados de dexopt
Si una llamada a dexoptPackage
inicia una operación, puedes obtener el resultado.
del valor que se muestra.
DexoptResult result;
try (var snapshot = getPackageManagerLocal().withFilteredSnapshot()) {
result = getArtManagerLocal().dexoptPackage(...);
}
// Process the result here.
...
El servicio de ART también inicia operaciones de dexopt por su cuenta en muchas situaciones, como
dexopt en segundo plano. Para escuchar todos los resultados de dexopt, ya sea que la operación se
iniciada por una llamada a dexoptPackage
o por un servicio de ART, usa
ArtManagerLocal#addDexoptDoneCallback
getArtManagerLocal().addDexoptDoneCallback(
false /* onlyIncludeUpdates */,
Runnable::run,
(result) -> {
// Process the result here.
...
});
El primer argumento determina si solo se incluyen actualizaciones en el resultado. Si solo quieres escuchar los paquetes que se actualizan con dexopt, configúralo como verdadero.
El segundo argumento es el ejecutor de la devolución de llamada. Para ejecutar la devolución de llamada en
el mismo subproceso que realiza el dexopt, usa Runnable::run
. Si no quieres que la
para bloquear el dexopt, usa un ejecutor asíncrono.
Puedes agregar varias devoluciones de llamada y el servicio de ART las ejecutará todas. de forma secuencial. Todas las devoluciones de llamada permanecerán activas para todas las llamadas futuras, a menos que y quitarlos.
Si deseas quitar una devolución de llamada, conserva la referencia cuando
agregarlo y 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);
Personaliza la lista de paquetes y los parámetros dexopt
El servicio de ART inicia operaciones de dexopt por su cuenta durante el inicio y el segundo plano.
el dexopt. Para personalizar la lista de paquetes o los parámetros dexopt para esas operaciones,
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.
}
});
Puedes agregar elementos a la lista del paquete, quitarlos, ordenarla o incluso usar una lista completamente diferente.
Tu devolución de llamada debe ignorar motivos desconocidos, ya que se podrían agregar más motivos en el futuro.
Puedes establecer como máximo un BatchDexoptStartCallback
. La devolución de llamada permanecerá
activo para todas las llamadas futuras, a menos que lo borres.
Si deseas borrar la devolución de llamada, usa
ArtManagerLocal#clearBatchDexoptStartCallback
getArtManagerLocal().clearBatchDexoptStartCallback();
Personalizar los parámetros del trabajo de dexopt en segundo plano
De forma predeterminada, el trabajo de dexopt en segundo plano se ejecuta una vez al día cuando el dispositivo está inactivo.
y cargando. Esto se puede cambiar
ArtManagerLocal#setScheduleBackgroundDexoptJobCallback
getArtManagerLocal().setScheduleBackgroundDexoptJobCallback(
Runnable::run,
builder -> {
builder.setPeriodic(TimeUnit.DAYS.toMillis(2));
});
Puedes establecer como máximo un ScheduleBackgroundDexoptJobCallback
. La devolución de llamada
permanecerá activa para todas las llamadas futuras, a menos que las borres.
Si deseas borrar la devolución de llamada, usa
ArtManagerLocal#clearScheduleBackgroundDexoptJobCallback
getArtManagerLocal().clearScheduleBackgroundDexoptJobCallback();
Inhabilitar dexopt temporalmente
Cualquier operación de dexopt que inicie el servicio de ART activará una
BatchDexoptStartCallback
Puedes seguir cancelando las operaciones para
inhabilitar eficazmente el dexopt.
Si la operación que cancelas es dexopt en segundo plano, sigue la operación predeterminada. política de reintentos (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);
Puedes tener un BatchDexoptStartCallback
como máximo. Si también quieres usar
BatchDexoptStartCallback
para personalizar la lista de paquetes o los parámetros de dexopt.
debes combinar el código en una devolución de llamada.
// Bad example.
// Disable dexopt.
getArtManagerLocal().unscheduleBackgroundDexoptJob();
// Re-enable dexopt.
getArtManagerLocal().scheduleBackgroundDexoptJob();
ART no inicia la operación dexopt que se realiza en la instalación de la app.
Servicio. En cambio, el administrador de paquetes la inicia a través de un
dexoptPackage
llamada. Por lo tanto, no activa
BatchDexoptStartCallback
Para inhabilitar el dexopt en la instalación de la aplicación, evita que
administrador de paquetes llame a dexoptPackage
.
Anula el filtro del compilador para ciertos paquetes (Android 15 [AOSP experimental] y versiones posteriores)
Puedes anular el filtro del compilador para ciertos paquetes registrando un
a través de setAdjustCompilerFilterCallback
. Se llama a la devolución de llamada
cada vez que un paquete se dexopta, independientemente de que el dexopt se inicie por
Servicio de ART durante el inicio y el dexopt en segundo plano o mediante una llamada a la API de dexoptPackage
.
Si un paquete no necesita ajustes, se debe mostrar la devolución de llamada.
originalCompilerFilter
getArtManagerLocal().setAdjustCompilerFilterCallback(
Runnable::run,
(packageName, originalCompilerFilter, reason) -> {
if (isVeryImportantPackage(packageName)) {
return "speed-profile";
}
return originalCompilerFilter;
});
Puedes establecer solo un AdjustCompilerFilterCallback
. Si quieres usar
AdjustCompilerFilterCallback
para anular el filtro del compilador para varios elementos
, debes combinar el código en una devolución de llamada. La devolución de llamada permanece
activo para todas las llamadas futuras, a menos que lo borres.
Si deseas borrar la devolución de llamada, usa
ArtManagerLocal#clearAdjustCompilerFilterCallback
getArtManagerLocal().clearAdjustCompilerFilterCallback();
Otras personalizaciones
El servicio de ART también admite algunas otras personalizaciones.
Establece el umbral térmico para el dexopt en segundo plano
El programador de trabajos ejecuta el control térmico del trabajo de dexopt en segundo plano.
El trabajo se cancela de inmediato cuando la temperatura alcanza
THERMAL_STATUS_MODERATE
El umbral de
THERMAL_STATUS_MODERATE
se puede ajustar.
Determina si se está ejecutando el dexopt en segundo plano
El programador de trabajos administra el trabajo de dexopt en segundo plano y su ID de trabajo es
27873780
Para determinar si el trabajo se está ejecutando, usa las APIs de 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.
...
}
Proporciona un perfil para dexopt
Para usar un perfil como guía para dexopt, coloca un archivo .prof
o .dm
junto al archivo
APK
El archivo .prof
debe ser un archivo de perfil en formato binario, y el nombre debe ser
el nombre del archivo del APK + .prof
. Por ejemplo:
base.apk.prof
El nombre del archivo .dm
debe ser el nombre del APK que tenga
La extensión se reemplazó por .dm
. Por ejemplo:
base.dm
Para verificar que el perfil se use para dexopt, ejecuta dexopt con
speed-profile
y verifica el resultado.
pm art clear-app-profiles <package-name>
pm compile -m speed-profile -f -v <package-name>
La primera línea borra todos los perfiles producidos por el entorno de ejecución (es decir, aquellos en
/data/misc/profiles
), si lo hay, para asegurarte de que el perfil junto al APK se
el único perfil que el servicio de ART puede usar. La segunda línea ejecuta dexopt
con speed-profile
y pasa -v
para imprimir el resultado detallado.
Si el perfil está en uso, verás actualCompilerFilter=speed-profile
en
el resultado. De lo contrario, verás actualCompilerFilter=verify
. Por ejemplo:
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}
Entre los motivos típicos por los que el servicio de ART no usa el perfil, se incluyen los siguientes:
- El perfil tiene un nombre de archivo incorrecto o no está junto al APK.
- El formato del perfil es incorrecto.
- El perfil no coincide con el APK. (Las sumas de comprobación del perfil no
coinciden con las sumas de comprobación de los archivos
.dex
del APK)