Konfigurasi Layanan ART

Sebelum memulai, lihat ikhtisar tingkat tinggi Layanan ART .

Dimulai dengan Android 14, kompilasi AOT di perangkat untuk aplikasi (alias dexopt) ditangani oleh ART Service. Layanan ART adalah bagian dari modul ART, dan Anda dapat menyesuaikannya melalui properti sistem dan API.

Properti sistem

Layanan ART mendukung semua opsi dex2oat yang relevan.

Selain itu, Layanan ART mendukung properti sistem berikut:

pm.dexopt.<alasan>

Ini adalah sekumpulan properti sistem yang menentukan filter kompiler default untuk semua alasan kompilasi yang telah ditentukan sebelumnya yang dijelaskan dalam skenario Dexopt .

Untuk informasi selengkapnya, lihat Filter kompiler .

Nilai default standarnya adalah:

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 (default: kecepatan)

Ini adalah filter kompiler cadangan untuk aplikasi yang digunakan oleh aplikasi lain.

Pada prinsipnya, Layanan ART melakukan kompilasi yang dipandu profil ( speed-profile ) untuk semua aplikasi bila memungkinkan, biasanya selama dexopt latar belakang. Namun, ada beberapa aplikasi yang digunakan oleh aplikasi lain (baik melalui <uses-library> atau dimuat secara dinamis menggunakan Context#createPackageContext dengan CONTEXT_INCLUDE_CODE ). Aplikasi tersebut tidak dapat menggunakan profil lokal karena alasan privasi.

Untuk aplikasi semacam itu, jika kompilasi yang dipandu profil diminta, Layanan ART terlebih dahulu mencoba menggunakan profil cloud. Jika profil cloud tidak ada, ART Service kembali menggunakan filter kompiler yang ditentukan oleh pm.dexopt.shared .

Jika kompilasi yang diminta tidak dipandu oleh profil, properti ini tidak akan berpengaruh.

pm.dexopt.<alasan>.konkurensi (default: 1)

Ini adalah jumlah pemanggilan dex2oat untuk alasan kompilasi tertentu yang telah ditentukan sebelumnya ( first-boot , boot-after-ota , boot-after-mainline-update , dan bg-dexopt ).

Perhatikan bahwa efek opsi ini dikombinasikan dengan opsi penggunaan sumber daya dex2oat ( dalvik.vm.*dex2oat-threads , dalvik.vm.*dex2oat-cpu-set , dan profil tugas):

  • dalvik.vm.*dex2oat-threads mengontrol jumlah thread untuk setiap pemanggilan dex2oat, sedangkan pm.dexopt.<reason>.concurrency mengontrol jumlah pemanggilan dex2oat. Artinya, jumlah maksimum thread bersamaan adalah produk dari dua properti sistem.
  • dalvik.vm.*dex2oat-cpu-set dan profil tugas selalu membatasi penggunaan inti CPU, berapa pun jumlah maksimum thread bersamaan (dibahas di atas).

Pemanggilan dex2oat tunggal mungkin tidak sepenuhnya memanfaatkan semua inti CPU, terlepas dari dalvik.vm.*dex2oat-threads . Oleh karena itu, meningkatkan jumlah pemanggilan dex2oat ( pm.dexopt.<reason>.concurrency ) dapat memanfaatkan inti CPU dengan lebih baik, untuk mempercepat kemajuan dexopt secara keseluruhan. Ini sangat berguna saat boot.

Namun, pemanggilan dex2oat yang terlalu banyak dapat menyebabkan perangkat kehabisan memori, meskipun hal ini dapat diatasi dengan menyetel dalvik.vm.dex2oat-swap ke true untuk mengizinkan penggunaan file swap. Terlalu banyak pemanggilan juga dapat menyebabkan peralihan konteks yang tidak perlu. Oleh karena itu, angka ini harus disesuaikan dengan cermat berdasarkan produk per produk.

pm.dexopt.downgrade_after_inactive_days (default: tidak disetel)

Jika opsi ini disetel, Layanan ART hanya menghapus aplikasi yang digunakan dalam beberapa hari terakhir.

Selain itu, Jika penyimpanan hampir habis, selama dexopt latar belakang, Layanan ART menurunkan versi filter kompiler aplikasi yang tidak digunakan dalam beberapa hari terakhir, untuk mengosongkan ruang. Alasan kompiler untuk ini adalah inactive , dan filter kompiler ditentukan oleh pm.dexopt.inactive . Ambang batas ruang untuk memicu fitur ini adalah ambang batas ruang rendah Manajer Penyimpanan (dapat dikonfigurasi melalui pengaturan global sys_storage_threshold_percentage dan sys_storage_threshold_max_bytes , default: 500MB) ditambah 500MB.

Jika Anda menyesuaikan daftar paket melalui ArtManagerLocal#setBatchDexoptStartCallback , paket dalam daftar yang disediakan oleh BatchDexoptStartCallback untuk bg-dexopt tidak akan pernah diturunkan versinya.

pm.dexopt.disable_bg_dexopt (default: salah)

Ini hanya untuk pengujian. Ini mencegah Layanan ART menjadwalkan pekerjaan dexopt latar belakang.

Jika pekerjaan dexopt latar belakang sudah dijadwalkan tetapi belum dijalankan, opsi ini tidak berpengaruh. Artinya, pekerjaan akan tetap berjalan.

Urutan perintah yang disarankan untuk mencegah berjalannya pekerjaan dexopt latar belakang adalah:

setprop pm.dexopt.disable_bg_dexopt true
pm bg-dexopt-job --disable

Baris pertama mencegah pekerjaan dexopt latar belakang dijadwalkan, jika belum dijadwalkan. Baris kedua membatalkan jadwal pekerjaan dexopt latar belakang, jika sudah dijadwalkan, dan segera membatalkan pekerjaan dexopt latar belakang, jika sedang berjalan.

API Layanan ART

Layanan ART memaparkan Java API untuk penyesuaian. API didefinisikan dalam ArtManagerLocal . Lihat Javadoc di art/libartservice/service/java/com/android/server/art/ArtManagerLocal.java untuk mengetahui penggunaan ( sumber Android 14 , sumber pengembangan yang belum dirilis ).

ArtManagerLocal adalah singleton yang dipegang oleh LocalManagerRegistry . Fungsi pembantu com.android.server.pm.DexOptHelper#getArtManagerLocal membantu Anda mendapatkannya.

import static com.android.server.pm.DexOptHelper.getArtManagerLocal;

Sebagian besar API memerlukan instance PackageManagerLocal.FilteredSnapshot , yang menyimpan informasi semua aplikasi. Anda bisa mendapatkannya dengan menelepon PackageManagerLocal#withFilteredSnapshot , di mana PackageManagerLocal juga merupakan singleton yang dipegang oleh LocalManagerRegistry dan dapat diperoleh dari com.android.server.pm.PackageManagerServiceUtils#getPackageManagerLocal .

import static com.android.server.pm.PackageManagerServiceUtils.getPackageManagerLocal;

Berikut ini adalah beberapa kasus penggunaan API yang umum.

Memicu dexopt untuk suatu aplikasi

Anda dapat memicu dexopt untuk aplikasi apa pun kapan saja dengan memanggil ArtManagerLocal#dexoptPackage .

try (var snapshot = getPackageManagerLocal().withFilteredSnapshot()) {
  getArtManagerLocal().dexoptPackage(
      snapshot,
      "com.google.android.calculator",
      new DexoptParams.Builder(ReasonMapping.REASON_INSTALL).build());
}

Anda juga dapat memberikan alasan dexopt Anda sendiri. Jika Anda melakukan itu, kelas prioritas dan filter kompiler harus disetel secara eksplisit.

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());
}

