Konfigurasi Layanan ART

Sebelum memulai, lihat ringkasan umum Layanan ART.

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

Properti sistem

Layanan ART mendukung semua opsi dex2oat.

Selain itu, Layanan ART mendukung properti sistem berikut:

pm.dexopt.<reason>

Ini adalah kumpulan properti sistem yang menentukan filter compiler default untuk semua alasan kompilasi standar yang dijelaskan dalam Skenario penghapusan.

Untuk informasi selengkapnya, lihat Filter compiler.

Nilai default standar 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 compiler penggantian untuk aplikasi yang digunakan oleh aplikasi lain.

Pada prinsipnya, Layanan ART melakukan kompilasi yang dipandu profil (speed-profile) untuk semua aplikasi jika 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 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, Layanan ART akan kembali untuk menggunakan filter compiler yang ditentukan oleh pm.dexopt.shared.

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

pm.dexopt.<reason>.concurrency (default: 1)

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

Perhatikan bahwa efek dari opsi ini digabungkan dengan opsi penggunaan resource dex2oat (dalvik.vm.*dex2oat-threads, dalvik.vm.*dex2oat-cpu-set, dan profil tugas):

  • dalvik.vm.*dex2oat-threads mengontrol jumlah thread untuk setiap dex2oat pemanggilan, sedangkan pm.dexopt.<reason>.concurrency mengontrol jumlah pemanggilan dex2oat. Artinya, jumlah maksimum thread serentak adalah hasil dari perkalian dua properti sistem.
  • dalvik.vm.*dex2oat-cpu-set dan profil tugas selalu mengikat core CPU penggunaan, terlepas dari jumlah maksimum thread serentak (dibahas di atas).

Satu pemanggilan dex2oat mungkin tidak sepenuhnya menggunakan semua core CPU, terlepas dari dari dalvik.vm.*dex2oat-threads. Oleh karena itu, meningkatkan jumlah pemanggilan (pm.dexopt.<reason>.concurrency) dapat memanfaatkan inti CPU dengan lebih baik, untuk mempercepat progres dexopt secara keseluruhan. Hal ini sangat berguna selama booting.

Namun, terlalu banyak pemanggilan dex2oat dapat menyebabkan perangkat kehabisan memori, meskipun hal ini dapat dimitigasi dengan menyetel dalvik.vm.dex2oat-swap ke true untuk mengizinkan penggunaan file swap. Terlalu banyak {i>pemanggilan<i} juga dapat menyebabkan pengalihan konteks yang tidak perlu. Oleh karena itu, angka ini harus disesuaikan dengan saksama per produk.

pm.dexopt.downgrade_after_inactive_days (default: tidak ditetapkan)

Jika opsi ini disetel, Layanan ART hanya akan melakukan dexopts aplikasi yang digunakan dalam jumlah hari.

Selain itu, jika penyimpanan hampir habis, selama dexopt latar belakang, Layanan ART menurunkan versi filter compiler aplikasi yang tidak digunakan dalam periode jumlah hari, untuk mengosongkan ruang penyimpanan. Alasan compiler untuk ini adalah inactive, dan filter compiler ditentukan oleh pm.dexopt.inactive. Ruang nilai minimum untuk memicu fitur ini adalah nilai minimum ruang penyimpanan Pengelola Penyimpanan (dapat dikonfigurasi melalui setelan global sys_storage_threshold_percentage dan sys_storage_threshold_max_bytes, default: 500MB) plus 500MB.

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

pm.dexopt.disable_bg_dexopt (default: false)

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

Jika tugas dexopt latar belakang sudah dijadwalkan tetapi belum berjalan, opsi tersebut tidak berpengaruh. Artinya, tugas akan tetap berjalan.

Urutan perintah yang disarankan untuk mencegah tugas dexopt latar belakang dari berjalan adalah:

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

Baris pertama mencegah tugas dexopt latar belakang dijadwalkan, jika belum dijadwalkan. Baris kedua membatalkan jadwal tugas dexopt latar belakang, jika sudah dijadwalkan, dan akan langsung membatalkan tugas dexopt latar belakang, jika komputernya berjalan.

API Layanan ART

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

ArtManagerLocal adalah singleton yang dipegang oleh LocalManagerRegistry. Pembantu fungsi 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 dari semua aplikasi. Anda bisa mendapatkannya dengan memanggil PackageManagerLocal#withFilteredSnapshot, dengan PackageManagerLocal juga singleton yang dimiliki 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 umum API.

Memicu dexopt untuk 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 bisa meneruskan alasan dexopt Anda sendiri. Jika Anda melakukannya, kelas prioritas dan filter compiler harus diatur 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 dexopt

Jika operasi dimulai oleh panggilan dexoptPackage, Anda dapat meneruskan sinyal pembatalan, yang memungkinkan Anda membatalkan operasi pada waktu tertentu. Hal ini dapat berguna saat 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();

Mendapatkan hasil dexopt

Jika operasi dimulai oleh panggilan dexoptPackage, Anda bisa mendapatkan hasilnya dari nilai yang ditampilkan.

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

// Process the result here.
...

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

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

Argumen pertama menentukan apakah hanya akan menyertakan pembaruan dalam hasil. Jika Anda hanya ingin mendengarkan paket yang diperbarui oleh {i>dexopt<i}, setel ke true.

