Konfiguracja usługi ART

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, a pm.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).