Batalkan deksopt

Jika suatu operasi dimulai oleh panggilan dexoptPackage , Anda dapat meneruskan sinyal pembatalan, yang memungkinkan Anda membatalkan operasi pada suatu saat. Ini bisa berguna ketika Anda menjalankan dexopt secara asinkron.

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();

Anda juga dapat membatalkan dexopt latar belakang, yang dimulai oleh Layanan ART.

getArtManagerLocal().cancelBackgroundDexoptJob();

Dapatkan hasil dexopt

Jika operasi dimulai oleh panggilan dexoptPackage , Anda bisa mendapatkan hasil dari nilai yang dikembalikan.

DexoptResult result;
try (var snapshot = getPackageManagerLocal().withFilteredSnapshot()) {
  result = getArtManagerLocal().dexoptPackage(...);
}

// Process the result here.
...

Layanan ART juga memulai operasi dexopt itu sendiri dalam banyak skenario, seperti dexopt latar belakang. Untuk mendengarkan semua hasil dexopt, baik operasi dimulai dengan panggilan dexoptPackage atau oleh ART Service, gunakan ArtManagerLocal#addDexoptDoneCallback .

getArtManagerLocal().addDexoptDoneCallback(
    false /* onlyIncludeUpdates */,
    Runnable::run,
    (result) -> {
      // Process the result here.
      ...
    });