Argumen kedua adalah eksekutor callback. Untuk menjalankan callback pada thread yang sama yang menjalankan dexopt, gunakan Runnable::run. Jika Anda tidak ingin untuk memblokir dexopt, menggunakan eksekutor asinkron.

Anda dapat menambahkan beberapa callback, dan Layanan ART akan menjalankan semuanya secara berurutan. Semua callback akan tetap aktif untuk semua panggilan mendatang kecuali Anda menghapusnya.

Jika Anda ingin menghapus callback, pertahankan referensi callback tersebut saat Anda menambahkannya, lalu 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);

Menyesuaikan daftar paket dan parameter dexopt

Layanan ART memulai operasi dexopt sendiri selama booting dan latar belakang {i>dexopt<i}. Untuk menyesuaikan daftar paket atau parameter {i>dexopt<i} 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 benar-benar berbeda.

Callback Anda harus mengabaikan alasan yang tidak diketahui karena alasan lain mungkin ditambahkan di masa depan.

Anda dapat menetapkan maksimal satu BatchDexoptStartCallback. Callback akan tetap aktif untuk semua panggilan mendatang kecuali Anda menghapusnya.

Jika Anda ingin menghapus callback, gunakan ArtManagerLocal#clearBatchDexoptStartCallback.

getArtManagerLocal().clearBatchDexoptStartCallback();

Menyesuaikan parameter tugas dexopt latar belakang

Secara default, tugas dexopt latar belakang berjalan sekali sehari saat perangkat tidak ada aktivitas dan pengisian daya. Hal ini dapat diubah menggunakan ArtManagerLocal#setScheduleBackgroundDexoptJobCallback.

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

Anda dapat menetapkan maksimal satu ScheduleBackgroundDexoptJobCallback. Callback akan tetap aktif untuk semua panggilan mendatang kecuali Anda menghapusnya.

Jika Anda ingin menghapus callback, gunakan ArtManagerLocal#clearScheduleBackgroundDexoptJobCallback.

getArtManagerLocal().clearScheduleBackgroundDexoptJobCallback();

Nonaktifkan dexopt untuk sementara

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

Jika operasi yang Anda batalkan adalah dexopt latar belakang, operasi tersebut akan mengikuti metode kebijakan percobaan ulang (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 maksimal satu BatchDexoptStartCallback. Jika Anda juga ingin menggunakan BatchDexoptStartCallback untuk menyesuaikan daftar paket atau parameter dexopt, Anda harus menggabungkan kode tersebut menjadi satu callback.

// Bad example.

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

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

Operasi dexopt yang dilakukan pada penginstalan aplikasi tidak dimulai oleh ART Layanan. Sebagai gantinya, ini dimulai oleh pengelola paket melalui sebuah Panggilan dexoptPackage. Oleh karena itu, tindakan ini tidak memicu BatchDexoptStartCallback. Untuk menonaktifkan dexopt saat penginstalan aplikasi, cegah pengelola paket agar tidak memanggil dexoptPackage.

Mengganti filter compiler untuk paket tertentu (Android 15+)

Anda dapat mengganti filter compiler untuk paket tertentu dengan mendaftarkan melalui setAdjustCompilerFilterCallback. Callback dipanggil setiap kali sebuah paket akan di-dexopt, tidak peduli dexopt yang dimulai oleh Layanan ART selama dexopt booting dan latar belakang atau dengan panggilan API dexoptPackage.

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

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

Anda hanya dapat menetapkan satu AdjustCompilerFilterCallback. Jika Anda ingin menggunakan AdjustCompilerFilterCallback untuk mengganti filter compiler untuk beberapa paket, Anda harus menggabungkan kode menjadi satu callback. Callback tetap aktif untuk semua panggilan mendatang kecuali Anda menghapusnya.

Jika Anda ingin menghapus callback, gunakan ArtManagerLocal#clearAdjustCompilerFilterCallback.

getArtManagerLocal().clearAdjustCompilerFilterCallback();

Penyesuaian lainnya

Layanan ART juga mendukung beberapa penyesuaian lainnya.

Menetapkan batas termal untuk dexopt latar belakang

Kontrol termal tugas dexopt latar belakang dilakukan oleh Job Scheduler. Tugas segera dibatalkan saat suhu mencapai THERMAL_STATUS_MODERATE Ambang batas THERMAL_STATUS_MODERATE dapat disetel.

Menentukan apakah dexopt latar belakang sedang berjalan

Tugas dexopt latar belakang dikelola oleh Job Scheduler, dan ID tugasnya adalah 27873780. Untuk menentukan apakah tugas sedang berjalan, gunakan 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.
  ...
}

Menyediakan profil untuk dexopt

Untuk menggunakan profil yang akan memandu dexopt, tempatkan file .prof atau .dm di samping APK lainnya.

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

base.apk.prof

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

base.dm

Untuk memverifikasi bahwa profil sedang 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, profil di /data/misc/profiles), jika ada, untuk memastikan bahwa profil di samping APK telah satu-satunya profil yang mungkin dapat digunakan oleh Layanan ART. Baris kedua menjalankan dexopt dengan speed-profile, dan akan meneruskan -v untuk mencetak hasil panjang.

Jika profil sedang digunakan, Anda akan melihat actualCompilerFilter=speed-profile di hasilnya. 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 Layanan ART tidak menggunakan profil meliputi:

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