Argumen pertama menentukan apakah hanya menyertakan pembaruan dalam hasil. Jika Anda hanya ingin mendengarkan paket yang diperbarui oleh dexopt, setel ke true.

Argumen kedua adalah pelaksana panggilan balik. Untuk menjalankan panggilan balik pada thread yang sama yang menjalankan dexopt, gunakan Runnable::run . Jika Anda tidak ingin panggilan balik memblokir dexopt, gunakan eksekutor asinkron.

Anda dapat menambahkan beberapa panggilan balik, dan ART Service akan menjalankan semuanya secara berurutan. Semua panggilan balik akan tetap aktif untuk semua panggilan berikutnya kecuali Anda menghapusnya.

Jika Anda ingin menghapus panggilan balik, simpan referensi panggilan balik tersebut saat Anda menambahkannya, dan gunakan 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);

Sesuaikan daftar paket dan parameter dexopt

Layanan ART memulai operasi dexopt sendiri selama boot dan dexopt di latar belakang. Untuk menyesuaikan daftar paket atau parameter dexopt untuk operasi tersebut, gunakan 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.
      }
    });

Anda dapat menambahkan item ke daftar paket, menghapus item darinya, mengurutkannya, atau bahkan menggunakan daftar yang sama sekali berbeda.

Panggilan balik Anda harus mengabaikan alasan yang tidak diketahui karena alasan lainnya mungkin ditambahkan di masa mendatang.

Anda dapat menyetel paling banyak satu BatchDexoptStartCallback . Panggilan balik akan tetap aktif untuk semua panggilan berikutnya kecuali Anda menghapusnya.

Jika Anda ingin menghapus panggilan balik, gunakan ArtManagerLocal#clearBatchDexoptStartCallback .

getArtManagerLocal().clearBatchDexoptStartCallback();

Sesuaikan parameter pekerjaan dexopt latar belakang

Secara default, pekerjaan dexopt latar belakang berjalan sekali sehari saat perangkat dalam keadaan idle dan mengisi daya. Ini dapat diubah menggunakan ArtManagerLocal#setScheduleBackgroundDexoptJobCallback .

getArtManagerLocal().setScheduleBackgroundDexoptJobCallback(
    Runnable::run,
    builder -> {
      builder.setPeriodic(TimeUnit.DAYS.toMillis(2));
    });

Anda dapat menyetel maksimal satu ScheduleBackgroundDexoptJobCallback . Panggilan balik akan tetap aktif untuk semua panggilan berikutnya kecuali Anda menghapusnya.

Jika Anda ingin menghapus panggilan balik, gunakan ArtManagerLocal#clearScheduleBackgroundDexoptJobCallback .

getArtManagerLocal().clearScheduleBackgroundDexoptJobCallback();

Nonaktifkan sementara dexopt

Setiap operasi dexopt yang dimulai oleh ART Service memicu BatchDexoptStartCallback . Anda dapat terus membatalkan operasi untuk menonaktifkan dexopt secara efektif.

Jika operasi yang Anda batalkan adalah dexopt latar belakang, operasi tersebut mengikuti kebijakan percobaan ulang default (30 detik, eksponensial, dibatasi hingga 5 jam).

// 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);

Anda dapat memiliki paling banyak satu BatchDexoptStartCallback . Jika Anda juga ingin menggunakan BatchDexoptStartCallback untuk menyesuaikan daftar paket atau parameter dexopt, Anda harus menggabungkan kode menjadi satu callback.

// Bad example.

// Disable dexopt.
getArtManagerLocal().unscheduleBackgroundDexoptJob();

// Re-enable dexopt.
getArtManagerLocal().scheduleBackgroundDexoptJob();

Operasi dexopt yang dilakukan pada pemasangan aplikasi tidak dimulai oleh Layanan ART. Sebaliknya, ini dimulai oleh manajer paket melalui panggilan dexoptPackage . Oleh karena itu, ini tidak memicu BatchDexoptStartCallback . Untuk menonaktifkan dexopt pada pemasangan aplikasi, cegah manajer paket memanggil dexoptPackage .

Ganti filter compiler untuk paket tertentu (Android 15 (eksperimental AOSP)+)

Anda dapat mengganti filter kompiler untuk paket tertentu dengan mendaftarkan panggilan balik melalui setAdjustCompilerFilterCallback . Callback dipanggil setiap kali sebuah paket akan didesopt, tidak peduli dexopt diinisiasi oleh ART Service selama boot dan dexopt di latar belakang atau dengan panggilan API dexoptPackage .

Jika sebuah paket tidak memerlukan penyesuaian, callback harus mengembalikan originalCompilerFilter .

getArtManagerLocal().setAdjustCompilerFilterCallback(
    Runnable::run,
    (packageName, originalCompilerFilter, reason) -> {
      if (isVeryImportantPackage(packageName)) {
        return "speed-profile";
      }
      return originalCompilerFilter;
    });

Anda hanya dapat menyetel satu AdjustCompilerFilterCallback . Jika Anda ingin menggunakan AdjustCompilerFilterCallback untuk mengganti filter kompiler untuk beberapa paket, Anda harus menggabungkan kode menjadi satu callback. Panggilan balik tetap aktif untuk semua panggilan berikutnya kecuali Anda menghapusnya.

Jika Anda ingin menghapus panggilan balik, gunakan ArtManagerLocal#clearAdjustCompilerFilterCallback .

getArtManagerLocal().clearAdjustCompilerFilterCallback();

Kustomisasi lainnya

Layanan ART juga mendukung beberapa penyesuaian lainnya.

Tetapkan ambang batas termal untuk dexopt latar belakang

Kontrol termal dari pekerjaan dexopt latar belakang dilakukan oleh Penjadwal Pekerjaan. Pekerjaan dibatalkan segera ketika suhu mencapai THERMAL_STATUS_MODERATE . Ambang batas THERMAL_STATUS_MODERATE dapat disesuaikan.

Tentukan apakah dexopt latar belakang sedang berjalan

Pekerjaan dexopt latar belakang dikelola oleh Penjadwal Pekerjaan, dan ID pekerjaannya adalah 27873780 . Untuk menentukan apakah pekerjaan sedang berjalan, gunakan API Penjadwal Pekerjaan.

// 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.
  ...
}

Berikan profil untuk dexopt

Untuk menggunakan profil untuk memandu dexopt, letakkan file .prof atau file .dm di sebelah APK.

File .prof harus berupa file profil berformat biner, dan nama file harus berupa nama file APK + .prof . Misalnya,

base.apk.prof

Nama file .dm harus berupa nama file APK dengan ekstensi yang diganti dengan .dm . Misalnya,

base.dm

Untuk memverifikasi bahwa profil digunakan untuk dexopt, jalankan dexopt dengan speed-profile dan periksa hasilnya.

pm art clear-app-profiles <package-name>
pm compile -m speed-profile -f -v <package-name>

Baris pertama menghapus semua profil yang dihasilkan oleh runtime (yaitu, yang ada di /data/misc/profiles ), jika ada, untuk memastikan bahwa profil di sebelah APK adalah satu-satunya profil yang mungkin dapat digunakan oleh ART Service. Baris kedua menjalankan dexopt dengan speed-profile , dan melewati -v untuk mencetak hasil verbose.

Jika profil sedang digunakan, Anda akan melihat hasil actualCompilerFilter=speed-profile . Jika tidak, Anda akan melihat actualCompilerFilter=verify . Misalnya,

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}

Alasan umum mengapa ART Service tidak menggunakan profil adalah sebagai berikut:

  • Profil tersebut memiliki nama file yang salah atau tidak berada di samping APK.
  • Profil memiliki format yang salah.
  • Profil tidak cocok dengan APK. (Checksum di profil tidak cocok dengan checksum file .dex di APK.)